@axiom-lattice/client-sdk 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/__tests__/capability-bundles.test.d.ts +2 -0
  2. package/dist/__tests__/capability-bundles.test.d.ts.map +1 -0
  3. package/dist/__tests__/capability-bundles.test.js +143 -0
  4. package/dist/__tests__/capability-bundles.test.js.map +1 -0
  5. package/dist/__tests__/project-rooms.test.d.ts +2 -0
  6. package/dist/__tests__/project-rooms.test.d.ts.map +1 -0
  7. package/dist/__tests__/project-rooms.test.js +144 -0
  8. package/dist/__tests__/project-rooms.test.js.map +1 -0
  9. package/dist/__tests__/sse-parser.test.d.ts +2 -0
  10. package/dist/__tests__/sse-parser.test.d.ts.map +1 -0
  11. package/dist/__tests__/sse-parser.test.js +16 -0
  12. package/dist/__tests__/sse-parser.test.js.map +1 -0
  13. package/dist/abstract-client.d.ts +70 -1
  14. package/dist/abstract-client.d.ts.map +1 -1
  15. package/dist/abstract-client.js +98 -0
  16. package/dist/abstract-client.js.map +1 -1
  17. package/dist/client.d.ts +2 -0
  18. package/dist/client.d.ts.map +1 -1
  19. package/dist/client.js +17 -134
  20. package/dist/client.js.map +1 -1
  21. package/dist/index.d.ts +252 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +574 -138
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +572 -138
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/project-rooms.d.ts +152 -0
  28. package/dist/project-rooms.d.ts.map +1 -0
  29. package/dist/project-rooms.js +240 -0
  30. package/dist/project-rooms.js.map +1 -0
  31. package/dist/sse-parser.d.ts +18 -0
  32. package/dist/sse-parser.d.ts.map +1 -0
  33. package/dist/sse-parser.js +119 -0
  34. package/dist/sse-parser.js.map +1 -0
  35. package/dist/types.d.ts +20 -2
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js.map +1 -1
  38. package/dist/wechat-client.d.ts +11 -0
  39. package/dist/wechat-client.d.ts.map +1 -1
  40. package/dist/wechat-client.js +29 -1
  41. package/dist/wechat-client.js.map +1 -1
  42. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -913,8 +913,8 @@ var require_encoding = __commonJS({
913
913
  }
914
914
  return serializeStream.call(this, output);
915
915
  };
916
- function TextEncoder(label, options) {
917
- if (!(this instanceof TextEncoder))
916
+ function TextEncoder2(label, options) {
917
+ if (!(this instanceof TextEncoder2))
918
918
  throw TypeError("Called as a function. Did you forget 'new'?");
919
919
  options = ToDictionary(options);
920
920
  this._encoding = null;
@@ -942,14 +942,14 @@ var require_encoding = __commonJS({
942
942
  return enc;
943
943
  }
944
944
  if (Object.defineProperty) {
945
- Object.defineProperty(TextEncoder.prototype, "encoding", {
945
+ Object.defineProperty(TextEncoder2.prototype, "encoding", {
946
946
  /** @this {TextEncoder} */
947
947
  get: function() {
948
948
  return this._encoding.name.toLowerCase();
949
949
  }
950
950
  });
951
951
  }
952
- TextEncoder.prototype.encode = function encode(opt_string, options) {
952
+ TextEncoder2.prototype.encode = function encode2(opt_string, options) {
953
953
  opt_string = opt_string === void 0 ? "" : String(opt_string);
954
954
  options = ToDictionary(options);
955
955
  if (!this._do_not_flush)
@@ -1805,7 +1805,7 @@ var require_encoding = __commonJS({
1805
1805
  return new XUserDefinedDecoder(options);
1806
1806
  };
1807
1807
  if (!global["TextEncoder"])
1808
- global["TextEncoder"] = TextEncoder;
1808
+ global["TextEncoder"] = TextEncoder2;
1809
1809
  if (!global["TextDecoder"])
1810
1810
  global["TextDecoder"] = TextDecoder2;
1811
1811
  if (typeof module !== "undefined" && module.exports) {
@@ -2200,6 +2200,127 @@ var AbstractClient = class {
2200
2200
  return response.data;
2201
2201
  }
2202
2202
  };
2203
+ /** Capability bundle namespace for managing tenant-scoped bundles. */
2204
+ this.capabilityBundles = {
2205
+ /**
2206
+ * List all capability bundles visible to the current tenant.
2207
+ * @returns The tenant's capability bundles, unwrapped from the API response.
2208
+ */
2209
+ list: async () => {
2210
+ const response = await this.makeRequest(
2211
+ "/api/capability-bundles"
2212
+ );
2213
+ return response.data;
2214
+ },
2215
+ /**
2216
+ * List valid bundles together with safe invalid-record summaries.
2217
+ * @returns Inventory suitable for management and remediation workflows.
2218
+ */
2219
+ listInventory: async () => {
2220
+ const response = await this.makeRequest("/api/capability-bundles");
2221
+ return { bundles: response.data, errors: response.errors ?? [] };
2222
+ },
2223
+ /**
2224
+ * Get one capability bundle by identifier.
2225
+ * @param bundleId - Capability bundle identifier.
2226
+ * @returns The requested capability bundle.
2227
+ */
2228
+ get: async (bundleId) => {
2229
+ const response = await this.makeRequest(
2230
+ `/api/capability-bundles/${encodeURIComponent(bundleId)}`
2231
+ );
2232
+ return response.data;
2233
+ },
2234
+ /**
2235
+ * Create a capability bundle for the current tenant.
2236
+ * @param input - Bundle name, optional description, and capabilities. The server generates the stable key.
2237
+ * @returns The created capability bundle.
2238
+ */
2239
+ create: async (input) => {
2240
+ const response = await this.makeRequest(
2241
+ "/api/capability-bundles",
2242
+ { method: "POST", body: input }
2243
+ );
2244
+ return response.data;
2245
+ },
2246
+ /**
2247
+ * Update a capability bundle for the current tenant.
2248
+ * @param bundleId - Capability bundle identifier.
2249
+ * @param input - The partial bundle fields and required expected revision to update.
2250
+ * @returns The updated capability bundle.
2251
+ */
2252
+ update: async (bundleId, input) => {
2253
+ const response = await this.makeRequest(
2254
+ `/api/capability-bundles/${encodeURIComponent(bundleId)}`,
2255
+ { method: "PUT", body: input }
2256
+ );
2257
+ return response.data;
2258
+ },
2259
+ /**
2260
+ * Delete a capability bundle when the backend permits deletion.
2261
+ * @param bundleId - Capability bundle identifier.
2262
+ * @returns A promise that resolves after the bundle is deleted.
2263
+ * @throws ApiError when the bundle is missing, in use, or the request fails.
2264
+ */
2265
+ delete: async (bundleId) => {
2266
+ await this.makeRequest(
2267
+ `/api/capability-bundles/${encodeURIComponent(bundleId)}`,
2268
+ { method: "DELETE" }
2269
+ );
2270
+ }
2271
+ };
2272
+ this.projects = {
2273
+ capabilities: {
2274
+ /**
2275
+ * Get a project's selected bundles and its persisted capability preview.
2276
+ * @param projectId - Project identifier.
2277
+ * @returns The project, selected bundles, and preview resolved from persisted selections.
2278
+ */
2279
+ get: async (projectId) => {
2280
+ const response = await this.makeRequest(
2281
+ `/api/projects/${encodeURIComponent(projectId)}/capability-bundles`
2282
+ );
2283
+ return response.data;
2284
+ },
2285
+ /**
2286
+ * Replace a project's selected capability bundles.
2287
+ * @param projectId - Project identifier.
2288
+ * @param bundleIds - Ordered capability bundle identifiers to persist.
2289
+ * @returns The updated project, selected bundles, and persisted-selection preview.
2290
+ */
2291
+ update: async (projectId, bundleIds, expectedRevisions) => {
2292
+ const response = await this.makeRequest(
2293
+ `/api/projects/${encodeURIComponent(projectId)}/capability-bundles`,
2294
+ { method: "PUT", body: { bundleIds, expectedRevisions } }
2295
+ );
2296
+ return response.data;
2297
+ },
2298
+ /**
2299
+ * Preview the capability bundles currently persisted on a project.
2300
+ * @param projectId - Project identifier.
2301
+ * @returns The preview resolved from the project's persisted bundle selections.
2302
+ */
2303
+ preview: async (projectId) => {
2304
+ const response = await this.makeRequest(
2305
+ `/api/projects/${encodeURIComponent(projectId)}/capability-preview`
2306
+ );
2307
+ return response.data;
2308
+ },
2309
+ /**
2310
+ * Preview a draft bundle selection without changing the project.
2311
+ * @param projectId - Project identifier.
2312
+ * @param bundleIds - Ordered capability bundle identifiers to preview.
2313
+ * @returns The draft preview resolved from the supplied bundle IDs; no project state is changed.
2314
+ */
2315
+ previewWithBundles: async (projectId, bundleIds) => {
2316
+ const response = await this.makeRequest(
2317
+ `/api/projects/${encodeURIComponent(projectId)}/capability-preview`,
2318
+ { method: "POST", body: { bundleIds } }
2319
+ );
2320
+ return response.data;
2321
+ }
2322
+ }
2323
+ };
2203
2324
  /** Agent Web Apps namespace for managing React SDK publications. */
2204
2325
  this.webApps = {
2205
2326
  /**
@@ -2215,7 +2336,7 @@ var AbstractClient = class {
2215
2336
  const query = searchParams.toString();
2216
2337
  const response = await this.makeRequest(`/api/web-apps${query ? `?${query}` : ""}`);
2217
2338
  return {
2218
- records: response.data.records.map((record) => this.hydrateAgentWebApp(record)),
2339
+ records: response.data.records.map((record2) => this.hydrateAgentWebApp(record2)),
2219
2340
  total: response.data.total
2220
2341
  };
2221
2342
  },
@@ -2856,19 +2977,19 @@ var AbstractClient = class {
2856
2977
  if (!value || typeof value !== "object" || Array.isArray(value)) {
2857
2978
  throw new ApiError("Invalid Agent Web App response", 500, value);
2858
2979
  }
2859
- const record = value;
2980
+ const record2 = value;
2860
2981
  const hydrateDate = (field) => {
2861
- const raw = record[field];
2862
- const date = raw instanceof Date ? new Date(raw.getTime()) : new Date(
2982
+ const raw = record2[field];
2983
+ const date2 = raw instanceof Date ? new Date(raw.getTime()) : new Date(
2863
2984
  typeof raw === "string" || typeof raw === "number" ? raw : Number.NaN
2864
2985
  );
2865
- if (Number.isNaN(date.getTime())) {
2986
+ if (Number.isNaN(date2.getTime())) {
2866
2987
  throw new ApiError(`Invalid Agent Web App ${field}`, 500, value);
2867
2988
  }
2868
- return date;
2989
+ return date2;
2869
2990
  };
2870
2991
  return {
2871
- ...record,
2992
+ ...record2,
2872
2993
  createdAt: hydrateDate("createdAt"),
2873
2994
  updatedAt: hydrateDate("updatedAt")
2874
2995
  };
@@ -3308,6 +3429,398 @@ var ExportImportClient = class {
3308
3429
  }
3309
3430
  };
3310
3431
 
3432
+ // src/sse-parser.ts
3433
+ var SseParseError = class extends Error {
3434
+ constructor(message) {
3435
+ super(message);
3436
+ this.code = "INVALID_EVENT";
3437
+ this.name = "SseParseError";
3438
+ }
3439
+ };
3440
+ async function* parseSseBody(body, options = {}) {
3441
+ const maxLine = options.maxLineBytes ?? 64 * 1024;
3442
+ const maxEvent = options.maxEventBytes ?? 1024 * 1024;
3443
+ const maxDataLines = options.maxDataLines ?? 1024;
3444
+ const reader = body.getReader();
3445
+ const decoder = new TextDecoder();
3446
+ let buffer = "";
3447
+ let event = "";
3448
+ let id;
3449
+ let retry;
3450
+ let data = [];
3451
+ let bytes = 0;
3452
+ const dispatch = () => {
3453
+ if (data.length === 0) {
3454
+ event = "";
3455
+ id = void 0;
3456
+ retry = void 0;
3457
+ bytes = 0;
3458
+ return void 0;
3459
+ }
3460
+ let parsed;
3461
+ try {
3462
+ parsed = JSON.parse(data.join("\n"));
3463
+ } catch {
3464
+ throw new SseParseError("Invalid SSE JSON");
3465
+ }
3466
+ if (options.strictJsonObject && (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)))
3467
+ throw new SseParseError("SSE data must be an object");
3468
+ const result = { event, data: parsed, ...id === void 0 ? {} : { id }, ...retry === void 0 ? {} : { retry } };
3469
+ event = "";
3470
+ id = void 0;
3471
+ retry = void 0;
3472
+ data = [];
3473
+ bytes = 0;
3474
+ return result;
3475
+ };
3476
+ const processLine = (raw) => {
3477
+ const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
3478
+ if (new TextEncoder().encode(line).byteLength > maxLine)
3479
+ throw new SseParseError("SSE line is too large");
3480
+ if (line === "")
3481
+ return dispatch();
3482
+ if (line.startsWith(":"))
3483
+ return void 0;
3484
+ const separator = line.indexOf(":");
3485
+ const field = separator < 0 ? line : line.slice(0, separator);
3486
+ let value = separator < 0 ? "" : line.slice(separator + 1);
3487
+ if (value.startsWith(" "))
3488
+ value = value.slice(1);
3489
+ if (field === "event")
3490
+ event = value;
3491
+ else if (field === "data") {
3492
+ if (data.length >= maxDataLines)
3493
+ throw new SseParseError("Too many SSE data lines");
3494
+ data.push(value);
3495
+ bytes += new TextEncoder().encode(value).byteLength + (data.length === 1 ? 0 : 1);
3496
+ if (bytes > maxEvent)
3497
+ throw new SseParseError("SSE event is too large");
3498
+ } else if (field === "id")
3499
+ id = value;
3500
+ else if (field === "retry") {
3501
+ const parsed = Number(value);
3502
+ if (!Number.isInteger(parsed) || parsed < 0 || !Number.isFinite(parsed))
3503
+ throw new SseParseError("Invalid SSE retry");
3504
+ retry = parsed;
3505
+ }
3506
+ return void 0;
3507
+ };
3508
+ try {
3509
+ while (true) {
3510
+ const chunk = await reader.read();
3511
+ if (chunk.done) {
3512
+ buffer += decoder.decode();
3513
+ if (new TextEncoder().encode(buffer).byteLength > maxLine)
3514
+ throw new SseParseError("SSE line is too large");
3515
+ break;
3516
+ }
3517
+ buffer += decoder.decode(chunk.value, { stream: true });
3518
+ if (new TextEncoder().encode(buffer.slice(0, Math.max(0, findLineBreak(buffer) < 0 ? buffer.length : findLineBreak(buffer)))).byteLength > maxLine)
3519
+ throw new SseParseError("SSE line is too large");
3520
+ let index = findLineBreak(buffer);
3521
+ while (index >= 0) {
3522
+ if (buffer[index] === "\r" && index === buffer.length - 1)
3523
+ break;
3524
+ const frame2 = processLine(buffer.slice(0, index));
3525
+ buffer = buffer.slice(index + lineBreakLength(buffer, index));
3526
+ if (frame2)
3527
+ yield frame2;
3528
+ index = findLineBreak(buffer);
3529
+ }
3530
+ }
3531
+ if (buffer) {
3532
+ const frame2 = processLine(buffer);
3533
+ if (frame2)
3534
+ yield frame2;
3535
+ }
3536
+ const frame = processLine("");
3537
+ if (frame)
3538
+ yield frame;
3539
+ } finally {
3540
+ await reader.cancel().catch(() => void 0);
3541
+ reader.releaseLock();
3542
+ }
3543
+ }
3544
+ function findLineBreak(value) {
3545
+ const lf = value.indexOf("\n");
3546
+ const cr = value.indexOf("\r");
3547
+ if (lf < 0)
3548
+ return cr;
3549
+ if (cr < 0)
3550
+ return lf;
3551
+ return Math.min(lf, cr);
3552
+ }
3553
+ function lineBreakLength(value, index) {
3554
+ return value[index] === "\r" && value[index + 1] === "\n" ? 2 : 1;
3555
+ }
3556
+
3557
+ // src/project-rooms.ts
3558
+ var ProjectRoomClientError = class extends Error {
3559
+ constructor(message, status, code, retryable, details) {
3560
+ super(message);
3561
+ this.status = status;
3562
+ this.code = code;
3563
+ this.retryable = retryable;
3564
+ this.details = details;
3565
+ this.name = "ProjectRoomClientError";
3566
+ }
3567
+ };
3568
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3569
+ var date = (value, field) => {
3570
+ const result = value instanceof Date ? new Date(value.getTime()) : new Date(typeof value === "string" || typeof value === "number" ? value : Number.NaN);
3571
+ if (!Number.isFinite(result.getTime()))
3572
+ throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
3573
+ return result;
3574
+ };
3575
+ var requiredString = (record2, field) => {
3576
+ if (typeof record2[field] !== "string")
3577
+ throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
3578
+ return record2[field];
3579
+ };
3580
+ var oneOf = (value, values, field) => {
3581
+ if (typeof value !== "string" || !values.includes(value))
3582
+ throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
3583
+ return value;
3584
+ };
3585
+ var messageSources = ["user", "agent", "task", "routine", "system"];
3586
+ var humanRoles = ["owner", "admin", "member", "viewer"];
3587
+ var memberStatuses = ["active", "removed"];
3588
+ var botRoles = ["coordinator", "specialist"];
3589
+ var botStatuses = ["active", "paused", "removed"];
3590
+ var exactKeys = (row, required, optional = []) => {
3591
+ if (required.some((key) => !Object.prototype.hasOwnProperty.call(row, key)) || Object.keys(row).some((key) => !required.includes(key) && !optional.includes(key)))
3592
+ throw new ProjectRoomClientError("Invalid Project Room response", 500, "INVALID_RESPONSE", false);
3593
+ };
3594
+ var hydrateAuthor = (value) => {
3595
+ const row = record(value);
3596
+ const type = oneOf(row.type, ["human", "bot", "system"], "author.type");
3597
+ if (type === "human") {
3598
+ exactKeys(row, ["type", "userId"]);
3599
+ return { type, userId: requiredString(row, "userId") };
3600
+ }
3601
+ if (type === "bot")
3602
+ return { type, membershipId: requiredString(row, "membershipId") };
3603
+ if (Object.keys(row).some((key) => key !== "type"))
3604
+ throw new ProjectRoomClientError("Invalid author", 500, "INVALID_RESPONSE", false);
3605
+ return { type };
3606
+ };
3607
+ var hydrateMentions = (value) => {
3608
+ if (!Array.isArray(value))
3609
+ throw new ProjectRoomClientError("Invalid mentions", 500, "INVALID_RESPONSE", false);
3610
+ return value.map((entry) => {
3611
+ const row = record(entry);
3612
+ const type = oneOf(row.type, ["bot", "team"], "mention.type");
3613
+ if (type === "team") {
3614
+ if (Object.keys(row).length !== 1)
3615
+ throw new ProjectRoomClientError("Invalid mention", 500, "INVALID_RESPONSE", false);
3616
+ return { type };
3617
+ }
3618
+ return { type, membershipId: requiredString(row, "membershipId") };
3619
+ });
3620
+ };
3621
+ var record = (value) => {
3622
+ if (!isRecord(value))
3623
+ throw new ProjectRoomClientError("Invalid Project Room response", 500, "INVALID_RESPONSE", false);
3624
+ return value;
3625
+ };
3626
+ var hydrateRoom = (value) => {
3627
+ const row = record(value);
3628
+ exactKeys(row, ["id", "tenantId", "workspaceId", "projectId", "type", "name", "createdAt", "updatedAt"]);
3629
+ return { id: requiredString(row, "id"), tenantId: requiredString(row, "tenantId"), workspaceId: requiredString(row, "workspaceId"), projectId: requiredString(row, "projectId"), type: oneOf(row.type, ["main"], "type"), name: requiredString(row, "name"), createdAt: date(row.createdAt, "createdAt"), updatedAt: date(row.updatedAt, "updatedAt") };
3630
+ };
3631
+ var hydrateMessage = (value) => {
3632
+ const row = record(value);
3633
+ exactKeys(row, ["id", "roomId", "author", "content", "mentions", "source", "createdAt"], ["replyToMessageId"]);
3634
+ const content = record(row.content);
3635
+ if (oneOf(content.type, ["text"], "content.type") !== "text")
3636
+ throw new ProjectRoomClientError("Invalid content", 500, "INVALID_RESPONSE", false);
3637
+ return { id: requiredString(row, "id"), roomId: requiredString(row, "roomId"), author: hydrateAuthor(row.author), content: { type: "text", text: requiredString(content, "text") }, mentions: hydrateMentions(row.mentions), ...row.replyToMessageId === void 0 ? {} : { replyToMessageId: requiredString(row, "replyToMessageId") }, source: oneOf(row.source, messageSources, "source"), createdAt: date(row.createdAt, "createdAt") };
3638
+ };
3639
+ var hydrateMember = (value) => {
3640
+ const row = record(value);
3641
+ exactKeys(row, ["id", "tenantId", "projectId", "userId", "role", "status", "joinedAt", "updatedAt"]);
3642
+ return { id: requiredString(row, "id"), tenantId: requiredString(row, "tenantId"), projectId: requiredString(row, "projectId"), userId: requiredString(row, "userId"), role: oneOf(row.role, humanRoles, "role"), status: oneOf(row.status, memberStatuses, "status"), joinedAt: date(row.joinedAt, "joinedAt"), updatedAt: date(row.updatedAt, "updatedAt") };
3643
+ };
3644
+ var hydrateBot = (value) => {
3645
+ const row = record(value);
3646
+ exactKeys(row, ["id", "tenantId", "workspaceId", "projectId", "roomId", "assistantId", "role", "title", "mentionName", "status", "roomThreadId", "joinedAt", "updatedAt"], ["responsibility"]);
3647
+ return { id: requiredString(row, "id"), tenantId: requiredString(row, "tenantId"), workspaceId: requiredString(row, "workspaceId"), projectId: requiredString(row, "projectId"), roomId: requiredString(row, "roomId"), assistantId: requiredString(row, "assistantId"), role: oneOf(row.role, botRoles, "role"), title: requiredString(row, "title"), ...row.responsibility === void 0 ? {} : { responsibility: requiredString(row, "responsibility") }, mentionName: requiredString(row, "mentionName"), status: oneOf(row.status, botStatuses, "status"), roomThreadId: requiredString(row, "roomThreadId"), joinedAt: date(row.joinedAt, "joinedAt"), updatedAt: date(row.updatedAt, "updatedAt") };
3648
+ };
3649
+ var iso = (value) => date(value, "date").toISOString();
3650
+ var hydrateDispatch = (value) => {
3651
+ const row = record(value);
3652
+ if (typeof row.success !== "boolean" || row.membershipId !== void 0 && typeof row.membershipId !== "string" || row.errorCode !== void 0 && typeof row.errorCode !== "string")
3653
+ throw new ProjectRoomClientError("Invalid dispatch response", 500, "INVALID_RESPONSE", false);
3654
+ return { success: row.success, ...row.membershipId === void 0 ? {} : { membershipId: row.membershipId }, ...row.errorCode === void 0 ? {} : { errorCode: row.errorCode } };
3655
+ };
3656
+ var encode = encodeURIComponent;
3657
+ var ProjectRoomsClient = class {
3658
+ constructor(baseURL, getHeaders) {
3659
+ this.baseURL = baseURL;
3660
+ this.getHeaders = getHeaders;
3661
+ this.messages = {
3662
+ list: async (projectId, options = {}) => {
3663
+ const query = new URLSearchParams();
3664
+ if (options.cursor) {
3665
+ query.set("beforeCreatedAt", iso(options.cursor.createdAt));
3666
+ query.set("beforeId", options.cursor.id);
3667
+ }
3668
+ if (options.limit !== void 0)
3669
+ query.set("limit", String(options.limit));
3670
+ const result = await this.request(`/api/projects/${encode(projectId)}/room/messages${query.toString() ? `?${query}` : ""}`);
3671
+ if (!Array.isArray(result))
3672
+ throw new ProjectRoomClientError("Invalid messages response", 500, "INVALID_RESPONSE", false);
3673
+ return result.map(hydrateMessage);
3674
+ },
3675
+ send: async (projectId, input) => {
3676
+ const result = await this.request(`/api/projects/${encode(projectId)}/room/messages`, { method: "POST", body: { text: input.text, mentions: input.mentions, ...input.replyToMessageId === void 0 ? {} : { replyToMessageId: input.replyToMessageId } }, headers: { "Idempotency-Key": input.idempotencyKey.trim() } });
3677
+ if (!Array.isArray(result.dispatch) || typeof result.replayed !== "boolean")
3678
+ throw new ProjectRoomClientError("Invalid send response", 500, "INVALID_RESPONSE", false);
3679
+ return { message: hydrateMessage(result.message), dispatch: result.dispatch.map(hydrateDispatch), replayed: result.replayed };
3680
+ },
3681
+ retry: async (projectId, messageId) => {
3682
+ const result = await this.request(`/api/projects/${encode(projectId)}/room/messages/${encode(messageId)}/retry`, { method: "POST", body: {} });
3683
+ if (!Array.isArray(result))
3684
+ throw new ProjectRoomClientError("Invalid retry response", 500, "INVALID_RESPONSE", false);
3685
+ return result.map(hydrateDispatch);
3686
+ }
3687
+ };
3688
+ this.members = {
3689
+ list: async (projectId) => this.records(`/api/projects/${encode(projectId)}/members`, hydrateMember),
3690
+ add: async (projectId, input) => hydrateMember(await this.request(`/api/projects/${encode(projectId)}/members`, { method: "POST", body: input })),
3691
+ update: async (projectId, membershipId, input) => hydrateMember(await this.request(`/api/projects/${encode(projectId)}/members/${encode(membershipId)}`, { method: "PATCH", body: { role: input.role, expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
3692
+ remove: async (projectId, membershipId, input) => this.request(`/api/projects/${encode(projectId)}/members/${encode(membershipId)}?expectedUpdatedAt=${encode(iso(input.expectedUpdatedAt))}`, { method: "DELETE" })
3693
+ };
3694
+ this.bots = {
3695
+ list: async (projectId) => this.records(`/api/projects/${encode(projectId)}/bots`, hydrateBot),
3696
+ add: async (projectId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots`, { method: "POST", body: input })),
3697
+ update: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}`, { method: "PATCH", body: { ...input, expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
3698
+ pause: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}/pause`, { method: "POST", body: { expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
3699
+ resume: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}/resume`, { method: "POST", body: { expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
3700
+ remove: async (projectId, membershipId, input) => this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}?expectedUpdatedAt=${encode(iso(input.expectedUpdatedAt))}`, { method: "DELETE" })
3701
+ };
3702
+ this.events = { connect: (projectId, options) => this.connect(projectId, options) };
3703
+ }
3704
+ async getRoom(projectId) {
3705
+ return hydrateRoom(await this.request(`/api/projects/${encode(projectId)}/room`));
3706
+ }
3707
+ async getRealtimeMode(projectId) {
3708
+ return this.request(`/api/projects/${encode(projectId)}/room/realtime-mode`);
3709
+ }
3710
+ async records(path, hydrate) {
3711
+ const result = await this.request(path);
3712
+ if (!Array.isArray(result))
3713
+ throw new ProjectRoomClientError("Invalid records response", 500, "INVALID_RESPONSE", false);
3714
+ return result.map(hydrate);
3715
+ }
3716
+ async request(path, options = {}) {
3717
+ const headers = { ...this.getHeaders(), ...options.headers ?? {} };
3718
+ const body = options.body === void 0 ? void 0 : JSON.parse(JSON.stringify(options.body));
3719
+ const response = await fetch(`${this.baseURL}${path}`, { method: options.method ?? "GET", headers, ...body === void 0 ? {} : { body: JSON.stringify(body) } });
3720
+ const payload = await response.json().catch(() => void 0);
3721
+ if (!response.ok || !payload?.success) {
3722
+ const error = payload?.error;
3723
+ throw new ProjectRoomClientError(typeof error?.message === "string" ? error.message : "Project Room request failed", response.status, typeof error?.code === "string" ? error.code : response.ok ? "INVALID_RESPONSE" : "HTTP_ERROR", error?.retryable === true, error?.details);
3724
+ }
3725
+ if (!Object.prototype.hasOwnProperty.call(payload, "data"))
3726
+ throw new ProjectRoomClientError("Missing response data", 500, "INVALID_RESPONSE", false);
3727
+ return payload.data;
3728
+ }
3729
+ connect(projectId, options) {
3730
+ const headers = { ...this.getHeaders(), Accept: "text/event-stream", ...options.lastEventId ? { "Last-Event-ID": options.lastEventId } : {} };
3731
+ let resolveOpen;
3732
+ let rejectOpen;
3733
+ const opened = new Promise((resolve, reject) => {
3734
+ resolveOpen = resolve;
3735
+ rejectOpen = reject;
3736
+ });
3737
+ const responsePromise = fetch(`${this.baseURL}/api/projects/${encode(projectId)}/room/events`, { headers, signal: options.signal }).then(async (response) => {
3738
+ if (!response.ok) {
3739
+ const payload = await response.json().catch(() => void 0);
3740
+ const error = payload?.error;
3741
+ throw new ProjectRoomClientError(typeof error?.message === "string" ? error.message : "Project Room stream failed", response.status, typeof error?.code === "string" ? error.code : "HTTP_ERROR", error?.retryable === true, error?.details);
3742
+ }
3743
+ if (response.headers?.get && response.headers.get("content-type")?.split(";")[0].trim() !== "text/event-stream")
3744
+ throw new ProjectRoomClientError("Project Room stream has invalid content type", response.status, "INVALID_RESPONSE", false);
3745
+ if (!response.body)
3746
+ throw new ProjectRoomClientError("Project Room stream has no body", 500, "INVALID_RESPONSE", false);
3747
+ resolveOpen({ status: 200, ...options.lastEventId === void 0 ? {} : { lastEventId: options.lastEventId } });
3748
+ return response;
3749
+ }).catch((error) => {
3750
+ rejectOpen(error);
3751
+ throw error;
3752
+ });
3753
+ const stream = async function* () {
3754
+ const response = await responsePromise;
3755
+ const body = response.body;
3756
+ if (!body)
3757
+ throw new ProjectRoomClientError("Project Room stream has no body", 500, "INVALID_RESPONSE", false);
3758
+ for await (const raw of parseSseBody(body, { strictJsonObject: true })) {
3759
+ try {
3760
+ const event = raw.event;
3761
+ const payload = isRecord(raw.data) ? raw.data : void 0;
3762
+ let value = payload;
3763
+ if (event === "ready" || event === "resync" || event === "access.revoked") {
3764
+ if (!payload || Object.prototype.hasOwnProperty.call(payload, "type"))
3765
+ throw new ProjectRoomClientError("Invalid SSE control", 200, "INVALID_EVENT", false);
3766
+ value = { type: event, data: payload };
3767
+ } else {
3768
+ if (typeof payload?.type !== "string" || payload.type !== event || typeof payload.id !== "string" || raw.id !== payload.id)
3769
+ throw new ProjectRoomClientError("Invalid SSE business event", 200, "INVALID_EVENT", false);
3770
+ value = payload;
3771
+ }
3772
+ yield { event: hydrateEvent(value), ...raw.id === void 0 ? {} : { id: raw.id }, ...raw.retry === void 0 ? {} : { retry: raw.retry } };
3773
+ } catch (error) {
3774
+ if (error instanceof ProjectRoomClientError && error.code === "INVALID_EVENT")
3775
+ throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false, error.details);
3776
+ if (error instanceof SseParseError)
3777
+ throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false);
3778
+ if (error instanceof ProjectRoomClientError)
3779
+ throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false, error.details);
3780
+ throw new ProjectRoomClientError("Invalid SSE event", 400, "INVALID_EVENT", false);
3781
+ }
3782
+ }
3783
+ }();
3784
+ return { opened, [Symbol.asyncIterator]: () => stream };
3785
+ }
3786
+ };
3787
+ function hydrateEvent(value) {
3788
+ const row = record(value);
3789
+ if (row.type === "ready") {
3790
+ exactKeys(row, ["type", "data"]);
3791
+ const data2 = record(row.data);
3792
+ exactKeys(data2, ["epoch", "headEventId"]);
3793
+ if (typeof data2.epoch !== "string" || data2.headEventId !== null && typeof data2.headEventId !== "string")
3794
+ throw new ProjectRoomClientError("Invalid SSE control", 200, "INVALID_EVENT", false);
3795
+ return { type: "ready", data: { epoch: data2.epoch, headEventId: data2.headEventId } };
3796
+ }
3797
+ if (row.type === "resync" || row.type === "access.revoked") {
3798
+ exactKeys(row, ["type", "data"]);
3799
+ const data2 = record(row.data);
3800
+ exactKeys(data2, ["reason"]);
3801
+ const reasons = row.type === "resync" ? ["SERVER_RESTART", "CURSOR_EXPIRED", "SLOW_CONSUMER"] : ["PROJECT_ACCESS_REVOKED", "TOKEN_EXPIRED"];
3802
+ return { type: row.type, data: { reason: oneOf(data2.reason, reasons, "reason") } };
3803
+ }
3804
+ const data = record(row.data);
3805
+ if (row.type === "message.created")
3806
+ return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { message: hydrateMessage(data.message) } };
3807
+ if (row.type === "roster.changed")
3808
+ return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { change: data.change, membership: hydratePublicBot(data.membership) } };
3809
+ if (row.type === "membership.changed")
3810
+ return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { change: data.change, membership: hydratePublicMember(data.membership) } };
3811
+ if (row.type === "task.changed")
3812
+ return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { taskId: requiredString(data, "taskId"), status: data.status, ownerMembershipId: requiredString(data, "ownerMembershipId"), updatedAt: date(data.updatedAt, "updatedAt") } };
3813
+ throw new ProjectRoomClientError("Invalid SSE event", 200, "INVALID_EVENT", false);
3814
+ }
3815
+ function hydratePublicMember(value) {
3816
+ const row = record(value);
3817
+ return { id: requiredString(row, "id"), userId: requiredString(row, "userId"), role: row.role, status: row.status, joinedAt: date(row.joinedAt, "joinedAt"), updatedAt: date(row.updatedAt, "updatedAt") };
3818
+ }
3819
+ function hydratePublicBot(value) {
3820
+ const row = record(value);
3821
+ return { id: requiredString(row, "id"), role: row.role, title: requiredString(row, "title"), ...row.responsibility === void 0 ? {} : { responsibility: row.responsibility }, mentionName: requiredString(row, "mentionName"), status: row.status, joinedAt: date(row.joinedAt, "joinedAt"), updatedAt: date(row.updatedAt, "updatedAt") };
3822
+ }
3823
+
3311
3824
  // src/client.ts
3312
3825
  var _Client = class extends AbstractClient {
3313
3826
  /**
@@ -3323,6 +3836,7 @@ var _Client = class extends AbstractClient {
3323
3836
  };
3324
3837
  this.resources = new ResourcesClient(this.config.baseURL, () => this.getAllHeaders());
3325
3838
  this.exportImport = new ExportImportClient(this.config, () => this.getAllHeaders());
3839
+ this.projectRooms = new ProjectRoomsClient(this.config.baseURL, () => this.getAllHeaders());
3326
3840
  }
3327
3841
  /**
3328
3842
  * Helper method to handle fetch responses and errors
@@ -3538,41 +4052,8 @@ var _Client = class extends AbstractClient {
3538
4052
  if (!response.body) {
3539
4053
  throw new Error("Response body is null");
3540
4054
  }
3541
- const reader = response.body.getReader();
3542
- const decoder = new TextDecoder();
3543
- let buffer = "";
3544
- while (true) {
3545
- const { done, value } = await reader.read();
3546
- if (done)
3547
- break;
3548
- const chunk = decoder.decode(value, { stream: true });
3549
- buffer += chunk;
3550
- const lines = buffer.split("\n");
3551
- buffer = lines.pop() || "";
3552
- for (const line of lines) {
3553
- if (line.trim().startsWith("data: ")) {
3554
- try {
3555
- const eventData = JSON.parse(line.trim().slice(6));
3556
- onEvent(eventData);
3557
- } catch (error) {
3558
- console.error("Error parsing SSE data:", line, error);
3559
- if (onError) {
3560
- onError(
3561
- error instanceof Error ? error : new Error(String(error))
3562
- );
3563
- }
3564
- }
3565
- }
3566
- }
3567
- }
3568
- if (buffer && buffer.trim().startsWith("data: ")) {
3569
- try {
3570
- const eventData = JSON.parse(buffer.trim().slice(6));
3571
- onEvent(eventData);
3572
- } catch (error) {
3573
- console.error("Error parsing SSE data:", buffer, error);
3574
- }
3575
- }
4055
+ for await (const frame of parseSseBody(response.body, { strictJsonObject: true }))
4056
+ onEvent(frame.data);
3576
4057
  if (onComplete) {
3577
4058
  onComplete();
3578
4059
  }
@@ -3615,62 +4096,18 @@ var _Client = class extends AbstractClient {
3615
4096
  const res = await fetch(`${this.config.baseURL}${path}`, { headers, signal });
3616
4097
  if (!res.ok || !res.body)
3617
4098
  throw new Error("Stream connection failed");
3618
- const reader = res.body.getReader();
3619
- const decoder = new TextDecoder();
3620
- let buffer = "";
3621
- let event = "";
3622
- let dataLines = [];
3623
- const processLine = (rawLine) => {
3624
- const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
3625
- if (line === "") {
3626
- if (dataLines.length === 0) {
3627
- event = "";
3628
- return null;
3629
- }
3630
- const data = dataLines.join("\n");
3631
- const eventName = event;
3632
- event = "";
3633
- dataLines = [];
3634
- try {
3635
- return { event: eventName, data: JSON.parse(data) };
3636
- } catch {
3637
- return null;
3638
- }
3639
- }
3640
- if (line.startsWith(":"))
3641
- return null;
3642
- const separator = line.indexOf(":");
3643
- const field = separator === -1 ? line : line.slice(0, separator);
3644
- let value = separator === -1 ? "" : line.slice(separator + 1);
3645
- if (value.startsWith(" "))
3646
- value = value.slice(1);
3647
- if (field === "event")
3648
- event = value;
3649
- else if (field === "data")
3650
- dataLines.push(value);
3651
- return null;
3652
- };
3653
- while (true) {
3654
- const { done, value } = await reader.read();
3655
- if (done) {
3656
- buffer += decoder.decode();
3657
- break;
4099
+ try {
4100
+ for await (const frame of parseSseBody(res.body, { strictJsonObject: true })) {
4101
+ yield { event: frame.event, data: frame.data };
3658
4102
  }
3659
- buffer += decoder.decode(value, { stream: true });
3660
- let newline = buffer.indexOf("\n");
3661
- while (newline !== -1) {
3662
- const parsed = processLine(buffer.slice(0, newline));
3663
- buffer = buffer.slice(newline + 1);
3664
- if (parsed)
3665
- yield parsed;
3666
- newline = buffer.indexOf("\n");
4103
+ } catch (error) {
4104
+ if (error instanceof SseParseError) {
4105
+ const parseError = new Error(error.message);
4106
+ parseError.name = "StreamParseError";
4107
+ throw parseError;
3667
4108
  }
4109
+ throw error;
3668
4110
  }
3669
- if (buffer.length > 0)
3670
- processLine(buffer);
3671
- const finalEvent = processLine("");
3672
- if (finalEvent)
3673
- yield finalEvent;
3674
4111
  }
3675
4112
  /**
3676
4113
  * Get all headers including workspace context
@@ -3712,41 +4149,8 @@ var _Client = class extends AbstractClient {
3712
4149
  if (!response.body) {
3713
4150
  throw new Error("Response body is null");
3714
4151
  }
3715
- const reader = response.body.getReader();
3716
- const decoder = new TextDecoder();
3717
- let buffer = "";
3718
- while (true) {
3719
- const { done, value } = await reader.read();
3720
- if (done)
3721
- break;
3722
- const chunk = decoder.decode(value, { stream: true });
3723
- buffer += chunk;
3724
- const lines = buffer.split("\n");
3725
- buffer = lines.pop() || "";
3726
- for (const line of lines) {
3727
- if (line.trim().startsWith("data: ")) {
3728
- try {
3729
- const eventData = JSON.parse(line.trim().slice(6));
3730
- onEvent(eventData);
3731
- } catch (error) {
3732
- console.error("Error parsing SSE data:", line, error);
3733
- if (onError) {
3734
- onError(
3735
- error instanceof Error ? error : new Error(String(error))
3736
- );
3737
- }
3738
- }
3739
- }
3740
- }
3741
- }
3742
- if (buffer && buffer.trim().startsWith("data: ")) {
3743
- try {
3744
- const eventData = JSON.parse(buffer.trim().slice(6));
3745
- onEvent(eventData);
3746
- } catch (error) {
3747
- console.error("Error parsing SSE data:", buffer, error);
3748
- }
3749
- }
4152
+ for await (const frame of parseSseBody(response.body, { strictJsonObject: true }))
4153
+ onEvent(frame.data);
3750
4154
  if (onComplete) {
3751
4155
  if (options.enableReturnStateWhenSteamCompleted) {
3752
4156
  try {
@@ -3796,6 +4200,32 @@ var WeChatClient = class extends AbstractClient {
3796
4200
  setTenantId(tenantId) {
3797
4201
  this.tenantId = tenantId;
3798
4202
  }
4203
+ /**
4204
+ * Set workspace and project headers for requests made by this client.
4205
+ * @param workspaceId - Workspace identifier, or undefined to leave it unchanged
4206
+ * @param projectId - Project identifier, or undefined to leave it unchanged
4207
+ */
4208
+ setWorkspaceContext(workspaceId, projectId) {
4209
+ if (workspaceId !== void 0) {
4210
+ if (workspaceId)
4211
+ this.workspaceHeaders["x-workspace-id"] = workspaceId;
4212
+ else
4213
+ delete this.workspaceHeaders["x-workspace-id"];
4214
+ }
4215
+ if (projectId !== void 0) {
4216
+ if (projectId)
4217
+ this.workspaceHeaders["x-project-id"] = projectId;
4218
+ else
4219
+ delete this.workspaceHeaders["x-project-id"];
4220
+ }
4221
+ }
4222
+ /**
4223
+ * Get the workspace and project headers currently applied to this client.
4224
+ * @returns A copy of the current workspace and project header values
4225
+ */
4226
+ getWorkspaceHeaders() {
4227
+ return { ...this.workspaceHeaders };
4228
+ }
3799
4229
  /**
3800
4230
  * Creates a new instance of the client with the given configuration
3801
4231
  * @param config - Configuration options for the client
@@ -3826,7 +4256,8 @@ var WeChatClient = class extends AbstractClient {
3826
4256
  return this.wechatRequest({
3827
4257
  url: fullUrl,
3828
4258
  method,
3829
- data: options?.body
4259
+ data: options?.body,
4260
+ headers: this.getWorkspaceHeaders()
3830
4261
  });
3831
4262
  }
3832
4263
  /**
@@ -3906,11 +4337,12 @@ var WeChatClient = class extends AbstractClient {
3906
4337
  * @private
3907
4338
  */
3908
4339
  async wechatRequest(options) {
3909
- const { url, method, data } = options;
4340
+ const { url, method, data, headers: requestHeaders } = options;
3910
4341
  const headers = {
3911
4342
  "Content-Type": "application/json",
3912
4343
  Authorization: `Bearer ${this.config.apiKey}`,
3913
- ...this.config.headers
4344
+ ...this.config.headers,
4345
+ ...requestHeaders
3914
4346
  };
3915
4347
  if (this.tenantId) {
3916
4348
  headers["x-tenant-id"] = this.tenantId;
@@ -4489,6 +4921,8 @@ export {
4489
4921
  Client,
4490
4922
  ExportImportClient,
4491
4923
  NetworkError,
4924
+ ProjectRoomClientError,
4925
+ ProjectRoomsClient,
4492
4926
  ResourcesClient,
4493
4927
  ScheduleExecutionType,
4494
4928
  ScheduledTaskStatus,