@doubling/types 0.4.2 → 0.5.0

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
@@ -1,8 +1,8 @@
1
1
  # @doubling/types
2
2
 
3
- Shared TypeScript interfaces and pure helpers consumed by `web/` and `sync/` (verified via each package's `package.json` dependency and `import … from '@doubling/types'` sites). Single source of truth for Firestore document shapes (file/folder entities, org membership, teams, user profiles), file-extension to MIME mappings, and storage-path helpers.
3
+ Shared TypeScript interfaces and pure helpers consumed by `web/`, `sync/`, and `functions/` (verified via each package's `package.json` dependency and `import … from '@doubling/types'` sites). Single source of truth for Firestore document shapes (file/folder entities, org membership, teams, user profiles), file-extension to MIME mappings, storage-path helpers, the file-body `Y.Text` key, and the content-hash helper.
4
4
 
5
- `functions/` does **not** depend on this package: it deliberately keeps a local mirror of `OrgMember` (see `functions/src/index.ts`, "kept local because functions/…") pending a later migration. Root [`../DESIGN.md` §5](../DESIGN.md) describes the shapes as consumed by web, sync, and functions that is a *structural* statement (functions stores the same documents), not a package dependency.
5
+ `functions/` installs a staged copy of this package as `file:./vendor/types` so Cloud Run's reinstall, which sees only the uploaded `functions/` tree, can resolve it without a registry publish. Restage with `npm run stage:types-for-functions` after rebuilding `types/`. `functions/` still keeps a local mirror of `OrgMember` (see `functions/src/index.ts`) pending a later migration of that shape.
6
6
 
7
7
  Lives at the repo root as an npm workspace (`@doubling/types`). The compiled output is shipped at `dist/`, regenerated on `npm install` via the `prepare` script and rebuilt explicitly via `npm run build`.
8
8
 
@@ -14,21 +14,33 @@ Before this package, `web/` and `sync/` each kept their own copy of:
14
14
  - The `EXT_TO_MIME` table mapping extensions to MIME types.
15
15
  - `mimeTypeFromExt`, `isTextMimeType`, `extFromPath`, `storagePathFor`.
16
16
 
17
- The duplication was load-bearing for shipping (web and sync run in different environments and the bytes / hash helpers are necessarily environment-specific), but the static parts drifted. New text extensions that landed on one side and not the other caused the daemon to upload with `application/octet-stream` while the web's eager-load path skipped the file because the mime didn't match. Adding `@doubling/types` collapses both copies for the static parts and leaves the env-specific bytes / hash helpers in each consumer.
17
+ The duplication was load-bearing for shipping (web and sync run in different environments and the byte-coercion helpers are necessarily environment-specific), but the static parts drifted. New text extensions that landed on one side and not the other caused the daemon to upload with `application/octet-stream` while the web's eager-load path skipped the file because the mime didn't match. Adding `@doubling/types` collapses both copies for the static parts. The content hash later joined them: three hand-rolled SHA-256 hex encodings could drift and stay green, so the helper lives here too. Env-specific byte coercion (`toBytes`, `contentByteSize`) stays in each consumer.
18
18
 
19
19
  ## Layout
20
20
 
21
- - `src/crdt-store.ts`: `UpdateRecord`, `Snapshot`, `UpdateStore`, and
22
- `updateStoreConformance`. The CRDT update-store contract plus the behavioural
23
- cases both `web/` and `sync/` run against their own backends. It lives here
24
- because it is the only dependency-free part of the CRDT stack — types over
25
- `Uint8Array` and `string`, since a store treats updates as opaque bytes — and
26
- because a package with shared runtime deps cannot be shared at all under this
27
- repo's nested install strategy (DOU-379).
21
+ - `src/crdt-store.ts`: `UpdateRecord`, `Snapshot`, `UpdateStore`,
22
+ `isAfterBaseline`, `isVisibleAfterFirestoreBaseline`,
23
+ `firestoreBaselineInclusiveMillis`,
24
+ `isReconnectFromCache`, `compactionPublishedCoveringBaseline`,
25
+ `isTransientResyncError`, `snapshotReloadUnchanged`, and
26
+ `updateStoreConformance`. The CRDT update-store contract plus the
27
+ behavioural cases both `web/` and `sync/` run against their own backends.
28
+ Contract comparison is the full record id. Firestore replay also keeps
29
+ the rest of the baseline millisecond because auto-ids are random and a
30
+ losing fold can leave a lower-id row from that millisecond in the log. It lives here because it is the only dependency-free
31
+ part of the CRDT stack (types over `Uint8Array` and `string`, since a
32
+ store treats updates as opaque bytes) and because a package with shared
33
+ runtime deps cannot be shared at all under this repo's nested install
34
+ strategy (DOU-379).
35
+ - `src/crdt-text.ts`: `YTEXT_KEY`, the `Y.Text` name the file body lives in.
36
+ - `src/content-hash.ts`: `contentBytes` and `computeContentHash` (Web Crypto,
37
+ async). Shared SHA-256 hex of the UTF-8 bytes.
38
+ - `src/content-hash-node.ts`: sync Node adapter, exported as
39
+ `@doubling/types/node` so a browser bundle never pulls `node:crypto`.
28
40
  - `src/firestore.ts`: `FileEntity`, `FolderEntity`, `Entity`, `OrgMembership`, `OrgMember`, `Team`, `TeamMember`, `UserProfile`, `Scope`.
29
41
  - `src/mime.ts`: `EXT_TO_MIME`, `mimeTypeFromExt`, `isTextMimeType`.
30
42
  - `src/paths.ts`: `extFromPath`, `storagePathFor`.
31
- - `src/index.ts`: barrel export.
43
+ - `src/index.ts`: barrel export. The Node hash adapter is not on the barrel.
32
44
 
33
45
  ## Adding a new extension
34
46
 
@@ -0,0 +1,4 @@
1
+ import { type ContentHashInput } from './content-hash.js';
2
+ export type { ContentHashInput };
3
+ export declare function computeContentHash(data: ContentHashInput): string;
4
+ //# sourceMappingURL=content-hash-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-hash-node.d.ts","sourceRoot":"","sources":["../src/content-hash-node.ts"],"names":[],"mappings":"AASA,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAExE,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAEjE"}
@@ -0,0 +1,13 @@
1
+ // Sync Node adapter for the shared content hash.
2
+ //
3
+ // The isomorphic helper is async (Web Crypto). The daemon hashes on
4
+ // paths that are still synchronous, so this adapter uses node:crypto on
5
+ // the same `contentBytes` normalisation. The types suite pins both
6
+ // against node:crypto so they cannot drift. Not exported from the
7
+ // package root: a browser bundle must not pull `node:crypto`.
8
+ import { createHash } from 'node:crypto';
9
+ import { contentBytes } from './content-hash.js';
10
+ export function computeContentHash(data) {
11
+ return createHash('sha256').update(contentBytes(data)).digest('hex');
12
+ }
13
+ //# sourceMappingURL=content-hash-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-hash-node.js","sourceRoot":"","sources":["../src/content-hash-node.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,oEAAoE;AACpE,wEAAwE;AACxE,mEAAmE;AACnE,kEAAkE;AAClE,8DAA8D;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAyB,MAAM,mBAAmB,CAAC;AAIxE,MAAM,UAAU,kBAAkB,CAAC,IAAsB;IACvD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,4 @@
1
+ export type ContentHashInput = string | Uint8Array | ArrayBuffer | null | undefined;
2
+ export declare function contentBytes(data: ContentHashInput): Uint8Array;
3
+ export declare function computeContentHash(data: ContentHashInput): Promise<string>;
4
+ //# sourceMappingURL=content-hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-hash.d.ts","sourceRoot":"","sources":["../src/content-hash.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;AAEpF,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,UAAU,CAK/D;AAiBD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAIhF"}
@@ -0,0 +1,35 @@
1
+ // Content hash shared by web, the daemon, and compaction.
2
+ //
3
+ // SHA-256 of the UTF-8 bytes, lowercase hex, no prefix. The daemon
4
+ // compares its own hash of the disk bytes against the stamped field, so
5
+ // an encoding difference would read as "the file changed" on every pull.
6
+ // Web Crypto is available in the browser and in Node 22, so this is the
7
+ // one implementation every surface can call.
8
+ export function contentBytes(data) {
9
+ if (data == null)
10
+ return new Uint8Array(0);
11
+ if (data instanceof Uint8Array)
12
+ return data;
13
+ if (data instanceof ArrayBuffer)
14
+ return new Uint8Array(data);
15
+ return new TextEncoder().encode(String(data));
16
+ }
17
+ function arrayBufferOf(bytes) {
18
+ if (bytes.buffer instanceof ArrayBuffer) {
19
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
20
+ }
21
+ return new Uint8Array(bytes).buffer;
22
+ }
23
+ function hexFromBytes(bytes) {
24
+ let hex = '';
25
+ for (let i = 0; i < bytes.length; i++) {
26
+ hex += (bytes[i] ?? 0).toString(16).padStart(2, '0');
27
+ }
28
+ return hex;
29
+ }
30
+ export async function computeContentHash(data) {
31
+ const bytes = contentBytes(data);
32
+ const digest = await globalThis.crypto.subtle.digest('SHA-256', arrayBufferOf(bytes));
33
+ return hexFromBytes(new Uint8Array(digest));
34
+ }
35
+ //# sourceMappingURL=content-hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-hash.js","sourceRoot":"","sources":["../src/content-hash.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,mEAAmE;AACnE,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AACxE,6CAA6C;AAI7C,MAAM,UAAU,YAAY,CAAC,IAAsB;IACjD,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3C,IAAI,IAAI,YAAY,UAAU;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,IAAI,YAAY,WAAW;QAAE,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IAC7D,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,aAAa,CAAC,KAAiB;IACtC,IAAI,KAAK,CAAC,MAAM,YAAY,WAAW,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AACtC,CAAC;AAED,SAAS,YAAY,CAAC,KAAiB;IACrC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAsB;IAC7D,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IACtF,OAAO,YAAY,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9C,CAAC"}
@@ -3,12 +3,19 @@ export interface UpdateRecord {
3
3
  id: string;
4
4
  update: Uint8Array;
5
5
  }
6
- /** A folded snapshot plus the highest update id it covers. */
6
+ /** A folded snapshot plus the highest update id it claims. */
7
7
  export interface Snapshot {
8
8
  state: Uint8Array;
9
9
  /** null means "no known baseline" — replay the whole log. */
10
10
  baselineId: string | null;
11
11
  }
12
+ /** Options for `UpdateStore.loadSnapshot`. */
13
+ export interface LoadSnapshotOptions {
14
+ /** When true, Firestore backends must not accept a cached document.
15
+ * Used on reconnect: `getDoc` can return the same stale cache that
16
+ * the listener just flipped away from. Memory backends ignore this. */
17
+ fromServer?: boolean;
18
+ }
12
19
  /**
13
20
  * The storage seam between a CRDT provider and any concrete backend.
14
21
  *
@@ -17,8 +24,19 @@ export interface Snapshot {
17
24
  * - Every `UpdateRecord` has a unique, monotonically-ordered `id`.
18
25
  * Backends choose the encoding (server timestamp + doc id, a counter,
19
26
  * a ULID) but iterating in id order must replay in append order.
20
- * - `baselineId` is the highest id covered by the current snapshot.
21
- * `loadUpdatesAfter(baselineId)` returns strictly newer records.
27
+ * - `baselineId` is the highest id the current snapshot claims.
28
+ * `loadUpdatesAfter(baselineId)` returns strictly newer records
29
+ * by full id, not by a timestamp prefix. Two Firestore records
30
+ * can share a `createdAt` millisecond; the later composite id
31
+ * is still after the baseline. Firestore backends also keep the
32
+ * rest of that millisecond: auto-ids are random, and a losing
33
+ * fold can leave a lower-id row from it in the log.
34
+ * The encoded snapshot may also contain refused future-dated rows
35
+ * that stay in the log (applied so a later claimed update that
36
+ * depends on them is not still pending when that claimed row is
37
+ * deleted). Yjs applies are idempotent, so replay of those rows
38
+ * is safe. Consumers must not assume the baseline is the highest
39
+ * id present in the snapshot bytes.
22
40
  * - Ids exist only on records **read back** from the store.
23
41
  * `appendUpdate` returns void: the backend assigns the id (a server
24
42
  * timestamp, in Firestore's case), so resolving it at append time
@@ -41,7 +59,7 @@ export interface Snapshot {
41
59
  * keep the method for those tests; it is simply not part of the contract.
42
60
  */
43
61
  export interface UpdateStore {
44
- loadSnapshot(): Promise<Snapshot | null>;
62
+ loadSnapshot(options?: LoadSnapshotOptions): Promise<Snapshot | null>;
45
63
  loadUpdatesAfter(baselineId: string | null): Promise<UpdateRecord[]>;
46
64
  appendUpdate(update: Uint8Array): Promise<void>;
47
65
  /** Stream records as they are appended.
@@ -55,9 +73,94 @@ export interface UpdateStore {
55
73
  * each re-reading everything (DOU-395).
56
74
  *
57
75
  * Implementations must honour it, including in-memory ones, so tests
58
- * exercise the same contract production does. */
59
- subscribeUpdates(onUpdate: (record: UpdateRecord) => void, baselineId?: string | null): () => void;
76
+ * exercise the same contract production does.
77
+ *
78
+ * `onResync` fires when the caller must treat its view as possibly
79
+ * stale and reload the snapshot. Implementations fire it after the
80
+ * stream reconnects (Firestore: cache-to-server). Both Firestore
81
+ * ports also fire it on the first server-served snapshot, because
82
+ * `loadInitial` finishes before the listener attaches and a fold in
83
+ * that gap has no cache-to-server transition. Updates missed while
84
+ * away may have been folded into the snapshot and deleted from the
85
+ * log, in which case they will never be delivered (DOU-424). Silent
86
+ * divergence, so the signal is part of the contract rather than a
87
+ * Firestore detail. */
88
+ subscribeUpdates(onUpdate: (record: UpdateRecord) => void, baselineId?: string | null, onResync?: () => void): () => void;
89
+ }
90
+ /** True when `id` is strictly newer than `baselineId`.
91
+ *
92
+ * Comparison is the full record id. Firestore encodes
93
+ * padded-millis_docId, so two records can share a millisecond
94
+ * and still be ordered by the document-id tiebreaker. */
95
+ export declare function isAfterBaseline(id: string, baselineId: string | null): boolean;
96
+ /** Inclusive createdAt millisecond for a padded-millis_docId baseline.
97
+ *
98
+ * Both Firestore stores query `createdAt >= fromMillis(this value)`.
99
+ * An exclusive `>` hides a same-millisecond leftover whose document
100
+ * id sorts below the baseline suffix. Published baselines stay on
101
+ * this millis encoding; a seconds-and-nanos formatId is a different
102
+ * migration. */
103
+ export declare function firestoreBaselineInclusiveMillis(baselineId: string): number;
104
+ /** Firestore padded-millis_docId visibility after a snapshot baseline.
105
+ *
106
+ * Auto-ids are random, so a later commit in the baseline millisecond
107
+ * can sort below the baseline suffix. A losing fold can also leave a
108
+ * lower-id row from that millisecond in the log. Keep every record in
109
+ * that millisecond except the baseline id itself. Earlier milliseconds
110
+ * stay dropped. */
111
+ export declare function isVisibleAfterFirestoreBaseline(id: string, baselineId: string | null): boolean;
112
+ /** True when snapshot metadata says this listener still needs a
113
+ * server-served result, or just came back from a cache-served window.
114
+ *
115
+ * Both Firestore ports start `servedFromCache` at `true`, so the first
116
+ * `fromCache === false` snapshot reconciles: `loadInitial` finishes
117
+ * before the listener attaches, and a fold in that gap has no
118
+ * cache-to-server transition. After that first server result the same
119
+ * predicate is the later reconnect signal: not "metadata changed",
120
+ * and not "went offline".
121
+ *
122
+ * Named and exported so both Firestore ports share one implementation
123
+ * and a unit test can exercise the detector without having to flip
124
+ * emulator networking (which does not reliably set `fromCache`). */
125
+ export declare function isReconnectFromCache(servedFromCache: boolean, fromCache: boolean): boolean;
126
+ /** Outcome of a `requestCompaction` call. `covered` is true only when
127
+ * this call published a snapshot baseline that includes the records the
128
+ * provider counted. Skip statuses leave those rows in the log. */
129
+ export interface CompactionRequestResult {
130
+ covered: boolean;
60
131
  }
132
+ /** True when the callable published a covering baseline.
133
+ *
134
+ * Accepts the provider result (`{ covered }`), the callable payload
135
+ * (`{ status: 'compacted' }`), or the httpsCallable wrap (`{ data }`).
136
+ * `undefined` is treated as covered so existing test callbacks that
137
+ * return void keep the reset they already assert. A `compacted`
138
+ * payload that also names `refusedFutureRows > 0` is not covering:
139
+ * those rows stay in the log. A present `refusedFutureRows` that is
140
+ * not a finite count of zero or more fails closed the same way.
141
+ * Every other unrecognized shape fails closed: a version-skewed or
142
+ * empty payload must not clear the backlog. */
143
+ export declare function compactionPublishedCoveringBaseline(result: unknown): boolean;
144
+ /** True when a reconnect confirm-read matches the first snapshot read.
145
+ *
146
+ * Null and a later snapshot are not stable, even when both have a
147
+ * null `baselineId`: a first fold can publish state without a
148
+ * baseline, and treating that as unchanged would skip applying it. */
149
+ export declare function snapshotReloadUnchanged(first: Snapshot | null, confirm: Snapshot | null): boolean;
150
+ /** Tag a snapshot decode or validation failure so resync stops.
151
+ *
152
+ * Stores throw a plain `Error` for an unknown encoding and Node Brotli
153
+ * throws a coded `Error`, neither of which is a `TypeError`. Both
154
+ * Firestore readers attach this code so `isTransientResyncError`
155
+ * classifies them as terminal. */
156
+ export declare function snapshotDecodeError(message: string, cause?: unknown): Error;
157
+ /** True when a reconnect snapshot reload should keep retrying.
158
+ *
159
+ * Permanent codes (permission-denied, unauthenticated, data-loss from
160
+ * an unreadable snapshot) stop the loop. Unknown errors without a
161
+ * code stay retryable: those are the connectivity failures the loop
162
+ * exists for. `TypeError` stays terminal for `Y.applyUpdate`. */
163
+ export declare function isTransientResyncError(err: unknown): boolean;
61
164
  /** Minimal assertion surface, so this module stays dependency-free and
62
165
  * can be driven by `node:assert`, vitest, or anything else. */
63
166
  export interface ConformanceAsserts {
@@ -1 +1 @@
1
- {"version":3,"file":"crdt-store.d.ts","sourceRoot":"","sources":["../src/crdt-store.ts"],"names":[],"mappings":"AA6BA,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,8DAA8D;AAC9D,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,UAAU,CAAC;IAClB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,WAAW;IAC1B,YAAY,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACzC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACrE,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD;;;;;;;;;;;qDAWiD;IACjD,gBAAgB,CACd,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,EACxC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GACzB,MAAM,IAAI,CAAC;CACf;AAID;+DAC+D;AAC/D,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClE,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAaD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,EAAE,eAAe,EAgGnD,CAAC"}
1
+ {"version":3,"file":"crdt-store.d.ts","sourceRoot":"","sources":["../src/crdt-store.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,152 @@
26
26
  // than something a reader has to notice. That is what actually failed
27
27
  // before — the divergences found in this subsystem were all found by
28
28
  // reading, never by a check.
29
+ /** True when `id` is strictly newer than `baselineId`.
30
+ *
31
+ * Comparison is the full record id. Firestore encodes
32
+ * padded-millis_docId, so two records can share a millisecond
33
+ * and still be ordered by the document-id tiebreaker. */
34
+ export function isAfterBaseline(id, baselineId) {
35
+ return baselineId === null || id > baselineId;
36
+ }
37
+ /** Inclusive createdAt millisecond for a padded-millis_docId baseline.
38
+ *
39
+ * Both Firestore stores query `createdAt >= fromMillis(this value)`.
40
+ * An exclusive `>` hides a same-millisecond leftover whose document
41
+ * id sorts below the baseline suffix. Published baselines stay on
42
+ * this millis encoding; a seconds-and-nanos formatId is a different
43
+ * migration. */
44
+ export function firestoreBaselineInclusiveMillis(baselineId) {
45
+ const millis = Number(baselineId.split('_')[0] ?? '');
46
+ if (!Number.isFinite(millis)) {
47
+ throw new Error('invalid Firestore baseline id');
48
+ }
49
+ return millis;
50
+ }
51
+ /** Firestore padded-millis_docId visibility after a snapshot baseline.
52
+ *
53
+ * Auto-ids are random, so a later commit in the baseline millisecond
54
+ * can sort below the baseline suffix. A losing fold can also leave a
55
+ * lower-id row from that millisecond in the log. Keep every record in
56
+ * that millisecond except the baseline id itself. Earlier milliseconds
57
+ * stay dropped. */
58
+ export function isVisibleAfterFirestoreBaseline(id, baselineId) {
59
+ if (baselineId === null)
60
+ return true;
61
+ if (id === baselineId)
62
+ return false;
63
+ const idMs = id.split('_')[0] ?? '';
64
+ const baseMs = baselineId.split('_')[0] ?? '';
65
+ return idMs >= baseMs;
66
+ }
67
+ /** True when snapshot metadata says this listener still needs a
68
+ * server-served result, or just came back from a cache-served window.
69
+ *
70
+ * Both Firestore ports start `servedFromCache` at `true`, so the first
71
+ * `fromCache === false` snapshot reconciles: `loadInitial` finishes
72
+ * before the listener attaches, and a fold in that gap has no
73
+ * cache-to-server transition. After that first server result the same
74
+ * predicate is the later reconnect signal: not "metadata changed",
75
+ * and not "went offline".
76
+ *
77
+ * Named and exported so both Firestore ports share one implementation
78
+ * and a unit test can exercise the detector without having to flip
79
+ * emulator networking (which does not reliably set `fromCache`). */
80
+ export function isReconnectFromCache(servedFromCache, fromCache) {
81
+ return servedFromCache && !fromCache;
82
+ }
83
+ const TERMINAL_RESYNC_CODES = new Set([
84
+ 'permission-denied',
85
+ 'unauthenticated',
86
+ 'invalid-argument',
87
+ 'failed-precondition',
88
+ 'data-loss',
89
+ ]);
90
+ function errorCode(err) {
91
+ if (typeof err !== 'object' || err === null)
92
+ return null;
93
+ if (!('code' in err))
94
+ return null;
95
+ const code = err.code;
96
+ return typeof code === 'string' ? code : null;
97
+ }
98
+ function unwrapCallableData(result) {
99
+ if (typeof result !== 'object' || result === null)
100
+ return result;
101
+ if ('data' in result)
102
+ return result.data;
103
+ return result;
104
+ }
105
+ /** True when the callable published a covering baseline.
106
+ *
107
+ * Accepts the provider result (`{ covered }`), the callable payload
108
+ * (`{ status: 'compacted' }`), or the httpsCallable wrap (`{ data }`).
109
+ * `undefined` is treated as covered so existing test callbacks that
110
+ * return void keep the reset they already assert. A `compacted`
111
+ * payload that also names `refusedFutureRows > 0` is not covering:
112
+ * those rows stay in the log. A present `refusedFutureRows` that is
113
+ * not a finite count of zero or more fails closed the same way.
114
+ * Every other unrecognized shape fails closed: a version-skewed or
115
+ * empty payload must not clear the backlog. */
116
+ export function compactionPublishedCoveringBaseline(result) {
117
+ if (result === undefined)
118
+ return true;
119
+ const data = unwrapCallableData(result);
120
+ if (typeof data !== 'object' || data === null)
121
+ return false;
122
+ if (refusedFutureRowsPreventCoverage(data))
123
+ return false;
124
+ if ('covered' in data)
125
+ return data.covered === true;
126
+ if ('status' in data)
127
+ return data.status === 'compacted';
128
+ return false;
129
+ }
130
+ function refusedFutureRowsPreventCoverage(data) {
131
+ if (!('refusedFutureRows' in data))
132
+ return false;
133
+ const n = data.refusedFutureRows;
134
+ if (typeof n !== 'number' || !Number.isFinite(n) || n < 0)
135
+ return true;
136
+ return n > 0;
137
+ }
138
+ /** True when a reconnect confirm-read matches the first snapshot read.
139
+ *
140
+ * Null and a later snapshot are not stable, even when both have a
141
+ * null `baselineId`: a first fold can publish state without a
142
+ * baseline, and treating that as unchanged would skip applying it. */
143
+ export function snapshotReloadUnchanged(first, confirm) {
144
+ if (first === null && confirm === null)
145
+ return true;
146
+ if (first === null || confirm === null)
147
+ return false;
148
+ return (first.baselineId ?? null) === (confirm.baselineId ?? null);
149
+ }
150
+ /** Tag a snapshot decode or validation failure so resync stops.
151
+ *
152
+ * Stores throw a plain `Error` for an unknown encoding and Node Brotli
153
+ * throws a coded `Error`, neither of which is a `TypeError`. Both
154
+ * Firestore readers attach this code so `isTransientResyncError`
155
+ * classifies them as terminal. */
156
+ export function snapshotDecodeError(message, cause) {
157
+ const err = cause !== undefined ? new Error(message, { cause }) : new Error(message);
158
+ return Object.assign(err, { code: 'data-loss' });
159
+ }
160
+ /** True when a reconnect snapshot reload should keep retrying.
161
+ *
162
+ * Permanent codes (permission-denied, unauthenticated, data-loss from
163
+ * an unreadable snapshot) stop the loop. Unknown errors without a
164
+ * code stay retryable: those are the connectivity failures the loop
165
+ * exists for. `TypeError` stays terminal for `Y.applyUpdate`. */
166
+ export function isTransientResyncError(err) {
167
+ if (err instanceof TypeError)
168
+ return false;
169
+ const code = errorCode(err);
170
+ if (!code)
171
+ return true;
172
+ const tail = code.includes('/') ? code.slice(code.lastIndexOf('/') + 1) : code;
173
+ return !TERMINAL_RESYNC_CODES.has(tail);
174
+ }
29
175
  const encoder = new TextEncoder();
30
176
  const decoder = new TextDecoder();
31
177
  function bytes(s) {
@@ -92,6 +238,22 @@ export const updateStoreConformance = [
92
238
  a.deepEqual(after.map((r) => text(r.update)), ['second']);
93
239
  },
94
240
  },
241
+ {
242
+ name: 'a later id that shares the baseline time prefix is still after it',
243
+ async run(store, a) {
244
+ // Memory backends use counters; Firestore uses padded-millis_docId.
245
+ // Either encoding must keep a record whose full id is greater,
246
+ // including when only the suffix differs (same millisecond).
247
+ await store.appendUpdate(bytes('first'));
248
+ await store.appendUpdate(bytes('second'));
249
+ const all = await store.loadUpdatesAfter(null);
250
+ a.equal(all.length, 2);
251
+ a.ok(isAfterBaseline(all[1].id, all[0].id));
252
+ a.ok(!isAfterBaseline(all[0].id, all[0].id));
253
+ const after = await store.loadUpdatesAfter(all[0].id);
254
+ a.deepEqual(after.map((r) => text(r.update)), ['second']);
255
+ },
256
+ },
95
257
  {
96
258
  name: 'the newest id yields an empty tail',
97
259
  async run(store, a) {
@@ -1 +1 @@
1
- {"version":3,"file":"crdt-store.js","sourceRoot":"","sources":["../src/crdt-store.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,oCAAoC;AACpC,EAAE;AACF,gEAAgE;AAChE,yEAAyE;AACzE,uEAAuE;AACvE,yEAAyE;AACzE,sEAAsE;AACtE,wDAAwD;AACxD,wEAAwE;AACxE,oEAAoE;AACpE,uEAAuE;AACvE,mEAAmE;AACnE,2DAA2D;AAC3D,6CAA6C;AAC7C,EAAE;AACF,wEAAwE;AACxE,yEAAyE;AACzE,sEAAsE;AACtE,kCAAkC;AAClC,EAAE;AACF,oEAAoE;AACpE,uEAAuE;AACvE,wEAAwE;AACxE,sEAAsE;AACtE,qEAAqE;AACrE,6BAA6B;AAmF7B,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAClC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC,SAAS,KAAK,CAAC,CAAS;IACtB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,IAAI,CAAC,CAAa;IACzB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACvD;QACE,IAAI,EAAE,sDAAsD;QAC5D,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,YAAY,EAAE,EAAE,IAAI,CAAC,CAAC;QAC5C,CAAC;KACF;IACD;QACE,IAAI,EAAE,kDAAkD;QACxD,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACtD,CAAC;KACF;IACD;QACE,IAAI,EAAE,4CAA4C;QAClD,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YACvC,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YACvC,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YACzC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC/C,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;QACvE,CAAC;KACF;IACD;QACE,IAAI,EAAE,kDAAkD;QACxD,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAClE,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YAC/B,CAAC,CAAC,SAAS,CACT,GAAG,EACH,MAAM,EACN,2EAA2E,CAC5E,CAAC;QACJ,CAAC;KACF;IACD;QACE,IAAI,EAAE,2DAA2D;QACjE,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YACzC,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC/C,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACvB,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC;YACvD,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5D,CAAC;KACF;IACD;QACE,IAAI,EAAE,oCAAoC;QAC1C,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;YACxC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC/C,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACzE,CAAC;KACF;IACD;QACE,IAAI,EAAE,qDAAqD;QAC3D,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,oEAAoE;YACpE,iEAAiE;YACjE,iEAAiE;YACjE,oEAAoE;YACpE,MAAM,KAAK,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC/C,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,mCAAmC,CAAC,CAAC;YAC5D,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC;KACF;IACD;QACE,IAAI,EAAE,8DAA8D;QACpE,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,GAAa,EAAE,CAAC;YAC1B,MAAM,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC7E,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;YACxC,6DAA6D;YAC7D,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAC5C,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,0BAA0B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC9E,WAAW,EAAE,CAAC;QAChB,CAAC;KACF;IACD;QACE,IAAI,EAAE,4BAA4B;QAClC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,GAAa,EAAE,CAAC;YAC1B,MAAM,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC7E,WAAW,EAAE,CAAC;YACd,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;YACrD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAC5C,CAAC,CAAC,EAAE,CACF,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EACnC,qCAAqC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAC5D,CAAC;QACJ,CAAC;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"crdt-store.js","sourceRoot":"","sources":["../src/crdt-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const YTEXT_KEY = "content";
2
+ //# sourceMappingURL=crdt-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crdt-text.d.ts","sourceRoot":"","sources":["../src/crdt-text.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,SAAS,YAAY,CAAC"}
@@ -0,0 +1,8 @@
1
+ // The Y.Text the file body lives in.
2
+ //
3
+ // getText on any other name returns an empty sequence, and for a file
4
+ // already declared CRDT-owned an empty document legally means the file
5
+ // is empty. A typo therefore silently empties the blob. Web, the daemon,
6
+ // and compaction all import this one definition so they cannot drift.
7
+ export const YTEXT_KEY = 'content';
8
+ //# sourceMappingURL=crdt-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crdt-text.js","sourceRoot":"","sources":["../src/crdt-text.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,sEAAsE;AACtE,uEAAuE;AACvE,yEAAyE;AACzE,sEAAsE;AAEtE,MAAM,CAAC,MAAM,SAAS,GAAG,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"firestore.d.ts","sourceRoot":"","sources":["../src/firestore.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAKvC,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AASD,MAAM,WAAW,UAAW,SAAQ,UAAU;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IA2BtB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAQhC,iBAAiB,CAAC,EAAE,IAAI,CAAC;CAC1B;AAGD,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,IAAI,EAAE,QAAQ,CAAC;CAChB;AAID,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;AAM/C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IAQjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAGD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
1
+ {"version":3,"file":"firestore.d.ts","sourceRoot":"","sources":["../src/firestore.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAKvC,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AASD,MAAM,WAAW,UAAW,SAAQ,UAAU;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IA4BtB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAQhC,iBAAiB,CAAC,EAAE,IAAI,CAAC;CAC1B;AAGD,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,IAAI,EAAE,QAAQ,CAAC;CAChB;AAID,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;AAM/C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IAQjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAGD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ export * from './content-hash.js';
1
2
  export * from './crdt-store.js';
2
3
  export * from './crdt-testing.js';
4
+ export * from './crdt-text.js';
3
5
  export * from './firestore.js';
4
6
  export * from './mime.js';
5
7
  export * from './paths.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -4,8 +4,10 @@
4
4
  // relative imports in TypeScript source, even though the actual file
5
5
  // on disk is `.ts`. tsc and Node's ESM loader rewrite to the
6
6
  // compiled `.js` at build / runtime.
7
+ export * from './content-hash.js';
7
8
  export * from './crdt-store.js';
8
9
  export * from './crdt-testing.js';
10
+ export * from './crdt-text.js';
9
11
  export * from './firestore.js';
10
12
  export * from './mime.js';
11
13
  export * from './paths.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,EAAE;AACF,6DAA6D;AAC7D,qEAAqE;AACrE,6DAA6D;AAC7D,qCAAqC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,EAAE;AACF,6DAA6D;AAC7D,qEAAqE;AACrE,6DAA6D;AAC7D,qCAAqC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@doubling/types",
3
- "version": "0.4.2",
4
- "description": "Shared Firestore document interfaces and MIME / path helpers consumed by web/ and sync/. Single source of truth so the two consumers can never drift on a document shape (DOU-182, TS Phase 2 of the monorepo TypeScript migration).",
3
+ "version": "0.5.0",
4
+ "description": "Shared Firestore document interfaces, MIME / path helpers, and CRDT constants consumed by web/, sync/, and functions/. Single source of truth so consumers cannot drift on a document shape or a content-hash encoding.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -9,6 +9,10 @@
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js"
12
+ },
13
+ "./node": {
14
+ "types": "./dist/content-hash-node.d.ts",
15
+ "import": "./dist/content-hash-node.js"
12
16
  }
13
17
  },
14
18
  "files": [