@tinycloud/web-sdk 3.2.6-beta.6 → 3.3.0-beta.8

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
@@ -46,6 +46,143 @@ const result = await storage.get('myKey');
46
46
  console.log(result.data); // { hello: 'world' }
47
47
  ```
48
48
 
49
+ ## Optional local KV replication
50
+
51
+ Install `@tinycloud/replica`, then load and register the optional browser plugin
52
+ **before** constructing a replication-enabled client:
53
+
54
+ ```typescript
55
+ import { TinyCloudWeb, registerBrowserReplica } from '@tinycloud/web-sdk';
56
+ import { browserReplicaPlugin, loadIndexedDbReplicaStorage } from '@tinycloud/web-sdk/replica';
57
+
58
+ const indexedDbReplicaStorage = await loadIndexedDbReplicaStorage();
59
+ registerBrowserReplica(browserReplicaPlugin);
60
+ const tc = new TinyCloudWeb({
61
+ replication: {
62
+ enabled: true,
63
+ prefixes: ['notes/'],
64
+ storage: indexedDbReplicaStorage(),
65
+ },
66
+ });
67
+ ```
68
+
69
+ Importing the optional entry alone does not register loaders or touch IndexedDB.
70
+ Duplicate registration throws immediately; enabling replication without
71
+ registration throws at construction. Replication off requires no plugin, and a
72
+ refused local replica does not end an otherwise valid network session.
73
+
74
+ Use the same module format for registration and the client: importing both
75
+ ESM and CJS root bundles in one process creates independent module registries.
76
+
77
+ `signIn()` selects a persisted session for the currently connected wallet;
78
+ switching wallets starts a fresh sign-in instead of reviving the prior wallet's
79
+ session. Explicit `restoreSession(address)` can restore a valid network session,
80
+ but local replication also requires that the provider currently reports that
81
+ wallet. An unknown, unavailable, or different provider account leaves network
82
+ use intact and gates local reads; restoring never creates or repairs a replica
83
+ stamp. Local reads recheck the connected account before returning replica data.
84
+
85
+ Size accounting uses the replica-e2e **Node size job** (Bun 1.3.14,
86
+ Rust 1.99.0), an absolute web-root ceiling, and separate opt-in first-import,
87
+ activation, and worker ceilings. The historical Phase 2 allowance of
88
+ 1,461,925 B ESM / 1,391,665 B CJS was measured against master `9891ed9d`
89
+ at 1,460,603 / 1,390,460 B; the reviewed fix-required row at `ddc032ca`
90
+ raised that historical ceiling to 1,462,034 / 1,391,799 B for copied-proof
91
+ restore, gated read events, durable denial, and GRANT_REVOKED projection.
92
+ The old 388 / 861 B allowance and #546/#553 ledger entries remain unchanged.
93
+ The historical file marginals are nonadditive; no synchronous TC-1208 fence moved.
94
+
95
+ GitHub's replica-e2e Node size jobs measured the **same approved shipped source**
96
+ under Bun 1.3.14 / Rust 1.99.0: master `9891ed9d` at
97
+ 1,462,590 / 1,393,500 B and #548 `e5b080d5` at
98
+ 1,464,102 / 1,394,869 B. The zero-headroom root ceilings are
99
+ 1,464,102 / 1,394,869 B (+1,512 / +1,369 B against that CI baseline).
100
+ The earlier local 1,462,685 / 1,393,687 B baseline and
101
+ 1,464,189 / 1,395,035 B candidate are recorded as **non-canonical smoke**
102
+ measurements; the prior +1,431 / +1,339 B and root ceilings remain
103
+ historical, not additive allowance. The diff from `ddc032ca` to
104
+ `2acd4ac5` changes only web size scripts, ledgers, tests and this README;
105
+ no shipped source or build input changed. The checker refuses mismatched local
106
+ Bun/Rust versions and later changes to this corrected ratchet.
107
+
108
+ The #565 fix-before-stable hardening (security L1/L2/I1 and correctness P2s)
109
+ raised these ceilings once, by the exact bytes GitHub run 39023273615 measured
110
+ after size cuts: root to 1,464,122 / 1,394,880 B (+20 / +11), first import
111
+ (+134 / +129), activation (+4 / +5) and the worker (+7). The ledger's
112
+ `hardeningRatchet` row records them and cannot change later.
113
+
114
+ The #571 sign-out contract (TC-841: the TC-721 owner revoke and the prepared-login
115
+ retry) raised only the root ceilings once more, by the exact bytes GitHub run
116
+ 39054822172 measured after size cuts: to 1,464,390 / 1,395,073 B (+268 / +193).
117
+ First import, activation and the worker keep #565's ceilings. The ledger's
118
+ `logoutRatchet` row records them and cannot change later. Because the cumulative
119
+ per-PR allowance (388 B for ESM) cannot absorb that growth, #571's `entries[]`
120
+ row is zero and the row's absolute ceiling carries it, as for Phase 2.
121
+
122
+ The TC-1413 typed node retry errors (`NODE_BUSY`, `REQUEST_TIMEOUT`, `OUTCOME_UNKNOWN`
123
+ in sdk-services and their consumers, #574) raised four buckets once more, by the exact
124
+ bytes GitHub run 39099093175 measured on source `20c29611`, in both jobs, against master
125
+ `3ae17bfc`: the root to 1,464,668 / 1,395,375 B (+278 / +302), first import
126
+ `replica.cjs` to 67,139 B (+1; `replica.mjs` +0), activation to 23,105 / 24,683 B
127
+ (+30 / +28) and the worker to 820,935 B (+827, also `MAX_WORKER_GZIP_BYTES`). No
128
+ replica-owned file changed; the sdk-services and sdk-core code is bundled into each
129
+ artifact. The ledger's `tc1413Ratchet` row and the matching optional allowance record
130
+ them and cannot change later; the `entries[]` rows carry zero (root) and the measured
131
+ optional deltas.
132
+
133
+ The TC-1436 terminal marker for `disableSubDelegation` (#578) raised only the root
134
+ ceilings once more, after size cuts, by the exact bytes GitHub run 39134326448
135
+ measured on source `d8e72fb9`, in both jobs, against master `7e10709c`: to
136
+ 1,465,995 / 1,395,719 B (+1,327 / +344). First import, activation, the gated artifact
137
+ and the worker keep TC-1413's ceilings. The ledger's `tc1436Ratchet` row records them
138
+ and cannot change later. If another root-growing PR lands first, #578 re-measures
139
+ against the new base and replaces its own row before it merges.
140
+
141
+ **Ancestry pins and squash merges.** A policy row records the PR-branch commit it
142
+ was reviewed at, and its introduction check requires that literal commit in the
143
+ PR head. js-sdk squash-merges, so that commit is unreachable from master
144
+ afterwards; ancestry is therefore checked only when a PR introduces a row. Any
145
+ new check that re-validates merged pins against HEAD would break master again
146
+ after the next squash, and only review prevents that. As a consistency check,
147
+ every PR also requires each merged row's pin to be on its base or landed by it:
148
+ the first first-parent master commit that added the pin to `scripts/`, normally
149
+ its squash commit (`landingCommit` in `scripts/replica-size-policy.ts`). After a
150
+ squash merge, nothing needs editing. Content keys (blob hashes) were rejected:
151
+ pinned files such as `authority.ts` legitimately change later, whereas the
152
+ landing commit stays an ancestor for good.
153
+
154
+ The opt-in first-import ceiling is 51,925 B ESM / 67,138 B CJS gzip
155
+ (including the replica parser and noble dependencies); awaiting the IndexedDB
156
+ factory has a separate 23,075 B / 24,655 B ceiling. The content-hashed worker
157
+ and WASM asset has an 820,108 B ceiling owned by `@tinycloud/replica`.
158
+ A compliant first local open therefore costs at most 895,108 B ESM /
159
+ 911,901 B CJS incremental gzip beyond the already-loaded web root; those
160
+ assets can then be cached. These byte ceilings do not replace real-worker
161
+ Chromium acceptance of local reads, denial, expiry, and sign-out.
162
+
163
+ A refused replica admission (stale, missing, or malformed restore stamp, or
164
+ failed fresh establishment) loads a separate network-only read observer capped
165
+ at 926 B ESM / 1,014 B CJS gzip. Successful opt-ins and replica-off clients
166
+ never fetch it; sign-out uses the already-loaded authority. If this observer
167
+ cannot load, the signed network session remains usable and local reads stay gated.
168
+
169
+ The original 51,201/66,132 B first-import ceiling was a Bun toolchain
170
+ measurement correction, not adapter allowance: exact `ce52494d` built with
171
+ Bun 1.3.14 measured 51,201/66,132 B versus 45,538/65,096 B with Bun 1.4.3
172
+ on the same SDK. The approved fix-required row added 584/863 B. Subsequent
173
+ local Rust 1.99.0 rebuild measurements (+1 ESM first-import, +2/+3 B
174
+ activation) were non-canonical; GitHub's [Postgres Node size job 117262499817](https://github.com/TinyCloudLabs/js-sdk/actions/runs/38987573493/job/117262499817)
175
+ measured #548 `1873c27d` at 51,791/67,009 B first-import and
176
+ 23,071/24,650 B activation, at the exact ledger ceilings.
177
+ The [replica-e2e Node size job 117166290134](https://github.com/TinyCloudLabs/js-sdk/actions/runs/38958197518/job/117166290134)
178
+ ran rustc 1.99.0 for WASM and the Phase-1 size step; the separate
179
+ [Chromium job 117166289795](https://github.com/TinyCloudLabs/js-sdk/actions/runs/38958197518/job/117166289795)
180
+ ran rustc 1.99.1 and does not set the web-root size baseline.
181
+ The [SQLite Node size job 117210798521](https://github.com/TinyCloudLabs/js-sdk/actions/runs/38971529166/job/117210798521)
182
+ and [Postgres Node size job 117210798348](https://github.com/TinyCloudLabs/js-sdk/actions/runs/38971529166/job/117210798348)
183
+ independently reported identical root and optional gzip bytes on `e5b080d5`;
184
+ the historical local measurements cannot set ledger ceilings.
185
+
49
186
  ## Basic Storage Operations
50
187
 
51
188
  ### Storing Data
@@ -26,6 +26,7 @@ export declare class BrowserSessionStorage implements ISessionStorage {
26
26
  /** Most recently saved, still-valid session address for provider-free reloads. */
27
27
  activeAddress(): string | undefined;
28
28
  load(address: string): Promise<PersistedSessionData | null>;
29
+ private validateForNetworkRestore;
29
30
  loadWithStatus(address: string): Promise<BrowserSessionLoadResult>;
30
31
  clear(address: string): Promise<void>;
31
32
  exists(address: string): boolean;