@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 +23 -11
- package/dist/content-hash-node.d.ts +4 -0
- package/dist/content-hash-node.d.ts.map +1 -0
- package/dist/content-hash-node.js +13 -0
- package/dist/content-hash-node.js.map +1 -0
- package/dist/content-hash.d.ts +4 -0
- package/dist/content-hash.d.ts.map +1 -0
- package/dist/content-hash.js +35 -0
- package/dist/content-hash.js.map +1 -0
- package/dist/crdt-store.d.ts +109 -6
- package/dist/crdt-store.d.ts.map +1 -1
- package/dist/crdt-store.js +162 -0
- package/dist/crdt-store.js.map +1 -1
- package/dist/crdt-text.d.ts +2 -0
- package/dist/crdt-text.d.ts.map +1 -0
- package/dist/crdt-text.js +8 -0
- package/dist/crdt-text.js.map +1 -0
- package/dist/firestore.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @doubling/types
|
|
2
2
|
|
|
3
|
-
Shared TypeScript interfaces and pure helpers consumed by `web
|
|
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/`
|
|
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
|
|
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`,
|
|
22
|
-
`
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
`
|
|
26
|
-
|
|
27
|
-
|
|
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 @@
|
|
|
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"}
|
package/dist/crdt-store.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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 {
|
package/dist/crdt-store.d.ts.map
CHANGED
|
@@ -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
|
|
1
|
+
{"version":3,"file":"crdt-store.d.ts","sourceRoot":"","sources":["../src/crdt-store.ts"],"names":[],"mappings":"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"}
|
package/dist/crdt-store.js
CHANGED
|
@@ -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) {
|
package/dist/crdt-store.js.map
CHANGED
|
@@ -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;
|
|
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;AAmG7B;;;;yDAIyD;AACzD,MAAM,UAAU,eAAe,CAAC,EAAU,EAAE,UAAyB;IACnE,OAAO,UAAU,KAAK,IAAI,IAAI,EAAE,GAAG,UAAU,CAAC;AAChD,CAAC;AAED;;;;;;gBAMgB;AAChB,MAAM,UAAU,gCAAgC,CAAC,UAAkB;IACjE,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;mBAMmB;AACnB,MAAM,UAAU,+BAA+B,CAC7C,EAAU,EACV,UAAyB;IAEzB,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,EAAE,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,OAAO,IAAI,IAAI,MAAM,CAAC;AACxB,CAAC;AAED;;;;;;;;;;;;oEAYoE;AACpE,MAAM,UAAU,oBAAoB,CAAC,eAAwB,EAAE,SAAkB;IAC/E,OAAO,eAAe,IAAI,CAAC,SAAS,CAAC;AACvC,CAAC;AASD,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,mBAAmB;IACnB,iBAAiB;IACjB,kBAAkB;IAClB,qBAAqB;IACrB,WAAW;CACZ,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACzD,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAClC,MAAM,IAAI,GAAI,GAAyB,CAAC,IAAI,CAAC;IAC7C,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAe;IACzC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACjE,IAAI,MAAM,IAAI,MAAM;QAAE,OAAQ,MAA4B,CAAC,IAAI,CAAC;IAChE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;+CAU+C;AAC/C,MAAM,UAAU,mCAAmC,CAAC,MAAe;IACjE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC5D,IAAI,gCAAgC,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,IAAI,SAAS,IAAI,IAAI;QAAE,OAAQ,IAA6B,CAAC,OAAO,KAAK,IAAI,CAAC;IAC9E,IAAI,QAAQ,IAAI,IAAI;QAAE,OAAQ,IAA4B,CAAC,MAAM,KAAK,WAAW,CAAC;IAClF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,gCAAgC,CAAC,IAAY;IACpD,IAAI,CAAC,CAAC,mBAAmB,IAAI,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,MAAM,CAAC,GAAI,IAAuC,CAAC,iBAAiB,CAAC;IACrE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;sEAIsE;AACtE,MAAM,UAAU,uBAAuB,CACrC,KAAsB,EACtB,OAAwB;IAExB,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACpD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACrD,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;AACrE,CAAC;AAED;;;;;kCAKkC;AAClC,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,KAAe;IAClE,MAAM,GAAG,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IACrF,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;AACnD,CAAC;AAED;;;;;iEAKiE;AACjE,MAAM,UAAU,sBAAsB,CAAC,GAAY;IACjD,IAAI,GAAG,YAAY,SAAS;QAAE,OAAO,KAAK,CAAC;IAC3C,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/E,OAAO,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC1C,CAAC;AAiBD,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,mEAAmE;QACzE,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAChB,oEAAoE;YACpE,+DAA+D;YAC/D,6DAA6D;YAC7D,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,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC9C,CAAC,CAAC,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/C,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"}
|
|
@@ -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"}
|
package/dist/firestore.d.ts.map
CHANGED
|
@@ -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;
|
|
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
package/dist/index.d.ts.map
CHANGED
|
@@ -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
|
-
"description": "Shared Firestore document interfaces
|
|
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": [
|