@axiom-lattice/protocols 4.1.1 → 4.1.3

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.
@@ -0,0 +1,265 @@
1
+ import { parseTrustedRunContext } from "../TrustedRunContextProtocol";
2
+ import vm from "node:vm";
3
+
4
+ function validProjectRoom(): Record<string, unknown> {
5
+ return {
6
+ tenantId: "tenant", workspaceId: "workspace", projectId: "project", roomId: "room",
7
+ sourceRoomMessageId: "source", membershipId: "membership", assistantId: "assistant",
8
+ inputMessageId: "input", role: "coordinator", title: "Coordinator",
9
+ };
10
+ }
11
+
12
+ function validProjectTask(): Record<string, unknown> {
13
+ return {
14
+ tenantId: "tenant-1", workspaceId: "workspace-1", projectId: "project-1",
15
+ roomId: "room-1", membershipId: "member-1", assistantId: "agent-1",
16
+ taskId: "task-1", threadId: "thread-1", inputMessageId: "input-1",
17
+ };
18
+ }
19
+
20
+ describe("parseTrustedRunContext", () => {
21
+ it("returns a canonical clone and accepts null-prototype records", () => {
22
+ const projectRoom = Object.assign(Object.create(null) as Record<string, unknown>, validProjectRoom());
23
+ const context = Object.assign(Object.create(null) as Record<string, unknown>, { projectRoom });
24
+
25
+ const parsed = parseTrustedRunContext(context);
26
+
27
+ expect(parsed).toEqual({ projectRoom: validProjectRoom() });
28
+ expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
29
+ expect(Object.getPrototypeOf(parsed.projectRoom)).toBe(Object.prototype);
30
+ });
31
+
32
+ it("accepts exact cross-realm records and returns a canonical local clone", () => {
33
+ const context = vm.runInNewContext(`({ projectRoom: ${JSON.stringify(validProjectRoom())} })`) as unknown;
34
+
35
+ const parsed = parseTrustedRunContext(context);
36
+
37
+ expect(parsed).toEqual({ projectRoom: validProjectRoom() });
38
+ expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
39
+ expect(Object.getPrototypeOf(parsed.projectRoom)).toBe(Object.prototype);
40
+ });
41
+
42
+ it("accepts custom prototypes while ignoring inherited values", () => {
43
+ let inheritedReads = 0;
44
+ const inherited = Object.defineProperty({}, "responsibility", {
45
+ enumerable: true,
46
+ get: () => {
47
+ inheritedReads += 1;
48
+ return "malicious";
49
+ },
50
+ });
51
+ const projectRoom = Object.assign(Object.create(inherited) as Record<string, unknown>, validProjectRoom());
52
+ const context = Object.assign(Object.create({ extra: true }) as Record<string, unknown>, { projectRoom });
53
+
54
+ const parsed = parseTrustedRunContext(context);
55
+
56
+ expect(parsed).toEqual({ projectRoom: validProjectRoom() });
57
+ expect(inheritedReads).toBe(0);
58
+ });
59
+
60
+ it("rejects symbol and non-enumerable extra keys", () => {
61
+ const stringExtra = { projectRoom: validProjectRoom(), extra: true };
62
+ const symbolExtra = { projectRoom: validProjectRoom(), [Symbol("extra")]: true };
63
+ const hiddenExtra = { projectRoom: validProjectRoom() };
64
+ Object.defineProperty(hiddenExtra, "extra", { value: true, enumerable: false });
65
+
66
+ expect(() => parseTrustedRunContext(stringExtra)).toThrow("Invalid trusted agent run context");
67
+ expect(() => parseTrustedRunContext(symbolExtra)).toThrow("Invalid trusted agent run context");
68
+ expect(() => parseTrustedRunContext(hiddenExtra)).toThrow("Invalid trusted agent run context");
69
+ });
70
+
71
+ it("rejects a top-level projectRoom getter without invoking it", () => {
72
+ let calls = 0;
73
+ const context = Object.defineProperty({}, "projectRoom", {
74
+ enumerable: true,
75
+ get: () => {
76
+ calls += 1;
77
+ return validProjectRoom();
78
+ },
79
+ });
80
+
81
+ expect(() => parseTrustedRunContext(context)).toThrow("Invalid trusted agent run context");
82
+ expect(calls).toBe(0);
83
+ });
84
+
85
+ it.each(["tenantId", "responsibility"])(
86
+ "rejects a nested %s getter without invoking it",
87
+ (field) => {
88
+ let calls = 0;
89
+ const projectRoom = validProjectRoom();
90
+ Object.defineProperty(projectRoom, field, {
91
+ enumerable: true,
92
+ get: () => {
93
+ calls += 1;
94
+ return field === "responsibility" ? "Lead" : "tenant";
95
+ },
96
+ });
97
+
98
+ expect(() => parseTrustedRunContext({ projectRoom })).toThrow("Invalid trusted agent run context");
99
+ expect(calls).toBe(0);
100
+ },
101
+ );
102
+
103
+ it("returns a canonical clone of an exact project task branch", () => {
104
+ const projectTask = Object.assign(Object.create(null) as Record<string, unknown>, validProjectTask());
105
+ const context = Object.assign(Object.create(null) as Record<string, unknown>, { projectTask });
106
+
107
+ const parsed = parseTrustedRunContext(context);
108
+
109
+ expect(parsed).toEqual({ projectTask: validProjectTask() });
110
+ expect(parsed.projectTask).not.toBe(projectTask);
111
+ expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
112
+ expect(Object.getPrototypeOf(parsed.projectTask)).toBe(Object.prototype);
113
+ });
114
+
115
+ it("accepts an exact cross-realm project task branch", () => {
116
+ const context = vm.runInNewContext(`({ projectTask: ${JSON.stringify(validProjectTask())} })`) as unknown;
117
+
118
+ const parsed = parseTrustedRunContext(context);
119
+
120
+ expect(parsed).toEqual({ projectTask: validProjectTask() });
121
+ expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
122
+ expect(Object.getPrototypeOf(parsed.projectTask)).toBe(Object.prototype);
123
+ });
124
+
125
+ it("accepts custom prototypes and ignores inherited project task values", () => {
126
+ let inheritedReads = 0;
127
+ const inherited = Object.defineProperty({}, "extra", {
128
+ enumerable: true,
129
+ get: () => {
130
+ inheritedReads += 1;
131
+ return "malicious";
132
+ },
133
+ });
134
+ const projectTask = Object.assign(Object.create(inherited) as Record<string, unknown>, validProjectTask());
135
+ const context = Object.assign(Object.create({ extra: true }) as Record<string, unknown>, { projectTask });
136
+
137
+ expect(parseTrustedRunContext(context)).toEqual({ projectTask: validProjectTask() });
138
+ expect(inheritedReads).toBe(0);
139
+ });
140
+
141
+ it("requires exactly one trusted context branch", () => {
142
+ expect(() => parseTrustedRunContext({})).toThrow("Invalid trusted agent run context");
143
+ expect(() => parseTrustedRunContext({ projectRoom: validProjectRoom(), projectTask: validProjectTask() }))
144
+ .toThrow("Invalid trusted agent run context");
145
+ expect(() => parseTrustedRunContext({ projectTask: undefined }))
146
+ .toThrow("Invalid trusted agent run context");
147
+ });
148
+
149
+ it.each(Object.keys(validProjectTask()))("rejects an empty project task %s", (field) => {
150
+ expect(() => parseTrustedRunContext({
151
+ projectTask: { ...validProjectTask(), [field]: "" },
152
+ })).toThrow("Invalid trusted agent run context");
153
+ });
154
+
155
+ it.each(Object.keys(validProjectTask()))("rejects a missing project task %s", (field) => {
156
+ const projectTask = validProjectTask();
157
+ delete projectTask[field];
158
+
159
+ expect(() => parseTrustedRunContext({ projectTask })).toThrow("Invalid trusted agent run context");
160
+ });
161
+
162
+ it("rejects project task string, symbol, and non-enumerable extra keys", () => {
163
+ const stringExtra = { ...validProjectTask(), extra: true };
164
+ const symbolExtra = { ...validProjectTask(), [Symbol("extra")]: true };
165
+ const hiddenExtra = validProjectTask();
166
+ Object.defineProperty(hiddenExtra, "extra", { value: true, enumerable: false });
167
+
168
+ expect(() => parseTrustedRunContext({ projectTask: stringExtra })).toThrow("Invalid trusted agent run context");
169
+ expect(() => parseTrustedRunContext({ projectTask: symbolExtra })).toThrow("Invalid trusted agent run context");
170
+ expect(() => parseTrustedRunContext({ projectTask: hiddenExtra })).toThrow("Invalid trusted agent run context");
171
+ });
172
+
173
+ it("rejects projectTask root symbol and non-enumerable extra keys", () => {
174
+ const symbolExtra = { projectTask: validProjectTask(), [Symbol("extra")]: true };
175
+ const hiddenExtra = { projectTask: validProjectTask() };
176
+ Object.defineProperty(hiddenExtra, "extra", { value: true, enumerable: false });
177
+
178
+ expect(() => parseTrustedRunContext(symbolExtra)).toThrow("Invalid trusted agent run context");
179
+ expect(() => parseTrustedRunContext(hiddenExtra)).toThrow("Invalid trusted agent run context");
180
+ });
181
+
182
+ it("rejects a top-level projectTask getter without invoking it", () => {
183
+ let calls = 0;
184
+ const context = Object.defineProperty({}, "projectTask", {
185
+ enumerable: true,
186
+ get: () => {
187
+ calls += 1;
188
+ return validProjectTask();
189
+ },
190
+ });
191
+
192
+ expect(() => parseTrustedRunContext(context)).toThrow("Invalid trusted agent run context");
193
+ expect(calls).toBe(0);
194
+ });
195
+
196
+ it.each(Object.keys(validProjectTask()))(
197
+ "rejects a nested project task %s getter without invoking it",
198
+ (field) => {
199
+ let calls = 0;
200
+ const projectTask = validProjectTask();
201
+ Object.defineProperty(projectTask, field, {
202
+ enumerable: true,
203
+ get: () => {
204
+ calls += 1;
205
+ return "malicious";
206
+ },
207
+ });
208
+
209
+ expect(() => parseTrustedRunContext({ projectTask })).toThrow("Invalid trusted agent run context");
210
+ expect(calls).toBe(0);
211
+ },
212
+ );
213
+
214
+ it("rejects inherited required project task fields without invoking getters", () => {
215
+ let calls = 0;
216
+ const inherited = Object.defineProperty({}, "tenantId", {
217
+ enumerable: true,
218
+ get: () => {
219
+ calls += 1;
220
+ return "tenant-1";
221
+ },
222
+ });
223
+ const projectTask = validProjectTask();
224
+ delete projectTask.tenantId;
225
+ Object.setPrototypeOf(projectTask, inherited);
226
+
227
+ expect(() => parseTrustedRunContext({ projectTask })).toThrow("Invalid trusted agent run context");
228
+ expect(calls).toBe(0);
229
+ });
230
+
231
+ it("rejects task accessors without reading polluted descriptor prototypes", () => {
232
+ const originalValue = Object.getOwnPropertyDescriptor(Object.prototype, "value");
233
+ const originalEnumerable = Object.getOwnPropertyDescriptor(Object.prototype, "enumerable");
234
+ let inheritedReads = 0;
235
+ const projectTask = validProjectTask();
236
+ Object.defineProperty(projectTask, "tenantId", {
237
+ enumerable: true,
238
+ get: () => "tenant-1",
239
+ });
240
+ try {
241
+ Object.defineProperty(Object.prototype, "value", {
242
+ configurable: true,
243
+ get: () => {
244
+ inheritedReads += 1;
245
+ return "tenant-1";
246
+ },
247
+ });
248
+ Object.defineProperty(Object.prototype, "enumerable", Object.assign(Object.create(null), {
249
+ configurable: true,
250
+ get: () => {
251
+ inheritedReads += 1;
252
+ return true;
253
+ },
254
+ }));
255
+
256
+ expect(() => parseTrustedRunContext({ projectTask })).toThrow("Invalid trusted agent run context");
257
+ expect(inheritedReads).toBe(0);
258
+ } finally {
259
+ if (originalValue) Object.defineProperty(Object.prototype, "value", originalValue);
260
+ else delete (Object.prototype as { value?: unknown }).value;
261
+ if (originalEnumerable) Object.defineProperty(Object.prototype, "enumerable", originalEnumerable);
262
+ else delete (Object.prototype as { enumerable?: unknown }).enumerable;
263
+ }
264
+ });
265
+ });
package/src/index.ts CHANGED
@@ -50,6 +50,13 @@ export * from "./AgentWebAppStoreProtocol";
50
50
  export * from "./AgentWebAppRuntimeProtocol";
51
51
  export * from "./CapabilityBundleStoreProtocol";
52
52
  export * from "./CapabilityRuntimeProtocol";
53
+ export * from "./ProjectRoomProtocol";
54
+ export * from "./ProjectRoomStoreProtocol";
55
+ export * from "./ProjectMembershipStoreProtocol";
56
+ export * from "./ProjectBotMembershipStoreProtocol";
57
+ export * from "./ProjectRoomMessageStoreProtocol";
58
+ export * from "./ExactDataSnapshot";
59
+ export * from "./ProjectRoomRealtimeProtocol";
53
60
 
54
61
  // Workflow DSL (concise, public API)
55
62
  export * from "./WorkflowDSL";
@@ -78,3 +85,4 @@ export type {
78
85
 
79
86
  // 导出通用类型
80
87
  export * from "./types";
88
+ export * from "./TrustedRunContextProtocol";
@@ -1,7 +1,9 @@
1
1
  import type {
2
+ ProjectTaskWorkItemStore,
2
3
  TaskWorkItem,
3
4
  TaskWorkItemStore,
4
5
  } from "../src/TaskWorkItemProtocol";
6
+ import { requireProjectTaskWorkItemStore } from "../src/TaskWorkItemProtocol";
5
7
 
6
8
  class LegacyTaskWorkItemStore implements TaskWorkItemStore {
7
9
  async create(): Promise<TaskWorkItem> {
@@ -21,5 +23,15 @@ class LegacyTaskWorkItemStore implements TaskWorkItemStore {
21
23
  }
22
24
  }
23
25
 
24
- const store: TaskWorkItemStore = new LegacyTaskWorkItemStore();
25
- void store;
26
+ const legacyStore: TaskWorkItemStore = new LegacyTaskWorkItemStore();
27
+ const completeStore = Object.assign(new LegacyTaskWorkItemStore(), {
28
+ createIfTaskSnapshot: async () => null,
29
+ listProjectLifecycleEvents: async () => [],
30
+ });
31
+ const baseStore: TaskWorkItemStore = completeStore;
32
+ const projectStore: ProjectTaskWorkItemStore = completeStore;
33
+ const refinedStore: ProjectTaskWorkItemStore = requireProjectTaskWorkItemStore(baseStore);
34
+
35
+ void legacyStore;
36
+ void projectStore;
37
+ void refinedStore;