js-bao-wss-client 2.0.0 → 2.0.2

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 (48) hide show
  1. package/README.md +10 -7
  2. package/dist/JsBaoClient.d.ts +18 -24
  3. package/dist/JsBaoClient.d.ts.map +1 -1
  4. package/dist/JsBaoClient.js +9 -77
  5. package/dist/JsBaoClient.js.map +1 -1
  6. package/dist/api/blobBucketsApi.d.ts +43 -4
  7. package/dist/api/blobBucketsApi.d.ts.map +1 -1
  8. package/dist/api/blobBucketsApi.js +8 -0
  9. package/dist/api/blobBucketsApi.js.map +1 -1
  10. package/dist/api/databasesApi.d.ts +14 -1
  11. package/dist/api/databasesApi.d.ts.map +1 -1
  12. package/dist/api/databasesApi.js.map +1 -1
  13. package/dist/api/documentsApi.d.ts.map +1 -1
  14. package/dist/api/documentsApi.js +35 -7
  15. package/dist/api/documentsApi.js.map +1 -1
  16. package/dist/api/geminiApi.d.ts +34 -1
  17. package/dist/api/geminiApi.d.ts.map +1 -1
  18. package/dist/api/geminiApi.js +14 -1
  19. package/dist/api/geminiApi.js.map +1 -1
  20. package/dist/api/llmApi.d.ts +18 -1
  21. package/dist/api/llmApi.d.ts.map +1 -1
  22. package/dist/api/llmApi.js +8 -1
  23. package/dist/api/llmApi.js.map +1 -1
  24. package/dist/browser.umd.js +82 -86
  25. package/dist/browser.umd.js.map +1 -1
  26. package/dist/dev/DevTools.d.ts +38 -0
  27. package/dist/dev/DevTools.d.ts.map +1 -0
  28. package/dist/dev/DevTools.js +203 -0
  29. package/dist/dev/DevTools.js.map +1 -0
  30. package/dist/dev/index.d.ts +35 -0
  31. package/dist/dev/index.d.ts.map +1 -0
  32. package/dist/dev/index.js +40 -0
  33. package/dist/dev/index.js.map +1 -0
  34. package/dist/dev/storage.d.ts +61 -0
  35. package/dist/dev/storage.d.ts.map +1 -0
  36. package/dist/dev/storage.js +130 -0
  37. package/dist/dev/storage.js.map +1 -0
  38. package/dist/dev/useDevToken.d.ts +155 -0
  39. package/dist/dev/useDevToken.d.ts.map +1 -0
  40. package/dist/dev/useDevToken.js +266 -0
  41. package/dist/dev/useDevToken.js.map +1 -0
  42. package/dist/internal/authController.d.ts.map +1 -1
  43. package/dist/internal/authController.js +8 -0
  44. package/dist/internal/authController.js.map +1 -1
  45. package/dist/internal/databaseSubscriptions.d.ts +3 -0
  46. package/dist/internal/databaseSubscriptions.d.ts.map +1 -1
  47. package/dist/internal/databaseSubscriptions.js.map +1 -1
  48. package/package.json +11 -2
@@ -4603,6 +4603,14 @@
4603
4603
  if (!response.ok)
4604
4604
  return false;
4605
4605
  const config = await response.json();
4606
+ // The browser confidential flow exchanges the code server-side with the
4607
+ // stored client_secret, so gate on `hasWebOAuth` (clientId AND secret),
4608
+ // not `hasOAuth` (which is clientId-only for native PKCE clients). Fall
4609
+ // back to the old check when talking to an older server that doesn't yet
4610
+ // return `hasWebOAuth`.
4611
+ if (typeof config.hasWebOAuth === "boolean") {
4612
+ return config.hasWebOAuth;
4613
+ }
4606
4614
  return config.hasOAuth && !!config.googleClientId;
4607
4615
  }
4608
4616
  catch (error) {
@@ -9582,12 +9590,6 @@
9582
9590
  // existing callers (the deprecated public `list`) keep working unchanged.
9583
9591
  const endpoint = internal?.endpoint || "documents";
9584
9592
  const ownerOnly = internal?.ownerOnly === true;
9585
- // Predicate applied at all three filter sites: local-cache fetch,
9586
- // network response handling, and merged-result final union. When
9587
- // `ownerOnly` is false (legacy `documents.list`), this is the identity.
9588
- const permissionFilter = ownerOnly
9589
- ? (entry) => entry?.permission === "owner"
9590
- : null;
9591
9593
  const includeRoot = options?.includeRoot === true;
9592
9594
  const refreshFromServer = options?.localOnly
9593
9595
  ? false
@@ -9616,6 +9618,23 @@
9616
9618
  return !isIdRoot && !isRootTagged;
9617
9619
  });
9618
9620
  };
9621
+ // Issue #875: the root doc's DocumentPermission is `read-write` (never
9622
+ // `owner`), so the defense-in-depth owner filter would re-drop the root
9623
+ // doc the server now returns under `includeRoot`. Exempt it by IDENTITY
9624
+ // (id/tag), mirroring `filterRoot` above. Without this the SDK would still
9625
+ // omit the root from `me.ownedDocuments({ includeRoot: true })`.
9626
+ const isRootEntry = (entry) => {
9627
+ const isIdRoot = rootId ? entry?.documentId === rootId : false;
9628
+ const isRootTagged = Array.isArray(entry?.tags) && entry.tags.includes(ROOT_DOCUMENT_TAG);
9629
+ return isIdRoot || isRootTagged;
9630
+ };
9631
+ // Predicate applied at all three filter sites: local-cache fetch,
9632
+ // network response handling, and merged-result final union. When
9633
+ // `ownerOnly` is false (legacy `documents.list`), this is the identity.
9634
+ const permissionFilter = ownerOnly
9635
+ ? (entry) => entry?.permission === "owner" ||
9636
+ (includeRoot && isRootEntry(entry))
9637
+ : null;
9619
9638
  // Helper: local metadata -> DocumentInfo-like
9620
9639
  const getLocalMetadataList = async (onlyWithLocalData) => {
9621
9640
  const items = await this.client.listLocalDocumentsUnified({
@@ -9910,7 +9929,24 @@
9910
9929
  forward,
9911
9930
  tag,
9912
9931
  });
9913
- firstPage.items = firstPage.items.slice(0, limit);
9932
+ // Issue #875: when `includeRoot` is requested, the server prepends the
9933
+ // user's root doc to page 1 (no incoming cursor) as a singleton OUTSIDE
9934
+ // the `limit` count — so a full page legitimately carries `limit + 1`
9935
+ // rows (`[root, owned1, ..., ownedN]`). A naive `slice(0, limit)` would
9936
+ // drop the LAST owned row while the server cursor has already advanced
9937
+ // past it, permanently skipping that doc on the next page. Mirror the
9938
+ // server's semantics here: keep `limit` OWNED rows plus the root, so the
9939
+ // root never evicts a real owned row. The cursor (which reflects the last
9940
+ // OWNED row emitted, not the root prepend) is left untouched and stays
9941
+ // correct.
9942
+ if (includeRoot && !cursor) {
9943
+ const rootRows = firstPage.items.filter((it) => isRootEntry(it));
9944
+ const nonRootRows = firstPage.items.filter((it) => !isRootEntry(it));
9945
+ firstPage.items = [...rootRows, ...nonRootRows.slice(0, limit)];
9946
+ }
9947
+ else {
9948
+ firstPage.items = firstPage.items.slice(0, limit);
9949
+ }
9914
9950
  if (!firstPage.cursor) {
9915
9951
  firstPage.cursor = undefined; // do not fabricate cursor
9916
9952
  }
@@ -11650,6 +11686,9 @@
11650
11686
  * @param options.max_tokens - Maximum number of tokens to generate in the response
11651
11687
  * @param options.reasoning - Controls extended thinking behavior (effort level, token budget, visibility)
11652
11688
  * @returns The assistant message with `role`, `content`, optional `annotations`, and `raw` provider response
11689
+ * @deprecated The direct LLM client API is deprecated and will be removed in a
11690
+ * future major release. Use {@link PromptsAPI.execute | client.prompts.execute}
11691
+ * (managed prompts) or a workflow `llm.chat` step instead.
11653
11692
  */
11654
11693
  async chat(options) {
11655
11694
  const analytics = this.getAnalyticsContext();
@@ -11695,7 +11734,11 @@
11695
11734
  }
11696
11735
  }
11697
11736
  /** Lists available LLM models and returns the default model name.
11698
- * @returns Object with `models` array and `defaultModel` name */
11737
+ * @returns Object with `models` array and `defaultModel` name
11738
+ * @deprecated The direct LLM client API is deprecated and will be removed in a
11739
+ * future major release. Use {@link PromptsAPI.execute | client.prompts.execute}
11740
+ * (managed prompts) or a workflow `llm.chat` step instead.
11741
+ */
11699
11742
  async models() {
11700
11743
  return this.client.makeRequest("GET", "/llm/models");
11701
11744
  }
@@ -11714,6 +11757,9 @@
11714
11757
  * @param options.safety - Safety filter settings that control content blocking thresholds
11715
11758
  * @param options.generationConfig - Low-level generation parameters (temperature, token limits, etc.)
11716
11759
  * @param options.structuredOutput - Constrains the response to a specific MIME type and/or JSON schema
11760
+ * @deprecated The direct Gemini client API is deprecated and will be removed in
11761
+ * a future major release. Use {@link PromptsAPI.execute | client.prompts.execute}
11762
+ * (managed prompts) or a workflow `gemini.generate` step instead.
11717
11763
  */
11718
11764
  async generate(options) {
11719
11765
  const analytics = this.getAnalyticsContext();
@@ -11736,7 +11782,11 @@
11736
11782
  }
11737
11783
  }
11738
11784
  /** Lists available Gemini models and returns the default model name.
11739
- * @returns Object with `models` array and `defaultModel` name */
11785
+ * @returns Object with `models` array and `defaultModel` name
11786
+ * @deprecated The direct Gemini client API is deprecated and will be removed in
11787
+ * a future major release. Use {@link PromptsAPI.execute | client.prompts.execute}
11788
+ * (managed prompts) or a workflow `gemini.generate` step instead.
11789
+ */
11740
11790
  async models() {
11741
11791
  return this.client.makeRequest("GET", "/gemini/models");
11742
11792
  }
@@ -11750,6 +11800,9 @@
11750
11800
  * @param options.generationConfig - Generation config (included for parity but does not affect counts)
11751
11801
  * @param options.structuredOutput - Structured output config (included for parity but does not affect counts)
11752
11802
  * @returns Object with `totalTokens` count and optional `promptTokens`, `candidates`, and `raw` response
11803
+ * @deprecated The direct Gemini client API is deprecated and will be removed in
11804
+ * a future major release. Use {@link PromptsAPI.execute | client.prompts.execute}
11805
+ * (managed prompts) or a workflow `gemini.generate` step instead.
11753
11806
  */
11754
11807
  async countTokens(options) {
11755
11808
  const analytics = this.getAnalyticsContext();
@@ -11777,6 +11830,9 @@
11777
11830
  * @param options.model - The Gemini model to target (required)
11778
11831
  * @param options.body - The raw JSON payload forwarded directly to the Gemini API
11779
11832
  * @param options.query - Additional query-string parameters appended to the request URL
11833
+ * @deprecated The direct Gemini client API is deprecated and will be removed in
11834
+ * a future major release. Use {@link PromptsAPI.execute | client.prompts.execute}
11835
+ * (managed prompts) or a workflow `gemini.generate` step instead.
11780
11836
  */
11781
11837
  async generateRaw(options) {
11782
11838
  if (!options || typeof options.model !== "string" || !options.model.trim()) {
@@ -12868,6 +12924,14 @@
12868
12924
  async getBucket(bucketIdOrKey) {
12869
12925
  return this.client.makeRequest("GET", `/blob-buckets/${encodeURIComponent(bucketIdOrKey)}`);
12870
12926
  }
12927
+ /**
12928
+ * Update a bucket's access without recreating it (#1020). Admin/owner only.
12929
+ * Change the `preset`, attach/swap/clear a custom `ruleSetId`, or edit
12930
+ * `name`/`description`. Setting a non-custom preset clears any rule set.
12931
+ */
12932
+ async updateBucket(bucketIdOrKey, params) {
12933
+ return this.client.makeRequest("PATCH", `/blob-buckets/${encodeURIComponent(bucketIdOrKey)}`, params);
12934
+ }
12871
12935
  /** Delete a bucket and all blobs inside it. */
12872
12936
  async deleteBucket(bucketIdOrKey) {
12873
12937
  return this.client.makeRequest("DELETE", `/blob-buckets/${encodeURIComponent(bucketIdOrKey)}`);
@@ -13364,7 +13428,6 @@
13364
13428
  }
13365
13429
 
13366
13430
  const DEFAULT_RETURN_ACTIVE_MIN_MS = 5 * 60 * 1000;
13367
- const DEFAULT_OFFLINE_RECOVERY_MIN_MS = 60 * 1000;
13368
13431
  const DEFAULT_SYNC_ERROR_MIN_MS = 30 * 1000;
13369
13432
  const logger = createLogger({ scope: "JsBaoClient" });
13370
13433
  function debugLog(tag, payload) {
@@ -13566,13 +13629,10 @@
13566
13629
  this.analyticsMetadataUserId = null;
13567
13630
  this.analyticsMetadataHydration = null;
13568
13631
  this.sessionStartAt = Date.now();
13569
- this.bootEventLogged = false;
13570
- this.lastOfflineRecoveryAt = 0;
13571
13632
  this.lastSyncErrorEventAt = 0;
13572
13633
  this.blobUploadStartLogged = new Set();
13573
13634
  this.blobUploadSuccessLogged = new Set();
13574
13635
  this.blobUploadFailureLogged = new Set();
13575
- this.serviceWorkerControlLogged = false;
13576
13636
  this.sessionEndLogged = false;
13577
13637
  this.bootDetectedOffline = false;
13578
13638
  this.authBootstrapPromise = null;
@@ -13722,20 +13782,6 @@
13722
13782
  analyticsAuto.minResumeMs >= 0
13723
13783
  ? analyticsAuto.minResumeMs
13724
13784
  : DEFAULT_RETURN_ACTIVE_MIN_MS;
13725
- const offlineRecoveryOption = analyticsAuto.offlineRecovery;
13726
- const offlineRecoveryEnabled = offlineRecoveryOption === undefined
13727
- ? true
13728
- : typeof offlineRecoveryOption === "boolean"
13729
- ? offlineRecoveryOption
13730
- : offlineRecoveryOption?.enabled !== false;
13731
- const offlineRecoveryMinMs = offlineRecoveryOption &&
13732
- typeof offlineRecoveryOption === "object" &&
13733
- offlineRecoveryOption !== null &&
13734
- typeof offlineRecoveryOption.minIntervalMs === "number" &&
13735
- Number.isFinite(offlineRecoveryOption.minIntervalMs) &&
13736
- offlineRecoveryOption.minIntervalMs >= 0
13737
- ? offlineRecoveryOption.minIntervalMs
13738
- : DEFAULT_OFFLINE_RECOVERY_MIN_MS;
13739
13785
  const syncErrorsOption = analyticsAuto.syncErrors;
13740
13786
  const syncErrorsEnabled = syncErrorsOption === undefined
13741
13787
  ? true
@@ -13792,31 +13838,10 @@
13792
13838
  geminiFailure = geminiOption.failure !== false;
13793
13839
  }
13794
13840
  }
13795
- const serviceWorkerOption = analyticsAuto.serviceWorker;
13796
- let serviceWorkerControl = true;
13797
- let serviceWorkerTokenUpdate = true;
13798
- if (serviceWorkerOption !== undefined) {
13799
- if (typeof serviceWorkerOption === "boolean") {
13800
- serviceWorkerControl = serviceWorkerOption;
13801
- serviceWorkerTokenUpdate = serviceWorkerOption;
13802
- }
13803
- else if (typeof serviceWorkerOption === "object" &&
13804
- serviceWorkerOption !== null) {
13805
- serviceWorkerControl = serviceWorkerOption.control !== false;
13806
- serviceWorkerTokenUpdate = serviceWorkerOption.tokenUpdate !== false;
13807
- }
13808
- }
13809
13841
  this.analyticsAutoEventsConfig = {
13810
13842
  dailyAuth: analyticsAuto.dailyAuth !== false,
13811
13843
  returnActive: analyticsAuto.returnActive !== false,
13812
13844
  minResumeMs,
13813
- boot: analyticsAuto.boot !== false,
13814
- firstDocOpen: analyticsAuto.firstDocOpen !== false,
13815
- firstDocEdit: analyticsAuto.firstDocEdit !== false,
13816
- offlineRecovery: {
13817
- enabled: offlineRecoveryEnabled,
13818
- minIntervalMs: offlineRecoveryMinMs,
13819
- },
13820
13845
  syncErrors: {
13821
13846
  enabled: syncErrorsEnabled,
13822
13847
  minIntervalMs: syncErrorsMinMs,
@@ -13836,10 +13861,6 @@
13836
13861
  success: geminiSuccess,
13837
13862
  failure: geminiFailure,
13838
13863
  },
13839
- serviceWorker: {
13840
- control: serviceWorkerControl,
13841
- tokenUpdate: serviceWorkerTokenUpdate,
13842
- },
13843
13864
  sessionEnd: analyticsAuto.sessionEnd !== false,
13844
13865
  };
13845
13866
  this.offlineStore = new OfflineStore(logger);
@@ -13930,7 +13951,6 @@
13930
13951
  },
13931
13952
  uploadConcurrency: options.blobUploadConcurrency,
13932
13953
  });
13933
- this.on("documentOpened", (payload) => this.handleDocumentOpenedForAnalytics(payload));
13934
13954
  this.on("blobs:upload-progress", (payload) => this.handleBlobUploadProgress(payload));
13935
13955
  this.on("blobs:upload-completed", (payload) => this.handleBlobUploadComplete(payload));
13936
13956
  this.on("blobs:upload-failed", (payload) => this.handleBlobUploadFailed(payload));
@@ -14185,7 +14205,6 @@
14185
14205
  }
14186
14206
  };
14187
14207
  }
14188
- this.logBootEvent();
14189
14208
  logger.log(`Initializing client for app ${options.appId}`);
14190
14209
  // Initialize KV cache and public cache API facade
14191
14210
  try {
@@ -15668,8 +15687,12 @@
15668
15687
  status = "apply_pending";
15669
15688
  else if (dbStatus === "apply_claimed")
15670
15689
  status = "apply_claimed";
15690
+ // Normalize the raw Cloudflare success spelling "complete" to the
15691
+ // canonical "completed" used by the workflowStatus event, runSync, and
15692
+ // the persisted run.status (issue #967). This matches the server's own
15693
+ // mapInstanceStatus helper.
15671
15694
  else if (cfStatus === "complete")
15672
- status = "complete";
15695
+ status = "completed";
15673
15696
  else if (cfStatus === "errored")
15674
15697
  status = "failed";
15675
15698
  else if (cfStatus === "terminated")
@@ -15701,8 +15724,11 @@
15701
15724
  const rawStatus = response?.status;
15702
15725
  const cfStatus = String(rawStatus?.status || "").toLowerCase();
15703
15726
  let status;
15727
+ // Normalize the raw Cloudflare success spelling "complete" to the
15728
+ // canonical "completed" (issue #967), consistent with getStatus and the
15729
+ // workflowStatus event.
15704
15730
  if (cfStatus === "complete")
15705
- status = "complete";
15731
+ status = "completed";
15706
15732
  else if (cfStatus === "errored")
15707
15733
  status = "failed";
15708
15734
  else if (cfStatus === "terminated")
@@ -16041,10 +16067,6 @@
16041
16067
  if (!this.isServiceWorkerBridgeEnvironment())
16042
16068
  return;
16043
16069
  this.serviceWorkerBridgePendingMessages.set(type, payload);
16044
- if (type === "jsBao:tokenUpdated") {
16045
- const safePayload = payload && typeof payload === "object" ? { cause: payload.cause } : undefined;
16046
- this.logServiceWorkerTokenUpdate(safePayload);
16047
- }
16048
16070
  this.flushServiceWorkerBridgeMessages();
16049
16071
  }
16050
16072
  flushServiceWorkerBridgeMessages() {
@@ -16057,7 +16079,6 @@
16057
16079
  this.ensureServiceWorkerControllerListener();
16058
16080
  return;
16059
16081
  }
16060
- this.logServiceWorkerControl();
16061
16082
  if (this.serviceWorkerBridgeInitPayload &&
16062
16083
  !this.serviceWorkerBridgePendingMessages.has("jsBao:init")) {
16063
16084
  this.serviceWorkerBridgePendingMessages.set("jsBao:init", this.serviceWorkerBridgeInitPayload);
@@ -16223,7 +16244,6 @@
16223
16244
  this.analyticsMetadataUserId = null;
16224
16245
  }
16225
16246
  resetSessionAutoEventState() {
16226
- this.lastOfflineRecoveryAt = 0;
16227
16247
  this.lastSyncErrorEventAt = 0;
16228
16248
  this.blobUploadStartLogged.clear();
16229
16249
  this.blobUploadSuccessLogged.clear();
@@ -16369,19 +16389,6 @@
16369
16389
  logger.warn("[analytics] return-active auto-event error", err);
16370
16390
  });
16371
16391
  }
16372
- logBootEvent() {
16373
- // Removed: client_boot fires before auth completes so it has no user.
16374
- // Listen for first user_active_daily instead.
16375
- }
16376
- handleDocumentOpenedForAnalytics(_event) {
16377
- // Removed: low value; apps can log their own document events.
16378
- }
16379
- maybeLogFirstDocEdit(_documentId) {
16380
- // Removed: low value; apps can log their own document events.
16381
- }
16382
- maybeLogOfflineRecoveryEvent(_source) {
16383
- // Removed: rare edge case, not actionable.
16384
- }
16385
16392
  maybeLogSyncErrorEvent(documentId, reason) {
16386
16393
  const config = this.analyticsAutoEventsConfig.syncErrors;
16387
16394
  if (!config.enabled)
@@ -16457,13 +16464,6 @@
16457
16464
  },
16458
16465
  });
16459
16466
  }
16460
- logServiceWorkerControl() {
16461
- // TODO: log service_worker_control in an admin-facing analytics system
16462
- // (fires before/without auth — no user context available)
16463
- }
16464
- logServiceWorkerTokenUpdate(_payload) {
16465
- // Removed: internal implementation detail.
16466
- }
16467
16467
  logSessionEndEvent(reason) {
16468
16468
  if (!this.analyticsAutoEventsConfig.sessionEnd || this.sessionEndLogged) {
16469
16469
  return;
@@ -16710,7 +16710,6 @@
16710
16710
  });
16711
16711
  }
16712
16712
  enqueueLocalUpdate(documentId, update) {
16713
- this.maybeLogFirstDocEdit(documentId);
16714
16713
  const existing = this.pendingLocalUpdates.get(documentId);
16715
16714
  const updateCopy = new Uint8Array(update); // clone to avoid accidental mutation
16716
16715
  if (existing) {
@@ -20017,9 +20016,6 @@
20017
20016
  }, this.buildCommitRetryContext());
20018
20017
  }
20019
20018
  catch (_) { }
20020
- if (previousMode === "offline") {
20021
- this.maybeLogOfflineRecoveryEvent("setNetworkMode");
20022
- }
20023
20019
  }
20024
20020
  else {
20025
20021
  // auto: if we have a token, allow connect/reconnect