@cplieger/actions 1.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.
Files changed (50) hide show
  1. package/.editorconfig +19 -0
  2. package/.htmlvalidate.json +28 -0
  3. package/.stylelintrc.json +67 -0
  4. package/LICENSE +692 -0
  5. package/README.md +176 -0
  6. package/dist/src/api.d.ts +56 -0
  7. package/dist/src/api.js +158 -0
  8. package/dist/src/cleanup.d.ts +11 -0
  9. package/dist/src/cleanup.js +63 -0
  10. package/dist/src/debounce.d.ts +28 -0
  11. package/dist/src/debounce.js +91 -0
  12. package/dist/src/define-helpers.d.ts +20 -0
  13. package/dist/src/define-helpers.js +83 -0
  14. package/dist/src/define.d.ts +14 -0
  15. package/dist/src/define.js +627 -0
  16. package/dist/src/error.d.ts +42 -0
  17. package/dist/src/error.js +174 -0
  18. package/dist/src/index.d.ts +17 -0
  19. package/dist/src/index.js +22 -0
  20. package/dist/src/loading.d.ts +15 -0
  21. package/dist/src/loading.js +114 -0
  22. package/dist/src/notifier.d.ts +21 -0
  23. package/dist/src/notifier.js +21 -0
  24. package/dist/src/poll.d.ts +23 -0
  25. package/dist/src/poll.js +120 -0
  26. package/dist/src/registry.d.ts +18 -0
  27. package/dist/src/registry.js +210 -0
  28. package/dist/src/retry.d.ts +9 -0
  29. package/dist/src/retry.js +78 -0
  30. package/dist/src/transport.d.ts +46 -0
  31. package/dist/src/transport.js +70 -0
  32. package/dist/src/types.d.ts +157 -0
  33. package/dist/src/types.js +7 -0
  34. package/eslint.config.base.mjs +186 -0
  35. package/jsr.json +22 -0
  36. package/package.json +41 -0
  37. package/src/api.ts +209 -0
  38. package/src/cleanup.ts +76 -0
  39. package/src/debounce.ts +128 -0
  40. package/src/define-helpers.ts +97 -0
  41. package/src/define.ts +699 -0
  42. package/src/error.ts +184 -0
  43. package/src/index.ts +60 -0
  44. package/src/loading.ts +149 -0
  45. package/src/notifier.ts +41 -0
  46. package/src/poll.ts +150 -0
  47. package/src/registry.ts +225 -0
  48. package/src/retry.ts +80 -0
  49. package/src/transport.ts +112 -0
  50. package/src/types.ts +198 -0
@@ -0,0 +1,83 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Pure utility helpers extracted from define.ts — independently testable
3
+ // without instantiating the full action framework.
4
+ // ---------------------------------------------------------------------------
5
+ /** Invoke a callback safely — errors are caught and logged without
6
+ * disrupting the dispatch lifecycle. */
7
+ export function safeInvoke(actionName, hookName, fn) {
8
+ try {
9
+ fn();
10
+ }
11
+ catch (e) {
12
+ console.error(`[actions] ${hookName} callback for ${actionName} threw`, e);
13
+ }
14
+ }
15
+ /** Monotonic counter for symbol identity in dedupe keys. Symbols with
16
+ * the same description are distinct values but String(sym) is identical,
17
+ * so we assign each unique symbol a stable numeric ID. */
18
+ let _symbolCounter = 0;
19
+ export const _symbolMap = new Map();
20
+ export function symbolId(sym) {
21
+ let id = _symbolMap.get(sym);
22
+ if (id === undefined) {
23
+ id = ++_symbolCounter;
24
+ _symbolMap.set(sym, id);
25
+ }
26
+ return id;
27
+ }
28
+ /** Reset symbol state — test-only. */
29
+ export function _resetSymbols() {
30
+ _symbolCounter = 0;
31
+ _symbolMap.clear();
32
+ }
33
+ /** Defensive JSON.stringify — falls back to String(args) on cycles
34
+ * or non-serializable values (DOM elements, functions). Used by
35
+ * the default dedupe key computation. */
36
+ export function safeStringify(args) {
37
+ if (args === undefined) {
38
+ return "undefined";
39
+ }
40
+ if (args === null || typeof args === "number" || typeof args === "boolean") {
41
+ return String(args);
42
+ }
43
+ if (typeof args === "string") {
44
+ return JSON.stringify(args);
45
+ }
46
+ if (typeof args === "bigint") {
47
+ return `${String(args)}n`;
48
+ }
49
+ if (typeof args === "symbol") {
50
+ return `@@sym${String(symbolId(args))}`;
51
+ }
52
+ try {
53
+ return JSON.stringify(args, (_key, value) => value === undefined ? "__undef__" : value);
54
+ }
55
+ catch {
56
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string -- intentional fallback for cyclic objects
57
+ return String(args);
58
+ }
59
+ }
60
+ /** Resolve a NotificationSpec to its message string. Returns null when
61
+ * the spec is `false` (suppressed) or undefined and no fallback. */
62
+ export function resolveNotification(spec, args, payload, fallback) {
63
+ if (spec === false) {
64
+ return null;
65
+ }
66
+ if (spec === undefined) {
67
+ return fallback ?? null;
68
+ }
69
+ if (typeof spec === "string") {
70
+ return spec;
71
+ }
72
+ return spec(args, payload);
73
+ }
74
+ /** @deprecated Use {@link resolveNotification} instead. */
75
+ export const resolveToast = resolveNotification;
76
+ /** Build a default error notification prefix from the action name.
77
+ * Converts "chat.delete" -> "Delete failed". */
78
+ export function defaultErrorPrefix(name) {
79
+ const parts = name.split(".");
80
+ const tail = parts[parts.length - 1] ?? name;
81
+ const readable = tail.replace(/[_-]/g, " ");
82
+ return readable.charAt(0).toUpperCase() + readable.slice(1) + " failed";
83
+ }
@@ -0,0 +1,14 @@
1
+ import type { Action, ActionDefinition } from "./types.js";
2
+ /** Header name used by apiAction when an idempotency key is generated. */
3
+ export declare const IDEMPOTENCY_HEADER = "Idempotency-Key";
4
+ /**
5
+ * Create an action from a declarative definition.
6
+ */
7
+ export declare function defineAction<TArgs, TResult, TOp = unknown>(def: ActionDefinition<TArgs, TResult, TOp>): Action<TArgs, TResult>;
8
+ /** Test-only: reset the instance counter + scope chains + dedupe map. */
9
+ export declare function _resetForTest(): void;
10
+ /** Test-only: expose internal map sizes for leak verification. */
11
+ export declare function _internalsForTest(): {
12
+ scopeChains: number;
13
+ activeDedupes: number;
14
+ };