@aomi-labs/client 0.1.11 → 0.1.13

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/cli.js CHANGED
@@ -729,6 +729,22 @@ function createSseSubscriber({
729
729
  // src/client.ts
730
730
  var SESSION_ID_HEADER = "X-Session-Id";
731
731
  var API_KEY_HEADER = "X-API-Key";
732
+ function joinApiPath(baseUrl, path) {
733
+ const normalizedBase = baseUrl === "/" ? "" : baseUrl.replace(/\/+$/, "");
734
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
735
+ return `${normalizedBase}${normalizedPath}` || normalizedPath;
736
+ }
737
+ function buildApiUrl(baseUrl, path, query) {
738
+ const url = joinApiPath(baseUrl, path);
739
+ if (!query) return url;
740
+ const params = new URLSearchParams();
741
+ for (const [key, value] of Object.entries(query)) {
742
+ if (value === void 0) continue;
743
+ params.set(key, value);
744
+ }
745
+ const queryString = params.toString();
746
+ return queryString ? `${url}?${queryString}` : url;
747
+ }
732
748
  function toQueryString(payload) {
733
749
  const params = new URLSearchParams();
734
750
  for (const [key, value] of Object.entries(payload)) {
@@ -776,12 +792,12 @@ var AomiClient = class {
776
792
  /**
777
793
  * Fetch current session state (messages, processing status, title).
778
794
  */
779
- async fetchState(sessionId, userState) {
780
- const url = new URL("/api/state", this.baseUrl);
781
- if (userState) {
782
- url.searchParams.set("user_state", JSON.stringify(userState));
783
- }
784
- const response = await fetch(url.toString(), {
795
+ async fetchState(sessionId, userState, clientId) {
796
+ const url = buildApiUrl(this.baseUrl, "/api/state", {
797
+ user_state: userState ? JSON.stringify(userState) : void 0,
798
+ client_id: clientId
799
+ });
800
+ const response = await fetch(url, {
785
801
  headers: withSessionHeader(sessionId)
786
802
  });
787
803
  if (!response.ok) {
@@ -803,6 +819,9 @@ var AomiClient = class {
803
819
  if (options == null ? void 0 : options.userState) {
804
820
  payload.user_state = JSON.stringify(options.userState);
805
821
  }
822
+ if (options == null ? void 0 : options.clientId) {
823
+ payload.client_id = options.clientId;
824
+ }
806
825
  return postState(
807
826
  this.baseUrl,
808
827
  "/api/chat",
@@ -834,6 +853,40 @@ var AomiClient = class {
834
853
  );
835
854
  }
836
855
  // ===========================================================================
856
+ // Secrets
857
+ // ===========================================================================
858
+ /**
859
+ * Ingest secrets for a client. Returns opaque `$SECRET:<name>` handles.
860
+ * Call this once at page load (or when secrets change) with a stable
861
+ * client_id for the browser tab. The same client_id should be passed
862
+ * to `sendMessage` / `fetchState` so sessions get associated.
863
+ */
864
+ async ingestSecrets(clientId, secrets) {
865
+ const url = joinApiPath(this.baseUrl, "/api/secrets");
866
+ const response = await fetch(url, {
867
+ method: "POST",
868
+ headers: { "Content-Type": "application/json" },
869
+ body: JSON.stringify({ client_id: clientId, secrets })
870
+ });
871
+ if (!response.ok) {
872
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
873
+ }
874
+ return await response.json();
875
+ }
876
+ /**
877
+ * Clear all secrets for a client (e.g. on page unload or logout).
878
+ */
879
+ async clearSecrets(clientId) {
880
+ const url = buildApiUrl(this.baseUrl, "/api/secrets", {
881
+ client_id: clientId
882
+ });
883
+ const response = await fetch(url, { method: "DELETE" });
884
+ if (!response.ok) {
885
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
886
+ }
887
+ return await response.json();
888
+ }
889
+ // ===========================================================================
837
890
  // SSE (Real-time Updates)
838
891
  // ===========================================================================
839
892
  /**
@@ -851,7 +904,9 @@ var AomiClient = class {
851
904
  * List all threads for a wallet address.
852
905
  */
853
906
  async listThreads(publicKey) {
854
- const url = `${this.baseUrl}/api/sessions?public_key=${encodeURIComponent(publicKey)}`;
907
+ const url = buildApiUrl(this.baseUrl, "/api/sessions", {
908
+ public_key: publicKey
909
+ });
855
910
  const response = await fetch(url);
856
911
  if (!response.ok) {
857
912
  throw new Error(`Failed to fetch threads: HTTP ${response.status}`);
@@ -862,7 +917,10 @@ var AomiClient = class {
862
917
  * Get a single thread by ID.
863
918
  */
864
919
  async getThread(sessionId) {
865
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
920
+ const url = buildApiUrl(
921
+ this.baseUrl,
922
+ `/api/sessions/${encodeURIComponent(sessionId)}`
923
+ );
866
924
  const response = await fetch(url, {
867
925
  headers: withSessionHeader(sessionId)
868
926
  });
@@ -877,7 +935,7 @@ var AomiClient = class {
877
935
  async createThread(threadId, publicKey) {
878
936
  const body = {};
879
937
  if (publicKey) body.public_key = publicKey;
880
- const url = `${this.baseUrl}/api/sessions`;
938
+ const url = buildApiUrl(this.baseUrl, "/api/sessions");
881
939
  const response = await fetch(url, {
882
940
  method: "POST",
883
941
  headers: withSessionHeader(threadId, {
@@ -894,7 +952,10 @@ var AomiClient = class {
894
952
  * Delete a thread by ID.
895
953
  */
896
954
  async deleteThread(sessionId) {
897
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
955
+ const url = buildApiUrl(
956
+ this.baseUrl,
957
+ `/api/sessions/${encodeURIComponent(sessionId)}`
958
+ );
898
959
  const response = await fetch(url, {
899
960
  method: "DELETE",
900
961
  headers: withSessionHeader(sessionId)
@@ -907,7 +968,10 @@ var AomiClient = class {
907
968
  * Rename a thread.
908
969
  */
909
970
  async renameThread(sessionId, newTitle) {
910
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
971
+ const url = buildApiUrl(
972
+ this.baseUrl,
973
+ `/api/sessions/${encodeURIComponent(sessionId)}`
974
+ );
911
975
  const response = await fetch(url, {
912
976
  method: "PATCH",
913
977
  headers: withSessionHeader(sessionId, {
@@ -923,7 +987,10 @@ var AomiClient = class {
923
987
  * Archive a thread.
924
988
  */
925
989
  async archiveThread(sessionId) {
926
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/archive`;
990
+ const url = buildApiUrl(
991
+ this.baseUrl,
992
+ `/api/sessions/${encodeURIComponent(sessionId)}/archive`
993
+ );
927
994
  const response = await fetch(url, {
928
995
  method: "POST",
929
996
  headers: withSessionHeader(sessionId)
@@ -936,7 +1003,10 @@ var AomiClient = class {
936
1003
  * Unarchive a thread.
937
1004
  */
938
1005
  async unarchiveThread(sessionId) {
939
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/unarchive`;
1006
+ const url = buildApiUrl(
1007
+ this.baseUrl,
1008
+ `/api/sessions/${encodeURIComponent(sessionId)}/unarchive`
1009
+ );
940
1010
  const response = await fetch(url, {
941
1011
  method: "POST",
942
1012
  headers: withSessionHeader(sessionId)
@@ -952,11 +1022,10 @@ var AomiClient = class {
952
1022
  * Get system events for a session.
953
1023
  */
954
1024
  async getSystemEvents(sessionId, count) {
955
- const url = new URL("/api/events", this.baseUrl);
956
- if (count !== void 0) {
957
- url.searchParams.set("count", String(count));
958
- }
959
- const response = await fetch(url.toString(), {
1025
+ const url = buildApiUrl(this.baseUrl, "/api/events", {
1026
+ count: count !== void 0 ? String(count) : void 0
1027
+ });
1028
+ const response = await fetch(url, {
960
1029
  headers: withSessionHeader(sessionId)
961
1030
  });
962
1031
  if (!response.ok) {
@@ -973,16 +1042,15 @@ var AomiClient = class {
973
1042
  */
974
1043
  async getApps(sessionId, options) {
975
1044
  var _a3;
976
- const url = new URL("/api/control/apps", this.baseUrl);
977
- if (options == null ? void 0 : options.publicKey) {
978
- url.searchParams.set("public_key", options.publicKey);
979
- }
1045
+ const url = buildApiUrl(this.baseUrl, "/api/control/apps", {
1046
+ public_key: options == null ? void 0 : options.publicKey
1047
+ });
980
1048
  const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
981
1049
  const headers = new Headers(withSessionHeader(sessionId));
982
1050
  if (apiKey) {
983
1051
  headers.set(API_KEY_HEADER, apiKey);
984
1052
  }
985
- const response = await fetch(url.toString(), { headers });
1053
+ const response = await fetch(url, { headers });
986
1054
  if (!response.ok) {
987
1055
  throw new Error(`Failed to get apps: HTTP ${response.status}`);
988
1056
  }
@@ -993,13 +1061,13 @@ var AomiClient = class {
993
1061
  */
994
1062
  async getModels(sessionId, options) {
995
1063
  var _a3;
996
- const url = new URL("/api/control/models", this.baseUrl);
1064
+ const url = buildApiUrl(this.baseUrl, "/api/control/models");
997
1065
  const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
998
1066
  const headers = new Headers(withSessionHeader(sessionId));
999
1067
  if (apiKey) {
1000
1068
  headers.set(API_KEY_HEADER, apiKey);
1001
1069
  }
1002
- const response = await fetch(url.toString(), {
1070
+ const response = await fetch(url, {
1003
1071
  headers
1004
1072
  });
1005
1073
  if (!response.ok) {
@@ -1228,6 +1296,9 @@ function toViemSignTypedDataArgs(payload) {
1228
1296
  }
1229
1297
 
1230
1298
  // src/session.ts
1299
+ function isRecord(value) {
1300
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1301
+ }
1231
1302
  function sortJson(value) {
1232
1303
  if (Array.isArray(value)) {
1233
1304
  return value.map((entry) => sortJson(entry));
@@ -1450,6 +1521,30 @@ var ClientSession = class extends TypedEventEmitter {
1450
1521
  this.publicKey = address;
1451
1522
  }
1452
1523
  }
1524
+ addExtValue(key, value) {
1525
+ var _a3;
1526
+ const current = (_a3 = this.userState) != null ? _a3 : {};
1527
+ const currentExt = isRecord(current["ext"]) ? current["ext"] : {};
1528
+ this.resolveUserState(__spreadProps(__spreadValues({}, current), {
1529
+ ext: __spreadProps(__spreadValues({}, currentExt), {
1530
+ [key]: value
1531
+ })
1532
+ }));
1533
+ }
1534
+ removeExtValue(key) {
1535
+ if (!this.userState) return;
1536
+ const currentExt = this.userState["ext"];
1537
+ if (!isRecord(currentExt)) return;
1538
+ const nextExt = __spreadValues({}, currentExt);
1539
+ delete nextExt[key];
1540
+ const nextState = __spreadValues({}, this.userState);
1541
+ if (Object.keys(nextExt).length === 0) {
1542
+ delete nextState["ext"];
1543
+ } else {
1544
+ nextState["ext"] = nextExt;
1545
+ }
1546
+ this.resolveUserState(nextState);
1547
+ }
1453
1548
  resolveWallet(address, chainId) {
1454
1549
  this.resolveUserState({ address, chainId: chainId != null ? chainId : 1, isConnected: true });
1455
1550
  }
package/dist/index.cjs CHANGED
@@ -254,6 +254,22 @@ function createSseSubscriber({
254
254
  // src/client.ts
255
255
  var SESSION_ID_HEADER = "X-Session-Id";
256
256
  var API_KEY_HEADER = "X-API-Key";
257
+ function joinApiPath(baseUrl, path) {
258
+ const normalizedBase = baseUrl === "/" ? "" : baseUrl.replace(/\/+$/, "");
259
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
260
+ return `${normalizedBase}${normalizedPath}` || normalizedPath;
261
+ }
262
+ function buildApiUrl(baseUrl, path, query) {
263
+ const url = joinApiPath(baseUrl, path);
264
+ if (!query) return url;
265
+ const params = new URLSearchParams();
266
+ for (const [key, value] of Object.entries(query)) {
267
+ if (value === void 0) continue;
268
+ params.set(key, value);
269
+ }
270
+ const queryString = params.toString();
271
+ return queryString ? `${url}?${queryString}` : url;
272
+ }
257
273
  function toQueryString(payload) {
258
274
  const params = new URLSearchParams();
259
275
  for (const [key, value] of Object.entries(payload)) {
@@ -301,12 +317,12 @@ var AomiClient = class {
301
317
  /**
302
318
  * Fetch current session state (messages, processing status, title).
303
319
  */
304
- async fetchState(sessionId, userState) {
305
- const url = new URL("/api/state", this.baseUrl);
306
- if (userState) {
307
- url.searchParams.set("user_state", JSON.stringify(userState));
308
- }
309
- const response = await fetch(url.toString(), {
320
+ async fetchState(sessionId, userState, clientId) {
321
+ const url = buildApiUrl(this.baseUrl, "/api/state", {
322
+ user_state: userState ? JSON.stringify(userState) : void 0,
323
+ client_id: clientId
324
+ });
325
+ const response = await fetch(url, {
310
326
  headers: withSessionHeader(sessionId)
311
327
  });
312
328
  if (!response.ok) {
@@ -328,6 +344,9 @@ var AomiClient = class {
328
344
  if (options == null ? void 0 : options.userState) {
329
345
  payload.user_state = JSON.stringify(options.userState);
330
346
  }
347
+ if (options == null ? void 0 : options.clientId) {
348
+ payload.client_id = options.clientId;
349
+ }
331
350
  return postState(
332
351
  this.baseUrl,
333
352
  "/api/chat",
@@ -359,6 +378,40 @@ var AomiClient = class {
359
378
  );
360
379
  }
361
380
  // ===========================================================================
381
+ // Secrets
382
+ // ===========================================================================
383
+ /**
384
+ * Ingest secrets for a client. Returns opaque `$SECRET:<name>` handles.
385
+ * Call this once at page load (or when secrets change) with a stable
386
+ * client_id for the browser tab. The same client_id should be passed
387
+ * to `sendMessage` / `fetchState` so sessions get associated.
388
+ */
389
+ async ingestSecrets(clientId, secrets) {
390
+ const url = joinApiPath(this.baseUrl, "/api/secrets");
391
+ const response = await fetch(url, {
392
+ method: "POST",
393
+ headers: { "Content-Type": "application/json" },
394
+ body: JSON.stringify({ client_id: clientId, secrets })
395
+ });
396
+ if (!response.ok) {
397
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
398
+ }
399
+ return await response.json();
400
+ }
401
+ /**
402
+ * Clear all secrets for a client (e.g. on page unload or logout).
403
+ */
404
+ async clearSecrets(clientId) {
405
+ const url = buildApiUrl(this.baseUrl, "/api/secrets", {
406
+ client_id: clientId
407
+ });
408
+ const response = await fetch(url, { method: "DELETE" });
409
+ if (!response.ok) {
410
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
411
+ }
412
+ return await response.json();
413
+ }
414
+ // ===========================================================================
362
415
  // SSE (Real-time Updates)
363
416
  // ===========================================================================
364
417
  /**
@@ -376,7 +429,9 @@ var AomiClient = class {
376
429
  * List all threads for a wallet address.
377
430
  */
378
431
  async listThreads(publicKey) {
379
- const url = `${this.baseUrl}/api/sessions?public_key=${encodeURIComponent(publicKey)}`;
432
+ const url = buildApiUrl(this.baseUrl, "/api/sessions", {
433
+ public_key: publicKey
434
+ });
380
435
  const response = await fetch(url);
381
436
  if (!response.ok) {
382
437
  throw new Error(`Failed to fetch threads: HTTP ${response.status}`);
@@ -387,7 +442,10 @@ var AomiClient = class {
387
442
  * Get a single thread by ID.
388
443
  */
389
444
  async getThread(sessionId) {
390
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
445
+ const url = buildApiUrl(
446
+ this.baseUrl,
447
+ `/api/sessions/${encodeURIComponent(sessionId)}`
448
+ );
391
449
  const response = await fetch(url, {
392
450
  headers: withSessionHeader(sessionId)
393
451
  });
@@ -402,7 +460,7 @@ var AomiClient = class {
402
460
  async createThread(threadId, publicKey) {
403
461
  const body = {};
404
462
  if (publicKey) body.public_key = publicKey;
405
- const url = `${this.baseUrl}/api/sessions`;
463
+ const url = buildApiUrl(this.baseUrl, "/api/sessions");
406
464
  const response = await fetch(url, {
407
465
  method: "POST",
408
466
  headers: withSessionHeader(threadId, {
@@ -419,7 +477,10 @@ var AomiClient = class {
419
477
  * Delete a thread by ID.
420
478
  */
421
479
  async deleteThread(sessionId) {
422
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
480
+ const url = buildApiUrl(
481
+ this.baseUrl,
482
+ `/api/sessions/${encodeURIComponent(sessionId)}`
483
+ );
423
484
  const response = await fetch(url, {
424
485
  method: "DELETE",
425
486
  headers: withSessionHeader(sessionId)
@@ -432,7 +493,10 @@ var AomiClient = class {
432
493
  * Rename a thread.
433
494
  */
434
495
  async renameThread(sessionId, newTitle) {
435
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
496
+ const url = buildApiUrl(
497
+ this.baseUrl,
498
+ `/api/sessions/${encodeURIComponent(sessionId)}`
499
+ );
436
500
  const response = await fetch(url, {
437
501
  method: "PATCH",
438
502
  headers: withSessionHeader(sessionId, {
@@ -448,7 +512,10 @@ var AomiClient = class {
448
512
  * Archive a thread.
449
513
  */
450
514
  async archiveThread(sessionId) {
451
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/archive`;
515
+ const url = buildApiUrl(
516
+ this.baseUrl,
517
+ `/api/sessions/${encodeURIComponent(sessionId)}/archive`
518
+ );
452
519
  const response = await fetch(url, {
453
520
  method: "POST",
454
521
  headers: withSessionHeader(sessionId)
@@ -461,7 +528,10 @@ var AomiClient = class {
461
528
  * Unarchive a thread.
462
529
  */
463
530
  async unarchiveThread(sessionId) {
464
- const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/unarchive`;
531
+ const url = buildApiUrl(
532
+ this.baseUrl,
533
+ `/api/sessions/${encodeURIComponent(sessionId)}/unarchive`
534
+ );
465
535
  const response = await fetch(url, {
466
536
  method: "POST",
467
537
  headers: withSessionHeader(sessionId)
@@ -477,11 +547,10 @@ var AomiClient = class {
477
547
  * Get system events for a session.
478
548
  */
479
549
  async getSystemEvents(sessionId, count) {
480
- const url = new URL("/api/events", this.baseUrl);
481
- if (count !== void 0) {
482
- url.searchParams.set("count", String(count));
483
- }
484
- const response = await fetch(url.toString(), {
550
+ const url = buildApiUrl(this.baseUrl, "/api/events", {
551
+ count: count !== void 0 ? String(count) : void 0
552
+ });
553
+ const response = await fetch(url, {
485
554
  headers: withSessionHeader(sessionId)
486
555
  });
487
556
  if (!response.ok) {
@@ -498,16 +567,15 @@ var AomiClient = class {
498
567
  */
499
568
  async getApps(sessionId, options) {
500
569
  var _a;
501
- const url = new URL("/api/control/apps", this.baseUrl);
502
- if (options == null ? void 0 : options.publicKey) {
503
- url.searchParams.set("public_key", options.publicKey);
504
- }
570
+ const url = buildApiUrl(this.baseUrl, "/api/control/apps", {
571
+ public_key: options == null ? void 0 : options.publicKey
572
+ });
505
573
  const apiKey = (_a = options == null ? void 0 : options.apiKey) != null ? _a : this.apiKey;
506
574
  const headers = new Headers(withSessionHeader(sessionId));
507
575
  if (apiKey) {
508
576
  headers.set(API_KEY_HEADER, apiKey);
509
577
  }
510
- const response = await fetch(url.toString(), { headers });
578
+ const response = await fetch(url, { headers });
511
579
  if (!response.ok) {
512
580
  throw new Error(`Failed to get apps: HTTP ${response.status}`);
513
581
  }
@@ -518,13 +586,13 @@ var AomiClient = class {
518
586
  */
519
587
  async getModels(sessionId, options) {
520
588
  var _a;
521
- const url = new URL("/api/control/models", this.baseUrl);
589
+ const url = buildApiUrl(this.baseUrl, "/api/control/models");
522
590
  const apiKey = (_a = options == null ? void 0 : options.apiKey) != null ? _a : this.apiKey;
523
591
  const headers = new Headers(withSessionHeader(sessionId));
524
592
  if (apiKey) {
525
593
  headers.set(API_KEY_HEADER, apiKey);
526
594
  }
527
- const response = await fetch(url.toString(), {
595
+ const response = await fetch(url, {
528
596
  headers
529
597
  });
530
598
  if (!response.ok) {
@@ -753,6 +821,9 @@ function toViemSignTypedDataArgs(payload) {
753
821
  }
754
822
 
755
823
  // src/session.ts
824
+ function isRecord(value) {
825
+ return typeof value === "object" && value !== null && !Array.isArray(value);
826
+ }
756
827
  function sortJson(value) {
757
828
  if (Array.isArray(value)) {
758
829
  return value.map((entry) => sortJson(entry));
@@ -975,6 +1046,30 @@ var ClientSession = class extends TypedEventEmitter {
975
1046
  this.publicKey = address;
976
1047
  }
977
1048
  }
1049
+ addExtValue(key, value) {
1050
+ var _a;
1051
+ const current = (_a = this.userState) != null ? _a : {};
1052
+ const currentExt = isRecord(current["ext"]) ? current["ext"] : {};
1053
+ this.resolveUserState(__spreadProps(__spreadValues({}, current), {
1054
+ ext: __spreadProps(__spreadValues({}, currentExt), {
1055
+ [key]: value
1056
+ })
1057
+ }));
1058
+ }
1059
+ removeExtValue(key) {
1060
+ if (!this.userState) return;
1061
+ const currentExt = this.userState["ext"];
1062
+ if (!isRecord(currentExt)) return;
1063
+ const nextExt = __spreadValues({}, currentExt);
1064
+ delete nextExt[key];
1065
+ const nextState = __spreadValues({}, this.userState);
1066
+ if (Object.keys(nextExt).length === 0) {
1067
+ delete nextState["ext"];
1068
+ } else {
1069
+ nextState["ext"] = nextExt;
1070
+ }
1071
+ this.resolveUserState(nextState);
1072
+ }
978
1073
  resolveWallet(address, chainId) {
979
1074
  this.resolveUserState({ address, chainId: chainId != null ? chainId : 1, isConnected: true });
980
1075
  }