@yourrealm/sdk 0.0.0-alpha.1378.ce03c8dc
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/LICENSE-EXCEPTION +26 -0
- package/README.md +34 -0
- package/dist/chunk-3R6KEFOI.js +22 -0
- package/dist/chunk-67BDAMYX.js +376 -0
- package/dist/chunk-AITGS27R.js +139 -0
- package/dist/chunk-CMAEHQ4F.js +6 -0
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-O3UIK34B.js +1430 -0
- package/dist/chunk-VHTUSZUX.js +176 -0
- package/dist/cli.js +9006 -0
- package/dist/docker.js +54 -0
- package/dist/index.js +1053 -0
- package/dist/ingress.js +436 -0
- package/dist/jsx-runtime.js +2 -0
- package/dist/preact.js +22 -0
- package/dist/service-url.js +11 -0
- package/dist/services.js +213 -0
- package/dist/test.js +5069 -0
- package/dist/ui.js +254 -0
- package/dist/worker-protocol.js +89 -0
- package/package.json +112 -0
- package/src/app-icon.ts +74 -0
- package/src/apply.ts +52 -0
- package/src/bundle-ui.ts +211 -0
- package/src/bundle.ts +546 -0
- package/src/cli/build-dev-landing.ts +84 -0
- package/src/cli/build-install-panel.ts +90 -0
- package/src/cli/build-runtime.ts +133 -0
- package/src/cli/build.ts +63 -0
- package/src/cli/dev.ts +107 -0
- package/src/cli/down.ts +60 -0
- package/src/cli/main.ts +56 -0
- package/src/cli/test.ts +61 -0
- package/src/cli/validate.ts +37 -0
- package/src/compile.ts +100 -0
- package/src/create-app.ts +982 -0
- package/src/deep-merge.ts +33 -0
- package/src/dev/fixture.ts +48 -0
- package/src/dev/install-handler.ts +383 -0
- package/src/dev/server.ts +968 -0
- package/src/dev/stack.ts +108 -0
- package/src/dev/state.ts +159 -0
- package/src/docker.ts +96 -0
- package/src/errors.ts +61 -0
- package/src/factory.ts +481 -0
- package/src/garage.ts +56 -0
- package/src/generator/hash.ts +6 -0
- package/src/generator/resolve-refs.ts +207 -0
- package/src/grants-builder.ts +100 -0
- package/src/grants.ts +260 -0
- package/src/home-api.ts +172 -0
- package/src/home-cookie.ts +10 -0
- package/src/home-registry.ts +120 -0
- package/src/home.ts +187 -0
- package/src/host-registry.ts +143 -0
- package/src/http-header.ts +20 -0
- package/src/identifiers.ts +49 -0
- package/src/index.ts +66 -0
- package/src/info.ts +64 -0
- package/src/ini.ts +50 -0
- package/src/json.ts +14 -0
- package/src/jsx-runtime/index.ts +5 -0
- package/src/keys.ts +29 -0
- package/src/mysql.ts +56 -0
- package/src/pack-build.ts +108 -0
- package/src/pack.ts +115 -0
- package/src/peer-registry.ts +121 -0
- package/src/peer-world.ts +117 -0
- package/src/permission-meta.ts +116 -0
- package/src/permissions.ts +108 -0
- package/src/pkg-root.ts +34 -0
- package/src/postgres.ts +79 -0
- package/src/preact/index.ts +27 -0
- package/src/redis.ts +43 -0
- package/src/ref.ts +271 -0
- package/src/remote-registry.ts +33 -0
- package/src/required-host-kinds.ts +110 -0
- package/src/resolve-context.ts +111 -0
- package/src/resolve.ts +471 -0
- package/src/runtime/docker/compose/compose-schema.ts +118 -0
- package/src/runtime/docker/compose/convert-to-docker-compose.ts +278 -0
- package/src/runtime/docker/compose/default-hardening.ts +21 -0
- package/src/runtime/docker/compose/effects.ts +107 -0
- package/src/runtime/docker/compose/index.ts +17 -0
- package/src/runtime/docker/compose/labels.ts +39 -0
- package/src/runtime/docker/compose/types.ts +78 -0
- package/src/runtime/docker/home-proxy-server/index.ts +177 -0
- package/src/runtime/docker/home-proxy-server/protocol.ts +53 -0
- package/src/runtime/docker/ingress/build-config.ts +819 -0
- package/src/runtime/docker/ingress/index.ts +16 -0
- package/src/runtime/docker/ingress/types.ts +182 -0
- package/src/runtime/docker/log-frames.ts +121 -0
- package/src/runtime/docker/logs-server/index.ts +366 -0
- package/src/runtime/docker/spawn-server/context-key.ts +82 -0
- package/src/runtime/docker/spawn-server/index.ts +492 -0
- package/src/runtime/docker/spawn-server/protocol.ts +70 -0
- package/src/runtime/docker/spawn-server/spec.ts +122 -0
- package/src/runtime/docker/stats-server/disks.ts +161 -0
- package/src/runtime/docker/stats-server/index.ts +322 -0
- package/src/runtime/home-client/index.ts +71 -0
- package/src/runtime/log-line.ts +24 -0
- package/src/runtime/logs-client/index.ts +175 -0
- package/src/runtime/spawn-client/index.ts +93 -0
- package/src/runtime/spawn-client/kaniko.ts +79 -0
- package/src/runtime/stats-client/index.ts +65 -0
- package/src/runtime/stats-sample.ts +95 -0
- package/src/safe-json.ts +37 -0
- package/src/sandbox.ts +1209 -0
- package/src/schema/build-apps.ts +38 -0
- package/src/schema/home.ts +217 -0
- package/src/schema/host.ts +792 -0
- package/src/schema/inputs.ts +26 -0
- package/src/schema/nodes.ts +75 -0
- package/src/schema/peer.ts +400 -0
- package/src/schema/public-domain.ts +116 -0
- package/src/schema/remote.ts +74 -0
- package/src/security.ts +594 -0
- package/src/serialize.ts +21 -0
- package/src/service-definition.ts +284 -0
- package/src/service-url.ts +64 -0
- package/src/service.ts +39 -0
- package/src/services/index.ts +5 -0
- package/src/shared.ts +65 -0
- package/src/speculative-silo.ts +96 -0
- package/src/stable-secret.ts +14 -0
- package/src/surfaces.ts +264 -0
- package/src/tailwind-bin.ts +56 -0
- package/src/test/boot.ts +192 -0
- package/src/test/compile.ts +501 -0
- package/src/test/describe.ts +117 -0
- package/src/test/index.ts +11 -0
- package/src/test/ingress-fixture.ts +37 -0
- package/src/test/types.ts +318 -0
- package/src/trusted-headers.ts +79 -0
- package/src/types.ts +126 -0
- package/src/ui/components/aside.tsx +96 -0
- package/src/ui/components/badge.tsx +42 -0
- package/src/ui/components/button.tsx +59 -0
- package/src/ui/components/card.tsx +106 -0
- package/src/ui/components/checkbox.tsx +37 -0
- package/src/ui/components/code-block.tsx +29 -0
- package/src/ui/components/combobox.tsx +119 -0
- package/src/ui/components/config-field.tsx +284 -0
- package/src/ui/components/dialog.tsx +137 -0
- package/src/ui/components/domain-editor.tsx +317 -0
- package/src/ui/components/domain-list.ts +205 -0
- package/src/ui/components/dropdown-menu.tsx +73 -0
- package/src/ui/components/empty-state.tsx +51 -0
- package/src/ui/components/highlight.ts +59 -0
- package/src/ui/components/icons.tsx +101 -0
- package/src/ui/components/image-posture.tsx +85 -0
- package/src/ui/components/input.tsx +28 -0
- package/src/ui/components/label.tsx +16 -0
- package/src/ui/components/line-chart.tsx +113 -0
- package/src/ui/components/page.tsx +39 -0
- package/src/ui/components/permission-row.tsx +262 -0
- package/src/ui/components/permission-section.tsx +51 -0
- package/src/ui/components/pie-chart.tsx +245 -0
- package/src/ui/components/schema-block.tsx +60 -0
- package/src/ui/components/separator.tsx +42 -0
- package/src/ui/components/sheet.tsx +130 -0
- package/src/ui/components/sidebar.tsx +650 -0
- package/src/ui/components/silo-picker.tsx +510 -0
- package/src/ui/components/skeleton.tsx +13 -0
- package/src/ui/components/sonner.tsx +33 -0
- package/src/ui/components/switch.tsx +58 -0
- package/src/ui/components/table-view.ts +219 -0
- package/src/ui/components/table.tsx +506 -0
- package/src/ui/components/tabs.tsx +59 -0
- package/src/ui/components/timeago.tsx +84 -0
- package/src/ui/components/tooltip.tsx +56 -0
- package/src/ui/components.json +21 -0
- package/src/ui/dev/dev-shell.tsx +145 -0
- package/src/ui/home/home-grid.tsx +177 -0
- package/src/ui/hooks/use-mobile.ts +19 -0
- package/src/ui/index.ts +189 -0
- package/src/ui/install/adapter.ts +193 -0
- package/src/ui/install/deploy-targets-picker.tsx +185 -0
- package/src/ui/install/install-app-panel.tsx +912 -0
- package/src/ui/install/install-error.tsx +62 -0
- package/src/ui/install/perms-inactive.ts +50 -0
- package/src/ui/install/required-fields.ts +37 -0
- package/src/ui/install/tabs-form.tsx +557 -0
- package/src/ui/tokens.css +279 -0
- package/src/ui/utils.ts +78 -0
- package/src/ui-error.ts +139 -0
- package/src/ui-runtime/dev-landing-entry.tsx +258 -0
- package/src/ui-runtime/index.ts +83 -0
- package/src/ui-runtime/install-entry.tsx +119 -0
- package/src/ui-runtime/mount.ts +367 -0
- package/src/ui-runtime/runtime.css +56 -0
- package/src/ui-surface.ts +451 -0
- package/src/valkey.ts +43 -0
- package/src/worker/extract-tar.ts +125 -0
- package/src/worker/identity.ts +183 -0
- package/src/worker/index.ts +16 -0
- package/src/worker/public-ip.ts +92 -0
- package/src/worker/queue.ts +54 -0
- package/src/worker/reconcile.ts +127 -0
- package/src/worker/start-worker.ts +227 -0
- package/src/worker/ui-proxy.ts +335 -0
- package/src/worker/uplink.ts +523 -0
- package/src/worker/validate.ts +34 -0
- package/src/worker/verify-relay.ts +102 -0
- package/src/worker-protocol/app-dirs.ts +94 -0
- package/src/worker-protocol/home-proxy-paths.ts +76 -0
- package/src/worker-protocol/index.ts +55 -0
- package/src/worker-protocol/ingress.ts +166 -0
- package/src/worker-protocol/logs-socket-path.ts +50 -0
- package/src/worker-protocol/networks.ts +39 -0
- package/src/worker-protocol/node-version.ts +70 -0
- package/src/worker-protocol/silo-paths.ts +114 -0
- package/src/worker-protocol/spawn-paths.ts +165 -0
- package/src/worker-protocol/stats-socket-path.ts +40 -0
- package/src/worker-protocol/update-files.ts +77 -0
- package/src/worker-protocol/uplink/constants.ts +86 -0
- package/src/worker-protocol/uplink/errors.ts +61 -0
- package/src/worker-protocol/uplink/frame.ts +114 -0
- package/src/worker-protocol/uplink/identity.ts +40 -0
- package/src/worker-protocol/uplink/index.ts +63 -0
- package/src/worker-protocol/uplink/methods.ts +462 -0
- package/src/worker-protocol/uplink/mux.ts +646 -0
- package/src/worker-protocol/uplink/protocol.ts +11 -0
- package/src/worker-protocol/uplink/rpc.ts +309 -0
- package/src/worker-protocol/uplink/session.ts +540 -0
- package/src/worker-protocol/uplink/test-support.ts +188 -0
- package/src/worker-protocol/worker-mount.ts +27 -0
- package/src/worker-protocol/worker-state.ts +190 -0
- package/src/xml.ts +49 -0
- package/src/yaml.ts +15 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// `realm-sdk build-install-panel --out <dir>` — esbuild the install panel entry
|
|
2
|
+
// into `install-panel.js`, alongside `runtime.js` from `build-runtime`. CSS is
|
|
3
|
+
// shared: runtime.css's Tailwind scan already covers `packages/sdk/src/ui/install/*`.
|
|
4
|
+
//
|
|
5
|
+
// `realm-sdk dev` builds both bundles into one temp dir on first boot and serves
|
|
6
|
+
// them at `/runtime.js` + `/install-panel.js`; the `/install` HTML shell loads
|
|
7
|
+
// runtime.css (no per-surface CSS) and mounts the panel.
|
|
8
|
+
|
|
9
|
+
import { resolve } from "@std/path";
|
|
10
|
+
import { sdkDir } from "../pkg-root.ts";
|
|
11
|
+
|
|
12
|
+
const ENTRY = resolve(sdkDir(import.meta.url), "src/ui-runtime/install-entry.tsx");
|
|
13
|
+
|
|
14
|
+
interface BuildOpts {
|
|
15
|
+
outDir: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function buildJs(outDir: string): Promise<void> {
|
|
19
|
+
const cmd = new Deno.Command("esbuild", {
|
|
20
|
+
args: [
|
|
21
|
+
ENTRY,
|
|
22
|
+
"--bundle",
|
|
23
|
+
`--outfile=${outDir}/install-panel.js`,
|
|
24
|
+
"--format=esm",
|
|
25
|
+
"--platform=browser",
|
|
26
|
+
"--target=es2020",
|
|
27
|
+
"--main-fields=module,main",
|
|
28
|
+
"--jsx=automatic",
|
|
29
|
+
"--jsx-import-source=preact",
|
|
30
|
+
// preact/compat keeps Ark UI's react adapter pointing at preact —
|
|
31
|
+
// same set of aliases the runtime build uses.
|
|
32
|
+
"--alias:react=preact/compat",
|
|
33
|
+
"--alias:react-dom=preact/compat",
|
|
34
|
+
"--alias:react/jsx-runtime=preact/jsx-runtime",
|
|
35
|
+
'--define:process.env.NODE_ENV="production"',
|
|
36
|
+
"--minify",
|
|
37
|
+
],
|
|
38
|
+
stdout: "piped",
|
|
39
|
+
stderr: "piped",
|
|
40
|
+
});
|
|
41
|
+
const { code, stderr } = await cmd.output();
|
|
42
|
+
if (code !== 0) {
|
|
43
|
+
const err = new TextDecoder().decode(stderr);
|
|
44
|
+
throw new Error(`esbuild install-panel failed:\n${err}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function buildInstallPanel(opts: BuildOpts): Promise<void> {
|
|
49
|
+
const outDir = resolve(Deno.cwd(), opts.outDir);
|
|
50
|
+
await Deno.mkdir(outDir, { recursive: true });
|
|
51
|
+
await buildJs(outDir);
|
|
52
|
+
const jsStat = await Deno.stat(`${outDir}/install-panel.js`);
|
|
53
|
+
console.log(
|
|
54
|
+
`install-panel → ${outDir}: install-panel.js (${(jsStat.size / 1024).toFixed(1)} KB)`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function runBuildInstallPanel(args: string[]): Promise<number> {
|
|
59
|
+
let outDir = "./ui-runtime";
|
|
60
|
+
for (let i = 0; i < args.length; i++) {
|
|
61
|
+
const a = args[i]!;
|
|
62
|
+
if (a === "--out" || a === "-o") {
|
|
63
|
+
const next = args[i + 1];
|
|
64
|
+
if (!next) {
|
|
65
|
+
console.error("--out requires a directory argument");
|
|
66
|
+
return 2;
|
|
67
|
+
}
|
|
68
|
+
outDir = next;
|
|
69
|
+
i++;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (a === "--help" || a === "-h") {
|
|
73
|
+
console.log(`Usage: realm-sdk build-install-panel [--out DIR]
|
|
74
|
+
|
|
75
|
+
Builds the install panel entry (install-panel.js) into DIR.
|
|
76
|
+
DIR defaults to ./ui-runtime (relative to the current directory).
|
|
77
|
+
`);
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
80
|
+
console.error(`Unknown flag: ${a}`);
|
|
81
|
+
return 2;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
await buildInstallPanel({ outDir });
|
|
85
|
+
return 0;
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error((err as Error).message);
|
|
88
|
+
return 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// `realm-sdk build-runtime --out <dir>` — build the iframe runtime (preact +
|
|
2
|
+
// hooks + @yourrealm/sdk/ui components + zod + the SDK's authoring surface)
|
|
3
|
+
// into a single ESM bundle plus the matching tailwind CSS.
|
|
4
|
+
//
|
|
5
|
+
// The shell HTML's importmap maps every external a surface bundle declares —
|
|
6
|
+
// `@yourrealm/sdk`, `@yourrealm/sdk/ui`, `@yourrealm/sdk/preact`,
|
|
7
|
+
// `@yourrealm/sdk/jsx-runtime`, `@yourrealm/sdk/services`, `zod` — to this one
|
|
8
|
+
// URL, and the browser dedupes by URL so every surface shares one instance.
|
|
9
|
+
//
|
|
10
|
+
// Home calls this at build time to populate `static/ui-runtime/`; `realm-sdk
|
|
11
|
+
// dev` calls it once into a temp dir on first boot. Both outputs are
|
|
12
|
+
// byte-identical for a given source tree.
|
|
13
|
+
|
|
14
|
+
import { resolve } from "@std/path";
|
|
15
|
+
import { sdkDir } from "../pkg-root.ts";
|
|
16
|
+
import { findTailwindBin } from "../tailwind-bin.ts";
|
|
17
|
+
|
|
18
|
+
const SDK_DIR = sdkDir(import.meta.url);
|
|
19
|
+
const ENTRY = resolve(SDK_DIR, "src/ui-runtime/index.ts");
|
|
20
|
+
const CSS_ENTRY = resolve(SDK_DIR, "src/ui-runtime/runtime.css");
|
|
21
|
+
|
|
22
|
+
interface BuildOpts {
|
|
23
|
+
outDir: string;
|
|
24
|
+
/**
|
|
25
|
+
* Where to resolve `node_modules/.bin/tailwindcss` from. The SDK
|
|
26
|
+
* package has `tailwindcss` as a devDependency so the binary lives at
|
|
27
|
+
* `packages/sdk/node_modules/.bin/tailwindcss` after `pnpm install`.
|
|
28
|
+
* Walking up from the script handles both monorepo dev and any future
|
|
29
|
+
* "ship the runtime as a JSR artifact" setup.
|
|
30
|
+
*/
|
|
31
|
+
workspaceRoot?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function buildJs(outDir: string): Promise<void> {
|
|
35
|
+
const cmd = new Deno.Command("esbuild", {
|
|
36
|
+
args: [
|
|
37
|
+
ENTRY,
|
|
38
|
+
"--bundle",
|
|
39
|
+
`--outfile=${outDir}/runtime.js`,
|
|
40
|
+
"--format=esm",
|
|
41
|
+
"--platform=browser",
|
|
42
|
+
"--target=es2020",
|
|
43
|
+
"--main-fields=module,main",
|
|
44
|
+
"--jsx=automatic",
|
|
45
|
+
"--jsx-import-source=@yourrealm/sdk",
|
|
46
|
+
// preact/compat keeps Ark UI's react adapter pointing at preact;
|
|
47
|
+
// bundle it so component imports of "react" resolve to compat.
|
|
48
|
+
"--alias:react=preact/compat",
|
|
49
|
+
"--alias:react-dom=preact/compat",
|
|
50
|
+
"--alias:react/jsx-runtime=preact/jsx-runtime",
|
|
51
|
+
// Preact has process.env.NODE_ENV branches; pick prod once for the
|
|
52
|
+
// runtime so dev-only warnings don't ship.
|
|
53
|
+
'--define:process.env.NODE_ENV="production"',
|
|
54
|
+
"--minify",
|
|
55
|
+
],
|
|
56
|
+
stdout: "piped",
|
|
57
|
+
stderr: "piped",
|
|
58
|
+
});
|
|
59
|
+
const { code, stderr } = await cmd.output();
|
|
60
|
+
if (code !== 0) {
|
|
61
|
+
const err = new TextDecoder().decode(stderr);
|
|
62
|
+
throw new Error(`esbuild ui-runtime failed:\n${err}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function buildCss(outDir: string, tailwindBin: string, cwd: string): Promise<void> {
|
|
67
|
+
const cmd = new Deno.Command(tailwindBin, {
|
|
68
|
+
args: ["--input", CSS_ENTRY, "--output", `${outDir}/runtime.css`, "--minify"],
|
|
69
|
+
cwd,
|
|
70
|
+
stdout: "piped",
|
|
71
|
+
stderr: "piped",
|
|
72
|
+
});
|
|
73
|
+
const { code, stderr } = await cmd.output();
|
|
74
|
+
if (code !== 0) {
|
|
75
|
+
const err = new TextDecoder().decode(stderr);
|
|
76
|
+
throw new Error(`tailwindcss ui-runtime failed:\n${err}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function buildRuntime(opts: BuildOpts): Promise<void> {
|
|
81
|
+
const outDir = resolve(Deno.cwd(), opts.outDir);
|
|
82
|
+
await Deno.mkdir(outDir, { recursive: true });
|
|
83
|
+
// Resolve tailwind's bin from the SDK package dir, so the search starts next
|
|
84
|
+
// to the runtime sources rather than at the caller's cwd.
|
|
85
|
+
const searchStart = opts.workspaceRoot ?? SDK_DIR;
|
|
86
|
+
const tailwindBin = findTailwindBin(searchStart);
|
|
87
|
+
// Tailwind resolves `@import "@yourrealm/sdk/ui/tokens.css"` via node_modules
|
|
88
|
+
// from cwd, so the cwd is the SDK package dir where `@yourrealm/sdk` (self)
|
|
89
|
+
// is in scope.
|
|
90
|
+
const tailwindCwd = SDK_DIR;
|
|
91
|
+
await Promise.all([buildJs(outDir), buildCss(outDir, tailwindBin, tailwindCwd)]);
|
|
92
|
+
const [jsStat, cssStat] = await Promise.all([
|
|
93
|
+
Deno.stat(`${outDir}/runtime.js`),
|
|
94
|
+
Deno.stat(`${outDir}/runtime.css`),
|
|
95
|
+
]);
|
|
96
|
+
console.log(
|
|
97
|
+
`ui-runtime → ${outDir}: runtime.js (${(jsStat.size / 1024).toFixed(1)} KB) + runtime.css (${(cssStat.size / 1024).toFixed(1)} KB)`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function runBuildRuntime(args: string[]): Promise<number> {
|
|
102
|
+
let outDir = "./ui-runtime";
|
|
103
|
+
for (let i = 0; i < args.length; i++) {
|
|
104
|
+
const a = args[i]!;
|
|
105
|
+
if (a === "--out" || a === "-o") {
|
|
106
|
+
const next = args[i + 1];
|
|
107
|
+
if (!next) {
|
|
108
|
+
console.error("--out requires a directory argument");
|
|
109
|
+
return 2;
|
|
110
|
+
}
|
|
111
|
+
outDir = next;
|
|
112
|
+
i++;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (a === "--help" || a === "-h") {
|
|
116
|
+
console.log(`Usage: realm-sdk build-runtime [--out DIR]
|
|
117
|
+
|
|
118
|
+
Builds the iframe runtime (runtime.js + runtime.css) into DIR.
|
|
119
|
+
DIR defaults to ./ui-runtime (relative to the current directory).
|
|
120
|
+
`);
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
console.error(`Unknown flag: ${a}`);
|
|
124
|
+
return 2;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
await buildRuntime({ outDir });
|
|
128
|
+
return 0;
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error((err as Error).message);
|
|
131
|
+
return 1;
|
|
132
|
+
}
|
|
133
|
+
}
|
package/src/cli/build.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// `realm-sdk build [--app DIR] [--out FILE]` — pack a multi-file app
|
|
2
|
+
// (realm.tsx + pages/*.tsx + widgets/*.tsx + relative helpers) into the single
|
|
3
|
+
// marker-delimited artifact Home ingests. Each file is preserved verbatim under
|
|
4
|
+
// a `// realm-file: <path>` marker, so the store can preview it file by file and
|
|
5
|
+
// any integrity digest is over readable source. Home unpacks + merges + bundles
|
|
6
|
+
// at install. Writes to FILE, or stdout when --out is omitted.
|
|
7
|
+
//
|
|
8
|
+
// Collecting the file set lives in ../pack-build.ts (shared with `realm-sdk
|
|
9
|
+
// dev`'s install panel); this file is the CLI shell plus a fail-fast merge +
|
|
10
|
+
// bundle + eval.
|
|
11
|
+
|
|
12
|
+
import { dirname, resolve } from "@std/path";
|
|
13
|
+
import { bundle } from "../bundle.ts";
|
|
14
|
+
import { buildPackedApp } from "../pack-build.ts";
|
|
15
|
+
import { extractSchema } from "../sandbox.ts";
|
|
16
|
+
|
|
17
|
+
export async function runBuild(args: string[]): Promise<number> {
|
|
18
|
+
let appDir = Deno.cwd();
|
|
19
|
+
let out: string | null = null;
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
if (args[i] === "--help" || args[i] === "-h") {
|
|
22
|
+
console.log(
|
|
23
|
+
"Usage: realm-sdk build [--app DIR] [--out FILE]\n\n" +
|
|
24
|
+
"Pack realm.tsx + pages/*.tsx + widgets/*.tsx into one marker-\n" +
|
|
25
|
+
"delimited artifact. Writes to FILE, or stdout when --out is omitted.",
|
|
26
|
+
);
|
|
27
|
+
return 0;
|
|
28
|
+
} else if (args[i] === "--app" || args[i] === "--out") {
|
|
29
|
+
const flag = args[i];
|
|
30
|
+
const value = args[++i];
|
|
31
|
+
if (value === undefined) {
|
|
32
|
+
console.error(`${flag} requires a value`);
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
35
|
+
if (flag === "--app") appDir = resolve(value);
|
|
36
|
+
else out = resolve(value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const packed = await buildPackedApp(appDir);
|
|
42
|
+
|
|
43
|
+
// Fail fast: prove the packed artifact bundles AND evaluates before handing
|
|
44
|
+
// it over. bundle() runs the exact merge + bundle Home does at install, and
|
|
45
|
+
// extractSchema evaluates the module top-level, so an inline `ui:` block
|
|
46
|
+
// colliding with file-based surfaces (attachSurfaces throws) is caught here,
|
|
47
|
+
// near the author, not at install on the operator.
|
|
48
|
+
const bundledCode = await bundle(packed);
|
|
49
|
+
await extractSchema(bundledCode);
|
|
50
|
+
|
|
51
|
+
if (out) {
|
|
52
|
+
await Deno.mkdir(dirname(out), { recursive: true });
|
|
53
|
+
await Deno.writeTextFile(out, packed);
|
|
54
|
+
console.error(`Built ${out}.`);
|
|
55
|
+
} else {
|
|
56
|
+
console.log(packed);
|
|
57
|
+
}
|
|
58
|
+
return 0;
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(`build failed: ${(err as Error).message}`);
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/cli/dev.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// `realm-sdk dev [path]` — boot the realm.ts(x) at `path` locally and serve
|
|
2
|
+
// every `ui:` surface on a hot-reloading HTTP server: the local mirror of what
|
|
3
|
+
// Home does in production, docker compose up + iframe shell + loader proxy, all
|
|
4
|
+
// driven by one realm.ts on disk.
|
|
5
|
+
//
|
|
6
|
+
// With no positional arg it looks for `realm.tsx` then `realm.ts` in the current
|
|
7
|
+
// directory; default port is 7100. All the lifting happens in `dev/server.ts`.
|
|
8
|
+
|
|
9
|
+
import { resolve } from "@std/path";
|
|
10
|
+
import { startDevServer } from "../dev/server.ts";
|
|
11
|
+
|
|
12
|
+
const HELP = `Usage: realm-sdk dev [path] [--port N]
|
|
13
|
+
|
|
14
|
+
Boots the realm.ts(x) at \`path\` (defaults to \`./realm.tsx\` then
|
|
15
|
+
\`./realm.ts\`) and serves its ui surfaces on http://localhost:7100.
|
|
16
|
+
File changes trigger a recompile and an iframe reload.
|
|
17
|
+
|
|
18
|
+
Options:
|
|
19
|
+
--port N Listen on port N (default: 7100).
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
interface ParsedArgs {
|
|
23
|
+
/** Explicit positional path, or null when defaulting to cwd discovery. */
|
|
24
|
+
realmFile: string | null;
|
|
25
|
+
port: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function parseArgs(args: string[]): ParsedArgs | null {
|
|
29
|
+
let port = 7100;
|
|
30
|
+
let positional: string | null = null;
|
|
31
|
+
for (let i = 0; i < args.length; i++) {
|
|
32
|
+
const a = args[i]!;
|
|
33
|
+
if (a === "--help" || a === "-h") return null;
|
|
34
|
+
if (a === "--port" || a === "-p") {
|
|
35
|
+
const next = args[i + 1];
|
|
36
|
+
if (!next) {
|
|
37
|
+
console.error("--port requires a number");
|
|
38
|
+
Deno.exit(2);
|
|
39
|
+
}
|
|
40
|
+
const n = Number(next);
|
|
41
|
+
if (!Number.isFinite(n) || n <= 0 || n > 65535) {
|
|
42
|
+
console.error(`invalid port: ${next}`);
|
|
43
|
+
Deno.exit(2);
|
|
44
|
+
}
|
|
45
|
+
port = n;
|
|
46
|
+
i++;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (a.startsWith("-")) {
|
|
50
|
+
console.error(`Unknown flag: ${a}`);
|
|
51
|
+
Deno.exit(2);
|
|
52
|
+
}
|
|
53
|
+
if (positional !== null) {
|
|
54
|
+
console.error("expected at most one positional argument (the realm.ts path)");
|
|
55
|
+
Deno.exit(2);
|
|
56
|
+
}
|
|
57
|
+
positional = a;
|
|
58
|
+
}
|
|
59
|
+
return { realmFile: positional !== null ? resolve(positional) : null, port };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function existsSync(path: string): boolean {
|
|
63
|
+
try {
|
|
64
|
+
Deno.statSync(path);
|
|
65
|
+
return true;
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function resolveRealmFile(parsed: ParsedArgs): string | null {
|
|
72
|
+
if (parsed.realmFile !== null) {
|
|
73
|
+
return existsSync(parsed.realmFile) ? parsed.realmFile : null;
|
|
74
|
+
}
|
|
75
|
+
// No positional arg — look for realm.tsx then realm.ts in cwd. tsx
|
|
76
|
+
// first because the rebrand examples + counter-fresh use it.
|
|
77
|
+
for (const candidate of ["realm.tsx", "realm.ts"]) {
|
|
78
|
+
const path = resolve(candidate);
|
|
79
|
+
if (existsSync(path)) return path;
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function runDev(args: string[]): Promise<number> {
|
|
85
|
+
const parsed = parseArgs(args);
|
|
86
|
+
if (parsed === null) {
|
|
87
|
+
console.log(HELP);
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
const realmFile = resolveRealmFile(parsed);
|
|
91
|
+
if (realmFile === null) {
|
|
92
|
+
if (parsed.realmFile !== null) {
|
|
93
|
+
console.error(`Cannot read ${parsed.realmFile}`);
|
|
94
|
+
} else {
|
|
95
|
+
console.error(
|
|
96
|
+
`No realm.tsx or realm.ts in ${Deno.cwd()} — pass an explicit path or cd into an app directory.`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return 1;
|
|
100
|
+
}
|
|
101
|
+
// The cwd anchors the file watcher and the dev fixture lookup. The realm.ts
|
|
102
|
+
// can live anywhere; the watcher just needs a parent directory.
|
|
103
|
+
const cwd = resolve(realmFile, "..");
|
|
104
|
+
|
|
105
|
+
await startDevServer({ cwd, port: parsed.port, realmFile });
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
package/src/cli/down.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// `realm-sdk down` — tears down any compose stacks the harness left
|
|
2
|
+
// running. Stacks are tagged with `com.realm.test=true`; we look up
|
|
3
|
+
// every container with that label, group by compose project name, and
|
|
4
|
+
// run `docker compose -p <project> down -v` per project.
|
|
5
|
+
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
async function listTestProjects(): Promise<string[]> {
|
|
9
|
+
const cmd = new Deno.Command("docker", {
|
|
10
|
+
args: ["ps", "-a", "--filter", "label=com.realm.test=true", "--format", "{{json .}}"],
|
|
11
|
+
stdout: "piped",
|
|
12
|
+
stderr: "inherit",
|
|
13
|
+
});
|
|
14
|
+
const { code, stdout } = await cmd.output();
|
|
15
|
+
if (code !== 0) throw new Error(`docker ps failed (exit ${code})`);
|
|
16
|
+
|
|
17
|
+
const projects = new Set<string>();
|
|
18
|
+
const text = new TextDecoder().decode(stdout);
|
|
19
|
+
for (const line of text.split("\n")) {
|
|
20
|
+
if (!line.trim()) continue;
|
|
21
|
+
const row = z.object({ Labels: z.string().optional() }).parse(JSON.parse(line));
|
|
22
|
+
const labels = row.Labels ?? "";
|
|
23
|
+
const match = labels.match(/com\.docker\.compose\.project=([^,]+)/);
|
|
24
|
+
if (match) projects.add(match[1]!);
|
|
25
|
+
}
|
|
26
|
+
return [...projects];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function tearDown(project: string): Promise<number> {
|
|
30
|
+
console.log(`Tearing down ${project}...`);
|
|
31
|
+
const cmd = new Deno.Command("docker", {
|
|
32
|
+
args: ["compose", "-p", project, "down", "-v"],
|
|
33
|
+
stdout: "inherit",
|
|
34
|
+
stderr: "inherit",
|
|
35
|
+
});
|
|
36
|
+
const { code } = await cmd.output();
|
|
37
|
+
return code;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function runDown(_args: string[]): Promise<number> {
|
|
41
|
+
let projects: string[];
|
|
42
|
+
try {
|
|
43
|
+
projects = await listTestProjects();
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (projects.length === 0) {
|
|
50
|
+
console.log("No realm-sdk test stacks running.");
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let exitCode = 0;
|
|
55
|
+
for (const project of projects) {
|
|
56
|
+
const code = await tearDown(project);
|
|
57
|
+
if (code !== 0) exitCode = code;
|
|
58
|
+
}
|
|
59
|
+
return exitCode;
|
|
60
|
+
}
|
package/src/cli/main.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env -S deno run --allow-all
|
|
2
|
+
// `realm-sdk` CLI dispatcher. Subcommands are named modules in this directory,
|
|
3
|
+
// each exporting a `run(args)` that returns the process exit code; subcommand
|
|
4
|
+
// selection, error formatting and the exit code stay here.
|
|
5
|
+
|
|
6
|
+
import { runTest } from "./test.ts";
|
|
7
|
+
import { runDown } from "./down.ts";
|
|
8
|
+
import { runValidate } from "./validate.ts";
|
|
9
|
+
import { runBuild } from "./build.ts";
|
|
10
|
+
import { runBuildRuntime } from "./build-runtime.ts";
|
|
11
|
+
import { runDev } from "./dev.ts";
|
|
12
|
+
|
|
13
|
+
const HELP = `Usage: realm-sdk <command> [args]
|
|
14
|
+
|
|
15
|
+
Commands:
|
|
16
|
+
test Run realm.ts tests (compile tier; pass --e2e for boot tests).
|
|
17
|
+
down Tear down any test stacks left running (com.realm.test=true).
|
|
18
|
+
validate Parse a realm.ts and report compile errors without a fixture.
|
|
19
|
+
build Collapse realm.tsx + pages/*.tsx + widgets/*.tsx into one source.
|
|
20
|
+
build-runtime Build the iframe runtime (runtime.js + runtime.css) into a directory.
|
|
21
|
+
dev Boot the app locally and serve its ui surfaces with hot reload.
|
|
22
|
+
|
|
23
|
+
Run \`realm-sdk <command> --help\` for command-specific options.
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
async function main(): Promise<number> {
|
|
27
|
+
const [cmd, ...rest] = Deno.args;
|
|
28
|
+
switch (cmd) {
|
|
29
|
+
case undefined:
|
|
30
|
+
case "--help":
|
|
31
|
+
case "-h":
|
|
32
|
+
case "help":
|
|
33
|
+
console.log(HELP);
|
|
34
|
+
return 0;
|
|
35
|
+
case "test":
|
|
36
|
+
return await runTest(rest);
|
|
37
|
+
case "down":
|
|
38
|
+
return await runDown(rest);
|
|
39
|
+
case "validate":
|
|
40
|
+
return await runValidate(rest);
|
|
41
|
+
case "build":
|
|
42
|
+
return await runBuild(rest);
|
|
43
|
+
case "build-runtime":
|
|
44
|
+
return await runBuildRuntime(rest);
|
|
45
|
+
case "dev":
|
|
46
|
+
return await runDev(rest);
|
|
47
|
+
default:
|
|
48
|
+
console.error(`Unknown command: ${cmd}\n`);
|
|
49
|
+
console.error(HELP);
|
|
50
|
+
return 2;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (import.meta.main) {
|
|
55
|
+
Deno.exit(await main());
|
|
56
|
+
}
|
package/src/cli/test.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// `realm-sdk test` — discovers `*.test.ts` from the working directory and runs
|
|
2
|
+
// them under `deno test`. The harness inside each test file drives compile/boot
|
|
3
|
+
// via `Realm.describe`; the CLI only invokes deno test with the right flags.
|
|
4
|
+
//
|
|
5
|
+
// Flag handling is deliberately thin:
|
|
6
|
+
// --e2e Intercepted. Sets REALM_TEST_E2E=1 so `t.boot` runs
|
|
7
|
+
// (default skipped) and strips the flag.
|
|
8
|
+
// everything else Forwarded to `deno test` as-is.
|
|
9
|
+
// args after `--` Forwarded to the test script. Snapshot regen lives
|
|
10
|
+
// here: `realm-sdk test -- --update`.
|
|
11
|
+
|
|
12
|
+
interface TestArgs {
|
|
13
|
+
e2e: boolean;
|
|
14
|
+
denoArgs: string[];
|
|
15
|
+
scriptArgs: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function parseArgs(args: string[]): TestArgs {
|
|
19
|
+
const denoArgs: string[] = [];
|
|
20
|
+
const scriptArgs: string[] = [];
|
|
21
|
+
let e2e = false;
|
|
22
|
+
let sawSeparator = false;
|
|
23
|
+
|
|
24
|
+
for (const arg of args) {
|
|
25
|
+
if (sawSeparator) {
|
|
26
|
+
scriptArgs.push(arg);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (arg === "--") {
|
|
30
|
+
sawSeparator = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (arg === "--e2e") {
|
|
34
|
+
e2e = true;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
denoArgs.push(arg);
|
|
38
|
+
}
|
|
39
|
+
return { e2e, denoArgs, scriptArgs };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function runTest(args: string[]): Promise<number> {
|
|
43
|
+
const { e2e, denoArgs, scriptArgs } = parseArgs(args);
|
|
44
|
+
|
|
45
|
+
const env: Record<string, string> = {};
|
|
46
|
+
if (e2e) env["REALM_TEST_E2E"] = "1";
|
|
47
|
+
|
|
48
|
+
const cliArgs = ["test", "--allow-all", ...denoArgs];
|
|
49
|
+
if (scriptArgs.length > 0) cliArgs.push("--", ...scriptArgs);
|
|
50
|
+
|
|
51
|
+
const cmd = new Deno.Command("deno", {
|
|
52
|
+
args: cliArgs,
|
|
53
|
+
env,
|
|
54
|
+
stdout: "inherit",
|
|
55
|
+
stderr: "inherit",
|
|
56
|
+
stdin: "inherit",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const { code } = await cmd.output();
|
|
60
|
+
return code;
|
|
61
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// `realm-sdk validate [path]` — bundles the realm.ts at `path` (default
|
|
2
|
+
// `./realm.ts`) and runs `extractSchema` to surface eval/syntax/blocked
|
|
3
|
+
// import errors. No fixture is required; this is the "is the source
|
|
4
|
+
// well-formed" check intended for CI gates and editor watchers.
|
|
5
|
+
|
|
6
|
+
import { resolve } from "@std/path";
|
|
7
|
+
import { bundle } from "../bundle.ts";
|
|
8
|
+
import { extractSchema } from "../sandbox.ts";
|
|
9
|
+
import { RealmCompileError, formatIssue } from "../errors.ts";
|
|
10
|
+
|
|
11
|
+
export async function runValidate(args: string[]): Promise<number> {
|
|
12
|
+
const target = resolve(args[0] ?? "realm.ts");
|
|
13
|
+
|
|
14
|
+
let source: string;
|
|
15
|
+
try {
|
|
16
|
+
source = await Deno.readTextFile(target);
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.error(`Cannot read ${target}: ${err instanceof Error ? err.message : err}`);
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const bundled = await bundle(source);
|
|
24
|
+
await extractSchema(bundled);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
if (err instanceof RealmCompileError) {
|
|
27
|
+
console.error(`${target}:`);
|
|
28
|
+
for (const issue of err.issues) console.error(` - ${formatIssue(issue)}`);
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
console.error(`${target}: ${err instanceof Error ? err.message : err}`);
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log(`${target}: ok`);
|
|
36
|
+
return 0;
|
|
37
|
+
}
|