@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.js CHANGED
@@ -919,8 +919,8 @@ var require_encoding = __commonJS({
919
919
  }
920
920
  return serializeStream.call(this, output);
921
921
  };
922
- function TextEncoder(label, options) {
923
- if (!(this instanceof TextEncoder))
922
+ function TextEncoder2(label, options) {
923
+ if (!(this instanceof TextEncoder2))
924
924
  throw TypeError("Called as a function. Did you forget 'new'?");
925
925
  options = ToDictionary(options);
926
926
  this._encoding = null;
@@ -948,14 +948,14 @@ var require_encoding = __commonJS({
948
948
  return enc;
949
949
  }
950
950
  if (Object.defineProperty) {
951
- Object.defineProperty(TextEncoder.prototype, "encoding", {
951
+ Object.defineProperty(TextEncoder2.prototype, "encoding", {
952
952
  /** @this {TextEncoder} */
953
953
  get: function() {
954
954
  return this._encoding.name.toLowerCase();
955
955
  }
956
956
  });
957
957
  }
958
- TextEncoder.prototype.encode = function encode(opt_string, options) {
958
+ TextEncoder2.prototype.encode = function encode2(opt_string, options) {
959
959
  opt_string = opt_string === void 0 ? "" : String(opt_string);
960
960
  options = ToDictionary(options);
961
961
  if (!this._do_not_flush)
@@ -1811,7 +1811,7 @@ var require_encoding = __commonJS({
1811
1811
  return new XUserDefinedDecoder(options);
1812
1812
  };
1813
1813
  if (!global["TextEncoder"])
1814
- global["TextEncoder"] = TextEncoder;
1814
+ global["TextEncoder"] = TextEncoder2;
1815
1815
  if (!global["TextDecoder"])
1816
1816
  global["TextDecoder"] = TextDecoder2;
1817
1817
  if (typeof module2 !== "undefined" && module2.exports) {
@@ -1834,6 +1834,8 @@ __export(src_exports, {
1834
1834
  Client: () => Client,
1835
1835
  ExportImportClient: () => ExportImportClient,
1836
1836
  NetworkError: () => NetworkError,
1837
+ ProjectRoomClientError: () => ProjectRoomClientError,
1838
+ ProjectRoomsClient: () => ProjectRoomsClient,
1837
1839
  ResourcesClient: () => ResourcesClient,
1838
1840
  ScheduleExecutionType: () => ScheduleExecutionType,
1839
1841
  ScheduledTaskStatus: () => ScheduledTaskStatus,
@@ -2224,6 +2226,127 @@ var AbstractClient = class {
2224
2226
  return response.data;
2225
2227
  }
2226
2228
  };
2229
+ /** Capability bundle namespace for managing tenant-scoped bundles. */
2230
+ this.capabilityBundles = {
2231
+ /**
2232
+ * List all capability bundles visible to the current tenant.
2233
+ * @returns The tenant's capability bundles, unwrapped from the API response.
2234
+ */
2235
+ list: async () => {
2236
+ const response = await this.makeRequest(
2237
+ "/api/capability-bundles"
2238
+ );
2239
+ return response.data;
2240
+ },
2241
+ /**
2242
+ * List valid bundles together with safe invalid-record summaries.
2243
+ * @returns Inventory suitable for management and remediation workflows.
2244
+ */
2245
+ listInventory: async () => {
2246
+ const response = await this.makeRequest("/api/capability-bundles");
2247
+ return { bundles: response.data, errors: response.errors ?? [] };
2248
+ },
2249
+ /**
2250
+ * Get one capability bundle by identifier.
2251
+ * @param bundleId - Capability bundle identifier.
2252
+ * @returns The requested capability bundle.
2253
+ */
2254
+ get: async (bundleId) => {
2255
+ const response = await this.makeRequest(
2256
+ `/api/capability-bundles/${encodeURIComponent(bundleId)}`
2257
+ );
2258
+ return response.data;
2259
+ },
2260
+ /**
2261
+ * Create a capability bundle for the current tenant.
2262
+ * @param input - Bundle name, optional description, and capabilities. The server generates the stable key.
2263
+ * @returns The created capability bundle.
2264
+ */
2265
+ create: async (input) => {
2266
+ const response = await this.makeRequest(
2267
+ "/api/capability-bundles",
2268
+ { method: "POST", body: input }
2269
+ );
2270
+ return response.data;
2271
+ },
2272
+ /**
2273
+ * Update a capability bundle for the current tenant.
2274
+ * @param bundleId - Capability bundle identifier.
2275
+ * @param input - The partial bundle fields and required expected revision to update.
2276
+ * @returns The updated capability bundle.
2277
+ */
2278
+ update: async (bundleId, input) => {
2279
+ const response = await this.makeRequest(
2280
+ `/api/capability-bundles/${encodeURIComponent(bundleId)}`,
2281
+ { method: "PUT", body: input }
2282
+ );
2283
+ return response.data;
2284
+ },
2285
+ /**
2286
+ * Delete a capability bundle when the backend permits deletion.
2287
+ * @param bundleId - Capability bundle identifier.
2288
+ * @returns A promise that resolves after the bundle is deleted.
2289
+ * @throws ApiError when the bundle is missing, in use, or the request fails.
2290
+ */
2291
+ delete: async (bundleId) => {
2292
+ await this.makeRequest(
2293
+ `/api/capability-bundles/${encodeURIComponent(bundleId)}`,
2294
+ { method: "DELETE" }
2295
+ );
2296
+ }
2297
+ };
2298
+ this.projects = {
2299
+ capabilities: {
2300
+ /**
2301
+ * Get a project's selected bundles and its persisted capability preview.
2302
+ * @param projectId - Project identifier.
2303
+ * @returns The project, selected bundles, and preview resolved from persisted selections.
2304
+ */
2305
+ get: async (projectId) => {
2306
+ const response = await this.makeRequest(
2307
+ `/api/projects/${encodeURIComponent(projectId)}/capability-bundles`
2308
+ );
2309
+ return response.data;
2310
+ },
2311
+ /**
2312
+ * Replace a project's selected capability bundles.
2313
+ * @param projectId - Project identifier.
2314
+ * @param bundleIds - Ordered capability bundle identifiers to persist.
2315
+ * @returns The updated project, selected bundles, and persisted-selection preview.
2316
+ */
2317
+ update: async (projectId, bundleIds, expectedRevisions) => {
2318
+ const response = await this.makeRequest(
2319
+ `/api/projects/${encodeURIComponent(projectId)}/capability-bundles`,
2320
+ { method: "PUT", body: { bundleIds, expectedRevisions } }
2321
+ );
2322
+ return response.data;
2323
+ },
2324
+ /**
2325
+ * Preview the capability bundles currently persisted on a project.
2326
+ * @param projectId - Project identifier.
2327
+ * @returns The preview resolved from the project's persisted bundle selections.
2328
+ */
2329
+ preview: async (projectId) => {
2330
+ const response = await this.makeRequest(
2331
+ `/api/projects/${encodeURIComponent(projectId)}/capability-preview`
2332
+ );
2333
+ return response.data;
2334
+ },
2335
+ /**
2336
+ * Preview a draft bundle selection without changing the project.
2337
+ * @param projectId - Project identifier.
2338
+ * @param bundleIds - Ordered capability bundle identifiers to preview.
2339
+ * @returns The draft preview resolved from the supplied bundle IDs; no project state is changed.
2340
+ */
2341
+ previewWithBundles: async (projectId, bundleIds) => {
2342
+ const response = await this.makeRequest(
2343
+ `/api/projects/${encodeURIComponent(projectId)}/capability-preview`,
2344
+ { method: "POST", body: { bundleIds } }
2345
+ );
2346
+ return response.data;
2347
+ }
2348
+ }
2349
+ };
2227
2350
  /** Agent Web Apps namespace for managing React SDK publications. */
2228
2351
  this.webApps = {
2229
2352
  /**
@@ -2239,7 +2362,7 @@ var AbstractClient = class {
2239
2362
  const query = searchParams.toString();
2240
2363
  const response = await this.makeRequest(`/api/web-apps${query ? `?${query}` : ""}`);
2241
2364
  return {
2242
- records: response.data.records.map((record) => this.hydrateAgentWebApp(record)),
2365
+ records: response.data.records.map((record2) => this.hydrateAgentWebApp(record2)),
2243
2366
  total: response.data.total
2244
2367
  };
2245
2368
  },
@@ -2880,19 +3003,19 @@ var AbstractClient = class {
2880
3003
  if (!value || typeof value !== "object" || Array.isArray(value)) {
2881
3004
  throw new ApiError("Invalid Agent Web App response", 500, value);
2882
3005
  }
2883
- const record = value;
3006
+ const record2 = value;
2884
3007
  const hydrateDate = (field) => {
2885
- const raw = record[field];
2886
- const date = raw instanceof Date ? new Date(raw.getTime()) : new Date(
3008
+ const raw = record2[field];
3009
+ const date2 = raw instanceof Date ? new Date(raw.getTime()) : new Date(
2887
3010
  typeof raw === "string" || typeof raw === "number" ? raw : Number.NaN
2888
3011
  );
2889
- if (Number.isNaN(date.getTime())) {
3012
+ if (Number.isNaN(date2.getTime())) {
2890
3013
  throw new ApiError(`Invalid Agent Web App ${field}`, 500, value);
2891
3014
  }
2892
- return date;
3015
+ return date2;
2893
3016
  };
2894
3017
  return {
2895
- ...record,
3018
+ ...record2,
2896
3019
  createdAt: hydrateDate("createdAt"),
2897
3020
  updatedAt: hydrateDate("updatedAt")
2898
3021
  };
@@ -3332,6 +3455,398 @@ var ExportImportClient = class {
3332
3455
  }
3333
3456
  };
3334
3457
 
3458
+ // src/sse-parser.ts
3459
+ var SseParseError = class extends Error {
3460
+ constructor(message) {
3461
+ super(message);
3462
+ this.code = "INVALID_EVENT";
3463
+ this.name = "SseParseError";
3464
+ }
3465
+ };
3466
+ async function* parseSseBody(body, options = {}) {
3467
+ const maxLine = options.maxLineBytes ?? 64 * 1024;
3468
+ const maxEvent = options.maxEventBytes ?? 1024 * 1024;
3469
+ const maxDataLines = options.maxDataLines ?? 1024;
3470
+ const reader = body.getReader();
3471
+ const decoder = new TextDecoder();
3472
+ let buffer = "";
3473
+ let event = "";
3474
+ let id;
3475
+ let retry;
3476
+ let data = [];
3477
+ let bytes = 0;
3478
+ const dispatch = () => {
3479
+ if (data.length === 0) {
3480
+ event = "";
3481
+ id = void 0;
3482
+ retry = void 0;
3483
+ bytes = 0;
3484
+ return void 0;
3485
+ }
3486
+ let parsed;
3487
+ try {
3488
+ parsed = JSON.parse(data.join("\n"));
3489
+ } catch {
3490
+ throw new SseParseError("Invalid SSE JSON");
3491
+ }
3492
+ if (options.strictJsonObject && (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)))
3493
+ throw new SseParseError("SSE data must be an object");
3494
+ const result = { event, data: parsed, ...id === void 0 ? {} : { id }, ...retry === void 0 ? {} : { retry } };
3495
+ event = "";
3496
+ id = void 0;
3497
+ retry = void 0;
3498
+ data = [];
3499
+ bytes = 0;
3500
+ return result;
3501
+ };
3502
+ const processLine = (raw) => {
3503
+ const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
3504
+ if (new TextEncoder().encode(line).byteLength > maxLine)
3505
+ throw new SseParseError("SSE line is too large");
3506
+ if (line === "")
3507
+ return dispatch();
3508
+ if (line.startsWith(":"))
3509
+ return void 0;
3510
+ const separator = line.indexOf(":");
3511
+ const field = separator < 0 ? line : line.slice(0, separator);
3512
+ let value = separator < 0 ? "" : line.slice(separator + 1);
3513
+ if (value.startsWith(" "))
3514
+ value = value.slice(1);
3515
+ if (field === "event")
3516
+ event = value;
3517
+ else if (field === "data") {
3518
+ if (data.length >= maxDataLines)
3519
+ throw new SseParseError("Too many SSE data lines");
3520
+ data.push(value);
3521
+ bytes += new TextEncoder().encode(value).byteLength + (data.length === 1 ? 0 : 1);
3522
+ if (bytes > maxEvent)
3523
+ throw new SseParseError("SSE event is too large");
3524
+ } else if (field === "id")
3525
+ id = value;
3526
+ else if (field === "retry") {
3527
+ const parsed = Number(value);
3528
+ if (!Number.isInteger(parsed) || parsed < 0 || !Number.isFinite(parsed))
3529
+ throw new SseParseError("Invalid SSE retry");
3530
+ retry = parsed;
3531
+ }
3532
+ return void 0;
3533
+ };
3534
+ try {
3535
+ while (true) {
3536
+ const chunk = await reader.read();
3537
+ if (chunk.done) {
3538
+ buffer += decoder.decode();
3539
+ if (new TextEncoder().encode(buffer).byteLength > maxLine)
3540
+ throw new SseParseError("SSE line is too large");
3541
+ break;
3542
+ }
3543
+ buffer += decoder.decode(chunk.value, { stream: true });
3544
+ if (new TextEncoder().encode(buffer.slice(0, Math.max(0, findLineBreak(buffer) < 0 ? buffer.length : findLineBreak(buffer)))).byteLength > maxLine)
3545
+ throw new SseParseError("SSE line is too large");
3546
+ let index = findLineBreak(buffer);
3547
+ while (index >= 0) {
3548
+ if (buffer[index] === "\r" && index === buffer.length - 1)
3549
+ break;
3550
+ const frame2 = processLine(buffer.slice(0, index));
3551
+ buffer = buffer.slice(index + lineBreakLength(buffer, index));
3552
+ if (frame2)
3553
+ yield frame2;
3554
+ index = findLineBreak(buffer);
3555
+ }
3556
+ }
3557
+ if (buffer) {
3558
+ const frame2 = processLine(buffer);
3559
+ if (frame2)
3560
+ yield frame2;
3561
+ }
3562
+ const frame = processLine("");
3563
+ if (frame)
3564
+ yield frame;
3565
+ } finally {
3566
+ await reader.cancel().catch(() => void 0);
3567
+ reader.releaseLock();
3568
+ }
3569
+ }
3570
+ function findLineBreak(value) {
3571
+ const lf = value.indexOf("\n");
3572
+ const cr = value.indexOf("\r");
3573
+ if (lf < 0)
3574
+ return cr;
3575
+ if (cr < 0)
3576
+ return lf;
3577
+ return Math.min(lf, cr);
3578
+ }
3579
+ function lineBreakLength(value, index) {
3580
+ return value[index] === "\r" && value[index + 1] === "\n" ? 2 : 1;
3581
+ }
3582
+
3583
+ // src/project-rooms.ts
3584
+ var ProjectRoomClientError = class extends Error {
3585
+ constructor(message, status, code, retryable, details) {
3586
+ super(message);
3587
+ this.status = status;
3588
+ this.code = code;
3589
+ this.retryable = retryable;
3590
+ this.details = details;
3591
+ this.name = "ProjectRoomClientError";
3592
+ }
3593
+ };
3594
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3595
+ var date = (value, field) => {
3596
+ const result = value instanceof Date ? new Date(value.getTime()) : new Date(typeof value === "string" || typeof value === "number" ? value : Number.NaN);
3597
+ if (!Number.isFinite(result.getTime()))
3598
+ throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
3599
+ return result;
3600
+ };
3601
+ var requiredString = (record2, field) => {
3602
+ if (typeof record2[field] !== "string")
3603
+ throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
3604
+ return record2[field];
3605
+ };
3606
+ var oneOf = (value, values, field) => {
3607
+ if (typeof value !== "string" || !values.includes(value))
3608
+ throw new ProjectRoomClientError(`Invalid ${field}`, 500, "INVALID_RESPONSE", false);
3609
+ return value;
3610
+ };
3611
+ var messageSources = ["user", "agent", "task", "routine", "system"];
3612
+ var humanRoles = ["owner", "admin", "member", "viewer"];
3613
+ var memberStatuses = ["active", "removed"];
3614
+ var botRoles = ["coordinator", "specialist"];
3615
+ var botStatuses = ["active", "paused", "removed"];
3616
+ var exactKeys = (row, required, optional = []) => {
3617
+ if (required.some((key) => !Object.prototype.hasOwnProperty.call(row, key)) || Object.keys(row).some((key) => !required.includes(key) && !optional.includes(key)))
3618
+ throw new ProjectRoomClientError("Invalid Project Room response", 500, "INVALID_RESPONSE", false);
3619
+ };
3620
+ var hydrateAuthor = (value) => {
3621
+ const row = record(value);
3622
+ const type = oneOf(row.type, ["human", "bot", "system"], "author.type");
3623
+ if (type === "human") {
3624
+ exactKeys(row, ["type", "userId"]);
3625
+ return { type, userId: requiredString(row, "userId") };
3626
+ }
3627
+ if (type === "bot")
3628
+ return { type, membershipId: requiredString(row, "membershipId") };
3629
+ if (Object.keys(row).some((key) => key !== "type"))
3630
+ throw new ProjectRoomClientError("Invalid author", 500, "INVALID_RESPONSE", false);
3631
+ return { type };
3632
+ };
3633
+ var hydrateMentions = (value) => {
3634
+ if (!Array.isArray(value))
3635
+ throw new ProjectRoomClientError("Invalid mentions", 500, "INVALID_RESPONSE", false);
3636
+ return value.map((entry) => {
3637
+ const row = record(entry);
3638
+ const type = oneOf(row.type, ["bot", "team"], "mention.type");
3639
+ if (type === "team") {
3640
+ if (Object.keys(row).length !== 1)
3641
+ throw new ProjectRoomClientError("Invalid mention", 500, "INVALID_RESPONSE", false);
3642
+ return { type };
3643
+ }
3644
+ return { type, membershipId: requiredString(row, "membershipId") };
3645
+ });
3646
+ };
3647
+ var record = (value) => {
3648
+ if (!isRecord(value))
3649
+ throw new ProjectRoomClientError("Invalid Project Room response", 500, "INVALID_RESPONSE", false);
3650
+ return value;
3651
+ };
3652
+ var hydrateRoom = (value) => {
3653
+ const row = record(value);
3654
+ exactKeys(row, ["id", "tenantId", "workspaceId", "projectId", "type", "name", "createdAt", "updatedAt"]);
3655
+ 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") };
3656
+ };
3657
+ var hydrateMessage = (value) => {
3658
+ const row = record(value);
3659
+ exactKeys(row, ["id", "roomId", "author", "content", "mentions", "source", "createdAt"], ["replyToMessageId"]);
3660
+ const content = record(row.content);
3661
+ if (oneOf(content.type, ["text"], "content.type") !== "text")
3662
+ throw new ProjectRoomClientError("Invalid content", 500, "INVALID_RESPONSE", false);
3663
+ 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") };
3664
+ };
3665
+ var hydrateMember = (value) => {
3666
+ const row = record(value);
3667
+ exactKeys(row, ["id", "tenantId", "projectId", "userId", "role", "status", "joinedAt", "updatedAt"]);
3668
+ 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") };
3669
+ };
3670
+ var hydrateBot = (value) => {
3671
+ const row = record(value);
3672
+ exactKeys(row, ["id", "tenantId", "workspaceId", "projectId", "roomId", "assistantId", "role", "title", "mentionName", "status", "roomThreadId", "joinedAt", "updatedAt"], ["responsibility"]);
3673
+ 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") };
3674
+ };
3675
+ var iso = (value) => date(value, "date").toISOString();
3676
+ var hydrateDispatch = (value) => {
3677
+ const row = record(value);
3678
+ if (typeof row.success !== "boolean" || row.membershipId !== void 0 && typeof row.membershipId !== "string" || row.errorCode !== void 0 && typeof row.errorCode !== "string")
3679
+ throw new ProjectRoomClientError("Invalid dispatch response", 500, "INVALID_RESPONSE", false);
3680
+ return { success: row.success, ...row.membershipId === void 0 ? {} : { membershipId: row.membershipId }, ...row.errorCode === void 0 ? {} : { errorCode: row.errorCode } };
3681
+ };
3682
+ var encode = encodeURIComponent;
3683
+ var ProjectRoomsClient = class {
3684
+ constructor(baseURL, getHeaders) {
3685
+ this.baseURL = baseURL;
3686
+ this.getHeaders = getHeaders;
3687
+ this.messages = {
3688
+ list: async (projectId, options = {}) => {
3689
+ const query = new URLSearchParams();
3690
+ if (options.cursor) {
3691
+ query.set("beforeCreatedAt", iso(options.cursor.createdAt));
3692
+ query.set("beforeId", options.cursor.id);
3693
+ }
3694
+ if (options.limit !== void 0)
3695
+ query.set("limit", String(options.limit));
3696
+ const result = await this.request(`/api/projects/${encode(projectId)}/room/messages${query.toString() ? `?${query}` : ""}`);
3697
+ if (!Array.isArray(result))
3698
+ throw new ProjectRoomClientError("Invalid messages response", 500, "INVALID_RESPONSE", false);
3699
+ return result.map(hydrateMessage);
3700
+ },
3701
+ send: async (projectId, input) => {
3702
+ 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() } });
3703
+ if (!Array.isArray(result.dispatch) || typeof result.replayed !== "boolean")
3704
+ throw new ProjectRoomClientError("Invalid send response", 500, "INVALID_RESPONSE", false);
3705
+ return { message: hydrateMessage(result.message), dispatch: result.dispatch.map(hydrateDispatch), replayed: result.replayed };
3706
+ },
3707
+ retry: async (projectId, messageId) => {
3708
+ const result = await this.request(`/api/projects/${encode(projectId)}/room/messages/${encode(messageId)}/retry`, { method: "POST", body: {} });
3709
+ if (!Array.isArray(result))
3710
+ throw new ProjectRoomClientError("Invalid retry response", 500, "INVALID_RESPONSE", false);
3711
+ return result.map(hydrateDispatch);
3712
+ }
3713
+ };
3714
+ this.members = {
3715
+ list: async (projectId) => this.records(`/api/projects/${encode(projectId)}/members`, hydrateMember),
3716
+ add: async (projectId, input) => hydrateMember(await this.request(`/api/projects/${encode(projectId)}/members`, { method: "POST", body: input })),
3717
+ 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) } })),
3718
+ remove: async (projectId, membershipId, input) => this.request(`/api/projects/${encode(projectId)}/members/${encode(membershipId)}?expectedUpdatedAt=${encode(iso(input.expectedUpdatedAt))}`, { method: "DELETE" })
3719
+ };
3720
+ this.bots = {
3721
+ list: async (projectId) => this.records(`/api/projects/${encode(projectId)}/bots`, hydrateBot),
3722
+ add: async (projectId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots`, { method: "POST", body: input })),
3723
+ update: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}`, { method: "PATCH", body: { ...input, expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
3724
+ pause: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}/pause`, { method: "POST", body: { expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
3725
+ resume: async (projectId, membershipId, input) => hydrateBot(await this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}/resume`, { method: "POST", body: { expectedUpdatedAt: iso(input.expectedUpdatedAt) } })),
3726
+ remove: async (projectId, membershipId, input) => this.request(`/api/projects/${encode(projectId)}/bots/${encode(membershipId)}?expectedUpdatedAt=${encode(iso(input.expectedUpdatedAt))}`, { method: "DELETE" })
3727
+ };
3728
+ this.events = { connect: (projectId, options) => this.connect(projectId, options) };
3729
+ }
3730
+ async getRoom(projectId) {
3731
+ return hydrateRoom(await this.request(`/api/projects/${encode(projectId)}/room`));
3732
+ }
3733
+ async getRealtimeMode(projectId) {
3734
+ return this.request(`/api/projects/${encode(projectId)}/room/realtime-mode`);
3735
+ }
3736
+ async records(path, hydrate) {
3737
+ const result = await this.request(path);
3738
+ if (!Array.isArray(result))
3739
+ throw new ProjectRoomClientError("Invalid records response", 500, "INVALID_RESPONSE", false);
3740
+ return result.map(hydrate);
3741
+ }
3742
+ async request(path, options = {}) {
3743
+ const headers = { ...this.getHeaders(), ...options.headers ?? {} };
3744
+ const body = options.body === void 0 ? void 0 : JSON.parse(JSON.stringify(options.body));
3745
+ const response = await fetch(`${this.baseURL}${path}`, { method: options.method ?? "GET", headers, ...body === void 0 ? {} : { body: JSON.stringify(body) } });
3746
+ const payload = await response.json().catch(() => void 0);
3747
+ if (!response.ok || !payload?.success) {
3748
+ const error = payload?.error;
3749
+ 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);
3750
+ }
3751
+ if (!Object.prototype.hasOwnProperty.call(payload, "data"))
3752
+ throw new ProjectRoomClientError("Missing response data", 500, "INVALID_RESPONSE", false);
3753
+ return payload.data;
3754
+ }
3755
+ connect(projectId, options) {
3756
+ const headers = { ...this.getHeaders(), Accept: "text/event-stream", ...options.lastEventId ? { "Last-Event-ID": options.lastEventId } : {} };
3757
+ let resolveOpen;
3758
+ let rejectOpen;
3759
+ const opened = new Promise((resolve, reject) => {
3760
+ resolveOpen = resolve;
3761
+ rejectOpen = reject;
3762
+ });
3763
+ const responsePromise = fetch(`${this.baseURL}/api/projects/${encode(projectId)}/room/events`, { headers, signal: options.signal }).then(async (response) => {
3764
+ if (!response.ok) {
3765
+ const payload = await response.json().catch(() => void 0);
3766
+ const error = payload?.error;
3767
+ 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);
3768
+ }
3769
+ if (response.headers?.get && response.headers.get("content-type")?.split(";")[0].trim() !== "text/event-stream")
3770
+ throw new ProjectRoomClientError("Project Room stream has invalid content type", response.status, "INVALID_RESPONSE", false);
3771
+ if (!response.body)
3772
+ throw new ProjectRoomClientError("Project Room stream has no body", 500, "INVALID_RESPONSE", false);
3773
+ resolveOpen({ status: 200, ...options.lastEventId === void 0 ? {} : { lastEventId: options.lastEventId } });
3774
+ return response;
3775
+ }).catch((error) => {
3776
+ rejectOpen(error);
3777
+ throw error;
3778
+ });
3779
+ const stream = async function* () {
3780
+ const response = await responsePromise;
3781
+ const body = response.body;
3782
+ if (!body)
3783
+ throw new ProjectRoomClientError("Project Room stream has no body", 500, "INVALID_RESPONSE", false);
3784
+ for await (const raw of parseSseBody(body, { strictJsonObject: true })) {
3785
+ try {
3786
+ const event = raw.event;
3787
+ const payload = isRecord(raw.data) ? raw.data : void 0;
3788
+ let value = payload;
3789
+ if (event === "ready" || event === "resync" || event === "access.revoked") {
3790
+ if (!payload || Object.prototype.hasOwnProperty.call(payload, "type"))
3791
+ throw new ProjectRoomClientError("Invalid SSE control", 200, "INVALID_EVENT", false);
3792
+ value = { type: event, data: payload };
3793
+ } else {
3794
+ if (typeof payload?.type !== "string" || payload.type !== event || typeof payload.id !== "string" || raw.id !== payload.id)
3795
+ throw new ProjectRoomClientError("Invalid SSE business event", 200, "INVALID_EVENT", false);
3796
+ value = payload;
3797
+ }
3798
+ yield { event: hydrateEvent(value), ...raw.id === void 0 ? {} : { id: raw.id }, ...raw.retry === void 0 ? {} : { retry: raw.retry } };
3799
+ } catch (error) {
3800
+ if (error instanceof ProjectRoomClientError && error.code === "INVALID_EVENT")
3801
+ throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false, error.details);
3802
+ if (error instanceof SseParseError)
3803
+ throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false);
3804
+ if (error instanceof ProjectRoomClientError)
3805
+ throw new ProjectRoomClientError(error.message, 400, "INVALID_EVENT", false, error.details);
3806
+ throw new ProjectRoomClientError("Invalid SSE event", 400, "INVALID_EVENT", false);
3807
+ }
3808
+ }
3809
+ }();
3810
+ return { opened, [Symbol.asyncIterator]: () => stream };
3811
+ }
3812
+ };
3813
+ function hydrateEvent(value) {
3814
+ const row = record(value);
3815
+ if (row.type === "ready") {
3816
+ exactKeys(row, ["type", "data"]);
3817
+ const data2 = record(row.data);
3818
+ exactKeys(data2, ["epoch", "headEventId"]);
3819
+ if (typeof data2.epoch !== "string" || data2.headEventId !== null && typeof data2.headEventId !== "string")
3820
+ throw new ProjectRoomClientError("Invalid SSE control", 200, "INVALID_EVENT", false);
3821
+ return { type: "ready", data: { epoch: data2.epoch, headEventId: data2.headEventId } };
3822
+ }
3823
+ if (row.type === "resync" || row.type === "access.revoked") {
3824
+ exactKeys(row, ["type", "data"]);
3825
+ const data2 = record(row.data);
3826
+ exactKeys(data2, ["reason"]);
3827
+ const reasons = row.type === "resync" ? ["SERVER_RESTART", "CURSOR_EXPIRED", "SLOW_CONSUMER"] : ["PROJECT_ACCESS_REVOKED", "TOKEN_EXPIRED"];
3828
+ return { type: row.type, data: { reason: oneOf(data2.reason, reasons, "reason") } };
3829
+ }
3830
+ const data = record(row.data);
3831
+ if (row.type === "message.created")
3832
+ return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { message: hydrateMessage(data.message) } };
3833
+ if (row.type === "roster.changed")
3834
+ return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { change: data.change, membership: hydratePublicBot(data.membership) } };
3835
+ if (row.type === "membership.changed")
3836
+ return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { change: data.change, membership: hydratePublicMember(data.membership) } };
3837
+ if (row.type === "task.changed")
3838
+ return { ...row, occurredAt: date(row.occurredAt, "occurredAt"), data: { taskId: requiredString(data, "taskId"), status: data.status, ownerMembershipId: requiredString(data, "ownerMembershipId"), updatedAt: date(data.updatedAt, "updatedAt") } };
3839
+ throw new ProjectRoomClientError("Invalid SSE event", 200, "INVALID_EVENT", false);
3840
+ }
3841
+ function hydratePublicMember(value) {
3842
+ const row = record(value);
3843
+ 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") };
3844
+ }
3845
+ function hydratePublicBot(value) {
3846
+ const row = record(value);
3847
+ 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") };
3848
+ }
3849
+
3335
3850
  // src/client.ts
3336
3851
  var _Client = class extends AbstractClient {
3337
3852
  /**
@@ -3347,6 +3862,7 @@ var _Client = class extends AbstractClient {
3347
3862
  };
3348
3863
  this.resources = new ResourcesClient(this.config.baseURL, () => this.getAllHeaders());
3349
3864
  this.exportImport = new ExportImportClient(this.config, () => this.getAllHeaders());
3865
+ this.projectRooms = new ProjectRoomsClient(this.config.baseURL, () => this.getAllHeaders());
3350
3866
  }
3351
3867
  /**
3352
3868
  * Helper method to handle fetch responses and errors
@@ -3562,41 +4078,8 @@ var _Client = class extends AbstractClient {
3562
4078
  if (!response.body) {
3563
4079
  throw new Error("Response body is null");
3564
4080
  }
3565
- const reader = response.body.getReader();
3566
- const decoder = new TextDecoder();
3567
- let buffer = "";
3568
- while (true) {
3569
- const { done, value } = await reader.read();
3570
- if (done)
3571
- break;
3572
- const chunk = decoder.decode(value, { stream: true });
3573
- buffer += chunk;
3574
- const lines = buffer.split("\n");
3575
- buffer = lines.pop() || "";
3576
- for (const line of lines) {
3577
- if (line.trim().startsWith("data: ")) {
3578
- try {
3579
- const eventData = JSON.parse(line.trim().slice(6));
3580
- onEvent(eventData);
3581
- } catch (error) {
3582
- console.error("Error parsing SSE data:", line, error);
3583
- if (onError) {
3584
- onError(
3585
- error instanceof Error ? error : new Error(String(error))
3586
- );
3587
- }
3588
- }
3589
- }
3590
- }
3591
- }
3592
- if (buffer && buffer.trim().startsWith("data: ")) {
3593
- try {
3594
- const eventData = JSON.parse(buffer.trim().slice(6));
3595
- onEvent(eventData);
3596
- } catch (error) {
3597
- console.error("Error parsing SSE data:", buffer, error);
3598
- }
3599
- }
4081
+ for await (const frame of parseSseBody(response.body, { strictJsonObject: true }))
4082
+ onEvent(frame.data);
3600
4083
  if (onComplete) {
3601
4084
  onComplete();
3602
4085
  }
@@ -3639,62 +4122,18 @@ var _Client = class extends AbstractClient {
3639
4122
  const res = await fetch(`${this.config.baseURL}${path}`, { headers, signal });
3640
4123
  if (!res.ok || !res.body)
3641
4124
  throw new Error("Stream connection failed");
3642
- const reader = res.body.getReader();
3643
- const decoder = new TextDecoder();
3644
- let buffer = "";
3645
- let event = "";
3646
- let dataLines = [];
3647
- const processLine = (rawLine) => {
3648
- const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
3649
- if (line === "") {
3650
- if (dataLines.length === 0) {
3651
- event = "";
3652
- return null;
3653
- }
3654
- const data = dataLines.join("\n");
3655
- const eventName = event;
3656
- event = "";
3657
- dataLines = [];
3658
- try {
3659
- return { event: eventName, data: JSON.parse(data) };
3660
- } catch {
3661
- return null;
3662
- }
3663
- }
3664
- if (line.startsWith(":"))
3665
- return null;
3666
- const separator = line.indexOf(":");
3667
- const field = separator === -1 ? line : line.slice(0, separator);
3668
- let value = separator === -1 ? "" : line.slice(separator + 1);
3669
- if (value.startsWith(" "))
3670
- value = value.slice(1);
3671
- if (field === "event")
3672
- event = value;
3673
- else if (field === "data")
3674
- dataLines.push(value);
3675
- return null;
3676
- };
3677
- while (true) {
3678
- const { done, value } = await reader.read();
3679
- if (done) {
3680
- buffer += decoder.decode();
3681
- break;
4125
+ try {
4126
+ for await (const frame of parseSseBody(res.body, { strictJsonObject: true })) {
4127
+ yield { event: frame.event, data: frame.data };
3682
4128
  }
3683
- buffer += decoder.decode(value, { stream: true });
3684
- let newline = buffer.indexOf("\n");
3685
- while (newline !== -1) {
3686
- const parsed = processLine(buffer.slice(0, newline));
3687
- buffer = buffer.slice(newline + 1);
3688
- if (parsed)
3689
- yield parsed;
3690
- newline = buffer.indexOf("\n");
4129
+ } catch (error) {
4130
+ if (error instanceof SseParseError) {
4131
+ const parseError = new Error(error.message);
4132
+ parseError.name = "StreamParseError";
4133
+ throw parseError;
3691
4134
  }
4135
+ throw error;
3692
4136
  }
3693
- if (buffer.length > 0)
3694
- processLine(buffer);
3695
- const finalEvent = processLine("");
3696
- if (finalEvent)
3697
- yield finalEvent;
3698
4137
  }
3699
4138
  /**
3700
4139
  * Get all headers including workspace context
@@ -3736,41 +4175,8 @@ var _Client = class extends AbstractClient {
3736
4175
  if (!response.body) {
3737
4176
  throw new Error("Response body is null");
3738
4177
  }
3739
- const reader = response.body.getReader();
3740
- const decoder = new TextDecoder();
3741
- let buffer = "";
3742
- while (true) {
3743
- const { done, value } = await reader.read();
3744
- if (done)
3745
- break;
3746
- const chunk = decoder.decode(value, { stream: true });
3747
- buffer += chunk;
3748
- const lines = buffer.split("\n");
3749
- buffer = lines.pop() || "";
3750
- for (const line of lines) {
3751
- if (line.trim().startsWith("data: ")) {
3752
- try {
3753
- const eventData = JSON.parse(line.trim().slice(6));
3754
- onEvent(eventData);
3755
- } catch (error) {
3756
- console.error("Error parsing SSE data:", line, error);
3757
- if (onError) {
3758
- onError(
3759
- error instanceof Error ? error : new Error(String(error))
3760
- );
3761
- }
3762
- }
3763
- }
3764
- }
3765
- }
3766
- if (buffer && buffer.trim().startsWith("data: ")) {
3767
- try {
3768
- const eventData = JSON.parse(buffer.trim().slice(6));
3769
- onEvent(eventData);
3770
- } catch (error) {
3771
- console.error("Error parsing SSE data:", buffer, error);
3772
- }
3773
- }
4178
+ for await (const frame of parseSseBody(response.body, { strictJsonObject: true }))
4179
+ onEvent(frame.data);
3774
4180
  if (onComplete) {
3775
4181
  if (options.enableReturnStateWhenSteamCompleted) {
3776
4182
  try {
@@ -3820,6 +4226,32 @@ var WeChatClient = class extends AbstractClient {
3820
4226
  setTenantId(tenantId) {
3821
4227
  this.tenantId = tenantId;
3822
4228
  }
4229
+ /**
4230
+ * Set workspace and project headers for requests made by this client.
4231
+ * @param workspaceId - Workspace identifier, or undefined to leave it unchanged
4232
+ * @param projectId - Project identifier, or undefined to leave it unchanged
4233
+ */
4234
+ setWorkspaceContext(workspaceId, projectId) {
4235
+ if (workspaceId !== void 0) {
4236
+ if (workspaceId)
4237
+ this.workspaceHeaders["x-workspace-id"] = workspaceId;
4238
+ else
4239
+ delete this.workspaceHeaders["x-workspace-id"];
4240
+ }
4241
+ if (projectId !== void 0) {
4242
+ if (projectId)
4243
+ this.workspaceHeaders["x-project-id"] = projectId;
4244
+ else
4245
+ delete this.workspaceHeaders["x-project-id"];
4246
+ }
4247
+ }
4248
+ /**
4249
+ * Get the workspace and project headers currently applied to this client.
4250
+ * @returns A copy of the current workspace and project header values
4251
+ */
4252
+ getWorkspaceHeaders() {
4253
+ return { ...this.workspaceHeaders };
4254
+ }
3823
4255
  /**
3824
4256
  * Creates a new instance of the client with the given configuration
3825
4257
  * @param config - Configuration options for the client
@@ -3850,7 +4282,8 @@ var WeChatClient = class extends AbstractClient {
3850
4282
  return this.wechatRequest({
3851
4283
  url: fullUrl,
3852
4284
  method,
3853
- data: options?.body
4285
+ data: options?.body,
4286
+ headers: this.getWorkspaceHeaders()
3854
4287
  });
3855
4288
  }
3856
4289
  /**
@@ -3930,11 +4363,12 @@ var WeChatClient = class extends AbstractClient {
3930
4363
  * @private
3931
4364
  */
3932
4365
  async wechatRequest(options) {
3933
- const { url, method, data } = options;
4366
+ const { url, method, data, headers: requestHeaders } = options;
3934
4367
  const headers = {
3935
4368
  "Content-Type": "application/json",
3936
4369
  Authorization: `Bearer ${this.config.apiKey}`,
3937
- ...this.config.headers
4370
+ ...this.config.headers,
4371
+ ...requestHeaders
3938
4372
  };
3939
4373
  if (this.tenantId) {
3940
4374
  headers["x-tenant-id"] = this.tenantId;
@@ -4514,6 +4948,8 @@ function createSimpleMessageMerger() {
4514
4948
  Client,
4515
4949
  ExportImportClient,
4516
4950
  NetworkError,
4951
+ ProjectRoomClientError,
4952
+ ProjectRoomsClient,
4517
4953
  ResourcesClient,
4518
4954
  ScheduleExecutionType,
4519
4955
  ScheduledTaskStatus,