@smoothbricks/cli 0.7.0 → 0.9.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +9 -0
- package/dist/monorepo/managed-files.d.ts +30 -0
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +69 -2
- package/dist/monorepo/packs/index.d.ts.map +1 -1
- package/dist/monorepo/packs/index.js +13 -0
- package/dist/monorepo/wrangler.d.ts +5 -0
- package/dist/monorepo/wrangler.d.ts.map +1 -0
- package/dist/monorepo/wrangler.js +122 -0
- package/dist/wrangler/prepare-env.d.ts +68 -0
- package/dist/wrangler/prepare-env.d.ts.map +1 -0
- package/dist/wrangler/prepare-env.js +253 -0
- package/dist/wrangler/scaffold.d.ts +7 -0
- package/dist/wrangler/scaffold.d.ts.map +1 -0
- package/dist/wrangler/scaffold.js +228 -0
- package/package.json +9 -1
- package/src/cli.ts +10 -0
- package/src/monorepo/managed-files.test.ts +101 -1
- package/src/monorepo/managed-files.ts +80 -2
- package/src/monorepo/packs/index.ts +13 -0
- package/src/monorepo/wrangler.test.ts +216 -0
- package/src/monorepo/wrangler.ts +135 -0
- package/src/release/__tests__/helpers/fixture-repo.ts +19 -1
- package/src/wrangler/prepare-env.test.ts +246 -0
- package/src/wrangler/prepare-env.ts +290 -0
- package/src/wrangler/scaffold.test.ts +200 -0
- package/src/wrangler/scaffold.ts +239 -0
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,wBAAsB,MAAM,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAexE"}
|
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import { variants } from './generate/index.js';
|
|
|
3
3
|
import { cliPackageVersion } from './lib/cli-package.js';
|
|
4
4
|
import { findRepoRoot } from './lib/run.js';
|
|
5
5
|
import { resolvePrConflicts } from './pr/index.js';
|
|
6
|
+
import { scaffold } from './wrangler/scaffold.js';
|
|
6
7
|
export async function runCli(argv = process.argv.slice(2)) {
|
|
7
8
|
const program = buildProgram();
|
|
8
9
|
try {
|
|
@@ -290,6 +291,14 @@ function buildProgram() {
|
|
|
290
291
|
process.exitCode = exitCode;
|
|
291
292
|
}
|
|
292
293
|
});
|
|
294
|
+
const wrangler = program.command('wrangler').description('Cloudflare wrangler project helpers');
|
|
295
|
+
wrangler
|
|
296
|
+
.command('scaffold <project>')
|
|
297
|
+
.description('Write a starter scripts/prepare-env.ts (manifest-driven) and wire its nx target')
|
|
298
|
+
.option('--force', 'overwrite an existing scripts/prepare-env.ts')
|
|
299
|
+
.action(async (project, options) => {
|
|
300
|
+
scaffold(await findRepoRoot(), project, { force: options.force });
|
|
301
|
+
});
|
|
293
302
|
return program;
|
|
294
303
|
}
|
|
295
304
|
function booleanOption(value) {
|
|
@@ -12,6 +12,36 @@ declare function splitLocalSection(current: string): {
|
|
|
12
12
|
};
|
|
13
13
|
/** Test seam for the pure splitter. */
|
|
14
14
|
export declare const splitLocalSectionForTest: typeof splitLocalSection;
|
|
15
|
+
/**
|
|
16
|
+
* A repo-owned block INSIDE the managed section — e.g. one extra pattern
|
|
17
|
+
* spliced into a formatter's list, where a trailing marker (LOCAL_SECTION_MARKER)
|
|
18
|
+
* can't express it because it isn't at the end of the file. Wrap it in
|
|
19
|
+
* `# smoo-local-begin` / `# smoo-local-end`; the block is anchored to the line
|
|
20
|
+
* immediately before `# smoo-local-begin`. On update, the block is re-spliced
|
|
21
|
+
* right after that same anchor line in the freshly rendered template — if the
|
|
22
|
+
* anchor no longer appears there (the template reworked that section), the
|
|
23
|
+
* update refuses rather than silently dropping the repo's customization.
|
|
24
|
+
*/
|
|
25
|
+
export declare const INLINE_LOCAL_BEGIN = "# smoo-local-begin";
|
|
26
|
+
export declare const INLINE_LOCAL_END = "# smoo-local-end";
|
|
27
|
+
interface InlineLocalBlock {
|
|
28
|
+
anchor: string;
|
|
29
|
+
lines: string;
|
|
30
|
+
}
|
|
31
|
+
/** Pull inline local blocks out of a managed section, returning the section
|
|
32
|
+
* with each block (and its markers) removed, plus the extracted blocks in
|
|
33
|
+
* the order they appeared. */
|
|
34
|
+
declare function extractInlineLocalBlocks(managed: string): {
|
|
35
|
+
withoutInline: string;
|
|
36
|
+
blocks: InlineLocalBlock[];
|
|
37
|
+
};
|
|
38
|
+
/** Test seam for the pure extractor. */
|
|
39
|
+
export declare const extractInlineLocalBlocksForTest: typeof extractInlineLocalBlocks;
|
|
40
|
+
/** Re-splice extracted inline blocks into freshly rendered managed content,
|
|
41
|
+
* each immediately after its anchor line. A no-op when there are no blocks. */
|
|
42
|
+
declare function reinsertInlineLocalBlocks(content: string, blocks: InlineLocalBlock[]): string;
|
|
43
|
+
/** Test seam for the pure re-splicer. */
|
|
44
|
+
export declare const reinsertInlineLocalBlocksForTest: typeof reinsertInlineLocalBlocks;
|
|
15
45
|
export interface FileResult {
|
|
16
46
|
target: string;
|
|
17
47
|
action: 'created' | 'updated' | 'unchanged' | 'skipped' | 'skipped-symlink' | 'drifted' | 'ok-symlink';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-files.d.ts","sourceRoot":"","sources":["../../src/monorepo/managed-files.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,yEAAyE,CAAC;AAU3G,sFAAsF;AACtF,iBAAS,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAIlF;AAED,uCAAuC;AACvC,eAAO,MAAM,wBAAwB,0BAAoB,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;CACxG;AA8GD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,EAAE,CAG/F;
|
|
1
|
+
{"version":3,"file":"managed-files.d.ts","sourceRoot":"","sources":["../../src/monorepo/managed-files.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,yEAAyE,CAAC;AAU3G,sFAAsF;AACtF,iBAAS,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAIlF;AAED,uCAAuC;AACvC,eAAO,MAAM,wBAAwB,0BAAoB,CAAC;AAE1D;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;8BAE8B;AAC9B,iBAAS,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAE,CA6BxG;AAED,wCAAwC;AACxC,eAAO,MAAM,+BAA+B,iCAA2B,CAAC;AAExE;+EAC+E;AAC/E,iBAAS,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,CActF;AAED,yCAAyC;AACzC,eAAO,MAAM,gCAAgC,kCAA4B,CAAC;AAE1E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;CACxG;AA8GD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,EAAE,CAG/F;AAgLD,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAIxD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQzD"}
|
|
@@ -21,6 +21,71 @@ function splitLocalSection(current) {
|
|
|
21
21
|
}
|
|
22
22
|
/** Test seam for the pure splitter. */
|
|
23
23
|
export const splitLocalSectionForTest = splitLocalSection;
|
|
24
|
+
/**
|
|
25
|
+
* A repo-owned block INSIDE the managed section — e.g. one extra pattern
|
|
26
|
+
* spliced into a formatter's list, where a trailing marker (LOCAL_SECTION_MARKER)
|
|
27
|
+
* can't express it because it isn't at the end of the file. Wrap it in
|
|
28
|
+
* `# smoo-local-begin` / `# smoo-local-end`; the block is anchored to the line
|
|
29
|
+
* immediately before `# smoo-local-begin`. On update, the block is re-spliced
|
|
30
|
+
* right after that same anchor line in the freshly rendered template — if the
|
|
31
|
+
* anchor no longer appears there (the template reworked that section), the
|
|
32
|
+
* update refuses rather than silently dropping the repo's customization.
|
|
33
|
+
*/
|
|
34
|
+
export const INLINE_LOCAL_BEGIN = '# smoo-local-begin';
|
|
35
|
+
export const INLINE_LOCAL_END = '# smoo-local-end';
|
|
36
|
+
/** Pull inline local blocks out of a managed section, returning the section
|
|
37
|
+
* with each block (and its markers) removed, plus the extracted blocks in
|
|
38
|
+
* the order they appeared. */
|
|
39
|
+
function extractInlineLocalBlocks(managed) {
|
|
40
|
+
const lines = managed.split('\n');
|
|
41
|
+
const kept = [];
|
|
42
|
+
const blocks = [];
|
|
43
|
+
let i = 0;
|
|
44
|
+
while (i < lines.length) {
|
|
45
|
+
const line = lines[i];
|
|
46
|
+
if (line !== undefined && line.trim() === INLINE_LOCAL_BEGIN) {
|
|
47
|
+
const anchor = kept.at(-1);
|
|
48
|
+
if (anchor === undefined) {
|
|
49
|
+
throw new Error(`${INLINE_LOCAL_BEGIN} on line ${i + 1} has no preceding anchor line`);
|
|
50
|
+
}
|
|
51
|
+
const blockLines = [];
|
|
52
|
+
i += 1;
|
|
53
|
+
while (i < lines.length && lines[i]?.trim() !== INLINE_LOCAL_END) {
|
|
54
|
+
blockLines.push(lines[i]);
|
|
55
|
+
i += 1;
|
|
56
|
+
}
|
|
57
|
+
if (i >= lines.length) {
|
|
58
|
+
throw new Error(`${INLINE_LOCAL_BEGIN} anchored on "${anchor}" has no matching ${INLINE_LOCAL_END}`);
|
|
59
|
+
}
|
|
60
|
+
blocks.push({ anchor, lines: blockLines.join('\n') });
|
|
61
|
+
i += 1; // skip the END marker line itself
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
kept.push(line);
|
|
65
|
+
i += 1;
|
|
66
|
+
}
|
|
67
|
+
return { withoutInline: kept.join('\n'), blocks };
|
|
68
|
+
}
|
|
69
|
+
/** Test seam for the pure extractor. */
|
|
70
|
+
export const extractInlineLocalBlocksForTest = extractInlineLocalBlocks;
|
|
71
|
+
/** Re-splice extracted inline blocks into freshly rendered managed content,
|
|
72
|
+
* each immediately after its anchor line. A no-op when there are no blocks. */
|
|
73
|
+
function reinsertInlineLocalBlocks(content, blocks) {
|
|
74
|
+
if (blocks.length === 0)
|
|
75
|
+
return content;
|
|
76
|
+
const lines = content.split('\n');
|
|
77
|
+
for (const block of blocks) {
|
|
78
|
+
const index = lines.indexOf(block.anchor);
|
|
79
|
+
if (index === -1) {
|
|
80
|
+
throw new Error(`${INLINE_LOCAL_BEGIN} block anchored on "${block.anchor}" no longer matches any line in the updated ` +
|
|
81
|
+
'template — reconcile the repo-owned block manually');
|
|
82
|
+
}
|
|
83
|
+
lines.splice(index + 1, 0, INLINE_LOCAL_BEGIN, ...block.lines.split('\n'), INLINE_LOCAL_END);
|
|
84
|
+
}
|
|
85
|
+
return lines.join('\n');
|
|
86
|
+
}
|
|
87
|
+
/** Test seam for the pure re-splicer. */
|
|
88
|
+
export const reinsertInlineLocalBlocksForTest = reinsertInlineLocalBlocks;
|
|
24
89
|
const managedFiles = [
|
|
25
90
|
{
|
|
26
91
|
kind: 'raw',
|
|
@@ -131,13 +196,15 @@ function applyManagedFile(root, file, mode, context) {
|
|
|
131
196
|
}
|
|
132
197
|
const current = readFileSync(target, 'utf8');
|
|
133
198
|
const { managed, localTail } = splitLocalSection(current);
|
|
134
|
-
|
|
199
|
+
const { withoutInline, blocks } = extractInlineLocalBlocks(managed);
|
|
200
|
+
if (withoutInline === content || (localTail !== '' && withoutInline === `${content}\n`)) {
|
|
135
201
|
return { target: file.target, action: 'unchanged' };
|
|
136
202
|
}
|
|
137
203
|
if (mode === 'check' || mode === 'diff') {
|
|
138
204
|
return { target: file.target, action: 'drifted' };
|
|
139
205
|
}
|
|
140
|
-
const
|
|
206
|
+
const rendered = reinsertInlineLocalBlocks(content, blocks);
|
|
207
|
+
const next = localTail === '' ? rendered : `${rendered}\n${localTail}`;
|
|
141
208
|
writeManagedFile(target, next, file.executable === true);
|
|
142
209
|
return { target: file.target, action: 'updated' };
|
|
143
210
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/monorepo/packs/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/monorepo/packs/index.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClD,WAAW,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD,YAAY,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,gBAAgB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAClE,iBAAiB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpE;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC9F;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AA4GD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,mBAAwB,EACjC,KAAK,GAAE,oBAAyB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA0B7B"}
|
|
@@ -10,6 +10,7 @@ import { applyFixableMonorepoDefaults, applyNxReleaseDefaults, applyPublicPackag
|
|
|
10
10
|
import { validatePackedPublicPackageManifest, validatePackedPublicPackagePublint, validatePackedPublicPackageTypes, } from '../packed-package.js';
|
|
11
11
|
import { syncRootRuntimeVersions } from '../runtime.js';
|
|
12
12
|
import { applyToolConfigDefaults, validateToolConfig } from '../tool-validation.js';
|
|
13
|
+
import { applyWranglerDefaults, validateWrangler } from '../wrangler.js';
|
|
13
14
|
const packs = [
|
|
14
15
|
{
|
|
15
16
|
name: 'core',
|
|
@@ -96,6 +97,18 @@ const packs = [
|
|
|
96
97
|
return validatePackedPublicPackageTypes(ctx.root);
|
|
97
98
|
},
|
|
98
99
|
},
|
|
100
|
+
{
|
|
101
|
+
name: 'wrangler',
|
|
102
|
+
init(ctx) {
|
|
103
|
+
applyWranglerDefaults(ctx.root);
|
|
104
|
+
},
|
|
105
|
+
fixPreBuild(ctx) {
|
|
106
|
+
applyWranglerDefaults(ctx.root);
|
|
107
|
+
},
|
|
108
|
+
validatePreBuild(ctx) {
|
|
109
|
+
return validateWrangler(ctx.root);
|
|
110
|
+
},
|
|
111
|
+
},
|
|
99
112
|
];
|
|
100
113
|
export async function runInitPacks(ctx) {
|
|
101
114
|
for (const pack of packs) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** First `[env.<name>]` header in a wrangler.toml, or `null` when the config declares no envs (top-level bindings only). */
|
|
2
|
+
export declare function firstWranglerEnv(tomlText: string): string | null;
|
|
3
|
+
export declare function applyWranglerDefaults(root: string): void;
|
|
4
|
+
export declare function validateWrangler(root: string): number;
|
|
5
|
+
//# sourceMappingURL=wrangler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrangler.d.ts","sourceRoot":"","sources":["../../src/monorepo/wrangler.ts"],"names":[],"mappings":"AAaA,4HAA4H;AAC5H,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAkCD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiDxD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgCrD"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
import { getOrCreateRecord, recordProperty, writeJsonObject } from '../lib/json.js';
|
|
4
|
+
import { getWorkspacePackageManifests } from '../lib/workspace.js';
|
|
5
|
+
/** First `[env.<name>]` header in a wrangler.toml, or `null` when the config declares no envs (top-level bindings only). */
|
|
6
|
+
export function firstWranglerEnv(tomlText) {
|
|
7
|
+
const match = tomlText.match(/^\s*\[env\.([A-Za-z0-9_-]+)/m);
|
|
8
|
+
return match ? match[1] : null;
|
|
9
|
+
}
|
|
10
|
+
function wranglerProjects(root) {
|
|
11
|
+
const projects = [];
|
|
12
|
+
for (const pkg of getWorkspacePackageManifests(root)) {
|
|
13
|
+
const tomlPath = join(pkg.path, 'wrangler.toml');
|
|
14
|
+
if (!existsSync(tomlPath)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
projects.push({
|
|
18
|
+
label: relative(root, pkg.path) || '.',
|
|
19
|
+
dir: pkg.path,
|
|
20
|
+
packageJsonPath: pkg.packageJsonPath,
|
|
21
|
+
json: pkg.json,
|
|
22
|
+
tomlPath,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return projects;
|
|
26
|
+
}
|
|
27
|
+
/** Ensure the root .gitignore ignores the local secret file + generated types (once). */
|
|
28
|
+
function ensureGitignore(root) {
|
|
29
|
+
const path = join(root, '.gitignore');
|
|
30
|
+
const text = existsSync(path) ? readFileSync(path, 'utf8') : '';
|
|
31
|
+
const lines = text.split('\n').map((line) => line.trim());
|
|
32
|
+
const missing = ['.dev.vars', 'worker-configuration.d.ts'].filter((entry) => !lines.includes(entry));
|
|
33
|
+
if (missing.length === 0) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const block = `${text.replace(/\s*$/, '')}\n\n# wrangler: local secret values + generated types (names live in .dev.vars.example)\n${missing.join('\n')}\n`;
|
|
37
|
+
writeFileSync(path, block);
|
|
38
|
+
console.log(`updated .gitignore (${missing.join(', ')})`);
|
|
39
|
+
}
|
|
40
|
+
export function applyWranglerDefaults(root) {
|
|
41
|
+
const projects = wranglerProjects(root);
|
|
42
|
+
if (projects.length > 0) {
|
|
43
|
+
ensureGitignore(root);
|
|
44
|
+
}
|
|
45
|
+
for (const project of projects) {
|
|
46
|
+
const env = firstWranglerEnv(readFileSync(project.tomlPath, 'utf8'));
|
|
47
|
+
const nx = getOrCreateRecord(project.json, 'nx');
|
|
48
|
+
const targets = getOrCreateRecord(nx, 'targets');
|
|
49
|
+
const desired = {
|
|
50
|
+
executor: 'nx:run-commands',
|
|
51
|
+
cache: true,
|
|
52
|
+
inputs: ['{projectRoot}/wrangler.toml', '{projectRoot}/.dev.vars.example'],
|
|
53
|
+
outputs: ['{projectRoot}/worker-configuration.d.ts'],
|
|
54
|
+
options: {
|
|
55
|
+
command: `wrangler types${env ? ` --env ${env}` : ''} --env-file .dev.vars.example --include-runtime false`,
|
|
56
|
+
cwd: '{projectRoot}',
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
let changed = false;
|
|
60
|
+
const existing = recordProperty(targets, 'wrangler-types');
|
|
61
|
+
if (!existing || JSON.stringify(existing) !== JSON.stringify(desired)) {
|
|
62
|
+
targets['wrangler-types'] = desired;
|
|
63
|
+
changed = true;
|
|
64
|
+
}
|
|
65
|
+
const typecheck = recordProperty(targets, 'typecheck');
|
|
66
|
+
if (typecheck) {
|
|
67
|
+
const dependsOn = Array.isArray(typecheck.dependsOn) ? typecheck.dependsOn : [];
|
|
68
|
+
if (!dependsOn.includes('wrangler-types')) {
|
|
69
|
+
dependsOn.push('wrangler-types');
|
|
70
|
+
typecheck.dependsOn = dependsOn;
|
|
71
|
+
changed = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (changed) {
|
|
75
|
+
writeJsonObject(project.packageJsonPath, project.json);
|
|
76
|
+
console.log(`updated ${project.label}/package.json wrangler-types target`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.log(`unchanged ${project.label}/package.json wrangler-types target`);
|
|
80
|
+
}
|
|
81
|
+
// Empty .dev.vars.example = "this worker declares no secrets". Bootstrap it
|
|
82
|
+
// when missing; humans add SECRET_NAME= lines if the worker reads any (the
|
|
83
|
+
// wrangler-types + tsc gate fails on an undeclared secret until they do).
|
|
84
|
+
const examplePath = join(project.dir, '.dev.vars.example');
|
|
85
|
+
if (!existsSync(examplePath)) {
|
|
86
|
+
writeFileSync(examplePath, '');
|
|
87
|
+
console.log(`created ${project.label}/.dev.vars.example (no secrets)`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function validateWrangler(root) {
|
|
92
|
+
const gitignorePath = join(root, '.gitignore');
|
|
93
|
+
const gitignoreLines = existsSync(gitignorePath)
|
|
94
|
+
? readFileSync(gitignorePath, 'utf8')
|
|
95
|
+
.split('\n')
|
|
96
|
+
.map((line) => line.trim())
|
|
97
|
+
: [];
|
|
98
|
+
const gitignoreCoversSecrets = gitignoreLines.includes('.dev.vars') && gitignoreLines.includes('worker-configuration.d.ts');
|
|
99
|
+
let problems = 0;
|
|
100
|
+
for (const project of wranglerProjects(root)) {
|
|
101
|
+
let projectProblems = 0;
|
|
102
|
+
if (!existsSync(join(project.dir, '.dev.vars.example'))) {
|
|
103
|
+
console.log(`⨯ ${project.label}: missing .dev.vars.example`);
|
|
104
|
+
projectProblems++;
|
|
105
|
+
}
|
|
106
|
+
const nx = recordProperty(project.json, 'nx');
|
|
107
|
+
const targets = nx ? recordProperty(nx, 'targets') : null;
|
|
108
|
+
if (!targets || !recordProperty(targets, 'wrangler-types')) {
|
|
109
|
+
console.log(`⨯ ${project.label}: missing wrangler-types nx target`);
|
|
110
|
+
projectProblems++;
|
|
111
|
+
}
|
|
112
|
+
if (!gitignoreCoversSecrets) {
|
|
113
|
+
console.log(`⨯ ${project.label}: root .gitignore must ignore .dev.vars and worker-configuration.d.ts`);
|
|
114
|
+
projectProblems++;
|
|
115
|
+
}
|
|
116
|
+
if (projectProblems === 0) {
|
|
117
|
+
console.log(`✓ ${project.label}: wrangler config`);
|
|
118
|
+
}
|
|
119
|
+
problems += projectProblems;
|
|
120
|
+
}
|
|
121
|
+
return problems;
|
|
122
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export declare function isRecord(v: unknown): v is Record<string, unknown>;
|
|
2
|
+
/** First `[env.<name>]` header, or `null` when the config declares no envs (top-level bindings only). */
|
|
3
|
+
export declare function firstWranglerEnv(toml: string): string | null;
|
|
4
|
+
/** True if the toml declares `[env.<env>]`. */
|
|
5
|
+
export declare function hasEnvBlock(toml: string, env: string): boolean;
|
|
6
|
+
/** A `[env.<env>.vars]` value, or null if unset/empty. Reads committed public config. */
|
|
7
|
+
export declare function getVar(toml: string, env: string, name: string): string | null;
|
|
8
|
+
/** Set a `[env.<env>.vars]` value, preserving any trailing comment. Throws if the key isn't present (scaffold first). */
|
|
9
|
+
export declare function setVar(toml: string, env: string, name: string, value: string): string;
|
|
10
|
+
/** The id written for `[[env.<env>.kv_namespaces]]` binding, or null if absent/empty. */
|
|
11
|
+
export declare function getKvId(toml: string, env: string, binding: string): string | null;
|
|
12
|
+
/** Rewrite the `id = ...` line of the `[[env.<env>.kv_namespaces]]` table whose binding matches. Throws if absent. */
|
|
13
|
+
export declare function setKvId(toml: string, env: string, binding: string, id: string, title: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Append a copy of the whole `[env.<from>]` … block-group (every `[env.<from>...]`
|
|
16
|
+
* table up to the next non-`from` env or EOF) rewritten for `<to>`. Returns the new
|
|
17
|
+
* toml. Throws if `<from>` is absent or `<to>` already exists (blank/fill instead).
|
|
18
|
+
*/
|
|
19
|
+
export declare function cloneEnvBlock(toml: string, from: string, to: string): string;
|
|
20
|
+
/** Blank every `NAME = "..."` under `[env.<env>.vars]` whose key is in `keys` (env-specific values to re-fill). */
|
|
21
|
+
export declare function blankEnvVars(toml: string, env: string, keys: string[]): string;
|
|
22
|
+
/** Blank every `id = ...` line under the env's `[[env.<env>.kv_namespaces]]` tables (per-env resource ids). */
|
|
23
|
+
export declare function blankKvIds(toml: string, env: string): string;
|
|
24
|
+
/** Parse-guard: throws if `toml` no longer parses, so a bad edit can't be written to disk. */
|
|
25
|
+
export declare function assertToml(toml: string): void;
|
|
26
|
+
/** Persist a toml string after confirming it still parses. */
|
|
27
|
+
export declare function saveToml(path: string, toml: string): void;
|
|
28
|
+
export interface Manifest {
|
|
29
|
+
/** KV binding names declared under `[[env.<env>.kv_namespaces]]` (resources to provision). */
|
|
30
|
+
kvBindings: string[];
|
|
31
|
+
/** Public var names declared in `[env.<env>.vars]` (committed config). */
|
|
32
|
+
vars: string[];
|
|
33
|
+
/** Secret names declared in `.dev.vars.example` (values live on the worker, never in the repo). */
|
|
34
|
+
secrets: string[];
|
|
35
|
+
}
|
|
36
|
+
/** Secret NAMES from a `.dev.vars.example` file (KEY=... / KEY="..."), ignoring comments/blanks. */
|
|
37
|
+
export declare function parseDevVarsExample(text: string): string[];
|
|
38
|
+
/**
|
|
39
|
+
* Read the vars/secrets split for `env` from `<root>/wrangler.toml` (public var
|
|
40
|
+
* keys) + `<root>/.dev.vars.example` (secret names). This is the "what to prompt
|
|
41
|
+
* for" manifest a prepare-env script derives its work from.
|
|
42
|
+
*/
|
|
43
|
+
export declare function readManifest(root: string, env: string): Manifest;
|
|
44
|
+
/** True if `value` looks like a PEM block (any `-----BEGIN ...-----`). */
|
|
45
|
+
export declare function isPem(value: string): boolean;
|
|
46
|
+
/** Read a `.pem` file (expanding a leading `~`) and assert it's a PEM block. Throws otherwise. */
|
|
47
|
+
export declare function readPemFile(path: string): string;
|
|
48
|
+
/** Heuristic: does this secret name suggest file input (PEM/key)? Used to preselect a file prompt — never to change semantics. */
|
|
49
|
+
export declare function looksLikeFileSecret(name: string): boolean;
|
|
50
|
+
export interface KvNamespace {
|
|
51
|
+
id: string;
|
|
52
|
+
title: string;
|
|
53
|
+
}
|
|
54
|
+
/** Best-effort ERROR line from a Bun ShellError (thrown on non-zero exit). */
|
|
55
|
+
export declare function errText(err: unknown): string;
|
|
56
|
+
/** Live KV namespaces on the account (`kv namespace list` emits a pure JSON array); `[]` when offline/unauthenticated. */
|
|
57
|
+
export declare function listNamespaces(cwd: string): Promise<KvNamespace[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Reuse the namespace whose title exactly matches `logical`, else create it. The
|
|
60
|
+
* id always comes from the structured `list` JSON (create prints freeform text),
|
|
61
|
+
* so we re-list rather than scrape. Returns the id, or null on failure.
|
|
62
|
+
*/
|
|
63
|
+
export declare function ensureNamespace(logical: string, existing: KvNamespace[], cwd: string): Promise<string | null>;
|
|
64
|
+
/** Current secret names on the worker for `env`; `[]` when none/unreachable (Cloudflare allows setting pre-deploy). */
|
|
65
|
+
export declare function listSecretNames(env: string, cwd: string): Promise<string[]>;
|
|
66
|
+
/** `wrangler secret put <name> --env <env>` piping `value` on stdin (never a CLI arg). Returns success. */
|
|
67
|
+
export declare function putSecret(name: string, value: string, env: string, cwd: string): Promise<boolean>;
|
|
68
|
+
//# sourceMappingURL=prepare-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare-env.d.ts","sourceRoot":"","sources":["../../src/wrangler/prepare-env.ts"],"names":[],"mappings":"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"}
|