@astralarium/repo-dev 0.0.0-stage → 0.1.0
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 +21 -0
- package/README.md +17 -2
- package/dist/allocation.d.ts +15 -0
- package/dist/allocation.js +28 -0
- package/dist/bin/db-image.d.ts +2 -0
- package/dist/bin/db-image.js +29 -0
- package/dist/bin/run-dev.d.ts +2 -0
- package/dist/bin/run-dev.js +15 -0
- package/dist/bin/siblings-inputs.d.ts +2 -0
- package/dist/bin/siblings-inputs.js +20 -0
- package/dist/config.d.ts +240 -0
- package/dist/config.js +90 -0
- package/dist/environment.d.ts +19 -0
- package/dist/environment.js +45 -0
- package/dist/exec.d.ts +4 -0
- package/dist/exec.js +14 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/launcher/hosts.d.ts +26 -0
- package/dist/launcher/hosts.js +152 -0
- package/dist/launcher/launcher.d.ts +23 -0
- package/dist/launcher/launcher.js +452 -0
- package/dist/launcher/servers.d.ts +39 -0
- package/dist/launcher/servers.js +154 -0
- package/dist/load-config.d.ts +3 -0
- package/dist/load-config.js +6 -0
- package/dist/ports.d.ts +3 -0
- package/dist/ports.js +32 -0
- package/dist/process.d.ts +43 -0
- package/dist/process.js +172 -0
- package/dist/resources.d.ts +23 -0
- package/dist/resources.js +74 -0
- package/dist/sibling-inputs.d.ts +5 -0
- package/dist/sibling-inputs.js +32 -0
- package/dist/source-hash.d.ts +2 -0
- package/dist/source-hash.js +29 -0
- package/dist/testkit/built-worker.d.ts +29 -0
- package/dist/testkit/built-worker.js +48 -0
- package/dist/testkit/env-template.d.ts +8 -0
- package/dist/testkit/env-template.js +14 -0
- package/dist/testkit/index.d.ts +8 -0
- package/dist/testkit/index.js +8 -0
- package/dist/testkit/ports.d.ts +8 -0
- package/dist/testkit/ports.js +20 -0
- package/dist/testkit/temp.d.ts +2 -0
- package/dist/testkit/temp.js +10 -0
- package/dist/testkit/test-cache.d.ts +14 -0
- package/dist/testkit/test-cache.js +174 -0
- package/dist/testkit/worker-build.d.ts +26 -0
- package/dist/testkit/worker-build.js +46 -0
- package/dist/vite.d.ts +96 -0
- package/dist/vite.js +254 -0
- package/dist/wait.d.ts +9 -0
- package/dist/wait.js +38 -0
- package/package.json +71 -3
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DevConfig } from "../config.ts";
|
|
2
|
+
/** Sorted key differences between `file` and the keys the launcher reads for `app`. */
|
|
3
|
+
export declare function overrideTemplateGaps(app: DevConfig, file?: string): {
|
|
4
|
+
/** Override keys absent from the template. */
|
|
5
|
+
missing: string[];
|
|
6
|
+
/** Template keys the launcher ignores. */
|
|
7
|
+
extra: string[];
|
|
8
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** `.env.tmpl` coverage of the launcher's override keys. */
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { parseEnv } from "node:util";
|
|
5
|
+
import { overrideKeys } from "../launcher/launcher.js";
|
|
6
|
+
/** Sorted key differences between `file` and the keys the launcher reads for `app`. */
|
|
7
|
+
export function overrideTemplateGaps(app, file = resolve(app.root, ".env.tmpl")) {
|
|
8
|
+
const template = Object.keys(parseEnv(readFileSync(file, "utf8")));
|
|
9
|
+
const keys = overrideKeys(app);
|
|
10
|
+
return {
|
|
11
|
+
missing: keys.filter((key) => !template.includes(key)).sort(),
|
|
12
|
+
extra: template.filter((key) => !keys.includes(key)).sort(),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Test support: built-worker checks and suite, `.env.tmpl` coverage,
|
|
2
|
+
* loopback ports, per-test temp dirs and turbo test caching. */
|
|
3
|
+
export { type BuiltWorkerConfig, findInBundle, type FindInBundleOptions, readBuiltWorkerConfig, requiredSecrets, } from "./built-worker.ts";
|
|
4
|
+
export * from "./env-template.ts";
|
|
5
|
+
export * from "./ports.ts";
|
|
6
|
+
export * from "./temp.ts";
|
|
7
|
+
export * from "./test-cache.ts";
|
|
8
|
+
export * from "./worker-build.ts";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Test support: built-worker checks and suite, `.env.tmpl` coverage,
|
|
2
|
+
* loopback ports, per-test temp dirs and turbo test caching. */
|
|
3
|
+
export { findInBundle, readBuiltWorkerConfig, requiredSecrets, } from "./built-worker.js";
|
|
4
|
+
export * from "./env-template.js";
|
|
5
|
+
export * from "./ports.js";
|
|
6
|
+
export * from "./temp.js";
|
|
7
|
+
export * from "./test-cache.js";
|
|
8
|
+
export * from "./worker-build.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Loopback ports for allocation tests. */
|
|
2
|
+
import { type Server } from "node:net";
|
|
3
|
+
/** A loopback port held open by a server pushed onto `held`. */
|
|
4
|
+
export declare function heldPort(held: Server[]): Promise<number>;
|
|
5
|
+
/** A loopback port free at the time of the call. */
|
|
6
|
+
export declare function freePort(): Promise<number>;
|
|
7
|
+
/** Closes every server in `held`, emptying it. */
|
|
8
|
+
export declare function releasePorts(held: Server[]): Promise<unknown>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Loopback ports for allocation tests. */
|
|
2
|
+
import { createServer } from "node:net";
|
|
3
|
+
/** A loopback port held open by a server pushed onto `held`. */
|
|
4
|
+
export async function heldPort(held) {
|
|
5
|
+
const server = createServer();
|
|
6
|
+
held.push(server);
|
|
7
|
+
await new Promise((done) => server.listen(0, "127.0.0.1", done));
|
|
8
|
+
return server.address().port;
|
|
9
|
+
}
|
|
10
|
+
/** A loopback port free at the time of the call. */
|
|
11
|
+
export async function freePort() {
|
|
12
|
+
const held = [];
|
|
13
|
+
const port = await heldPort(held);
|
|
14
|
+
await new Promise((done) => held[0].close(done));
|
|
15
|
+
return port;
|
|
16
|
+
}
|
|
17
|
+
/** Closes every server in `held`, emptying it. */
|
|
18
|
+
export function releasePorts(held) {
|
|
19
|
+
return Promise.all(held.splice(0).map((server) => new Promise((done) => server.close(done))));
|
|
20
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { onTestFinished } from "vitest";
|
|
5
|
+
/** A fresh directory under the OS temp dir, removed when the current test finishes. */
|
|
6
|
+
export function tempDir(prefix) {
|
|
7
|
+
const dir = mkdtempSync(join(tmpdir(), prefix));
|
|
8
|
+
onTestFinished(() => rmSync(dir, { recursive: true, force: true }));
|
|
9
|
+
return dir;
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** A workspace's turbo wiring under test. */
|
|
2
|
+
export interface TestCachingOptions {
|
|
3
|
+
/** Root `turbo.json` text: `//#siblings:inputs`, `inputs`, `test` and
|
|
4
|
+
* `db:image` tasks. */
|
|
5
|
+
rootTurbo: string;
|
|
6
|
+
/** `turbo.json` text of the app whose tests read the database image. */
|
|
7
|
+
appTurbo: string;
|
|
8
|
+
/** Package whose `db:image` writes `.turbo/db-image.json`. */
|
|
9
|
+
imagePackage: string;
|
|
10
|
+
}
|
|
11
|
+
/** Runs turbo over a fixture workspace wired by `options`, asserting each
|
|
12
|
+
* test reruns exactly when its database image, sources or sibling assets
|
|
13
|
+
* change; throws on the first miss. */
|
|
14
|
+
export declare function assertTestCaching({ rootTurbo, appTurbo, imagePackage, }: TestCachingOptions): void;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/** Turbo test caching over a fixture workspace: database image, sibling
|
|
2
|
+
* sources and dependency edges invalidate exactly the tests they feed. */
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { pathToFileURL } from "node:url";
|
|
9
|
+
import { tempDir } from "./temp.js";
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
/** `@astralarium/repo-dev`, as the fixture's `siblings:inputs` imports it for
|
|
12
|
+
* `writeSiblingInputs`. */
|
|
13
|
+
const SIBLING_INPUTS = pathToFileURL(require.resolve("@astralarium/repo-dev")).href;
|
|
14
|
+
/** Runs turbo over a fixture workspace wired by `options`, asserting each
|
|
15
|
+
* test reruns exactly when its database image, sources or sibling assets
|
|
16
|
+
* change; throws on the first miss. */
|
|
17
|
+
export function assertTestCaching({ rootTurbo, appTurbo, imagePackage, }) {
|
|
18
|
+
const dir = tempDir("test-cache-");
|
|
19
|
+
const root = join(dir, "repo");
|
|
20
|
+
const upstream = join(dir, "upstream-image");
|
|
21
|
+
const assets = join(dir, "assets");
|
|
22
|
+
const write = (path, contents) => {
|
|
23
|
+
const target = join(root, path);
|
|
24
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
25
|
+
writeFileSync(target, contents);
|
|
26
|
+
};
|
|
27
|
+
write("package.json", JSON.stringify({
|
|
28
|
+
name: "cache-fixture",
|
|
29
|
+
private: true,
|
|
30
|
+
packageManager: "pnpm@10.18.1",
|
|
31
|
+
scripts: {
|
|
32
|
+
"siblings:inputs": "node siblings.cjs",
|
|
33
|
+
},
|
|
34
|
+
}));
|
|
35
|
+
write("pnpm-workspace.yaml", "packages:\n - apps/*\n - packages/*\n");
|
|
36
|
+
const sharedPackage = (consumesAssets) => {
|
|
37
|
+
write("packages/shared/package.json", JSON.stringify({
|
|
38
|
+
name: "@repo/new-assets-consumer",
|
|
39
|
+
scripts: { test: "node test.cjs" },
|
|
40
|
+
...(consumesAssets
|
|
41
|
+
? { dependencies: { "@repo/assets": "link:../../../assets" } }
|
|
42
|
+
: {}),
|
|
43
|
+
}));
|
|
44
|
+
write("pnpm-lock.yaml", `lockfileVersion: '9.0'
|
|
45
|
+
importers:
|
|
46
|
+
.: {}
|
|
47
|
+
packages/image: {}
|
|
48
|
+
packages/unrelated: {}
|
|
49
|
+
packages/shared:${consumesAssets
|
|
50
|
+
? `
|
|
51
|
+
dependencies:
|
|
52
|
+
'@repo/assets':
|
|
53
|
+
specifier: link:../../../assets
|
|
54
|
+
version: link:../../../assets`
|
|
55
|
+
: " {}"}
|
|
56
|
+
apps/web:
|
|
57
|
+
dependencies:
|
|
58
|
+
'${imagePackage}':
|
|
59
|
+
specifier: workspace:*
|
|
60
|
+
version: link:../../packages/image
|
|
61
|
+
'@repo/new-assets-consumer':
|
|
62
|
+
specifier: workspace:*
|
|
63
|
+
version: link:../../packages/shared
|
|
64
|
+
`);
|
|
65
|
+
};
|
|
66
|
+
sharedPackage(false);
|
|
67
|
+
write(".gitignore", ".turbo/\n");
|
|
68
|
+
write("turbo.json", rootTurbo);
|
|
69
|
+
write("apps/web/turbo.json", appTurbo);
|
|
70
|
+
write("siblings.cjs", `import(${JSON.stringify(SIBLING_INPUTS)})
|
|
71
|
+
.then(({ writeSiblingInputs }) => writeSiblingInputs(process.cwd(), [
|
|
72
|
+
{ package: "@repo/assets", dir: ${JSON.stringify(assets)}, sources: ["package.json", "runtime"] },
|
|
73
|
+
]));
|
|
74
|
+
`);
|
|
75
|
+
write("packages/image/package.json", JSON.stringify({
|
|
76
|
+
name: imagePackage,
|
|
77
|
+
scripts: { "db:image": "node image.cjs" },
|
|
78
|
+
}));
|
|
79
|
+
write("packages/image/image.cjs", `const fs = require('node:fs');
|
|
80
|
+
const image = fs.readFileSync(${JSON.stringify(upstream)}, 'utf8');
|
|
81
|
+
if (image === 'unavailable') process.exit(1);
|
|
82
|
+
fs.mkdirSync('.turbo', { recursive: true });
|
|
83
|
+
fs.writeFileSync('.turbo/db-image.json', JSON.stringify({ image }));
|
|
84
|
+
fs.appendFileSync('.turbo/builds', 'build\\n');
|
|
85
|
+
`);
|
|
86
|
+
write("packages/unrelated/package.json", JSON.stringify({
|
|
87
|
+
name: "@repo/unrelated",
|
|
88
|
+
scripts: { test: "node test.cjs" },
|
|
89
|
+
}));
|
|
90
|
+
for (const name of ["shared", "unrelated"])
|
|
91
|
+
write(`packages/${name}/test.cjs`, `const fs = require('node:fs');
|
|
92
|
+
fs.mkdirSync('.turbo', { recursive: true });
|
|
93
|
+
fs.appendFileSync('.turbo/executions', 'run\\n');
|
|
94
|
+
`);
|
|
95
|
+
write("packages/shared/source.ts", "export const value = 1;\n");
|
|
96
|
+
write("apps/web/package.json", JSON.stringify({
|
|
97
|
+
name: "web",
|
|
98
|
+
dependencies: {
|
|
99
|
+
[imagePackage]: "workspace:*",
|
|
100
|
+
"@repo/new-assets-consumer": "workspace:*",
|
|
101
|
+
},
|
|
102
|
+
scripts: { test: "node test.cjs" },
|
|
103
|
+
}));
|
|
104
|
+
write("apps/web/test.cjs", `const fs = require('node:fs');
|
|
105
|
+
const { image } = JSON.parse(fs.readFileSync('../../packages/image/.turbo/db-image.json', 'utf8'));
|
|
106
|
+
fs.mkdirSync('.turbo', { recursive: true });
|
|
107
|
+
fs.appendFileSync('.turbo/executions', image + '\\n');
|
|
108
|
+
`);
|
|
109
|
+
execFileSync("git", ["init", "--quiet", root]);
|
|
110
|
+
mkdirSync(join(assets, "runtime"), { recursive: true });
|
|
111
|
+
execFileSync("git", ["init", "--quiet", assets]);
|
|
112
|
+
writeFileSync(join(assets, "package.json"), JSON.stringify({ name: "@repo/assets" }));
|
|
113
|
+
const assetSource = join(assets, "runtime/model.ts");
|
|
114
|
+
// The fixture's turbo owns its caching: an ambient `TURBO_FORCE`
|
|
115
|
+
// would rerun every task.
|
|
116
|
+
const env = { ...process.env };
|
|
117
|
+
for (const key of Object.keys(env))
|
|
118
|
+
if (key.startsWith("TURBO_"))
|
|
119
|
+
delete env[key];
|
|
120
|
+
const run = (args = []) => execFileSync(process.execPath, [
|
|
121
|
+
require.resolve("turbo"),
|
|
122
|
+
"run",
|
|
123
|
+
"test",
|
|
124
|
+
"--continue=dependencies-successful",
|
|
125
|
+
...args,
|
|
126
|
+
"--cache=local:rw",
|
|
127
|
+
"--ui=stream",
|
|
128
|
+
], { cwd: root, env, encoding: "utf8", stdio: "pipe", timeout: 60_000 });
|
|
129
|
+
const executions = () => readFileSync(join(root, "apps/web/.turbo/executions"), "utf8");
|
|
130
|
+
const sharedExecutions = () => readFileSync(join(root, "packages/shared/.turbo/executions"), "utf8");
|
|
131
|
+
const unrelatedExecutions = () => readFileSync(join(root, "packages/unrelated/.turbo/executions"), "utf8");
|
|
132
|
+
writeFileSync(upstream, "first");
|
|
133
|
+
writeFileSync(assetSource, "original-assets");
|
|
134
|
+
run();
|
|
135
|
+
run();
|
|
136
|
+
assert.equal(executions(), "first\n");
|
|
137
|
+
writeFileSync(upstream, "second");
|
|
138
|
+
run();
|
|
139
|
+
assert.equal(executions(), "first\nsecond\n");
|
|
140
|
+
write("packages/shared/source.ts", "export const value = 2;\n");
|
|
141
|
+
run();
|
|
142
|
+
assert.equal(executions(), "first\nsecond\nsecond\n");
|
|
143
|
+
sharedPackage(true);
|
|
144
|
+
run();
|
|
145
|
+
assert.equal(executions(), "first\nsecond\nsecond\nsecond\n");
|
|
146
|
+
const unrelatedBeforeAssets = unrelatedExecutions();
|
|
147
|
+
writeFileSync(assetSource, "changed-assets");
|
|
148
|
+
run(["--filter=@repo/new-assets-consumer"]);
|
|
149
|
+
assert.equal(sharedExecutions(), "run\n".repeat(4));
|
|
150
|
+
assert.equal(executions(), "first\n" + "second\n".repeat(3));
|
|
151
|
+
run();
|
|
152
|
+
assert.equal(executions(), "first\n" + "second\n".repeat(4));
|
|
153
|
+
assert.equal(sharedExecutions(), "run\n".repeat(4));
|
|
154
|
+
assert.equal(unrelatedExecutions(), unrelatedBeforeAssets);
|
|
155
|
+
rmSync(join(root, "packages/image/.turbo/db-image.json"));
|
|
156
|
+
rmSync(join(root, "packages/shared/.turbo/siblings.json"));
|
|
157
|
+
run();
|
|
158
|
+
assert.equal(executions(), "first\n" + "second\n".repeat(4));
|
|
159
|
+
sharedPackage(false);
|
|
160
|
+
run();
|
|
161
|
+
assert.equal(executions(), "first\n" + "second\n".repeat(4));
|
|
162
|
+
assert.equal(sharedExecutions(), "run\n".repeat(4));
|
|
163
|
+
const unrelatedAfterRemoval = unrelatedExecutions();
|
|
164
|
+
writeFileSync(assetSource, "assets-with-no-consumers");
|
|
165
|
+
run();
|
|
166
|
+
assert.equal(executions(), "first\n" + "second\n".repeat(4));
|
|
167
|
+
assert.equal(sharedExecutions(), "run\n".repeat(4));
|
|
168
|
+
assert.equal(unrelatedExecutions(), unrelatedAfterRemoval);
|
|
169
|
+
assert.equal(readFileSync(join(root, "packages/image/.turbo/builds"), "utf8"), "build\n".repeat(9));
|
|
170
|
+
writeFileSync(upstream, "unavailable");
|
|
171
|
+
write("packages/shared/source.ts", "export const value = 3;\n");
|
|
172
|
+
assert.throws(() => run());
|
|
173
|
+
assert.equal(executions(), "first\n" + "second\n".repeat(4));
|
|
174
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** A client of a running worker: its answer to a GET of `path`. */
|
|
2
|
+
export type WorkerRequester = (path: string) => Promise<{
|
|
3
|
+
status: number;
|
|
4
|
+
body: {
|
|
5
|
+
cancel(): Promise<void>;
|
|
6
|
+
} | null;
|
|
7
|
+
}>;
|
|
8
|
+
/** What `testWorkerBuild` runs against. */
|
|
9
|
+
export interface WorkerBuildSuite {
|
|
10
|
+
/** App directory: source `wrangler.jsonc`, the deployment worker built
|
|
11
|
+
* in `dist/server/`, the prerender worker in `dist/prerender/`. */
|
|
12
|
+
root: string;
|
|
13
|
+
/** Wrangler env the build targets; top level when absent. Env blocks
|
|
14
|
+
* replace bindings. */
|
|
15
|
+
env?: string;
|
|
16
|
+
/** Text only dev servers carry; absent from the deployment bundle. */
|
|
17
|
+
devOnly: readonly string[];
|
|
18
|
+
/** The built prerender worker: a client of it running with inherited
|
|
19
|
+
* connection settings, and a database-backed page. */
|
|
20
|
+
prerender?: {
|
|
21
|
+
request: WorkerRequester;
|
|
22
|
+
databasePath: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** Tests of an app's built workers against its source wrangler config. */
|
|
26
|
+
export declare function testWorkerBuild({ root, env, devOnly, prerender, }: WorkerBuildSuite): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Test suite of an app's built workers: the deployment worker keeps
|
|
2
|
+
* what its wrangler config declares; the prerender worker runs without
|
|
3
|
+
* bindings or secrets. */
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import JSON5 from "json5";
|
|
7
|
+
import { describe, expect, test } from "vitest";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { BuiltWorkerConfig, findInBundle, readBuiltWorkerConfig, } from "./built-worker.js";
|
|
10
|
+
/** The declarations of a wrangler config block a build must keep. */
|
|
11
|
+
const Declarations = BuiltWorkerConfig.omit({ vars: true });
|
|
12
|
+
/** A source wrangler config: top-level block and named envs. */
|
|
13
|
+
const SourceConfig = Declarations.extend({
|
|
14
|
+
env: z.record(z.string(), Declarations).default({}),
|
|
15
|
+
});
|
|
16
|
+
/** Tests of an app's built workers against its source wrangler config. */
|
|
17
|
+
export function testWorkerBuild({ root, env, devOnly, prerender, }) {
|
|
18
|
+
const source = join(root, "wrangler.jsonc");
|
|
19
|
+
const deployment = join(root, "dist/server");
|
|
20
|
+
describe("worker build", () => {
|
|
21
|
+
test("the deployment worker keeps the Hyperdrive bindings and required secrets its wrangler config declares", async () => {
|
|
22
|
+
const config = SourceConfig.parse(JSON5.parse(await readFile(source, "utf8")));
|
|
23
|
+
const declared = env ? config.env[env] : config;
|
|
24
|
+
if (!declared)
|
|
25
|
+
throw new Error(`${source} declares no env.${env}`);
|
|
26
|
+
const built = await readBuiltWorkerConfig(deployment);
|
|
27
|
+
expect(built.hyperdrive.map(({ binding }) => binding)).toEqual(expect.arrayContaining(declared.hyperdrive.map(({ binding }) => binding)));
|
|
28
|
+
expect(built.secrets.required).toEqual(expect.arrayContaining(declared.secrets.required));
|
|
29
|
+
});
|
|
30
|
+
test.each(devOnly)("the deployment worker bundle omits dev-only %s", async (needle) => {
|
|
31
|
+
expect(await findInBundle(deployment, needle)).toEqual([]);
|
|
32
|
+
});
|
|
33
|
+
if (!prerender)
|
|
34
|
+
return;
|
|
35
|
+
test("the prerender worker declares no Hyperdrive bindings or required secrets", async () => {
|
|
36
|
+
const built = await readBuiltWorkerConfig(join(root, "dist/prerender"));
|
|
37
|
+
expect(built.hyperdrive).toEqual([]);
|
|
38
|
+
expect(built.secrets.required).toEqual([]);
|
|
39
|
+
});
|
|
40
|
+
test("the prerender worker refuses database-backed pages despite inherited connection settings", async () => {
|
|
41
|
+
const response = await prerender.request(prerender.databasePath);
|
|
42
|
+
expect(response.status).toBe(500);
|
|
43
|
+
await response.body?.cancel();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { type ConfigEnv, type Plugin, type UserConfig } from "vite";
|
|
2
|
+
/**
|
|
3
|
+
* Listener of a launched app (`listenerEnv`): dev servers serve on
|
|
4
|
+
* `SITE_ORIGIN`'s port, over HTTPS with `SSL_KEY` / `SSL_CERT`; every
|
|
5
|
+
* server binds `DEV_SERVER_HOST` (default `localhost`) on a strict port
|
|
6
|
+
* and allows the `LOCAL_ORIGINS` hostnames. Config comes from process env:
|
|
7
|
+
* Vite reads no dot-env file.
|
|
8
|
+
*/
|
|
9
|
+
export declare function devListener({ command, isPreview, mode }: ConfigEnv, env?: NodeJS.ProcessEnv): Pick<UserConfig, "envDir" | "server">;
|
|
10
|
+
/** `@cloudflare/vite-plugin` options `cloudflareDevOptions` sets. */
|
|
11
|
+
interface CloudflareDevOptions {
|
|
12
|
+
persistState?: false;
|
|
13
|
+
inspectorPort?: number | false;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Cloudflare Vite plugin options of a launched app: a `testEnv` build
|
|
17
|
+
* (`CLOUDFLARE_ENV`, the Vitest fixtures') keeps no state and opens no
|
|
18
|
+
* inspector; other servers open `DEV_INSPECTOR_PORT` (`listenerEnv`), or
|
|
19
|
+
* none when it is blank or unset.
|
|
20
|
+
*/
|
|
21
|
+
export declare function cloudflareDevOptions({ testEnv, env, }?: {
|
|
22
|
+
/** Wrangler environment of Vitest fixture builds. */
|
|
23
|
+
testEnv?: string;
|
|
24
|
+
env?: NodeJS.ProcessEnv;
|
|
25
|
+
}): CloudflareDevOptions;
|
|
26
|
+
/**
|
|
27
|
+
* Fails a build shipping dev files or test support, or server-only
|
|
28
|
+
* modules in a client environment (`isDevFile`, `isTestFile`,
|
|
29
|
+
* `isServerFile` from `@astralarium/repo-package-files`). Dev assets never inline,
|
|
30
|
+
* so they emit and fail; library builds inline every asset, skipping
|
|
31
|
+
* the check.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildGuard(): Plugin;
|
|
34
|
+
/**
|
|
35
|
+
* Keeps dev classes out of built CSS: appends `@source not` for each
|
|
36
|
+
* workspace package's dev folders (`isDevFile`) to every Tailwind entry
|
|
37
|
+
* (CSS importing `tailwindcss`). Precedes `tailwindcss()`. Skips
|
|
38
|
+
* `?url`/`?raw`, which wrap the CSS as JS.
|
|
39
|
+
*/
|
|
40
|
+
export declare function tailwindDevSources(): Plugin;
|
|
41
|
+
/**
|
|
42
|
+
* Reuses the compiled SSR bundle inside an isolated prerender worker: the
|
|
43
|
+
* prerender environment's `entry` re-exports the SSR build's
|
|
44
|
+
* `wrangler.json` `main`, emitted under `runtime/`. Requires the Cloudflare
|
|
45
|
+
* Vite plugin: its entry worker builds as the `ssr` environment (TanStack
|
|
46
|
+
* Start's server) and writes `wrangler.json`; its
|
|
47
|
+
* `experimental.prerenderWorker` builds as `environment`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function prerenderRuntime({ entry, environment, }: {
|
|
50
|
+
/** Server entry module, relative to the Vite root. */
|
|
51
|
+
entry: string;
|
|
52
|
+
/** Prerender worker's Vite environment. */
|
|
53
|
+
environment?: string;
|
|
54
|
+
}): Plugin;
|
|
55
|
+
/** The Cloudflare Vite plugin's built entry worker, as its
|
|
56
|
+
* `prerenderWorker.config` callback receives it. */
|
|
57
|
+
interface PrerenderEntryWorker {
|
|
58
|
+
main: string | undefined;
|
|
59
|
+
compatibility_date: string;
|
|
60
|
+
compatibility_flags: string[];
|
|
61
|
+
vars: Readonly<Record<string, unknown>>;
|
|
62
|
+
}
|
|
63
|
+
/** Prerender worker config: the entry worker's bundle and public `vars`. */
|
|
64
|
+
interface PrerenderWorker {
|
|
65
|
+
name: string;
|
|
66
|
+
main: string | undefined;
|
|
67
|
+
compatibility_date: string;
|
|
68
|
+
compatibility_flags: string[];
|
|
69
|
+
/** Empty: wrangler reads only declared vars and required secrets from
|
|
70
|
+
* `.dev.vars`, `.env` and process env. */
|
|
71
|
+
secrets: {
|
|
72
|
+
required: [];
|
|
73
|
+
};
|
|
74
|
+
vars: Record<string, string>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Isolates the prerender worker from runtime bindings and secrets: the
|
|
78
|
+
* Cloudflare Vite plugin's `experimental.prerenderWorker.config`. The
|
|
79
|
+
* worker runs the entry worker's bundle (`main`, compatibility date and
|
|
80
|
+
* flags) with `vars` as its whole environment; the entry worker's
|
|
81
|
+
* bindings, other vars, and required secrets stay behind.
|
|
82
|
+
*/
|
|
83
|
+
export declare function prerenderWorkerConfig({ name, vars, }: {
|
|
84
|
+
/** Worker name. */
|
|
85
|
+
name: string;
|
|
86
|
+
/** Public vars, from the entry worker's `vars`; throws on an invalid one. */
|
|
87
|
+
vars: (entryVars: Readonly<Record<string, unknown>>) => Record<string, string>;
|
|
88
|
+
}): (config: unknown, context: {
|
|
89
|
+
entryWorkerConfig: PrerenderEntryWorker;
|
|
90
|
+
}) => PrerenderWorker;
|
|
91
|
+
/**
|
|
92
|
+
* Re-transforms a deleted file's importers, so a rename reaches them.
|
|
93
|
+
* Vite soft-invalidates them: their code keeps the deleted import path.
|
|
94
|
+
*/
|
|
95
|
+
export declare function renameRecovery(): Plugin;
|
|
96
|
+
export {};
|