@capitalos/js 0.1.0
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.
- package/README.md +51 -0
- package/dist/index.d.mts +34 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +196 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +160 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# CapitalOS for JavaScript
|
|
2
|
+
|
|
3
|
+
Framework-agnostic JavaScript SDK for embedding CapitalOS Experiences without a dedicated framework package.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @capitalos/js
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
Please refer to the [official docs](https://docs.capitalos.com/docs/using-vanilla-js-client-library) for more details.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Create one CapitalOS client with a backend-backed one-time-token callback, then mount the Cards App into a DOM element.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { createCapitalOsClient } from '@capitalos/js'
|
|
21
|
+
|
|
22
|
+
const capitalOs = createCapitalOsClient({
|
|
23
|
+
getToken: async () => {
|
|
24
|
+
const response = await fetch('/api/capitalos/token', { method: 'POST' })
|
|
25
|
+
const data = await response.json()
|
|
26
|
+
return data.token
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const cards = capitalOs.mountCardsApp('#capitalos-cards', {
|
|
31
|
+
onLoaded: () => {
|
|
32
|
+
// Hide your loading UI.
|
|
33
|
+
},
|
|
34
|
+
onError: (error) => {
|
|
35
|
+
// Handle CapitalOSError.
|
|
36
|
+
console.error(error.code, error.message)
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Later, when navigating away or closing a modal:
|
|
41
|
+
cards.destroy()
|
|
42
|
+
capitalOs.destroy()
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`mountCardsApp` returns a Mount handle synchronously. Programmer errors such as a missing selector throw synchronously.
|
|
46
|
+
|
|
47
|
+
The SDK manages the iframe lifecycle, auto-sizing, Penpal connection, token exchange, token refresh, and cleanup.
|
|
48
|
+
|
|
49
|
+
## TypeScript support
|
|
50
|
+
|
|
51
|
+
TypeScript definitions for `@capitalos/js` are built into the npm package and should be automatically picked up by your editor.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CapitalOSError, CapitalOSError as CapitalOSError$1, ErrorCode, Logger, Logger as Logger$1, ThemeColorScheme, ThemeColorScheme as ThemeColorScheme$1 } from "@capitalos/core";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
interface CapitalOsClientConfig {
|
|
5
|
+
getToken: () => Promise<string>;
|
|
6
|
+
theme?: ThemeColorScheme$1;
|
|
7
|
+
enableLogging?: boolean;
|
|
8
|
+
logger?: Logger$1;
|
|
9
|
+
}
|
|
10
|
+
interface MountOptions {
|
|
11
|
+
onLoaded?: () => void;
|
|
12
|
+
onError?: (error: CapitalOSError$1) => void;
|
|
13
|
+
theme?: ThemeColorScheme$1;
|
|
14
|
+
enableLogging?: boolean;
|
|
15
|
+
heightOffsetPx?: number;
|
|
16
|
+
}
|
|
17
|
+
interface CapitalOsMount {
|
|
18
|
+
ready: Promise<void>;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
}
|
|
21
|
+
interface CapitalOsClient {
|
|
22
|
+
mountCardsApp(target: string | HTMLElement, options?: MountOptions): CapitalOsMount;
|
|
23
|
+
destroy(): void;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/capital-os-client.d.ts
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
28
|
+
declare function createCapitalOsClient(config: CapitalOsClientConfig): CapitalOsClient;
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
//# sourceMappingURL=capital-os-client.d.ts.map
|
|
32
|
+
|
|
33
|
+
export { CapitalOSError, CapitalOsClient, CapitalOsClientConfig, CapitalOsMount, ErrorCode, Logger, MountOptions, ThemeColorScheme, createCapitalOsClient };
|
|
34
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/capital-os-client.ts"],"sourcesContent":null,"mappings":";;;UAEiB,qBAAA;kBACC;EADD,KAAA,CAAA,EAEP,kBAF4B;EAAA,aAAA,CAAA,EAAA,OAAA;EAAA,MACpB,CAAA,EAGP,QAHO;;AAGP,UAGM,YAAA,CAHN;EAAM,QAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAGA,OAAA,CAAA,EAAA,CAAA,KAAY,EAET,gBAFS,EAAA,GAAA,IAAA;EAAA,KAAA,CAAA,EAGnB,kBAHmB;EAAA,aAET,CAAA,EAAA,OAAA;EAAc,cACxB,CAAA,EAAA,MAAA;AAAgB;AAKT,UAAA,cAAA,CACR;EAIQ,KAAA,EAJR,OAIQ,CAAA,IAAe,CAAA;EAAA,OAAA,EAAA,EAAA,IAAA;;AACwB,UADvC,eAAA,CACuC;EAAY,aAAG,CAAA,MAAA,EAAA,MAAA,GAAtC,WAAsC,EAAA,OAAA,CAAA,EAAf,YAAe,CAAA,EAAA,cAAA;EAAc,OAAA,EAAA,EAAA,IAAA;;;;;iBCwNrE,qBAAA,SAA8B,wBAAwB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CapitalOSError, CapitalOSError as CapitalOSError$1, ErrorCode, Logger, Logger as Logger$1, ThemeColorScheme, ThemeColorScheme as ThemeColorScheme$1 } from "@capitalos/core";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
interface CapitalOsClientConfig {
|
|
5
|
+
getToken: () => Promise<string>;
|
|
6
|
+
theme?: ThemeColorScheme$1;
|
|
7
|
+
enableLogging?: boolean;
|
|
8
|
+
logger?: Logger$1;
|
|
9
|
+
}
|
|
10
|
+
interface MountOptions {
|
|
11
|
+
onLoaded?: () => void;
|
|
12
|
+
onError?: (error: CapitalOSError$1) => void;
|
|
13
|
+
theme?: ThemeColorScheme$1;
|
|
14
|
+
enableLogging?: boolean;
|
|
15
|
+
heightOffsetPx?: number;
|
|
16
|
+
}
|
|
17
|
+
interface CapitalOsMount {
|
|
18
|
+
ready: Promise<void>;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
}
|
|
21
|
+
interface CapitalOsClient {
|
|
22
|
+
mountCardsApp(target: string | HTMLElement, options?: MountOptions): CapitalOsMount;
|
|
23
|
+
destroy(): void;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/capital-os-client.d.ts
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
28
|
+
declare function createCapitalOsClient(config: CapitalOsClientConfig): CapitalOsClient;
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
//# sourceMappingURL=capital-os-client.d.ts.map
|
|
32
|
+
|
|
33
|
+
export { CapitalOSError, CapitalOsClient, CapitalOsClientConfig, CapitalOsMount, ErrorCode, Logger, MountOptions, ThemeColorScheme, createCapitalOsClient };
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/capital-os-client.ts"],"sourcesContent":null,"mappings":";;;UAEiB,qBAAA;kBACC;EADD,KAAA,CAAA,EAEP,kBAF4B;EAAA,aAAA,CAAA,EAAA,OAAA;EAAA,MACpB,CAAA,EAGP,QAHO;;AAGP,UAGM,YAAA,CAHN;EAAM,QAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAGA,OAAA,CAAA,EAAA,CAAA,KAAY,EAET,gBAFS,EAAA,GAAA,IAAA;EAAA,KAAA,CAAA,EAGnB,kBAHmB;EAAA,aAET,CAAA,EAAA,OAAA;EAAc,cACxB,CAAA,EAAA,MAAA;AAAgB;AAKT,UAAA,cAAA,CACR;EAIQ,KAAA,EAJR,OAIQ,CAAA,IAAe,CAAA;EAAA,OAAA,EAAA,EAAA,IAAA;;AACwB,UADvC,eAAA,CACuC;EAAY,aAAG,CAAA,MAAA,EAAA,MAAA,GAAtC,WAAsC,EAAA,OAAA,CAAA,EAAf,YAAe,CAAA,EAAA,cAAA;EAAc,OAAA,EAAA,EAAA,IAAA;;;;;iBCwNrE,qBAAA,SAA8B,wBAAwB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//#region rolldown:runtime
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
const __capitalos_core = __toESM(require("@capitalos/core"));
|
|
26
|
+
|
|
27
|
+
//#region package.json
|
|
28
|
+
var version = "0.1.0";
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/capital-os-client.ts
|
|
32
|
+
function isHTMLElement(value) {
|
|
33
|
+
return typeof HTMLElement !== "undefined" && value instanceof HTMLElement;
|
|
34
|
+
}
|
|
35
|
+
function resolveTarget(target) {
|
|
36
|
+
if (typeof target === "string") {
|
|
37
|
+
if (typeof document === "undefined") throw new Error("Cannot resolve selector because document is unavailable");
|
|
38
|
+
const element = document.querySelector(target);
|
|
39
|
+
if (!isHTMLElement(element)) throw new Error(`No HTMLElement found for selector "${target}"`);
|
|
40
|
+
return element;
|
|
41
|
+
}
|
|
42
|
+
if (!isHTMLElement(target)) throw new Error("target must be a CSS selector string or HTMLElement");
|
|
43
|
+
return target;
|
|
44
|
+
}
|
|
45
|
+
function createReadyDeferred() {
|
|
46
|
+
let resolveReady = () => {};
|
|
47
|
+
let rejectReady = () => {};
|
|
48
|
+
const promise = new Promise((resolve, reject) => {
|
|
49
|
+
resolveReady = resolve;
|
|
50
|
+
rejectReady = reject;
|
|
51
|
+
});
|
|
52
|
+
promise.catch(() => {});
|
|
53
|
+
return {
|
|
54
|
+
promise,
|
|
55
|
+
reject: rejectReady,
|
|
56
|
+
resolve: resolveReady
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
var CardsAppMount = class {
|
|
60
|
+
ready;
|
|
61
|
+
iframeManager = null;
|
|
62
|
+
isDestroyed = false;
|
|
63
|
+
isReadySettled = false;
|
|
64
|
+
readyDeferred = createReadyDeferred();
|
|
65
|
+
unsubscribeTokenData;
|
|
66
|
+
unsubscribeError;
|
|
67
|
+
constructor(params) {
|
|
68
|
+
this.params = params;
|
|
69
|
+
this.ready = this.readyDeferred.promise;
|
|
70
|
+
this.unsubscribeTokenData = params.controller.onTokenData((tokenData) => {
|
|
71
|
+
if (tokenData) this.initializeIframe(tokenData);
|
|
72
|
+
});
|
|
73
|
+
this.unsubscribeError = params.controller.onError((error) => {
|
|
74
|
+
this.handleError(error);
|
|
75
|
+
});
|
|
76
|
+
const existingTokenData = params.controller.getTokenData();
|
|
77
|
+
if (existingTokenData) this.initializeIframe(existingTokenData);
|
|
78
|
+
params.controller.start().catch(() => {});
|
|
79
|
+
}
|
|
80
|
+
destroy() {
|
|
81
|
+
if (this.isDestroyed) return;
|
|
82
|
+
this.isDestroyed = true;
|
|
83
|
+
this.unsubscribeTokenData();
|
|
84
|
+
this.unsubscribeError();
|
|
85
|
+
this.iframeManager?.destroy();
|
|
86
|
+
this.iframeManager = null;
|
|
87
|
+
this.params.onDestroy(this);
|
|
88
|
+
if (!this.isReadySettled) {
|
|
89
|
+
this.isReadySettled = true;
|
|
90
|
+
this.readyDeferred.reject(new __capitalos_core.CapitalOSError({
|
|
91
|
+
code: __capitalos_core.ErrorCode.internal_error,
|
|
92
|
+
message: "Mount was destroyed before it finished loading"
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
initializeIframe(tokenData) {
|
|
97
|
+
if (this.isDestroyed) return;
|
|
98
|
+
this.iframeManager?.destroy();
|
|
99
|
+
this.iframeManager = new __capitalos_core.IframeManager({
|
|
100
|
+
container: this.params.container,
|
|
101
|
+
tokenData,
|
|
102
|
+
renderingContext: this.getRenderingContext(),
|
|
103
|
+
theme: this.params.options?.theme ?? this.params.sessionConfig.theme,
|
|
104
|
+
enableLogging: this.params.options?.enableLogging ?? this.params.sessionConfig.enableLogging ?? false,
|
|
105
|
+
logger: this.params.sessionConfig.logger,
|
|
106
|
+
sdkVersion: version,
|
|
107
|
+
heightOffsetPx: this.params.options?.heightOffsetPx ?? 12,
|
|
108
|
+
callbacks: {
|
|
109
|
+
onLoad: () => {
|
|
110
|
+
this.resolveReady();
|
|
111
|
+
this.params.options?.onLoaded?.();
|
|
112
|
+
},
|
|
113
|
+
onError: (rawError) => {
|
|
114
|
+
this.handleError(new __capitalos_core.CapitalOSError(rawError));
|
|
115
|
+
},
|
|
116
|
+
onTokenExpired: () => {
|
|
117
|
+
this.params.controller.invalidate().catch(() => {});
|
|
118
|
+
},
|
|
119
|
+
onConnectionError: (error) => {
|
|
120
|
+
this.handleError(error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
getRenderingContext() {
|
|
126
|
+
return { entryPoint: "cardsApp" };
|
|
127
|
+
}
|
|
128
|
+
resolveReady() {
|
|
129
|
+
if (this.isReadySettled) return;
|
|
130
|
+
this.isReadySettled = true;
|
|
131
|
+
this.readyDeferred.resolve();
|
|
132
|
+
}
|
|
133
|
+
handleError(error) {
|
|
134
|
+
if (this.isDestroyed) return;
|
|
135
|
+
const capitalOsError = (0, __capitalos_core.toCapitalOSError)(error);
|
|
136
|
+
if (!this.isReadySettled) {
|
|
137
|
+
this.isReadySettled = true;
|
|
138
|
+
this.readyDeferred.reject(capitalOsError);
|
|
139
|
+
}
|
|
140
|
+
this.params.options?.onError?.(capitalOsError);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
var CapitalOsClientImpl = class {
|
|
144
|
+
controller;
|
|
145
|
+
mounts = new Set();
|
|
146
|
+
isDestroyed = false;
|
|
147
|
+
constructor(config) {
|
|
148
|
+
this.config = config;
|
|
149
|
+
this.controller = (0, __capitalos_core.createEmbedController)({
|
|
150
|
+
getToken: config.getToken,
|
|
151
|
+
enableLogging: config.enableLogging,
|
|
152
|
+
logger: config.logger,
|
|
153
|
+
sdkVersion: version
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
mountCardsApp(target, options) {
|
|
157
|
+
if (this.isDestroyed) throw new Error("CapitalOS client has been destroyed");
|
|
158
|
+
const mount = new CardsAppMount({
|
|
159
|
+
container: resolveTarget(target),
|
|
160
|
+
controller: this.controller,
|
|
161
|
+
onDestroy: (destroyedMount) => {
|
|
162
|
+
this.mounts.delete(destroyedMount);
|
|
163
|
+
},
|
|
164
|
+
options,
|
|
165
|
+
sessionConfig: this.config
|
|
166
|
+
});
|
|
167
|
+
this.mounts.add(mount);
|
|
168
|
+
return mount;
|
|
169
|
+
}
|
|
170
|
+
destroy() {
|
|
171
|
+
if (this.isDestroyed) return;
|
|
172
|
+
this.isDestroyed = true;
|
|
173
|
+
for (const mount of Array.from(this.mounts)) mount.destroy();
|
|
174
|
+
this.mounts.clear();
|
|
175
|
+
this.controller.destroy();
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
function createCapitalOsClient(config) {
|
|
179
|
+
return new CapitalOsClientImpl(config);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
//#endregion
|
|
183
|
+
Object.defineProperty(exports, 'CapitalOSError', {
|
|
184
|
+
enumerable: true,
|
|
185
|
+
get: function () {
|
|
186
|
+
return __capitalos_core.CapitalOSError;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
Object.defineProperty(exports, 'ErrorCode', {
|
|
190
|
+
enumerable: true,
|
|
191
|
+
get: function () {
|
|
192
|
+
return __capitalos_core.ErrorCode;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
exports.createCapitalOsClient = createCapitalOsClient
|
|
196
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["value: unknown","target: string | HTMLElement","resolveReady: () => void","rejectReady: (error: CapitalOSError) => void","params: CardsAppMountParams","CapitalOSError","ErrorCode","tokenData: TokenData","IframeManager","SDK_VERSION","rawError: RawErrorDetails","error: Error","error: unknown","config: CapitalOsClientConfig","options?: MountOptions"],"sources":["../package.json","../src/capital-os-client.ts"],"sourcesContent":["{\n \"name\": \"@capitalos/js\",\n \"version\": \"0.1.0\",\n \"description\": \"Framework-agnostic JavaScript SDK for CapitalOS\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": {\n \"types\": \"./dist/index.d.mts\",\n \"default\": \"./dist/index.mjs\"\n },\n \"require\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n }\n }\n },\n \"files\": [\n \"dist\",\n \"package.json\",\n \"README.md\"\n ],\n \"scripts\": {\n \"build\": \"tsdown\",\n \"dev\": \"tsdown --watch\",\n \"lint\": \"eslint src test --ext .ts --fix\",\n \"lint-ci\": \"eslint src test --ext .ts\",\n \"test\": \"vitest run\",\n \"test:pack\": \"pnpm build && pnpm pack\",\n \"prepublishOnly\": \"pnpm build\"\n },\n \"keywords\": [\n \"capitalos\",\n \"javascript\",\n \"sdk\",\n \"iframe\"\n ],\n \"homepage\": \"https://docs.capitalos.com/docs/using-vanilla-js-client-library\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/CapitalOS/theboss\",\n \"directory\": \"sdk/js\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/CapitalOS/theboss/issues\"\n },\n \"author\": \"CapitalOS\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@capitalos/core\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@types/iframe-resizer\": \"^3.5.13\",\n \"@typescript-eslint/eslint-plugin\": \"^7.2.0\",\n \"@typescript-eslint/parser\": \"^7.2.0\",\n \"eslint\": \"^8.57.0\",\n \"eslint-config-prettier\": \"^9.1.0\",\n \"eslint-plugin-prettier\": \"^5.1.3\",\n \"prettier\": \"^3.2.5\",\n \"tsdown\": \"^0.9.2\",\n \"typescript\": \"^5.6.2\",\n \"vitest\": \"^4.1.0\"\n }\n}\n","import {\n CapitalOSError,\n ErrorCode,\n IframeManager,\n createEmbedController,\n toCapitalOSError,\n type EmbedController,\n type IframeManagerConfig,\n type RawErrorDetails,\n type RenderingContext,\n type TokenData,\n} from '@capitalos/core'\n\nimport { version as SDK_VERSION } from '../package.json'\nimport type { CapitalOsClient, CapitalOsClientConfig, CapitalOsMount, MountOptions } from './types'\n\nfunction isHTMLElement(value: unknown): value is HTMLElement {\n return typeof HTMLElement !== 'undefined' && value instanceof HTMLElement\n}\n\nfunction resolveTarget(target: string | HTMLElement): HTMLElement {\n if (typeof target === 'string') {\n if (typeof document === 'undefined') {\n throw new Error('Cannot resolve selector because document is unavailable')\n }\n\n const element = document.querySelector(target)\n if (!isHTMLElement(element)) {\n throw new Error(`No HTMLElement found for selector \"${target}\"`)\n }\n\n return element\n }\n\n if (!isHTMLElement(target)) {\n throw new Error('target must be a CSS selector string or HTMLElement')\n }\n\n return target\n}\n\ntype ReadyDeferred = {\n promise: Promise<void>\n reject: (error: CapitalOSError) => void\n resolve: () => void\n}\n\nfunction createReadyDeferred(): ReadyDeferred {\n let resolveReady: () => void = () => {}\n let rejectReady: (error: CapitalOSError) => void = () => {}\n\n const promise = new Promise<void>((resolve, reject) => {\n resolveReady = resolve\n rejectReady = reject\n })\n\n // `ready` is optional for callers; attach a no-op catch so a rejection never\n // surfaces as an unhandledrejection when nobody awaits it.\n promise.catch(() => {})\n\n return {\n promise,\n reject: rejectReady,\n resolve: resolveReady,\n }\n}\n\ntype CardsAppMountParams = {\n container: HTMLElement\n controller: EmbedController\n onDestroy: (mount: CardsAppMount) => void\n options: MountOptions | undefined\n sessionConfig: CapitalOsClientConfig\n}\n\nclass CardsAppMount implements CapitalOsMount {\n readonly ready: Promise<void>\n\n private iframeManager: IframeManager | null = null\n private isDestroyed = false\n private isReadySettled = false\n private readonly readyDeferred = createReadyDeferred()\n private readonly unsubscribeTokenData: () => void\n private readonly unsubscribeError: () => void\n\n constructor(private readonly params: CardsAppMountParams) {\n this.ready = this.readyDeferred.promise\n\n this.unsubscribeTokenData = params.controller.onTokenData((tokenData) => {\n if (tokenData) {\n this.initializeIframe(tokenData)\n }\n })\n this.unsubscribeError = params.controller.onError((error) => {\n this.handleError(error)\n })\n\n const existingTokenData = params.controller.getTokenData()\n if (existingTokenData) {\n this.initializeIframe(existingTokenData)\n }\n\n // Lazy-start auth on first mount. Failures are intentionally routed through\n // the `onError` subscription above (and `ready`), not this promise.\n void params.controller.start().catch(() => {})\n }\n\n destroy(): void {\n if (this.isDestroyed) {\n return\n }\n\n this.isDestroyed = true\n this.unsubscribeTokenData()\n this.unsubscribeError()\n this.iframeManager?.destroy()\n this.iframeManager = null\n this.params.onDestroy(this)\n\n if (!this.isReadySettled) {\n this.isReadySettled = true\n this.readyDeferred.reject(\n new CapitalOSError({\n code: ErrorCode.internal_error,\n message: 'Mount was destroyed before it finished loading',\n })\n )\n }\n }\n\n private initializeIframe(tokenData: TokenData): void {\n if (this.isDestroyed) {\n return\n }\n\n this.iframeManager?.destroy()\n this.iframeManager = new IframeManager({\n container: this.params.container,\n tokenData,\n renderingContext: this.getRenderingContext(),\n theme: this.params.options?.theme ?? this.params.sessionConfig.theme,\n enableLogging: this.params.options?.enableLogging ?? this.params.sessionConfig.enableLogging ?? false,\n logger: this.params.sessionConfig.logger,\n sdkVersion: SDK_VERSION,\n heightOffsetPx: this.params.options?.heightOffsetPx ?? 12,\n callbacks: {\n onLoad: () => {\n this.resolveReady()\n this.params.options?.onLoaded?.()\n },\n onError: (rawError: RawErrorDetails) => {\n this.handleError(new CapitalOSError(rawError))\n },\n onTokenExpired: () => {\n void this.params.controller.invalidate().catch(() => {})\n },\n onConnectionError: (error: Error) => {\n this.handleError(error)\n },\n } satisfies IframeManagerConfig['callbacks'],\n })\n }\n\n private getRenderingContext(): RenderingContext {\n return { entryPoint: 'cardsApp' }\n }\n\n private resolveReady(): void {\n if (this.isReadySettled) {\n return\n }\n\n this.isReadySettled = true\n this.readyDeferred.resolve()\n }\n\n private handleError(error: unknown): void {\n if (this.isDestroyed) {\n return\n }\n\n const capitalOsError = toCapitalOSError(error)\n\n if (!this.isReadySettled) {\n this.isReadySettled = true\n this.readyDeferred.reject(capitalOsError)\n }\n\n this.params.options?.onError?.(capitalOsError)\n }\n}\n\nclass CapitalOsClientImpl implements CapitalOsClient {\n private readonly controller: EmbedController\n private readonly mounts = new Set<CardsAppMount>()\n private isDestroyed = false\n\n constructor(private readonly config: CapitalOsClientConfig) {\n this.controller = createEmbedController({\n getToken: config.getToken,\n enableLogging: config.enableLogging,\n logger: config.logger,\n sdkVersion: SDK_VERSION,\n })\n }\n\n mountCardsApp(target: string | HTMLElement, options?: MountOptions): CapitalOsMount {\n if (this.isDestroyed) {\n throw new Error('CapitalOS client has been destroyed')\n }\n\n const mount = new CardsAppMount({\n container: resolveTarget(target),\n controller: this.controller,\n onDestroy: (destroyedMount) => {\n this.mounts.delete(destroyedMount)\n },\n options,\n sessionConfig: this.config,\n })\n\n this.mounts.add(mount)\n return mount\n }\n\n destroy(): void {\n if (this.isDestroyed) {\n return\n }\n\n this.isDestroyed = true\n for (const mount of Array.from(this.mounts)) {\n mount.destroy()\n }\n this.mounts.clear()\n this.controller.destroy()\n }\n}\n\nexport function createCapitalOsClient(config: CapitalOsClientConfig): CapitalOsClient {\n return new CapitalOsClientImpl(config)\n}\n"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { CapitalOSError, CapitalOSError as CapitalOSError$1, ErrorCode, ErrorCode as ErrorCode$1, IframeManager, createEmbedController, toCapitalOSError } from "@capitalos/core";
|
|
2
|
+
|
|
3
|
+
//#region package.json
|
|
4
|
+
var version = "0.1.0";
|
|
5
|
+
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/capital-os-client.ts
|
|
8
|
+
function isHTMLElement(value) {
|
|
9
|
+
return typeof HTMLElement !== "undefined" && value instanceof HTMLElement;
|
|
10
|
+
}
|
|
11
|
+
function resolveTarget(target) {
|
|
12
|
+
if (typeof target === "string") {
|
|
13
|
+
if (typeof document === "undefined") throw new Error("Cannot resolve selector because document is unavailable");
|
|
14
|
+
const element = document.querySelector(target);
|
|
15
|
+
if (!isHTMLElement(element)) throw new Error(`No HTMLElement found for selector "${target}"`);
|
|
16
|
+
return element;
|
|
17
|
+
}
|
|
18
|
+
if (!isHTMLElement(target)) throw new Error("target must be a CSS selector string or HTMLElement");
|
|
19
|
+
return target;
|
|
20
|
+
}
|
|
21
|
+
function createReadyDeferred() {
|
|
22
|
+
let resolveReady = () => {};
|
|
23
|
+
let rejectReady = () => {};
|
|
24
|
+
const promise = new Promise((resolve, reject) => {
|
|
25
|
+
resolveReady = resolve;
|
|
26
|
+
rejectReady = reject;
|
|
27
|
+
});
|
|
28
|
+
promise.catch(() => {});
|
|
29
|
+
return {
|
|
30
|
+
promise,
|
|
31
|
+
reject: rejectReady,
|
|
32
|
+
resolve: resolveReady
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
var CardsAppMount = class {
|
|
36
|
+
ready;
|
|
37
|
+
iframeManager = null;
|
|
38
|
+
isDestroyed = false;
|
|
39
|
+
isReadySettled = false;
|
|
40
|
+
readyDeferred = createReadyDeferred();
|
|
41
|
+
unsubscribeTokenData;
|
|
42
|
+
unsubscribeError;
|
|
43
|
+
constructor(params) {
|
|
44
|
+
this.params = params;
|
|
45
|
+
this.ready = this.readyDeferred.promise;
|
|
46
|
+
this.unsubscribeTokenData = params.controller.onTokenData((tokenData) => {
|
|
47
|
+
if (tokenData) this.initializeIframe(tokenData);
|
|
48
|
+
});
|
|
49
|
+
this.unsubscribeError = params.controller.onError((error) => {
|
|
50
|
+
this.handleError(error);
|
|
51
|
+
});
|
|
52
|
+
const existingTokenData = params.controller.getTokenData();
|
|
53
|
+
if (existingTokenData) this.initializeIframe(existingTokenData);
|
|
54
|
+
params.controller.start().catch(() => {});
|
|
55
|
+
}
|
|
56
|
+
destroy() {
|
|
57
|
+
if (this.isDestroyed) return;
|
|
58
|
+
this.isDestroyed = true;
|
|
59
|
+
this.unsubscribeTokenData();
|
|
60
|
+
this.unsubscribeError();
|
|
61
|
+
this.iframeManager?.destroy();
|
|
62
|
+
this.iframeManager = null;
|
|
63
|
+
this.params.onDestroy(this);
|
|
64
|
+
if (!this.isReadySettled) {
|
|
65
|
+
this.isReadySettled = true;
|
|
66
|
+
this.readyDeferred.reject(new CapitalOSError$1({
|
|
67
|
+
code: ErrorCode$1.internal_error,
|
|
68
|
+
message: "Mount was destroyed before it finished loading"
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
initializeIframe(tokenData) {
|
|
73
|
+
if (this.isDestroyed) return;
|
|
74
|
+
this.iframeManager?.destroy();
|
|
75
|
+
this.iframeManager = new IframeManager({
|
|
76
|
+
container: this.params.container,
|
|
77
|
+
tokenData,
|
|
78
|
+
renderingContext: this.getRenderingContext(),
|
|
79
|
+
theme: this.params.options?.theme ?? this.params.sessionConfig.theme,
|
|
80
|
+
enableLogging: this.params.options?.enableLogging ?? this.params.sessionConfig.enableLogging ?? false,
|
|
81
|
+
logger: this.params.sessionConfig.logger,
|
|
82
|
+
sdkVersion: version,
|
|
83
|
+
heightOffsetPx: this.params.options?.heightOffsetPx ?? 12,
|
|
84
|
+
callbacks: {
|
|
85
|
+
onLoad: () => {
|
|
86
|
+
this.resolveReady();
|
|
87
|
+
this.params.options?.onLoaded?.();
|
|
88
|
+
},
|
|
89
|
+
onError: (rawError) => {
|
|
90
|
+
this.handleError(new CapitalOSError$1(rawError));
|
|
91
|
+
},
|
|
92
|
+
onTokenExpired: () => {
|
|
93
|
+
this.params.controller.invalidate().catch(() => {});
|
|
94
|
+
},
|
|
95
|
+
onConnectionError: (error) => {
|
|
96
|
+
this.handleError(error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
getRenderingContext() {
|
|
102
|
+
return { entryPoint: "cardsApp" };
|
|
103
|
+
}
|
|
104
|
+
resolveReady() {
|
|
105
|
+
if (this.isReadySettled) return;
|
|
106
|
+
this.isReadySettled = true;
|
|
107
|
+
this.readyDeferred.resolve();
|
|
108
|
+
}
|
|
109
|
+
handleError(error) {
|
|
110
|
+
if (this.isDestroyed) return;
|
|
111
|
+
const capitalOsError = toCapitalOSError(error);
|
|
112
|
+
if (!this.isReadySettled) {
|
|
113
|
+
this.isReadySettled = true;
|
|
114
|
+
this.readyDeferred.reject(capitalOsError);
|
|
115
|
+
}
|
|
116
|
+
this.params.options?.onError?.(capitalOsError);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var CapitalOsClientImpl = class {
|
|
120
|
+
controller;
|
|
121
|
+
mounts = new Set();
|
|
122
|
+
isDestroyed = false;
|
|
123
|
+
constructor(config) {
|
|
124
|
+
this.config = config;
|
|
125
|
+
this.controller = createEmbedController({
|
|
126
|
+
getToken: config.getToken,
|
|
127
|
+
enableLogging: config.enableLogging,
|
|
128
|
+
logger: config.logger,
|
|
129
|
+
sdkVersion: version
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
mountCardsApp(target, options) {
|
|
133
|
+
if (this.isDestroyed) throw new Error("CapitalOS client has been destroyed");
|
|
134
|
+
const mount = new CardsAppMount({
|
|
135
|
+
container: resolveTarget(target),
|
|
136
|
+
controller: this.controller,
|
|
137
|
+
onDestroy: (destroyedMount) => {
|
|
138
|
+
this.mounts.delete(destroyedMount);
|
|
139
|
+
},
|
|
140
|
+
options,
|
|
141
|
+
sessionConfig: this.config
|
|
142
|
+
});
|
|
143
|
+
this.mounts.add(mount);
|
|
144
|
+
return mount;
|
|
145
|
+
}
|
|
146
|
+
destroy() {
|
|
147
|
+
if (this.isDestroyed) return;
|
|
148
|
+
this.isDestroyed = true;
|
|
149
|
+
for (const mount of Array.from(this.mounts)) mount.destroy();
|
|
150
|
+
this.mounts.clear();
|
|
151
|
+
this.controller.destroy();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
function createCapitalOsClient(config) {
|
|
155
|
+
return new CapitalOsClientImpl(config);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
//#endregion
|
|
159
|
+
export { CapitalOSError, ErrorCode, createCapitalOsClient };
|
|
160
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["value: unknown","target: string | HTMLElement","resolveReady: () => void","rejectReady: (error: CapitalOSError) => void","params: CardsAppMountParams","CapitalOSError","ErrorCode","tokenData: TokenData","SDK_VERSION","rawError: RawErrorDetails","error: Error","error: unknown","config: CapitalOsClientConfig","options?: MountOptions"],"sources":["../package.json","../src/capital-os-client.ts"],"sourcesContent":["{\n \"name\": \"@capitalos/js\",\n \"version\": \"0.1.0\",\n \"description\": \"Framework-agnostic JavaScript SDK for CapitalOS\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": {\n \"types\": \"./dist/index.d.mts\",\n \"default\": \"./dist/index.mjs\"\n },\n \"require\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n }\n }\n },\n \"files\": [\n \"dist\",\n \"package.json\",\n \"README.md\"\n ],\n \"scripts\": {\n \"build\": \"tsdown\",\n \"dev\": \"tsdown --watch\",\n \"lint\": \"eslint src test --ext .ts --fix\",\n \"lint-ci\": \"eslint src test --ext .ts\",\n \"test\": \"vitest run\",\n \"test:pack\": \"pnpm build && pnpm pack\",\n \"prepublishOnly\": \"pnpm build\"\n },\n \"keywords\": [\n \"capitalos\",\n \"javascript\",\n \"sdk\",\n \"iframe\"\n ],\n \"homepage\": \"https://docs.capitalos.com/docs/using-vanilla-js-client-library\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/CapitalOS/theboss\",\n \"directory\": \"sdk/js\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/CapitalOS/theboss/issues\"\n },\n \"author\": \"CapitalOS\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@capitalos/core\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@types/iframe-resizer\": \"^3.5.13\",\n \"@typescript-eslint/eslint-plugin\": \"^7.2.0\",\n \"@typescript-eslint/parser\": \"^7.2.0\",\n \"eslint\": \"^8.57.0\",\n \"eslint-config-prettier\": \"^9.1.0\",\n \"eslint-plugin-prettier\": \"^5.1.3\",\n \"prettier\": \"^3.2.5\",\n \"tsdown\": \"^0.9.2\",\n \"typescript\": \"^5.6.2\",\n \"vitest\": \"^4.1.0\"\n }\n}\n","import {\n CapitalOSError,\n ErrorCode,\n IframeManager,\n createEmbedController,\n toCapitalOSError,\n type EmbedController,\n type IframeManagerConfig,\n type RawErrorDetails,\n type RenderingContext,\n type TokenData,\n} from '@capitalos/core'\n\nimport { version as SDK_VERSION } from '../package.json'\nimport type { CapitalOsClient, CapitalOsClientConfig, CapitalOsMount, MountOptions } from './types'\n\nfunction isHTMLElement(value: unknown): value is HTMLElement {\n return typeof HTMLElement !== 'undefined' && value instanceof HTMLElement\n}\n\nfunction resolveTarget(target: string | HTMLElement): HTMLElement {\n if (typeof target === 'string') {\n if (typeof document === 'undefined') {\n throw new Error('Cannot resolve selector because document is unavailable')\n }\n\n const element = document.querySelector(target)\n if (!isHTMLElement(element)) {\n throw new Error(`No HTMLElement found for selector \"${target}\"`)\n }\n\n return element\n }\n\n if (!isHTMLElement(target)) {\n throw new Error('target must be a CSS selector string or HTMLElement')\n }\n\n return target\n}\n\ntype ReadyDeferred = {\n promise: Promise<void>\n reject: (error: CapitalOSError) => void\n resolve: () => void\n}\n\nfunction createReadyDeferred(): ReadyDeferred {\n let resolveReady: () => void = () => {}\n let rejectReady: (error: CapitalOSError) => void = () => {}\n\n const promise = new Promise<void>((resolve, reject) => {\n resolveReady = resolve\n rejectReady = reject\n })\n\n // `ready` is optional for callers; attach a no-op catch so a rejection never\n // surfaces as an unhandledrejection when nobody awaits it.\n promise.catch(() => {})\n\n return {\n promise,\n reject: rejectReady,\n resolve: resolveReady,\n }\n}\n\ntype CardsAppMountParams = {\n container: HTMLElement\n controller: EmbedController\n onDestroy: (mount: CardsAppMount) => void\n options: MountOptions | undefined\n sessionConfig: CapitalOsClientConfig\n}\n\nclass CardsAppMount implements CapitalOsMount {\n readonly ready: Promise<void>\n\n private iframeManager: IframeManager | null = null\n private isDestroyed = false\n private isReadySettled = false\n private readonly readyDeferred = createReadyDeferred()\n private readonly unsubscribeTokenData: () => void\n private readonly unsubscribeError: () => void\n\n constructor(private readonly params: CardsAppMountParams) {\n this.ready = this.readyDeferred.promise\n\n this.unsubscribeTokenData = params.controller.onTokenData((tokenData) => {\n if (tokenData) {\n this.initializeIframe(tokenData)\n }\n })\n this.unsubscribeError = params.controller.onError((error) => {\n this.handleError(error)\n })\n\n const existingTokenData = params.controller.getTokenData()\n if (existingTokenData) {\n this.initializeIframe(existingTokenData)\n }\n\n // Lazy-start auth on first mount. Failures are intentionally routed through\n // the `onError` subscription above (and `ready`), not this promise.\n void params.controller.start().catch(() => {})\n }\n\n destroy(): void {\n if (this.isDestroyed) {\n return\n }\n\n this.isDestroyed = true\n this.unsubscribeTokenData()\n this.unsubscribeError()\n this.iframeManager?.destroy()\n this.iframeManager = null\n this.params.onDestroy(this)\n\n if (!this.isReadySettled) {\n this.isReadySettled = true\n this.readyDeferred.reject(\n new CapitalOSError({\n code: ErrorCode.internal_error,\n message: 'Mount was destroyed before it finished loading',\n })\n )\n }\n }\n\n private initializeIframe(tokenData: TokenData): void {\n if (this.isDestroyed) {\n return\n }\n\n this.iframeManager?.destroy()\n this.iframeManager = new IframeManager({\n container: this.params.container,\n tokenData,\n renderingContext: this.getRenderingContext(),\n theme: this.params.options?.theme ?? this.params.sessionConfig.theme,\n enableLogging: this.params.options?.enableLogging ?? this.params.sessionConfig.enableLogging ?? false,\n logger: this.params.sessionConfig.logger,\n sdkVersion: SDK_VERSION,\n heightOffsetPx: this.params.options?.heightOffsetPx ?? 12,\n callbacks: {\n onLoad: () => {\n this.resolveReady()\n this.params.options?.onLoaded?.()\n },\n onError: (rawError: RawErrorDetails) => {\n this.handleError(new CapitalOSError(rawError))\n },\n onTokenExpired: () => {\n void this.params.controller.invalidate().catch(() => {})\n },\n onConnectionError: (error: Error) => {\n this.handleError(error)\n },\n } satisfies IframeManagerConfig['callbacks'],\n })\n }\n\n private getRenderingContext(): RenderingContext {\n return { entryPoint: 'cardsApp' }\n }\n\n private resolveReady(): void {\n if (this.isReadySettled) {\n return\n }\n\n this.isReadySettled = true\n this.readyDeferred.resolve()\n }\n\n private handleError(error: unknown): void {\n if (this.isDestroyed) {\n return\n }\n\n const capitalOsError = toCapitalOSError(error)\n\n if (!this.isReadySettled) {\n this.isReadySettled = true\n this.readyDeferred.reject(capitalOsError)\n }\n\n this.params.options?.onError?.(capitalOsError)\n }\n}\n\nclass CapitalOsClientImpl implements CapitalOsClient {\n private readonly controller: EmbedController\n private readonly mounts = new Set<CardsAppMount>()\n private isDestroyed = false\n\n constructor(private readonly config: CapitalOsClientConfig) {\n this.controller = createEmbedController({\n getToken: config.getToken,\n enableLogging: config.enableLogging,\n logger: config.logger,\n sdkVersion: SDK_VERSION,\n })\n }\n\n mountCardsApp(target: string | HTMLElement, options?: MountOptions): CapitalOsMount {\n if (this.isDestroyed) {\n throw new Error('CapitalOS client has been destroyed')\n }\n\n const mount = new CardsAppMount({\n container: resolveTarget(target),\n controller: this.controller,\n onDestroy: (destroyedMount) => {\n this.mounts.delete(destroyedMount)\n },\n options,\n sessionConfig: this.config,\n })\n\n this.mounts.add(mount)\n return mount\n }\n\n destroy(): void {\n if (this.isDestroyed) {\n return\n }\n\n this.isDestroyed = true\n for (const mount of Array.from(this.mounts)) {\n mount.destroy()\n }\n this.mounts.clear()\n this.controller.destroy()\n }\n}\n\nexport function createCapitalOsClient(config: CapitalOsClientConfig): CapitalOsClient {\n return new CapitalOsClientImpl(config)\n}\n"],"mappings":";;;cAEa;;;;ACcb,SAAS,cAAcA,OAAsC;AAC3D,eAAc,gBAAgB,eAAe,iBAAiB;AAC/D;AAED,SAAS,cAAcC,QAA2C;AAChE,YAAW,WAAW,UAAU;AAC9B,aAAW,aAAa,YACtB,OAAM,IAAI,MAAM;EAGlB,MAAM,UAAU,SAAS,cAAc,OAAO;AAC9C,OAAK,cAAc,QAAQ,CACzB,OAAM,IAAI,OAAO,qCAAqC,OAAO;AAG/D,SAAO;CACR;AAED,MAAK,cAAc,OAAO,CACxB,OAAM,IAAI,MAAM;AAGlB,QAAO;AACR;AAQD,SAAS,sBAAqC;CAC5C,IAAIC,eAA2B,MAAM,CAAE;CACvC,IAAIC,cAA+C,MAAM,CAAE;CAE3D,MAAM,UAAU,IAAI,QAAc,CAAC,SAAS,WAAW;AACrD,iBAAe;AACf,gBAAc;CACf;AAID,SAAQ,MAAM,MAAM,CAAE,EAAC;AAEvB,QAAO;EACL;EACA,QAAQ;EACR,SAAS;CACV;AACF;AAUD,IAAM,gBAAN,MAA8C;CAC5C,AAAS;CAET,AAAQ,gBAAsC;CAC9C,AAAQ,cAAc;CACtB,AAAQ,iBAAiB;CACzB,AAAiB,gBAAgB,qBAAqB;CACtD,AAAiB;CACjB,AAAiB;CAEjB,YAA6BC,QAA6B;EA6J3D,KA7J8B;AAC3B,OAAK,QAAQ,KAAK,cAAc;AAEhC,OAAK,uBAAuB,OAAO,WAAW,YAAY,CAAC,cAAc;AACvE,OAAI,UACF,MAAK,iBAAiB,UAAU;EAEnC,EAAC;AACF,OAAK,mBAAmB,OAAO,WAAW,QAAQ,CAAC,UAAU;AAC3D,QAAK,YAAY,MAAM;EACxB,EAAC;EAEF,MAAM,oBAAoB,OAAO,WAAW,cAAc;AAC1D,MAAI,kBACF,MAAK,iBAAiB,kBAAkB;AAK1C,EAAK,OAAO,WAAW,OAAO,CAAC,MAAM,MAAM,CAAE,EAAC;CAC/C;CAED,UAAgB;AACd,MAAI,KAAK,YACP;AAGF,OAAK,cAAc;AACnB,OAAK,sBAAsB;AAC3B,OAAK,kBAAkB;AACvB,OAAK,eAAe,SAAS;AAC7B,OAAK,gBAAgB;AACrB,OAAK,OAAO,UAAU,KAAK;AAE3B,OAAK,KAAK,gBAAgB;AACxB,QAAK,iBAAiB;AACtB,QAAK,cAAc,OACjB,IAAIC,iBAAe;IACjB,MAAMC,YAAU;IAChB,SAAS;GACV,GACF;EACF;CACF;CAED,AAAQ,iBAAiBC,WAA4B;AACnD,MAAI,KAAK,YACP;AAGF,OAAK,eAAe,SAAS;AAC7B,OAAK,gBAAgB,IAAI,cAAc;GACrC,WAAW,KAAK,OAAO;GACvB;GACA,kBAAkB,KAAK,qBAAqB;GAC5C,OAAO,KAAK,OAAO,SAAS,SAAS,KAAK,OAAO,cAAc;GAC/D,eAAe,KAAK,OAAO,SAAS,iBAAiB,KAAK,OAAO,cAAc,iBAAiB;GAChG,QAAQ,KAAK,OAAO,cAAc;GAClC,YAAYC;GACZ,gBAAgB,KAAK,OAAO,SAAS,kBAAkB;GACvD,WAAW;IACT,QAAQ,MAAM;AACZ,UAAK,cAAc;AACnB,UAAK,OAAO,SAAS,YAAY;IAClC;IACD,SAAS,CAACC,aAA8B;AACtC,UAAK,YAAY,IAAIJ,iBAAe,UAAU;IAC/C;IACD,gBAAgB,MAAM;AACpB,KAAK,KAAK,OAAO,WAAW,YAAY,CAAC,MAAM,MAAM,CAAE,EAAC;IACzD;IACD,mBAAmB,CAACK,UAAiB;AACnC,UAAK,YAAY,MAAM;IACxB;GACF;EACF;CACF;CAED,AAAQ,sBAAwC;AAC9C,SAAO,EAAE,YAAY,WAAY;CAClC;CAED,AAAQ,eAAqB;AAC3B,MAAI,KAAK,eACP;AAGF,OAAK,iBAAiB;AACtB,OAAK,cAAc,SAAS;CAC7B;CAED,AAAQ,YAAYC,OAAsB;AACxC,MAAI,KAAK,YACP;EAGF,MAAM,iBAAiB,iBAAiB,MAAM;AAE9C,OAAK,KAAK,gBAAgB;AACxB,QAAK,iBAAiB;AACtB,QAAK,cAAc,OAAO,eAAe;EAC1C;AAED,OAAK,OAAO,SAAS,UAAU,eAAe;CAC/C;AACF;AAED,IAAM,sBAAN,MAAqD;CACnD,AAAiB;CACjB,AAAiB,SAAS,IAAI;CAC9B,AAAQ,cAAc;CAEtB,YAA6BC,QAA+B;EA6C5D,KA7C6B;AAC3B,OAAK,aAAa,sBAAsB;GACtC,UAAU,OAAO;GACjB,eAAe,OAAO;GACtB,QAAQ,OAAO;GACf,YAAYJ;EACb,EAAC;CACH;CAED,cAAcP,QAA8BY,SAAwC;AAClF,MAAI,KAAK,YACP,OAAM,IAAI,MAAM;EAGlB,MAAM,QAAQ,IAAI,cAAc;GAC9B,WAAW,cAAc,OAAO;GAChC,YAAY,KAAK;GACjB,WAAW,CAAC,mBAAmB;AAC7B,SAAK,OAAO,OAAO,eAAe;GACnC;GACD;GACA,eAAe,KAAK;EACrB;AAED,OAAK,OAAO,IAAI,MAAM;AACtB,SAAO;CACR;CAED,UAAgB;AACd,MAAI,KAAK,YACP;AAGF,OAAK,cAAc;AACnB,OAAK,MAAM,SAAS,MAAM,KAAK,KAAK,OAAO,CACzC,OAAM,SAAS;AAEjB,OAAK,OAAO,OAAO;AACnB,OAAK,WAAW,SAAS;CAC1B;AACF;AAED,SAAgB,sBAAsBD,QAAgD;AACpF,QAAO,IAAI,oBAAoB;AAChC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@capitalos/js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Framework-agnostic JavaScript SDK for CapitalOS",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"package.json",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"capitalos",
|
|
27
|
+
"javascript",
|
|
28
|
+
"sdk",
|
|
29
|
+
"iframe"
|
|
30
|
+
],
|
|
31
|
+
"homepage": "https://docs.capitalos.com/docs/using-vanilla-js-client-library",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/CapitalOS/theboss",
|
|
35
|
+
"directory": "sdk/js"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/CapitalOS/theboss/issues"
|
|
39
|
+
},
|
|
40
|
+
"author": "CapitalOS",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@capitalos/core": "0.5.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/iframe-resizer": "^3.5.13",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
|
48
|
+
"@typescript-eslint/parser": "^7.2.0",
|
|
49
|
+
"eslint": "^8.57.0",
|
|
50
|
+
"eslint-config-prettier": "^9.1.0",
|
|
51
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
52
|
+
"prettier": "^3.2.5",
|
|
53
|
+
"tsdown": "^0.9.2",
|
|
54
|
+
"typescript": "^5.6.2",
|
|
55
|
+
"vitest": "^4.1.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsdown",
|
|
59
|
+
"dev": "tsdown --watch",
|
|
60
|
+
"lint": "eslint src test --ext .ts --fix",
|
|
61
|
+
"lint-ci": "eslint src test --ext .ts",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"test:pack": "pnpm build && pnpm pack"
|
|
64
|
+
}
|
|
65
|
+
}
|