@decocms/start 2.29.0 → 2.30.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/.agents/skills/deco-to-tanstack-migration/SKILL.md +1 -1
- package/.agents/skills/deco-to-tanstack-migration/references/vtex-commerce.md +5 -1
- package/.agents/skills/deco-to-tanstack-migration/references/worker-cloudflare.md +107 -10
- package/.agents/skills/deco-to-tanstack-migration/templates/package-json.md +5 -1
- package/.cursor/rules/migration-tooling-policy.mdc +22 -2
- package/.github/workflows/deploy.yml +115 -0
- package/.github/workflows/preview.yml +143 -0
- package/.github/workflows/regen-blocks.yml +56 -0
- package/.github/workflows/release.yml +26 -0
- package/.github/workflows/sync-secrets.yml +173 -0
- package/CODEOWNERS +16 -0
- package/MIGRATION_TOOLING_PLAN.md +16 -4
- package/deploy/README.md +85 -0
- package/deploy/sites/als-tanstack.jsonc +7 -0
- package/deploy/sites/americanas-tanstack.jsonc +4 -0
- package/deploy/sites/baggagio-tanstack.jsonc +4 -0
- package/deploy/sites/casaevideo-storefront.jsonc +11 -0
- package/deploy/sites/lebiscuit-tanstack.jsonc +19 -0
- package/deploy/sites/miess-01-tanstack.jsonc +8 -0
- package/deploy/wrangler-template.jsonc +28 -0
- package/package.json +3 -2
- package/scripts/deploy/build-wrangler-config.mjs +49 -0
- package/scripts/deploy/jsonc.mjs +76 -0
- package/scripts/deploy/resolve-site.mjs +58 -0
- package/scripts/deploy/site-registry.mjs +142 -0
- package/scripts/deploy/wrangler-wrapper.mjs +126 -0
- package/scripts/migrate/phase-scaffold.ts +13 -3
- package/scripts/migrate/phase-verify.ts +6 -1
- package/scripts/migrate/templates/github-workflows.ts +98 -0
- package/scripts/migrate/templates/package-json.ts +9 -2
- package/scripts/migrate/templates/wrangler.ts +0 -30
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Shared registry helpers for the deploy scripts.
|
|
2
|
+
//
|
|
3
|
+
// `loadSiteManifest(decoStartPath, siteName)` returns the validated
|
|
4
|
+
// per-site manifest object. `mergeWithTemplate(template, site)` deep-merges a
|
|
5
|
+
// site manifest on top of the canonical template and returns the wrangler
|
|
6
|
+
// config object ready for serialization.
|
|
7
|
+
//
|
|
8
|
+
// Trust model: `siteName` is always derived from `${{ github.repository }}` in
|
|
9
|
+
// CI (or from the local git remote in the wrapper CLI), never from a
|
|
10
|
+
// user-supplied input. A site that is not registered in `deploy/sites/` cannot
|
|
11
|
+
// be deployed -- this is enforced here.
|
|
12
|
+
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { readJsoncFile } from "./jsonc.mjs";
|
|
16
|
+
|
|
17
|
+
/** @typedef {{
|
|
18
|
+
* worker_name: string;
|
|
19
|
+
* routes?: Array<{ pattern: string; zone_name?: string; custom_domain?: boolean }>;
|
|
20
|
+
* kv_namespaces?: Array<{ binding: string; id: string; preview_id?: string }>;
|
|
21
|
+
* analytics_engine_datasets?: Array<{ binding: string; dataset: string }>;
|
|
22
|
+
* version_metadata?: { binding: string };
|
|
23
|
+
* }} SiteManifest
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const ALLOWED_SITE_KEYS = new Set([
|
|
27
|
+
"worker_name",
|
|
28
|
+
"routes",
|
|
29
|
+
"kv_namespaces",
|
|
30
|
+
"analytics_engine_datasets",
|
|
31
|
+
"version_metadata",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} decoStartPath
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
export function templatePath(decoStartPath) {
|
|
39
|
+
return join(decoStartPath, "deploy", "wrangler-template.jsonc");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {string} decoStartPath
|
|
44
|
+
* @param {string} siteName
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
export function siteManifestPath(decoStartPath, siteName) {
|
|
48
|
+
return join(decoStartPath, "deploy", "sites", `${siteName}.jsonc`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} decoStartPath
|
|
53
|
+
* @param {string} siteName
|
|
54
|
+
* @returns {SiteManifest}
|
|
55
|
+
*/
|
|
56
|
+
export function loadSiteManifest(decoStartPath, siteName) {
|
|
57
|
+
if (!siteName || !/^[a-z0-9][a-z0-9-]*$/.test(siteName)) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Refusing to load manifest for invalid site name: ${JSON.stringify(siteName)}. Site names must be lowercase, hyphen-separated.`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const path = siteManifestPath(decoStartPath, siteName);
|
|
63
|
+
if (!existsSync(path)) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`No registry entry for site "${siteName}" at ${path}.\n` +
|
|
66
|
+
`Add deploy/sites/${siteName}.jsonc to decocms/deco-start before deploying.`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const raw = readJsoncFile(path);
|
|
70
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
71
|
+
throw new Error(`Site manifest at ${path} must be a JSON object.`);
|
|
72
|
+
}
|
|
73
|
+
const manifest = /** @type {Record<string, unknown>} */ (raw);
|
|
74
|
+
if (typeof manifest.worker_name !== "string" || manifest.worker_name.length === 0) {
|
|
75
|
+
throw new Error(`Site manifest at ${path} is missing the required "worker_name" string.`);
|
|
76
|
+
}
|
|
77
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(/** @type {string} */ (manifest.worker_name))) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Site manifest at ${path} has an invalid "worker_name": ${JSON.stringify(manifest.worker_name)}. Use lowercase, hyphen-separated.`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
for (const key of Object.keys(manifest)) {
|
|
83
|
+
if (!ALLOWED_SITE_KEYS.has(key)) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Site manifest at ${path} contains unsupported key "${key}". Allowed: ${[...ALLOWED_SITE_KEYS].join(", ")}.`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return /** @type {SiteManifest} */ (manifest);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {string} decoStartPath
|
|
94
|
+
* @returns {Record<string, unknown>}
|
|
95
|
+
*/
|
|
96
|
+
export function loadTemplate(decoStartPath) {
|
|
97
|
+
const path = templatePath(decoStartPath);
|
|
98
|
+
if (!existsSync(path)) {
|
|
99
|
+
throw new Error(`wrangler-template.jsonc not found at ${path}.`);
|
|
100
|
+
}
|
|
101
|
+
const raw = readJsoncFile(path);
|
|
102
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
103
|
+
throw new Error(`Template at ${path} must be a JSON object.`);
|
|
104
|
+
}
|
|
105
|
+
return /** @type {Record<string, unknown>} */ (raw);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Deep-merge `source` on top of `target`. Arrays in `source` REPLACE arrays in
|
|
110
|
+
* `target` (they are not concatenated) -- this matches the semantics wrangler
|
|
111
|
+
* itself expects for `routes`, `kv_namespaces`, etc.
|
|
112
|
+
*
|
|
113
|
+
* @template T
|
|
114
|
+
* @param {T} target
|
|
115
|
+
* @param {unknown} source
|
|
116
|
+
* @returns {T}
|
|
117
|
+
*/
|
|
118
|
+
function deepMerge(target, source) {
|
|
119
|
+
if (source === null || source === undefined) return target;
|
|
120
|
+
if (Array.isArray(source)) return /** @type {T} */ (source);
|
|
121
|
+
if (typeof source !== "object") return /** @type {T} */ (source);
|
|
122
|
+
const base = target && typeof target === "object" && !Array.isArray(target) ? target : {};
|
|
123
|
+
const out = /** @type {Record<string, unknown>} */ ({ ...base });
|
|
124
|
+
for (const [k, v] of Object.entries(source)) {
|
|
125
|
+
out[k] = deepMerge(out[k], v);
|
|
126
|
+
}
|
|
127
|
+
return /** @type {T} */ (out);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Produce the wrangler config object by deep-merging a site manifest on top of
|
|
132
|
+
* the canonical template. The site's `worker_name` becomes wrangler's `name`.
|
|
133
|
+
*
|
|
134
|
+
* @param {Record<string, unknown>} template
|
|
135
|
+
* @param {SiteManifest} site
|
|
136
|
+
* @returns {Record<string, unknown>}
|
|
137
|
+
*/
|
|
138
|
+
export function mergeWithTemplate(template, site) {
|
|
139
|
+
const { worker_name, ...rest } = site;
|
|
140
|
+
const merged = deepMerge(template, rest);
|
|
141
|
+
return { name: worker_name, ...merged };
|
|
142
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// deco-wrangler
|
|
3
|
+
//
|
|
4
|
+
// Local-dev wrapper around `wrangler` for storefront repos that no longer
|
|
5
|
+
// commit a `wrangler.jsonc`. Generates the canonical config from
|
|
6
|
+
// `@decocms/start`'s registry into `./wrangler.jsonc` (gitignored), then
|
|
7
|
+
// optionally execs the real `wrangler` with that config in cwd.
|
|
8
|
+
//
|
|
9
|
+
// Usage from a customer repo (after `npm i -D @decocms/start@latest`):
|
|
10
|
+
//
|
|
11
|
+
// npx deco-wrangler gen # generate ./wrangler.jsonc and exit
|
|
12
|
+
// # (used by predev/prebuild/prepare hooks)
|
|
13
|
+
// npx deco-wrangler tail # tail prod logs (worker name resolved automatically)
|
|
14
|
+
// npx deco-wrangler types # regenerate worker-configuration.d.ts
|
|
15
|
+
// npx deco-wrangler deploy # discouraged in dev; deploys go via CI
|
|
16
|
+
// npx deco-wrangler --help # passes through to wrangler
|
|
17
|
+
//
|
|
18
|
+
// All non-`gen` invocations also (re)generate ./wrangler.jsonc first so the
|
|
19
|
+
// file is always in sync with the registry before wrangler runs. The
|
|
20
|
+
// `@cloudflare/vite-plugin` and the `wrangler` CLI both auto-discover
|
|
21
|
+
// ./wrangler.jsonc in cwd, so no extra config plumbing is required.
|
|
22
|
+
//
|
|
23
|
+
// Site identity (which entry of `deploy/sites/` to load) resolves in this
|
|
24
|
+
// order:
|
|
25
|
+
//
|
|
26
|
+
// 1. DECO_SITE_NAME env var (explicit override)
|
|
27
|
+
// 2. git remote `origin` URL parsed for the GitHub repo name
|
|
28
|
+
// 3. package.json `name` field
|
|
29
|
+
//
|
|
30
|
+
// Fails loudly if none of these match a registered site -- no implicit "guess
|
|
31
|
+
// the worker" behavior. The local wrapper enforces the same trust model the CI
|
|
32
|
+
// pipeline does.
|
|
33
|
+
|
|
34
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
35
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
36
|
+
import { dirname, resolve } from "node:path";
|
|
37
|
+
import { fileURLToPath } from "node:url";
|
|
38
|
+
import { loadSiteManifest, loadTemplate, mergeWithTemplate } from "./site-registry.mjs";
|
|
39
|
+
|
|
40
|
+
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
41
|
+
// scripts/deploy/wrangler-wrapper.mjs -> deco-start root
|
|
42
|
+
const DECO_START_PATH = resolve(SCRIPT_DIR, "..", "..");
|
|
43
|
+
|
|
44
|
+
function eprintln(msg) {
|
|
45
|
+
process.stderr.write(`[deco-wrangler] ${msg}\n`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function tryGitRemoteSiteName() {
|
|
49
|
+
try {
|
|
50
|
+
const url = execSync("git remote get-url origin", {
|
|
51
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
52
|
+
})
|
|
53
|
+
.toString()
|
|
54
|
+
.trim();
|
|
55
|
+
// matches both git@github.com:org/repo(.git) and https://github.com/org/repo(.git)
|
|
56
|
+
const m = url.match(/github\.com[:/][^/]+\/([^/]+?)(?:\.git)?$/);
|
|
57
|
+
return m?.[1];
|
|
58
|
+
} catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function tryPackageJsonName() {
|
|
64
|
+
try {
|
|
65
|
+
const pkg = JSON.parse(readFileSync(resolve(process.cwd(), "package.json"), "utf8"));
|
|
66
|
+
return typeof pkg.name === "string" ? pkg.name : undefined;
|
|
67
|
+
} catch {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function resolveSiteName() {
|
|
73
|
+
const envName = process.env.DECO_SITE_NAME?.trim();
|
|
74
|
+
if (envName) return { name: envName, source: "DECO_SITE_NAME env var" };
|
|
75
|
+
const gitName = tryGitRemoteSiteName();
|
|
76
|
+
if (gitName) return { name: gitName, source: "git remote origin" };
|
|
77
|
+
const pkgName = tryPackageJsonName();
|
|
78
|
+
if (pkgName) return { name: pkgName, source: "package.json name" };
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const resolved = resolveSiteName();
|
|
83
|
+
if (!resolved) {
|
|
84
|
+
eprintln(
|
|
85
|
+
"Could not determine site name. Set DECO_SITE_NAME or run from a repo with a github.com 'origin' remote.",
|
|
86
|
+
);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let manifest;
|
|
91
|
+
try {
|
|
92
|
+
manifest = loadSiteManifest(DECO_START_PATH, resolved.name);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
eprintln(err instanceof Error ? err.message : String(err));
|
|
95
|
+
eprintln(`Site name "${resolved.name}" was inferred from ${resolved.source}.`);
|
|
96
|
+
eprintln(
|
|
97
|
+
`If this is a personal sandbox, set DECO_SITE_NAME=<registered-site> or open a PR to deco-start adding deploy/sites/${resolved.name}.jsonc.`,
|
|
98
|
+
);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const merged = mergeWithTemplate(loadTemplate(DECO_START_PATH), manifest);
|
|
103
|
+
|
|
104
|
+
const outputPath = resolve(process.cwd(), "wrangler.jsonc");
|
|
105
|
+
const header = `// AUTOGENERATED by deco-wrangler -- DO NOT COMMIT.
|
|
106
|
+
// Add wrangler.jsonc to .gitignore. Regenerated on every \`deco-wrangler\` run.
|
|
107
|
+
// Source: @decocms/start deploy/sites/${resolved.name}.jsonc + wrangler-template.jsonc
|
|
108
|
+
`;
|
|
109
|
+
writeFileSync(outputPath, `${header}${JSON.stringify(merged, null, 2)}\n`);
|
|
110
|
+
|
|
111
|
+
eprintln(
|
|
112
|
+
`Resolved site "${resolved.name}" -> worker "${manifest.worker_name}" (via ${resolved.source})`,
|
|
113
|
+
);
|
|
114
|
+
eprintln(`Generated ${outputPath}`);
|
|
115
|
+
|
|
116
|
+
const argv = process.argv.slice(2);
|
|
117
|
+
// `gen` mode: just write the config and exit. Used by package.json
|
|
118
|
+
// predev/prebuild/prepare hooks to keep wrangler.jsonc in sync with the
|
|
119
|
+
// registry without invoking wrangler itself.
|
|
120
|
+
if (argv[0] === "gen" || argv[0] === "generate") {
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const wranglerArgs = ["wrangler", ...argv];
|
|
125
|
+
const result = spawnSync("npx", wranglerArgs, { stdio: "inherit" });
|
|
126
|
+
process.exit(result.status ?? 1);
|
|
@@ -5,7 +5,7 @@ import { log, logPhase } from "./types";
|
|
|
5
5
|
import { generatePackageJson } from "./templates/package-json";
|
|
6
6
|
import { generateTsconfig } from "./templates/tsconfig";
|
|
7
7
|
import { generateViteConfig } from "./templates/vite-config";
|
|
8
|
-
import {
|
|
8
|
+
import { generateGithubWorkflows } from "./templates/github-workflows";
|
|
9
9
|
import { generateKnipConfig } from "./templates/knip-config";
|
|
10
10
|
import { generateRoutes } from "./templates/routes";
|
|
11
11
|
import { generateSetup } from "./templates/setup";
|
|
@@ -50,13 +50,20 @@ function writeMultiFile(ctx: MigrationContext, files: Record<string, string>) {
|
|
|
50
50
|
export function scaffold(ctx: MigrationContext): void {
|
|
51
51
|
logPhase("Scaffold");
|
|
52
52
|
|
|
53
|
-
// Root config files
|
|
53
|
+
// Root config files. wrangler.jsonc is INTENTIONALLY not generated --
|
|
54
|
+
// per D6, the canonical wrangler config lives in decocms/deco-start under
|
|
55
|
+
// deploy/wrangler-template.jsonc and per-site overrides under
|
|
56
|
+
// deploy/sites/<repo>.jsonc; the file is materialized locally by
|
|
57
|
+
// `deco-wrangler gen` and gitignored.
|
|
54
58
|
writeFile(ctx, "package.json", generatePackageJson(ctx));
|
|
55
59
|
writeFile(ctx, "tsconfig.json", generateTsconfig());
|
|
56
60
|
writeFile(ctx, "vite.config.ts", generateViteConfig(ctx));
|
|
57
|
-
writeFile(ctx, "wrangler.jsonc", generateWrangler(ctx));
|
|
58
61
|
writeFile(ctx, "knip.config.ts", generateKnipConfig());
|
|
59
62
|
writeFile(ctx, ".gitignore", generateGitignore());
|
|
63
|
+
|
|
64
|
+
// Caller workflow stubs that delegate to decocms/deco-start's reusable
|
|
65
|
+
// workflows. The customer repo holds no deploy logic of its own.
|
|
66
|
+
writeMultiFile(ctx, generateGithubWorkflows());
|
|
60
67
|
writeFile(ctx, ".prettierrc", JSON.stringify({
|
|
61
68
|
semi: true,
|
|
62
69
|
singleQuote: false,
|
|
@@ -209,6 +216,9 @@ dist/
|
|
|
209
216
|
# Cloudflare Workers
|
|
210
217
|
.wrangler/
|
|
211
218
|
.dev.vars
|
|
219
|
+
# Generated by \`deco-wrangler\` from @decocms/start's central registry.
|
|
220
|
+
# Source of truth lives in decocms/deco-start under deploy/sites/<repo>.jsonc.
|
|
221
|
+
wrangler.jsonc
|
|
212
222
|
|
|
213
223
|
# TanStack Router (auto-generated)
|
|
214
224
|
src/routeTree.gen.ts
|
|
@@ -13,7 +13,12 @@ const REQUIRED_FILES = [
|
|
|
13
13
|
"package.json",
|
|
14
14
|
"tsconfig.json",
|
|
15
15
|
"vite.config.ts",
|
|
16
|
-
|
|
16
|
+
// wrangler.jsonc is INTENTIONALLY absent -- D6: it lives in decocms/deco-start
|
|
17
|
+
// under deploy/sites/<repo>.jsonc and is generated locally by `deco-wrangler gen`.
|
|
18
|
+
".github/workflows/deploy.yml",
|
|
19
|
+
".github/workflows/preview.yml",
|
|
20
|
+
".github/workflows/regen-blocks.yml",
|
|
21
|
+
".github/workflows/sync-secrets.yml",
|
|
17
22
|
"knip.config.ts",
|
|
18
23
|
".prettierrc",
|
|
19
24
|
"src/server.ts",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Caller workflow stubs for new sites. Each stub delegates to a reusable
|
|
2
|
+
// workflow under `decocms/deco-start/.github/workflows/` -- the customer repo
|
|
3
|
+
// holds no deploy/build logic of its own. See D6 in
|
|
4
|
+
// `.cursor/rules/migration-tooling-policy.mdc` and the `deploy/` directory
|
|
5
|
+
// for the central registry contract.
|
|
6
|
+
|
|
7
|
+
const DEPLOY_YML = `name: Deploy
|
|
8
|
+
|
|
9
|
+
# Thin caller for decocms/deco-start's central deploy workflow.
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
deploy:
|
|
20
|
+
uses: decocms/deco-start/.github/workflows/deploy.yml@v2
|
|
21
|
+
secrets: inherit
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
const PREVIEW_YML = `name: Preview
|
|
25
|
+
|
|
26
|
+
# Thin caller for decocms/deco-start's central preview workflow.
|
|
27
|
+
|
|
28
|
+
on:
|
|
29
|
+
repository_dispatch:
|
|
30
|
+
types: [preview-deploy]
|
|
31
|
+
pull_request:
|
|
32
|
+
types: [opened, synchronize, reopened]
|
|
33
|
+
push:
|
|
34
|
+
branches: ['env/**']
|
|
35
|
+
|
|
36
|
+
permissions:
|
|
37
|
+
contents: read
|
|
38
|
+
pull-requests: write
|
|
39
|
+
statuses: write
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
preview:
|
|
43
|
+
uses: decocms/deco-start/.github/workflows/preview.yml@v2
|
|
44
|
+
secrets: inherit
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
const REGEN_BLOCKS_YML = `name: Regenerate blocks.gen.json
|
|
48
|
+
|
|
49
|
+
# Thin caller for decocms/deco-start's central regen-blocks workflow.
|
|
50
|
+
|
|
51
|
+
on:
|
|
52
|
+
push:
|
|
53
|
+
branches: [main]
|
|
54
|
+
paths:
|
|
55
|
+
- ".deco/blocks/**"
|
|
56
|
+
|
|
57
|
+
permissions:
|
|
58
|
+
contents: write
|
|
59
|
+
|
|
60
|
+
jobs:
|
|
61
|
+
regen:
|
|
62
|
+
uses: decocms/deco-start/.github/workflows/regen-blocks.yml@v2
|
|
63
|
+
secrets: inherit
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
const SYNC_SECRETS_YML = `name: Sync worker secrets
|
|
67
|
+
|
|
68
|
+
# Thin caller for decocms/deco-start's central sync-secrets workflow.
|
|
69
|
+
|
|
70
|
+
on:
|
|
71
|
+
workflow_dispatch:
|
|
72
|
+
inputs:
|
|
73
|
+
mode:
|
|
74
|
+
description: "dry-run = print diff only | apply = set secrets on worker"
|
|
75
|
+
required: true
|
|
76
|
+
default: "dry-run"
|
|
77
|
+
type: choice
|
|
78
|
+
options: [dry-run, apply]
|
|
79
|
+
|
|
80
|
+
permissions:
|
|
81
|
+
contents: read
|
|
82
|
+
|
|
83
|
+
jobs:
|
|
84
|
+
sync:
|
|
85
|
+
uses: decocms/deco-start/.github/workflows/sync-secrets.yml@v2
|
|
86
|
+
with:
|
|
87
|
+
mode: \${{ inputs.mode }}
|
|
88
|
+
secrets: inherit
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
export function generateGithubWorkflows(): Record<string, string> {
|
|
92
|
+
return {
|
|
93
|
+
".github/workflows/deploy.yml": DEPLOY_YML,
|
|
94
|
+
".github/workflows/preview.yml": PREVIEW_YML,
|
|
95
|
+
".github/workflows/regen-blocks.yml": REGEN_BLOCKS_YML,
|
|
96
|
+
".github/workflows/sync-secrets.yml": SYNC_SECRETS_YML,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -109,8 +109,15 @@ export function generatePackageJson(ctx: MigrationContext): string {
|
|
|
109
109
|
build:
|
|
110
110
|
"npm run generate:blocks && npm run generate:sections && npm run generate:loaders && npm run generate:schema && npm run generate:invoke && tsr generate && vite build",
|
|
111
111
|
preview: "vite preview",
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
// wrangler.jsonc is generated by `deco-wrangler gen` from the central
|
|
113
|
+
// registry in @decocms/start (D6). Predev/prebuild ensure it is up to
|
|
114
|
+
// date before vite runs the @cloudflare/vite-plugin which reads it.
|
|
115
|
+
"gen:wrangler": "deco-wrangler gen",
|
|
116
|
+
predev: "deco-wrangler gen",
|
|
117
|
+
prebuild: "deco-wrangler gen",
|
|
118
|
+
deploy:
|
|
119
|
+
"echo 'Production deploys are managed by .github/workflows/deploy.yml on push to main. For an emergency manual deploy run: npx deco-wrangler deploy'; exit 1",
|
|
120
|
+
types: "deco-wrangler types",
|
|
114
121
|
typecheck: "tsc --noEmit",
|
|
115
122
|
format: 'prettier --write "src/**/*.{ts,tsx}"',
|
|
116
123
|
"format:check": 'prettier --check "src/**/*.{ts,tsx}"',
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { MigrationContext } from "../types";
|
|
2
|
-
|
|
3
|
-
export function generateWrangler(ctx: MigrationContext): string {
|
|
4
|
-
const workerName = ctx.siteName
|
|
5
|
-
.toLowerCase()
|
|
6
|
-
.replace(/[^a-z0-9-]/g, "-")
|
|
7
|
-
.replace(/-+/g, "-");
|
|
8
|
-
|
|
9
|
-
return `{
|
|
10
|
-
"name": "${workerName}-tanstack",
|
|
11
|
-
// TODO: Set your Cloudflare account_id for deployment
|
|
12
|
-
// "account_id": "YOUR_ACCOUNT_ID",
|
|
13
|
-
"compatibility_date": "2026-02-14",
|
|
14
|
-
"compatibility_flags": ["nodejs_compat", "no_handle_cross_request_promise_resolution"],
|
|
15
|
-
"main": "./src/worker-entry.ts",
|
|
16
|
-
"workers_dev": true,
|
|
17
|
-
"preview_urls": true,
|
|
18
|
-
// Uncomment and set KV namespace ID for redirect/AB testing:
|
|
19
|
-
// "kv_namespaces": [
|
|
20
|
-
// { "binding": "SITES_KV", "id": "YOUR_KV_NAMESPACE_ID" }
|
|
21
|
-
// ],
|
|
22
|
-
"observability": {
|
|
23
|
-
"logs": {
|
|
24
|
-
"enabled": true,
|
|
25
|
-
"invocation_logs": true
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
`;
|
|
30
|
-
}
|