🧹 Moved Sb1 API to separate workspace and created common workspace
- Created common workspace - Create Sparebank1Api workspace - Moved logger to common - Moved SB1 types to types.ts - Logger will avoid duplicating first line when capturing console.logs - Updated imports and added type keyword - Added nonUniqueId type
This commit is contained in:
12
packages/sparebank1Api/common.ts
Normal file
12
packages/sparebank1Api/common.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { Failure, Success } from "./types"
|
||||
|
||||
export const baseUrl = "https://api.sparebank1.no"
|
||||
|
||||
export const success = <T>(data: T): Success<T> => ({
|
||||
status: "success",
|
||||
data: data,
|
||||
})
|
||||
export const failure = <T>(data: T): Failure<T> => ({
|
||||
status: "failure",
|
||||
data: data,
|
||||
})
|
30
packages/sparebank1Api/oauth.ts
Normal file
30
packages/sparebank1Api/oauth.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { OAuthTokenResponse, Result } from "./types"
|
||||
import * as querystring from "node:querystring"
|
||||
import { baseUrl, failure, success } from "./common"
|
||||
import logger from "@common/logger"
|
||||
|
||||
export async function refreshToken(
|
||||
clientId: string,
|
||||
clientSecret: string,
|
||||
refreshToken: string,
|
||||
): Promise<Result<OAuthTokenResponse, string>> {
|
||||
const queries = querystring.stringify({
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
refresh_token: refreshToken,
|
||||
grant_type: "refresh_token",
|
||||
})
|
||||
const url = `${baseUrl}/oauth/token?${queries}`
|
||||
logger.debug(`Sending POST request to url: '${url}'`)
|
||||
const response = await fetch(url, {
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
})
|
||||
logger.debug(`Received response with status '${response.status}'`)
|
||||
if (!response.ok) {
|
||||
return failure(await response.text())
|
||||
}
|
||||
return success(await response.json())
|
||||
}
|
6
packages/sparebank1Api/package.json
Normal file
6
packages/sparebank1Api/package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "packages",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"license": "ISC"
|
||||
}
|
35
packages/sparebank1Api/transactions.ts
Normal file
35
packages/sparebank1Api/transactions.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import type { Interval, TransactionResponse } from "./types"
|
||||
import * as querystring from "node:querystring"
|
||||
import { toISODateString } from "@common/date"
|
||||
import logger from "@common/logger"
|
||||
import { baseUrl } from "./common"
|
||||
|
||||
export async function list(
|
||||
accessToken: string,
|
||||
accountKeys: string | ReadonlyArray<string>,
|
||||
interval?: Interval,
|
||||
): Promise<TransactionResponse> {
|
||||
const queryString = querystring.stringify({
|
||||
accountKey: accountKeys,
|
||||
...(interval && {
|
||||
fromDate: toISODateString(interval.fromDate),
|
||||
toDate: toISODateString(interval.toDate),
|
||||
}),
|
||||
})
|
||||
|
||||
const url = `${baseUrl}/personal/banking/transactions?${queryString}`
|
||||
logger.debug(`Sending GET request to '${url}'`)
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: "application/vnd.sparebank1.v1+json;charset=utf-8",
|
||||
},
|
||||
})
|
||||
logger.debug(`Received response with status '${response.status}'`)
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
} else {
|
||||
logger.warn(await response.json())
|
||||
return { transactions: [] }
|
||||
}
|
||||
}
|
43
packages/sparebank1Api/types.ts
Normal file
43
packages/sparebank1Api/types.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import type { Dayjs } from "dayjs"
|
||||
|
||||
export type Success<T> = { status: "success"; data: T }
|
||||
export type Failure<T> = { status: "failure"; data: T }
|
||||
export type Result<OK, Err> = Success<OK> | Failure<Err>
|
||||
|
||||
export interface Interval {
|
||||
fromDate: Dayjs
|
||||
toDate: Dayjs
|
||||
}
|
||||
|
||||
export interface OAuthTokenResponse {
|
||||
access_token: string
|
||||
expires_in: number
|
||||
refresh_token_expires_in: number
|
||||
refresh_token_absolute_expires_in: number
|
||||
token_type: "Bearer"
|
||||
refresh_token: string
|
||||
}
|
||||
|
||||
export type BookingStatus = "PENDING" | "BOOKED"
|
||||
|
||||
export type NonUniqueId = "000000000000000000" | `${number}`
|
||||
|
||||
export interface SB1Transaction {
|
||||
id: string
|
||||
nonUniqueId: NonUniqueId
|
||||
// The Id of the account
|
||||
accountKey: string
|
||||
// Unix time
|
||||
date: number
|
||||
// Amount in NOK
|
||||
amount: number
|
||||
cleanedDescription: string
|
||||
remoteAccountName: string
|
||||
bookingStatus: BookingStatus
|
||||
|
||||
[key: string]: string | number | boolean | unknown
|
||||
}
|
||||
|
||||
export interface TransactionResponse {
|
||||
transactions: ReadonlyArray<SB1Transaction>
|
||||
}
|
Reference in New Issue
Block a user