@tearleads/client-sdk 0.1.71 → 0.1.73
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/client/containerContents/index.js +8 -2
- package/client/containerContents/index.js.map +1 -1
- package/client/containerContents/types.d.ts +4 -1
- package/client/containerContents/types.js.map +1 -1
- package/client/documents/index.d.ts +4 -1
- package/client/documents/index.js +6 -2
- package/client/documents/index.js.map +1 -1
- package/data/shared/userTiming.js +42 -0
- package/data/shared/userTiming.js.map +1 -0
- package/data/sqlite/sqlExec.js +27 -3
- package/data/sqlite/sqlExec.js.map +1 -1
- package/data/sync/coordinatorLaneRun.js +29 -6
- package/data/sync/coordinatorLaneRun.js.map +1 -1
- package/data/sync/coordinatorState.d.ts +3 -1
- package/data/sync/coordinatorState.js +1 -0
- package/data/sync/coordinatorState.js.map +1 -1
- package/data/sync/syncTelemetry.d.ts +15 -0
- package/data/sync/syncTelemetry.js +10 -0
- package/data/sync/syncTelemetry.js.map +1 -1
- package/data/sync/uploadLane.js +20 -3
- package/data/sync/uploadLane.js.map +1 -1
- package/package.json +1 -1
- package/stores/documents/documentStore/index.js +5 -1
- package/stores/documents/documentStore/index.js.map +1 -1
- package/stores/documents/documentStore/initialization/index.js +4 -1
- package/stores/documents/documentStore/initialization/index.js.map +1 -1
- package/stores/documents/documentStore/initialization/initialContent.js +44 -0
- package/stores/documents/documentStore/initialization/initialContent.js.map +1 -0
- package/stores/documents/documentStore/{rows.js → rows/index.js} +12 -21
- package/stores/documents/documentStore/rows/index.js.map +1 -0
- package/stores/documents/documentStore/rows/rowAttribution.js +11 -0
- package/stores/documents/documentStore/rows/rowAttribution.js.map +1 -0
- package/stores/documents/documentStore/snapshotEquality.js +29 -0
- package/stores/documents/documentStore/snapshotEquality.js.map +1 -0
- package/stores/documents/documentStore/state.js +1 -28
- package/stores/documents/documentStore/state.js.map +1 -1
- package/stores/documents/types.d.ts +8 -0
- package/stores/documents/types.js.map +1 -1
- package/stores/documents/documentStore/rows.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordinatorLaneRun.js","sourceRoot":"","sources":["coordinatorLaneRun.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DomainSyncCoordinatorState,\n SyncLaneState,\n} from \"./coordinatorState\";\nimport {\n describeSyncLaneError,\n publishSyncCoordinatorSnapshot,\n} from \"./coordinatorState\";\nimport type { SyncLaneConfig } from \"./syncLaneConfig\";\nimport { createSyncTimestamp } from \"./syncTelemetry\";\n\nconst SYNC_LANE_WATCHDOG_MS = 120_000;\nconst FAILED_LANE_REARM_BACKOFF_MS = 1000;\n\ntype SyncLaneRunResult =\n | { status: \"completed\" }\n | { status: \"failed\"; error: unknown };\n\n// Keyed on the registered config so a discarded lane is collectable.\nconst lastReportedFailureByConfig = new WeakMap<SyncLaneConfig, string>();\n\n// Local-only dedup key. describeSyncLaneError joins messages without their\n// types, so the name keeps a swallowed DatabaseUnavailableError distinct from\n// a plain Error carrying the same text; the cause chain keeps a re-wrapped\n// failure distinct from its origin.\nfunction describeSyncLaneFailureSignature(error: unknown): string {\n const name = error instanceof Error ? error.name : typeof error;\n return JSON.stringify([name, describeSyncLaneError(error)]);\n}\n\n// Observability only: a failing lane re-arms every FAILED_LANE_REARM_BACKOFF_MS\n// for the rest of the session, and mobile WebViews are never reloaded, so an\n// unrecoverable lane would report once a second. The signature is deliberately\n// never cleared on a completed run: alternating success and failure would\n// re-admit the same report every pass and evict the surrounding diagnostic\n// trail from the host's bounded log.\nfunction reportUnexpectedSyncLaneFailure(\n state: SyncLaneState,\n error: unknown,\n): void {\n const report = state.config.reportUnexpectedError;\n if (!report) return;\n const signature = describeSyncLaneFailureSignature(error);\n if (lastReportedFailureByConfig.get(state.config) === signature) return;\n lastReportedFailureByConfig.set(state.config, signature);\n try {\n void Promise.resolve(report(error)).catch(() => undefined);\n } catch {\n // Hosts may throw synchronously or return a rejected promise.\n }\n}\n\nasync function runSyncLane(state: SyncLaneState): Promise<SyncLaneRunResult> {\n try {\n await state.config.run();\n return { status: \"completed\" };\n } catch (error: unknown) {\n if (state.config.shouldIgnoreError?.(error)) {\n return { status: \"completed\" };\n }\n reportUnexpectedSyncLaneFailure(state, error);\n\n if (state.config.onUnexpectedError) {\n state.config.onUnexpectedError(error);\n return { status: \"failed\", error };\n }\n\n throw error;\n }\n}\n\n// Console-only on purpose. This runs only when the lane's OWN error handler\n// already threw, so it must never route through reportUnexpectedSyncLaneFailure\n// as well: re-entering a handler that just threw would reject runResultPromise\n// from inside its own onRejected callback, leaving `running` true and\n// `activeRunToken` set, which wedges the lane for the rest of the session.\nfunction reportUnexpectedSyncLaneError(state: SyncLaneState, error: unknown) {\n console.error(`Failed to run sync lane ${state.key}:`, error);\n}\n\nfunction recordSyncLaneRunResult(\n lane: SyncLaneState,\n runResult: SyncLaneRunResult,\n): void {\n lane.lastActionAt = createSyncTimestamp();\n if (runResult.status === \"failed\") {\n lane.errorCount += 1;\n lane.lastAction = \"failed\";\n lane.lastError = describeSyncLaneError(runResult.error);\n lane.lastFailedAt = lane.lastActionAt;\n } else {\n lane.lastAction = \"completed\";\n lane.lastCompletedAt = lane.lastActionAt;\n lane.lastError = null;\n }\n}\n\n// Replace the watchdog failure with the late result, then release queued work.\nfunction settleAbandonedSyncLaneRun(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n runToken: object,\n runResult: SyncLaneRunResult,\n wake: () => void,\n): void {\n if (lane.activeRunToken !== runToken) {\n return;\n }\n lane.activeRunToken = null;\n lane.runAbandoned = false;\n recordSyncLaneRunResult(lane, runResult);\n publishSyncCoordinatorSnapshot(coordinatorState);\n if (!coordinatorState.disposed && lane.requested) {\n wake();\n }\n}\n\nfunction startSyncLaneRun(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n) {\n lane.requested = false;\n lane.notBeforeAtMs = null;\n lane.running = true;\n lane.runCount += 1;\n lane.lastAction = \"started\";\n lane.lastActionAt = createSyncTimestamp();\n lane.lastStartedAt = lane.lastActionAt;\n lane.runAbandoned = false;\n const runToken = {};\n lane.activeRunToken = runToken;\n publishSyncCoordinatorSnapshot(coordinatorState);\n\n // Keep follow-up requests even on failure to preserve phase ordering; see\n // docs/client-sync-ordering.md.\n // The fallback also catches errors thrown by the lane's error handlers.\n const runResultPromise: Promise<SyncLaneRunResult> = runSyncLane(lane).then(\n (result) => result,\n (error: unknown) => {\n reportUnexpectedSyncLaneError(lane, error);\n return { status: \"failed\", error };\n },\n );\n\n return { runToken, runResultPromise };\n}\n\nexport async function runCoordinatorLane(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n wake: () => void,\n): Promise<void> {\n const { runToken, runResultPromise } = startSyncLaneRun(\n coordinatorState,\n lane,\n );\n // Clamp overrides to at least 1ms so every run has a chance to complete.\n const watchdogMs = Math.max(\n 1,\n lane.config.watchdogMs ?? SYNC_LANE_WATCHDOG_MS,\n );\n let watchdogTimer: ReturnType<typeof setTimeout> | null = null;\n const raceOutcome = await Promise.race([\n runResultPromise.then((result) => ({\n kind: \"settled\" as const,\n result,\n })),\n new Promise<{ kind: \"timed-out\" }>((resolve) => {\n watchdogTimer = setTimeout(\n () => resolve({ kind: \"timed-out\" }),\n watchdogMs,\n );\n }),\n ]);\n if (watchdogTimer !== null) {\n clearTimeout(watchdogTimer);\n }\n\n lane.running = false;\n let runResult: SyncLaneRunResult;\n if (raceOutcome.kind === \"settled\") {\n lane.activeRunToken = null;\n runResult = raceOutcome.result;\n } else {\n lane.runAbandoned = true;\n runResult = {\n status: \"failed\",\n error: new Error(\n `Sync lane watchdog: run exceeded ${watchdogMs}ms; continuing with other lanes`,\n ),\n };\n void runResultPromise.then((result) =>\n settleAbandonedSyncLaneRun(\n coordinatorState,\n lane,\n runToken,\n result,\n wake,\n ),\n );\n }\n recordSyncLaneRunResult(lane, runResult);\n publishSyncCoordinatorSnapshot(coordinatorState);\n\n if (\n runResult.status === \"failed\" &&\n lane.requested &&\n raceOutcome.kind === \"settled\"\n ) {\n // A fresh hint cannot bypass a failed lane's cooldown. Other document\n // lanes remain runnable; structural retries still preserve the barrier.\n lane.backingOff = true;\n setTimeout(() => {\n lane.backingOff = false;\n wake();\n }, FAILED_LANE_REARM_BACKOFF_MS);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"coordinatorLaneRun.js","sourceRoot":"","sources":["coordinatorLaneRun.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n readUserTimingClock,\n recordUserTimingEntry,\n} from \"../shared/userTiming\";\nimport type {\n DomainSyncCoordinatorState,\n SyncLaneState,\n} from \"./coordinatorState\";\nimport {\n describeSyncLaneError,\n publishSyncCoordinatorSnapshot,\n} from \"./coordinatorState\";\nimport type { SyncLaneConfig } from \"./syncLaneConfig\";\nimport { addSyncLaneRunDuration, createSyncTimestamp } from \"./syncTelemetry\";\n\nconst SYNC_LANE_WATCHDOG_MS = 120_000;\nconst FAILED_LANE_REARM_BACKOFF_MS = 1000;\n\ntype SyncLaneRunResult =\n | { status: \"completed\" }\n | { status: \"failed\"; error: unknown };\n\n// Keyed on the registered config so a discarded lane is collectable.\nconst lastReportedFailureByConfig = new WeakMap<SyncLaneConfig, string>();\n\n// Local-only dedup key. describeSyncLaneError joins messages without their\n// types, so the name keeps a swallowed DatabaseUnavailableError distinct from\n// a plain Error carrying the same text; the cause chain keeps a re-wrapped\n// failure distinct from its origin.\nfunction describeSyncLaneFailureSignature(error: unknown): string {\n const name = error instanceof Error ? error.name : typeof error;\n return JSON.stringify([name, describeSyncLaneError(error)]);\n}\n\n// Observability only: a failing lane re-arms every FAILED_LANE_REARM_BACKOFF_MS\n// for the rest of the session, and mobile WebViews are never reloaded, so an\n// unrecoverable lane would report once a second. The signature is deliberately\n// never cleared on a completed run: alternating success and failure would\n// re-admit the same report every pass and evict the surrounding diagnostic\n// trail from the host's bounded log.\nfunction reportUnexpectedSyncLaneFailure(\n state: SyncLaneState,\n error: unknown,\n): void {\n const report = state.config.reportUnexpectedError;\n if (!report) return;\n const signature = describeSyncLaneFailureSignature(error);\n if (lastReportedFailureByConfig.get(state.config) === signature) return;\n lastReportedFailureByConfig.set(state.config, signature);\n try {\n void Promise.resolve(report(error)).catch(() => undefined);\n } catch {\n // Hosts may throw synchronously or return a rejected promise.\n }\n}\n\nasync function runSyncLane(state: SyncLaneState): Promise<SyncLaneRunResult> {\n try {\n await state.config.run();\n return { status: \"completed\" };\n } catch (error: unknown) {\n if (state.config.shouldIgnoreError?.(error)) {\n return { status: \"completed\" };\n }\n reportUnexpectedSyncLaneFailure(state, error);\n\n if (state.config.onUnexpectedError) {\n state.config.onUnexpectedError(error);\n return { status: \"failed\", error };\n }\n\n throw error;\n }\n}\n\n// Console-only on purpose. This runs only when the lane's OWN error handler\n// already threw, so it must never route through reportUnexpectedSyncLaneFailure\n// as well: re-entering a handler that just threw would reject runResultPromise\n// from inside its own onRejected callback, leaving `running` true and\n// `activeRunToken` set, which wedges the lane for the rest of the session.\nfunction reportUnexpectedSyncLaneError(state: SyncLaneState, error: unknown) {\n console.error(`Failed to run sync lane ${state.key}:`, error);\n}\n\nfunction recordSyncLaneRunResult(\n lane: SyncLaneState,\n runResult: SyncLaneRunResult,\n): void {\n lane.lastActionAt = createSyncTimestamp();\n if (runResult.status === \"failed\") {\n lane.errorCount += 1;\n lane.lastAction = \"failed\";\n lane.lastError = describeSyncLaneError(runResult.error);\n lane.lastFailedAt = lane.lastActionAt;\n } else {\n lane.lastAction = \"completed\";\n lane.lastCompletedAt = lane.lastActionAt;\n lane.lastError = null;\n }\n}\n\n// Times a settled run and draws it on the DevTools \"Sync lanes\" track. A\n// watchdog verdict is not a settlement and records nothing: the abandoned run\n// is timed when its late result arrives.\nfunction recordSyncLaneRunTiming(\n lane: SyncLaneState,\n startedAtMs: number,\n runResult: SyncLaneRunResult,\n abandoned: boolean,\n): void {\n const endedAtMs = readUserTimingClock();\n lane.runDurations = addSyncLaneRunDuration(\n lane.runDurations,\n endedAtMs - startedAtMs,\n );\n recordUserTimingEntry({\n endMs: endedAtMs,\n failed: runResult.status === \"failed\",\n name: `Sync lane: ${lane.config.label ?? lane.key}`,\n properties: [\n [\"phase\", lane.config.phase ?? \"document\"],\n [\"outcome\", runResult.status],\n [\"watchdog\", abandoned ? \"abandoned\" : \"within limit\"],\n ],\n startMs: startedAtMs,\n track: \"Sync lanes\",\n });\n}\n\n// Replace the watchdog failure with the late result, then release queued work.\nfunction settleAbandonedSyncLaneRun(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n run: { readonly startedAtMs: number; readonly token: object },\n runResult: SyncLaneRunResult,\n wake: () => void,\n): void {\n if (lane.activeRunToken !== run.token) {\n return;\n }\n lane.activeRunToken = null;\n lane.runAbandoned = false;\n recordSyncLaneRunTiming(lane, run.startedAtMs, runResult, true);\n recordSyncLaneRunResult(lane, runResult);\n publishSyncCoordinatorSnapshot(coordinatorState);\n if (!coordinatorState.disposed && lane.requested) {\n wake();\n }\n}\n\nfunction startSyncLaneRun(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n) {\n lane.requested = false;\n lane.notBeforeAtMs = null;\n lane.running = true;\n lane.runCount += 1;\n lane.lastAction = \"started\";\n lane.lastActionAt = createSyncTimestamp();\n lane.lastStartedAt = lane.lastActionAt;\n lane.runAbandoned = false;\n const runToken = {};\n lane.activeRunToken = runToken;\n publishSyncCoordinatorSnapshot(coordinatorState);\n const startedAtMs = readUserTimingClock();\n\n // Keep follow-up requests even on failure to preserve phase ordering; see\n // docs/client-sync-ordering.md.\n // The fallback also catches errors thrown by the lane's error handlers.\n const runResultPromise: Promise<SyncLaneRunResult> = runSyncLane(lane).then(\n (result) => result,\n (error: unknown) => {\n reportUnexpectedSyncLaneError(lane, error);\n return { status: \"failed\", error };\n },\n );\n\n return { runToken, runResultPromise, startedAtMs };\n}\n\nexport async function runCoordinatorLane(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n wake: () => void,\n): Promise<void> {\n const { runToken, runResultPromise, startedAtMs } = startSyncLaneRun(\n coordinatorState,\n lane,\n );\n // Clamp overrides to at least 1ms so every run has a chance to complete.\n const watchdogMs = Math.max(\n 1,\n lane.config.watchdogMs ?? SYNC_LANE_WATCHDOG_MS,\n );\n let watchdogTimer: ReturnType<typeof setTimeout> | null = null;\n const raceOutcome = await Promise.race([\n runResultPromise.then((result) => ({\n kind: \"settled\" as const,\n result,\n })),\n new Promise<{ kind: \"timed-out\" }>((resolve) => {\n watchdogTimer = setTimeout(\n () => resolve({ kind: \"timed-out\" }),\n watchdogMs,\n );\n }),\n ]);\n if (watchdogTimer !== null) {\n clearTimeout(watchdogTimer);\n }\n\n lane.running = false;\n let runResult: SyncLaneRunResult;\n if (raceOutcome.kind === \"settled\") {\n lane.activeRunToken = null;\n runResult = raceOutcome.result;\n recordSyncLaneRunTiming(lane, startedAtMs, runResult, false);\n } else {\n lane.runAbandoned = true;\n runResult = {\n status: \"failed\",\n error: new Error(\n `Sync lane watchdog: run exceeded ${watchdogMs}ms; continuing with other lanes`,\n ),\n };\n void runResultPromise.then((result) =>\n settleAbandonedSyncLaneRun(\n coordinatorState,\n lane,\n { startedAtMs, token: runToken },\n result,\n wake,\n ),\n );\n }\n recordSyncLaneRunResult(lane, runResult);\n publishSyncCoordinatorSnapshot(coordinatorState);\n\n if (\n runResult.status === \"failed\" &&\n lane.requested &&\n raceOutcome.kind === \"settled\"\n ) {\n // A fresh hint cannot bypass a failed lane's cooldown. Other document\n // lanes remain runnable; structural retries still preserve the barrier.\n lane.backingOff = true;\n setTimeout(() => {\n lane.backingOff = false;\n wake();\n }, FAILED_LANE_REARM_BACKOFF_MS);\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SyncLaneConfig } from "./syncLaneConfig.js";
|
|
2
|
-
import type { DomainSyncSnapshot, SyncLaneLastAction, SyncLaneProgress } from "./syncTelemetry.js";
|
|
2
|
+
import type { DomainSyncSnapshot, SyncLaneLastAction, SyncLaneProgress, SyncLaneRunDurations } from "./syncTelemetry.js";
|
|
3
3
|
export interface SyncLaneState {
|
|
4
4
|
activeRunToken: object | null;
|
|
5
5
|
backingOff: boolean;
|
|
@@ -23,6 +23,7 @@ export interface SyncLaneState {
|
|
|
23
23
|
requested: boolean;
|
|
24
24
|
runAbandoned: boolean;
|
|
25
25
|
runCount: number;
|
|
26
|
+
runDurations: SyncLaneRunDurations | null;
|
|
26
27
|
running: boolean;
|
|
27
28
|
}
|
|
28
29
|
export interface DomainSyncCoordinatorState {
|
|
@@ -41,6 +42,7 @@ export declare const INITIAL_SYNC_LANE_RUN_STATE: {
|
|
|
41
42
|
readonly lastRunOrder: 0;
|
|
42
43
|
readonly runAbandoned: false;
|
|
43
44
|
readonly runCount: 0;
|
|
45
|
+
readonly runDurations: null;
|
|
44
46
|
readonly running: false;
|
|
45
47
|
};
|
|
46
48
|
export declare function describeSyncLaneError(error: unknown): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordinatorState.js","sourceRoot":"","sources":["coordinatorState.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"coordinatorState.js","sourceRoot":"","sources":["coordinatorState.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAgD3D,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,cAAc,EAAE,IAAI;IACpB,UAAU,EAAE,KAAK;IACjB,YAAY,EAAE,CAAC;IACf,YAAY,EAAE,KAAK;IACnB,QAAQ,EAAE,CAAC;IACX,YAAY,EAAE,IAAI;IAClB,OAAO,EAAE,KAAK;CACN,CAAC;AAEX,SAAS,2BAA2B,CAAC,KAAc;IACjD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IACD,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,SAAS,IAAI,KAAK;QAClB,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EACjC,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAChC,IAAI,OAAO,GAAY,KAAK,CAAC;IAE7B,OAAO,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACvE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,MAAM,OAAO,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,yEAAyE;AACzE,wEAAwE;AACxE,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED,+EAA+E;AAC/E,8EAA8E;AAC9E,yEAAyE;AACzE,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAAC,KAA8B;IAC/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,KAAiC;IAEjC,KAAK,CAAC,QAAQ,GAAG,wBAAwB,CAAC;QACxC,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACxE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE;QAC3B,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI;KACzB,CAAC,CAAC;IACH,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC;YACH,QAAQ,EAAE,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;QACrE,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import type { SyncLaneConfig } from \"./syncLaneConfig\";\nimport type {\n DomainSyncSnapshot,\n SyncLaneLastAction,\n SyncLaneProgress,\n SyncLaneRunDurations,\n} from \"./syncTelemetry\";\nimport { createDomainSyncSnapshot } from \"./syncTelemetry\";\n\nexport interface SyncLaneState {\n // Identity of the lane's live run, set for the duration of a run INCLUDING\n // after a watchdog timeout abandons it. Selection skips lanes whose token is\n // set, so a lane can never run concurrently with its own abandoned run; the\n // late-settle continuation clears it (matching on identity) and re-pumps.\n activeRunToken: object | null;\n backingOff: boolean;\n lastRunOrder: number;\n blobStorageKey: string | null;\n config: SyncLaneConfig;\n errorCount: number;\n key: string;\n lastAction: SyncLaneLastAction;\n lastActionAt: string;\n lastCompletedAt: string | null;\n lastError: string | null;\n lastFailedAt: string | null;\n lastRequestedAt: string | null;\n lastStartedAt: string | null;\n notBeforeAtMs: number | null;\n progress: SyncLaneProgress | null;\n // Registered lanes are driven by the coordinator pump. Blob upload lanes\n // are observational telemetry driven directly by the upload workflow.\n pumpDriven: boolean;\n registrationIndex: number;\n requestCount: number;\n requested: boolean;\n runAbandoned: boolean;\n runCount: number;\n runDurations: SyncLaneRunDurations | null;\n running: boolean;\n}\n\nexport interface DomainSyncCoordinatorState {\n // Set by dispose(): stop admitting work and drain already-running callbacks\n // (or their watchdogs). No new pump can be scheduled after runtime teardown.\n disposed: boolean;\n lanes: Map<string, SyncLaneState>;\n listeners: Set<() => void>;\n nextRegistrationIndex: number;\n nextRunOrder: number;\n wakePump: (() => void) | null;\n pump: Promise<void> | null;\n snapshot: DomainSyncSnapshot;\n}\n\nexport const INITIAL_SYNC_LANE_RUN_STATE = {\n activeRunToken: null,\n backingOff: false,\n lastRunOrder: 0,\n runAbandoned: false,\n runCount: 0,\n runDurations: null,\n running: false,\n} as const;\n\nfunction describeSingleSyncLaneError(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n\n return String(error);\n}\n\nfunction readErrorCause(error: unknown): unknown {\n if (typeof error !== \"object\" || error === null) {\n return undefined;\n }\n\n return Reflect.get(error, \"cause\");\n}\n\nexport function describeSyncLaneError(error: unknown): string {\n const messages: string[] = [];\n const seen = new Set<unknown>();\n let current: unknown = error;\n\n while (current !== undefined && current !== null && !seen.has(current)) {\n seen.add(current);\n const message = describeSingleSyncLaneError(current);\n if (message.length > 0) {\n messages.push(message);\n }\n current = readErrorCause(current);\n }\n\n return messages.length > 0 ? messages.join(\" Caused by: \") : String(error);\n}\n\n// Observational upload lanes never enter the pump, so their run is never\n// invoked; this satisfies the SyncLaneConfig contract without behavior.\nexport function noopLaneRun(): Promise<void> {\n return Promise.resolve();\n}\n\n// Deliberately ignores activeRunToken (unlike the pump's hasRunnableLaneWork):\n// a watchdog-abandoned run is detached background work, and idle/pending-work\n// reporting must not block on a hung run that may never settle. Its late\n// settle still publishes a snapshot and re-pumps any queued re-request.\nexport function hasPendingLaneWork(lanes: Iterable<SyncLaneState>): boolean {\n for (const lane of lanes) {\n if (lane.requested || lane.running) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function publishSyncCoordinatorSnapshot(\n state: DomainSyncCoordinatorState,\n) {\n state.snapshot = createDomainSyncSnapshot({\n hasPendingWork: !!state.pump || hasPendingLaneWork(state.lanes.values()),\n lanes: state.lanes.values(),\n pumpActive: !!state.pump,\n });\n for (const listener of [...state.listeners]) {\n try {\n listener();\n } catch {\n // Keep one observer failure from blocking sync or later observers.\n }\n }\n}\n"]}
|
|
@@ -12,6 +12,17 @@ export interface SyncLaneProgress {
|
|
|
12
12
|
partsCompleted: number;
|
|
13
13
|
partsTotal: number;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Monotonic durations of a lane's settled runs. A run abandoned by its
|
|
17
|
+
* watchdog is counted when it finally settles, with its real duration; the
|
|
18
|
+
* watchdog verdict itself records none, since the run had not finished.
|
|
19
|
+
*/
|
|
20
|
+
export interface SyncLaneRunDurations {
|
|
21
|
+
count: number;
|
|
22
|
+
lastMs: number;
|
|
23
|
+
maxMs: number;
|
|
24
|
+
totalMs: number;
|
|
25
|
+
}
|
|
15
26
|
export interface SyncLaneSnapshot {
|
|
16
27
|
/** Storage key used to open the associated blob, when this is a blob lane. */
|
|
17
28
|
blobStorageKey: string | null;
|
|
@@ -32,6 +43,8 @@ export interface SyncLaneSnapshot {
|
|
|
32
43
|
requested: boolean;
|
|
33
44
|
runAbandoned: boolean;
|
|
34
45
|
runCount: number;
|
|
46
|
+
/** Null until a run settles. */
|
|
47
|
+
runDurations: SyncLaneRunDurations | null;
|
|
35
48
|
running: boolean;
|
|
36
49
|
status: SyncLaneStatus;
|
|
37
50
|
}
|
|
@@ -63,6 +76,7 @@ interface SyncLaneTelemetryState {
|
|
|
63
76
|
requested: boolean;
|
|
64
77
|
runAbandoned: boolean;
|
|
65
78
|
runCount: number;
|
|
79
|
+
runDurations: SyncLaneRunDurations | null;
|
|
66
80
|
running: boolean;
|
|
67
81
|
}
|
|
68
82
|
/**
|
|
@@ -77,6 +91,7 @@ interface SyncLaneOrderInput {
|
|
|
77
91
|
registrationIndex: number;
|
|
78
92
|
}
|
|
79
93
|
export declare function createSyncTimestamp(): string;
|
|
94
|
+
export declare function addSyncLaneRunDuration(durations: SyncLaneRunDurations | null, durationMs: number): SyncLaneRunDurations;
|
|
80
95
|
export declare function compareSyncLaneOrder(left: SyncLaneOrderInput, right: SyncLaneOrderInput): number;
|
|
81
96
|
export declare function createDomainSyncSnapshot(input: {
|
|
82
97
|
hasPendingWork: boolean;
|
|
@@ -7,6 +7,15 @@ const SYNC_LANE_PHASE_RANK = {
|
|
|
7
7
|
export function createSyncTimestamp() {
|
|
8
8
|
return new Date().toISOString();
|
|
9
9
|
}
|
|
10
|
+
// Returns a new object, so a published snapshot can share it safely.
|
|
11
|
+
export function addSyncLaneRunDuration(durations, durationMs) {
|
|
12
|
+
return {
|
|
13
|
+
count: (durations?.count ?? 0) + 1,
|
|
14
|
+
lastMs: durationMs,
|
|
15
|
+
maxMs: Math.max(durations?.maxMs ?? 0, durationMs),
|
|
16
|
+
totalMs: (durations?.totalMs ?? 0) + durationMs,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
10
19
|
function getSyncLanePhaseRank(state) {
|
|
11
20
|
return SYNC_LANE_PHASE_RANK[state.config.phase ?? DEFAULT_SYNC_LANE_PHASE];
|
|
12
21
|
}
|
|
@@ -52,6 +61,7 @@ function createSyncLaneSnapshot(state) {
|
|
|
52
61
|
requested: state.requested,
|
|
53
62
|
runAbandoned: state.runAbandoned,
|
|
54
63
|
runCount: state.runCount,
|
|
64
|
+
runDurations: state.runDurations,
|
|
55
65
|
running: state.running,
|
|
56
66
|
status: getSyncLaneStatus(state),
|
|
57
67
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncTelemetry.js","sourceRoot":"","sources":["syncTelemetry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"syncTelemetry.js","sourceRoot":"","sources":["syncTelemetry.ts"],"names":[],"mappings":"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","sourcesContent":["export type SyncLanePhase = \"structural\" | \"document\" | \"blob\";\nexport type SyncLaneStatus =\n | \"idle\"\n | \"queued\"\n | \"running\"\n | \"complete\"\n | \"error\";\nexport type SyncLaneLastAction =\n | \"registered\"\n | \"requested\"\n | \"started\"\n | \"completed\"\n | \"failed\";\n\n/**\n * Fine-grained progress for lanes that expose it (currently multipart blob\n * uploads). Coarse status lanes leave this null and fall back to the\n * status-keyed progress bar in the visualizer.\n */\nexport interface SyncLaneProgress {\n bytesTotal: number;\n bytesUploaded: number;\n partsCompleted: number;\n partsTotal: number;\n}\n\n/**\n * Monotonic durations of a lane's settled runs. A run abandoned by its\n * watchdog is counted when it finally settles, with its real duration; the\n * watchdog verdict itself records none, since the run had not finished.\n */\nexport interface SyncLaneRunDurations {\n count: number;\n lastMs: number;\n maxMs: number;\n totalMs: number;\n}\n\nexport interface SyncLaneSnapshot {\n /** Storage key used to open the associated blob, when this is a blob lane. */\n blobStorageKey: string | null;\n errorCount: number;\n key: string;\n label: string;\n lastAction: SyncLaneLastAction;\n lastActionAt: string;\n lastCompletedAt: string | null;\n lastError: string | null;\n lastFailedAt: string | null;\n lastRequestedAt: string | null;\n lastStartedAt: string | null;\n phase: SyncLanePhase;\n progress: SyncLaneProgress | null;\n registrationIndex: number;\n requestCount: number;\n requested: boolean;\n runAbandoned: boolean;\n runCount: number;\n /** Null until a run settles. */\n runDurations: SyncLaneRunDurations | null;\n running: boolean;\n status: SyncLaneStatus;\n}\n\nexport interface DomainSyncSnapshot {\n hasPendingWork: boolean;\n lanes: ReadonlyArray<SyncLaneSnapshot>;\n pumpActive: boolean;\n updatedAt: string;\n}\n\ninterface SyncLaneTelemetryConfig {\n label?: string | undefined;\n phase?: SyncLanePhase | undefined;\n}\n\ninterface SyncLaneTelemetryState {\n blobStorageKey: string | null;\n config: SyncLaneTelemetryConfig;\n errorCount: number;\n key: string;\n lastAction: SyncLaneLastAction;\n lastActionAt: string;\n lastCompletedAt: string | null;\n lastError: string | null;\n lastFailedAt: string | null;\n lastRequestedAt: string | null;\n lastStartedAt: string | null;\n progress?: SyncLaneProgress | null;\n registrationIndex: number;\n requestCount: number;\n requested: boolean;\n runAbandoned: boolean;\n runCount: number;\n runDurations: SyncLaneRunDurations | null;\n running: boolean;\n}\n\nconst DEFAULT_SYNC_LANE_PHASE: SyncLanePhase = \"document\";\nconst SYNC_LANE_PHASE_RANK: Record<SyncLanePhase, number> = {\n structural: 0,\n document: 1,\n blob: 2,\n};\n\n/**\n * Structural subset of a sync lane needed to order it: its phase and the\n * registration index that breaks phase ties. Accepts both the coordinator's\n * `SyncLaneState` and the telemetry `SyncLaneTelemetryState`.\n */\ninterface SyncLaneOrderInput {\n config: { phase?: SyncLanePhase | undefined };\n registrationIndex: number;\n}\n\nexport function createSyncTimestamp(): string {\n return new Date().toISOString();\n}\n\n// Returns a new object, so a published snapshot can share it safely.\nexport function addSyncLaneRunDuration(\n durations: SyncLaneRunDurations | null,\n durationMs: number,\n): SyncLaneRunDurations {\n return {\n count: (durations?.count ?? 0) + 1,\n lastMs: durationMs,\n maxMs: Math.max(durations?.maxMs ?? 0, durationMs),\n totalMs: (durations?.totalMs ?? 0) + durationMs,\n };\n}\n\nfunction getSyncLanePhaseRank(state: SyncLaneOrderInput): number {\n return SYNC_LANE_PHASE_RANK[state.config.phase ?? DEFAULT_SYNC_LANE_PHASE];\n}\n\nexport function compareSyncLaneOrder(\n left: SyncLaneOrderInput,\n right: SyncLaneOrderInput,\n): number {\n const phaseRank = getSyncLanePhaseRank(left) - getSyncLanePhaseRank(right);\n if (phaseRank !== 0) {\n return phaseRank;\n }\n\n return left.registrationIndex - right.registrationIndex;\n}\n\nfunction getSyncLaneStatus(state: SyncLaneTelemetryState): SyncLaneStatus {\n if (state.running) {\n return \"running\";\n }\n\n if (state.requested) {\n return \"queued\";\n }\n\n if (state.lastAction === \"failed\") {\n return \"error\";\n }\n\n if (state.lastCompletedAt) {\n return \"complete\";\n }\n\n return \"idle\";\n}\n\nfunction createSyncLaneSnapshot(\n state: SyncLaneTelemetryState,\n): SyncLaneSnapshot {\n return {\n blobStorageKey: state.blobStorageKey,\n errorCount: state.errorCount,\n key: state.key,\n label: state.config.label ?? state.key,\n lastAction: state.lastAction,\n lastActionAt: state.lastActionAt,\n lastCompletedAt: state.lastCompletedAt,\n lastError: state.lastError,\n lastFailedAt: state.lastFailedAt,\n lastRequestedAt: state.lastRequestedAt,\n lastStartedAt: state.lastStartedAt,\n phase: state.config.phase ?? DEFAULT_SYNC_LANE_PHASE,\n progress: state.progress ?? null,\n registrationIndex: state.registrationIndex,\n requestCount: state.requestCount,\n requested: state.requested,\n runAbandoned: state.runAbandoned,\n runCount: state.runCount,\n runDurations: state.runDurations,\n running: state.running,\n status: getSyncLaneStatus(state),\n };\n}\n\nexport function createDomainSyncSnapshot(input: {\n hasPendingWork: boolean;\n lanes: Iterable<SyncLaneTelemetryState>;\n pumpActive: boolean;\n}): DomainSyncSnapshot {\n return {\n hasPendingWork: input.hasPendingWork,\n lanes: Array.from(input.lanes)\n .sort(compareSyncLaneOrder)\n .map(createSyncLaneSnapshot),\n pumpActive: input.pumpActive,\n updatedAt: createSyncTimestamp(),\n };\n}\n"]}
|
package/data/sync/uploadLane.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { readUserTimingClock } from "../shared/userTiming.js";
|
|
1
2
|
import { describeSyncLaneError, INITIAL_SYNC_LANE_RUN_STATE, noopLaneRun, publishSyncCoordinatorSnapshot, } from "./coordinatorState.js";
|
|
2
|
-
import { createSyncTimestamp } from "./syncTelemetry.js";
|
|
3
|
+
import { addSyncLaneRunDuration, createSyncTimestamp } from "./syncTelemetry.js";
|
|
3
4
|
// Completed/failed upload lanes are retained so a finished upload stays visible
|
|
4
5
|
// in the visualizer, but capped so a long-lived session can't grow `lanes`
|
|
5
6
|
// without bound (one upload lane is created per attachment slot upload).
|
|
@@ -20,6 +21,21 @@ function evictRetainedUploadLanes(coordinatorState) {
|
|
|
20
21
|
coordinatorState.lanes.delete(lane.key);
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
// Returns the session's run-ending step. Upload rows are timed like pump runs,
|
|
25
|
+
// once per session, but stay off the User Timing tracks: the owning document
|
|
26
|
+
// lane's run already spans them.
|
|
27
|
+
function startUploadLaneRun(lane) {
|
|
28
|
+
const startedAtMs = readUserTimingClock();
|
|
29
|
+
let timed = false;
|
|
30
|
+
return () => {
|
|
31
|
+
lane.running = false;
|
|
32
|
+
if (timed) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
timed = true;
|
|
36
|
+
lane.runDurations = addSyncLaneRunDuration(lane.runDurations, readUserTimingClock() - startedAtMs);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
23
39
|
export function beginUploadLane(coordinatorState, key, options) {
|
|
24
40
|
const startedAt = createSyncTimestamp();
|
|
25
41
|
let lane = coordinatorState.lanes.get(key);
|
|
@@ -70,12 +86,13 @@ export function beginUploadLane(coordinatorState, key, options) {
|
|
|
70
86
|
// callbacks can't clobber the newer upload's state.
|
|
71
87
|
const sessionRunCount = uploadLane.runCount;
|
|
72
88
|
const isCurrentSession = () => uploadLane.runCount === sessionRunCount;
|
|
89
|
+
const endRun = startUploadLaneRun(uploadLane);
|
|
73
90
|
return {
|
|
74
91
|
complete() {
|
|
75
92
|
if (!isCurrentSession()) {
|
|
76
93
|
return;
|
|
77
94
|
}
|
|
78
|
-
|
|
95
|
+
endRun();
|
|
79
96
|
uploadLane.lastAction = "completed";
|
|
80
97
|
uploadLane.lastActionAt = createSyncTimestamp();
|
|
81
98
|
uploadLane.lastCompletedAt = uploadLane.lastActionAt;
|
|
@@ -94,7 +111,7 @@ export function beginUploadLane(coordinatorState, key, options) {
|
|
|
94
111
|
if (!isCurrentSession()) {
|
|
95
112
|
return;
|
|
96
113
|
}
|
|
97
|
-
|
|
114
|
+
endRun();
|
|
98
115
|
uploadLane.errorCount += 1;
|
|
99
116
|
uploadLane.lastAction = "failed";
|
|
100
117
|
uploadLane.lastActionAt = createSyncTimestamp();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploadLane.js","sourceRoot":"","sources":["uploadLane.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DomainSyncCoordinatorState,\n SyncLaneState,\n} from \"./coordinatorState\";\nimport {\n describeSyncLaneError,\n INITIAL_SYNC_LANE_RUN_STATE,\n noopLaneRun,\n publishSyncCoordinatorSnapshot,\n} from \"./coordinatorState\";\nimport type { SyncLaneProgress } from \"./syncTelemetry\";\nimport { createSyncTimestamp } from \"./syncTelemetry\";\n\n/**\n * Handle for an observational upload lane. Unlike pump-driven lanes, these are\n * never `requested` — the upload path that owns the handle drives the lane's\n * running/progress/terminal state directly. The coordinator pump ignores them\n * because `selectNextRequestedLane` only ever picks `requested` lanes.\n */\nexport interface UploadSyncLane {\n reportProgress: (progress: SyncLaneProgress) => void;\n complete: () => void;\n fail: (error: unknown) => void;\n}\n\nexport interface UploadSyncLaneOptions {\n blobStorageKey?: string | undefined;\n label?: string | undefined;\n}\n\n// Completed/failed upload lanes are retained so a finished upload stays visible\n// in the visualizer, but capped so a long-lived session can't grow `lanes`\n// without bound (one upload lane is created per attachment slot upload).\nconst MAX_RETAINED_UPLOAD_LANES = 10;\n\nfunction evictRetainedUploadLanes(\n coordinatorState: DomainSyncCoordinatorState,\n) {\n const settledUploadLanes: SyncLaneState[] = [];\n for (const lane of coordinatorState.lanes.values()) {\n if (lane.config.phase === \"blob\" && !lane.running) {\n settledUploadLanes.push(lane);\n }\n }\n\n if (settledUploadLanes.length <= MAX_RETAINED_UPLOAD_LANES) {\n return;\n }\n\n settledUploadLanes.sort(\n (left, right) => left.registrationIndex - right.registrationIndex,\n );\n const removeCount = settledUploadLanes.length - MAX_RETAINED_UPLOAD_LANES;\n for (const lane of settledUploadLanes.slice(0, removeCount)) {\n coordinatorState.lanes.delete(lane.key);\n }\n}\n\nexport function beginUploadLane(\n coordinatorState: DomainSyncCoordinatorState,\n key: string,\n options: UploadSyncLaneOptions,\n): UploadSyncLane {\n const startedAt = createSyncTimestamp();\n let lane = coordinatorState.lanes.get(key);\n if (lane) {\n lane.config = { label: options.label, phase: \"blob\", run: noopLaneRun };\n lane.blobStorageKey = options.blobStorageKey ?? null;\n } else {\n lane = {\n ...INITIAL_SYNC_LANE_RUN_STATE,\n blobStorageKey: options.blobStorageKey ?? null,\n config: { label: options.label, phase: \"blob\", run: noopLaneRun },\n errorCount: 0,\n key,\n lastAction: \"started\",\n lastActionAt: startedAt,\n lastCompletedAt: null,\n lastError: null,\n lastFailedAt: null,\n lastRequestedAt: null,\n lastStartedAt: startedAt,\n notBeforeAtMs: null,\n progress: null,\n pumpDriven: false,\n registrationIndex: coordinatorState.nextRegistrationIndex,\n requestCount: 0,\n requested: false,\n };\n coordinatorState.nextRegistrationIndex += 1;\n coordinatorState.lanes.set(key, lane);\n }\n\n const uploadLane = lane;\n // A stale executable handle may share this key. Make the upload row\n // observational before publishing and discard any queued pump request.\n uploadLane.pumpDriven = false;\n uploadLane.requested = false;\n uploadLane.running = true;\n uploadLane.runCount += 1;\n uploadLane.lastAction = \"started\";\n uploadLane.lastActionAt = startedAt;\n uploadLane.lastStartedAt = startedAt;\n uploadLane.lastError = null;\n uploadLane.progress = null;\n evictRetainedUploadLanes(coordinatorState);\n publishSyncCoordinatorSnapshot(coordinatorState);\n\n // If this lane key is re-begun (or evicted and recreated), runCount advances\n // and a stale handle from the prior session becomes a no-op, so out-of-order\n // callbacks can't clobber the newer upload's state.\n const sessionRunCount = uploadLane.runCount;\n const isCurrentSession = () => uploadLane.runCount === sessionRunCount;\n\n return {\n complete() {\n if (!isCurrentSession()) {\n return;\n }\n uploadLane.running = false;\n uploadLane.lastAction = \"completed\";\n uploadLane.lastActionAt = createSyncTimestamp();\n uploadLane.lastCompletedAt = uploadLane.lastActionAt;\n uploadLane.lastError = null;\n if (uploadLane.progress) {\n uploadLane.progress = {\n ...uploadLane.progress,\n bytesUploaded: uploadLane.progress.bytesTotal,\n partsCompleted: uploadLane.progress.partsTotal,\n };\n }\n evictRetainedUploadLanes(coordinatorState);\n publishSyncCoordinatorSnapshot(coordinatorState);\n },\n fail(error: unknown) {\n if (!isCurrentSession()) {\n return;\n }\n uploadLane.running = false;\n uploadLane.errorCount += 1;\n uploadLane.lastAction = \"failed\";\n uploadLane.lastActionAt = createSyncTimestamp();\n uploadLane.lastError = describeSyncLaneError(error);\n uploadLane.lastFailedAt = uploadLane.lastActionAt;\n evictRetainedUploadLanes(coordinatorState);\n publishSyncCoordinatorSnapshot(coordinatorState);\n },\n reportProgress(progress: SyncLaneProgress) {\n if (!isCurrentSession()) {\n return;\n }\n uploadLane.progress = { ...progress };\n uploadLane.lastActionAt = createSyncTimestamp();\n publishSyncCoordinatorSnapshot(coordinatorState);\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"uploadLane.js","sourceRoot":"","sources":["uploadLane.ts"],"names":[],"mappings":"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","sourcesContent":["import { readUserTimingClock } from \"../shared/userTiming\";\nimport type {\n DomainSyncCoordinatorState,\n SyncLaneState,\n} from \"./coordinatorState\";\nimport {\n describeSyncLaneError,\n INITIAL_SYNC_LANE_RUN_STATE,\n noopLaneRun,\n publishSyncCoordinatorSnapshot,\n} from \"./coordinatorState\";\nimport type { SyncLaneProgress } from \"./syncTelemetry\";\nimport { addSyncLaneRunDuration, createSyncTimestamp } from \"./syncTelemetry\";\n\n/**\n * Handle for an observational upload lane. Unlike pump-driven lanes, these are\n * never `requested` — the upload path that owns the handle drives the lane's\n * running/progress/terminal state directly. The coordinator pump ignores them\n * because `selectNextRequestedLane` only ever picks `requested` lanes.\n */\nexport interface UploadSyncLane {\n reportProgress: (progress: SyncLaneProgress) => void;\n complete: () => void;\n fail: (error: unknown) => void;\n}\n\nexport interface UploadSyncLaneOptions {\n blobStorageKey?: string | undefined;\n label?: string | undefined;\n}\n\n// Completed/failed upload lanes are retained so a finished upload stays visible\n// in the visualizer, but capped so a long-lived session can't grow `lanes`\n// without bound (one upload lane is created per attachment slot upload).\nconst MAX_RETAINED_UPLOAD_LANES = 10;\n\nfunction evictRetainedUploadLanes(\n coordinatorState: DomainSyncCoordinatorState,\n) {\n const settledUploadLanes: SyncLaneState[] = [];\n for (const lane of coordinatorState.lanes.values()) {\n if (lane.config.phase === \"blob\" && !lane.running) {\n settledUploadLanes.push(lane);\n }\n }\n\n if (settledUploadLanes.length <= MAX_RETAINED_UPLOAD_LANES) {\n return;\n }\n\n settledUploadLanes.sort(\n (left, right) => left.registrationIndex - right.registrationIndex,\n );\n const removeCount = settledUploadLanes.length - MAX_RETAINED_UPLOAD_LANES;\n for (const lane of settledUploadLanes.slice(0, removeCount)) {\n coordinatorState.lanes.delete(lane.key);\n }\n}\n\n// Returns the session's run-ending step. Upload rows are timed like pump runs,\n// once per session, but stay off the User Timing tracks: the owning document\n// lane's run already spans them.\nfunction startUploadLaneRun(lane: SyncLaneState): () => void {\n const startedAtMs = readUserTimingClock();\n let timed = false;\n return () => {\n lane.running = false;\n if (timed) {\n return;\n }\n timed = true;\n lane.runDurations = addSyncLaneRunDuration(\n lane.runDurations,\n readUserTimingClock() - startedAtMs,\n );\n };\n}\n\nexport function beginUploadLane(\n coordinatorState: DomainSyncCoordinatorState,\n key: string,\n options: UploadSyncLaneOptions,\n): UploadSyncLane {\n const startedAt = createSyncTimestamp();\n let lane = coordinatorState.lanes.get(key);\n if (lane) {\n lane.config = { label: options.label, phase: \"blob\", run: noopLaneRun };\n lane.blobStorageKey = options.blobStorageKey ?? null;\n } else {\n lane = {\n ...INITIAL_SYNC_LANE_RUN_STATE,\n blobStorageKey: options.blobStorageKey ?? null,\n config: { label: options.label, phase: \"blob\", run: noopLaneRun },\n errorCount: 0,\n key,\n lastAction: \"started\",\n lastActionAt: startedAt,\n lastCompletedAt: null,\n lastError: null,\n lastFailedAt: null,\n lastRequestedAt: null,\n lastStartedAt: startedAt,\n notBeforeAtMs: null,\n progress: null,\n pumpDriven: false,\n registrationIndex: coordinatorState.nextRegistrationIndex,\n requestCount: 0,\n requested: false,\n };\n coordinatorState.nextRegistrationIndex += 1;\n coordinatorState.lanes.set(key, lane);\n }\n\n const uploadLane = lane;\n // A stale executable handle may share this key. Make the upload row\n // observational before publishing and discard any queued pump request.\n uploadLane.pumpDriven = false;\n uploadLane.requested = false;\n uploadLane.running = true;\n uploadLane.runCount += 1;\n uploadLane.lastAction = \"started\";\n uploadLane.lastActionAt = startedAt;\n uploadLane.lastStartedAt = startedAt;\n uploadLane.lastError = null;\n uploadLane.progress = null;\n evictRetainedUploadLanes(coordinatorState);\n publishSyncCoordinatorSnapshot(coordinatorState);\n\n // If this lane key is re-begun (or evicted and recreated), runCount advances\n // and a stale handle from the prior session becomes a no-op, so out-of-order\n // callbacks can't clobber the newer upload's state.\n const sessionRunCount = uploadLane.runCount;\n const isCurrentSession = () => uploadLane.runCount === sessionRunCount;\n const endRun = startUploadLaneRun(uploadLane);\n\n return {\n complete() {\n if (!isCurrentSession()) {\n return;\n }\n endRun();\n uploadLane.lastAction = \"completed\";\n uploadLane.lastActionAt = createSyncTimestamp();\n uploadLane.lastCompletedAt = uploadLane.lastActionAt;\n uploadLane.lastError = null;\n if (uploadLane.progress) {\n uploadLane.progress = {\n ...uploadLane.progress,\n bytesUploaded: uploadLane.progress.bytesTotal,\n partsCompleted: uploadLane.progress.partsTotal,\n };\n }\n evictRetainedUploadLanes(coordinatorState);\n publishSyncCoordinatorSnapshot(coordinatorState);\n },\n fail(error: unknown) {\n if (!isCurrentSession()) {\n return;\n }\n endRun();\n uploadLane.errorCount += 1;\n uploadLane.lastAction = \"failed\";\n uploadLane.lastActionAt = createSyncTimestamp();\n uploadLane.lastError = describeSyncLaneError(error);\n uploadLane.lastFailedAt = uploadLane.lastActionAt;\n evictRetainedUploadLanes(coordinatorState);\n publishSyncCoordinatorSnapshot(coordinatorState);\n },\n reportProgress(progress: SyncLaneProgress) {\n if (!isCurrentSession()) {\n return;\n }\n uploadLane.progress = { ...progress };\n uploadLane.lastActionAt = createSyncTimestamp();\n publishSyncCoordinatorSnapshot(coordinatorState);\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -5,10 +5,11 @@ import { attachFilesToDocumentStore, replaceAttachmentInDocumentStore, } from ".
|
|
|
5
5
|
import { removeAttachmentFromDocumentStore } from "./attachments/attachmentRemoval.js";
|
|
6
6
|
import { discardDocumentStoreLocalState } from "./discard.js";
|
|
7
7
|
import { ensureDocumentStoreInitialized, ensureDocumentStoreReady, relinkDocumentStore, } from "./initialization/index.js";
|
|
8
|
+
import { assertInitialContentFitsKind } from "./initialization/initialContent.js";
|
|
8
9
|
import { registerInternalDocumentRelink } from "./internalRelink.js";
|
|
9
10
|
import { setDocumentStructuredFields, setDocumentText } from "./mutations.js";
|
|
10
11
|
import { assertDocumentStoreCanRotateContentKey } from "./rotation/index.js";
|
|
11
|
-
import { addRowToDocumentStore, removeRowFromDocumentStore, updateRowInDocumentStore, } from "./rows.js";
|
|
12
|
+
import { addRowToDocumentStore, removeRowFromDocumentStore, updateRowInDocumentStore, } from "./rows/index.js";
|
|
12
13
|
import { createDocumentStoreState, refreshAttachabilitySnapshot, resetDocumentStore, subscribeToDocumentStore, } from "./state.js";
|
|
13
14
|
import { registerDocumentStoreSyncLane } from "./sync/index.js";
|
|
14
15
|
import { logRevalidationScheduled } from "./sync/remoteRevalidationTelemetry.js";
|
|
@@ -156,6 +157,9 @@ function createBackingStoreContext(localId, runtime, persistence, documentId, te
|
|
|
156
157
|
}, documentId, text, documentKind, (options.remoteSyncMode ?? "startup") === "startup");
|
|
157
158
|
if (options.deferInitialUpdate)
|
|
158
159
|
state.deferInitialUpdate = true;
|
|
160
|
+
const { initialRows, initialStructuredFields } = options;
|
|
161
|
+
assertInitialContentFitsKind({ initialStructuredFields }, documentKind);
|
|
162
|
+
state.initialContent = { initialRows, initialStructuredFields };
|
|
159
163
|
refreshDocumentStoreSyncLane(state);
|
|
160
164
|
const scheduleSync = () => requestDocumentStoreSync(state);
|
|
161
165
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../../../data/documents/documentConstants\";\nimport type { StoredDocumentKind } from \"../../../data/documents/documentKinds\";\nimport type { DomainScope } from \"../../../data/shared/domainScope\";\nimport {\n createDocumentProjectionUserKeyResolver,\n type DocumentsPersistence,\n defaultDocumentsPersistence,\n didDocumentProjectionKeyRuntimeChange,\n didRegainSyncPrerequisites,\n requestDocumentSyncLaneAndWait,\n} from \"../../../workflows/documents\";\nimport {\n createDocumentStoreFacade,\n emitPersistedDocument,\n getOrCreateDocumentStoreRegistry,\n registerDocumentStore,\n registerDocumentStoreIdentity,\n requestDocumentStoreSync,\n resolveDocumentStoreKey,\n} from \"../registry\";\nimport type {\n DocumentAttachmentUpload,\n DocumentStore,\n DocumentStoreFacade,\n DocumentStoreOpenOptions,\n DocumentsRuntime,\n} from \"../types\";\nimport {\n attachFilesToDocumentStore,\n replaceAttachmentInDocumentStore,\n} from \"./attachments\";\nimport { removeAttachmentFromDocumentStore } from \"./attachments/attachmentRemoval\";\nimport { discardDocumentStoreLocalState } from \"./discard\";\nimport {\n ensureDocumentStoreInitialized,\n ensureDocumentStoreReady,\n relinkDocumentStore,\n} from \"./initialization\";\nimport { registerInternalDocumentRelink } from \"./internalRelink\";\nimport { setDocumentStructuredFields, setDocumentText } from \"./mutations\";\nimport { assertDocumentStoreCanRotateContentKey } from \"./rotation\";\nimport {\n addRowToDocumentStore,\n removeRowFromDocumentStore,\n updateRowInDocumentStore,\n} from \"./rows\";\nimport {\n createDocumentStoreState,\n type DocumentStoreState,\n refreshAttachabilitySnapshot,\n resetDocumentStore,\n subscribeToDocumentStore,\n} from \"./state\";\nimport { registerDocumentStoreSyncLane } from \"./sync\";\nimport { logRevalidationScheduled } from \"./sync/remoteRevalidationTelemetry\";\nimport {\n allowDocumentStoreRemoteSync,\n captureDocumentStoreRemoteSyncRequestGeneration,\n captureDocumentStoreSyncLaneGeneration,\n type DocumentStoreRemoteSyncRequestGeneration,\n type DocumentStoreSyncLaneGeneration,\n didDocumentStoreRemoteSyncRequestComplete,\n hasPendingIndependentDocumentStoreRemoteSync,\n invalidateDocumentStoreRemoteSync,\n invalidateDocumentStoreSyncLane,\n isDocumentStoreRemoteSyncBlocked,\n isDocumentStoreRemoteSyncRequestGenerationCurrent,\n markDocumentStoreRemoteSyncPending,\n registerDocumentStoreRemoteSyncWaiter,\n} from \"./sync/syncGeneration\";\nimport { handleDocumentRemoteEvents } from \"./sync/syncRemoteSignals\";\n\nexport {\n discardRegisteredDocumentLocalState,\n requestDomainDocumentSync,\n subscribeToPersistedDocuments,\n} from \"../registry\";\n\nfunction refreshDocumentStoreSyncLane(\n state: DocumentStoreState,\n force = false,\n): void {\n if (!force && state.syncLane && !state.syncLane.isDisposed?.()) {\n return;\n }\n if (state.syncLane) {\n invalidateDocumentStoreSyncLane(state);\n }\n let syncLaneGeneration: DocumentStoreSyncLaneGeneration | null = null;\n state.syncLane = registerDocumentStoreSyncLane(\n state,\n () => syncLaneGeneration,\n );\n syncLaneGeneration = captureDocumentStoreSyncLaneGeneration(state);\n}\n\nfunction updateDocumentStoreRuntime(\n state: DocumentStoreState,\n nextRuntime: DocumentsRuntime,\n scheduleSync: () => void,\n) {\n const previousRuntime = state.runtime;\n const serverEventsReconnected =\n (nextRuntime.state.serverEventsConnectionGeneration ?? 0) >\n (previousRuntime.state.serverEventsConnectionGeneration ?? 0);\n const domainScopeChanged =\n previousRuntime.state.domainScope !== nextRuntime.state.domainScope;\n const projectionKeyRuntimeChanged = didDocumentProjectionKeyRuntimeChange(\n previousRuntime,\n nextRuntime,\n );\n if (projectionKeyRuntimeChanged) {\n state.resolveProjectionUserKey =\n createDocumentProjectionUserKeyResolver(nextRuntime);\n state.writerProjection = null;\n }\n state.runtime = nextRuntime;\n refreshDocumentStoreSyncLane(state, domainScopeChanged);\n if (domainScopeChanged) {\n state.locallyAcceptedUpdateIds = new Set();\n state.remoteUpdatePending = false;\n state.writerProjection = null;\n }\n\n if (nextRuntime.infra.dbStatus !== \"ready\") {\n if (state.snapshot.ready || state.initialized || state.initializePromise) {\n resetDocumentStore(state);\n }\n state.lastEventCount = nextRuntime.state.events.length;\n return;\n }\n\n refreshAttachabilitySnapshot(state);\n ensureDocumentStoreInitialized(state, scheduleSync);\n handleDocumentRemoteEvents(state, scheduleSync);\n\n if (state.snapshot.ready) {\n if (serverEventsReconnected) {\n // The invalidation stream is lossy while disconnected. Once the server\n // has acknowledged this socket's authoritative interest declaration,\n // every already-open remote document needs one HTTP probe to cover peer\n // writes made during the gap. This also closes iOS background/resume reconnects where the\n // native network source remained online throughout.\n requestRemoteDocumentStoreSync(state, scheduleSync);\n logRevalidationScheduled(state.runtime, \"reconnect\");\n } else if (didRegainSyncPrerequisites(previousRuntime, state.runtime)) {\n scheduleSync();\n }\n }\n}\n\nfunction requestRemoteDocumentStoreSync(\n state: DocumentStoreState,\n scheduleSync: () => void,\n owner: \"independent\" | \"waiter\" = \"independent\",\n): number {\n allowDocumentStoreRemoteSync(state);\n const signalSequence = markDocumentStoreRemoteSyncPending(state, owner);\n scheduleSync();\n return signalSequence;\n}\n\nfunction requestOrdinaryDocumentStoreSync(\n state: DocumentStoreState,\n scheduleSync: () => void,\n): void {\n // A normal UI reopen is a fresh owner for remote-only work. It may recover\n // a probe that an earlier, now-unmounted owner aborted.\n if (isDocumentStoreRemoteSyncBlocked(state)) {\n requestRemoteDocumentStoreSync(state, scheduleSync);\n return;\n }\n scheduleSync();\n}\n\nfunction requestRemoteDocumentStoreSyncAndWait(\n state: DocumentStoreState,\n scheduleSync: () => void,\n signal?: AbortSignal,\n): Promise<boolean> {\n let requestGeneration: DocumentStoreRemoteSyncRequestGeneration | null = null;\n let requestedSignalSequence = 0;\n let releaseWaiter: (() => boolean) | null = null;\n const releaseRemoteSyncWaiter = (invalidate: boolean) => {\n const releasedLastWaiter = releaseWaiter?.() ?? false;\n if (\n invalidate &&\n releasedLastWaiter &&\n requestGeneration !== null &&\n isDocumentStoreRemoteSyncRequestGenerationCurrent(\n state,\n requestGeneration,\n ) &&\n !hasPendingIndependentDocumentStoreRemoteSync(state)\n ) {\n invalidateDocumentStoreRemoteSync(state);\n }\n };\n // A coordinator can be disposed and recreated while this same-scope store\n // remains registered. Refresh its handle before requesting work.\n refreshDocumentStoreSyncLane(state);\n return requestDocumentSyncLaneAndWait({\n didCompleteRequest: () =>\n requestGeneration !== null &&\n didDocumentStoreRemoteSyncRequestComplete(\n state,\n requestGeneration,\n requestedSignalSequence,\n ),\n domainScope: state.runtime.state.domainScope,\n localId: state.localId,\n request: () => {\n requestGeneration =\n captureDocumentStoreRemoteSyncRequestGeneration(state);\n releaseWaiter = registerDocumentStoreRemoteSyncWaiter(\n state,\n requestGeneration,\n );\n requestedSignalSequence = requestRemoteDocumentStoreSync(\n state,\n scheduleSync,\n \"waiter\",\n );\n },\n onInvalidated: () => releaseRemoteSyncWaiter(true),\n signal,\n }).then(\n (completed) => {\n releaseRemoteSyncWaiter(!completed);\n return completed;\n },\n (error: unknown) => {\n releaseRemoteSyncWaiter(true);\n throw error;\n },\n );\n}\n\nasync function assertBackingDocumentStoreCanRotate(\n state: DocumentStoreState,\n scheduleSync: () => void,\n) {\n if (!(await ensureDocumentStoreReady(state, scheduleSync)) || !state.doc) {\n throw new Error(\n \"Document must finish loading before its content key can rotate\",\n );\n }\n return assertDocumentStoreCanRotateContentKey(state);\n}\n\nasync function discardBackingDocumentStoreLocalState(\n state: DocumentStoreState,\n scheduleSync: () => void,\n expectedDocumentId: string,\n) {\n try {\n return await discardDocumentStoreLocalState(state, expectedDocumentId);\n } finally {\n // Restart hydration whenever the attempt reset the store. This runs outside\n // its identity-chained task because initialization also chains writes.\n ensureDocumentStoreInitialized(state, scheduleSync);\n scheduleSync();\n }\n}\n\nfunction createLiveSyncLaneRequest(state: DocumentStoreState) {\n return <Result>(request: () => Result): Result => {\n refreshDocumentStoreSyncLane(state);\n return request();\n };\n}\n\nfunction registerBackingStoreInternalRelink(input: {\n scheduleSync: () => void;\n state: DocumentStoreState;\n store: DocumentStore;\n withLiveSyncLane: ReturnType<typeof createLiveSyncLaneRequest>;\n}): DocumentStore {\n registerInternalDocumentRelink(input.store, (relinkInput, commitSideEffect) =>\n input.withLiveSyncLane(() =>\n relinkDocumentStore(\n input.state,\n relinkInput,\n input.scheduleSync,\n commitSideEffect,\n ),\n ),\n );\n return input.store;\n}\n\nfunction createBackingStoreContext(\n localId: string,\n runtime: DocumentsRuntime,\n persistence: DocumentsPersistence,\n documentId: string | null,\n text: string,\n documentKind: StoredDocumentKind,\n options: DocumentStoreOpenOptions,\n) {\n const state = createDocumentStoreState(\n localId,\n runtime,\n persistence,\n {\n emitPersistedDocument,\n registerDocumentIdentity: registerDocumentStoreIdentity,\n },\n documentId,\n text,\n documentKind,\n (options.remoteSyncMode ?? \"startup\") === \"startup\",\n );\n if (options.deferInitialUpdate) state.deferInitialUpdate = true;\n refreshDocumentStoreSyncLane(state);\n const scheduleSync = () => requestDocumentStoreSync(state);\n return {\n scheduleSync,\n state,\n withLiveSyncLane: createLiveSyncLaneRequest(state),\n };\n}\n\nfunction createBackingDocumentStore(\n localId: string,\n initialRuntime: DocumentsRuntime,\n persistence: DocumentsPersistence = defaultDocumentsPersistence,\n initialDocumentId: string | null = null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n openOptions: DocumentStoreOpenOptions = {},\n): DocumentStore {\n const { scheduleSync, state, withLiveSyncLane } = createBackingStoreContext(\n localId,\n initialRuntime,\n persistence,\n initialDocumentId,\n initialText,\n initialDocumentKind,\n openOptions,\n );\n\n const store: DocumentStore = {\n addRow: (fields) =>\n withLiveSyncLane(() =>\n addRowToDocumentStore(state, scheduleSync, fields),\n ),\n assertCanRotateContentKey: () =>\n withLiveSyncLane(() =>\n assertBackingDocumentStoreCanRotate(state, scheduleSync),\n ),\n attachFiles: (files: ReadonlyArray<DocumentAttachmentUpload>) =>\n withLiveSyncLane(() =>\n attachFilesToDocumentStore(state, scheduleSync, files),\n ),\n discardLocalState: (expectedDocumentId: string) =>\n withLiveSyncLane(() =>\n discardBackingDocumentStoreLocalState(\n state,\n scheduleSync,\n expectedDocumentId,\n ),\n ),\n ensureInitialized: () =>\n withLiveSyncLane(() => ensureDocumentStoreReady(state, scheduleSync)),\n getSnapshot: () => state.snapshot,\n removeAttachment: (slotId: string) =>\n withLiveSyncLane(() =>\n removeAttachmentFromDocumentStore(state, scheduleSync, slotId),\n ),\n removeRow: (id) =>\n withLiveSyncLane(() =>\n removeRowFromDocumentStore(state, scheduleSync, id),\n ),\n replaceAttachment: (slotId: string, file: DocumentAttachmentUpload) =>\n withLiveSyncLane(() =>\n replaceAttachmentInDocumentStore(state, scheduleSync, slotId, file),\n ),\n requestRemoteSync: () =>\n withLiveSyncLane(() =>\n requestRemoteDocumentStoreSync(state, scheduleSync),\n ),\n requestRemoteSyncAndWait: (signal) =>\n requestRemoteDocumentStoreSyncAndWait(state, scheduleSync, signal),\n requestSync: () =>\n withLiveSyncLane(() =>\n requestOrdinaryDocumentStoreSync(state, scheduleSync),\n ),\n relink: (input) =>\n withLiveSyncLane(() => relinkDocumentStore(state, input, scheduleSync)),\n setStructuredFields: (kind, patch, options) =>\n withLiveSyncLane(() =>\n setDocumentStructuredFields(state, scheduleSync, kind, patch, options),\n ),\n setText: (value: string) =>\n withLiveSyncLane(() => setDocumentText(state, scheduleSync, value)),\n subscribe: (listener) => subscribeToDocumentStore(state, listener),\n updateRowFields: (id, patch) =>\n withLiveSyncLane(() =>\n updateRowInDocumentStore(state, scheduleSync, id, patch),\n ),\n updateRuntime: (runtime: DocumentsRuntime) =>\n updateDocumentStoreRuntime(state, runtime, scheduleSync),\n };\n return registerBackingStoreInternalRelink({\n scheduleSync,\n state,\n store,\n withLiveSyncLane,\n });\n}\n\nexport function createDocumentStore(\n localId: string,\n initialRuntime: DocumentsRuntime,\n persistence: DocumentsPersistence = defaultDocumentsPersistence,\n initialDocumentId: string | null = null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n options: DocumentStoreOpenOptions = {},\n): DocumentStoreFacade {\n return createDocumentStoreFacade(\n createBackingDocumentStore(\n localId,\n initialRuntime,\n persistence,\n initialDocumentId,\n initialText,\n initialDocumentKind,\n options,\n ),\n );\n}\n\nexport function getOrCreateDocumentStore(\n domainScope: DomainScope,\n localId: string,\n runtime: DocumentsRuntime,\n initialDocumentId: string | null = null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n options: DocumentStoreOpenOptions = {},\n): DocumentStore {\n const registry = getOrCreateDocumentStoreRegistry(domainScope);\n const existingStore = registry.storesByKey.get(\n resolveDocumentStoreKey(registry, localId, initialDocumentId),\n );\n if (existingStore) {\n registerDocumentStore(\n domainScope,\n localId,\n existingStore,\n initialDocumentId,\n );\n return existingStore;\n }\n\n const nextStore = createDocumentStore(\n localId,\n runtime,\n defaultDocumentsPersistence,\n initialDocumentId,\n initialText,\n initialDocumentKind,\n options,\n );\n registerDocumentStore(domainScope, localId, nextStore, initialDocumentId);\n return nextStore;\n}\n\nexport function openDocumentStore(\n domainScope: DomainScope,\n localId: string,\n runtime: DocumentsRuntime,\n initialDocumentId: string | null = null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n options: DocumentStoreOpenOptions = {},\n): DocumentStore {\n const store = getOrCreateDocumentStore(\n domainScope,\n localId,\n runtime,\n initialDocumentId,\n initialText,\n initialDocumentKind,\n options,\n );\n store.updateRuntime(runtime);\n return store;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../../../data/documents/documentConstants\";\nimport type { StoredDocumentKind } from \"../../../data/documents/documentKinds\";\nimport type { DomainScope } from \"../../../data/shared/domainScope\";\nimport {\n createDocumentProjectionUserKeyResolver,\n type DocumentsPersistence,\n defaultDocumentsPersistence,\n didDocumentProjectionKeyRuntimeChange,\n didRegainSyncPrerequisites,\n requestDocumentSyncLaneAndWait,\n} from \"../../../workflows/documents\";\nimport {\n createDocumentStoreFacade,\n emitPersistedDocument,\n getOrCreateDocumentStoreRegistry,\n registerDocumentStore,\n registerDocumentStoreIdentity,\n requestDocumentStoreSync,\n resolveDocumentStoreKey,\n} from \"../registry\";\nimport type {\n DocumentAttachmentUpload,\n DocumentStore,\n DocumentStoreFacade,\n DocumentStoreOpenOptions,\n DocumentsRuntime,\n} from \"../types\";\nimport {\n attachFilesToDocumentStore,\n replaceAttachmentInDocumentStore,\n} from \"./attachments\";\nimport { removeAttachmentFromDocumentStore } from \"./attachments/attachmentRemoval\";\nimport { discardDocumentStoreLocalState } from \"./discard\";\nimport {\n ensureDocumentStoreInitialized,\n ensureDocumentStoreReady,\n relinkDocumentStore,\n} from \"./initialization\";\nimport { assertInitialContentFitsKind } from \"./initialization/initialContent\";\nimport { registerInternalDocumentRelink } from \"./internalRelink\";\nimport { setDocumentStructuredFields, setDocumentText } from \"./mutations\";\nimport { assertDocumentStoreCanRotateContentKey } from \"./rotation\";\nimport {\n addRowToDocumentStore,\n removeRowFromDocumentStore,\n updateRowInDocumentStore,\n} from \"./rows\";\nimport {\n createDocumentStoreState,\n type DocumentStoreState,\n refreshAttachabilitySnapshot,\n resetDocumentStore,\n subscribeToDocumentStore,\n} from \"./state\";\nimport { registerDocumentStoreSyncLane } from \"./sync\";\nimport { logRevalidationScheduled } from \"./sync/remoteRevalidationTelemetry\";\nimport {\n allowDocumentStoreRemoteSync,\n captureDocumentStoreRemoteSyncRequestGeneration,\n captureDocumentStoreSyncLaneGeneration,\n type DocumentStoreRemoteSyncRequestGeneration,\n type DocumentStoreSyncLaneGeneration,\n didDocumentStoreRemoteSyncRequestComplete,\n hasPendingIndependentDocumentStoreRemoteSync,\n invalidateDocumentStoreRemoteSync,\n invalidateDocumentStoreSyncLane,\n isDocumentStoreRemoteSyncBlocked,\n isDocumentStoreRemoteSyncRequestGenerationCurrent,\n markDocumentStoreRemoteSyncPending,\n registerDocumentStoreRemoteSyncWaiter,\n} from \"./sync/syncGeneration\";\nimport { handleDocumentRemoteEvents } from \"./sync/syncRemoteSignals\";\n\nexport {\n discardRegisteredDocumentLocalState,\n requestDomainDocumentSync,\n subscribeToPersistedDocuments,\n} from \"../registry\";\n\nfunction refreshDocumentStoreSyncLane(\n state: DocumentStoreState,\n force = false,\n): void {\n if (!force && state.syncLane && !state.syncLane.isDisposed?.()) {\n return;\n }\n if (state.syncLane) {\n invalidateDocumentStoreSyncLane(state);\n }\n let syncLaneGeneration: DocumentStoreSyncLaneGeneration | null = null;\n state.syncLane = registerDocumentStoreSyncLane(\n state,\n () => syncLaneGeneration,\n );\n syncLaneGeneration = captureDocumentStoreSyncLaneGeneration(state);\n}\n\nfunction updateDocumentStoreRuntime(\n state: DocumentStoreState,\n nextRuntime: DocumentsRuntime,\n scheduleSync: () => void,\n) {\n const previousRuntime = state.runtime;\n const serverEventsReconnected =\n (nextRuntime.state.serverEventsConnectionGeneration ?? 0) >\n (previousRuntime.state.serverEventsConnectionGeneration ?? 0);\n const domainScopeChanged =\n previousRuntime.state.domainScope !== nextRuntime.state.domainScope;\n const projectionKeyRuntimeChanged = didDocumentProjectionKeyRuntimeChange(\n previousRuntime,\n nextRuntime,\n );\n if (projectionKeyRuntimeChanged) {\n state.resolveProjectionUserKey =\n createDocumentProjectionUserKeyResolver(nextRuntime);\n state.writerProjection = null;\n }\n state.runtime = nextRuntime;\n refreshDocumentStoreSyncLane(state, domainScopeChanged);\n if (domainScopeChanged) {\n state.locallyAcceptedUpdateIds = new Set();\n state.remoteUpdatePending = false;\n state.writerProjection = null;\n }\n\n if (nextRuntime.infra.dbStatus !== \"ready\") {\n if (state.snapshot.ready || state.initialized || state.initializePromise) {\n resetDocumentStore(state);\n }\n state.lastEventCount = nextRuntime.state.events.length;\n return;\n }\n\n refreshAttachabilitySnapshot(state);\n ensureDocumentStoreInitialized(state, scheduleSync);\n handleDocumentRemoteEvents(state, scheduleSync);\n\n if (state.snapshot.ready) {\n if (serverEventsReconnected) {\n // The invalidation stream is lossy while disconnected. Once the server\n // has acknowledged this socket's authoritative interest declaration,\n // every already-open remote document needs one HTTP probe to cover peer\n // writes made during the gap. This also closes iOS background/resume reconnects where the\n // native network source remained online throughout.\n requestRemoteDocumentStoreSync(state, scheduleSync);\n logRevalidationScheduled(state.runtime, \"reconnect\");\n } else if (didRegainSyncPrerequisites(previousRuntime, state.runtime)) {\n scheduleSync();\n }\n }\n}\n\nfunction requestRemoteDocumentStoreSync(\n state: DocumentStoreState,\n scheduleSync: () => void,\n owner: \"independent\" | \"waiter\" = \"independent\",\n): number {\n allowDocumentStoreRemoteSync(state);\n const signalSequence = markDocumentStoreRemoteSyncPending(state, owner);\n scheduleSync();\n return signalSequence;\n}\n\nfunction requestOrdinaryDocumentStoreSync(\n state: DocumentStoreState,\n scheduleSync: () => void,\n): void {\n // A normal UI reopen is a fresh owner for remote-only work. It may recover\n // a probe that an earlier, now-unmounted owner aborted.\n if (isDocumentStoreRemoteSyncBlocked(state)) {\n requestRemoteDocumentStoreSync(state, scheduleSync);\n return;\n }\n scheduleSync();\n}\n\nfunction requestRemoteDocumentStoreSyncAndWait(\n state: DocumentStoreState,\n scheduleSync: () => void,\n signal?: AbortSignal,\n): Promise<boolean> {\n let requestGeneration: DocumentStoreRemoteSyncRequestGeneration | null = null;\n let requestedSignalSequence = 0;\n let releaseWaiter: (() => boolean) | null = null;\n const releaseRemoteSyncWaiter = (invalidate: boolean) => {\n const releasedLastWaiter = releaseWaiter?.() ?? false;\n if (\n invalidate &&\n releasedLastWaiter &&\n requestGeneration !== null &&\n isDocumentStoreRemoteSyncRequestGenerationCurrent(\n state,\n requestGeneration,\n ) &&\n !hasPendingIndependentDocumentStoreRemoteSync(state)\n ) {\n invalidateDocumentStoreRemoteSync(state);\n }\n };\n // A coordinator can be disposed and recreated while this same-scope store\n // remains registered. Refresh its handle before requesting work.\n refreshDocumentStoreSyncLane(state);\n return requestDocumentSyncLaneAndWait({\n didCompleteRequest: () =>\n requestGeneration !== null &&\n didDocumentStoreRemoteSyncRequestComplete(\n state,\n requestGeneration,\n requestedSignalSequence,\n ),\n domainScope: state.runtime.state.domainScope,\n localId: state.localId,\n request: () => {\n requestGeneration =\n captureDocumentStoreRemoteSyncRequestGeneration(state);\n releaseWaiter = registerDocumentStoreRemoteSyncWaiter(\n state,\n requestGeneration,\n );\n requestedSignalSequence = requestRemoteDocumentStoreSync(\n state,\n scheduleSync,\n \"waiter\",\n );\n },\n onInvalidated: () => releaseRemoteSyncWaiter(true),\n signal,\n }).then(\n (completed) => {\n releaseRemoteSyncWaiter(!completed);\n return completed;\n },\n (error: unknown) => {\n releaseRemoteSyncWaiter(true);\n throw error;\n },\n );\n}\n\nasync function assertBackingDocumentStoreCanRotate(\n state: DocumentStoreState,\n scheduleSync: () => void,\n) {\n if (!(await ensureDocumentStoreReady(state, scheduleSync)) || !state.doc) {\n throw new Error(\n \"Document must finish loading before its content key can rotate\",\n );\n }\n return assertDocumentStoreCanRotateContentKey(state);\n}\n\nasync function discardBackingDocumentStoreLocalState(\n state: DocumentStoreState,\n scheduleSync: () => void,\n expectedDocumentId: string,\n) {\n try {\n return await discardDocumentStoreLocalState(state, expectedDocumentId);\n } finally {\n // Restart hydration whenever the attempt reset the store. This runs outside\n // its identity-chained task because initialization also chains writes.\n ensureDocumentStoreInitialized(state, scheduleSync);\n scheduleSync();\n }\n}\n\nfunction createLiveSyncLaneRequest(state: DocumentStoreState) {\n return <Result>(request: () => Result): Result => {\n refreshDocumentStoreSyncLane(state);\n return request();\n };\n}\n\nfunction registerBackingStoreInternalRelink(input: {\n scheduleSync: () => void;\n state: DocumentStoreState;\n store: DocumentStore;\n withLiveSyncLane: ReturnType<typeof createLiveSyncLaneRequest>;\n}): DocumentStore {\n registerInternalDocumentRelink(input.store, (relinkInput, commitSideEffect) =>\n input.withLiveSyncLane(() =>\n relinkDocumentStore(\n input.state,\n relinkInput,\n input.scheduleSync,\n commitSideEffect,\n ),\n ),\n );\n return input.store;\n}\n\nfunction createBackingStoreContext(\n localId: string,\n runtime: DocumentsRuntime,\n persistence: DocumentsPersistence,\n documentId: string | null,\n text: string,\n documentKind: StoredDocumentKind,\n options: DocumentStoreOpenOptions,\n) {\n const state = createDocumentStoreState(\n localId,\n runtime,\n persistence,\n {\n emitPersistedDocument,\n registerDocumentIdentity: registerDocumentStoreIdentity,\n },\n documentId,\n text,\n documentKind,\n (options.remoteSyncMode ?? \"startup\") === \"startup\",\n );\n if (options.deferInitialUpdate) state.deferInitialUpdate = true;\n const { initialRows, initialStructuredFields } = options;\n assertInitialContentFitsKind({ initialStructuredFields }, documentKind);\n state.initialContent = { initialRows, initialStructuredFields };\n refreshDocumentStoreSyncLane(state);\n const scheduleSync = () => requestDocumentStoreSync(state);\n return {\n scheduleSync,\n state,\n withLiveSyncLane: createLiveSyncLaneRequest(state),\n };\n}\n\nfunction createBackingDocumentStore(\n localId: string,\n initialRuntime: DocumentsRuntime,\n persistence: DocumentsPersistence = defaultDocumentsPersistence,\n initialDocumentId: string | null = null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n openOptions: DocumentStoreOpenOptions = {},\n): DocumentStore {\n const { scheduleSync, state, withLiveSyncLane } = createBackingStoreContext(\n localId,\n initialRuntime,\n persistence,\n initialDocumentId,\n initialText,\n initialDocumentKind,\n openOptions,\n );\n\n const store: DocumentStore = {\n addRow: (fields) =>\n withLiveSyncLane(() =>\n addRowToDocumentStore(state, scheduleSync, fields),\n ),\n assertCanRotateContentKey: () =>\n withLiveSyncLane(() =>\n assertBackingDocumentStoreCanRotate(state, scheduleSync),\n ),\n attachFiles: (files: ReadonlyArray<DocumentAttachmentUpload>) =>\n withLiveSyncLane(() =>\n attachFilesToDocumentStore(state, scheduleSync, files),\n ),\n discardLocalState: (expectedDocumentId: string) =>\n withLiveSyncLane(() =>\n discardBackingDocumentStoreLocalState(\n state,\n scheduleSync,\n expectedDocumentId,\n ),\n ),\n ensureInitialized: () =>\n withLiveSyncLane(() => ensureDocumentStoreReady(state, scheduleSync)),\n getSnapshot: () => state.snapshot,\n removeAttachment: (slotId: string) =>\n withLiveSyncLane(() =>\n removeAttachmentFromDocumentStore(state, scheduleSync, slotId),\n ),\n removeRow: (id) =>\n withLiveSyncLane(() =>\n removeRowFromDocumentStore(state, scheduleSync, id),\n ),\n replaceAttachment: (slotId: string, file: DocumentAttachmentUpload) =>\n withLiveSyncLane(() =>\n replaceAttachmentInDocumentStore(state, scheduleSync, slotId, file),\n ),\n requestRemoteSync: () =>\n withLiveSyncLane(() =>\n requestRemoteDocumentStoreSync(state, scheduleSync),\n ),\n requestRemoteSyncAndWait: (signal) =>\n requestRemoteDocumentStoreSyncAndWait(state, scheduleSync, signal),\n requestSync: () =>\n withLiveSyncLane(() =>\n requestOrdinaryDocumentStoreSync(state, scheduleSync),\n ),\n relink: (input) =>\n withLiveSyncLane(() => relinkDocumentStore(state, input, scheduleSync)),\n setStructuredFields: (kind, patch, options) =>\n withLiveSyncLane(() =>\n setDocumentStructuredFields(state, scheduleSync, kind, patch, options),\n ),\n setText: (value: string) =>\n withLiveSyncLane(() => setDocumentText(state, scheduleSync, value)),\n subscribe: (listener) => subscribeToDocumentStore(state, listener),\n updateRowFields: (id, patch) =>\n withLiveSyncLane(() =>\n updateRowInDocumentStore(state, scheduleSync, id, patch),\n ),\n updateRuntime: (runtime: DocumentsRuntime) =>\n updateDocumentStoreRuntime(state, runtime, scheduleSync),\n };\n return registerBackingStoreInternalRelink({\n scheduleSync,\n state,\n store,\n withLiveSyncLane,\n });\n}\n\nexport function createDocumentStore(\n localId: string,\n initialRuntime: DocumentsRuntime,\n persistence: DocumentsPersistence = defaultDocumentsPersistence,\n initialDocumentId: string | null = null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n options: DocumentStoreOpenOptions = {},\n): DocumentStoreFacade {\n return createDocumentStoreFacade(\n createBackingDocumentStore(\n localId,\n initialRuntime,\n persistence,\n initialDocumentId,\n initialText,\n initialDocumentKind,\n options,\n ),\n );\n}\n\nexport function getOrCreateDocumentStore(\n domainScope: DomainScope,\n localId: string,\n runtime: DocumentsRuntime,\n initialDocumentId: string | null = null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n options: DocumentStoreOpenOptions = {},\n): DocumentStore {\n const registry = getOrCreateDocumentStoreRegistry(domainScope);\n const existingStore = registry.storesByKey.get(\n resolveDocumentStoreKey(registry, localId, initialDocumentId),\n );\n if (existingStore) {\n registerDocumentStore(\n domainScope,\n localId,\n existingStore,\n initialDocumentId,\n );\n return existingStore;\n }\n\n const nextStore = createDocumentStore(\n localId,\n runtime,\n defaultDocumentsPersistence,\n initialDocumentId,\n initialText,\n initialDocumentKind,\n options,\n );\n registerDocumentStore(domainScope, localId, nextStore, initialDocumentId);\n return nextStore;\n}\n\nexport function openDocumentStore(\n domainScope: DomainScope,\n localId: string,\n runtime: DocumentsRuntime,\n initialDocumentId: string | null = null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n options: DocumentStoreOpenOptions = {},\n): DocumentStore {\n const store = getOrCreateDocumentStore(\n domainScope,\n localId,\n runtime,\n initialDocumentId,\n initialText,\n initialDocumentKind,\n options,\n );\n store.updateRuntime(runtime);\n return store;\n}\n"]}
|
|
@@ -11,6 +11,7 @@ import { setReadySnapshot, } from "../state.js";
|
|
|
11
11
|
import { createStoredDocument } from "../storedDocument.js";
|
|
12
12
|
import { logRevalidationScheduled } from "../sync/remoteRevalidationTelemetry.js";
|
|
13
13
|
import { allowDocumentStoreRemoteSync, captureDocumentStoreSyncGeneration, invalidateDocumentStoreRemoteSync, isDocumentStoreSyncGenerationCurrent, markDocumentStoreRemoteSyncPending, } from "../sync/syncGeneration.js";
|
|
14
|
+
import { writeInitialDocumentContent } from "./initialContent.js";
|
|
14
15
|
import { installPersistedAttachments, } from "./initializationAttachments.js";
|
|
15
16
|
import { restoredRemoteTailCoverage, restorePersistedDocumentContent, } from "./initializationHistory.js";
|
|
16
17
|
import { healLocalAttachmentDetachState, recoverDroppedAttachmentSlots, } from "./initializationRecovery.js";
|
|
@@ -19,8 +20,10 @@ async function createInitialDocumentRecord(state, nextDoc) {
|
|
|
19
20
|
if (state.initialText.length > 0) {
|
|
20
21
|
nextDoc.getText("text").update(state.initialText);
|
|
21
22
|
}
|
|
23
|
+
const wroteInitialContent = writeInitialDocumentContent(state, nextDoc);
|
|
22
24
|
const initialDocumentState = readStoredDocumentState(nextDoc, state.runtime.infra.documentProjectors);
|
|
23
|
-
const hasInitialContent =
|
|
25
|
+
const hasInitialContent = wroteInitialContent ||
|
|
26
|
+
state.initialText.length > 0 ||
|
|
24
27
|
state.initialDocumentKind !== DEFAULT_DOCUMENT_KIND;
|
|
25
28
|
const initialUpdate = hasInitialContent
|
|
26
29
|
? createPendingUpdateFields(exportAllUpdates(nextDoc))
|