coaction 2.0.0 → 3.0.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.d.mts CHANGED
@@ -2,6 +2,12 @@ import { Transport } from "data-transport";
2
2
  import { Draft, Patches } from "mutative";
3
3
  import { computed, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, signal, startBatch, trigger } from "alien-signals";
4
4
 
5
+ //#region packages/core/src/jsonTypes.d.ts
6
+ type JsonPrimitive = null | boolean | number | string;
7
+ type JsonValue = JsonPrimitive | JsonValue[] | {
8
+ [key: string]: JsonValue;
9
+ };
10
+ //#endregion
5
11
  //#region packages/core/src/interface.d.ts
6
12
  /**
7
13
  * Generic object shape used by stores and slices.
@@ -156,6 +162,22 @@ interface Store<T extends ISlices = ISlices> {
156
162
  * `MiddlewareStore` instead of relying on deprecated `patch` or `trace` hooks.
157
163
  */
158
164
  interface MiddlewareStore<T extends ISlices = ISlices> extends Store<T> {}
165
+ type TransportPolicyRequest = {
166
+ action: readonly string[];
167
+ args: readonly JsonValue[];
168
+ type: 'execute';
169
+ } | {
170
+ type: 'fullSync';
171
+ };
172
+ type TransportPolicy = {
173
+ /** Further restrict action paths declared by the authoritative store. */allowedActions?: readonly (readonly string[])[]; /** Authorize a decoded JSON request before serving it. */
174
+ authorize?: (request: TransportPolicyRequest) => boolean | Promise<boolean>;
175
+ /**
176
+ * Map a caught execute error to an explicitly client-visible message.
177
+ * Returning `undefined` keeps the generic redacted message.
178
+ */
179
+ mapError?: (error: unknown, request: TransportPolicyRequest) => string | undefined | Promise<string | undefined>;
180
+ };
159
181
  /**
160
182
  * Helper passed into {@link Slice} and {@link Slices} factories.
161
183
  *
@@ -243,7 +265,8 @@ type StoreOptions<T extends CreateState> = {
243
265
  /**
244
266
  * Inject a pre-built transport for advanced shared-store setups.
245
267
  */
246
- transport?: Transport;
268
+ transport?: Transport; /** Restrict requests accepted by a shared-main store. */
269
+ transportPolicy?: TransportPolicy;
247
270
  /**
248
271
  * Middleware chain applied before the initial state is finalized.
249
272
  */
@@ -379,197 +402,45 @@ type Creator = {
379
402
  * a shared store.
380
403
  *
381
404
  * @remarks
382
- * - Pass a {@link Slice} function for a single store.
383
- * - Pass an object of slice factories for a slices store.
384
- * - When an object input only contains functions, prefer explicit `sliceMode`
385
- * to avoid ambiguous inference.
386
- * - When `clientTransport` or `worker` is provided, returned store methods
387
- * become promise-returning methods because execution happens on the main
388
- * shared store.
389
- * - New semantics should prefer explicit helpers or variants over adding more
390
- * ambiguous `create()` input forms.
405
+ * Prefer the static `coaction/local` entry when transport support is not
406
+ * required. It excludes the JSON protocol and reconnect runtime from the
407
+ * consumer dependency graph.
391
408
  */
392
409
  declare const create: Creator;
393
410
  //#endregion
394
- //#region packages/core/src/internal.d.ts
395
- type MutationOperation = 'setState' | 'apply';
396
- type SignalSlot = {
397
- refresh: () => void;
398
- };
399
- interface Internal<T extends CreateState = CreateState> {
400
- /**
401
- * The store module.
402
- */
403
- module: T;
404
- /**
405
- * The root state.
406
- */
407
- rootState: T | Draft<T>;
408
- /**
409
- * The backup state.
410
- */
411
- backupState: T | Draft<T>;
412
- /**
413
- * Finalize the draft.
414
- */
415
- finalizeDraft: () => [T, Patches, Patches];
416
- /**
417
- * The mutable instance.
418
- */
419
- mutableInstance: any;
420
- /**
421
- * The sequence number.
422
- */
423
- sequence: number;
424
- /**
425
- * Whether the batch is running.
426
- */
427
- isBatching: boolean;
428
- /**
429
- * The listeners.
430
- */
431
- listeners: Set<Listener>;
432
- /**
433
- * Publish an externally-owned immutable state change to signal slots and
434
- * store subscribers.
435
- */
436
- notifyStateChange: () => void;
437
- /**
438
- * Reactive state slots used by computed getters/selectors.
439
- */
440
- signalSlots?: Set<SignalSlot>;
441
- /**
442
- * The act is used to run the function in the action for mutable state.
443
- */
444
- actMutable?: <T extends () => any>(fn: T) => ReturnType<T>;
445
- /**
446
- * Get the mutable raw instance via the initial state.
447
- */
448
- toMutableRaw?: (key: any) => any;
449
- /**
450
- * The update immutable function.
451
- */
452
- updateImmutable?: (state: T) => void;
453
- /**
454
- * Adapter-level authority check for low-level mutations.
455
- */
456
- assertMutationAllowed?: (operation: MutationOperation) => void;
457
- /**
458
- * Authorized client-mirror state application used by transports.
459
- */
460
- applyClientState?: (state?: T, patches?: Patches) => void;
461
- }
462
- //#endregion
463
- //#region packages/core/src/binder.d.ts
464
- type ExternalStoreAdapterOptions<F = (...args: any[]) => any> = {
465
- /**
466
- * Normalize a third-party store instance into a raw state object plus the
467
- * binding hook used during initialization.
468
- */
469
- handleState: <T extends object = object>(state: T) => {
470
- /**
471
- * Copy of the incoming state object that Coaction should consume.
472
- */
473
- copyState: T;
474
- /**
475
- * Optional nested key when the adapter exposes a single child object from
476
- * the third-party store.
477
- */
478
- key?: keyof T;
479
- /**
480
- * Convert the external state object into the raw state shape used by
481
- * Coaction.
482
- */
483
- bind: (state: T) => T;
484
- };
485
- /**
486
- * Wire Coaction's store lifecycle to the external store implementation.
487
- */
488
- handleStore: (
489
- /**
490
- * Coaction store wrapper.
491
- */
492
-
493
- store: Store<object>,
494
- /**
495
- * Raw state object returned from `bind`.
496
- */
497
-
498
- rawState: object,
499
- /**
500
- * Original external store state object.
501
- */
502
-
503
- state: object,
504
- /**
505
- * Low-level Coaction adapter hooks used by official bindings.
506
- */
507
-
508
- internal: Internal<object>,
509
- /**
510
- * Optional nested key returned by `handleState`.
511
- */
512
-
513
- key?: PropertyKey) => void;
514
- };
411
+ //#region packages/core/src/getRawStateClientAction.d.ts
515
412
  /**
516
- * Build an adapter helper for bridging an external store implementation into
517
- * Coaction.
518
- *
519
- * @remarks
520
- * Official bindings use this to integrate stores such as Redux, Jotai, Pinia,
521
- * Zustand, MobX, and Valtio. Binder-backed integrations are whole-store
522
- * adapters; they are not compatible with Coaction slices mode.
413
+ * The authority changed while a remote action was in flight, so its side-effect
414
+ * outcome cannot be determined safely from the current client mirror.
523
415
  */
524
- declare function createBinder<F = (...args: any[]) => any>({
525
- handleState,
526
- handleStore
527
- }: ExternalStoreAdapterOptions<F>): F;
528
- /**
529
- * Define a whole-store adapter for integrating an external state runtime with
530
- * Coaction.
531
- *
532
- * @remarks
533
- * This is the stable 2.x name for adapter authors. `createBinder()` remains as
534
- * a compatibility alias for existing official and community integrations.
535
- */
536
- declare function defineExternalStoreAdapter<F = (...args: any[]) => any>(options: ExternalStoreAdapterOptions<F>): F;
416
+ declare class ActionAuthorityChangedError extends Error {
417
+ readonly code = "COACTION_ACTION_AUTHORITY_CHANGED";
418
+ readonly outcome = "unknown";
419
+ constructor(action: string);
420
+ }
537
421
  //#endregion
538
422
  //#region packages/core/src/lifecycle.d.ts
539
423
  declare const onStoreReady: <T extends CreateState>(store: Store<T>, callback: () => void) => () => void;
540
424
  //#endregion
541
- //#region packages/core/src/reactiveTracker.d.ts
542
- type ReactiveTracker = {
543
- getSnapshot: () => number;
544
- subscribe: (listener: () => void) => () => void;
545
- track: <T>(fn: () => T) => T;
546
- dispose: () => void;
547
- };
548
- declare const createReactiveTracker: () => ReactiveTracker;
549
- //#endregion
550
- //#region packages/core/src/replaceExternalStoreState.d.ts
551
- type ReplaceExternalStoreStateOptions = {
552
- syncImmutable?: boolean;
553
- };
554
- declare const replaceExternalStoreState: <T extends CreateState>(store: MiddlewareStore<T>, internal: Internal<T>, source: Record<PropertyKey, unknown>, {
555
- syncImmutable
556
- }?: ReplaceExternalStoreStateOptions) => void;
557
- //#endregion
558
425
  //#region packages/core/src/utils.d.ts
559
- declare const replaceOwnEnumerable: (target: Record<PropertyKey, unknown>, source: Record<PropertyKey, unknown>) => void;
426
+ declare class UnsafePatchPathError extends Error {
427
+ name: string;
428
+ }
429
+ declare class StateSchemaError extends Error {
430
+ name: string;
431
+ }
432
+ declare const isStateSchemaError: (error: unknown) => error is StateSchemaError;
433
+ declare const assertSafePatches: <T extends {
434
+ path: unknown;
435
+ }>(patches: T[] | undefined, source?: string) => void;
436
+ declare const sanitizePatches: <T extends {
437
+ path: unknown;
438
+ value?: unknown;
439
+ }>(patches: T[] | undefined, options?: {
440
+ source?: string;
441
+ warnOnDropped?: boolean;
442
+ }) => T[] | undefined;
560
443
  declare const sanitizeReplacementState: <T>(source: T, seen?: WeakMap<object, unknown>) => T;
561
444
  declare const sanitizeInitialStateValue: <T>(source: T, seen?: WeakMap<object, unknown>) => T;
562
445
  //#endregion
563
- //#region packages/core/src/wrapStore.d.ts
564
- /**
565
- * Convert a store object into Coaction's callable store shape.
566
- *
567
- * @remarks
568
- * Framework bindings use this to attach selector-aware readers while
569
- * preserving the underlying store API on the returned function object. Most
570
- * applications should call {@link create} instead of using `wrapStore()`
571
- * directly.
572
- */
573
- declare const wrapStore: <T extends object>(store: Store<T>, getState?: (...args: unknown[]) => T) => StoreReturn<T>;
574
- //#endregion
575
- export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ExternalStoreAdapterOptions, type ISlices, type Middleware, type MiddlewareStore, type PatchTransform, type ReactiveTracker, type Slice, type SliceState, type Slices, type Store, type StoreOptions, type StoreTraceEvent, computed, create, createBinder, createReactiveTracker, defineExternalStoreAdapter, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, onStoreReady, replaceExternalStoreState, replaceOwnEnumerable, sanitizeInitialStateValue, sanitizeReplacementState, signal, startBatch, trigger, wrapStore };
446
+ export { ActionAuthorityChangedError, type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ISlices, type JsonPrimitive, type JsonValue, type Middleware, type MiddlewareStore, type PatchTransform, type Slice, type SliceState, type Slices, StateSchemaError, type Store, type StoreOptions, type StoreTraceEvent, type TransportPolicy, type TransportPolicyRequest, UnsafePatchPathError, assertSafePatches, computed, create, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, isStateSchemaError, onStoreReady, sanitizeInitialStateValue, sanitizePatches, sanitizeReplacementState, signal, startBatch, trigger };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,12 @@ import { Transport } from "data-transport";
2
2
  import { Draft, Patches } from "mutative";
3
3
  import { computed, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, signal, startBatch, trigger } from "alien-signals";
4
4
 
5
+ //#region packages/core/src/jsonTypes.d.ts
6
+ type JsonPrimitive = null | boolean | number | string;
7
+ type JsonValue = JsonPrimitive | JsonValue[] | {
8
+ [key: string]: JsonValue;
9
+ };
10
+ //#endregion
5
11
  //#region packages/core/src/interface.d.ts
6
12
  /**
7
13
  * Generic object shape used by stores and slices.
@@ -156,6 +162,22 @@ interface Store<T extends ISlices = ISlices> {
156
162
  * `MiddlewareStore` instead of relying on deprecated `patch` or `trace` hooks.
157
163
  */
158
164
  interface MiddlewareStore<T extends ISlices = ISlices> extends Store<T> {}
165
+ type TransportPolicyRequest = {
166
+ action: readonly string[];
167
+ args: readonly JsonValue[];
168
+ type: 'execute';
169
+ } | {
170
+ type: 'fullSync';
171
+ };
172
+ type TransportPolicy = {
173
+ /** Further restrict action paths declared by the authoritative store. */allowedActions?: readonly (readonly string[])[]; /** Authorize a decoded JSON request before serving it. */
174
+ authorize?: (request: TransportPolicyRequest) => boolean | Promise<boolean>;
175
+ /**
176
+ * Map a caught execute error to an explicitly client-visible message.
177
+ * Returning `undefined` keeps the generic redacted message.
178
+ */
179
+ mapError?: (error: unknown, request: TransportPolicyRequest) => string | undefined | Promise<string | undefined>;
180
+ };
159
181
  /**
160
182
  * Helper passed into {@link Slice} and {@link Slices} factories.
161
183
  *
@@ -243,7 +265,8 @@ type StoreOptions<T extends CreateState> = {
243
265
  /**
244
266
  * Inject a pre-built transport for advanced shared-store setups.
245
267
  */
246
- transport?: Transport;
268
+ transport?: Transport; /** Restrict requests accepted by a shared-main store. */
269
+ transportPolicy?: TransportPolicy;
247
270
  /**
248
271
  * Middleware chain applied before the initial state is finalized.
249
272
  */
@@ -379,197 +402,45 @@ type Creator = {
379
402
  * a shared store.
380
403
  *
381
404
  * @remarks
382
- * - Pass a {@link Slice} function for a single store.
383
- * - Pass an object of slice factories for a slices store.
384
- * - When an object input only contains functions, prefer explicit `sliceMode`
385
- * to avoid ambiguous inference.
386
- * - When `clientTransport` or `worker` is provided, returned store methods
387
- * become promise-returning methods because execution happens on the main
388
- * shared store.
389
- * - New semantics should prefer explicit helpers or variants over adding more
390
- * ambiguous `create()` input forms.
405
+ * Prefer the static `coaction/local` entry when transport support is not
406
+ * required. It excludes the JSON protocol and reconnect runtime from the
407
+ * consumer dependency graph.
391
408
  */
392
409
  declare const create: Creator;
393
410
  //#endregion
394
- //#region packages/core/src/internal.d.ts
395
- type MutationOperation = 'setState' | 'apply';
396
- type SignalSlot = {
397
- refresh: () => void;
398
- };
399
- interface Internal<T extends CreateState = CreateState> {
400
- /**
401
- * The store module.
402
- */
403
- module: T;
404
- /**
405
- * The root state.
406
- */
407
- rootState: T | Draft<T>;
408
- /**
409
- * The backup state.
410
- */
411
- backupState: T | Draft<T>;
412
- /**
413
- * Finalize the draft.
414
- */
415
- finalizeDraft: () => [T, Patches, Patches];
416
- /**
417
- * The mutable instance.
418
- */
419
- mutableInstance: any;
420
- /**
421
- * The sequence number.
422
- */
423
- sequence: number;
424
- /**
425
- * Whether the batch is running.
426
- */
427
- isBatching: boolean;
428
- /**
429
- * The listeners.
430
- */
431
- listeners: Set<Listener>;
432
- /**
433
- * Publish an externally-owned immutable state change to signal slots and
434
- * store subscribers.
435
- */
436
- notifyStateChange: () => void;
437
- /**
438
- * Reactive state slots used by computed getters/selectors.
439
- */
440
- signalSlots?: Set<SignalSlot>;
441
- /**
442
- * The act is used to run the function in the action for mutable state.
443
- */
444
- actMutable?: <T extends () => any>(fn: T) => ReturnType<T>;
445
- /**
446
- * Get the mutable raw instance via the initial state.
447
- */
448
- toMutableRaw?: (key: any) => any;
449
- /**
450
- * The update immutable function.
451
- */
452
- updateImmutable?: (state: T) => void;
453
- /**
454
- * Adapter-level authority check for low-level mutations.
455
- */
456
- assertMutationAllowed?: (operation: MutationOperation) => void;
457
- /**
458
- * Authorized client-mirror state application used by transports.
459
- */
460
- applyClientState?: (state?: T, patches?: Patches) => void;
461
- }
462
- //#endregion
463
- //#region packages/core/src/binder.d.ts
464
- type ExternalStoreAdapterOptions<F = (...args: any[]) => any> = {
465
- /**
466
- * Normalize a third-party store instance into a raw state object plus the
467
- * binding hook used during initialization.
468
- */
469
- handleState: <T extends object = object>(state: T) => {
470
- /**
471
- * Copy of the incoming state object that Coaction should consume.
472
- */
473
- copyState: T;
474
- /**
475
- * Optional nested key when the adapter exposes a single child object from
476
- * the third-party store.
477
- */
478
- key?: keyof T;
479
- /**
480
- * Convert the external state object into the raw state shape used by
481
- * Coaction.
482
- */
483
- bind: (state: T) => T;
484
- };
485
- /**
486
- * Wire Coaction's store lifecycle to the external store implementation.
487
- */
488
- handleStore: (
489
- /**
490
- * Coaction store wrapper.
491
- */
492
-
493
- store: Store<object>,
494
- /**
495
- * Raw state object returned from `bind`.
496
- */
497
-
498
- rawState: object,
499
- /**
500
- * Original external store state object.
501
- */
502
-
503
- state: object,
504
- /**
505
- * Low-level Coaction adapter hooks used by official bindings.
506
- */
507
-
508
- internal: Internal<object>,
509
- /**
510
- * Optional nested key returned by `handleState`.
511
- */
512
-
513
- key?: PropertyKey) => void;
514
- };
411
+ //#region packages/core/src/getRawStateClientAction.d.ts
515
412
  /**
516
- * Build an adapter helper for bridging an external store implementation into
517
- * Coaction.
518
- *
519
- * @remarks
520
- * Official bindings use this to integrate stores such as Redux, Jotai, Pinia,
521
- * Zustand, MobX, and Valtio. Binder-backed integrations are whole-store
522
- * adapters; they are not compatible with Coaction slices mode.
413
+ * The authority changed while a remote action was in flight, so its side-effect
414
+ * outcome cannot be determined safely from the current client mirror.
523
415
  */
524
- declare function createBinder<F = (...args: any[]) => any>({
525
- handleState,
526
- handleStore
527
- }: ExternalStoreAdapterOptions<F>): F;
528
- /**
529
- * Define a whole-store adapter for integrating an external state runtime with
530
- * Coaction.
531
- *
532
- * @remarks
533
- * This is the stable 2.x name for adapter authors. `createBinder()` remains as
534
- * a compatibility alias for existing official and community integrations.
535
- */
536
- declare function defineExternalStoreAdapter<F = (...args: any[]) => any>(options: ExternalStoreAdapterOptions<F>): F;
416
+ declare class ActionAuthorityChangedError extends Error {
417
+ readonly code = "COACTION_ACTION_AUTHORITY_CHANGED";
418
+ readonly outcome = "unknown";
419
+ constructor(action: string);
420
+ }
537
421
  //#endregion
538
422
  //#region packages/core/src/lifecycle.d.ts
539
423
  declare const onStoreReady: <T extends CreateState>(store: Store<T>, callback: () => void) => () => void;
540
424
  //#endregion
541
- //#region packages/core/src/reactiveTracker.d.ts
542
- type ReactiveTracker = {
543
- getSnapshot: () => number;
544
- subscribe: (listener: () => void) => () => void;
545
- track: <T>(fn: () => T) => T;
546
- dispose: () => void;
547
- };
548
- declare const createReactiveTracker: () => ReactiveTracker;
549
- //#endregion
550
- //#region packages/core/src/replaceExternalStoreState.d.ts
551
- type ReplaceExternalStoreStateOptions = {
552
- syncImmutable?: boolean;
553
- };
554
- declare const replaceExternalStoreState: <T extends CreateState>(store: MiddlewareStore<T>, internal: Internal<T>, source: Record<PropertyKey, unknown>, {
555
- syncImmutable
556
- }?: ReplaceExternalStoreStateOptions) => void;
557
- //#endregion
558
425
  //#region packages/core/src/utils.d.ts
559
- declare const replaceOwnEnumerable: (target: Record<PropertyKey, unknown>, source: Record<PropertyKey, unknown>) => void;
426
+ declare class UnsafePatchPathError extends Error {
427
+ name: string;
428
+ }
429
+ declare class StateSchemaError extends Error {
430
+ name: string;
431
+ }
432
+ declare const isStateSchemaError: (error: unknown) => error is StateSchemaError;
433
+ declare const assertSafePatches: <T extends {
434
+ path: unknown;
435
+ }>(patches: T[] | undefined, source?: string) => void;
436
+ declare const sanitizePatches: <T extends {
437
+ path: unknown;
438
+ value?: unknown;
439
+ }>(patches: T[] | undefined, options?: {
440
+ source?: string;
441
+ warnOnDropped?: boolean;
442
+ }) => T[] | undefined;
560
443
  declare const sanitizeReplacementState: <T>(source: T, seen?: WeakMap<object, unknown>) => T;
561
444
  declare const sanitizeInitialStateValue: <T>(source: T, seen?: WeakMap<object, unknown>) => T;
562
445
  //#endregion
563
- //#region packages/core/src/wrapStore.d.ts
564
- /**
565
- * Convert a store object into Coaction's callable store shape.
566
- *
567
- * @remarks
568
- * Framework bindings use this to attach selector-aware readers while
569
- * preserving the underlying store API on the returned function object. Most
570
- * applications should call {@link create} instead of using `wrapStore()`
571
- * directly.
572
- */
573
- declare const wrapStore: <T extends object>(store: Store<T>, getState?: (...args: unknown[]) => T) => StoreReturn<T>;
574
- //#endregion
575
- export { type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ExternalStoreAdapterOptions, type ISlices, type Middleware, type MiddlewareStore, type PatchTransform, type ReactiveTracker, type Slice, type SliceState, type Slices, type Store, type StoreOptions, type StoreTraceEvent, computed, create, createBinder, createReactiveTracker, defineExternalStoreAdapter, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, onStoreReady, replaceExternalStoreState, replaceOwnEnumerable, sanitizeInitialStateValue, sanitizeReplacementState, signal, startBatch, trigger, wrapStore };
446
+ export { ActionAuthorityChangedError, type StoreWithAsyncFunction as AsyncStore, type Asyncify, type ClientStoreOptions, type ISlices, type JsonPrimitive, type JsonValue, type Middleware, type MiddlewareStore, type PatchTransform, type Slice, type SliceState, type Slices, StateSchemaError, type Store, type StoreOptions, type StoreTraceEvent, type TransportPolicy, type TransportPolicyRequest, UnsafePatchPathError, assertSafePatches, computed, create, effect, effectScope, endBatch, isComputed, isEffect, isEffectScope, isSignal, isStateSchemaError, onStoreReady, sanitizeInitialStateValue, sanitizePatches, sanitizeReplacementState, signal, startBatch, trigger };