@fairfox/polly 0.58.0 → 0.60.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.
|
@@ -23,6 +23,7 @@ import { Repo, type StorageAdapterInterface } from "@automerge/automerge-repo/sl
|
|
|
23
23
|
import type { KeyringStorage } from "./keyring-storage";
|
|
24
24
|
import { type MeshKeyring, MeshNetworkAdapter } from "./mesh-network-adapter";
|
|
25
25
|
import { MeshSignalingClient, type MeshSignalingClientOptions } from "./mesh-signaling-client";
|
|
26
|
+
import { type MeshStateLazyWrapperRecord, type MeshStateLoadedRejectionBreadcrumb } from "./mesh-state";
|
|
26
27
|
import { MeshWebRTCAdapter, type MeshWebRTCAdapterOptions } from "./mesh-webrtc-adapter";
|
|
27
28
|
/** Options for {@link createMeshClient}. */
|
|
28
29
|
export interface CreateMeshClientOptions {
|
|
@@ -232,6 +233,42 @@ export interface MeshStateModuleDiagnostics {
|
|
|
232
233
|
* true` (they're using a module instance no mesh client ever
|
|
233
234
|
* configured). */
|
|
234
235
|
wasResolved: boolean;
|
|
236
|
+
/** Polly#107 post-H5 instrumentation. Count of `$meshState`-family
|
|
237
|
+
* lazy factory invocations since module load. Once the consumer's
|
|
238
|
+
* pre-warm pass completes, this equals the number of distinct
|
|
239
|
+
* `$mesh*` wrappers whose handles the loader actually tried to
|
|
240
|
+
* resolve. Compared to {@link lazyReachedRepo}: gap = throws
|
|
241
|
+
* before any Repo work. */
|
|
242
|
+
lazyInvocations: number;
|
|
243
|
+
/** Polly#107 post-H5 instrumentation. Count of factory invocations
|
|
244
|
+
* that reached the Repo subsystem (`repo.handles[...]`, `repo.find`
|
|
245
|
+
* or `repo.import`) before returning or throwing. If
|
|
246
|
+
* {@link lazyInvocations} is N and this is N, every wrapper
|
|
247
|
+
* touched the Repo — any missing handles are downstream of Repo
|
|
248
|
+
* registration. If this is < N, the gap is the call site to
|
|
249
|
+
* instrument next. */
|
|
250
|
+
lazyReachedRepo: number;
|
|
251
|
+
/** Polly#107 post-H5 instrumentation. Breadcrumb for the most
|
|
252
|
+
* recent rejection from a `$meshState`-family `loaded` promise
|
|
253
|
+
* (or its factory). Captured even when the consumer's wrapper
|
|
254
|
+
* never awaits `loaded` and the rejection would otherwise vanish
|
|
255
|
+
* silently. `undefined` means no rejection has escaped any
|
|
256
|
+
* wrapper on THIS module instance since module load. */
|
|
257
|
+
lastLoadedRejection: MeshStateLoadedRejectionBreadcrumb | undefined;
|
|
258
|
+
/** Polly#107 post-v0.59 instrumentation. Per-factory-invocation
|
|
259
|
+
* structured log — one record per `$mesh*` wrapper's lazy handle
|
|
260
|
+
* factory call, ring-buffered at 64 entries. Each row names the
|
|
261
|
+
* exit path (`returned-cached`, `loaded-from-storage`,
|
|
262
|
+
* `seeded-and-imported`, `threw`) and the synchronous peek at
|
|
263
|
+
* `repo.handles[docId]` taken in the factory's `finally`. The
|
|
264
|
+
* v0.59.0 fingerprint had `lazyInvocations === lazyReachedRepo`
|
|
265
|
+
* and no `lastLoadedRejection`; this field disambiguates which
|
|
266
|
+
* exit path each "successful" invocation actually took and
|
|
267
|
+
* whether the Repo registered the handle in spite of the lack of
|
|
268
|
+
* a thrown error. The smoking gun for H-Q1 is rows with
|
|
269
|
+
* `exitReason: "seeded-and-imported"` and
|
|
270
|
+
* `handleRegistered: false`. */
|
|
271
|
+
lazyWrappers: MeshStateLazyWrapperRecord[];
|
|
235
272
|
}
|
|
236
273
|
/** The mesh client's enriched per-peer state snapshot. Mirrors the
|
|
237
274
|
* underlying {@link MeshWebRTCAdapter.getPeerStateSnapshot} shape but
|
|
@@ -113,6 +113,96 @@ export declare function isMeshStateConfigured(): boolean;
|
|
|
113
113
|
* called against this module instance. See
|
|
114
114
|
* {@link meshStateEverResolved}. */
|
|
115
115
|
export declare function wasMeshStateResolved(): boolean;
|
|
116
|
+
/** Returns the count of factory invocations since module load. See
|
|
117
|
+
* {@link lazyInvocations}. */
|
|
118
|
+
export declare function getLazyInvocations(): number;
|
|
119
|
+
/** Returns the count of factory invocations that reached
|
|
120
|
+
* `repo.find` / `repo.import` since module load. See
|
|
121
|
+
* {@link lazyReachedRepo}. */
|
|
122
|
+
export declare function getLazyReachedRepo(): number;
|
|
123
|
+
/** Polly#107 post-H5 instrumentation. Records the most recent
|
|
124
|
+
* rejection (or synchronous throw) escaping the factory body — the
|
|
125
|
+
* `loaded` promise's rejection path. Today an unawaited rejection
|
|
126
|
+
* inside a consumer wrapper vanishes without trace; capturing the
|
|
127
|
+
* message + stack here on the module and exposing it via the
|
|
128
|
+
* snapshot leaves a breadcrumb the operator can read in one paste.
|
|
129
|
+
*
|
|
130
|
+
* The format is the JSON-safe `{ name, message, stack, at }` shape
|
|
131
|
+
* so the snapshot read does not have to traffic in `Error`
|
|
132
|
+
* instances. `at` is `Date.now()` at the time the rejection was
|
|
133
|
+
* captured. */
|
|
134
|
+
export interface MeshStateLoadedRejectionBreadcrumb {
|
|
135
|
+
name: string;
|
|
136
|
+
message: string;
|
|
137
|
+
stack: string | undefined;
|
|
138
|
+
at: number;
|
|
139
|
+
}
|
|
140
|
+
/** Returns the most recent rejection escaping a `$meshState` factory
|
|
141
|
+
* invocation since module load. See {@link lastLoadedRejection}. */
|
|
142
|
+
export declare function getLastLoadedRejection(): MeshStateLoadedRejectionBreadcrumb | undefined;
|
|
143
|
+
/** Polly#107 post-v0.59 instrumentation. Categorises the exit path
|
|
144
|
+
* a `$mesh*` lazy factory invocation took. The v0.59.0 fingerprint
|
|
145
|
+
* showed `lazyInvocations === lazyReachedRepo === 17` and no
|
|
146
|
+
* `lastLoadedRejection` — every factory reached the first
|
|
147
|
+
* `repo.handles[docId]` access, none rejected loudly, yet 16 of 17
|
|
148
|
+
* handles never landed in `repo.handles`. Without per-exit detail
|
|
149
|
+
* the snapshot cannot disambiguate "factory returned the cached
|
|
150
|
+
* handle", "factory hydrated from storage", "factory seeded and
|
|
151
|
+
* imported a fresh doc", or "factory took the cached branch but
|
|
152
|
+
* `whenReady` resolved to `unavailable` and the code fell
|
|
153
|
+
* through". Each exit reason corresponds to a single line in
|
|
154
|
+
* {@link buildHandleFactory}; the snapshot record names it
|
|
155
|
+
* verbatim so the operator can grep the source from one read. */
|
|
156
|
+
export type LazyWrapperExitReason = "returned-cached" | "loaded-from-storage" | "seeded-and-imported" | "threw";
|
|
157
|
+
/** Polly#107 post-v0.59 instrumentation. One record per factory
|
|
158
|
+
* invocation, ring-buffered on the module and surfaced through
|
|
159
|
+
* `MeshClient.getPeerStateSnapshot()` as
|
|
160
|
+
* `meshStateModule.lazyWrappers`. The five fields together answer
|
|
161
|
+
* the post-v0.59 question "if every factory reached the Repo and
|
|
162
|
+
* nothing rejected, why are 16 of 17 handles absent from
|
|
163
|
+
* `repo.handles`?" — `exitReason` names which of the three success
|
|
164
|
+
* paths each took, `handleRegistered` is the synchronous peek at
|
|
165
|
+
* `repo.handles[docId]` taken in the factory's `finally` (i.e. at
|
|
166
|
+
* the moment of would-be return), and `handleState` is the
|
|
167
|
+
* lifecycle state observed in that peek. A row where
|
|
168
|
+
* `exitReason: "seeded-and-imported"` and `handleRegistered: false`
|
|
169
|
+
* is the smoking gun for H-Q1 (`repo.import` returned without
|
|
170
|
+
* registering); rows where `exitReason: "returned-cached"` repeats
|
|
171
|
+
* for sixteen of seventeen distinct keys indicates collisions or
|
|
172
|
+
* that the factory is being called multiple times against a
|
|
173
|
+
* Repo-state-machine that has already filled the slot. */
|
|
174
|
+
export interface MeshStateLazyWrapperRecord {
|
|
175
|
+
/** The logical application key passed to `$meshState(key, ...)`. */
|
|
176
|
+
key: string;
|
|
177
|
+
/** Stringified Automerge `DocumentId` derived from the key. */
|
|
178
|
+
docId: string;
|
|
179
|
+
/** `Date.now()` captured at the moment the factory was about to
|
|
180
|
+
* return (or rethrow). */
|
|
181
|
+
at: number;
|
|
182
|
+
/** Which of the four exit paths the factory took. See
|
|
183
|
+
* {@link LazyWrapperExitReason}. */
|
|
184
|
+
exitReason: LazyWrapperExitReason;
|
|
185
|
+
/** Snapshot peek `repo.handles[docId] !== undefined` taken in the
|
|
186
|
+
* factory's `finally` clause. `true` means the local Repo
|
|
187
|
+
* registered the handle; `false` means the factory thinks it
|
|
188
|
+
* succeeded but the Repo does not hold the handle for this
|
|
189
|
+
* documentId. The "polly#107 post-v0.59" smoking gun is
|
|
190
|
+
* `exitReason: "seeded-and-imported", handleRegistered: false`. */
|
|
191
|
+
handleRegistered: boolean;
|
|
192
|
+
/** Lifecycle state of `repo.handles[docId]` at the synchronous
|
|
193
|
+
* peek time. `undefined` when the handle was not registered.
|
|
194
|
+
* Useful for distinguishing the "registered as loading/unavailable"
|
|
195
|
+
* case from the "registered as ready" case. */
|
|
196
|
+
handleState: string | undefined;
|
|
197
|
+
/** Error message if `exitReason === "threw"`; `undefined`
|
|
198
|
+
* otherwise. The full rejection still flows into
|
|
199
|
+
* {@link lastLoadedRejection}; this field is the row-local
|
|
200
|
+
* summary so the snapshot can show the failure cause inline. */
|
|
201
|
+
errorMessage: string | undefined;
|
|
202
|
+
}
|
|
203
|
+
/** Returns a copy of the lazy-wrapper invocation log. See
|
|
204
|
+
* {@link MeshStateLazyWrapperRecord}. */
|
|
205
|
+
export declare function getLazyWrappers(): MeshStateLazyWrapperRecord[];
|
|
116
206
|
/**
|
|
117
207
|
* Create a peer-replicated state primitive backed by Automerge with a mesh
|
|
118
208
|
* transport. Every device holds a full replica; no central server holds a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fairfox/polly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.60.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Multi-execution-context framework with reactive state and cross-context messaging for Chrome extensions, PWAs, and worker-based applications",
|