@ankhorage/runtime 5.1.3 → 5.2.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.
@@ -1,11 +1,13 @@
1
1
  import { isRecord } from '@ankhorage/utility/object';
2
2
  /*** Keeps local state mutations while preferring the configured host executor for API capabilities. */
3
3
  export function composeRuntimeCapabilityExecutor(composition) {
4
- return async (args) => args.capability === 'state.set'
5
- ? executeStateSetCapabilityAsync(args, composition.stateAdapter)
6
- : args.capability.startsWith('api.')
7
- ? executeApiCapabilityAsync(args, composition)
8
- : executeApplicationCapabilityAsync(args, composition.capabilityExecutor);
4
+ return async (args) => args.capability.startsWith('api.')
5
+ ? executeApiCapabilityAsync(args, composition)
6
+ : args.capability === 'state.set'
7
+ ? executeStateSetCapabilityAsync(args, composition.stateAdapter)
8
+ : args.capability === 'state.update'
9
+ ? executeStateUpdateCapabilityAsync(args, composition.stateAdapter)
10
+ : executeApplicationCapabilityAsync(args, composition.capabilityExecutor);
9
11
  }
10
12
  /*** Uses the host API executor when supplied, falling back to the manifest executor. */
11
13
  function executeApiCapabilityAsync(args, composition) {
@@ -37,6 +39,28 @@ function executeStateSetCapabilityAsync(args, stateAdapter) {
37
39
  return Promise.resolve(stateAdapterSetErrorResult(error));
38
40
  }
39
41
  }
42
+ /*** Applies a serializable atomic state update through the configured state adapter. */
43
+ function executeStateUpdateCapabilityAsync(args, stateAdapter) {
44
+ if (stateAdapter?.update === undefined)
45
+ return Promise.resolve(missingStateUpdateAdapterResult());
46
+ const input = resolveStateUpdateInput(args.input);
47
+ if (input === undefined)
48
+ return Promise.resolve(invalidStateUpdateInputResult());
49
+ try {
50
+ const result = stateAdapter.update(input.path, input.update);
51
+ return Promise.resolve(result.ok
52
+ ? { data: { path: input.path, value: result.data }, ok: true }
53
+ : {
54
+ diagnostics: [
55
+ { code: result.error.code, message: result.error.message, severity: 'error' },
56
+ ],
57
+ ok: false,
58
+ });
59
+ }
60
+ catch (error) {
61
+ return Promise.resolve(stateAdapterUpdateErrorResult(error));
62
+ }
63
+ }
40
64
  async function executeApplicationCapabilityAsync(args, capabilityExecutor) {
41
65
  if (capabilityExecutor !== undefined)
42
66
  return capabilityExecutor(args);
@@ -59,6 +83,19 @@ function resolveStateSetInput(input) {
59
83
  return undefined;
60
84
  return { path, value };
61
85
  }
86
+ /*** Validates a portable append update before it reaches the StateAdapter boundary. */
87
+ function resolveStateUpdateInput(input) {
88
+ if (!isRecord(input))
89
+ return undefined;
90
+ const { path, update } = input;
91
+ if (!isStatePath(path) || !isStateUpdate(update))
92
+ return undefined;
93
+ return { path, update };
94
+ }
95
+ /*** Narrows unknown manifest input to the released serializable append descriptor. */
96
+ function isStateUpdate(value) {
97
+ return isRecord(value) && value.kind === 'append' && isStateValue(value.value);
98
+ }
62
99
  function isStatePath(value) {
63
100
  return ((typeof value === 'string' && value.trim().length > 0) ||
64
101
  (Array.isArray(value) &&
@@ -87,6 +124,19 @@ function stateAdapterSetErrorResult(error) {
87
124
  ok: false,
88
125
  };
89
126
  }
127
+ /*** Converts thrown state-update adapter failures into public Runtime diagnostics. */
128
+ function stateAdapterUpdateErrorResult(error) {
129
+ return {
130
+ diagnostics: [
131
+ {
132
+ code: 'state-adapter-error',
133
+ message: error instanceof Error ? error.message : 'StateAdapter.update failed.',
134
+ severity: 'error',
135
+ },
136
+ ],
137
+ ok: false,
138
+ };
139
+ }
90
140
  function missingStateAdapterResult() {
91
141
  return {
92
142
  diagnostics: [
@@ -111,4 +161,30 @@ function invalidStateSetInputResult() {
111
161
  ok: false,
112
162
  };
113
163
  }
164
+ /*** Reports an unavailable atomic-update adapter without delegating application execution. */
165
+ function missingStateUpdateAdapterResult() {
166
+ return {
167
+ diagnostics: [
168
+ {
169
+ code: 'missing-adapter',
170
+ message: "Capability 'state.update' requires a configured StateAdapter with update support.",
171
+ severity: 'error',
172
+ },
173
+ ],
174
+ ok: false,
175
+ };
176
+ }
177
+ /*** Reports malformed state-update descriptors at the Runtime capability boundary. */
178
+ function invalidStateUpdateInputResult() {
179
+ return {
180
+ diagnostics: [
181
+ {
182
+ code: 'invalid-input',
183
+ message: "Capability 'state.update' requires a non-empty path and serializable append update.",
184
+ severity: 'error',
185
+ },
186
+ ],
187
+ ok: false,
188
+ };
189
+ }
114
190
  //# sourceMappingURL=runtimeCapabilityExecutor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeCapabilityExecutor.js","sourceRoot":"","sources":["../src/runtimeCapabilityExecutor.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StateAdapter, StatePath, StateValue } from '@ankhorage/contracts';\nimport { isRecord } from '@ankhorage/utility/object';\n\nimport type {\n RuntimeCapabilityExecutionArgs,\n RuntimeCapabilityExecutionResult,\n RuntimeCapabilityExecutor,\n} from './runtimeBindings';\n\nexport interface RuntimeCapabilityExecutorComposition {\n readonly apiCapabilityExecutor: RuntimeCapabilityExecutor;\n readonly capabilityExecutor?: RuntimeCapabilityExecutor;\n readonly stateAdapter?: StateAdapter;\n}\n\n/*** Keeps local state mutations while preferring the configured host executor for API capabilities. */\nexport function composeRuntimeCapabilityExecutor(\n composition: RuntimeCapabilityExecutorComposition,\n): RuntimeCapabilityExecutor {\n return async (args) =>\n args.capability === 'state.set'\n ? executeStateSetCapabilityAsync(args, composition.stateAdapter)\n : args.capability.startsWith('api.')\n ? executeApiCapabilityAsync(args, composition)\n : executeApplicationCapabilityAsync(args, composition.capabilityExecutor);\n}\n\n/*** Uses the host API executor when supplied, falling back to the manifest executor. */\nfunction executeApiCapabilityAsync(\n args: RuntimeCapabilityExecutionArgs,\n composition: RuntimeCapabilityExecutorComposition,\n): Promise<RuntimeCapabilityExecutionResult> {\n return composition.capabilityExecutor?.(args) ?? composition.apiCapabilityExecutor(args);\n}\n\n/*** Applies one serializable state value through the configured application state adapter. */\nfunction executeStateSetCapabilityAsync(\n args: RuntimeCapabilityExecutionArgs,\n stateAdapter: StateAdapter | undefined,\n): Promise<RuntimeCapabilityExecutionResult> {\n if (stateAdapter === undefined) return Promise.resolve(missingStateAdapterResult());\n\n const input = resolveStateSetInput(args.input);\n if (input === undefined) return Promise.resolve(invalidStateSetInputResult());\n\n try {\n const result = stateAdapter.set(input.path, input.value);\n return Promise.resolve(\n result.ok\n ? { data: { path: input.path, value: input.value }, ok: true }\n : {\n diagnostics: [\n {\n code: result.error.code,\n message: result.error.message,\n severity: 'error',\n },\n ],\n ok: false,\n },\n );\n } catch (error) {\n return Promise.resolve(stateAdapterSetErrorResult(error));\n }\n}\n\nasync function executeApplicationCapabilityAsync(\n args: RuntimeCapabilityExecutionArgs,\n capabilityExecutor: RuntimeCapabilityExecutor | undefined,\n): Promise<RuntimeCapabilityExecutionResult> {\n if (capabilityExecutor !== undefined) return capabilityExecutor(args);\n return {\n diagnostics: [\n {\n code: 'missing-operation',\n message: `Capability '${args.capability}' has no configured executor.`,\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\nfunction resolveStateSetInput(\n input: RuntimeCapabilityExecutionArgs['input'],\n): { readonly path: StatePath; readonly value: StateValue } | undefined {\n if (!isRecord(input) || !('value' in input)) return undefined;\n const { path, value } = input;\n if (!isStatePath(path) || !isStateValue(value)) return undefined;\n return { path, value };\n}\n\nfunction isStatePath(value: unknown): value is StatePath {\n return (\n (typeof value === 'string' && value.trim().length > 0) ||\n (Array.isArray(value) &&\n value.length > 0 &&\n value.every((part) => typeof part === 'string' && part.trim().length > 0))\n );\n}\n\nfunction isStateValue(value: unknown): value is StateValue {\n if (value === null || typeof value === 'boolean' || typeof value === 'string') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (Array.isArray(value)) return value.every(isStateValue);\n return isRecord(value) && Object.values(value).every(isStateValue);\n}\n\n/*** Converts thrown adapter failures into capability diagnostics at the public Runtime boundary. */\nfunction stateAdapterSetErrorResult(error: unknown): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'state-adapter-error',\n message: error instanceof Error ? error.message : 'StateAdapter.set failed.',\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\nfunction missingStateAdapterResult(): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'missing-adapter',\n message: \"Capability 'state.set' requires a configured StateAdapter.\",\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\nfunction invalidStateSetInputResult(): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'invalid-input',\n message: \"Capability 'state.set' requires a non-empty path and serializable value.\",\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n"]}
1
+ {"version":3,"file":"runtimeCapabilityExecutor.js","sourceRoot":"","sources":["../src/runtimeCapabilityExecutor.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StateAdapter, StatePath, StateUpdate, StateValue } from '@ankhorage/contracts';\nimport { isRecord } from '@ankhorage/utility/object';\n\nimport type {\n RuntimeCapabilityExecutionArgs,\n RuntimeCapabilityExecutionResult,\n RuntimeCapabilityExecutor,\n} from './runtimeBindings';\n\nexport interface RuntimeCapabilityExecutorComposition {\n readonly apiCapabilityExecutor: RuntimeCapabilityExecutor;\n readonly capabilityExecutor?: RuntimeCapabilityExecutor;\n readonly stateAdapter?: StateAdapter;\n}\n\n/*** Keeps local state mutations while preferring the configured host executor for API capabilities. */\nexport function composeRuntimeCapabilityExecutor(\n composition: RuntimeCapabilityExecutorComposition,\n): RuntimeCapabilityExecutor {\n return async (args) =>\n args.capability.startsWith('api.')\n ? executeApiCapabilityAsync(args, composition)\n : args.capability === 'state.set'\n ? executeStateSetCapabilityAsync(args, composition.stateAdapter)\n : args.capability === 'state.update'\n ? executeStateUpdateCapabilityAsync(args, composition.stateAdapter)\n : executeApplicationCapabilityAsync(args, composition.capabilityExecutor);\n}\n\n/*** Uses the host API executor when supplied, falling back to the manifest executor. */\nfunction executeApiCapabilityAsync(\n args: RuntimeCapabilityExecutionArgs,\n composition: RuntimeCapabilityExecutorComposition,\n): Promise<RuntimeCapabilityExecutionResult> {\n return composition.capabilityExecutor?.(args) ?? composition.apiCapabilityExecutor(args);\n}\n\n/*** Applies one serializable state value through the configured application state adapter. */\nfunction executeStateSetCapabilityAsync(\n args: RuntimeCapabilityExecutionArgs,\n stateAdapter: StateAdapter | undefined,\n): Promise<RuntimeCapabilityExecutionResult> {\n if (stateAdapter === undefined) return Promise.resolve(missingStateAdapterResult());\n\n const input = resolveStateSetInput(args.input);\n if (input === undefined) return Promise.resolve(invalidStateSetInputResult());\n\n try {\n const result = stateAdapter.set(input.path, input.value);\n return Promise.resolve(\n result.ok\n ? { data: { path: input.path, value: input.value }, ok: true }\n : {\n diagnostics: [\n {\n code: result.error.code,\n message: result.error.message,\n severity: 'error',\n },\n ],\n ok: false,\n },\n );\n } catch (error) {\n return Promise.resolve(stateAdapterSetErrorResult(error));\n }\n}\n\n/*** Applies a serializable atomic state update through the configured state adapter. */\nfunction executeStateUpdateCapabilityAsync(\n args: RuntimeCapabilityExecutionArgs,\n stateAdapter: StateAdapter | undefined,\n): Promise<RuntimeCapabilityExecutionResult> {\n if (stateAdapter?.update === undefined) return Promise.resolve(missingStateUpdateAdapterResult());\n\n const input = resolveStateUpdateInput(args.input);\n if (input === undefined) return Promise.resolve(invalidStateUpdateInputResult());\n\n try {\n const result = stateAdapter.update(input.path, input.update);\n return Promise.resolve(\n result.ok\n ? { data: { path: input.path, value: result.data }, ok: true }\n : {\n diagnostics: [\n { code: result.error.code, message: result.error.message, severity: 'error' },\n ],\n ok: false,\n },\n );\n } catch (error) {\n return Promise.resolve(stateAdapterUpdateErrorResult(error));\n }\n}\n\nasync function executeApplicationCapabilityAsync(\n args: RuntimeCapabilityExecutionArgs,\n capabilityExecutor: RuntimeCapabilityExecutor | undefined,\n): Promise<RuntimeCapabilityExecutionResult> {\n if (capabilityExecutor !== undefined) return capabilityExecutor(args);\n return {\n diagnostics: [\n {\n code: 'missing-operation',\n message: `Capability '${args.capability}' has no configured executor.`,\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\nfunction resolveStateSetInput(\n input: RuntimeCapabilityExecutionArgs['input'],\n): { readonly path: StatePath; readonly value: StateValue } | undefined {\n if (!isRecord(input) || !('value' in input)) return undefined;\n const { path, value } = input;\n if (!isStatePath(path) || !isStateValue(value)) return undefined;\n return { path, value };\n}\n\n/*** Validates a portable append update before it reaches the StateAdapter boundary. */\nfunction resolveStateUpdateInput(\n input: RuntimeCapabilityExecutionArgs['input'],\n): { readonly path: StatePath; readonly update: StateUpdate } | undefined {\n if (!isRecord(input)) return undefined;\n const { path, update } = input;\n if (!isStatePath(path) || !isStateUpdate(update)) return undefined;\n return { path, update };\n}\n\n/*** Narrows unknown manifest input to the released serializable append descriptor. */\nfunction isStateUpdate(value: unknown): value is StateUpdate {\n return isRecord(value) && value.kind === 'append' && isStateValue(value.value);\n}\n\nfunction isStatePath(value: unknown): value is StatePath {\n return (\n (typeof value === 'string' && value.trim().length > 0) ||\n (Array.isArray(value) &&\n value.length > 0 &&\n value.every((part) => typeof part === 'string' && part.trim().length > 0))\n );\n}\n\nfunction isStateValue(value: unknown): value is StateValue {\n if (value === null || typeof value === 'boolean' || typeof value === 'string') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (Array.isArray(value)) return value.every(isStateValue);\n return isRecord(value) && Object.values(value).every(isStateValue);\n}\n\n/*** Converts thrown adapter failures into capability diagnostics at the public Runtime boundary. */\nfunction stateAdapterSetErrorResult(error: unknown): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'state-adapter-error',\n message: error instanceof Error ? error.message : 'StateAdapter.set failed.',\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\n/*** Converts thrown state-update adapter failures into public Runtime diagnostics. */\nfunction stateAdapterUpdateErrorResult(error: unknown): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'state-adapter-error',\n message: error instanceof Error ? error.message : 'StateAdapter.update failed.',\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\nfunction missingStateAdapterResult(): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'missing-adapter',\n message: \"Capability 'state.set' requires a configured StateAdapter.\",\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\nfunction invalidStateSetInputResult(): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'invalid-input',\n message: \"Capability 'state.set' requires a non-empty path and serializable value.\",\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\n/*** Reports an unavailable atomic-update adapter without delegating application execution. */\nfunction missingStateUpdateAdapterResult(): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'missing-adapter',\n message:\n \"Capability 'state.update' requires a configured StateAdapter with update support.\",\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n\n/*** Reports malformed state-update descriptors at the Runtime capability boundary. */\nfunction invalidStateUpdateInputResult(): RuntimeCapabilityExecutionResult {\n return {\n diagnostics: [\n {\n code: 'invalid-input',\n message:\n \"Capability 'state.update' requires a non-empty path and serializable append update.\",\n severity: 'error',\n },\n ],\n ok: false,\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { StateAdapter, StateValue } from '@ankhorage/contracts';
1
+ import { type StateAdapter, type StateValue } from '@ankhorage/contracts';
2
2
  export interface RuntimeMemoryStateAdapterOptions {
3
3
  readonly initialState?: Readonly<Record<string, StateValue>>;
4
4
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeStateAdapter.d.ts","sourceRoot":"","sources":["../src/runtimeStateAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAMZ,UAAU,EACX,MAAM,sBAAsB,CAAC;AAS9B,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CAC9D;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,gCAAqC,GAC7C,YAAY,CAmFd"}
1
+ {"version":3,"file":"runtimeStateAdapter.d.ts","sourceRoot":"","sources":["../src/runtimeStateAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EAOjB,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAc9B,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CAC9D;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,gCAAqC,GAC7C,YAAY,CAmHd"}
@@ -1,18 +1,35 @@
1
+ import { isSerializableValue, } from '@ankhorage/contracts';
1
2
  export function createRuntimeMemoryStateAdapter(options = {}) {
2
3
  let rootState = { ...(options.initialState ?? {}) };
3
4
  const listeners = new Map();
5
+ const notifications = [];
6
+ let isNotifying = false;
4
7
  const emit = (path) => {
5
8
  const pathResult = normalizeStatePath(path);
6
9
  if (!pathResult.ok)
7
10
  return;
8
- for (const entry of listeners.values()) {
9
- if (!areStatePathsRelated(pathResult.parts, entry.parts))
10
- continue;
11
- const value = readStatePath(rootState, entry.parts);
12
- for (const listener of entry.listeners) {
13
- listener(value);
11
+ notifications.push({ changedParts: pathResult.parts, state: rootState });
12
+ if (isNotifying)
13
+ return;
14
+ isNotifying = true;
15
+ try {
16
+ while (notifications.length > 0) {
17
+ const notification = notifications.shift();
18
+ if (notification === undefined)
19
+ continue;
20
+ for (const entry of [...listeners.values()]) {
21
+ if (!areStatePathsRelated(notification.changedParts, entry.parts))
22
+ continue;
23
+ const value = readStatePath(notification.state, entry.parts);
24
+ for (const listener of [...entry.listeners]) {
25
+ listener(value);
26
+ }
27
+ }
14
28
  }
15
29
  }
30
+ finally {
31
+ isNotifying = false;
32
+ }
16
33
  };
17
34
  return {
18
35
  capabilities: {
@@ -37,6 +54,20 @@ export function createRuntimeMemoryStateAdapter(options = {}) {
37
54
  emit(path);
38
55
  return { ok: true };
39
56
  },
57
+ update(path, update) {
58
+ const pathResult = normalizeStatePath(path);
59
+ if (!pathResult.ok)
60
+ return pathResult;
61
+ const updateResult = applyStateUpdate(readStatePath(rootState, pathResult.parts), update);
62
+ if (!updateResult.ok)
63
+ return updateResult;
64
+ const nextStateResult = setStatePath(rootState, pathResult.parts, updateResult.data);
65
+ if (!nextStateResult.ok)
66
+ return nextStateResult;
67
+ rootState = nextStateResult.data;
68
+ emit(path);
69
+ return createStateDataResult(updateResult.data);
70
+ },
40
71
  subscribe(path, listener) {
41
72
  const pathResult = normalizeStatePath(path);
42
73
  if (!pathResult.ok)
@@ -128,6 +159,17 @@ function setStatePath(source, parts, value) {
128
159
  [head]: childResult.data,
129
160
  });
130
161
  }
162
+ /*** Applies one supported atomic update without observing an intermediate state. */
163
+ function applyStateUpdate(value, update) {
164
+ if (value !== undefined && !isStateValueArray(value)) {
165
+ return createStateError('incompatible_value', 'Append updates require an existing array state value.');
166
+ }
167
+ return createStateDataResult([...(value ?? []), update.value]);
168
+ }
169
+ /*** Narrows a serializable value to an element-preserving state array. */
170
+ function isStateValueArray(value) {
171
+ return Array.isArray(value) && value.every(isSerializableValue);
172
+ }
131
173
  function deleteStatePath(source, parts) {
132
174
  const [head, ...tail] = parts;
133
175
  if (head === undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeStateAdapter.js","sourceRoot":"","sources":["../src/runtimeStateAdapter.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,+BAA+B,CAC7C,UAA4C,EAAE;IAE9C,IAAI,SAAS,GAAuB,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAC;IACxE,MAAM,SAAS,GAAG,IAAI,GAAG,EAA8B,CAAC;IAExD,MAAM,IAAI,GAAG,CAAC,IAAe,EAAE,EAAE;QAC/B,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU,CAAC,EAAE;YAAE,OAAO;QAE3B,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;gBAAE,SAAS;YAEnE,MAAM,KAAK,GAAG,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YACpD,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;gBACvC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,YAAY,EAAE;YACZ,aAAa,EAAE,IAAI;YACnB,QAAQ,EAAE,KAAK;YACf,WAAW,EAAE,KAAK;SACnB;QACD,GAAG,CAAyC,IAAe;YACzD,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC;YAEtC,OAAO,qBAAqB,CAC1B,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAuB,CACjE,CAAC;QACJ,CAAC;QACD,GAAG,CAAyC,IAAe,EAAE,KAAa;YACxE,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC;YAEtC,MAAM,eAAe,GAAG,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACzE,IAAI,CAAC,eAAe,CAAC,EAAE;gBAAE,OAAO,eAAe,CAAC;YAEhD,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,CAAC;YACX,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QACD,SAAS,CACP,IAAe,EACf,QAA+B;YAE/B,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC;YAEtC,MAAM,GAAG,GAAG,cAAc,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;gBAClC,SAAS,EAAE,IAAI,GAAG,EAA2C;gBAC7D,KAAK,EAAE,UAAU,CAAC,KAAK;aACxB,CAAC;YACF,MAAM,eAAe,GAAG,CAAC,KAA6B,EAAE,EAAE;gBACxD,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAA2B,EAAE,CAAC,CAAC;YACzD,CAAC,CAAC;YAEF,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACrC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAE1B,OAAO,qBAAqB,CAAC;gBAC3B,WAAW;oBACT,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;oBACxC,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;wBAC/B,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACxB,CAAC;gBACH,CAAC;aACF,CAAC,CAAC;QACL,CAAC;QACD,MAAM,CAAC,IAAe;YACpB,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC;YAEtC,MAAM,eAAe,GAAG,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;YACrE,IAAI,CAAC,eAAe,CAAC,EAAE;gBAAE,OAAO,eAAe,CAAC;YAEhD,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,CAAC;YACX,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;KACF,CAAC;AACJ,CAAC;AAcD,SAAS,kBAAkB,CAAC,IAAe;IACzC,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEpE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,gBAAgB,CAAC,cAAc,EAAE,+CAA+C,CAAC,CAAC;IAC3F,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,UAAU;KAClB,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAwB;IAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,mGAAmG;AACnG,SAAS,oBAAoB,CAC3B,YAA+B,EAC/B,eAAkC;IAElC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3E,OAAO,YAAY;SAChB,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;SACtB,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,aAAa,CACpB,MAA0B,EAC1B,KAAwB;IAExB,IAAI,YAAY,GAA2B,MAAM,CAAC;IAElD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,YAAY,CACnB,MAA0B,EAC1B,KAAwB,EACxB,KAAiB;IAEjB,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;IAC9B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,gBAAgB,CAAC,cAAc,EAAE,+CAA+C,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,qBAAqB,CAAC;YAC3B,GAAG,MAAM;YACT,CAAC,IAAI,CAAC,EAAE,KAAK;SACd,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IACrD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,gBAAgB,CACrB,eAAe,EACf,0DAA0D,IAAI,IAAI,CACnE,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACrD,IAAI,CAAC,WAAW,CAAC,EAAE;QAAE,OAAO,WAAW,CAAC;IAExC,OAAO,qBAAqB,CAAC;QAC3B,GAAG,MAAM;QACT,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,IAAI;KACzB,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CACtB,MAA0B,EAC1B,KAAwB;IAExB,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;IAC9B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,gBAAgB,CAAC,cAAc,EAAE,+CAA+C,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,SAAS,GAAuB,EAAE,CAAC;QACzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACzB,CAAC;QACH,CAAC;QAED,OAAO,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,gBAAgB,CACrB,eAAe,EACf,6DAA6D,IAAI,IAAI,CACtE,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,WAAW,CAAC,EAAE;QAAE,OAAO,WAAW,CAAC;IAExC,OAAO,qBAAqB,CAAC;QAC3B,GAAG,MAAM;QACT,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,IAAI;KACzB,CAAC,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,KAA6B;IAClD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY,EAAE,OAAe;IACrD,MAAM,KAAK,GAAsB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACnD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,SAAS,qBAAqB,CAAS,IAAY;IACjD,MAAM,MAAM,GAAG;QACb,EAAE,EAAE,IAAI;QACR,IAAI;KACL,CAAC;IAEF,OAAO,MAA6B,CAAC;AACvC,CAAC","sourcesContent":["import type {\n StateAdapter,\n StateAdapterError,\n StateListener,\n StatePath,\n StateResult,\n StateSubscription,\n StateValue,\n} from '@ankhorage/contracts';\n\ntype MutableStateRecord = Record<string, StateValue>;\ntype StateListenerSet = Set<(value: StateValue | undefined) => void>;\ninterface StateListenerEntry {\n readonly listeners: StateListenerSet;\n readonly parts: readonly string[];\n}\n\nexport interface RuntimeMemoryStateAdapterOptions {\n readonly initialState?: Readonly<Record<string, StateValue>>;\n}\n\nexport function createRuntimeMemoryStateAdapter(\n options: RuntimeMemoryStateAdapterOptions = {},\n): StateAdapter {\n let rootState: MutableStateRecord = { ...(options.initialState ?? {}) };\n const listeners = new Map<string, StateListenerEntry>();\n\n const emit = (path: StatePath) => {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return;\n\n for (const entry of listeners.values()) {\n if (!areStatePathsRelated(pathResult.parts, entry.parts)) continue;\n\n const value = readStatePath(rootState, entry.parts);\n for (const listener of entry.listeners) {\n listener(value);\n }\n }\n };\n\n return {\n capabilities: {\n subscriptions: true,\n computed: false,\n persistence: false,\n },\n get<TValue extends StateValue = StateValue>(path: StatePath): StateResult<TValue | undefined> {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n return createStateDataResult(\n readStatePath(rootState, pathResult.parts) as TValue | undefined,\n );\n },\n set<TValue extends StateValue = StateValue>(path: StatePath, value: TValue): StateResult {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n const nextStateResult = setStatePath(rootState, pathResult.parts, value);\n if (!nextStateResult.ok) return nextStateResult;\n\n rootState = nextStateResult.data;\n emit(path);\n return { ok: true };\n },\n subscribe<TValue extends StateValue = StateValue>(\n path: StatePath,\n listener: StateListener<TValue>,\n ): StateResult<StateSubscription> {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n const key = pathPartsToKey(pathResult.parts);\n const entry = listeners.get(key) ?? {\n listeners: new Set<(value: StateValue | undefined) => void>(),\n parts: pathResult.parts,\n };\n const wrappedListener = (value: StateValue | undefined) => {\n listener({ path, value: value as TValue | undefined });\n };\n\n entry.listeners.add(wrappedListener);\n listeners.set(key, entry);\n\n return createStateDataResult({\n unsubscribe() {\n entry.listeners.delete(wrappedListener);\n if (entry.listeners.size === 0) {\n listeners.delete(key);\n }\n },\n });\n },\n delete(path: StatePath): StateResult {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n const nextStateResult = deleteStatePath(rootState, pathResult.parts);\n if (!nextStateResult.ok) return nextStateResult;\n\n rootState = nextStateResult.data;\n emit(path);\n return { ok: true };\n },\n };\n}\n\ninterface ResolvedStatePath {\n readonly ok: true;\n readonly parts: readonly string[];\n}\n\ninterface StatePathError {\n readonly ok: false;\n readonly error: StateAdapterError;\n}\n\ntype StatePathResult = ResolvedStatePath | StatePathError;\n\nfunction normalizeStatePath(path: StatePath): StatePathResult {\n const parts = typeof path === 'string' ? path.split('.') : [...path];\n const normalized = parts.map((part) => part.trim()).filter(Boolean);\n\n if (normalized.length === 0) {\n return createStateError('invalid_path', 'State path must contain at least one segment.');\n }\n\n return {\n ok: true,\n parts: normalized,\n };\n}\n\nfunction pathPartsToKey(parts: readonly string[]): string {\n return parts.join('.');\n}\n\n/*** Determines whether a state mutation changes an ancestor, descendant, or exact subscription. */\nfunction areStatePathsRelated(\n changedParts: readonly string[],\n subscribedParts: readonly string[],\n): boolean {\n const sharedLength = Math.min(changedParts.length, subscribedParts.length);\n return changedParts\n .slice(0, sharedLength)\n .every((part, index) => part === subscribedParts[index]);\n}\n\nfunction readStatePath(\n source: MutableStateRecord,\n parts: readonly string[],\n): StateValue | undefined {\n let currentValue: StateValue | undefined = source;\n\n for (const part of parts) {\n if (!isStateRecord(currentValue)) {\n return undefined;\n }\n\n currentValue = currentValue[part];\n }\n\n return currentValue;\n}\n\nfunction setStatePath(\n source: MutableStateRecord,\n parts: readonly string[],\n value: StateValue,\n): StateResult<MutableStateRecord> {\n const [head, ...tail] = parts;\n if (head === undefined) {\n return createStateError('invalid_path', 'State path must contain at least one segment.');\n }\n\n if (tail.length === 0) {\n return createStateDataResult({\n ...source,\n [head]: value,\n });\n }\n\n const existing = source[head];\n const child = existing === undefined ? {} : existing;\n if (!isStateRecord(child)) {\n return createStateError(\n 'path_conflict',\n `Cannot set nested state below non-object path segment \"${head}\".`,\n );\n }\n\n const childResult = setStatePath(child, tail, value);\n if (!childResult.ok) return childResult;\n\n return createStateDataResult({\n ...source,\n [head]: childResult.data,\n });\n}\n\nfunction deleteStatePath(\n source: MutableStateRecord,\n parts: readonly string[],\n): StateResult<MutableStateRecord> {\n const [head, ...tail] = parts;\n if (head === undefined) {\n return createStateError('invalid_path', 'State path must contain at least one segment.');\n }\n\n if (tail.length === 0) {\n const nextState: MutableStateRecord = {};\n for (const [key, value] of Object.entries(source)) {\n if (key !== head) {\n nextState[key] = value;\n }\n }\n\n return createStateDataResult(nextState);\n }\n\n const existing = source[head];\n if (existing === undefined) {\n return createStateDataResult(source);\n }\n\n if (!isStateRecord(existing)) {\n return createStateError(\n 'path_conflict',\n `Cannot delete nested state below non-object path segment \"${head}\".`,\n );\n }\n\n const childResult = deleteStatePath(existing, tail);\n if (!childResult.ok) return childResult;\n\n return createStateDataResult({\n ...source,\n [head]: childResult.data,\n });\n}\n\nfunction isStateRecord(value: StateValue | undefined): value is MutableStateRecord {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction createStateError(code: string, message: string): StatePathError {\n const error: StateAdapterError = { code, message };\n return { ok: false, error };\n}\n\nfunction createStateDataResult<TValue>(data: TValue): StateResult<TValue> {\n const result = {\n ok: true,\n data,\n };\n\n return result as StateResult<TValue>;\n}\n"]}
1
+ {"version":3,"file":"runtimeStateAdapter.js","sourceRoot":"","sources":["../src/runtimeStateAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isSerializableValue,\n type StateAdapter,\n type StateAdapterError,\n type StateListener,\n type StatePath,\n type StateResult,\n type StateSubscription,\n type StateUpdate,\n type StateValue,\n} from '@ankhorage/contracts';\n\ntype MutableStateRecord = Record<string, StateValue>;\ntype StateListenerSet = Set<(value: StateValue | undefined) => void>;\ninterface StateListenerEntry {\n readonly listeners: StateListenerSet;\n readonly parts: readonly string[];\n}\n\ninterface StateNotification {\n readonly changedParts: readonly string[];\n readonly state: MutableStateRecord;\n}\n\nexport interface RuntimeMemoryStateAdapterOptions {\n readonly initialState?: Readonly<Record<string, StateValue>>;\n}\n\nexport function createRuntimeMemoryStateAdapter(\n options: RuntimeMemoryStateAdapterOptions = {},\n): StateAdapter {\n let rootState: MutableStateRecord = { ...(options.initialState ?? {}) };\n const listeners = new Map<string, StateListenerEntry>();\n const notifications: StateNotification[] = [];\n let isNotifying = false;\n\n const emit = (path: StatePath) => {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return;\n\n notifications.push({ changedParts: pathResult.parts, state: rootState });\n if (isNotifying) return;\n\n isNotifying = true;\n try {\n while (notifications.length > 0) {\n const notification = notifications.shift();\n if (notification === undefined) continue;\n\n for (const entry of [...listeners.values()]) {\n if (!areStatePathsRelated(notification.changedParts, entry.parts)) continue;\n\n const value = readStatePath(notification.state, entry.parts);\n for (const listener of [...entry.listeners]) {\n listener(value);\n }\n }\n }\n } finally {\n isNotifying = false;\n }\n };\n\n return {\n capabilities: {\n subscriptions: true,\n computed: false,\n persistence: false,\n },\n get<TValue extends StateValue = StateValue>(path: StatePath): StateResult<TValue | undefined> {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n return createStateDataResult(\n readStatePath(rootState, pathResult.parts) as TValue | undefined,\n );\n },\n set<TValue extends StateValue = StateValue>(path: StatePath, value: TValue): StateResult {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n const nextStateResult = setStatePath(rootState, pathResult.parts, value);\n if (!nextStateResult.ok) return nextStateResult;\n\n rootState = nextStateResult.data;\n emit(path);\n return { ok: true };\n },\n update<TValue extends StateValue = StateValue>(\n path: StatePath,\n update: StateUpdate,\n ): StateResult<TValue> {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n const updateResult = applyStateUpdate(readStatePath(rootState, pathResult.parts), update);\n if (!updateResult.ok) return updateResult;\n\n const nextStateResult = setStatePath(rootState, pathResult.parts, updateResult.data);\n if (!nextStateResult.ok) return nextStateResult;\n\n rootState = nextStateResult.data;\n emit(path);\n return createStateDataResult(updateResult.data as TValue);\n },\n subscribe<TValue extends StateValue = StateValue>(\n path: StatePath,\n listener: StateListener<TValue>,\n ): StateResult<StateSubscription> {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n const key = pathPartsToKey(pathResult.parts);\n const entry = listeners.get(key) ?? {\n listeners: new Set<(value: StateValue | undefined) => void>(),\n parts: pathResult.parts,\n };\n const wrappedListener = (value: StateValue | undefined) => {\n listener({ path, value: value as TValue | undefined });\n };\n\n entry.listeners.add(wrappedListener);\n listeners.set(key, entry);\n\n return createStateDataResult({\n unsubscribe() {\n entry.listeners.delete(wrappedListener);\n if (entry.listeners.size === 0) {\n listeners.delete(key);\n }\n },\n });\n },\n delete(path: StatePath): StateResult {\n const pathResult = normalizeStatePath(path);\n if (!pathResult.ok) return pathResult;\n\n const nextStateResult = deleteStatePath(rootState, pathResult.parts);\n if (!nextStateResult.ok) return nextStateResult;\n\n rootState = nextStateResult.data;\n emit(path);\n return { ok: true };\n },\n };\n}\n\ninterface ResolvedStatePath {\n readonly ok: true;\n readonly parts: readonly string[];\n}\n\ninterface StatePathError {\n readonly ok: false;\n readonly error: StateAdapterError;\n}\n\ntype StatePathResult = ResolvedStatePath | StatePathError;\n\nfunction normalizeStatePath(path: StatePath): StatePathResult {\n const parts = typeof path === 'string' ? path.split('.') : [...path];\n const normalized = parts.map((part) => part.trim()).filter(Boolean);\n\n if (normalized.length === 0) {\n return createStateError('invalid_path', 'State path must contain at least one segment.');\n }\n\n return {\n ok: true,\n parts: normalized,\n };\n}\n\nfunction pathPartsToKey(parts: readonly string[]): string {\n return parts.join('.');\n}\n\n/*** Determines whether a state mutation changes an ancestor, descendant, or exact subscription. */\nfunction areStatePathsRelated(\n changedParts: readonly string[],\n subscribedParts: readonly string[],\n): boolean {\n const sharedLength = Math.min(changedParts.length, subscribedParts.length);\n return changedParts\n .slice(0, sharedLength)\n .every((part, index) => part === subscribedParts[index]);\n}\n\nfunction readStatePath(\n source: MutableStateRecord,\n parts: readonly string[],\n): StateValue | undefined {\n let currentValue: StateValue | undefined = source;\n\n for (const part of parts) {\n if (!isStateRecord(currentValue)) {\n return undefined;\n }\n\n currentValue = currentValue[part];\n }\n\n return currentValue;\n}\n\nfunction setStatePath(\n source: MutableStateRecord,\n parts: readonly string[],\n value: StateValue,\n): StateResult<MutableStateRecord> {\n const [head, ...tail] = parts;\n if (head === undefined) {\n return createStateError('invalid_path', 'State path must contain at least one segment.');\n }\n\n if (tail.length === 0) {\n return createStateDataResult({\n ...source,\n [head]: value,\n });\n }\n\n const existing = source[head];\n const child = existing === undefined ? {} : existing;\n if (!isStateRecord(child)) {\n return createStateError(\n 'path_conflict',\n `Cannot set nested state below non-object path segment \"${head}\".`,\n );\n }\n\n const childResult = setStatePath(child, tail, value);\n if (!childResult.ok) return childResult;\n\n return createStateDataResult({\n ...source,\n [head]: childResult.data,\n });\n}\n\n/*** Applies one supported atomic update without observing an intermediate state. */\nfunction applyStateUpdate(\n value: StateValue | undefined,\n update: StateUpdate,\n): StateResult<StateValue> {\n if (value !== undefined && !isStateValueArray(value)) {\n return createStateError(\n 'incompatible_value',\n 'Append updates require an existing array state value.',\n );\n }\n\n return createStateDataResult([...(value ?? []), update.value]);\n}\n\n/*** Narrows a serializable value to an element-preserving state array. */\nfunction isStateValueArray(value: StateValue): value is readonly StateValue[] {\n return Array.isArray(value) && value.every(isSerializableValue);\n}\n\nfunction deleteStatePath(\n source: MutableStateRecord,\n parts: readonly string[],\n): StateResult<MutableStateRecord> {\n const [head, ...tail] = parts;\n if (head === undefined) {\n return createStateError('invalid_path', 'State path must contain at least one segment.');\n }\n\n if (tail.length === 0) {\n const nextState: MutableStateRecord = {};\n for (const [key, value] of Object.entries(source)) {\n if (key !== head) {\n nextState[key] = value;\n }\n }\n\n return createStateDataResult(nextState);\n }\n\n const existing = source[head];\n if (existing === undefined) {\n return createStateDataResult(source);\n }\n\n if (!isStateRecord(existing)) {\n return createStateError(\n 'path_conflict',\n `Cannot delete nested state below non-object path segment \"${head}\".`,\n );\n }\n\n const childResult = deleteStatePath(existing, tail);\n if (!childResult.ok) return childResult;\n\n return createStateDataResult({\n ...source,\n [head]: childResult.data,\n });\n}\n\nfunction isStateRecord(value: StateValue | undefined): value is MutableStateRecord {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction createStateError(code: string, message: string): StatePathError {\n const error: StateAdapterError = { code, message };\n return { ok: false, error };\n}\n\nfunction createStateDataResult<TValue>(data: TValue): StateResult<TValue> {\n const result = {\n ok: true,\n data,\n };\n\n return result as StateResult<TValue>;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/runtime",
3
- "version": "5.1.3",
3
+ "version": "5.2.0",
4
4
  "description": "Platform-neutral runtime renderer, contracts, and helpers for Ankhorage generated apps.",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -166,6 +166,88 @@
166
166
  }
167
167
  }
168
168
  },
169
+ {
170
+ "id": "state.update",
171
+ "owner": "@ankhorage/runtime",
172
+ "access": [
173
+ "invoke",
174
+ "write"
175
+ ],
176
+ "binding": {
177
+ "kind": "state",
178
+ "bindableAs": [
179
+ "target"
180
+ ]
181
+ },
182
+ "label": "Update runtime state",
183
+ "input": {
184
+ "schema": {
185
+ "type": "object",
186
+ "required": [
187
+ "path",
188
+ "update"
189
+ ],
190
+ "properties": {
191
+ "path": {
192
+ "anyOf": [
193
+ {
194
+ "type": "string"
195
+ },
196
+ {
197
+ "type": "array",
198
+ "items": {
199
+ "type": "string"
200
+ }
201
+ }
202
+ ]
203
+ },
204
+ "update": {
205
+ "type": "object",
206
+ "required": [
207
+ "kind",
208
+ "value"
209
+ ],
210
+ "properties": {
211
+ "kind": {
212
+ "type": "string",
213
+ "enum": [
214
+ "append"
215
+ ]
216
+ },
217
+ "value": {}
218
+ }
219
+ }
220
+ }
221
+ }
222
+ },
223
+ "output": {
224
+ "schema": {
225
+ "type": "object",
226
+ "required": [
227
+ "path",
228
+ "value"
229
+ ],
230
+ "properties": {
231
+ "path": {
232
+ "anyOf": [
233
+ {
234
+ "type": "string"
235
+ },
236
+ {
237
+ "type": "array",
238
+ "items": {
239
+ "type": "string"
240
+ }
241
+ }
242
+ ]
243
+ },
244
+ "value": {
245
+ "type": "array"
246
+ }
247
+ }
248
+ }
249
+ }
250
+ },
169
251
  {
170
252
  "id": "runtime.eventOperation",
171
253
  "owner": "@ankhorage/runtime",
@@ -261,7 +343,7 @@
261
343
  },
262
344
  "dependencies": {
263
345
  "@ankhorage/capability": "^0.2.2",
264
- "@ankhorage/contracts": "^26.0.2",
346
+ "@ankhorage/contracts": "^26.2.0",
265
347
  "@ankhorage/data-sources": "^2.1.3",
266
348
  "@ankhorage/utility": "^1.10.0"
267
349
  },
@@ -1,7 +1,7 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="90" height="20" role="img" aria-label="npm: v5.1.3">
2
- <title>npm: v5.1.3</title>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="90" height="20" role="img" aria-label="npm: v5.2.0">
2
+ <title>npm: v5.2.0</title>
3
3
  <rect width="38" height="20" fill="#374151"/>
4
4
  <rect x="38" width="52" height="20" fill="#cb3837"/>
5
5
  <text x="19" y="14" fill="#ffffff" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11" text-anchor="middle">npm</text>
6
- <text x="64" y="14" fill="#ffffff" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11" text-anchor="middle">v5.1.3</text>
6
+ <text x="64" y="14" fill="#ffffff" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11" text-anchor="middle">v5.2.0</text>
7
7
  </svg>
@@ -148,6 +148,9 @@ graph TD
148
148
  module_src_runtimeScreenLoaders_ts["src/runtimeScreenLoaders.ts"]
149
149
  package__ankhorage_runtime -.-> module_src_runtimeScreenLoaders_ts
150
150
  module_src_runtimeScreenLoaders_ts --> module_src_runtimeBindings_ts
151
+ module_src_runtimeStateAdapter_test_ts["src/runtimeStateAdapter.test.ts"]
152
+ package__ankhorage_runtime -.-> module_src_runtimeStateAdapter_test_ts
153
+ module_src_runtimeStateAdapter_test_ts --> module_src_runtimeStateAdapter_ts
151
154
  module_src_runtimeStateAdapter_ts["src/runtimeStateAdapter.ts"]
152
155
  package__ankhorage_runtime -.-> module_src_runtimeStateAdapter_ts
153
156
  module_src_runtimeStateReactivity_test_tsx["src/runtimeStateReactivity.test.tsx"]
@@ -39,6 +39,7 @@ graph LR
39
39
  module_src_RuntimeScreen_tsx["src/RuntimeScreen.tsx"]
40
40
  module_src_runtimeScreenLoaders_test_ts["src/runtimeScreenLoaders.test.ts"]
41
41
  module_src_runtimeScreenLoaders_ts["src/runtimeScreenLoaders.ts"]
42
+ module_src_runtimeStateAdapter_test_ts["src/runtimeStateAdapter.test.ts"]
42
43
  module_src_runtimeStateAdapter_ts["src/runtimeStateAdapter.ts"]
43
44
  module_src_runtimeStateReactivity_test_tsx["src/runtimeStateReactivity.test.tsx"]
44
45
  module_src_useRuntimeMediaProps_ts["src/useRuntimeMediaProps.ts"]
@@ -39,6 +39,7 @@ graph LR
39
39
  module_src_RuntimeScreen_tsx["src/RuntimeScreen.tsx"]
40
40
  module_src_runtimeScreenLoaders_test_ts["src/runtimeScreenLoaders.test.ts"]
41
41
  module_src_runtimeScreenLoaders_ts["src/runtimeScreenLoaders.ts"]
42
+ module_src_runtimeStateAdapter_test_ts["src/runtimeStateAdapter.test.ts"]
42
43
  module_src_runtimeStateAdapter_ts["src/runtimeStateAdapter.ts"]
43
44
  module_src_runtimeStateReactivity_test_tsx["src/runtimeStateReactivity.test.tsx"]
44
45
  module_src_useRuntimeMediaProps_ts["src/useRuntimeMediaProps.ts"]
@@ -113,6 +114,7 @@ graph LR
113
114
  module_src_RuntimeScreen_tsx --> module_src_runtimeStateAdapter_ts
114
115
  module_src_runtimeScreenLoaders_test_ts --> module_src_runtimeScreenLoaders_ts
115
116
  module_src_runtimeScreenLoaders_ts --> module_src_runtimeBindings_ts
117
+ module_src_runtimeStateAdapter_test_ts --> module_src_runtimeStateAdapter_ts
116
118
  module_src_runtimeStateReactivity_test_tsx --> module_src_registry_tsx
117
119
  module_src_runtimeStateReactivity_test_tsx --> module_src_runtimeBindings_ts
118
120
  module_src_runtimeStateReactivity_test_tsx --> module_src_runtimeStateAdapter_ts
@@ -201,7 +201,7 @@
201
201
  "modulePath": "src/runtimeActionRegistry.ts",
202
202
  "sourceLocation": {
203
203
  "filePath": "src/runtimeActionRegistry.ts",
204
- "line": 179,
204
+ "line": 183,
205
205
  "column": 1
206
206
  },
207
207
  "exportPaths": [
@@ -472,7 +472,7 @@
472
472
  "modulePath": "src/runtimeStateAdapter.ts",
473
473
  "sourceLocation": {
474
474
  "filePath": "src/runtimeStateAdapter.ts",
475
- "line": 22,
475
+ "line": 29,
476
476
  "column": 1
477
477
  },
478
478
  "exportPaths": [
@@ -1012,7 +1012,7 @@
1012
1012
  "modulePath": "src/runtimeActionRegistry.ts",
1013
1013
  "sourceLocation": {
1014
1014
  "filePath": "src/runtimeActionRegistry.ts",
1015
- "line": 193,
1015
+ "line": 197,
1016
1016
  "column": 1
1017
1017
  },
1018
1018
  "exportPaths": [
@@ -2897,7 +2897,7 @@
2897
2897
  "modulePath": "src/runtimeStateAdapter.ts",
2898
2898
  "sourceLocation": {
2899
2899
  "filePath": "src/runtimeStateAdapter.ts",
2900
- "line": 18,
2900
+ "line": 25,
2901
2901
  "column": 1
2902
2902
  },
2903
2903
  "exportPaths": [
@@ -3804,7 +3804,7 @@
3804
3804
  "modulePath": "src/runtimeActionRegistry.ts",
3805
3805
  "sourceLocation": {
3806
3806
  "filePath": "src/runtimeActionRegistry.ts",
3807
- "line": 149,
3807
+ "line": 153,
3808
3808
  "column": 1
3809
3809
  },
3810
3810
  "exportPaths": [
@@ -65,7 +65,7 @@ Source: `src/RuntimeRendererConfig.tsx:64:1`
65
65
 
66
66
  Kind: `function`
67
67
  Module: `src/runtimeActionRegistry.ts`
68
- Source: `src/runtimeActionRegistry.ts:179:1`
68
+ Source: `src/runtimeActionRegistry.ts:183:1`
69
69
 
70
70
  Maps a platform callback invocation to the portable component event representation.
71
71
 
@@ -158,7 +158,7 @@ Source: `src/runtimeEventOperationLifecycle.ts:40:1`
158
158
 
159
159
  Kind: `function`
160
160
  Module: `src/runtimeStateAdapter.ts`
161
- Source: `src/runtimeStateAdapter.ts:22:1`
161
+ Source: `src/runtimeStateAdapter.ts:29:1`
162
162
 
163
163
  ### Signatures
164
164
 
@@ -339,7 +339,7 @@ Resolves an invocation input map without executing a capability.
339
339
 
340
340
  Kind: `function`
341
341
  Module: `src/runtimeActionRegistry.ts`
342
- Source: `src/runtimeActionRegistry.ts:193:1`
342
+ Source: `src/runtimeActionRegistry.ts:197:1`
343
343
 
344
344
  Resolves an authored expression-shaped payload for imperative consumers.
345
345
 
@@ -892,7 +892,7 @@ Source: `src/runtimeMedia.ts:9:1`
892
892
 
893
893
  Kind: `type`
894
894
  Module: `src/runtimeStateAdapter.ts`
895
- Source: `src/runtimeStateAdapter.ts:18:1`
895
+ Source: `src/runtimeStateAdapter.ts:25:1`
896
896
 
897
897
  ### Members
898
898
 
@@ -1155,7 +1155,7 @@ Runs screen capability invocations when their serialized request input changes.
1155
1155
 
1156
1156
  Kind: `function`
1157
1157
  Module: `src/runtimeActionRegistry.ts`
1158
- Source: `src/runtimeActionRegistry.ts:149:1`
1158
+ Source: `src/runtimeActionRegistry.ts:153:1`
1159
1159
 
1160
1160
  Wraps component callbacks so manifest event bindings retain the original callback behavior.
1161
1161