assistant-cloud 0.1.43 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +66 -0
  2. package/dist/AssistantCloud.d.ts +6 -1
  3. package/dist/AssistantCloud.d.ts.map +1 -1
  4. package/dist/AssistantCloud.js +13 -5
  5. package/dist/AssistantCloud.js.map +1 -1
  6. package/dist/AssistantCloudAPI.d.ts +28 -3
  7. package/dist/AssistantCloudAPI.d.ts.map +1 -1
  8. package/dist/AssistantCloudAPI.js +37 -10
  9. package/dist/AssistantCloudAPI.js.map +1 -1
  10. package/dist/AssistantCloudAuthStrategy.d.ts +4 -1
  11. package/dist/AssistantCloudAuthStrategy.d.ts.map +1 -1
  12. package/dist/AssistantCloudAuthStrategy.js +15 -3
  13. package/dist/AssistantCloudAuthStrategy.js.map +1 -1
  14. package/dist/AssistantCloudEvents.d.ts +32 -0
  15. package/dist/AssistantCloudEvents.d.ts.map +1 -0
  16. package/dist/AssistantCloudEvents.js +119 -0
  17. package/dist/AssistantCloudEvents.js.map +1 -0
  18. package/dist/AssistantCloudFiles.d.ts +12 -1
  19. package/dist/AssistantCloudFiles.d.ts.map +1 -1
  20. package/dist/AssistantCloudFiles.js +13 -1
  21. package/dist/AssistantCloudFiles.js.map +1 -1
  22. package/dist/AssistantCloudRuns.d.ts +12 -0
  23. package/dist/AssistantCloudRuns.d.ts.map +1 -1
  24. package/dist/AssistantCloudRuns.js +2 -1
  25. package/dist/AssistantCloudRuns.js.map +1 -1
  26. package/dist/AssistantCloudScores.d.ts +27 -0
  27. package/dist/AssistantCloudScores.d.ts.map +1 -0
  28. package/dist/AssistantCloudScores.js +30 -0
  29. package/dist/AssistantCloudScores.js.map +1 -0
  30. package/dist/AssistantCloudThreadMessages.d.ts +11 -1
  31. package/dist/AssistantCloudThreadMessages.d.ts.map +1 -1
  32. package/dist/AssistantCloudThreadMessages.js +12 -1
  33. package/dist/AssistantCloudThreadMessages.js.map +1 -1
  34. package/dist/AssistantCloudThreads.d.ts +8 -0
  35. package/dist/AssistantCloudThreads.d.ts.map +1 -1
  36. package/dist/AssistantCloudThreads.js +9 -1
  37. package/dist/AssistantCloudThreads.js.map +1 -1
  38. package/dist/CloudEngagementReporter.d.ts +74 -0
  39. package/dist/CloudEngagementReporter.d.ts.map +1 -0
  40. package/dist/CloudEngagementReporter.js +132 -0
  41. package/dist/CloudEngagementReporter.js.map +1 -0
  42. package/dist/CloudMessagePersistence.d.ts +12 -9
  43. package/dist/CloudMessagePersistence.d.ts.map +1 -1
  44. package/dist/CloudMessagePersistence.js +54 -20
  45. package/dist/CloudMessagePersistence.js.map +1 -1
  46. package/dist/CloudRunReporter.d.ts +20 -0
  47. package/dist/CloudRunReporter.d.ts.map +1 -0
  48. package/dist/CloudRunReporter.js +38 -0
  49. package/dist/CloudRunReporter.js.map +1 -0
  50. package/dist/FormattedCloudPersistence.d.ts +3 -8
  51. package/dist/FormattedCloudPersistence.d.ts.map +1 -1
  52. package/dist/FormattedCloudPersistence.js +3 -8
  53. package/dist/FormattedCloudPersistence.js.map +1 -1
  54. package/dist/ai-sdk/index.d.ts +33 -0
  55. package/dist/ai-sdk/index.d.ts.map +1 -0
  56. package/dist/ai-sdk/index.js +147 -0
  57. package/dist/ai-sdk/index.js.map +1 -0
  58. package/dist/cloudResponse.d.ts +4 -1
  59. package/dist/cloudResponse.d.ts.map +1 -1
  60. package/dist/cloudResponse.js +14 -1
  61. package/dist/cloudResponse.js.map +1 -1
  62. package/dist/generateThreadTitle.js +1 -0
  63. package/dist/generateThreadTitle.js.map +1 -1
  64. package/dist/index.d.ts +10 -4
  65. package/dist/index.js +7 -2
  66. package/dist/instrumentMcpSampling.d.ts.map +1 -1
  67. package/dist/instrumentMcpSampling.js +12 -2
  68. package/dist/instrumentMcpSampling.js.map +1 -1
  69. package/dist/runTelemetry.d.ts +86 -7
  70. package/dist/runTelemetry.d.ts.map +1 -1
  71. package/dist/runTelemetry.js +144 -1
  72. package/dist/runTelemetry.js.map +1 -1
  73. package/dist/telemetry/index.d.ts +32 -0
  74. package/dist/telemetry/index.d.ts.map +1 -0
  75. package/dist/telemetry/index.js +62 -0
  76. package/dist/telemetry/index.js.map +1 -0
  77. package/dist/version.d.ts +5 -0
  78. package/dist/version.d.ts.map +1 -0
  79. package/dist/version.js +6 -0
  80. package/dist/version.js.map +1 -0
  81. package/package.json +43 -6
  82. package/src/AssistantCloud.ts +23 -8
  83. package/src/AssistantCloudAPI.ts +72 -10
  84. package/src/AssistantCloudAuthStrategy.ts +17 -2
  85. package/src/AssistantCloudEvents.test.ts +149 -0
  86. package/src/AssistantCloudEvents.ts +190 -0
  87. package/src/AssistantCloudFiles.test.ts +59 -0
  88. package/src/AssistantCloudFiles.ts +39 -0
  89. package/src/AssistantCloudRuns.ts +13 -1
  90. package/src/AssistantCloudScores.test.ts +113 -0
  91. package/src/AssistantCloudScores.ts +61 -0
  92. package/src/AssistantCloudThreadMessages.test.ts +51 -0
  93. package/src/AssistantCloudThreadMessages.ts +33 -0
  94. package/src/AssistantCloudThreads.test.ts +21 -0
  95. package/src/AssistantCloudThreads.ts +21 -0
  96. package/src/CloudEngagementReporter.ts +231 -0
  97. package/src/CloudMessagePersistence.ts +70 -27
  98. package/src/CloudRunReporter.ts +38 -0
  99. package/src/FormattedCloudPersistence.ts +3 -8
  100. package/src/ai-sdk/index.test.ts +258 -0
  101. package/src/ai-sdk/index.ts +222 -0
  102. package/src/cloudResponse.test.ts +34 -1
  103. package/src/cloudResponse.ts +30 -0
  104. package/src/generateThreadTitle.test.ts +32 -0
  105. package/src/generateThreadTitle.ts +1 -0
  106. package/src/index.ts +35 -2
  107. package/src/instrumentMcpSampling.test.ts +102 -0
  108. package/src/instrumentMcpSampling.ts +16 -2
  109. package/src/runTelemetry.test.ts +325 -0
  110. package/src/runTelemetry.ts +274 -6
  111. package/src/telemetry/index.test.ts +252 -0
  112. package/src/telemetry/index.ts +98 -0
  113. package/src/tests/AssistantCloud.test.ts +55 -1
  114. package/src/tests/AssistantCloudAPI.test.ts +95 -4
  115. package/src/tests/AssistantCloudAuthStrategy.test.ts +93 -2
  116. package/src/tests/AssistantCloudProjects.test.ts +1 -5
  117. package/src/tests/CloudEngagementReporter.test.ts +184 -0
  118. package/src/tests/CloudMessagePersistence.test.ts +350 -0
  119. package/src/tests/CloudRunReporter.test.ts +100 -0
  120. package/src/version.ts +4 -0
package/README.md CHANGED
@@ -31,6 +31,72 @@ export function Provider({ children }: { children: React.ReactNode }) {
31
31
  }
32
32
  ```
33
33
 
34
+ ## Building an integration
35
+
36
+ The pieces every client integration needs live in the package, so a runtime binding only maps its own events onto them.
37
+
38
+ Every API request carries `Aui-Sdk` with the client's own version and the identities integrations pass to `registerSdk` (the anonymous token bootstrap requests do not), so the cloud can tell which packages talk to a project.
39
+
40
+ - `CloudRunReporter` sends run reports: nothing while telemetry is off, the cloud's environment, release and tags on every report, the `beforeReport` hook applied last, and a failed send that never surfaces. A report given a key is sent once per key, so the key has to name one run; without a key every call reports.
41
+ - `CloudEngagementReporter` derives engagement events (`message_sent`, `run_stopped`, `error_shown`, `suggestions_shown` and the rest) from what a chat integration observes and keeps the per thread state they need, such as a run's start for the stop duration. An id resolver turns the integration's own thread and message ids into the ids the cloud stores.
42
+ - `assistant-cloud/ai-sdk` holds the AI SDK specifics: `aiSDKV6FormatAdapter`, the stored form of a `UIMessage`, and `extractAISDKRunTelemetry`, which reads the run report fields out of one run's assistant messages. The entry types its messages with `ai` and needs no runtime from it.
43
+
44
+ ```ts
45
+ import { AssistantCloud, CloudRunReporter } from "assistant-cloud";
46
+ import { extractAISDKRunTelemetry } from "assistant-cloud/ai-sdk";
47
+
48
+ const cloud = new AssistantCloud({ baseUrl, anonymous: true });
49
+ const reporter = new CloudRunReporter(cloud);
50
+
51
+ const run = extractAISDKRunTelemetry(messages);
52
+ if (run) {
53
+ await reporter.report(
54
+ { threadId, ...run },
55
+ run.assistantMessageId && `${threadId}:${run.assistantMessageId}`,
56
+ );
57
+ }
58
+ ```
59
+
60
+ ## Server telemetry
61
+
62
+ Send AI SDK 7 GenAI spans to Assistant Cloud from a Next.js `instrumentation.ts` file. The `assistant-cloud/telemetry` entry needs the OpenTelemetry packages installed next to it:
63
+
64
+ ```sh
65
+ npm i @vercel/otel @opentelemetry/api @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http
66
+ ```
67
+
68
+ ```ts
69
+ import { registerOTel } from "@vercel/otel";
70
+ import {
71
+ createAssistantCloudSpanProcessor,
72
+ createAssistantCloudTraceExporter,
73
+ } from "assistant-cloud/telemetry";
74
+
75
+ export function register() {
76
+ registerOTel({
77
+ serviceName: "my-app",
78
+ spanProcessors: [
79
+ "auto",
80
+ createAssistantCloudSpanProcessor(
81
+ createAssistantCloudTraceExporter({
82
+ apiKey: process.env.ASSISTANT_API_KEY!,
83
+ }),
84
+ ),
85
+ ],
86
+ });
87
+ }
88
+ ```
89
+
90
+ Pass the active server trace ID to the browser with `messageMetadata` in the route that calls `streamText`:
91
+
92
+ ```ts
93
+ import { withAssistantCloudTraceMetadata } from "assistant-cloud/telemetry";
94
+
95
+ return result.toUIMessageStreamResponse({
96
+ messageMetadata: withAssistantCloudTraceMetadata(),
97
+ });
98
+ ```
99
+
34
100
  ## Authentication
35
101
 
36
102
  | Mode | Required fields | Use case |
@@ -1,9 +1,11 @@
1
1
  import { AssistantCloudRuns } from "./AssistantCloudRuns.js";
2
- import { AssistantCloudConfig, AssistantCloudTelemetryConfig } from "./AssistantCloudAPI.js";
2
+ import { AssistantCloudConfig, AssistantCloudTelemetryConfig, SdkIdentity } from "./AssistantCloudAPI.js";
3
3
  import { AssistantCloudAuthTokens } from "./AssistantCloudAuthTokens.js";
4
4
  import { AssistantCloudThreads } from "./AssistantCloudThreads.js";
5
5
  import { AssistantCloudProjects } from "./AssistantCloudProjects.js";
6
6
  import { AssistantCloudFiles } from "./AssistantCloudFiles.js";
7
+ import { AssistantCloudEvents } from "./AssistantCloudEvents.js";
8
+ import { AssistantCloudScores } from "./AssistantCloudScores.js";
7
9
  //#region src/AssistantCloud.d.ts
8
10
  declare class AssistantCloud {
9
11
  readonly threads: AssistantCloudThreads;
@@ -13,7 +15,10 @@ declare class AssistantCloud {
13
15
  };
14
16
  readonly runs: AssistantCloudRuns;
15
17
  readonly files: AssistantCloudFiles;
18
+ readonly events: AssistantCloudEvents;
19
+ readonly scores: AssistantCloudScores;
16
20
  readonly telemetry: AssistantCloudTelemetryConfig;
21
+ readonly registerSdk: (sdk: SdkIdentity) => void;
17
22
  constructor(config: AssistantCloudConfig);
18
23
  }
19
24
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantCloud.d.ts","names":[],"sources":["../src/AssistantCloud.ts"],"mappings":";;;;;;;cAWa;WACK,SAAO;WACP,UAAQ;WACR;;;WACA,MAAI;WACJ,OAAK;WACL,WAAW;EAEf,YAAA,QAAQ"}
1
+ {"version":3,"file":"AssistantCloud.d.ts","names":[],"sources":["../src/AssistantCloud.ts"],"mappings":";;;;;;;;;cAca;WACK,SAAO;WACP,UAAQ;WACR;;;WACA,MAAI;WACJ,OAAK;WACL,QAAM;WACN,QAAM;WACN,WAAW;WACX,cAAc,KAAK;EAEvB,YAAA,QAAQ"}
@@ -4,6 +4,8 @@ import { AssistantCloudThreads } from "./AssistantCloudThreads.js";
4
4
  import { AssistantCloudProjects } from "./AssistantCloudProjects.js";
5
5
  import { AssistantCloudRuns } from "./AssistantCloudRuns.js";
6
6
  import { AssistantCloudFiles } from "./AssistantCloudFiles.js";
7
+ import { AssistantCloudEvents } from "./AssistantCloudEvents.js";
8
+ import { AssistantCloudScores } from "./AssistantCloudScores.js";
7
9
  //#region src/AssistantCloud.ts
8
10
  var AssistantCloud = class {
9
11
  threads;
@@ -11,19 +13,25 @@ var AssistantCloud = class {
11
13
  auth;
12
14
  runs;
13
15
  files;
16
+ events;
17
+ scores;
14
18
  telemetry;
19
+ registerSdk;
15
20
  constructor(config) {
16
21
  const api = new AssistantCloudAPI(config);
17
- this.threads = new AssistantCloudThreads(api);
18
- this.projects = new AssistantCloudProjects(api);
19
- this.auth = { tokens: new AssistantCloudAuthTokens(api) };
20
- this.runs = new AssistantCloudRuns(api);
21
- this.files = new AssistantCloudFiles(api);
22
+ this.registerSdk = api.registerSdk;
22
23
  const t = config.telemetry;
23
24
  this.telemetry = t === false ? { enabled: false } : t === true || t === void 0 ? { enabled: true } : {
24
25
  ...t,
25
26
  enabled: t.enabled !== false
26
27
  };
28
+ this.threads = new AssistantCloudThreads(api);
29
+ this.projects = new AssistantCloudProjects(api);
30
+ this.auth = { tokens: new AssistantCloudAuthTokens(api) };
31
+ this.runs = new AssistantCloudRuns(api);
32
+ this.files = new AssistantCloudFiles(api);
33
+ this.events = new AssistantCloudEvents(api, () => this.telemetry.enabled !== false && this.telemetry.events !== false);
34
+ this.scores = new AssistantCloudScores(api);
27
35
  }
28
36
  };
29
37
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantCloud.js","names":[],"sources":["../src/AssistantCloud.ts"],"sourcesContent":["import {\n AssistantCloudAPI,\n type AssistantCloudConfig,\n type AssistantCloudTelemetryConfig,\n} from \"./AssistantCloudAPI\";\nimport { AssistantCloudAuthTokens } from \"./AssistantCloudAuthTokens\";\nimport { AssistantCloudProjects } from \"./AssistantCloudProjects\";\nimport { AssistantCloudRuns } from \"./AssistantCloudRuns\";\nimport { AssistantCloudThreads } from \"./AssistantCloudThreads\";\nimport { AssistantCloudFiles } from \"./AssistantCloudFiles\";\n\nexport class AssistantCloud {\n public readonly threads;\n public readonly projects;\n public readonly auth;\n public readonly runs;\n public readonly files;\n public readonly telemetry: AssistantCloudTelemetryConfig;\n\n constructor(config: AssistantCloudConfig) {\n const api = new AssistantCloudAPI(config);\n this.threads = new AssistantCloudThreads(api);\n this.projects = new AssistantCloudProjects(api);\n this.auth = {\n tokens: new AssistantCloudAuthTokens(api),\n };\n this.runs = new AssistantCloudRuns(api);\n this.files = new AssistantCloudFiles(api);\n\n const t = config.telemetry;\n this.telemetry =\n t === false\n ? { enabled: false }\n : t === true || t === undefined\n ? { enabled: true }\n : { ...t, enabled: t.enabled !== false };\n }\n}\n"],"mappings":";;;;;;;AAWA,IAAa,iBAAb,MAA4B;CAC1B;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,QAA8B;EACxC,MAAM,MAAM,IAAI,kBAAkB,MAAM;EACxC,KAAK,UAAU,IAAI,sBAAsB,GAAG;EAC5C,KAAK,WAAW,IAAI,uBAAuB,GAAG;EAC9C,KAAK,OAAO,EACV,QAAQ,IAAI,yBAAyB,GAAG,EAC1C;EACA,KAAK,OAAO,IAAI,mBAAmB,GAAG;EACtC,KAAK,QAAQ,IAAI,oBAAoB,GAAG;EAExC,MAAM,IAAI,OAAO;EACjB,KAAK,YACH,MAAM,QACF,EAAE,SAAS,MAAM,IACjB,MAAM,QAAQ,MAAM,KAAA,IAClB,EAAE,SAAS,KAAK,IAChB;GAAE,GAAG;GAAG,SAAS,EAAE,YAAY;EAAM;CAC/C;AACF"}
1
+ {"version":3,"file":"AssistantCloud.js","names":[],"sources":["../src/AssistantCloud.ts"],"sourcesContent":["import {\n AssistantCloudAPI,\n type AssistantCloudConfig,\n type SdkIdentity,\n type AssistantCloudTelemetryConfig,\n} from \"./AssistantCloudAPI\";\nimport { AssistantCloudAuthTokens } from \"./AssistantCloudAuthTokens\";\nimport { AssistantCloudProjects } from \"./AssistantCloudProjects\";\nimport { AssistantCloudRuns } from \"./AssistantCloudRuns\";\nimport { AssistantCloudThreads } from \"./AssistantCloudThreads\";\nimport { AssistantCloudFiles } from \"./AssistantCloudFiles\";\nimport { AssistantCloudEvents } from \"./AssistantCloudEvents\";\nimport { AssistantCloudScores } from \"./AssistantCloudScores\";\n\nexport class AssistantCloud {\n public readonly threads;\n public readonly projects;\n public readonly auth;\n public readonly runs;\n public readonly files;\n public readonly events;\n public readonly scores;\n public readonly telemetry: AssistantCloudTelemetryConfig;\n public readonly registerSdk: (sdk: SdkIdentity) => void;\n\n constructor(config: AssistantCloudConfig) {\n const api = new AssistantCloudAPI(config);\n this.registerSdk = api.registerSdk;\n const t = config.telemetry;\n this.telemetry =\n t === false\n ? { enabled: false }\n : t === true || t === undefined\n ? { enabled: true }\n : {\n ...t,\n enabled: t.enabled !== false,\n };\n\n this.threads = new AssistantCloudThreads(api);\n this.projects = new AssistantCloudProjects(api);\n this.auth = {\n tokens: new AssistantCloudAuthTokens(api),\n };\n this.runs = new AssistantCloudRuns(api);\n this.files = new AssistantCloudFiles(api);\n this.events = new AssistantCloudEvents(\n api,\n () => this.telemetry.enabled !== false && this.telemetry.events !== false,\n );\n this.scores = new AssistantCloudScores(api);\n }\n}\n"],"mappings":";;;;;;;;;AAcA,IAAa,iBAAb,MAA4B;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,QAA8B;EACxC,MAAM,MAAM,IAAI,kBAAkB,MAAM;EACxC,KAAK,cAAc,IAAI;EACvB,MAAM,IAAI,OAAO;EACjB,KAAK,YACH,MAAM,QACF,EAAE,SAAS,MAAM,IACjB,MAAM,QAAQ,MAAM,KAAA,IAClB,EAAE,SAAS,KAAK,IAChB;GACE,GAAG;GACH,SAAS,EAAE,YAAY;EACzB;EAER,KAAK,UAAU,IAAI,sBAAsB,GAAG;EAC5C,KAAK,WAAW,IAAI,uBAAuB,GAAG;EAC9C,KAAK,OAAO,EACV,QAAQ,IAAI,yBAAyB,GAAG,EAC1C;EACA,KAAK,OAAO,IAAI,mBAAmB,GAAG;EACtC,KAAK,QAAQ,IAAI,oBAAoB,GAAG;EACxC,KAAK,SAAS,IAAI,qBAChB,WACM,KAAK,UAAU,YAAY,SAAS,KAAK,UAAU,WAAW,KACtE;EACA,KAAK,SAAS,IAAI,qBAAqB,GAAG;CAC5C;AACF"}
@@ -1,8 +1,25 @@
1
1
  import { AssistantCloudAuthStrategy } from "./AssistantCloudAuthStrategy.js";
2
2
  import { AssistantCloudRunReport } from "./AssistantCloudRuns.js";
3
3
  //#region src/AssistantCloudAPI.d.ts
4
+ type SdkIdentity = {
5
+ name: string;
6
+ version: string;
7
+ };
4
8
  type AssistantCloudTelemetryConfig = {
9
+ /**
10
+ * Enables Assistant Cloud telemetry. Defaults to `true`. Set to `false` to
11
+ * disable both run reports and engagement events.
12
+ */
5
13
  enabled?: boolean;
14
+ /**
15
+ * Enables Assistant Cloud engagement events. Defaults to `true` when
16
+ * telemetry is enabled. Set to `false` to keep run reports while disabling
17
+ * engagement events.
18
+ */
19
+ events?: boolean;
20
+ release?: string;
21
+ environment?: string;
22
+ tags?: string[];
6
23
  /**
7
24
  * Called before each telemetry report is sent.
8
25
  * Return a modified report to enrich it (e.g. add `model_id`),
@@ -27,7 +44,10 @@ type AssistantCloudConfig = ({
27
44
  *
28
45
  * When enabled, the SDK automatically reports run metadata (status, step
29
46
  * count, tool calls, and token usage) to Assistant Cloud after each
30
- * assistant message is saved. No message content is sent.
47
+ * assistant message is saved. Reports can also include assistant output,
48
+ * tool arguments and results, errors, and metadata, which may contain
49
+ * sensitive content. Use `beforeReport` to redact or drop reports, or
50
+ * `telemetry: false` to disable reporting.
31
51
  *
32
52
  * - `true` / `undefined` — enabled with defaults
33
53
  * - `false` — disabled
@@ -37,22 +57,27 @@ type AssistantCloudConfig = ({
37
57
  };
38
58
  declare class CloudAPIError extends Error {
39
59
  readonly status: number;
40
- constructor(message: string, status: number);
60
+ readonly code?: string;
61
+ readonly details?: Record<string, unknown>;
62
+ constructor(message: string, status: number, code?: string, details?: Record<string, unknown>);
41
63
  }
42
64
  type MakeRequestOptions = {
43
65
  method?: "POST" | "PUT" | "DELETE" | undefined;
44
66
  headers?: Record<string, string> | undefined;
45
67
  query?: Record<string, string | number | boolean> | undefined;
46
68
  body?: object | undefined;
69
+ keepalive?: boolean | undefined;
47
70
  };
48
71
  declare class AssistantCloudAPI {
49
72
  _auth: AssistantCloudAuthStrategy;
50
73
  _baseUrl: string;
74
+ readonly registerSdk: (sdk: SdkIdentity) => void;
75
+ readonly sdkHeader: () => string;
51
76
  constructor(config: AssistantCloudConfig);
52
77
  initializeAuth(): Promise<boolean>;
53
78
  makeRawRequest(endpoint: string, options?: MakeRequestOptions): Promise<Response>;
54
79
  makeRequest(endpoint: string, options?: MakeRequestOptions): Promise<any>;
55
80
  }
56
81
  //#endregion
57
- export { AssistantCloudAPI, AssistantCloudConfig, AssistantCloudTelemetryConfig, CloudAPIError };
82
+ export { AssistantCloudAPI, AssistantCloudConfig, AssistantCloudTelemetryConfig, CloudAPIError, SdkIdentity };
58
83
  //# sourceMappingURL=AssistantCloudAPI.d.ts.map
@@ -1 +1 @@
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;WACjB;EAEJ,YAAA,iBAAiB;;KAO1B;EACH;EACA,UAAU;EACV,QAAQ;EACR;;cAQW;EACJ,OAAO;EACP;EAEK,YAAA,QAAQ;EAuBP,kBAAc;EAId,eACX,kBACA,UAAS,qBAAuB,QAAA;EAoDrB,YAAY,kBAAkB,UAAS,qBAAuB"}
1
+ {"version":3,"file":"AssistantCloudAPI.d.ts","names":[],"sources":["../src/AssistantCloudAPI.ts"],"mappings":";;;KAUY;EACV;EACA;;KAGU;;;;;EAKV;;;;;;EAMA;EACA;EACA;EACA;;;;;;EAMA,gBACE,QAAQ,4BACL;;KAGK;EAEN;EACA,iBAAiB;;EAGjB;EACA;EACA;EACA;;EAGA;EACA;;;;;;;;;;;;;;;;EAiBJ,sBAAsB;;cAGX,sBAAsB;WACjB;WACA;WACA,UAAU;EAGxB,YAAA,iBACA,gBACA,eACA,UAAU;;KAUT;EACH;EACA,UAAU;EACV,QAAQ;EACR;EACA;;cAKW;EACJ,OAAO;EACP;WACS,cAAc,KAAK;WACnB;EAEJ,YAAA,QAAQ;EAuCP,kBAAc;EAId,eACX,kBACA,UAAS,qBAAuB,QAAA;EAkErB,YAAY,kBAAkB,UAAS,qBAAuB"}
@@ -1,21 +1,36 @@
1
- import { AssistantCloudAPIKeyAuthStrategy, AssistantCloudAnonymousAuthStrategy, AssistantCloudJWTAuthStrategy } from "./AssistantCloudAuthStrategy.js";
1
+ import { AssistantCloudAPIKeyAuthStrategy, AssistantCloudAnonymousAuthStrategy, AssistantCloudJWTAuthStrategy, normalizeBaseUrl } from "./AssistantCloudAuthStrategy.js";
2
+ import { ASSISTANT_CLOUD_VERSION } from "./version.js";
2
3
  //#region src/AssistantCloudAPI.ts
3
4
  var CloudAPIError = class extends Error {
4
5
  status;
5
- constructor(message, status) {
6
+ code;
7
+ details;
8
+ constructor(message, status, code, details) {
6
9
  super(message);
7
10
  this.status = status;
11
+ if (code !== void 0) this.code = code;
12
+ if (details !== void 0) this.details = details;
8
13
  this.name = "CloudAPIError";
9
14
  }
10
15
  };
11
- const normalizeBaseUrl = (baseUrl) => {
12
- if (!baseUrl || !baseUrl.endsWith("/")) return baseUrl;
13
- return baseUrl.slice(0, -1);
14
- };
16
+ const HEADER_TOKEN = /^[\x21-\x7e]+$/;
15
17
  var AssistantCloudAPI = class {
16
18
  _auth;
17
19
  _baseUrl;
20
+ registerSdk;
21
+ sdkHeader;
18
22
  constructor(config) {
23
+ const sdks = /* @__PURE__ */ new Map();
24
+ this.registerSdk = (sdk) => {
25
+ const name = sdk.name.trim();
26
+ const version = sdk.version.trim();
27
+ if (!HEADER_TOKEN.test(name) || !HEADER_TOKEN.test(version)) return;
28
+ sdks.set(`${name}/${version}`, {
29
+ name,
30
+ version
31
+ });
32
+ };
33
+ this.sdkHeader = () => [`assistant-cloud/${ASSISTANT_CLOUD_VERSION}`, ...Array.from(sdks.values(), ({ name, version }) => `${name}/${version}`)].join(" ");
19
34
  if ("authToken" in config) {
20
35
  this._baseUrl = normalizeBaseUrl(config.baseUrl);
21
36
  this._auth = new AssistantCloudJWTAuthStrategy(config.authToken);
@@ -36,7 +51,8 @@ var AssistantCloudAPI = class {
36
51
  const headers = {
37
52
  ...authHeaders,
38
53
  ...options.headers,
39
- "Content-Type": "application/json"
54
+ "Content-Type": "application/json",
55
+ "Aui-Sdk": this.sdkHeader()
40
56
  };
41
57
  const queryParams = new URLSearchParams();
42
58
  if (options.query) for (const [key, value] of Object.entries(options.query)) {
@@ -49,17 +65,28 @@ var AssistantCloudAPI = class {
49
65
  const response = await fetch(url, {
50
66
  method: options.method ?? "GET",
51
67
  headers,
52
- body: options.body ? JSON.stringify(options.body) : null
68
+ body: options.body ? JSON.stringify(options.body) : null,
69
+ ...options.keepalive ? { keepalive: true } : {}
53
70
  });
54
71
  this._auth.readAuthHeaders(response.headers);
55
72
  if (!response.ok) {
56
73
  const text = await response.text();
57
74
  let message;
75
+ let code;
76
+ let details;
58
77
  try {
59
78
  const body = JSON.parse(text);
60
- if (typeof body?.message === "string" && body.message.length > 0) message = body.message;
79
+ if (typeof body === "object" && body !== null && !Array.isArray(body)) {
80
+ const record = body;
81
+ if (typeof record.message === "string" && record.message.length > 0) message = record.message;
82
+ if (typeof record.error === "string") {
83
+ code = record.error;
84
+ details = { ...record };
85
+ delete details.error;
86
+ }
87
+ }
61
88
  } catch {}
62
- throw new CloudAPIError(message ?? `Request failed with status ${response.status}, ${text}`, response.status);
89
+ throw new CloudAPIError(message ?? `Request failed with status ${response.status}, ${text}`, response.status, code, details);
63
90
  }
64
91
  return response;
65
92
  }
@@ -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\nexport class CloudAPIError extends Error {\n public readonly status: number;\n\n constructor(message: string, status: number) {\n super(message);\n this.status = status;\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\nconst normalizeBaseUrl = (baseUrl: string) => {\n if (!baseUrl || !baseUrl.endsWith(\"/\")) return baseUrl;\n return baseUrl.slice(0, -1);\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 = normalizeBaseUrl(config.baseUrl);\n this._auth = new AssistantCloudJWTAuthStrategy(config.authToken);\n } else if (\"apiKey\" in config) {\n this._baseUrl = normalizeBaseUrl(\n config.baseUrl ?? \"https://backend.assistant-api.com\",\n );\n this._auth = new AssistantCloudAPIKeyAuthStrategy(\n config.apiKey,\n config.userId,\n config.workspaceId,\n );\n } else if (\"anonymous\" in config) {\n this._baseUrl = normalizeBaseUrl(config.baseUrl);\n this._auth = new AssistantCloudAnonymousAuthStrategy(this._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 let message: string | undefined;\n try {\n const body = JSON.parse(text);\n if (typeof body?.message === \"string\" && body.message.length > 0) {\n message = body.message;\n }\n } catch {}\n throw new CloudAPIError(\n message ?? `Request failed with status ${response.status}, ${text}`,\n response.status,\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;CACvC;CAEA,YAAY,SAAiB,QAAgB;EAC3C,MAAM,OAAO;EACb,KAAK,SAAS;EACd,KAAK,OAAO;CACd;AACF;AASA,MAAM,oBAAoB,YAAoB;CAC5C,IAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,GAAG,GAAG,OAAO;CAC/C,OAAO,QAAQ,MAAM,GAAG,EAAE;AAC5B;AAEA,IAAa,oBAAb,MAA+B;CAC7B;CACA;CAEA,YAAY,QAA8B;EACxC,IAAI,eAAe,QAAQ;GACzB,KAAK,WAAW,iBAAiB,OAAO,OAAO;GAC/C,KAAK,QAAQ,IAAI,8BAA8B,OAAO,SAAS;EACjE,OAAO,IAAI,YAAY,QAAQ;GAC7B,KAAK,WAAW,iBACd,OAAO,WAAW,mCACpB;GACA,KAAK,QAAQ,IAAI,iCACf,OAAO,QACP,OAAO,QACP,OAAO,WACT;EACF,OAAO,IAAI,eAAe,QAAQ;GAChC,KAAK,WAAW,iBAAiB,OAAO,OAAO;GAC/C,KAAK,QAAQ,IAAI,oCAAoC,KAAK,QAAQ;EACpE,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;GACJ,IAAI;IACF,MAAM,OAAO,KAAK,MAAM,IAAI;IAC5B,IAAI,OAAO,MAAM,YAAY,YAAY,KAAK,QAAQ,SAAS,GAC7D,UAAU,KAAK;GAEnB,QAAQ,CAAC;GACT,MAAM,IAAI,cACR,WAAW,8BAA8B,SAAS,OAAO,IAAI,QAC7D,SAAS,MACX;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
+ {"version":3,"file":"AssistantCloudAPI.js","names":[],"sources":["../src/AssistantCloudAPI.ts"],"sourcesContent":["import {\n type AssistantCloudAuthStrategy,\n AssistantCloudJWTAuthStrategy,\n AssistantCloudAPIKeyAuthStrategy,\n AssistantCloudAnonymousAuthStrategy,\n normalizeBaseUrl,\n} from \"./AssistantCloudAuthStrategy\";\nimport type { AssistantCloudRunReport } from \"./AssistantCloudRuns\";\nimport { ASSISTANT_CLOUD_VERSION } from \"./version\";\n\nexport type SdkIdentity = {\n name: string;\n version: string;\n};\n\nexport type AssistantCloudTelemetryConfig = {\n /**\n * Enables Assistant Cloud telemetry. Defaults to `true`. Set to `false` to\n * disable both run reports and engagement events.\n */\n enabled?: boolean;\n /**\n * Enables Assistant Cloud engagement events. Defaults to `true` when\n * telemetry is enabled. Set to `false` to keep run reports while disabling\n * engagement events.\n */\n events?: boolean;\n release?: string;\n environment?: string;\n tags?: string[];\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. Reports can also include assistant output,\n * tool arguments and results, errors, and metadata, which may contain\n * sensitive content. Use `beforeReport` to redact or drop reports, or\n * `telemetry: false` to disable reporting.\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 public readonly status: number;\n public readonly code?: string;\n public readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n status: number,\n code?: string,\n details?: Record<string, unknown>,\n ) {\n super(message);\n this.status = status;\n if (code !== undefined) this.code = code;\n if (details !== undefined) this.details = details;\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 keepalive?: boolean | undefined;\n};\n\nconst HEADER_TOKEN = /^[\\x21-\\x7e]+$/;\n\nexport class AssistantCloudAPI {\n public _auth: AssistantCloudAuthStrategy;\n public _baseUrl;\n public readonly registerSdk: (sdk: SdkIdentity) => void;\n public readonly sdkHeader: () => string;\n\n constructor(config: AssistantCloudConfig) {\n const sdks = new Map<string, SdkIdentity>();\n this.registerSdk = (sdk) => {\n const name = sdk.name.trim();\n const version = sdk.version.trim();\n if (!HEADER_TOKEN.test(name) || !HEADER_TOKEN.test(version)) return;\n sdks.set(`${name}/${version}`, { name, version });\n };\n this.sdkHeader = () =>\n [\n `assistant-cloud/${ASSISTANT_CLOUD_VERSION}`,\n ...Array.from(\n sdks.values(),\n ({ name, version }) => `${name}/${version}`,\n ),\n ].join(\" \");\n\n if (\"authToken\" in config) {\n this._baseUrl = normalizeBaseUrl(config.baseUrl);\n this._auth = new AssistantCloudJWTAuthStrategy(config.authToken);\n } else if (\"apiKey\" in config) {\n this._baseUrl = normalizeBaseUrl(\n config.baseUrl ?? \"https://backend.assistant-api.com\",\n );\n this._auth = new AssistantCloudAPIKeyAuthStrategy(\n config.apiKey,\n config.userId,\n config.workspaceId,\n );\n } else if (\"anonymous\" in config) {\n this._baseUrl = normalizeBaseUrl(config.baseUrl);\n this._auth = new AssistantCloudAnonymousAuthStrategy(this._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 \"Aui-Sdk\": this.sdkHeader(),\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 ...(options.keepalive ? { keepalive: true } : {}),\n });\n\n this._auth.readAuthHeaders(response.headers);\n\n if (!response.ok) {\n const text = await response.text();\n let message: string | undefined;\n let code: string | undefined;\n let details: Record<string, unknown> | undefined;\n try {\n const body = JSON.parse(text) as unknown;\n if (typeof body === \"object\" && body !== null && !Array.isArray(body)) {\n const record = body as Record<string, unknown>;\n if (typeof record.message === \"string\" && record.message.length > 0) {\n message = record.message;\n }\n if (typeof record.error === \"string\") {\n code = record.error;\n details = { ...record };\n delete details.error;\n }\n }\n } catch {}\n throw new CloudAPIError(\n message ?? `Request failed with status ${response.status}, ${text}`,\n response.status,\n code,\n details,\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":"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"}
@@ -22,6 +22,9 @@ declare class AssistantCloudAPIKeyAuthStrategy implements AssistantCloudAuthStra
22
22
  getAuthHeaders(): Promise<Record<string, string>>;
23
23
  readAuthHeaders(): void;
24
24
  }
25
+ declare const normalizeBaseUrl: (baseUrl: string) => string;
26
+ /** The refresh token of the anonymous identity this browser holds for `baseUrl`, or null when it has none. */
27
+ declare const readAnonymousRefreshToken: (baseUrl: string) => string | null;
25
28
  declare class AssistantCloudAnonymousAuthStrategy implements AssistantCloudAuthStrategy {
26
29
  readonly strategy = "anon";
27
30
  private baseUrl;
@@ -31,5 +34,5 @@ declare class AssistantCloudAnonymousAuthStrategy implements AssistantCloudAuthS
31
34
  readAuthHeaders(headers: Headers): void;
32
35
  }
33
36
  //#endregion
34
- export { AssistantCloudAPIKeyAuthStrategy, AssistantCloudAnonymousAuthStrategy, AssistantCloudAuthStrategy, AssistantCloudJWTAuthStrategy };
37
+ export { AssistantCloudAPIKeyAuthStrategy, AssistantCloudAnonymousAuthStrategy, AssistantCloudAuthStrategy, AssistantCloudJWTAuthStrategy, normalizeBaseUrl, readAnonymousRefreshToken };
35
38
  //# sourceMappingURL=AssistantCloudAuthStrategy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantCloudAuthStrategy.d.ts","names":[],"sources":["../src/AssistantCloudAuthStrategy.ts"],"mappings":";KAkCY;WACD;EACT,kBAAkB,QAAQ;EAC1B,gBAAgB,SAAS;;cAmFd,yCAAyC;;WACpC;UAER;UACA;UACA;EAGI,YAAA,yBAAyB;EAIxB,kBAAkB,QAAQ;UA0BzB;EAUP,gBAAgB,SAAS;;cAcrB,4CAA4C;;WACvC;EAMJ,YAAA,gBAAgB,gBAAgB;EAM/B,kBAAkB,QAAQ;EAQhC;;cAwHI,+CAA+C;WAC1C;UAER;UACA;EAEI,YAAA;EAwFC,kBAAkB,QAAQ;EAIhC,gBAAgB,SAAS"}
1
+ {"version":3,"file":"AssistantCloudAuthStrategy.d.ts","names":[],"sources":["../src/AssistantCloudAuthStrategy.ts"],"mappings":";KAkCY;WACD;EACT,kBAAkB,QAAQ;EAC1B,gBAAgB,SAAS;;cAmFd,yCAAyC;;WACpC;UAER;UACA;UACA;EAGI,YAAA,yBAAyB;EAIxB,kBAAkB,QAAQ;UA0BzB;EAWP,gBAAgB,SAAS;;cAerB,4CAA4C;;WACvC;EAMJ,YAAA,gBAAgB,gBAAgB;EAM/B,kBAAkB,QAAQ;EAQhC;;cAuDI,mBAAoB;;cAMpB,4BAA6B;cAwE7B,+CAA+C;WAC1C;UAER;UACA;EAEI,YAAA;EAwFC,kBAAkB,QAAQ;EAIhC,gBAAgB,SAAS"}
@@ -79,8 +79,9 @@ var AssistantCloudJWTAuthStrategy = class {
79
79
  async fetchAuthHeaders() {
80
80
  const token = await this.#authTokenCallback();
81
81
  if (!token) return false;
82
+ const tokenExpiry = getJwtExpiry(token);
82
83
  this.cachedToken = token;
83
- this.tokenExpiry = getJwtExpiry(token);
84
+ this.tokenExpiry = tokenExpiry;
84
85
  return { Authorization: `Bearer ${token}` };
85
86
  }
86
87
  readAuthHeaders(headers) {
@@ -88,8 +89,9 @@ var AssistantCloudJWTAuthStrategy = class {
88
89
  if (!authHeader) return;
89
90
  const [scheme, token] = authHeader.split(" ");
90
91
  if (scheme !== "Bearer" || !token) throw new Error("Invalid auth header received");
92
+ const tokenExpiry = getJwtExpiry(token);
91
93
  this.cachedToken = token;
92
- this.tokenExpiry = getJwtExpiry(token);
94
+ this.tokenExpiry = tokenExpiry;
93
95
  }
94
96
  };
95
97
  var AssistantCloudAPIKeyAuthStrategy = class {
@@ -152,6 +154,16 @@ const readRefreshToken = (baseUrl) => {
152
154
  return;
153
155
  }
154
156
  };
157
+ const normalizeBaseUrl = (baseUrl) => {
158
+ if (!baseUrl || !baseUrl.endsWith("/")) return baseUrl;
159
+ return baseUrl.slice(0, -1);
160
+ };
161
+ /** The refresh token of the anonymous identity this browser holds for `baseUrl`, or null when it has none. */
162
+ const readAnonymousRefreshToken = (baseUrl) => {
163
+ const refreshToken = readRefreshToken(normalizeBaseUrl(baseUrl));
164
+ if (!refreshToken) return null;
165
+ return new Date(refreshToken.expires_at).getTime() - Date.now() > 3e4 ? refreshToken.token : null;
166
+ };
155
167
  const writeRefreshToken = (baseUrl, refreshToken) => {
156
168
  const storage = getLocalStorage();
157
169
  if (!storage) return;
@@ -239,6 +251,6 @@ var AssistantCloudAnonymousAuthStrategy = class {
239
251
  }
240
252
  };
241
253
  //#endregion
242
- export { AssistantCloudAPIKeyAuthStrategy, AssistantCloudAnonymousAuthStrategy, AssistantCloudJWTAuthStrategy };
254
+ export { AssistantCloudAPIKeyAuthStrategy, AssistantCloudAnonymousAuthStrategy, AssistantCloudJWTAuthStrategy, normalizeBaseUrl, readAnonymousRefreshToken };
243
255
 
244
256
  //# sourceMappingURL=AssistantCloudAuthStrategy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantCloudAuthStrategy.js","names":[],"sources":["../src/AssistantCloudAuthStrategy.ts"],"sourcesContent":["import {\n CloudResponseError,\n readCloudRecord,\n readCloudString,\n} from \"./cloudResponse\";\n\nconst AUTH_TOKEN_REQUEST_TIMEOUT_MS = 30_000;\n\nconst withAuthTokenDeadline = async <T>(\n operation: string,\n run: (signal: AbortSignal) => Promise<T>,\n): Promise<T> => {\n const controller = new AbortController();\n let timedOut = false;\n const timeout = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, AUTH_TOKEN_REQUEST_TIMEOUT_MS);\n\n try {\n return await run(controller.signal);\n } catch (error) {\n if (timedOut) {\n throw new Error(\n `Assistant Cloud ${operation} timed out after ${AUTH_TOKEN_REQUEST_TIMEOUT_MS}ms`,\n { cause: error },\n );\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n};\n\nexport 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\ntype RefreshToken = {\n token: string;\n expires_at: string;\n};\n\nconst readNonEmptyCloudString = (value: unknown, field: string): string => {\n const result = readCloudString(value, field);\n if (result.length === 0) {\n throw new CloudResponseError(\n `Invalid Assistant Cloud response for \"${field}\": expected a non-empty string`,\n );\n }\n return result;\n};\n\nconst readRefreshTokenResponse = (\n value: unknown,\n field: string,\n): RefreshToken => {\n const refreshToken = readCloudRecord(value, field);\n return {\n token: readNonEmptyCloudString(refreshToken.token, `${field}.token`),\n expires_at: readNonEmptyCloudString(\n refreshToken.expires_at,\n `${field}.expires_at`,\n ),\n };\n};\n\nconst readAuthTokenResponse = async (\n response: Response,\n field: string,\n): Promise<{ data: Record<string, unknown>; accessToken: string }> => {\n let value: unknown;\n try {\n value = await response.json();\n } catch {\n throw new CloudResponseError(\n `Invalid Assistant Cloud response for \"${field}\": expected valid JSON`,\n );\n }\n\n const data = readCloudRecord(value, field);\n const accessToken = readNonEmptyCloudString(\n data.access_token,\n `${field}.access_token`,\n );\n return { data, accessToken };\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 private tokenRequest: Promise<Record<string, string> | false> | 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 if (!this.tokenRequest) {\n this.tokenRequest = this.fetchAuthHeaders();\n }\n\n const tokenRequest = this.tokenRequest;\n try {\n return await tokenRequest;\n } finally {\n if (this.tokenRequest === tokenRequest) {\n this.tokenRequest = null;\n }\n }\n }\n\n private async fetchAuthHeaders(): Promise<Record<string, string> | false> {\n const token = await this.#authTokenCallback();\n if (!token) return false;\n\n this.cachedToken = token;\n this.tokenExpiry = getJwtExpiry(token);\n\n return { Authorization: `Bearer ${token}` };\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 LEGACY_AUI_REFRESH_TOKEN_NAME = \"aui:refresh_token\";\n\nconst getRefreshTokenName = (baseUrl: string): string =>\n `${LEGACY_AUI_REFRESH_TOKEN_NAME}:${baseUrl}`;\n\nconst removeLegacyRefreshToken = (storage: Storage): void => {\n try {\n storage.removeItem(LEGACY_AUI_REFRESH_TOKEN_NAME);\n } catch {}\n};\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 = (baseUrl: string): RefreshToken | undefined => {\n const storage = getLocalStorage();\n if (!storage) return undefined;\n try {\n const name = getRefreshTokenName(baseUrl);\n const value = storage.getItem(name);\n if (value) {\n removeLegacyRefreshToken(storage);\n return JSON.parse(value) as RefreshToken;\n }\n\n const legacyValue = storage.getItem(LEGACY_AUI_REFRESH_TOKEN_NAME);\n if (!legacyValue) return undefined;\n\n let refreshToken: RefreshToken;\n try {\n refreshToken = JSON.parse(legacyValue) as RefreshToken;\n } catch {\n removeLegacyRefreshToken(storage);\n return undefined;\n }\n\n storage.setItem(name, legacyValue);\n removeLegacyRefreshToken(storage);\n return refreshToken;\n } catch {\n return undefined;\n }\n};\n\nconst writeRefreshToken = (\n baseUrl: string,\n refreshToken: RefreshToken,\n): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.setItem(getRefreshTokenName(baseUrl), JSON.stringify(refreshToken));\n } catch {}\n};\n\nconst removeRefreshToken = (baseUrl: string): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.removeItem(getRefreshTokenName(baseUrl));\n } catch {}\n};\n\n// In-flight sharing follows refresh-token storage scope to isolate server requests.\nconst anonymousAuthTokenRequests = new WeakMap<\n Storage,\n Map<string, Promise<string | null>>\n>();\n\nconst getWebLockManager = (): LockManager | null => {\n if (!(\"navigator\" in globalThis)) return null;\n return (\n (globalThis as { navigator?: { locks?: LockManager } }).navigator?.locks ??\n null\n );\n};\n\nconst getAnonymousAuthLockName = (baseUrl: string): string =>\n `assistant-cloud:anonymous-auth:${baseUrl}`;\n\nconst getSharedAnonymousAuthToken = (\n baseUrl: string,\n requestToken: () => Promise<string | null>,\n): Promise<string | null> => {\n const storage = getLocalStorage();\n if (!storage) return requestToken();\n\n let storageRequests = anonymousAuthTokenRequests.get(storage);\n if (!storageRequests) {\n storageRequests = new Map();\n anonymousAuthTokenRequests.set(storage, storageRequests);\n }\n\n const activeRequest = storageRequests.get(baseUrl);\n if (activeRequest) return activeRequest;\n\n const locks = getWebLockManager();\n const request = locks\n ? locks.request(getAnonymousAuthLockName(baseUrl), requestToken)\n : requestToken();\n const sharedRequest = request.finally(() => {\n if (storageRequests.get(baseUrl) === sharedRequest) {\n storageRequests.delete(baseUrl);\n }\n });\n storageRequests.set(baseUrl, sharedRequest);\n return sharedRequest;\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 const requestAuthToken = async (): Promise<string | null> => {\n const currentTime = Date.now();\n const storedRefreshToken = readRefreshToken(this.baseUrl);\n\n if (storedRefreshToken) {\n const refreshExpiry = new Date(storedRefreshToken.expires_at).getTime();\n if (refreshExpiry - currentTime > 30 * 1000) {\n const refreshedAccessToken = await withAuthTokenDeadline(\n \"refresh token request\",\n async (signal) => {\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({\n refresh_token: storedRefreshToken.token,\n }),\n signal,\n },\n );\n\n if (response.ok) {\n const { data, accessToken } = await readAuthTokenResponse(\n response,\n \"refresh auth token response\",\n );\n if (data.refresh_token != null) {\n writeRefreshToken(\n this.baseUrl,\n readRefreshTokenResponse(\n data.refresh_token,\n \"refresh auth token response.refresh_token\",\n ),\n );\n }\n return accessToken;\n }\n\n if (response.status === 429 || response.status >= 500) {\n throw new Error(\n `Assistant Cloud token refresh failed with status ${response.status}`,\n );\n }\n\n return null;\n },\n );\n if (refreshedAccessToken !== null) return refreshedAccessToken;\n } else {\n removeRefreshToken(this.baseUrl);\n }\n }\n\n // No valid refresh token; request a new anonymous token\n return withAuthTokenDeadline(\n \"anonymous token request\",\n async (signal) => {\n const response = await fetch(\n `${this.baseUrl}/v1/auth/tokens/anonymous`,\n { method: \"POST\", signal },\n );\n\n if (!response.ok) return null;\n\n const { data, accessToken } = await readAuthTokenResponse(\n response,\n \"anonymous auth token response\",\n );\n\n writeRefreshToken(\n this.baseUrl,\n readRefreshTokenResponse(\n data.refresh_token,\n \"anonymous auth token response.refresh_token\",\n ),\n );\n return accessToken;\n },\n );\n };\n this.jwtStrategy = new AssistantCloudJWTAuthStrategy(() =>\n getSharedAnonymousAuthToken(this.baseUrl, requestAuthToken),\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
+ {"version":3,"file":"AssistantCloudAuthStrategy.js","names":[],"sources":["../src/AssistantCloudAuthStrategy.ts"],"sourcesContent":["import {\n CloudResponseError,\n readCloudRecord,\n readCloudString,\n} from \"./cloudResponse\";\n\nconst AUTH_TOKEN_REQUEST_TIMEOUT_MS = 30_000;\n\nconst withAuthTokenDeadline = async <T>(\n operation: string,\n run: (signal: AbortSignal) => Promise<T>,\n): Promise<T> => {\n const controller = new AbortController();\n let timedOut = false;\n const timeout = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, AUTH_TOKEN_REQUEST_TIMEOUT_MS);\n\n try {\n return await run(controller.signal);\n } catch (error) {\n if (timedOut) {\n throw new Error(\n `Assistant Cloud ${operation} timed out after ${AUTH_TOKEN_REQUEST_TIMEOUT_MS}ms`,\n { cause: error },\n );\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n};\n\nexport 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\ntype RefreshToken = {\n token: string;\n expires_at: string;\n};\n\nconst readNonEmptyCloudString = (value: unknown, field: string): string => {\n const result = readCloudString(value, field);\n if (result.length === 0) {\n throw new CloudResponseError(\n `Invalid Assistant Cloud response for \"${field}\": expected a non-empty string`,\n );\n }\n return result;\n};\n\nconst readRefreshTokenResponse = (\n value: unknown,\n field: string,\n): RefreshToken => {\n const refreshToken = readCloudRecord(value, field);\n return {\n token: readNonEmptyCloudString(refreshToken.token, `${field}.token`),\n expires_at: readNonEmptyCloudString(\n refreshToken.expires_at,\n `${field}.expires_at`,\n ),\n };\n};\n\nconst readAuthTokenResponse = async (\n response: Response,\n field: string,\n): Promise<{ data: Record<string, unknown>; accessToken: string }> => {\n let value: unknown;\n try {\n value = await response.json();\n } catch {\n throw new CloudResponseError(\n `Invalid Assistant Cloud response for \"${field}\": expected valid JSON`,\n );\n }\n\n const data = readCloudRecord(value, field);\n const accessToken = readNonEmptyCloudString(\n data.access_token,\n `${field}.access_token`,\n );\n return { data, accessToken };\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 private tokenRequest: Promise<Record<string, string> | false> | 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 if (!this.tokenRequest) {\n this.tokenRequest = this.fetchAuthHeaders();\n }\n\n const tokenRequest = this.tokenRequest;\n try {\n return await tokenRequest;\n } finally {\n if (this.tokenRequest === tokenRequest) {\n this.tokenRequest = null;\n }\n }\n }\n\n private async fetchAuthHeaders(): Promise<Record<string, string> | false> {\n const token = await this.#authTokenCallback();\n if (!token) return false;\n\n const tokenExpiry = getJwtExpiry(token);\n this.cachedToken = token;\n this.tokenExpiry = tokenExpiry;\n\n return { Authorization: `Bearer ${token}` };\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 const tokenExpiry = getJwtExpiry(token);\n this.cachedToken = token;\n this.tokenExpiry = tokenExpiry;\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 LEGACY_AUI_REFRESH_TOKEN_NAME = \"aui:refresh_token\";\n\nconst getRefreshTokenName = (baseUrl: string): string =>\n `${LEGACY_AUI_REFRESH_TOKEN_NAME}:${baseUrl}`;\n\nconst removeLegacyRefreshToken = (storage: Storage): void => {\n try {\n storage.removeItem(LEGACY_AUI_REFRESH_TOKEN_NAME);\n } catch {}\n};\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 = (baseUrl: string): RefreshToken | undefined => {\n const storage = getLocalStorage();\n if (!storage) return undefined;\n try {\n const name = getRefreshTokenName(baseUrl);\n const value = storage.getItem(name);\n if (value) {\n removeLegacyRefreshToken(storage);\n return JSON.parse(value) as RefreshToken;\n }\n\n const legacyValue = storage.getItem(LEGACY_AUI_REFRESH_TOKEN_NAME);\n if (!legacyValue) return undefined;\n\n let refreshToken: RefreshToken;\n try {\n refreshToken = JSON.parse(legacyValue) as RefreshToken;\n } catch {\n removeLegacyRefreshToken(storage);\n return undefined;\n }\n\n storage.setItem(name, legacyValue);\n removeLegacyRefreshToken(storage);\n return refreshToken;\n } catch {\n return undefined;\n }\n};\n\nexport const normalizeBaseUrl = (baseUrl: string): string => {\n if (!baseUrl || !baseUrl.endsWith(\"/\")) return baseUrl;\n return baseUrl.slice(0, -1);\n};\n\n/** The refresh token of the anonymous identity this browser holds for `baseUrl`, or null when it has none. */\nexport const readAnonymousRefreshToken = (baseUrl: string): string | null => {\n const refreshToken = readRefreshToken(normalizeBaseUrl(baseUrl));\n if (!refreshToken) return null;\n const refreshExpiry = new Date(refreshToken.expires_at).getTime();\n return refreshExpiry - Date.now() > 30 * 1000 ? refreshToken.token : null;\n};\n\nconst writeRefreshToken = (\n baseUrl: string,\n refreshToken: RefreshToken,\n): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.setItem(getRefreshTokenName(baseUrl), JSON.stringify(refreshToken));\n } catch {}\n};\n\nconst removeRefreshToken = (baseUrl: string): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.removeItem(getRefreshTokenName(baseUrl));\n } catch {}\n};\n\n// In-flight sharing follows refresh-token storage scope to isolate server requests.\nconst anonymousAuthTokenRequests = new WeakMap<\n Storage,\n Map<string, Promise<string | null>>\n>();\n\nconst getWebLockManager = (): LockManager | null => {\n if (!(\"navigator\" in globalThis)) return null;\n return (\n (globalThis as { navigator?: { locks?: LockManager } }).navigator?.locks ??\n null\n );\n};\n\nconst getAnonymousAuthLockName = (baseUrl: string): string =>\n `assistant-cloud:anonymous-auth:${baseUrl}`;\n\nconst getSharedAnonymousAuthToken = (\n baseUrl: string,\n requestToken: () => Promise<string | null>,\n): Promise<string | null> => {\n const storage = getLocalStorage();\n if (!storage) return requestToken();\n\n let storageRequests = anonymousAuthTokenRequests.get(storage);\n if (!storageRequests) {\n storageRequests = new Map();\n anonymousAuthTokenRequests.set(storage, storageRequests);\n }\n\n const activeRequest = storageRequests.get(baseUrl);\n if (activeRequest) return activeRequest;\n\n const locks = getWebLockManager();\n const request = locks\n ? locks.request(getAnonymousAuthLockName(baseUrl), requestToken)\n : requestToken();\n const sharedRequest = request.finally(() => {\n if (storageRequests.get(baseUrl) === sharedRequest) {\n storageRequests.delete(baseUrl);\n }\n });\n storageRequests.set(baseUrl, sharedRequest);\n return sharedRequest;\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 const requestAuthToken = async (): Promise<string | null> => {\n const currentTime = Date.now();\n const storedRefreshToken = readRefreshToken(this.baseUrl);\n\n if (storedRefreshToken) {\n const refreshExpiry = new Date(storedRefreshToken.expires_at).getTime();\n if (refreshExpiry - currentTime > 30 * 1000) {\n const refreshedAccessToken = await withAuthTokenDeadline(\n \"refresh token request\",\n async (signal) => {\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({\n refresh_token: storedRefreshToken.token,\n }),\n signal,\n },\n );\n\n if (response.ok) {\n const { data, accessToken } = await readAuthTokenResponse(\n response,\n \"refresh auth token response\",\n );\n if (data.refresh_token != null) {\n writeRefreshToken(\n this.baseUrl,\n readRefreshTokenResponse(\n data.refresh_token,\n \"refresh auth token response.refresh_token\",\n ),\n );\n }\n return accessToken;\n }\n\n if (response.status === 429 || response.status >= 500) {\n throw new Error(\n `Assistant Cloud token refresh failed with status ${response.status}`,\n );\n }\n\n return null;\n },\n );\n if (refreshedAccessToken !== null) return refreshedAccessToken;\n } else {\n removeRefreshToken(this.baseUrl);\n }\n }\n\n // No valid refresh token; request a new anonymous token\n return withAuthTokenDeadline(\n \"anonymous token request\",\n async (signal) => {\n const response = await fetch(\n `${this.baseUrl}/v1/auth/tokens/anonymous`,\n { method: \"POST\", signal },\n );\n\n if (!response.ok) return null;\n\n const { data, accessToken } = await readAuthTokenResponse(\n response,\n \"anonymous auth token response\",\n );\n\n writeRefreshToken(\n this.baseUrl,\n readRefreshTokenResponse(\n data.refresh_token,\n \"anonymous auth token response.refresh_token\",\n ),\n );\n return accessToken;\n },\n );\n };\n this.jwtStrategy = new AssistantCloudJWTAuthStrategy(() =>\n getSharedAnonymousAuthToken(this.baseUrl, requestAuthToken),\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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"}
@@ -0,0 +1,32 @@
1
+ import { AssistantCloudAPI } from "./AssistantCloudAPI.js";
2
+ //#region src/AssistantCloudEvents.d.ts
3
+ type AssistantCloudEventKind = "message_sent" | "message_edited" | "run_stopped" | "message_regenerated" | "message_copied" | "branch_switched" | "suggestions_shown" | "suggestion_clicked" | "attachment_added" | "attachment_failed" | "thread_switched" | "tool_approved" | "tool_rejected" | "speech_started" | "voice_started" | "error_shown";
4
+ type AssistantCloudEvent = {
5
+ kind: AssistantCloudEventKind;
6
+ thread_id?: string | undefined;
7
+ message_id?: string | undefined;
8
+ run_id?: string | undefined;
9
+ value?: number | undefined;
10
+ props?: Readonly<Record<string, string | number | boolean>> | undefined;
11
+ };
12
+ declare class AssistantCloudEvents {
13
+ private buffer;
14
+ private timer;
15
+ private flushing;
16
+ private readonly cloud;
17
+ private readonly isEnabled;
18
+ private listening;
19
+ constructor(cloud: AssistantCloudAPI, isEnabled: () => boolean);
20
+ track(event: AssistantCloudEvent): void;
21
+ private listen;
22
+ private unlisten;
23
+ dispose(): void;
24
+ private onVisibilityChange;
25
+ private flush;
26
+ private flushPending;
27
+ private scheduleFlush;
28
+ private clearFlushTimer;
29
+ }
30
+ //#endregion
31
+ export { AssistantCloudEvent, AssistantCloudEventKind, AssistantCloudEvents };
32
+ //# sourceMappingURL=AssistantCloudEvents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssistantCloudEvents.d.ts","names":[],"sources":["../src/AssistantCloudEvents.ts"],"mappings":";;KAEY;KAkBA;EACV,MAAM;EACN;EACA;EACA;EACA;EACA,QAAQ,SAAS;;cAON;UACH;UACA;UACA;mBAES;mBACA;UAET;EAEI,YAAA,OAAO,mBAAmB;EAK/B,MAAM,OAAO;UAaZ;UAaA;EAOD;UAMC;UAMA;UAyBM;UAkBN;UAQA"}