@manifesto-ai/core 1.0.0 → 1.3.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/README.md +33 -13
- package/dist/__tests__/apply.test.d.ts +2 -0
- package/dist/__tests__/apply.test.d.ts.map +1 -0
- package/dist/__tests__/apply.test.js +144 -0
- package/dist/__tests__/apply.test.js.map +1 -0
- package/dist/__tests__/jcs.test.d.ts +2 -0
- package/dist/__tests__/jcs.test.d.ts.map +1 -0
- package/dist/__tests__/jcs.test.js +45 -0
- package/dist/__tests__/jcs.test.js.map +1 -0
- package/dist/core/apply.d.ts +2 -1
- package/dist/core/apply.d.ts.map +1 -1
- package/dist/core/apply.js +92 -14
- package/dist/core/apply.js.map +1 -1
- package/dist/core/compute.d.ts.map +1 -1
- package/dist/core/compute.js +95 -5
- package/dist/core/compute.js.map +1 -1
- package/dist/core/compute.test.js +291 -58
- package/dist/core/compute.test.js.map +1 -1
- package/dist/core/explain.d.ts.map +1 -1
- package/dist/core/explain.js +14 -10
- package/dist/core/explain.js.map +1 -1
- package/dist/core/validate.d.ts +2 -1
- package/dist/core/validate.d.ts.map +1 -1
- package/dist/core/validate.js +219 -1
- package/dist/core/validate.js.map +1 -1
- package/dist/core/validate.test.js +196 -8
- package/dist/core/validate.test.js.map +1 -1
- package/dist/core/validation-utils.d.ts +20 -0
- package/dist/core/validation-utils.d.ts.map +1 -0
- package/dist/core/validation-utils.js +289 -0
- package/dist/core/validation-utils.js.map +1 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/evaluator/computed.d.ts.map +1 -1
- package/dist/evaluator/computed.js +7 -4
- package/dist/evaluator/computed.js.map +1 -1
- package/dist/evaluator/context.d.ts +14 -1
- package/dist/evaluator/context.d.ts.map +1 -1
- package/dist/evaluator/context.js +7 -1
- package/dist/evaluator/context.js.map +1 -1
- package/dist/evaluator/expr.d.ts.map +1 -1
- package/dist/evaluator/expr.js +155 -4
- package/dist/evaluator/expr.js.map +1 -1
- package/dist/evaluator/expr.test.js +27 -4
- package/dist/evaluator/expr.test.js.map +1 -1
- package/dist/evaluator/flow.d.ts.map +1 -1
- package/dist/evaluator/flow.js +175 -22
- package/dist/evaluator/flow.js.map +1 -1
- package/dist/evaluator/flow.test.js +59 -6
- package/dist/evaluator/flow.test.js.map +1 -1
- package/dist/factories.d.ts +4 -2
- package/dist/factories.d.ts.map +1 -1
- package/dist/factories.js +20 -19
- package/dist/factories.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/schema/domain.d.ts +4 -0
- package/dist/schema/domain.d.ts.map +1 -1
- package/dist/schema/domain.js +6 -0
- package/dist/schema/domain.js.map +1 -1
- package/dist/schema/expr.d.ts +44 -1
- package/dist/schema/expr.d.ts.map +1 -1
- package/dist/schema/expr.js +40 -4
- package/dist/schema/expr.js.map +1 -1
- package/dist/schema/host-context.d.ts +12 -0
- package/dist/schema/host-context.d.ts.map +1 -0
- package/dist/schema/host-context.js +23 -0
- package/dist/schema/host-context.js.map +1 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/result.d.ts +12 -0
- package/dist/schema/result.d.ts.map +1 -1
- package/dist/schema/result.js +5 -1
- package/dist/schema/result.js.map +1 -1
- package/dist/schema/snapshot.d.ts +2 -0
- package/dist/schema/snapshot.d.ts.map +1 -1
- package/dist/schema/snapshot.js +4 -0
- package/dist/schema/snapshot.js.map +1 -1
- package/dist/schema/trace.d.ts +12 -1
- package/dist/schema/trace.d.ts.map +1 -1
- package/dist/schema/trace.js +14 -3
- package/dist/schema/trace.js.map +1 -1
- package/dist/schema/type-spec.d.ts +34 -0
- package/dist/schema/type-spec.d.ts.map +1 -0
- package/dist/schema/type-spec.js +40 -0
- package/dist/schema/type-spec.js.map +1 -0
- package/dist/utils/canonical.d.ts +8 -0
- package/dist/utils/canonical.d.ts.map +1 -1
- package/dist/utils/canonical.js +66 -0
- package/dist/utils/canonical.js.map +1 -1
- package/dist/utils/canonical.test.js +31 -1
- package/dist/utils/canonical.test.js.map +1 -1
- package/dist/utils/hash.d.ts +9 -1
- package/dist/utils/hash.d.ts.map +1 -1
- package/dist/utils/hash.js +116 -2
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/hash.test.js +44 -20
- package/dist/utils/hash.test.js.map +1 -1
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -63,32 +63,52 @@ const core = createCore();
|
|
|
63
63
|
|
|
64
64
|
// Define a simple schema (usually from @manifesto-ai/builder)
|
|
65
65
|
const schema: DomainSchema = {
|
|
66
|
+
id: "example:counter",
|
|
66
67
|
version: "1.0.0",
|
|
68
|
+
hash: "example-hash",
|
|
69
|
+
types: {},
|
|
67
70
|
state: {
|
|
68
|
-
|
|
71
|
+
fields: {
|
|
72
|
+
count: { type: "number", required: true, default: 0 },
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
computed: {
|
|
76
|
+
fields: {
|
|
77
|
+
"computed.count": {
|
|
78
|
+
deps: ["count"],
|
|
79
|
+
expr: { kind: "get", path: "count" },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
69
82
|
},
|
|
70
83
|
actions: {
|
|
71
84
|
increment: {
|
|
72
85
|
flow: {
|
|
73
86
|
kind: "patch",
|
|
74
87
|
op: "set",
|
|
75
|
-
path: "
|
|
76
|
-
value: {
|
|
88
|
+
path: "count",
|
|
89
|
+
value: {
|
|
90
|
+
kind: "add",
|
|
91
|
+
left: { kind: "get", path: "count" },
|
|
92
|
+
right: { kind: "lit", value: 1 },
|
|
93
|
+
},
|
|
77
94
|
},
|
|
78
95
|
},
|
|
79
96
|
},
|
|
80
97
|
};
|
|
81
98
|
|
|
99
|
+
// Create host context (deterministic inputs)
|
|
100
|
+
const context = { now: 0, randomSeed: "seed" };
|
|
101
|
+
|
|
82
102
|
// Create initial snapshot
|
|
83
|
-
const snapshot = createSnapshot(schema);
|
|
103
|
+
const snapshot = createSnapshot({ count: 0 }, schema.hash, context);
|
|
84
104
|
|
|
85
105
|
// Create intent
|
|
86
|
-
const intent = createIntent("increment");
|
|
106
|
+
const intent = createIntent("increment", "intent-1");
|
|
87
107
|
|
|
88
108
|
// Compute result (pure, deterministic)
|
|
89
|
-
const result = await core.compute(schema, snapshot, intent);
|
|
109
|
+
const result = await core.compute(schema, snapshot, intent, context);
|
|
90
110
|
|
|
91
|
-
console.log(result.status); // → "
|
|
111
|
+
console.log(result.status); // → "complete"
|
|
92
112
|
console.log(result.snapshot.data.count); // → 1
|
|
93
113
|
```
|
|
94
114
|
|
|
@@ -106,18 +126,18 @@ function createCore(): ManifestoCore;
|
|
|
106
126
|
|
|
107
127
|
// Core interface
|
|
108
128
|
interface ManifestoCore {
|
|
109
|
-
compute(schema, snapshot, intent): Promise<ComputeResult>;
|
|
110
|
-
apply(schema, snapshot, patches): Snapshot;
|
|
129
|
+
compute(schema, snapshot, intent, context): Promise<ComputeResult>;
|
|
130
|
+
apply(schema, snapshot, patches, context): Snapshot;
|
|
111
131
|
validate(schema): ValidationResult;
|
|
112
132
|
explain(schema, snapshot, path): ExplainResult;
|
|
113
133
|
}
|
|
114
134
|
|
|
115
135
|
// Key types
|
|
116
|
-
type DomainSchema = { version, state, computed
|
|
136
|
+
type DomainSchema = { id, version, hash, types, state, computed, actions, meta? };
|
|
117
137
|
type Snapshot = { data, computed, system, input, meta };
|
|
118
138
|
type Intent = { type, input?, intentId };
|
|
119
139
|
type Patch = { op: "set" | "unset" | "merge", path, value? };
|
|
120
|
-
type ComputeResult = { status, snapshot,
|
|
140
|
+
type ComputeResult = { status, snapshot, requirements, trace };
|
|
121
141
|
```
|
|
122
142
|
|
|
123
143
|
> See [SPEC.md](../../docs/packages/core/SPEC.md) for complete API reference.
|
|
@@ -186,8 +206,8 @@ For typical usage, see [`@manifesto-ai/react`](../react/) or [`@manifesto-ai/hos
|
|
|
186
206
|
| Document | Purpose |
|
|
187
207
|
|----------|---------|
|
|
188
208
|
| [GUIDE.md](../../docs/packages/core/GUIDE.md) | Step-by-step usage guide |
|
|
189
|
-
| [SPEC.md](
|
|
190
|
-
| [FDR.md](
|
|
209
|
+
| [SPEC.md](docs/SPEC.md) | Complete specification |
|
|
210
|
+
| [FDR.md](docs/FDR.md) | Design rationale |
|
|
191
211
|
|
|
192
212
|
---
|
|
193
213
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/apply.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { apply } from "../core/apply.js";
|
|
3
|
+
import { createSnapshot } from "../factories.js";
|
|
4
|
+
const HOST_CONTEXT = { now: 0, randomSeed: "seed" };
|
|
5
|
+
describe("apply", () => {
|
|
6
|
+
it("should surface computed evaluation errors as values", () => {
|
|
7
|
+
const schema = {
|
|
8
|
+
id: "manifesto:test",
|
|
9
|
+
version: "1.0.0",
|
|
10
|
+
hash: "test-hash",
|
|
11
|
+
types: {},
|
|
12
|
+
state: {
|
|
13
|
+
fields: {
|
|
14
|
+
dummy: { type: "string", required: true },
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
computed: {
|
|
18
|
+
fields: {
|
|
19
|
+
"computed.a": {
|
|
20
|
+
expr: { kind: "get", path: "computed.b" },
|
|
21
|
+
deps: ["computed.b"],
|
|
22
|
+
},
|
|
23
|
+
"computed.b": {
|
|
24
|
+
expr: { kind: "get", path: "computed.a" },
|
|
25
|
+
deps: ["computed.a"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
actions: {
|
|
30
|
+
noop: { flow: { kind: "halt", reason: "noop" } },
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const snapshot = createSnapshot({ dummy: "initial" }, schema.hash, HOST_CONTEXT);
|
|
34
|
+
const result = apply(schema, snapshot, [{ op: "set", path: "dummy", value: "updated" }], HOST_CONTEXT);
|
|
35
|
+
expect(result.data).toEqual({ dummy: "updated" });
|
|
36
|
+
expect(result.system.status).toBe("error");
|
|
37
|
+
expect(result.system.lastError?.code).toBe("CYCLIC_DEPENDENCY");
|
|
38
|
+
expect(result.computed).toEqual({});
|
|
39
|
+
});
|
|
40
|
+
it("should record errors for unknown patch paths", () => {
|
|
41
|
+
const schema = {
|
|
42
|
+
id: "manifesto:test",
|
|
43
|
+
version: "1.0.0",
|
|
44
|
+
hash: "test-hash",
|
|
45
|
+
types: {},
|
|
46
|
+
state: {
|
|
47
|
+
fields: {
|
|
48
|
+
dummy: { type: "string", required: true },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
computed: { fields: {} },
|
|
52
|
+
actions: {
|
|
53
|
+
noop: { flow: { kind: "halt", reason: "noop" } },
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const snapshot = createSnapshot({ dummy: "initial" }, schema.hash, HOST_CONTEXT);
|
|
57
|
+
const result = apply(schema, snapshot, [{ op: "set", path: "missing", value: "value" }], HOST_CONTEXT);
|
|
58
|
+
expect(result.data).toEqual({ dummy: "initial" });
|
|
59
|
+
expect(result.system.status).toBe("error");
|
|
60
|
+
expect(result.system.lastError?.code).toBe("PATH_NOT_FOUND");
|
|
61
|
+
});
|
|
62
|
+
it("should record errors for invalid patch value types", () => {
|
|
63
|
+
const schema = {
|
|
64
|
+
id: "manifesto:test",
|
|
65
|
+
version: "1.0.0",
|
|
66
|
+
hash: "test-hash",
|
|
67
|
+
types: {},
|
|
68
|
+
state: {
|
|
69
|
+
fields: {
|
|
70
|
+
dummy: { type: "string", required: true },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
computed: { fields: {} },
|
|
74
|
+
actions: {
|
|
75
|
+
noop: { flow: { kind: "halt", reason: "noop" } },
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const snapshot = createSnapshot({ dummy: "initial" }, schema.hash, HOST_CONTEXT);
|
|
79
|
+
const result = apply(schema, snapshot, [{ op: "set", path: "dummy", value: 42 }], HOST_CONTEXT);
|
|
80
|
+
expect(result.data).toEqual({ dummy: "initial" });
|
|
81
|
+
expect(result.system.status).toBe("error");
|
|
82
|
+
expect(result.system.lastError?.code).toBe("TYPE_MISMATCH");
|
|
83
|
+
});
|
|
84
|
+
it("should ignore patches to computed and meta", () => {
|
|
85
|
+
const schema = {
|
|
86
|
+
id: "manifesto:test",
|
|
87
|
+
version: "1.0.0",
|
|
88
|
+
hash: "test-hash",
|
|
89
|
+
types: {},
|
|
90
|
+
state: {
|
|
91
|
+
fields: {
|
|
92
|
+
count: { type: "number", required: true },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
computed: {
|
|
96
|
+
fields: {
|
|
97
|
+
"computed.double": {
|
|
98
|
+
expr: {
|
|
99
|
+
kind: "mul",
|
|
100
|
+
left: { kind: "get", path: "count" },
|
|
101
|
+
right: { kind: "lit", value: 2 },
|
|
102
|
+
},
|
|
103
|
+
deps: ["count"],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
actions: {
|
|
108
|
+
noop: { flow: { kind: "halt", reason: "noop" } },
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
const snapshot = createSnapshot({ count: 2 }, schema.hash, HOST_CONTEXT);
|
|
112
|
+
const result = apply(schema, snapshot, [
|
|
113
|
+
{ op: "set", path: "computed.double", value: 999 },
|
|
114
|
+
{ op: "set", path: "meta.version", value: 999 },
|
|
115
|
+
{ op: "set", path: "count", value: 3 },
|
|
116
|
+
], HOST_CONTEXT);
|
|
117
|
+
expect(result.data).toEqual({ count: 3 });
|
|
118
|
+
expect(result.computed["computed.double"]).toBe(6);
|
|
119
|
+
expect(result.meta.version).toBe(snapshot.meta.version + 1);
|
|
120
|
+
});
|
|
121
|
+
it("should record errors for merge patches on non-object fields", () => {
|
|
122
|
+
const schema = {
|
|
123
|
+
id: "manifesto:test",
|
|
124
|
+
version: "1.0.0",
|
|
125
|
+
hash: "test-hash",
|
|
126
|
+
types: {},
|
|
127
|
+
state: {
|
|
128
|
+
fields: {
|
|
129
|
+
name: { type: "string", required: true },
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
computed: { fields: {} },
|
|
133
|
+
actions: {
|
|
134
|
+
noop: { flow: { kind: "halt", reason: "noop" } },
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
const snapshot = createSnapshot({ name: "initial" }, schema.hash, HOST_CONTEXT);
|
|
138
|
+
const result = apply(schema, snapshot, [{ op: "merge", path: "name", value: { extra: "value" } }], HOST_CONTEXT);
|
|
139
|
+
expect(result.data).toEqual({ name: "initial" });
|
|
140
|
+
expect(result.system.status).toBe("error");
|
|
141
|
+
expect(result.system.lastError?.code).toBe("TYPE_MISMATCH");
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=apply.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.test.js","sourceRoot":"","sources":["../../src/__tests__/apply.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jcs.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/jcs.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { toJcs } from "../utils/canonical.js";
|
|
3
|
+
describe("toJcs", () => {
|
|
4
|
+
it("should serialize -0 as 0", () => {
|
|
5
|
+
expect(toJcs(-0)).toBe("0");
|
|
6
|
+
});
|
|
7
|
+
it("should use exponent form for large and small numbers", () => {
|
|
8
|
+
expect(toJcs(1e21)).toBe("1e+21");
|
|
9
|
+
expect(toJcs(1e-7)).toBe("1e-7");
|
|
10
|
+
});
|
|
11
|
+
it("should omit undefined and symbol object properties", () => {
|
|
12
|
+
const sym = Symbol("x");
|
|
13
|
+
const value = { b: 1, a: undefined, c: sym, d: null };
|
|
14
|
+
expect(toJcs(value)).toBe('{"b":1,"d":null}');
|
|
15
|
+
});
|
|
16
|
+
it("should convert non-serializable array items to null", () => {
|
|
17
|
+
const sym = Symbol("x");
|
|
18
|
+
const fn = () => { };
|
|
19
|
+
expect(toJcs([1, undefined, fn, sym, 2])).toBe("[1,null,null,null,2]");
|
|
20
|
+
});
|
|
21
|
+
it("should escape control characters in strings", () => {
|
|
22
|
+
const value = { text: "line\nbreak\tend" };
|
|
23
|
+
expect(toJcs(value)).toBe("{\"text\":\"line\\nbreak\\tend\"}");
|
|
24
|
+
});
|
|
25
|
+
it("should order keys by code point, including surrogate pairs", () => {
|
|
26
|
+
const keyA = "\uD834\uDD1E";
|
|
27
|
+
const keyB = "\uD834\uDD1F";
|
|
28
|
+
const value = {
|
|
29
|
+
[keyB]: 2,
|
|
30
|
+
a: 3,
|
|
31
|
+
[keyA]: 1,
|
|
32
|
+
};
|
|
33
|
+
const expected = `{"a":3,${JSON.stringify(keyA)}:1,${JSON.stringify(keyB)}:2}`;
|
|
34
|
+
expect(toJcs(value)).toBe(expected);
|
|
35
|
+
});
|
|
36
|
+
it("should escape quotes and backslashes", () => {
|
|
37
|
+
const value = { text: "quote\"slash\\end" };
|
|
38
|
+
expect(toJcs(value)).toBe("{\"text\":\"quote\\\"slash\\\\end\"}");
|
|
39
|
+
});
|
|
40
|
+
it("should escape null character", () => {
|
|
41
|
+
const value = { text: "nul\u0000end" };
|
|
42
|
+
expect(toJcs(value)).toBe("{\"text\":\"nul\\u0000end\"}");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=jcs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jcs.test.js","sourceRoot":"","sources":["../../src/__tests__/jcs.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE9C,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;QAEtD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,MAAM,EAAE,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QAEpB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;QAE3C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,IAAI,GAAG,cAAc,CAAC;QAC5B,MAAM,IAAI,GAAG,cAAc,CAAC;QAC5B,MAAM,KAAK,GAA2B;YACpC,CAAC,IAAI,CAAC,EAAE,CAAC;YACT,CAAC,EAAE,CAAC;YACJ,CAAC,IAAI,CAAC,EAAE,CAAC;SACV,CAAC;QAEF,MAAM,QAAQ,GAAG,UAAU,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;QAE/E,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;QAE5C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;QAEvC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/core/apply.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DomainSchema } from "../schema/domain.js";
|
|
2
2
|
import type { Snapshot } from "../schema/snapshot.js";
|
|
3
3
|
import type { Patch } from "../schema/patch.js";
|
|
4
|
+
import type { HostContext } from "../schema/host-context.js";
|
|
4
5
|
/**
|
|
5
6
|
* Apply patches to a snapshot
|
|
6
7
|
*
|
|
@@ -12,5 +13,5 @@ import type { Patch } from "../schema/patch.js";
|
|
|
12
13
|
*
|
|
13
14
|
* Note: Version and timestamp are Core-owned - Host MUST NOT modify these directly.
|
|
14
15
|
*/
|
|
15
|
-
export declare function apply(schema: DomainSchema, snapshot: Snapshot, patches: readonly Patch[]): Snapshot;
|
|
16
|
+
export declare function apply(schema: DomainSchema, snapshot: Snapshot, patches: readonly Patch[], context: HostContext): Snapshot;
|
|
16
17
|
//# sourceMappingURL=apply.d.ts.map
|
package/dist/core/apply.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAS7D;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CACnB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,SAAS,KAAK,EAAE,EACzB,OAAO,EAAE,WAAW,GACnB,QAAQ,CA2GV"}
|
package/dist/core/apply.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { setByPath, unsetByPath, mergeAtPath } from "../utils/path.js";
|
|
2
2
|
import { evaluateComputed } from "../evaluator/computed.js";
|
|
3
|
-
import { isOk } from "../schema/common.js";
|
|
3
|
+
import { isOk, isErr } from "../schema/common.js";
|
|
4
|
+
import { createError } from "../errors.js";
|
|
5
|
+
import { getFieldSpecAtPath, validateValueAgainstFieldSpec } from "./validation-utils.js";
|
|
4
6
|
/**
|
|
5
7
|
* Apply patches to a snapshot
|
|
6
8
|
*
|
|
@@ -12,41 +14,117 @@ import { isOk } from "../schema/common.js";
|
|
|
12
14
|
*
|
|
13
15
|
* Note: Version and timestamp are Core-owned - Host MUST NOT modify these directly.
|
|
14
16
|
*/
|
|
15
|
-
export function apply(schema, snapshot, patches) {
|
|
16
|
-
// 1. Apply patches to data
|
|
17
|
+
export function apply(schema, snapshot, patches, context) {
|
|
18
|
+
// 1. Apply patches to data/system/input (data is default root)
|
|
17
19
|
let newData = snapshot.data;
|
|
20
|
+
let newSystem = snapshot.system;
|
|
21
|
+
let newInput = snapshot.input;
|
|
22
|
+
const validationErrors = [];
|
|
23
|
+
const rootSpec = { type: "object", required: true, fields: schema.state.fields };
|
|
18
24
|
for (const patch of patches) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
const { root, subPath } = splitPatchPath(patch.path);
|
|
26
|
+
switch (root) {
|
|
27
|
+
case "data":
|
|
28
|
+
{
|
|
29
|
+
const fieldSpec = getFieldSpecAtPath(rootSpec, subPath);
|
|
30
|
+
if (!fieldSpec) {
|
|
31
|
+
validationErrors.push(createError("PATH_NOT_FOUND", `Unknown patch path: ${patch.path}`, snapshot.system.currentAction ?? "", patch.path, context.now, { patch }));
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
if (patch.op !== "unset") {
|
|
35
|
+
const result = validateValueAgainstFieldSpec(patch.value, fieldSpec, {
|
|
36
|
+
allowPartial: patch.op === "merge",
|
|
37
|
+
allowUndefined: false,
|
|
38
|
+
});
|
|
39
|
+
if (!result.ok) {
|
|
40
|
+
validationErrors.push(createError("TYPE_MISMATCH", `Invalid patch value at ${patch.path}: ${result.message ?? "type mismatch"}`, snapshot.system.currentAction ?? "", patch.path, context.now, { patch }));
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
newData = applyPatch(newData, patch, subPath);
|
|
45
|
+
}
|
|
22
46
|
break;
|
|
23
|
-
case "
|
|
24
|
-
|
|
47
|
+
case "system":
|
|
48
|
+
newSystem = applyPatch(newSystem, patch, subPath);
|
|
25
49
|
break;
|
|
26
|
-
case "
|
|
27
|
-
|
|
50
|
+
case "input":
|
|
51
|
+
newInput = applyPatch(newInput, patch, subPath);
|
|
52
|
+
break;
|
|
53
|
+
case "computed":
|
|
54
|
+
case "meta":
|
|
55
|
+
// Computed/meta are Core-owned; ignore external patch attempts.
|
|
28
56
|
break;
|
|
29
57
|
}
|
|
30
58
|
}
|
|
59
|
+
if (validationErrors.length > 0) {
|
|
60
|
+
const lastError = validationErrors[validationErrors.length - 1];
|
|
61
|
+
newSystem = {
|
|
62
|
+
...newSystem,
|
|
63
|
+
status: "error",
|
|
64
|
+
lastError,
|
|
65
|
+
errors: [...newSystem.errors, ...validationErrors],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
31
68
|
// 2. Create intermediate snapshot with new data
|
|
32
69
|
const intermediateSnapshot = {
|
|
33
70
|
...snapshot,
|
|
34
71
|
data: newData,
|
|
72
|
+
system: newSystem,
|
|
73
|
+
input: newInput,
|
|
35
74
|
};
|
|
36
75
|
// 3. Recompute all computed values
|
|
37
76
|
const computedResult = evaluateComputed(schema, intermediateSnapshot);
|
|
38
|
-
|
|
77
|
+
let computed = snapshot.computed;
|
|
78
|
+
if (isOk(computedResult)) {
|
|
79
|
+
computed = computedResult.value;
|
|
80
|
+
}
|
|
81
|
+
else if (isErr(computedResult)) {
|
|
82
|
+
const error = computedResult.error;
|
|
83
|
+
computed = {};
|
|
84
|
+
newSystem = {
|
|
85
|
+
...newSystem,
|
|
86
|
+
status: "error",
|
|
87
|
+
lastError: error,
|
|
88
|
+
errors: [...newSystem.errors, error],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
39
91
|
// 4. Return new snapshot with updated metadata
|
|
40
92
|
return {
|
|
41
93
|
data: newData,
|
|
42
94
|
computed,
|
|
43
|
-
system:
|
|
44
|
-
input:
|
|
95
|
+
system: newSystem,
|
|
96
|
+
input: newInput,
|
|
45
97
|
meta: {
|
|
46
98
|
...snapshot.meta,
|
|
47
99
|
version: snapshot.meta.version + 1,
|
|
48
|
-
timestamp:
|
|
100
|
+
timestamp: context.now,
|
|
101
|
+
randomSeed: context.randomSeed,
|
|
49
102
|
},
|
|
50
103
|
};
|
|
51
104
|
}
|
|
105
|
+
function splitPatchPath(path) {
|
|
106
|
+
if (path === "system" || path.startsWith("system.")) {
|
|
107
|
+
return { root: "system", subPath: path === "system" ? "" : path.slice(7) };
|
|
108
|
+
}
|
|
109
|
+
if (path === "input" || path.startsWith("input.")) {
|
|
110
|
+
return { root: "input", subPath: path === "input" ? "" : path.slice(6) };
|
|
111
|
+
}
|
|
112
|
+
if (path === "computed" || path.startsWith("computed.")) {
|
|
113
|
+
return { root: "computed", subPath: path === "computed" ? "" : path.slice(9) };
|
|
114
|
+
}
|
|
115
|
+
if (path === "meta" || path.startsWith("meta.")) {
|
|
116
|
+
return { root: "meta", subPath: path === "meta" ? "" : path.slice(5) };
|
|
117
|
+
}
|
|
118
|
+
return { root: "data", subPath: path };
|
|
119
|
+
}
|
|
120
|
+
function applyPatch(value, patch, subPath) {
|
|
121
|
+
switch (patch.op) {
|
|
122
|
+
case "set":
|
|
123
|
+
return setByPath(value, subPath, patch.value);
|
|
124
|
+
case "unset":
|
|
125
|
+
return unsetByPath(value, subPath);
|
|
126
|
+
case "merge":
|
|
127
|
+
return mergeAtPath(value, subPath, patch.value);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
52
130
|
//# sourceMappingURL=apply.js.map
|
package/dist/core/apply.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAE1F;;;;;;;;;;GAUG;AACH,MAAM,UAAU,KAAK,CACnB,MAAoB,EACpB,QAAkB,EAClB,OAAyB,EACzB,OAAoB;IAEpB,+DAA+D;IAC/D,IAAI,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC5B,IAAI,SAAS,GAAgB,QAAQ,CAAC,MAAM,CAAC;IAC7C,IAAI,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC9B,MAAM,gBAAgB,GAAiB,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IAE5F,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrD,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,MAAM;gBACT,CAAC;oBACC,MAAM,SAAS,GAAG,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;oBACxD,IAAI,CAAC,SAAS,EAAE,CAAC;wBACf,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAC/B,gBAAgB,EAChB,uBAAuB,KAAK,CAAC,IAAI,EAAE,EACnC,QAAQ,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE,EACnC,KAAK,CAAC,IAAI,EACV,OAAO,CAAC,GAAG,EACX,EAAE,KAAK,EAAE,CACV,CAAC,CAAC;wBACH,MAAM;oBACR,CAAC;oBAED,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;wBACzB,MAAM,MAAM,GAAG,6BAA6B,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE;4BACnE,YAAY,EAAE,KAAK,CAAC,EAAE,KAAK,OAAO;4BAClC,cAAc,EAAE,KAAK;yBACtB,CAAC,CAAC;wBACH,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;4BACf,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAC/B,eAAe,EACf,0BAA0B,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,IAAI,eAAe,EAAE,EAC5E,QAAQ,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE,EACnC,KAAK,CAAC,IAAI,EACV,OAAO,CAAC,GAAG,EACX,EAAE,KAAK,EAAE,CACV,CAAC,CAAC;4BACH,MAAM;wBACR,CAAC;oBACH,CAAC;oBAED,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;gBAChD,CAAC;gBACD,MAAM;YACR,KAAK,QAAQ;gBACX,SAAS,GAAG,UAAU,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAgB,CAAC;gBACjE,MAAM;YACR,KAAK,OAAO;gBACV,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;gBAChD,MAAM;YACR,KAAK,UAAU,CAAC;YAChB,KAAK,MAAM;gBACT,gEAAgE;gBAChE,MAAM;QACV,CAAC;IACH,CAAC;IAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAChE,SAAS,GAAG;YACV,GAAG,SAAS;YACZ,MAAM,EAAE,OAAO;YACf,SAAS;YACT,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG,gBAAgB,CAAC;SACnD,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,MAAM,oBAAoB,GAAa;QACrC,GAAG,QAAQ;QACX,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,SAAS;QACjB,KAAK,EAAE,QAAQ;KAChB,CAAC;IAEF,mCAAmC;IACnC,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACtE,IAAI,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;IACjC,IAAI,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QACzB,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC;IAClC,CAAC;SAAM,IAAI,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC;QACnC,QAAQ,GAAG,EAAE,CAAC;QACd,SAAS,GAAG;YACV,GAAG,SAAS;YACZ,MAAM,EAAE,OAAO;YACf,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;SACrC,CAAC;IACJ,CAAC;IAED,+CAA+C;IAC/C,OAAO;QACL,IAAI,EAAE,OAAO;QACb,QAAQ;QACR,MAAM,EAAE,SAAS;QACjB,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE;YACJ,GAAG,QAAQ,CAAC,IAAI;YAChB,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC;YAClC,SAAS,EAAE,OAAO,CAAC,GAAG;YACtB,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B;KACF,CAAC;AACJ,CAAC;AAID,SAAS,cAAc,CAAC,IAAY;IAClC,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,CAAC;IACD,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACxD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,KAAY,EAAE,OAAe;IAC/D,QAAQ,KAAK,CAAC,EAAE,EAAE,CAAC;QACjB,KAAK,KAAK;YACR,OAAO,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAChD,KAAK,OAAO;YACV,OAAO,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACrC,KAAK,OAAO;YACV,OAAO,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../../src/core/compute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../../src/core/compute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAC;AAUxE;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CAiKxB"}
|
package/dist/core/compute.js
CHANGED
|
@@ -31,15 +31,29 @@ export async function compute(schema, snapshot, intent) {
|
|
|
31
31
|
if (!action) {
|
|
32
32
|
return createErrorResult(currentSnapshot, intent, "UNKNOWN_ACTION", `Unknown action: ${intent.type}`, startTime);
|
|
33
33
|
}
|
|
34
|
+
// 1.5 Validate intentId (must be non-empty)
|
|
35
|
+
if (!intent.intentId || intent.intentId === "") {
|
|
36
|
+
return createErrorResult(currentSnapshot, intent, "INVALID_INPUT", "Intent must have a non-empty intentId", startTime);
|
|
37
|
+
}
|
|
38
|
+
// 1.6 Validate input against action's input schema
|
|
39
|
+
if (action.input) {
|
|
40
|
+
const inputError = validateInput(action.input, intent.input);
|
|
41
|
+
if (inputError) {
|
|
42
|
+
return createErrorResult(currentSnapshot, intent, "INVALID_INPUT", inputError, startTime);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
34
45
|
// 2. Check availability condition
|
|
35
46
|
if (action.available) {
|
|
36
|
-
const ctx = createContext(currentSnapshot, schema, intent.type, "available");
|
|
47
|
+
const ctx = createContext(currentSnapshot, schema, intent.type, "available", intent.intentId);
|
|
37
48
|
const availResult = evaluateExpr(action.available, ctx);
|
|
38
49
|
if (isErr(availResult)) {
|
|
39
50
|
return createErrorResult(currentSnapshot, intent, "INTERNAL_ERROR", `Error evaluating availability: ${availResult.error.message}`, startTime);
|
|
40
51
|
}
|
|
41
|
-
|
|
42
|
-
if (
|
|
52
|
+
// Availability must return a boolean (A28: available conditions must be pure)
|
|
53
|
+
if (typeof availResult.value !== "boolean") {
|
|
54
|
+
return createErrorResult(currentSnapshot, intent, "TYPE_MISMATCH", `Availability condition must return boolean, got ${typeof availResult.value}`, startTime);
|
|
55
|
+
}
|
|
56
|
+
if (!availResult.value) {
|
|
43
57
|
return createErrorResult(currentSnapshot, intent, "ACTION_UNAVAILABLE", `Action "${intent.type}" is not available`, startTime);
|
|
44
58
|
}
|
|
45
59
|
}
|
|
@@ -54,7 +68,7 @@ export async function compute(schema, snapshot, intent) {
|
|
|
54
68
|
},
|
|
55
69
|
};
|
|
56
70
|
// 4. Create evaluation context and flow state
|
|
57
|
-
const ctx = createContext(preparedSnapshot, schema, intent.type, `actions.${intent.type}.flow
|
|
71
|
+
const ctx = createContext(preparedSnapshot, schema, intent.type, `actions.${intent.type}.flow`, intent.intentId);
|
|
58
72
|
const flowState = createFlowState(preparedSnapshot);
|
|
59
73
|
// 5. Evaluate the flow
|
|
60
74
|
const flowResult = await evaluateFlow(action.flow, ctx, flowState, `actions.${intent.type}.flow`);
|
|
@@ -100,6 +114,7 @@ export async function compute(schema, snapshot, intent) {
|
|
|
100
114
|
};
|
|
101
115
|
return {
|
|
102
116
|
snapshot: finalSnapshot,
|
|
117
|
+
requirements: [...flowResult.state.requirements],
|
|
103
118
|
trace,
|
|
104
119
|
status: systemStatus,
|
|
105
120
|
};
|
|
@@ -154,7 +169,7 @@ function collectTraceNodes(root) {
|
|
|
154
169
|
* Create an error result
|
|
155
170
|
*/
|
|
156
171
|
function createErrorResult(snapshot, intent, code, message, startTime) {
|
|
157
|
-
const error = createError(code, message, intent.type, "");
|
|
172
|
+
const error = createError(code, message, intent.type, "", Date.now());
|
|
158
173
|
const errorSnapshot = {
|
|
159
174
|
...snapshot,
|
|
160
175
|
input: intent.input,
|
|
@@ -190,8 +205,83 @@ function createErrorResult(snapshot, intent, code, message, startTime) {
|
|
|
190
205
|
};
|
|
191
206
|
return {
|
|
192
207
|
snapshot: errorSnapshot,
|
|
208
|
+
requirements: [],
|
|
193
209
|
trace,
|
|
194
210
|
status: "error",
|
|
195
211
|
};
|
|
196
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Validate input against action's input schema
|
|
215
|
+
* Returns error message if invalid, null if valid
|
|
216
|
+
*/
|
|
217
|
+
function validateInput(inputSpec, input) {
|
|
218
|
+
// Check type
|
|
219
|
+
if (inputSpec.type === "object") {
|
|
220
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
221
|
+
return `Expected object input, got ${typeof input}`;
|
|
222
|
+
}
|
|
223
|
+
const inputObj = input;
|
|
224
|
+
const fields = inputSpec.fields ?? {};
|
|
225
|
+
// Check for required fields
|
|
226
|
+
for (const [fieldName, fieldSpec] of Object.entries(fields)) {
|
|
227
|
+
if (fieldSpec.required && !(fieldName in inputObj)) {
|
|
228
|
+
return `Missing required field: ${fieldName}`;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Check for unknown fields
|
|
232
|
+
for (const key of Object.keys(inputObj)) {
|
|
233
|
+
if (!(key in fields)) {
|
|
234
|
+
return `Unknown field: ${key}`;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Recursively validate nested fields
|
|
238
|
+
for (const [fieldName, fieldSpec] of Object.entries(fields)) {
|
|
239
|
+
if (fieldName in inputObj) {
|
|
240
|
+
const error = validateFieldValue(fieldSpec, inputObj[fieldName], fieldName);
|
|
241
|
+
if (error)
|
|
242
|
+
return error;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Validate a field value against its spec
|
|
250
|
+
*/
|
|
251
|
+
function validateFieldValue(spec, value, path) {
|
|
252
|
+
if (value === undefined || value === null) {
|
|
253
|
+
if (spec.required) {
|
|
254
|
+
return `Missing required field: ${path}`;
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
switch (spec.type) {
|
|
259
|
+
case "string":
|
|
260
|
+
if (typeof value !== "string") {
|
|
261
|
+
return `Expected string for ${path}, got ${typeof value}`;
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
case "number":
|
|
265
|
+
if (typeof value !== "number") {
|
|
266
|
+
return `Expected number for ${path}, got ${typeof value}`;
|
|
267
|
+
}
|
|
268
|
+
break;
|
|
269
|
+
case "boolean":
|
|
270
|
+
if (typeof value !== "boolean") {
|
|
271
|
+
return `Expected boolean for ${path}, got ${typeof value}`;
|
|
272
|
+
}
|
|
273
|
+
break;
|
|
274
|
+
case "array":
|
|
275
|
+
if (!Array.isArray(value)) {
|
|
276
|
+
return `Expected array for ${path}, got ${typeof value}`;
|
|
277
|
+
}
|
|
278
|
+
break;
|
|
279
|
+
case "object":
|
|
280
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
281
|
+
return `Expected object for ${path}, got ${typeof value}`;
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
197
287
|
//# sourceMappingURL=compute.js.map
|