@rindle/client 0.4.2 → 0.4.4
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 +31 -161
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/mutation-ops.d.ts +73 -13
- package/dist/mutation-ops.d.ts.map +1 -1
- package/dist/mutation-ops.js +22 -3
- package/dist/mutation-ops.js.map +1 -1
- package/dist/schema.d.ts +130 -22
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +61 -6
- package/dist/schema.js.map +1 -1
- package/dist/store.d.ts +17 -6
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +34 -14
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/view.d.ts +56 -7
- package/dist/view.d.ts.map +1 -1
- package/dist/view.js +319 -18
- package/dist/view.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +6 -1
- package/src/mutation-ops.ts +98 -24
- package/src/schema.ts +189 -37
- package/src/store.ts +43 -16
- package/src/types.ts +13 -3
- package/src/view.ts +316 -17
package/dist/schema.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { Arg, Cond } from "./operators.ts";
|
|
2
|
-
import type { ColType } from "./types.ts";
|
|
2
|
+
import type { ColType, WireValue } from "./types.ts";
|
|
3
3
|
/** A column descriptor. `type` drives the comparator + JSON parsing; `__t` is a phantom. A
|
|
4
4
|
* nullable column is a `Col<T | null>` — that is the ONLY thing nullability changes at the type
|
|
5
|
-
* level, so `RowOf` (and the field-condition factory) widen automatically.
|
|
5
|
+
* level, so `RowOf` (and the field-condition factory) widen automatically.
|
|
6
|
+
*
|
|
7
|
+
* `optional` is the runtime companion of that phantom: set by {@link ColBuilder.nullable}, it is
|
|
8
|
+
* what the write funnels read to make a nullable column omittable from an insert (filled with
|
|
9
|
+
* `null`, design 206 §6.2). It mirrors the engine's `ColumnDef.optional`
|
|
10
|
+
* (`pragma_table_info.notnull == 0`); absent ⇒ `NOT NULL` / required. */
|
|
6
11
|
export interface Col<T> {
|
|
7
12
|
readonly type: ColType;
|
|
13
|
+
readonly optional?: boolean;
|
|
8
14
|
readonly __t?: T;
|
|
9
15
|
}
|
|
10
16
|
export type ColT<X> = X extends Col<infer T> ? T : never;
|
|
@@ -15,9 +21,10 @@ export type RowOf<C extends AnyCols> = {
|
|
|
15
21
|
/** The chainable form returned by the column factories: a {@link Col} plus `.nullable()`.
|
|
16
22
|
*
|
|
17
23
|
* `.nullable()` widens the column's value type to `T | null` — its `Row<…>` field becomes
|
|
18
|
-
* `T | null
|
|
19
|
-
* `.nullable()` for every nullable (non-`NOT NULL`) SQL
|
|
20
|
-
* local-only table's columns. It is idempotent and stays
|
|
24
|
+
* `T | null` — and sets the runtime {@link Col.optional} marker so it may be omitted from an insert
|
|
25
|
+
* (design 206 §6.2). `rindle schema gen` emits `.nullable()` for every nullable (non-`NOT NULL`) SQL
|
|
26
|
+
* column; you can also call it by hand on a local-only table's columns. It is idempotent and stays
|
|
27
|
+
* chainable. */
|
|
21
28
|
export interface ColBuilder<T> extends Col<T> {
|
|
22
29
|
nullable(): ColBuilder<T | null>;
|
|
23
30
|
}
|
|
@@ -27,25 +34,34 @@ export declare const boolean: () => ColBuilder<boolean>;
|
|
|
27
34
|
export declare const json: <T = unknown>() => ColBuilder<T>;
|
|
28
35
|
/** Metadata key on a {@link TableDef} (a `unique symbol`, so no column name collides). */
|
|
29
36
|
export declare const SCHEMA: unique symbol;
|
|
30
|
-
export interface TableMeta<N extends string = string, C extends AnyCols = AnyCols> {
|
|
37
|
+
export interface TableMeta<N extends string = string, C extends AnyCols = AnyCols, PK extends string = string> {
|
|
31
38
|
readonly name: N;
|
|
32
39
|
readonly columns: C;
|
|
33
|
-
readonly primaryKey: readonly
|
|
40
|
+
readonly primaryKey: readonly PK[];
|
|
34
41
|
/** A **local-only** table (`201-LOCAL-ONLY-TABLES-DESIGN.md`): client-authoritative,
|
|
35
42
|
* never synced/tracked/rebased. The single marker the whole design keys off (§4) — it is
|
|
36
43
|
* immutable for the table's lifetime (N2) and never crosses the wire (C2). Absent ⇒ an
|
|
37
|
-
* ordinary synced table.
|
|
38
|
-
|
|
44
|
+
* ordinary synced table.
|
|
45
|
+
*
|
|
46
|
+
* `true` ⇒ eligible for the local-persistence plane (durable + cross-tab when the client
|
|
47
|
+
* enables `persistLocal`, `207-LOCAL-TABLE-PERSISTENCE-DESIGN.md`). `"session"` ⇒ local but
|
|
48
|
+
* EPHEMERAL: outside the plane entirely — never persisted, never replicated across tabs,
|
|
49
|
+
* per-client-instance state that empties on reload (201's original behavior) even when
|
|
50
|
+
* `persistLocal` is on. Every OTHER locality rule (untracked source, M1/M2 guards, E3/Q1
|
|
51
|
+
* wire exclusion) treats both variants identically. */
|
|
52
|
+
readonly local?: boolean | "session";
|
|
39
53
|
}
|
|
40
54
|
/** Options for {@link table}. */
|
|
41
55
|
export interface TableOptions {
|
|
42
56
|
/** Declare a {@link TableMeta.local local-only} table (selection state, draft text, view
|
|
43
57
|
* prefs, scratch rows): client-authoritative, never synced or rebased. See
|
|
44
|
-
* `201-LOCAL-ONLY-TABLES-DESIGN.md`.
|
|
45
|
-
|
|
58
|
+
* `201-LOCAL-ONLY-TABLES-DESIGN.md`. Pass `"session"` for a local table that must stay
|
|
59
|
+
* EPHEMERAL and per-tab even when the client enables `persistLocal` — e.g. selection state
|
|
60
|
+
* that should not follow the user across tabs or reloads (207 §5.4). */
|
|
61
|
+
local?: boolean | "session";
|
|
46
62
|
}
|
|
47
|
-
export type TableDef<N extends string, C extends AnyCols> = {
|
|
48
|
-
readonly [SCHEMA]: TableMeta<N, C>;
|
|
63
|
+
export type TableDef<N extends string, C extends AnyCols, PK extends string = string> = {
|
|
64
|
+
readonly [SCHEMA]: TableMeta<N, C, PK>;
|
|
49
65
|
} & {
|
|
50
66
|
readonly [K in keyof C]: (arg: Arg<ColT<C[K]>>) => Cond<RowOf<C>>;
|
|
51
67
|
};
|
|
@@ -60,11 +76,52 @@ export type AnyTable = TableLike<AnyCols>;
|
|
|
60
76
|
* whole-table ergonomic form of {@link RowOf}, so app code derives its row interfaces from
|
|
61
77
|
* the schema instead of hand-maintaining a parallel twin. */
|
|
62
78
|
export type Row<T extends AnyTable> = RowOf<T[typeof SCHEMA]["columns"]>;
|
|
79
|
+
/** Flatten an intersection of mapped types into a single object type (preserving `?`/`readonly`) so
|
|
80
|
+
* {@link InsertOf} reads as one clean shape in editor hovers, not `A & B`. */
|
|
81
|
+
type Simplify<T> = {
|
|
82
|
+
[K in keyof T]: T[K];
|
|
83
|
+
};
|
|
84
|
+
/** True for the top types `unknown`/`any` (`unknown extends any` too), where `[null] extends [T]` is
|
|
85
|
+
* vacuously true and so can't tell a `.nullable()` apart. */
|
|
86
|
+
type IsTop<T> = unknown extends T ? true : false;
|
|
87
|
+
/** Whether column `X` may be OMITTED from an insert: it admits `null` at the type level — EXCLUDING
|
|
88
|
+
* the top types. A bare `json()` is `json<unknown>()`, and `unknown | null` collapses back to
|
|
89
|
+
* `unknown`, erasing whether `.nullable()` was applied; treating it as required is the safe
|
|
90
|
+
* direction (a `NOT NULL` json column is never wrongly made optional). Declare `json<T>()` to make a
|
|
91
|
+
* nullable json column omittable. The runtime companion is `Col.optional` (design 206 §6.2/§7). */
|
|
92
|
+
type InsertOptional<X> = IsTop<ColT<X>> extends true ? false : [null] extends [ColT<X>] ? true : false;
|
|
93
|
+
/** The INSERT shape of a column map: {@link RowOf} with every NULLABLE column made OPTIONAL (`?`) —
|
|
94
|
+
* it may be omitted and is filled with `null` by both write funnels (design 206 §6.2/§7). `NOT NULL`
|
|
95
|
+
* columns stay required. The insert-side twin of {@link RowOf}, mirroring Drizzle's `$inferInsert`
|
|
96
|
+
* vs `$inferSelect` split. */
|
|
97
|
+
export type InsertOf<C extends AnyCols> = Simplify<{
|
|
98
|
+
[K in keyof C as InsertOptional<C[K]> extends true ? never : K]: ColT<C[K]>;
|
|
99
|
+
} & {
|
|
100
|
+
[K in keyof C as InsertOptional<C[K]> extends true ? K : never]?: ColT<C[K]>;
|
|
101
|
+
}>;
|
|
102
|
+
/** The insert type of a table def: `Insert<typeof issue>` → `{ id: string; … assignee?: string | null }`.
|
|
103
|
+
* The whole-table ergonomic form of {@link InsertOf} (the insert-side twin of {@link Row}). */
|
|
104
|
+
export type Insert<T extends AnyTable> = InsertOf<T[typeof SCHEMA]["columns"]>;
|
|
105
|
+
/** The exact PRIMARY-KEY columns of a table (each typed), required — the identity a `delete`/`row`,
|
|
106
|
+
* and the WHERE half of an `update`, take. `PK` is the table's pk-column union (the schema's `__pk`). */
|
|
107
|
+
export type PkOf<C extends AnyCols, PK extends string> = {
|
|
108
|
+
[K in PK & keyof C]: ColT<C[K & keyof C]>;
|
|
109
|
+
};
|
|
110
|
+
/** The UPDATE shape of a table: its {@link PkOf primary-key columns} REQUIRED (they identify the row)
|
|
111
|
+
* plus every non-pk column OPTIONAL (`?`) and typed — a nullable one stays `T | null` (settable to
|
|
112
|
+
* null), a `NOT NULL` one is `T`. Omitted non-pk columns are left unchanged. */
|
|
113
|
+
export type UpdateOf<C extends AnyCols, PK extends string> = Simplify<PkOf<C, PK> & {
|
|
114
|
+
[K in Exclude<keyof C, PK>]?: ColT<C[K]>;
|
|
115
|
+
}>;
|
|
116
|
+
/** The primary-key column union for table `N` of a schema, read from its `__pk` map `P` and narrowed
|
|
117
|
+
* to `N`'s actual columns (falling back to all columns when `P` doesn't name `N` — e.g. the loose
|
|
118
|
+
* default schema). Feeds {@link PkOf}/{@link UpdateOf} in the typed mutator tx. */
|
|
119
|
+
export type PkColsOf<S extends ColsMap, P extends Record<string, string>, N extends keyof S> = (N extends keyof P ? P[N] : keyof S[N] & string) & keyof S[N] & string;
|
|
63
120
|
/** `table("issue").columns({ id: string(), … }).primaryKey("id")`. Pass `{ local: true }` for a
|
|
64
121
|
* {@link TableMeta.local local-only} table (`201-LOCAL-ONLY-TABLES-DESIGN.md`). */
|
|
65
122
|
export declare function table<N extends string>(name: N, opts?: TableOptions): {
|
|
66
123
|
columns<C extends AnyCols>(cols: C): {
|
|
67
|
-
primaryKey<K extends keyof C & string>(...keys: K[]): TableDef<N, C>;
|
|
124
|
+
primaryKey<K extends keyof C & string>(...keys: K[]): TableDef<N, C, K>;
|
|
68
125
|
};
|
|
69
126
|
};
|
|
70
127
|
/** Read a table's metadata (columns / PK / name). */
|
|
@@ -73,12 +130,24 @@ export declare function tableMeta(t: AnyTable): TableMeta;
|
|
|
73
130
|
export type SchemaOf<T extends readonly AnyTable[]> = {
|
|
74
131
|
[E in T[number] as E[typeof SCHEMA]["name"]]: E[typeof SCHEMA]["columns"];
|
|
75
132
|
};
|
|
133
|
+
/** name → its primary-key column union, derived from the tables array (the PK captured by the
|
|
134
|
+
* `primaryKey(...)` builder). Powers the mutator tx's typed `update`/`delete`/`row` pk args. */
|
|
135
|
+
export type PkMapOf<T extends readonly AnyTable[]> = {
|
|
136
|
+
[E in T[number] as E[typeof SCHEMA]["name"]]: E[typeof SCHEMA]["primaryKey"][number];
|
|
137
|
+
};
|
|
76
138
|
/** name → columns, the resolved schema map carried in the {@link Schema} type. */
|
|
77
139
|
export type ColsMap = Record<string, AnyCols>;
|
|
78
|
-
|
|
140
|
+
/** name → (some subset of its column names): the loose shape a {@link Schema}'s pk-map satisfies. The
|
|
141
|
+
* fallback when a schema wasn't built through {@link createSchema} — every column could be the pk. */
|
|
142
|
+
export type PkMap<S extends ColsMap> = {
|
|
143
|
+
[N in keyof S]: keyof S[N] & string;
|
|
144
|
+
};
|
|
145
|
+
export interface Schema<S extends ColsMap = ColsMap, P extends Record<string, string> = PkMap<S>> {
|
|
79
146
|
readonly tables: Readonly<Record<string, TableMeta>>;
|
|
80
147
|
/** Phantom carrying name→columns for query-root inference (never read at runtime). */
|
|
81
148
|
readonly __cols: S;
|
|
149
|
+
/** Phantom carrying name→pk-column-union for the typed mutator tx (never read at runtime). */
|
|
150
|
+
readonly __pk: P;
|
|
82
151
|
}
|
|
83
152
|
/** Table-name prefixes reserved by the engine for SYNTHETIC tables — `__agg_<fnv>` aggregate
|
|
84
153
|
* bases (`AGGREGATE-SYNC-DESIGN.md` §3.3) and `_rindle_*` system tables (e.g. the lmid table).
|
|
@@ -92,7 +161,7 @@ export declare const RESERVED_TABLE_PREFIXES: readonly ["__agg_", "_rindle_"];
|
|
|
92
161
|
export declare function isReservedTableName(name: string): boolean;
|
|
93
162
|
export declare function createSchema<const T extends readonly AnyTable[]>(opts: {
|
|
94
163
|
tables: T;
|
|
95
|
-
}): Schema<SchemaOf<T>>;
|
|
164
|
+
}): Schema<SchemaOf<T>, PkMapOf<T>>;
|
|
96
165
|
/** Extend a generated/synced schema with client-authoritative local-only tables.
|
|
97
166
|
*
|
|
98
167
|
* This is the ergonomic path for SQL-first apps: keep `schema.gen.ts` fully generated, define
|
|
@@ -100,9 +169,9 @@ export declare function createSchema<const T extends readonly AnyTable[]>(opts:
|
|
|
100
169
|
* client. The added tables MUST be `table(name, { local: true })`: `extendSchema` deliberately
|
|
101
170
|
* refuses to append ordinary synced tables, because those need to come from daemon introspection
|
|
102
171
|
* (`rindle schema gen`) so the server and client cannot drift. */
|
|
103
|
-
export declare function extendSchema<S extends ColsMap, const T extends readonly AnyTable[]>(base: Schema<S>, opts: {
|
|
172
|
+
export declare function extendSchema<S extends ColsMap, P extends Record<string, string>, const T extends readonly AnyTable[]>(base: Schema<S, P>, opts: {
|
|
104
173
|
tables: T;
|
|
105
|
-
}): Schema<S & SchemaOf<T>>;
|
|
174
|
+
}): Schema<S & SchemaOf<T>, P & PkMapOf<T>>;
|
|
106
175
|
/** Per-column narrowings for {@link refineTable}: each entry must keep the column's kind and narrow
|
|
107
176
|
* its TS type (`Col<T2>` with `T2 extends T`) — `json<Meta>()` on a json column, a literal-union
|
|
108
177
|
* `string<"a" | "b">()` on a string column. Kind changes are rejected (cross-kind at compile time,
|
|
@@ -137,14 +206,29 @@ export type RefinedColsMap<S extends ColsMap, T extends readonly AnyTable[]> = {
|
|
|
137
206
|
* Runtime-validated identity: each def must name a table already in the schema and match its
|
|
138
207
|
* runtime shape exactly (same columns, kinds, primary key, and locality) — refinement narrows TS
|
|
139
208
|
* types, never what's on the wire. Composes with {@link extendSchema} in either order. */
|
|
140
|
-
export declare function refineSchema<S extends ColsMap, const T extends readonly RefinableTable<S>[]>(base: Schema<S>, opts: {
|
|
209
|
+
export declare function refineSchema<S extends ColsMap, P extends Record<string, string>, const T extends readonly RefinableTable<S>[]>(base: Schema<S, P>, opts: {
|
|
141
210
|
tables: T;
|
|
142
|
-
}): Schema<RefinedColsMap<S, T
|
|
211
|
+
}): Schema<RefinedColsMap<S, T>, P>;
|
|
143
212
|
/** Whether `table` is a {@link TableMeta.local local-only} table in `schema` (an unknown table
|
|
144
|
-
* reads as non-local). The single locality predicate the backends key off.
|
|
213
|
+
* reads as non-local). The single locality predicate the backends key off. BOTH variants —
|
|
214
|
+
* `true` and `"session"` — are local here; the persisted/ephemeral split matters only to the
|
|
215
|
+
* persistence plane ({@link persistedLocalTableNames}). */
|
|
145
216
|
export declare function isLocalTable<S extends ColsMap>(schema: Schema<S>, table: string): boolean;
|
|
146
|
-
/** The set of local-only table names in `schema` (`201-LOCAL-ONLY-TABLES-DESIGN.md` §4)
|
|
217
|
+
/** The set of local-only table names in `schema` (`201-LOCAL-ONLY-TABLES-DESIGN.md` §4) — BOTH
|
|
218
|
+
* variants (`true` and `"session"`); every locality rule except persistence keys off this set. */
|
|
147
219
|
export declare function localTableNames<S extends ColsMap>(schema: Schema<S>): Set<string>;
|
|
220
|
+
/** The subset of {@link localTableNames} eligible for the persistence plane — `local: true` only.
|
|
221
|
+
* A `local: "session"` table stays outside it: never persisted, never replicated across tabs
|
|
222
|
+
* (`207-LOCAL-TABLE-PERSISTENCE-DESIGN.md` §5.4). */
|
|
223
|
+
export declare function persistedLocalTableNames<S extends ColsMap>(schema: Schema<S>): Set<string>;
|
|
224
|
+
/** A stable fingerprint of the schema's PERSISTED local tables only — the persistence gate's
|
|
225
|
+
* `schemaHash` (`207-LOCAL-TABLE-PERSISTENCE-DESIGN.md` §3.3 / P7). Per `local: true` table:
|
|
226
|
+
* `(name, ordered column names + types + optionality, pk columns)`. Column order is kept (rows are
|
|
227
|
+
* positional); tables are sorted by name so registration order can't skew it; synced-table AND
|
|
228
|
+
* `local: "session"` changes never move it (reshaping an ephemeral table must not wipe durable
|
|
229
|
+
* data). The value is the canonical descriptor itself, not a digest — local-table sets are tiny,
|
|
230
|
+
* and exactness (no collision can ever skip a P7 clear) beats compactness here. */
|
|
231
|
+
export declare function localSchemaHash<S extends ColsMap>(schema: Schema<S>): string;
|
|
148
232
|
/** Brand on a {@link Relationship} value (a `unique symbol`, distinct from a {@link TableDef}). */
|
|
149
233
|
declare const RELATIONSHIP_BRAND: unique symbol;
|
|
150
234
|
/**
|
|
@@ -183,6 +267,30 @@ export declare function tableSpec(meta: TableMeta): {
|
|
|
183
267
|
columns: string[];
|
|
184
268
|
primaryKey: number[];
|
|
185
269
|
};
|
|
270
|
+
/** A table's insert-completeness plan, derived once from its `Col` markers and shared by BOTH write
|
|
271
|
+
* funnels — the client `trackingTx` and the server `renderOp` — so their required-sets can't drift
|
|
272
|
+
* (design 206 §6.1/§6.2). A `NOT NULL` column is `required`; a nullable column (`.nullable()` set
|
|
273
|
+
* `Col.optional`) may be omitted and is filled with `null` (see {@link insertCell}). PK columns are
|
|
274
|
+
* never nullable (introspection forces them non-null), so they are always required. */
|
|
275
|
+
export interface InsertPlan {
|
|
276
|
+
/** Every column, in wire order. */
|
|
277
|
+
readonly columns: string[];
|
|
278
|
+
/** Columns that MUST be present on a full insert — the non-nullable ones. */
|
|
279
|
+
readonly required: string[];
|
|
280
|
+
/** The nullable (omittable-to-null) columns, for a fast membership test in the fill. */
|
|
281
|
+
readonly nullable: ReadonlySet<string>;
|
|
282
|
+
}
|
|
283
|
+
/** Derive a table's {@link InsertPlan} from its column markers. */
|
|
284
|
+
export declare function insertPlan(meta: TableMeta): InsertPlan;
|
|
285
|
+
/** The cell a full insert writes for column `c`: the given value, or `null` when a nullable column
|
|
286
|
+
* is omitted (design 206 §6.2). The caller's completeness check ({@link InsertPlan.required})
|
|
287
|
+
* guarantees a non-nullable column is present, so its omission never reaches here. */
|
|
288
|
+
export declare function insertCell(row: Record<string, WireValue>, c: string): WireValue;
|
|
289
|
+
/** Encode a keyed-row cell to its wire {@link WireValue} for a column KIND — the one place both write
|
|
290
|
+
* funnels stringify a `json<T>` object (the typed mutator surface / design 206 §7). An
|
|
291
|
+
* already-stringified json value (a `string`) or any non-json cell passes through unchanged, so a
|
|
292
|
+
* mutator may pass EITHER a parsed object OR a JSON string. Mirrors `store.positionalize`. */
|
|
293
|
+
export declare function toCell(v: WireValue | object, type: ColType): WireValue;
|
|
186
294
|
/** The client's per-table flat schema (name + column order + PK indices), the shape a
|
|
187
295
|
* normalized `hello` advertises (NORMALIZED-CHANGES-DESIGN.md §3). Used to validate a
|
|
188
296
|
* server hello against the CLIENT's own typed schema so a column-order / PK skew is caught
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.js
CHANGED
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
// (WASM-CLIENT-DESIGN.md §6). Schema metadata is stored under a `unique symbol` key so it
|
|
7
7
|
// never collides with a column name.
|
|
8
8
|
import { fieldCondition } from "./operators.js";
|
|
9
|
-
const makeCol = (type
|
|
9
|
+
const makeCol = (type, optional = false) => ({
|
|
10
|
+
type,
|
|
11
|
+
...(optional ? { optional: true } : null),
|
|
12
|
+
nullable: () => makeCol(type, true),
|
|
13
|
+
});
|
|
10
14
|
export const string = () => makeCol("string");
|
|
11
15
|
export const number = () => makeCol("number");
|
|
12
16
|
export const boolean = () => makeCol("boolean");
|
|
@@ -72,7 +76,7 @@ export function extendSchema(base, opts) {
|
|
|
72
76
|
const tables = { ...base.tables };
|
|
73
77
|
for (const t of opts.tables) {
|
|
74
78
|
const m = t[SCHEMA];
|
|
75
|
-
if (m.local
|
|
79
|
+
if (!m.local) {
|
|
76
80
|
throw new Error(`extendSchema: table "${m.name}" is not local-only — synced tables must be generated from the daemon schema.`);
|
|
77
81
|
}
|
|
78
82
|
addTableMeta(tables, m, "extendSchema");
|
|
@@ -146,7 +150,9 @@ function assertRefinementMatches(m, baseMeta) {
|
|
|
146
150
|
cols.every((c) => baseMeta.columns[c] !== undefined && m.columns[c].type === baseMeta.columns[c].type) &&
|
|
147
151
|
m.primaryKey.length === baseMeta.primaryKey.length &&
|
|
148
152
|
m.primaryKey.every((k, i) => baseMeta.primaryKey[i] === k) &&
|
|
149
|
-
|
|
153
|
+
// Locality must match EXACTLY, including the persisted-vs-session variant (a refinement
|
|
154
|
+
// flipping `true` ↔ `"session"` would silently change the table's durability).
|
|
155
|
+
(m.local ?? false) === (baseMeta.local ?? false);
|
|
150
156
|
if (!matches) {
|
|
151
157
|
throw new Error(`refineSchema: table "${m.name}" does not match the schema's table of that name — pass the ` +
|
|
152
158
|
`output of refineTable over the SAME generated def (identical columns, kinds, primary key, ` +
|
|
@@ -154,14 +160,42 @@ function assertRefinementMatches(m, baseMeta) {
|
|
|
154
160
|
}
|
|
155
161
|
}
|
|
156
162
|
/** Whether `table` is a {@link TableMeta.local local-only} table in `schema` (an unknown table
|
|
157
|
-
* reads as non-local). The single locality predicate the backends key off.
|
|
163
|
+
* reads as non-local). The single locality predicate the backends key off. BOTH variants —
|
|
164
|
+
* `true` and `"session"` — are local here; the persisted/ephemeral split matters only to the
|
|
165
|
+
* persistence plane ({@link persistedLocalTableNames}). */
|
|
158
166
|
export function isLocalTable(schema, table) {
|
|
159
|
-
return schema.tables[table]?.local
|
|
167
|
+
return Boolean(schema.tables[table]?.local);
|
|
160
168
|
}
|
|
161
|
-
/** The set of local-only table names in `schema` (`201-LOCAL-ONLY-TABLES-DESIGN.md` §4)
|
|
169
|
+
/** The set of local-only table names in `schema` (`201-LOCAL-ONLY-TABLES-DESIGN.md` §4) — BOTH
|
|
170
|
+
* variants (`true` and `"session"`); every locality rule except persistence keys off this set. */
|
|
162
171
|
export function localTableNames(schema) {
|
|
163
172
|
return new Set(Object.keys(schema.tables).filter((n) => schema.tables[n].local));
|
|
164
173
|
}
|
|
174
|
+
/** The subset of {@link localTableNames} eligible for the persistence plane — `local: true` only.
|
|
175
|
+
* A `local: "session"` table stays outside it: never persisted, never replicated across tabs
|
|
176
|
+
* (`207-LOCAL-TABLE-PERSISTENCE-DESIGN.md` §5.4). */
|
|
177
|
+
export function persistedLocalTableNames(schema) {
|
|
178
|
+
return new Set(Object.keys(schema.tables).filter((n) => schema.tables[n].local === true));
|
|
179
|
+
}
|
|
180
|
+
/** A stable fingerprint of the schema's PERSISTED local tables only — the persistence gate's
|
|
181
|
+
* `schemaHash` (`207-LOCAL-TABLE-PERSISTENCE-DESIGN.md` §3.3 / P7). Per `local: true` table:
|
|
182
|
+
* `(name, ordered column names + types + optionality, pk columns)`. Column order is kept (rows are
|
|
183
|
+
* positional); tables are sorted by name so registration order can't skew it; synced-table AND
|
|
184
|
+
* `local: "session"` changes never move it (reshaping an ephemeral table must not wipe durable
|
|
185
|
+
* data). The value is the canonical descriptor itself, not a digest — local-table sets are tiny,
|
|
186
|
+
* and exactness (no collision can ever skip a P7 clear) beats compactness here. */
|
|
187
|
+
export function localSchemaHash(schema) {
|
|
188
|
+
// Derived from persistedLocalTableNames — the hash's contract is "fingerprints exactly the
|
|
189
|
+
// tables the plane persists", so the two must share one predicate, not two copies of it.
|
|
190
|
+
const tables = [...persistedLocalTableNames(schema)]
|
|
191
|
+
.sort()
|
|
192
|
+
.map((n) => {
|
|
193
|
+
const meta = schema.tables[n];
|
|
194
|
+
const cols = Object.keys(meta.columns).map((c) => [c, meta.columns[c].type, meta.columns[c].optional === true]);
|
|
195
|
+
return [n, cols, meta.primaryKey];
|
|
196
|
+
});
|
|
197
|
+
return `v1:${JSON.stringify(tables)}`;
|
|
198
|
+
}
|
|
165
199
|
// ----------------------------- relationships (FRAGMENT-COMPOSITION-DESIGN §4.2, named edges) -----
|
|
166
200
|
//
|
|
167
201
|
// A relationship is the correlation (`parent.col → child.col`) declared ONCE as a value, so `sub`,
|
|
@@ -194,6 +228,27 @@ export function tableSpec(meta) {
|
|
|
194
228
|
const primaryKey = meta.primaryKey.map((k) => columns.indexOf(k));
|
|
195
229
|
return { columns, primaryKey };
|
|
196
230
|
}
|
|
231
|
+
/** Derive a table's {@link InsertPlan} from its column markers. */
|
|
232
|
+
export function insertPlan(meta) {
|
|
233
|
+
const columns = Object.keys(meta.columns);
|
|
234
|
+
const nullable = new Set(columns.filter((c) => meta.columns[c].optional === true));
|
|
235
|
+
return { columns, required: columns.filter((c) => !nullable.has(c)), nullable };
|
|
236
|
+
}
|
|
237
|
+
/** The cell a full insert writes for column `c`: the given value, or `null` when a nullable column
|
|
238
|
+
* is omitted (design 206 §6.2). The caller's completeness check ({@link InsertPlan.required})
|
|
239
|
+
* guarantees a non-nullable column is present, so its omission never reaches here. */
|
|
240
|
+
export function insertCell(row, c) {
|
|
241
|
+
return c in row ? row[c] : null;
|
|
242
|
+
}
|
|
243
|
+
/** Encode a keyed-row cell to its wire {@link WireValue} for a column KIND — the one place both write
|
|
244
|
+
* funnels stringify a `json<T>` object (the typed mutator surface / design 206 §7). An
|
|
245
|
+
* already-stringified json value (a `string`) or any non-json cell passes through unchanged, so a
|
|
246
|
+
* mutator may pass EITHER a parsed object OR a JSON string. Mirrors `store.positionalize`. */
|
|
247
|
+
export function toCell(v, type) {
|
|
248
|
+
if (type === "json" && v !== null && typeof v === "object")
|
|
249
|
+
return JSON.stringify(v);
|
|
250
|
+
return v;
|
|
251
|
+
}
|
|
197
252
|
/** The client's per-table flat schema (name + column order + PK indices), the shape a
|
|
198
253
|
* normalized `hello` advertises (NORMALIZED-CHANGES-DESIGN.md §3). Used to validate a
|
|
199
254
|
* server hello against the CLIENT's own typed schema so a column-order / PK skew is caught
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,EAAE;AACF,6EAA6E;AAC7E,2FAA2F;AAC3F,sFAAsF;AACtF,0FAA0F;AAC1F,qCAAqC;AAGrC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Ast } from "./ast.ts";
|
|
2
2
|
import { type Query, type QueryRoot } from "./query.ts";
|
|
3
|
-
import type { ColsMap, RowOf, Schema } from "./schema.ts";
|
|
3
|
+
import type { ColsMap, InsertOf, RowOf, Schema } from "./schema.ts";
|
|
4
4
|
import type { Backend, ChangeEvent, QueryId, ResultType, WireValue } from "./types.ts";
|
|
5
|
-
import { type ArrayView } from "./view.ts";
|
|
5
|
+
import { type ArrayView, type ViewChangeListener } from "./view.ts";
|
|
6
6
|
/** One query's SSR snapshot, keyed by its `viewKey` ({@link stableKey} of the AST): the
|
|
7
7
|
* pre-projected first-paint `rows` plus the `cvMin` watermark they reflect (SSR-DESIGN.md §6.2).
|
|
8
8
|
* Serializable as-is into the HTML — `rows` are already JSON values (json columns parsed). */
|
|
@@ -22,9 +22,13 @@ export interface AssembledNode {
|
|
|
22
22
|
[rel: string]: unknown;
|
|
23
23
|
}
|
|
24
24
|
/** The write transaction handed to `store.write(tx => …)`. Rows are objects keyed by column;
|
|
25
|
-
* the Store positionalizes them (and stringifies json columns) before the backend sees them.
|
|
25
|
+
* the Store positionalizes them (and stringifies json columns) before the backend sees them.
|
|
26
|
+
*
|
|
27
|
+
* `add` takes an {@link InsertOf} row — a nullable column may be omitted (it is filled with `null`,
|
|
28
|
+
* design 206 §7). `remove`/`edit` take a full {@link RowOf} row: they identify an EXISTING row, so
|
|
29
|
+
* every column (nullable ones as their actual `T | null` value) must be present. */
|
|
26
30
|
export interface WriteTx<S extends ColsMap> {
|
|
27
|
-
add<N extends keyof S & string>(table: N, row:
|
|
31
|
+
add<N extends keyof S & string>(table: N, row: InsertOf<S[N]>): void;
|
|
28
32
|
remove<N extends keyof S & string>(table: N, row: RowOf<S[N]>): void;
|
|
29
33
|
edit<N extends keyof S & string>(table: N, oldRow: RowOf<S[N]>, newRow: RowOf<S[N]>): void;
|
|
30
34
|
}
|
|
@@ -77,8 +81,15 @@ export declare class Store<S extends ColsMap> {
|
|
|
77
81
|
private readonly pendingChanges;
|
|
78
82
|
constructor(schema: Schema<S>, backend: Backend);
|
|
79
83
|
/** Materialize any fluent query object. Named queries subscribe remotely by `(name,args)`;
|
|
80
|
-
* ad-hoc builder queries are local-only for local-first backends.
|
|
81
|
-
|
|
84
|
+
* ad-hoc builder queries are local-only for local-first backends.
|
|
85
|
+
*
|
|
86
|
+
* `opts.onChanges` binds a narrator to this view's DIFF stream ({@link ArrayView.onChanges}) — the
|
|
87
|
+
* per-view seam that replaces filtering the store-global {@link subscribeChanges} by `qid`. It is
|
|
88
|
+
* wired BEFORE the backend registers the query, so a synchronous backend's first `snapshot` (fired
|
|
89
|
+
* inside `registerQuery`, before this returns) is delivered too. */
|
|
90
|
+
materialize<Q extends Query<any, any, any>>(query: Q, opts?: {
|
|
91
|
+
onChanges?: ViewChangeListener;
|
|
92
|
+
}): ReturnType<Q["materialize"]>;
|
|
82
93
|
/** True when the backend can retain a remote named query independently from the local
|
|
83
94
|
* materialized AST view. React uses this to keep one local view per AST while still sending
|
|
84
95
|
* every mounted `(name,args)` lease through the backend. */
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAW,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/store.js
CHANGED
|
@@ -20,7 +20,9 @@ export class Store {
|
|
|
20
20
|
syncLeases = new Map();
|
|
21
21
|
// SSR seeds (SSR-DESIGN.md §6), keyed by `viewKey`: a view materialized for one of these is
|
|
22
22
|
// seeded for first paint; a seed is consumed (dropped) the moment its query's first live
|
|
23
|
-
// `hello`
|
|
23
|
+
// SNAPSHOT lands — NOT its `hello` — so the seed bridges the `hello`→snapshot gap (the live
|
|
24
|
+
// data arrives on the snapshot, a round-trip after the hello) and later mounts of a now-live
|
|
25
|
+
// query don't re-seed stale SSR data.
|
|
24
26
|
seeds = new Map();
|
|
25
27
|
// Public per-query change subscribers ({@link subscribeChanges}). `undefined` until the first
|
|
26
28
|
// subscription, so an app that never narrates (nor attaches devtools) pays one undefined-check per
|
|
@@ -88,10 +90,15 @@ export class Store {
|
|
|
88
90
|
this.query = queries(this.schema, (query) => this.materialize(query), { includeLocal: true });
|
|
89
91
|
}
|
|
90
92
|
/** Materialize any fluent query object. Named queries subscribe remotely by `(name,args)`;
|
|
91
|
-
* ad-hoc builder queries are local-only for local-first backends.
|
|
92
|
-
|
|
93
|
+
* ad-hoc builder queries are local-only for local-first backends.
|
|
94
|
+
*
|
|
95
|
+
* `opts.onChanges` binds a narrator to this view's DIFF stream ({@link ArrayView.onChanges}) — the
|
|
96
|
+
* per-view seam that replaces filtering the store-global {@link subscribeChanges} by `qid`. It is
|
|
97
|
+
* wired BEFORE the backend registers the query, so a synchronous backend's first `snapshot` (fired
|
|
98
|
+
* inside `registerQuery`, before this returns) is delivered too. */
|
|
99
|
+
materialize(query, opts) {
|
|
93
100
|
const remote = typeof query.name === "string" ? { name: query.name, args: query.args } : undefined;
|
|
94
|
-
return this.registerMaterialized(query.ast(), remote).view;
|
|
101
|
+
return this.registerMaterialized(query.ast(), remote, opts?.onChanges).view;
|
|
95
102
|
}
|
|
96
103
|
/** True when the backend can retain a remote named query independently from the local
|
|
97
104
|
* materialized AST view. React uses this to keep one local view per AST while still sending
|
|
@@ -262,7 +269,7 @@ export class Store {
|
|
|
262
269
|
return out;
|
|
263
270
|
}
|
|
264
271
|
// --- internals ---------------------------------------------------------------
|
|
265
|
-
registerMaterialized(ast, remote) {
|
|
272
|
+
registerMaterialized(ast, remote, onChanges) {
|
|
266
273
|
const qid = this.nextId++;
|
|
267
274
|
this.asts.set(qid, ast);
|
|
268
275
|
// Pre-create the view (PENDING) so `materialize` is synchronous for ANY backend — a remote
|
|
@@ -284,6 +291,10 @@ export class Store {
|
|
|
284
291
|
}
|
|
285
292
|
baseDestroy();
|
|
286
293
|
};
|
|
294
|
+
// Bind the narrator BEFORE `registerQuery` fires (a synchronous backend dispatches this query's
|
|
295
|
+
// first `hello`+`snapshot` inside it) so the initial snapshot reaches the change listener too.
|
|
296
|
+
if (onChanges)
|
|
297
|
+
view.onChanges(onChanges);
|
|
287
298
|
// If the backend rejects the registration (E3: a remote query naming a local-only table), roll
|
|
288
299
|
// back the per-qid state we just created — otherwise the view + ast entry leak (the caller never
|
|
289
300
|
// gets a handle to `destroy()` them, since the throw aborts before we return).
|
|
@@ -321,21 +332,30 @@ export class Store {
|
|
|
321
332
|
onEvent(qid, ev) {
|
|
322
333
|
if (ev.type === "hello") {
|
|
323
334
|
const ast = this.asts.get(qid);
|
|
324
|
-
// First live hello for this view ⇒ retire its SSR seed: the maintained tree now owns the
|
|
325
|
-
// result, so no future mount of the same query should flash the stale first-paint rows.
|
|
326
|
-
if (ast)
|
|
327
|
-
this.seeds.delete(stableKey(ast));
|
|
328
335
|
const types = ast ? this.viewTypes(ev.schema, ast) : undefined;
|
|
329
336
|
// Reset the (pre-created or existing) view IN PLACE — first hello OR a re-hydrate (new
|
|
330
|
-
// epoch) — so the materialized reference the caller holds survives a re-subscribe.
|
|
337
|
+
// epoch) — so the materialized reference the caller holds survives a re-subscribe. The SSR
|
|
338
|
+
// seed is KEPT across the reset and retired on the first `snapshot` below (the live data
|
|
339
|
+
// lands then, not on the hello), so a seeded query bridges the gap instead of flashing empty.
|
|
331
340
|
const view = this.views.get(qid) ?? this.views.set(qid, new FlatArrayView(undefined, undefined, qid)).get(qid);
|
|
332
341
|
view.reset(ev.schema, types);
|
|
333
342
|
}
|
|
334
343
|
else if (ev.type === "snapshot") {
|
|
335
|
-
|
|
344
|
+
// The first live snapshot IS the query's hydration point (even an empty one — 0 rows is an
|
|
345
|
+
// authoritative answer): retire the SSR seed now, from the view (so `data` switches to the
|
|
346
|
+
// maintained tree) AND from the seeds map (so no later mount re-seeds a now-live query),
|
|
347
|
+
// BEFORE folding so the fold's notify already reflects the live tree with no empty gap.
|
|
348
|
+
const ast = this.asts.get(qid);
|
|
349
|
+
if (ast)
|
|
350
|
+
this.seeds.delete(stableKey(ast));
|
|
351
|
+
this.views.get(qid)?.retireSeed();
|
|
352
|
+
this.applyAndTrack(qid, ev.adds, "snapshot");
|
|
336
353
|
}
|
|
337
354
|
else {
|
|
338
|
-
|
|
355
|
+
// A `catchUp` batch is a query's initial hydration delivered as a delta (the optimistic
|
|
356
|
+
// backend hydrates through its reconcile cycle), so phase it as a `snapshot` — a narrator's
|
|
357
|
+
// "what CHANGED" default then ignores the initial rows instead of narrating each as an add.
|
|
358
|
+
this.applyAndTrack(qid, ev.events, ev.catchUp ? "snapshot" : "batch");
|
|
339
359
|
}
|
|
340
360
|
// Fan the same post-fold frame out to subscribers (narration, devtools, …). Inside a commit
|
|
341
361
|
// bracket the frames are BUFFERED and delivered together at the boundary (after every view has
|
|
@@ -357,12 +377,12 @@ export class Store {
|
|
|
357
377
|
/** Fold a batch into its view, then notify now or — inside a commit bracket — defer the view's
|
|
358
378
|
* notification to the commit boundary, so all sibling views fold first (cross-view-atomic
|
|
359
379
|
* notification; see `commitDepth`). */
|
|
360
|
-
applyAndTrack(qid, events) {
|
|
380
|
+
applyAndTrack(qid, events, phase) {
|
|
361
381
|
const view = this.views.get(qid);
|
|
362
382
|
if (!view)
|
|
363
383
|
return;
|
|
364
384
|
const deferring = this.commitDepth > 0;
|
|
365
|
-
if (view.applyChanges(events, this.removedSubtreeWanted > 0, deferring) && deferring) {
|
|
385
|
+
if (view.applyChanges(events, this.removedSubtreeWanted > 0, deferring, phase) && deferring) {
|
|
366
386
|
this.pendingFlush.add(view);
|
|
367
387
|
}
|
|
368
388
|
}
|