@pixerate/editor 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -1
- package/THIRD_PARTY_NOTICES.md +51 -0
- package/dist/agent/index.cjs +9 -8
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +4 -3
- package/dist/agent/index.d.ts +4 -3
- package/dist/agent/index.js +3 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +1210 -17
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +318 -1
- package/dist/canvas/index.d.ts +318 -1
- package/dist/canvas/index.js +1199 -6
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-QBJ22YZR.js → chunk-3CN2WD3X.js} +1354 -206
- package/dist/chunk-3CN2WD3X.js.map +1 -0
- package/dist/{chunk-JJDLPEWL.js → chunk-3LV6RRPH.js} +2 -2
- package/dist/{chunk-MJZBNWG7.js → chunk-5S3Z4PPF.js} +78 -557
- package/dist/chunk-5S3Z4PPF.js.map +1 -0
- package/dist/chunk-664LQYFJ.js +115 -0
- package/dist/chunk-664LQYFJ.js.map +1 -0
- package/dist/{chunk-AA4ZEVCC.cjs → chunk-D27YFC46.cjs} +101 -580
- package/dist/chunk-D27YFC46.cjs.map +1 -0
- package/dist/chunk-D6FH2YAX.cjs +131 -0
- package/dist/chunk-D6FH2YAX.cjs.map +1 -0
- package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
- package/dist/chunk-FD4LPFAE.cjs.map +1 -0
- package/dist/chunk-FODNLX5N.js +749 -0
- package/dist/chunk-FODNLX5N.js.map +1 -0
- package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
- package/dist/chunk-FPENXAEJ.js.map +1 -0
- package/dist/chunk-HLIMTC6N.js +1 -0
- package/dist/chunk-HLIMTC6N.js.map +1 -0
- package/dist/{chunk-QGHGJ56O.js → chunk-ITBSKI26.js} +1483 -19
- package/dist/chunk-ITBSKI26.js.map +1 -0
- package/dist/{chunk-XDMXXC4Z.cjs → chunk-MA2F5KHF.cjs} +350 -227
- package/dist/chunk-MA2F5KHF.cjs.map +1 -0
- package/dist/{chunk-RIKBJLS2.cjs → chunk-MCSJFWAO.cjs} +1356 -208
- package/dist/chunk-MCSJFWAO.cjs.map +1 -0
- package/dist/chunk-MKA3AHLV.cjs +256 -0
- package/dist/chunk-MKA3AHLV.cjs.map +1 -0
- package/dist/chunk-OLZJXL4R.cjs +749 -0
- package/dist/chunk-OLZJXL4R.cjs.map +1 -0
- package/dist/chunk-OXSV64JX.js +689 -0
- package/dist/chunk-OXSV64JX.js.map +1 -0
- package/dist/chunk-P3RQ5UJE.cjs +689 -0
- package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
- package/dist/chunk-P6ODPZ4W.js +256 -0
- package/dist/chunk-P6ODPZ4W.js.map +1 -0
- package/dist/chunk-PGNZKFQS.js +685 -0
- package/dist/chunk-PGNZKFQS.js.map +1 -0
- package/dist/chunk-PL4JB3BF.cjs +1 -0
- package/dist/chunk-PL4JB3BF.cjs.map +1 -0
- package/dist/{chunk-GVSMRPHB.cjs → chunk-SBCZ6RN5.cjs} +1568 -104
- package/dist/chunk-SBCZ6RN5.cjs.map +1 -0
- package/dist/{chunk-CL37JGFW.cjs → chunk-SML64VJG.cjs} +4 -4
- package/dist/{chunk-CL37JGFW.cjs.map → chunk-SML64VJG.cjs.map} +1 -1
- package/dist/chunk-TNNJXF46.cjs +115 -0
- package/dist/chunk-TNNJXF46.cjs.map +1 -0
- package/dist/chunk-U5HZSFCS.js +131 -0
- package/dist/chunk-U5HZSFCS.js.map +1 -0
- package/dist/{chunk-K3R5NG2D.js → chunk-U5KWZU4X.js} +251 -128
- package/dist/chunk-U5KWZU4X.js.map +1 -0
- package/dist/chunk-XNORY7M6.cjs +685 -0
- package/dist/chunk-XNORY7M6.cjs.map +1 -0
- package/dist/commands/index.d.cts +5 -353
- package/dist/commands/index.d.ts +5 -353
- package/dist/comment-store-BEMgVlAA.d.cts +135 -0
- package/dist/comment-store-BEMgVlAA.d.ts +135 -0
- package/dist/compare/index.cjs +15 -0
- package/dist/compare/index.cjs.map +1 -0
- package/dist/compare/index.d.cts +58 -0
- package/dist/compare/index.d.ts +58 -0
- package/dist/compare/index.js +15 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/{controller-pePCJLT1.d.cts → controller-BhLLAoi8.d.cts} +45 -4
- package/dist/{controller-pePCJLT1.d.ts → controller-BhLLAoi8.d.ts} +45 -4
- package/dist/documents-BQjzJNe2.d.ts +76 -0
- package/dist/documents-KRTPhvst.d.cts +76 -0
- package/dist/extensions/index.cjs +53 -5
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +7 -3
- package/dist/extensions/index.d.ts +7 -3
- package/dist/extensions/index.js +52 -4
- package/dist/generation/index.cjs +1373 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +554 -0
- package/dist/generation/index.d.ts +554 -0
- package/dist/generation/index.js +1373 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/grammar/index.cjs +48 -3
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +322 -100
- package/dist/grammar/index.d.ts +322 -100
- package/dist/grammar/index.js +54 -9
- package/dist/image-editor/index.cjs +1831 -30
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +590 -3
- package/dist/image-editor/index.d.ts +590 -3
- package/dist/image-editor/index.js +1807 -6
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{index-CCr_z9kF.d.cts → index-BhJBSm2d.d.cts} +370 -4
- package/dist/{index-Ck6ajwXh.d.ts → index-fJrlkJCd.d.ts} +370 -4
- package/dist/index.cjs +162 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -8
- package/dist/index.d.ts +14 -8
- package/dist/index.js +174 -37
- package/dist/index.js.map +1 -1
- package/dist/migrate-iTlm3a8h.d.cts +112 -0
- package/dist/migrate-iTlm3a8h.d.ts +112 -0
- package/dist/persistence/index.cjs +676 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +347 -0
- package/dist/persistence/index.d.ts +347 -0
- package/dist/persistence/index.js +676 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
- package/dist/registry-D32LpIc4.d.cts +354 -0
- package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
- package/dist/registry-evKTP4ls.d.ts +354 -0
- package/dist/schema-DYDGdYL9.d.cts +41 -0
- package/dist/schema-DYDGdYL9.d.ts +41 -0
- package/dist/serializers/index.cjs +4 -3
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +2 -1
- package/dist/serializers/index.d.ts +2 -1
- package/dist/serializers/index.js +3 -2
- package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
- package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
- package/dist/spreadsheet/index.cjs +37 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +188 -17
- package/dist/spreadsheet/index.d.ts +188 -17
- package/dist/spreadsheet/index.js +43 -9
- package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
- package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
- package/dist/{track-changes-BSF58RK0.d.ts → track-changes-BK5sVf4_.d.cts} +18 -136
- package/dist/{track-changes-BSF58RK0.d.cts → track-changes-CDjCrwKe.d.ts} +18 -136
- package/package.json +16 -1
- package/dist/chunk-4SUNJZWB.cjs.map +0 -1
- package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
- package/dist/chunk-AXV2ZW34.cjs +0 -118
- package/dist/chunk-AXV2ZW34.cjs.map +0 -1
- package/dist/chunk-B2ZRLN4S.js +0 -118
- package/dist/chunk-B2ZRLN4S.js.map +0 -1
- package/dist/chunk-GVSMRPHB.cjs.map +0 -1
- package/dist/chunk-K3R5NG2D.js.map +0 -1
- package/dist/chunk-MJZBNWG7.js.map +0 -1
- package/dist/chunk-OYXSKQFR.js.map +0 -1
- package/dist/chunk-QBJ22YZR.js.map +0 -1
- package/dist/chunk-QGHGJ56O.js.map +0 -1
- package/dist/chunk-RIKBJLS2.cjs.map +0 -1
- package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
- /package/dist/{chunk-JJDLPEWL.js.map → chunk-3LV6RRPH.js.map} +0 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
export { J as JsonObject, L as LoadDocumentOptions, a as LoadDocumentResult, b as LoadReport, c as LoadSectionsOptions, d as LoadSectionsResult, M as MigrateOptions, e as MigrateResult, f as MigrationStep, R as ReadOnlyReason, S as SectionProblem, g as SectionSpec, h as SectionSpecs, i as createLoadReport, j as hasLoadProblems, l as loadDocument, k as loadSections, m as migrateDocument } from '../migrate-iTlm3a8h.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What the caller should do now (see `RecoveryPolicy.tick`).
|
|
5
|
+
*
|
|
6
|
+
* - `writeSnapshot`: write the snapshot and a dirty meta for `revision`, then report with `written`.
|
|
7
|
+
* - `writeClean`: write a clean meta (retire the snapshot), then report with `cleaned`.
|
|
8
|
+
* - `wakeAfter`: nothing now; tick again after `delay` (same unit as `now`).
|
|
9
|
+
*/
|
|
10
|
+
type RecoveryAction = {
|
|
11
|
+
type: "nothing";
|
|
12
|
+
} | {
|
|
13
|
+
type: "writeSnapshot";
|
|
14
|
+
revision: number;
|
|
15
|
+
} | {
|
|
16
|
+
type: "writeClean";
|
|
17
|
+
} | {
|
|
18
|
+
type: "wakeAfter";
|
|
19
|
+
delay: number;
|
|
20
|
+
};
|
|
21
|
+
interface RecoveryPolicyOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Minimum time between snapshots of a changing document, in the unit of `now`
|
|
24
|
+
* (default 5000, i.e. milliseconds).
|
|
25
|
+
*/
|
|
26
|
+
interval?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Wait before retrying after the `failures`-th consecutive failed write
|
|
29
|
+
* (default: `interval`, as in FilmCraft). Use `exponentialBackoff` for doubling delays.
|
|
30
|
+
*/
|
|
31
|
+
retryDelay?: (failures: number) => number;
|
|
32
|
+
}
|
|
33
|
+
interface RecoveryTickOptions {
|
|
34
|
+
/** Ignore the interval and any retry wait (e.g. on `pagehide`). */
|
|
35
|
+
force?: boolean;
|
|
36
|
+
}
|
|
37
|
+
interface RecoveryPolicy {
|
|
38
|
+
/** Called whenever something may have changed, with the revisions and the current time. */
|
|
39
|
+
tick(now: number, revision: number, savedRevision: number, options?: RecoveryTickOptions): RecoveryAction;
|
|
40
|
+
/** The snapshot write for `revision` finished. */
|
|
41
|
+
written(revision: number, ok: boolean, now: number): void;
|
|
42
|
+
/** The clean-meta write finished. */
|
|
43
|
+
cleaned(ok: boolean, now: number): void;
|
|
44
|
+
/** Whether this session wrote a dirty snapshot that is not retired yet. */
|
|
45
|
+
readonly ownsSnapshot: boolean;
|
|
46
|
+
/** Consecutive failed writes (reset by a successful one). */
|
|
47
|
+
readonly failures: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Exponential backoff: `base`, `2·base`, `4·base`, … capped at `max`.
|
|
51
|
+
* `failures` is 1 for the first failure.
|
|
52
|
+
*/
|
|
53
|
+
declare function exponentialBackoff(failures: number, base?: number, max?: number): number;
|
|
54
|
+
/**
|
|
55
|
+
* Pure state machine deciding when a crash-recovery snapshot is written or
|
|
56
|
+
* retired. Deterministic: time is always passed in.
|
|
57
|
+
*
|
|
58
|
+
* - A dirty document is snapshotted at most every `interval`, once per revision.
|
|
59
|
+
* A write that fails is retried after `retryDelay`, without waiting for another edit.
|
|
60
|
+
* - The snapshot is marked clean only if this session wrote it. A snapshot left by an
|
|
61
|
+
* earlier session (that was not restored) stays dirty, so it can still be recovered.
|
|
62
|
+
* - An edit made while the clean write is in flight keeps the snapshot owned.
|
|
63
|
+
*/
|
|
64
|
+
declare function createRecoveryPolicy(options?: RecoveryPolicyOptions): RecoveryPolicy;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Key/value storage adapters for autosave and crash recovery. Every adapter is
|
|
68
|
+
* async, stores strings, feature-detects its backend (an unavailable backend
|
|
69
|
+
* rejects every call with `StorageUnavailableError` instead of throwing at
|
|
70
|
+
* construction, so SSR and old browsers are safe) and accepts an injectable
|
|
71
|
+
* failure mode for tests.
|
|
72
|
+
*/
|
|
73
|
+
type StorageOperation = "get" | "set" | "remove";
|
|
74
|
+
/**
|
|
75
|
+
* Injected failure: return `true` (or an `Error`) to make that operation fail.
|
|
76
|
+
* Example: `failure: (op) => op === "set"` simulates a full disk.
|
|
77
|
+
*/
|
|
78
|
+
type StorageFailureMode = (operation: StorageOperation, key: string) => boolean | Error | undefined | void;
|
|
79
|
+
interface StorageAdapter {
|
|
80
|
+
/** Short backend name, e.g. `"memory"`, `"localStorage"`, `"indexedDB"`, `"opfs"`. */
|
|
81
|
+
readonly kind: string;
|
|
82
|
+
/** Whether the backend was found. When `false`, every call rejects. */
|
|
83
|
+
readonly available: boolean;
|
|
84
|
+
get(key: string): Promise<string | null>;
|
|
85
|
+
set(key: string, value: string): Promise<void>;
|
|
86
|
+
remove(key: string): Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
interface StorageAdapterOptions {
|
|
89
|
+
failure?: StorageFailureMode;
|
|
90
|
+
}
|
|
91
|
+
declare class StorageUnavailableError extends Error {
|
|
92
|
+
constructor(kind: string);
|
|
93
|
+
}
|
|
94
|
+
declare class InjectedStorageError extends Error {
|
|
95
|
+
constructor(operation: StorageOperation, key: string);
|
|
96
|
+
}
|
|
97
|
+
/** Wraps an adapter so `failure` can make any of its operations fail. */
|
|
98
|
+
declare function withStorageFailures(inner: StorageAdapter, failure: StorageFailureMode): StorageAdapter;
|
|
99
|
+
interface MemoryStorage extends StorageAdapter {
|
|
100
|
+
/** The underlying map (inspect it in tests). */
|
|
101
|
+
readonly entries: Map<string, string>;
|
|
102
|
+
}
|
|
103
|
+
/** In-memory storage (tests, SSR, or a session-only fallback). */
|
|
104
|
+
declare function createMemoryStorage(options?: StorageAdapterOptions & {
|
|
105
|
+
initial?: Record<string, string>;
|
|
106
|
+
}): MemoryStorage;
|
|
107
|
+
/** Minimal `Storage` surface used by the localStorage adapter. */
|
|
108
|
+
interface WebStorageLike {
|
|
109
|
+
getItem(key: string): string | null;
|
|
110
|
+
setItem(key: string, value: string): void;
|
|
111
|
+
removeItem(key: string): void;
|
|
112
|
+
}
|
|
113
|
+
interface LocalStorageAdapterOptions extends StorageAdapterOptions {
|
|
114
|
+
/** Storage to use (default `globalThis.localStorage`, e.g. pass `sessionStorage`). */
|
|
115
|
+
storage?: WebStorageLike;
|
|
116
|
+
}
|
|
117
|
+
/** Whether `localStorage` can be used (it throws when site data is blocked). */
|
|
118
|
+
declare function isLocalStorageAvailable(): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* `localStorage` adapter; every key is prefixed with `prefix`. Writes are
|
|
121
|
+
* synchronous under the hood, so they complete even inside `pagehide`.
|
|
122
|
+
* A full quota rejects the `set` (`QuotaExceededError`).
|
|
123
|
+
*/
|
|
124
|
+
declare function createLocalStorageAdapter(prefix?: string, options?: LocalStorageAdapterOptions): StorageAdapter;
|
|
125
|
+
/** Minimal `IDBFactory` surface (the real `indexedDB`, or a fake in tests). */
|
|
126
|
+
interface IdbFactoryLike {
|
|
127
|
+
open(name: string, version?: number): any;
|
|
128
|
+
}
|
|
129
|
+
interface IndexedDbAdapterOptions extends StorageAdapterOptions {
|
|
130
|
+
/** Object store name (default `"kv"`). */
|
|
131
|
+
store?: string;
|
|
132
|
+
/** Factory to use (default `globalThis.indexedDB`). */
|
|
133
|
+
indexedDB?: IdbFactoryLike;
|
|
134
|
+
}
|
|
135
|
+
/** Whether `indexedDB` exists in this environment. */
|
|
136
|
+
declare function isIndexedDbAvailable(): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* IndexedDB adapter: one database `name` with a single key/value object store.
|
|
139
|
+
* A `set` resolves when its transaction completes (not merely when the request
|
|
140
|
+
* succeeds), so a resolved write is durable.
|
|
141
|
+
*/
|
|
142
|
+
declare function createIndexedDbAdapter(name?: string, options?: IndexedDbAdapterOptions): StorageAdapter;
|
|
143
|
+
/** Minimal `FileSystemDirectoryHandle` surface used by the OPFS adapter. */
|
|
144
|
+
interface OpfsDirectoryLike {
|
|
145
|
+
getDirectoryHandle(name: string, options?: {
|
|
146
|
+
create?: boolean;
|
|
147
|
+
}): Promise<OpfsDirectoryLike>;
|
|
148
|
+
getFileHandle(name: string, options?: {
|
|
149
|
+
create?: boolean;
|
|
150
|
+
}): Promise<OpfsFileLike>;
|
|
151
|
+
removeEntry(name: string): Promise<void>;
|
|
152
|
+
}
|
|
153
|
+
interface OpfsFileLike {
|
|
154
|
+
getFile(): Promise<{
|
|
155
|
+
text(): Promise<string>;
|
|
156
|
+
}>;
|
|
157
|
+
createWritable?(): Promise<{
|
|
158
|
+
write(data: string): Promise<void>;
|
|
159
|
+
close(): Promise<void>;
|
|
160
|
+
}>;
|
|
161
|
+
/** Rename in place (Chromium, Safari). Used for temp-file + rename writes. */
|
|
162
|
+
move?(name: string): Promise<void>;
|
|
163
|
+
}
|
|
164
|
+
interface OpfsAdapterOptions extends StorageAdapterOptions {
|
|
165
|
+
/** Root directory (default `navigator.storage.getDirectory()`). */
|
|
166
|
+
root?: () => Promise<OpfsDirectoryLike>;
|
|
167
|
+
/** Force the write-then-pointer-swap strategy even when `move` exists. */
|
|
168
|
+
disableRename?: boolean;
|
|
169
|
+
}
|
|
170
|
+
/** Whether the Origin Private File System exists (`navigator.storage.getDirectory`). */
|
|
171
|
+
declare function isOpfsAvailable(): boolean;
|
|
172
|
+
/**
|
|
173
|
+
* Origin Private File System adapter. Values are files in `dir` (created on
|
|
174
|
+
* demand), named after the URI-encoded key.
|
|
175
|
+
*
|
|
176
|
+
* Writes never leave a half-written value behind: where file handles support
|
|
177
|
+
* `move`, the value is written to `<file>.tmp` and renamed over `<file>`;
|
|
178
|
+
* otherwise it alternates between two slots (`<file>.a` / `<file>.b`) and then
|
|
179
|
+
* swaps a pointer file (`<file>.ptr`), so a crash mid-write keeps the previous
|
|
180
|
+
* value. Main-thread writes need `createWritable` (missing in some Safari
|
|
181
|
+
* versions); without it, `set` rejects with `StorageUnavailableError`.
|
|
182
|
+
*/
|
|
183
|
+
declare function createOpfsAdapter(dir?: string, options?: OpfsAdapterOptions): StorageAdapter;
|
|
184
|
+
|
|
185
|
+
type AutosaveStatus = "idle" | "dirty" | "saving" | "saved" | "error";
|
|
186
|
+
interface AutosaveStatusInfo {
|
|
187
|
+
status: AutosaveStatus;
|
|
188
|
+
/** Last write error (while `status` is `"error"`). */
|
|
189
|
+
error: unknown;
|
|
190
|
+
/** Consecutive failed writes. */
|
|
191
|
+
failures: number;
|
|
192
|
+
/** When the next attempt is due (`now()` units), while waiting. */
|
|
193
|
+
nextAttemptAt: number | null;
|
|
194
|
+
/** When the last snapshot was written (`now()` units). */
|
|
195
|
+
lastSavedAt: number | null;
|
|
196
|
+
/** Whether `ready()` was called. */
|
|
197
|
+
ready: boolean;
|
|
198
|
+
}
|
|
199
|
+
/** Stored next to the snapshot (`<key>:meta`). */
|
|
200
|
+
interface RecoveryMeta {
|
|
201
|
+
dirty: boolean;
|
|
202
|
+
revision?: number;
|
|
203
|
+
/** `Date.now()` of the write. */
|
|
204
|
+
time?: number;
|
|
205
|
+
/** Document name, for the "Restore unsaved changes from …?" prompt. */
|
|
206
|
+
name?: string;
|
|
207
|
+
}
|
|
208
|
+
interface AutosaveRecovery<T = unknown> {
|
|
209
|
+
/** The parsed snapshot (`undefined` when `deserialize` threw; see `error`). */
|
|
210
|
+
snapshot: T | undefined;
|
|
211
|
+
/** The stored text. */
|
|
212
|
+
text: string;
|
|
213
|
+
meta: RecoveryMeta & {
|
|
214
|
+
dirty: true;
|
|
215
|
+
};
|
|
216
|
+
error?: unknown;
|
|
217
|
+
}
|
|
218
|
+
interface AutosaveControllerOptions<T> {
|
|
219
|
+
storage: StorageAdapter;
|
|
220
|
+
/** Snapshot key; the meta lives at `<key>:meta`. */
|
|
221
|
+
key: string;
|
|
222
|
+
/** Reads the current document. */
|
|
223
|
+
getSnapshot: () => T;
|
|
224
|
+
/** Default `JSON.stringify`. */
|
|
225
|
+
serialize?: (snapshot: T) => string;
|
|
226
|
+
/** Default `JSON.parse` (used by `checkRecovery`). */
|
|
227
|
+
deserialize?: (text: string) => T;
|
|
228
|
+
/** Current document revision; must change on every edit. */
|
|
229
|
+
revision: () => number;
|
|
230
|
+
/** Revision of the last explicit save (equal to `revision()` when clean). */
|
|
231
|
+
savedRevision: () => number;
|
|
232
|
+
/** Document name stored in the meta. */
|
|
233
|
+
name?: string | (() => string | undefined);
|
|
234
|
+
onStatus?: (info: AutosaveStatusInfo) => void;
|
|
235
|
+
/** Minimum time between snapshots while edits keep coming (default 5000 ms). */
|
|
236
|
+
interval?: number;
|
|
237
|
+
/** Quiet time after the last edit before a snapshot is written (default 1000 ms). */
|
|
238
|
+
debounceMs?: number;
|
|
239
|
+
/** First retry delay after a failed write; doubles per failure (default 1000 ms). */
|
|
240
|
+
retryBaseMs?: number;
|
|
241
|
+
/** Retry delay cap (default 30000 ms). */
|
|
242
|
+
retryMaxMs?: number;
|
|
243
|
+
/** Clock for scheduling (default `Date.now`). */
|
|
244
|
+
now?: () => number;
|
|
245
|
+
/** Wall clock stored in the meta (default `Date.now`). */
|
|
246
|
+
wallClock?: () => number;
|
|
247
|
+
setTimeout?: (fn: () => void, ms: number) => unknown;
|
|
248
|
+
clearTimeout?: (handle: any) => void;
|
|
249
|
+
/** Start hydrated, i.e. as if `ready()` was already called (default `false`). */
|
|
250
|
+
ready?: boolean;
|
|
251
|
+
}
|
|
252
|
+
interface AutosaveController<T = unknown> {
|
|
253
|
+
/** Current status. */
|
|
254
|
+
getStatus(): AutosaveStatusInfo;
|
|
255
|
+
/** Listener is called on every status change (not immediately). */
|
|
256
|
+
subscribe(listener: (info: AutosaveStatusInfo) => void): () => void;
|
|
257
|
+
/** Call after every change (edit, undo, save). Cheap; the write is scheduled. */
|
|
258
|
+
notify(): void;
|
|
259
|
+
/** Lifts the hydration gate: no snapshot is written before this. */
|
|
260
|
+
ready(): void;
|
|
261
|
+
readonly isReady: boolean;
|
|
262
|
+
/**
|
|
263
|
+
* Writes a snapshot of unsaved changes right away, skipping the debounce, the
|
|
264
|
+
* interval and retry waits. Use on `pagehide` / `visibilitychange`. Resolves
|
|
265
|
+
* once the write settled.
|
|
266
|
+
*/
|
|
267
|
+
flushNow(): Promise<void>;
|
|
268
|
+
/**
|
|
269
|
+
* Call after the document was saved (`savedRevision()` now equals
|
|
270
|
+
* `revision()`): retires the snapshot only if this session wrote it.
|
|
271
|
+
*/
|
|
272
|
+
markClean(): Promise<void>;
|
|
273
|
+
/**
|
|
274
|
+
* A dirty snapshot left by an earlier session, or `null`. Returns `null` once
|
|
275
|
+
* this session has written its own snapshot.
|
|
276
|
+
*/
|
|
277
|
+
checkRecovery(): Promise<AutosaveRecovery<T> | null>;
|
|
278
|
+
/** Deletes an earlier session's snapshot. No-op once this session wrote its own. */
|
|
279
|
+
discardRecovery(): Promise<boolean>;
|
|
280
|
+
/** Runs one scheduling step now (normally driven by `notify` and timers). */
|
|
281
|
+
tick(): void;
|
|
282
|
+
/** Resolves when no write is in flight. */
|
|
283
|
+
whenIdle(): Promise<void>;
|
|
284
|
+
/** Stops all timers. Pending changes are not written; call `flushNow` first. */
|
|
285
|
+
destroy(): void;
|
|
286
|
+
}
|
|
287
|
+
declare const recoveryMetaKey: (key: string) => string;
|
|
288
|
+
/**
|
|
289
|
+
* Text for a recovery prompt: "Restore unsaved changes from <time>?" (the
|
|
290
|
+
* React and Svelte `RecoveryPrompt` components use it).
|
|
291
|
+
*/
|
|
292
|
+
declare function formatRecoveryMessage(meta: Pick<RecoveryMeta, "time">, formatTime?: (time: number) => string): string;
|
|
293
|
+
/**
|
|
294
|
+
* Debounced autosave of crash-recovery snapshots.
|
|
295
|
+
*
|
|
296
|
+
* - Hydration gate: nothing is written until `ready()`, so loading a document
|
|
297
|
+
* (or deciding about a recovered one) never overwrites the previous session's snapshot.
|
|
298
|
+
* - A snapshot is written `debounceMs` after the last edit, and at least every
|
|
299
|
+
* `interval` while edits keep coming; never twice for one revision.
|
|
300
|
+
* - Failed writes are retried with exponential backoff (`retryBaseMs` doubling up to
|
|
301
|
+
* `retryMaxMs`) without waiting for another edit.
|
|
302
|
+
* - The snapshot is written before its dirty meta, so the meta never points at a
|
|
303
|
+
* missing snapshot. Once saved, the meta is marked clean only if this session
|
|
304
|
+
* wrote the snapshot (`createRecoveryPolicy`).
|
|
305
|
+
*/
|
|
306
|
+
declare function createAutosaveController<T>(options: AutosaveControllerOptions<T>): AutosaveController<T>;
|
|
307
|
+
|
|
308
|
+
/** Anything that notifies on every document change (`HistoryManager` satisfies it). */
|
|
309
|
+
interface RevisionChangeSource {
|
|
310
|
+
subscribe(listener: (...args: any[]) => void): () => void;
|
|
311
|
+
}
|
|
312
|
+
/** Anything with a dirty flag (`DirtyTracker` and `HistoryDirtyBinding` satisfy it). */
|
|
313
|
+
interface DirtyFlagSource {
|
|
314
|
+
readonly dirty: boolean;
|
|
315
|
+
subscribe(listener: (dirty: boolean) => void): () => void;
|
|
316
|
+
}
|
|
317
|
+
interface RevisionTrackerOptions {
|
|
318
|
+
/** Change notifications (e.g. a `HistoryManager`). Every notification is a new revision. */
|
|
319
|
+
history?: RevisionChangeSource;
|
|
320
|
+
/**
|
|
321
|
+
* Saved-vs-current flag (e.g. `bindDirtyToHistory(...)` or a `DirtyTracker`).
|
|
322
|
+
* Whenever it reads clean, the current revision counts as saved, so undoing
|
|
323
|
+
* back to the saved state needs no snapshot. Without it, call `markSaved()`.
|
|
324
|
+
*/
|
|
325
|
+
dirty?: DirtyFlagSource;
|
|
326
|
+
}
|
|
327
|
+
interface RevisionTracker {
|
|
328
|
+
/** Bumped on every change. */
|
|
329
|
+
revision(): number;
|
|
330
|
+
/** Revision of the last save; equals `revision()` while clean. */
|
|
331
|
+
savedRevision(): number;
|
|
332
|
+
/** Records a change made outside `history`. */
|
|
333
|
+
bump(): void;
|
|
334
|
+
/** Marks the current revision saved. */
|
|
335
|
+
markSaved(): void;
|
|
336
|
+
/** Called after every change, save or dirty flip. */
|
|
337
|
+
subscribe(listener: () => void): () => void;
|
|
338
|
+
destroy(): void;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Derives the `revision` / `savedRevision` pair an autosave controller needs
|
|
342
|
+
* from a history and a dirty flag (`bindDirtyToHistory` or `DirtyTracker`).
|
|
343
|
+
* Structural types only, so this entry stays dependency-free.
|
|
344
|
+
*/
|
|
345
|
+
declare function createRevisionTracker(options?: RevisionTrackerOptions): RevisionTracker;
|
|
346
|
+
|
|
347
|
+
export { type AutosaveController, type AutosaveControllerOptions, type AutosaveRecovery, type AutosaveStatus, type AutosaveStatusInfo, type DirtyFlagSource, type IdbFactoryLike, type IndexedDbAdapterOptions, InjectedStorageError, type LocalStorageAdapterOptions, type MemoryStorage, type OpfsAdapterOptions, type OpfsDirectoryLike, type OpfsFileLike, type RecoveryAction, type RecoveryMeta, type RecoveryPolicy, type RecoveryPolicyOptions, type RecoveryTickOptions, type RevisionChangeSource, type RevisionTracker, type RevisionTrackerOptions, type StorageAdapter, type StorageAdapterOptions, type StorageFailureMode, type StorageOperation, StorageUnavailableError, type WebStorageLike, createAutosaveController, createIndexedDbAdapter, createLocalStorageAdapter, createMemoryStorage, createOpfsAdapter, createRecoveryPolicy, createRevisionTracker, exponentialBackoff, formatRecoveryMessage, isIndexedDbAvailable, isLocalStorageAvailable, isOpfsAvailable, recoveryMetaKey, withStorageFailures };
|