fabricjs-document-engine 1.0.0 → 1.0.1

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.
@@ -167,12 +167,16 @@ function createDocumentEngine(options) {
167
167
  if (!storage || discardUnsavedChanges || !saving.state().isDirty) return;
168
168
  throw new require_errors.DocumentEngineError("UNSAVED_CHANGES", "The current document has unsaved changes. Save first, or pass { discardUnsavedChanges: true } to replace it anyway.");
169
169
  }
170
- async function loadMigratedDocument(input, loadOptions, importDetails) {
171
- ensureUsable();
172
- protectUnsavedChanges(loadOptions.discardUnsavedChanges);
170
+ function startLoad() {
173
171
  activeLoad?.abort();
174
172
  const controller = new AbortController();
175
173
  activeLoad = controller;
174
+ return controller;
175
+ }
176
+ async function loadMigratedDocument(input, loadOptions, importDetails, startedLoad) {
177
+ ensureUsable();
178
+ protectUnsavedChanges(loadOptions.discardUnsavedChanges);
179
+ const controller = startedLoad ?? startLoad();
176
180
  const documentId = describeDocumentId(input);
177
181
  events.emit("load:start", { documentId });
178
182
  try {
@@ -318,16 +322,24 @@ function createDocumentEngine(options) {
318
322
  ensureUsable();
319
323
  const source = requireStorage();
320
324
  protectUnsavedChanges(loadOptions?.discardUnsavedChanges);
325
+ const controller = startLoad();
321
326
  let stored;
322
327
  try {
323
328
  stored = await source.loadDocument(documentId);
329
+ if (controller.signal.aborted) throw new Error("aborted");
324
330
  } catch (error) {
331
+ if (activeLoad === controller) activeLoad = null;
332
+ if (controller.signal.aborted) {
333
+ const aborted = toLoadError(error, controller.signal);
334
+ events.emit("load:error", { error: aborted });
335
+ throw aborted;
336
+ }
325
337
  const reason = error instanceof Error ? error.message : String(error);
326
338
  const engineError = require_errors.isDocumentEngineError(error) ? error : new require_errors.DocumentEngineError("LOAD_FAILED", `Storage could not load "${documentId}": ${reason}`, { cause: error });
327
339
  events.emit("load:error", { error: engineError });
328
340
  throw engineError;
329
341
  }
330
- return loadMigratedDocument(stored, loadOptions ?? {}, { id: documentId });
342
+ return loadMigratedDocument(stored, loadOptions ?? {}, { id: documentId }, controller);
331
343
  }
332
344
  function save(saveOptions) {
333
345
  try {
@@ -335,6 +347,7 @@ function createDocumentEngine(options) {
335
347
  } catch (error) {
336
348
  return Promise.reject(error);
337
349
  }
350
+ history.flush();
338
351
  return saving.save(saveOptions);
339
352
  }
340
353
  function newDocument(newOptions = {}) {
@@ -495,7 +508,8 @@ function createDocumentEngine(options) {
495
508
  }
496
509
  function destroy() {
497
510
  if (destroyed) return;
498
- if (recovery && saving.state().isDirty) recovery.writeNow();
511
+ const { disposed } = canvas;
512
+ if (recovery && saving.state().isDirty && !disposed) recovery.writeNow();
499
513
  destroyed = true;
500
514
  activeLoad?.abort();
501
515
  history.destroy();
@@ -569,6 +583,7 @@ function createDocumentEngine(options) {
569
583
  getHistory: () => history.labels(),
570
584
  clearHistory() {
571
585
  ensureUsable();
586
+ history.flush();
572
587
  history.reset();
573
588
  },
574
589
  on: (name, handler) => events.on(name, handler),
@@ -167,12 +167,16 @@ function createDocumentEngine(options) {
167
167
  if (!storage || discardUnsavedChanges || !saving.state().isDirty) return;
168
168
  throw new DocumentEngineError("UNSAVED_CHANGES", "The current document has unsaved changes. Save first, or pass { discardUnsavedChanges: true } to replace it anyway.");
169
169
  }
170
- async function loadMigratedDocument(input, loadOptions, importDetails) {
171
- ensureUsable();
172
- protectUnsavedChanges(loadOptions.discardUnsavedChanges);
170
+ function startLoad() {
173
171
  activeLoad?.abort();
174
172
  const controller = new AbortController();
175
173
  activeLoad = controller;
174
+ return controller;
175
+ }
176
+ async function loadMigratedDocument(input, loadOptions, importDetails, startedLoad) {
177
+ ensureUsable();
178
+ protectUnsavedChanges(loadOptions.discardUnsavedChanges);
179
+ const controller = startedLoad ?? startLoad();
176
180
  const documentId = describeDocumentId(input);
177
181
  events.emit("load:start", { documentId });
178
182
  try {
@@ -318,16 +322,24 @@ function createDocumentEngine(options) {
318
322
  ensureUsable();
319
323
  const source = requireStorage();
320
324
  protectUnsavedChanges(loadOptions?.discardUnsavedChanges);
325
+ const controller = startLoad();
321
326
  let stored;
322
327
  try {
323
328
  stored = await source.loadDocument(documentId);
329
+ if (controller.signal.aborted) throw new Error("aborted");
324
330
  } catch (error) {
331
+ if (activeLoad === controller) activeLoad = null;
332
+ if (controller.signal.aborted) {
333
+ const aborted = toLoadError(error, controller.signal);
334
+ events.emit("load:error", { error: aborted });
335
+ throw aborted;
336
+ }
325
337
  const reason = error instanceof Error ? error.message : String(error);
326
338
  const engineError = isDocumentEngineError(error) ? error : new DocumentEngineError("LOAD_FAILED", `Storage could not load "${documentId}": ${reason}`, { cause: error });
327
339
  events.emit("load:error", { error: engineError });
328
340
  throw engineError;
329
341
  }
330
- return loadMigratedDocument(stored, loadOptions ?? {}, { id: documentId });
342
+ return loadMigratedDocument(stored, loadOptions ?? {}, { id: documentId }, controller);
331
343
  }
332
344
  function save(saveOptions) {
333
345
  try {
@@ -335,6 +347,7 @@ function createDocumentEngine(options) {
335
347
  } catch (error) {
336
348
  return Promise.reject(error);
337
349
  }
350
+ history.flush();
338
351
  return saving.save(saveOptions);
339
352
  }
340
353
  function newDocument(newOptions = {}) {
@@ -495,7 +508,8 @@ function createDocumentEngine(options) {
495
508
  }
496
509
  function destroy() {
497
510
  if (destroyed) return;
498
- if (recovery && saving.state().isDirty) recovery.writeNow();
511
+ const { disposed } = canvas;
512
+ if (recovery && saving.state().isDirty && !disposed) recovery.writeNow();
499
513
  destroyed = true;
500
514
  activeLoad?.abort();
501
515
  history.destroy();
@@ -569,6 +583,7 @@ function createDocumentEngine(options) {
569
583
  getHistory: () => history.labels(),
570
584
  clearHistory() {
571
585
  ensureUsable();
586
+ history.flush();
572
587
  history.reset();
573
588
  },
574
589
  on: (name, handler) => events.on(name, handler),
@@ -178,6 +178,7 @@ function createHistory(options) {
178
178
  redo: stack.redoLabels()
179
179
  }),
180
180
  withoutRecording,
181
+ flush: commitPendingChanges,
181
182
  reset() {
182
183
  pendingChanges = [];
183
184
  stack.clear();
@@ -178,6 +178,7 @@ function createHistory(options) {
178
178
  redo: stack.redoLabels()
179
179
  }),
180
180
  withoutRecording,
181
+ flush: commitPendingChanges,
181
182
  reset() {
182
183
  pendingChanges = [];
183
184
  stack.clear();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fabricjs-document-engine",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Turn an existing Fabric.js canvas into a dependable editable document: stable object ids, versioned save and load, undo and redo, safe autosave with conflict protection, custom objects and clear errors.",
5
5
  "keywords": [
6
6
  "fabric",