@frockbot/computer-core 0.3.17 → 0.3.18
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/package.json +2 -2
- package/src/core.ts +23 -0
- package/src/index.test.ts +65 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/computer-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.18",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@frockbot/kernel-contracts": "0.3.
|
|
15
|
+
"@frockbot/kernel-contracts": "0.3.18",
|
|
16
16
|
"cordis": "4.0.0-rc.8"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
package/src/core.ts
CHANGED
|
@@ -895,6 +895,29 @@ function guardedHandle(
|
|
|
895
895
|
guardedOperation(assertCurrent, () =>
|
|
896
896
|
sync.reconcile(reason, options),
|
|
897
897
|
),
|
|
898
|
+
// Forwarded when the provider offers it. Dropping it here is how a
|
|
899
|
+
// publish's required `dist/` pull was "refused: this Computer cannot
|
|
900
|
+
// reconcile a single durable root" on production (Bob, 2026-09-04)
|
|
901
|
+
// while the provider underneath could — and once ordinary sync
|
|
902
|
+
// stopped carrying `dist/`, that refusal was the whole failure.
|
|
903
|
+
...(sync.reconcileRoot
|
|
904
|
+
? {
|
|
905
|
+
reconcileRoot: (
|
|
906
|
+
root: Parameters<
|
|
907
|
+
NonNullable<ComputerSyncV1["reconcileRoot"]>
|
|
908
|
+
>[0],
|
|
909
|
+
reason: Parameters<
|
|
910
|
+
NonNullable<ComputerSyncV1["reconcileRoot"]>
|
|
911
|
+
>[1],
|
|
912
|
+
options?: Parameters<
|
|
913
|
+
NonNullable<ComputerSyncV1["reconcileRoot"]>
|
|
914
|
+
>[2],
|
|
915
|
+
) =>
|
|
916
|
+
guardedOperation(assertCurrent, () =>
|
|
917
|
+
sync.reconcileRoot!(root, reason, options),
|
|
918
|
+
),
|
|
919
|
+
}
|
|
920
|
+
: {}),
|
|
898
921
|
signal: (options) =>
|
|
899
922
|
guardedOperation(assertCurrent, () => sync.signal(options)),
|
|
900
923
|
}
|
package/src/index.test.ts
CHANGED
|
@@ -230,6 +230,71 @@ describe("ComputerRegistry", () => {
|
|
|
230
230
|
await root.fiber.dispose();
|
|
231
231
|
});
|
|
232
232
|
|
|
233
|
+
test("keeps a provider's single-root reconciliation on the guarded handle", async () => {
|
|
234
|
+
// Bob on production (2026-09-04): the provider could reconcile one root,
|
|
235
|
+
// the guarded handle dropped that method, and the publish that needed
|
|
236
|
+
// `dist/` pulled explicitly was refused as "cannot reconcile a single
|
|
237
|
+
// durable root" while ordinary sync no longer carried build output.
|
|
238
|
+
const root = new Context();
|
|
239
|
+
await root.plugin(ComputerRegistry);
|
|
240
|
+
const calls: string[] = [];
|
|
241
|
+
const syncing: ComputerProvider = {
|
|
242
|
+
id: "sprites",
|
|
243
|
+
open: async (identity, tenant, assignment) => ({
|
|
244
|
+
assignment,
|
|
245
|
+
identity,
|
|
246
|
+
tenant,
|
|
247
|
+
sync: {
|
|
248
|
+
reconcile: async (reason) => {
|
|
249
|
+
calls.push(`reconcile:${reason}`);
|
|
250
|
+
return { status: "ok" } as never;
|
|
251
|
+
},
|
|
252
|
+
reconcileRoot: async (declared, reason, options) => {
|
|
253
|
+
calls.push(
|
|
254
|
+
`root:${reason}:${declared.kind}:${(options?.requiredPaths ?? []).join(",")}`,
|
|
255
|
+
);
|
|
256
|
+
return { status: "ok" } as never;
|
|
257
|
+
},
|
|
258
|
+
signal: async () => undefined,
|
|
259
|
+
},
|
|
260
|
+
close: () => Promise.resolve(),
|
|
261
|
+
}),
|
|
262
|
+
};
|
|
263
|
+
root.computers.register(syncing);
|
|
264
|
+
const identity = { userId: "user-1" };
|
|
265
|
+
root.computers.assign(identity, "sprites");
|
|
266
|
+
const computer = await root.computers.open(identity, { botId: "bot-1" });
|
|
267
|
+
|
|
268
|
+
expect(computer.sync?.reconcileRoot).toBeDefined();
|
|
269
|
+
await computer.sync?.reconcileRoot?.(
|
|
270
|
+
{
|
|
271
|
+
kind: "package-declared",
|
|
272
|
+
userId: "user-1",
|
|
273
|
+
packageId: "applets",
|
|
274
|
+
rootId: "source",
|
|
275
|
+
},
|
|
276
|
+
"publish",
|
|
277
|
+
{ requiredPaths: ["a.b/dist/server.js"] },
|
|
278
|
+
);
|
|
279
|
+
expect(calls).toEqual(["root:publish:package-declared:a.b/dist/server.js"]);
|
|
280
|
+
|
|
281
|
+
// Still guarded: a stale handle refuses it like every other operation.
|
|
282
|
+
root.computers.register({ ...syncing, id: "local" });
|
|
283
|
+
root.computers.assign(identity, "local");
|
|
284
|
+
await expect(
|
|
285
|
+
computer.sync?.reconcileRoot?.(
|
|
286
|
+
{
|
|
287
|
+
kind: "package-declared",
|
|
288
|
+
userId: "user-1",
|
|
289
|
+
packageId: "applets",
|
|
290
|
+
rootId: "source",
|
|
291
|
+
},
|
|
292
|
+
"publish",
|
|
293
|
+
),
|
|
294
|
+
).rejects.toMatchObject({ code: "stale-assignment" });
|
|
295
|
+
await root.fiber.dispose();
|
|
296
|
+
});
|
|
297
|
+
|
|
233
298
|
test("fails clearly when a User has no Computer assignment", async () => {
|
|
234
299
|
const root = new Context();
|
|
235
300
|
await root.plugin(ComputerRegistry);
|