@seamapi/http 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE.txt +20 -0
  2. package/README.md +155 -0
  3. package/connect.d.ts +1 -0
  4. package/connect.js +2 -0
  5. package/connect.js.map +1 -0
  6. package/dist/connect.cjs +219 -0
  7. package/dist/connect.cjs.map +1 -0
  8. package/dist/connect.d.cts +35 -0
  9. package/dist/index.cjs +8 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.d.cts +3 -0
  12. package/index.d.ts +2 -0
  13. package/index.js +2 -0
  14. package/index.js.map +1 -0
  15. package/lib/seam/connect/auth.d.ts +7 -0
  16. package/lib/seam/connect/auth.js +47 -0
  17. package/lib/seam/connect/auth.js.map +1 -0
  18. package/lib/seam/connect/axios.d.ts +3 -0
  19. package/lib/seam/connect/axios.js +17 -0
  20. package/lib/seam/connect/axios.js.map +1 -0
  21. package/lib/seam/connect/client-options.d.ts +19 -0
  22. package/lib/seam/connect/client-options.js +29 -0
  23. package/lib/seam/connect/client-options.js.map +1 -0
  24. package/lib/seam/connect/client.d.ts +11 -0
  25. package/lib/seam/connect/client.js +51 -0
  26. package/lib/seam/connect/client.js.map +1 -0
  27. package/lib/seam/connect/index.d.ts +1 -0
  28. package/lib/seam/connect/index.js +2 -0
  29. package/lib/seam/connect/index.js.map +1 -0
  30. package/lib/seam/connect/legacy/workspaces.d.ts +8 -0
  31. package/lib/seam/connect/legacy/workspaces.js +10 -0
  32. package/lib/seam/connect/legacy/workspaces.js.map +1 -0
  33. package/lib/seam/connect/parse-options.d.ts +2 -0
  34. package/lib/seam/connect/parse-options.js +20 -0
  35. package/lib/seam/connect/parse-options.js.map +1 -0
  36. package/lib/seam/connect/routes/workspaces.d.ts +11 -0
  37. package/lib/seam/connect/routes/workspaces.js +20 -0
  38. package/lib/seam/connect/routes/workspaces.js.map +1 -0
  39. package/package.json +109 -0
  40. package/src/connect.ts +1 -0
  41. package/src/index.ts +1 -0
  42. package/src/lib/seam/connect/auth.ts +86 -0
  43. package/src/lib/seam/connect/axios.ts +23 -0
  44. package/src/lib/seam/connect/client-options.ts +62 -0
  45. package/src/lib/seam/connect/client.ts +63 -0
  46. package/src/lib/seam/connect/index.ts +1 -0
  47. package/src/lib/seam/connect/legacy/workspaces.ts +26 -0
  48. package/src/lib/seam/connect/parse-options.ts +28 -0
  49. package/src/lib/seam/connect/routes/workspaces.ts +41 -0
@@ -0,0 +1,51 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _SeamHttp_legacy;
13
+ import { createAxiosClient } from './axios.js';
14
+ import { InvalidSeamHttpOptionsError, isSeamHttpOptionsWithApiKey, isSeamHttpOptionsWithClientSessionToken, } from './client-options.js';
15
+ import { LegacyWorkspacesHttp } from './legacy/workspaces.js';
16
+ import { parseOptions } from './parse-options.js';
17
+ import { WorkspacesHttp } from './routes/workspaces.js';
18
+ export class SeamHttp {
19
+ constructor(apiKeyOrOptions) {
20
+ _SeamHttp_legacy.set(this, void 0);
21
+ const options = parseOptions(apiKeyOrOptions);
22
+ __classPrivateFieldSet(this, _SeamHttp_legacy, options.enableLegacyMethodBehaivor, "f");
23
+ this.client = createAxiosClient(options);
24
+ }
25
+ static fromApiKey(apiKey, options = {}) {
26
+ const opts = { ...options, apiKey };
27
+ if (!isSeamHttpOptionsWithApiKey(opts)) {
28
+ throw new InvalidSeamHttpOptionsError('Missing apiKey');
29
+ }
30
+ return new SeamHttp(opts);
31
+ }
32
+ static fromClientSessionToken(clientSessionToken, options = {}) {
33
+ const opts = { ...options, clientSessionToken };
34
+ if (!isSeamHttpOptionsWithClientSessionToken(opts)) {
35
+ throw new InvalidSeamHttpOptionsError('Missing clientSessionToken');
36
+ }
37
+ return new SeamHttp(opts);
38
+ }
39
+ // TODO
40
+ // static fromPublishableKey and deprecate getClientSessionToken
41
+ // TODO: Should we keep makeRequest?
42
+ // Better to implement error handling and wrapping in an error handler.
43
+ // makeRequest
44
+ get workspaces() {
45
+ if (__classPrivateFieldGet(this, _SeamHttp_legacy, "f"))
46
+ return new LegacyWorkspacesHttp(this.client);
47
+ return new WorkspacesHttp(this.client);
48
+ }
49
+ }
50
+ _SeamHttp_legacy = new WeakMap();
51
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/lib/seam/connect/client.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EACL,2BAA2B,EAC3B,2BAA2B,EAC3B,uCAAuC,GAIxC,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEvD,MAAM,OAAO,QAAQ;IAKnB,YAAY,eAAyC;QAFrD,mCAAgB;QAGd,MAAM,OAAO,GAAG,YAAY,CAAC,eAAe,CAAC,CAAA;QAC7C,uBAAA,IAAI,oBAAW,OAAO,CAAC,0BAA0B,MAAA,CAAA;QACjD,IAAI,CAAC,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAC1C,CAAC;IAED,MAAM,CAAC,UAAU,CACf,MAA2C,EAC3C,UAAqD,EAAE;QAEvD,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAA;QACnC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,EAAE;YACtC,MAAM,IAAI,2BAA2B,CAAC,gBAAgB,CAAC,CAAA;SACxD;QACD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;IAED,MAAM,CAAC,sBAAsB,CAC3B,kBAA+E,EAC/E,UAGI,EAAE;QAEN,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,EAAE,kBAAkB,EAAE,CAAA;QAC/C,IAAI,CAAC,uCAAuC,CAAC,IAAI,CAAC,EAAE;YAClD,MAAM,IAAI,2BAA2B,CAAC,4BAA4B,CAAC,CAAA;SACpE;QACD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;IAED,OAAO;IACP,gEAAgE;IAEhE,oCAAoC;IACpC,uEAAuE;IACvE,cAAc;IAEd,IAAI,UAAU;QACZ,IAAI,uBAAA,IAAI,wBAAQ;YAAE,OAAO,IAAI,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC9D,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACxC,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export * from './client.js';
@@ -0,0 +1,2 @@
1
+ export * from './client.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/seam/connect/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA"}
@@ -0,0 +1,8 @@
1
+ import type { RouteRequestParams, RouteResponse } from '@seamapi/types/connect';
2
+ import type { SetNonNullable } from 'type-fest';
3
+ import { WorkspacesHttp } from '../../../../lib/seam/connect/routes/workspaces.js';
4
+ export declare class LegacyWorkspacesHttp extends WorkspacesHttp {
5
+ get(params?: WorkspacesGetParams): Promise<WorkspacesGetResponse['workspace']>;
6
+ }
7
+ export type WorkspacesGetParams = SetNonNullable<Required<RouteRequestParams<'/workspaces/get'>>>;
8
+ export type WorkspacesGetResponse = SetNonNullable<Required<RouteResponse<'/workspaces/get'>>>;
@@ -0,0 +1,10 @@
1
+ import { WorkspacesHttp } from '../../../../lib/seam/connect/routes/workspaces.js';
2
+ export class LegacyWorkspacesHttp extends WorkspacesHttp {
3
+ async get(params = {}) {
4
+ const { data } = await this.client.get('/workspaces/get', {
5
+ params,
6
+ });
7
+ return data.workspace;
8
+ }
9
+ }
10
+ //# sourceMappingURL=workspaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../../src/lib/seam/connect/legacy/workspaces.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAA;AAEtE,MAAM,OAAO,oBAAqB,SAAQ,cAAc;IAC7C,KAAK,CAAC,GAAG,CAChB,SAA8B,EAAE;QAEhC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CACpC,iBAAiB,EACjB;YACE,MAAM;SACP,CACF,CAAA;QACD,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ import type { SeamHttpOptions } from './client-options.js';
2
+ export declare const parseOptions: (apiKeyOrOptions: string | SeamHttpOptions) => Required<SeamHttpOptions>;
@@ -0,0 +1,20 @@
1
+ export const parseOptions = (apiKeyOrOptions) => {
2
+ const options = typeof apiKeyOrOptions === 'string'
3
+ ? { apiKey: apiKeyOrOptions }
4
+ : apiKeyOrOptions;
5
+ const endpoint = options.endpoint ??
6
+ globalThis.process?.env?.['SEAM_ENDPOINT'] ??
7
+ globalThis.process?.env?.['SEAM_API_URL'] ??
8
+ 'https://connect.getseam.com';
9
+ const apiKey = 'apiKey' in options
10
+ ? options.apiKey
11
+ : globalThis.process?.env?.['SEAM_API_KEY'];
12
+ return {
13
+ ...options,
14
+ ...(apiKey != null ? { apiKey } : {}),
15
+ endpoint,
16
+ axiosOptions: options.axiosOptions ?? {},
17
+ enableLegacyMethodBehaivor: false,
18
+ };
19
+ };
20
+ //# sourceMappingURL=parse-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-options.js","sourceRoot":"","sources":["../../../src/lib/seam/connect/parse-options.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,eAAyC,EACd,EAAE;IAC7B,MAAM,OAAO,GACX,OAAO,eAAe,KAAK,QAAQ;QACjC,CAAC,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE;QAC7B,CAAC,CAAC,eAAe,CAAA;IAErB,MAAM,QAAQ,GACZ,OAAO,CAAC,QAAQ;QAChB,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC;QAC1C,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC;QACzC,6BAA6B,CAAA;IAE/B,MAAM,MAAM,GACV,QAAQ,IAAI,OAAO;QACjB,CAAC,CAAC,OAAO,CAAC,MAAM;QAChB,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,CAAA;IAE/C,OAAO;QACL,GAAG,OAAO;QACV,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,QAAQ;QACR,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,EAAE;QACxC,0BAA0B,EAAE,KAAK;KAClC,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,11 @@
1
+ import type { RouteRequestParams, RouteResponse } from '@seamapi/types/connect';
2
+ import { Axios } from 'axios';
3
+ import type { SetNonNullable } from 'type-fest';
4
+ import type { SeamHttpOptions } from '../../../../lib/seam/connect/client-options.js';
5
+ export declare class WorkspacesHttp {
6
+ client: Axios;
7
+ constructor(apiKeyOrOptionsOrClient: Axios | string | SeamHttpOptions);
8
+ get(params?: WorkspacesGetParams): Promise<WorkspacesGetResponse['workspace']>;
9
+ }
10
+ export type WorkspacesGetParams = SetNonNullable<Required<RouteRequestParams<'/workspaces/get'>>>;
11
+ export type WorkspacesGetResponse = SetNonNullable<Required<RouteResponse<'/workspaces/get'>>>;
@@ -0,0 +1,20 @@
1
+ import { Axios } from 'axios';
2
+ import { createAxiosClient } from '../../../../lib/seam/connect/axios.js';
3
+ import { parseOptions } from '../../../../lib/seam/connect/parse-options.js';
4
+ export class WorkspacesHttp {
5
+ constructor(apiKeyOrOptionsOrClient) {
6
+ if (apiKeyOrOptionsOrClient instanceof Axios) {
7
+ this.client = apiKeyOrOptionsOrClient;
8
+ return;
9
+ }
10
+ const options = parseOptions(apiKeyOrOptionsOrClient);
11
+ this.client = createAxiosClient(options);
12
+ }
13
+ async get(params = {}) {
14
+ const { data } = await this.client.get('/workspaces/get', {
15
+ params,
16
+ });
17
+ return data.workspace;
18
+ }
19
+ }
20
+ //# sourceMappingURL=workspaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../../src/lib/seam/connect/routes/workspaces.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAG7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAA;AAEhE,MAAM,OAAO,cAAc;IAGzB,YAAY,uBAAyD;QACnE,IAAI,uBAAuB,YAAY,KAAK,EAAE;YAC5C,IAAI,CAAC,MAAM,GAAG,uBAAuB,CAAA;YACrC,OAAM;SACP;QAED,MAAM,OAAO,GAAG,YAAY,CAAC,uBAAuB,CAAC,CAAA;QACrD,IAAI,CAAC,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAC1C,CAAC;IAED,KAAK,CAAC,GAAG,CACP,SAA8B,EAAE;QAEhC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CACpC,iBAAiB,EACjB;YACE,MAAM;SACP,CACF,CAAA;QACD,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "@seamapi/http",
3
+ "version": "0.0.2",
4
+ "description": "JavaScript HTTP client for the Seam API written in TypeScript.",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "types": "index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./index.js",
11
+ "require": "./dist/index.cjs",
12
+ "types": "./index.d.ts"
13
+ },
14
+ "./connect": {
15
+ "import": "./connect.js",
16
+ "require": "./dist/connect.cjs",
17
+ "types": "./connect.d.ts"
18
+ }
19
+ },
20
+ "module": "index.js",
21
+ "sideEffects": false,
22
+ "keywords": [
23
+ "node"
24
+ ],
25
+ "homepage": "https://github.com/seamapi/javascript-http",
26
+ "bugs": "https://github.com/seamapi/javascript-http/issues",
27
+ "repository": "seamapi/javascript-http",
28
+ "license": "MIT",
29
+ "author": {
30
+ "name": "Seam Labs, Inc.",
31
+ "email": "devops@getseam.com"
32
+ },
33
+ "files": [
34
+ "index.js",
35
+ "index.js.map",
36
+ "index.d.ts",
37
+ "connect.js",
38
+ "connect.js.map",
39
+ "connect.d.ts",
40
+ "dist",
41
+ "lib",
42
+ "src",
43
+ "!**/*.test.ts"
44
+ ],
45
+ "scripts": {
46
+ "build": "npm run build:entrypoints",
47
+ "prebuild": "concurrently --raw --group 'tsx src/index.ts' 'tsx src/connect.ts'",
48
+ "postbuild": "concurrently --raw --group 'node ./index.js' 'node ./connect.js'",
49
+ "build:entrypoints": "npm run build:ts",
50
+ "postbuild:entrypoints": "tsup",
51
+ "build:ts": "tsc --project tsconfig.build.json",
52
+ "prebuild:ts": "del 'index.*' 'connect.*' 'lib'",
53
+ "postbuild:ts": "tsc-alias --project tsconfig.build.json",
54
+ "typecheck": "tsc",
55
+ "test": "c8 ava",
56
+ "pretest": "tsx src/index.ts",
57
+ "test:update": "ava --update-snapshots",
58
+ "test:watch": "ava --watch",
59
+ "test:debug": "ava debug --break",
60
+ "lint": "eslint --ignore-path .gitignore .",
61
+ "prelint": "prettier --check --ignore-path .gitignore .",
62
+ "postversion": "git push --follow-tags",
63
+ "example": "tsx examples",
64
+ "example:inspect": "tsx --inspect examples",
65
+ "format": "eslint --ignore-path .gitignore --fix .",
66
+ "preformat": "prettier --write --ignore-path .gitignore .",
67
+ "report": "c8 report"
68
+ },
69
+ "engines": {
70
+ "node": ">=16.13.0",
71
+ "npm": ">= 8.1.0"
72
+ },
73
+ "peerDependencies": {
74
+ "@seamapi/types": "^1.0.0",
75
+ "type-fest": "^4.0.0"
76
+ },
77
+ "peerDependenciesMeta": {
78
+ "@seamapi/types": {
79
+ "optional": true
80
+ },
81
+ "type-fest": {
82
+ "optional": true
83
+ }
84
+ },
85
+ "dependencies": {
86
+ "axios": "^1.5.0"
87
+ },
88
+ "devDependencies": {
89
+ "@seamapi/types": "^1.14.0",
90
+ "@types/node": "^18.11.18",
91
+ "ava": "^5.0.1",
92
+ "c8": "^8.0.0",
93
+ "concurrently": "^8.2.1",
94
+ "del-cli": "^5.0.0",
95
+ "eslint": "^8.9.0",
96
+ "eslint-config-prettier": "^9.0.0",
97
+ "eslint-config-standard": "^17.1.0",
98
+ "eslint-config-standard-with-typescript": "^39.0.0",
99
+ "eslint-plugin-simple-import-sort": "^10.0.0",
100
+ "eslint-plugin-unused-imports": "^3.0.0",
101
+ "landlubber": "^1.0.0",
102
+ "prettier": "^3.0.0",
103
+ "tsc-alias": "^1.8.2",
104
+ "tsup": "^7.2.0",
105
+ "tsx": "^3.12.1",
106
+ "type-fest": "^4.3.1",
107
+ "typescript": "^5.1.0"
108
+ }
109
+ }
package/src/connect.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './lib/seam/connect/index.js'
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export default null
@@ -0,0 +1,86 @@
1
+ import {
2
+ InvalidSeamHttpOptionsError,
3
+ isSeamHttpOptionsWithApiKey,
4
+ isSeamHttpOptionsWithClientSessionToken,
5
+ type SeamHttpOptions,
6
+ type SeamHttpOptionsWithApiKey,
7
+ type SeamHttpOptionsWithClientSessionToken,
8
+ } from './client-options.js'
9
+
10
+ type Headers = Record<string, string>
11
+
12
+ export const getAuthHeaders = (options: SeamHttpOptions): Headers => {
13
+ if (isSeamHttpOptionsWithApiKey(options)) {
14
+ return getAuthHeadersForApiKey(options)
15
+ }
16
+
17
+ if (isSeamHttpOptionsWithClientSessionToken(options)) {
18
+ return getAuthHeadersForClientSessionToken(options)
19
+ }
20
+
21
+ throw new InvalidSeamHttpOptionsError(
22
+ 'Must specify an apiKey or clientSessionToken',
23
+ )
24
+ }
25
+
26
+ const getAuthHeadersForApiKey = ({
27
+ apiKey,
28
+ }: SeamHttpOptionsWithApiKey): Headers => {
29
+ if (isClientSessionToken(apiKey)) {
30
+ throw new InvalidSeamTokenError(
31
+ 'A Client Session Token cannot be used as an apiKey',
32
+ )
33
+ }
34
+
35
+ if (isAccessToken(apiKey)) {
36
+ throw new InvalidSeamTokenError(
37
+ 'An access token cannot be used as an apiKey',
38
+ )
39
+ }
40
+
41
+ if (isJwt(apiKey) || !isSeamToken(apiKey)) {
42
+ throw new InvalidSeamTokenError(
43
+ `Unknown or invalid apiKey format, expected token to start with ${tokenPrefix}`,
44
+ )
45
+ }
46
+
47
+ return {
48
+ authorization: `Bearer ${apiKey}`,
49
+ }
50
+ }
51
+
52
+ const getAuthHeadersForClientSessionToken = ({
53
+ clientSessionToken,
54
+ }: SeamHttpOptionsWithClientSessionToken): Headers => {
55
+ if (!isClientSessionToken(clientSessionToken)) {
56
+ throw new InvalidSeamTokenError(
57
+ `Unknown or invalid clientSessionToken format, expected token to start with ${clientSessionTokenPrefix}`,
58
+ )
59
+ }
60
+
61
+ return {
62
+ authorization: `Bearer ${clientSessionToken}`,
63
+ 'client-session-token': clientSessionToken,
64
+ }
65
+ }
66
+
67
+ export class InvalidSeamTokenError extends Error {
68
+ constructor(message: string) {
69
+ super(`SeamHttp received an invalid token: ${message}`)
70
+ this.name = this.constructor.name
71
+ Error.captureStackTrace(this, this.constructor)
72
+ }
73
+ }
74
+
75
+ const tokenPrefix = 'seam_'
76
+
77
+ const clientSessionTokenPrefix = 'seam_cst'
78
+
79
+ const isClientSessionToken = (token: string): boolean =>
80
+ token.startsWith(clientSessionTokenPrefix)
81
+
82
+ const isAccessToken = (token: string): boolean => token.startsWith('seam_at')
83
+
84
+ const isJwt = (token: string): boolean => token.startsWith('ey')
85
+
86
+ const isSeamToken = (token: string): boolean => token.startsWith(tokenPrefix)
@@ -0,0 +1,23 @@
1
+ import axios, { type Axios } from 'axios'
2
+
3
+ import { getAuthHeaders } from './auth.js'
4
+ import {
5
+ isSeamHttpOptionsWithClientSessionToken,
6
+ type SeamHttpOptions,
7
+ } from './client-options.js'
8
+
9
+ export const createAxiosClient = (
10
+ options: Required<SeamHttpOptions>,
11
+ ): Axios => {
12
+ // TODO: axiosRetry? Allow options to configure this if so
13
+ return axios.create({
14
+ baseURL: options.endpoint,
15
+ withCredentials: isSeamHttpOptionsWithClientSessionToken(options),
16
+ ...options.axiosOptions,
17
+ headers: {
18
+ ...getAuthHeaders(options),
19
+ ...options.axiosOptions.headers,
20
+ // TODO: User-Agent
21
+ },
22
+ })
23
+ }
@@ -0,0 +1,62 @@
1
+ import type { AxiosRequestConfig } from 'axios'
2
+
3
+ export type SeamHttpOptions =
4
+ | SeamHttpOptionsWithApiKey
5
+ | SeamHttpOptionsWithClientSessionToken
6
+
7
+ interface SeamHttpCommonOptions {
8
+ endpoint?: string
9
+ axiosOptions?: AxiosRequestConfig
10
+ enableLegacyMethodBehaivor?: boolean
11
+ }
12
+
13
+ export interface SeamHttpOptionsWithApiKey extends SeamHttpCommonOptions {
14
+ apiKey: string
15
+ }
16
+
17
+ export const isSeamHttpOptionsWithApiKey = (
18
+ options: SeamHttpOptions,
19
+ ): options is SeamHttpOptionsWithApiKey => {
20
+ if (!('apiKey' in options)) return false
21
+
22
+ if ('clientSessionToken' in options && options.clientSessionToken != null) {
23
+ throw new InvalidSeamHttpOptionsError(
24
+ 'The clientSessionToken option cannot be used with the apiKey option.',
25
+ )
26
+ }
27
+
28
+ return true
29
+ }
30
+
31
+ export interface SeamHttpOptionsWithClientSessionToken
32
+ extends SeamHttpCommonOptions {
33
+ clientSessionToken: string
34
+ }
35
+
36
+ export const isSeamHttpOptionsWithClientSessionToken = (
37
+ options: SeamHttpOptions,
38
+ ): options is SeamHttpOptionsWithClientSessionToken => {
39
+ if (!('clientSessionToken' in options)) return false
40
+
41
+ if ('apiKey' in options && options.apiKey != null) {
42
+ throw new InvalidSeamHttpOptionsError(
43
+ 'The clientSessionToken option cannot be used with the apiKey option.',
44
+ )
45
+ }
46
+
47
+ return true
48
+ }
49
+
50
+ export class InvalidSeamHttpOptionsError extends Error {
51
+ constructor(message: string) {
52
+ super(`SeamHttp received invalid options: ${message}`)
53
+ this.name = this.constructor.name
54
+ Error.captureStackTrace(this, this.constructor)
55
+ }
56
+ }
57
+
58
+ // TODO: withSessionToken { sessionToken } or withMultiWorkspaceApiKey { apiKey }?
59
+ // export interface SeamHttpOptionsWithSessionToken extends SeamHttpCommonOptions {
60
+ // workspaceId: string
61
+ // apiKey: string
62
+ // }
@@ -0,0 +1,63 @@
1
+ import type { Axios } from 'axios'
2
+
3
+ import { createAxiosClient } from './axios.js'
4
+ import {
5
+ InvalidSeamHttpOptionsError,
6
+ isSeamHttpOptionsWithApiKey,
7
+ isSeamHttpOptionsWithClientSessionToken,
8
+ type SeamHttpOptions,
9
+ type SeamHttpOptionsWithApiKey,
10
+ type SeamHttpOptionsWithClientSessionToken,
11
+ } from './client-options.js'
12
+ import { LegacyWorkspacesHttp } from './legacy/workspaces.js'
13
+ import { parseOptions } from './parse-options.js'
14
+ import { WorkspacesHttp } from './routes/workspaces.js'
15
+
16
+ export class SeamHttp {
17
+ client: Axios
18
+
19
+ #legacy: boolean
20
+
21
+ constructor(apiKeyOrOptions: string | SeamHttpOptions) {
22
+ const options = parseOptions(apiKeyOrOptions)
23
+ this.#legacy = options.enableLegacyMethodBehaivor
24
+ this.client = createAxiosClient(options)
25
+ }
26
+
27
+ static fromApiKey(
28
+ apiKey: SeamHttpOptionsWithApiKey['apiKey'],
29
+ options: Omit<SeamHttpOptionsWithApiKey, 'apiKey'> = {},
30
+ ): SeamHttp {
31
+ const opts = { ...options, apiKey }
32
+ if (!isSeamHttpOptionsWithApiKey(opts)) {
33
+ throw new InvalidSeamHttpOptionsError('Missing apiKey')
34
+ }
35
+ return new SeamHttp(opts)
36
+ }
37
+
38
+ static fromClientSessionToken(
39
+ clientSessionToken: SeamHttpOptionsWithClientSessionToken['clientSessionToken'],
40
+ options: Omit<
41
+ SeamHttpOptionsWithClientSessionToken,
42
+ 'clientSessionToken'
43
+ > = {},
44
+ ): SeamHttp {
45
+ const opts = { ...options, clientSessionToken }
46
+ if (!isSeamHttpOptionsWithClientSessionToken(opts)) {
47
+ throw new InvalidSeamHttpOptionsError('Missing clientSessionToken')
48
+ }
49
+ return new SeamHttp(opts)
50
+ }
51
+
52
+ // TODO
53
+ // static fromPublishableKey and deprecate getClientSessionToken
54
+
55
+ // TODO: Should we keep makeRequest?
56
+ // Better to implement error handling and wrapping in an error handler.
57
+ // makeRequest
58
+
59
+ get workspaces(): WorkspacesHttp {
60
+ if (this.#legacy) return new LegacyWorkspacesHttp(this.client)
61
+ return new WorkspacesHttp(this.client)
62
+ }
63
+ }
@@ -0,0 +1 @@
1
+ export * from './client.js'
@@ -0,0 +1,26 @@
1
+ import type { RouteRequestParams, RouteResponse } from '@seamapi/types/connect'
2
+ import type { SetNonNullable } from 'type-fest'
3
+
4
+ import { WorkspacesHttp } from 'lib/seam/connect/routes/workspaces.js'
5
+
6
+ export class LegacyWorkspacesHttp extends WorkspacesHttp {
7
+ override async get(
8
+ params: WorkspacesGetParams = {},
9
+ ): Promise<WorkspacesGetResponse['workspace']> {
10
+ const { data } = await this.client.get<WorkspacesGetResponse>(
11
+ '/workspaces/get',
12
+ {
13
+ params,
14
+ },
15
+ )
16
+ return data.workspace
17
+ }
18
+ }
19
+
20
+ export type WorkspacesGetParams = SetNonNullable<
21
+ Required<RouteRequestParams<'/workspaces/get'>>
22
+ >
23
+
24
+ export type WorkspacesGetResponse = SetNonNullable<
25
+ Required<RouteResponse<'/workspaces/get'>>
26
+ >
@@ -0,0 +1,28 @@
1
+ import type { SeamHttpOptions } from './client-options.js'
2
+ export const parseOptions = (
3
+ apiKeyOrOptions: string | SeamHttpOptions,
4
+ ): Required<SeamHttpOptions> => {
5
+ const options =
6
+ typeof apiKeyOrOptions === 'string'
7
+ ? { apiKey: apiKeyOrOptions }
8
+ : apiKeyOrOptions
9
+
10
+ const endpoint =
11
+ options.endpoint ??
12
+ globalThis.process?.env?.['SEAM_ENDPOINT'] ??
13
+ globalThis.process?.env?.['SEAM_API_URL'] ??
14
+ 'https://connect.getseam.com'
15
+
16
+ const apiKey =
17
+ 'apiKey' in options
18
+ ? options.apiKey
19
+ : globalThis.process?.env?.['SEAM_API_KEY']
20
+
21
+ return {
22
+ ...options,
23
+ ...(apiKey != null ? { apiKey } : {}),
24
+ endpoint,
25
+ axiosOptions: options.axiosOptions ?? {},
26
+ enableLegacyMethodBehaivor: false,
27
+ }
28
+ }
@@ -0,0 +1,41 @@
1
+ import type { RouteRequestParams, RouteResponse } from '@seamapi/types/connect'
2
+ import { Axios } from 'axios'
3
+ import type { SetNonNullable } from 'type-fest'
4
+
5
+ import { createAxiosClient } from 'lib/seam/connect/axios.js'
6
+ import type { SeamHttpOptions } from 'lib/seam/connect/client-options.js'
7
+ import { parseOptions } from 'lib/seam/connect/parse-options.js'
8
+
9
+ export class WorkspacesHttp {
10
+ client: Axios
11
+
12
+ constructor(apiKeyOrOptionsOrClient: Axios | string | SeamHttpOptions) {
13
+ if (apiKeyOrOptionsOrClient instanceof Axios) {
14
+ this.client = apiKeyOrOptionsOrClient
15
+ return
16
+ }
17
+
18
+ const options = parseOptions(apiKeyOrOptionsOrClient)
19
+ this.client = createAxiosClient(options)
20
+ }
21
+
22
+ async get(
23
+ params: WorkspacesGetParams = {},
24
+ ): Promise<WorkspacesGetResponse['workspace']> {
25
+ const { data } = await this.client.get<WorkspacesGetResponse>(
26
+ '/workspaces/get',
27
+ {
28
+ params,
29
+ },
30
+ )
31
+ return data.workspace
32
+ }
33
+ }
34
+
35
+ export type WorkspacesGetParams = SetNonNullable<
36
+ Required<RouteRequestParams<'/workspaces/get'>>
37
+ >
38
+
39
+ export type WorkspacesGetResponse = SetNonNullable<
40
+ Required<RouteResponse<'/workspaces/get'>>
41
+ >