@prismer/sdk 2.0.4 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AIPIdentity: () => import_aip_sdk.AIPIdentity,
34
34
  AccountClient: () => AccountClient,
35
+ AgentsClient: () => AgentsClient,
35
36
  AssetsClient: () => AssetsClient,
36
37
  AttachmentQueue: () => AttachmentQueue,
37
38
  BindingsClient: () => BindingsClient,
@@ -3451,6 +3452,44 @@ function resolveBaseUrl(explicit) {
3451
3452
  }
3452
3453
  return void 0;
3453
3454
  }
3455
+ function generateIdempotencyKey() {
3456
+ try {
3457
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
3458
+ return crypto.randomUUID();
3459
+ }
3460
+ } catch {
3461
+ }
3462
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
3463
+ const r = Math.random() * 16 | 0;
3464
+ return (c === "x" ? r : r & 3 | 8).toString(16);
3465
+ });
3466
+ }
3467
+ function buildSendPayload(content, options) {
3468
+ const key = options?.idempotencyKey ?? generateIdempotencyKey();
3469
+ const isBlocks = Array.isArray(content);
3470
+ const body = {
3471
+ // For ContentBlock[] inputs, populate `content` as a fallback summary
3472
+ // (server's legacy `content` column stays compatible during the 6-sprint
3473
+ // double-write window from §4.6); the SOT is `contentBlocks`.
3474
+ content: isBlocks ? "" : content,
3475
+ type: options?.type ?? "text",
3476
+ metadata: options?.metadata,
3477
+ attachments: options?.attachments,
3478
+ parentId: options?.parentId,
3479
+ quotedMessageId: options?.quotedMessageId,
3480
+ idempotencyKey: key
3481
+ };
3482
+ if (isBlocks) {
3483
+ body.contentBlocks = content;
3484
+ } else if (options?.contentBlocks) {
3485
+ body.contentBlocks = options.contentBlocks;
3486
+ }
3487
+ return {
3488
+ body,
3489
+ opts: { headers: { "X-Idempotency-Key": key } },
3490
+ key
3491
+ };
3492
+ }
3454
3493
  var AccountClient = class {
3455
3494
  constructor(_r) {
3456
3495
  this._r = _r;
@@ -3493,16 +3532,17 @@ var DirectClient = class {
3493
3532
  constructor(_r) {
3494
3533
  this._r = _r;
3495
3534
  }
3496
- /** Send a direct message to a user */
3535
+ /**
3536
+ * Send a direct message to a user.
3537
+ *
3538
+ * v2.0 §4.6 — `content` may now be a `ContentBlock[]` for multimodal sends.
3539
+ * v2.0 §3.0.2 Gap A-④ — when `options.idempotencyKey` is omitted, the SDK
3540
+ * generates a UUID per call and stamps it into the `X-Idempotency-Key`
3541
+ * header. Pass the same key across retries to trigger server dedup.
3542
+ */
3497
3543
  async send(userId, content, options) {
3498
- return this._r("POST", `/api/im/direct/${userId}/messages`, {
3499
- content,
3500
- type: options?.type ?? "text",
3501
- metadata: options?.metadata,
3502
- attachments: options?.attachments,
3503
- parentId: options?.parentId,
3504
- quotedMessageId: options?.quotedMessageId
3505
- });
3544
+ const { body, opts } = buildSendPayload(content, options);
3545
+ return this._r("POST", `/api/im/direct/${userId}/messages`, body, void 0, opts);
3506
3546
  }
3507
3547
  /** Get direct message history with a user */
3508
3548
  async getMessages(userId, options) {
@@ -3528,16 +3568,15 @@ var GroupsClient = class {
3528
3568
  async get(groupId) {
3529
3569
  return this._r("GET", `/api/im/groups/${groupId}`);
3530
3570
  }
3531
- /** Send a message to a group */
3571
+ /**
3572
+ * Send a message to a group.
3573
+ *
3574
+ * v2.0 §4.6 — `content` may now be a `ContentBlock[]` for multimodal sends.
3575
+ * v2.0 §3.0.2 Gap A-④ — auto-generates `X-Idempotency-Key` per call.
3576
+ */
3532
3577
  async send(groupId, content, options) {
3533
- return this._r("POST", `/api/im/groups/${groupId}/messages`, {
3534
- content,
3535
- type: options?.type ?? "text",
3536
- metadata: options?.metadata,
3537
- attachments: options?.attachments,
3538
- parentId: options?.parentId,
3539
- quotedMessageId: options?.quotedMessageId
3540
- });
3578
+ const { body, opts } = buildSendPayload(content, options);
3579
+ return this._r("POST", `/api/im/groups/${groupId}/messages`, body, void 0, opts);
3541
3580
  }
3542
3581
  /** Get group message history */
3543
3582
  async getMessages(groupId, options) {
@@ -3607,16 +3646,23 @@ var MessagesClient = class {
3607
3646
  constructor(_r) {
3608
3647
  this._r = _r;
3609
3648
  }
3610
- /** Send a message to a conversation */
3649
+ /**
3650
+ * Send a message to a conversation.
3651
+ *
3652
+ * v2.0 §4.6 — `content` may now be a `ContentBlock[]` for multimodal sends.
3653
+ * The SDK serialises ContentBlock[] into `body.contentBlocks` (preferred
3654
+ * path) while still writing a string `content` for legacy renderers during
3655
+ * the §4.6 6-sprint double-read window.
3656
+ *
3657
+ * v2.0 §3.0.2 Gap A-④ — when `options.idempotencyKey` is omitted, the SDK
3658
+ * auto-generates `crypto.randomUUID()` per call and includes it as the
3659
+ * `X-Idempotency-Key` HTTP header. The server applies UNIQUE
3660
+ * `(conversationId, idempotencyKey)` dedup; pass the same key across
3661
+ * retries to safely re-send.
3662
+ */
3611
3663
  async send(conversationId, content, options) {
3612
- return this._r("POST", `/api/im/messages/${conversationId}`, {
3613
- content,
3614
- type: options?.type ?? "text",
3615
- metadata: options?.metadata,
3616
- attachments: options?.attachments,
3617
- parentId: options?.parentId,
3618
- quotedMessageId: options?.quotedMessageId
3619
- });
3664
+ const { body, opts } = buildSendPayload(content, options);
3665
+ return this._r("POST", `/api/im/messages/${conversationId}`, body, void 0, opts);
3620
3666
  }
3621
3667
  /** Get message history for a conversation */
3622
3668
  async getHistory(conversationId, options) {
@@ -4154,6 +4200,46 @@ var EvolutionSkillsClient = class {
4154
4200
  return this._r("POST", `/api/im/skills/${encodeURIComponent(skillId)}/star`);
4155
4201
  }
4156
4202
  };
4203
+ var AgentsClient = class {
4204
+ constructor(_r) {
4205
+ this._r = _r;
4206
+ }
4207
+ async spec(agentId, workspaceId) {
4208
+ const query = workspaceId ? { workspaceId } : void 0;
4209
+ return this._r("GET", `/api/im/agents/${encodeURIComponent(agentId)}/spec`, void 0, query);
4210
+ }
4211
+ async snapshot(agentId, options) {
4212
+ return this._r("POST", `/api/im/agents/${encodeURIComponent(agentId)}/snapshot`, options ?? {});
4213
+ }
4214
+ async snapshots(agentId, options) {
4215
+ const query = {};
4216
+ if (options?.cursor) query.cursor = options.cursor;
4217
+ if (options?.limit != null) query.limit = String(options.limit);
4218
+ return this._r("GET", `/api/im/agents/${encodeURIComponent(agentId)}/snapshots`, void 0, query);
4219
+ }
4220
+ async restore(agentId, options) {
4221
+ return this._r("POST", `/api/im/agents/${encodeURIComponent(agentId)}/restore`, options);
4222
+ }
4223
+ async publish(agentId, options) {
4224
+ return this._r("POST", `/api/im/agents/${encodeURIComponent(agentId)}/publish`, options ?? {});
4225
+ }
4226
+ async listPacks(options) {
4227
+ const query = {};
4228
+ if (options?.q) query.q = options.q;
4229
+ if (options?.curatedQuality) query.curatedQuality = options.curatedQuality;
4230
+ if (options?.license) query.license = options.license;
4231
+ if (options?.publisherDid) query.publisherDid = options.publisherDid;
4232
+ if (options?.cursor) query.cursor = options.cursor;
4233
+ if (options?.limit != null) query.limit = String(options.limit);
4234
+ return this._r("GET", "/api/im/agent-packs", void 0, query);
4235
+ }
4236
+ async forkPack(packIdOrSlug, options) {
4237
+ return this._r("POST", `/api/im/agent-packs/${encodeURIComponent(packIdOrSlug)}/fork`, options);
4238
+ }
4239
+ async deletePack(packIdOrSlug) {
4240
+ return this._r("DELETE", `/api/im/agent-packs/${encodeURIComponent(packIdOrSlug)}`);
4241
+ }
4242
+ };
4157
4243
  var EvolutionClient = class {
4158
4244
  constructor(_r) {
4159
4245
  this._r = _r;
@@ -5394,6 +5480,7 @@ var IMClient = class {
5394
5480
  this.knowledge = new KnowledgeLinkClient(request);
5395
5481
  this.identity = new IdentityClient(request);
5396
5482
  this.security = new SecurityClient(request);
5483
+ this.agents = new AgentsClient(request);
5397
5484
  this.evolution = new EvolutionClient(request);
5398
5485
  this.community = new CommunityHub(request, communityHubConfig ?? void 0);
5399
5486
  this.files = new FilesClient(request, wsBase, fetchFn, getAuthHeaders);
@@ -5459,6 +5546,9 @@ var PrismerClient = class {
5459
5546
  if (config.offline) {
5460
5547
  this._offlineManager = new OfflineManager(
5461
5548
  config.offline.storage,
5549
+ // OfflineManager has a 4-arg RequestFn signature (legacy); the 5th
5550
+ // opts param is dropped on the offline path until OfflineManager is
5551
+ // upgraded. Online path forwards opts (see below).
5462
5552
  (m, p, b, q) => this._request(m, p, b, q),
5463
5553
  config.offline
5464
5554
  );
@@ -5466,23 +5556,28 @@ var PrismerClient = class {
5466
5556
  (err) => console.warn("[PrismerSDK] Offline storage init failed:", err)
5467
5557
  );
5468
5558
  }
5469
- let imRequest = this._offlineManager ? (m, p, b, q) => this._offlineManager.dispatch(m, p, b, q) : (m, p, b, q) => this._request(m, p, b, q);
5559
+ let imRequest = this._offlineManager ? (m, p, b, q, _opts) => (
5560
+ // Offline path: opts dropped (manager doesn't forward headers yet).
5561
+ // Idempotency key is also stamped into the body JSON, so server-side
5562
+ // dedup still works via the JSON field even without the header.
5563
+ this._offlineManager.dispatch(m, p, b, q)
5564
+ ) : (m, p, b, q, opts) => this._request(m, p, b, q, opts);
5470
5565
  if (config.identity) {
5471
5566
  const baseRequest = imRequest;
5472
- imRequest = (method, path, body, query) => {
5567
+ imRequest = (method, path, body, query, opts) => {
5473
5568
  if (method === "POST" && path.includes("/messages") && body) {
5474
5569
  const b = body;
5475
5570
  if (!b.signature && !b.skipSigning) {
5476
5571
  const ready = this._identityReady || Promise.resolve();
5477
5572
  return ready.then(() => {
5478
5573
  if (this._identity) {
5479
- return this._signAndSend(baseRequest, method, path, b, query);
5574
+ return this._signAndSend(baseRequest, method, path, b, query, opts);
5480
5575
  }
5481
- return baseRequest(method, path, body, query);
5576
+ return baseRequest(method, path, body, query, opts);
5482
5577
  });
5483
5578
  }
5484
5579
  }
5485
- return baseRequest(method, path, body, query);
5580
+ return baseRequest(method, path, body, query, opts);
5486
5581
  };
5487
5582
  }
5488
5583
  this.im = new IMClient(
@@ -5504,9 +5599,9 @@ var PrismerClient = class {
5504
5599
  return this._identity;
5505
5600
  }
5506
5601
  /** Auto-sign a message body and send (v1.8.0 S1) */
5507
- async _signAndSend(baseRequest, method, path, body, query) {
5602
+ async _signAndSend(baseRequest, method, path, body, query, opts) {
5508
5603
  if (this._identityReady) await this._identityReady;
5509
- if (!this._identity) return baseRequest(method, path, body, query);
5604
+ if (!this._identity) return baseRequest(method, path, body, query, opts);
5510
5605
  const content = body.content || "";
5511
5606
  const contentHashBytes = new Uint8Array(
5512
5607
  await crypto.subtle.digest("SHA-256", new TextEncoder().encode(content))
@@ -5523,7 +5618,7 @@ var PrismerClient = class {
5523
5618
  contentHash,
5524
5619
  signature,
5525
5620
  signedAt: timestamp
5526
- }, query);
5621
+ }, query, opts);
5527
5622
  }
5528
5623
  /** Build auth headers for raw HTTP requests (used by file upload) */
5529
5624
  _getAuthHeaders() {
@@ -5581,7 +5676,7 @@ var PrismerClient = class {
5581
5676
  // --------------------------------------------------------------------------
5582
5677
  // Internal request helper
5583
5678
  // --------------------------------------------------------------------------
5584
- async _request(method, path, body, query, _isRetry) {
5679
+ async _request(method, path, body, query, opts, _isRetry) {
5585
5680
  const controller = new AbortController();
5586
5681
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
5587
5682
  try {
@@ -5596,6 +5691,9 @@ var PrismerClient = class {
5596
5691
  if (this.imAgent) {
5597
5692
  headers["X-IM-Agent"] = this.imAgent;
5598
5693
  }
5694
+ if (opts?.headers) {
5695
+ for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;
5696
+ }
5599
5697
  const init = { method, headers, signal: controller.signal };
5600
5698
  if (body !== void 0) {
5601
5699
  headers["Content-Type"] = "application/json";
@@ -5605,10 +5703,10 @@ var PrismerClient = class {
5605
5703
  const data = await response.json();
5606
5704
  if (response.status === 401 && this.apiKey.startsWith("eyJ") && !_isRetry && !path.includes("/token/refresh")) {
5607
5705
  try {
5608
- const refreshRes = await this._request("POST", "/api/im/token/refresh", void 0, void 0, true);
5706
+ const refreshRes = await this._request("POST", "/api/im/token/refresh", void 0, void 0, void 0, true);
5609
5707
  if (refreshRes?.ok && refreshRes?.data?.token) {
5610
5708
  this.apiKey = refreshRes.data.token;
5611
- return this._request(method, path, body, query, true);
5709
+ return this._request(method, path, body, query, opts, true);
5612
5710
  }
5613
5711
  } catch {
5614
5712
  }
@@ -5702,6 +5800,7 @@ function createClient(config) {
5702
5800
  0 && (module.exports = {
5703
5801
  AIPIdentity,
5704
5802
  AccountClient,
5803
+ AgentsClient,
5705
5804
  AssetsClient,
5706
5805
  AttachmentQueue,
5707
5806
  BindingsClient,
package/dist/index.mjs CHANGED
@@ -3382,6 +3382,44 @@ function resolveBaseUrl(explicit) {
3382
3382
  }
3383
3383
  return void 0;
3384
3384
  }
3385
+ function generateIdempotencyKey() {
3386
+ try {
3387
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
3388
+ return crypto.randomUUID();
3389
+ }
3390
+ } catch {
3391
+ }
3392
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
3393
+ const r = Math.random() * 16 | 0;
3394
+ return (c === "x" ? r : r & 3 | 8).toString(16);
3395
+ });
3396
+ }
3397
+ function buildSendPayload(content, options) {
3398
+ const key = options?.idempotencyKey ?? generateIdempotencyKey();
3399
+ const isBlocks = Array.isArray(content);
3400
+ const body = {
3401
+ // For ContentBlock[] inputs, populate `content` as a fallback summary
3402
+ // (server's legacy `content` column stays compatible during the 6-sprint
3403
+ // double-write window from §4.6); the SOT is `contentBlocks`.
3404
+ content: isBlocks ? "" : content,
3405
+ type: options?.type ?? "text",
3406
+ metadata: options?.metadata,
3407
+ attachments: options?.attachments,
3408
+ parentId: options?.parentId,
3409
+ quotedMessageId: options?.quotedMessageId,
3410
+ idempotencyKey: key
3411
+ };
3412
+ if (isBlocks) {
3413
+ body.contentBlocks = content;
3414
+ } else if (options?.contentBlocks) {
3415
+ body.contentBlocks = options.contentBlocks;
3416
+ }
3417
+ return {
3418
+ body,
3419
+ opts: { headers: { "X-Idempotency-Key": key } },
3420
+ key
3421
+ };
3422
+ }
3385
3423
  var AccountClient = class {
3386
3424
  constructor(_r) {
3387
3425
  this._r = _r;
@@ -3424,16 +3462,17 @@ var DirectClient = class {
3424
3462
  constructor(_r) {
3425
3463
  this._r = _r;
3426
3464
  }
3427
- /** Send a direct message to a user */
3465
+ /**
3466
+ * Send a direct message to a user.
3467
+ *
3468
+ * v2.0 §4.6 — `content` may now be a `ContentBlock[]` for multimodal sends.
3469
+ * v2.0 §3.0.2 Gap A-④ — when `options.idempotencyKey` is omitted, the SDK
3470
+ * generates a UUID per call and stamps it into the `X-Idempotency-Key`
3471
+ * header. Pass the same key across retries to trigger server dedup.
3472
+ */
3428
3473
  async send(userId, content, options) {
3429
- return this._r("POST", `/api/im/direct/${userId}/messages`, {
3430
- content,
3431
- type: options?.type ?? "text",
3432
- metadata: options?.metadata,
3433
- attachments: options?.attachments,
3434
- parentId: options?.parentId,
3435
- quotedMessageId: options?.quotedMessageId
3436
- });
3474
+ const { body, opts } = buildSendPayload(content, options);
3475
+ return this._r("POST", `/api/im/direct/${userId}/messages`, body, void 0, opts);
3437
3476
  }
3438
3477
  /** Get direct message history with a user */
3439
3478
  async getMessages(userId, options) {
@@ -3459,16 +3498,15 @@ var GroupsClient = class {
3459
3498
  async get(groupId) {
3460
3499
  return this._r("GET", `/api/im/groups/${groupId}`);
3461
3500
  }
3462
- /** Send a message to a group */
3501
+ /**
3502
+ * Send a message to a group.
3503
+ *
3504
+ * v2.0 §4.6 — `content` may now be a `ContentBlock[]` for multimodal sends.
3505
+ * v2.0 §3.0.2 Gap A-④ — auto-generates `X-Idempotency-Key` per call.
3506
+ */
3463
3507
  async send(groupId, content, options) {
3464
- return this._r("POST", `/api/im/groups/${groupId}/messages`, {
3465
- content,
3466
- type: options?.type ?? "text",
3467
- metadata: options?.metadata,
3468
- attachments: options?.attachments,
3469
- parentId: options?.parentId,
3470
- quotedMessageId: options?.quotedMessageId
3471
- });
3508
+ const { body, opts } = buildSendPayload(content, options);
3509
+ return this._r("POST", `/api/im/groups/${groupId}/messages`, body, void 0, opts);
3472
3510
  }
3473
3511
  /** Get group message history */
3474
3512
  async getMessages(groupId, options) {
@@ -3538,16 +3576,23 @@ var MessagesClient = class {
3538
3576
  constructor(_r) {
3539
3577
  this._r = _r;
3540
3578
  }
3541
- /** Send a message to a conversation */
3579
+ /**
3580
+ * Send a message to a conversation.
3581
+ *
3582
+ * v2.0 §4.6 — `content` may now be a `ContentBlock[]` for multimodal sends.
3583
+ * The SDK serialises ContentBlock[] into `body.contentBlocks` (preferred
3584
+ * path) while still writing a string `content` for legacy renderers during
3585
+ * the §4.6 6-sprint double-read window.
3586
+ *
3587
+ * v2.0 §3.0.2 Gap A-④ — when `options.idempotencyKey` is omitted, the SDK
3588
+ * auto-generates `crypto.randomUUID()` per call and includes it as the
3589
+ * `X-Idempotency-Key` HTTP header. The server applies UNIQUE
3590
+ * `(conversationId, idempotencyKey)` dedup; pass the same key across
3591
+ * retries to safely re-send.
3592
+ */
3542
3593
  async send(conversationId, content, options) {
3543
- return this._r("POST", `/api/im/messages/${conversationId}`, {
3544
- content,
3545
- type: options?.type ?? "text",
3546
- metadata: options?.metadata,
3547
- attachments: options?.attachments,
3548
- parentId: options?.parentId,
3549
- quotedMessageId: options?.quotedMessageId
3550
- });
3594
+ const { body, opts } = buildSendPayload(content, options);
3595
+ return this._r("POST", `/api/im/messages/${conversationId}`, body, void 0, opts);
3551
3596
  }
3552
3597
  /** Get message history for a conversation */
3553
3598
  async getHistory(conversationId, options) {
@@ -4085,6 +4130,46 @@ var EvolutionSkillsClient = class {
4085
4130
  return this._r("POST", `/api/im/skills/${encodeURIComponent(skillId)}/star`);
4086
4131
  }
4087
4132
  };
4133
+ var AgentsClient = class {
4134
+ constructor(_r) {
4135
+ this._r = _r;
4136
+ }
4137
+ async spec(agentId, workspaceId) {
4138
+ const query = workspaceId ? { workspaceId } : void 0;
4139
+ return this._r("GET", `/api/im/agents/${encodeURIComponent(agentId)}/spec`, void 0, query);
4140
+ }
4141
+ async snapshot(agentId, options) {
4142
+ return this._r("POST", `/api/im/agents/${encodeURIComponent(agentId)}/snapshot`, options ?? {});
4143
+ }
4144
+ async snapshots(agentId, options) {
4145
+ const query = {};
4146
+ if (options?.cursor) query.cursor = options.cursor;
4147
+ if (options?.limit != null) query.limit = String(options.limit);
4148
+ return this._r("GET", `/api/im/agents/${encodeURIComponent(agentId)}/snapshots`, void 0, query);
4149
+ }
4150
+ async restore(agentId, options) {
4151
+ return this._r("POST", `/api/im/agents/${encodeURIComponent(agentId)}/restore`, options);
4152
+ }
4153
+ async publish(agentId, options) {
4154
+ return this._r("POST", `/api/im/agents/${encodeURIComponent(agentId)}/publish`, options ?? {});
4155
+ }
4156
+ async listPacks(options) {
4157
+ const query = {};
4158
+ if (options?.q) query.q = options.q;
4159
+ if (options?.curatedQuality) query.curatedQuality = options.curatedQuality;
4160
+ if (options?.license) query.license = options.license;
4161
+ if (options?.publisherDid) query.publisherDid = options.publisherDid;
4162
+ if (options?.cursor) query.cursor = options.cursor;
4163
+ if (options?.limit != null) query.limit = String(options.limit);
4164
+ return this._r("GET", "/api/im/agent-packs", void 0, query);
4165
+ }
4166
+ async forkPack(packIdOrSlug, options) {
4167
+ return this._r("POST", `/api/im/agent-packs/${encodeURIComponent(packIdOrSlug)}/fork`, options);
4168
+ }
4169
+ async deletePack(packIdOrSlug) {
4170
+ return this._r("DELETE", `/api/im/agent-packs/${encodeURIComponent(packIdOrSlug)}`);
4171
+ }
4172
+ };
4088
4173
  var EvolutionClient = class {
4089
4174
  constructor(_r) {
4090
4175
  this._r = _r;
@@ -5325,6 +5410,7 @@ var IMClient = class {
5325
5410
  this.knowledge = new KnowledgeLinkClient(request);
5326
5411
  this.identity = new IdentityClient(request);
5327
5412
  this.security = new SecurityClient(request);
5413
+ this.agents = new AgentsClient(request);
5328
5414
  this.evolution = new EvolutionClient(request);
5329
5415
  this.community = new CommunityHub(request, communityHubConfig ?? void 0);
5330
5416
  this.files = new FilesClient(request, wsBase, fetchFn, getAuthHeaders);
@@ -5390,6 +5476,9 @@ var PrismerClient = class {
5390
5476
  if (config.offline) {
5391
5477
  this._offlineManager = new OfflineManager(
5392
5478
  config.offline.storage,
5479
+ // OfflineManager has a 4-arg RequestFn signature (legacy); the 5th
5480
+ // opts param is dropped on the offline path until OfflineManager is
5481
+ // upgraded. Online path forwards opts (see below).
5393
5482
  (m, p, b, q) => this._request(m, p, b, q),
5394
5483
  config.offline
5395
5484
  );
@@ -5397,23 +5486,28 @@ var PrismerClient = class {
5397
5486
  (err) => console.warn("[PrismerSDK] Offline storage init failed:", err)
5398
5487
  );
5399
5488
  }
5400
- let imRequest = this._offlineManager ? (m, p, b, q) => this._offlineManager.dispatch(m, p, b, q) : (m, p, b, q) => this._request(m, p, b, q);
5489
+ let imRequest = this._offlineManager ? (m, p, b, q, _opts) => (
5490
+ // Offline path: opts dropped (manager doesn't forward headers yet).
5491
+ // Idempotency key is also stamped into the body JSON, so server-side
5492
+ // dedup still works via the JSON field even without the header.
5493
+ this._offlineManager.dispatch(m, p, b, q)
5494
+ ) : (m, p, b, q, opts) => this._request(m, p, b, q, opts);
5401
5495
  if (config.identity) {
5402
5496
  const baseRequest = imRequest;
5403
- imRequest = (method, path, body, query) => {
5497
+ imRequest = (method, path, body, query, opts) => {
5404
5498
  if (method === "POST" && path.includes("/messages") && body) {
5405
5499
  const b = body;
5406
5500
  if (!b.signature && !b.skipSigning) {
5407
5501
  const ready = this._identityReady || Promise.resolve();
5408
5502
  return ready.then(() => {
5409
5503
  if (this._identity) {
5410
- return this._signAndSend(baseRequest, method, path, b, query);
5504
+ return this._signAndSend(baseRequest, method, path, b, query, opts);
5411
5505
  }
5412
- return baseRequest(method, path, body, query);
5506
+ return baseRequest(method, path, body, query, opts);
5413
5507
  });
5414
5508
  }
5415
5509
  }
5416
- return baseRequest(method, path, body, query);
5510
+ return baseRequest(method, path, body, query, opts);
5417
5511
  };
5418
5512
  }
5419
5513
  this.im = new IMClient(
@@ -5435,9 +5529,9 @@ var PrismerClient = class {
5435
5529
  return this._identity;
5436
5530
  }
5437
5531
  /** Auto-sign a message body and send (v1.8.0 S1) */
5438
- async _signAndSend(baseRequest, method, path, body, query) {
5532
+ async _signAndSend(baseRequest, method, path, body, query, opts) {
5439
5533
  if (this._identityReady) await this._identityReady;
5440
- if (!this._identity) return baseRequest(method, path, body, query);
5534
+ if (!this._identity) return baseRequest(method, path, body, query, opts);
5441
5535
  const content = body.content || "";
5442
5536
  const contentHashBytes = new Uint8Array(
5443
5537
  await crypto.subtle.digest("SHA-256", new TextEncoder().encode(content))
@@ -5454,7 +5548,7 @@ var PrismerClient = class {
5454
5548
  contentHash,
5455
5549
  signature,
5456
5550
  signedAt: timestamp
5457
- }, query);
5551
+ }, query, opts);
5458
5552
  }
5459
5553
  /** Build auth headers for raw HTTP requests (used by file upload) */
5460
5554
  _getAuthHeaders() {
@@ -5512,7 +5606,7 @@ var PrismerClient = class {
5512
5606
  // --------------------------------------------------------------------------
5513
5607
  // Internal request helper
5514
5608
  // --------------------------------------------------------------------------
5515
- async _request(method, path, body, query, _isRetry) {
5609
+ async _request(method, path, body, query, opts, _isRetry) {
5516
5610
  const controller = new AbortController();
5517
5611
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
5518
5612
  try {
@@ -5527,6 +5621,9 @@ var PrismerClient = class {
5527
5621
  if (this.imAgent) {
5528
5622
  headers["X-IM-Agent"] = this.imAgent;
5529
5623
  }
5624
+ if (opts?.headers) {
5625
+ for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;
5626
+ }
5530
5627
  const init = { method, headers, signal: controller.signal };
5531
5628
  if (body !== void 0) {
5532
5629
  headers["Content-Type"] = "application/json";
@@ -5536,10 +5633,10 @@ var PrismerClient = class {
5536
5633
  const data = await response.json();
5537
5634
  if (response.status === 401 && this.apiKey.startsWith("eyJ") && !_isRetry && !path.includes("/token/refresh")) {
5538
5635
  try {
5539
- const refreshRes = await this._request("POST", "/api/im/token/refresh", void 0, void 0, true);
5636
+ const refreshRes = await this._request("POST", "/api/im/token/refresh", void 0, void 0, void 0, true);
5540
5637
  if (refreshRes?.ok && refreshRes?.data?.token) {
5541
5638
  this.apiKey = refreshRes.data.token;
5542
- return this._request(method, path, body, query, true);
5639
+ return this._request(method, path, body, query, opts, true);
5543
5640
  }
5544
5641
  } catch {
5545
5642
  }
@@ -5632,6 +5729,7 @@ function createClient(config) {
5632
5729
  export {
5633
5730
  AIPIdentity,
5634
5731
  AccountClient,
5732
+ AgentsClient,
5635
5733
  AssetsClient,
5636
5734
  AttachmentQueue,
5637
5735
  BindingsClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismer/sdk",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "Official TypeScript SDK for Prismer Cloud API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",