coaction 1.2.0 → 1.4.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
@@ -53,18 +53,23 @@ var createAsyncClientStore = (createStore, asyncStoreClientOption) => {
53
53
  }
54
54
  asyncClientStore.transport = transport;
55
55
  let syncingPromise = null;
56
- const fullSync = async () => {
56
+ let awaitingReconnectSync = false;
57
+ let reconnectSequenceBaseline = null;
58
+ const fullSync = async (allowLowerSequence = false) => {
57
59
  if (!syncingPromise) {
58
60
  syncingPromise = (async () => {
59
61
  const latest = await transport.emit("fullSync");
60
62
  if (typeof latest.sequence !== "number" || typeof latest.state !== "string") {
61
63
  throw new Error("Invalid fullSync payload");
62
64
  }
63
- if (latest.sequence < internal.sequence) {
65
+ const canApplyLowerSequence = allowLowerSequence && awaitingReconnectSync && reconnectSequenceBaseline !== null && reconnectSequenceBaseline === internal.sequence;
66
+ if (latest.sequence < internal.sequence && !canApplyLowerSequence) {
64
67
  return;
65
68
  }
66
69
  asyncClientStore.apply(JSON.parse(latest.state));
67
70
  internal.sequence = latest.sequence;
71
+ awaitingReconnectSync = false;
72
+ reconnectSequenceBaseline = null;
68
73
  })().finally(() => {
69
74
  syncingPromise = null;
70
75
  });
@@ -75,28 +80,55 @@ var createAsyncClientStore = (createStore, asyncStoreClientOption) => {
75
80
  throw new Error("transport.onConnect is required");
76
81
  }
77
82
  transport.onConnect?.(() => {
78
- void fullSync().catch((error) => {
83
+ awaitingReconnectSync = true;
84
+ reconnectSequenceBaseline = internal.sequence;
85
+ void fullSync(true).catch((error) => {
79
86
  if (process.env.NODE_ENV === "development") {
80
87
  console.error(error);
81
88
  }
82
89
  });
83
90
  });
84
91
  transport.listen("update", async (options) => {
92
+ let shouldFullSync = false;
93
+ let allowLowerSequence = false;
85
94
  try {
86
95
  if (typeof options.sequence !== "number") {
87
- await fullSync();
88
- return;
89
- }
90
- if (options.sequence <= internal.sequence) {
91
- return;
92
- }
93
- if (options.sequence === internal.sequence + 1) {
94
- internal.sequence = options.sequence;
96
+ shouldFullSync = true;
97
+ } else if (options.sequence <= internal.sequence) {
98
+ if (awaitingReconnectSync) {
99
+ shouldFullSync = true;
100
+ allowLowerSequence = true;
101
+ } else if (options.sequence === 0 && internal.sequence > 0) {
102
+ awaitingReconnectSync = true;
103
+ reconnectSequenceBaseline = internal.sequence;
104
+ shouldFullSync = true;
105
+ allowLowerSequence = true;
106
+ } else {
107
+ return;
108
+ }
109
+ } else if (options.sequence === internal.sequence + 1) {
95
110
  asyncClientStore.apply(void 0, options.patches);
111
+ internal.sequence = options.sequence;
112
+ awaitingReconnectSync = false;
113
+ reconnectSequenceBaseline = null;
114
+ return;
96
115
  } else {
97
- await fullSync();
116
+ shouldFullSync = true;
117
+ allowLowerSequence = awaitingReconnectSync;
118
+ }
119
+ if (shouldFullSync) {
120
+ await fullSync(allowLowerSequence);
98
121
  }
99
122
  } catch (error) {
123
+ if (!shouldFullSync) {
124
+ try {
125
+ await fullSync(awaitingReconnectSync);
126
+ } catch (syncError) {
127
+ if (process.env.NODE_ENV === "development") {
128
+ console.error(syncError);
129
+ }
130
+ }
131
+ }
100
132
  if (process.env.NODE_ENV === "development") {
101
133
  console.error(error);
102
134
  }
@@ -187,12 +219,6 @@ var getInitialState = (store, createState, internal) => {
187
219
  ) : makeState(createState);
188
220
  };
189
221
 
190
- // src/getRawState.ts
191
- import {
192
- create as createWithMutative,
193
- isDraft
194
- } from "mutative";
195
-
196
222
  // src/utils.ts
197
223
  var isEqual = (x, y) => {
198
224
  if (x === y) {
@@ -200,6 +226,15 @@ var isEqual = (x, y) => {
200
226
  }
201
227
  return x !== x && y !== y;
202
228
  };
229
+ var isUnsafeKey = (key) => key === "__proto__" || key === "prototype" || key === "constructor";
230
+ var assignOwnEnumerable = (target, source) => {
231
+ for (const key of Object.keys(source)) {
232
+ if (isUnsafeKey(key)) {
233
+ continue;
234
+ }
235
+ target[key] = source[key];
236
+ }
237
+ };
203
238
  var areShallowEqualWithArray = (prev, next) => {
204
239
  if (prev === null || next === null || prev.length !== next.length) {
205
240
  return false;
@@ -216,31 +251,253 @@ var mergeObject = (target, source, isSlice) => {
216
251
  if (isSlice) {
217
252
  if (typeof source === "object" && source !== null) {
218
253
  for (const key of Object.keys(source)) {
254
+ if (isUnsafeKey(key)) {
255
+ continue;
256
+ }
257
+ if (!Object.prototype.hasOwnProperty.call(target, key)) {
258
+ continue;
259
+ }
219
260
  const sourceValue = source[key];
220
261
  if (typeof sourceValue !== "object" || sourceValue === null) {
221
262
  continue;
222
263
  }
223
264
  const targetValue = target[key];
224
265
  if (typeof targetValue === "object" && targetValue !== null) {
225
- Object.assign(targetValue, sourceValue);
266
+ assignOwnEnumerable(targetValue, sourceValue);
226
267
  }
227
268
  }
228
269
  }
229
270
  } else {
230
- Object.assign(target, source);
271
+ if (typeof source === "object" && source !== null) {
272
+ assignOwnEnumerable(target, source);
273
+ }
231
274
  }
232
275
  };
233
276
  var uuid = () => {
234
277
  let timestamp = (/* @__PURE__ */ new Date()).getTime();
235
278
  const uuidTemplate = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
236
279
  const uuid2 = uuidTemplate.replace(/[xy]/g, (char) => {
237
- let randomNum = (timestamp + Math.random() * 16) % 16 | 0;
280
+ const randomNum = (timestamp + Math.random() * 16) % 16 | 0;
238
281
  timestamp = Math.floor(timestamp / 16);
239
282
  return (char === "x" ? randomNum : randomNum & 3 | 8).toString(16);
240
283
  });
241
284
  return uuid2;
242
285
  };
243
286
 
287
+ // src/getRawStateClientAction.ts
288
+ var transportErrorMarker = "__coactionTransportError__";
289
+ var isTransportErrorEnvelope = (value) => {
290
+ if (typeof value !== "object" || value === null) {
291
+ return false;
292
+ }
293
+ return value[transportErrorMarker] === true && typeof value.message === "string";
294
+ };
295
+ var isLegacyTransportErrorEnvelope = (value) => {
296
+ if (typeof value !== "object" || value === null) {
297
+ return false;
298
+ }
299
+ const candidate = value;
300
+ return typeof candidate.$$Error === "string" && candidate.$$Error.length > 0 && Object.keys(candidate).length === 1;
301
+ };
302
+ var createClientAction = ({
303
+ clientExecuteSyncTimeoutMs,
304
+ internal,
305
+ key,
306
+ store,
307
+ sliceKey
308
+ }) => {
309
+ return (...args) => {
310
+ let actionId;
311
+ let done;
312
+ if (store.trace) {
313
+ actionId = uuid();
314
+ store.trace({
315
+ method: key,
316
+ parameters: args,
317
+ id: actionId,
318
+ sliceKey
319
+ });
320
+ done = (result) => {
321
+ store.trace({
322
+ method: key,
323
+ id: actionId,
324
+ result,
325
+ sliceKey
326
+ });
327
+ };
328
+ }
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
339
+ );
340
+ }
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");
374
+ }
375
+ store.apply(JSON.parse(next.state));
376
+ internal.sequence = next.sequence;
377
+ if (internal.sequence >= sequence) {
378
+ finishResolve();
379
+ return;
380
+ }
381
+ finishReject(
382
+ new Error(
383
+ `Stale fullSync sequence: expected >= ${sequence}, got ${internal.sequence}`
384
+ )
385
+ );
386
+ }).catch((error) => {
387
+ finishReject(error);
388
+ });
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
+ });
403
+ };
404
+ };
405
+
406
+ // src/getRawStateLocalAction.ts
407
+ import {
408
+ create as createWithMutative,
409
+ isDraft
410
+ } from "mutative";
411
+ var getActionTarget = (store, sliceKey) => {
412
+ return sliceKey ? store.getState()[sliceKey] : store.getState();
413
+ };
414
+ var createLocalAction = ({
415
+ fn,
416
+ internal,
417
+ key,
418
+ options,
419
+ store,
420
+ sliceKey
421
+ }) => {
422
+ return (...args) => {
423
+ let actionId;
424
+ let done;
425
+ if (store.trace) {
426
+ actionId = uuid();
427
+ store.trace({
428
+ method: key,
429
+ parameters: args,
430
+ id: actionId,
431
+ sliceKey
432
+ });
433
+ done = (result2) => {
434
+ store.trace({
435
+ method: key,
436
+ id: actionId,
437
+ result: result2,
438
+ sliceKey
439
+ });
440
+ };
441
+ }
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;
454
+ }
455
+ };
456
+ const isDrafted = isDraft(internal.rootState);
457
+ if (isDrafted) {
458
+ handleResult();
459
+ }
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;
471
+ }
472
+ } finally {
473
+ if (asyncResult) {
474
+ } else {
475
+ handleResult(isDrafted);
476
+ }
477
+ }
478
+ if (asyncResult) {
479
+ return asyncResult.finally(() => {
480
+ const result3 = handleResult(isDrafted);
481
+ done?.(result3);
482
+ return result3;
483
+ });
484
+ }
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;
498
+ };
499
+ };
500
+
244
501
  // src/computed.ts
245
502
  var Computed = class {
246
503
  constructor(deps, fn) {
@@ -274,23 +531,76 @@ var createSelectorCreatorWithArray = (memoize = defaultMemoize) => {
274
531
  };
275
532
  var createSelectorWithArray = createSelectorCreatorWithArray();
276
533
 
277
- // src/getRawState.ts
278
- var clientExecuteSyncTimeoutMs = 1500;
279
- var transportErrorMarker = "__coactionTransportError__";
280
- var isTransportErrorEnvelope = (value) => {
281
- if (typeof value !== "object" || value === null) {
282
- return false;
534
+ // src/getRawStateStateProperty.ts
535
+ var prepareStateDescriptor = ({
536
+ descriptor,
537
+ internal,
538
+ key,
539
+ rawState,
540
+ sliceKey
541
+ }) => {
542
+ const isComputed = descriptor.value instanceof Computed;
543
+ if (internal.mutableInstance) {
544
+ Object.defineProperty(rawState, key, {
545
+ get: () => internal.mutableInstance[key],
546
+ set: (value) => {
547
+ internal.mutableInstance[key] = value;
548
+ },
549
+ enumerable: true
550
+ });
551
+ } else if (!isComputed) {
552
+ rawState[key] = descriptor.value;
283
553
  }
284
- return value[transportErrorMarker] === true && typeof value.message === "string";
554
+ if (isComputed) {
555
+ if (internal.mutableInstance) {
556
+ throw new Error("Computed is not supported with mutable instance");
557
+ }
558
+ const { deps, fn } = descriptor.value;
559
+ const depsCallbackSelector = createSelectorWithArray(
560
+ // the root state should be updated, and the computed property will be updated.
561
+ () => [internal.rootState],
562
+ () => {
563
+ return deps(internal.module);
564
+ }
565
+ );
566
+ const selector = createSelectorWithArray(
567
+ (that) => depsCallbackSelector.call(that),
568
+ fn
569
+ );
570
+ descriptor.get = function() {
571
+ return selector.call(this);
572
+ };
573
+ } else if (sliceKey) {
574
+ descriptor.get = () => internal.rootState[sliceKey][key];
575
+ descriptor.set = (value) => {
576
+ internal.rootState[sliceKey][key] = value;
577
+ };
578
+ } else {
579
+ descriptor.get = () => internal.rootState[key];
580
+ descriptor.set = (value) => {
581
+ internal.rootState[key] = value;
582
+ };
583
+ }
584
+ delete descriptor.value;
585
+ delete descriptor.writable;
285
586
  };
286
- var isLegacyTransportErrorEnvelope = (value) => {
287
- if (typeof value !== "object" || value === null) {
288
- return false;
587
+
588
+ // src/getRawState.ts
589
+ var defaultClientExecuteSyncTimeoutMs = 1500;
590
+ var getClientExecuteSyncTimeoutMs = (options) => {
591
+ const timeout = options.executeSyncTimeoutMs;
592
+ if (typeof timeout === "undefined") {
593
+ return defaultClientExecuteSyncTimeoutMs;
289
594
  }
290
- const candidate = value;
291
- return typeof candidate.$$Error === "string" && candidate.$$Error.length > 0 && Object.keys(candidate).length === 1;
595
+ if (!Number.isFinite(timeout) || timeout < 0) {
596
+ throw new Error(
597
+ "executeSyncTimeoutMs must be a finite number greater than or equal to 0"
598
+ );
599
+ }
600
+ return timeout;
292
601
  };
293
602
  var getRawState = (store, internal, initialState, options) => {
603
+ const clientExecuteSyncTimeoutMs = getClientExecuteSyncTimeoutMs(options);
294
604
  const rawState = {};
295
605
  const handle = (_rawState, _initialState, sliceKey) => {
296
606
  internal.mutableInstance = internal.toMutableRaw?.(_initialState);
@@ -298,234 +608,30 @@ var getRawState = (store, internal, initialState, options) => {
298
608
  Object.entries(descriptors).forEach(([key, descriptor]) => {
299
609
  if (Object.prototype.hasOwnProperty.call(descriptor, "value")) {
300
610
  if (typeof descriptor.value !== "function") {
301
- const isComputed = descriptor.value instanceof Computed;
302
- if (internal.mutableInstance) {
303
- Object.defineProperty(_rawState, key, {
304
- get: () => internal.mutableInstance[key],
305
- set: (value) => {
306
- internal.mutableInstance[key] = value;
307
- },
308
- enumerable: true
309
- });
310
- } else if (!isComputed) {
311
- _rawState[key] = descriptor.value;
312
- }
313
- if (isComputed) {
314
- if (internal.mutableInstance) {
315
- throw new Error(
316
- "Computed is not supported with mutable instance"
317
- );
318
- }
319
- const { deps, fn } = descriptor.value;
320
- const depsCallbackSelector = createSelectorWithArray(
321
- // the root state should be updated, and the computed property will be updated.
322
- () => [internal.rootState],
323
- () => {
324
- return deps(internal.module);
325
- }
326
- );
327
- const selector = createSelectorWithArray(
328
- (that) => depsCallbackSelector.call(that),
329
- fn
330
- );
331
- descriptor.get = function() {
332
- return selector.call(this);
333
- };
334
- } else {
335
- if (sliceKey) {
336
- descriptor.get = () => internal.rootState[sliceKey][key];
337
- descriptor.set = (value) => {
338
- internal.rootState[sliceKey][key] = value;
339
- };
340
- } else {
341
- descriptor.get = () => internal.rootState[key];
342
- descriptor.set = (value) => {
343
- internal.rootState[key] = value;
344
- };
345
- }
346
- }
347
- delete descriptor.value;
348
- delete descriptor.writable;
611
+ prepareStateDescriptor({
612
+ descriptor,
613
+ internal,
614
+ key,
615
+ rawState: _rawState,
616
+ sliceKey
617
+ });
349
618
  } else if (store.share === "client") {
350
- descriptor.value = (...args) => {
351
- let actionId;
352
- let done;
353
- if (store.trace) {
354
- actionId = uuid();
355
- store.trace({
356
- method: key,
357
- parameters: args,
358
- id: actionId,
359
- sliceKey
360
- });
361
- done = (result) => {
362
- store.trace({
363
- method: key,
364
- id: actionId,
365
- result,
366
- sliceKey
367
- });
368
- };
369
- }
370
- const keys = sliceKey ? [sliceKey, key] : [key];
371
- return store.transport.emit("execute", keys, args).then(async (response) => {
372
- const result = Array.isArray(response) ? response[0] : response;
373
- const sequence = Array.isArray(response) ? typeof response[1] === "number" ? response[1] : internal.sequence : internal.sequence;
374
- if (internal.sequence < sequence) {
375
- if (process.env.NODE_ENV === "development") {
376
- console.warn(
377
- `The sequence of the action is not consistent.`,
378
- sequence,
379
- internal.sequence
380
- );
381
- }
382
- await new Promise((resolve, reject) => {
383
- let settled = false;
384
- let unsubscribe = () => {
385
- };
386
- let timeoutId;
387
- const cleanup = () => {
388
- unsubscribe();
389
- if (typeof timeoutId !== "undefined") {
390
- clearTimeout(timeoutId);
391
- }
392
- };
393
- const finishResolve = () => {
394
- if (settled) return;
395
- settled = true;
396
- cleanup();
397
- resolve();
398
- };
399
- const finishReject = (error) => {
400
- if (settled) return;
401
- settled = true;
402
- cleanup();
403
- reject(error);
404
- };
405
- unsubscribe = store.subscribe(() => {
406
- if (internal.sequence >= sequence) {
407
- finishResolve();
408
- }
409
- });
410
- timeoutId = setTimeout(() => {
411
- void store.transport.emit("fullSync").then((latest) => {
412
- const next = latest;
413
- if (typeof next.state !== "string" || typeof next.sequence !== "number") {
414
- throw new Error("Invalid fullSync payload");
415
- }
416
- store.apply(JSON.parse(next.state));
417
- internal.sequence = next.sequence;
418
- if (internal.sequence >= sequence) {
419
- finishResolve();
420
- return;
421
- }
422
- finishReject(
423
- new Error(
424
- `Stale fullSync sequence: expected >= ${sequence}, got ${internal.sequence}`
425
- )
426
- );
427
- }).catch((error) => {
428
- finishReject(error);
429
- });
430
- }, clientExecuteSyncTimeoutMs);
431
- });
432
- }
433
- if (isTransportErrorEnvelope(result)) {
434
- done?.(result);
435
- throw new Error(result.message);
436
- }
437
- if (isLegacyTransportErrorEnvelope(result)) {
438
- done?.(result);
439
- throw new Error(result.$$Error);
440
- }
441
- done?.(result);
442
- return result;
443
- });
444
- };
619
+ descriptor.value = createClientAction({
620
+ clientExecuteSyncTimeoutMs,
621
+ internal,
622
+ key,
623
+ store,
624
+ sliceKey
625
+ });
445
626
  } else {
446
- const fn = descriptor.value;
447
- descriptor.value = (...args) => {
448
- let actionId;
449
- let done;
450
- if (store.trace) {
451
- actionId = uuid();
452
- store.trace({
453
- method: key,
454
- parameters: args,
455
- id: actionId,
456
- sliceKey
457
- });
458
- done = (result2) => {
459
- store.trace({
460
- method: key,
461
- id: actionId,
462
- result: result2,
463
- sliceKey
464
- });
465
- };
466
- }
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] = createWithMutative(
475
- internal.rootState,
476
- {
477
- enablePatches: true
478
- }
479
- );
480
- internal.finalizeDraft = finalize2;
481
- internal.rootState = draft2;
482
- }
483
- };
484
- const isDrafted = isDraft(internal.rootState);
485
- if (isDrafted) {
486
- handleResult();
487
- }
488
- internal.backupState = internal.rootState;
489
- const [draft, finalize] = createWithMutative(internal.rootState, {
490
- enablePatches: true
491
- });
492
- internal.finalizeDraft = finalize;
493
- internal.rootState = draft;
494
- try {
495
- result2 = fn.apply(
496
- sliceKey ? store.getState()[sliceKey] : store.getState(),
497
- args
498
- );
499
- } finally {
500
- if (result2 instanceof Promise) {
501
- return result2.finally(() => {
502
- const result3 = handleResult(isDrafted);
503
- done?.(result3);
504
- return result3;
505
- });
506
- }
507
- handleResult(isDrafted);
508
- }
509
- done?.(result2);
510
- return result2;
511
- }
512
- if (internal.mutableInstance && internal.actMutable) {
513
- const result2 = internal.actMutable(() => {
514
- return fn.apply(
515
- sliceKey ? store.getState()[sliceKey] : store.getState(),
516
- args
517
- );
518
- });
519
- done?.(result2);
520
- return result2;
521
- }
522
- const result = fn.apply(
523
- sliceKey ? store.getState()[sliceKey] : store.getState(),
524
- args
525
- );
526
- done?.(result);
527
- return result;
528
- };
627
+ descriptor.value = createLocalAction({
628
+ fn: descriptor.value,
629
+ internal,
630
+ key,
631
+ options,
632
+ store,
633
+ sliceKey
634
+ });
529
635
  }
530
636
  }
531
637
  });
@@ -771,6 +877,16 @@ var handleMainTransport = (store, internal, storeTransport, workerType, checkEna
771
877
 
772
878
  // src/create.ts
773
879
  var namespaceMap = /* @__PURE__ */ new Map();
880
+ var hasWarnedAmbiguousFunctionMap = false;
881
+ var warnAmbiguousFunctionMap = () => {
882
+ if (hasWarnedAmbiguousFunctionMap || process.env.NODE_ENV === "production" || process.env.NODE_ENV === "test") {
883
+ return;
884
+ }
885
+ hasWarnedAmbiguousFunctionMap = true;
886
+ 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.`
888
+ );
889
+ };
774
890
  var create = (createState, options = {}) => {
775
891
  const checkEnablePatches = Object.hasOwnProperty.call(options, "enablePatches") && !options.enablePatches;
776
892
  const workerType = options.workerType ?? WorkerType;
@@ -826,34 +942,31 @@ var create = (createState, options = {}) => {
826
942
  }
827
943
  };
828
944
  const getPureState = () => internal2.rootState;
829
- const inferSliceStore = () => {
945
+ const isFunctionMapObject = () => {
830
946
  if (typeof createState === "object" && createState !== null) {
831
947
  const values = Object.values(createState);
832
948
  return values.length > 0 && values.every((value) => typeof value === "function");
833
949
  }
834
950
  return false;
835
951
  };
836
- const isValidSliceObject = () => {
837
- if (typeof createState !== "object" || createState === null) {
838
- return false;
839
- }
840
- const values = Object.values(createState);
841
- return values.length > 0 && values.every((value) => typeof value === "function");
842
- };
843
952
  const getIsSliceStore = () => {
844
953
  const sliceMode = options.sliceMode ?? "auto";
845
954
  if (sliceMode === "single") {
846
955
  return false;
847
956
  }
848
957
  if (sliceMode === "slices") {
849
- if (!isValidSliceObject()) {
958
+ if (!isFunctionMapObject()) {
850
959
  throw new Error(
851
960
  `sliceMode: 'slices' requires createState to be an object of slice functions.`
852
961
  );
853
962
  }
854
963
  return true;
855
964
  }
856
- return inferSliceStore();
965
+ if (isFunctionMapObject()) {
966
+ warnAmbiguousFunctionMap();
967
+ return true;
968
+ }
969
+ return false;
857
970
  };
858
971
  const isSliceStore = getIsSliceStore();
859
972
  Object.assign(store2, {