assistant-cloud 0.1.33 → 0.1.35
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/dist/AssistantCloud.d.ts +0 -1
- package/dist/AssistantCloud.d.ts.map +1 -1
- package/dist/AssistantCloudAPI.d.ts +5 -2
- package/dist/AssistantCloudAPI.d.ts.map +1 -1
- package/dist/AssistantCloudAPI.js +13 -7
- package/dist/AssistantCloudAPI.js.map +1 -1
- package/dist/AssistantCloudAuthStrategy.d.ts.map +1 -1
- package/dist/AssistantCloudAuthStrategy.js +36 -5
- package/dist/AssistantCloudAuthStrategy.js.map +1 -1
- package/dist/AssistantCloudAuthTokens.d.ts +0 -1
- package/dist/AssistantCloudAuthTokens.d.ts.map +1 -1
- package/dist/AssistantCloudFiles.d.ts +0 -1
- package/dist/AssistantCloudFiles.d.ts.map +1 -1
- package/dist/AssistantCloudRuns.d.ts +0 -1
- package/dist/AssistantCloudRuns.d.ts.map +1 -1
- package/dist/AssistantCloudThreadMessages.d.ts +0 -1
- package/dist/AssistantCloudThreadMessages.d.ts.map +1 -1
- package/dist/AssistantCloudThreads.d.ts +0 -1
- package/dist/AssistantCloudThreads.d.ts.map +1 -1
- package/dist/CloudMessagePersistence.d.ts +0 -1
- package/dist/CloudMessagePersistence.d.ts.map +1 -1
- package/dist/FormattedCloudPersistence.d.ts +0 -1
- package/dist/FormattedCloudPersistence.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/instrumentMcpSampling.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/AssistantCloudAPI.ts +20 -7
- package/src/AssistantCloudAuthStrategy.ts +47 -18
- package/src/index.ts +1 -0
- package/src/tests/AssistantCloudAPI.test.ts +76 -7
- package/src/tests/AssistantCloudAuthStrategy.test.ts +163 -0
package/dist/AssistantCloud.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { AssistantCloudConfig, AssistantCloudTelemetryConfig } from "./Assistant
|
|
|
3
3
|
import { AssistantCloudAuthTokens } from "./AssistantCloudAuthTokens.js";
|
|
4
4
|
import { AssistantCloudThreads } from "./AssistantCloudThreads.js";
|
|
5
5
|
import { AssistantCloudFiles } from "./AssistantCloudFiles.js";
|
|
6
|
-
|
|
7
6
|
//#region src/AssistantCloud.d.ts
|
|
8
7
|
declare class AssistantCloud {
|
|
9
8
|
readonly threads: AssistantCloudThreads;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloud.d.ts","names":[],"sources":["../src/AssistantCloud.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssistantCloud.d.ts","names":[],"sources":["../src/AssistantCloud.ts"],"mappings":";;;;;;cAUa;WACK,SAAO;WACP;;;WACA,MAAI;WACJ,OAAK;WACL,WAAW;cAEf,QAAQ"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AssistantCloudAuthStrategy } from "./AssistantCloudAuthStrategy.js";
|
|
2
2
|
import { AssistantCloudRunReport } from "./AssistantCloudRuns.js";
|
|
3
|
-
|
|
4
3
|
//#region src/AssistantCloudAPI.d.ts
|
|
5
4
|
type AssistantCloudTelemetryConfig = {
|
|
6
5
|
enabled?: boolean;
|
|
@@ -36,6 +35,10 @@ type AssistantCloudConfig = ({
|
|
|
36
35
|
*/
|
|
37
36
|
telemetry?: boolean | AssistantCloudTelemetryConfig;
|
|
38
37
|
};
|
|
38
|
+
declare class CloudAPIError extends Error {
|
|
39
|
+
readonly status: number;
|
|
40
|
+
constructor(message: string, status: number);
|
|
41
|
+
}
|
|
39
42
|
type MakeRequestOptions = {
|
|
40
43
|
method?: "POST" | "PUT" | "DELETE" | undefined;
|
|
41
44
|
headers?: Record<string, string> | undefined;
|
|
@@ -51,5 +54,5 @@ declare class AssistantCloudAPI {
|
|
|
51
54
|
makeRequest(endpoint: string, options?: MakeRequestOptions): Promise<any>;
|
|
52
55
|
}
|
|
53
56
|
//#endregion
|
|
54
|
-
export { AssistantCloudAPI, AssistantCloudConfig, AssistantCloudTelemetryConfig };
|
|
57
|
+
export { AssistantCloudAPI, AssistantCloudConfig, AssistantCloudTelemetryConfig, CloudAPIError };
|
|
55
58
|
//# sourceMappingURL=AssistantCloudAPI.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudAPI.d.ts","names":[],"sources":["../src/AssistantCloudAPI.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssistantCloudAPI.d.ts","names":[],"sources":["../src/AssistantCloudAPI.ts"],"mappings":";;;KAQY;EACV;;;;;;EAMA,gBACE,QAAQ,4BACL;;KAGK;EAEN;EACA,iBAAiB;;EAGjB;EACA;EACA;EACA;;EAGA;EACA;;;;;;;;;;;;;EAcJ,sBAAsB;;cAGX,sBAAsB;WAGf;cADhB,iBACgB;;KAOf;EACH;EACA,UAAU;EACV,QAAQ;EACR;;cAGW;EACJ,OAAO;EACP;cAEK,QAAQ;EAuBP,kBAAc;EAId,eACX,kBACA,UAAS,qBAAuB,QAAA;EAmDrB,YAAY,kBAAkB,UAAS,qBAAuB"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { AssistantCloudAPIKeyAuthStrategy, AssistantCloudAnonymousAuthStrategy, AssistantCloudJWTAuthStrategy } from "./AssistantCloudAuthStrategy.js";
|
|
2
2
|
//#region src/AssistantCloudAPI.ts
|
|
3
3
|
var CloudAPIError = class extends Error {
|
|
4
|
-
|
|
4
|
+
status;
|
|
5
|
+
constructor(message, status) {
|
|
5
6
|
super(message);
|
|
6
|
-
this.
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.name = "CloudAPIError";
|
|
7
9
|
}
|
|
8
10
|
};
|
|
9
11
|
var AssistantCloudAPI = class {
|
|
@@ -22,7 +24,7 @@ var AssistantCloudAPI = class {
|
|
|
22
24
|
} else throw new Error("Invalid configuration: Must provide authToken, apiKey, or anonymous configuration");
|
|
23
25
|
}
|
|
24
26
|
async initializeAuth() {
|
|
25
|
-
return !!this._auth.getAuthHeaders();
|
|
27
|
+
return !!await this._auth.getAuthHeaders();
|
|
26
28
|
}
|
|
27
29
|
async makeRawRequest(endpoint, options = {}) {
|
|
28
30
|
const authHeaders = await this._auth.getAuthHeaders();
|
|
@@ -49,19 +51,23 @@ var AssistantCloudAPI = class {
|
|
|
49
51
|
if (!response.ok) {
|
|
50
52
|
const text = await response.text();
|
|
51
53
|
try {
|
|
52
|
-
throw new CloudAPIError(JSON.parse(text).message);
|
|
54
|
+
throw new CloudAPIError(JSON.parse(text).message, response.status);
|
|
53
55
|
} catch (error) {
|
|
54
56
|
if (error instanceof CloudAPIError) throw error;
|
|
55
|
-
throw new
|
|
57
|
+
throw new CloudAPIError(`Request failed with status ${response.status}, ${text}`, response.status);
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
return response;
|
|
59
61
|
}
|
|
60
62
|
async makeRequest(endpoint, options = {}) {
|
|
61
|
-
|
|
63
|
+
const response = await this.makeRawRequest(endpoint, options);
|
|
64
|
+
if (response.status === 204 || response.headers.get("content-length") === "0") return void 0;
|
|
65
|
+
const text = await response.text();
|
|
66
|
+
if (text.trim() === "") return void 0;
|
|
67
|
+
return JSON.parse(text);
|
|
62
68
|
}
|
|
63
69
|
};
|
|
64
70
|
//#endregion
|
|
65
|
-
export { AssistantCloudAPI };
|
|
71
|
+
export { AssistantCloudAPI, CloudAPIError };
|
|
66
72
|
|
|
67
73
|
//# sourceMappingURL=AssistantCloudAPI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudAPI.js","names":[],"sources":["../src/AssistantCloudAPI.ts"],"sourcesContent":["import {\n type AssistantCloudAuthStrategy,\n AssistantCloudJWTAuthStrategy,\n AssistantCloudAPIKeyAuthStrategy,\n AssistantCloudAnonymousAuthStrategy,\n} from \"./AssistantCloudAuthStrategy\";\nimport type { AssistantCloudRunReport } from \"./AssistantCloudRuns\";\n\nexport type AssistantCloudTelemetryConfig = {\n enabled?: boolean;\n /**\n * Called before each telemetry report is sent.\n * Return a modified report to enrich it (e.g. add `model_id`),\n * or return `null` to skip the report.\n */\n beforeReport?: (\n report: AssistantCloudRunReport,\n ) => AssistantCloudRunReport | null;\n};\n\nexport type AssistantCloudConfig = (\n | {\n baseUrl: string;\n authToken: () => Promise<string | null>;\n }\n | {\n baseUrl?: string;\n apiKey: string;\n userId: string;\n workspaceId: string;\n }\n | {\n baseUrl: string;\n anonymous: true;\n }\n) & {\n /**\n * Client-side run telemetry reporting. Default: `true`.\n *\n * When enabled, the SDK automatically reports run metadata (status, step\n * count, tool calls, and token usage) to Assistant Cloud after each\n * assistant message is saved. No message content is sent.\n *\n * - `true` / `undefined` — enabled with defaults\n * - `false` — disabled\n * - `{ beforeReport }` — enabled with a hook to enrich or filter reports\n */\n telemetry?: boolean | AssistantCloudTelemetryConfig;\n};\n\
|
|
1
|
+
{"version":3,"file":"AssistantCloudAPI.js","names":[],"sources":["../src/AssistantCloudAPI.ts"],"sourcesContent":["import {\n type AssistantCloudAuthStrategy,\n AssistantCloudJWTAuthStrategy,\n AssistantCloudAPIKeyAuthStrategy,\n AssistantCloudAnonymousAuthStrategy,\n} from \"./AssistantCloudAuthStrategy\";\nimport type { AssistantCloudRunReport } from \"./AssistantCloudRuns\";\n\nexport type AssistantCloudTelemetryConfig = {\n enabled?: boolean;\n /**\n * Called before each telemetry report is sent.\n * Return a modified report to enrich it (e.g. add `model_id`),\n * or return `null` to skip the report.\n */\n beforeReport?: (\n report: AssistantCloudRunReport,\n ) => AssistantCloudRunReport | null;\n};\n\nexport type AssistantCloudConfig = (\n | {\n baseUrl: string;\n authToken: () => Promise<string | null>;\n }\n | {\n baseUrl?: string;\n apiKey: string;\n userId: string;\n workspaceId: string;\n }\n | {\n baseUrl: string;\n anonymous: true;\n }\n) & {\n /**\n * Client-side run telemetry reporting. Default: `true`.\n *\n * When enabled, the SDK automatically reports run metadata (status, step\n * count, tool calls, and token usage) to Assistant Cloud after each\n * assistant message is saved. No message content is sent.\n *\n * - `true` / `undefined` — enabled with defaults\n * - `false` — disabled\n * - `{ beforeReport }` — enabled with a hook to enrich or filter reports\n */\n telemetry?: boolean | AssistantCloudTelemetryConfig;\n};\n\nexport class CloudAPIError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = \"CloudAPIError\";\n }\n}\n\ntype MakeRequestOptions = {\n method?: \"POST\" | \"PUT\" | \"DELETE\" | undefined;\n headers?: Record<string, string> | undefined;\n query?: Record<string, string | number | boolean> | undefined;\n body?: object | undefined;\n};\n\nexport class AssistantCloudAPI {\n public _auth: AssistantCloudAuthStrategy;\n public _baseUrl;\n\n constructor(config: AssistantCloudConfig) {\n if (\"authToken\" in config) {\n this._baseUrl = config.baseUrl;\n this._auth = new AssistantCloudJWTAuthStrategy(config.authToken);\n } else if (\"apiKey\" in config) {\n this._baseUrl = (\n config.baseUrl ?? \"https://backend.assistant-api.com\"\n ).replace(/\\/$/, \"\");\n this._auth = new AssistantCloudAPIKeyAuthStrategy(\n config.apiKey,\n config.userId,\n config.workspaceId,\n );\n } else if (\"anonymous\" in config) {\n this._baseUrl = config.baseUrl;\n this._auth = new AssistantCloudAnonymousAuthStrategy(config.baseUrl);\n } else {\n throw new Error(\n \"Invalid configuration: Must provide authToken, apiKey, or anonymous configuration\",\n );\n }\n }\n\n public async initializeAuth() {\n return !!(await this._auth.getAuthHeaders());\n }\n\n public async makeRawRequest(\n endpoint: string,\n options: MakeRequestOptions = {},\n ) {\n const authHeaders = await this._auth.getAuthHeaders();\n if (!authHeaders) throw new Error(\"Authorization failed\");\n\n const headers = {\n ...authHeaders,\n ...options.headers,\n \"Content-Type\": \"application/json\",\n };\n\n const queryParams = new URLSearchParams();\n if (options.query) {\n for (const [key, value] of Object.entries(options.query)) {\n if (value === false) continue;\n if (value === true) {\n queryParams.set(key, \"true\");\n } else {\n queryParams.set(key, value.toString());\n }\n }\n }\n\n const url = new URL(`${this._baseUrl}/v1${endpoint}`);\n url.search = queryParams.toString();\n\n const response = await fetch(url, {\n method: options.method ?? \"GET\",\n headers,\n body: options.body ? JSON.stringify(options.body) : null,\n });\n\n this._auth.readAuthHeaders(response.headers);\n\n if (!response.ok) {\n const text = await response.text();\n try {\n const body = JSON.parse(text);\n throw new CloudAPIError(body.message, response.status);\n } catch (error) {\n if (error instanceof CloudAPIError) throw error;\n throw new CloudAPIError(\n `Request failed with status ${response.status}, ${text}`,\n response.status,\n );\n }\n }\n\n return response;\n }\n\n public async makeRequest(endpoint: string, options: MakeRequestOptions = {}) {\n const response = await this.makeRawRequest(endpoint, options);\n if (\n response.status === 204 ||\n response.headers.get(\"content-length\") === \"0\"\n )\n return undefined;\n\n const text = await response.text();\n if (text.trim() === \"\") return undefined;\n\n return JSON.parse(text);\n }\n}\n"],"mappings":";;AAkDA,IAAa,gBAAb,cAAmC,MAAM;CAGrB;CAFlB,YACE,SACA,QACA;EACA,MAAM,OAAO;EAFG,KAAA,SAAA;EAGhB,KAAK,OAAO;CACd;AACF;AASA,IAAa,oBAAb,MAA+B;CAC7B;CACA;CAEA,YAAY,QAA8B;EACxC,IAAI,eAAe,QAAQ;GACzB,KAAK,WAAW,OAAO;GACvB,KAAK,QAAQ,IAAI,8BAA8B,OAAO,SAAS;EACjE,OAAO,IAAI,YAAY,QAAQ;GAC7B,KAAK,YACH,OAAO,WAAW,oCAAA,CAClB,QAAQ,OAAO,EAAE;GACnB,KAAK,QAAQ,IAAI,iCACf,OAAO,QACP,OAAO,QACP,OAAO,WACT;EACF,OAAO,IAAI,eAAe,QAAQ;GAChC,KAAK,WAAW,OAAO;GACvB,KAAK,QAAQ,IAAI,oCAAoC,OAAO,OAAO;EACrE,OACE,MAAM,IAAI,MACR,mFACF;CAEJ;CAEA,MAAa,iBAAiB;EAC5B,OAAO,CAAC,CAAE,MAAM,KAAK,MAAM,eAAe;CAC5C;CAEA,MAAa,eACX,UACA,UAA8B,CAAC,GAC/B;EACA,MAAM,cAAc,MAAM,KAAK,MAAM,eAAe;EACpD,IAAI,CAAC,aAAa,MAAM,IAAI,MAAM,sBAAsB;EAExD,MAAM,UAAU;GACd,GAAG;GACH,GAAG,QAAQ;GACX,gBAAgB;EAClB;EAEA,MAAM,cAAc,IAAI,gBAAgB;EACxC,IAAI,QAAQ,OACV,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,KAAK,GAAG;GACxD,IAAI,UAAU,OAAO;GACrB,IAAI,UAAU,MACZ,YAAY,IAAI,KAAK,MAAM;QAE3B,YAAY,IAAI,KAAK,MAAM,SAAS,CAAC;EAEzC;EAGF,MAAM,MAAM,IAAI,IAAI,GAAG,KAAK,SAAS,KAAK,UAAU;EACpD,IAAI,SAAS,YAAY,SAAS;EAElC,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ,QAAQ,UAAU;GAC1B;GACA,MAAM,QAAQ,OAAO,KAAK,UAAU,QAAQ,IAAI,IAAI;EACtD,CAAC;EAED,KAAK,MAAM,gBAAgB,SAAS,OAAO;EAE3C,IAAI,CAAC,SAAS,IAAI;GAChB,MAAM,OAAO,MAAM,SAAS,KAAK;GACjC,IAAI;IAEF,MAAM,IAAI,cADG,KAAK,MAAM,IACA,CAAA,CAAK,SAAS,SAAS,MAAM;GACvD,SAAS,OAAO;IACd,IAAI,iBAAiB,eAAe,MAAM;IAC1C,MAAM,IAAI,cACR,8BAA8B,SAAS,OAAO,IAAI,QAClD,SAAS,MACX;GACF;EACF;EAEA,OAAO;CACT;CAEA,MAAa,YAAY,UAAkB,UAA8B,CAAC,GAAG;EAC3E,MAAM,WAAW,MAAM,KAAK,eAAe,UAAU,OAAO;EAC5D,IACE,SAAS,WAAW,OACpB,SAAS,QAAQ,IAAI,gBAAgB,MAAM,KAE3C,OAAO,KAAA;EAET,MAAM,OAAO,MAAM,SAAS,KAAK;EACjC,IAAI,KAAK,KAAK,MAAM,IAAI,OAAO,KAAA;EAE/B,OAAO,KAAK,MAAM,IAAI;CACxB;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudAuthStrategy.d.ts","names":[],"sources":["../src/AssistantCloudAuthStrategy.ts"],"mappings":";KAAY
|
|
1
|
+
{"version":3,"file":"AssistantCloudAuthStrategy.d.ts","names":[],"sources":["../src/AssistantCloudAuthStrategy.ts"],"mappings":";KAAY;WACD;EACT,kBAAkB,QAAQ;EAC1B,gBAAgB,SAAS;;cAiCd,yCAAyC;;WACpC;UAER;UACA;cAGI,yBAAyB;EAIxB,kBAAkB,QAAQ;EAsBhC,gBAAgB,SAAS;;cAcrB,4CAA4C;;WACvC;cAMJ,gBAAgB,gBAAgB;EAM/B,kBAAkB,QAAQ;EAQhC;;cAkDI,+CAA+C;WAC1C;UAER;UACA;cAEI;EAgDC,kBAAkB,QAAQ;EAIhC,gBAAgB,SAAS"}
|
|
@@ -59,6 +59,38 @@ var AssistantCloudAPIKeyAuthStrategy = class {
|
|
|
59
59
|
readAuthHeaders() {}
|
|
60
60
|
};
|
|
61
61
|
const AUI_REFRESH_TOKEN_NAME = "aui:refresh_token";
|
|
62
|
+
const getLocalStorage = () => {
|
|
63
|
+
if (!("localStorage" in globalThis)) return null;
|
|
64
|
+
try {
|
|
65
|
+
return globalThis.localStorage;
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const readRefreshToken = () => {
|
|
71
|
+
const storage = getLocalStorage();
|
|
72
|
+
if (!storage) return void 0;
|
|
73
|
+
try {
|
|
74
|
+
const value = storage.getItem(AUI_REFRESH_TOKEN_NAME);
|
|
75
|
+
return value ? JSON.parse(value) : void 0;
|
|
76
|
+
} catch {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const writeRefreshToken = (refreshToken) => {
|
|
81
|
+
const storage = getLocalStorage();
|
|
82
|
+
if (!storage) return;
|
|
83
|
+
try {
|
|
84
|
+
storage.setItem(AUI_REFRESH_TOKEN_NAME, JSON.stringify(refreshToken));
|
|
85
|
+
} catch {}
|
|
86
|
+
};
|
|
87
|
+
const removeRefreshToken = () => {
|
|
88
|
+
const storage = getLocalStorage();
|
|
89
|
+
if (!storage) return;
|
|
90
|
+
try {
|
|
91
|
+
storage.removeItem(AUI_REFRESH_TOKEN_NAME);
|
|
92
|
+
} catch {}
|
|
93
|
+
};
|
|
62
94
|
var AssistantCloudAnonymousAuthStrategy = class {
|
|
63
95
|
strategy = "anon";
|
|
64
96
|
baseUrl;
|
|
@@ -67,8 +99,7 @@ var AssistantCloudAnonymousAuthStrategy = class {
|
|
|
67
99
|
this.baseUrl = baseUrl;
|
|
68
100
|
this.jwtStrategy = new AssistantCloudJWTAuthStrategy(async () => {
|
|
69
101
|
const currentTime = Date.now();
|
|
70
|
-
const
|
|
71
|
-
const storedRefreshToken = storedRefreshTokenJson ? JSON.parse(storedRefreshTokenJson) : void 0;
|
|
102
|
+
const storedRefreshToken = readRefreshToken();
|
|
72
103
|
if (storedRefreshToken) if (new Date(storedRefreshToken.expires_at).getTime() - currentTime > 30 * 1e3) {
|
|
73
104
|
const response = await fetch(`${this.baseUrl}/v1/auth/tokens/refresh`, {
|
|
74
105
|
method: "POST",
|
|
@@ -77,15 +108,15 @@ var AssistantCloudAnonymousAuthStrategy = class {
|
|
|
77
108
|
});
|
|
78
109
|
if (response.ok) {
|
|
79
110
|
const { access_token, refresh_token } = await response.json();
|
|
80
|
-
if (refresh_token)
|
|
111
|
+
if (refresh_token) writeRefreshToken(refresh_token);
|
|
81
112
|
return access_token;
|
|
82
113
|
}
|
|
83
|
-
} else
|
|
114
|
+
} else removeRefreshToken();
|
|
84
115
|
const response = await fetch(`${this.baseUrl}/v1/auth/tokens/anonymous`, { method: "POST" });
|
|
85
116
|
if (!response.ok) return null;
|
|
86
117
|
const { access_token, refresh_token } = await response.json();
|
|
87
118
|
if (!access_token || !refresh_token) return null;
|
|
88
|
-
|
|
119
|
+
writeRefreshToken(refresh_token);
|
|
89
120
|
return access_token;
|
|
90
121
|
});
|
|
91
122
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudAuthStrategy.js","names":["#authTokenCallback","#apiKey","#userId","#workspaceId"],"sources":["../src/AssistantCloudAuthStrategy.ts"],"sourcesContent":["export type AssistantCloudAuthStrategy = {\n readonly strategy: \"anon\" | \"jwt\" | \"api-key\";\n getAuthHeaders(): Promise<Record<string, string> | false>;\n readAuthHeaders(headers: Headers): void;\n};\n\nconst getJwtExpiry = (jwt: string): number => {\n try {\n const parts = jwt.split(\".\");\n const bodyPart = parts[1];\n if (!bodyPart) {\n throw new Error(\"Invalid JWT format\");\n }\n\n // Convert from Base64Url to Base64 and add padding if necessary\n let base64 = bodyPart.replace(/-/g, \"+\").replace(/_/g, \"/\");\n while (base64.length % 4 !== 0) {\n base64 += \"=\";\n }\n\n // Decode the Base64 string and parse the payload\n const payload = atob(base64);\n const payloadObj = JSON.parse(payload);\n const exp = payloadObj.exp;\n\n if (!exp || typeof exp !== \"number\") {\n throw new Error('JWT does not contain a valid \"exp\" field');\n }\n\n // Convert expiration time to milliseconds\n return exp * 1000;\n } catch (error) {\n throw new Error(`Unable to determine the token expiry: ${error}`);\n }\n};\n\nexport class AssistantCloudJWTAuthStrategy implements AssistantCloudAuthStrategy {\n public readonly strategy = \"jwt\";\n\n private cachedToken: string | null = null;\n private tokenExpiry: number | null = null;\n #authTokenCallback: () => Promise<string | null>;\n\n constructor(authTokenCallback: () => Promise<string | null>) {\n this.#authTokenCallback = authTokenCallback;\n }\n\n public async getAuthHeaders(): Promise<Record<string, string> | false> {\n const currentTime = Date.now();\n\n // Use cached token if it's valid for at least 30 more seconds\n if (\n this.cachedToken &&\n this.tokenExpiry &&\n this.tokenExpiry - currentTime > 30 * 1000\n ) {\n return { Authorization: `Bearer ${this.cachedToken}` };\n }\n\n // Fetch a new token via the callback\n const newToken = await this.#authTokenCallback();\n if (!newToken) return false;\n\n this.cachedToken = newToken;\n this.tokenExpiry = getJwtExpiry(newToken);\n\n return { Authorization: `Bearer ${newToken}` };\n }\n\n public readAuthHeaders(headers: Headers) {\n const authHeader = headers.get(\"Authorization\");\n if (!authHeader) return;\n\n const [scheme, token] = authHeader.split(\" \");\n if (scheme !== \"Bearer\" || !token) {\n throw new Error(\"Invalid auth header received\");\n }\n\n this.cachedToken = token;\n this.tokenExpiry = getJwtExpiry(token);\n }\n}\n\nexport class AssistantCloudAPIKeyAuthStrategy implements AssistantCloudAuthStrategy {\n public readonly strategy = \"api-key\";\n\n #apiKey: string;\n #userId: string;\n #workspaceId: string;\n\n constructor(apiKey: string, userId: string, workspaceId: string) {\n this.#apiKey = apiKey;\n this.#userId = userId;\n this.#workspaceId = workspaceId;\n }\n\n public async getAuthHeaders(): Promise<Record<string, string>> {\n return {\n Authorization: `Bearer ${this.#apiKey}`,\n \"Aui-User-Id\": this.#userId,\n \"Aui-Workspace-Id\": this.#workspaceId,\n };\n }\n\n public readAuthHeaders() {\n // No operation needed for API key auth\n }\n}\n\nconst AUI_REFRESH_TOKEN_NAME = \"aui:refresh_token\";\n\nexport class AssistantCloudAnonymousAuthStrategy implements AssistantCloudAuthStrategy {\n public readonly strategy = \"anon\";\n\n private baseUrl: string;\n private jwtStrategy: AssistantCloudJWTAuthStrategy;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl;\n this.jwtStrategy = new AssistantCloudJWTAuthStrategy(async () => {\n const currentTime = Date.now();\n const
|
|
1
|
+
{"version":3,"file":"AssistantCloudAuthStrategy.js","names":["#authTokenCallback","#apiKey","#userId","#workspaceId"],"sources":["../src/AssistantCloudAuthStrategy.ts"],"sourcesContent":["export type AssistantCloudAuthStrategy = {\n readonly strategy: \"anon\" | \"jwt\" | \"api-key\";\n getAuthHeaders(): Promise<Record<string, string> | false>;\n readAuthHeaders(headers: Headers): void;\n};\n\nconst getJwtExpiry = (jwt: string): number => {\n try {\n const parts = jwt.split(\".\");\n const bodyPart = parts[1];\n if (!bodyPart) {\n throw new Error(\"Invalid JWT format\");\n }\n\n // Convert from Base64Url to Base64 and add padding if necessary\n let base64 = bodyPart.replace(/-/g, \"+\").replace(/_/g, \"/\");\n while (base64.length % 4 !== 0) {\n base64 += \"=\";\n }\n\n // Decode the Base64 string and parse the payload\n const payload = atob(base64);\n const payloadObj = JSON.parse(payload);\n const exp = payloadObj.exp;\n\n if (!exp || typeof exp !== \"number\") {\n throw new Error('JWT does not contain a valid \"exp\" field');\n }\n\n // Convert expiration time to milliseconds\n return exp * 1000;\n } catch (error) {\n throw new Error(`Unable to determine the token expiry: ${error}`);\n }\n};\n\nexport class AssistantCloudJWTAuthStrategy implements AssistantCloudAuthStrategy {\n public readonly strategy = \"jwt\";\n\n private cachedToken: string | null = null;\n private tokenExpiry: number | null = null;\n #authTokenCallback: () => Promise<string | null>;\n\n constructor(authTokenCallback: () => Promise<string | null>) {\n this.#authTokenCallback = authTokenCallback;\n }\n\n public async getAuthHeaders(): Promise<Record<string, string> | false> {\n const currentTime = Date.now();\n\n // Use cached token if it's valid for at least 30 more seconds\n if (\n this.cachedToken &&\n this.tokenExpiry &&\n this.tokenExpiry - currentTime > 30 * 1000\n ) {\n return { Authorization: `Bearer ${this.cachedToken}` };\n }\n\n // Fetch a new token via the callback\n const newToken = await this.#authTokenCallback();\n if (!newToken) return false;\n\n this.cachedToken = newToken;\n this.tokenExpiry = getJwtExpiry(newToken);\n\n return { Authorization: `Bearer ${newToken}` };\n }\n\n public readAuthHeaders(headers: Headers) {\n const authHeader = headers.get(\"Authorization\");\n if (!authHeader) return;\n\n const [scheme, token] = authHeader.split(\" \");\n if (scheme !== \"Bearer\" || !token) {\n throw new Error(\"Invalid auth header received\");\n }\n\n this.cachedToken = token;\n this.tokenExpiry = getJwtExpiry(token);\n }\n}\n\nexport class AssistantCloudAPIKeyAuthStrategy implements AssistantCloudAuthStrategy {\n public readonly strategy = \"api-key\";\n\n #apiKey: string;\n #userId: string;\n #workspaceId: string;\n\n constructor(apiKey: string, userId: string, workspaceId: string) {\n this.#apiKey = apiKey;\n this.#userId = userId;\n this.#workspaceId = workspaceId;\n }\n\n public async getAuthHeaders(): Promise<Record<string, string>> {\n return {\n Authorization: `Bearer ${this.#apiKey}`,\n \"Aui-User-Id\": this.#userId,\n \"Aui-Workspace-Id\": this.#workspaceId,\n };\n }\n\n public readAuthHeaders() {\n // No operation needed for API key auth\n }\n}\n\nconst AUI_REFRESH_TOKEN_NAME = \"aui:refresh_token\";\n\nconst getLocalStorage = (): Storage | null => {\n if (!(\"localStorage\" in globalThis)) return null;\n try {\n return (globalThis as { localStorage: Storage }).localStorage;\n } catch {\n return null;\n }\n};\n\nconst readRefreshToken = ():\n | { token: string; expires_at: string }\n | undefined => {\n const storage = getLocalStorage();\n if (!storage) return undefined;\n try {\n const value = storage.getItem(AUI_REFRESH_TOKEN_NAME);\n return value\n ? (JSON.parse(value) as { token: string; expires_at: string })\n : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst writeRefreshToken = (refreshToken: {\n token: string;\n expires_at: string;\n}): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.setItem(AUI_REFRESH_TOKEN_NAME, JSON.stringify(refreshToken));\n } catch {}\n};\n\nconst removeRefreshToken = (): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.removeItem(AUI_REFRESH_TOKEN_NAME);\n } catch {}\n};\n\nexport class AssistantCloudAnonymousAuthStrategy implements AssistantCloudAuthStrategy {\n public readonly strategy = \"anon\";\n\n private baseUrl: string;\n private jwtStrategy: AssistantCloudJWTAuthStrategy;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl;\n this.jwtStrategy = new AssistantCloudJWTAuthStrategy(async () => {\n const currentTime = Date.now();\n const storedRefreshToken = readRefreshToken();\n\n if (storedRefreshToken) {\n const refreshExpiry = new Date(storedRefreshToken.expires_at).getTime();\n if (refreshExpiry - currentTime > 30 * 1000) {\n const response = await fetch(\n `${this.baseUrl}/v1/auth/tokens/refresh`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: storedRefreshToken.token }),\n },\n );\n\n if (response.ok) {\n const data = await response.json();\n const { access_token, refresh_token } = data;\n if (refresh_token) {\n writeRefreshToken(refresh_token);\n }\n return access_token;\n }\n } else {\n removeRefreshToken();\n }\n }\n\n // No valid refresh token; request a new anonymous token\n const response = await fetch(`${this.baseUrl}/v1/auth/tokens/anonymous`, {\n method: \"POST\",\n });\n\n if (!response.ok) return null;\n\n const data = await response.json();\n const { access_token, refresh_token } = data;\n\n if (!access_token || !refresh_token) return null;\n\n writeRefreshToken(refresh_token);\n return access_token;\n });\n }\n\n public async getAuthHeaders(): Promise<Record<string, string> | false> {\n return this.jwtStrategy.getAuthHeaders();\n }\n\n public readAuthHeaders(headers: Headers): void {\n this.jwtStrategy.readAuthHeaders(headers);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudAuthTokens.d.ts","names":[],"sources":["../src/AssistantCloudAuthTokens.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssistantCloudAuthTokens.d.ts","names":[],"sources":["../src/AssistantCloudAuthTokens.ts"],"mappings":";;KAEK;EACH;;cAGW;UACS;cAAA,OAAO;EAEd,UAAU,QAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudFiles.d.ts","names":[],"sources":["../src/AssistantCloudFiles.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssistantCloudFiles.d.ts","names":[],"sources":["../src/AssistantCloudFiles.ts"],"mappings":";;KAEK;EACH;EACA;;KAGG;EACH;EACA;EACA;;KAGG;EACH;;KAGG;EACH;EACA;EACA;EACA;;cAGW;UACS;cAAA,OAAO;EAEd,YACX,MAAM,yBACL,QAAQ;EAOE,2BACX,MAAM,wCACL,QAAQ"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { SamplingCallData } from "./instrumentMcpSampling.js";
|
|
2
2
|
import { AssistantCloudAPI } from "./AssistantCloudAPI.js";
|
|
3
3
|
import { AssistantStream } from "assistant-stream";
|
|
4
|
-
|
|
5
4
|
//#region src/AssistantCloudRuns.d.ts
|
|
6
5
|
type AssistantCloudRunsStreamBody = {
|
|
7
6
|
thread_id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudRuns.d.ts","names":[],"sources":["../src/AssistantCloudRuns.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssistantCloudRuns.d.ts","names":[],"sources":["../src/AssistantCloudRuns.ts"],"mappings":";;;;KAIK;EACH;EACA;EACA;;KAGG;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA,iBAAiB;;KAMP;EACV;EACA;EACA;EACA,aAAa;EACb;IACE;IACA;IACA;IACA;IACA,aAAa;IACb;IACA;;EAEF;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;;cAGA;UACS;cAAA,OAAO;EAEpB,+BAA+B;;;;;;;;;;;EAmBzB,OACX,MAAM,+BACL,QAAQ;EAWE,OACX,MAAM,0BACL;IAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudThreadMessages.d.ts","names":[],"sources":["../src/AssistantCloudThreadMessages.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssistantCloudThreadMessages.d.ts","names":[],"sources":["../src/AssistantCloudThreadMessages.ts"],"mappings":";;;KAGY;EACV;EACA;EACA;EACA,YAAY;EACZ,YAAY;EACZ;EACA,SAAS;;KAGN;EACH;;KAGG;EACH,UAAU;;KAGP;EACH;EACA;EACA,SAAS;;KAGN;EACH;;KAGG;EACH,SAAS;;cAGE;UACS;cAAA,OAAO;EAEd,KACX,kBACA,QAAQ,uCACP,QAAQ;EAOE,OACX,kBACA,MAAM,wCACL,QAAQ;EAOE,OACX,kBACA,mBACA,MAAM,wCACL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantCloudThreads.d.ts","names":[],"sources":["../src/AssistantCloudThreads.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssistantCloudThreads.d.ts","names":[],"sources":["../src/AssistantCloudThreads.ts"],"mappings":";;;KAGK;EACH;EACA;EACA;;KAGG;EACH;EACA,iBAAiB;EACjB;EACA;EACA;EACA;EACA,YAAY;EACZ,YAAY;EACZ;EACA;;KAGG;EACH,SAAS;;KAGN;EACH;EACA,iBAAiB;EACjB;EACA;;KAGG;EACH;;KAGG;EACH;EACA,kBAAkB;EAClB;EACA;;cAGW;UAGS;WAFJ,UAAU;cAEN,OAAO;EAId,KACX,QAAQ,iCACP,QAAQ;EAIE,IAAI,mBAAmB,QAAQ;EAI/B,OACX,MAAM,kCACL,QAAQ;EAIE,OACX,kBACA,MAAM,kCACL;EAOU,OAAO,mBAAmB"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { CloudMessage } from "./AssistantCloudThreadMessages.js";
|
|
2
2
|
import { AssistantCloud } from "./AssistantCloud.js";
|
|
3
3
|
import { ReadonlyJSONObject } from "assistant-stream/utils";
|
|
4
|
-
|
|
5
4
|
//#region src/CloudMessagePersistence.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* Shared persistence logic for cloud message storage.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudMessagePersistence.d.ts","names":[],"sources":["../src/CloudMessagePersistence.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CloudMessagePersistence.d.ts","names":[],"sources":["../src/CloudMessagePersistence.ts"],"mappings":";;;;;;;;;;;;;;;cAca;UAGS;UAFZ;cAEY,OAAO;;;;;;;;;;EAWrB,OACJ,kBACA,mBACA,yBACA,gBACA,SAAS,qBACR;;;;EAgCG,OACJ,kBACA,mBACA,iBACA,SAAS,qBACR;;;;EASH,YAAY;;;;;EAQN,YAAY,oBAAoB;;;;;;;;;;;EAgBhC,KAAK,kBAAkB,kBAAe,QAhBN;;;;EA+BtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormattedCloudPersistence.d.ts","names":[],"sources":["../src/FormattedCloudPersistence.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"FormattedCloudPersistence.d.ts","names":[],"sources":["../src/FormattedCloudPersistence.ts"],"mappings":";;;;;;;KAOY,qBAAqB,UAAU;EACzC;EACA,OAAO;IAAQ;IAAyB,SAAS;MAAa;EAC9D,OAAO;IACL;IACA;IACA;IACA,SAAS;;IACL;IAAyB,SAAS;;EACxC,MAAM,SAAS;;;;;;;;;;;;cAaJ,6BAA8B,UAAU,gBACnD;EACE,SACE,kBACA,mBACA,yBACA,gBACA,SAAS,uBACN;EACL,OAAO,kBAAkB,oBAAoB;EAC7C,cAAc;EACd,UACE,kBACA,mBACA,gBACA,SAAS,uBACN;GAEP,SAAS,qBAAqB,UAAU;6BAGtB;IACR;IAAyB,SAAS;QACzC;8BAamB;IACR;IAAyB,SAAS;KAAU,sBAEnD;8BAUsB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { McpSamplingHandler, SamplingCallData, createSamplingCollector, wrapSamplingHandler } from "./instrumentMcpSampling.js";
|
|
2
2
|
import { AssistantCloudRunReport } from "./AssistantCloudRuns.js";
|
|
3
|
-
import { AssistantCloudTelemetryConfig } from "./AssistantCloudAPI.js";
|
|
3
|
+
import { AssistantCloudTelemetryConfig, CloudAPIError } from "./AssistantCloudAPI.js";
|
|
4
4
|
import { CloudMessage } from "./AssistantCloudThreadMessages.js";
|
|
5
5
|
import { AssistantCloud } from "./AssistantCloud.js";
|
|
6
6
|
import { CloudMessagePersistence } from "./CloudMessagePersistence.js";
|
|
7
7
|
import { MessageFormatAdapter, createFormattedPersistence } from "./FormattedCloudPersistence.js";
|
|
8
|
-
export { AssistantCloud, type AssistantCloudRunReport, type AssistantCloudTelemetryConfig, type CloudMessage, CloudMessagePersistence, type McpSamplingHandler, type MessageFormatAdapter, type SamplingCallData, createFormattedPersistence, createSamplingCollector, wrapSamplingHandler };
|
|
8
|
+
export { AssistantCloud, type AssistantCloudRunReport, type AssistantCloudTelemetryConfig, CloudAPIError, type CloudMessage, CloudMessagePersistence, type McpSamplingHandler, type MessageFormatAdapter, type SamplingCallData, createFormattedPersistence, createSamplingCollector, wrapSamplingHandler };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { CloudAPIError } from "./AssistantCloudAPI.js";
|
|
1
2
|
import { AssistantCloud } from "./AssistantCloud.js";
|
|
2
3
|
import { CloudMessagePersistence } from "./CloudMessagePersistence.js";
|
|
3
4
|
import { createFormattedPersistence } from "./FormattedCloudPersistence.js";
|
|
4
5
|
import { createSamplingCollector, wrapSamplingHandler } from "./instrumentMcpSampling.js";
|
|
5
|
-
export { AssistantCloud, CloudMessagePersistence, createFormattedPersistence, createSamplingCollector, wrapSamplingHandler };
|
|
6
|
+
export { AssistantCloud, CloudAPIError, CloudMessagePersistence, createFormattedPersistence, createSamplingCollector, wrapSamplingHandler };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentMcpSampling.d.ts","names":[],"sources":["../src/instrumentMcpSampling.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"instrumentMcpSampling.d.ts","names":[],"sources":["../src/instrumentMcpSampling.ts"],"mappings":";;;;;;;;KAQY;EACV;EACA;EACA;EACA;EACA;EACA;;KAGU,sBACV,SAAS,uBACN,QAAQ;KAED;EACV;EACA;IACE;IACA;MAAqB;QAAU;;;IAC/B;KACC;;;KAIO;EACV;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;;GAED;;;;;;;;;;;;;;;;;;;;iBAqBa,oBACd,SAAS,oBACT,iBAAiB,MAAM,4BACtB;;;;;;;;;;;;;iBA6Ca;kBAGI;kBAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assistant-cloud",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"description": "Cloud integration for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"assistant",
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
],
|
|
28
28
|
"sideEffects": false,
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"assistant-stream": "^0.3.
|
|
30
|
+
"assistant-stream": "^0.3.26"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@types/node": "^
|
|
34
|
-
"vitest": "^4.1.
|
|
35
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
33
|
+
"@types/node": "^26.1.1",
|
|
34
|
+
"vitest": "^4.1.10",
|
|
35
|
+
"@assistant-ui/x-buildutils": "0.0.18"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public",
|
package/src/AssistantCloudAPI.ts
CHANGED
|
@@ -48,10 +48,13 @@ export type AssistantCloudConfig = (
|
|
|
48
48
|
telemetry?: boolean | AssistantCloudTelemetryConfig;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
class CloudAPIError extends Error {
|
|
52
|
-
constructor(
|
|
51
|
+
export class CloudAPIError extends Error {
|
|
52
|
+
constructor(
|
|
53
|
+
message: string,
|
|
54
|
+
public readonly status: number,
|
|
55
|
+
) {
|
|
53
56
|
super(message);
|
|
54
|
-
this.name = "
|
|
57
|
+
this.name = "CloudAPIError";
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
|
|
@@ -90,7 +93,7 @@ export class AssistantCloudAPI {
|
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
public async initializeAuth() {
|
|
93
|
-
return !!this._auth.getAuthHeaders();
|
|
96
|
+
return !!(await this._auth.getAuthHeaders());
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
public async makeRawRequest(
|
|
@@ -133,11 +136,12 @@ export class AssistantCloudAPI {
|
|
|
133
136
|
const text = await response.text();
|
|
134
137
|
try {
|
|
135
138
|
const body = JSON.parse(text);
|
|
136
|
-
throw new CloudAPIError(body.message);
|
|
139
|
+
throw new CloudAPIError(body.message, response.status);
|
|
137
140
|
} catch (error) {
|
|
138
141
|
if (error instanceof CloudAPIError) throw error;
|
|
139
|
-
throw new
|
|
142
|
+
throw new CloudAPIError(
|
|
140
143
|
`Request failed with status ${response.status}, ${text}`,
|
|
144
|
+
response.status,
|
|
141
145
|
);
|
|
142
146
|
}
|
|
143
147
|
}
|
|
@@ -147,6 +151,15 @@ export class AssistantCloudAPI {
|
|
|
147
151
|
|
|
148
152
|
public async makeRequest(endpoint: string, options: MakeRequestOptions = {}) {
|
|
149
153
|
const response = await this.makeRawRequest(endpoint, options);
|
|
150
|
-
|
|
154
|
+
if (
|
|
155
|
+
response.status === 204 ||
|
|
156
|
+
response.headers.get("content-length") === "0"
|
|
157
|
+
)
|
|
158
|
+
return undefined;
|
|
159
|
+
|
|
160
|
+
const text = await response.text();
|
|
161
|
+
if (text.trim() === "") return undefined;
|
|
162
|
+
|
|
163
|
+
return JSON.parse(text);
|
|
151
164
|
}
|
|
152
165
|
}
|
|
@@ -109,6 +109,49 @@ export class AssistantCloudAPIKeyAuthStrategy implements AssistantCloudAuthStrat
|
|
|
109
109
|
|
|
110
110
|
const AUI_REFRESH_TOKEN_NAME = "aui:refresh_token";
|
|
111
111
|
|
|
112
|
+
const getLocalStorage = (): Storage | null => {
|
|
113
|
+
if (!("localStorage" in globalThis)) return null;
|
|
114
|
+
try {
|
|
115
|
+
return (globalThis as { localStorage: Storage }).localStorage;
|
|
116
|
+
} catch {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const readRefreshToken = ():
|
|
122
|
+
| { token: string; expires_at: string }
|
|
123
|
+
| undefined => {
|
|
124
|
+
const storage = getLocalStorage();
|
|
125
|
+
if (!storage) return undefined;
|
|
126
|
+
try {
|
|
127
|
+
const value = storage.getItem(AUI_REFRESH_TOKEN_NAME);
|
|
128
|
+
return value
|
|
129
|
+
? (JSON.parse(value) as { token: string; expires_at: string })
|
|
130
|
+
: undefined;
|
|
131
|
+
} catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const writeRefreshToken = (refreshToken: {
|
|
137
|
+
token: string;
|
|
138
|
+
expires_at: string;
|
|
139
|
+
}): void => {
|
|
140
|
+
const storage = getLocalStorage();
|
|
141
|
+
if (!storage) return;
|
|
142
|
+
try {
|
|
143
|
+
storage.setItem(AUI_REFRESH_TOKEN_NAME, JSON.stringify(refreshToken));
|
|
144
|
+
} catch {}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const removeRefreshToken = (): void => {
|
|
148
|
+
const storage = getLocalStorage();
|
|
149
|
+
if (!storage) return;
|
|
150
|
+
try {
|
|
151
|
+
storage.removeItem(AUI_REFRESH_TOKEN_NAME);
|
|
152
|
+
} catch {}
|
|
153
|
+
};
|
|
154
|
+
|
|
112
155
|
export class AssistantCloudAnonymousAuthStrategy implements AssistantCloudAuthStrategy {
|
|
113
156
|
public readonly strategy = "anon";
|
|
114
157
|
|
|
@@ -119,15 +162,7 @@ export class AssistantCloudAnonymousAuthStrategy implements AssistantCloudAuthSt
|
|
|
119
162
|
this.baseUrl = baseUrl;
|
|
120
163
|
this.jwtStrategy = new AssistantCloudJWTAuthStrategy(async () => {
|
|
121
164
|
const currentTime = Date.now();
|
|
122
|
-
const
|
|
123
|
-
AUI_REFRESH_TOKEN_NAME,
|
|
124
|
-
);
|
|
125
|
-
const storedRefreshToken = storedRefreshTokenJson
|
|
126
|
-
? (JSON.parse(storedRefreshTokenJson) as {
|
|
127
|
-
token: string;
|
|
128
|
-
expires_at: string;
|
|
129
|
-
})
|
|
130
|
-
: undefined;
|
|
165
|
+
const storedRefreshToken = readRefreshToken();
|
|
131
166
|
|
|
132
167
|
if (storedRefreshToken) {
|
|
133
168
|
const refreshExpiry = new Date(storedRefreshToken.expires_at).getTime();
|
|
@@ -145,15 +180,12 @@ export class AssistantCloudAnonymousAuthStrategy implements AssistantCloudAuthSt
|
|
|
145
180
|
const data = await response.json();
|
|
146
181
|
const { access_token, refresh_token } = data;
|
|
147
182
|
if (refresh_token) {
|
|
148
|
-
|
|
149
|
-
AUI_REFRESH_TOKEN_NAME,
|
|
150
|
-
JSON.stringify(refresh_token),
|
|
151
|
-
);
|
|
183
|
+
writeRefreshToken(refresh_token);
|
|
152
184
|
}
|
|
153
185
|
return access_token;
|
|
154
186
|
}
|
|
155
187
|
} else {
|
|
156
|
-
|
|
188
|
+
removeRefreshToken();
|
|
157
189
|
}
|
|
158
190
|
}
|
|
159
191
|
|
|
@@ -169,10 +201,7 @@ export class AssistantCloudAnonymousAuthStrategy implements AssistantCloudAuthSt
|
|
|
169
201
|
|
|
170
202
|
if (!access_token || !refresh_token) return null;
|
|
171
203
|
|
|
172
|
-
|
|
173
|
-
AUI_REFRESH_TOKEN_NAME,
|
|
174
|
-
JSON.stringify(refresh_token),
|
|
175
|
-
);
|
|
204
|
+
writeRefreshToken(refresh_token);
|
|
176
205
|
return access_token;
|
|
177
206
|
});
|
|
178
207
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type { CloudMessage } from "./AssistantCloudThreadMessages";
|
|
2
2
|
export type { AssistantCloudTelemetryConfig } from "./AssistantCloudAPI";
|
|
3
|
+
export { CloudAPIError } from "./AssistantCloudAPI";
|
|
3
4
|
export type { AssistantCloudRunReport } from "./AssistantCloudRuns";
|
|
4
5
|
export { AssistantCloud } from "./AssistantCloud";
|
|
5
6
|
export { CloudMessagePersistence } from "./CloudMessagePersistence";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { AssistantCloudAPI } from "../AssistantCloudAPI";
|
|
2
|
+
import { AssistantCloudAPI, CloudAPIError } from "../AssistantCloudAPI";
|
|
3
3
|
|
|
4
4
|
describe("AssistantCloudAPI", () => {
|
|
5
5
|
beforeEach(() => {
|
|
@@ -105,6 +105,15 @@ describe("AssistantCloudAPI", () => {
|
|
|
105
105
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
+
it("returns false from initializeAuth when auth token callback returns null", async () => {
|
|
109
|
+
const api = new AssistantCloudAPI({
|
|
110
|
+
baseUrl: "https://test.example.com",
|
|
111
|
+
authToken: async () => null,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await expect(api.initializeAuth()).resolves.toBe(false);
|
|
115
|
+
});
|
|
116
|
+
|
|
108
117
|
it("throws APIError with parsed message for JSON error responses", async () => {
|
|
109
118
|
const fetchMock = vi.fn().mockResolvedValue({
|
|
110
119
|
ok: false,
|
|
@@ -125,9 +134,10 @@ describe("AssistantCloudAPI", () => {
|
|
|
125
134
|
});
|
|
126
135
|
|
|
127
136
|
const error = await api.makeRawRequest("/threads").catch((e) => e);
|
|
128
|
-
expect(error).toBeInstanceOf(
|
|
129
|
-
expect(error.name).toBe("
|
|
137
|
+
expect(error).toBeInstanceOf(CloudAPIError);
|
|
138
|
+
expect(error.name).toBe("CloudAPIError");
|
|
130
139
|
expect(error.message).toBe("invalid request payload");
|
|
140
|
+
expect(error.status).toBe(400);
|
|
131
141
|
});
|
|
132
142
|
|
|
133
143
|
it("throws generic error with status for non-JSON error responses", async () => {
|
|
@@ -145,9 +155,10 @@ describe("AssistantCloudAPI", () => {
|
|
|
145
155
|
workspaceId: "w-1",
|
|
146
156
|
});
|
|
147
157
|
|
|
148
|
-
await
|
|
149
|
-
|
|
150
|
-
);
|
|
158
|
+
const error = await api.makeRawRequest("/threads").catch((e) => e);
|
|
159
|
+
expect(error).toBeInstanceOf(CloudAPIError);
|
|
160
|
+
expect(error.message).toBe("Request failed with status 502, Bad Gateway");
|
|
161
|
+
expect(error.status).toBe(502);
|
|
151
162
|
});
|
|
152
163
|
|
|
153
164
|
it("makeRequest returns parsed JSON from a successful response", async () => {
|
|
@@ -155,7 +166,7 @@ describe("AssistantCloudAPI", () => {
|
|
|
155
166
|
const fetchMock = vi.fn().mockResolvedValue({
|
|
156
167
|
ok: true,
|
|
157
168
|
headers: new Headers(),
|
|
158
|
-
|
|
169
|
+
text: vi.fn().mockResolvedValue(JSON.stringify(responseData)),
|
|
159
170
|
});
|
|
160
171
|
vi.stubGlobal("fetch", fetchMock);
|
|
161
172
|
|
|
@@ -168,4 +179,62 @@ describe("AssistantCloudAPI", () => {
|
|
|
168
179
|
const result = await api.makeRequest("/threads");
|
|
169
180
|
expect(result).toEqual(responseData);
|
|
170
181
|
});
|
|
182
|
+
|
|
183
|
+
it("makeRequest returns undefined from a successful empty response", async () => {
|
|
184
|
+
const fetchMock = vi.fn().mockResolvedValue({
|
|
185
|
+
ok: true,
|
|
186
|
+
status: 204,
|
|
187
|
+
headers: new Headers(),
|
|
188
|
+
text: vi.fn().mockResolvedValue(""),
|
|
189
|
+
});
|
|
190
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
191
|
+
|
|
192
|
+
const api = new AssistantCloudAPI({
|
|
193
|
+
apiKey: "test-key",
|
|
194
|
+
userId: "u-1",
|
|
195
|
+
workspaceId: "w-1",
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
await expect(
|
|
199
|
+
api.makeRequest("/threads/t-1", { method: "DELETE" }),
|
|
200
|
+
).resolves.toBeUndefined();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("makeRequest returns undefined when content-length is zero", async () => {
|
|
204
|
+
const text = vi.fn().mockResolvedValue("");
|
|
205
|
+
const fetchMock = vi.fn().mockResolvedValue({
|
|
206
|
+
ok: true,
|
|
207
|
+
status: 200,
|
|
208
|
+
headers: new Headers({ "content-length": "0" }),
|
|
209
|
+
text,
|
|
210
|
+
});
|
|
211
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
212
|
+
|
|
213
|
+
const api = new AssistantCloudAPI({
|
|
214
|
+
apiKey: "test-key",
|
|
215
|
+
userId: "u-1",
|
|
216
|
+
workspaceId: "w-1",
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
await expect(api.makeRequest("/threads/t-1")).resolves.toBeUndefined();
|
|
220
|
+
expect(text).not.toHaveBeenCalled();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("makeRequest returns undefined from a whitespace-only success body", async () => {
|
|
224
|
+
const fetchMock = vi.fn().mockResolvedValue({
|
|
225
|
+
ok: true,
|
|
226
|
+
status: 200,
|
|
227
|
+
headers: new Headers(),
|
|
228
|
+
text: vi.fn().mockResolvedValue(" "),
|
|
229
|
+
});
|
|
230
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
231
|
+
|
|
232
|
+
const api = new AssistantCloudAPI({
|
|
233
|
+
apiKey: "test-key",
|
|
234
|
+
userId: "u-1",
|
|
235
|
+
workspaceId: "w-1",
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
await expect(api.makeRequest("/threads/t-1")).resolves.toBeUndefined();
|
|
239
|
+
});
|
|
171
240
|
});
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { AssistantCloudAnonymousAuthStrategy } from "../AssistantCloudAuthStrategy";
|
|
3
|
+
|
|
4
|
+
const baseUrl = "https://test.example.com";
|
|
5
|
+
const accessToken = `${Buffer.from(JSON.stringify({ alg: "none" })).toString("base64url")}.${Buffer.from(JSON.stringify({ exp: 4102444800 })).toString("base64url")}.sig`;
|
|
6
|
+
const refreshToken = { token: "r1", expires_at: "2099-01-01" };
|
|
7
|
+
|
|
8
|
+
let originalLocalStorageDescriptor: PropertyDescriptor | undefined;
|
|
9
|
+
|
|
10
|
+
const installLocalStorage = (storage: Storage): void => {
|
|
11
|
+
Object.defineProperty(globalThis, "localStorage", {
|
|
12
|
+
configurable: true,
|
|
13
|
+
value: storage,
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const mockAnonymousTokenFetch = () => {
|
|
18
|
+
const fetchMock = vi.fn().mockResolvedValue({
|
|
19
|
+
ok: true,
|
|
20
|
+
json: vi.fn().mockResolvedValue({
|
|
21
|
+
access_token: accessToken,
|
|
22
|
+
refresh_token: refreshToken,
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
26
|
+
return fetchMock;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
describe("AssistantCloudAnonymousAuthStrategy", () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
originalLocalStorageDescriptor = Object.getOwnPropertyDescriptor(
|
|
32
|
+
globalThis,
|
|
33
|
+
"localStorage",
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
vi.unstubAllGlobals();
|
|
39
|
+
if (originalLocalStorageDescriptor) {
|
|
40
|
+
Object.defineProperty(
|
|
41
|
+
globalThis,
|
|
42
|
+
"localStorage",
|
|
43
|
+
originalLocalStorageDescriptor,
|
|
44
|
+
);
|
|
45
|
+
} else {
|
|
46
|
+
delete (globalThis as { localStorage?: Storage }).localStorage;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("persists the refresh token and returns the anonymous access token", async () => {
|
|
51
|
+
const values = new Map<string, string>();
|
|
52
|
+
installLocalStorage({
|
|
53
|
+
getItem: (key) => values.get(key) ?? null,
|
|
54
|
+
setItem: (key, value) => {
|
|
55
|
+
values.set(key, value);
|
|
56
|
+
},
|
|
57
|
+
removeItem: (key) => {
|
|
58
|
+
values.delete(key);
|
|
59
|
+
},
|
|
60
|
+
} as Storage);
|
|
61
|
+
const fetchMock = mockAnonymousTokenFetch();
|
|
62
|
+
|
|
63
|
+
const strategy = new AssistantCloudAnonymousAuthStrategy(baseUrl);
|
|
64
|
+
|
|
65
|
+
await expect(strategy.getAuthHeaders()).resolves.toEqual({
|
|
66
|
+
Authorization: `Bearer ${accessToken}`,
|
|
67
|
+
});
|
|
68
|
+
expect(values.get("aui:refresh_token")).toBe(JSON.stringify(refreshToken));
|
|
69
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
70
|
+
`${baseUrl}/v1/auth/tokens/anonymous`,
|
|
71
|
+
{ method: "POST" },
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("returns an anonymous access token without localStorage", async () => {
|
|
76
|
+
delete (globalThis as { localStorage?: Storage }).localStorage;
|
|
77
|
+
mockAnonymousTokenFetch();
|
|
78
|
+
|
|
79
|
+
const strategy = new AssistantCloudAnonymousAuthStrategy(baseUrl);
|
|
80
|
+
|
|
81
|
+
await expect(strategy.getAuthHeaders()).resolves.toEqual({
|
|
82
|
+
Authorization: `Bearer ${accessToken}`,
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("returns an anonymous access token when localStorage access is blocked", async () => {
|
|
87
|
+
Object.defineProperty(globalThis, "localStorage", {
|
|
88
|
+
configurable: true,
|
|
89
|
+
get() {
|
|
90
|
+
throw new DOMException("blocked", "SecurityError");
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
mockAnonymousTokenFetch();
|
|
94
|
+
|
|
95
|
+
const strategy = new AssistantCloudAnonymousAuthStrategy(baseUrl);
|
|
96
|
+
|
|
97
|
+
await expect(strategy.getAuthHeaders()).resolves.toEqual({
|
|
98
|
+
Authorization: `Bearer ${accessToken}`,
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("returns an anonymous access token when storage methods throw", async () => {
|
|
103
|
+
const getItem = vi
|
|
104
|
+
.fn<(key: string) => string | null>()
|
|
105
|
+
.mockReturnValueOnce(JSON.stringify(refreshToken))
|
|
106
|
+
.mockImplementation(() => {
|
|
107
|
+
throw new DOMException("blocked", "SecurityError");
|
|
108
|
+
});
|
|
109
|
+
const setItem = vi.fn(() => {
|
|
110
|
+
throw new DOMException("blocked", "SecurityError");
|
|
111
|
+
});
|
|
112
|
+
const removeItem = vi.fn(() => {
|
|
113
|
+
throw new DOMException("blocked", "SecurityError");
|
|
114
|
+
});
|
|
115
|
+
installLocalStorage({ getItem, setItem, removeItem } as Storage);
|
|
116
|
+
mockAnonymousTokenFetch();
|
|
117
|
+
|
|
118
|
+
const originalDate = globalThis.Date;
|
|
119
|
+
const fixedDate = (originalDate as unknown as () => Date)();
|
|
120
|
+
const fixedTime = originalDate.now();
|
|
121
|
+
globalThis.Date = Object.assign(
|
|
122
|
+
function Date() {
|
|
123
|
+
return fixedDate;
|
|
124
|
+
},
|
|
125
|
+
{ now: () => fixedTime },
|
|
126
|
+
) as unknown as DateConstructor;
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
await expect(
|
|
130
|
+
new AssistantCloudAnonymousAuthStrategy(baseUrl).getAuthHeaders(),
|
|
131
|
+
).resolves.toEqual({ Authorization: `Bearer ${accessToken}` });
|
|
132
|
+
await expect(
|
|
133
|
+
new AssistantCloudAnonymousAuthStrategy(baseUrl).getAuthHeaders(),
|
|
134
|
+
).resolves.toEqual({ Authorization: `Bearer ${accessToken}` });
|
|
135
|
+
} finally {
|
|
136
|
+
globalThis.Date = originalDate;
|
|
137
|
+
}
|
|
138
|
+
expect(getItem).toHaveBeenCalledTimes(2);
|
|
139
|
+
expect(setItem).toHaveBeenCalledTimes(2);
|
|
140
|
+
expect(removeItem).toHaveBeenCalledTimes(1);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("treats corrupted refresh token JSON as absent", async () => {
|
|
144
|
+
const values = new Map([["aui:refresh_token", "not-json{"]]);
|
|
145
|
+
installLocalStorage({
|
|
146
|
+
getItem: (key) => values.get(key) ?? null,
|
|
147
|
+
setItem: (key, value) => {
|
|
148
|
+
values.set(key, value);
|
|
149
|
+
},
|
|
150
|
+
removeItem: (key) => {
|
|
151
|
+
values.delete(key);
|
|
152
|
+
},
|
|
153
|
+
} as Storage);
|
|
154
|
+
mockAnonymousTokenFetch();
|
|
155
|
+
|
|
156
|
+
const strategy = new AssistantCloudAnonymousAuthStrategy(baseUrl);
|
|
157
|
+
|
|
158
|
+
await expect(strategy.getAuthHeaders()).resolves.toEqual({
|
|
159
|
+
Authorization: `Bearer ${accessToken}`,
|
|
160
|
+
});
|
|
161
|
+
expect(values.get("aui:refresh_token")).toBe(JSON.stringify(refreshToken));
|
|
162
|
+
});
|
|
163
|
+
});
|