@donotdev/cli 0.0.20 → 0.0.21
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/README.md +31 -0
- package/dependencies-matrix.json +86 -19
- package/dist/bin/commands/agent-setup.js +2 -2
- package/dist/bin/commands/build.js +6 -6
- package/dist/bin/commands/bump.js +491 -69
- package/dist/bin/commands/cacheout.js +6 -6
- package/dist/bin/commands/coach.js +6 -6
- package/dist/bin/commands/create-app.js +23 -15
- package/dist/bin/commands/create-project.js +101 -16
- package/dist/bin/commands/db.js +142136 -0
- package/dist/bin/commands/deploy.js +336 -126
- package/dist/bin/commands/dev.js +6 -6
- package/dist/bin/commands/doctor.js +140 -33
- package/dist/bin/commands/emu.js +6 -6
- package/dist/bin/commands/format.js +6 -6
- package/dist/bin/commands/get-demo.js +11 -6
- package/dist/bin/commands/make-admin.js +14210 -13770
- package/dist/bin/commands/preview.js +6 -6
- package/dist/bin/commands/seed.js +142426 -0
- package/dist/bin/commands/setup-cicd.js +8904 -0
- package/dist/bin/commands/setup.js +256 -212
- package/dist/bin/commands/staging.js +343 -127
- package/dist/bin/commands/sync-secrets.js +55 -33
- package/dist/bin/commands/type-check.js +6 -6
- package/dist/bin/commands/wai.js +6 -6
- package/dist/bin/dndev.js +76 -11
- package/dist/bin/donotdev.js +21 -12
- package/dist/index.js +437 -142
- package/package.json +1 -1
- package/templates/app-demo/.env.example +1 -0
- package/templates/{root-consumer → app-demo}/entities/ExampleEntity.ts.example +15 -9
- package/templates/app-demo/index.html.example +1 -1
- package/templates/app-dndev/index.html.example +164 -0
- package/templates/app-dndev/public/logo.svg.example +1 -0
- package/templates/app-dndev/public/manifest.json.example +10 -0
- package/templates/app-dndev/src/App.tsx.example +35 -0
- package/templates/app-dndev/src/components/CockpitLayout.css.example +181 -0
- package/templates/app-dndev/src/components/CockpitLayout.tsx.example +209 -0
- package/templates/app-dndev/src/components/Kanban.css.example +385 -0
- package/templates/app-dndev/src/components/ModeToggle.tsx.example +32 -0
- package/templates/app-dndev/src/components/OverlaySlot.tsx.example +68 -0
- package/templates/app-dndev/src/components/TerminalPanel.css.example +228 -0
- package/templates/app-dndev/src/components/TerminalPanel.tsx.example +714 -0
- package/templates/app-dndev/src/components/markdown-prose.css.example +49 -0
- package/templates/app-dndev/src/components/phases/CaptainLog.tsx.example +107 -0
- package/templates/app-dndev/src/components/phases/ContextTabs.tsx.example +352 -0
- package/templates/app-dndev/src/components/phases/PhaseCard.tsx.example +126 -0
- package/templates/app-dndev/src/components/phases/PhaseDetail.tsx.example +147 -0
- package/templates/app-dndev/src/components/phases/ReviewPanel.tsx.example +115 -0
- package/templates/app-dndev/src/components/phases/phaseData.ts.example +366 -0
- package/templates/app-dndev/src/config/app.ts.example +103 -0
- package/templates/app-dndev/src/config/commands.ts.example +171 -0
- package/templates/app-dndev/src/config/legal.ts.example +170 -0
- package/templates/app-dndev/src/config/providers.ts.example +7 -0
- package/templates/app-dndev/src/globals.css.example +10 -0
- package/templates/app-dndev/src/hooks/useDndevFile.ts.example +144 -0
- package/templates/app-dndev/src/main.tsx.example +21 -0
- package/templates/app-dndev/src/pages/BoardPage.tsx.example +640 -0
- package/templates/app-dndev/src/pages/GrillPage.tsx.example +658 -0
- package/templates/app-dndev/src/pages/HomePage.tsx.example +347 -0
- package/templates/app-dndev/src/pages/NotFoundPage.tsx.example +33 -0
- package/templates/app-dndev/src/pages/PhasesPage.tsx.example +137 -0
- package/templates/app-dndev/src/pages/SettingsPage.tsx.example +64 -0
- package/templates/app-dndev/src/pages/legal/LegalNoticePage.tsx.example +75 -0
- package/templates/app-dndev/src/pages/legal/PrivacyPage.tsx.example +69 -0
- package/templates/app-dndev/src/pages/legal/TermsPage.tsx.example +71 -0
- package/templates/app-dndev/src/stores/dndevStore.ts.example +386 -0
- package/templates/app-dndev/src/themes.css.example +161 -0
- package/templates/app-dndev/terminal-sidecar.cjs.example +341 -0
- package/templates/app-dndev/tsconfig.json.example +9 -0
- package/templates/app-dndev/vite.config.ts.example +24 -0
- package/templates/app-next/src/locales/home_en.json.example +6 -6
- package/templates/app-vite/index.html.example +1 -1
- package/templates/app-vite/src/locales/home_en.json.example +6 -6
- package/templates/functions-supabase/supabase/functions/.env.example +0 -2
- package/templates/root-consumer/.claude/commands/grill.md.example +86 -8
- package/templates/root-consumer/.dndev.secrets.example +32 -0
- package/templates/root-consumer/.gitignore.example +3 -0
- package/templates/root-consumer/AI.md.example +4 -0
- package/templates/root-consumer/entities/index.ts.example +2 -5
- package/templates/root-consumer/guides/dndev/COMPONENTS_ATOMIC.md.example +4 -0
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +23 -20
- package/templates/root-consumer/guides/dndev/INDEX.md.example +1 -0
- package/templates/root-consumer/guides/dndev/SETUP_BILLING.md.example +3 -7
- package/templates/root-consumer/guides/dndev/SETUP_CICD.md.example +115 -0
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +41 -0
- package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +13 -18
- package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +17 -12
- package/templates/root-consumer/guides/dndev/advanced/COOKIE_REFERENCE.md.example +252 -252
- package/templates/root-consumer/guides/dndev/advanced/VERSION_CONTROL.md.example +174 -174
- package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +185 -251
- package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +26 -8
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +66 -49
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +6 -5
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +9 -9
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +1 -1
- package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +7 -6
- package/templates/root-consumer/guides/wai-way/context_map.json.example +51 -20
- package/templates/root-consumer/guides/wai-way/hld_template.md.example +138 -0
- package/templates/root-consumer/guides/wai-way/lld_template.md.example +103 -0
- package/templates/root-consumer/guides/wai-way/prd_template.md.example +140 -0
- /package/templates/{root-consumer → app-demo}/entities/Contact.ts.example +0 -0
- /package/templates/{root-consumer → app-demo}/entities/demo.ts.example +0 -0
|
@@ -3209,9 +3209,9 @@ var require_parse2 = __commonJS({
|
|
|
3209
3209
|
const idx = prev.value.lastIndexOf("[");
|
|
3210
3210
|
const pre = prev.value.slice(0, idx);
|
|
3211
3211
|
const rest2 = prev.value.slice(idx + 2);
|
|
3212
|
-
const
|
|
3213
|
-
if (
|
|
3214
|
-
prev.value = pre +
|
|
3212
|
+
const posix2 = POSIX_REGEX_SOURCE[rest2];
|
|
3213
|
+
if (posix2) {
|
|
3214
|
+
prev.value = pre + posix2;
|
|
3215
3215
|
state.backtrack = true;
|
|
3216
3216
|
advance();
|
|
3217
3217
|
if (!bos.output && tokens.indexOf(prev) === 1) {
|
|
@@ -3733,7 +3733,7 @@ var require_picomatch = __commonJS({
|
|
|
3733
3733
|
throw new TypeError("Expected pattern to be a non-empty string");
|
|
3734
3734
|
}
|
|
3735
3735
|
const opts = options || {};
|
|
3736
|
-
const
|
|
3736
|
+
const posix2 = utils.isWindows(options);
|
|
3737
3737
|
const regex = isState ? picomatch.compileRe(glob, options) : picomatch.makeRe(glob, options, false, true);
|
|
3738
3738
|
const state = regex.state;
|
|
3739
3739
|
delete regex.state;
|
|
@@ -3743,8 +3743,8 @@ var require_picomatch = __commonJS({
|
|
|
3743
3743
|
isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
|
|
3744
3744
|
}
|
|
3745
3745
|
const matcher = (input, returnObject = false) => {
|
|
3746
|
-
const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix });
|
|
3747
|
-
const result = { glob, state, regex, posix, input, output, match, isMatch };
|
|
3746
|
+
const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix: posix2 });
|
|
3747
|
+
const result = { glob, state, regex, posix: posix2, input, output, match, isMatch };
|
|
3748
3748
|
if (typeof opts.onResult === "function") {
|
|
3749
3749
|
opts.onResult(result);
|
|
3750
3750
|
}
|
|
@@ -3769,7 +3769,7 @@ var require_picomatch = __commonJS({
|
|
|
3769
3769
|
}
|
|
3770
3770
|
return matcher;
|
|
3771
3771
|
};
|
|
3772
|
-
picomatch.test = (input, regex, options, { glob, posix } = {}) => {
|
|
3772
|
+
picomatch.test = (input, regex, options, { glob, posix: posix2 } = {}) => {
|
|
3773
3773
|
if (typeof input !== "string") {
|
|
3774
3774
|
throw new TypeError("Expected input to be a string");
|
|
3775
3775
|
}
|
|
@@ -3777,7 +3777,7 @@ var require_picomatch = __commonJS({
|
|
|
3777
3777
|
return { isMatch: false, output: "" };
|
|
3778
3778
|
}
|
|
3779
3779
|
const opts = options || {};
|
|
3780
|
-
const format = opts.format || (
|
|
3780
|
+
const format = opts.format || (posix2 ? utils.toPosixSlashes : null);
|
|
3781
3781
|
let match = input === glob;
|
|
3782
3782
|
let output = match && format ? format(input) : input;
|
|
3783
3783
|
if (match === false) {
|
|
@@ -3786,14 +3786,14 @@ var require_picomatch = __commonJS({
|
|
|
3786
3786
|
}
|
|
3787
3787
|
if (match === false || opts.capture === true) {
|
|
3788
3788
|
if (opts.matchBase === true || opts.basename === true) {
|
|
3789
|
-
match = picomatch.matchBase(input, regex, options,
|
|
3789
|
+
match = picomatch.matchBase(input, regex, options, posix2);
|
|
3790
3790
|
} else {
|
|
3791
3791
|
match = regex.exec(output);
|
|
3792
3792
|
}
|
|
3793
3793
|
}
|
|
3794
3794
|
return { isMatch: Boolean(match), match, output };
|
|
3795
3795
|
};
|
|
3796
|
-
picomatch.matchBase = (input, glob, options,
|
|
3796
|
+
picomatch.matchBase = (input, glob, options, posix2 = utils.isWindows(options)) => {
|
|
3797
3797
|
const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
|
|
3798
3798
|
return regex.test(path.basename(input));
|
|
3799
3799
|
};
|
|
@@ -3984,9 +3984,9 @@ var require_micromatch = __commonJS({
|
|
|
3984
3984
|
return [].concat(patterns).every((p2) => picomatch(p2, options)(str));
|
|
3985
3985
|
};
|
|
3986
3986
|
micromatch.capture = (glob, input, options) => {
|
|
3987
|
-
let
|
|
3987
|
+
let posix2 = utils.isWindows(options);
|
|
3988
3988
|
let regex = picomatch.makeRe(String(glob), { ...options, capture: true });
|
|
3989
|
-
let match = regex.exec(
|
|
3989
|
+
let match = regex.exec(posix2 ? utils.toPosixSlashes(input) : input);
|
|
3990
3990
|
if (match) {
|
|
3991
3991
|
return match.slice(1).map((v2) => v2 === void 0 ? "" : v2);
|
|
3992
3992
|
}
|
|
@@ -4166,15 +4166,15 @@ var require_pattern = __commonJS({
|
|
|
4166
4166
|
exports.removeDuplicateSlashes = removeDuplicateSlashes;
|
|
4167
4167
|
function partitionAbsoluteAndRelative(patterns) {
|
|
4168
4168
|
const absolute = [];
|
|
4169
|
-
const
|
|
4169
|
+
const relative4 = [];
|
|
4170
4170
|
for (const pattern of patterns) {
|
|
4171
4171
|
if (isAbsolute(pattern)) {
|
|
4172
4172
|
absolute.push(pattern);
|
|
4173
4173
|
} else {
|
|
4174
|
-
|
|
4174
|
+
relative4.push(pattern);
|
|
4175
4175
|
}
|
|
4176
4176
|
}
|
|
4177
|
-
return [absolute,
|
|
4177
|
+
return [absolute, relative4];
|
|
4178
4178
|
}
|
|
4179
4179
|
exports.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
|
|
4180
4180
|
function isAbsolute(pattern) {
|
|
@@ -4484,7 +4484,7 @@ var require_async = __commonJS({
|
|
|
4484
4484
|
callSuccessCallback(callback, lstat);
|
|
4485
4485
|
return;
|
|
4486
4486
|
}
|
|
4487
|
-
settings.fs.stat(path, (statError,
|
|
4487
|
+
settings.fs.stat(path, (statError, stat2) => {
|
|
4488
4488
|
if (statError !== null) {
|
|
4489
4489
|
if (settings.throwErrorOnBrokenSymbolicLink) {
|
|
4490
4490
|
callFailureCallback(callback, statError);
|
|
@@ -4494,9 +4494,9 @@ var require_async = __commonJS({
|
|
|
4494
4494
|
return;
|
|
4495
4495
|
}
|
|
4496
4496
|
if (settings.markSymbolicLink) {
|
|
4497
|
-
|
|
4497
|
+
stat2.isSymbolicLink = () => true;
|
|
4498
4498
|
}
|
|
4499
|
-
callSuccessCallback(callback,
|
|
4499
|
+
callSuccessCallback(callback, stat2);
|
|
4500
4500
|
});
|
|
4501
4501
|
});
|
|
4502
4502
|
}
|
|
@@ -4523,11 +4523,11 @@ var require_sync = __commonJS({
|
|
|
4523
4523
|
return lstat;
|
|
4524
4524
|
}
|
|
4525
4525
|
try {
|
|
4526
|
-
const
|
|
4526
|
+
const stat2 = settings.fs.statSync(path);
|
|
4527
4527
|
if (settings.markSymbolicLink) {
|
|
4528
|
-
|
|
4528
|
+
stat2.isSymbolicLink = () => true;
|
|
4529
4529
|
}
|
|
4530
|
-
return
|
|
4530
|
+
return stat2;
|
|
4531
4531
|
} catch (error2) {
|
|
4532
4532
|
if (!settings.throwErrorOnBrokenSymbolicLink) {
|
|
4533
4533
|
return lstat;
|
|
@@ -4597,14 +4597,14 @@ var require_out = __commonJS({
|
|
|
4597
4597
|
var sync = require_sync();
|
|
4598
4598
|
var settings_1 = require_settings();
|
|
4599
4599
|
exports.Settings = settings_1.default;
|
|
4600
|
-
function
|
|
4600
|
+
function stat2(path, optionsOrSettingsOrCallback, callback) {
|
|
4601
4601
|
if (typeof optionsOrSettingsOrCallback === "function") {
|
|
4602
4602
|
async.read(path, getSettings(), optionsOrSettingsOrCallback);
|
|
4603
4603
|
return;
|
|
4604
4604
|
}
|
|
4605
4605
|
async.read(path, getSettings(optionsOrSettingsOrCallback), callback);
|
|
4606
4606
|
}
|
|
4607
|
-
exports.stat =
|
|
4607
|
+
exports.stat = stat2;
|
|
4608
4608
|
function statSync3(path, optionsOrSettings) {
|
|
4609
4609
|
const settings = getSettings(optionsOrSettings);
|
|
4610
4610
|
return sync.read(path, settings);
|
|
@@ -4774,7 +4774,7 @@ var require_async2 = __commonJS({
|
|
|
4774
4774
|
readdirWithFileTypes(directory, settings, callback);
|
|
4775
4775
|
return;
|
|
4776
4776
|
}
|
|
4777
|
-
|
|
4777
|
+
readdir2(directory, settings, callback);
|
|
4778
4778
|
}
|
|
4779
4779
|
exports.read = read;
|
|
4780
4780
|
function readdirWithFileTypes(directory, settings, callback) {
|
|
@@ -4823,7 +4823,7 @@ var require_async2 = __commonJS({
|
|
|
4823
4823
|
});
|
|
4824
4824
|
};
|
|
4825
4825
|
}
|
|
4826
|
-
function
|
|
4826
|
+
function readdir2(directory, settings, callback) {
|
|
4827
4827
|
settings.fs.readdir(directory, (readdirError, names) => {
|
|
4828
4828
|
if (readdirError !== null) {
|
|
4829
4829
|
callFailureCallback(callback, readdirError);
|
|
@@ -4858,7 +4858,7 @@ var require_async2 = __commonJS({
|
|
|
4858
4858
|
});
|
|
4859
4859
|
});
|
|
4860
4860
|
}
|
|
4861
|
-
exports.readdir =
|
|
4861
|
+
exports.readdir = readdir2;
|
|
4862
4862
|
function callFailureCallback(callback, error2) {
|
|
4863
4863
|
callback(error2);
|
|
4864
4864
|
}
|
|
@@ -4883,7 +4883,7 @@ var require_sync2 = __commonJS({
|
|
|
4883
4883
|
if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) {
|
|
4884
4884
|
return readdirWithFileTypes(directory, settings);
|
|
4885
4885
|
}
|
|
4886
|
-
return
|
|
4886
|
+
return readdir2(directory, settings);
|
|
4887
4887
|
}
|
|
4888
4888
|
exports.read = read;
|
|
4889
4889
|
function readdirWithFileTypes(directory, settings) {
|
|
@@ -4908,7 +4908,7 @@ var require_sync2 = __commonJS({
|
|
|
4908
4908
|
});
|
|
4909
4909
|
}
|
|
4910
4910
|
exports.readdirWithFileTypes = readdirWithFileTypes;
|
|
4911
|
-
function
|
|
4911
|
+
function readdir2(directory, settings) {
|
|
4912
4912
|
const names = settings.fs.readdirSync(directory);
|
|
4913
4913
|
return names.map((name) => {
|
|
4914
4914
|
const entryPath = common.joinPathSegments(directory, name, settings.pathSegmentSeparator);
|
|
@@ -4924,7 +4924,7 @@ var require_sync2 = __commonJS({
|
|
|
4924
4924
|
return entry;
|
|
4925
4925
|
});
|
|
4926
4926
|
}
|
|
4927
|
-
exports.readdir =
|
|
4927
|
+
exports.readdir = readdir2;
|
|
4928
4928
|
}
|
|
4929
4929
|
});
|
|
4930
4930
|
|
|
@@ -6486,19 +6486,19 @@ var require_out4 = __commonJS({
|
|
|
6486
6486
|
return utils.path.convertPathToPattern(source);
|
|
6487
6487
|
}
|
|
6488
6488
|
FastGlob2.convertPathToPattern = convertPathToPattern;
|
|
6489
|
-
let
|
|
6490
|
-
(function(
|
|
6489
|
+
let posix2;
|
|
6490
|
+
(function(posix3) {
|
|
6491
6491
|
function escapePath2(source) {
|
|
6492
6492
|
assertPatternsInput(source);
|
|
6493
6493
|
return utils.path.escapePosixPath(source);
|
|
6494
6494
|
}
|
|
6495
|
-
|
|
6495
|
+
posix3.escapePath = escapePath2;
|
|
6496
6496
|
function convertPathToPattern2(source) {
|
|
6497
6497
|
assertPatternsInput(source);
|
|
6498
6498
|
return utils.path.convertPosixPathToPattern(source);
|
|
6499
6499
|
}
|
|
6500
|
-
|
|
6501
|
-
})(
|
|
6500
|
+
posix3.convertPathToPattern = convertPathToPattern2;
|
|
6501
|
+
})(posix2 = FastGlob2.posix || (FastGlob2.posix = {}));
|
|
6502
6502
|
let win32;
|
|
6503
6503
|
(function(win322) {
|
|
6504
6504
|
function escapePath2(source) {
|
|
@@ -7077,7 +7077,7 @@ var init_PathResolver = __esm({
|
|
|
7077
7077
|
}
|
|
7078
7078
|
const detectedFormat = this._detectFormat(filePath, format);
|
|
7079
7079
|
let writeContent;
|
|
7080
|
-
if (
|
|
7080
|
+
if (Buffer.isBuffer(content)) {
|
|
7081
7081
|
writeContent = content;
|
|
7082
7082
|
} else if (detectedFormat === "json" && typeof content === "object") {
|
|
7083
7083
|
writeContent = JSON.stringify(content, null, 2);
|
|
@@ -7086,7 +7086,7 @@ var init_PathResolver = __esm({
|
|
|
7086
7086
|
}
|
|
7087
7087
|
try {
|
|
7088
7088
|
return await safeExecuteAsync(async () => {
|
|
7089
|
-
if (
|
|
7089
|
+
if (Buffer.isBuffer(writeContent)) {
|
|
7090
7090
|
await fs.promises.writeFile(normalizedPath, writeContent);
|
|
7091
7091
|
} else {
|
|
7092
7092
|
await fs.promises.writeFile(normalizedPath, writeContent, "utf8");
|
|
@@ -7138,7 +7138,7 @@ var init_PathResolver = __esm({
|
|
|
7138
7138
|
}
|
|
7139
7139
|
const detectedFormat = this._detectFormat(filePath, format);
|
|
7140
7140
|
let writeContent;
|
|
7141
|
-
if (
|
|
7141
|
+
if (Buffer.isBuffer(content)) {
|
|
7142
7142
|
writeContent = content;
|
|
7143
7143
|
} else if (detectedFormat === "json" && typeof content === "object") {
|
|
7144
7144
|
writeContent = JSON.stringify(content, null, 2);
|
|
@@ -7146,7 +7146,7 @@ var init_PathResolver = __esm({
|
|
|
7146
7146
|
writeContent = String(content);
|
|
7147
7147
|
}
|
|
7148
7148
|
try {
|
|
7149
|
-
if (
|
|
7149
|
+
if (Buffer.isBuffer(writeContent)) {
|
|
7150
7150
|
fs.writeFileSync(normalizedPath, writeContent);
|
|
7151
7151
|
} else {
|
|
7152
7152
|
fs.writeFileSync(normalizedPath, writeContent, "utf8");
|
|
@@ -7970,7 +7970,7 @@ var init_typed_file_operations = __esm({
|
|
|
7970
7970
|
});
|
|
7971
7971
|
|
|
7972
7972
|
// packages/tooling/src/bundler/utils.ts
|
|
7973
|
-
import { Buffer
|
|
7973
|
+
import { Buffer } from "node:buffer";
|
|
7974
7974
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
7975
7975
|
import { createRequire as createRequire3 } from "node:module";
|
|
7976
7976
|
import { dirname as dirname3, resolve as resolve3 } from "node:path";
|
|
@@ -7987,7 +7987,7 @@ var init_utils = __esm({
|
|
|
7987
7987
|
globalThis.require = require2;
|
|
7988
7988
|
globalThis.__filename = __filename;
|
|
7989
7989
|
globalThis.__dirname = __dirname;
|
|
7990
|
-
globalThis.Buffer =
|
|
7990
|
+
globalThis.Buffer = Buffer;
|
|
7991
7991
|
globalThis.process = process;
|
|
7992
7992
|
if (typeof global === "undefined") {
|
|
7993
7993
|
globalThis.global = globalThis;
|
|
@@ -8335,7 +8335,28 @@ var init_cli_tools = __esm({
|
|
|
8335
8335
|
}
|
|
8336
8336
|
});
|
|
8337
8337
|
|
|
8338
|
-
// packages/tooling/src/
|
|
8338
|
+
// packages/tooling/src/utils/secrets-resolver.ts
|
|
8339
|
+
function parseEnvFile(filePath) {
|
|
8340
|
+
if (!pathExists(filePath)) return {};
|
|
8341
|
+
const content = readSync(filePath, { format: "text" });
|
|
8342
|
+
if (typeof content !== "string" || !content) return {};
|
|
8343
|
+
const result = {};
|
|
8344
|
+
for (const line of content.split(/\r?\n/)) {
|
|
8345
|
+
const trimmed = line.trim();
|
|
8346
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
8347
|
+
const eqIdx = trimmed.indexOf("=");
|
|
8348
|
+
if (eqIdx === -1) continue;
|
|
8349
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
8350
|
+
let value = trimmed.slice(eqIdx + 1).trim();
|
|
8351
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
8352
|
+
value = value.slice(1, -1);
|
|
8353
|
+
}
|
|
8354
|
+
if (key && value) {
|
|
8355
|
+
result[key] = value;
|
|
8356
|
+
}
|
|
8357
|
+
}
|
|
8358
|
+
return result;
|
|
8359
|
+
}
|
|
8339
8360
|
function readEnvVar(filePath, varName) {
|
|
8340
8361
|
if (!pathExists(filePath)) return null;
|
|
8341
8362
|
const content = readSync(filePath, { format: "text" });
|
|
@@ -8344,16 +8365,93 @@ function readEnvVar(filePath, varName) {
|
|
|
8344
8365
|
const trimmed = line.trim();
|
|
8345
8366
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
8346
8367
|
if (trimmed.startsWith(`${varName}=`)) {
|
|
8347
|
-
|
|
8368
|
+
let val = trimmed.substring(`${varName}=`.length).trim();
|
|
8348
8369
|
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
8349
|
-
|
|
8370
|
+
val = val.slice(1, -1);
|
|
8350
8371
|
}
|
|
8351
8372
|
return val || null;
|
|
8352
8373
|
}
|
|
8353
8374
|
}
|
|
8354
8375
|
return null;
|
|
8355
8376
|
}
|
|
8356
|
-
function
|
|
8377
|
+
function loadDndevSecrets(projectRoot) {
|
|
8378
|
+
const secretsPath = joinPath(projectRoot, ".dndev.secrets");
|
|
8379
|
+
if (cachedSecretsPath === secretsPath && cachedSecrets) {
|
|
8380
|
+
return cachedSecrets;
|
|
8381
|
+
}
|
|
8382
|
+
cachedSecrets = parseEnvFile(secretsPath);
|
|
8383
|
+
cachedSecretsPath = secretsPath;
|
|
8384
|
+
return cachedSecrets;
|
|
8385
|
+
}
|
|
8386
|
+
function resolveSecret(name, projectRoot, opts) {
|
|
8387
|
+
const appDir = opts?.appDir ?? projectRoot;
|
|
8388
|
+
const envValue = process.env[name];
|
|
8389
|
+
if (envValue) {
|
|
8390
|
+
return { value: envValue, source: "process.env" };
|
|
8391
|
+
}
|
|
8392
|
+
const secrets = loadDndevSecrets(projectRoot);
|
|
8393
|
+
if (secrets[name]) {
|
|
8394
|
+
return { value: secrets[name], source: ".dndev.secrets" };
|
|
8395
|
+
}
|
|
8396
|
+
if (name === "SUPABASE_SECRET_KEY" && secrets["SUPABASE_SERVICE_ROLE_KEY"]) {
|
|
8397
|
+
return {
|
|
8398
|
+
value: secrets["SUPABASE_SERVICE_ROLE_KEY"],
|
|
8399
|
+
source: ".dndev.secrets"
|
|
8400
|
+
};
|
|
8401
|
+
}
|
|
8402
|
+
const legacyPaths = LEGACY_PATHS[name];
|
|
8403
|
+
if (legacyPaths) {
|
|
8404
|
+
for (const relPath of legacyPaths) {
|
|
8405
|
+
const fullPath = joinPath(appDir, relPath);
|
|
8406
|
+
const value = readEnvVar(fullPath, name);
|
|
8407
|
+
if (value) {
|
|
8408
|
+
if (!opts?.silent && !warnedLegacy.has(name)) {
|
|
8409
|
+
warnedLegacy.add(name);
|
|
8410
|
+
log.warn(
|
|
8411
|
+
`${name} found in ${relPath} (legacy). Move it to .dndev.secrets at project root.`
|
|
8412
|
+
);
|
|
8413
|
+
}
|
|
8414
|
+
return { value, source: "legacy", legacyPath: relPath };
|
|
8415
|
+
}
|
|
8416
|
+
if (name === "SUPABASE_SECRET_KEY") {
|
|
8417
|
+
const aliasValue = readEnvVar(fullPath, "SUPABASE_SERVICE_ROLE_KEY");
|
|
8418
|
+
if (aliasValue) {
|
|
8419
|
+
if (!opts?.silent && !warnedLegacy.has(name)) {
|
|
8420
|
+
warnedLegacy.add(name);
|
|
8421
|
+
log.warn(
|
|
8422
|
+
`${name} found in ${relPath} (legacy). Move it to .dndev.secrets at project root.`
|
|
8423
|
+
);
|
|
8424
|
+
}
|
|
8425
|
+
return { value: aliasValue, source: "legacy", legacyPath: relPath };
|
|
8426
|
+
}
|
|
8427
|
+
}
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8430
|
+
return null;
|
|
8431
|
+
}
|
|
8432
|
+
var LEGACY_PATHS, warnedLegacy, cachedSecretsPath, cachedSecrets;
|
|
8433
|
+
var init_secrets_resolver = __esm({
|
|
8434
|
+
"packages/tooling/src/utils/secrets-resolver.ts"() {
|
|
8435
|
+
"use strict";
|
|
8436
|
+
init_utils();
|
|
8437
|
+
init_pathResolver();
|
|
8438
|
+
init_cli_output();
|
|
8439
|
+
LEGACY_PATHS = {
|
|
8440
|
+
VERCEL_TOKEN: [".env.local"],
|
|
8441
|
+
SUPABASE_SECRET_KEY: ["supabase/functions/.env", "functions/.env"],
|
|
8442
|
+
SUPABASE_DB_URL: ["supabase/functions/.env", "functions/.env"],
|
|
8443
|
+
SUPABASE_ACCESS_TOKEN: ["supabase/functions/.env", "functions/.env"],
|
|
8444
|
+
STRIPE_SECRET_KEY: ["supabase/functions/.env", "functions/.env"],
|
|
8445
|
+
STRIPE_WEBHOOK_SECRET: ["supabase/functions/.env", "functions/.env"]
|
|
8446
|
+
};
|
|
8447
|
+
warnedLegacy = /* @__PURE__ */ new Set();
|
|
8448
|
+
cachedSecretsPath = null;
|
|
8449
|
+
cachedSecrets = null;
|
|
8450
|
+
}
|
|
8451
|
+
});
|
|
8452
|
+
|
|
8453
|
+
// packages/tooling/src/cli/setup/vercel-token.ts
|
|
8454
|
+
function resolvePerAppVar(appDir, varName) {
|
|
8357
8455
|
if (process.env[varName]) return process.env[varName];
|
|
8358
8456
|
const fromLocal = readEnvVar(joinPath(appDir, ".env.local"), varName);
|
|
8359
8457
|
if (fromLocal) return fromLocal;
|
|
@@ -8361,10 +8459,11 @@ function resolveVercelVar(appDir, varName) {
|
|
|
8361
8459
|
if (fromEnv) return fromEnv;
|
|
8362
8460
|
return null;
|
|
8363
8461
|
}
|
|
8364
|
-
function resolveVercelCredentials(appDir) {
|
|
8365
|
-
const
|
|
8366
|
-
const
|
|
8367
|
-
const
|
|
8462
|
+
function resolveVercelCredentials(appDir, projectRoot) {
|
|
8463
|
+
const root = projectRoot ?? process.cwd();
|
|
8464
|
+
const token = resolveSecret("VERCEL_TOKEN", root, { appDir })?.value ?? null;
|
|
8465
|
+
const orgId = resolvePerAppVar(appDir, "VERCEL_ORG_ID");
|
|
8466
|
+
const projectId = resolvePerAppVar(appDir, "VERCEL_PROJECT_ID");
|
|
8368
8467
|
const missing = [];
|
|
8369
8468
|
if (!token) missing.push("VERCEL_TOKEN");
|
|
8370
8469
|
if (!orgId) missing.push("VERCEL_ORG_ID");
|
|
@@ -8378,6 +8477,7 @@ var init_vercel_token = __esm({
|
|
|
8378
8477
|
"packages/tooling/src/cli/setup/vercel-token.ts"() {
|
|
8379
8478
|
"use strict";
|
|
8380
8479
|
init_utils();
|
|
8480
|
+
init_secrets_resolver();
|
|
8381
8481
|
init_pathResolver();
|
|
8382
8482
|
}
|
|
8383
8483
|
});
|
|
@@ -15770,10 +15870,14 @@ var init_error_handling = __esm({
|
|
|
15770
15870
|
var sync_secrets_exports = {};
|
|
15771
15871
|
__export(sync_secrets_exports, {
|
|
15772
15872
|
default: () => sync_secrets_default,
|
|
15773
|
-
|
|
15873
|
+
detectGitHubRepo: () => detectGitHubRepo,
|
|
15874
|
+
main: () => main,
|
|
15875
|
+
parseSecretsWithFallback: () => parseSecretsWithFallback,
|
|
15876
|
+
setGitHubSecret: () => setGitHubSecret,
|
|
15877
|
+
uploadServiceAccountToGitHub: () => uploadServiceAccountToGitHub
|
|
15774
15878
|
});
|
|
15775
|
-
import { spawnSync as
|
|
15776
|
-
function
|
|
15879
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
15880
|
+
function parseEnvFile2(filePath) {
|
|
15777
15881
|
if (!pathExists(filePath)) {
|
|
15778
15882
|
throw new DoNotDevError(
|
|
15779
15883
|
`Environment file not found: ${filePath}`,
|
|
@@ -15781,30 +15885,22 @@ function parseEnvFile(filePath) {
|
|
|
15781
15885
|
{ context: { filePath } }
|
|
15782
15886
|
);
|
|
15783
15887
|
}
|
|
15784
|
-
const
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
throw new Error(`Failed to read secrets file: ${filePath}`);
|
|
15888
|
+
const result = parseEnvFile(filePath);
|
|
15889
|
+
if (Object.keys(result).length === 0) {
|
|
15890
|
+
log.debug(`No key-value pairs found in ${filePath}`);
|
|
15788
15891
|
}
|
|
15789
|
-
|
|
15790
|
-
|
|
15791
|
-
|
|
15792
|
-
|
|
15793
|
-
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
return;
|
|
15799
|
-
}
|
|
15800
|
-
const key = trimmedLine.substring(0, equalIndex).trim();
|
|
15801
|
-
const value = trimmedLine.substring(equalIndex + 1).trim();
|
|
15802
|
-
const cleanValue = value.replace(/^["']|["']$/g, "");
|
|
15803
|
-
if (key && cleanValue) {
|
|
15804
|
-
secrets[key] = cleanValue;
|
|
15892
|
+
return result;
|
|
15893
|
+
}
|
|
15894
|
+
function parseSecretsWithFallback(envFilePath, projectRoot) {
|
|
15895
|
+
const dndevSecretsPath = joinPath(projectRoot, ".dndev.secrets");
|
|
15896
|
+
if (pathExists(dndevSecretsPath)) {
|
|
15897
|
+
const secrets = parseEnvFile(dndevSecretsPath);
|
|
15898
|
+
if (Object.keys(secrets).length > 0) {
|
|
15899
|
+
log.info(`Reading secrets from: ${dndevSecretsPath}`);
|
|
15900
|
+
return secrets;
|
|
15805
15901
|
}
|
|
15806
|
-
}
|
|
15807
|
-
return
|
|
15902
|
+
}
|
|
15903
|
+
return parseEnvFile2(envFilePath);
|
|
15808
15904
|
}
|
|
15809
15905
|
function detectPlatform() {
|
|
15810
15906
|
const currentDir = process.cwd();
|
|
@@ -15895,8 +15991,8 @@ function detectAppsWithFunctions() {
|
|
|
15895
15991
|
try {
|
|
15896
15992
|
const appsList = readdirSync2(appsDir).filter((item) => {
|
|
15897
15993
|
const itemPath = joinPath(appsDir, item);
|
|
15898
|
-
const
|
|
15899
|
-
return
|
|
15994
|
+
const stat2 = statSync2(itemPath);
|
|
15995
|
+
return stat2?.isDirectory() === true;
|
|
15900
15996
|
});
|
|
15901
15997
|
for (const app of appsList) {
|
|
15902
15998
|
const functionsEnvFile = joinPath(appsDir, app, "functions", ".env");
|
|
@@ -15962,7 +16058,7 @@ async function setFirebaseSecret(key, value, projectId, dryRun = false, cwd) {
|
|
|
15962
16058
|
NODE_OPTIONS: ""
|
|
15963
16059
|
// Clear to avoid conflicts
|
|
15964
16060
|
};
|
|
15965
|
-
const result =
|
|
16061
|
+
const result = spawnSync5(firebaseCmd, args, {
|
|
15966
16062
|
input: value,
|
|
15967
16063
|
encoding: "utf8",
|
|
15968
16064
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -16055,7 +16151,7 @@ function setVercelSecret(key, value, projectId, dryRun = false) {
|
|
|
16055
16151
|
if (projectId) {
|
|
16056
16152
|
args.push("--project", projectId);
|
|
16057
16153
|
}
|
|
16058
|
-
const result =
|
|
16154
|
+
const result = spawnSync5("vercel", args, {
|
|
16059
16155
|
input: value,
|
|
16060
16156
|
encoding: "utf8",
|
|
16061
16157
|
stdio: ["pipe", "inherit", "inherit"]
|
|
@@ -16084,7 +16180,7 @@ function setVercelSecret(key, value, projectId, dryRun = false) {
|
|
|
16084
16180
|
}
|
|
16085
16181
|
function detectGitHubRepo() {
|
|
16086
16182
|
try {
|
|
16087
|
-
const result =
|
|
16183
|
+
const result = spawnSync5("git", ["remote", "get-url", "origin"], {
|
|
16088
16184
|
encoding: "utf8",
|
|
16089
16185
|
stdio: ["pipe", "pipe", "pipe"]
|
|
16090
16186
|
});
|
|
@@ -16112,7 +16208,7 @@ function setGitHubSecret(key, value, repo, dryRun = false) {
|
|
|
16112
16208
|
if (repo) {
|
|
16113
16209
|
args.push("--repo", repo);
|
|
16114
16210
|
}
|
|
16115
|
-
const result =
|
|
16211
|
+
const result = spawnSync5("gh", args, {
|
|
16116
16212
|
input: value,
|
|
16117
16213
|
encoding: "utf8",
|
|
16118
16214
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -16164,7 +16260,7 @@ function uploadServiceAccountToGitHub(appDir, repo, dryRun = false, staging = fa
|
|
|
16164
16260
|
const contentRaw = readSync(filePath, { format: "text" });
|
|
16165
16261
|
const content = typeof contentRaw === "string" ? contentRaw : null;
|
|
16166
16262
|
if (!content) return;
|
|
16167
|
-
const encoded =
|
|
16263
|
+
const encoded = Buffer.from(content).toString("base64");
|
|
16168
16264
|
setGitHubSecret(secretName, encoded, repo, dryRun);
|
|
16169
16265
|
}
|
|
16170
16266
|
async function main(options = {}) {
|
|
@@ -16251,7 +16347,7 @@ Examples:
|
|
|
16251
16347
|
return 1;
|
|
16252
16348
|
}
|
|
16253
16349
|
log.info(`Syncing secrets to GitHub repository: ${repo}`);
|
|
16254
|
-
const secrets2 =
|
|
16350
|
+
const secrets2 = parseSecretsWithFallback(envFilePath, currentDir);
|
|
16255
16351
|
const secretKeys2 = Object.keys(secrets2);
|
|
16256
16352
|
if (secretKeys2.length === 0) {
|
|
16257
16353
|
log.info("No secrets found in .env file");
|
|
@@ -16287,14 +16383,13 @@ Examples:
|
|
|
16287
16383
|
return 0;
|
|
16288
16384
|
}
|
|
16289
16385
|
const platform = config.platform || detectPlatform();
|
|
16290
|
-
log.info(`Reading secrets from: ${envFilePath}`);
|
|
16291
16386
|
if (config.verbose) {
|
|
16292
16387
|
log.debug(`Working directory: ${currentDir}`);
|
|
16293
16388
|
log.debug(`Environment file: ${envFilePath}`);
|
|
16294
16389
|
log.debug(`Platform: ${platform}`);
|
|
16295
16390
|
log.debug(`Dry run mode: ${config.dryRun}`);
|
|
16296
16391
|
}
|
|
16297
|
-
const secrets =
|
|
16392
|
+
const secrets = parseSecretsWithFallback(envFilePath, currentDir);
|
|
16298
16393
|
const secretKeys = Object.keys(secrets);
|
|
16299
16394
|
if (secretKeys.length === 0) {
|
|
16300
16395
|
log.info("No secrets found in .env file");
|
|
@@ -16355,6 +16450,7 @@ var init_sync_secrets = __esm({
|
|
|
16355
16450
|
init_cli_output();
|
|
16356
16451
|
init_errors();
|
|
16357
16452
|
init_pathResolver();
|
|
16453
|
+
init_secrets_resolver();
|
|
16358
16454
|
sync_secrets_default = main;
|
|
16359
16455
|
}
|
|
16360
16456
|
});
|
|
@@ -16380,8 +16476,8 @@ async function deploySupabaseFunctions(appDir, config) {
|
|
|
16380
16476
|
);
|
|
16381
16477
|
const functionDirs = readdirSync2(functionsDir).filter((item) => {
|
|
16382
16478
|
const itemPath = joinPath(functionsDir, item);
|
|
16383
|
-
const
|
|
16384
|
-
return
|
|
16479
|
+
const stat2 = statSync2(itemPath);
|
|
16480
|
+
return stat2?.isDirectory() === true;
|
|
16385
16481
|
}).filter((dir) => {
|
|
16386
16482
|
const indexPath = joinPath(functionsDir, dir, "index.ts");
|
|
16387
16483
|
return pathExists(indexPath);
|
|
@@ -16603,48 +16699,168 @@ async function deployFrontend(appDir, serviceAccountPath, projectId, config) {
|
|
|
16603
16699
|
init_utils();
|
|
16604
16700
|
init_cli_output();
|
|
16605
16701
|
init_vercel_token();
|
|
16606
|
-
|
|
16702
|
+
init_pathResolver();
|
|
16703
|
+
import { createHash } from "node:crypto";
|
|
16704
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
16705
|
+
import { join as join3, relative as relative3 } from "node:path";
|
|
16706
|
+
var VERCEL_API = "https://api.vercel.com";
|
|
16707
|
+
var UPLOAD_BATCH_SIZE = 10;
|
|
16708
|
+
var POLL_INTERVAL_MS = 3e3;
|
|
16709
|
+
var POLL_MAX_ATTEMPTS = 100;
|
|
16710
|
+
function apiHeaders(token, extra) {
|
|
16711
|
+
return { Authorization: `Bearer ${token}`, ...extra };
|
|
16712
|
+
}
|
|
16713
|
+
function teamQuery(orgId) {
|
|
16714
|
+
return `?teamId=${encodeURIComponent(orgId)}`;
|
|
16715
|
+
}
|
|
16716
|
+
async function collectDistFiles(distDir) {
|
|
16717
|
+
const files = [];
|
|
16718
|
+
async function walk(dir) {
|
|
16719
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
16720
|
+
for (const entry of entries) {
|
|
16721
|
+
const fullPath = join3(dir, entry.name);
|
|
16722
|
+
if (entry.isDirectory()) {
|
|
16723
|
+
await walk(fullPath);
|
|
16724
|
+
} else {
|
|
16725
|
+
const content = await readFile(fullPath);
|
|
16726
|
+
const sha = createHash("sha1").update(content).digest("hex");
|
|
16727
|
+
const rel = relative3(distDir, fullPath).split("\\").join("/");
|
|
16728
|
+
files.push({
|
|
16729
|
+
relativePath: rel,
|
|
16730
|
+
content,
|
|
16731
|
+
sha,
|
|
16732
|
+
size: content.byteLength
|
|
16733
|
+
});
|
|
16734
|
+
}
|
|
16735
|
+
}
|
|
16736
|
+
}
|
|
16737
|
+
await walk(distDir);
|
|
16738
|
+
return files;
|
|
16739
|
+
}
|
|
16740
|
+
async function uploadFiles(files, token, orgId) {
|
|
16741
|
+
const q2 = teamQuery(orgId);
|
|
16742
|
+
for (let i = 0; i < files.length; i += UPLOAD_BATCH_SIZE) {
|
|
16743
|
+
const batch = files.slice(i, i + UPLOAD_BATCH_SIZE);
|
|
16744
|
+
await Promise.all(
|
|
16745
|
+
batch.map(async (file) => {
|
|
16746
|
+
const res = await fetch(`${VERCEL_API}/v2/files${q2}`, {
|
|
16747
|
+
method: "POST",
|
|
16748
|
+
headers: apiHeaders(token, {
|
|
16749
|
+
"Content-Type": "application/octet-stream",
|
|
16750
|
+
"x-vercel-digest": file.sha,
|
|
16751
|
+
"Content-Length": String(file.size)
|
|
16752
|
+
}),
|
|
16753
|
+
body: new Uint8Array(file.content)
|
|
16754
|
+
});
|
|
16755
|
+
if (!res.ok) {
|
|
16756
|
+
const body = await res.text();
|
|
16757
|
+
throw new Error(
|
|
16758
|
+
`File upload failed for ${file.relativePath} (${res.status}): ${body}`
|
|
16759
|
+
);
|
|
16760
|
+
}
|
|
16761
|
+
})
|
|
16762
|
+
);
|
|
16763
|
+
}
|
|
16764
|
+
}
|
|
16765
|
+
async function createDeployment(files, token, orgId, projectId) {
|
|
16766
|
+
const q2 = teamQuery(orgId);
|
|
16767
|
+
const body = {
|
|
16768
|
+
project: projectId,
|
|
16769
|
+
target: "production",
|
|
16770
|
+
files: files.map((f) => ({
|
|
16771
|
+
file: f.relativePath,
|
|
16772
|
+
sha: f.sha,
|
|
16773
|
+
size: f.size
|
|
16774
|
+
})),
|
|
16775
|
+
projectSettings: {
|
|
16776
|
+
buildCommand: "",
|
|
16777
|
+
installCommand: "",
|
|
16778
|
+
outputDirectory: "."
|
|
16779
|
+
}
|
|
16780
|
+
};
|
|
16781
|
+
const res = await fetch(`${VERCEL_API}/v13/deployments${q2}`, {
|
|
16782
|
+
method: "POST",
|
|
16783
|
+
headers: apiHeaders(token, { "Content-Type": "application/json" }),
|
|
16784
|
+
body: JSON.stringify(body)
|
|
16785
|
+
});
|
|
16786
|
+
if (!res.ok) {
|
|
16787
|
+
const text = await res.text();
|
|
16788
|
+
throw new Error(`Create deployment failed (${res.status}): ${text}`);
|
|
16789
|
+
}
|
|
16790
|
+
return await res.json();
|
|
16791
|
+
}
|
|
16792
|
+
async function waitForReady(deploymentId, token, orgId) {
|
|
16793
|
+
const q2 = teamQuery(orgId);
|
|
16794
|
+
for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {
|
|
16795
|
+
const res = await fetch(
|
|
16796
|
+
`${VERCEL_API}/v13/deployments/${deploymentId}${q2}`,
|
|
16797
|
+
{ headers: apiHeaders(token) }
|
|
16798
|
+
);
|
|
16799
|
+
if (!res.ok) {
|
|
16800
|
+
const text = await res.text();
|
|
16801
|
+
throw new Error(
|
|
16802
|
+
`Deployment status check failed (${res.status}): ${text}`
|
|
16803
|
+
);
|
|
16804
|
+
}
|
|
16805
|
+
const data = await res.json();
|
|
16806
|
+
if (data.readyState === "READY") return data;
|
|
16807
|
+
if (data.readyState === "ERROR") {
|
|
16808
|
+
throw new Error(
|
|
16809
|
+
`Deployment failed: ${data.errorMessage || "Unknown error"}`
|
|
16810
|
+
);
|
|
16811
|
+
}
|
|
16812
|
+
if (data.readyState === "CANCELED") {
|
|
16813
|
+
throw new Error("Deployment was canceled");
|
|
16814
|
+
}
|
|
16815
|
+
await new Promise((r2) => setTimeout(r2, POLL_INTERVAL_MS));
|
|
16816
|
+
}
|
|
16817
|
+
throw new Error("Deployment timed out (5+ minutes)");
|
|
16818
|
+
}
|
|
16607
16819
|
async function deployVercelFrontend(appDir, _config) {
|
|
16608
16820
|
const result = resolveVercelCredentials(appDir);
|
|
16609
16821
|
if (result.missing) {
|
|
16822
|
+
const secretVars = result.missing.filter((v2) => v2 === "VERCEL_TOKEN");
|
|
16823
|
+
const appVars = result.missing.filter((v2) => v2 !== "VERCEL_TOKEN");
|
|
16824
|
+
const hints = [];
|
|
16825
|
+
if (secretVars.length > 0)
|
|
16826
|
+
hints.push("Add VERCEL_TOKEN to .dndev.secrets at project root.");
|
|
16827
|
+
if (appVars.length > 0)
|
|
16828
|
+
hints.push(`Add ${appVars.join(", ")} to apps/<app>/.env`);
|
|
16610
16829
|
throw new Error(
|
|
16611
|
-
`Missing Vercel credentials
|
|
16612
|
-
|
|
16830
|
+
`Missing Vercel credentials: ${result.missing.join(", ")}
|
|
16831
|
+
` + hints.join("\n") + "\nSee guides/dndev/SETUP_VERCEL.md"
|
|
16613
16832
|
);
|
|
16614
16833
|
}
|
|
16615
16834
|
const { token, orgId, projectId } = result.credentials;
|
|
16616
|
-
|
|
16617
|
-
|
|
16618
|
-
|
|
16619
|
-
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
16624
|
-
|
|
16625
|
-
|
|
16626
|
-
|
|
16627
|
-
|
|
16628
|
-
|
|
16629
|
-
|
|
16630
|
-
|
|
16631
|
-
|
|
16632
|
-
);
|
|
16633
|
-
|
|
16634
|
-
|
|
16635
|
-
}
|
|
16636
|
-
|
|
16637
|
-
|
|
16638
|
-
log.success(`Production: ${deployUrl}`);
|
|
16639
|
-
} else {
|
|
16640
|
-
log.success("Frontend deployed to Vercel");
|
|
16835
|
+
const distDir = joinPath(appDir, "dist");
|
|
16836
|
+
if (!pathExists(distDir)) {
|
|
16837
|
+
throw new Error(`dist/ not found at ${distDir}. Run build first.`);
|
|
16838
|
+
}
|
|
16839
|
+
log.debug("Using Vercel REST API (token-based, no CLI)");
|
|
16840
|
+
log.info("Collecting dist/ files...");
|
|
16841
|
+
const files = await collectDistFiles(distDir);
|
|
16842
|
+
if (files.length === 0) {
|
|
16843
|
+
throw new Error("dist/ is empty \u2014 nothing to deploy.");
|
|
16844
|
+
}
|
|
16845
|
+
log.info(`Found ${files.length} files`);
|
|
16846
|
+
log.info("Uploading files to Vercel...");
|
|
16847
|
+
await uploadFiles(files, token, orgId);
|
|
16848
|
+
log.success(`${files.length} files uploaded`);
|
|
16849
|
+
log.info("Creating production deployment...");
|
|
16850
|
+
const deployment = await createDeployment(files, token, orgId, projectId);
|
|
16851
|
+
log.info(`Deployment ${deployment.id} created, waiting...`);
|
|
16852
|
+
const ready = await waitForReady(deployment.id, token, orgId);
|
|
16853
|
+
const prodUrl = `https://${ready.url}`;
|
|
16854
|
+
log.success(`Production: ${prodUrl}`);
|
|
16855
|
+
if (ready.alias?.length) {
|
|
16856
|
+
log.info(`Aliases: ${ready.alias.join(", ")}`);
|
|
16641
16857
|
}
|
|
16642
16858
|
}
|
|
16643
16859
|
|
|
16644
16860
|
// packages/tooling/src/apps/deploy-functions.ts
|
|
16645
16861
|
init_utils();
|
|
16646
16862
|
var import_yaml = __toESM(require_dist(), 1);
|
|
16647
|
-
import { execSync as execSync2, spawnSync as
|
|
16863
|
+
import { execSync as execSync2, spawnSync as spawnSync3 } from "node:child_process";
|
|
16648
16864
|
init_pathResolver();
|
|
16649
16865
|
init_cli_tools();
|
|
16650
16866
|
init_typed_file_operations();
|
|
@@ -16831,7 +17047,7 @@ function updateCloudRunIAM(functionNames, projectId, region, serviceAccountPath,
|
|
|
16831
17047
|
let failCount = 0;
|
|
16832
17048
|
for (const funcName of functionNames) {
|
|
16833
17049
|
try {
|
|
16834
|
-
const result =
|
|
17050
|
+
const result = spawnSync3(
|
|
16835
17051
|
"gcloud",
|
|
16836
17052
|
[
|
|
16837
17053
|
"run",
|
|
@@ -16949,7 +17165,7 @@ async function autoSyncSecrets(functionsDir, projectId, config) {
|
|
|
16949
17165
|
let failCount = 0;
|
|
16950
17166
|
for (const { key, value } of secrets) {
|
|
16951
17167
|
try {
|
|
16952
|
-
const result =
|
|
17168
|
+
const result = spawnSync3(
|
|
16953
17169
|
firebaseCmd,
|
|
16954
17170
|
["functions:secrets:set", key, "--project", projectId],
|
|
16955
17171
|
{
|
|
@@ -17136,7 +17352,7 @@ async function deployRules(appDir, serviceAccountPath, projectId, config, option
|
|
|
17136
17352
|
|
|
17137
17353
|
// packages/tooling/src/apps/deploy-utils.ts
|
|
17138
17354
|
init_utils();
|
|
17139
|
-
import { spawnSync as
|
|
17355
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
17140
17356
|
init_pathResolver();
|
|
17141
17357
|
init_typed_file_operations();
|
|
17142
17358
|
init_error_handling();
|
|
@@ -17148,8 +17364,8 @@ function detectAvailableApps() {
|
|
|
17148
17364
|
}
|
|
17149
17365
|
return readdirSync2(appsDir).filter((item) => {
|
|
17150
17366
|
const itemPath = joinPath(appsDir, item);
|
|
17151
|
-
const
|
|
17152
|
-
return
|
|
17367
|
+
const stat2 = statSync2(itemPath);
|
|
17368
|
+
return stat2?.isDirectory() === true;
|
|
17153
17369
|
}).filter((app) => {
|
|
17154
17370
|
const appDir = joinPath(appsDir, app);
|
|
17155
17371
|
const firebaseJsonPath = joinPath(appDir, "firebase.json");
|
|
@@ -17324,7 +17540,7 @@ How to fix:
|
|
|
17324
17540
|
if (shouldOpen) {
|
|
17325
17541
|
try {
|
|
17326
17542
|
const openCommand = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
17327
|
-
|
|
17543
|
+
spawnSync4(openCommand, [consoleUrl], { shell: true });
|
|
17328
17544
|
log.success("Opening Firebase Console...");
|
|
17329
17545
|
} catch {
|
|
17330
17546
|
log.warn("Could not open browser. Please open the URL manually.");
|
|
@@ -17755,12 +17971,6 @@ async function main2(options = {}) {
|
|
|
17755
17971
|
...serviceAccountPath ? [`Service Account: ${serviceAccountPath}`] : []
|
|
17756
17972
|
].join("\n");
|
|
17757
17973
|
Me(configNote, "Deployment Configuration");
|
|
17758
|
-
if (shouldDeployVercelFrontend) {
|
|
17759
|
-
requireCLI(
|
|
17760
|
-
CLI_TOOLS.VERCEL,
|
|
17761
|
-
"Vercel CLI is required to deploy the frontend.\nInstall: bun install -g vercel"
|
|
17762
|
-
);
|
|
17763
|
-
}
|
|
17764
17974
|
if (shouldDeployFirebaseFrontend && serviceAccountPath && config.project) {
|
|
17765
17975
|
await deployFrontend(appDir, serviceAccountPath, config.project, config);
|
|
17766
17976
|
}
|