@frockbot/computer-host-runtime 0.3.17 → 0.3.19
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 +1 -1
- package/src/runtime.test.ts +44 -10
- package/src/runtime.ts +25 -13
package/package.json
CHANGED
package/src/runtime.test.ts
CHANGED
|
@@ -448,7 +448,7 @@ state running`);
|
|
|
448
448
|
);
|
|
449
449
|
});
|
|
450
450
|
|
|
451
|
-
test("the update runner replaces files and
|
|
451
|
+
test("the update runner replaces files and only repairs Applet dependencies", () => {
|
|
452
452
|
expect(UPDATE_PHASES.map((phase) => phase.name)).toEqual([
|
|
453
453
|
"runtime",
|
|
454
454
|
"applets",
|
|
@@ -460,16 +460,16 @@ state running`);
|
|
|
460
460
|
const updateDocument = UPDATE_PHASES.map((phase) => phase.body).join("\n");
|
|
461
461
|
expect(updateDocument).not.toContain("apt-get");
|
|
462
462
|
expect(updateDocument).not.toContain("playwright-core/cli.js install");
|
|
463
|
-
// An in-place update swaps names over files it owns
|
|
464
|
-
//
|
|
465
|
-
//
|
|
466
|
-
// is absent, which is exactly when nothing can be running out of it.
|
|
463
|
+
// An in-place update swaps names over files it owns. It installs the SDK
|
|
464
|
+
// only while absent, and fills the four shared React dependencies only
|
|
465
|
+
// when the resolution probe proves an older installation needs repair.
|
|
467
466
|
expect(updateDocument).not.toContain("miniflare@");
|
|
468
467
|
const installs = updateDocument
|
|
469
468
|
.split("\n")
|
|
470
469
|
.filter((line) => line.includes("npm install"));
|
|
471
470
|
expect(installs).toEqual([
|
|
472
471
|
` if npm install --prefix ${APPLETS_ROOT} --no-audit --no-fund @frockbot/applet-sdk@${APPLET_SDK_VERSION}; then`,
|
|
472
|
+
` npm install --prefix ${APPLETS_ROOT} --no-audit --no-fund react@19.2.8 react-dom@19.2.8 @types/react@19.2.18 @types/react-dom@19.2.4 || true`,
|
|
473
473
|
]);
|
|
474
474
|
expect(updateDocument).toContain(
|
|
475
475
|
`if [ ! -d ${APPLETS_ROOT}/node_modules/@frockbot/applet-sdk ]; then`,
|
|
@@ -528,18 +528,52 @@ describe("the applets phase", () => {
|
|
|
528
528
|
expect(appletSdkInstallScript).not.toContain("user-packages");
|
|
529
529
|
});
|
|
530
530
|
|
|
531
|
-
test("
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
531
|
+
test("repairs old SDK installs and verifies every shared build import", () => {
|
|
532
|
+
const fallback =
|
|
533
|
+
`npm install --prefix ${APPLETS_ROOT} --no-audit --no-fund ` +
|
|
534
|
+
"react@19.2.8 react-dom@19.2.8 @types/react@19.2.18 @types/react-dom@19.2.4";
|
|
535
|
+
const fallbackProbe = `cd ${APPLETS_ROOT} && node -e "require.resolve('react-dom/client')"`;
|
|
536
|
+
|
|
537
|
+
expect(appletSdkInstallScript).toContain(fallback);
|
|
538
|
+
expect(appletSdkInstallScript).toContain(fallbackProbe);
|
|
539
|
+
expect(appletSdkInstallScript).toContain(
|
|
540
|
+
`SDK_RESOLUTION_ERROR=$(cd ${APPLETS_ROOT} && node -e`,
|
|
541
|
+
);
|
|
542
|
+
for (const specifier of [
|
|
543
|
+
"react-dom/client",
|
|
544
|
+
"react",
|
|
545
|
+
"@frockbot/applet-sdk/client",
|
|
546
|
+
]) {
|
|
547
|
+
expect(appletSdkInstallScript).toContain(`'${specifier}'`);
|
|
548
|
+
}
|
|
549
|
+
expect(appletSdkInstallScript.indexOf(fallbackProbe)).toBeLessThan(
|
|
550
|
+
appletSdkInstallScript.indexOf(fallback),
|
|
551
|
+
);
|
|
552
|
+
expect(appletSdkInstallScript.indexOf(fallback)).toBeLessThan(
|
|
553
|
+
appletSdkInstallScript.indexOf("SDK_RESOLUTION_ERROR=$(cd"),
|
|
554
|
+
);
|
|
555
|
+
expect(appletSdkInstallScript).toContain(`> ${APPLETS_SDK_FAILURE_PATH}`);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
test("an SDK that cannot be fetched or resolved leaves a record and not a failed run", () => {
|
|
559
|
+
// A Computer whose SDK could not be installed or resolved still browses,
|
|
560
|
+
// execs, and syncs, so the phase records the failure for the doctor rather
|
|
561
|
+
// than failing provisioning.
|
|
535
562
|
const applets = PROVISION_PHASES.find((phase) => phase.name === "applets")!;
|
|
536
563
|
expect(applets.body).toContain(`> ${APPLETS_SDK_FAILURE_PATH}`);
|
|
537
564
|
expect(applets.body).toContain(`rm -f ${APPLETS_SDK_FAILURE_PATH}`);
|
|
538
565
|
expect(boxDoctorScript).toContain("record applets-sdk fail");
|
|
539
566
|
expect(boxDoctorScript).toContain("record applets-sdk pass");
|
|
567
|
+
expect(
|
|
568
|
+
boxDoctorScript.indexOf(`[ -f ${APPLETS_SDK_FAILURE_PATH} ]`),
|
|
569
|
+
).toBeLessThan(
|
|
570
|
+
boxDoctorScript.indexOf(
|
|
571
|
+
`[ -d ${APPLETS_ROOT}/node_modules/@frockbot/applet-sdk ]`,
|
|
572
|
+
),
|
|
573
|
+
);
|
|
540
574
|
});
|
|
541
575
|
|
|
542
|
-
test("runs again rather than once
|
|
576
|
+
test("runs again rather than once so old SDK installs can be repaired", () => {
|
|
543
577
|
const applets = PROVISION_PHASES.find((phase) => phase.name === "applets")!;
|
|
544
578
|
expect(applets.always).toBe(true);
|
|
545
579
|
expect(provisionScript).not.toContain('[ ! -f "$MARKERS/applets"');
|
package/src/runtime.ts
CHANGED
|
@@ -1647,19 +1647,22 @@ exec "$APPLET" "$@"
|
|
|
1647
1647
|
`;
|
|
1648
1648
|
|
|
1649
1649
|
/**
|
|
1650
|
-
* Installs the Applets SDK when
|
|
1650
|
+
* Installs the Applets SDK when it is absent and verifies its shared imports.
|
|
1651
1651
|
*
|
|
1652
1652
|
* Guarded, and deliberately not fatal: a Computer that cannot fetch the SDK
|
|
1653
1653
|
* is still a Computer — it browses, execs, and syncs — so the failure is
|
|
1654
1654
|
* recorded as a file the doctor reports under `applets-sdk` rather than as a
|
|
1655
1655
|
* phase that fails and leaves the whole run resumable-but-unfinished.
|
|
1656
1656
|
*
|
|
1657
|
-
* The
|
|
1658
|
-
*
|
|
1659
|
-
* and
|
|
1660
|
-
*
|
|
1661
|
-
*
|
|
1662
|
-
*
|
|
1657
|
+
* The React fallback repairs SDK releases published before those build-time
|
|
1658
|
+
* dependencies moved from development/peer metadata into dependencies. It is
|
|
1659
|
+
* idempotent and runs only when Node cannot resolve `react-dom/client` from
|
|
1660
|
+
* the shared prefix. The final probe covers React, React DOM, and the SDK's
|
|
1661
|
+
* client entry; its concise failure is durable input to box-doctor.
|
|
1662
|
+
*
|
|
1663
|
+
* Changing this script changes the runtime document digest, which is the
|
|
1664
|
+
* version marker that causes every existing Computer to run UPDATE_PHASES on
|
|
1665
|
+
* its next open.
|
|
1663
1666
|
*/
|
|
1664
1667
|
export const appletSdkInstallScript = `if [ ! -d ${APPLETS_ROOT}/node_modules/@frockbot/applet-sdk ]; then
|
|
1665
1668
|
if npm install --prefix ${APPLETS_ROOT} --no-audit --no-fund @frockbot/applet-sdk@${APPLET_SDK_VERSION}; then
|
|
@@ -1667,6 +1670,16 @@ export const appletSdkInstallScript = `if [ ! -d ${APPLETS_ROOT}/node_modules/@f
|
|
|
1667
1670
|
else
|
|
1668
1671
|
printf '%s\\n' "npm could not install @frockbot/applet-sdk@${APPLET_SDK_VERSION}" > ${APPLETS_SDK_FAILURE_PATH}
|
|
1669
1672
|
fi
|
|
1673
|
+
fi
|
|
1674
|
+
if [ -d ${APPLETS_ROOT}/node_modules/@frockbot/applet-sdk ]; then
|
|
1675
|
+
if ! (cd ${APPLETS_ROOT} && node -e "require.resolve('react-dom/client')") >/dev/null 2>&1; then
|
|
1676
|
+
npm install --prefix ${APPLETS_ROOT} --no-audit --no-fund react@19.2.8 react-dom@19.2.8 @types/react@19.2.18 @types/react-dom@19.2.4 || true
|
|
1677
|
+
fi
|
|
1678
|
+
if SDK_RESOLUTION_ERROR=$(cd ${APPLETS_ROOT} && node -e "for (const id of ['react-dom/client', 'react', '@frockbot/applet-sdk/client']) { try { require.resolve(id) } catch { console.error('could not resolve ' + id); process.exitCode = 1 } }" 2>&1); then
|
|
1679
|
+
rm -f ${APPLETS_SDK_FAILURE_PATH}
|
|
1680
|
+
else
|
|
1681
|
+
printf '%s\\n' "Applets SDK dependency resolution failed: $SDK_RESOLUTION_ERROR" > ${APPLETS_SDK_FAILURE_PATH}
|
|
1682
|
+
fi
|
|
1670
1683
|
fi`;
|
|
1671
1684
|
|
|
1672
1685
|
/** The files the `applets` phase installs, with their modes. */
|
|
@@ -1887,13 +1900,12 @@ elif [ -x ${APPLET_SHIM_PATH} ]; then
|
|
|
1887
1900
|
else
|
|
1888
1901
|
record applets fail "no ${APPLET_SHIM_PATH}; provisioning installs it, and no Applet can be checked, built, or previewed without it"
|
|
1889
1902
|
fi
|
|
1890
|
-
# Named and non-fatal on purpose:
|
|
1891
|
-
#
|
|
1892
|
-
|
|
1893
|
-
if [ -d ${APPLETS_ROOT}/node_modules/@frockbot/applet-sdk ]; then
|
|
1894
|
-
record applets-sdk pass "the Applets SDK is installed under ${APPLETS_ROOT}"
|
|
1895
|
-
elif [ -f ${APPLETS_SDK_FAILURE_PATH} ]; then
|
|
1903
|
+
# Named and non-fatal on purpose: an install or dependency-resolution failure
|
|
1904
|
+
# leaves this file rather than failing the whole Computer run.
|
|
1905
|
+
if [ -f ${APPLETS_SDK_FAILURE_PATH} ]; then
|
|
1896
1906
|
record applets-sdk fail "$(head -n 1 ${APPLETS_SDK_FAILURE_PATH} 2>/dev/null); everything else on this Computer is unaffected"
|
|
1907
|
+
elif [ -d ${APPLETS_ROOT}/node_modules/@frockbot/applet-sdk ]; then
|
|
1908
|
+
record applets-sdk pass "the Applets SDK and its shared imports resolve under ${APPLETS_ROOT}"
|
|
1897
1909
|
else
|
|
1898
1910
|
record applets-sdk fail "no Applets SDK under ${APPLETS_ROOT} and no record of an attempt; it installs when this Computer is next provisioned"
|
|
1899
1911
|
fi
|