coaction 1.4.0 → 1.5.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/dist/index.js CHANGED
@@ -255,14 +255,22 @@ var isEqual = (x, y) => {
255
255
  return x !== x && y !== y;
256
256
  };
257
257
  var isUnsafeKey = (key) => key === "__proto__" || key === "prototype" || key === "constructor";
258
+ var setOwnEnumerable = (target, key, value) => {
259
+ if (typeof key === "string" && isUnsafeKey(key)) {
260
+ return;
261
+ }
262
+ target[key] = value;
263
+ };
258
264
  var assignOwnEnumerable = (target, source) => {
259
265
  for (const key of Object.keys(source)) {
260
- if (isUnsafeKey(key)) {
261
- continue;
262
- }
263
- target[key] = source[key];
266
+ setOwnEnumerable(target, key, source[key]);
264
267
  }
265
268
  };
269
+ var cloneOwnEnumerable = (source) => {
270
+ const target = {};
271
+ assignOwnEnumerable(target, source);
272
+ return target;
273
+ };
266
274
  var areShallowEqualWithArray = (prev, next) => {
267
275
  if (prev === null || next === null || prev.length !== next.length) {
268
276
  return false;
@@ -354,80 +362,101 @@ var createClientAction = ({
354
362
  });
355
363
  };
356
364
  }
357
- const keys = sliceKey ? [sliceKey, key] : [key];
358
- return store.transport.emit("execute", keys, args).then(async (response) => {
359
- const result = Array.isArray(response) ? response[0] : response;
360
- const sequence = Array.isArray(response) ? typeof response[1] === "number" ? response[1] : internal.sequence : internal.sequence;
361
- if (internal.sequence < sequence) {
362
- if (process.env.NODE_ENV === "development") {
363
- console.warn(
364
- `The sequence of the action is not consistent.`,
365
- sequence,
366
- internal.sequence
365
+ const traceAction = (run) => {
366
+ try {
367
+ const result = run();
368
+ if (result instanceof Promise) {
369
+ return result.then(
370
+ (value) => {
371
+ done?.(value);
372
+ return value;
373
+ },
374
+ (error) => {
375
+ done?.(error);
376
+ throw error;
377
+ }
367
378
  );
368
379
  }
369
- await new Promise((resolve, reject) => {
370
- let settled = false;
371
- let unsubscribe = () => {
372
- };
373
- const timeoutRef = {};
374
- const cleanup = () => {
375
- unsubscribe();
376
- if (typeof timeoutRef.current !== "undefined") {
377
- clearTimeout(timeoutRef.current);
378
- }
379
- };
380
- const finishResolve = () => {
381
- if (settled) return;
382
- settled = true;
383
- cleanup();
384
- resolve();
385
- };
386
- const finishReject = (error) => {
387
- if (settled) return;
388
- settled = true;
389
- cleanup();
390
- reject(error);
391
- };
392
- unsubscribe = store.subscribe(() => {
393
- if (internal.sequence >= sequence) {
394
- finishResolve();
395
- }
396
- });
397
- timeoutRef.current = setTimeout(() => {
398
- void store.transport.emit("fullSync").then((latest) => {
399
- const next = latest;
400
- if (typeof next.state !== "string" || typeof next.sequence !== "number") {
401
- throw new Error("Invalid fullSync payload");
380
+ done?.(result);
381
+ return result;
382
+ } catch (error) {
383
+ done?.(error);
384
+ throw error;
385
+ }
386
+ };
387
+ const keys = sliceKey ? [sliceKey, key] : [key];
388
+ return traceAction(
389
+ () => store.transport.emit("execute", keys, args).then(async (response) => {
390
+ const result = Array.isArray(response) ? response[0] : response;
391
+ const sequence = Array.isArray(response) ? typeof response[1] === "number" ? response[1] : internal.sequence : internal.sequence;
392
+ if (internal.sequence < sequence) {
393
+ if (process.env.NODE_ENV === "development") {
394
+ console.warn(
395
+ `The sequence of the action is not consistent.`,
396
+ sequence,
397
+ internal.sequence
398
+ );
399
+ }
400
+ await new Promise((resolve, reject) => {
401
+ let settled = false;
402
+ let unsubscribe = () => {
403
+ };
404
+ const timeoutRef = {};
405
+ const cleanup = () => {
406
+ unsubscribe();
407
+ if (typeof timeoutRef.current !== "undefined") {
408
+ clearTimeout(timeoutRef.current);
402
409
  }
403
- store.apply(JSON.parse(next.state));
404
- internal.sequence = next.sequence;
410
+ };
411
+ const finishResolve = () => {
412
+ if (settled) return;
413
+ settled = true;
414
+ cleanup();
415
+ resolve();
416
+ };
417
+ const finishReject = (error) => {
418
+ if (settled) return;
419
+ settled = true;
420
+ cleanup();
421
+ reject(error);
422
+ };
423
+ unsubscribe = store.subscribe(() => {
405
424
  if (internal.sequence >= sequence) {
406
425
  finishResolve();
407
- return;
408
426
  }
409
- finishReject(
410
- new Error(
411
- `Stale fullSync sequence: expected >= ${sequence}, got ${internal.sequence}`
412
- )
413
- );
414
- }).catch((error) => {
415
- finishReject(error);
416
427
  });
417
- }, clientExecuteSyncTimeoutMs);
418
- });
419
- }
420
- if (isTransportErrorEnvelope(result)) {
421
- done?.(result);
422
- throw new Error(result.message);
423
- }
424
- if (isLegacyTransportErrorEnvelope(result)) {
425
- done?.(result);
426
- throw new Error(result.$$Error);
427
- }
428
- done?.(result);
429
- return result;
430
- });
428
+ timeoutRef.current = setTimeout(() => {
429
+ void store.transport.emit("fullSync").then((latest) => {
430
+ const next = latest;
431
+ if (typeof next.state !== "string" || typeof next.sequence !== "number") {
432
+ throw new Error("Invalid fullSync payload");
433
+ }
434
+ if (next.sequence >= sequence) {
435
+ store.apply(JSON.parse(next.state));
436
+ internal.sequence = next.sequence;
437
+ finishResolve();
438
+ return;
439
+ }
440
+ finishReject(
441
+ new Error(
442
+ `Stale fullSync sequence: expected >= ${sequence}, got ${next.sequence}`
443
+ )
444
+ );
445
+ }).catch((error) => {
446
+ finishReject(error);
447
+ });
448
+ }, clientExecuteSyncTimeoutMs);
449
+ });
450
+ }
451
+ if (isTransportErrorEnvelope(result)) {
452
+ throw new Error(result.message);
453
+ }
454
+ if (isLegacyTransportErrorEnvelope(result)) {
455
+ throw new Error(result.$$Error);
456
+ }
457
+ return result;
458
+ })
459
+ );
431
460
  };
432
461
  };
433
462
 
@@ -455,71 +484,94 @@ var createLocalAction = ({
455
484
  id: actionId,
456
485
  sliceKey
457
486
  });
458
- done = (result2) => {
487
+ done = (result) => {
459
488
  store.trace({
460
489
  method: key,
461
490
  id: actionId,
462
- result: result2,
491
+ result,
463
492
  sliceKey
464
493
  });
465
494
  };
466
495
  }
467
- const enablePatches = store.transport ?? options.enablePatches;
468
- if (internal.mutableInstance && !internal.isBatching && enablePatches) {
469
- let result2;
470
- const handleResult = (isDrafted2) => {
471
- handleDraft(store, internal);
472
- if (isDrafted2) {
473
- internal.backupState = internal.rootState;
474
- const [draft2, finalize2] = (0, import_mutative.create)(internal.rootState, {
475
- enablePatches: true
476
- });
477
- internal.finalizeDraft = finalize2;
478
- internal.rootState = draft2;
496
+ const traceAction = (run) => {
497
+ try {
498
+ const result = run();
499
+ if (result instanceof Promise) {
500
+ return result.then(
501
+ (value) => {
502
+ done?.(value);
503
+ return value;
504
+ },
505
+ (error) => {
506
+ done?.(error);
507
+ throw error;
508
+ }
509
+ );
479
510
  }
480
- };
481
- const isDrafted = (0, import_mutative.isDraft)(internal.rootState);
482
- if (isDrafted) {
483
- handleResult();
511
+ done?.(result);
512
+ return result;
513
+ } catch (error) {
514
+ done?.(error);
515
+ throw error;
484
516
  }
485
- internal.backupState = internal.rootState;
486
- const [draft, finalize] = (0, import_mutative.create)(internal.rootState, {
487
- enablePatches: true
488
- });
489
- internal.finalizeDraft = finalize;
490
- internal.rootState = draft;
491
- let asyncResult;
492
- try {
493
- result2 = fn.apply(getActionTarget(store, sliceKey), args);
494
- if (result2 instanceof Promise) {
495
- asyncResult = result2;
517
+ };
518
+ const enablePatches = store.transport ?? options.enablePatches;
519
+ return traceAction(() => {
520
+ if (internal.mutableInstance && !internal.isBatching && enablePatches) {
521
+ let result;
522
+ const handleResult = (isDrafted2) => {
523
+ handleDraft(store, internal);
524
+ if (isDrafted2) {
525
+ internal.backupState = internal.rootState;
526
+ const [draft2, finalize2] = (0, import_mutative.create)(internal.rootState, {
527
+ enablePatches: true
528
+ });
529
+ internal.finalizeDraft = finalize2;
530
+ internal.rootState = draft2;
531
+ }
532
+ };
533
+ const isDrafted = (0, import_mutative.isDraft)(internal.rootState);
534
+ if (isDrafted) {
535
+ handleResult();
536
+ }
537
+ internal.backupState = internal.rootState;
538
+ const [draft, finalize] = (0, import_mutative.create)(internal.rootState, {
539
+ enablePatches: true
540
+ });
541
+ internal.finalizeDraft = finalize;
542
+ internal.rootState = draft;
543
+ let asyncResult;
544
+ try {
545
+ result = fn.apply(getActionTarget(store, sliceKey), args);
546
+ if (result instanceof Promise) {
547
+ asyncResult = result;
548
+ }
549
+ } finally {
550
+ if (!asyncResult) {
551
+ handleResult(isDrafted);
552
+ }
496
553
  }
497
- } finally {
498
554
  if (asyncResult) {
499
- } else {
500
- handleResult(isDrafted);
555
+ return asyncResult.then(
556
+ (value) => {
557
+ handleResult(isDrafted);
558
+ return value;
559
+ },
560
+ (error) => {
561
+ handleResult(isDrafted);
562
+ throw error;
563
+ }
564
+ );
501
565
  }
566
+ return result;
502
567
  }
503
- if (asyncResult) {
504
- return asyncResult.finally(() => {
505
- const result3 = handleResult(isDrafted);
506
- done?.(result3);
507
- return result3;
568
+ if (internal.mutableInstance && internal.actMutable) {
569
+ return internal.actMutable(() => {
570
+ return fn.apply(getActionTarget(store, sliceKey), args);
508
571
  });
509
572
  }
510
- done?.(result2);
511
- return result2;
512
- }
513
- if (internal.mutableInstance && internal.actMutable) {
514
- const result2 = internal.actMutable(() => {
515
- return fn.apply(getActionTarget(store, sliceKey), args);
516
- });
517
- done?.(result2);
518
- return result2;
519
- }
520
- const result = fn.apply(getActionTarget(store, sliceKey), args);
521
- done?.(result);
522
- return result;
573
+ return fn.apply(getActionTarget(store, sliceKey), args);
574
+ });
523
575
  };
524
576
  };
525
577
 
@@ -574,7 +626,7 @@ var prepareStateDescriptor = ({
574
626
  enumerable: true
575
627
  });
576
628
  } else if (!isComputed) {
577
- rawState[key] = descriptor.value;
629
+ setOwnEnumerable(rawState, key, descriptor.value);
578
630
  }
579
631
  if (isComputed) {
580
632
  if (internal.mutableInstance) {
@@ -629,8 +681,19 @@ var getRawState = (store, internal, initialState, options) => {
629
681
  const rawState = {};
630
682
  const handle = (_rawState, _initialState, sliceKey) => {
631
683
  internal.mutableInstance = internal.toMutableRaw?.(_initialState);
684
+ const safeDescriptors = {};
632
685
  const descriptors = Object.getOwnPropertyDescriptors(_initialState);
633
- Object.entries(descriptors).forEach(([key, descriptor]) => {
686
+ Reflect.ownKeys(descriptors).forEach((key) => {
687
+ if (typeof key === "string" && isUnsafeKey(key)) {
688
+ return;
689
+ }
690
+ safeDescriptors[key] = Reflect.get(descriptors, key);
691
+ });
692
+ Reflect.ownKeys(safeDescriptors).forEach((key) => {
693
+ const descriptor = safeDescriptors[key];
694
+ if (typeof descriptor === "undefined") {
695
+ return;
696
+ }
634
697
  if (Object.prototype.hasOwnProperty.call(descriptor, "value")) {
635
698
  if (typeof descriptor.value !== "function") {
636
699
  prepareStateDescriptor({
@@ -640,7 +703,12 @@ var getRawState = (store, internal, initialState, options) => {
640
703
  rawState: _rawState,
641
704
  sliceKey
642
705
  });
643
- } else if (store.share === "client") {
706
+ return;
707
+ }
708
+ if (typeof key !== "string") {
709
+ return;
710
+ }
711
+ if (store.share === "client") {
644
712
  descriptor.value = createClientAction({
645
713
  clientExecuteSyncTimeoutMs,
646
714
  internal,
@@ -660,14 +728,22 @@ var getRawState = (store, internal, initialState, options) => {
660
728
  }
661
729
  }
662
730
  });
663
- const slice = Object.defineProperties({}, descriptors);
731
+ const slice = Object.defineProperties({}, safeDescriptors);
664
732
  return slice;
665
733
  };
666
734
  if (store.isSliceStore) {
667
735
  internal.module = {};
668
736
  Object.entries(initialState).forEach(([key, value]) => {
669
- rawState[key] = {};
670
- internal.module[key] = handle(rawState[key], value, key);
737
+ if (isUnsafeKey(key)) {
738
+ return;
739
+ }
740
+ const sliceRawState = {};
741
+ setOwnEnumerable(rawState, key, sliceRawState);
742
+ setOwnEnumerable(
743
+ internal.module,
744
+ key,
745
+ handle(sliceRawState, value, key)
746
+ );
671
747
  });
672
748
  } else {
673
749
  internal.module = handle(rawState, initialState);
@@ -726,13 +802,6 @@ var handleState = (store, internal, options) => {
726
802
  const finalPatches = store.patch ? store.patch({ patches, inversePatches }) : { patches, inversePatches };
727
803
  if (finalPatches.patches.length) {
728
804
  store.apply(internal.rootState, finalPatches.patches);
729
- if (!internal.mutableInstance) {
730
- if (internal.updateImmutable) {
731
- internal.updateImmutable(internal.rootState);
732
- } else {
733
- internal.listeners.forEach((listener) => listener());
734
- }
735
- }
736
805
  }
737
806
  return [
738
807
  internal.rootState,
@@ -748,6 +817,9 @@ var handleState = (store, internal, options) => {
748
817
  if (internal.isBatching) {
749
818
  throw new Error("setState cannot be called within the updater");
750
819
  }
820
+ if (next === null) {
821
+ return [];
822
+ }
751
823
  internal.isBatching = true;
752
824
  if (!store.share && !options.enablePatches && !internal.mutableInstance) {
753
825
  if (typeof next === "function") {
@@ -766,13 +838,28 @@ var handleState = (store, internal, options) => {
766
838
  throw error;
767
839
  }
768
840
  } else {
769
- const copy = {};
770
- const rootState = internal.rootState;
771
- for (const key of Object.keys(rootState)) {
772
- copy[key] = rootState[key];
773
- }
774
- for (const key of Object.keys(next)) {
775
- copy[key] = next[key];
841
+ const copy = cloneOwnEnumerable(internal.rootState);
842
+ if (store.isSliceStore) {
843
+ for (const key of Object.keys(next)) {
844
+ if (!Object.prototype.hasOwnProperty.call(copy, key)) {
845
+ continue;
846
+ }
847
+ const sourceValue = next[key];
848
+ if (typeof sourceValue !== "object" || sourceValue === null) {
849
+ continue;
850
+ }
851
+ const targetValue = copy[key];
852
+ if (typeof targetValue !== "object" || targetValue === null) {
853
+ continue;
854
+ }
855
+ const sliceCopy = cloneOwnEnumerable(
856
+ targetValue
857
+ );
858
+ mergeObject(sliceCopy, sourceValue);
859
+ setOwnEnumerable(copy, key, sliceCopy);
860
+ }
861
+ } else {
862
+ mergeObject(copy, next);
776
863
  }
777
864
  internal.rootState = copy;
778
865
  }
@@ -900,23 +987,55 @@ var handleMainTransport = (store, internal, storeTransport, workerType, checkEna
900
987
  // src/create.ts
901
988
  var namespaceMap = /* @__PURE__ */ new Map();
902
989
  var hasWarnedAmbiguousFunctionMap = false;
990
+ var isMainWorkerType = (workerType) => workerType === "SharedWorkerInternal" || workerType === "WebWorkerInternal";
991
+ var isClientWorkerType = (workerType) => workerType === "SharedWorkerClient" || workerType === "WebWorkerClient";
992
+ var validateCreateModeOptions = (options) => {
993
+ const storeTransport = options.transport;
994
+ const clientTransport = options.clientTransport;
995
+ const worker = options.worker;
996
+ const explicitWorkerType = options.workerType;
997
+ if (storeTransport && clientTransport) {
998
+ throw new Error(
999
+ "transport and clientTransport cannot be used together, please use one authority model per store."
1000
+ );
1001
+ }
1002
+ if (storeTransport && worker) {
1003
+ throw new Error(
1004
+ "transport and worker cannot be used together, please use one authority model per store."
1005
+ );
1006
+ }
1007
+ if (clientTransport && worker) {
1008
+ throw new Error(
1009
+ "clientTransport and worker cannot be used together, please use one client transport source."
1010
+ );
1011
+ }
1012
+ if (isMainWorkerType(explicitWorkerType) && (clientTransport || worker)) {
1013
+ throw new Error(
1014
+ "main workerType cannot be combined with client transport settings."
1015
+ );
1016
+ }
1017
+ if (isClientWorkerType(explicitWorkerType) && storeTransport) {
1018
+ throw new Error("client workerType cannot be combined with transport.");
1019
+ }
1020
+ };
903
1021
  var warnAmbiguousFunctionMap = () => {
904
1022
  if (hasWarnedAmbiguousFunctionMap || process.env.NODE_ENV === "production" || process.env.NODE_ENV === "test") {
905
1023
  return;
906
1024
  }
907
1025
  hasWarnedAmbiguousFunctionMap = true;
908
1026
  console.warn(
909
- `sliceMode: 'auto' inferred slices from an object of functions. This shape is ambiguous with a single store that only contains methods. Set sliceMode to 'slices' or 'single' explicitly.`
1027
+ [
1028
+ `sliceMode: 'auto' inferred slices from an object of functions.`,
1029
+ `This shape is ambiguous with a single store that only contains methods.`,
1030
+ `Use create({ ping() {} }, { sliceMode: 'single' }) for a plain method store,`,
1031
+ `or create({ counter: (set) => ({ count: 0 }) }, { sliceMode: 'slices' }) for slices.`
1032
+ ].join(" ")
910
1033
  );
911
1034
  };
912
1035
  var create = (createState, options = {}) => {
913
1036
  const checkEnablePatches = Object.hasOwnProperty.call(options, "enablePatches") && !options.enablePatches;
1037
+ validateCreateModeOptions(options);
914
1038
  const workerType = options.workerType ?? WorkerType;
915
- if (process.env.NODE_ENV === "development" && options.transport && options.clientTransport) {
916
- throw new Error(
917
- `transport and clientTransport cannot be used together, please use one of them.`
918
- );
919
- }
920
1039
  const storeTransport = options.transport;
921
1040
  const share = workerType === "WebWorkerInternal" || workerType === "SharedWorkerInternal" || storeTransport ? "main" : void 0;
922
1041
  const createStore = ({ share: share2 }) => {