@pithy-sh/cli 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/package.json +72 -0
- package/scripts/templateManifest.ts +49 -0
- package/scripts/tsconfig.json +26 -0
- package/scripts/vendorTemplate.ts +84 -0
- package/scripts/verifyPack.ts +88 -0
- package/src/audit/cliAudit.ts +406 -0
- package/src/bin.ts +111 -0
- package/src/capabilities/add.ts +288 -0
- package/src/capabilities/addBootstrap.ts +275 -0
- package/src/capabilities/catalog.ts +175 -0
- package/src/capabilities/compose.ts +39 -0
- package/src/capabilities/configConstants.ts +74 -0
- package/src/capabilities/configImports.ts +397 -0
- package/src/capabilities/eject.ts +331 -0
- package/src/capabilities/emailProvisioner.ts +346 -0
- package/src/capabilities/entitlementGap.ts +70 -0
- package/src/capabilities/entryExports.ts +162 -0
- package/src/capabilities/flow.ts +550 -0
- package/src/capabilities/hostRegistry.ts +368 -0
- package/src/capabilities/loadFailure.ts +208 -0
- package/src/capabilities/manifests.ts +238 -0
- package/src/capabilities/mediaProvisioner.ts +471 -0
- package/src/capabilities/mintSecrets.ts +306 -0
- package/src/capabilities/paymentsProvisioner.ts +207 -0
- package/src/capabilities/prerequisites.ts +168 -0
- package/src/capabilities/r2Bucket.ts +113 -0
- package/src/capabilities/reconcile.ts +1483 -0
- package/src/capabilities/remove.ts +597 -0
- package/src/capabilities/requiredOptions.ts +92 -0
- package/src/capabilities/rotateSecrets.ts +305 -0
- package/src/capabilities/secrets.ts +178 -0
- package/src/capabilities/secretsDispatcher.ts +29 -0
- package/src/capabilities/secretsProvisioner.ts +389 -0
- package/src/capabilities/storageProvisioner.ts +414 -0
- package/src/capabilities/supportProvisioner.ts +515 -0
- package/src/capabilities/testersLoader.ts +52 -0
- package/src/capabilities/testersProvisioner.ts +236 -0
- package/src/capabilities/turnstileProvisioner.ts +347 -0
- package/src/capabilities/vectorProvisioner.ts +260 -0
- package/src/ci/fileModes.ts +223 -0
- package/src/ci/sourceFiles.ts +200 -0
- package/src/ci/workflowDrivers.ts +524 -0
- package/src/cloudflare/accountAnswer.ts +110 -0
- package/src/cloudflare/config.ts +685 -0
- package/src/cloudflare/storeId.ts +129 -0
- package/src/commands/add.ts +372 -0
- package/src/commands/alias.ts +205 -0
- package/src/commands/dashboard.ts +651 -0
- package/src/commands/deploy.ts +150 -0
- package/src/commands/dev.ts +37 -0
- package/src/commands/doctor.ts +2059 -0
- package/src/commands/email.ts +425 -0
- package/src/commands/env.ts +155 -0
- package/src/commands/feature.ts +359 -0
- package/src/commands/init.ts +538 -0
- package/src/commands/media.ts +303 -0
- package/src/commands/migrate.ts +129 -0
- package/src/commands/payments.ts +336 -0
- package/src/commands/provision.ts +368 -0
- package/src/commands/remove.ts +151 -0
- package/src/commands/secrets.ts +652 -0
- package/src/commands/seed.ts +229 -0
- package/src/commands/storage.ts +309 -0
- package/src/commands/support.ts +331 -0
- package/src/commands/testers.ts +1020 -0
- package/src/commands/token.ts +364 -0
- package/src/commands/turnstile.ts +271 -0
- package/src/commands/ui.ts +222 -0
- package/src/commands/upgrade.ts +517 -0
- package/src/commands/vector.ts +390 -0
- package/src/commands/worker.ts +295 -0
- package/src/dashboard/api.ts +323 -0
- package/src/dashboard/connect.ts +758 -0
- package/src/dashboard/contract.ts +289 -0
- package/src/dashboard/grant.ts +124 -0
- package/src/dashboard/registry.ts +519 -0
- package/src/dashboard/resolveTarget.ts +119 -0
- package/src/dev/delivery.ts +174 -0
- package/src/dev/devLogin.ts +155 -0
- package/src/dev/devLoginTargets.ts +91 -0
- package/src/dev/env.ts +206 -0
- package/src/dev/hostWorkers.ts +290 -0
- package/src/dev/keys.ts +111 -0
- package/src/dev/logging.ts +87 -0
- package/src/dev/openUrl.ts +75 -0
- package/src/dev/orchestrator.ts +1014 -0
- package/src/dev/ports.ts +220 -0
- package/src/dev/readyWatch.ts +142 -0
- package/src/dev/state.ts +90 -0
- package/src/devSecrets/bootstrapVars.ts +265 -0
- package/src/devSecrets/devVars.ts +240 -0
- package/src/devSecrets/edit.ts +256 -0
- package/src/devSecrets/file.ts +277 -0
- package/src/devSecrets/generate.ts +428 -0
- package/src/devSecrets/location.ts +80 -0
- package/src/devSecrets/mode.ts +71 -0
- package/src/devSecrets/records.ts +30 -0
- package/src/devSecrets/report.ts +99 -0
- package/src/devSecrets/seed.ts +344 -0
- package/src/devSecrets/store.ts +262 -0
- package/src/devSecrets/targets.ts +204 -0
- package/src/dispatch.ts +147 -0
- package/src/docs/catalog.ts +246 -0
- package/src/docs/writeCatalog.ts +45 -0
- package/src/doctor/cloudflare.ts +287 -0
- package/src/doctor/devPreferences.ts +155 -0
- package/src/doctor/devSecrets.ts +464 -0
- package/src/doctor/devVars.ts +414 -0
- package/src/doctor/devVarsLocal.ts +138 -0
- package/src/doctor/environments.ts +155 -0
- package/src/doctor/health.ts +354 -0
- package/src/doctor/localDelivery.ts +91 -0
- package/src/doctor/portsRegistry.ts +252 -0
- package/src/doctor/projectName.ts +584 -0
- package/src/doctor/secretBindings.ts +166 -0
- package/src/doctor/settings.ts +274 -0
- package/src/doctor/settingsSources.ts +202 -0
- package/src/doctor/workerName.ts +174 -0
- package/src/doctor/wranglerVars.ts +33 -0
- package/src/feature/bindings.ts +93 -0
- package/src/feature/create.ts +179 -0
- package/src/feature/destroy.ts +160 -0
- package/src/feature/devConfig.ts +201 -0
- package/src/feature/identity.ts +100 -0
- package/src/feature/manifest.ts +132 -0
- package/src/feature/ports.ts +615 -0
- package/src/feature/provision.ts +362 -0
- package/src/feature/sync.ts +148 -0
- package/src/feature/worktree.ts +282 -0
- package/src/help/groups.ts +47 -0
- package/src/help/rootUsage.ts +135 -0
- package/src/main.ts +73 -0
- package/src/migrations/ledger.ts +129 -0
- package/src/migrations/registry.ts +47 -0
- package/src/migrations/run.ts +1066 -0
- package/src/notifier/check.ts +129 -0
- package/src/notifier/installer.ts +48 -0
- package/src/notifier/notify.ts +152 -0
- package/src/notifier/state.ts +248 -0
- package/src/notifier/version.ts +59 -0
- package/src/platform/editor.ts +333 -0
- package/src/platform/rc.ts +118 -0
- package/src/platform/shell.ts +83 -0
- package/src/project/appBindings.ts +184 -0
- package/src/project/appWorkflows.ts +266 -0
- package/src/project/applyDomains.ts +166 -0
- package/src/project/askDomains.ts +220 -0
- package/src/project/atomic.ts +466 -0
- package/src/project/bindingEntries.ts +425 -0
- package/src/project/config.ts +701 -0
- package/src/project/dashboard.ts +118 -0
- package/src/project/deploy.ts +364 -0
- package/src/project/devVars.ts +113 -0
- package/src/project/domainPrompt.ts +191 -0
- package/src/project/domains.ts +386 -0
- package/src/project/envInventory.ts +356 -0
- package/src/project/environment.ts +125 -0
- package/src/project/extensions.ts +69 -0
- package/src/project/jsonc.ts +289 -0
- package/src/project/packageManager.ts +238 -0
- package/src/project/readOptionalFile.ts +342 -0
- package/src/project/rollback.ts +145 -0
- package/src/project/scaffold.ts +1088 -0
- package/src/project/templateFiles.ts +53 -0
- package/src/project/verifyDeploy.ts +230 -0
- package/src/project/versionMetadata.ts +77 -0
- package/src/project/workerAddress.ts +176 -0
- package/src/project/workerCommand.ts +564 -0
- package/src/project/workerIdentity.ts +50 -0
- package/src/project/workerManifest.ts +135 -0
- package/src/project/workerScaffold.ts +289 -0
- package/src/project/workerScope.ts +394 -0
- package/src/project/workers.ts +86 -0
- package/src/project/workflows.ts +281 -0
- package/src/project/wrangler.ts +168 -0
- package/src/provision/confirm.ts +86 -0
- package/src/provision/environment.ts +407 -0
- package/src/provision/featureConfig.ts +98 -0
- package/src/provision/mode.ts +62 -0
- package/src/provision/pendingSecrets.ts +96 -0
- package/src/provision/resources.ts +126 -0
- package/src/provision/secretBindings.ts +149 -0
- package/src/provision/store.ts +33 -0
- package/src/provision/unprovisioned.ts +114 -0
- package/src/provision/wranglerEnv.ts +220 -0
- package/src/rootFlags.ts +48 -0
- package/src/seed/drivers.ts +423 -0
- package/src/seed/media.ts +187 -0
- package/src/seed/plan.ts +137 -0
- package/src/seed/prepare.ts +224 -0
- package/src/seed/registry.ts +25 -0
- package/src/seed/run.ts +793 -0
- package/src/seed/safety.ts +206 -0
- package/src/terminal/logger.ts +42 -0
- package/src/terminal/output.ts +64 -0
- package/src/terminal/style.ts +132 -0
- package/src/test-utils/doctorHarness.ts +190 -0
- package/src/test-utils/migrateHarness.ts +126 -0
- package/src/test-utils/seedHarness.ts +173 -0
- package/src/test-utils/tempRepo.ts +45 -0
- package/src/tokens/config.ts +16 -0
- package/src/tokens/engine.ts +345 -0
- package/src/tokens/mintedTokens.ts +233 -0
- package/src/tokens/sinks.ts +84 -0
- package/src/ui/flow.ts +451 -0
- package/src/ui/react.ts +112 -0
- package/src/ui/routeAllowlist.ts +208 -0
- package/src/ui/scaffold.ts +113 -0
- package/src/ui/screenStyles.ts +127 -0
- package/src/ui/stubs.ts +135 -0
- package/src/ui/templates.ts +52 -0
- package/src/ui/wire.ts +311 -0
- package/src/ui/workerUi.ts +172 -0
- package/templates/starter/.dev.secrets.example.jsonc +43 -0
- package/templates/starter/.dev.vars.example +30 -0
- package/templates/starter/apps/api/package.json +22 -0
- package/templates/starter/apps/api/pithy.config.ts +65 -0
- package/templates/starter/apps/api/pithy.worker.jsonc +11 -0
- package/templates/starter/apps/api/src/bindings.workers.test.ts +18 -0
- package/templates/starter/apps/api/src/cloudflare-test.d.ts +11 -0
- package/templates/starter/apps/api/src/index.ts +8 -0
- package/templates/starter/apps/api/tsconfig.json +26 -0
- package/templates/starter/apps/api/wrangler.jsonc +68 -0
- package/templates/starter/biome.template.jsonc +75 -0
- package/templates/starter/gitignore +37 -0
- package/templates/starter/package.json +28 -0
- package/templates/starter/pithy.config.ts +67 -0
- package/templates/starter/plugins/no-console.grit +25 -0
- package/templates/starter/plugins/no-process-io.grit +25 -0
- package/templates/starter/tsconfig.json +14 -0
- package/templates/starter/tsconfig.tools.json +30 -0
- package/templates/starter/vitest.config.ts +124 -0
- package/templates/starter/vitest.workers.config.ts +26 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { env } from "cloudflare:test";
|
|
2
|
+
import { expect, test } from "vitest";
|
|
3
|
+
|
|
4
|
+
// The one test the scaffold ships, and it exists to prove the wiring rather than the code: a
|
|
5
|
+
// `*.workers.test.ts` file runs inside workerd with real bindings. Delete it once your own tests do.
|
|
6
|
+
//
|
|
7
|
+
// This is the kit's whole testing argument. A test that mocks D1 proves the mock works; a test against
|
|
8
|
+
// the real thing catches the SQL, the codec, and the binding name.
|
|
9
|
+
|
|
10
|
+
test("the Workers test project hands out a real D1 database", async () => {
|
|
11
|
+
const { results } = await env.DB.prepare("select 1 as one").all<{ one: number }>();
|
|
12
|
+
expect(results).toEqual([{ one: 1 }]);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("and a real KV namespace", async () => {
|
|
16
|
+
await env.SESSIONS.put("hello", "there");
|
|
17
|
+
expect(await env.SESSIONS.get("hello")).toBe("there");
|
|
18
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// <reference types="@cloudflare/vitest-plugin/types" />
|
|
2
|
+
|
|
3
|
+
// What `*.workers.test.ts` gets from `cloudflare:test`, matching the bindings the root
|
|
4
|
+
// vitest.workers.config.ts declares. Add a binding in both places or the test sees `undefined` typed
|
|
5
|
+
// as something real — the one shape of test failure that looks like a bug in your code.
|
|
6
|
+
declare namespace Cloudflare {
|
|
7
|
+
interface Env {
|
|
8
|
+
DB: D1Database;
|
|
9
|
+
SESSIONS: KVNamespace;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createEntrypoint } from "@pithy-sh/core/src/createEntrypoint";
|
|
2
|
+
import config from "../pithy.config";
|
|
3
|
+
|
|
4
|
+
// The Worker. createEntrypoint assembles the capabilities in pithy.config.ts into
|
|
5
|
+
// a Worker entrypoint: `fetch` is one Hono app (typed db/kv registries on every
|
|
6
|
+
// request, fail-fast binding validation, GET /health), and `email` fans inbound
|
|
7
|
+
// mail to every capability that handles it (e.g. @pithy-sh/email's bounce handler).
|
|
8
|
+
export default createEntrypoint(config);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Matches the Pithy toolchain defaults: strict, ESM-only, TS-7 ready.
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "Bundler",
|
|
8
|
+
"moduleDetection": "force",
|
|
9
|
+
"verbatimModuleSyntax": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"noImplicitOverride": true,
|
|
14
|
+
"noUncheckedIndexedAccess": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"types": ["@cloudflare/workers-types"],
|
|
17
|
+
// Referenced from the root solution file, which requires `composite` — and `composite` makes tsc
|
|
18
|
+
// write build state. It goes under the PROJECT's `dist/`, already gitignored, and deliberately not
|
|
19
|
+
// under this Worker's: once this Worker carries a UI, Vite owns `apps/<worker>/dist` and empties it
|
|
20
|
+
// on every build, which would throw the incremental state away each time.
|
|
21
|
+
"composite": true,
|
|
22
|
+
"tsBuildInfoFile": "../../dist/api.server.tsbuildinfo",
|
|
23
|
+
"noEmit": true
|
|
24
|
+
},
|
|
25
|
+
"include": ["src/**/*.ts", "pithy.config.ts"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "node_modules/wrangler/config-schema.json",
|
|
3
|
+
"name": "pithy-app",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"compatibility_date": "2026-06-01",
|
|
6
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
7
|
+
|
|
8
|
+
// Workers Logs, on by default. Every `c.var.log` record is a structured, per-line entry you can
|
|
9
|
+
// query in the dashboard — no setup. `head_sampling_rate` keeps 100% of records; lower it (0-1) to
|
|
10
|
+
// sample under heavy traffic. To fan records to a tail-consumer or Logpush, add `tail_consumers`
|
|
11
|
+
// here and attach a transport to the logger (see docs/LOGGING.md).
|
|
12
|
+
"observability": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"head_sampling_rate": 1
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// The deployed version of this Worker, injected by Cloudflare. Top level, so every environment
|
|
18
|
+
// inherits it — this is metadata about the build, not a per-environment setting.
|
|
19
|
+
// It answers the first question anyone asks when a deploy goes wrong: which build produced this?
|
|
20
|
+
// The id reaches five places from here — the `version` field on every log record, the
|
|
21
|
+
// control-plane manifest, a header on every control-plane response, every audit event, and the
|
|
22
|
+
// check `pithy deploy` runs to prove the Worker it just shipped is the one answering at your
|
|
23
|
+
// domain. `CF_VERSION_METADATA` is the name the code reads; renaming it binds something nothing
|
|
24
|
+
// consumes.
|
|
25
|
+
"version_metadata": { "binding": "CF_VERSION_METADATA" },
|
|
26
|
+
|
|
27
|
+
// The top level is the dev environment — what `wrangler dev` runs locally.
|
|
28
|
+
// `pithy add <capability>` appends the bindings a capability needs, per environment.
|
|
29
|
+
// `ENVIRONMENT` names this environment — the one signal that decides dev vs deployed,
|
|
30
|
+
// and the value log records carry as their `env` correlation field.
|
|
31
|
+
// `PROJECT` names the owning project (the root pithy.config.ts `name`). Cloudflare Images and
|
|
32
|
+
// Stream are account-flat and key an asset by an id they mint, so this var is the only thing
|
|
33
|
+
// that says which project owns an upload this Worker makes.
|
|
34
|
+
// `WORKER` names this Worker — its apps/<name> directory. The runtime tells a script nothing
|
|
35
|
+
// about itself, and two Workers that declare the same binding share one database, so this is
|
|
36
|
+
// what separates their audit events. Every environment repeats all three:
|
|
37
|
+
// `env.<name>.vars` REPLACES this block rather than merging it.
|
|
38
|
+
"vars": {
|
|
39
|
+
"ENVIRONMENT": "dev",
|
|
40
|
+
"PROJECT": "pithy-app",
|
|
41
|
+
"WORKER": "api"
|
|
42
|
+
},
|
|
43
|
+
"d1_databases": [],
|
|
44
|
+
"kv_namespaces": [],
|
|
45
|
+
|
|
46
|
+
// Staging serves test users; production serves paid users. Deployed names get the
|
|
47
|
+
// environment suffix automatically (pithy-app-staging, pithy-app-prod).
|
|
48
|
+
"env": {
|
|
49
|
+
"staging": {
|
|
50
|
+
"vars": {
|
|
51
|
+
"ENVIRONMENT": "staging",
|
|
52
|
+
"PROJECT": "pithy-app",
|
|
53
|
+
"WORKER": "api"
|
|
54
|
+
},
|
|
55
|
+
"d1_databases": [],
|
|
56
|
+
"kv_namespaces": []
|
|
57
|
+
},
|
|
58
|
+
"prod": {
|
|
59
|
+
"vars": {
|
|
60
|
+
"ENVIRONMENT": "prod",
|
|
61
|
+
"PROJECT": "pithy-app",
|
|
62
|
+
"WORKER": "api"
|
|
63
|
+
},
|
|
64
|
+
"d1_databases": [],
|
|
65
|
+
"kv_namespaces": []
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.5.8/schema.json",
|
|
3
|
+
// Biome for both lint and format — one tool, one pass, no ESLint/Prettier pair to keep in step.
|
|
4
|
+
// `bun run lint` reports; `bun run format` writes.
|
|
5
|
+
//
|
|
6
|
+
// No `vcs` block on purpose. Reading .gitignore needs a repository, and `pithy init` scaffolds into
|
|
7
|
+
// directories that are not one yet — the ignores are stated here instead, so the first `bun run lint`
|
|
8
|
+
// works before the first `git init`.
|
|
9
|
+
"files": {
|
|
10
|
+
"ignoreUnknown": true,
|
|
11
|
+
"includes": ["**", "!**/dist", "!**/.wrangler", "!**/.worktrees"]
|
|
12
|
+
},
|
|
13
|
+
// The logging gate. Scoped to each Worker's own `.ts` source, because that is the code that runs in
|
|
14
|
+
// the Worker, where `c.var.log` and `createWorkerLogger()` exist. A `.tsx` file is the client, and a
|
|
15
|
+
// browser console is not a Workers log. A test printing to a terminal is output for a human, not a
|
|
16
|
+
// log line, so tests are out too.
|
|
17
|
+
//
|
|
18
|
+
// `no-process-io.grit` is the same rule for `process.stdout` / `process.stderr` — the Node habit that
|
|
19
|
+
// reaches for a stream instead of a logger. Same scope, and for the same reason: it is the Worker's
|
|
20
|
+
// source that must stay queryable. A build script or a Node CLI of your own writing to stdout is
|
|
21
|
+
// correct, and neither lives under `apps/*/src`.
|
|
22
|
+
//
|
|
23
|
+
// Yours to change, like every other line here — narrow them, widen them, or drop an entry and delete
|
|
24
|
+
// its plugin file with it. Both plugin files say the same.
|
|
25
|
+
"plugins": [
|
|
26
|
+
{
|
|
27
|
+
"path": "plugins/no-console.grit",
|
|
28
|
+
"includes": ["**/apps/*/src/**/*.ts", "!**/*.test.ts"]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"path": "plugins/no-process-io.grit",
|
|
32
|
+
"includes": ["**/apps/*/src/**/*.ts", "!**/*.test.ts"]
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"formatter": {
|
|
36
|
+
"enabled": true,
|
|
37
|
+
"indentStyle": "space",
|
|
38
|
+
"indentWidth": 2,
|
|
39
|
+
"lineWidth": 120,
|
|
40
|
+
"lineEnding": "lf"
|
|
41
|
+
// Nothing is exempt. `wrangler.jsonc` and `pithy.worker.jsonc` were, because the writer behind
|
|
42
|
+
// `pithy add` and `pithy ui sync` put every array element on its own line and Biome collapses the
|
|
43
|
+
// short ones — so the CLI's own output failed the commit hook the CLI scaffolds (#249). Exempting
|
|
44
|
+
// the two files Pithy touches most from the formatter is not a fix; the writer prints what Biome
|
|
45
|
+
// would print now, and these are ordinary files again.
|
|
46
|
+
},
|
|
47
|
+
"assist": {
|
|
48
|
+
"actions": {
|
|
49
|
+
"source": {
|
|
50
|
+
"organizeImports": { "level": "on" }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"linter": {
|
|
55
|
+
"enabled": true,
|
|
56
|
+
"rules": { "preset": "recommended" }
|
|
57
|
+
},
|
|
58
|
+
"javascript": {
|
|
59
|
+
"formatter": {
|
|
60
|
+
"quoteStyle": "double",
|
|
61
|
+
"semicolons": "always",
|
|
62
|
+
"trailingCommas": "all"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"json": {
|
|
66
|
+
// Every config Pithy writes is JSONC — wrangler.jsonc, pithy.worker.jsonc, and the tsconfigs.
|
|
67
|
+
"parser": {
|
|
68
|
+
"allowComments": true,
|
|
69
|
+
"allowTrailingCommas": false
|
|
70
|
+
},
|
|
71
|
+
"formatter": {
|
|
72
|
+
"trailingCommas": "none"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# deps & build
|
|
2
|
+
node_modules/
|
|
3
|
+
dist/
|
|
4
|
+
|
|
5
|
+
# cloudflare / wrangler
|
|
6
|
+
.wrangler/
|
|
7
|
+
.dev.vars
|
|
8
|
+
.dev.vars.*
|
|
9
|
+
!.dev.vars.example
|
|
10
|
+
|
|
11
|
+
# pithy local dev state
|
|
12
|
+
.dev-state.json
|
|
13
|
+
# Legacy: the port registry lives at <config>/dev-ports.json now (#435). Kept so a project scaffolded
|
|
14
|
+
# before the move keeps ignoring the file it already has.
|
|
15
|
+
.dev-ports.json
|
|
16
|
+
logs/
|
|
17
|
+
|
|
18
|
+
# pithy feature worktrees + per-feature state
|
|
19
|
+
.worktrees/
|
|
20
|
+
.dev.config.json
|
|
21
|
+
.pithy-feature.json
|
|
22
|
+
|
|
23
|
+
# env & secrets
|
|
24
|
+
# No dev secrets line. They live at <config>/<project>/secrets.jsonc, outside every checkout, so there
|
|
25
|
+
# is nothing here to ignore — and `.dev.secrets.example.jsonc` is committed documentation. See #156.
|
|
26
|
+
.env
|
|
27
|
+
.env.*
|
|
28
|
+
!.env.example
|
|
29
|
+
|
|
30
|
+
# atomic-write temp siblings (.dev.vars.<rand>.tmp, …). A write interrupted by SIGINT leaves one
|
|
31
|
+
# holding the full plaintext; it must never be committable.
|
|
32
|
+
*.tmp
|
|
33
|
+
|
|
34
|
+
# editor / os
|
|
35
|
+
.DS_Store
|
|
36
|
+
*.log
|
|
37
|
+
coverage/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pithy-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=22"
|
|
7
|
+
},
|
|
8
|
+
"workspaces": [
|
|
9
|
+
"apps/*"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "pithy dev",
|
|
13
|
+
"deploy": "pithy deploy",
|
|
14
|
+
"deploy:staging": "pithy deploy --env staging",
|
|
15
|
+
"deploy:prod": "pithy deploy --env prod",
|
|
16
|
+
"typecheck": "tsc -b",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"lint": "biome check .",
|
|
19
|
+
"format": "biome format --write ."
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@biomejs/biome": "^2.5.8",
|
|
23
|
+
"@cloudflare/vitest-plugin": "^1.0.0",
|
|
24
|
+
"@types/node": "^22.15.0",
|
|
25
|
+
"typescript": "^7.0.2",
|
|
26
|
+
"vitest": "^4.1.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// pithy.config.ts — your project's identity and policy.
|
|
2
|
+
//
|
|
3
|
+
// This file is project-wide. It deliberately does NOT list capabilities: what a
|
|
4
|
+
// Worker is made of is per-Worker, and lives in apps/<name>/pithy.config.ts.
|
|
5
|
+
// Only settings that cannot be per-Worker belong here.
|
|
6
|
+
|
|
7
|
+
const config = {
|
|
8
|
+
// The project name, and the first segment of every name Pithy provisions:
|
|
9
|
+
// <project>-<env>-<thing>, kebab-case, one rule for every namespace — D1, KV,
|
|
10
|
+
// R2, Worker scripts, Workflows, Secrets Store entries, and Cloudflare API
|
|
11
|
+
// tokens. A thing shared across environments puts the literal `global` in the
|
|
12
|
+
// environment slot. Feature resources extend the same shape
|
|
13
|
+
// (<project>-f<issue>-<slug>-<binding>-<kind>).
|
|
14
|
+
//
|
|
15
|
+
// Cloudflare's namespaces are flat and account-wide, so this segment is the
|
|
16
|
+
// only thing keeping two projects in one account from adopting each other's
|
|
17
|
+
// resources — and it is the only key teardown has to find them by. Renaming it
|
|
18
|
+
// does not rename anything already provisioned: it orphans it, silently. Set it
|
|
19
|
+
// once, keep it stable across machines and checkouts, and don't rename it.
|
|
20
|
+
// `pithy doctor` checks that it still matches what your workers declare.
|
|
21
|
+
name: "pithy-app",
|
|
22
|
+
|
|
23
|
+
// Every environment this project deploys to, in the order provisioning walks
|
|
24
|
+
// them — least-production first. It is the SECOND segment of every Cloudflare
|
|
25
|
+
// name the project composes (<project>-<env>-<thing>), the set `pithy secrets
|
|
26
|
+
// provision` gives a master key and a manager to, and the set each Worker's
|
|
27
|
+
// `env.<name>` wrangler stanzas are generated from. `dev` is never listed: it
|
|
28
|
+
// is local, it is the top-level wrangler stanza, and it always exists.
|
|
29
|
+
//
|
|
30
|
+
// Absent means ["staging", "prod"], which is what `pithy init` scaffolds
|
|
31
|
+
// unless you told it otherwise. Like `name`, this is effectively permanent:
|
|
32
|
+
// renaming an environment does not rename anything already provisioned under
|
|
33
|
+
// the old name — it orphans it. `pithy doctor` reports a change rather than
|
|
34
|
+
// applying one.
|
|
35
|
+
// environments: ["staging", "prod"],
|
|
36
|
+
|
|
37
|
+
// Which Cloudflare account this project belongs to. `pithy init` writes this
|
|
38
|
+
// block when it can discover the account from your token.
|
|
39
|
+
//
|
|
40
|
+
// `accountName` selects the credentials file: <config>/cloudflare.<name>.json
|
|
41
|
+
// rather than <config>/cloudflare.json. One machine, several companies, one
|
|
42
|
+
// file each — without it every project on the machine reads the same file, so
|
|
43
|
+
// switching accounts means editing that file in place and every project
|
|
44
|
+
// silently follows. A bare token: lowercase, digits, single hyphens. It
|
|
45
|
+
// becomes a file name, so nothing else is accepted.
|
|
46
|
+
//
|
|
47
|
+
// `accountId` pins the account those credentials must belong to. Every command
|
|
48
|
+
// that resolves them compares the two and refuses on a mismatch, naming both.
|
|
49
|
+
// The nickname above means whatever each machine says it means; this is what
|
|
50
|
+
// makes the repository the authority. An account id is an identifier, not a
|
|
51
|
+
// secret — wrangler.toml commits them — so it is safe here, including in a
|
|
52
|
+
// public repository. Optional, and it earns its keep the moment more than one
|
|
53
|
+
// person deploys.
|
|
54
|
+
// cloudflare: { accountName: "acme", accountId: "" },
|
|
55
|
+
|
|
56
|
+
// Overrides for the predefined Cloudflare API token profiles (`pithy token`).
|
|
57
|
+
// Account-level, so it lives here rather than on a Worker.
|
|
58
|
+
// tokens: { overrides: {} },
|
|
59
|
+
|
|
60
|
+
// `pithy seed` policy. `productionEnvironments` names every environment this
|
|
61
|
+
// project treats as production, beyond the built-in production/prod — each one
|
|
62
|
+
// requires the type-to-confirm phrase, not just --yes. A safety rule no single
|
|
63
|
+
// Worker should be able to quietly omit.
|
|
64
|
+
// seed: { includeExamples: false, productionEnvironments: ["live"] },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default config;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Your project's logging gate. Scoped by biome.jsonc to each Worker's own `.ts` source.
|
|
2
|
+
//
|
|
3
|
+
// A console line carries no level, no logger name, and no request id. Workers Logs cannot filter it,
|
|
4
|
+
// and nothing downstream can key on it — so it is output you can read once, live, and never again.
|
|
5
|
+
// The replacement is already wired: `c.var.log` inside a request handler, bound to that request, and
|
|
6
|
+
// `createWorkerLogger()` anywhere else in the Worker.
|
|
7
|
+
//
|
|
8
|
+
// Biome ships `suspicious/noConsole` and it matches the same code. This exists instead because its
|
|
9
|
+
// message names the replacement — a rule that only prohibits gets ignored by the next person who
|
|
10
|
+
// needs a line of output, since it never told them where the line was supposed to go.
|
|
11
|
+
//
|
|
12
|
+
// This file is yours. Narrow the `includes` in biome.jsonc, widen them, or delete both the entry and
|
|
13
|
+
// this file. Pithy ships the practice; the code is yours.
|
|
14
|
+
//
|
|
15
|
+
// The match is the member access rather than the call, so `items.forEach(console.log)` and
|
|
16
|
+
// `const sink = console.error` are caught alongside `console.log(x)`. A call contains the member
|
|
17
|
+
// access, so each site still reports exactly once.
|
|
18
|
+
language js
|
|
19
|
+
|
|
20
|
+
or {
|
|
21
|
+
`console.$method`,
|
|
22
|
+
`globalThis.console.$method`
|
|
23
|
+
} as $ref where {
|
|
24
|
+
register_diagnostic(span=$ref, message="console is not the logger. Reach for c.var.log in a request, or createWorkerLogger() elsewhere — a console line carries no level, name, or request id, and Workers Logs cannot filter it.")
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// The sibling of no-console.grit, for the other way a line of output gets written by hand.
|
|
2
|
+
//
|
|
3
|
+
// `process.stdout.write` and `process.stderr.write` are Node habits. Your Worker enables
|
|
4
|
+
// `nodejs_compat`, so they resolve rather than throwing — and what they write is an unstructured line
|
|
5
|
+
// with no level, no logger name, and no request id, which Workers Logs cannot filter. Same hole as
|
|
6
|
+
// `console.log`, with the extra catch that it only works at all because of a compatibility flag.
|
|
7
|
+
//
|
|
8
|
+
// `c.var.log` inside a request handler, `createWorkerLogger()` anywhere else in the Worker.
|
|
9
|
+
//
|
|
10
|
+
// Scoped to `apps/*/src/**/*.ts` — your Worker code. If you add a build script or a Node CLI of your
|
|
11
|
+
// own, writing to stdout there is correct and this gate should not reach it; that is why the scope is
|
|
12
|
+
// the Worker's source and not the whole project.
|
|
13
|
+
//
|
|
14
|
+
// This file is yours. Narrow it, widen it, or delete the entry in biome.jsonc and this file with it.
|
|
15
|
+
//
|
|
16
|
+
// The match is the member access rather than the call, so a method handed off as a callback is caught
|
|
17
|
+
// alongside a direct call. A call contains the member access, so each site reports exactly once.
|
|
18
|
+
language js
|
|
19
|
+
|
|
20
|
+
or {
|
|
21
|
+
`process.stdout.$method`,
|
|
22
|
+
`process.stderr.$method`
|
|
23
|
+
} as $ref where {
|
|
24
|
+
register_diagnostic(span=$ref, message="A Worker log must be queryable. process.stdout writes an unstructured line with no level, name, or request id, and Workers Logs cannot filter it. Reach for c.var.log in a request, or createWorkerLogger() elsewhere.")
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
// The SOLUTION file. It compiles nothing of its own — `"files": []` — and names the programs that do.
|
|
3
|
+
// `bun run typecheck` is `tsc -b`, which builds every reference below, in order.
|
|
4
|
+
//
|
|
5
|
+
// Why several programs rather than one: a Worker needs `@cloudflare/workers-types`, a browser client
|
|
6
|
+
// needs the DOM, and TypeScript cannot hold both in one program. Load both and `Uint8Array` stops being
|
|
7
|
+
// assignable to `BufferSource`, which breaks every crypto call in the kit's control-plane signing code.
|
|
8
|
+
// Keeping them apart by construction is what this file is for.
|
|
9
|
+
//
|
|
10
|
+
// `pithy ui add` appends that Worker's client programs here. `pithy worker add` does not yet — add the
|
|
11
|
+
// new Worker's `tsconfig.json` yourself, or its source is typechecked by nothing.
|
|
12
|
+
"files": [],
|
|
13
|
+
"references": [{ "path": "./tsconfig.tools.json" }, { "path": "./apps/api/tsconfig.json" }]
|
|
14
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
// The TOOLING program: the files that configure the project rather than run in it. They execute on
|
|
3
|
+
// Node, not in a Worker and not in a browser, so they get their own program and `types: ["node"]`.
|
|
4
|
+
//
|
|
5
|
+
// Left out of the solution, these were config files nothing checked — which is how a Vitest config
|
|
6
|
+
// that names a project no longer present, or a `pithy.config.ts` with a typo in a key, survives until
|
|
7
|
+
// the command that reads it fails.
|
|
8
|
+
"compilerOptions": {
|
|
9
|
+
"target": "ES2022",
|
|
10
|
+
"lib": ["ES2022"],
|
|
11
|
+
"module": "ESNext",
|
|
12
|
+
"moduleResolution": "Bundler",
|
|
13
|
+
"moduleDetection": "force",
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"esModuleInterop": true,
|
|
17
|
+
"strict": true,
|
|
18
|
+
"noImplicitOverride": true,
|
|
19
|
+
"noUncheckedIndexedAccess": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
21
|
+
"types": ["node"],
|
|
22
|
+
// `composite` is what a referenced project must declare, and it makes tsc write build state.
|
|
23
|
+
// Under `dist/`, which .gitignore already covers — and the project root's `dist/`, never a
|
|
24
|
+
// Worker's: Vite empties a Worker's on every client build, taking the incremental state with it.
|
|
25
|
+
"composite": true,
|
|
26
|
+
"tsBuildInfoFile": "dist/tools.tsbuildinfo",
|
|
27
|
+
"noEmit": true
|
|
28
|
+
},
|
|
29
|
+
"include": ["pithy.config.ts", "vitest.config.ts", "vitest.workers.config.ts"]
|
|
30
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { defineConfig } from "vitest/config";
|
|
6
|
+
|
|
7
|
+
/** This file sits at the project root, and every path below is resolved from it rather than from a cwd. */
|
|
8
|
+
const PROJECT_ROOT = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The directory `name` resolves to when a Worker asks for it, or `null` when it resolves nowhere.
|
|
12
|
+
*
|
|
13
|
+
* Node's own resolution, walking outward from the Worker: `apps/<worker>/node_modules` first, then the
|
|
14
|
+
* project root's, then whatever is above that. Deliberately not a fixed path — Bun installs a workspace
|
|
15
|
+
* member's dependencies beside that member, npm and pnpm hoist most of them to the root, and both
|
|
16
|
+
* answers are correct. Asking the resolver means this file needs no opinion about which you use.
|
|
17
|
+
*
|
|
18
|
+
* `<name>/package.json` rather than the bare name, because the bare name answers with an entry file
|
|
19
|
+
* that differs per export condition, and what an alias replacement needs is the package's directory.
|
|
20
|
+
*/
|
|
21
|
+
function packageDir(from: string, name: string): string | null {
|
|
22
|
+
try {
|
|
23
|
+
return dirname(createRequire(join(from, "package.json")).resolve(`${name}/package.json`));
|
|
24
|
+
} catch {
|
|
25
|
+
// Nothing there. A project with no front end has no React at all, which is not an error here.
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* One React, however many checkouts the packages live in.
|
|
32
|
+
*
|
|
33
|
+
* Vite resolves a symlinked package from its realpath, so a package linked in from somewhere else — the
|
|
34
|
+
* Pithy kit, a design system, any workspace you point at by path — imports `react` out of *its* tree
|
|
35
|
+
* rather than out of this project's. Two copies of React is `invalid hook call` in every component that
|
|
36
|
+
* package renders, and the stack blames the component rather than the resolution. It stays invisible for
|
|
37
|
+
* as long as no linked component is mounted, which in a project that owns its own screens is a long
|
|
38
|
+
* time: the first one you ever mount is the one that fails.
|
|
39
|
+
*
|
|
40
|
+
* **An alias and not `dedupe`, and the reason is where React lives.** `dedupe` resolves the names it is
|
|
41
|
+
* given from Vite's root, and this config's root is the project root, where React is not installed — it
|
|
42
|
+
* is a dependency of `apps/<worker>`. So `dedupe` here finds nothing and changes nothing, without a
|
|
43
|
+
* word. `apps/<worker>/vite.config.ts` is rooted at the Worker and uses `dedupe` for that reason; this
|
|
44
|
+
* file cannot, and a `dedupe` line added here would read as covered while resolving nothing.
|
|
45
|
+
*
|
|
46
|
+
* **Two rules per package, an exact one and a prefixed one.** The exact rule answers `react`; the
|
|
47
|
+
* prefixed one answers the subpaths — `react/jsx-runtime`, `react-dom/client`. A single `^react` rule
|
|
48
|
+
* would answer `react-dom` too and rewrite it through React's own directory, which lands on a path that
|
|
49
|
+
* exists only while the two packages happen to sit side by side under one `node_modules`.
|
|
50
|
+
*
|
|
51
|
+
* **No Worker is named here, because none of them is the project's.** The first `apps/*` that resolves
|
|
52
|
+
* React is the copy every test gets. A name written into this file would be one more place your Worker's
|
|
53
|
+
* name lives, and it would go stale the day you rename it or `pithy worker add` a second one.
|
|
54
|
+
*
|
|
55
|
+
* **An empty list is a legitimate answer, and it says nothing.** No `apps/*` resolves React in a project
|
|
56
|
+
* with no front end, which is every project between `pithy init` and its first `pithy ui add`. Throwing
|
|
57
|
+
* would fail `bun run test` on a fresh scaffold; warning would print on every run of a project that
|
|
58
|
+
* simply has no client. What separates this from the `dedupe` line it replaces is therefore not noise,
|
|
59
|
+
* it is reach: an alias list is a value, so an empty one is visible to anything that cares to look — the
|
|
60
|
+
* kit's own gates plant a Worker with no React and require the loop to skip past it.
|
|
61
|
+
*
|
|
62
|
+
* It is not a workaround for a symlink. It is what every linked-package setup needs, it costs nothing
|
|
63
|
+
* when nothing is linked, and it goes on costing nothing the day `@pithy-sh/*` is published.
|
|
64
|
+
*/
|
|
65
|
+
function oneReact(): { find: RegExp; replacement: string }[] {
|
|
66
|
+
const apps = join(PROJECT_ROOT, "apps");
|
|
67
|
+
if (!existsSync(apps)) return [];
|
|
68
|
+
// Sorted, so a project with two front ends resolves the same React on every machine.
|
|
69
|
+
const workers = readdirSync(apps, { withFileTypes: true })
|
|
70
|
+
.filter((entry) => entry.isDirectory())
|
|
71
|
+
.map((entry) => entry.name)
|
|
72
|
+
.sort();
|
|
73
|
+
for (const worker of workers) {
|
|
74
|
+
const react = packageDir(join(apps, worker), "react");
|
|
75
|
+
const reactDom = packageDir(join(apps, worker), "react-dom");
|
|
76
|
+
if (react === null || reactDom === null) continue;
|
|
77
|
+
return [
|
|
78
|
+
{ find: /^react-dom$/, replacement: reactDom },
|
|
79
|
+
{ find: /^react-dom\//, replacement: `${reactDom}/` },
|
|
80
|
+
{ find: /^react$/, replacement: react },
|
|
81
|
+
{ find: /^react\//, replacement: `${react}/` },
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const ONE_REACT = oneReact();
|
|
88
|
+
|
|
89
|
+
// Two projects, split by runtime, because a Pithy project has two runtimes.
|
|
90
|
+
//
|
|
91
|
+
// `node` runs plain unit tests in Node — codecs, pure logic, anything with no binding in it.
|
|
92
|
+
// `workers` runs against the real Workers runtime with real D1 and KV, in vitest.workers.config.ts.
|
|
93
|
+
// A test that touches a binding belongs there and nowhere else: mocking D1 proves your mock works.
|
|
94
|
+
//
|
|
95
|
+
// The split is by filename, not by directory: `*.workers.test.ts` is the Workers project, every other
|
|
96
|
+
// `*.test.ts` is the node one. Tests sit beside the code they cover, so a folder rule would mean
|
|
97
|
+
// choosing between co-location and the runtime — and the runtime is not negotiable.
|
|
98
|
+
//
|
|
99
|
+
// `.tsx` is in the include for the same reason. A front end scaffolded by `pithy ui add` is all `.tsx`,
|
|
100
|
+
// so a `.ts`-only pattern silently collected none of its tests — and `passWithNoTests` made that green
|
|
101
|
+
// (#245). Every co-located test runs, whatever the file's extension.
|
|
102
|
+
export default defineConfig({
|
|
103
|
+
test: {
|
|
104
|
+
// A scaffolded project starts with almost no tests. `bun run test` should still be green.
|
|
105
|
+
passWithNoTests: true,
|
|
106
|
+
projects: [
|
|
107
|
+
{
|
|
108
|
+
// See `oneReact` at the head of this file. On the project rather than beside `passWithNoTests`,
|
|
109
|
+
// and that is measured rather than assumed: on vitest 4.1.10 a `resolve.alias` stated at the
|
|
110
|
+
// root of a `projects` config does not reach an inline project, and one stated here does. Up
|
|
111
|
+
// there it would read as covered and rewrite nothing. This is also the project that collects
|
|
112
|
+
// the `.tsx` tests a front end brings, so this is where it has to be either way.
|
|
113
|
+
resolve: { alias: ONE_REACT },
|
|
114
|
+
test: {
|
|
115
|
+
name: "node",
|
|
116
|
+
environment: "node",
|
|
117
|
+
include: ["apps/*/src/**/*.test.{ts,tsx}"],
|
|
118
|
+
exclude: ["apps/*/src/**/*.workers.test.{ts,tsx}"],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
"./vitest.workers.config.ts",
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cloudflareTest } from "@cloudflare/vitest-plugin";
|
|
2
|
+
import { defineConfig } from "vitest/config";
|
|
3
|
+
|
|
4
|
+
// The Workers-runtime project: `*.workers.test.ts` runs inside workerd, against a real D1 database and
|
|
5
|
+
// a real KV namespace that Miniflare creates per run and throws away after. No mocks, no fakes.
|
|
6
|
+
//
|
|
7
|
+
// The bindings here are declared for the *test* runtime, not read from a Worker's wrangler.jsonc — one
|
|
8
|
+
// test run covers every Worker under apps/, and they do not all declare the same bindings. Add a
|
|
9
|
+
// binding here when a capability you compose needs one; `pithy add <capability>` writes it into the
|
|
10
|
+
// Worker's wrangler.jsonc, and this file is the matching statement for tests.
|
|
11
|
+
export default defineConfig({
|
|
12
|
+
plugins: [
|
|
13
|
+
cloudflareTest({
|
|
14
|
+
miniflare: {
|
|
15
|
+
compatibilityDate: "2026-06-01",
|
|
16
|
+
compatibilityFlags: ["nodejs_compat"],
|
|
17
|
+
d1Databases: ["DB"],
|
|
18
|
+
kvNamespaces: ["SESSIONS"],
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
],
|
|
22
|
+
test: {
|
|
23
|
+
name: "workers",
|
|
24
|
+
include: ["apps/*/src/**/*.workers.test.ts"],
|
|
25
|
+
},
|
|
26
|
+
});
|