@frockbot/plugin-fly-sprite 0.3.3 → 0.3.5
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 +8 -8
- package/src/computer.test.ts +4 -1
- package/src/computer.ts +2 -1
- package/src/host-client.test.ts +22 -0
- package/src/host-client.ts +26 -5
- package/src/host.ts +5 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/plugin-fly-sprite",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -25,16 +25,16 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@cordisjs/plugin-webui": "0.8.2",
|
|
28
|
-
"@frockbot/computer-core": "0.3.
|
|
29
|
-
"@frockbot/computer-host-protocol": "0.3.
|
|
30
|
-
"@frockbot/computer-host-runtime": "0.3.
|
|
31
|
-
"@frockbot/kernel-contracts": "0.3.
|
|
32
|
-
"@frockbot/plugin-computer": "0.3.
|
|
28
|
+
"@frockbot/computer-core": "0.3.5",
|
|
29
|
+
"@frockbot/computer-host-protocol": "0.3.5",
|
|
30
|
+
"@frockbot/computer-host-runtime": "0.3.5",
|
|
31
|
+
"@frockbot/kernel-contracts": "0.3.5",
|
|
32
|
+
"@frockbot/plugin-computer": "0.3.5",
|
|
33
33
|
"cordis": "4.0.0-rc.8"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@frockbot/plugin-testkit": "0.3.
|
|
37
|
-
"@frockbot/workspace-store": "0.3.
|
|
36
|
+
"@frockbot/plugin-testkit": "0.3.5",
|
|
37
|
+
"@frockbot/workspace-store": "0.3.5",
|
|
38
38
|
"@types/bun": "1.4.0",
|
|
39
39
|
"@types/node": "26.2.0",
|
|
40
40
|
"typescript": "5.9.3"
|
package/src/computer.test.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { describe, expect, test } from "bun:test";
|
|
4
4
|
import type { ComputerConnectionProgressV1 } from "@frockbot/computer-core";
|
|
5
|
+
import { COMPUTER_UNCONFIGURED_MESSAGE_V1 } from "@frockbot/computer-core";
|
|
5
6
|
import { verifyPluginPackage } from "@frockbot/plugin-testkit";
|
|
6
7
|
import { DESKTOP_GUI_LEASE_KEY } from "@frockbot/computer-host-runtime";
|
|
7
8
|
import manifest from "../frockbot.json" with { type: "json" };
|
|
@@ -316,8 +317,10 @@ describe("Fly Sprite computer", () => {
|
|
|
316
317
|
test("an unconfigured Computer refuses rather than pretending", async () => {
|
|
317
318
|
const computer = new FlySpriteComputer({ spriteName: "frockbot-test" });
|
|
318
319
|
expect(computer.configured).toBe(false);
|
|
320
|
+
// The refusal is addressed to the User, not to whoever deploys the host:
|
|
321
|
+
// it names no environment variable and no settings screen.
|
|
319
322
|
await expect(computer.bot("general").ensure()).rejects.toThrow(
|
|
320
|
-
|
|
323
|
+
COMPUTER_UNCONFIGURED_MESSAGE_V1,
|
|
321
324
|
);
|
|
322
325
|
});
|
|
323
326
|
|
package/src/computer.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import {
|
|
3
|
+
COMPUTER_UNCONFIGURED_MESSAGE_V1,
|
|
3
4
|
ComputerError,
|
|
4
5
|
decodeComputerDoctorReportV1,
|
|
5
6
|
type ComputerConnectionOptionsV1,
|
|
@@ -1181,7 +1182,7 @@ export class FlySpriteComputer {
|
|
|
1181
1182
|
if (!this.host) {
|
|
1182
1183
|
throw new ComputerError(
|
|
1183
1184
|
"provider-unavailable",
|
|
1184
|
-
|
|
1185
|
+
COMPUTER_UNCONFIGURED_MESSAGE_V1,
|
|
1185
1186
|
);
|
|
1186
1187
|
}
|
|
1187
1188
|
let held = this.surfaces.get(layout.key);
|
package/src/host-client.test.ts
CHANGED
|
@@ -11,8 +11,10 @@ import {
|
|
|
11
11
|
type ComputerHostOpenFrameV1,
|
|
12
12
|
type ComputerHostProvisioningV1,
|
|
13
13
|
} from "@frockbot/computer-host-protocol";
|
|
14
|
+
import { COMPUTER_COLD_PROVISION_EXPECTATION_MS } from "@frockbot/plugin-computer/protocol";
|
|
14
15
|
import {
|
|
15
16
|
ComputerHostClient,
|
|
17
|
+
COMPUTER_HOST_OPEN_TIMEOUT_MS,
|
|
16
18
|
type ComputerHostFetcherV1,
|
|
17
19
|
} from "./host-client.ts";
|
|
18
20
|
|
|
@@ -566,6 +568,26 @@ describe("ComputerHostClient failures", () => {
|
|
|
566
568
|
);
|
|
567
569
|
});
|
|
568
570
|
|
|
571
|
+
test("open outlasts the cold provision the product advertises", async () => {
|
|
572
|
+
// A first-ever wake that takes exactly as long as the Computer card
|
|
573
|
+
// promises must not abort on our own clock: on the shared 120 s default it
|
|
574
|
+
// reached the User as `provider-unavailable`, which reads as a broken
|
|
575
|
+
// Computer rather than one that is still coming up.
|
|
576
|
+
expect(COMPUTER_HOST_OPEN_TIMEOUT_MS).toBeGreaterThan(
|
|
577
|
+
COMPUTER_COLD_PROVISION_EXPECTATION_MS,
|
|
578
|
+
);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
test("a deadline the client set says the Computer may still be starting", async () => {
|
|
582
|
+
const error = await client(hanging())
|
|
583
|
+
.exec({ script: "sleep 600", timeoutMs: 5 }, { timeoutMs: 5 })
|
|
584
|
+
.catch((thrown: unknown) => thrown);
|
|
585
|
+
// Addressed to whoever reads it in the app, with the next move in it.
|
|
586
|
+
expect((error as ComputerError).message).toBe(
|
|
587
|
+
"The Computer did not answer in time. It may still be starting up; try again in a moment.",
|
|
588
|
+
);
|
|
589
|
+
}, 10_000);
|
|
590
|
+
|
|
569
591
|
test("the client's own deadline expiring is provider-unavailable", async () => {
|
|
570
592
|
const error = await client(hanging())
|
|
571
593
|
.exec({ script: "sleep 600", timeoutMs: 5 }, { timeoutMs: 5 })
|
package/src/host-client.ts
CHANGED
|
@@ -83,6 +83,18 @@ export const COMPUTER_HOST_TIMEOUT_GRACE_MS = 5_000;
|
|
|
83
83
|
/** The deadline for a call that declares none of its own. */
|
|
84
84
|
export const COMPUTER_HOST_DEFAULT_TIMEOUT_MS = 120_000;
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* The deadline for `open`, which is the one call that may provision.
|
|
88
|
+
*
|
|
89
|
+
* It has to outlast the slowest thing the product tells the User to expect:
|
|
90
|
+
* the Computer card advertises "This usually takes 2-3 minutes" for a cold
|
|
91
|
+
* provision. On the shared 120 s default a first-ever wake that took exactly
|
|
92
|
+
* as long as the UI promised aborted on our own clock and reached the User as
|
|
93
|
+
* `provider-unavailable` — "the Computer is broken" — rather than as a
|
|
94
|
+
* Computer that was still coming up.
|
|
95
|
+
*/
|
|
96
|
+
export const COMPUTER_HOST_OPEN_TIMEOUT_MS = 300_000;
|
|
97
|
+
|
|
86
98
|
/** The deadline for a best-effort cancel, which must never outlive its caller. */
|
|
87
99
|
const CANCEL_TIMEOUT_MS = 5_000;
|
|
88
100
|
|
|
@@ -336,15 +348,21 @@ export class ComputerHostClient {
|
|
|
336
348
|
async open(
|
|
337
349
|
options?: ComputerHostOpenOptionsV1,
|
|
338
350
|
): Promise<ComputerHostOpenResultV1> {
|
|
351
|
+
// A caller's own deadline still wins; absent one, `open` gets the cold
|
|
352
|
+
// provision's, not the shared default.
|
|
353
|
+
const openOptions: ComputerHostOpenOptionsV1 = {
|
|
354
|
+
...options,
|
|
355
|
+
timeoutMs: options?.timeoutMs ?? COMPUTER_HOST_OPEN_TIMEOUT_MS,
|
|
356
|
+
};
|
|
339
357
|
if (!options?.onProgress) {
|
|
340
358
|
return this.json(
|
|
341
359
|
{ kind: "open" },
|
|
342
360
|
decodeComputerHostOpenResultV1,
|
|
343
|
-
|
|
361
|
+
openOptions,
|
|
344
362
|
);
|
|
345
363
|
}
|
|
346
|
-
const effectId = this.effectIdFor(
|
|
347
|
-
const lease = this.lease(
|
|
364
|
+
const effectId = this.effectIdFor(openOptions);
|
|
365
|
+
const lease = this.lease(COMPUTER_HOST_OPEN_TIMEOUT_MS, openOptions);
|
|
348
366
|
try {
|
|
349
367
|
const response = await this.send(
|
|
350
368
|
{ kind: "open", stream: true },
|
|
@@ -379,7 +397,7 @@ export class ComputerHostClient {
|
|
|
379
397
|
return await this.json(
|
|
380
398
|
{ kind: "open" },
|
|
381
399
|
decodeComputerHostOpenResultV1,
|
|
382
|
-
|
|
400
|
+
openOptions,
|
|
383
401
|
);
|
|
384
402
|
} finally {
|
|
385
403
|
lease.release();
|
|
@@ -900,9 +918,12 @@ export class ComputerHostClient {
|
|
|
900
918
|
);
|
|
901
919
|
}
|
|
902
920
|
if (lease.timedOut) {
|
|
921
|
+
// Written for whoever reads it in the app. A deadline this call set is
|
|
922
|
+
// not a broken Computer: most often the Computer is still starting, and
|
|
923
|
+
// "try again" is exactly the right next move.
|
|
903
924
|
return new ComputerError(
|
|
904
925
|
"provider-unavailable",
|
|
905
|
-
"The Computer
|
|
926
|
+
"The Computer did not answer in time. It may still be starting up; try again in a moment.",
|
|
906
927
|
true,
|
|
907
928
|
{ cause: error },
|
|
908
929
|
);
|
package/src/host.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { Entry } from "@cordisjs/plugin-webui";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
COMPUTER_UNCONFIGURED_MESSAGE_V1,
|
|
4
|
+
ComputerError,
|
|
5
|
+
} from "@frockbot/computer-core";
|
|
3
6
|
import type { ComputerState } from "@frockbot/plugin-computer/shared";
|
|
4
7
|
import { computerUpdateLabelV1 } from "@frockbot/plugin-computer/protocol";
|
|
5
8
|
import {
|
|
@@ -50,7 +53,7 @@ class FlySpriteHostController {
|
|
|
50
53
|
configured: computer.configured,
|
|
51
54
|
message: computer.configured
|
|
52
55
|
? "Persistent Fly Sprite computer"
|
|
53
|
-
:
|
|
56
|
+
: COMPUTER_UNCONFIGURED_MESSAGE_V1,
|
|
54
57
|
});
|
|
55
58
|
const data: ComputerState = {
|
|
56
59
|
...this.machine,
|