js-bao-wss-client 2.2.0-alpha.14 → 2.2.0-alpha.15

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/README.md CHANGED
@@ -18,7 +18,6 @@ A TypeScript/JavaScript client library for js-bao-wss that provides HTTP APIs an
18
18
  - **Analytics**: Buffered event logging API with optional automatic lifecycle events
19
19
  - **Blob Storage**: Upload/list/get/downloadUrl/delete per document with offline cache
20
20
  - **Server Functions**: Invoke your app's server functions, start and wait on long-running runs, and join the channels they authorize
21
- - **LLM**: Chat API and model listing _(deprecated — run a managed prompt from a server function (`ctx.prompts.run`) instead)_
22
21
  - **Offline-first Open**: Non-blocking open with IndexedDB-backed cache
23
22
  - **Offline Blob Cache**: Cache API + IndexedDB backed uploads/reads with eviction and retry
24
23
  - **Network Controls**: Online/offline modes, reachability, connection control
@@ -595,7 +594,6 @@ The client exposes a buffered analytics queue that batches events, retries on re
595
594
  - `client.analytics.logEvent({ action, feature, context_json?, ... })`: enqueue a single event. `context_json` accepts an object (auto-serialized) or a JSON string.
596
595
  - `client.analytics.flush()`: attempt to send the queue immediately; also runs automatically on reconnect and right before unload/destroy.
597
596
  - `client.analytics.setPlanOverride(plan)` and `.setAppVersionOverride(version)`: stamp metadata onto every subsequent event until you clear or replace it.
598
- - `client.getLlmAnalyticsContext()`: returns `{ logEvent, isEnabled }` when any LLM auto phases are enabled so higher-level features can coordinate their own analytics.
599
597
 
600
598
  Queued events are persisted in IndexedDB when offline storage is active, so short offline windows or reloads do not drop data. Everything funnels through the same `analytics.batch` WebSocket channel used by the live event test.
601
599
 
@@ -608,9 +606,6 @@ All automatic emitters are on by default; pass `analyticsAutoEvents` when constr
608
606
  - `sync_error` (`"sync"`, toggle: `analyticsAutoEvents.syncErrors.enabled`): records the `documentId` and `reason` when flush/send attempts fail (with interval throttling).
609
607
  - `blob_upload_started` / `blob_upload_succeeded` / `blob_upload_failed` (`"blobs"`, toggles: `analyticsAutoEvents.blobUploads.{start|success|failure}`): include blob/document identifiers, attempt counts, byte size, and retry details (with truncated error text on failure).
610
608
  - `session_end` (`"session"`, toggle: `analyticsAutoEvents.sessionEnd`): emitted on `beforeunload` and `client.destroy()`, including `duration_ms` and exit reason.
611
- - `prompt_started` / `prompt_succeeded` / `prompt_failed` (`"llm"` or `"gemini"`, toggles: `analyticsAutoEvents.llm.{start|success|failure}` and `analyticsAutoEvents.gemini.{start|success|failure}`): unified prompt lifecycle events emitted by `client.llm.chat()` and `client.gemini.generate()`/`client.gemini.countTokens()`. The `feature` field distinguishes the provider.
612
-
613
- When `analyticsAutoEvents.llm` enables any of `start`, `success`, or `failure`, `client.getLlmAnalyticsContext()` becomes non-null so LLM helpers can emit structured events without guessing configuration. `analyticsAutoEvents.gemini` controls `client.getGeminiAnalyticsContext()`, which powers automatic logging inside the Gemini namespace.
614
609
 
615
610
  **Removed events** (no longer emitted, and their option flags have been removed from `analyticsAutoEvents`): `client_boot` (`boot`), `first_doc_open` (`firstDocOpen`), `first_doc_edit` (`firstDocEdit`), `offline_recovery` (`offlineRecovery`), `service_worker_control` / `service_worker_token_update` (`serviceWorker`), `llm_request_*`, `gemini_request_*`.
616
611
 
@@ -621,7 +616,7 @@ const client = await initializeClient({
621
616
  ...options,
622
617
  analyticsAutoEvents: {
623
618
  blobUploads: { start: false, success: true, failure: true },
624
- llm: { start: true, success: true, failure: false },
619
+ sessionEnd: false,
625
620
  },
626
621
  });
627
622
  ```
@@ -1802,142 +1797,6 @@ const user = await client.users.getBasic("u01H...");
1802
1797
  console.log(user.name, user.email, user.appRole);
1803
1798
  ```
1804
1799
 
1805
- ## Large Language Models (LLM)
1806
-
1807
- > **Deprecated.** The direct LLM client API (`client.llm.*`) is deprecated and will be removed in a future major release. Run a managed prompt from a server function (`ctx.prompts.run`) instead.
1808
-
1809
- ```typescript
1810
- // List available models
1811
- const { models, defaultModel } = await client.llm.models();
1812
- console.log("Default model:", defaultModel);
1813
-
1814
- // Basic chat
1815
- const reply = await client.llm.chat({
1816
- // model is optional; uses server default when omitted
1817
- messages: [
1818
- { role: "system", content: "You are a helpful assistant." },
1819
- { role: "user", content: "Summarize: Collaborative editing with Yjs." },
1820
- ],
1821
- temperature: 0.2,
1822
- max_tokens: 512,
1823
- reasoning: {
1824
- effort: "medium",
1825
- exclude: false,
1826
- },
1827
- });
1828
- console.log(reply.content);
1829
-
1830
- // Chat with image attachment (base64-encoded PNG)
1831
- const imageBase64 = await loadImageAsBase64("/path/to/screenshot.png");
1832
- const imageReply = await client.llm.chat({
1833
- messages: [
1834
- {
1835
- role: "system",
1836
- content: "You analyze screenshots and respond helpfully.",
1837
- },
1838
- { role: "user", content: "Describe what you see in this image." },
1839
- ],
1840
- attachments: [
1841
- {
1842
- type: "image",
1843
- mime: "image/png",
1844
- base64: imageBase64,
1845
- },
1846
- ],
1847
- });
1848
- console.log(imageReply.content);
1849
- ```
1850
-
1851
- ## Gemini
1852
-
1853
- > **Deprecated.** The direct Gemini client API (`client.gemini.*`) is deprecated and will be removed in a future major release. Run a managed prompt from a server function (`ctx.prompts.run`) instead.
1854
-
1855
- ```typescript
1856
- // Text generation with optional structured output
1857
- const result = await client.gemini.generate({
1858
- messages: [
1859
- {
1860
- role: "system",
1861
- parts: [{ type: "text", text: "Reply in JSON with keys title and summary." }],
1862
- },
1863
- {
1864
- role: "user",
1865
- parts: [{ type: "text", text: "Summarize collaborative editing with Yjs." }],
1866
- },
1867
- ],
1868
- structuredOutput: {
1869
- responseMimeType: "application/json",
1870
- responseJsonSchema: {
1871
- type: "object",
1872
- properties: {
1873
- title: { type: "string" },
1874
- summary: { type: "string" },
1875
- },
1876
- required: ["title", "summary"],
1877
- },
1878
- },
1879
- });
1880
- console.log(result.message.parts[0].text);
1881
-
1882
- // Multimodal prompt with inline image data
1883
- const screenshot = await loadImageAsBase64("/path/to/screenshot.png");
1884
- await client.gemini.generate({
1885
- messages: [
1886
- {
1887
- role: "user",
1888
- parts: [
1889
- { type: "text", text: "Describe this screenshot." },
1890
- { type: "image", mimeType: "image/png", base64Data: screenshot },
1891
- ],
1892
- },
1893
- ],
1894
- });
1895
-
1896
- // Raw passthrough using Google's payload schema
1897
- const rawPayload = {
1898
- contents: [
1899
- {
1900
- role: "user",
1901
- parts: [
1902
- {
1903
- text: "Summarize this JSON.",
1904
- },
1905
- {
1906
- inline_data: {
1907
- mimeType: "application/json",
1908
- data: someBase64Json,
1909
- },
1910
- },
1911
- ],
1912
- },
1913
- ],
1914
- };
1915
- const rawResponse = await client.gemini.generateRaw({
1916
- model: "models/gemini-2.5-flash",
1917
- body: rawPayload,
1918
- });
1919
- console.log(rawResponse.candidates?.[0]?.content);
1920
-
1921
- // Token usage estimation
1922
- const tokens = await client.gemini.countTokens({
1923
- model: "models/gemini-2.5-flash",
1924
- messages: [{ role: "user", parts: [{ type: "text", text: "How many tokens?" }] }],
1925
- });
1926
- console.log(tokens.totalTokens);
1927
- ```
1928
-
1929
- ### Gemini Configuration & Notes
1930
-
1931
- - `client.gemini` proxies to server-side routes:
1932
- - `GET /gemini/models` → `client.gemini.models()`
1933
- - `POST /gemini/generate` → `client.gemini.generate(...)`
1934
- - `POST /gemini/count-tokens` → `client.gemini.countTokens(...)`
1935
- - `POST /gemini/generate-raw` → `client.gemini.generateRaw({ model, body })`
1936
- These endpoints run server-side, so browser clients never see Google credentials.
1937
- - Inline multimodal content uses base64 `parts` (text, image, file), up to about 25 MB per request.
1938
- - Structured output leverages `generationConfig.responseMimeType` plus optional `responseSchema` / `responseJsonSchema` so Gemini can return deterministic JSON. The full server response is always available via the `raw` field when you need annotations or safety metadata.
1939
- - Error handling surfaces `JsBaoError` with `code: "GEMINI_ERROR"`; the `details` property contains the raw upstream payload so you can log or render troubleshooting info.
1940
-
1941
1800
  ## Server Functions
1942
1801
 
1943
1802
  A server function is TypeScript your app's team writes in its config tree and
@@ -20,8 +20,6 @@ import { DocumentsAPI, DocumentContext, type DocumentInfo, type ResolveAliasPara
20
20
  import { type CacheFacade } from "./api/cacheFacade";
21
21
  import { MeAPI } from "./api/meApi";
22
22
  import { SessionAPI } from "./api/sessionApi";
23
- import { LlmAPI } from "./api/llmApi";
24
- import { GeminiAPI } from "./api/geminiApi";
25
23
  import { UsersAPI } from "./api/usersApi";
26
24
  import { DatabasesAPI } from "./api/databasesApi";
27
25
  import { GroupsAPI } from "./api/groupsApi";
@@ -56,15 +54,12 @@ export type { AppInvitationInfo, InvitationQuota, CreateInvitationParams, Invita
56
54
  export type { DoDb, DOClientEngine, ModelIdentifier, ModelFieldInfo, SaveOptions } from "js-bao/client";
57
55
  export type { DiscoveredSchema, DiscoveredModel, DiscoveredField, DiscoveredConstraint, DiscoveredRelationship } from "js-bao";
58
56
  export type { CacheFacade } from "./api/cacheFacade";
59
- export type { ReasoningOptions, LlmChatOptions } from "./api/llmApi";
60
57
  export type { AnalyticsEventInput } from "./internal/analyticsQueue";
61
58
  export { ANALYTICS_UNAUTHENTICATED_USER } from "./internal/analyticsQueue";
62
59
  export type { DocumentBlobContext, BlobUploadSourceOptions, BlobUploadResult, BlobListResult, BlobUploadStatus, BlobReadOptions, BlobPrefetchOptions, BlobProxyUrlOptions, BlobDisposition, } from "./internal/blobManager";
63
60
  export type { DocumentsAPI, DocumentContext, DocumentAliasesAPI, DocumentIngestsAPI, DocumentSnapshotsAPI, } from "./api/documentsApi";
64
61
  export type { DatabasesAPI } from "./api/databasesApi";
65
62
  export type { CollectionsAPI } from "./api/collectionsApi";
66
- export type { GeminiAPI } from "./api/geminiApi";
67
- export type { LlmAPI } from "./api/llmApi";
68
63
  export type { MeAPI } from "./api/meApi";
69
64
  export type { SessionAPI } from "./api/sessionApi";
70
65
  export type { UsersAPI } from "./api/usersApi";
@@ -86,7 +81,6 @@ export type { CreateGroupTypeConfigParams, UpdateGroupTypeConfigParams, } from "
86
81
  export type { CreateRuleSetParams, DebugRuleSetParams, ListRuleSetsOptions, TestRuleSetParams, UpdateRuleSetParams, } from "./api/ruleSetsApi";
87
82
  export type { GetMeOptions, UpdateMeParams } from "./api/meApi";
88
83
  export type { GetUserOptions } from "./api/usersApi";
89
- export type { GeminiCandidate, GeminiFilePart, GeminiGenerationConfig, GeminiImagePart, GeminiSafetySetting, GeminiTextPart, } from "./api/geminiApi";
90
84
  export type { AggregateGroupByEntry, CreateOperationParamsOf, DatabaseOperationInfoOf, ObjectOrParamsRef, PipelineAggregateStep, PipelineCountStep, PipelineQueryStep, } from "./api/operationDefinition";
91
85
  export type { NotificationTokenAttempt } from "./api/notificationsApi";
92
86
  export type { InvitationsAPI, InvitationListOptions, DeferredGrantListOptions, } from "./api/invitationsApi";
@@ -106,7 +100,7 @@ export type { ResourceMetadataReadResult, ResourceMetadataWriteResult, ResourceM
106
100
  * `analyticsAutoEvents` in {@link JsBaoClientOptions}. Every category is
107
101
  * enabled by default; set a flag (or a category's sub-flags) to `false` to
108
102
  * opt out. Categories cover daily auth, return-to-active resumes, sync
109
- * errors, blob upload lifecycle, session end, and LLM / Gemini calls.
103
+ * errors, blob upload lifecycle, and session end.
110
104
  */
111
105
  export interface AnalyticsAutoEventsOptions {
112
106
  dailyAuth?: boolean;
@@ -122,18 +116,7 @@ export interface AnalyticsAutoEventsOptions {
122
116
  failure?: boolean;
123
117
  };
124
118
  sessionEnd?: boolean;
125
- llm?: boolean | {
126
- start?: boolean;
127
- success?: boolean;
128
- failure?: boolean;
129
- };
130
- gemini?: boolean | {
131
- start?: boolean;
132
- success?: boolean;
133
- failure?: boolean;
134
- };
135
119
  }
136
- export type { GeminiRole, GeminiContentPart, GeminiMessage, GeminiPromptOptions, GeminiGenerateOptions, GeminiGenerateResult, GeminiModelSummary, GeminiStructuredOutput, GeminiGenerateRawOptions, } from "./api/geminiApi";
137
120
  /**
138
121
  * Request passed to `client.integrations.call()`. Identifies the integration
139
122
  * by key and describes the HTTP request to send through the integration
@@ -2520,18 +2503,6 @@ export declare class JsBaoClient extends Observable<any> {
2520
2503
  /** Sub-API for session management (sign in, sign out, token refresh).
2521
2504
  * @group Sub-APIs */
2522
2505
  session: SessionAPI;
2523
- /** Sub-API for LLM (large language model) operations.
2524
- * @group Sub-APIs
2525
- * @deprecated The direct LLM client API is deprecated and will be removed in a
2526
- * future major release. Run a managed prompt from a
2527
- * server function instead: `ctx.prompts.run` (see the Server Functions guide). */
2528
- llm: LlmAPI;
2529
- /** Sub-API for Gemini model operations.
2530
- * @group Sub-APIs
2531
- * @deprecated The direct Gemini client API is deprecated and will be removed in
2532
- * a future major release. Run a managed prompt from a
2533
- * server function instead: `ctx.prompts.run` (see the Server Functions guide). */
2534
- gemini: GeminiAPI;
2535
2506
  /** Sub-API for managing app users.
2536
2507
  * @group Sub-APIs */
2537
2508
  users: UsersAPI;
@@ -3049,18 +3020,6 @@ export declare class JsBaoClient extends Observable<any> {
3049
3020
  private handleBlobUploadComplete;
3050
3021
  private handleBlobUploadFailed;
3051
3022
  private logSessionEndEvent;
3052
- /** Get the analytics context for LLM operations.
3053
- * @group Configuration */
3054
- getLlmAnalyticsContext(): {
3055
- logEvent: (event: Omit<AnalyticsEventInput, "user_ulid">) => void;
3056
- isEnabled: (phase?: "start" | "success" | "failure") => boolean;
3057
- } | null;
3058
- /** Get the analytics context for Gemini operations.
3059
- * @group Configuration */
3060
- getGeminiAnalyticsContext(): {
3061
- logEvent: (event: Omit<AnalyticsEventInput, "user_ulid">) => void;
3062
- isEnabled: (phase?: "start" | "success" | "failure") => boolean;
3063
- } | null;
3064
3023
  private sanitizeOverride;
3065
3024
  private readEnvNumber;
3066
3025
  /** Check if a document is synced with the server.
@@ -33,8 +33,6 @@ import { DocumentsAPI, } from "./api/documentsApi";
33
33
  import { createCacheFacade } from "./api/cacheFacade";
34
34
  import { MeAPI } from "./api/meApi";
35
35
  import { SessionAPI } from "./api/sessionApi";
36
- import { LlmAPI } from "./api/llmApi";
37
- import { GeminiAPI } from "./api/geminiApi";
38
36
  import { UsersAPI } from "./api/usersApi";
39
37
  import { DatabasesAPI } from "./api/databasesApi";
40
38
  import { GroupsAPI } from "./api/groupsApi";
@@ -1057,38 +1055,6 @@ export class JsBaoClient extends Observable {
1057
1055
  const blobUploadsFailure = typeof blobUploadsOption.failure === "boolean"
1058
1056
  ? blobUploadsOption.failure
1059
1057
  : true;
1060
- const llmOption = analyticsAuto.llm;
1061
- let llmStart = true;
1062
- let llmSuccess = true;
1063
- let llmFailure = true;
1064
- if (llmOption !== undefined) {
1065
- if (typeof llmOption === "boolean") {
1066
- llmStart = llmOption;
1067
- llmSuccess = llmOption;
1068
- llmFailure = llmOption;
1069
- }
1070
- else if (typeof llmOption === "object" && llmOption !== null) {
1071
- llmStart = llmOption.start !== false;
1072
- llmSuccess = llmOption.success !== false;
1073
- llmFailure = llmOption.failure !== false;
1074
- }
1075
- }
1076
- const geminiOption = analyticsAuto.gemini;
1077
- let geminiStart = true;
1078
- let geminiSuccess = true;
1079
- let geminiFailure = true;
1080
- if (geminiOption !== undefined) {
1081
- if (typeof geminiOption === "boolean") {
1082
- geminiStart = geminiOption;
1083
- geminiSuccess = geminiOption;
1084
- geminiFailure = geminiOption;
1085
- }
1086
- else if (typeof geminiOption === "object" && geminiOption !== null) {
1087
- geminiStart = geminiOption.start !== false;
1088
- geminiSuccess = geminiOption.success !== false;
1089
- geminiFailure = geminiOption.failure !== false;
1090
- }
1091
- }
1092
1058
  this.analyticsAutoEventsConfig = {
1093
1059
  dailyAuth: analyticsAuto.dailyAuth !== false,
1094
1060
  returnActive: analyticsAuto.returnActive !== false,
@@ -1102,16 +1068,6 @@ export class JsBaoClient extends Observable {
1102
1068
  success: blobUploadsSuccess,
1103
1069
  failure: blobUploadsFailure,
1104
1070
  },
1105
- llm: {
1106
- start: llmStart,
1107
- success: llmSuccess,
1108
- failure: llmFailure,
1109
- },
1110
- gemini: {
1111
- start: geminiStart,
1112
- success: geminiSuccess,
1113
- failure: geminiFailure,
1114
- },
1115
1071
  sessionEnd: analyticsAuto.sessionEnd !== false,
1116
1072
  };
1117
1073
  this.offlineStore = new OfflineStore(logger);
@@ -1221,8 +1177,6 @@ export class JsBaoClient extends Observable {
1221
1177
  this.documents = new DocumentsAPI(this, this.docManager, DEFAULT_AVAILABILITY_WAIT_MS, logger);
1222
1178
  this.me = new MeAPI(this);
1223
1179
  this.session = new SessionAPI(this);
1224
- this.llm = new LlmAPI(this);
1225
- this.gemini = new GeminiAPI(this);
1226
1180
  this.users = new UsersAPI(this);
1227
1181
  this.dbSubscriptions = new DatabaseSubscriptionRegistry(logger);
1228
1182
  // Wire the origin lookups so the registry can synthesize per-recipient
@@ -2305,6 +2259,11 @@ export class JsBaoClient extends Observable {
2305
2259
  logger.log(`[JsBaoClient] Created ${tomlModels.length} model classes from schemaToml`);
2306
2260
  }
2307
2261
  catch (err) {
2262
+ // #3719 — a unique constraint on a stringset field is a declaration
2263
+ // the author has to fix, not a parse hiccup: surface it as the init
2264
+ // failure (`jsBaoInitError`) rather than starting with no models.
2265
+ if (err?.name === "UniqueStringsetError")
2266
+ throw err;
2308
2267
  logger.warn("[JsBaoClient] Failed to parse schemaToml:", err);
2309
2268
  }
2310
2269
  }
@@ -4632,50 +4591,6 @@ export class JsBaoClient extends Observable {
4632
4591
  },
4633
4592
  });
4634
4593
  }
4635
- /** Get the analytics context for LLM operations.
4636
- * @group Configuration */
4637
- getLlmAnalyticsContext() {
4638
- const config = this.analyticsAutoEventsConfig.llm;
4639
- if (!config.start && !config.success && !config.failure) {
4640
- return null;
4641
- }
4642
- return {
4643
- logEvent: (event) => this.logAnalyticsEvent(event),
4644
- isEnabled: (phase) => {
4645
- if (!phase)
4646
- return config.start || config.success || config.failure;
4647
- if (phase === "start")
4648
- return config.start;
4649
- if (phase === "success")
4650
- return config.success;
4651
- if (phase === "failure")
4652
- return config.failure;
4653
- return true;
4654
- },
4655
- };
4656
- }
4657
- /** Get the analytics context for Gemini operations.
4658
- * @group Configuration */
4659
- getGeminiAnalyticsContext() {
4660
- const config = this.analyticsAutoEventsConfig.gemini;
4661
- if (!config.start && !config.success && !config.failure) {
4662
- return null;
4663
- }
4664
- return {
4665
- logEvent: (event) => this.logAnalyticsEvent(event),
4666
- isEnabled: (phase) => {
4667
- if (!phase)
4668
- return config.start || config.success || config.failure;
4669
- if (phase === "start")
4670
- return config.start;
4671
- if (phase === "success")
4672
- return config.success;
4673
- if (phase === "failure")
4674
- return config.failure;
4675
- return true;
4676
- },
4677
- };
4678
- }
4679
4594
  sanitizeOverride(value) {
4680
4595
  if (typeof value !== "string")
4681
4596
  return undefined;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The decode and encode rules of the platform session models — #3802.
3
+ *
4
+ * `sessionModels.generated.ts` renders one spec per model from the platform
5
+ * schema (`src/agents/session-document-schema.ts`) and calls through here, so
6
+ * the rules live once rather than once per column. Rows are flat, so most of
7
+ * a record is the row's own columns; the rules are the few places a value is
8
+ * interpreted:
9
+ *
10
+ * - A scalar column is copied as read. A number column holding a non-number,
11
+ * a string or date column holding a non-string, and a boolean column
12
+ * holding anything but a boolean or a number read as `undefined`; a number
13
+ * in a boolean column is `false` for `0` and `true` otherwise (the Swift
14
+ * client's `rowBoolValue`).
15
+ * - An enum outside its vocabulary reads as `"unknown"`; the raw string stays
16
+ * on the record's `row`.
17
+ * - A part whose `kind` is unknown is the opaque `{ kind: "unknown", rawKind,
18
+ * row }`.
19
+ * - A stringset reads as its string members in stored order, from an array or
20
+ * a js-bao `StringSet`; an absent one is `[]`.
21
+ * - A JSON column's absent or malformed text is `undefined`. Valid text is
22
+ * the value (`any`), an object keeping every key (`object`), or the queue's
23
+ * well-formed entries (`queue`); valid text of the wrong top-level type is
24
+ * `{}` or `[]` where the column says so, else `undefined`.
25
+ * - Columns the schema does not declare are neither decoded nor carried.
26
+ * - A row missing a required scalar column does not decode.
27
+ * - Encoding writes a column verbatim from the record's `row` when the value
28
+ * decoded from it equals the record's value, so an unchanged record comes
29
+ * back exactly as it was read; a changed value is written canonically.
30
+ */
31
+ import { autoRegisterModel } from "js-bao";
32
+ type ModelClass = Parameters<typeof autoRegisterModel>[0];
33
+ export type SessionModelColumn = {
34
+ kind: "id";
35
+ } | {
36
+ kind: "string" | "number" | "boolean" | "date";
37
+ required?: boolean;
38
+ } | {
39
+ kind: "enum";
40
+ values: string[];
41
+ required?: boolean;
42
+ } | {
43
+ kind: "stringset";
44
+ } | {
45
+ kind: "json";
46
+ shape: "any" | "object" | "queue";
47
+ emptyOnWrongType?: boolean;
48
+ };
49
+ export interface SessionModelSpec {
50
+ name: string;
51
+ columns: {
52
+ [column: string]: SessionModelColumn;
53
+ };
54
+ discriminator?: {
55
+ column: string;
56
+ variants: {
57
+ [kind: string]: {
58
+ columns: string[];
59
+ enums?: {
60
+ [column: string]: string[];
61
+ };
62
+ };
63
+ };
64
+ };
65
+ }
66
+ /** One author waiting in the session queue, with their batch in order. */
67
+ export interface PrimitiveQueueEntry {
68
+ userId: string;
69
+ messageIds: string[];
70
+ }
71
+ /**
72
+ * The text a JSON column stores: `JSON.stringify` with no whitespace — the
73
+ * same bytes the session object writes for the same value. `null` is a value;
74
+ * `undefined` has no text, so omit the column instead.
75
+ */
76
+ export declare function encodeJsonColumn(value: unknown): string;
77
+ /** A JSON column's value, or `undefined` when it is absent or not JSON. */
78
+ export declare function decodeJsonColumn(text: unknown): unknown;
79
+ type Row = Record<string, unknown>;
80
+ export type DecodedRow = {
81
+ ok: true;
82
+ record: Record<string, unknown>;
83
+ } | {
84
+ ok: false;
85
+ column: string;
86
+ };
87
+ /** One stored column's decoded value; `undefined` when it has none. */
88
+ export declare function decodeColumn(column: SessionModelColumn, raw: unknown): unknown;
89
+ /**
90
+ * Decode one row (a model instance or plain attrs). Fails naming the first
91
+ * required scalar column the row cannot supply.
92
+ */
93
+ export declare function decodeModelRow(spec: SessionModelSpec, input: object): DecodedRow;
94
+ /** The error a session row that cannot be decoded throws. */
95
+ export declare function sessionRowInvalid(column: string): Error & {
96
+ code: "AGENT_SESSION_ROW_INVALID";
97
+ column: string;
98
+ };
99
+ /**
100
+ * Structural equality over decoded values; an `undefined` key is absent. Only
101
+ * own keys count, so a JSON `__proto__` key never matches an inherited one.
102
+ */
103
+ export declare function sessionValuesEqual(a: unknown, b: unknown): boolean;
104
+ /**
105
+ * A record's row attrs. A column whose value still equals what its `row`
106
+ * decodes to is written as the row held it (its text, its array, its raw
107
+ * value, or absent); anything else is written from the value. An `unknown`
108
+ * enum with no source to copy is written as the text `unknown`, which decodes
109
+ * back to the same value. An opaque part writes its common columns the same
110
+ * way and every other column from its `row`, with `rawKind` as its kind.
111
+ */
112
+ export declare function encodeModelRecord(spec: SessionModelSpec, record: Record<string, unknown>): Row;
113
+ /** The error `agentSessionModels()` throws when an app class holds a platform name. */
114
+ export declare function sessionModelNameTaken(model: string): Error & {
115
+ code: "AGENT_SESSION_MODEL_NAME_TAKEN";
116
+ model: string;
117
+ };
118
+ /**
119
+ * Register the platform classes with js-bao's registry, refusing — before
120
+ * anything is registered — when an app class already holds one of the names.
121
+ * js-bao itself would only warn and overwrite the app's class.
122
+ */
123
+ export declare function registerSessionModels(models: ReadonlyArray<ModelClass>): void;
124
+ export {};