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.mjs CHANGED
@@ -227,14 +227,22 @@ var isEqual = (x, y) => {
227
227
  return x !== x && y !== y;
228
228
  };
229
229
  var isUnsafeKey = (key) => key === "__proto__" || key === "prototype" || key === "constructor";
230
+ var setOwnEnumerable = (target, key, value) => {
231
+ if (typeof key === "string" && isUnsafeKey(key)) {
232
+ return;
233
+ }
234
+ target[key] = value;
235
+ };
230
236
  var assignOwnEnumerable = (target, source) => {
231
237
  for (const key of Object.keys(source)) {
232
- if (isUnsafeKey(key)) {
233
- continue;
234
- }
235
- target[key] = source[key];
238
+ setOwnEnumerable(target, key, source[key]);
236
239
  }
237
240
  };
241
+ var cloneOwnEnumerable = (source) => {
242
+ const target = {};
243
+ assignOwnEnumerable(target, source);
244
+ return target;
245
+ };
238
246
  var areShallowEqualWithArray = (prev, next) => {
239
247
  if (prev === null || next === null || prev.length !== next.length) {
240
248
  return false;
@@ -326,80 +334,101 @@ var createClientAction = ({
326
334
  });
327
335
  };
328
336
  }
329
- const keys = sliceKey ? [sliceKey, key] : [key];
330
- return store.transport.emit("execute", keys, args).then(async (response) => {
331
- const result = Array.isArray(response) ? response[0] : response;
332
- const sequence = Array.isArray(response) ? typeof response[1] === "number" ? response[1] : internal.sequence : internal.sequence;
333
- if (internal.sequence < sequence) {
334
- if (process.env.NODE_ENV === "development") {
335
- console.warn(
336
- `The sequence of the action is not consistent.`,
337
- sequence,
338
- internal.sequence
337
+ const traceAction = (run) => {
338
+ try {
339
+ const result = run();
340
+ if (result instanceof Promise) {
341
+ return result.then(
342
+ (value) => {
343
+ done?.(value);
344
+ return value;
345
+ },
346
+ (error) => {
347
+ done?.(error);
348
+ throw error;
349
+ }
339
350
  );
340
351
  }
341
- await new Promise((resolve, reject) => {
342
- let settled = false;
343
- let unsubscribe = () => {
344
- };
345
- const timeoutRef = {};
346
- const cleanup = () => {
347
- unsubscribe();
348
- if (typeof timeoutRef.current !== "undefined") {
349
- clearTimeout(timeoutRef.current);
350
- }
351
- };
352
- const finishResolve = () => {
353
- if (settled) return;
354
- settled = true;
355
- cleanup();
356
- resolve();
357
- };
358
- const finishReject = (error) => {
359
- if (settled) return;
360
- settled = true;
361
- cleanup();
362
- reject(error);
363
- };
364
- unsubscribe = store.subscribe(() => {
365
- if (internal.sequence >= sequence) {
366
- finishResolve();
367
- }
368
- });
369
- timeoutRef.current = setTimeout(() => {
370
- void store.transport.emit("fullSync").then((latest) => {
371
- const next = latest;
372
- if (typeof next.state !== "string" || typeof next.sequence !== "number") {
373
- throw new Error("Invalid fullSync payload");
352
+ done?.(result);
353
+ return result;
354
+ } catch (error) {
355
+ done?.(error);
356
+ throw error;
357
+ }
358
+ };
359
+ const keys = sliceKey ? [sliceKey, key] : [key];
360
+ return traceAction(
361
+ () => store.transport.emit("execute", keys, args).then(async (response) => {
362
+ const result = Array.isArray(response) ? response[0] : response;
363
+ const sequence = Array.isArray(response) ? typeof response[1] === "number" ? response[1] : internal.sequence : internal.sequence;
364
+ if (internal.sequence < sequence) {
365
+ if (process.env.NODE_ENV === "development") {
366
+ console.warn(
367
+ `The sequence of the action is not consistent.`,
368
+ sequence,
369
+ internal.sequence
370
+ );
371
+ }
372
+ await new Promise((resolve, reject) => {
373
+ let settled = false;
374
+ let unsubscribe = () => {
375
+ };
376
+ const timeoutRef = {};
377
+ const cleanup = () => {
378
+ unsubscribe();
379
+ if (typeof timeoutRef.current !== "undefined") {
380
+ clearTimeout(timeoutRef.current);
374
381
  }
375
- store.apply(JSON.parse(next.state));
376
- internal.sequence = next.sequence;
382
+ };
383
+ const finishResolve = () => {
384
+ if (settled) return;
385
+ settled = true;
386
+ cleanup();
387
+ resolve();
388
+ };
389
+ const finishReject = (error) => {
390
+ if (settled) return;
391
+ settled = true;
392
+ cleanup();
393
+ reject(error);
394
+ };
395
+ unsubscribe = store.subscribe(() => {
377
396
  if (internal.sequence >= sequence) {
378
397
  finishResolve();
379
- return;
380
398
  }
381
- finishReject(
382
- new Error(
383
- `Stale fullSync sequence: expected >= ${sequence}, got ${internal.sequence}`
384
- )
385
- );
386
- }).catch((error) => {
387
- finishReject(error);
388
399
  });
389
- }, clientExecuteSyncTimeoutMs);
390
- });
391
- }
392
- if (isTransportErrorEnvelope(result)) {
393
- done?.(result);
394
- throw new Error(result.message);
395
- }
396
- if (isLegacyTransportErrorEnvelope(result)) {
397
- done?.(result);
398
- throw new Error(result.$$Error);
399
- }
400
- done?.(result);
401
- return result;
402
- });
400
+ timeoutRef.current = setTimeout(() => {
401
+ void store.transport.emit("fullSync").then((latest) => {
402
+ const next = latest;
403
+ if (typeof next.state !== "string" || typeof next.sequence !== "number") {
404
+ throw new Error("Invalid fullSync payload");
405
+ }
406
+ if (next.sequence >= sequence) {
407
+ store.apply(JSON.parse(next.state));
408
+ internal.sequence = next.sequence;
409
+ finishResolve();
410
+ return;
411
+ }
412
+ finishReject(
413
+ new Error(
414
+ `Stale fullSync sequence: expected >= ${sequence}, got ${next.sequence}`
415
+ )
416
+ );
417
+ }).catch((error) => {
418
+ finishReject(error);
419
+ });
420
+ }, clientExecuteSyncTimeoutMs);
421
+ });
422
+ }
423
+ if (isTransportErrorEnvelope(result)) {
424
+ throw new Error(result.message);
425
+ }
426
+ if (isLegacyTransportErrorEnvelope(result)) {
427
+ throw new Error(result.$$Error);
428
+ }
429
+ return result;
430
+ })
431
+ );
403
432
  };
404
433
  };
405
434
 
@@ -430,71 +459,94 @@ var createLocalAction = ({
430
459
  id: actionId,
431
460
  sliceKey
432
461
  });
433
- done = (result2) => {
462
+ done = (result) => {
434
463
  store.trace({
435
464
  method: key,
436
465
  id: actionId,
437
- result: result2,
466
+ result,
438
467
  sliceKey
439
468
  });
440
469
  };
441
470
  }
442
- const enablePatches = store.transport ?? options.enablePatches;
443
- if (internal.mutableInstance && !internal.isBatching && enablePatches) {
444
- let result2;
445
- const handleResult = (isDrafted2) => {
446
- handleDraft(store, internal);
447
- if (isDrafted2) {
448
- internal.backupState = internal.rootState;
449
- const [draft2, finalize2] = createWithMutative(internal.rootState, {
450
- enablePatches: true
451
- });
452
- internal.finalizeDraft = finalize2;
453
- internal.rootState = draft2;
471
+ const traceAction = (run) => {
472
+ try {
473
+ const result = run();
474
+ if (result instanceof Promise) {
475
+ return result.then(
476
+ (value) => {
477
+ done?.(value);
478
+ return value;
479
+ },
480
+ (error) => {
481
+ done?.(error);
482
+ throw error;
483
+ }
484
+ );
454
485
  }
455
- };
456
- const isDrafted = isDraft(internal.rootState);
457
- if (isDrafted) {
458
- handleResult();
486
+ done?.(result);
487
+ return result;
488
+ } catch (error) {
489
+ done?.(error);
490
+ throw error;
459
491
  }
460
- internal.backupState = internal.rootState;
461
- const [draft, finalize] = createWithMutative(internal.rootState, {
462
- enablePatches: true
463
- });
464
- internal.finalizeDraft = finalize;
465
- internal.rootState = draft;
466
- let asyncResult;
467
- try {
468
- result2 = fn.apply(getActionTarget(store, sliceKey), args);
469
- if (result2 instanceof Promise) {
470
- asyncResult = result2;
492
+ };
493
+ const enablePatches = store.transport ?? options.enablePatches;
494
+ return traceAction(() => {
495
+ if (internal.mutableInstance && !internal.isBatching && enablePatches) {
496
+ let result;
497
+ const handleResult = (isDrafted2) => {
498
+ handleDraft(store, internal);
499
+ if (isDrafted2) {
500
+ internal.backupState = internal.rootState;
501
+ const [draft2, finalize2] = createWithMutative(internal.rootState, {
502
+ enablePatches: true
503
+ });
504
+ internal.finalizeDraft = finalize2;
505
+ internal.rootState = draft2;
506
+ }
507
+ };
508
+ const isDrafted = isDraft(internal.rootState);
509
+ if (isDrafted) {
510
+ handleResult();
511
+ }
512
+ internal.backupState = internal.rootState;
513
+ const [draft, finalize] = createWithMutative(internal.rootState, {
514
+ enablePatches: true
515
+ });
516
+ internal.finalizeDraft = finalize;
517
+ internal.rootState = draft;
518
+ let asyncResult;
519
+ try {
520
+ result = fn.apply(getActionTarget(store, sliceKey), args);
521
+ if (result instanceof Promise) {
522
+ asyncResult = result;
523
+ }
524
+ } finally {
525
+ if (!asyncResult) {
526
+ handleResult(isDrafted);
527
+ }
471
528
  }
472
- } finally {
473
529
  if (asyncResult) {
474
- } else {
475
- handleResult(isDrafted);
530
+ return asyncResult.then(
531
+ (value) => {
532
+ handleResult(isDrafted);
533
+ return value;
534
+ },
535
+ (error) => {
536
+ handleResult(isDrafted);
537
+ throw error;
538
+ }
539
+ );
476
540
  }
541
+ return result;
477
542
  }
478
- if (asyncResult) {
479
- return asyncResult.finally(() => {
480
- const result3 = handleResult(isDrafted);
481
- done?.(result3);
482
- return result3;
543
+ if (internal.mutableInstance && internal.actMutable) {
544
+ return internal.actMutable(() => {
545
+ return fn.apply(getActionTarget(store, sliceKey), args);
483
546
  });
484
547
  }
485
- done?.(result2);
486
- return result2;
487
- }
488
- if (internal.mutableInstance && internal.actMutable) {
489
- const result2 = internal.actMutable(() => {
490
- return fn.apply(getActionTarget(store, sliceKey), args);
491
- });
492
- done?.(result2);
493
- return result2;
494
- }
495
- const result = fn.apply(getActionTarget(store, sliceKey), args);
496
- done?.(result);
497
- return result;
548
+ return fn.apply(getActionTarget(store, sliceKey), args);
549
+ });
498
550
  };
499
551
  };
500
552
 
@@ -549,7 +601,7 @@ var prepareStateDescriptor = ({
549
601
  enumerable: true
550
602
  });
551
603
  } else if (!isComputed) {
552
- rawState[key] = descriptor.value;
604
+ setOwnEnumerable(rawState, key, descriptor.value);
553
605
  }
554
606
  if (isComputed) {
555
607
  if (internal.mutableInstance) {
@@ -604,8 +656,19 @@ var getRawState = (store, internal, initialState, options) => {
604
656
  const rawState = {};
605
657
  const handle = (_rawState, _initialState, sliceKey) => {
606
658
  internal.mutableInstance = internal.toMutableRaw?.(_initialState);
659
+ const safeDescriptors = {};
607
660
  const descriptors = Object.getOwnPropertyDescriptors(_initialState);
608
- Object.entries(descriptors).forEach(([key, descriptor]) => {
661
+ Reflect.ownKeys(descriptors).forEach((key) => {
662
+ if (typeof key === "string" && isUnsafeKey(key)) {
663
+ return;
664
+ }
665
+ safeDescriptors[key] = Reflect.get(descriptors, key);
666
+ });
667
+ Reflect.ownKeys(safeDescriptors).forEach((key) => {
668
+ const descriptor = safeDescriptors[key];
669
+ if (typeof descriptor === "undefined") {
670
+ return;
671
+ }
609
672
  if (Object.prototype.hasOwnProperty.call(descriptor, "value")) {
610
673
  if (typeof descriptor.value !== "function") {
611
674
  prepareStateDescriptor({
@@ -615,7 +678,12 @@ var getRawState = (store, internal, initialState, options) => {
615
678
  rawState: _rawState,
616
679
  sliceKey
617
680
  });
618
- } else if (store.share === "client") {
681
+ return;
682
+ }
683
+ if (typeof key !== "string") {
684
+ return;
685
+ }
686
+ if (store.share === "client") {
619
687
  descriptor.value = createClientAction({
620
688
  clientExecuteSyncTimeoutMs,
621
689
  internal,
@@ -635,14 +703,22 @@ var getRawState = (store, internal, initialState, options) => {
635
703
  }
636
704
  }
637
705
  });
638
- const slice = Object.defineProperties({}, descriptors);
706
+ const slice = Object.defineProperties({}, safeDescriptors);
639
707
  return slice;
640
708
  };
641
709
  if (store.isSliceStore) {
642
710
  internal.module = {};
643
711
  Object.entries(initialState).forEach(([key, value]) => {
644
- rawState[key] = {};
645
- internal.module[key] = handle(rawState[key], value, key);
712
+ if (isUnsafeKey(key)) {
713
+ return;
714
+ }
715
+ const sliceRawState = {};
716
+ setOwnEnumerable(rawState, key, sliceRawState);
717
+ setOwnEnumerable(
718
+ internal.module,
719
+ key,
720
+ handle(sliceRawState, value, key)
721
+ );
646
722
  });
647
723
  } else {
648
724
  internal.module = handle(rawState, initialState);
@@ -704,13 +780,6 @@ var handleState = (store, internal, options) => {
704
780
  const finalPatches = store.patch ? store.patch({ patches, inversePatches }) : { patches, inversePatches };
705
781
  if (finalPatches.patches.length) {
706
782
  store.apply(internal.rootState, finalPatches.patches);
707
- if (!internal.mutableInstance) {
708
- if (internal.updateImmutable) {
709
- internal.updateImmutable(internal.rootState);
710
- } else {
711
- internal.listeners.forEach((listener) => listener());
712
- }
713
- }
714
783
  }
715
784
  return [
716
785
  internal.rootState,
@@ -726,6 +795,9 @@ var handleState = (store, internal, options) => {
726
795
  if (internal.isBatching) {
727
796
  throw new Error("setState cannot be called within the updater");
728
797
  }
798
+ if (next === null) {
799
+ return [];
800
+ }
729
801
  internal.isBatching = true;
730
802
  if (!store.share && !options.enablePatches && !internal.mutableInstance) {
731
803
  if (typeof next === "function") {
@@ -744,13 +816,28 @@ var handleState = (store, internal, options) => {
744
816
  throw error;
745
817
  }
746
818
  } else {
747
- const copy = {};
748
- const rootState = internal.rootState;
749
- for (const key of Object.keys(rootState)) {
750
- copy[key] = rootState[key];
751
- }
752
- for (const key of Object.keys(next)) {
753
- copy[key] = next[key];
819
+ const copy = cloneOwnEnumerable(internal.rootState);
820
+ if (store.isSliceStore) {
821
+ for (const key of Object.keys(next)) {
822
+ if (!Object.prototype.hasOwnProperty.call(copy, key)) {
823
+ continue;
824
+ }
825
+ const sourceValue = next[key];
826
+ if (typeof sourceValue !== "object" || sourceValue === null) {
827
+ continue;
828
+ }
829
+ const targetValue = copy[key];
830
+ if (typeof targetValue !== "object" || targetValue === null) {
831
+ continue;
832
+ }
833
+ const sliceCopy = cloneOwnEnumerable(
834
+ targetValue
835
+ );
836
+ mergeObject(sliceCopy, sourceValue);
837
+ setOwnEnumerable(copy, key, sliceCopy);
838
+ }
839
+ } else {
840
+ mergeObject(copy, next);
754
841
  }
755
842
  internal.rootState = copy;
756
843
  }
@@ -878,23 +965,55 @@ var handleMainTransport = (store, internal, storeTransport, workerType, checkEna
878
965
  // src/create.ts
879
966
  var namespaceMap = /* @__PURE__ */ new Map();
880
967
  var hasWarnedAmbiguousFunctionMap = false;
968
+ var isMainWorkerType = (workerType) => workerType === "SharedWorkerInternal" || workerType === "WebWorkerInternal";
969
+ var isClientWorkerType = (workerType) => workerType === "SharedWorkerClient" || workerType === "WebWorkerClient";
970
+ var validateCreateModeOptions = (options) => {
971
+ const storeTransport = options.transport;
972
+ const clientTransport = options.clientTransport;
973
+ const worker = options.worker;
974
+ const explicitWorkerType = options.workerType;
975
+ if (storeTransport && clientTransport) {
976
+ throw new Error(
977
+ "transport and clientTransport cannot be used together, please use one authority model per store."
978
+ );
979
+ }
980
+ if (storeTransport && worker) {
981
+ throw new Error(
982
+ "transport and worker cannot be used together, please use one authority model per store."
983
+ );
984
+ }
985
+ if (clientTransport && worker) {
986
+ throw new Error(
987
+ "clientTransport and worker cannot be used together, please use one client transport source."
988
+ );
989
+ }
990
+ if (isMainWorkerType(explicitWorkerType) && (clientTransport || worker)) {
991
+ throw new Error(
992
+ "main workerType cannot be combined with client transport settings."
993
+ );
994
+ }
995
+ if (isClientWorkerType(explicitWorkerType) && storeTransport) {
996
+ throw new Error("client workerType cannot be combined with transport.");
997
+ }
998
+ };
881
999
  var warnAmbiguousFunctionMap = () => {
882
1000
  if (hasWarnedAmbiguousFunctionMap || process.env.NODE_ENV === "production" || process.env.NODE_ENV === "test") {
883
1001
  return;
884
1002
  }
885
1003
  hasWarnedAmbiguousFunctionMap = true;
886
1004
  console.warn(
887
- `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.`
1005
+ [
1006
+ `sliceMode: 'auto' inferred slices from an object of functions.`,
1007
+ `This shape is ambiguous with a single store that only contains methods.`,
1008
+ `Use create({ ping() {} }, { sliceMode: 'single' }) for a plain method store,`,
1009
+ `or create({ counter: (set) => ({ count: 0 }) }, { sliceMode: 'slices' }) for slices.`
1010
+ ].join(" ")
888
1011
  );
889
1012
  };
890
1013
  var create = (createState, options = {}) => {
891
1014
  const checkEnablePatches = Object.hasOwnProperty.call(options, "enablePatches") && !options.enablePatches;
1015
+ validateCreateModeOptions(options);
892
1016
  const workerType = options.workerType ?? WorkerType;
893
- if (process.env.NODE_ENV === "development" && options.transport && options.clientTransport) {
894
- throw new Error(
895
- `transport and clientTransport cannot be used together, please use one of them.`
896
- );
897
- }
898
1017
  const storeTransport = options.transport;
899
1018
  const share = workerType === "WebWorkerInternal" || workerType === "SharedWorkerInternal" || storeTransport ? "main" : void 0;
900
1019
  const createStore = ({ share: share2 }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coaction",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "A sleek JavaScript library designed for high-performance and multithreading web apps.",
5
5
  "keywords": [
6
6
  "coaction"