@vielzeug/ledger 26.11.4 → 26.11.6
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 +6 -2
- package/dist/compose.js +1 -2
- package/dist/errors.js +1 -2
- package/dist/ledger.js +2 -4
- package/dist/ledger.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -19,9 +19,13 @@ let value = 'before';
|
|
|
19
19
|
const ledger = createLedger();
|
|
20
20
|
|
|
21
21
|
await ledger.do({
|
|
22
|
-
apply: () => {
|
|
22
|
+
apply: () => {
|
|
23
|
+
value = 'after';
|
|
24
|
+
},
|
|
23
25
|
label: 'Rename value',
|
|
24
|
-
revert: () => {
|
|
26
|
+
revert: () => {
|
|
27
|
+
value = 'before';
|
|
28
|
+
},
|
|
25
29
|
});
|
|
26
30
|
|
|
27
31
|
await ledger.undo();
|
package/dist/compose.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/compose.ts
|
|
2
2
|
function snapshotCommand(e) {
|
|
3
3
|
let { apply: t, label: n, meta: r, revert: i } = e;
|
|
4
4
|
return {
|
|
@@ -37,7 +37,6 @@ function compose(e, t) {
|
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
//#endregion
|
|
41
40
|
export { compose };
|
|
42
41
|
|
|
43
42
|
//# sourceMappingURL=compose.js.map
|
package/dist/errors.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
// src/errors.ts
|
|
2
2
|
var LedgerError = class extends Error {
|
|
3
3
|
constructor(e, t) {
|
|
4
4
|
super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
|
|
5
5
|
}
|
|
6
6
|
}, LedgerCancelledError = class extends LedgerError {}, LedgerDisposedError = class extends LedgerError {}, LedgerExecutionError = class extends LedgerError {}, LedgerRollbackError = class extends LedgerError {}, LedgerConfigError = class extends LedgerError {};
|
|
7
|
-
//#endregion
|
|
8
7
|
export { LedgerCancelledError, LedgerConfigError, LedgerDisposedError, LedgerError, LedgerExecutionError, LedgerRollbackError };
|
|
9
8
|
|
|
10
9
|
//# sourceMappingURL=errors.js.map
|
package/dist/ledger.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/compose.ts
|
|
2
2
|
function snapshotCommand$1(e) {
|
|
3
3
|
let { apply: t, label: n, meta: r, revert: i } = e;
|
|
4
4
|
return {
|
|
@@ -37,8 +37,7 @@ function compose(e, t) {
|
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
|
|
41
|
-
//#region src/errors.ts
|
|
40
|
+
// src/errors.ts
|
|
42
41
|
var LedgerError = class extends Error {
|
|
43
42
|
constructor(e, t) {
|
|
44
43
|
super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
|
|
@@ -278,7 +277,6 @@ function createLedger(e = {}) {
|
|
|
278
277
|
}
|
|
279
278
|
};
|
|
280
279
|
}
|
|
281
|
-
//#endregion
|
|
282
280
|
export { LedgerCancelledError, LedgerConfigError, LedgerDisposedError, LedgerError, LedgerExecutionError, LedgerRollbackError, compose, createLedger };
|
|
283
281
|
|
|
284
282
|
//# sourceMappingURL=ledger.js.map
|
package/dist/ledger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.js","names":["snapshotCommand","command","steps","commands","applied","context","error","compensationFailures","compensationError","failures","message","opts","initial","next","listener","state","disposed","method","options","maxHistory","commandStore","disposalController","idleWaiters","operations","queue","update","waiter","operation","abortSignal","externalSignal","current","task","undo","entry","queued","snapshot","callOptions"],"sources":["../src/compose.ts","../src/errors.ts","../src/ledger.ts"],"sourcesContent":["import type { CommandContext, ReversibleCommand } from './types';\n\nfunction snapshotCommand<TMeta>(command: ReversibleCommand<TMeta>): ReversibleCommand<TMeta> {\n const { apply, label, meta, revert } = command;\n\n return { apply, label, meta, revert };\n}\n\n/**\n * Composes reversible commands into one reversible command.\n *\n * `apply` runs each child in order. `revert` runs children in reverse order.\n * A failed child application compensates completed children before rethrowing.\n *\n * @example\n * await ledger.do(compose([\n * { apply: () => { node.x = newX; }, revert: () => { node.x = oldX; } },\n * { apply: () => { node.y = newY; }, revert: () => { node.y = oldY; } },\n * ], 'Move node'));\n */\nexport function compose<TMeta = undefined>(\n commands: readonly ReversibleCommand<TMeta>[],\n label?: string,\n): ReversibleCommand<TMeta> {\n const steps = commands.map(snapshotCommand);\n\n return {\n apply: async (context: CommandContext) => {\n const applied: ReversibleCommand<TMeta>[] = [];\n\n try {\n for (const command of steps) {\n await command.apply(context);\n applied.push(command);\n }\n } catch (error) {\n const compensationFailures: unknown[] = [];\n\n for (const command of [...applied].reverse()) {\n try {\n await command.revert(context);\n } catch (compensationError) {\n compensationFailures.push(compensationError);\n }\n }\n\n if (compensationFailures.length > 0) {\n throw new AggregateError([error, ...compensationFailures], 'Command application and compensation failed', {\n cause: error,\n });\n }\n\n throw error;\n }\n },\n label,\n revert: async (context: CommandContext) => {\n const failures: unknown[] = [];\n\n for (const command of [...steps].reverse()) {\n try {\n await command.revert(context);\n } catch (error) {\n failures.push(error);\n }\n }\n\n if (failures.length > 0) throw new AggregateError(failures, 'Command reversion failed');\n },\n };\n}\n","/** Base class for all ledger errors. Use `instanceof LedgerError` to catch any ledger-originated error. */\nexport class LedgerError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a queued operation is cancelled before user code starts, or an active operation cooperatively stops. */\nexport class LedgerCancelledError extends LedgerError {}\n\n/** Thrown when a method is called on a disposed ledger instance. */\nexport class LedgerDisposedError extends LedgerError {}\n\n/** Thrown when a command's `apply()` function throws. The original error is available via `.cause`. */\nexport class LedgerExecutionError extends LedgerError {}\n\n/** Thrown when a command's `revert()` function throws during an undo operation. The original error is available via `.cause`. */\nexport class LedgerRollbackError extends LedgerError {}\n\n/** Thrown when the ledger is constructed with invalid options. */\nexport class LedgerConfigError extends LedgerError {}\n","import {\n LedgerCancelledError,\n LedgerConfigError,\n LedgerDisposedError,\n LedgerError,\n LedgerExecutionError,\n LedgerRollbackError,\n} from './errors';\nimport type {\n CommandContext,\n HistoryEntry,\n Ledger,\n LedgerCallOptions,\n LedgerOptions,\n LedgerState,\n ReversibleCommand,\n Subscribable,\n Unsubscribe,\n} from './types';\n\ntype StoredCommand<TMeta> = {\n apply: (context: CommandContext) => Promise<void> | void;\n entry: HistoryEntry<TMeta>;\n revert: (context: CommandContext) => Promise<void> | void;\n};\n\ntype Operation = {\n cancel: () => void;\n reject: (reason?: unknown) => void;\n resolve: () => void;\n settled: boolean;\n start: () => Promise<void>;\n started: boolean;\n};\n\nclass StateStore<T> implements Subscribable<T> {\n private current: T;\n private readonly listeners = new Set<() => void>();\n\n constructor(initial: T) {\n this.current = initial;\n }\n\n getSnapshot(): T {\n return this.current;\n }\n\n set(next: T): void {\n this.current = next;\n\n for (const listener of [...this.listeners]) {\n try {\n listener();\n } catch (error) {\n queueMicrotask(() => {\n throw error;\n });\n }\n }\n }\n\n subscribe(listener: () => void): Unsubscribe {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n}\n\nfunction toMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction snapshotCommand<TMeta>(command: ReversibleCommand<TMeta>): StoredCommand<TMeta> {\n const { apply, label, meta, revert } = command;\n\n return { apply, entry: Object.freeze({ label, meta }), revert };\n}\n\nfunction snapshotState<TMeta>(state: LedgerState<TMeta>): LedgerState<TMeta> {\n return Object.freeze({\n ...state,\n redo: Object.freeze([...state.redo]),\n undo: Object.freeze([...state.undo]),\n });\n}\n\nfunction operationError(method: string, disposed: boolean): LedgerCancelledError | LedgerDisposedError {\n return disposed\n ? new LedgerDisposedError(`Cannot call ${method}() on a disposed ledger.`)\n : new LedgerCancelledError(`${method}() was cancelled before it started.`);\n}\n\n/**\n * Creates a serialized history of reversible commands.\n *\n * Commands are snapshotted when submitted. Queued commands cancelled before their queue turn do\n * not invoke user code. Active commands receive an abort signal and stop cooperatively.\n *\n * @example\n * const ledger = createLedger({ maxHistory: 50 });\n * await ledger.do({\n * apply: () => { item.name = next; },\n * revert: () => { item.name = previous; },\n * });\n * await ledger.undo();\n * await ledger.redo();\n * using ledger = createLedger();\n */\nexport function createLedger<TMeta = undefined>(options: LedgerOptions = {}): Ledger<TMeta> {\n const { maxHistory = 100 } = options;\n\n if (!Number.isSafeInteger(maxHistory) || maxHistory < 0) {\n throw new LedgerConfigError('maxHistory must be a non-negative safe integer');\n }\n\n const state = new StateStore<LedgerState<TMeta>>(snapshotState({ queued: 0, redo: [], running: 0, undo: [] }));\n const commandStore = new WeakMap<HistoryEntry<TMeta>, StoredCommand<TMeta>>();\n const disposalController = new AbortController();\n const idleWaiters = new Set<{ readonly reject: (reason?: unknown) => void; readonly resolve: () => void }>();\n const operations = new Set<Operation>();\n let disposed = false;\n let queue = Promise.resolve();\n\n function updateState(update: (current: LedgerState<TMeta>) => LedgerState<TMeta>): void {\n state.set(snapshotState(update(state.getSnapshot())));\n\n if (state.getSnapshot().queued === 0 && state.getSnapshot().running === 0) {\n for (const waiter of idleWaiters) waiter.resolve();\n idleWaiters.clear();\n }\n }\n\n function settle(operation: Operation, error?: unknown): void {\n if (operation.settled) return;\n\n operation.settled = true;\n operations.delete(operation);\n operation.cancel();\n\n if (error === undefined) operation.resolve();\n else operation.reject(error);\n }\n\n function enqueue(\n method: string,\n externalSignal: AbortSignal | undefined,\n task: (context: CommandContext) => Promise<void>,\n ): Promise<void> {\n if (disposed) return Promise.reject(operationError(method, true));\n\n const abortSignal = externalSignal\n ? AbortSignal.any([externalSignal, disposalController.signal])\n : disposalController.signal;\n\n return new Promise<void>((resolve, reject) => {\n const onAbort = (): void => {\n if (operation.started || operation.settled || disposed) return;\n\n updateState((current) => ({ ...current, queued: current.queued - 1 }));\n settle(operation, operationError(method, false));\n };\n\n const operation: Operation = {\n cancel: () => abortSignal.removeEventListener('abort', onAbort),\n reject,\n resolve,\n settled: false,\n start: async () => {\n if (operation.settled) return;\n\n if (disposed || abortSignal.aborted) {\n updateState((current) => ({ ...current, queued: current.queued - 1 }));\n settle(operation, operationError(method, disposed));\n\n return;\n }\n\n operation.started = true;\n updateState((current) => ({ ...current, queued: current.queued - 1, running: current.running + 1 }));\n\n try {\n await task({ signal: abortSignal });\n settle(operation);\n } catch (error) {\n settle(operation, error);\n } finally {\n updateState((current) => ({ ...current, running: current.running - 1 }));\n }\n },\n started: false,\n };\n\n abortSignal.addEventListener('abort', onAbort, { once: true });\n operations.add(operation);\n updateState((current) => ({ ...current, queued: current.queued + 1 }));\n queue = queue.then(operation.start, operation.start);\n });\n }\n\n async function runDo(command: StoredCommand<TMeta>, context: CommandContext): Promise<void> {\n try {\n await command.apply(context);\n } catch (error) {\n throw context.signal.aborted\n ? new LedgerCancelledError('do() was cancelled while running.', { cause: error })\n : new LedgerExecutionError(toMessage(error), { cause: error });\n }\n\n if (disposed || context.signal.aborted) {\n throw new LedgerCancelledError('do() was cancelled while running.');\n }\n\n updateState((current) => {\n if (maxHistory === 0) return { ...current, redo: [] };\n\n const undo = [...current.undo, command.entry];\n\n if (undo.length > maxHistory) undo.shift();\n\n return { ...current, redo: [], undo };\n });\n commandStore.set(command.entry, command);\n }\n\n async function runUndo(context: CommandContext): Promise<void> {\n const entry = state.getSnapshot().undo[state.getSnapshot().undo.length - 1];\n\n if (!entry) return;\n\n const command = commandStore.get(entry);\n\n if (!command) throw new LedgerError('Undo history is corrupted.');\n\n try {\n await command.revert(context);\n } catch (error) {\n throw context.signal.aborted\n ? new LedgerCancelledError('undo() was cancelled while running.', { cause: error })\n : new LedgerRollbackError(toMessage(error), { cause: error });\n }\n\n if (disposed || context.signal.aborted) {\n throw new LedgerCancelledError('undo() was cancelled while running.');\n }\n\n updateState((current) => ({ ...current, redo: [...current.redo, entry], undo: current.undo.slice(0, -1) }));\n }\n\n async function runRedo(context: CommandContext): Promise<void> {\n const entry = state.getSnapshot().redo[state.getSnapshot().redo.length - 1];\n\n if (!entry) return;\n\n const command = commandStore.get(entry);\n\n if (!command) throw new LedgerError('Redo history is corrupted.');\n\n try {\n await command.apply(context);\n } catch (error) {\n throw context.signal.aborted\n ? new LedgerCancelledError('redo() was cancelled while running.', { cause: error })\n : new LedgerExecutionError(toMessage(error), { cause: error });\n }\n\n if (disposed || context.signal.aborted) {\n throw new LedgerCancelledError('redo() was cancelled while running.');\n }\n\n updateState((current) => ({ ...current, redo: current.redo.slice(0, -1), undo: [...current.undo, entry] }));\n }\n\n return {\n clear(): Promise<void> {\n if (state.getSnapshot().undo.length === 0 && state.getSnapshot().redo.length === 0) {\n return disposed ? Promise.reject(operationError('clear', true)) : Promise.resolve();\n }\n\n return enqueue('clear', undefined, async () => {\n updateState((current) => ({ ...current, redo: [], undo: [] }));\n });\n },\n\n get disposalSignal(): AbortSignal {\n return disposalController.signal;\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n disposalController.abort();\n\n const queued = [...operations].filter((operation) => !operation.started);\n\n for (const operation of queued) settle(operation, operationError('operation', true));\n\n for (const waiter of idleWaiters) waiter.reject(operationError('whenIdle', true));\n idleWaiters.clear();\n\n updateState((current) => ({ ...current, queued: 0, redo: [], undo: [] }));\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n do(command: ReversibleCommand<TMeta>, callOptions?: LedgerCallOptions): Promise<void> {\n const snapshot = snapshotCommand(command);\n\n return enqueue('do', callOptions?.signal, (context) => runDo(snapshot, context));\n },\n\n record(command: ReversibleCommand<TMeta>): void {\n if (disposed) throw new LedgerDisposedError('Cannot call record() on a disposed ledger.');\n\n const snapshot = snapshotCommand(command);\n updateState((current) => {\n if (maxHistory === 0) return { ...current, redo: [] };\n\n const undo = [...current.undo, snapshot.entry];\n\n if (undo.length > maxHistory) undo.shift();\n\n return { ...current, redo: [], undo };\n });\n commandStore.set(snapshot.entry, snapshot);\n },\n\n redo(callOptions?: LedgerCallOptions): Promise<void> {\n return enqueue('redo', callOptions?.signal, runRedo);\n },\n\n get state() {\n return state;\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n\n undo(callOptions?: LedgerCallOptions): Promise<void> {\n return enqueue('undo', callOptions?.signal, runUndo);\n },\n\n whenIdle(): Promise<void> {\n if (state.getSnapshot().queued === 0 && state.getSnapshot().running === 0) {\n return disposed ? Promise.reject(operationError('whenIdle', true)) : Promise.resolve();\n }\n\n return new Promise<void>((resolve, reject) => idleWaiters.add({ reject, resolve }));\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ledger.js","names":["snapshotCommand","command","steps","commands","applied","context","error","compensationFailures","compensationError","failures","message","opts","initial","next","listener","state","disposed","method","options","maxHistory","commandStore","disposalController","idleWaiters","operations","queue","update","waiter","operation","abortSignal","externalSignal","current","task","undo","entry","queued","snapshot","callOptions"],"sources":["../src/compose.ts","../src/errors.ts","../src/ledger.ts"],"sourcesContent":["import type { CommandContext, ReversibleCommand } from './types';\n\nfunction snapshotCommand<TMeta>(command: ReversibleCommand<TMeta>): ReversibleCommand<TMeta> {\n const { apply, label, meta, revert } = command;\n\n return { apply, label, meta, revert };\n}\n\n/**\n * Composes reversible commands into one reversible command.\n *\n * `apply` runs each child in order. `revert` runs children in reverse order.\n * A failed child application compensates completed children before rethrowing.\n *\n * @example\n * await ledger.do(compose([\n * { apply: () => { node.x = newX; }, revert: () => { node.x = oldX; } },\n * { apply: () => { node.y = newY; }, revert: () => { node.y = oldY; } },\n * ], 'Move node'));\n */\nexport function compose<TMeta = undefined>(\n commands: readonly ReversibleCommand<TMeta>[],\n label?: string,\n): ReversibleCommand<TMeta> {\n const steps = commands.map(snapshotCommand);\n\n return {\n apply: async (context: CommandContext) => {\n const applied: ReversibleCommand<TMeta>[] = [];\n\n try {\n for (const command of steps) {\n await command.apply(context);\n applied.push(command);\n }\n } catch (error) {\n const compensationFailures: unknown[] = [];\n\n for (const command of [...applied].reverse()) {\n try {\n await command.revert(context);\n } catch (compensationError) {\n compensationFailures.push(compensationError);\n }\n }\n\n if (compensationFailures.length > 0) {\n throw new AggregateError([error, ...compensationFailures], 'Command application and compensation failed', {\n cause: error,\n });\n }\n\n throw error;\n }\n },\n label,\n revert: async (context: CommandContext) => {\n const failures: unknown[] = [];\n\n for (const command of [...steps].reverse()) {\n try {\n await command.revert(context);\n } catch (error) {\n failures.push(error);\n }\n }\n\n if (failures.length > 0) throw new AggregateError(failures, 'Command reversion failed');\n },\n };\n}\n","/** Base class for all ledger errors. Use `instanceof LedgerError` to catch any ledger-originated error. */\nexport class LedgerError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a queued operation is cancelled before user code starts, or an active operation cooperatively stops. */\nexport class LedgerCancelledError extends LedgerError {}\n\n/** Thrown when a method is called on a disposed ledger instance. */\nexport class LedgerDisposedError extends LedgerError {}\n\n/** Thrown when a command's `apply()` function throws. The original error is available via `.cause`. */\nexport class LedgerExecutionError extends LedgerError {}\n\n/** Thrown when a command's `revert()` function throws during an undo operation. The original error is available via `.cause`. */\nexport class LedgerRollbackError extends LedgerError {}\n\n/** Thrown when the ledger is constructed with invalid options. */\nexport class LedgerConfigError extends LedgerError {}\n","import {\n LedgerCancelledError,\n LedgerConfigError,\n LedgerDisposedError,\n LedgerError,\n LedgerExecutionError,\n LedgerRollbackError,\n} from './errors';\nimport type {\n CommandContext,\n HistoryEntry,\n Ledger,\n LedgerCallOptions,\n LedgerOptions,\n LedgerState,\n ReversibleCommand,\n Subscribable,\n Unsubscribe,\n} from './types';\n\ntype StoredCommand<TMeta> = {\n apply: (context: CommandContext) => Promise<void> | void;\n entry: HistoryEntry<TMeta>;\n revert: (context: CommandContext) => Promise<void> | void;\n};\n\ntype Operation = {\n cancel: () => void;\n reject: (reason?: unknown) => void;\n resolve: () => void;\n settled: boolean;\n start: () => Promise<void>;\n started: boolean;\n};\n\nclass StateStore<T> implements Subscribable<T> {\n private current: T;\n private readonly listeners = new Set<() => void>();\n\n constructor(initial: T) {\n this.current = initial;\n }\n\n getSnapshot(): T {\n return this.current;\n }\n\n set(next: T): void {\n this.current = next;\n\n for (const listener of [...this.listeners]) {\n try {\n listener();\n } catch (error) {\n queueMicrotask(() => {\n throw error;\n });\n }\n }\n }\n\n subscribe(listener: () => void): Unsubscribe {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n}\n\nfunction toMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction snapshotCommand<TMeta>(command: ReversibleCommand<TMeta>): StoredCommand<TMeta> {\n const { apply, label, meta, revert } = command;\n\n return { apply, entry: Object.freeze({ label, meta }), revert };\n}\n\nfunction snapshotState<TMeta>(state: LedgerState<TMeta>): LedgerState<TMeta> {\n return Object.freeze({\n ...state,\n redo: Object.freeze([...state.redo]),\n undo: Object.freeze([...state.undo]),\n });\n}\n\nfunction operationError(method: string, disposed: boolean): LedgerCancelledError | LedgerDisposedError {\n return disposed\n ? new LedgerDisposedError(`Cannot call ${method}() on a disposed ledger.`)\n : new LedgerCancelledError(`${method}() was cancelled before it started.`);\n}\n\n/**\n * Creates a serialized history of reversible commands.\n *\n * Commands are snapshotted when submitted. Queued commands cancelled before their queue turn do\n * not invoke user code. Active commands receive an abort signal and stop cooperatively.\n *\n * @example\n * const ledger = createLedger({ maxHistory: 50 });\n * await ledger.do({\n * apply: () => { item.name = next; },\n * revert: () => { item.name = previous; },\n * });\n * await ledger.undo();\n * await ledger.redo();\n * using ledger = createLedger();\n */\nexport function createLedger<TMeta = undefined>(options: LedgerOptions = {}): Ledger<TMeta> {\n const { maxHistory = 100 } = options;\n\n if (!Number.isSafeInteger(maxHistory) || maxHistory < 0) {\n throw new LedgerConfigError('maxHistory must be a non-negative safe integer');\n }\n\n const state = new StateStore<LedgerState<TMeta>>(snapshotState({ queued: 0, redo: [], running: 0, undo: [] }));\n const commandStore = new WeakMap<HistoryEntry<TMeta>, StoredCommand<TMeta>>();\n const disposalController = new AbortController();\n const idleWaiters = new Set<{ readonly reject: (reason?: unknown) => void; readonly resolve: () => void }>();\n const operations = new Set<Operation>();\n let disposed = false;\n let queue = Promise.resolve();\n\n function updateState(update: (current: LedgerState<TMeta>) => LedgerState<TMeta>): void {\n state.set(snapshotState(update(state.getSnapshot())));\n\n if (state.getSnapshot().queued === 0 && state.getSnapshot().running === 0) {\n for (const waiter of idleWaiters) waiter.resolve();\n idleWaiters.clear();\n }\n }\n\n function settle(operation: Operation, error?: unknown): void {\n if (operation.settled) return;\n\n operation.settled = true;\n operations.delete(operation);\n operation.cancel();\n\n if (error === undefined) operation.resolve();\n else operation.reject(error);\n }\n\n function enqueue(\n method: string,\n externalSignal: AbortSignal | undefined,\n task: (context: CommandContext) => Promise<void>,\n ): Promise<void> {\n if (disposed) return Promise.reject(operationError(method, true));\n\n const abortSignal = externalSignal\n ? AbortSignal.any([externalSignal, disposalController.signal])\n : disposalController.signal;\n\n return new Promise<void>((resolve, reject) => {\n const onAbort = (): void => {\n if (operation.started || operation.settled || disposed) return;\n\n updateState((current) => ({ ...current, queued: current.queued - 1 }));\n settle(operation, operationError(method, false));\n };\n\n const operation: Operation = {\n cancel: () => abortSignal.removeEventListener('abort', onAbort),\n reject,\n resolve,\n settled: false,\n start: async () => {\n if (operation.settled) return;\n\n if (disposed || abortSignal.aborted) {\n updateState((current) => ({ ...current, queued: current.queued - 1 }));\n settle(operation, operationError(method, disposed));\n\n return;\n }\n\n operation.started = true;\n updateState((current) => ({ ...current, queued: current.queued - 1, running: current.running + 1 }));\n\n try {\n await task({ signal: abortSignal });\n settle(operation);\n } catch (error) {\n settle(operation, error);\n } finally {\n updateState((current) => ({ ...current, running: current.running - 1 }));\n }\n },\n started: false,\n };\n\n abortSignal.addEventListener('abort', onAbort, { once: true });\n operations.add(operation);\n updateState((current) => ({ ...current, queued: current.queued + 1 }));\n queue = queue.then(operation.start, operation.start);\n });\n }\n\n async function runDo(command: StoredCommand<TMeta>, context: CommandContext): Promise<void> {\n try {\n await command.apply(context);\n } catch (error) {\n throw context.signal.aborted\n ? new LedgerCancelledError('do() was cancelled while running.', { cause: error })\n : new LedgerExecutionError(toMessage(error), { cause: error });\n }\n\n if (disposed || context.signal.aborted) {\n throw new LedgerCancelledError('do() was cancelled while running.');\n }\n\n updateState((current) => {\n if (maxHistory === 0) return { ...current, redo: [] };\n\n const undo = [...current.undo, command.entry];\n\n if (undo.length > maxHistory) undo.shift();\n\n return { ...current, redo: [], undo };\n });\n commandStore.set(command.entry, command);\n }\n\n async function runUndo(context: CommandContext): Promise<void> {\n const entry = state.getSnapshot().undo[state.getSnapshot().undo.length - 1];\n\n if (!entry) return;\n\n const command = commandStore.get(entry);\n\n if (!command) throw new LedgerError('Undo history is corrupted.');\n\n try {\n await command.revert(context);\n } catch (error) {\n throw context.signal.aborted\n ? new LedgerCancelledError('undo() was cancelled while running.', { cause: error })\n : new LedgerRollbackError(toMessage(error), { cause: error });\n }\n\n if (disposed || context.signal.aborted) {\n throw new LedgerCancelledError('undo() was cancelled while running.');\n }\n\n updateState((current) => ({ ...current, redo: [...current.redo, entry], undo: current.undo.slice(0, -1) }));\n }\n\n async function runRedo(context: CommandContext): Promise<void> {\n const entry = state.getSnapshot().redo[state.getSnapshot().redo.length - 1];\n\n if (!entry) return;\n\n const command = commandStore.get(entry);\n\n if (!command) throw new LedgerError('Redo history is corrupted.');\n\n try {\n await command.apply(context);\n } catch (error) {\n throw context.signal.aborted\n ? new LedgerCancelledError('redo() was cancelled while running.', { cause: error })\n : new LedgerExecutionError(toMessage(error), { cause: error });\n }\n\n if (disposed || context.signal.aborted) {\n throw new LedgerCancelledError('redo() was cancelled while running.');\n }\n\n updateState((current) => ({ ...current, redo: current.redo.slice(0, -1), undo: [...current.undo, entry] }));\n }\n\n return {\n clear(): Promise<void> {\n if (state.getSnapshot().undo.length === 0 && state.getSnapshot().redo.length === 0) {\n return disposed ? Promise.reject(operationError('clear', true)) : Promise.resolve();\n }\n\n return enqueue('clear', undefined, async () => {\n updateState((current) => ({ ...current, redo: [], undo: [] }));\n });\n },\n\n get disposalSignal(): AbortSignal {\n return disposalController.signal;\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n disposalController.abort();\n\n const queued = [...operations].filter((operation) => !operation.started);\n\n for (const operation of queued) settle(operation, operationError('operation', true));\n\n for (const waiter of idleWaiters) waiter.reject(operationError('whenIdle', true));\n idleWaiters.clear();\n\n updateState((current) => ({ ...current, queued: 0, redo: [], undo: [] }));\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n do(command: ReversibleCommand<TMeta>, callOptions?: LedgerCallOptions): Promise<void> {\n const snapshot = snapshotCommand(command);\n\n return enqueue('do', callOptions?.signal, (context) => runDo(snapshot, context));\n },\n\n record(command: ReversibleCommand<TMeta>): void {\n if (disposed) throw new LedgerDisposedError('Cannot call record() on a disposed ledger.');\n\n const snapshot = snapshotCommand(command);\n updateState((current) => {\n if (maxHistory === 0) return { ...current, redo: [] };\n\n const undo = [...current.undo, snapshot.entry];\n\n if (undo.length > maxHistory) undo.shift();\n\n return { ...current, redo: [], undo };\n });\n commandStore.set(snapshot.entry, snapshot);\n },\n\n redo(callOptions?: LedgerCallOptions): Promise<void> {\n return enqueue('redo', callOptions?.signal, runRedo);\n },\n\n get state() {\n return state;\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n\n undo(callOptions?: LedgerCallOptions): Promise<void> {\n return enqueue('undo', callOptions?.signal, runUndo);\n },\n\n whenIdle(): Promise<void> {\n if (state.getSnapshot().queued === 0 && state.getSnapshot().running === 0) {\n return disposed ? Promise.reject(operationError('whenIdle', true)) : Promise.resolve();\n }\n\n return new Promise<void>((resolve, reject) => idleWaiters.add({ reject, resolve }));\n },\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/ledger",
|
|
3
|
-
"version": "26.11.
|
|
3
|
+
"version": "26.11.6",
|
|
4
4
|
"description": "Serialized reversible command history with atomic framework-neutral state and cancellation ownership",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,18 +31,18 @@
|
|
|
31
31
|
"registry": "https://registry.npmjs.org/"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
|
-
"build": "vite build &&
|
|
34
|
+
"build": "vite build && bun run --silent build:bundle && bun run --silent build:types",
|
|
35
35
|
"build:bundle": "vite build --config vite.bundle.config.ts",
|
|
36
36
|
"build:types": "tsc -p tsconfig.declarations.json",
|
|
37
37
|
"fix": "biome check --write src",
|
|
38
38
|
"lint": "biome ci src",
|
|
39
|
-
"prepublishOnly": "
|
|
39
|
+
"prepublishOnly": "bun run --silent build",
|
|
40
40
|
"test": "vitest"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@types/node": "^26.6.
|
|
43
|
+
"@types/node": "^26.6.6",
|
|
44
44
|
"typescript": "^6.0.3",
|
|
45
|
-
"vite": "^8.3.
|
|
46
|
-
"vitest": "^5.0
|
|
45
|
+
"vite": "^8.3.6",
|
|
46
|
+
"vitest": "^5.1.0"
|
|
47
47
|
}
|
|
48
48
|
}
|