@donotdev/cli 0.0.13 → 0.0.15
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/dependencies-matrix.json +357 -89
- package/dist/bin/commands/agent-setup.d.ts +6 -0
- package/dist/bin/commands/agent-setup.d.ts.map +1 -0
- package/dist/bin/commands/agent-setup.js +629 -0
- package/dist/bin/commands/agent-setup.js.map +1 -0
- package/dist/bin/commands/build.js +131 -50
- package/dist/bin/commands/bump.js +137 -49
- package/dist/bin/commands/cacheout.js +50 -21
- package/dist/bin/commands/create-app.js +270 -261
- package/dist/bin/commands/create-project.js +418 -197
- package/dist/bin/commands/deploy.js +1752 -712
- package/dist/bin/commands/dev.js +151 -35
- package/dist/bin/commands/emu.js +228 -70
- package/dist/bin/commands/format.js +50 -21
- package/dist/bin/commands/lint.js +50 -21
- package/dist/bin/commands/preview.js +155 -35
- package/dist/bin/commands/supabase-setup.d.ts +6 -0
- package/dist/bin/commands/supabase-setup.d.ts.map +1 -0
- package/dist/bin/commands/supabase-setup.js +7 -0
- package/dist/bin/commands/supabase-setup.js.map +1 -0
- package/dist/bin/commands/sync-secrets.js +224 -46
- package/dist/bin/commands/type-check.d.ts +14 -0
- package/dist/bin/commands/type-check.d.ts.map +1 -0
- package/dist/bin/commands/type-check.js +314 -0
- package/dist/bin/commands/type-check.js.map +1 -0
- package/dist/bin/commands/wai.js +7399 -11
- package/dist/bin/dndev.js +27 -2
- package/dist/bin/donotdev.js +27 -2
- package/dist/index.js +3960 -2996
- package/package.json +2 -2
- package/templates/app-demo/src/App.tsx.example +1 -0
- package/templates/app-demo/src/pages/FullPage.tsx.example +2 -2
- package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +2 -2
- package/templates/app-demo/src/themes.css.example +5 -12
- package/templates/app-expo/.env.example +64 -0
- package/templates/app-expo/.expo/README.md.example +5 -0
- package/templates/app-expo/.gitignore.example +36 -0
- package/templates/app-expo/README.md.example +58 -0
- package/templates/app-expo/app/.gitkeep +2 -0
- package/templates/app-expo/app/_layout.tsx.example +41 -0
- package/templates/app-expo/app/form.tsx.example +52 -0
- package/templates/app-expo/app/index.tsx.example +89 -0
- package/templates/app-expo/app/list.tsx.example +32 -0
- package/templates/app-expo/app/profile.tsx.example +76 -0
- package/templates/app-expo/app/signin.tsx.example +53 -0
- package/templates/app-expo/app.json.example +39 -0
- package/templates/app-expo/babel.config.js.example +10 -0
- package/templates/app-expo/eas.json.example +20 -0
- package/templates/app-expo/expo-env.d.ts.example +4 -0
- package/templates/app-expo/metro.config.js.example +20 -0
- package/templates/app-expo/service-account-key.json.example +12 -0
- package/templates/app-expo/tsconfig.json.example +19 -0
- package/templates/app-next/.env.example +4 -33
- package/templates/app-next/src/app/ClientLayout.tsx.example +2 -0
- package/templates/app-next/src/app/layout.tsx.example +7 -6
- package/templates/app-next/src/globals.css.example +2 -11
- package/templates/app-next/src/pages/HomePage.tsx.example +1 -1
- package/templates/app-next/src/themes.css.example +10 -13
- package/templates/app-vite/.env.example +3 -32
- package/templates/app-vite/index.html.example +2 -24
- package/templates/app-vite/src/App.tsx.example +2 -0
- package/templates/app-vite/src/globals.css.example +2 -12
- package/templates/app-vite/src/pages/FormPageExample.tsx.example +1 -2
- package/templates/app-vite/src/pages/HomePage.tsx.example +1 -1
- package/templates/app-vite/src/themes.css.example +109 -79
- package/templates/app-vite/vercel.json.example +11 -0
- package/templates/functions-firebase/build.mjs.example +2 -72
- package/templates/functions-firebase/functions-firebase/.env.example.example +23 -25
- package/templates/functions-firebase/functions-firebase/build.mjs.example +2 -72
- package/templates/functions-firebase/functions-firebase/tsconfig.json.example +1 -1
- package/templates/functions-supabase/supabase/functions/cancel-subscription/index.ts.example +7 -0
- package/templates/functions-supabase/supabase/functions/change-plan/index.ts.example +11 -0
- package/templates/functions-supabase/supabase/functions/create-checkout-session/index.ts.example +11 -0
- package/templates/functions-supabase/supabase/functions/create-customer-portal/index.ts.example +7 -0
- package/templates/functions-supabase/supabase/functions/crud/index.ts.example +16 -0
- package/templates/functions-supabase/supabase/functions/delete-account/index.ts.example +7 -0
- package/templates/functions-supabase/supabase/functions/get-custom-claims/index.ts.example +7 -0
- package/templates/functions-supabase/supabase/functions/get-user-auth-status/index.ts.example +7 -0
- package/templates/functions-supabase/supabase/functions/refresh-subscription-status/index.ts.example +7 -0
- package/templates/functions-supabase/supabase/functions/remove-custom-claims/index.ts.example +7 -0
- package/templates/functions-supabase/supabase/functions/set-custom-claims/index.ts.example +7 -0
- package/templates/functions-supabase/supabase/migrations/20250101000000_idempotency.sql +24 -0
- package/templates/functions-supabase/supabase/migrations/20250101000001_rate_limits.sql +22 -0
- package/templates/functions-supabase/supabase/migrations/20250101000002_cleanup_jobs.sql +28 -0
- package/templates/functions-supabase/supabase/migrations/20250101000003_operation_metrics.sql +28 -0
- package/templates/functions-vercel/functions-vercel/tsconfig.json.example +1 -1
- package/templates/functions-vercel/functions-vercel/vercel.json.example +1 -1
- package/templates/functions-vercel/vercel.json.example +1 -1
- package/templates/github/github/workflows/firebase-deploy.yml.example +1 -1
- package/templates/github/workflows/firebase-deploy.yml.example +1 -1
- package/templates/overlay-firebase/env.fragment.example +34 -0
- package/templates/overlay-firebase/env.fragment.expo.example +34 -0
- package/templates/overlay-firebase/env.fragment.nextjs.example +34 -0
- package/templates/overlay-firebase/src/config/providers.expo.ts.example +49 -0
- package/templates/overlay-firebase/src/config/providers.ts.example +23 -0
- package/templates/overlay-supabase/env.fragment.example +7 -0
- package/templates/overlay-supabase/env.fragment.expo.example +7 -0
- package/templates/overlay-supabase/env.fragment.nextjs.example +7 -0
- package/templates/overlay-supabase/src/config/providers.expo.ts.example +35 -0
- package/templates/overlay-supabase/src/config/providers.ts.example +33 -0
- package/templates/overlay-supabase/vercel.headers.example +23 -0
- package/templates/overlay-supabase/vercel.json.example +22 -0
- package/templates/overlay-vercel/env.fragment.example +34 -0
- package/templates/overlay-vercel/env.fragment.nextjs.example +34 -0
- package/templates/overlay-vercel/src/config/providers.ts.example +24 -0
- package/templates/root-consumer/.claude/agents/architect.md.example +2 -310
- package/templates/root-consumer/.claude/agents/builder.md.example +2 -326
- package/templates/root-consumer/.claude/agents/coder.md.example +2 -83
- package/templates/root-consumer/.claude/agents/extractor.md.example +2 -231
- package/templates/root-consumer/.claude/agents/polisher.md.example +2 -132
- package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +2 -81
- package/templates/root-consumer/.claude/commands/brainstorm.md.example +1 -1
- package/templates/root-consumer/.claude/commands/build.md.example +1 -1
- package/templates/root-consumer/.claude/commands/design.md.example +1 -1
- package/templates/root-consumer/.claude/commands/grill.md.example +30 -0
- package/templates/root-consumer/.claude/commands/polish.md.example +1 -1
- package/templates/root-consumer/.claude/commands/techdebt.md.example +28 -0
- package/templates/root-consumer/.clinerules.example +1 -0
- package/templates/root-consumer/.cursor/rules/no-docs.mdc.example +15 -0
- package/templates/root-consumer/.cursorrules.example +1 -0
- package/templates/root-consumer/.dndev/args.json.example +6 -0
- package/templates/root-consumer/.gemini/settings.json.example +2 -2
- package/templates/root-consumer/.github/copilot-instructions.md.example +1 -0
- package/templates/root-consumer/.windsurfrules.example +1 -0
- package/templates/root-consumer/AI.md.example +25 -108
- package/templates/root-consumer/CLAUDE.md.example +1 -128
- package/templates/root-consumer/CONVENTIONS.md.example +1 -0
- package/templates/root-consumer/GEMINI.md.example +1 -0
- package/templates/root-consumer/firebase.json.example +1 -1
- package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +54 -0
- package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +0 -18
- package/templates/root-consumer/guides/dndev/COMPONENTS_UI.md.example +1 -1
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +99 -30
- package/templates/root-consumer/guides/dndev/GOTCHAS.md.example +186 -0
- package/templates/root-consumer/guides/dndev/INDEX.md.example +4 -1
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +143 -12
- package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +9 -3
- package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +12 -7
- package/templates/root-consumer/guides/dndev/SETUP_SOC2.md.example +234 -0
- package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +124 -0
- package/templates/root-consumer/guides/dndev/SETUP_THEMES.md.example +6 -2
- package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +176 -0
- package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +5 -9
- package/templates/root-consumer/guides/dndev/essences_reference.css.example +174 -0
- package/templates/root-consumer/guides/wai-way/agents/builder.md.example +10 -0
- package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +25 -5
- package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +13 -2
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +2 -2
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +47 -11
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +15 -4
- package/templates/root-consumer/guides/wai-way/spec_template.md.example +7 -6
- package/templates/app-payload/.env.example +0 -28
- package/templates/app-payload/README.md.example +0 -233
- package/templates/app-payload/collections/Company.ts.example +0 -125
- package/templates/app-payload/collections/Hero.ts.example +0 -62
- package/templates/app-payload/collections/Media.ts.example +0 -41
- package/templates/app-payload/collections/Products.ts.example +0 -115
- package/templates/app-payload/collections/Services.ts.example +0 -104
- package/templates/app-payload/collections/Testimonials.ts.example +0 -92
- package/templates/app-payload/collections/Users.ts.example +0 -35
- package/templates/app-payload/src/server.ts.example +0 -79
- package/templates/app-payload/tsconfig.json.example +0 -24
|
@@ -16,6 +16,10 @@ var __esm = (fn, res) => function __init() {
|
|
|
16
16
|
var __commonJS = (cb, mod) => function __require2() {
|
|
17
17
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
18
18
|
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
22
|
+
};
|
|
19
23
|
var __copyProps = (to, from, except, desc) => {
|
|
20
24
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
25
|
for (let key of __getOwnPropNames(from))
|
|
@@ -2068,7 +2072,7 @@ var require_parse = __commonJS({
|
|
|
2068
2072
|
CHAR_NO_BREAK_SPACE,
|
|
2069
2073
|
CHAR_ZERO_WIDTH_NOBREAK_SPACE
|
|
2070
2074
|
} = require_constants();
|
|
2071
|
-
var
|
|
2075
|
+
var parse2 = (input, options = {}) => {
|
|
2072
2076
|
if (typeof input !== "string") {
|
|
2073
2077
|
throw new TypeError("Expected a string");
|
|
2074
2078
|
}
|
|
@@ -2268,7 +2272,7 @@ var require_parse = __commonJS({
|
|
|
2268
2272
|
push({ type: "eos" });
|
|
2269
2273
|
return ast;
|
|
2270
2274
|
};
|
|
2271
|
-
module.exports =
|
|
2275
|
+
module.exports = parse2;
|
|
2272
2276
|
}
|
|
2273
2277
|
});
|
|
2274
2278
|
|
|
@@ -2280,7 +2284,7 @@ var require_braces = __commonJS({
|
|
|
2280
2284
|
var stringify2 = require_stringify();
|
|
2281
2285
|
var compile = require_compile();
|
|
2282
2286
|
var expand = require_expand();
|
|
2283
|
-
var
|
|
2287
|
+
var parse2 = require_parse();
|
|
2284
2288
|
var braces = (input, options = {}) => {
|
|
2285
2289
|
let output = [];
|
|
2286
2290
|
if (Array.isArray(input)) {
|
|
@@ -2300,7 +2304,7 @@ var require_braces = __commonJS({
|
|
|
2300
2304
|
}
|
|
2301
2305
|
return output;
|
|
2302
2306
|
};
|
|
2303
|
-
braces.parse = (input, options = {}) =>
|
|
2307
|
+
braces.parse = (input, options = {}) => parse2(input, options);
|
|
2304
2308
|
braces.stringify = (input, options = {}) => {
|
|
2305
2309
|
if (typeof input === "string") {
|
|
2306
2310
|
return stringify2(braces.parse(input, options), options);
|
|
@@ -2957,7 +2961,7 @@ var require_parse2 = __commonJS({
|
|
|
2957
2961
|
var syntaxError = (type, char) => {
|
|
2958
2962
|
return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
|
|
2959
2963
|
};
|
|
2960
|
-
var
|
|
2964
|
+
var parse2 = (input, options) => {
|
|
2961
2965
|
if (typeof input !== "string") {
|
|
2962
2966
|
throw new TypeError("Expected a string");
|
|
2963
2967
|
}
|
|
@@ -3106,7 +3110,7 @@ var require_parse2 = __commonJS({
|
|
|
3106
3110
|
output = token.close = `)$))${extglobStar}`;
|
|
3107
3111
|
}
|
|
3108
3112
|
if (token.inner.includes("*") && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
|
|
3109
|
-
const expression =
|
|
3113
|
+
const expression = parse2(rest, { ...options, fastpaths: false }).output;
|
|
3110
3114
|
output = token.close = `)${expression})${extglobStar})`;
|
|
3111
3115
|
}
|
|
3112
3116
|
if (token.prev.type === "bos") {
|
|
@@ -3631,7 +3635,7 @@ var require_parse2 = __commonJS({
|
|
|
3631
3635
|
}
|
|
3632
3636
|
return state;
|
|
3633
3637
|
};
|
|
3634
|
-
|
|
3638
|
+
parse2.fastpaths = (input, options) => {
|
|
3635
3639
|
const opts = { ...options };
|
|
3636
3640
|
const max = typeof opts.maxLength === "number" ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
|
|
3637
3641
|
const len = input.length;
|
|
@@ -3697,7 +3701,7 @@ var require_parse2 = __commonJS({
|
|
|
3697
3701
|
}
|
|
3698
3702
|
return source;
|
|
3699
3703
|
};
|
|
3700
|
-
module.exports =
|
|
3704
|
+
module.exports = parse2;
|
|
3701
3705
|
}
|
|
3702
3706
|
});
|
|
3703
3707
|
|
|
@@ -3708,7 +3712,7 @@ var require_picomatch = __commonJS({
|
|
|
3708
3712
|
init_utils();
|
|
3709
3713
|
var path = __require("path");
|
|
3710
3714
|
var scan = require_scan();
|
|
3711
|
-
var
|
|
3715
|
+
var parse2 = require_parse2();
|
|
3712
3716
|
var utils = require_utils2();
|
|
3713
3717
|
var constants2 = require_constants2();
|
|
3714
3718
|
var isObject = (val) => val && typeof val === "object" && !Array.isArray(val);
|
|
@@ -3796,7 +3800,7 @@ var require_picomatch = __commonJS({
|
|
|
3796
3800
|
picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
|
|
3797
3801
|
picomatch.parse = (pattern, options) => {
|
|
3798
3802
|
if (Array.isArray(pattern)) return pattern.map((p2) => picomatch.parse(p2, options));
|
|
3799
|
-
return
|
|
3803
|
+
return parse2(pattern, { ...options, fastpaths: false });
|
|
3800
3804
|
};
|
|
3801
3805
|
picomatch.scan = (input, options) => scan(input, options);
|
|
3802
3806
|
picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
|
|
@@ -3822,10 +3826,10 @@ var require_picomatch = __commonJS({
|
|
|
3822
3826
|
}
|
|
3823
3827
|
let parsed = { negated: false, fastpaths: true };
|
|
3824
3828
|
if (options.fastpaths !== false && (input[0] === "." || input[0] === "*")) {
|
|
3825
|
-
parsed.output =
|
|
3829
|
+
parsed.output = parse2.fastpaths(input, options);
|
|
3826
3830
|
}
|
|
3827
3831
|
if (!parsed.output) {
|
|
3828
|
-
parsed =
|
|
3832
|
+
parsed = parse2(input, options);
|
|
3829
3833
|
}
|
|
3830
3834
|
return picomatch.compileRe(parsed, options, returnOutput, returnState);
|
|
3831
3835
|
};
|
|
@@ -7687,11 +7691,39 @@ var init_PathResolver = __esm({
|
|
|
7687
7691
|
});
|
|
7688
7692
|
|
|
7689
7693
|
// packages/tooling/src/utils/errors.ts
|
|
7690
|
-
var DoNotDevError;
|
|
7694
|
+
var DO_NOT_DEV_ERROR_CODES, DoNotDevError;
|
|
7691
7695
|
var init_errors = __esm({
|
|
7692
7696
|
"packages/tooling/src/utils/errors.ts"() {
|
|
7693
7697
|
"use strict";
|
|
7694
7698
|
init_utils();
|
|
7699
|
+
DO_NOT_DEV_ERROR_CODES = {
|
|
7700
|
+
CONFIGURATION_ERROR: "configuration-error",
|
|
7701
|
+
CONFIG_NOT_FOUND: "config-not-found",
|
|
7702
|
+
CONFIG_INVALID: "config-invalid",
|
|
7703
|
+
PATH_RESOLUTION_ERROR: "path-resolution-error",
|
|
7704
|
+
FILE_OPERATION_ERROR: "file-operation-error",
|
|
7705
|
+
FILE_NOT_FOUND: "file-not-found",
|
|
7706
|
+
PERMISSION_DENIED: "permission-denied",
|
|
7707
|
+
GENERATION_ERROR: "generation-error",
|
|
7708
|
+
TEMPLATE_ERROR: "template-error",
|
|
7709
|
+
TEMPLATE_NOT_FOUND: "template-not-found",
|
|
7710
|
+
CLI_EXECUTION_ERROR: "cli-execution-error",
|
|
7711
|
+
COMMAND_NOT_FOUND: "command-not-found",
|
|
7712
|
+
COMMAND_FAILED: "command-failed",
|
|
7713
|
+
VALIDATION_ERROR: "validation-error",
|
|
7714
|
+
SCHEMA_ERROR: "schema-error",
|
|
7715
|
+
DEPENDENCY_ERROR: "dependency-error",
|
|
7716
|
+
DEPENDENCY_NOT_FOUND: "dependency-not-found",
|
|
7717
|
+
DEPENDENCY_VERSION_ERROR: "dependency-version-error",
|
|
7718
|
+
INVALID_ARGUMENT: "invalid-argument",
|
|
7719
|
+
MISSING_ARGUMENT: "missing-argument",
|
|
7720
|
+
MISSING_PROJECT_ID: "missing-project-id",
|
|
7721
|
+
FIREBASE_CLI_ERROR: "firebase-cli-error",
|
|
7722
|
+
DEPLOYMENT_FAILED: "deployment-failed",
|
|
7723
|
+
OPERATION_CANCELLED: "operation-cancelled",
|
|
7724
|
+
TIMEOUT_ERROR: "timeout-error",
|
|
7725
|
+
UNKNOWN_ERROR: "unknown-error"
|
|
7726
|
+
};
|
|
7695
7727
|
DoNotDevError = class _DoNotDevError extends Error {
|
|
7696
7728
|
/** The error code categorizing this error */
|
|
7697
7729
|
code;
|
|
@@ -7711,7 +7743,7 @@ var init_errors = __esm({
|
|
|
7711
7743
|
* @param {Record<string, any>} [options.context] - Additional context data
|
|
7712
7744
|
* @param {boolean} [options.displayable=true] - Whether this error should be displayed to the user
|
|
7713
7745
|
*/
|
|
7714
|
-
constructor(message, code =
|
|
7746
|
+
constructor(message, code = DO_NOT_DEV_ERROR_CODES.UNKNOWN_ERROR, options) {
|
|
7715
7747
|
super(message);
|
|
7716
7748
|
this.name = "DoNotDevError";
|
|
7717
7749
|
this.code = code;
|
|
@@ -7742,7 +7774,7 @@ var init_errors = __esm({
|
|
|
7742
7774
|
* @param {boolean} [options.displayable=true] - Whether this error should be displayed to the user
|
|
7743
7775
|
* @returns {DoNotDevError} New DoNotDev error wrapping the original
|
|
7744
7776
|
*/
|
|
7745
|
-
static from(error2, context, code =
|
|
7777
|
+
static from(error2, context, code = DO_NOT_DEV_ERROR_CODES.UNKNOWN_ERROR, options) {
|
|
7746
7778
|
if (!(error2 instanceof Error)) {
|
|
7747
7779
|
return new _DoNotDevError(
|
|
7748
7780
|
`Unknown error: ${String(error2)}`,
|
|
@@ -7779,21 +7811,21 @@ var init_errors = __esm({
|
|
|
7779
7811
|
}
|
|
7780
7812
|
const message = error2.message.toLowerCase();
|
|
7781
7813
|
if (error2.name === "ValidationError" || message.includes("validation")) {
|
|
7782
|
-
return
|
|
7814
|
+
return DO_NOT_DEV_ERROR_CODES.VALIDATION_ERROR;
|
|
7783
7815
|
}
|
|
7784
7816
|
if (message.includes("not found") || message.includes("no such file")) {
|
|
7785
|
-
return
|
|
7817
|
+
return DO_NOT_DEV_ERROR_CODES.FILE_NOT_FOUND;
|
|
7786
7818
|
}
|
|
7787
7819
|
if (message.includes("permission") || message.includes("access denied")) {
|
|
7788
|
-
return
|
|
7820
|
+
return DO_NOT_DEV_ERROR_CODES.PERMISSION_DENIED;
|
|
7789
7821
|
}
|
|
7790
7822
|
if (message.includes("timeout") || message.includes("timed out")) {
|
|
7791
|
-
return
|
|
7823
|
+
return DO_NOT_DEV_ERROR_CODES.TIMEOUT_ERROR;
|
|
7792
7824
|
}
|
|
7793
7825
|
if (message.includes("dependency") || message.includes("module not found")) {
|
|
7794
|
-
return
|
|
7826
|
+
return DO_NOT_DEV_ERROR_CODES.DEPENDENCY_ERROR;
|
|
7795
7827
|
}
|
|
7796
|
-
return
|
|
7828
|
+
return DO_NOT_DEV_ERROR_CODES.UNKNOWN_ERROR;
|
|
7797
7829
|
}
|
|
7798
7830
|
};
|
|
7799
7831
|
}
|
|
@@ -7808,13 +7840,14 @@ import {
|
|
|
7808
7840
|
extname as extname2,
|
|
7809
7841
|
relative as relative2,
|
|
7810
7842
|
resolve as resolve2,
|
|
7843
|
+
parse,
|
|
7811
7844
|
isAbsolute as pathIsAbsolute
|
|
7812
7845
|
} from "node:path";
|
|
7813
7846
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7814
7847
|
function readdirSync2(dirPath, options) {
|
|
7815
7848
|
return pathResolverInstance.readdirSync(dirPath, options);
|
|
7816
7849
|
}
|
|
7817
|
-
var pathResolverInstance, resolvePackage, normalizePath, pathExists, readSync, writeSync, removeSync, statSync2, ensureDirSync, joinPath;
|
|
7850
|
+
var pathResolverInstance, resolvePackage, normalizePath, pathExists, readSync, write, writeSync, remove, removeSync, statSync2, ensureDir, ensureDirSync, getRelativePathBetween, getDirname, joinPath;
|
|
7818
7851
|
var init_pathResolver = __esm({
|
|
7819
7852
|
"packages/tooling/src/utils/pathResolver.ts"() {
|
|
7820
7853
|
"use strict";
|
|
@@ -7827,16 +7860,111 @@ var init_pathResolver = __esm({
|
|
|
7827
7860
|
};
|
|
7828
7861
|
pathExists = (filePath, silent = false) => pathResolverInstance.pathExists(filePath, silent);
|
|
7829
7862
|
readSync = (filePath, options) => pathResolverInstance.readSync(filePath, options);
|
|
7863
|
+
write = async (filePath, content, options) => pathResolverInstance.write(filePath, content, options);
|
|
7830
7864
|
writeSync = (filePath, content, options) => pathResolverInstance.writeSync(filePath, content, options);
|
|
7865
|
+
remove = async (path) => pathResolverInstance.remove(path);
|
|
7831
7866
|
removeSync = (path) => pathResolverInstance.removeSync(path);
|
|
7832
7867
|
statSync2 = (filePath) => pathResolverInstance.statSync(filePath);
|
|
7868
|
+
ensureDir = async (dirPath) => pathResolverInstance.ensureDir(dirPath);
|
|
7833
7869
|
ensureDirSync = (dirPath) => pathResolverInstance.ensureDirSync(dirPath);
|
|
7870
|
+
getRelativePathBetween = (from, to) => {
|
|
7871
|
+
return normalizePath(relative2(from, to));
|
|
7872
|
+
};
|
|
7873
|
+
getDirname = (filePath) => {
|
|
7874
|
+
return normalizePath(dirname2(filePath));
|
|
7875
|
+
};
|
|
7834
7876
|
joinPath = (...pathSegments) => {
|
|
7835
7877
|
return normalizePath(...pathSegments);
|
|
7836
7878
|
};
|
|
7837
7879
|
}
|
|
7838
7880
|
});
|
|
7839
7881
|
|
|
7882
|
+
// packages/tooling/src/utils/typed-file-operations.ts
|
|
7883
|
+
function readFirebaseJson(filePath) {
|
|
7884
|
+
if (!pathExists(filePath)) {
|
|
7885
|
+
throw new DoNotDevError(
|
|
7886
|
+
`firebase.json not found: ${filePath}`,
|
|
7887
|
+
DO_NOT_DEV_ERROR_CODES.FILE_NOT_FOUND,
|
|
7888
|
+
{ context: { filePath } }
|
|
7889
|
+
);
|
|
7890
|
+
}
|
|
7891
|
+
const content = readSync(filePath, { format: "json" });
|
|
7892
|
+
if (!content || typeof content !== "object") {
|
|
7893
|
+
throw new DoNotDevError(
|
|
7894
|
+
`Invalid firebase.json: ${filePath}`,
|
|
7895
|
+
DO_NOT_DEV_ERROR_CODES.CONFIG_INVALID,
|
|
7896
|
+
{ context: { filePath } }
|
|
7897
|
+
);
|
|
7898
|
+
}
|
|
7899
|
+
return content;
|
|
7900
|
+
}
|
|
7901
|
+
function readFirebaserc(filePath) {
|
|
7902
|
+
if (!pathExists(filePath)) {
|
|
7903
|
+
return { projects: {} };
|
|
7904
|
+
}
|
|
7905
|
+
const content = readSync(filePath, { format: "json" });
|
|
7906
|
+
if (!content || typeof content !== "object") {
|
|
7907
|
+
throw new DoNotDevError(
|
|
7908
|
+
`Invalid .firebaserc: ${filePath}`,
|
|
7909
|
+
DO_NOT_DEV_ERROR_CODES.CONFIG_INVALID,
|
|
7910
|
+
{ context: { filePath } }
|
|
7911
|
+
);
|
|
7912
|
+
}
|
|
7913
|
+
return content;
|
|
7914
|
+
}
|
|
7915
|
+
function readPackageJson(filePath) {
|
|
7916
|
+
if (!pathExists(filePath)) {
|
|
7917
|
+
throw new DoNotDevError(
|
|
7918
|
+
`package.json not found: ${filePath}`,
|
|
7919
|
+
DO_NOT_DEV_ERROR_CODES.FILE_NOT_FOUND,
|
|
7920
|
+
{ context: { filePath } }
|
|
7921
|
+
);
|
|
7922
|
+
}
|
|
7923
|
+
const content = readSync(filePath, { format: "json" });
|
|
7924
|
+
if (!content || typeof content !== "object" || !("name" in content)) {
|
|
7925
|
+
throw new DoNotDevError(
|
|
7926
|
+
`Invalid package.json: ${filePath}`,
|
|
7927
|
+
DO_NOT_DEV_ERROR_CODES.CONFIG_INVALID,
|
|
7928
|
+
{ context: { filePath } }
|
|
7929
|
+
);
|
|
7930
|
+
}
|
|
7931
|
+
return content;
|
|
7932
|
+
}
|
|
7933
|
+
function readServiceAccountKey(filePath) {
|
|
7934
|
+
if (!pathExists(filePath)) {
|
|
7935
|
+
throw new DoNotDevError(
|
|
7936
|
+
`Service account key not found: ${filePath}`,
|
|
7937
|
+
DO_NOT_DEV_ERROR_CODES.FILE_NOT_FOUND,
|
|
7938
|
+
{ context: { filePath } }
|
|
7939
|
+
);
|
|
7940
|
+
}
|
|
7941
|
+
const content = readSync(filePath, { format: "json" });
|
|
7942
|
+
if (!content || typeof content !== "object") {
|
|
7943
|
+
throw new DoNotDevError(
|
|
7944
|
+
`Invalid service account key: ${filePath}`,
|
|
7945
|
+
DO_NOT_DEV_ERROR_CODES.CONFIG_INVALID,
|
|
7946
|
+
{ context: { filePath } }
|
|
7947
|
+
);
|
|
7948
|
+
}
|
|
7949
|
+
const key = content;
|
|
7950
|
+
if (!key.project_id || !key.private_key || !key.client_email) {
|
|
7951
|
+
throw new DoNotDevError(
|
|
7952
|
+
`Invalid service account key: missing required fields`,
|
|
7953
|
+
DO_NOT_DEV_ERROR_CODES.CONFIG_INVALID,
|
|
7954
|
+
{ context: { filePath, missingFields: ["project_id", "private_key", "client_email"].filter((f) => !key[f]) } }
|
|
7955
|
+
);
|
|
7956
|
+
}
|
|
7957
|
+
return content;
|
|
7958
|
+
}
|
|
7959
|
+
var init_typed_file_operations = __esm({
|
|
7960
|
+
"packages/tooling/src/utils/typed-file-operations.ts"() {
|
|
7961
|
+
"use strict";
|
|
7962
|
+
init_utils();
|
|
7963
|
+
init_pathResolver();
|
|
7964
|
+
init_errors();
|
|
7965
|
+
}
|
|
7966
|
+
});
|
|
7967
|
+
|
|
7840
7968
|
// packages/tooling/src/bundler/utils.ts
|
|
7841
7969
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
7842
7970
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
@@ -7864,131 +7992,468 @@ var init_utils = __esm({
|
|
|
7864
7992
|
}
|
|
7865
7993
|
});
|
|
7866
7994
|
|
|
7867
|
-
//
|
|
7868
|
-
|
|
7869
|
-
|
|
7995
|
+
// packages/tooling/src/utils/cli-input.ts
|
|
7996
|
+
async function askForInput(message, defaultValue = "") {
|
|
7997
|
+
const result = await he({
|
|
7998
|
+
message,
|
|
7999
|
+
placeholder: defaultValue || void 0,
|
|
8000
|
+
defaultValue: defaultValue || void 0
|
|
8001
|
+
});
|
|
8002
|
+
if (pD(result)) {
|
|
8003
|
+
xe("Operation cancelled.");
|
|
8004
|
+
process.exit(0);
|
|
8005
|
+
}
|
|
8006
|
+
return result;
|
|
8007
|
+
}
|
|
8008
|
+
async function askForConfirmation(message, defaultValue = false) {
|
|
8009
|
+
const result = await ye({
|
|
8010
|
+
message,
|
|
8011
|
+
initialValue: defaultValue
|
|
8012
|
+
});
|
|
8013
|
+
if (pD(result)) {
|
|
8014
|
+
xe("Operation cancelled.");
|
|
8015
|
+
process.exit(0);
|
|
8016
|
+
}
|
|
8017
|
+
return result;
|
|
8018
|
+
}
|
|
8019
|
+
async function askForSelection(message, choices, defaultValue = 0) {
|
|
8020
|
+
const options = choices.map((choice) => ({
|
|
8021
|
+
value: choice.value,
|
|
8022
|
+
label: choice.title,
|
|
8023
|
+
hint: choice.hint
|
|
8024
|
+
}));
|
|
8025
|
+
const result = await ve({
|
|
8026
|
+
message,
|
|
8027
|
+
options,
|
|
8028
|
+
initialValue: choices[defaultValue]?.value
|
|
8029
|
+
});
|
|
8030
|
+
if (pD(result)) {
|
|
8031
|
+
xe("Operation cancelled.");
|
|
8032
|
+
process.exit(0);
|
|
8033
|
+
}
|
|
8034
|
+
return result;
|
|
8035
|
+
}
|
|
8036
|
+
var init_cli_input = __esm({
|
|
8037
|
+
"packages/tooling/src/utils/cli-input.ts"() {
|
|
7870
8038
|
"use strict";
|
|
7871
8039
|
init_utils();
|
|
7872
|
-
|
|
7873
|
-
var DOC = /* @__PURE__ */ Symbol.for("yaml.document");
|
|
7874
|
-
var MAP = /* @__PURE__ */ Symbol.for("yaml.map");
|
|
7875
|
-
var PAIR = /* @__PURE__ */ Symbol.for("yaml.pair");
|
|
7876
|
-
var SCALAR = /* @__PURE__ */ Symbol.for("yaml.scalar");
|
|
7877
|
-
var SEQ = /* @__PURE__ */ Symbol.for("yaml.seq");
|
|
7878
|
-
var NODE_TYPE = /* @__PURE__ */ Symbol.for("yaml.node.type");
|
|
7879
|
-
var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
|
7880
|
-
var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
|
7881
|
-
var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
|
7882
|
-
var isPair = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === PAIR;
|
|
7883
|
-
var isScalar = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SCALAR;
|
|
7884
|
-
var isSeq = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SEQ;
|
|
7885
|
-
function isCollection(node) {
|
|
7886
|
-
if (node && typeof node === "object")
|
|
7887
|
-
switch (node[NODE_TYPE]) {
|
|
7888
|
-
case MAP:
|
|
7889
|
-
case SEQ:
|
|
7890
|
-
return true;
|
|
7891
|
-
}
|
|
7892
|
-
return false;
|
|
7893
|
-
}
|
|
7894
|
-
function isNode(node) {
|
|
7895
|
-
if (node && typeof node === "object")
|
|
7896
|
-
switch (node[NODE_TYPE]) {
|
|
7897
|
-
case ALIAS:
|
|
7898
|
-
case MAP:
|
|
7899
|
-
case SCALAR:
|
|
7900
|
-
case SEQ:
|
|
7901
|
-
return true;
|
|
7902
|
-
}
|
|
7903
|
-
return false;
|
|
7904
|
-
}
|
|
7905
|
-
var hasAnchor = (node) => (isScalar(node) || isCollection(node)) && !!node.anchor;
|
|
7906
|
-
exports.ALIAS = ALIAS;
|
|
7907
|
-
exports.DOC = DOC;
|
|
7908
|
-
exports.MAP = MAP;
|
|
7909
|
-
exports.NODE_TYPE = NODE_TYPE;
|
|
7910
|
-
exports.PAIR = PAIR;
|
|
7911
|
-
exports.SCALAR = SCALAR;
|
|
7912
|
-
exports.SEQ = SEQ;
|
|
7913
|
-
exports.hasAnchor = hasAnchor;
|
|
7914
|
-
exports.isAlias = isAlias;
|
|
7915
|
-
exports.isCollection = isCollection;
|
|
7916
|
-
exports.isDocument = isDocument;
|
|
7917
|
-
exports.isMap = isMap;
|
|
7918
|
-
exports.isNode = isNode;
|
|
7919
|
-
exports.isPair = isPair;
|
|
7920
|
-
exports.isScalar = isScalar;
|
|
7921
|
-
exports.isSeq = isSeq;
|
|
8040
|
+
init_dist2();
|
|
7922
8041
|
}
|
|
7923
8042
|
});
|
|
7924
8043
|
|
|
7925
|
-
//
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
const
|
|
7936
|
-
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
node.items.splice(i, 1);
|
|
7963
|
-
i -= 1;
|
|
8044
|
+
// packages/tooling/src/utils/cli-tools.ts
|
|
8045
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
8046
|
+
function checkCLI(command, args = ["--version"], useCache = true) {
|
|
8047
|
+
const cacheKey = `${command}:${args.join(",")}`;
|
|
8048
|
+
if (useCache && cliCache.has(cacheKey)) {
|
|
8049
|
+
return cliCache.get(cacheKey);
|
|
8050
|
+
}
|
|
8051
|
+
try {
|
|
8052
|
+
let result;
|
|
8053
|
+
if (process.platform === "win32") {
|
|
8054
|
+
const username = process.env.USERNAME || process.env.USER || "";
|
|
8055
|
+
const programFiles = process.env.ProgramFiles || "C:\\Program Files";
|
|
8056
|
+
const commonPaths = [
|
|
8057
|
+
`${programFiles}\\nodejs\\${command}.ps1`,
|
|
8058
|
+
`${programFiles}\\nodejs\\${command}.cmd`,
|
|
8059
|
+
`${programFiles}\\nodejs\\${command}`,
|
|
8060
|
+
`C:\\Users\\${username}\\AppData\\Roaming\\npm\\${command}.ps1`,
|
|
8061
|
+
`C:\\Users\\${username}\\AppData\\Roaming\\npm\\${command}.cmd`,
|
|
8062
|
+
`C:\\Users\\${username}\\AppData\\Roaming\\npm\\${command}`,
|
|
8063
|
+
process.env.APPDATA ? `${process.env.APPDATA}\\npm\\${command}.ps1` : null,
|
|
8064
|
+
process.env.APPDATA ? `${process.env.APPDATA}\\npm\\${command}.cmd` : null,
|
|
8065
|
+
process.env.APPDATA ? `${process.env.APPDATA}\\npm\\${command}` : null
|
|
8066
|
+
].filter(Boolean);
|
|
8067
|
+
for (const fullPath of commonPaths) {
|
|
8068
|
+
try {
|
|
8069
|
+
const testResult = spawnSync2(
|
|
8070
|
+
"powershell.exe",
|
|
8071
|
+
[
|
|
8072
|
+
"-NoProfile",
|
|
8073
|
+
"-ExecutionPolicy",
|
|
8074
|
+
"Bypass",
|
|
8075
|
+
"-Command",
|
|
8076
|
+
`& '${fullPath}' ${args.join(" ")}`
|
|
8077
|
+
],
|
|
8078
|
+
{
|
|
8079
|
+
stdio: "pipe",
|
|
8080
|
+
shell: false
|
|
7964
8081
|
}
|
|
8082
|
+
);
|
|
8083
|
+
if (testResult.status === 0) {
|
|
8084
|
+
cliCache.set(cacheKey, true);
|
|
8085
|
+
return true;
|
|
7965
8086
|
}
|
|
7966
|
-
}
|
|
7967
|
-
|
|
7968
|
-
const ck = visit_("key", node.key, visitor, path);
|
|
7969
|
-
if (ck === BREAK)
|
|
7970
|
-
return BREAK;
|
|
7971
|
-
else if (ck === REMOVE)
|
|
7972
|
-
node.key = null;
|
|
7973
|
-
const cv = visit_("value", node.value, visitor, path);
|
|
7974
|
-
if (cv === BREAK)
|
|
7975
|
-
return BREAK;
|
|
7976
|
-
else if (cv === REMOVE)
|
|
7977
|
-
node.value = null;
|
|
8087
|
+
} catch {
|
|
8088
|
+
continue;
|
|
7978
8089
|
}
|
|
7979
8090
|
}
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
8091
|
+
result = spawnSync2(
|
|
8092
|
+
"powershell.exe",
|
|
8093
|
+
[
|
|
8094
|
+
"-NoProfile",
|
|
8095
|
+
"-ExecutionPolicy",
|
|
8096
|
+
"Bypass",
|
|
8097
|
+
"-Command",
|
|
8098
|
+
`${command} ${args.join(" ")}`
|
|
8099
|
+
],
|
|
8100
|
+
{
|
|
8101
|
+
stdio: "pipe",
|
|
8102
|
+
shell: false
|
|
8103
|
+
}
|
|
8104
|
+
);
|
|
8105
|
+
} else {
|
|
8106
|
+
result = spawnSync2(command, args, {
|
|
8107
|
+
stdio: "pipe",
|
|
8108
|
+
shell: true
|
|
8109
|
+
});
|
|
7990
8110
|
}
|
|
7991
|
-
|
|
8111
|
+
const isAvailable = result.status === 0;
|
|
8112
|
+
cliCache.set(cacheKey, isAvailable);
|
|
8113
|
+
return isAvailable;
|
|
8114
|
+
} catch (err) {
|
|
8115
|
+
cliCache.set(cacheKey, false);
|
|
8116
|
+
return false;
|
|
8117
|
+
}
|
|
8118
|
+
}
|
|
8119
|
+
function checkBun() {
|
|
8120
|
+
return checkCLI("bun");
|
|
8121
|
+
}
|
|
8122
|
+
function checkNpm() {
|
|
8123
|
+
return checkCLI("npm");
|
|
8124
|
+
}
|
|
8125
|
+
function checkYarn() {
|
|
8126
|
+
return checkCLI("yarn");
|
|
8127
|
+
}
|
|
8128
|
+
function checkFirebase() {
|
|
8129
|
+
return checkCLI("firebase");
|
|
8130
|
+
}
|
|
8131
|
+
function checkSentry() {
|
|
8132
|
+
return checkCLI("sentry-cli");
|
|
8133
|
+
}
|
|
8134
|
+
function checkGitHub() {
|
|
8135
|
+
return checkCLI("gh");
|
|
8136
|
+
}
|
|
8137
|
+
function checkGit() {
|
|
8138
|
+
return checkCLI("git");
|
|
8139
|
+
}
|
|
8140
|
+
function checkTsx() {
|
|
8141
|
+
return checkCLI("tsx");
|
|
8142
|
+
}
|
|
8143
|
+
function getCLIInstallInstructions(tool) {
|
|
8144
|
+
const platform = process.platform;
|
|
8145
|
+
const instructions = {
|
|
8146
|
+
[CLI_TOOLS.BUN]: {
|
|
8147
|
+
win32: [
|
|
8148
|
+
'powershell -c "irm bun.sh/install.ps1 | iex"',
|
|
8149
|
+
"Or download from: https://bun.sh"
|
|
8150
|
+
],
|
|
8151
|
+
darwin: [
|
|
8152
|
+
"curl -fsSL https://bun.sh/install | bash",
|
|
8153
|
+
"Or: brew install bun"
|
|
8154
|
+
],
|
|
8155
|
+
linux: [
|
|
8156
|
+
"curl -fsSL https://bun.sh/install | bash",
|
|
8157
|
+
"Or check your package manager (apt, dnf, pacman, etc.)"
|
|
8158
|
+
]
|
|
8159
|
+
},
|
|
8160
|
+
[CLI_TOOLS.NPM]: {
|
|
8161
|
+
win32: [
|
|
8162
|
+
"Install Node.js from: https://nodejs.org",
|
|
8163
|
+
"npm comes bundled with Node.js"
|
|
8164
|
+
],
|
|
8165
|
+
darwin: [
|
|
8166
|
+
"Install Node.js from: https://nodejs.org",
|
|
8167
|
+
"Or: brew install node",
|
|
8168
|
+
"npm comes bundled with Node.js"
|
|
8169
|
+
],
|
|
8170
|
+
linux: [
|
|
8171
|
+
"Install Node.js from: https://nodejs.org",
|
|
8172
|
+
"Or use your package manager: dnf install nodejs, apt install nodejs, etc.",
|
|
8173
|
+
"npm comes bundled with Node.js"
|
|
8174
|
+
]
|
|
8175
|
+
},
|
|
8176
|
+
[CLI_TOOLS.YARN]: {
|
|
8177
|
+
win32: ["npm install -g yarn", "Or: choco install yarn"],
|
|
8178
|
+
darwin: ["npm install -g yarn", "Or: brew install yarn"],
|
|
8179
|
+
linux: ["npm install -g yarn", "Or check your package manager"]
|
|
8180
|
+
},
|
|
8181
|
+
[CLI_TOOLS.FIREBASE]: {
|
|
8182
|
+
win32: [
|
|
8183
|
+
"npm install -g firebase-tools",
|
|
8184
|
+
"Or download standalone binary: https://firebase.google.com/docs/cli#windows-standalone-binary"
|
|
8185
|
+
],
|
|
8186
|
+
darwin: [
|
|
8187
|
+
"npm install -g firebase-tools",
|
|
8188
|
+
"Or: brew install firebase-cli"
|
|
8189
|
+
],
|
|
8190
|
+
linux: [
|
|
8191
|
+
"npm install -g firebase-tools",
|
|
8192
|
+
"Or check your package manager (dnf, apt, pacman, etc.)"
|
|
8193
|
+
]
|
|
8194
|
+
},
|
|
8195
|
+
[CLI_TOOLS.SUPABASE]: {
|
|
8196
|
+
win32: [
|
|
8197
|
+
"npm install -g supabase",
|
|
8198
|
+
"Or download from: https://github.com/supabase/cli/releases"
|
|
8199
|
+
],
|
|
8200
|
+
darwin: [
|
|
8201
|
+
"brew install supabase/tap/supabase",
|
|
8202
|
+
"Or: npm install -g supabase"
|
|
8203
|
+
],
|
|
8204
|
+
linux: [
|
|
8205
|
+
"npm install -g supabase",
|
|
8206
|
+
"Or see: https://supabase.com/docs/guides/cli"
|
|
8207
|
+
]
|
|
8208
|
+
},
|
|
8209
|
+
[CLI_TOOLS.VERCEL]: {
|
|
8210
|
+
win32: ["npm install -g vercel", "Or: npx vercel (no install)"],
|
|
8211
|
+
darwin: ["npm install -g vercel", "Or: brew install vercel", "Or: npx vercel"],
|
|
8212
|
+
linux: ["npm install -g vercel", "Or: npx vercel"]
|
|
8213
|
+
},
|
|
8214
|
+
[CLI_TOOLS.SENTRY_CLI]: {
|
|
8215
|
+
win32: [
|
|
8216
|
+
"npm install -g @sentry/cli",
|
|
8217
|
+
"Or download from: https://github.com/getsentry/sentry-cli/releases"
|
|
8218
|
+
],
|
|
8219
|
+
darwin: [
|
|
8220
|
+
"npm install -g @sentry/cli",
|
|
8221
|
+
"Or: brew install getsentry/tools/sentry-cli"
|
|
8222
|
+
],
|
|
8223
|
+
linux: [
|
|
8224
|
+
"npm install -g @sentry/cli",
|
|
8225
|
+
"Or: curl -sL https://sentry.io/get-cli/ | bash"
|
|
8226
|
+
]
|
|
8227
|
+
},
|
|
8228
|
+
[CLI_TOOLS.GH]: {
|
|
8229
|
+
win32: [
|
|
8230
|
+
"Download from: https://cli.github.com",
|
|
8231
|
+
"Or: winget install --id GitHub.cli",
|
|
8232
|
+
"Or: choco install gh"
|
|
8233
|
+
],
|
|
8234
|
+
darwin: ["brew install gh", "Or download from: https://cli.github.com"],
|
|
8235
|
+
linux: [
|
|
8236
|
+
"See: https://github.com/cli/cli/blob/trunk/docs/install_linux.md",
|
|
8237
|
+
"dnf install gh",
|
|
8238
|
+
"apt install gh",
|
|
8239
|
+
"Or download from: https://cli.github.com"
|
|
8240
|
+
]
|
|
8241
|
+
},
|
|
8242
|
+
[CLI_TOOLS.GIT]: {
|
|
8243
|
+
win32: [
|
|
8244
|
+
"Download from: https://git-scm.com/download/win",
|
|
8245
|
+
"Or: winget install --id Git.Git"
|
|
8246
|
+
],
|
|
8247
|
+
darwin: ["brew install git", "Or: xcode-select --install"],
|
|
8248
|
+
linux: [
|
|
8249
|
+
"Use your package manager: dnf install git, apt install git, etc."
|
|
8250
|
+
]
|
|
8251
|
+
},
|
|
8252
|
+
[CLI_TOOLS.TSX]: {
|
|
8253
|
+
win32: ["npm install -g tsx"],
|
|
8254
|
+
darwin: ["npm install -g tsx"],
|
|
8255
|
+
linux: ["npm install -g tsx"]
|
|
8256
|
+
}
|
|
8257
|
+
};
|
|
8258
|
+
const platformInstructions = instructions[tool]?.[platform] || instructions[tool]?.linux || [];
|
|
8259
|
+
return platformInstructions.join("\n \u2022 ");
|
|
8260
|
+
}
|
|
8261
|
+
function formatCLIMissingError(tool, additionalContext) {
|
|
8262
|
+
const toolName = tool === CLI_TOOLS.SENTRY_CLI ? "Sentry CLI" : tool.toUpperCase();
|
|
8263
|
+
M2.error(`${toolName} is not installed or not in PATH.`);
|
|
8264
|
+
const instructions = getCLIInstallInstructions(tool);
|
|
8265
|
+
if (instructions) {
|
|
8266
|
+
M2.warn("Install it with:");
|
|
8267
|
+
M2.message(` \u2022 ${instructions}`);
|
|
8268
|
+
}
|
|
8269
|
+
if (additionalContext) {
|
|
8270
|
+
M2.info(`
|
|
8271
|
+
${additionalContext}`);
|
|
8272
|
+
}
|
|
8273
|
+
const platform = process.platform;
|
|
8274
|
+
M2.info("\nIf already installed, ensure it's in your PATH:");
|
|
8275
|
+
if (platform === "win32") {
|
|
8276
|
+
M2.message(" \u2022 Check with: where " + tool);
|
|
8277
|
+
M2.message(
|
|
8278
|
+
" \u2022 Common location: C:\\Users\\<username>\\AppData\\Roaming\\npm\\"
|
|
8279
|
+
);
|
|
8280
|
+
} else {
|
|
8281
|
+
M2.message(" \u2022 Check with: which " + tool);
|
|
8282
|
+
M2.message(" \u2022 Common locations:");
|
|
8283
|
+
M2.message(" - ~/.nvm/versions/node/*/bin/" + tool);
|
|
8284
|
+
M2.message(" - ~/.bun/bin/" + tool);
|
|
8285
|
+
M2.message(" - /usr/local/bin/" + tool);
|
|
8286
|
+
M2.message(" - /usr/bin/" + tool);
|
|
8287
|
+
}
|
|
8288
|
+
}
|
|
8289
|
+
function requireCLI(tool, additionalContext) {
|
|
8290
|
+
const checkers = {
|
|
8291
|
+
[CLI_TOOLS.BUN]: checkBun,
|
|
8292
|
+
[CLI_TOOLS.NPM]: checkNpm,
|
|
8293
|
+
[CLI_TOOLS.YARN]: checkYarn,
|
|
8294
|
+
[CLI_TOOLS.FIREBASE]: checkFirebase,
|
|
8295
|
+
[CLI_TOOLS.SUPABASE]: () => checkCLI(CLI_TOOLS.SUPABASE),
|
|
8296
|
+
[CLI_TOOLS.VERCEL]: () => checkCLI(CLI_TOOLS.VERCEL),
|
|
8297
|
+
[CLI_TOOLS.SENTRY_CLI]: checkSentry,
|
|
8298
|
+
[CLI_TOOLS.GH]: checkGitHub,
|
|
8299
|
+
[CLI_TOOLS.GIT]: checkGit,
|
|
8300
|
+
[CLI_TOOLS.TSX]: checkTsx
|
|
8301
|
+
};
|
|
8302
|
+
cliCache.delete(`${tool}:--version`);
|
|
8303
|
+
const isAvailable = checkers[tool]?.();
|
|
8304
|
+
if (!isAvailable) {
|
|
8305
|
+
formatCLIMissingError(tool, additionalContext);
|
|
8306
|
+
process.exit(1);
|
|
8307
|
+
}
|
|
8308
|
+
return true;
|
|
8309
|
+
}
|
|
8310
|
+
var CLI_TOOLS, cliCache;
|
|
8311
|
+
var init_cli_tools = __esm({
|
|
8312
|
+
"packages/tooling/src/utils/cli-tools.ts"() {
|
|
8313
|
+
"use strict";
|
|
8314
|
+
init_utils();
|
|
8315
|
+
init_dist2();
|
|
8316
|
+
CLI_TOOLS = {
|
|
8317
|
+
BUN: "bun",
|
|
8318
|
+
NPM: "npm",
|
|
8319
|
+
YARN: "yarn",
|
|
8320
|
+
FIREBASE: "firebase",
|
|
8321
|
+
SUPABASE: "supabase",
|
|
8322
|
+
VERCEL: "vercel",
|
|
8323
|
+
SENTRY_CLI: "sentry-cli",
|
|
8324
|
+
GH: "gh",
|
|
8325
|
+
GIT: "git",
|
|
8326
|
+
TSX: "tsx"
|
|
8327
|
+
};
|
|
8328
|
+
cliCache = /* @__PURE__ */ new Map();
|
|
8329
|
+
}
|
|
8330
|
+
});
|
|
8331
|
+
|
|
8332
|
+
// node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/identity.js
|
|
8333
|
+
var require_identity = __commonJS({
|
|
8334
|
+
"node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/identity.js"(exports) {
|
|
8335
|
+
"use strict";
|
|
8336
|
+
init_utils();
|
|
8337
|
+
var ALIAS = /* @__PURE__ */ Symbol.for("yaml.alias");
|
|
8338
|
+
var DOC = /* @__PURE__ */ Symbol.for("yaml.document");
|
|
8339
|
+
var MAP = /* @__PURE__ */ Symbol.for("yaml.map");
|
|
8340
|
+
var PAIR = /* @__PURE__ */ Symbol.for("yaml.pair");
|
|
8341
|
+
var SCALAR = /* @__PURE__ */ Symbol.for("yaml.scalar");
|
|
8342
|
+
var SEQ = /* @__PURE__ */ Symbol.for("yaml.seq");
|
|
8343
|
+
var NODE_TYPE = /* @__PURE__ */ Symbol.for("yaml.node.type");
|
|
8344
|
+
var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
|
8345
|
+
var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
|
8346
|
+
var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
|
8347
|
+
var isPair = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === PAIR;
|
|
8348
|
+
var isScalar = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SCALAR;
|
|
8349
|
+
var isSeq = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SEQ;
|
|
8350
|
+
function isCollection(node) {
|
|
8351
|
+
if (node && typeof node === "object")
|
|
8352
|
+
switch (node[NODE_TYPE]) {
|
|
8353
|
+
case MAP:
|
|
8354
|
+
case SEQ:
|
|
8355
|
+
return true;
|
|
8356
|
+
}
|
|
8357
|
+
return false;
|
|
8358
|
+
}
|
|
8359
|
+
function isNode(node) {
|
|
8360
|
+
if (node && typeof node === "object")
|
|
8361
|
+
switch (node[NODE_TYPE]) {
|
|
8362
|
+
case ALIAS:
|
|
8363
|
+
case MAP:
|
|
8364
|
+
case SCALAR:
|
|
8365
|
+
case SEQ:
|
|
8366
|
+
return true;
|
|
8367
|
+
}
|
|
8368
|
+
return false;
|
|
8369
|
+
}
|
|
8370
|
+
var hasAnchor = (node) => (isScalar(node) || isCollection(node)) && !!node.anchor;
|
|
8371
|
+
exports.ALIAS = ALIAS;
|
|
8372
|
+
exports.DOC = DOC;
|
|
8373
|
+
exports.MAP = MAP;
|
|
8374
|
+
exports.NODE_TYPE = NODE_TYPE;
|
|
8375
|
+
exports.PAIR = PAIR;
|
|
8376
|
+
exports.SCALAR = SCALAR;
|
|
8377
|
+
exports.SEQ = SEQ;
|
|
8378
|
+
exports.hasAnchor = hasAnchor;
|
|
8379
|
+
exports.isAlias = isAlias;
|
|
8380
|
+
exports.isCollection = isCollection;
|
|
8381
|
+
exports.isDocument = isDocument;
|
|
8382
|
+
exports.isMap = isMap;
|
|
8383
|
+
exports.isNode = isNode;
|
|
8384
|
+
exports.isPair = isPair;
|
|
8385
|
+
exports.isScalar = isScalar;
|
|
8386
|
+
exports.isSeq = isSeq;
|
|
8387
|
+
}
|
|
8388
|
+
});
|
|
8389
|
+
|
|
8390
|
+
// node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/visit.js
|
|
8391
|
+
var require_visit = __commonJS({
|
|
8392
|
+
"node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/visit.js"(exports) {
|
|
8393
|
+
"use strict";
|
|
8394
|
+
init_utils();
|
|
8395
|
+
var identity = require_identity();
|
|
8396
|
+
var BREAK = /* @__PURE__ */ Symbol("break visit");
|
|
8397
|
+
var SKIP = /* @__PURE__ */ Symbol("skip children");
|
|
8398
|
+
var REMOVE = /* @__PURE__ */ Symbol("remove node");
|
|
8399
|
+
function visit(node, visitor) {
|
|
8400
|
+
const visitor_ = initVisitor(visitor);
|
|
8401
|
+
if (identity.isDocument(node)) {
|
|
8402
|
+
const cd = visit_(null, node.contents, visitor_, Object.freeze([node]));
|
|
8403
|
+
if (cd === REMOVE)
|
|
8404
|
+
node.contents = null;
|
|
8405
|
+
} else
|
|
8406
|
+
visit_(null, node, visitor_, Object.freeze([]));
|
|
8407
|
+
}
|
|
8408
|
+
visit.BREAK = BREAK;
|
|
8409
|
+
visit.SKIP = SKIP;
|
|
8410
|
+
visit.REMOVE = REMOVE;
|
|
8411
|
+
function visit_(key, node, visitor, path) {
|
|
8412
|
+
const ctrl = callVisitor(key, node, visitor, path);
|
|
8413
|
+
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
8414
|
+
replaceNode(key, path, ctrl);
|
|
8415
|
+
return visit_(key, ctrl, visitor, path);
|
|
8416
|
+
}
|
|
8417
|
+
if (typeof ctrl !== "symbol") {
|
|
8418
|
+
if (identity.isCollection(node)) {
|
|
8419
|
+
path = Object.freeze(path.concat(node));
|
|
8420
|
+
for (let i = 0; i < node.items.length; ++i) {
|
|
8421
|
+
const ci = visit_(i, node.items[i], visitor, path);
|
|
8422
|
+
if (typeof ci === "number")
|
|
8423
|
+
i = ci - 1;
|
|
8424
|
+
else if (ci === BREAK)
|
|
8425
|
+
return BREAK;
|
|
8426
|
+
else if (ci === REMOVE) {
|
|
8427
|
+
node.items.splice(i, 1);
|
|
8428
|
+
i -= 1;
|
|
8429
|
+
}
|
|
8430
|
+
}
|
|
8431
|
+
} else if (identity.isPair(node)) {
|
|
8432
|
+
path = Object.freeze(path.concat(node));
|
|
8433
|
+
const ck = visit_("key", node.key, visitor, path);
|
|
8434
|
+
if (ck === BREAK)
|
|
8435
|
+
return BREAK;
|
|
8436
|
+
else if (ck === REMOVE)
|
|
8437
|
+
node.key = null;
|
|
8438
|
+
const cv = visit_("value", node.value, visitor, path);
|
|
8439
|
+
if (cv === BREAK)
|
|
8440
|
+
return BREAK;
|
|
8441
|
+
else if (cv === REMOVE)
|
|
8442
|
+
node.value = null;
|
|
8443
|
+
}
|
|
8444
|
+
}
|
|
8445
|
+
return ctrl;
|
|
8446
|
+
}
|
|
8447
|
+
async function visitAsync(node, visitor) {
|
|
8448
|
+
const visitor_ = initVisitor(visitor);
|
|
8449
|
+
if (identity.isDocument(node)) {
|
|
8450
|
+
const cd = await visitAsync_(null, node.contents, visitor_, Object.freeze([node]));
|
|
8451
|
+
if (cd === REMOVE)
|
|
8452
|
+
node.contents = null;
|
|
8453
|
+
} else
|
|
8454
|
+
await visitAsync_(null, node, visitor_, Object.freeze([]));
|
|
8455
|
+
}
|
|
8456
|
+
visitAsync.BREAK = BREAK;
|
|
7992
8457
|
visitAsync.SKIP = SKIP;
|
|
7993
8458
|
visitAsync.REMOVE = REMOVE;
|
|
7994
8459
|
async function visitAsync_(key, node, visitor, path) {
|
|
@@ -15124,7 +15589,7 @@ var require_public_api = __commonJS({
|
|
|
15124
15589
|
}
|
|
15125
15590
|
return doc;
|
|
15126
15591
|
}
|
|
15127
|
-
function
|
|
15592
|
+
function parse2(src, reviver, options) {
|
|
15128
15593
|
let _reviver = void 0;
|
|
15129
15594
|
if (typeof reviver === "function") {
|
|
15130
15595
|
_reviver = reviver;
|
|
@@ -15165,7 +15630,7 @@ var require_public_api = __commonJS({
|
|
|
15165
15630
|
return value.toString(options);
|
|
15166
15631
|
return new Document.Document(value, _replacer, options).toString(options);
|
|
15167
15632
|
}
|
|
15168
|
-
exports.parse =
|
|
15633
|
+
exports.parse = parse2;
|
|
15169
15634
|
exports.parseAllDocuments = parseAllDocuments;
|
|
15170
15635
|
exports.parseDocument = parseDocument;
|
|
15171
15636
|
exports.stringify = stringify2;
|
|
@@ -15214,450 +15679,819 @@ var require_dist = __commonJS({
|
|
|
15214
15679
|
exports.YAMLSeq = YAMLSeq.YAMLSeq;
|
|
15215
15680
|
exports.CST = cst;
|
|
15216
15681
|
exports.Lexer = lexer.Lexer;
|
|
15217
|
-
exports.LineCounter = lineCounter.LineCounter;
|
|
15218
|
-
exports.Parser = parser.Parser;
|
|
15219
|
-
exports.parse = publicApi.parse;
|
|
15220
|
-
exports.parseAllDocuments = publicApi.parseAllDocuments;
|
|
15221
|
-
exports.parseDocument = publicApi.parseDocument;
|
|
15222
|
-
exports.stringify = publicApi.stringify;
|
|
15223
|
-
exports.visit = visit.visit;
|
|
15224
|
-
exports.visitAsync = visit.visitAsync;
|
|
15225
|
-
}
|
|
15226
|
-
});
|
|
15227
|
-
|
|
15228
|
-
// packages/cli/src/bin/commands/deploy.ts
|
|
15229
|
-
init_utils();
|
|
15230
|
-
|
|
15231
|
-
// packages/tooling/src/index.ts
|
|
15232
|
-
init_utils();
|
|
15233
|
-
|
|
15234
|
-
// packages/tooling/src/cli/index.ts
|
|
15235
|
-
init_utils();
|
|
15236
|
-
|
|
15237
|
-
// packages/tooling/src/utils/cli-input.ts
|
|
15238
|
-
init_utils();
|
|
15239
|
-
init_dist2();
|
|
15240
|
-
async function askForInput(message, defaultValue = "") {
|
|
15241
|
-
const result = await he({
|
|
15242
|
-
message,
|
|
15243
|
-
placeholder: defaultValue || void 0,
|
|
15244
|
-
initialValue: defaultValue || void 0
|
|
15245
|
-
});
|
|
15246
|
-
if (pD(result)) {
|
|
15247
|
-
xe("Operation cancelled.");
|
|
15248
|
-
process.exit(0);
|
|
15249
|
-
}
|
|
15250
|
-
return result;
|
|
15251
|
-
}
|
|
15252
|
-
async function askForConfirmation(message, defaultValue = false) {
|
|
15253
|
-
const result = await ye({
|
|
15254
|
-
message,
|
|
15255
|
-
initialValue: defaultValue
|
|
15256
|
-
});
|
|
15257
|
-
if (pD(result)) {
|
|
15258
|
-
xe("Operation cancelled.");
|
|
15259
|
-
process.exit(0);
|
|
15260
|
-
}
|
|
15261
|
-
return result;
|
|
15262
|
-
}
|
|
15263
|
-
async function askForSelection(message, choices, defaultValue = 0) {
|
|
15264
|
-
const options = choices.map((choice) => ({
|
|
15265
|
-
value: choice.value,
|
|
15266
|
-
label: choice.title,
|
|
15267
|
-
hint: choice.hint
|
|
15268
|
-
}));
|
|
15269
|
-
const result = await ve({
|
|
15270
|
-
message,
|
|
15271
|
-
options,
|
|
15272
|
-
initialValue: choices[defaultValue]?.value
|
|
15273
|
-
});
|
|
15274
|
-
if (pD(result)) {
|
|
15275
|
-
xe("Operation cancelled.");
|
|
15276
|
-
process.exit(0);
|
|
15682
|
+
exports.LineCounter = lineCounter.LineCounter;
|
|
15683
|
+
exports.Parser = parser.Parser;
|
|
15684
|
+
exports.parse = publicApi.parse;
|
|
15685
|
+
exports.parseAllDocuments = publicApi.parseAllDocuments;
|
|
15686
|
+
exports.parseDocument = publicApi.parseDocument;
|
|
15687
|
+
exports.stringify = publicApi.stringify;
|
|
15688
|
+
exports.visit = visit.visit;
|
|
15689
|
+
exports.visitAsync = visit.visitAsync;
|
|
15277
15690
|
}
|
|
15278
|
-
|
|
15279
|
-
}
|
|
15691
|
+
});
|
|
15280
15692
|
|
|
15281
|
-
// packages/tooling/src/
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
|
|
15285
|
-
|
|
15286
|
-
|
|
15287
|
-
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15292
|
-
|
|
15293
|
-
|
|
15294
|
-
|
|
15295
|
-
|
|
15296
|
-
|
|
15297
|
-
|
|
15298
|
-
|
|
15693
|
+
// packages/tooling/src/apps/sync-secrets.ts
|
|
15694
|
+
var sync_secrets_exports = {};
|
|
15695
|
+
__export(sync_secrets_exports, {
|
|
15696
|
+
default: () => sync_secrets_default,
|
|
15697
|
+
main: () => main
|
|
15698
|
+
});
|
|
15699
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
15700
|
+
function parseEnvFile(filePath) {
|
|
15701
|
+
if (!pathExists(filePath)) {
|
|
15702
|
+
throw new DoNotDevError(
|
|
15703
|
+
`Environment file not found: ${filePath}`,
|
|
15704
|
+
"file-not-found",
|
|
15705
|
+
{ context: { filePath } }
|
|
15706
|
+
);
|
|
15707
|
+
}
|
|
15708
|
+
const contentRaw = readSync(filePath, { format: "text" });
|
|
15709
|
+
const content = typeof contentRaw === "string" ? contentRaw : null;
|
|
15710
|
+
if (!content) {
|
|
15711
|
+
throw new Error(`Failed to read secrets file: ${filePath}`);
|
|
15712
|
+
}
|
|
15713
|
+
const secrets = {};
|
|
15714
|
+
content.split("\n").forEach((line, index) => {
|
|
15715
|
+
const trimmedLine = line.trim();
|
|
15716
|
+
if (!trimmedLine || trimmedLine.startsWith("#")) {
|
|
15717
|
+
return;
|
|
15718
|
+
}
|
|
15719
|
+
const equalIndex = trimmedLine.indexOf("=");
|
|
15720
|
+
if (equalIndex === -1) {
|
|
15721
|
+
log.warn(`Invalid line format at line ${index + 1}: ${trimmedLine}`);
|
|
15722
|
+
return;
|
|
15723
|
+
}
|
|
15724
|
+
const key = trimmedLine.substring(0, equalIndex).trim();
|
|
15725
|
+
const value = trimmedLine.substring(equalIndex + 1).trim();
|
|
15726
|
+
const cleanValue = value.replace(/^["']|["']$/g, "");
|
|
15727
|
+
if (key && cleanValue) {
|
|
15728
|
+
secrets[key] = cleanValue;
|
|
15729
|
+
}
|
|
15299
15730
|
});
|
|
15731
|
+
return secrets;
|
|
15300
15732
|
}
|
|
15301
|
-
function
|
|
15302
|
-
const
|
|
15303
|
-
|
|
15304
|
-
|
|
15305
|
-
stdio: "inherit",
|
|
15306
|
-
env: deployEnv
|
|
15307
|
-
};
|
|
15308
|
-
let result;
|
|
15309
|
-
result = spawnSync("firebase", args, { ...spawnOptions, shell: true });
|
|
15310
|
-
if (result.error) {
|
|
15311
|
-
return {
|
|
15312
|
-
success: false,
|
|
15313
|
-
status: 1,
|
|
15314
|
-
error: result.error
|
|
15315
|
-
};
|
|
15733
|
+
function detectPlatform() {
|
|
15734
|
+
const currentDir = process.cwd();
|
|
15735
|
+
if (pathExists(joinPath(currentDir, "firebase.json"))) {
|
|
15736
|
+
return "firebase";
|
|
15316
15737
|
}
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
|
|
15320
|
-
|
|
15321
|
-
|
|
15322
|
-
};
|
|
15738
|
+
if (pathExists(joinPath(currentDir, "vercel.json")) || pathExists(joinPath(currentDir, ".vercel"))) {
|
|
15739
|
+
return "vercel";
|
|
15740
|
+
}
|
|
15741
|
+
log.warn("No platform detected, defaulting to Firebase");
|
|
15742
|
+
return "firebase";
|
|
15323
15743
|
}
|
|
15324
|
-
function
|
|
15325
|
-
const
|
|
15326
|
-
const
|
|
15327
|
-
const
|
|
15328
|
-
|
|
15329
|
-
|
|
15744
|
+
function findFirebaseProjectDir(envFilePath) {
|
|
15745
|
+
const currentDir = process.cwd();
|
|
15746
|
+
const resolvedPath = joinPath(currentDir, envFilePath);
|
|
15747
|
+
const envFileDir = getDirname(resolvedPath);
|
|
15748
|
+
const appsMatch = envFileDir.match(/apps[\\/]([^\\/]+)[\\/]functions/);
|
|
15749
|
+
if (appsMatch && appsMatch[1]) {
|
|
15750
|
+
const appDir = joinPath(currentDir, "apps", appsMatch[1]);
|
|
15751
|
+
if (pathExists(joinPath(appDir, "firebase.json"))) {
|
|
15752
|
+
return appDir;
|
|
15753
|
+
}
|
|
15330
15754
|
}
|
|
15331
|
-
|
|
15332
|
-
|
|
15755
|
+
let searchDir = envFileDir;
|
|
15756
|
+
const rootDir = getDirname(currentDir);
|
|
15757
|
+
while (searchDir !== rootDir && searchDir !== getDirname(searchDir)) {
|
|
15758
|
+
if (pathExists(joinPath(searchDir, "firebase.json"))) {
|
|
15759
|
+
return searchDir;
|
|
15760
|
+
}
|
|
15761
|
+
const parentDir = getDirname(searchDir);
|
|
15762
|
+
if (parentDir === searchDir) break;
|
|
15763
|
+
searchDir = parentDir;
|
|
15333
15764
|
}
|
|
15334
|
-
|
|
15335
|
-
|
|
15765
|
+
return currentDir;
|
|
15766
|
+
}
|
|
15767
|
+
function isFirebaseReservedKey(key) {
|
|
15768
|
+
const reservedPrefixes = ["X_GOOGLE_", "FIREBASE_", "EXT_", "GCLOUD_"];
|
|
15769
|
+
const configOnlyKeys = [
|
|
15770
|
+
"FIREBASE_REGION",
|
|
15771
|
+
"FIREBASE_PROJECT_ID",
|
|
15772
|
+
"FIREBASE_AUTH_DOMAIN"
|
|
15773
|
+
];
|
|
15774
|
+
if (configOnlyKeys.includes(key)) {
|
|
15775
|
+
return true;
|
|
15336
15776
|
}
|
|
15337
|
-
return
|
|
15777
|
+
return reservedPrefixes.some((prefix) => key.startsWith(prefix));
|
|
15338
15778
|
}
|
|
15339
|
-
function
|
|
15340
|
-
const
|
|
15341
|
-
const
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
|
|
15345
|
-
|
|
15346
|
-
|
|
15347
|
-
|
|
15348
|
-
|
|
15349
|
-
|
|
15350
|
-
|
|
15779
|
+
function detectFirebaseProjectId(cwd) {
|
|
15780
|
+
const searchDir = cwd || process.cwd();
|
|
15781
|
+
const firebasercPath = joinPath(searchDir, ".firebaserc");
|
|
15782
|
+
if (pathExists(firebasercPath)) {
|
|
15783
|
+
try {
|
|
15784
|
+
const firebasercRaw = readSync(firebasercPath, { format: "json" });
|
|
15785
|
+
const firebaserc = firebasercRaw && typeof firebasercRaw === "object" ? firebasercRaw : null;
|
|
15786
|
+
if (firebaserc && firebaserc.projects?.default) {
|
|
15787
|
+
return firebaserc.projects.default;
|
|
15788
|
+
}
|
|
15789
|
+
} catch {
|
|
15790
|
+
}
|
|
15351
15791
|
}
|
|
15352
|
-
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
|
|
15792
|
+
let current = searchDir;
|
|
15793
|
+
const root = getDirname(current);
|
|
15794
|
+
while (current !== root) {
|
|
15795
|
+
const firebasercPath2 = joinPath(current, ".firebaserc");
|
|
15796
|
+
if (pathExists(firebasercPath2)) {
|
|
15797
|
+
try {
|
|
15798
|
+
const firebasercRaw = readSync(firebasercPath2, { format: "json" });
|
|
15799
|
+
const firebaserc = firebasercRaw && typeof firebasercRaw === "object" ? firebasercRaw : null;
|
|
15800
|
+
if (firebaserc && firebaserc.projects?.default) {
|
|
15801
|
+
return firebaserc.projects.default;
|
|
15802
|
+
}
|
|
15803
|
+
} catch {
|
|
15804
|
+
}
|
|
15805
|
+
}
|
|
15806
|
+
const parent = getDirname(current);
|
|
15807
|
+
if (parent === current) break;
|
|
15808
|
+
current = parent;
|
|
15356
15809
|
}
|
|
15357
|
-
return
|
|
15810
|
+
return void 0;
|
|
15358
15811
|
}
|
|
15359
|
-
function
|
|
15360
|
-
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
|
|
15812
|
+
function detectAppsWithFunctions() {
|
|
15813
|
+
const currentDir = process.cwd();
|
|
15814
|
+
const appsDir = joinPath(currentDir, "apps");
|
|
15815
|
+
if (!pathExists(appsDir)) {
|
|
15816
|
+
return [];
|
|
15817
|
+
}
|
|
15818
|
+
const apps = [];
|
|
15819
|
+
try {
|
|
15820
|
+
const appsList = readdirSync2(appsDir).filter((item) => {
|
|
15821
|
+
const itemPath = joinPath(appsDir, item);
|
|
15822
|
+
const stat = statSync2(itemPath);
|
|
15823
|
+
return stat?.isDirectory() === true;
|
|
15824
|
+
});
|
|
15825
|
+
for (const app of appsList) {
|
|
15826
|
+
const functionsEnvFile = joinPath(appsDir, app, "functions", ".env");
|
|
15827
|
+
if (pathExists(functionsEnvFile)) {
|
|
15828
|
+
apps.push({
|
|
15829
|
+
name: app,
|
|
15830
|
+
dir: joinPath(appsDir, app),
|
|
15831
|
+
envFile: functionsEnvFile
|
|
15832
|
+
});
|
|
15833
|
+
}
|
|
15834
|
+
}
|
|
15835
|
+
} catch {
|
|
15364
15836
|
}
|
|
15837
|
+
return apps.sort((a, b3) => a.name.localeCompare(b3.name));
|
|
15365
15838
|
}
|
|
15366
|
-
function
|
|
15367
|
-
|
|
15368
|
-
|
|
15369
|
-
|
|
15370
|
-
|
|
15371
|
-
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
|
|
15839
|
+
async function setFirebaseSecret(key, value, projectId, dryRun = false, cwd) {
|
|
15840
|
+
if (isFirebaseReservedKey(key)) {
|
|
15841
|
+
const configOnlyKeys = [
|
|
15842
|
+
"FIREBASE_REGION",
|
|
15843
|
+
"FIREBASE_PROJECT_ID",
|
|
15844
|
+
"FIREBASE_AUTH_DOMAIN"
|
|
15845
|
+
];
|
|
15846
|
+
if (configOnlyKeys.includes(key)) {
|
|
15847
|
+
log.debug(
|
|
15848
|
+
`\u23ED\uFE0F Skipping ${key}: Configuration variable (stays in .env, not synced as secret)`
|
|
15849
|
+
);
|
|
15850
|
+
} else {
|
|
15851
|
+
log.warn(
|
|
15852
|
+
`\u23ED\uFE0F Skipping ${key}: Reserved Firebase prefix (X_GOOGLE_, FIREBASE_, EXT_, GCLOUD_)`
|
|
15853
|
+
);
|
|
15854
|
+
}
|
|
15855
|
+
return;
|
|
15856
|
+
}
|
|
15857
|
+
const finalProjectId = projectId || detectFirebaseProjectId(cwd);
|
|
15858
|
+
if (dryRun) {
|
|
15859
|
+
log.info(
|
|
15860
|
+
`[DRY RUN] Would set Firebase secret: ${key}${finalProjectId ? ` (project: ${finalProjectId})` : ""}`
|
|
15861
|
+
);
|
|
15862
|
+
return;
|
|
15863
|
+
}
|
|
15864
|
+
if (!finalProjectId) {
|
|
15865
|
+
throw new DoNotDevError(
|
|
15866
|
+
`Firebase project ID required for secret '${key}'. Use --project <project_id> or ensure .firebaserc exists with a default project.`,
|
|
15867
|
+
"missing-project-id",
|
|
15868
|
+
{
|
|
15869
|
+
context: {
|
|
15870
|
+
platform: "firebase",
|
|
15871
|
+
key,
|
|
15872
|
+
cwd: cwd || process.cwd(),
|
|
15873
|
+
suggestion: "Run: dn sync-secrets --project <project_id> or create .firebaserc with default project"
|
|
15874
|
+
}
|
|
15875
|
+
}
|
|
15876
|
+
);
|
|
15877
|
+
}
|
|
15878
|
+
try {
|
|
15879
|
+
log.info(`Setting Firebase secret: ${key} (project: ${finalProjectId})`);
|
|
15880
|
+
const tempDir = joinPath(process.cwd(), ".tmp");
|
|
15881
|
+
await ensureDir(tempDir);
|
|
15882
|
+
const tempFile = joinPath(tempDir, `secret-${key}-${Date.now()}.txt`);
|
|
15883
|
+
await write(tempFile, value);
|
|
15884
|
+
try {
|
|
15885
|
+
const args = ["functions:secrets:set", key, "--project", finalProjectId];
|
|
15886
|
+
const firebaseCmd = process.platform === "win32" ? "firebase.cmd" : "firebase";
|
|
15887
|
+
const deployEnv = {
|
|
15888
|
+
...process.env,
|
|
15889
|
+
NODE_OPTIONS: ""
|
|
15890
|
+
// Clear to avoid conflicts
|
|
15891
|
+
};
|
|
15892
|
+
const result = spawnSync5(firebaseCmd, args, {
|
|
15893
|
+
input: value,
|
|
15894
|
+
encoding: "utf8",
|
|
15895
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
15896
|
+
env: deployEnv,
|
|
15897
|
+
cwd: cwd || process.cwd(),
|
|
15898
|
+
shell: false
|
|
15899
|
+
});
|
|
15900
|
+
if (result.error) {
|
|
15901
|
+
throw result.error;
|
|
15902
|
+
}
|
|
15903
|
+
if (result.status !== 0) {
|
|
15904
|
+
const stderr = result.stderr?.toString() || "";
|
|
15905
|
+
const stdout = result.stdout?.toString() || "";
|
|
15906
|
+
const errorOutput = stderr || stdout;
|
|
15907
|
+
const errorLower = errorOutput.toLowerCase();
|
|
15908
|
+
if (errorLower.includes("not logged in") || errorLower.includes("authentication required") || errorLower.includes("please login") || errorLower.includes("run firebase login") || errorLower.includes("unauthorized") || errorOutput.includes("401")) {
|
|
15909
|
+
throw new DoNotDevError(
|
|
15910
|
+
`Firebase CLI authentication required. Please run 'firebase login' to authenticate.`,
|
|
15911
|
+
"permission-denied",
|
|
15912
|
+
{
|
|
15913
|
+
context: {
|
|
15914
|
+
platform: "firebase",
|
|
15915
|
+
key,
|
|
15916
|
+
error: errorOutput,
|
|
15917
|
+
suggestion: "Run: firebase login"
|
|
15918
|
+
}
|
|
15919
|
+
}
|
|
15920
|
+
);
|
|
15921
|
+
}
|
|
15922
|
+
if (errorOutput.includes("403") || errorOutput.includes("Permission denied") || errorOutput.includes("secretmanager.secrets.get") || errorOutput.includes("secretmanager.secrets.create")) {
|
|
15923
|
+
const permissionError = new DoNotDevError(
|
|
15924
|
+
`Permission denied: Missing required Google Cloud permissions for secret '${key}'. Required permissions: secretmanager.secrets.get, secretmanager.secrets.create, secretmanager.versions.add. Ensure you're logged in with 'firebase login' and your account has the 'Secret Manager Admin' role.`,
|
|
15925
|
+
"permission-denied",
|
|
15926
|
+
{
|
|
15927
|
+
context: {
|
|
15928
|
+
platform: "firebase",
|
|
15929
|
+
key,
|
|
15930
|
+
error: errorOutput,
|
|
15931
|
+
suggestion: 'Run: firebase login && gcloud projects add-iam-policy-binding donotdevelopp --member="user:YOUR_EMAIL" --role="roles/secretmanager.admin"'
|
|
15932
|
+
}
|
|
15933
|
+
}
|
|
15934
|
+
);
|
|
15935
|
+
throw permissionError;
|
|
15936
|
+
}
|
|
15937
|
+
if (errorOutput.includes("No currently active project")) {
|
|
15938
|
+
throw new DoNotDevError(
|
|
15939
|
+
`Firebase CLI exited with code ${result.status}: No active project. Please specify the project using '--project <project_id>' or set an active project with 'firebase use --add'.`,
|
|
15940
|
+
"firebase-cli-error",
|
|
15941
|
+
{
|
|
15942
|
+
context: {
|
|
15943
|
+
platform: "firebase",
|
|
15944
|
+
key,
|
|
15945
|
+
error: errorOutput,
|
|
15946
|
+
suggestion: `Run 'dn sync-secrets --project ${finalProjectId}' or 'firebase use --add ${finalProjectId}'`
|
|
15947
|
+
}
|
|
15948
|
+
}
|
|
15949
|
+
);
|
|
15950
|
+
}
|
|
15951
|
+
throw new Error(
|
|
15952
|
+
`Firebase CLI exited with code ${result.status}
|
|
15953
|
+
${errorOutput}`
|
|
15954
|
+
);
|
|
15955
|
+
}
|
|
15956
|
+
log.success(`Firebase secret ${key} set successfully`);
|
|
15957
|
+
} finally {
|
|
15958
|
+
if (pathExists(tempFile)) {
|
|
15959
|
+
await remove(tempFile);
|
|
15377
15960
|
}
|
|
15378
15961
|
}
|
|
15379
|
-
)
|
|
15962
|
+
} catch (err) {
|
|
15963
|
+
log.error(`Failed to set Firebase secret ${key}:`, err);
|
|
15964
|
+
throw new DoNotDevError(
|
|
15965
|
+
`Failed to set Firebase secret ${key}`,
|
|
15966
|
+
"command-failed",
|
|
15967
|
+
{
|
|
15968
|
+
context: {
|
|
15969
|
+
platform: "firebase",
|
|
15970
|
+
key,
|
|
15971
|
+
error: err instanceof Error ? err.message : String(err)
|
|
15972
|
+
}
|
|
15973
|
+
}
|
|
15974
|
+
);
|
|
15975
|
+
}
|
|
15380
15976
|
}
|
|
15381
|
-
function
|
|
15382
|
-
if (
|
|
15383
|
-
|
|
15977
|
+
function setVercelSecret(key, value, projectId, dryRun = false) {
|
|
15978
|
+
if (dryRun) {
|
|
15979
|
+
log.info(`[DRY RUN] Would set Vercel environment variable: ${key}`);
|
|
15980
|
+
return;
|
|
15384
15981
|
}
|
|
15385
15982
|
try {
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
|
|
15983
|
+
log.info(`Setting Vercel environment variable: ${key}`);
|
|
15984
|
+
const args = ["env", "add", key];
|
|
15985
|
+
if (projectId) {
|
|
15986
|
+
args.push("--project", projectId);
|
|
15987
|
+
}
|
|
15988
|
+
const result = spawnSync5("vercel", args, {
|
|
15989
|
+
input: value,
|
|
15990
|
+
encoding: "utf8",
|
|
15991
|
+
stdio: ["pipe", "inherit", "inherit"]
|
|
15992
|
+
});
|
|
15993
|
+
if (result.error) {
|
|
15994
|
+
throw result.error;
|
|
15389
15995
|
}
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
const message = options.failureMessage ?? `Could not remove ${path}: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
15393
|
-
if (options.silent !== false) {
|
|
15394
|
-
log.warn(message);
|
|
15996
|
+
if (result.status !== 0) {
|
|
15997
|
+
throw new Error(`Vercel CLI exited with code ${result.status}`);
|
|
15395
15998
|
}
|
|
15396
|
-
|
|
15999
|
+
log.success(`Vercel environment variable ${key} set successfully`);
|
|
16000
|
+
} catch (err) {
|
|
16001
|
+
log.error(`Failed to set Vercel environment variable ${key}:`, err);
|
|
16002
|
+
throw new DoNotDevError(
|
|
16003
|
+
`Failed to set Vercel environment variable ${key}`,
|
|
16004
|
+
"command-failed",
|
|
16005
|
+
{
|
|
16006
|
+
context: {
|
|
16007
|
+
platform: "vercel",
|
|
16008
|
+
key,
|
|
16009
|
+
error: err instanceof Error ? err.message : String(err)
|
|
16010
|
+
}
|
|
16011
|
+
}
|
|
16012
|
+
);
|
|
15397
16013
|
}
|
|
15398
16014
|
}
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
|
|
15413
|
-
|
|
15414
|
-
|
|
15415
|
-
|
|
16015
|
+
function detectGitHubRepo() {
|
|
16016
|
+
try {
|
|
16017
|
+
const result = spawnSync5("git", ["remote", "get-url", "origin"], {
|
|
16018
|
+
encoding: "utf8",
|
|
16019
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
16020
|
+
});
|
|
16021
|
+
if (result.status !== 0 || !result.stdout) return void 0;
|
|
16022
|
+
const url = result.stdout.trim();
|
|
16023
|
+
const sshMatch = url.match(/github\.com[:/]([^/]+\/[^/.]+)/);
|
|
16024
|
+
if (sshMatch) return sshMatch[1];
|
|
16025
|
+
const httpsMatch = url.match(/github\.com\/([^/]+\/[^/.]+)/);
|
|
16026
|
+
if (httpsMatch) return httpsMatch[1];
|
|
16027
|
+
return void 0;
|
|
16028
|
+
} catch {
|
|
16029
|
+
return void 0;
|
|
16030
|
+
}
|
|
16031
|
+
}
|
|
16032
|
+
function setGitHubSecret(key, value, repo, dryRun = false) {
|
|
16033
|
+
if (dryRun) {
|
|
16034
|
+
log.info(
|
|
16035
|
+
`[DRY RUN] Would set GitHub secret: ${key}${repo ? ` (repo: ${repo})` : ""}`
|
|
16036
|
+
);
|
|
16037
|
+
return;
|
|
15416
16038
|
}
|
|
15417
16039
|
try {
|
|
15418
|
-
|
|
15419
|
-
|
|
15420
|
-
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15430
|
-
|
|
15431
|
-
|
|
15432
|
-
|
|
15433
|
-
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
|
|
15438
|
-
|
|
15439
|
-
|
|
15440
|
-
|
|
15441
|
-
|
|
15442
|
-
|
|
15443
|
-
|
|
15444
|
-
|
|
15445
|
-
|
|
15446
|
-
|
|
15447
|
-
|
|
16040
|
+
log.info(`Setting GitHub secret: ${key}${repo ? ` (repo: ${repo})` : ""}`);
|
|
16041
|
+
const args = ["secret", "set", key];
|
|
16042
|
+
if (repo) {
|
|
16043
|
+
args.push("--repo", repo);
|
|
16044
|
+
}
|
|
16045
|
+
const result = spawnSync5("gh", args, {
|
|
16046
|
+
input: value,
|
|
16047
|
+
encoding: "utf8",
|
|
16048
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
16049
|
+
});
|
|
16050
|
+
if (result.error) {
|
|
16051
|
+
throw result.error;
|
|
16052
|
+
}
|
|
16053
|
+
if (result.status !== 0) {
|
|
16054
|
+
const stderr = result.stderr?.toString() || "";
|
|
16055
|
+
const stdout = result.stdout?.toString() || "";
|
|
16056
|
+
const errorOutput = stderr || stdout;
|
|
16057
|
+
if (errorOutput.includes("not logged in") || errorOutput.includes("authentication")) {
|
|
16058
|
+
throw new DoNotDevError(
|
|
16059
|
+
`GitHub CLI authentication required. Run 'gh auth login' to authenticate.`,
|
|
16060
|
+
"permission-denied",
|
|
16061
|
+
{ context: { key, error: errorOutput } }
|
|
16062
|
+
);
|
|
16063
|
+
}
|
|
16064
|
+
throw new Error(
|
|
16065
|
+
`gh CLI exited with code ${result.status}
|
|
16066
|
+
${errorOutput}`
|
|
16067
|
+
);
|
|
16068
|
+
}
|
|
16069
|
+
log.success(`GitHub secret ${key} set successfully`);
|
|
16070
|
+
} catch (err) {
|
|
16071
|
+
if (err instanceof DoNotDevError) throw err;
|
|
16072
|
+
log.error(`Failed to set GitHub secret ${key}:`, err);
|
|
16073
|
+
throw new DoNotDevError(
|
|
16074
|
+
`Failed to set GitHub secret ${key}`,
|
|
16075
|
+
"command-failed",
|
|
16076
|
+
{
|
|
16077
|
+
context: {
|
|
16078
|
+
target: "github",
|
|
16079
|
+
key,
|
|
16080
|
+
error: err instanceof Error ? err.message : String(err)
|
|
16081
|
+
}
|
|
16082
|
+
}
|
|
16083
|
+
);
|
|
16084
|
+
}
|
|
16085
|
+
}
|
|
16086
|
+
function uploadServiceAccountToGitHub(appDir, repo, dryRun = false, staging = false) {
|
|
16087
|
+
const fileName = staging ? "service-account-key.staging.json" : "service-account-key.json";
|
|
16088
|
+
const secretName = staging ? "FIREBASE_SERVICE_ACCOUNT_STAGING" : "FIREBASE_SERVICE_ACCOUNT";
|
|
16089
|
+
const filePath = joinPath(appDir, fileName);
|
|
16090
|
+
if (!pathExists(filePath)) {
|
|
16091
|
+
log.debug(`No ${fileName} found in ${appDir}, skipping GitHub upload`);
|
|
16092
|
+
return;
|
|
16093
|
+
}
|
|
16094
|
+
const contentRaw = readSync(filePath, { format: "text" });
|
|
16095
|
+
const content = typeof contentRaw === "string" ? contentRaw : null;
|
|
16096
|
+
if (!content) return;
|
|
16097
|
+
const encoded = Buffer2.from(content).toString("base64");
|
|
16098
|
+
setGitHubSecret(secretName, encoded, repo, dryRun);
|
|
16099
|
+
}
|
|
16100
|
+
async function main(options = {}) {
|
|
16101
|
+
const config = {
|
|
16102
|
+
envFile: options.envFile || ".env",
|
|
16103
|
+
platform: options.platform,
|
|
16104
|
+
projectId: options.projectId,
|
|
16105
|
+
vercelProjectId: options.vercelProjectId,
|
|
16106
|
+
target: options.target || "runtime",
|
|
16107
|
+
repo: options.repo,
|
|
16108
|
+
dryRun: options.dryRun ?? false,
|
|
16109
|
+
verbose: options.verbose ?? false
|
|
16110
|
+
};
|
|
16111
|
+
if (process.argv.includes("--help")) {
|
|
16112
|
+
log.info(`
|
|
16113
|
+
Secrets Sync Tool
|
|
16114
|
+
|
|
16115
|
+
Usage: bun run sync-secrets [options]
|
|
16116
|
+
|
|
16117
|
+
Options:
|
|
16118
|
+
--env-file <path> Path to .env file (default: .env)
|
|
16119
|
+
--target <target> Sync target: 'runtime' (default) or 'github'
|
|
16120
|
+
--platform <platform> Platform to sync to: 'firebase' or 'vercel' (runtime target only, auto-detected)
|
|
16121
|
+
--project <id> Firebase project ID (for Firebase platform)
|
|
16122
|
+
--vercel-project <id> Vercel project ID (for Vercel platform)
|
|
16123
|
+
--repo <owner/repo> GitHub repository (github target only, auto-detected from git remote)
|
|
16124
|
+
--dry-run, --dry Show what would be done without actually setting secrets
|
|
16125
|
+
--verbose Show detailed output
|
|
16126
|
+
--help Show this help message
|
|
16127
|
+
|
|
16128
|
+
Examples:
|
|
16129
|
+
dndev sync-secrets # sync to Firebase/Vercel runtime
|
|
16130
|
+
dndev sync-secrets --target github # sync to GitHub Secrets
|
|
16131
|
+
dndev sync-secrets --target github --repo owner/repo # sync to specific repo
|
|
16132
|
+
dndev sync-secrets --platform=firebase
|
|
16133
|
+
dndev sync-secrets --dry-run
|
|
16134
|
+
dndev sync-secrets --env-file .env.production --project my-project
|
|
16135
|
+
`);
|
|
16136
|
+
return 0;
|
|
16137
|
+
}
|
|
16138
|
+
try {
|
|
16139
|
+
const currentDir = process.cwd();
|
|
16140
|
+
let firebaseProjectDir;
|
|
16141
|
+
if (!options.envFile || config.envFile === ".env") {
|
|
16142
|
+
const appsWithFunctions = detectAppsWithFunctions();
|
|
16143
|
+
if (appsWithFunctions.length > 0) {
|
|
16144
|
+
let selectedApp;
|
|
16145
|
+
if (appsWithFunctions.length === 1) {
|
|
16146
|
+
selectedApp = appsWithFunctions[0];
|
|
16147
|
+
Me(`Using app: ${selectedApp.name}`, "Auto-detected");
|
|
16148
|
+
} else {
|
|
16149
|
+
const appName = await askForSelection(
|
|
16150
|
+
"Which app would you like to sync secrets for?",
|
|
16151
|
+
appsWithFunctions.map((app) => ({
|
|
16152
|
+
title: app.name,
|
|
16153
|
+
value: app.name,
|
|
16154
|
+
hint: `functions/.env in ${app.name}`
|
|
16155
|
+
}))
|
|
15448
16156
|
);
|
|
15449
|
-
|
|
15450
|
-
|
|
15451
|
-
|
|
16157
|
+
selectedApp = appsWithFunctions.find((a) => a.name === appName);
|
|
16158
|
+
}
|
|
16159
|
+
if (selectedApp) {
|
|
16160
|
+
const envFileAbsolute = normalizePath(selectedApp.envFile);
|
|
16161
|
+
const envFileRelative = getRelativePathBetween(
|
|
16162
|
+
currentDir,
|
|
16163
|
+
envFileAbsolute
|
|
16164
|
+
);
|
|
16165
|
+
config.envFile = envFileRelative;
|
|
16166
|
+
firebaseProjectDir = selectedApp.dir;
|
|
16167
|
+
if (!config.projectId) {
|
|
16168
|
+
config.projectId = detectFirebaseProjectId(selectedApp.dir);
|
|
15452
16169
|
}
|
|
15453
|
-
} catch {
|
|
15454
|
-
continue;
|
|
15455
16170
|
}
|
|
15456
16171
|
}
|
|
15457
|
-
|
|
15458
|
-
|
|
15459
|
-
|
|
15460
|
-
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
|
|
15467
|
-
|
|
15468
|
-
|
|
15469
|
-
|
|
16172
|
+
}
|
|
16173
|
+
const envFilePath = joinPath(currentDir, config.envFile);
|
|
16174
|
+
const syncTarget = config.target || "runtime";
|
|
16175
|
+
if (syncTarget === "github") {
|
|
16176
|
+
const repo = config.repo || detectGitHubRepo();
|
|
16177
|
+
if (!repo) {
|
|
16178
|
+
log.error(
|
|
16179
|
+
"Could not detect GitHub repository. Use --repo owner/repo or ensure a GitHub remote is configured."
|
|
16180
|
+
);
|
|
16181
|
+
return 1;
|
|
16182
|
+
}
|
|
16183
|
+
log.info(`Syncing secrets to GitHub repository: ${repo}`);
|
|
16184
|
+
const secrets2 = parseEnvFile(envFilePath);
|
|
16185
|
+
const secretKeys2 = Object.keys(secrets2);
|
|
16186
|
+
if (secretKeys2.length === 0) {
|
|
16187
|
+
log.info("No secrets found in .env file");
|
|
16188
|
+
} else {
|
|
16189
|
+
log.info(`Found ${secretKeys2.length} secrets to sync to GitHub:`);
|
|
16190
|
+
secretKeys2.forEach((key) => log.info(` ${key}`));
|
|
16191
|
+
for (const [key, value] of Object.entries(secrets2)) {
|
|
16192
|
+
setGitHubSecret(key, value, repo, config.dryRun);
|
|
16193
|
+
}
|
|
16194
|
+
}
|
|
16195
|
+
if (firebaseProjectDir) {
|
|
16196
|
+
uploadServiceAccountToGitHub(
|
|
16197
|
+
firebaseProjectDir,
|
|
16198
|
+
repo,
|
|
16199
|
+
config.dryRun,
|
|
16200
|
+
false
|
|
16201
|
+
);
|
|
16202
|
+
uploadServiceAccountToGitHub(
|
|
16203
|
+
firebaseProjectDir,
|
|
16204
|
+
repo,
|
|
16205
|
+
config.dryRun,
|
|
16206
|
+
true
|
|
16207
|
+
);
|
|
16208
|
+
} else {
|
|
16209
|
+
uploadServiceAccountToGitHub(currentDir, repo, config.dryRun, false);
|
|
16210
|
+
uploadServiceAccountToGitHub(currentDir, repo, config.dryRun, true);
|
|
16211
|
+
}
|
|
16212
|
+
if (config.dryRun) {
|
|
16213
|
+
log.success("\nDry run completed. No GitHub secrets were set.");
|
|
16214
|
+
} else {
|
|
16215
|
+
log.success("\nAll secrets synced to GitHub successfully!");
|
|
16216
|
+
}
|
|
16217
|
+
return 0;
|
|
16218
|
+
}
|
|
16219
|
+
const platform = config.platform || detectPlatform();
|
|
16220
|
+
log.info(`Reading secrets from: ${envFilePath}`);
|
|
16221
|
+
if (config.verbose) {
|
|
16222
|
+
log.debug(`Working directory: ${currentDir}`);
|
|
16223
|
+
log.debug(`Environment file: ${envFilePath}`);
|
|
16224
|
+
log.debug(`Platform: ${platform}`);
|
|
16225
|
+
log.debug(`Dry run mode: ${config.dryRun}`);
|
|
16226
|
+
}
|
|
16227
|
+
const secrets = parseEnvFile(envFilePath);
|
|
16228
|
+
const secretKeys = Object.keys(secrets);
|
|
16229
|
+
if (secretKeys.length === 0) {
|
|
16230
|
+
log.info("No secrets found in .env file");
|
|
16231
|
+
return 0;
|
|
16232
|
+
}
|
|
16233
|
+
log.info(`Found ${secretKeys.length} secrets to sync to ${platform}:`);
|
|
16234
|
+
secretKeys.forEach((key) => {
|
|
16235
|
+
if (config.verbose) {
|
|
16236
|
+
const value = secrets[key];
|
|
16237
|
+
log.debug(
|
|
16238
|
+
` ${key}: ${value ? value.substring(0, 10) + "..." : "undefined"}`
|
|
16239
|
+
);
|
|
16240
|
+
} else {
|
|
16241
|
+
log.info(` ${key}`);
|
|
16242
|
+
}
|
|
16243
|
+
});
|
|
16244
|
+
const finalFirebaseProjectDir = platform === "firebase" ? firebaseProjectDir || findFirebaseProjectDir(config.envFile) : void 0;
|
|
16245
|
+
if (config.verbose && finalFirebaseProjectDir) {
|
|
16246
|
+
log.debug(`Firebase project directory: ${finalFirebaseProjectDir}`);
|
|
16247
|
+
}
|
|
16248
|
+
for (const [key, value] of Object.entries(secrets)) {
|
|
16249
|
+
if (platform === "firebase") {
|
|
16250
|
+
await setFirebaseSecret(
|
|
16251
|
+
key,
|
|
16252
|
+
value,
|
|
16253
|
+
config.projectId,
|
|
16254
|
+
config.dryRun,
|
|
16255
|
+
finalFirebaseProjectDir
|
|
16256
|
+
);
|
|
16257
|
+
} else if (platform === "vercel") {
|
|
16258
|
+
setVercelSecret(key, value, config.vercelProjectId, config.dryRun);
|
|
16259
|
+
}
|
|
16260
|
+
}
|
|
16261
|
+
if (config.dryRun) {
|
|
16262
|
+
log.success(
|
|
16263
|
+
`
|
|
16264
|
+
Dry run completed. No secrets were actually set to ${platform}.`
|
|
15470
16265
|
);
|
|
15471
16266
|
} else {
|
|
15472
|
-
|
|
15473
|
-
|
|
15474
|
-
shell: true
|
|
15475
|
-
});
|
|
16267
|
+
log.success(`
|
|
16268
|
+
All secrets synced successfully to ${platform}!`);
|
|
15476
16269
|
}
|
|
15477
|
-
|
|
15478
|
-
cliCache.set(cacheKey, isAvailable);
|
|
15479
|
-
return isAvailable;
|
|
16270
|
+
return 0;
|
|
15480
16271
|
} catch (err) {
|
|
15481
|
-
|
|
15482
|
-
|
|
16272
|
+
log.error(
|
|
16273
|
+
"Error syncing secrets:",
|
|
16274
|
+
DoNotDevError.from(err, "Sync-secrets failed", "cli-execution-error")
|
|
16275
|
+
);
|
|
16276
|
+
return 1;
|
|
15483
16277
|
}
|
|
15484
16278
|
}
|
|
15485
|
-
|
|
15486
|
-
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
}
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
}
|
|
15500
|
-
|
|
15501
|
-
|
|
16279
|
+
var sync_secrets_default;
|
|
16280
|
+
var init_sync_secrets = __esm({
|
|
16281
|
+
"packages/tooling/src/apps/sync-secrets.ts"() {
|
|
16282
|
+
"use strict";
|
|
16283
|
+
init_utils();
|
|
16284
|
+
init_cli_input();
|
|
16285
|
+
init_cli_output();
|
|
16286
|
+
init_errors();
|
|
16287
|
+
init_pathResolver();
|
|
16288
|
+
sync_secrets_default = main;
|
|
16289
|
+
}
|
|
16290
|
+
});
|
|
16291
|
+
|
|
16292
|
+
// packages/tooling/src/apps/deploy-supabase-functions.ts
|
|
16293
|
+
var deploy_supabase_functions_exports = {};
|
|
16294
|
+
__export(deploy_supabase_functions_exports, {
|
|
16295
|
+
deploySupabaseFunctions: () => deploySupabaseFunctions
|
|
16296
|
+
});
|
|
16297
|
+
import { execSync as execSync4 } from "node:child_process";
|
|
16298
|
+
async function deploySupabaseFunctions(appDir, config) {
|
|
16299
|
+
const supabaseDir = joinPath(appDir, "supabase");
|
|
16300
|
+
const functionsDir = joinPath(supabaseDir, "functions");
|
|
16301
|
+
if (!pathExists(functionsDir)) {
|
|
16302
|
+
log.warn("No supabase/functions/ directory found. Skipping Supabase functions deployment.");
|
|
16303
|
+
return;
|
|
16304
|
+
}
|
|
16305
|
+
requireCLI(
|
|
16306
|
+
CLI_TOOLS.SUPABASE,
|
|
16307
|
+
"Supabase CLI is required to deploy Edge Functions.\nInstall: https://supabase.com/docs/guides/cli"
|
|
16308
|
+
);
|
|
16309
|
+
const functionDirs = readdirSync2(functionsDir).filter((item) => {
|
|
16310
|
+
const itemPath = joinPath(functionsDir, item);
|
|
16311
|
+
const stat = statSync2(itemPath);
|
|
16312
|
+
return stat?.isDirectory() === true;
|
|
16313
|
+
}).filter((dir) => {
|
|
16314
|
+
const indexPath = joinPath(functionsDir, dir, "index.ts");
|
|
16315
|
+
return pathExists(indexPath);
|
|
16316
|
+
});
|
|
16317
|
+
if (functionDirs.length === 0) {
|
|
16318
|
+
log.warn("No Edge Functions found in supabase/functions/. Skipping deployment.");
|
|
16319
|
+
return;
|
|
16320
|
+
}
|
|
16321
|
+
log.info(`Found ${functionDirs.length} Edge Function(s): ${functionDirs.join(", ")}`);
|
|
16322
|
+
const s = Y2();
|
|
16323
|
+
for (const functionName of functionDirs) {
|
|
16324
|
+
s.start(`Deploying Edge Function: ${functionName}...`);
|
|
16325
|
+
try {
|
|
16326
|
+
execSync4(`supabase functions deploy ${functionName}`, {
|
|
16327
|
+
cwd: supabaseDir,
|
|
16328
|
+
stdio: config.verbose ? "inherit" : "pipe",
|
|
16329
|
+
env: {
|
|
16330
|
+
...process.env,
|
|
16331
|
+
DNDEV_APP_ROOT: appDir
|
|
16332
|
+
}
|
|
16333
|
+
});
|
|
16334
|
+
s.stop(`Deployed: ${functionName}`);
|
|
16335
|
+
} catch (error2) {
|
|
16336
|
+
s.stop(`Failed to deploy: ${functionName}`);
|
|
16337
|
+
throw new DoNotDevError(
|
|
16338
|
+
`Failed to deploy Supabase Edge Function: ${functionName}`,
|
|
16339
|
+
"deployment-failed",
|
|
16340
|
+
{ context: { functionName, error: error2 instanceof Error ? error2.message : String(error2) } }
|
|
16341
|
+
);
|
|
16342
|
+
}
|
|
16343
|
+
}
|
|
16344
|
+
log.success(`Successfully deployed ${functionDirs.length} Edge Function(s)`);
|
|
15502
16345
|
}
|
|
15503
|
-
|
|
15504
|
-
|
|
16346
|
+
var init_deploy_supabase_functions = __esm({
|
|
16347
|
+
"packages/tooling/src/apps/deploy-supabase-functions.ts"() {
|
|
16348
|
+
"use strict";
|
|
16349
|
+
init_utils();
|
|
16350
|
+
init_pathResolver();
|
|
16351
|
+
init_cli_output();
|
|
16352
|
+
init_cli_tools();
|
|
16353
|
+
init_errors();
|
|
16354
|
+
}
|
|
16355
|
+
});
|
|
16356
|
+
|
|
16357
|
+
// packages/cli/src/bin/commands/deploy.ts
|
|
16358
|
+
init_utils();
|
|
16359
|
+
|
|
16360
|
+
// packages/tooling/src/index.ts
|
|
16361
|
+
init_utils();
|
|
16362
|
+
|
|
16363
|
+
// packages/tooling/src/cli/index.ts
|
|
16364
|
+
init_utils();
|
|
16365
|
+
|
|
16366
|
+
// packages/tooling/src/utils/spawn-utils.ts
|
|
16367
|
+
init_utils();
|
|
16368
|
+
init_cli_output();
|
|
16369
|
+
init_errors();
|
|
16370
|
+
init_pathResolver();
|
|
16371
|
+
import { spawnSync, execSync } from "node:child_process";
|
|
16372
|
+
function clearConflictingAuth(env) {
|
|
16373
|
+
const cleaned = { ...env };
|
|
16374
|
+
delete cleaned.FIREBASE_TOKEN;
|
|
16375
|
+
delete cleaned.FIREBASE_AUTH_TOKEN;
|
|
16376
|
+
return cleaned;
|
|
15505
16377
|
}
|
|
15506
|
-
function
|
|
15507
|
-
return
|
|
16378
|
+
function createDeployEnv(serviceAccountPath) {
|
|
16379
|
+
return clearConflictingAuth({
|
|
16380
|
+
...process.env,
|
|
16381
|
+
GOOGLE_APPLICATION_CREDENTIALS: serviceAccountPath,
|
|
16382
|
+
NODE_OPTIONS: "",
|
|
16383
|
+
NODE_ENV: "production"
|
|
16384
|
+
});
|
|
15508
16385
|
}
|
|
15509
|
-
function
|
|
15510
|
-
const
|
|
15511
|
-
const
|
|
15512
|
-
|
|
15513
|
-
|
|
15514
|
-
|
|
15515
|
-
|
|
15516
|
-
|
|
15517
|
-
|
|
15518
|
-
|
|
15519
|
-
|
|
15520
|
-
|
|
15521
|
-
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
|
|
15525
|
-
|
|
15526
|
-
|
|
15527
|
-
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
],
|
|
15531
|
-
darwin: [
|
|
15532
|
-
"Install Node.js from: https://nodejs.org",
|
|
15533
|
-
"Or: brew install node",
|
|
15534
|
-
"npm comes bundled with Node.js"
|
|
15535
|
-
],
|
|
15536
|
-
linux: [
|
|
15537
|
-
"Install Node.js from: https://nodejs.org",
|
|
15538
|
-
"Or use your package manager: dnf install nodejs, apt install nodejs, etc.",
|
|
15539
|
-
"npm comes bundled with Node.js"
|
|
15540
|
-
]
|
|
15541
|
-
},
|
|
15542
|
-
yarn: {
|
|
15543
|
-
win32: ["npm install -g yarn", "Or: choco install yarn"],
|
|
15544
|
-
darwin: ["npm install -g yarn", "Or: brew install yarn"],
|
|
15545
|
-
linux: ["npm install -g yarn", "Or check your package manager"]
|
|
15546
|
-
},
|
|
15547
|
-
firebase: {
|
|
15548
|
-
win32: [
|
|
15549
|
-
"npm install -g firebase-tools",
|
|
15550
|
-
"Or download standalone binary: https://firebase.google.com/docs/cli#windows-standalone-binary"
|
|
15551
|
-
],
|
|
15552
|
-
darwin: [
|
|
15553
|
-
"npm install -g firebase-tools",
|
|
15554
|
-
"Or: brew install firebase-cli"
|
|
15555
|
-
],
|
|
15556
|
-
linux: [
|
|
15557
|
-
"npm install -g firebase-tools",
|
|
15558
|
-
"Or check your package manager (dnf, apt, pacman, etc.)"
|
|
15559
|
-
]
|
|
15560
|
-
},
|
|
15561
|
-
"sentry-cli": {
|
|
15562
|
-
win32: [
|
|
15563
|
-
"npm install -g @sentry/cli",
|
|
15564
|
-
"Or download from: https://github.com/getsentry/sentry-cli/releases"
|
|
15565
|
-
],
|
|
15566
|
-
darwin: [
|
|
15567
|
-
"npm install -g @sentry/cli",
|
|
15568
|
-
"Or: brew install getsentry/tools/sentry-cli"
|
|
15569
|
-
],
|
|
15570
|
-
linux: [
|
|
15571
|
-
"npm install -g @sentry/cli",
|
|
15572
|
-
"Or: curl -sL https://sentry.io/get-cli/ | bash"
|
|
15573
|
-
]
|
|
15574
|
-
},
|
|
15575
|
-
gh: {
|
|
15576
|
-
win32: [
|
|
15577
|
-
"Download from: https://cli.github.com",
|
|
15578
|
-
"Or: winget install --id GitHub.cli",
|
|
15579
|
-
"Or: choco install gh"
|
|
15580
|
-
],
|
|
15581
|
-
darwin: ["brew install gh", "Or download from: https://cli.github.com"],
|
|
15582
|
-
linux: [
|
|
15583
|
-
"See: https://github.com/cli/cli/blob/trunk/docs/install_linux.md",
|
|
15584
|
-
"dnf install gh",
|
|
15585
|
-
"apt install gh",
|
|
15586
|
-
"Or download from: https://cli.github.com"
|
|
15587
|
-
]
|
|
15588
|
-
},
|
|
15589
|
-
git: {
|
|
15590
|
-
win32: [
|
|
15591
|
-
"Download from: https://git-scm.com/download/win",
|
|
15592
|
-
"Or: winget install --id Git.Git"
|
|
15593
|
-
],
|
|
15594
|
-
darwin: ["brew install git", "Or: xcode-select --install"],
|
|
15595
|
-
linux: [
|
|
15596
|
-
"Use your package manager: dnf install git, apt install git, etc."
|
|
15597
|
-
]
|
|
15598
|
-
},
|
|
15599
|
-
tsx: {
|
|
15600
|
-
win32: ["npm install -g tsx"],
|
|
15601
|
-
darwin: ["npm install -g tsx"],
|
|
15602
|
-
linux: ["npm install -g tsx"]
|
|
15603
|
-
}
|
|
16386
|
+
function executeFirebaseCommand(args, options) {
|
|
16387
|
+
const deployEnv = createDeployEnv(options.serviceAccountPath);
|
|
16388
|
+
const spawnOptions = {
|
|
16389
|
+
cwd: options.cwd,
|
|
16390
|
+
stdio: "inherit",
|
|
16391
|
+
env: deployEnv
|
|
16392
|
+
};
|
|
16393
|
+
let result;
|
|
16394
|
+
result = spawnSync("firebase", args, { ...spawnOptions, shell: true });
|
|
16395
|
+
if (result.error) {
|
|
16396
|
+
return {
|
|
16397
|
+
success: false,
|
|
16398
|
+
status: 1,
|
|
16399
|
+
error: result.error
|
|
16400
|
+
};
|
|
16401
|
+
}
|
|
16402
|
+
const errorOutput = result.stderr?.toString() || result.stdout?.toString() || "";
|
|
16403
|
+
return {
|
|
16404
|
+
success: result.status === 0,
|
|
16405
|
+
status: result.status ?? 1,
|
|
16406
|
+
errorOutput
|
|
15604
16407
|
};
|
|
15605
|
-
const platformInstructions = instructions[tool]?.[platform] || instructions[tool]?.linux || [];
|
|
15606
|
-
return platformInstructions.join("\n \u2022 ");
|
|
15607
16408
|
}
|
|
15608
|
-
function
|
|
15609
|
-
const
|
|
15610
|
-
|
|
15611
|
-
const
|
|
15612
|
-
if (
|
|
15613
|
-
|
|
15614
|
-
M2.message(` \u2022 ${instructions}`);
|
|
16409
|
+
function buildFirebaseDeployArgs(deployTargets, projectId, debug, force) {
|
|
16410
|
+
const targets = Array.isArray(deployTargets) ? deployTargets : [deployTargets];
|
|
16411
|
+
const targetString = targets.join(",");
|
|
16412
|
+
const args = ["deploy", "--only", targetString, "--non-interactive"];
|
|
16413
|
+
if (projectId) {
|
|
16414
|
+
args.push("--project", projectId);
|
|
15615
16415
|
}
|
|
15616
|
-
if (
|
|
15617
|
-
|
|
15618
|
-
${additionalContext}`);
|
|
16416
|
+
if (debug) {
|
|
16417
|
+
args.push("--debug");
|
|
15619
16418
|
}
|
|
15620
|
-
|
|
15621
|
-
|
|
15622
|
-
|
|
15623
|
-
|
|
15624
|
-
|
|
15625
|
-
|
|
16419
|
+
if (force) {
|
|
16420
|
+
args.push("--force");
|
|
16421
|
+
}
|
|
16422
|
+
return args;
|
|
16423
|
+
}
|
|
16424
|
+
function analyzeDeploymentError(errorOutput) {
|
|
16425
|
+
const isRetryError = errorOutput.includes("retries exhausted") || errorOutput.includes("retry");
|
|
16426
|
+
const isHashError = errorOutput.includes("hash") || errorOutput.includes("content hash");
|
|
16427
|
+
const isAuthError = errorOutput.includes("401") || errorOutput.includes("authentication") || errorOutput.includes("credentials");
|
|
16428
|
+
const tips = [];
|
|
16429
|
+
if (isRetryError || isHashError) {
|
|
16430
|
+
tips.push("Try deploying with --debug flag for more details");
|
|
16431
|
+
tips.push("Disable VPN if active - VPNs can corrupt file uploads");
|
|
16432
|
+
tips.push("Clear Firebase cache: Remove .firebase directory");
|
|
16433
|
+
tips.push(
|
|
16434
|
+
"Ensure no file watchers or antivirus are modifying files during upload"
|
|
15626
16435
|
);
|
|
15627
|
-
} else {
|
|
15628
|
-
M2.message(" \u2022 Check with: which " + tool);
|
|
15629
|
-
M2.message(" \u2022 Common locations:");
|
|
15630
|
-
M2.message(" - ~/.nvm/versions/node/*/bin/" + tool);
|
|
15631
|
-
M2.message(" - ~/.bun/bin/" + tool);
|
|
15632
|
-
M2.message(" - /usr/local/bin/" + tool);
|
|
15633
|
-
M2.message(" - /usr/bin/" + tool);
|
|
15634
16436
|
}
|
|
16437
|
+
if (isAuthError) {
|
|
16438
|
+
tips.push("Verify service account has required IAM roles");
|
|
16439
|
+
tips.push("Check service account key file is valid JSON");
|
|
16440
|
+
tips.push("Ensure FIREBASE_TOKEN and FIREBASE_AUTH_TOKEN are cleared");
|
|
16441
|
+
}
|
|
16442
|
+
return { isRetryError, isHashError, isAuthError, tips };
|
|
15635
16443
|
}
|
|
15636
|
-
function
|
|
15637
|
-
|
|
15638
|
-
|
|
15639
|
-
|
|
15640
|
-
|
|
15641
|
-
|
|
15642
|
-
|
|
15643
|
-
|
|
15644
|
-
|
|
15645
|
-
|
|
15646
|
-
|
|
15647
|
-
|
|
15648
|
-
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
16444
|
+
function logTroubleshootingTips(tips) {
|
|
16445
|
+
if (tips.length > 0) {
|
|
16446
|
+
log.warn("\nTroubleshooting Tips:");
|
|
16447
|
+
tips.forEach((tip) => log.warn(` - ${tip}`));
|
|
16448
|
+
log.warn("");
|
|
16449
|
+
}
|
|
16450
|
+
}
|
|
16451
|
+
function handleDeploymentFailure(result, command, serviceAccountPath) {
|
|
16452
|
+
const analysis = analyzeDeploymentError(result.errorOutput || "");
|
|
16453
|
+
logTroubleshootingTips(analysis.tips);
|
|
16454
|
+
throw new DoNotDevError(
|
|
16455
|
+
`Firebase deployment failed with exit code ${result.status}`,
|
|
16456
|
+
"command-failed",
|
|
16457
|
+
{
|
|
16458
|
+
context: {
|
|
16459
|
+
command,
|
|
16460
|
+
serviceAccountPath,
|
|
16461
|
+
troubleshootingTips: analysis.tips.length > 0 ? analysis.tips : void 0
|
|
16462
|
+
}
|
|
16463
|
+
}
|
|
16464
|
+
);
|
|
16465
|
+
}
|
|
16466
|
+
function safeRemove(path, options = {}) {
|
|
16467
|
+
if (!pathExists(path)) {
|
|
16468
|
+
return false;
|
|
16469
|
+
}
|
|
16470
|
+
try {
|
|
16471
|
+
removeSync(path);
|
|
16472
|
+
if (options.logSuccess) {
|
|
16473
|
+
log.debug(options.successMessage ?? `Removed: ${path}`);
|
|
16474
|
+
}
|
|
16475
|
+
return true;
|
|
16476
|
+
} catch (error2) {
|
|
16477
|
+
const message = options.failureMessage ?? `Could not remove ${path}: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
16478
|
+
if (options.silent !== false) {
|
|
16479
|
+
log.warn(message);
|
|
16480
|
+
}
|
|
16481
|
+
return false;
|
|
15652
16482
|
}
|
|
15653
|
-
return true;
|
|
15654
16483
|
}
|
|
15655
16484
|
|
|
16485
|
+
// packages/tooling/src/apps/deploy.ts
|
|
16486
|
+
init_utils();
|
|
16487
|
+
import { execSync as execSync5 } from "node:child_process";
|
|
16488
|
+
|
|
15656
16489
|
// packages/tooling/src/apps/deploy-frontend.ts
|
|
16490
|
+
init_utils();
|
|
15657
16491
|
async function deployFrontend(appDir, serviceAccountPath, projectId, config) {
|
|
15658
16492
|
const s = Y2();
|
|
15659
16493
|
s.start("Deploying frontend to Firebase Hosting...");
|
|
15660
|
-
const args = buildFirebaseDeployArgs("hosting", projectId, config.debug);
|
|
16494
|
+
const args = buildFirebaseDeployArgs("hosting", projectId, config.debug, config.force ?? true);
|
|
15661
16495
|
const result = executeFirebaseCommand(args, {
|
|
15662
16496
|
cwd: appDir,
|
|
15663
16497
|
serviceAccountPath,
|
|
@@ -15679,11 +16513,31 @@ async function deployFrontend(appDir, serviceAccountPath, projectId, config) {
|
|
|
15679
16513
|
s.stop("Frontend deployed successfully");
|
|
15680
16514
|
}
|
|
15681
16515
|
|
|
16516
|
+
// packages/tooling/src/apps/deploy-vercel-frontend.ts
|
|
16517
|
+
init_utils();
|
|
16518
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
16519
|
+
async function deployVercelFrontend(appDir, _config) {
|
|
16520
|
+
const s = Y2();
|
|
16521
|
+
s.start("Deploying frontend to Vercel...");
|
|
16522
|
+
try {
|
|
16523
|
+
execSync2("npx vercel --prod --yes", {
|
|
16524
|
+
cwd: appDir,
|
|
16525
|
+
stdio: "inherit"
|
|
16526
|
+
});
|
|
16527
|
+
s.stop("Frontend deployed to Vercel");
|
|
16528
|
+
} catch (err) {
|
|
16529
|
+
s.stop("Vercel deployment failed");
|
|
16530
|
+
throw err;
|
|
16531
|
+
}
|
|
16532
|
+
}
|
|
16533
|
+
|
|
15682
16534
|
// packages/tooling/src/apps/deploy-functions.ts
|
|
15683
16535
|
init_utils();
|
|
15684
16536
|
var import_yaml = __toESM(require_dist(), 1);
|
|
15685
|
-
import { execSync as
|
|
16537
|
+
import { execSync as execSync3, spawnSync as spawnSync3 } from "node:child_process";
|
|
15686
16538
|
init_pathResolver();
|
|
16539
|
+
init_cli_tools();
|
|
16540
|
+
init_typed_file_operations();
|
|
15687
16541
|
function backupFiles(functionsDir) {
|
|
15688
16542
|
const backupDir = joinPath(functionsDir, ".deploy-backup");
|
|
15689
16543
|
const packageJsonPath = joinPath(functionsDir, "package.json");
|
|
@@ -15693,14 +16547,16 @@ function backupFiles(functionsDir) {
|
|
|
15693
16547
|
const backupPackageJson = joinPath(backupDir, "package.json");
|
|
15694
16548
|
const backupPackageLockJson = joinPath(backupDir, "package-lock.json");
|
|
15695
16549
|
if (pathExists(packageJsonPath)) {
|
|
15696
|
-
const
|
|
16550
|
+
const contentRaw = readSync(packageJsonPath, { format: "text" });
|
|
16551
|
+
const content = typeof contentRaw === "string" ? contentRaw : null;
|
|
15697
16552
|
if (!content) {
|
|
15698
16553
|
throw new Error(`Failed to read package.json: ${packageJsonPath}`);
|
|
15699
16554
|
}
|
|
15700
16555
|
writeSync(backupPackageJson, content, { overwrite: true });
|
|
15701
16556
|
}
|
|
15702
16557
|
if (pathExists(packageLockJsonPath)) {
|
|
15703
|
-
const
|
|
16558
|
+
const contentRaw = readSync(packageLockJsonPath, { format: "text" });
|
|
16559
|
+
const content = typeof contentRaw === "string" ? contentRaw : null;
|
|
15704
16560
|
if (!content) {
|
|
15705
16561
|
throw new Error(
|
|
15706
16562
|
`Failed to read package-lock.json: ${packageLockJsonPath}`
|
|
@@ -15727,8 +16583,8 @@ function generateCleanPackageJson(functionsDir) {
|
|
|
15727
16583
|
"file-not-found"
|
|
15728
16584
|
);
|
|
15729
16585
|
}
|
|
15730
|
-
const packageJson =
|
|
15731
|
-
if (!packageJson) {
|
|
16586
|
+
const packageJson = readPackageJson(packageJsonPath);
|
|
16587
|
+
if (!packageJson.name) {
|
|
15732
16588
|
throw new Error(
|
|
15733
16589
|
`package.json is empty or invalid JSON at ${packageJsonPath}`
|
|
15734
16590
|
);
|
|
@@ -15820,7 +16676,9 @@ function getDeployedFunctionNames(functionsDir) {
|
|
|
15820
16676
|
}
|
|
15821
16677
|
return Object.keys(parsed.endpoints);
|
|
15822
16678
|
} catch (error2) {
|
|
15823
|
-
log.warn(
|
|
16679
|
+
log.warn(
|
|
16680
|
+
`Failed to parse functions.yaml: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
16681
|
+
);
|
|
15824
16682
|
return [];
|
|
15825
16683
|
}
|
|
15826
16684
|
}
|
|
@@ -15830,12 +16688,16 @@ function updateCloudRunIAM(functionNames, projectId, region, serviceAccountPath,
|
|
|
15830
16688
|
}
|
|
15831
16689
|
if (!checkCLI("gcloud", ["--version"])) {
|
|
15832
16690
|
log.warn("gcloud CLI not found. Skipping Cloud Run IAM updates.");
|
|
15833
|
-
log.warn(
|
|
16691
|
+
log.warn(
|
|
16692
|
+
"Functions may require manual IAM configuration for CORS preflight."
|
|
16693
|
+
);
|
|
15834
16694
|
log.warn("Install gcloud: https://cloud.google.com/sdk/docs/install");
|
|
15835
16695
|
return;
|
|
15836
16696
|
}
|
|
15837
16697
|
const s = Y2();
|
|
15838
|
-
s.start(
|
|
16698
|
+
s.start(
|
|
16699
|
+
`Updating Cloud Run IAM for ${functionNames.length} functions (CORS preflight)...`
|
|
16700
|
+
);
|
|
15839
16701
|
const deployEnv = createDeployEnv(serviceAccountPath);
|
|
15840
16702
|
let successCount = 0;
|
|
15841
16703
|
let failCount = 0;
|
|
@@ -15874,7 +16736,9 @@ function updateCloudRunIAM(functionNames, projectId, region, serviceAccountPath,
|
|
|
15874
16736
|
}
|
|
15875
16737
|
} catch (error2) {
|
|
15876
16738
|
failCount++;
|
|
15877
|
-
log.warn(
|
|
16739
|
+
log.warn(
|
|
16740
|
+
`Error updating IAM for ${funcName}: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
16741
|
+
);
|
|
15878
16742
|
}
|
|
15879
16743
|
}
|
|
15880
16744
|
if (successCount > 0) {
|
|
@@ -15883,7 +16747,9 @@ function updateCloudRunIAM(functionNames, projectId, region, serviceAccountPath,
|
|
|
15883
16747
|
s.stop("Cloud Run IAM update completed with errors");
|
|
15884
16748
|
}
|
|
15885
16749
|
if (failCount > 0) {
|
|
15886
|
-
log.warn(
|
|
16750
|
+
log.warn(
|
|
16751
|
+
`${failCount} function(s) failed IAM update. They may require manual configuration.`
|
|
16752
|
+
);
|
|
15887
16753
|
}
|
|
15888
16754
|
}
|
|
15889
16755
|
function getFirebaseRegion(functionsDir) {
|
|
@@ -15924,7 +16790,11 @@ async function autoSyncSecrets(functionsDir, projectId, config) {
|
|
|
15924
16790
|
const envContent = readSync(envPath, { format: "text" });
|
|
15925
16791
|
if (!envContent) return;
|
|
15926
16792
|
const reservedPrefixes = ["X_GOOGLE_", "FIREBASE_", "EXT_", "GCLOUD_"];
|
|
15927
|
-
const configOnlyKeys = [
|
|
16793
|
+
const configOnlyKeys = [
|
|
16794
|
+
"FIREBASE_REGION",
|
|
16795
|
+
"FIREBASE_PROJECT_ID",
|
|
16796
|
+
"FIREBASE_AUTH_DOMAIN"
|
|
16797
|
+
];
|
|
15928
16798
|
const secrets = [];
|
|
15929
16799
|
for (const line of envContent.split("\n")) {
|
|
15930
16800
|
const trimmed = line.trim();
|
|
@@ -15943,7 +16813,9 @@ async function autoSyncSecrets(functionsDir, projectId, config) {
|
|
|
15943
16813
|
return;
|
|
15944
16814
|
}
|
|
15945
16815
|
const s = Y2();
|
|
15946
|
-
s.start(
|
|
16816
|
+
s.start(
|
|
16817
|
+
`Syncing ${secrets.length} secret(s) to Firebase Secret Manager...`
|
|
16818
|
+
);
|
|
15947
16819
|
const firebaseCmd = process.platform === "win32" ? "firebase.cmd" : "firebase";
|
|
15948
16820
|
let successCount = 0;
|
|
15949
16821
|
let failCount = 0;
|
|
@@ -15983,8 +16855,12 @@ async function autoSyncSecrets(functionsDir, projectId, config) {
|
|
|
15983
16855
|
log.warn('Could not sync secrets. Run "dn sync-secrets" manually.');
|
|
15984
16856
|
}
|
|
15985
16857
|
} catch (error2) {
|
|
15986
|
-
log.debug(
|
|
15987
|
-
|
|
16858
|
+
log.debug(
|
|
16859
|
+
`Could not sync secrets: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
16860
|
+
);
|
|
16861
|
+
log.info(
|
|
16862
|
+
'Run "dn sync-secrets" manually to sync secrets to Firebase Secret Manager.'
|
|
16863
|
+
);
|
|
15988
16864
|
}
|
|
15989
16865
|
}
|
|
15990
16866
|
async function deployFunctions(appDir, serviceAccountPath, projectId, config) {
|
|
@@ -16027,7 +16903,7 @@ To fix this, run:
|
|
|
16027
16903
|
const s2 = Y2();
|
|
16028
16904
|
s2.start("Building functions...");
|
|
16029
16905
|
try {
|
|
16030
|
-
|
|
16906
|
+
execSync3("bun run build", {
|
|
16031
16907
|
cwd: functionsDir,
|
|
16032
16908
|
stdio: config.verbose ? "inherit" : "pipe"
|
|
16033
16909
|
});
|
|
@@ -16045,7 +16921,8 @@ To fix this, run:
|
|
|
16045
16921
|
"functions",
|
|
16046
16922
|
projectId,
|
|
16047
16923
|
config.debug,
|
|
16048
|
-
config.force
|
|
16924
|
+
config.force ?? true
|
|
16925
|
+
// Default --force for functions (auto-sets artifact cleanup policy)
|
|
16049
16926
|
);
|
|
16050
16927
|
const result = executeFirebaseCommand(args, {
|
|
16051
16928
|
cwd: firebaseProjectDir,
|
|
@@ -16069,7 +16946,13 @@ To fix this, run:
|
|
|
16069
16946
|
const functionNames = getDeployedFunctionNames(functionsDir);
|
|
16070
16947
|
if (functionNames.length > 0) {
|
|
16071
16948
|
const region = getFirebaseRegion(functionsDir);
|
|
16072
|
-
updateCloudRunIAM(
|
|
16949
|
+
updateCloudRunIAM(
|
|
16950
|
+
functionNames,
|
|
16951
|
+
projectId,
|
|
16952
|
+
region,
|
|
16953
|
+
serviceAccountPath,
|
|
16954
|
+
config.verbose ?? false
|
|
16955
|
+
);
|
|
16073
16956
|
}
|
|
16074
16957
|
await autoSyncSecrets(functionsDir, projectId, config);
|
|
16075
16958
|
} finally {
|
|
@@ -16096,7 +16979,7 @@ async function deployRules(appDir, serviceAccountPath, projectId, config, option
|
|
|
16096
16979
|
const targetNames = targets.join(", ");
|
|
16097
16980
|
const s = Y2();
|
|
16098
16981
|
s.start(`Deploying ${targetNames}...`);
|
|
16099
|
-
const args = buildFirebaseDeployArgs(targets, projectId, config.debug);
|
|
16982
|
+
const args = buildFirebaseDeployArgs(targets, projectId, config.debug, config.force ?? true);
|
|
16100
16983
|
const result = executeFirebaseCommand(args, {
|
|
16101
16984
|
cwd: appDir,
|
|
16102
16985
|
serviceAccountPath,
|
|
@@ -16122,6 +17005,27 @@ async function deployRules(appDir, serviceAccountPath, projectId, config, option
|
|
|
16122
17005
|
init_utils();
|
|
16123
17006
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
16124
17007
|
init_pathResolver();
|
|
17008
|
+
init_typed_file_operations();
|
|
17009
|
+
|
|
17010
|
+
// packages/tooling/src/utils/error-handling.ts
|
|
17011
|
+
init_utils();
|
|
17012
|
+
function isError(error2) {
|
|
17013
|
+
return error2 instanceof Error;
|
|
17014
|
+
}
|
|
17015
|
+
function getErrorMessage(error2) {
|
|
17016
|
+
if (isError(error2)) {
|
|
17017
|
+
return error2.message;
|
|
17018
|
+
}
|
|
17019
|
+
if (typeof error2 === "string") {
|
|
17020
|
+
return error2;
|
|
17021
|
+
}
|
|
17022
|
+
if (error2 && typeof error2 === "object" && "message" in error2) {
|
|
17023
|
+
return String(error2.message);
|
|
17024
|
+
}
|
|
17025
|
+
return String(error2);
|
|
17026
|
+
}
|
|
17027
|
+
|
|
17028
|
+
// packages/tooling/src/apps/deploy-utils.ts
|
|
16125
17029
|
function detectAvailableApps() {
|
|
16126
17030
|
const currentDir = process.cwd();
|
|
16127
17031
|
const appsDir = joinPath(currentDir, "apps");
|
|
@@ -16133,8 +17037,11 @@ function detectAvailableApps() {
|
|
|
16133
17037
|
const stat = statSync2(itemPath);
|
|
16134
17038
|
return stat?.isDirectory() === true;
|
|
16135
17039
|
}).filter((app) => {
|
|
16136
|
-
const
|
|
16137
|
-
|
|
17040
|
+
const appDir = joinPath(appsDir, app);
|
|
17041
|
+
const firebaseJsonPath = joinPath(appDir, "firebase.json");
|
|
17042
|
+
const supabaseDir = joinPath(appDir, "supabase");
|
|
17043
|
+
const vercelJsonPath = joinPath(appDir, "vercel.json");
|
|
17044
|
+
return pathExists(firebaseJsonPath) || pathExists(supabaseDir) || pathExists(vercelJsonPath);
|
|
16138
17045
|
}).sort();
|
|
16139
17046
|
}
|
|
16140
17047
|
function detectAppDir(appName) {
|
|
@@ -16173,40 +17080,7 @@ function validateServiceAccount(appDir, options) {
|
|
|
16173
17080
|
};
|
|
16174
17081
|
}
|
|
16175
17082
|
try {
|
|
16176
|
-
const keyData =
|
|
16177
|
-
if (!keyData) {
|
|
16178
|
-
return {
|
|
16179
|
-
valid: false,
|
|
16180
|
-
info: {
|
|
16181
|
-
path: keyPath,
|
|
16182
|
-
projectId: "",
|
|
16183
|
-
clientEmail: "",
|
|
16184
|
-
valid: false,
|
|
16185
|
-
errors: ["Service account key file is empty or invalid JSON"]
|
|
16186
|
-
}
|
|
16187
|
-
};
|
|
16188
|
-
}
|
|
16189
|
-
if (!keyData.project_id) {
|
|
16190
|
-
errors.push("Missing required field: project_id");
|
|
16191
|
-
}
|
|
16192
|
-
if (!keyData.private_key) {
|
|
16193
|
-
errors.push("Missing required field: private_key");
|
|
16194
|
-
}
|
|
16195
|
-
if (!keyData.client_email) {
|
|
16196
|
-
errors.push("Missing required field: client_email");
|
|
16197
|
-
}
|
|
16198
|
-
if (errors.length > 0) {
|
|
16199
|
-
return {
|
|
16200
|
-
valid: false,
|
|
16201
|
-
info: {
|
|
16202
|
-
path: keyPath,
|
|
16203
|
-
projectId: keyData.project_id || "",
|
|
16204
|
-
clientEmail: keyData.client_email || "",
|
|
16205
|
-
valid: false,
|
|
16206
|
-
errors
|
|
16207
|
-
}
|
|
16208
|
-
};
|
|
16209
|
-
}
|
|
17083
|
+
const keyData = readServiceAccountKey(keyPath);
|
|
16210
17084
|
return {
|
|
16211
17085
|
valid: true,
|
|
16212
17086
|
info: {
|
|
@@ -16225,9 +17099,7 @@ function validateServiceAccount(appDir, options) {
|
|
|
16225
17099
|
projectId: "",
|
|
16226
17100
|
clientEmail: "",
|
|
16227
17101
|
valid: false,
|
|
16228
|
-
errors: [
|
|
16229
|
-
`Invalid JSON format: ${error2 instanceof DoNotDevError ? error2.message : error2 instanceof Error ? error2.message : String(error2)}`
|
|
16230
|
-
]
|
|
17102
|
+
errors: [`Invalid service account key: ${getErrorMessage(error2)}`]
|
|
16231
17103
|
}
|
|
16232
17104
|
};
|
|
16233
17105
|
}
|
|
@@ -16246,12 +17118,7 @@ function validateFirebaseJson(appDir) {
|
|
|
16246
17118
|
};
|
|
16247
17119
|
}
|
|
16248
17120
|
try {
|
|
16249
|
-
const config =
|
|
16250
|
-
if (!config) {
|
|
16251
|
-
throw new Error(
|
|
16252
|
-
`firebase.json is empty or invalid JSON at ${firebaseJsonPath}`
|
|
16253
|
-
);
|
|
16254
|
-
}
|
|
17121
|
+
const config = readFirebaseJson(firebaseJsonPath);
|
|
16255
17122
|
const hasHosting = !!config.hosting;
|
|
16256
17123
|
const hasFunctions = !!config.functions && Array.isArray(config.functions);
|
|
16257
17124
|
const hasFirestoreRules = !!config.firestore?.rules && pathExists(joinPath(appDir, config.firestore.rules));
|
|
@@ -16275,9 +17142,7 @@ function validateFirebaseJson(appDir) {
|
|
|
16275
17142
|
hasFirestoreRules: false,
|
|
16276
17143
|
hasFirestoreIndexes: false,
|
|
16277
17144
|
hasStorageRules: false,
|
|
16278
|
-
errors: [
|
|
16279
|
-
`Invalid JSON format: ${error2 instanceof DoNotDevError ? error2.message : error2 instanceof Error ? error2.message : String(error2)}`
|
|
16280
|
-
]
|
|
17145
|
+
errors: [`Invalid firebase.json: ${getErrorMessage(error2)}`]
|
|
16281
17146
|
};
|
|
16282
17147
|
}
|
|
16283
17148
|
}
|
|
@@ -16303,11 +17168,11 @@ function readStagingProject(startDir) {
|
|
|
16303
17168
|
const firebasercPath = joinPath(current, ".firebaserc");
|
|
16304
17169
|
if (pathExists(firebasercPath)) {
|
|
16305
17170
|
try {
|
|
16306
|
-
const firebaserc =
|
|
17171
|
+
const firebaserc = readFirebaserc(firebasercPath);
|
|
16307
17172
|
if (firebaserc?.projects?.staging) {
|
|
16308
17173
|
return firebaserc.projects.staging;
|
|
16309
17174
|
}
|
|
16310
|
-
} catch {
|
|
17175
|
+
} catch (error2) {
|
|
16311
17176
|
}
|
|
16312
17177
|
}
|
|
16313
17178
|
const parent = joinPath(current, "..");
|
|
@@ -16393,12 +17258,87 @@ function clearFirebaseCache(appDir) {
|
|
|
16393
17258
|
}
|
|
16394
17259
|
}
|
|
16395
17260
|
|
|
17261
|
+
// packages/tooling/src/utils/provider-detection.ts
|
|
17262
|
+
init_utils();
|
|
17263
|
+
init_pathResolver();
|
|
17264
|
+
function detectProvider(appDir) {
|
|
17265
|
+
const firebaseJsonPath = joinPath(appDir, "firebase.json");
|
|
17266
|
+
const supabaseDir = joinPath(appDir, "supabase");
|
|
17267
|
+
const supabaseConfigPath = joinPath(supabaseDir, "config.toml");
|
|
17268
|
+
const supabaseFunctionsDir = joinPath(supabaseDir, "functions");
|
|
17269
|
+
const supabaseMigrationsDir = joinPath(supabaseDir, "migrations");
|
|
17270
|
+
const hasFirebase = pathExists(firebaseJsonPath);
|
|
17271
|
+
const hasSupabase = pathExists(supabaseDir) || pathExists(supabaseConfigPath);
|
|
17272
|
+
let provider = "unknown";
|
|
17273
|
+
if (hasFirebase && hasSupabase) {
|
|
17274
|
+
provider = "both";
|
|
17275
|
+
} else if (hasFirebase) {
|
|
17276
|
+
provider = "firebase";
|
|
17277
|
+
} else if (hasSupabase) {
|
|
17278
|
+
provider = "supabase";
|
|
17279
|
+
}
|
|
17280
|
+
let firebaseConfig;
|
|
17281
|
+
if (hasFirebase) {
|
|
17282
|
+
try {
|
|
17283
|
+
const config = readSync(firebaseJsonPath, { format: "json" });
|
|
17284
|
+
if (config && typeof config === "object" && "projectId" in config) {
|
|
17285
|
+
const firebaseConfigObj = config;
|
|
17286
|
+
firebaseConfig = {
|
|
17287
|
+
projectId: firebaseConfigObj.projectId,
|
|
17288
|
+
hasHosting: !!firebaseConfigObj.hosting,
|
|
17289
|
+
hasFunctions: !!firebaseConfigObj.functions,
|
|
17290
|
+
hasFirestoreRules: !!firebaseConfigObj.firestore?.rules,
|
|
17291
|
+
hasStorageRules: !!firebaseConfigObj.storage?.rules
|
|
17292
|
+
};
|
|
17293
|
+
} else {
|
|
17294
|
+
throw new Error("Invalid firebase.json structure");
|
|
17295
|
+
}
|
|
17296
|
+
} catch {
|
|
17297
|
+
firebaseConfig = {
|
|
17298
|
+
hasHosting: false,
|
|
17299
|
+
hasFunctions: false,
|
|
17300
|
+
hasFirestoreRules: false,
|
|
17301
|
+
hasStorageRules: false
|
|
17302
|
+
};
|
|
17303
|
+
}
|
|
17304
|
+
}
|
|
17305
|
+
let supabaseConfig;
|
|
17306
|
+
if (hasSupabase) {
|
|
17307
|
+
let url;
|
|
17308
|
+
try {
|
|
17309
|
+
const envPath = joinPath(appDir, ".env");
|
|
17310
|
+
if (pathExists(envPath)) {
|
|
17311
|
+
const envContent = readSync(envPath);
|
|
17312
|
+
const urlMatch = envContent.match(/VITE_SUPABASE_URL=(.+)/);
|
|
17313
|
+
if (urlMatch && urlMatch[1]) {
|
|
17314
|
+
url = urlMatch[1].trim();
|
|
17315
|
+
}
|
|
17316
|
+
}
|
|
17317
|
+
} catch {
|
|
17318
|
+
}
|
|
17319
|
+
supabaseConfig = {
|
|
17320
|
+
url,
|
|
17321
|
+
hasFunctions: pathExists(supabaseFunctionsDir),
|
|
17322
|
+
hasMigrations: pathExists(supabaseMigrationsDir)
|
|
17323
|
+
};
|
|
17324
|
+
}
|
|
17325
|
+
return {
|
|
17326
|
+
provider,
|
|
17327
|
+
hasFirebase,
|
|
17328
|
+
hasSupabase,
|
|
17329
|
+
firebaseConfig,
|
|
17330
|
+
supabaseConfig
|
|
17331
|
+
};
|
|
17332
|
+
}
|
|
17333
|
+
|
|
16396
17334
|
// packages/tooling/src/apps/deploy.ts
|
|
17335
|
+
init_cli_input();
|
|
16397
17336
|
init_cli_output();
|
|
16398
17337
|
init_cli_output();
|
|
17338
|
+
init_cli_tools();
|
|
16399
17339
|
init_errors();
|
|
16400
17340
|
init_pathResolver();
|
|
16401
|
-
async function
|
|
17341
|
+
async function main2(options = {}) {
|
|
16402
17342
|
const isStaging = options.staging ?? false;
|
|
16403
17343
|
const config = {
|
|
16404
17344
|
app: options.app,
|
|
@@ -16406,27 +17346,43 @@ async function main(options = {}) {
|
|
|
16406
17346
|
verbose: options.verbose ?? false,
|
|
16407
17347
|
skipBuild: options.skipBuild ?? false,
|
|
16408
17348
|
debug: options.debug ?? false,
|
|
16409
|
-
force: options.force
|
|
17349
|
+
force: options.force,
|
|
16410
17350
|
staging: isStaging
|
|
16411
17351
|
};
|
|
16412
17352
|
try {
|
|
16413
|
-
|
|
16414
|
-
|
|
16415
|
-
|
|
16416
|
-
"
|
|
17353
|
+
const projectRoot = process.cwd();
|
|
17354
|
+
const providerInfo = detectProvider(projectRoot);
|
|
17355
|
+
Ie(
|
|
17356
|
+
isStaging ? "DoNotDev Staging Deployment" : providerInfo.provider === "supabase" ? "DoNotDev Supabase Deployment" : providerInfo.provider === "both" ? "DoNotDev Deployment (Firebase + Supabase)" : "DoNotDev Firebase Deployment"
|
|
16417
17357
|
);
|
|
17358
|
+
if (providerInfo.hasFirebase) {
|
|
17359
|
+
requireCLI(
|
|
17360
|
+
CLI_TOOLS.FIREBASE,
|
|
17361
|
+
"This script uses service account authentication.\nThe Firebase CLI is only needed as a deployment tool, not for authentication."
|
|
17362
|
+
);
|
|
17363
|
+
}
|
|
17364
|
+
if (providerInfo.hasSupabase && providerInfo.supabaseConfig?.hasFunctions) {
|
|
17365
|
+
requireCLI(
|
|
17366
|
+
CLI_TOOLS.SUPABASE,
|
|
17367
|
+
"Supabase CLI is required to deploy Edge Functions.\nInstall: https://supabase.com/docs/guides/cli"
|
|
17368
|
+
);
|
|
17369
|
+
}
|
|
16418
17370
|
const COMMAND_NAMES = ["deploy", "staging", "uat"];
|
|
16419
17371
|
const cliArgs = process.argv.slice(2);
|
|
16420
17372
|
let appName = config.app || (cliArgs[0] && !cliArgs[0].startsWith("--") && !COMMAND_NAMES.includes(cliArgs[0]) ? cliArgs[0] : void 0);
|
|
16421
17373
|
if (!appName) {
|
|
16422
17374
|
const availableApps = detectAvailableApps();
|
|
16423
17375
|
if (availableApps.length === 0) {
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
|
|
17376
|
+
if (providerInfo.hasSupabase && !providerInfo.hasFirebase) {
|
|
17377
|
+
log.info("Supabase project detected. Deploying Supabase resources...");
|
|
17378
|
+
} else {
|
|
17379
|
+
log.info("No apps with firebase.json or supabase/ directory found.");
|
|
17380
|
+
log.info(
|
|
17381
|
+
"To deploy, ensure your app has a firebase.json or supabase/ configuration."
|
|
17382
|
+
);
|
|
17383
|
+
log.info("Run from a DoNotDev project, or create one with: dndev init");
|
|
17384
|
+
return;
|
|
17385
|
+
}
|
|
16430
17386
|
}
|
|
16431
17387
|
if (availableApps.length === 1) {
|
|
16432
17388
|
appName = availableApps[0];
|
|
@@ -16442,55 +17398,92 @@ async function main(options = {}) {
|
|
|
16442
17398
|
log.error("App name is required but was not provided.");
|
|
16443
17399
|
process.exit(1);
|
|
16444
17400
|
}
|
|
16445
|
-
const appDir = detectAppDir(appName);
|
|
17401
|
+
const appDir = appName ? detectAppDir(appName) : projectRoot;
|
|
17402
|
+
const appProviderInfo = detectProvider(appDir);
|
|
17403
|
+
const hasVercelConfig = pathExists(joinPath(appDir, "vercel.json"));
|
|
16446
17404
|
let deploymentType = config.deploymentType;
|
|
16447
17405
|
if (!deploymentType) {
|
|
16448
|
-
const firebaseConfig2 = validateFirebaseJson(appDir);
|
|
16449
17406
|
const choices = [];
|
|
16450
|
-
if (
|
|
16451
|
-
|
|
16452
|
-
|
|
16453
|
-
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16470
|
-
|
|
17407
|
+
if (appProviderInfo.hasFirebase && appProviderInfo.firebaseConfig) {
|
|
17408
|
+
const fbConfig = appProviderInfo.firebaseConfig;
|
|
17409
|
+
if (fbConfig.hasHosting) {
|
|
17410
|
+
choices.push({
|
|
17411
|
+
title: "Frontend only (Firebase Hosting)",
|
|
17412
|
+
value: "frontend",
|
|
17413
|
+
hint: "Deploy Firebase hosting"
|
|
17414
|
+
});
|
|
17415
|
+
}
|
|
17416
|
+
if (fbConfig.hasFunctions) {
|
|
17417
|
+
choices.push({
|
|
17418
|
+
title: "Functions only (Firebase Cloud Functions)",
|
|
17419
|
+
value: "functions",
|
|
17420
|
+
hint: "Deploy Firebase cloud functions"
|
|
17421
|
+
});
|
|
17422
|
+
}
|
|
17423
|
+
const hasRules = fbConfig.hasFirestoreRules || fbConfig.hasStorageRules;
|
|
17424
|
+
if (hasRules) {
|
|
17425
|
+
choices.push({
|
|
17426
|
+
title: "Rules only (Firestore/Storage)",
|
|
17427
|
+
value: "rules",
|
|
17428
|
+
hint: "Deploy Firestore/Storage rules"
|
|
17429
|
+
});
|
|
17430
|
+
}
|
|
17431
|
+
if (fbConfig.hasHosting && fbConfig.hasFunctions) {
|
|
17432
|
+
choices.push({
|
|
17433
|
+
title: "Frontend + Functions (Firebase)",
|
|
17434
|
+
value: "both",
|
|
17435
|
+
hint: "Deploy Firebase hosting and functions"
|
|
17436
|
+
});
|
|
17437
|
+
}
|
|
17438
|
+
const deployableKindsCount = [
|
|
17439
|
+
fbConfig.hasHosting,
|
|
17440
|
+
fbConfig.hasFunctions,
|
|
17441
|
+
hasRules
|
|
17442
|
+
].filter(Boolean).length;
|
|
17443
|
+
if (deployableKindsCount > 1) {
|
|
17444
|
+
choices.push({
|
|
17445
|
+
title: "All (Firebase)",
|
|
17446
|
+
value: "all",
|
|
17447
|
+
hint: "Deploy everything Firebase (hosting, functions, rules)"
|
|
17448
|
+
});
|
|
17449
|
+
}
|
|
16471
17450
|
}
|
|
16472
|
-
if (
|
|
17451
|
+
if (hasVercelConfig) {
|
|
17452
|
+
const fbFrontendIdx = choices.findIndex(
|
|
17453
|
+
(c) => c.value === "frontend" && c.title.includes("Firebase")
|
|
17454
|
+
);
|
|
17455
|
+
if (fbFrontendIdx !== -1) choices.splice(fbFrontendIdx, 1);
|
|
17456
|
+
const fbBothIdx = choices.findIndex(
|
|
17457
|
+
(c) => c.value === "both" && c.title.includes("Firebase")
|
|
17458
|
+
);
|
|
17459
|
+
if (fbBothIdx !== -1) choices.splice(fbBothIdx, 1);
|
|
16473
17460
|
choices.push({
|
|
16474
|
-
title: "Frontend
|
|
16475
|
-
value: "
|
|
16476
|
-
hint: "Deploy
|
|
17461
|
+
title: "Frontend only (Vercel)",
|
|
17462
|
+
value: "frontend",
|
|
17463
|
+
hint: "Deploy frontend to Vercel"
|
|
16477
17464
|
});
|
|
17465
|
+
const hasFunctions = appProviderInfo.hasFirebase && appProviderInfo.firebaseConfig?.hasFunctions || appProviderInfo.hasSupabase && appProviderInfo.supabaseConfig?.hasFunctions;
|
|
17466
|
+
if (hasFunctions) {
|
|
17467
|
+
choices.push({
|
|
17468
|
+
title: "Frontend + Functions (Vercel + backend)",
|
|
17469
|
+
value: "both",
|
|
17470
|
+
hint: "Deploy frontend to Vercel and functions to backend provider"
|
|
17471
|
+
});
|
|
17472
|
+
}
|
|
16478
17473
|
}
|
|
16479
|
-
|
|
16480
|
-
|
|
16481
|
-
|
|
16482
|
-
|
|
16483
|
-
|
|
16484
|
-
|
|
16485
|
-
|
|
16486
|
-
|
|
16487
|
-
|
|
16488
|
-
hint: "Deploy everything (hosting, functions, rules)"
|
|
16489
|
-
});
|
|
17474
|
+
if (appProviderInfo.hasSupabase && appProviderInfo.supabaseConfig) {
|
|
17475
|
+
const sbConfig = appProviderInfo.supabaseConfig;
|
|
17476
|
+
if (sbConfig.hasFunctions) {
|
|
17477
|
+
choices.push({
|
|
17478
|
+
title: "Edge Functions only (Supabase)",
|
|
17479
|
+
value: "functions",
|
|
17480
|
+
hint: "Deploy Supabase Edge Functions"
|
|
17481
|
+
});
|
|
17482
|
+
}
|
|
16490
17483
|
}
|
|
16491
17484
|
if (choices.length === 0) {
|
|
16492
17485
|
log.error(
|
|
16493
|
-
"No deployment targets found. firebase.json
|
|
17486
|
+
"No deployment targets found. Ensure your project has:\n - Firebase: firebase.json with hosting/functions/rules\n - Supabase: supabase/functions/ directory"
|
|
16494
17487
|
);
|
|
16495
17488
|
process.exit(1);
|
|
16496
17489
|
}
|
|
@@ -16504,71 +17497,78 @@ async function main(options = {}) {
|
|
|
16504
17497
|
);
|
|
16505
17498
|
}
|
|
16506
17499
|
}
|
|
16507
|
-
|
|
16508
|
-
|
|
16509
|
-
|
|
16510
|
-
|
|
16511
|
-
|
|
16512
|
-
|
|
16513
|
-
);
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16519
|
-
projectId = readStagingProject(appDir) ?? void 0;
|
|
16520
|
-
if (!projectId) {
|
|
16521
|
-
log.error(
|
|
16522
|
-
'Staging project not found. Add "staging" alias to .firebaserc:\n { "projects": { "default": "my-app", "staging": "my-app-uat" } }'
|
|
17500
|
+
let serviceAccountPath;
|
|
17501
|
+
let projectId;
|
|
17502
|
+
const needsFirebase = appProviderInfo.hasFirebase && (deploymentType === "frontend" && !hasVercelConfig || deploymentType === "functions" || deploymentType === "rules" || deploymentType === "both" || deploymentType === "all");
|
|
17503
|
+
if (needsFirebase) {
|
|
17504
|
+
const serviceAccountResult = validateServiceAccount(appDir, {
|
|
17505
|
+
staging: isStaging
|
|
17506
|
+
});
|
|
17507
|
+
if (!serviceAccountResult.valid) {
|
|
17508
|
+
const firebaseConfig2 = validateFirebaseJson(appDir);
|
|
17509
|
+
await showServiceAccountError(
|
|
17510
|
+
serviceAccountResult.info,
|
|
17511
|
+
firebaseConfig2.projectId
|
|
16523
17512
|
);
|
|
16524
17513
|
process.exit(1);
|
|
16525
17514
|
}
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
if (!
|
|
16538
|
-
|
|
17515
|
+
serviceAccountPath = normalizePath(serviceAccountResult.info.path);
|
|
17516
|
+
projectId = config.project;
|
|
17517
|
+
if (!projectId && isStaging) {
|
|
17518
|
+
projectId = readStagingProject(appDir) ?? void 0;
|
|
17519
|
+
if (!projectId) {
|
|
17520
|
+
log.error(
|
|
17521
|
+
'Staging project not found. Add "staging" alias to .firebaserc:\n { "projects": { "default": "my-app", "staging": "my-app-uat" } }'
|
|
17522
|
+
);
|
|
17523
|
+
process.exit(1);
|
|
17524
|
+
}
|
|
17525
|
+
}
|
|
17526
|
+
if (!projectId) {
|
|
17527
|
+
const fallbackConfig = validateFirebaseJson(appDir);
|
|
17528
|
+
projectId = serviceAccountResult.info.projectId || fallbackConfig.projectId;
|
|
17529
|
+
}
|
|
17530
|
+
if (!projectId) {
|
|
17531
|
+
const inputProjectId = await askForInput(
|
|
17532
|
+
"Firebase project ID not detected. Please enter it:"
|
|
17533
|
+
);
|
|
17534
|
+
if (!inputProjectId) {
|
|
17535
|
+
log.error("Project ID is required for deployment.");
|
|
17536
|
+
process.exit(1);
|
|
17537
|
+
}
|
|
17538
|
+
config.project = inputProjectId;
|
|
17539
|
+
} else {
|
|
17540
|
+
config.project = projectId;
|
|
17541
|
+
}
|
|
17542
|
+
const firebaseConfig = await validateFirebaseJson(appDir);
|
|
17543
|
+
if (!firebaseConfig.valid) {
|
|
17544
|
+
showFirebaseJsonError(firebaseConfig.errors, appDir, deploymentType);
|
|
16539
17545
|
process.exit(1);
|
|
16540
17546
|
}
|
|
16541
|
-
config.project = inputProjectId;
|
|
16542
|
-
} else {
|
|
16543
|
-
config.project = projectId;
|
|
16544
|
-
}
|
|
16545
|
-
const firebaseConfig = validateFirebaseJson(appDir);
|
|
16546
|
-
if (!firebaseConfig.valid) {
|
|
16547
|
-
showFirebaseJsonError(firebaseConfig.errors, appDir, deploymentType);
|
|
16548
|
-
process.exit(1);
|
|
16549
17547
|
}
|
|
16550
|
-
const
|
|
16551
|
-
const
|
|
16552
|
-
const
|
|
16553
|
-
|
|
17548
|
+
const shouldDeployFirebaseFrontend = appProviderInfo.hasFirebase && appProviderInfo.firebaseConfig?.hasHosting && !hasVercelConfig && (deploymentType === "frontend" || deploymentType === "both" || deploymentType === "all");
|
|
17549
|
+
const shouldDeployFirebaseFunctions = appProviderInfo.hasFirebase && appProviderInfo.firebaseConfig?.hasFunctions && (deploymentType === "functions" || deploymentType === "both" || deploymentType === "all");
|
|
17550
|
+
const shouldDeployFirebaseRules = appProviderInfo.hasFirebase && (deploymentType === "rules" || deploymentType === "all") && (appProviderInfo.firebaseConfig?.hasFirestoreRules || appProviderInfo.firebaseConfig?.hasStorageRules);
|
|
17551
|
+
const shouldDeploySupabaseFunctions = appProviderInfo.hasSupabase && appProviderInfo.supabaseConfig?.hasFunctions && deploymentType === "functions";
|
|
17552
|
+
const shouldDeployVercelFrontend = hasVercelConfig && (deploymentType === "frontend" || deploymentType === "both" || deploymentType === "all");
|
|
17553
|
+
if (deploymentType === "frontend" && !shouldDeployFirebaseFrontend && !shouldDeployVercelFrontend) {
|
|
16554
17554
|
log.error(
|
|
16555
|
-
"firebase.json
|
|
17555
|
+
"No hosting configuration found. Ensure firebase.json has hosting config, or (for Supabase apps) vercel.json exists."
|
|
16556
17556
|
);
|
|
16557
17557
|
process.exit(1);
|
|
16558
17558
|
}
|
|
16559
|
-
if (deploymentType === "functions" && !
|
|
17559
|
+
if (deploymentType === "functions" && !shouldDeployFirebaseFunctions && !shouldDeploySupabaseFunctions) {
|
|
16560
17560
|
log.error(
|
|
16561
|
-
"firebase.json
|
|
17561
|
+
"No functions configuration found. Ensure firebase.json has functions config or supabase/functions/ directory exists."
|
|
16562
17562
|
);
|
|
16563
17563
|
process.exit(1);
|
|
16564
17564
|
}
|
|
16565
|
-
if (deploymentType === "rules" && !
|
|
17565
|
+
if (deploymentType === "rules" && !shouldDeployFirebaseRules) {
|
|
16566
17566
|
log.error(
|
|
16567
17567
|
"firebase.json does not contain rules configuration, but rules deployment was requested."
|
|
16568
17568
|
);
|
|
16569
17569
|
process.exit(1);
|
|
16570
17570
|
}
|
|
16571
|
-
if (
|
|
17571
|
+
if (shouldDeployFirebaseFrontend || shouldDeployVercelFrontend) {
|
|
16572
17572
|
const buildStatus = validateBuild(appDir);
|
|
16573
17573
|
let shouldBuild = false;
|
|
16574
17574
|
if (!buildStatus.exists || buildStatus.isEmpty) {
|
|
@@ -16595,9 +17595,11 @@ async function main(options = {}) {
|
|
|
16595
17595
|
if (shouldBuild) {
|
|
16596
17596
|
const s = Y2();
|
|
16597
17597
|
const buildCmd = isStaging ? "bun run build -- --mode staging" : "bun run build";
|
|
16598
|
-
s.start(
|
|
17598
|
+
s.start(
|
|
17599
|
+
isStaging ? "Building (staging mode)..." : "Building application..."
|
|
17600
|
+
);
|
|
16599
17601
|
try {
|
|
16600
|
-
|
|
17602
|
+
execSync5(buildCmd, {
|
|
16601
17603
|
cwd: appDir,
|
|
16602
17604
|
stdio: "inherit",
|
|
16603
17605
|
env: {
|
|
@@ -16612,19 +17614,52 @@ async function main(options = {}) {
|
|
|
16612
17614
|
}
|
|
16613
17615
|
}
|
|
16614
17616
|
}
|
|
16615
|
-
|
|
17617
|
+
if (appProviderInfo.hasFirebase) {
|
|
17618
|
+
clearFirebaseCache(appDir);
|
|
17619
|
+
}
|
|
16616
17620
|
const envLabel = isStaging ? " (STAGING)" : "";
|
|
16617
|
-
|
|
16618
|
-
|
|
16619
|
-
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
16624
|
-
|
|
17621
|
+
const providerLabel = appProviderInfo.provider === "both" ? " (Firebase + Supabase)" : appProviderInfo.provider === "supabase" ? " (Supabase)" : " (Firebase)";
|
|
17622
|
+
const configNote = [
|
|
17623
|
+
`App: ${appName || "root"}`,
|
|
17624
|
+
...config.project ? [`Project: ${config.project}${envLabel}`] : [],
|
|
17625
|
+
`Provider: ${appProviderInfo.provider}${providerLabel}`,
|
|
17626
|
+
`Deployment: ${deploymentType}`,
|
|
17627
|
+
...serviceAccountPath ? [`Service Account: ${serviceAccountPath}`] : []
|
|
17628
|
+
].join("\n");
|
|
17629
|
+
Me(configNote, "Deployment Configuration");
|
|
17630
|
+
if (shouldDeployVercelFrontend) {
|
|
17631
|
+
requireCLI(
|
|
17632
|
+
CLI_TOOLS.VERCEL,
|
|
17633
|
+
"Vercel CLI is required to deploy the frontend.\nInstall: npm i -g vercel or use npx vercel"
|
|
17634
|
+
);
|
|
17635
|
+
}
|
|
17636
|
+
if (shouldDeployFirebaseFrontend && serviceAccountPath && config.project) {
|
|
16625
17637
|
await deployFrontend(appDir, serviceAccountPath, config.project, config);
|
|
16626
17638
|
}
|
|
16627
|
-
if (
|
|
17639
|
+
if (shouldDeployVercelFrontend) {
|
|
17640
|
+
await deployVercelFrontend(appDir, config);
|
|
17641
|
+
}
|
|
17642
|
+
if (shouldDeployFirebaseFunctions && serviceAccountPath && config.project) {
|
|
17643
|
+
const functionsEnvPath = joinPath(appDir, "functions", ".env");
|
|
17644
|
+
if (pathExists(functionsEnvPath)) {
|
|
17645
|
+
const shouldSync = await askForConfirmation(
|
|
17646
|
+
"Sync runtime secrets (functions/.env) before deploying?"
|
|
17647
|
+
);
|
|
17648
|
+
if (shouldSync) {
|
|
17649
|
+
const { main: syncSecrets } = await Promise.resolve().then(() => (init_sync_secrets(), sync_secrets_exports));
|
|
17650
|
+
const syncResult = await syncSecrets({
|
|
17651
|
+
envFile: normalizePath(functionsEnvPath),
|
|
17652
|
+
projectId: config.project,
|
|
17653
|
+
dryRun: false,
|
|
17654
|
+
verbose: config.verbose
|
|
17655
|
+
});
|
|
17656
|
+
if (syncResult !== 0) {
|
|
17657
|
+
log.warn(
|
|
17658
|
+
"Secrets sync returned non-zero. Functions may not have latest secrets at runtime."
|
|
17659
|
+
);
|
|
17660
|
+
}
|
|
17661
|
+
}
|
|
17662
|
+
}
|
|
16628
17663
|
await deployFunctions(
|
|
16629
17664
|
appDir,
|
|
16630
17665
|
serviceAccountPath,
|
|
@@ -16632,13 +17667,18 @@ Service Account: ${serviceAccountResult.info.clientEmail}`,
|
|
|
16632
17667
|
config
|
|
16633
17668
|
);
|
|
16634
17669
|
}
|
|
16635
|
-
if (
|
|
17670
|
+
if (shouldDeployFirebaseRules && serviceAccountPath && config.project && appProviderInfo.firebaseConfig) {
|
|
16636
17671
|
await deployRules(appDir, serviceAccountPath, config.project, config, {
|
|
16637
|
-
firestore: firebaseConfig.hasFirestoreRules,
|
|
16638
|
-
firestoreIndexes:
|
|
16639
|
-
|
|
17672
|
+
firestore: appProviderInfo.firebaseConfig.hasFirestoreRules,
|
|
17673
|
+
firestoreIndexes: false,
|
|
17674
|
+
// TODO: detect this
|
|
17675
|
+
storage: appProviderInfo.firebaseConfig.hasStorageRules
|
|
16640
17676
|
});
|
|
16641
17677
|
}
|
|
17678
|
+
if (shouldDeploySupabaseFunctions) {
|
|
17679
|
+
const { deploySupabaseFunctions: deploySupabaseFunctions2 } = await Promise.resolve().then(() => (init_deploy_supabase_functions(), deploy_supabase_functions_exports));
|
|
17680
|
+
await deploySupabaseFunctions2(appDir, config);
|
|
17681
|
+
}
|
|
16642
17682
|
Se("Deployment completed successfully!");
|
|
16643
17683
|
} catch (error2) {
|
|
16644
17684
|
if (error2 instanceof DoNotDevError) {
|
|
@@ -16655,7 +17695,7 @@ Service Account: ${serviceAccountResult.info.clientEmail}`,
|
|
|
16655
17695
|
}
|
|
16656
17696
|
}
|
|
16657
17697
|
export {
|
|
16658
|
-
main
|
|
17698
|
+
main2 as main
|
|
16659
17699
|
};
|
|
16660
17700
|
/*! Bundled license information:
|
|
16661
17701
|
|