@donotdev/cli 0.0.17 → 0.0.19
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 +67 -60
- package/dist/bin/commands/coach.js +8177 -0
- package/dist/bin/commands/create-app.js +94 -145
- package/dist/bin/commands/create-project.js +98 -149
- package/dist/bin/commands/deploy.js +81 -59
- package/dist/bin/commands/doctor.js +243 -698
- package/dist/bin/commands/emu.js +2 -2
- package/dist/bin/commands/format.js +4 -1
- package/dist/bin/commands/get-demo.js +8351 -0
- package/dist/bin/commands/make-admin.js +773 -152
- package/dist/bin/commands/setup.js +519 -1711
- package/dist/bin/commands/staging.js +17852 -0
- package/dist/bin/commands/sync-secrets.js +2 -11
- package/dist/bin/commands/type-check.js +7733 -1713
- package/dist/bin/dndev.js +913 -182
- package/dist/bin/donotdev.js +913 -182
- package/dist/index.js +191 -211
- package/package.json +1 -1
- package/templates/app-demo/index.html.example +147 -10
- package/templates/app-demo/src/App.tsx.example +7 -13
- package/templates/app-demo/src/config/app.ts.example +12 -48
- package/templates/app-demo/src/entities/product.ts.example +38 -0
- package/templates/app-demo/src/globals.css.example +5 -1
- package/templates/app-demo/src/main.tsx.example +13 -7
- package/templates/app-demo/src/pages/ChangelogPage.tsx.example +14 -0
- package/templates/app-demo/src/pages/DashboardPage.tsx.example +15 -0
- package/templates/app-demo/src/pages/HomePage.tsx.example +3 -77
- package/templates/app-demo/src/pages/PricingPage.tsx.example +14 -0
- package/templates/app-demo/src/pages/ProductsPage.tsx.example +17 -0
- package/templates/app-demo/src/pages/ProfilePage.tsx.example +16 -0
- package/templates/app-demo/src/pages/SettingsPage.tsx.example +15 -0
- package/templates/app-demo/src/pages/ShowcaseDetailPage.tsx.example +112 -0
- package/templates/app-demo/src/pages/ShowcasePage.tsx.example +91 -0
- package/templates/app-demo/src/pages/legal/LegalPage.tsx.example +14 -0
- package/templates/app-demo/src/pages/legal/PrivacyPage.tsx.example +14 -0
- package/templates/app-demo/src/pages/legal/TermsPage.tsx.example +14 -0
- package/templates/app-demo/tsconfig.json.example +1 -1
- package/templates/app-demo/vite.config.ts.example +23 -48
- package/templates/app-expo/README.md.example +1 -1
- package/templates/app-expo/app/index.tsx.example +1 -1
- package/templates/app-vite/src/pages/HomePage.tsx.example +8 -10
- package/templates/overlay-firebase/env.fragment.example +1 -1
- package/templates/overlay-firebase/env.fragment.expo.example +1 -1
- package/templates/overlay-firebase/env.fragment.nextjs.example +1 -1
- package/templates/overlay-supabase/env.fragment.example +1 -1
- package/templates/overlay-supabase/env.fragment.expo.example +1 -1
- package/templates/overlay-supabase/env.fragment.nextjs.example +1 -1
- package/templates/overlay-vercel/env.fragment.example +1 -1
- package/templates/overlay-vercel/env.fragment.nextjs.example +1 -1
- package/templates/root-consumer/.claude/commands/brainstorm.md.example +15 -1
- package/templates/root-consumer/.claude/commands/build.md.example +24 -2
- package/templates/root-consumer/.claude/commands/design.md.example +17 -0
- package/templates/root-consumer/.claude/commands/polish.md.example +17 -0
- package/templates/root-consumer/AI.md.example +54 -21
- package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +21 -6
- package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +16 -179
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +19 -21
- package/templates/root-consumer/guides/dndev/GOTCHAS.md.example +14 -3
- package/templates/root-consumer/guides/dndev/INDEX.md.example +2 -2
- package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +3 -3
- package/templates/root-consumer/guides/dndev/SETUP_BLOG.md.example +19 -2
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +35 -1
- package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +17 -12
- package/templates/root-consumer/guides/dndev/SETUP_LAYOUTS.md.example +32 -0
- package/templates/root-consumer/guides/dndev/SETUP_OAUTH_PROVIDERS.md.example +1 -1
- package/templates/root-consumer/guides/dndev/SETUP_PAGES.md.example +74 -6
- package/templates/root-consumer/guides/dndev/SETUP_STRIPE.md.example +2 -2
- package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +17 -12
- package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +37 -16
- package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +18 -18
- package/templates/root-consumer/guides/dndev/essences_reference.css.example +119 -2
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +1 -1
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +14 -0
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +6 -0
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +14 -0
- package/templates/root-consumer/guides/wai-way/entity_patterns.md.example +4 -5
- package/templates/root-consumer/guides/wai-way/page_patterns.md.example +2 -2
- package/dist/bin/commands/agent-setup.d.ts +0 -6
- package/dist/bin/commands/agent-setup.d.ts.map +0 -1
- package/dist/bin/commands/agent-setup.js.map +0 -1
- package/dist/bin/commands/build.d.ts +0 -11
- package/dist/bin/commands/build.d.ts.map +0 -1
- package/dist/bin/commands/build.js.map +0 -1
- package/dist/bin/commands/bump.d.ts +0 -11
- package/dist/bin/commands/bump.d.ts.map +0 -1
- package/dist/bin/commands/bump.js.map +0 -1
- package/dist/bin/commands/cacheout.d.ts +0 -11
- package/dist/bin/commands/cacheout.d.ts.map +0 -1
- package/dist/bin/commands/cacheout.js.map +0 -1
- package/dist/bin/commands/create-app.d.ts +0 -11
- package/dist/bin/commands/create-app.d.ts.map +0 -1
- package/dist/bin/commands/create-app.js.map +0 -1
- package/dist/bin/commands/create-project.d.ts +0 -11
- package/dist/bin/commands/create-project.d.ts.map +0 -1
- package/dist/bin/commands/create-project.js.map +0 -1
- package/dist/bin/commands/deploy.d.ts +0 -11
- package/dist/bin/commands/deploy.d.ts.map +0 -1
- package/dist/bin/commands/deploy.js.map +0 -1
- package/dist/bin/commands/dev.d.ts +0 -11
- package/dist/bin/commands/dev.d.ts.map +0 -1
- package/dist/bin/commands/dev.js.map +0 -1
- package/dist/bin/commands/doctor.d.ts +0 -6
- package/dist/bin/commands/doctor.d.ts.map +0 -1
- package/dist/bin/commands/doctor.js.map +0 -1
- package/dist/bin/commands/emu.d.ts +0 -11
- package/dist/bin/commands/emu.d.ts.map +0 -1
- package/dist/bin/commands/emu.js.map +0 -1
- package/dist/bin/commands/format.d.ts +0 -11
- package/dist/bin/commands/format.d.ts.map +0 -1
- package/dist/bin/commands/format.js.map +0 -1
- package/dist/bin/commands/make-admin.d.ts +0 -11
- package/dist/bin/commands/make-admin.d.ts.map +0 -1
- package/dist/bin/commands/make-admin.js.map +0 -1
- package/dist/bin/commands/preview.d.ts +0 -11
- package/dist/bin/commands/preview.d.ts.map +0 -1
- package/dist/bin/commands/preview.js.map +0 -1
- package/dist/bin/commands/setup.d.ts +0 -6
- package/dist/bin/commands/setup.d.ts.map +0 -1
- package/dist/bin/commands/setup.js.map +0 -1
- package/dist/bin/commands/sync-secrets.d.ts +0 -11
- package/dist/bin/commands/sync-secrets.d.ts.map +0 -1
- package/dist/bin/commands/sync-secrets.js.map +0 -1
- package/dist/bin/commands/type-check.d.ts +0 -14
- package/dist/bin/commands/type-check.d.ts.map +0 -1
- package/dist/bin/commands/type-check.js.map +0 -1
- package/dist/bin/commands/wai.d.ts +0 -11
- package/dist/bin/commands/wai.d.ts.map +0 -1
- package/dist/bin/commands/wai.js.map +0 -1
- package/dist/index.d.ts +0 -8
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/templates/app-demo/src/components/ThemeToggle.tsx.example +0 -48
- package/templates/app-demo/src/pages/DetailPage.tsx.example +0 -103
- package/templates/app-demo/src/pages/FullPage.tsx.example +0 -142
- package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +0 -266
- package/templates/app-demo/src/pages/components/LayoutRoute.tsx.example +0 -20
- package/templates/functions-firebase/functions-firebase/README.md.example +0 -123
- package/templates/functions-firebase/functions-firebase/build.mjs.example +0 -5
- package/templates/functions-firebase/functions-firebase/src/auth/getCustomClaims.ts.example +0 -19
- package/templates/functions-firebase/functions-firebase/src/auth/getUserAuthStatus.ts.example +0 -21
- package/templates/functions-firebase/functions-firebase/src/auth/index.ts.example +0 -11
- package/templates/functions-firebase/functions-firebase/src/auth/removeCustomClaims.ts.example +0 -21
- package/templates/functions-firebase/functions-firebase/src/auth/setCustomClaims.ts.example +0 -21
- package/templates/functions-firebase/functions-firebase/src/billing/handleStripeWebhook.ts.example +0 -24
- package/templates/functions-firebase/functions-firebase/src/billing/index.ts.example +0 -10
- package/templates/functions-firebase/functions-firebase/src/billing/processPaymentSuccess.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/billing/refreshSubscriptionStatus.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/index.ts.example +0 -39
- package/templates/functions-firebase/functions-firebase/src/oauth/checkGitHubAccess.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/disconnect.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/exchangeToken.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/getConnections.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/grantGitHubAccess.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/index.ts.example +0 -17
- package/templates/functions-firebase/functions-firebase/src/oauth/refreshToken.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/revokeGitHubAccess.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/tsconfig.json.example +0 -21
- package/templates/functions-vercel/functions-vercel/README.md.example +0 -116
- package/templates/functions-vercel/functions-vercel/build.mjs.example +0 -52
- package/templates/functions-vercel/functions-vercel/src/api/auth/getCustomClaims.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/auth/getUserAuthStatus.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/auth/removeCustomClaims.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/auth/setCustomClaims.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/billing/handleStripeWebhook.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/billing/processPaymentSuccess.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/billing/refreshSubscriptionStatus.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/createEntity.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/deleteEntity.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/getEntity.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/listEntities.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/updateEntity.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/checkGitHubAccess.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/disconnect.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/exchangeToken.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/getConnections.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/grantGitHubAccess.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/refreshToken.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/revokeGitHubAccess.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/tsconfig.json.example +0 -21
- package/templates/functions-vercel/functions-vercel/vercel.json.example +0 -14
- package/templates/github/github/workflows/firebase-deploy.yml.example +0 -79
- /package/templates/functions-firebase/{functions-firebase/.env.example.example → .env.example} +0 -0
- /package/templates/functions-vercel/{functions-vercel/.env.example.example → .env.example} +0 -0
|
@@ -281,7 +281,7 @@ function fD({ input: e2 = j, output: u2 = M, overwrite: t = true, hideCursor: F2
|
|
|
281
281
|
e2.off("keypress", i), F2 && u2.write(import_sisteransi.cursor.show), e2.isTTY && !AD && e2.setRawMode(false), s.terminal = false, s.close();
|
|
282
282
|
};
|
|
283
283
|
}
|
|
284
|
-
var import_sisteransi, import_picocolors, uD, W, tD, eD, FD, sD, w, N, I, R, r, iD, CD, ED, d, oD, y, V, nD, G, _, z, K, aD, k, hD, lD, xD, B, AD, S, gD, vD, h, x, dD, A,
|
|
284
|
+
var import_sisteransi, import_picocolors, uD, W, tD, eD, FD, sD, w, N, I, R, r, iD, CD, ED, d, oD, y, V, nD, G, _, z, K, aD, k, hD, lD, xD, B, AD, S, gD, vD, h, x, dD, A, OD, PD, J, LD, RD;
|
|
285
285
|
var init_dist = __esm({
|
|
286
286
|
"node_modules/.bun/@clack+prompts@0.11.0/node_modules/@clack/prompts/node_modules/@clack/core/dist/index.mjs"() {
|
|
287
287
|
init_utils();
|
|
@@ -519,63 +519,6 @@ var init_dist = __esm({
|
|
|
519
519
|
}
|
|
520
520
|
};
|
|
521
521
|
A = /* @__PURE__ */ new WeakMap();
|
|
522
|
-
kD = Object.defineProperty;
|
|
523
|
-
$D = (e2, u2, t) => u2 in e2 ? kD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
524
|
-
H = (e2, u2, t) => ($D(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
525
|
-
SD = class extends x {
|
|
526
|
-
constructor(u2) {
|
|
527
|
-
super(u2, false), H(this, "options"), H(this, "cursor", 0), this.options = u2.options, this.value = [...u2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u2.cursorAt), 0), this.on("key", (t) => {
|
|
528
|
-
t === "a" && this.toggleAll();
|
|
529
|
-
}), this.on("cursor", (t) => {
|
|
530
|
-
switch (t) {
|
|
531
|
-
case "left":
|
|
532
|
-
case "up":
|
|
533
|
-
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
534
|
-
break;
|
|
535
|
-
case "down":
|
|
536
|
-
case "right":
|
|
537
|
-
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
538
|
-
break;
|
|
539
|
-
case "space":
|
|
540
|
-
this.toggleValue();
|
|
541
|
-
break;
|
|
542
|
-
}
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
get _value() {
|
|
546
|
-
return this.options[this.cursor].value;
|
|
547
|
-
}
|
|
548
|
-
toggleAll() {
|
|
549
|
-
const u2 = this.value.length === this.options.length;
|
|
550
|
-
this.value = u2 ? [] : this.options.map((t) => t.value);
|
|
551
|
-
}
|
|
552
|
-
toggleValue() {
|
|
553
|
-
const u2 = this.value.includes(this._value);
|
|
554
|
-
this.value = u2 ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
|
|
555
|
-
}
|
|
556
|
-
};
|
|
557
|
-
TD = Object.defineProperty;
|
|
558
|
-
jD = (e2, u2, t) => u2 in e2 ? TD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
559
|
-
U = (e2, u2, t) => (jD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
560
|
-
MD = class extends x {
|
|
561
|
-
constructor({ mask: u2, ...t }) {
|
|
562
|
-
super(t), U(this, "valueWithCursor", ""), U(this, "_mask", "\u2022"), this._mask = u2 ?? "\u2022", this.on("finalize", () => {
|
|
563
|
-
this.valueWithCursor = this.masked;
|
|
564
|
-
}), this.on("value", () => {
|
|
565
|
-
if (this.cursor >= this.value.length) this.valueWithCursor = `${this.masked}${import_picocolors.default.inverse(import_picocolors.default.hidden("_"))}`;
|
|
566
|
-
else {
|
|
567
|
-
const F2 = this.masked.slice(0, this.cursor), s = this.masked.slice(this.cursor);
|
|
568
|
-
this.valueWithCursor = `${F2}${import_picocolors.default.inverse(s[0])}${s.slice(1)}`;
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
get cursor() {
|
|
573
|
-
return this._cursor;
|
|
574
|
-
}
|
|
575
|
-
get masked() {
|
|
576
|
-
return this.value.replaceAll(/./g, this._mask);
|
|
577
|
-
}
|
|
578
|
-
};
|
|
579
522
|
OD = Object.defineProperty;
|
|
580
523
|
PD = (e2, u2, t) => u2 in e2 ? OD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
581
524
|
J = (e2, u2, t) => (PD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
@@ -627,7 +570,7 @@ import y2 from "node:process";
|
|
|
627
570
|
function ce() {
|
|
628
571
|
return y2.platform !== "win32" ? y2.env.TERM !== "linux" : !!y2.env.CI || !!y2.env.WT_SESSION || !!y2.env.TERMINUS_SUBLIME || y2.env.ConEmuTask === "{cmd::Cmder}" || y2.env.TERM_PROGRAM === "Terminus-Sublime" || y2.env.TERM_PROGRAM === "vscode" || y2.env.TERM === "xterm-256color" || y2.env.TERM === "alacritty" || y2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
629
572
|
}
|
|
630
|
-
var import_picocolors2, import_sisteransi2, V2, u, le, L2, W2, C, ue, o, d2, k2, P2, A2, T, F, $e, _2, me, de, pe, q, D,
|
|
573
|
+
var import_picocolors2, import_sisteransi2, V2, u, le, L2, W2, C, ue, o, d2, k2, P2, A2, T, F, $e, _2, me, de, pe, q, D, U, K2, b2, G2, he, ye, ve, Me, xe, Ie, Se, M2, J2, Y2;
|
|
631
574
|
var init_dist2 = __esm({
|
|
632
575
|
"node_modules/.bun/@clack+prompts@0.11.0/node_modules/@clack/prompts/dist/index.mjs"() {
|
|
633
576
|
init_utils();
|
|
@@ -656,7 +599,7 @@ var init_dist2 = __esm({
|
|
|
656
599
|
pe = u("\u256F", "+");
|
|
657
600
|
q = u("\u25CF", "\u2022");
|
|
658
601
|
D = u("\u25C6", "*");
|
|
659
|
-
|
|
602
|
+
U = u("\u25B2", "!");
|
|
660
603
|
K2 = u("\u25A0", "x");
|
|
661
604
|
b2 = (t) => {
|
|
662
605
|
switch (t) {
|
|
@@ -699,27 +642,6 @@ ${import_picocolors2.default.gray(o)}` : ""}`;
|
|
|
699
642
|
default:
|
|
700
643
|
return `${n}${import_picocolors2.default.cyan(o)} ${i}
|
|
701
644
|
${import_picocolors2.default.cyan(d2)}
|
|
702
|
-
`;
|
|
703
|
-
}
|
|
704
|
-
} }).prompt();
|
|
705
|
-
ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
|
|
706
|
-
const n = `${import_picocolors2.default.gray(o)}
|
|
707
|
-
${b2(this.state)} ${t.message}
|
|
708
|
-
`, r2 = this.valueWithCursor, i = this.masked;
|
|
709
|
-
switch (this.state) {
|
|
710
|
-
case "error":
|
|
711
|
-
return `${n.trim()}
|
|
712
|
-
${import_picocolors2.default.yellow(o)} ${i}
|
|
713
|
-
${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
|
|
714
|
-
`;
|
|
715
|
-
case "submit":
|
|
716
|
-
return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(i)}`;
|
|
717
|
-
case "cancel":
|
|
718
|
-
return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(i ?? ""))}${i ? `
|
|
719
|
-
${import_picocolors2.default.gray(o)}` : ""}`;
|
|
720
|
-
default:
|
|
721
|
-
return `${n}${import_picocolors2.default.cyan(o)} ${r2}
|
|
722
|
-
${import_picocolors2.default.cyan(d2)}
|
|
723
645
|
`;
|
|
724
646
|
}
|
|
725
647
|
} }).prompt();
|
|
@@ -770,46 +692,6 @@ ${import_picocolors2.default.gray(o)}`;
|
|
|
770
692
|
return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
|
|
771
693
|
${import_picocolors2.default.cyan(o)} `)}
|
|
772
694
|
${import_picocolors2.default.cyan(d2)}
|
|
773
|
-
`;
|
|
774
|
-
}
|
|
775
|
-
} }).prompt();
|
|
776
|
-
};
|
|
777
|
-
fe = (t) => {
|
|
778
|
-
const n = (r2, i) => {
|
|
779
|
-
const s = r2.label ?? String(r2.value);
|
|
780
|
-
return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
|
|
781
|
-
};
|
|
782
|
-
return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
|
|
783
|
-
if (this.required && r2.length === 0) return `Please select at least one option.
|
|
784
|
-
${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
|
|
785
|
-
}, render() {
|
|
786
|
-
const r2 = `${import_picocolors2.default.gray(o)}
|
|
787
|
-
${b2(this.state)} ${t.message}
|
|
788
|
-
`, i = (s, c) => {
|
|
789
|
-
const a = this.value.includes(s.value);
|
|
790
|
-
return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
|
|
791
|
-
};
|
|
792
|
-
switch (this.state) {
|
|
793
|
-
case "submit":
|
|
794
|
-
return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
|
|
795
|
-
case "cancel": {
|
|
796
|
-
const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
|
|
797
|
-
return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
|
|
798
|
-
${import_picocolors2.default.gray(o)}` : ""}`;
|
|
799
|
-
}
|
|
800
|
-
case "error": {
|
|
801
|
-
const s = this.error.split(`
|
|
802
|
-
`).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
|
|
803
|
-
`);
|
|
804
|
-
return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
|
|
805
|
-
${import_picocolors2.default.yellow(o)} `)}
|
|
806
|
-
${s}
|
|
807
|
-
`;
|
|
808
|
-
}
|
|
809
|
-
default:
|
|
810
|
-
return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
|
|
811
|
-
${import_picocolors2.default.cyan(o)} `)}
|
|
812
|
-
${import_picocolors2.default.cyan(d2)}
|
|
813
695
|
`;
|
|
814
696
|
}
|
|
815
697
|
} }).prompt();
|
|
@@ -861,7 +743,7 @@ ${import_picocolors2.default.gray(d2)} ${t}
|
|
|
861
743
|
}, step: (t) => {
|
|
862
744
|
M2.message(t, { symbol: import_picocolors2.default.green(C) });
|
|
863
745
|
}, warn: (t) => {
|
|
864
|
-
M2.message(t, { symbol: import_picocolors2.default.yellow(
|
|
746
|
+
M2.message(t, { symbol: import_picocolors2.default.yellow(U) });
|
|
865
747
|
}, warning: (t) => {
|
|
866
748
|
M2.warn(t);
|
|
867
749
|
}, error: (t) => {
|
|
@@ -888,7 +770,7 @@ ${import_picocolors2.default.gray(d2)} ${t}
|
|
|
888
770
|
}, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
|
|
889
771
|
const h2 = (performance.now() - m2) / 1e3, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
|
|
890
772
|
return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
|
|
891
|
-
},
|
|
773
|
+
}, H = (m2 = "") => {
|
|
892
774
|
a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
|
|
893
775
|
`);
|
|
894
776
|
let h2 = 0, w2 = 0;
|
|
@@ -911,7 +793,7 @@ ${import_picocolors2.default.gray(d2)} ${t}
|
|
|
911
793
|
`) : process.stdout.write(`${w2} ${l2}
|
|
912
794
|
`), E(), s();
|
|
913
795
|
};
|
|
914
|
-
return { start:
|
|
796
|
+
return { start: H, stop: N2, message: (m2 = "") => {
|
|
915
797
|
l2 = R2(m2 ?? l2);
|
|
916
798
|
} };
|
|
917
799
|
};
|
|
@@ -8361,24 +8243,6 @@ async function askForSelection(message, choices, defaultValue = 0) {
|
|
|
8361
8243
|
}
|
|
8362
8244
|
return result;
|
|
8363
8245
|
}
|
|
8364
|
-
async function askForMultiSelection(message, choices, defaultIndices = []) {
|
|
8365
|
-
const options = choices.map((choice) => ({
|
|
8366
|
-
value: choice.value,
|
|
8367
|
-
label: choice.title,
|
|
8368
|
-
hint: choice.hint
|
|
8369
|
-
}));
|
|
8370
|
-
const initialValues = defaultIndices.map((i) => choices[i]?.value).filter(Boolean);
|
|
8371
|
-
const result = await fe({
|
|
8372
|
-
message,
|
|
8373
|
-
options,
|
|
8374
|
-
initialValues: initialValues.length > 0 ? initialValues : void 0
|
|
8375
|
-
});
|
|
8376
|
-
if (pD(result)) {
|
|
8377
|
-
xe("Operation cancelled.");
|
|
8378
|
-
process.exit(0);
|
|
8379
|
-
}
|
|
8380
|
-
return result;
|
|
8381
|
-
}
|
|
8382
8246
|
var init_cli_input = __esm({
|
|
8383
8247
|
"packages/tooling/src/utils/cli-input.ts"() {
|
|
8384
8248
|
"use strict";
|
|
@@ -8405,14 +8269,27 @@ function readEnvVar(filePath, varName) {
|
|
|
8405
8269
|
}
|
|
8406
8270
|
return null;
|
|
8407
8271
|
}
|
|
8408
|
-
function
|
|
8409
|
-
if (process.env
|
|
8410
|
-
const
|
|
8411
|
-
if (fromEnv) return fromEnv;
|
|
8412
|
-
const fromLocal = readEnvVar(joinPath(appDir, ".env.local"), "VERCEL_TOKEN");
|
|
8272
|
+
function resolveVercelVar(appDir, varName) {
|
|
8273
|
+
if (process.env[varName]) return process.env[varName];
|
|
8274
|
+
const fromLocal = readEnvVar(joinPath(appDir, ".env.local"), varName);
|
|
8413
8275
|
if (fromLocal) return fromLocal;
|
|
8276
|
+
const fromEnv = readEnvVar(joinPath(appDir, ".env"), varName);
|
|
8277
|
+
if (fromEnv) return fromEnv;
|
|
8414
8278
|
return null;
|
|
8415
8279
|
}
|
|
8280
|
+
function resolveVercelCredentials(appDir) {
|
|
8281
|
+
const token = resolveVercelVar(appDir, "VERCEL_TOKEN");
|
|
8282
|
+
const orgId = resolveVercelVar(appDir, "VERCEL_ORG_ID");
|
|
8283
|
+
const projectId = resolveVercelVar(appDir, "VERCEL_PROJECT_ID");
|
|
8284
|
+
const missing = [];
|
|
8285
|
+
if (!token) missing.push("VERCEL_TOKEN");
|
|
8286
|
+
if (!orgId) missing.push("VERCEL_ORG_ID");
|
|
8287
|
+
if (!projectId) missing.push("VERCEL_PROJECT_ID");
|
|
8288
|
+
if (missing.length > 0) return { missing };
|
|
8289
|
+
return {
|
|
8290
|
+
credentials: { token, orgId, projectId }
|
|
8291
|
+
};
|
|
8292
|
+
}
|
|
8416
8293
|
var init_vercel_token = __esm({
|
|
8417
8294
|
"packages/tooling/src/cli/setup/vercel-token.ts"() {
|
|
8418
8295
|
"use strict";
|
|
@@ -8444,6 +8321,67 @@ var init_error_handling = __esm({
|
|
|
8444
8321
|
}
|
|
8445
8322
|
});
|
|
8446
8323
|
|
|
8324
|
+
// packages/tooling/src/utils/cross-app-detection.ts
|
|
8325
|
+
function detectBackendFromProviders(appDir) {
|
|
8326
|
+
for (const candidate of PROVIDERS_CANDIDATES) {
|
|
8327
|
+
const filePath = joinPath(appDir, candidate);
|
|
8328
|
+
if (!pathExists(filePath)) continue;
|
|
8329
|
+
const content = readSync(filePath, { format: "text" });
|
|
8330
|
+
if (typeof content !== "string") continue;
|
|
8331
|
+
if (content.includes("@donotdev/firebase") || content.includes("FirebaseAuth") || content.includes("firebaseAuth")) {
|
|
8332
|
+
return "firebase";
|
|
8333
|
+
}
|
|
8334
|
+
if (content.includes("@donotdev/supabase") || content.includes("SupabaseAuth") || content.includes("supabaseAuth")) {
|
|
8335
|
+
return "supabase";
|
|
8336
|
+
}
|
|
8337
|
+
break;
|
|
8338
|
+
}
|
|
8339
|
+
return null;
|
|
8340
|
+
}
|
|
8341
|
+
function analyzeProjectTopology(projectRoot) {
|
|
8342
|
+
const apps = detectApps(projectRoot);
|
|
8343
|
+
const appBackends = /* @__PURE__ */ new Map();
|
|
8344
|
+
const backendOwners = /* @__PURE__ */ new Map();
|
|
8345
|
+
for (const app of apps) {
|
|
8346
|
+
let backend = app.platform === "firebase" || app.platform === "supabase" ? app.platform : null;
|
|
8347
|
+
if (!backend) {
|
|
8348
|
+
backend = detectBackendFromProviders(app.path);
|
|
8349
|
+
}
|
|
8350
|
+
appBackends.set(app.name, backend);
|
|
8351
|
+
if (pathExists(joinPath(app.path, "supabase", "config.toml"))) {
|
|
8352
|
+
backendOwners.set("supabase", app);
|
|
8353
|
+
}
|
|
8354
|
+
if (pathExists(joinPath(app.path, "firebase.json")) || pathExists(joinPath(app.path, "functions", "firebase.json"))) {
|
|
8355
|
+
backendOwners.set("firebase", app);
|
|
8356
|
+
}
|
|
8357
|
+
}
|
|
8358
|
+
if (!backendOwners.has("firebase") && (pathExists(joinPath(projectRoot, "firebase.json")) || pathExists(joinPath(projectRoot, ".firebaserc")))) {
|
|
8359
|
+
}
|
|
8360
|
+
return { apps, appBackends, backendOwners };
|
|
8361
|
+
}
|
|
8362
|
+
function findBackendApp(topology, appName) {
|
|
8363
|
+
const backend = topology.appBackends.get(appName);
|
|
8364
|
+
if (!backend) return void 0;
|
|
8365
|
+
return topology.backendOwners.get(backend);
|
|
8366
|
+
}
|
|
8367
|
+
var PROVIDERS_CANDIDATES;
|
|
8368
|
+
var init_cross_app_detection = __esm({
|
|
8369
|
+
"packages/tooling/src/utils/cross-app-detection.ts"() {
|
|
8370
|
+
"use strict";
|
|
8371
|
+
init_utils();
|
|
8372
|
+
init_app_detection();
|
|
8373
|
+
init_pathResolver();
|
|
8374
|
+
PROVIDERS_CANDIDATES = [
|
|
8375
|
+
"src/config/providers.ts",
|
|
8376
|
+
"src/config/providers.tsx",
|
|
8377
|
+
"src/providers.ts",
|
|
8378
|
+
"src/providers.tsx",
|
|
8379
|
+
"src/lib/providers.ts",
|
|
8380
|
+
"src/lib/providers.tsx"
|
|
8381
|
+
];
|
|
8382
|
+
}
|
|
8383
|
+
});
|
|
8384
|
+
|
|
8447
8385
|
// packages/tooling/src/cli/setup/types.ts
|
|
8448
8386
|
function computeOverallStatus(steps) {
|
|
8449
8387
|
const hasFailure = steps.some((s) => s.status === "failed");
|
|
@@ -8523,7 +8461,7 @@ function isFirebaseInstalled() {
|
|
|
8523
8461
|
async function checkPrerequisites() {
|
|
8524
8462
|
if (!isFirebaseInstalled()) {
|
|
8525
8463
|
log.error("Firebase CLI is not installed.");
|
|
8526
|
-
log.info("Install it with:
|
|
8464
|
+
log.info("Install it with: bun install -g firebase-tools");
|
|
8527
8465
|
process.exit(1);
|
|
8528
8466
|
}
|
|
8529
8467
|
if (!isFirebaseLoggedIn()) {
|
|
@@ -8974,15 +8912,40 @@ var init_firebase = __esm({
|
|
|
8974
8912
|
});
|
|
8975
8913
|
|
|
8976
8914
|
// packages/tooling/src/utils/supabase-management.ts
|
|
8977
|
-
import { execSync } from "node:child_process";
|
|
8978
|
-
function
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8915
|
+
import { execSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
8916
|
+
function stripQuotes(value) {
|
|
8917
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
8918
|
+
return value.slice(1, -1);
|
|
8919
|
+
}
|
|
8920
|
+
return value;
|
|
8921
|
+
}
|
|
8922
|
+
function detectDbUrl(appDir) {
|
|
8923
|
+
const envPaths = [
|
|
8924
|
+
joinPath(appDir, "supabase", "functions", ".env"),
|
|
8925
|
+
joinPath(appDir, "functions", ".env"),
|
|
8926
|
+
joinPath(appDir, ".env.local"),
|
|
8927
|
+
joinPath(appDir, ".env")
|
|
8928
|
+
];
|
|
8929
|
+
for (const envPath of envPaths) {
|
|
8930
|
+
if (!pathExists(envPath)) continue;
|
|
8931
|
+
try {
|
|
8932
|
+
const content = readSync(envPath);
|
|
8933
|
+
if (!content) continue;
|
|
8934
|
+
for (const line of content.split("\n")) {
|
|
8935
|
+
const trimmed = line.trim();
|
|
8936
|
+
if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
|
|
8937
|
+
const eqIdx = trimmed.indexOf("=");
|
|
8938
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
8939
|
+
const value = stripQuotes(trimmed.slice(eqIdx + 1).trim());
|
|
8940
|
+
if (key === "SUPABASE_DB_URL" && value) {
|
|
8941
|
+
return value;
|
|
8942
|
+
}
|
|
8943
|
+
}
|
|
8944
|
+
} catch {
|
|
8945
|
+
continue;
|
|
8946
|
+
}
|
|
8984
8947
|
}
|
|
8985
|
-
return
|
|
8948
|
+
return null;
|
|
8986
8949
|
}
|
|
8987
8950
|
async function cleanupOldEntityMigrations(supabaseDir, latestFile) {
|
|
8988
8951
|
const migrationsDir = joinPath(supabaseDir, "migrations");
|
|
@@ -9040,35 +9003,38 @@ async function executeMigration(options) {
|
|
|
9040
9003
|
const projectRoot = dirname4(supabaseDir);
|
|
9041
9004
|
try {
|
|
9042
9005
|
const cmd = getSupabaseCmd();
|
|
9043
|
-
|
|
9006
|
+
const parts = cmd.split(" ");
|
|
9007
|
+
const bin = parts[0];
|
|
9008
|
+
const baseArgs = [
|
|
9009
|
+
...parts.slice(1),
|
|
9010
|
+
"db",
|
|
9011
|
+
"push",
|
|
9012
|
+
"--include-all",
|
|
9013
|
+
"--db-url",
|
|
9014
|
+
options.dbUrl
|
|
9015
|
+
];
|
|
9016
|
+
const result = spawnSync2(bin, baseArgs, {
|
|
9044
9017
|
cwd: projectRoot,
|
|
9045
9018
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9046
9019
|
input: "Y\n",
|
|
9047
9020
|
env: { ...process.env }
|
|
9048
9021
|
});
|
|
9022
|
+
if (result.status !== 0) {
|
|
9023
|
+
const stderr = result.stderr?.toString() || "";
|
|
9024
|
+
throw new Error(stderr || `Process exited with code ${result.status}`);
|
|
9025
|
+
}
|
|
9049
9026
|
} catch (error2) {
|
|
9050
|
-
const
|
|
9027
|
+
const raw = error2 instanceof Error ? error2.message : String(error2);
|
|
9028
|
+
const sanitized = raw.replace(
|
|
9029
|
+
/postgresql:\/\/[^\s"']*/g,
|
|
9030
|
+
"postgresql://***"
|
|
9031
|
+
);
|
|
9051
9032
|
throw new Error(
|
|
9052
|
-
`Failed to push migrations: ${
|
|
9053
|
-
|
|
9033
|
+
`Failed to push migrations: ${sanitized}
|
|
9034
|
+
Check your SUPABASE_DB_URL (format: postgresql://postgres:<password>@db.<ref>.supabase.co:5432/postgres)`
|
|
9054
9035
|
);
|
|
9055
9036
|
}
|
|
9056
9037
|
}
|
|
9057
|
-
function ensureProjectLinked(appDir, projectRef) {
|
|
9058
|
-
const linkMarker = joinPath(appDir, ".supabase");
|
|
9059
|
-
if (pathExists(linkMarker)) return;
|
|
9060
|
-
const cmd = getSupabaseCmd();
|
|
9061
|
-
try {
|
|
9062
|
-
execSync(`${cmd} link --project-ref ${projectRef}`, {
|
|
9063
|
-
cwd: appDir,
|
|
9064
|
-
stdio: "pipe",
|
|
9065
|
-
env: { ...process.env }
|
|
9066
|
-
});
|
|
9067
|
-
} catch (error2) {
|
|
9068
|
-
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
9069
|
-
throw new Error(`Failed to link Supabase project: ${message}`);
|
|
9070
|
-
}
|
|
9071
|
-
}
|
|
9072
9038
|
function getSupabaseCmd() {
|
|
9073
9039
|
try {
|
|
9074
9040
|
execSync("supabase --version", { stdio: "pipe" });
|
|
@@ -10288,30 +10254,32 @@ async function main3(options = {}) {
|
|
|
10288
10254
|
const supabaseUrl = existingConfig.url;
|
|
10289
10255
|
log.success(`Supabase URL: ${supabaseUrl}`);
|
|
10290
10256
|
const secretKey = detectSecretKey(appDir);
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10257
|
+
const dbUrl = detectDbUrl(appDir);
|
|
10258
|
+
if (secretKey) log.success("Secret key detected");
|
|
10259
|
+
else log.error("Missing SUPABASE_SECRET_KEY in supabase/functions/.env");
|
|
10260
|
+
if (dbUrl) log.success("DB URL detected");
|
|
10261
|
+
else log.error("Missing SUPABASE_DB_URL in supabase/functions/.env");
|
|
10262
|
+
if (!secretKey || !dbUrl) {
|
|
10294
10263
|
const functionsEnvPath = joinPath(supabaseDir, "functions", ".env");
|
|
10264
|
+
const missing = [];
|
|
10265
|
+
if (!secretKey) missing.push(" SUPABASE_SECRET_KEY=your-service-role-key");
|
|
10266
|
+
if (!dbUrl)
|
|
10267
|
+
missing.push(
|
|
10268
|
+
" SUPABASE_DB_URL=postgresql://postgres:...@db.<ref>.supabase.co:5432/postgres"
|
|
10269
|
+
);
|
|
10295
10270
|
Me(
|
|
10296
10271
|
[
|
|
10297
10272
|
`Fill in ${functionsEnvPath}:`,
|
|
10298
|
-
|
|
10273
|
+
...missing,
|
|
10299
10274
|
"",
|
|
10300
|
-
"Get
|
|
10275
|
+
"Get these from: https://supabase.com/dashboard > Settings > Database",
|
|
10301
10276
|
"",
|
|
10302
|
-
"
|
|
10277
|
+
"Then re-run: dndev setup supabase"
|
|
10303
10278
|
].join("\n"),
|
|
10304
|
-
"Missing
|
|
10305
|
-
);
|
|
10306
|
-
}
|
|
10307
|
-
try {
|
|
10308
|
-
const projectRef = extractProjectRef(supabaseUrl);
|
|
10309
|
-
ensureProjectLinked(appDir, projectRef);
|
|
10310
|
-
log.success("Supabase CLI linked");
|
|
10311
|
-
} catch (error2) {
|
|
10312
|
-
log.warn(
|
|
10313
|
-
`Could not link Supabase project: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
10279
|
+
"Missing Credentials"
|
|
10314
10280
|
);
|
|
10281
|
+
Se("Setup aborted.");
|
|
10282
|
+
return;
|
|
10315
10283
|
}
|
|
10316
10284
|
const entitiesDir = joinPath(projectRoot, "entities");
|
|
10317
10285
|
const hasEntities = pathExists(entitiesDir) && pathExists(joinPath(entitiesDir, "index.ts"));
|
|
@@ -10364,25 +10332,21 @@ async function main3(options = {}) {
|
|
|
10364
10332
|
}
|
|
10365
10333
|
}
|
|
10366
10334
|
let migrationsPushed = false;
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
|
|
10371
|
-
|
|
10372
|
-
|
|
10373
|
-
);
|
|
10374
|
-
|
|
10375
|
-
|
|
10376
|
-
s.
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
s.stop("Failed to push migrations");
|
|
10383
|
-
log.error(`${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
10384
|
-
log.info("Apply manually via the Supabase Dashboard SQL Editor.");
|
|
10385
|
-
}
|
|
10335
|
+
const shouldPush = await askForConfirmation(
|
|
10336
|
+
"Push migrations to remote database?",
|
|
10337
|
+
true
|
|
10338
|
+
);
|
|
10339
|
+
if (shouldPush) {
|
|
10340
|
+
const s = Y2();
|
|
10341
|
+
s.start("Pushing migrations...");
|
|
10342
|
+
try {
|
|
10343
|
+
await executeMigration({ supabaseDir, dbUrl });
|
|
10344
|
+
s.stop("Migrations pushed successfully");
|
|
10345
|
+
migrationsPushed = true;
|
|
10346
|
+
} catch (error2) {
|
|
10347
|
+
s.stop("Failed to push migrations");
|
|
10348
|
+
log.error(`${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
10349
|
+
log.info("Apply manually via the Supabase Dashboard SQL Editor.");
|
|
10386
10350
|
}
|
|
10387
10351
|
}
|
|
10388
10352
|
try {
|
|
@@ -10441,96 +10405,121 @@ var init_supabase = __esm({
|
|
|
10441
10405
|
async run(ctx) {
|
|
10442
10406
|
const steps = [];
|
|
10443
10407
|
const framework = ctx.app?.framework === "nextjs" ? "nextjs" : "vite";
|
|
10408
|
+
const supabaseDir = joinPath(ctx.appDir, "supabase");
|
|
10444
10409
|
const existingConfig = detectPublicConfig(ctx.appDir, framework);
|
|
10445
10410
|
if (!existingConfig) {
|
|
10446
|
-
const prefix = framework === "nextjs" ? "NEXT_PUBLIC_" : "VITE_";
|
|
10447
|
-
const envPath = joinPath(ctx.appDir, ".env");
|
|
10448
|
-
Me(
|
|
10449
|
-
[
|
|
10450
|
-
`Fill in ${envPath}:`,
|
|
10451
|
-
` ${prefix}SUPABASE_URL=https://your-project.supabase.co`,
|
|
10452
|
-
` ${prefix}SUPABASE_PUBLIC_KEY=sb_publishable_...`,
|
|
10453
|
-
"",
|
|
10454
|
-
"Get these from: https://supabase.com/dashboard > Settings > API",
|
|
10455
|
-
"",
|
|
10456
|
-
"Then re-run: dndev setup supabase"
|
|
10457
|
-
].join("\n"),
|
|
10458
|
-
"Missing Public Credentials"
|
|
10459
|
-
);
|
|
10460
10411
|
steps.push({
|
|
10461
10412
|
name: "Credentials",
|
|
10462
10413
|
status: "failed",
|
|
10463
|
-
message: "Missing Supabase
|
|
10464
|
-
coachingTopic: "supabase-credentials"
|
|
10414
|
+
message: "Missing Supabase URL or public key in .env"
|
|
10465
10415
|
});
|
|
10466
10416
|
return { provider: "supabase", steps, overallStatus: "failed" };
|
|
10467
10417
|
}
|
|
10468
|
-
const supabaseUrl = existingConfig.url;
|
|
10469
|
-
steps.push({
|
|
10470
|
-
name: "Public credentials",
|
|
10471
|
-
status: "success",
|
|
10472
|
-
message: `URL: ${supabaseUrl}`
|
|
10473
|
-
});
|
|
10474
10418
|
const secretKey = detectSecretKey(ctx.appDir);
|
|
10475
|
-
|
|
10419
|
+
const dbUrl = detectDbUrl(ctx.appDir);
|
|
10420
|
+
const missingSecrets = [];
|
|
10421
|
+
if (!secretKey) missingSecrets.push("SUPABASE_SECRET_KEY");
|
|
10422
|
+
if (!dbUrl) missingSecrets.push("SUPABASE_DB_URL");
|
|
10423
|
+
if (missingSecrets.length > 0) {
|
|
10476
10424
|
steps.push({
|
|
10477
|
-
name: "
|
|
10478
|
-
status: "
|
|
10479
|
-
message:
|
|
10425
|
+
name: "Credentials",
|
|
10426
|
+
status: "failed",
|
|
10427
|
+
message: `Missing in functions/.env: ${missingSecrets.join(", ")}`
|
|
10480
10428
|
});
|
|
10429
|
+
return { provider: "supabase", steps, overallStatus: "failed" };
|
|
10430
|
+
}
|
|
10431
|
+
steps.push({
|
|
10432
|
+
name: "Credentials",
|
|
10433
|
+
status: "success",
|
|
10434
|
+
message: `${existingConfig.url}`
|
|
10435
|
+
});
|
|
10436
|
+
const entitiesDir = joinPath(ctx.projectRoot, "entities");
|
|
10437
|
+
const hasEntities = pathExists(entitiesDir) && pathExists(joinPath(entitiesDir, "index.ts"));
|
|
10438
|
+
let generatedEntityFile = null;
|
|
10439
|
+
if (hasEntities) {
|
|
10440
|
+
try {
|
|
10441
|
+
const { SqlGenerator: SqlGenerator2 } = await Promise.resolve().then(() => (init_sql_generator(), sql_generator_exports));
|
|
10442
|
+
const generator = new SqlGenerator2({
|
|
10443
|
+
entityDir: entitiesDir,
|
|
10444
|
+
outputDir: joinPath(supabaseDir, "migrations"),
|
|
10445
|
+
singleFile: true
|
|
10446
|
+
});
|
|
10447
|
+
const s = Y2();
|
|
10448
|
+
s.start("Generating SQL from entities...");
|
|
10449
|
+
const result = await generator.run();
|
|
10450
|
+
if (result.success) {
|
|
10451
|
+
s.stop("SQL generated");
|
|
10452
|
+
generatedEntityFile = result.generatedFiles[0] ?? null;
|
|
10453
|
+
steps.push({
|
|
10454
|
+
name: "SQL generation",
|
|
10455
|
+
status: "success",
|
|
10456
|
+
message: `${result.filesGenerated} migration file(s)`
|
|
10457
|
+
});
|
|
10458
|
+
} else {
|
|
10459
|
+
s.stop("SQL generation failed");
|
|
10460
|
+
steps.push({
|
|
10461
|
+
name: "SQL generation",
|
|
10462
|
+
status: "failed",
|
|
10463
|
+
message: "Generator returned failure"
|
|
10464
|
+
});
|
|
10465
|
+
}
|
|
10466
|
+
} catch (error2) {
|
|
10467
|
+
steps.push({
|
|
10468
|
+
name: "SQL generation",
|
|
10469
|
+
status: "failed",
|
|
10470
|
+
message: getErrorMessage(error2)
|
|
10471
|
+
});
|
|
10472
|
+
}
|
|
10481
10473
|
} else {
|
|
10482
|
-
const supabaseDir = joinPath(ctx.appDir, "supabase");
|
|
10483
|
-
const functionsEnvPath = joinPath(supabaseDir, "functions", ".env");
|
|
10484
|
-
Me(
|
|
10485
|
-
[
|
|
10486
|
-
`Fill in ${functionsEnvPath}:`,
|
|
10487
|
-
" SUPABASE_SECRET_KEY=your-service-role-key",
|
|
10488
|
-
"",
|
|
10489
|
-
"Get this from: https://supabase.com/dashboard > Settings > API > service_role key"
|
|
10490
|
-
].join("\n"),
|
|
10491
|
-
"Missing Secret Key"
|
|
10492
|
-
);
|
|
10493
10474
|
steps.push({
|
|
10494
|
-
name: "
|
|
10495
|
-
status: "
|
|
10496
|
-
message: "
|
|
10497
|
-
coachingTopic: "supabase-secret-key"
|
|
10475
|
+
name: "SQL generation",
|
|
10476
|
+
status: "skipped",
|
|
10477
|
+
message: "No entities/ directory"
|
|
10498
10478
|
});
|
|
10499
10479
|
}
|
|
10500
|
-
if (
|
|
10480
|
+
if (generatedEntityFile) {
|
|
10481
|
+
try {
|
|
10482
|
+
await cleanupOldEntityMigrations(supabaseDir, generatedEntityFile);
|
|
10483
|
+
} catch {
|
|
10484
|
+
}
|
|
10485
|
+
}
|
|
10486
|
+
const migrationsDir = joinPath(supabaseDir, "migrations");
|
|
10487
|
+
if (pathExists(migrationsDir)) {
|
|
10488
|
+
const s = Y2();
|
|
10489
|
+
s.start("Pushing migrations...");
|
|
10501
10490
|
try {
|
|
10502
|
-
|
|
10503
|
-
|
|
10491
|
+
await executeMigration({ supabaseDir, dbUrl });
|
|
10492
|
+
s.stop("Migrations pushed");
|
|
10504
10493
|
steps.push({
|
|
10505
|
-
name: "
|
|
10494
|
+
name: "DB migrations",
|
|
10506
10495
|
status: "success",
|
|
10507
|
-
message: "
|
|
10496
|
+
message: "All migrations applied"
|
|
10508
10497
|
});
|
|
10509
|
-
} catch (
|
|
10498
|
+
} catch (error2) {
|
|
10499
|
+
s.stop("Migration push failed");
|
|
10510
10500
|
steps.push({
|
|
10511
|
-
name: "
|
|
10501
|
+
name: "DB migrations",
|
|
10512
10502
|
status: "failed",
|
|
10513
|
-
message: getErrorMessage(
|
|
10503
|
+
message: getErrorMessage(error2)
|
|
10504
|
+
});
|
|
10505
|
+
}
|
|
10506
|
+
}
|
|
10507
|
+
if (hasEntities) {
|
|
10508
|
+
try {
|
|
10509
|
+
await generateCrudFunction(supabaseDir, ctx.projectRoot);
|
|
10510
|
+
steps.push({
|
|
10511
|
+
name: "CRUD function",
|
|
10512
|
+
status: "success",
|
|
10513
|
+
message: "Entity imports patched"
|
|
10514
|
+
});
|
|
10515
|
+
} catch (error2) {
|
|
10516
|
+
steps.push({
|
|
10517
|
+
name: "CRUD function",
|
|
10518
|
+
status: "failed",
|
|
10519
|
+
message: getErrorMessage(error2)
|
|
10514
10520
|
});
|
|
10515
10521
|
}
|
|
10516
|
-
} else {
|
|
10517
|
-
steps.push({ name: "CLI link", status: "skipped", message: "Dry run" });
|
|
10518
10522
|
}
|
|
10519
|
-
Me(
|
|
10520
|
-
[
|
|
10521
|
-
"If you use custom RLS policies beyond the defaults,",
|
|
10522
|
-
"review them in the Supabase Dashboard:",
|
|
10523
|
-
"",
|
|
10524
|
-
"https://supabase.com/dashboard > Authentication > Policies"
|
|
10525
|
-
].join("\n"),
|
|
10526
|
-
"Row Level Security"
|
|
10527
|
-
);
|
|
10528
|
-
steps.push({
|
|
10529
|
-
name: "RLS policies",
|
|
10530
|
-
status: "needs-manual",
|
|
10531
|
-
message: "Review custom RLS policies in dashboard",
|
|
10532
|
-
coachingTopic: "supabase-rls"
|
|
10533
|
-
});
|
|
10534
10523
|
return {
|
|
10535
10524
|
provider: "supabase",
|
|
10536
10525
|
steps,
|
|
@@ -10546,27 +10535,13 @@ var vercel_exports = {};
|
|
|
10546
10535
|
__export(vercel_exports, {
|
|
10547
10536
|
vercelWizard: () => vercelWizard
|
|
10548
10537
|
});
|
|
10549
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
10550
|
-
function isVercelInstalled() {
|
|
10551
|
-
try {
|
|
10552
|
-
const result = spawnSync2("vercel", ["--version"], {
|
|
10553
|
-
stdio: "pipe",
|
|
10554
|
-
encoding: "utf-8"
|
|
10555
|
-
});
|
|
10556
|
-
return result.status === 0;
|
|
10557
|
-
} catch {
|
|
10558
|
-
return false;
|
|
10559
|
-
}
|
|
10560
|
-
}
|
|
10561
10538
|
var vercelWizard;
|
|
10562
10539
|
var init_vercel = __esm({
|
|
10563
10540
|
"packages/tooling/src/cli/setup/vercel.ts"() {
|
|
10564
10541
|
"use strict";
|
|
10565
10542
|
init_utils();
|
|
10566
10543
|
init_cli_output();
|
|
10567
|
-
init_cli_output();
|
|
10568
10544
|
init_pathResolver();
|
|
10569
|
-
init_error_handling();
|
|
10570
10545
|
init_types();
|
|
10571
10546
|
init_vercel_token();
|
|
10572
10547
|
vercelWizard = {
|
|
@@ -10577,108 +10552,22 @@ var init_vercel = __esm({
|
|
|
10577
10552
|
},
|
|
10578
10553
|
async run(ctx) {
|
|
10579
10554
|
const steps = [];
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
log.
|
|
10583
|
-
steps.push({
|
|
10584
|
-
name: "Vercel CLI",
|
|
10585
|
-
status: "failed",
|
|
10586
|
-
message: "Not installed. Run: npm install -g vercel"
|
|
10587
|
-
});
|
|
10588
|
-
return { provider: "vercel", steps, overallStatus: "failed" };
|
|
10589
|
-
}
|
|
10590
|
-
steps.push({ name: "Vercel CLI", status: "success", message: "Installed" });
|
|
10591
|
-
const token = resolveVercelToken(ctx.appDir);
|
|
10592
|
-
if (token) {
|
|
10593
|
-
log.success("VERCEL_TOKEN detected \u2014 no login required");
|
|
10555
|
+
const result = resolveVercelCredentials(ctx.appDir);
|
|
10556
|
+
if (result.credentials) {
|
|
10557
|
+
log.success("Vercel credentials detected");
|
|
10594
10558
|
steps.push({
|
|
10595
|
-
name: "
|
|
10559
|
+
name: "Credentials",
|
|
10596
10560
|
status: "success",
|
|
10597
|
-
message: "
|
|
10598
|
-
});
|
|
10599
|
-
} else {
|
|
10600
|
-
Me(
|
|
10601
|
-
[
|
|
10602
|
-
"No VERCEL_TOKEN found. Add to .env or .env.local:",
|
|
10603
|
-
" VERCEL_TOKEN=your_token_here",
|
|
10604
|
-
"",
|
|
10605
|
-
"Your customer generates it at:",
|
|
10606
|
-
" https://vercel.com/account/tokens",
|
|
10607
|
-
" \u2192 Scope to their team for isolation",
|
|
10608
|
-
"",
|
|
10609
|
-
"This way you deploy to THEIR Vercel without logging in."
|
|
10610
|
-
].join("\n"),
|
|
10611
|
-
"Vercel Authentication"
|
|
10612
|
-
);
|
|
10613
|
-
steps.push({
|
|
10614
|
-
name: "Auth",
|
|
10615
|
-
status: "needs-manual",
|
|
10616
|
-
message: "Drop VERCEL_TOKEN in .env (get it from customer)",
|
|
10617
|
-
coachingTopic: "vercel-token"
|
|
10618
|
-
});
|
|
10619
|
-
}
|
|
10620
|
-
if (token && !ctx.dryRun) {
|
|
10621
|
-
const s = Y2();
|
|
10622
|
-
s.start("Linking Vercel project...");
|
|
10623
|
-
try {
|
|
10624
|
-
const result = spawnSync2(
|
|
10625
|
-
"vercel",
|
|
10626
|
-
["link", "--yes", "--token", token],
|
|
10627
|
-
{
|
|
10628
|
-
cwd: ctx.appDir,
|
|
10629
|
-
stdio: ["inherit", "pipe", "pipe"],
|
|
10630
|
-
encoding: "utf-8",
|
|
10631
|
-
timeout: 3e4
|
|
10632
|
-
}
|
|
10633
|
-
);
|
|
10634
|
-
if (result.status === 0) {
|
|
10635
|
-
s.stop("Vercel project linked");
|
|
10636
|
-
steps.push({
|
|
10637
|
-
name: "Project link",
|
|
10638
|
-
status: "success",
|
|
10639
|
-
message: "Linked to Vercel project"
|
|
10640
|
-
});
|
|
10641
|
-
} else {
|
|
10642
|
-
s.stop("Vercel link failed");
|
|
10643
|
-
const stderr = result.stderr?.trim() || "Unknown error";
|
|
10644
|
-
steps.push({
|
|
10645
|
-
name: "Project link",
|
|
10646
|
-
status: "failed",
|
|
10647
|
-
message: stderr
|
|
10648
|
-
});
|
|
10649
|
-
}
|
|
10650
|
-
} catch (err) {
|
|
10651
|
-
s.stop("Vercel link failed");
|
|
10652
|
-
steps.push({
|
|
10653
|
-
name: "Project link",
|
|
10654
|
-
status: "failed",
|
|
10655
|
-
message: getErrorMessage(err)
|
|
10656
|
-
});
|
|
10657
|
-
}
|
|
10658
|
-
} else if (!token) {
|
|
10659
|
-
steps.push({
|
|
10660
|
-
name: "Project link",
|
|
10661
|
-
status: "skipped",
|
|
10662
|
-
message: "No token \u2014 cannot link"
|
|
10561
|
+
message: "VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID found"
|
|
10663
10562
|
});
|
|
10664
10563
|
} else {
|
|
10564
|
+
log.error(`Missing in .env.local: ${result.missing.join(", ")}`);
|
|
10665
10565
|
steps.push({
|
|
10666
|
-
name: "
|
|
10667
|
-
status: "
|
|
10668
|
-
message: "
|
|
10566
|
+
name: "Credentials",
|
|
10567
|
+
status: "failed",
|
|
10568
|
+
message: `Missing: ${result.missing.join(", ")}`
|
|
10669
10569
|
});
|
|
10670
10570
|
}
|
|
10671
|
-
Me(
|
|
10672
|
-
[
|
|
10673
|
-
"Once VERCEL_TOKEN is in .env:",
|
|
10674
|
-
" dndev deploy \u2192 picks it up automatically",
|
|
10675
|
-
" dndev deploy:web \u2192 deploy specific app",
|
|
10676
|
-
"",
|
|
10677
|
-
"deploy.ts reads vercel.json + injects the token.",
|
|
10678
|
-
'No separate "vercel deploy" needed.'
|
|
10679
|
-
].join("\n"),
|
|
10680
|
-
"Deployment"
|
|
10681
|
-
);
|
|
10682
10571
|
return {
|
|
10683
10572
|
provider: "vercel",
|
|
10684
10573
|
steps,
|
|
@@ -10689,868 +10578,77 @@ var init_vercel = __esm({
|
|
|
10689
10578
|
}
|
|
10690
10579
|
});
|
|
10691
10580
|
|
|
10692
|
-
// packages/
|
|
10693
|
-
|
|
10694
|
-
__export(stripe_exports, {
|
|
10695
|
-
stripeWizard: () => stripeWizard
|
|
10696
|
-
});
|
|
10697
|
-
function isValidPublishableKey(key) {
|
|
10698
|
-
return key.startsWith("pk_test_") || key.startsWith("pk_live_");
|
|
10699
|
-
}
|
|
10700
|
-
function isValidSecretKey(key) {
|
|
10701
|
-
return key.startsWith("sk_test_") || key.startsWith("sk_live_") || key.startsWith("rk_test_") || key.startsWith("rk_live_");
|
|
10702
|
-
}
|
|
10703
|
-
function isValidWebhookSecret(key) {
|
|
10704
|
-
return key.startsWith("whsec_");
|
|
10705
|
-
}
|
|
10706
|
-
function readEnvValue(envPath, varName) {
|
|
10707
|
-
if (!pathExists(envPath)) return null;
|
|
10708
|
-
const content = readSync(envPath, { format: "text" });
|
|
10709
|
-
if (typeof content !== "string") return null;
|
|
10710
|
-
for (const line of content.split(/\r?\n/)) {
|
|
10711
|
-
const trimmed = line.trim();
|
|
10712
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
10713
|
-
if (trimmed.startsWith(`${varName}=`)) {
|
|
10714
|
-
return trimmed.substring(`${varName}=`.length).trim();
|
|
10715
|
-
}
|
|
10716
|
-
}
|
|
10717
|
-
return null;
|
|
10718
|
-
}
|
|
10719
|
-
function writeEnvVar(envPath, varName, value) {
|
|
10720
|
-
let content = "";
|
|
10721
|
-
if (pathExists(envPath)) {
|
|
10722
|
-
const raw = readSync(envPath, { format: "text" });
|
|
10723
|
-
content = typeof raw === "string" ? raw : "";
|
|
10724
|
-
}
|
|
10725
|
-
const lines = content.split("\n");
|
|
10726
|
-
let replaced = false;
|
|
10727
|
-
const updated = lines.map((line) => {
|
|
10728
|
-
if (line.trim().startsWith(`${varName}=`) || line.trim().startsWith(`# ${varName}=`)) {
|
|
10729
|
-
replaced = true;
|
|
10730
|
-
return `${varName}=${value}`;
|
|
10731
|
-
}
|
|
10732
|
-
return line;
|
|
10733
|
-
});
|
|
10734
|
-
if (!replaced) {
|
|
10735
|
-
updated.push(`${varName}=${value}`);
|
|
10736
|
-
}
|
|
10737
|
-
write(envPath, updated.join("\n"));
|
|
10738
|
-
}
|
|
10739
|
-
var stripeWizard;
|
|
10740
|
-
var init_stripe = __esm({
|
|
10741
|
-
"packages/tooling/src/cli/setup/stripe.ts"() {
|
|
10742
|
-
"use strict";
|
|
10743
|
-
init_utils();
|
|
10744
|
-
init_dist2();
|
|
10745
|
-
init_cli_output();
|
|
10746
|
-
init_cli_output();
|
|
10747
|
-
init_pathResolver();
|
|
10748
|
-
init_cli_input();
|
|
10749
|
-
init_types();
|
|
10750
|
-
stripeWizard = {
|
|
10751
|
-
id: "stripe",
|
|
10752
|
-
name: "Stripe",
|
|
10753
|
-
isRelevant(ctx) {
|
|
10754
|
-
const envPath = joinPath(ctx.appDir, ".env");
|
|
10755
|
-
if (pathExists(envPath)) {
|
|
10756
|
-
const content = readSync(envPath, { format: "text" });
|
|
10757
|
-
if (typeof content === "string" && content.includes("STRIPE_"))
|
|
10758
|
-
return true;
|
|
10759
|
-
}
|
|
10760
|
-
const pkgPath = joinPath(ctx.appDir, "package.json");
|
|
10761
|
-
if (pathExists(pkgPath)) {
|
|
10762
|
-
const pkg = readSync(pkgPath, { format: "json" });
|
|
10763
|
-
if (pkg && typeof pkg === "object") {
|
|
10764
|
-
const deps = {
|
|
10765
|
-
...pkg.dependencies
|
|
10766
|
-
};
|
|
10767
|
-
if (deps["@donotdev/billing"]) return true;
|
|
10768
|
-
}
|
|
10769
|
-
}
|
|
10770
|
-
return false;
|
|
10771
|
-
},
|
|
10772
|
-
async run(ctx) {
|
|
10773
|
-
const steps = [];
|
|
10774
|
-
const framework = ctx.app?.framework === "nextjs" ? "nextjs" : "vite";
|
|
10775
|
-
const prefix = framework === "nextjs" ? "NEXT_PUBLIC_" : "VITE_";
|
|
10776
|
-
const envPath = joinPath(ctx.appDir, ".env");
|
|
10777
|
-
const existingPk = readEnvValue(envPath, `${prefix}STRIPE_PUBLISHABLE_KEY`);
|
|
10778
|
-
let publishableKey = existingPk;
|
|
10779
|
-
if (existingPk && isValidPublishableKey(existingPk)) {
|
|
10780
|
-
steps.push({
|
|
10781
|
-
name: "Publishable key",
|
|
10782
|
-
status: "success",
|
|
10783
|
-
message: "Found in .env"
|
|
10784
|
-
});
|
|
10785
|
-
} else {
|
|
10786
|
-
const pk = await askForInput(
|
|
10787
|
-
"Stripe publishable key (pk_test_... or pk_live_...)",
|
|
10788
|
-
""
|
|
10789
|
-
);
|
|
10790
|
-
if (isValidPublishableKey(pk)) {
|
|
10791
|
-
if (!ctx.dryRun) {
|
|
10792
|
-
writeEnvVar(envPath, `${prefix}STRIPE_PUBLISHABLE_KEY`, pk);
|
|
10793
|
-
log.success("Wrote STRIPE_PUBLISHABLE_KEY to .env");
|
|
10794
|
-
}
|
|
10795
|
-
publishableKey = pk;
|
|
10796
|
-
steps.push({
|
|
10797
|
-
name: "Publishable key",
|
|
10798
|
-
status: "success",
|
|
10799
|
-
message: "Written to .env"
|
|
10800
|
-
});
|
|
10801
|
-
} else {
|
|
10802
|
-
steps.push({
|
|
10803
|
-
name: "Publishable key",
|
|
10804
|
-
status: "failed",
|
|
10805
|
-
message: "Invalid format \u2014 must start with pk_test_ or pk_live_"
|
|
10806
|
-
});
|
|
10807
|
-
}
|
|
10808
|
-
}
|
|
10809
|
-
const functionsEnvPath = joinPath(
|
|
10810
|
-
ctx.appDir,
|
|
10811
|
-
"supabase",
|
|
10812
|
-
"functions",
|
|
10813
|
-
".env"
|
|
10814
|
-
);
|
|
10815
|
-
const altFunctionsEnvPath = joinPath(ctx.appDir, "functions", ".env");
|
|
10816
|
-
const secretEnvPath = pathExists(functionsEnvPath) ? functionsEnvPath : altFunctionsEnvPath;
|
|
10817
|
-
const existingSk = readEnvValue(secretEnvPath, "STRIPE_SECRET_KEY");
|
|
10818
|
-
if (existingSk && isValidSecretKey(existingSk)) {
|
|
10819
|
-
steps.push({
|
|
10820
|
-
name: "Secret key",
|
|
10821
|
-
status: "success",
|
|
10822
|
-
message: "Found in functions/.env"
|
|
10823
|
-
});
|
|
10824
|
-
} else {
|
|
10825
|
-
const sk = await ge({
|
|
10826
|
-
message: "Stripe secret key (sk_test_... or sk_live_...):"
|
|
10827
|
-
});
|
|
10828
|
-
if (typeof sk === "string" && isValidSecretKey(sk)) {
|
|
10829
|
-
if (!ctx.dryRun) {
|
|
10830
|
-
writeEnvVar(secretEnvPath, "STRIPE_SECRET_KEY", sk);
|
|
10831
|
-
log.success("Wrote STRIPE_SECRET_KEY to functions/.env");
|
|
10832
|
-
}
|
|
10833
|
-
steps.push({
|
|
10834
|
-
name: "Secret key",
|
|
10835
|
-
status: "success",
|
|
10836
|
-
message: "Written to functions/.env"
|
|
10837
|
-
});
|
|
10838
|
-
} else {
|
|
10839
|
-
steps.push({
|
|
10840
|
-
name: "Secret key",
|
|
10841
|
-
status: "failed",
|
|
10842
|
-
message: "STRIPE_SECRET_KEY has invalid format"
|
|
10843
|
-
});
|
|
10844
|
-
}
|
|
10845
|
-
}
|
|
10846
|
-
const existingWh = readEnvValue(secretEnvPath, "STRIPE_WEBHOOK_SECRET");
|
|
10847
|
-
if (existingWh && isValidWebhookSecret(existingWh)) {
|
|
10848
|
-
steps.push({
|
|
10849
|
-
name: "Webhook secret",
|
|
10850
|
-
status: "success",
|
|
10851
|
-
message: "Found in functions/.env"
|
|
10852
|
-
});
|
|
10853
|
-
} else {
|
|
10854
|
-
Me(
|
|
10855
|
-
[
|
|
10856
|
-
"Set up your Stripe webhook endpoint:",
|
|
10857
|
-
"",
|
|
10858
|
-
"1. Go to https://dashboard.stripe.com/webhooks",
|
|
10859
|
-
'2. Click "Add endpoint"',
|
|
10860
|
-
"3. Set URL to your functions endpoint:",
|
|
10861
|
-
" e.g., https://your-project.supabase.co/functions/v1/stripe-webhook",
|
|
10862
|
-
"4. Select events: checkout.session.completed, customer.subscription.*",
|
|
10863
|
-
"5. Copy the webhook signing secret (whsec_...)",
|
|
10864
|
-
"",
|
|
10865
|
-
`Then add to ${secretEnvPath}:`,
|
|
10866
|
-
" STRIPE_WEBHOOK_SECRET=whsec_..."
|
|
10867
|
-
].join("\n"),
|
|
10868
|
-
"Webhook Setup"
|
|
10869
|
-
);
|
|
10870
|
-
steps.push({
|
|
10871
|
-
name: "Webhook secret",
|
|
10872
|
-
status: "needs-manual",
|
|
10873
|
-
message: "Configure webhook endpoint in Stripe Dashboard",
|
|
10874
|
-
coachingTopic: "stripe-webhook"
|
|
10875
|
-
});
|
|
10876
|
-
}
|
|
10877
|
-
return {
|
|
10878
|
-
provider: "stripe",
|
|
10879
|
-
steps,
|
|
10880
|
-
overallStatus: computeOverallStatus(steps)
|
|
10881
|
-
};
|
|
10882
|
-
}
|
|
10883
|
-
};
|
|
10884
|
-
}
|
|
10885
|
-
});
|
|
10581
|
+
// packages/cli/src/bin/commands/setup.ts
|
|
10582
|
+
init_utils();
|
|
10886
10583
|
|
|
10887
|
-
// packages/tooling/src/
|
|
10888
|
-
|
|
10889
|
-
__export(oauth_exports, {
|
|
10890
|
-
oauthWizard: () => oauthWizard
|
|
10891
|
-
});
|
|
10892
|
-
function getRedirectUri(ctx, provider) {
|
|
10893
|
-
if (provider === "firebase") {
|
|
10894
|
-
const rcPath = joinPath(ctx.projectRoot, ".firebaserc");
|
|
10895
|
-
if (pathExists(rcPath)) {
|
|
10896
|
-
try {
|
|
10897
|
-
const raw = readSync(rcPath, { format: "text" });
|
|
10898
|
-
const rc = JSON.parse(typeof raw === "string" ? raw : "{}");
|
|
10899
|
-
const projectId = rc?.projects?.default;
|
|
10900
|
-
if (projectId) {
|
|
10901
|
-
return `https://${projectId}.firebaseapp.com/__/auth/handler`;
|
|
10902
|
-
}
|
|
10903
|
-
} catch {
|
|
10904
|
-
}
|
|
10905
|
-
}
|
|
10906
|
-
return "https://<YOUR_PROJECT_ID>.firebaseapp.com/__/auth/handler";
|
|
10907
|
-
}
|
|
10908
|
-
const envPath = joinPath(ctx.appDir, ".env");
|
|
10909
|
-
if (pathExists(envPath)) {
|
|
10910
|
-
const content = readSync(envPath, { format: "text" });
|
|
10911
|
-
if (typeof content === "string") {
|
|
10912
|
-
const match = content.match(/(?:VITE_|NEXT_PUBLIC_)SUPABASE_URL=(.+)/);
|
|
10913
|
-
if (match?.[1]) {
|
|
10914
|
-
return `${match[1].trim()}/auth/v1/callback`;
|
|
10915
|
-
}
|
|
10916
|
-
}
|
|
10917
|
-
}
|
|
10918
|
-
return "https://<YOUR_PROJECT_REF>.supabase.co/auth/v1/callback";
|
|
10919
|
-
}
|
|
10920
|
-
var OAUTH_PROVIDERS, oauthWizard;
|
|
10921
|
-
var init_oauth = __esm({
|
|
10922
|
-
"packages/tooling/src/cli/setup/oauth.ts"() {
|
|
10923
|
-
"use strict";
|
|
10924
|
-
init_utils();
|
|
10925
|
-
init_cli_output();
|
|
10926
|
-
init_pathResolver();
|
|
10927
|
-
init_cli_input();
|
|
10928
|
-
init_types();
|
|
10929
|
-
OAUTH_PROVIDERS = [
|
|
10930
|
-
{
|
|
10931
|
-
id: "google",
|
|
10932
|
-
name: "Google",
|
|
10933
|
-
consoleUrl: "https://console.cloud.google.com/apis/credentials",
|
|
10934
|
-
instructions: [
|
|
10935
|
-
"1. Go to Google Cloud Console > APIs & Services > Credentials",
|
|
10936
|
-
"2. Create OAuth 2.0 Client ID (Web application)",
|
|
10937
|
-
"3. Add authorized redirect URI (see below)",
|
|
10938
|
-
"4. Copy Client ID + Client Secret"
|
|
10939
|
-
]
|
|
10940
|
-
},
|
|
10941
|
-
{
|
|
10942
|
-
id: "github",
|
|
10943
|
-
name: "GitHub",
|
|
10944
|
-
consoleUrl: "https://github.com/settings/developers",
|
|
10945
|
-
instructions: [
|
|
10946
|
-
"1. Go to GitHub > Settings > Developer settings > OAuth Apps",
|
|
10947
|
-
'2. Click "New OAuth App"',
|
|
10948
|
-
"3. Set Authorization callback URL (see below)",
|
|
10949
|
-
"4. Copy Client ID + Client Secret"
|
|
10950
|
-
]
|
|
10951
|
-
},
|
|
10952
|
-
{
|
|
10953
|
-
id: "apple",
|
|
10954
|
-
name: "Apple",
|
|
10955
|
-
consoleUrl: "https://developer.apple.com/account/resources/identifiers/list/serviceId",
|
|
10956
|
-
instructions: [
|
|
10957
|
-
"1. Go to Apple Developer > Certificates, Identifiers & Profiles",
|
|
10958
|
-
"2. Create a Services ID",
|
|
10959
|
-
'3. Enable "Sign In with Apple"',
|
|
10960
|
-
"4. Configure redirect URL (see below)",
|
|
10961
|
-
"5. Create a private key for Sign In with Apple"
|
|
10962
|
-
]
|
|
10963
|
-
}
|
|
10964
|
-
];
|
|
10965
|
-
oauthWizard = {
|
|
10966
|
-
id: "oauth",
|
|
10967
|
-
name: "OAuth Providers",
|
|
10968
|
-
isRelevant(ctx) {
|
|
10969
|
-
const pkgPath = joinPath(ctx.appDir, "package.json");
|
|
10970
|
-
if (pathExists(pkgPath)) {
|
|
10971
|
-
const pkg = readSync(pkgPath, { format: "json" });
|
|
10972
|
-
if (pkg && typeof pkg === "object") {
|
|
10973
|
-
const deps = pkg.dependencies;
|
|
10974
|
-
if (deps?.["@donotdev/auth"] || deps?.["@donotdev/oauth"]) return true;
|
|
10975
|
-
}
|
|
10976
|
-
}
|
|
10977
|
-
return false;
|
|
10978
|
-
},
|
|
10979
|
-
async run(ctx) {
|
|
10980
|
-
const steps = [];
|
|
10981
|
-
const hasFirebase = pathExists(joinPath(ctx.projectRoot, ".firebaserc")) || pathExists(joinPath(ctx.appDir, "firebase.json"));
|
|
10982
|
-
const hasSupabase = pathExists(joinPath(ctx.appDir, "supabase"));
|
|
10983
|
-
const backendProvider = hasFirebase ? "firebase" : "supabase";
|
|
10984
|
-
const redirectUri = getRedirectUri(ctx, backendProvider);
|
|
10985
|
-
const selected = await askForMultiSelection(
|
|
10986
|
-
"Which OAuth providers do you want to configure?",
|
|
10987
|
-
OAUTH_PROVIDERS.map((p2) => ({
|
|
10988
|
-
title: p2.name,
|
|
10989
|
-
value: p2.id
|
|
10990
|
-
}))
|
|
10991
|
-
);
|
|
10992
|
-
if (selected.length === 0) {
|
|
10993
|
-
steps.push({
|
|
10994
|
-
name: "OAuth",
|
|
10995
|
-
status: "skipped",
|
|
10996
|
-
message: "No providers selected"
|
|
10997
|
-
});
|
|
10998
|
-
return { provider: "oauth", steps, overallStatus: "success" };
|
|
10999
|
-
}
|
|
11000
|
-
for (const providerId of selected) {
|
|
11001
|
-
const provider = OAUTH_PROVIDERS.find((p2) => p2.id === providerId);
|
|
11002
|
-
if (!provider) continue;
|
|
11003
|
-
Me(
|
|
11004
|
-
[
|
|
11005
|
-
...provider.instructions,
|
|
11006
|
-
"",
|
|
11007
|
-
`Redirect URI: ${redirectUri}`,
|
|
11008
|
-
"",
|
|
11009
|
-
`Console: ${provider.consoleUrl}`,
|
|
11010
|
-
"",
|
|
11011
|
-
hasSupabase ? `Then enable "${provider.name}" in Supabase Dashboard > Authentication > Providers` : `Then enable "${provider.name}" in Firebase Console > Authentication > Sign-in method`
|
|
11012
|
-
].join("\n"),
|
|
11013
|
-
`${provider.name} OAuth Setup`
|
|
11014
|
-
);
|
|
11015
|
-
steps.push({
|
|
11016
|
-
name: `${provider.name} OAuth`,
|
|
11017
|
-
status: "needs-manual",
|
|
11018
|
-
message: `Register app in ${provider.name} console + enable provider`,
|
|
11019
|
-
coachingTopic: `oauth-${provider.id}`
|
|
11020
|
-
});
|
|
11021
|
-
}
|
|
11022
|
-
return {
|
|
11023
|
-
provider: "oauth",
|
|
11024
|
-
steps,
|
|
11025
|
-
overallStatus: computeOverallStatus(steps)
|
|
11026
|
-
};
|
|
11027
|
-
}
|
|
11028
|
-
};
|
|
11029
|
-
}
|
|
11030
|
-
});
|
|
10584
|
+
// packages/tooling/src/index.ts
|
|
10585
|
+
init_utils();
|
|
11031
10586
|
|
|
11032
|
-
// packages/tooling/src/cli/
|
|
11033
|
-
|
|
11034
|
-
__export(auth_exports, {
|
|
11035
|
-
authWizard: () => authWizard
|
|
11036
|
-
});
|
|
11037
|
-
function detectAuthProviders(ctx) {
|
|
11038
|
-
const providers = ["email"];
|
|
11039
|
-
const srcDir = joinPath(ctx.appDir, "src");
|
|
11040
|
-
if (!pathExists(srcDir)) return providers;
|
|
11041
|
-
const candidates = [
|
|
11042
|
-
joinPath(srcDir, "providers.ts"),
|
|
11043
|
-
joinPath(srcDir, "providers.tsx"),
|
|
11044
|
-
joinPath(srcDir, "config", "providers.ts"),
|
|
11045
|
-
joinPath(srcDir, "lib", "providers.ts")
|
|
11046
|
-
];
|
|
11047
|
-
for (const candidate of candidates) {
|
|
11048
|
-
if (!pathExists(candidate)) continue;
|
|
11049
|
-
const content = readSync(candidate, { format: "text" });
|
|
11050
|
-
if (typeof content !== "string") continue;
|
|
11051
|
-
if (content.includes("google") || content.includes("Google"))
|
|
11052
|
-
providers.push("google");
|
|
11053
|
-
if (content.includes("github") || content.includes("GitHub"))
|
|
11054
|
-
providers.push("github");
|
|
11055
|
-
if (content.includes("apple") || content.includes("Apple"))
|
|
11056
|
-
providers.push("apple");
|
|
11057
|
-
if (content.includes("facebook") || content.includes("Facebook"))
|
|
11058
|
-
providers.push("facebook");
|
|
11059
|
-
break;
|
|
11060
|
-
}
|
|
11061
|
-
return [...new Set(providers)];
|
|
11062
|
-
}
|
|
11063
|
-
var authWizard;
|
|
11064
|
-
var init_auth = __esm({
|
|
11065
|
-
"packages/tooling/src/cli/setup/auth.ts"() {
|
|
11066
|
-
"use strict";
|
|
11067
|
-
init_utils();
|
|
11068
|
-
init_cli_output();
|
|
11069
|
-
init_pathResolver();
|
|
11070
|
-
init_types();
|
|
11071
|
-
authWizard = {
|
|
11072
|
-
id: "auth",
|
|
11073
|
-
name: "Authentication",
|
|
11074
|
-
isRelevant(ctx) {
|
|
11075
|
-
const pkgPath = joinPath(ctx.appDir, "package.json");
|
|
11076
|
-
if (pathExists(pkgPath)) {
|
|
11077
|
-
const pkg = readSync(pkgPath, { format: "json" });
|
|
11078
|
-
if (pkg && typeof pkg === "object") {
|
|
11079
|
-
const deps = pkg.dependencies;
|
|
11080
|
-
if (deps?.["@donotdev/auth"]) return true;
|
|
11081
|
-
}
|
|
11082
|
-
}
|
|
11083
|
-
return false;
|
|
11084
|
-
},
|
|
11085
|
-
async run(ctx) {
|
|
11086
|
-
const steps = [];
|
|
11087
|
-
const detectedProviders = detectAuthProviders(ctx);
|
|
11088
|
-
const hasFirebase = pathExists(joinPath(ctx.projectRoot, ".firebaserc")) || pathExists(joinPath(ctx.appDir, "firebase.json"));
|
|
11089
|
-
const hasSupabase = pathExists(joinPath(ctx.appDir, "supabase"));
|
|
11090
|
-
steps.push({
|
|
11091
|
-
name: "Detected providers",
|
|
11092
|
-
status: "success",
|
|
11093
|
-
message: `Found: ${detectedProviders.join(", ")}`
|
|
11094
|
-
});
|
|
11095
|
-
if (hasFirebase) {
|
|
11096
|
-
const rcPath = joinPath(ctx.projectRoot, ".firebaserc");
|
|
11097
|
-
let projectId = "<YOUR_PROJECT_ID>";
|
|
11098
|
-
if (pathExists(rcPath)) {
|
|
11099
|
-
try {
|
|
11100
|
-
const raw = readSync(rcPath, { format: "text" });
|
|
11101
|
-
const rc = JSON.parse(typeof raw === "string" ? raw : "{}");
|
|
11102
|
-
if (rc?.projects?.default) projectId = rc.projects.default;
|
|
11103
|
-
} catch {
|
|
11104
|
-
}
|
|
11105
|
-
}
|
|
11106
|
-
const providerList = detectedProviders.map((p2) => ` - ${p2.charAt(0).toUpperCase() + p2.slice(1)}`).join("\n");
|
|
11107
|
-
Me(
|
|
11108
|
-
[
|
|
11109
|
-
"Enable these auth providers in Firebase Console:",
|
|
11110
|
-
`https://console.firebase.google.com/project/${projectId}/authentication/providers`,
|
|
11111
|
-
"",
|
|
11112
|
-
providerList,
|
|
11113
|
-
"",
|
|
11114
|
-
"For each provider:",
|
|
11115
|
-
"\u2192 Click the provider \u2192 Enable \u2192 Save",
|
|
11116
|
-
"\u2192 For OAuth providers, paste the Client ID + Secret from the provider console"
|
|
11117
|
-
].join("\n"),
|
|
11118
|
-
"Firebase Authentication"
|
|
11119
|
-
);
|
|
11120
|
-
steps.push({
|
|
11121
|
-
name: "Firebase Auth",
|
|
11122
|
-
status: "needs-manual",
|
|
11123
|
-
message: "Enable auth providers in Firebase Console",
|
|
11124
|
-
coachingTopic: "auth-firebase"
|
|
11125
|
-
});
|
|
11126
|
-
}
|
|
11127
|
-
if (hasSupabase) {
|
|
11128
|
-
const providerList = detectedProviders.map((p2) => ` - ${p2.charAt(0).toUpperCase() + p2.slice(1)}`).join("\n");
|
|
11129
|
-
Me(
|
|
11130
|
-
[
|
|
11131
|
-
"Enable these auth providers in Supabase Dashboard:",
|
|
11132
|
-
"https://supabase.com/dashboard > Authentication > Providers",
|
|
11133
|
-
"",
|
|
11134
|
-
providerList,
|
|
11135
|
-
"",
|
|
11136
|
-
"For each provider:",
|
|
11137
|
-
"\u2192 Toggle the provider on",
|
|
11138
|
-
"\u2192 For OAuth providers, paste the Client ID + Secret from the provider console"
|
|
11139
|
-
].join("\n"),
|
|
11140
|
-
"Supabase Authentication"
|
|
11141
|
-
);
|
|
11142
|
-
steps.push({
|
|
11143
|
-
name: "Supabase Auth",
|
|
11144
|
-
status: "needs-manual",
|
|
11145
|
-
message: "Enable auth providers in Supabase Dashboard",
|
|
11146
|
-
coachingTopic: "auth-supabase"
|
|
11147
|
-
});
|
|
11148
|
-
}
|
|
11149
|
-
return {
|
|
11150
|
-
provider: "auth",
|
|
11151
|
-
steps,
|
|
11152
|
-
overallStatus: computeOverallStatus(steps)
|
|
11153
|
-
};
|
|
11154
|
-
}
|
|
11155
|
-
};
|
|
11156
|
-
}
|
|
11157
|
-
});
|
|
10587
|
+
// packages/tooling/src/cli/index.ts
|
|
10588
|
+
init_utils();
|
|
11158
10589
|
|
|
11159
|
-
// packages/tooling/src/cli/
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
});
|
|
11165
|
-
function parseEnvFile(filePath) {
|
|
11166
|
-
const map = /* @__PURE__ */ new Map();
|
|
11167
|
-
if (!pathExists(filePath)) return map;
|
|
11168
|
-
const content = readSync(filePath, { format: "text" });
|
|
11169
|
-
if (typeof content !== "string") return map;
|
|
11170
|
-
for (const line of content.split(/\r?\n/)) {
|
|
11171
|
-
const trimmed = line.trim();
|
|
11172
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
11173
|
-
const eqIdx = trimmed.indexOf("=");
|
|
11174
|
-
if (eqIdx < 0) continue;
|
|
11175
|
-
const key = trimmed.substring(0, eqIdx).trim();
|
|
11176
|
-
const value = trimmed.substring(eqIdx + 1).trim();
|
|
11177
|
-
if (key) map.set(key, value);
|
|
11178
|
-
}
|
|
11179
|
-
return map;
|
|
11180
|
-
}
|
|
11181
|
-
var envCheck;
|
|
11182
|
-
var init_check_env = __esm({
|
|
11183
|
-
"packages/tooling/src/cli/doctor/check-env.ts"() {
|
|
11184
|
-
"use strict";
|
|
11185
|
-
init_utils();
|
|
11186
|
-
init_pathResolver();
|
|
11187
|
-
envCheck = {
|
|
11188
|
-
id: "env",
|
|
11189
|
-
name: "Environment Files",
|
|
11190
|
-
isRelevant(_ctx) {
|
|
11191
|
-
return true;
|
|
11192
|
-
},
|
|
11193
|
-
async run(ctx) {
|
|
11194
|
-
const results = [];
|
|
11195
|
-
const envPath = joinPath(ctx.appDir, ".env");
|
|
11196
|
-
const examplePath = joinPath(ctx.appDir, ".env.example");
|
|
11197
|
-
if (!pathExists(envPath)) {
|
|
11198
|
-
results.push({
|
|
11199
|
-
name: ".env file",
|
|
11200
|
-
status: "fail",
|
|
11201
|
-
message: "Not found \u2014 run dndev setup"
|
|
11202
|
-
});
|
|
11203
|
-
return results;
|
|
11204
|
-
}
|
|
11205
|
-
results.push({ name: ".env file", status: "pass", message: "Found" });
|
|
11206
|
-
if (pathExists(examplePath)) {
|
|
11207
|
-
const example = parseEnvFile(examplePath);
|
|
11208
|
-
const actual = parseEnvFile(envPath);
|
|
11209
|
-
const missing = [];
|
|
11210
|
-
const empty = [];
|
|
11211
|
-
for (const [key] of example) {
|
|
11212
|
-
if (!actual.has(key)) {
|
|
11213
|
-
missing.push(key);
|
|
11214
|
-
} else if (!actual.get(key)) {
|
|
11215
|
-
empty.push(key);
|
|
11216
|
-
}
|
|
11217
|
-
}
|
|
11218
|
-
if (missing.length > 0) {
|
|
11219
|
-
results.push({
|
|
11220
|
-
name: "Missing vars",
|
|
11221
|
-
status: "fail",
|
|
11222
|
-
message: `${missing.length} var(s) in .env.example not in .env: ${missing.join(", ")}`
|
|
11223
|
-
});
|
|
11224
|
-
}
|
|
11225
|
-
if (empty.length > 0) {
|
|
11226
|
-
results.push({
|
|
11227
|
-
name: "Empty vars",
|
|
11228
|
-
status: "warn",
|
|
11229
|
-
message: `${empty.length} var(s) are empty: ${empty.join(", ")}`
|
|
11230
|
-
});
|
|
11231
|
-
}
|
|
11232
|
-
if (missing.length === 0 && empty.length === 0) {
|
|
11233
|
-
results.push({
|
|
11234
|
-
name: ".env vs .env.example",
|
|
11235
|
-
status: "pass",
|
|
11236
|
-
message: `All ${example.size} expected vars present`
|
|
11237
|
-
});
|
|
11238
|
-
}
|
|
11239
|
-
}
|
|
11240
|
-
const gitignorePath = joinPath(ctx.projectRoot, ".gitignore");
|
|
11241
|
-
if (pathExists(gitignorePath)) {
|
|
11242
|
-
const content = readSync(gitignorePath, { format: "text" });
|
|
11243
|
-
if (typeof content === "string") {
|
|
11244
|
-
const hasEnvIgnore = content.split("\n").some((line) => {
|
|
11245
|
-
const trimmed = line.trim();
|
|
11246
|
-
if (!trimmed || trimmed.startsWith("#")) return false;
|
|
11247
|
-
return /^\.env(\*|\..*)?$/.test(trimmed);
|
|
11248
|
-
});
|
|
11249
|
-
if (hasEnvIgnore) {
|
|
11250
|
-
results.push({
|
|
11251
|
-
name: ".gitignore",
|
|
11252
|
-
status: "pass",
|
|
11253
|
-
message: ".env is gitignored"
|
|
11254
|
-
});
|
|
11255
|
-
} else {
|
|
11256
|
-
results.push({
|
|
11257
|
-
name: ".gitignore",
|
|
11258
|
-
status: "warn",
|
|
11259
|
-
message: ".env might not be gitignored \u2014 verify manually"
|
|
11260
|
-
});
|
|
11261
|
-
}
|
|
11262
|
-
}
|
|
11263
|
-
}
|
|
11264
|
-
return results;
|
|
11265
|
-
}
|
|
11266
|
-
};
|
|
11267
|
-
}
|
|
11268
|
-
});
|
|
10590
|
+
// packages/tooling/src/cli/setup/setup.ts
|
|
10591
|
+
init_utils();
|
|
10592
|
+
init_cli_output();
|
|
10593
|
+
init_pathResolver();
|
|
10594
|
+
init_cross_app_detection();
|
|
11269
10595
|
|
|
11270
|
-
// packages/tooling/src/cli/
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
stdio: "pipe",
|
|
11293
|
-
encoding: "utf-8",
|
|
11294
|
-
timeout: 1e4
|
|
11295
|
-
});
|
|
11296
|
-
if (result.status === 0) {
|
|
11297
|
-
results.push({
|
|
11298
|
-
name: "Firebase CLI",
|
|
11299
|
-
status: "pass",
|
|
11300
|
-
message: result.stdout.trim()
|
|
11301
|
-
});
|
|
11302
|
-
} else {
|
|
11303
|
-
results.push({
|
|
11304
|
-
name: "Firebase CLI",
|
|
11305
|
-
status: "fail",
|
|
11306
|
-
message: "Not installed"
|
|
11307
|
-
});
|
|
11308
|
-
}
|
|
11309
|
-
} catch {
|
|
11310
|
-
results.push({
|
|
11311
|
-
name: "Firebase CLI",
|
|
11312
|
-
status: "fail",
|
|
11313
|
-
message: "Not installed"
|
|
11314
|
-
});
|
|
11315
|
-
}
|
|
11316
|
-
const rcPath = joinPath(ctx.projectRoot, ".firebaserc");
|
|
11317
|
-
if (pathExists(rcPath)) {
|
|
11318
|
-
try {
|
|
11319
|
-
const raw = readSync(rcPath, { format: "text" });
|
|
11320
|
-
if (typeof raw !== "string") throw new Error("Not a string");
|
|
11321
|
-
const rc = JSON.parse(raw);
|
|
11322
|
-
const projects = rc?.projects;
|
|
11323
|
-
const projectId = projects && typeof projects === "object" ? projects.default : void 0;
|
|
11324
|
-
if (projectId && typeof projectId === "string") {
|
|
11325
|
-
results.push({
|
|
11326
|
-
name: ".firebaserc",
|
|
11327
|
-
status: "pass",
|
|
11328
|
-
message: `Project: ${projectId}`
|
|
11329
|
-
});
|
|
11330
|
-
} else {
|
|
11331
|
-
results.push({
|
|
11332
|
-
name: ".firebaserc",
|
|
11333
|
-
status: "warn",
|
|
11334
|
-
message: "No default project set"
|
|
11335
|
-
});
|
|
11336
|
-
}
|
|
11337
|
-
} catch {
|
|
11338
|
-
results.push({
|
|
11339
|
-
name: ".firebaserc",
|
|
11340
|
-
status: "warn",
|
|
11341
|
-
message: "Invalid JSON"
|
|
11342
|
-
});
|
|
11343
|
-
}
|
|
11344
|
-
} else {
|
|
11345
|
-
results.push({
|
|
11346
|
-
name: ".firebaserc",
|
|
11347
|
-
status: "fail",
|
|
11348
|
-
message: "Missing \u2014 run dndev setup firebase"
|
|
11349
|
-
});
|
|
11350
|
-
}
|
|
11351
|
-
const framework = ctx.app?.framework ?? "vite";
|
|
11352
|
-
const prefix = framework === "nextjs" ? "NEXT_PUBLIC_" : "VITE_";
|
|
11353
|
-
const envPath = joinPath(ctx.appDir, ".env");
|
|
11354
|
-
if (pathExists(envPath)) {
|
|
11355
|
-
const content = readSync(envPath, { format: "text" });
|
|
11356
|
-
if (typeof content === "string") {
|
|
11357
|
-
const requiredKeys = [
|
|
11358
|
-
"FIREBASE_API_KEY",
|
|
11359
|
-
"FIREBASE_PROJECT_ID",
|
|
11360
|
-
"FIREBASE_AUTH_DOMAIN"
|
|
11361
|
-
];
|
|
11362
|
-
const missing = requiredKeys.filter(
|
|
11363
|
-
(key) => !content.includes(`${prefix}${key}=`)
|
|
11364
|
-
);
|
|
11365
|
-
if (missing.length === 0) {
|
|
11366
|
-
results.push({
|
|
11367
|
-
name: "Firebase .env",
|
|
11368
|
-
status: "pass",
|
|
11369
|
-
message: "All required keys present"
|
|
11370
|
-
});
|
|
11371
|
-
} else {
|
|
11372
|
-
results.push({
|
|
11373
|
-
name: "Firebase .env",
|
|
11374
|
-
status: "fail",
|
|
11375
|
-
message: `Missing: ${missing.join(", ")}`
|
|
11376
|
-
});
|
|
11377
|
-
}
|
|
11378
|
-
}
|
|
11379
|
-
} else {
|
|
11380
|
-
results.push({
|
|
11381
|
-
name: "Firebase .env",
|
|
11382
|
-
status: "fail",
|
|
11383
|
-
message: ".env file not found"
|
|
11384
|
-
});
|
|
11385
|
-
}
|
|
11386
|
-
const saKeyPaths = [
|
|
11387
|
-
joinPath(ctx.appDir, "service-account-key.json"),
|
|
11388
|
-
joinPath(ctx.projectRoot, "service-account-key.json")
|
|
11389
|
-
];
|
|
11390
|
-
const saFound = saKeyPaths.some((p2) => pathExists(p2));
|
|
11391
|
-
if (saFound) {
|
|
11392
|
-
results.push({
|
|
11393
|
-
name: "Service account key",
|
|
11394
|
-
status: "pass",
|
|
11395
|
-
message: "Found"
|
|
11396
|
-
});
|
|
11397
|
-
} else {
|
|
11398
|
-
results.push({
|
|
11399
|
-
name: "Service account key",
|
|
11400
|
-
status: "warn",
|
|
11401
|
-
message: "Not found (needed for deploy/emu)"
|
|
11402
|
-
});
|
|
11403
|
-
}
|
|
11404
|
-
return results;
|
|
11405
|
-
}
|
|
11406
|
-
};
|
|
10596
|
+
// packages/tooling/src/cli/setup/validate-env.ts
|
|
10597
|
+
init_utils();
|
|
10598
|
+
init_pathResolver();
|
|
10599
|
+
init_cli_output();
|
|
10600
|
+
var FIREBASE_VARS = [
|
|
10601
|
+
{
|
|
10602
|
+
provider: "Firebase",
|
|
10603
|
+
varName: "FIREBASE_API_KEY",
|
|
10604
|
+
envFile: ".env",
|
|
10605
|
+
needsPrefix: true
|
|
10606
|
+
},
|
|
10607
|
+
{
|
|
10608
|
+
provider: "Firebase",
|
|
10609
|
+
varName: "FIREBASE_PROJECT_ID",
|
|
10610
|
+
envFile: ".env",
|
|
10611
|
+
needsPrefix: true
|
|
10612
|
+
},
|
|
10613
|
+
{
|
|
10614
|
+
provider: "Firebase",
|
|
10615
|
+
varName: "FIREBASE_AUTH_DOMAIN",
|
|
10616
|
+
envFile: ".env",
|
|
10617
|
+
needsPrefix: true
|
|
11407
10618
|
}
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
init_pathResolver();
|
|
11422
|
-
init_supabase();
|
|
11423
|
-
supabaseCheck = {
|
|
11424
|
-
id: "supabase",
|
|
11425
|
-
name: "Supabase",
|
|
11426
|
-
isRelevant(ctx) {
|
|
11427
|
-
return pathExists(joinPath(ctx.appDir, "supabase")) || pathExists(joinPath(ctx.appDir, "supabase", "config.toml"));
|
|
11428
|
-
},
|
|
11429
|
-
async run(ctx) {
|
|
11430
|
-
const results = [];
|
|
11431
|
-
const framework = ctx.app?.framework === "nextjs" ? "nextjs" : "vite";
|
|
11432
|
-
const prefix = framework === "nextjs" ? "NEXT_PUBLIC_" : "VITE_";
|
|
11433
|
-
try {
|
|
11434
|
-
const result = spawnSync4("supabase", ["--version"], {
|
|
11435
|
-
stdio: "pipe",
|
|
11436
|
-
encoding: "utf-8",
|
|
11437
|
-
timeout: 1e4
|
|
11438
|
-
});
|
|
11439
|
-
if (result.status === 0) {
|
|
11440
|
-
results.push({
|
|
11441
|
-
name: "Supabase CLI",
|
|
11442
|
-
status: "pass",
|
|
11443
|
-
message: result.stdout.trim()
|
|
11444
|
-
});
|
|
11445
|
-
} else {
|
|
11446
|
-
results.push({
|
|
11447
|
-
name: "Supabase CLI",
|
|
11448
|
-
status: "warn",
|
|
11449
|
-
message: "Not installed (needed for migrations)"
|
|
11450
|
-
});
|
|
11451
|
-
}
|
|
11452
|
-
} catch {
|
|
11453
|
-
results.push({
|
|
11454
|
-
name: "Supabase CLI",
|
|
11455
|
-
status: "warn",
|
|
11456
|
-
message: "Not installed"
|
|
11457
|
-
});
|
|
11458
|
-
}
|
|
11459
|
-
const configPath = joinPath(ctx.appDir, "supabase", "config.toml");
|
|
11460
|
-
if (pathExists(configPath)) {
|
|
11461
|
-
results.push({ name: "config.toml", status: "pass", message: "Found" });
|
|
11462
|
-
} else {
|
|
11463
|
-
results.push({
|
|
11464
|
-
name: "config.toml",
|
|
11465
|
-
status: "warn",
|
|
11466
|
-
message: "Missing (expected at supabase/config.toml)"
|
|
11467
|
-
});
|
|
11468
|
-
}
|
|
11469
|
-
const envPath = joinPath(ctx.appDir, ".env");
|
|
11470
|
-
if (pathExists(envPath)) {
|
|
11471
|
-
const content = readSync(envPath, { format: "text" });
|
|
11472
|
-
if (typeof content === "string") {
|
|
11473
|
-
const urlMatch = content.match(
|
|
11474
|
-
new RegExp(`${prefix}SUPABASE_URL=(.+)`)
|
|
11475
|
-
);
|
|
11476
|
-
const url = urlMatch?.[1]?.trim();
|
|
11477
|
-
if (url && isValidSupabaseUrl(url)) {
|
|
11478
|
-
results.push({ name: "Supabase URL", status: "pass", message: url });
|
|
11479
|
-
} else if (url) {
|
|
11480
|
-
results.push({
|
|
11481
|
-
name: "Supabase URL",
|
|
11482
|
-
status: "fail",
|
|
11483
|
-
message: "Invalid URL format"
|
|
11484
|
-
});
|
|
11485
|
-
} else {
|
|
11486
|
-
results.push({
|
|
11487
|
-
name: "Supabase URL",
|
|
11488
|
-
status: "fail",
|
|
11489
|
-
message: "Missing in .env"
|
|
11490
|
-
});
|
|
11491
|
-
}
|
|
11492
|
-
const keyMatch = content.match(
|
|
11493
|
-
new RegExp(`${prefix}SUPABASE_(?:PUBLIC_KEY|ANON_KEY)=(.+)`)
|
|
11494
|
-
);
|
|
11495
|
-
const key = keyMatch?.[1]?.trim();
|
|
11496
|
-
if (key && isValidPublicKey(key)) {
|
|
11497
|
-
results.push({
|
|
11498
|
-
name: "Supabase public key",
|
|
11499
|
-
status: "pass",
|
|
11500
|
-
message: "Present"
|
|
11501
|
-
});
|
|
11502
|
-
} else {
|
|
11503
|
-
results.push({
|
|
11504
|
-
name: "Supabase public key",
|
|
11505
|
-
status: "fail",
|
|
11506
|
-
message: "Missing in .env"
|
|
11507
|
-
});
|
|
11508
|
-
}
|
|
11509
|
-
}
|
|
11510
|
-
} else {
|
|
11511
|
-
results.push({
|
|
11512
|
-
name: "Supabase .env",
|
|
11513
|
-
status: "fail",
|
|
11514
|
-
message: ".env file not found"
|
|
11515
|
-
});
|
|
11516
|
-
}
|
|
11517
|
-
const functionsEnvCandidates = [
|
|
11518
|
-
joinPath(ctx.appDir, "supabase", "functions", ".env"),
|
|
11519
|
-
joinPath(ctx.appDir, "functions", ".env")
|
|
11520
|
-
];
|
|
11521
|
-
let secretFound = false;
|
|
11522
|
-
for (const fenvPath of functionsEnvCandidates) {
|
|
11523
|
-
if (!pathExists(fenvPath)) continue;
|
|
11524
|
-
const content = readSync(fenvPath, { format: "text" });
|
|
11525
|
-
if (typeof content === "string" && content.match(/SUPABASE_(?:SECRET|SERVICE_ROLE)_KEY=.+/)) {
|
|
11526
|
-
secretFound = true;
|
|
11527
|
-
results.push({
|
|
11528
|
-
name: "Secret key",
|
|
11529
|
-
status: "pass",
|
|
11530
|
-
message: `Found in ${fenvPath.split("/").pop()}`
|
|
11531
|
-
});
|
|
11532
|
-
break;
|
|
11533
|
-
}
|
|
11534
|
-
}
|
|
11535
|
-
if (!secretFound) {
|
|
11536
|
-
results.push({
|
|
11537
|
-
name: "Secret key",
|
|
11538
|
-
status: "warn",
|
|
11539
|
-
message: "Not found (needed for migrations + deploy)"
|
|
11540
|
-
});
|
|
11541
|
-
}
|
|
11542
|
-
return results;
|
|
11543
|
-
}
|
|
11544
|
-
};
|
|
10619
|
+
];
|
|
10620
|
+
var SUPABASE_VARS = [
|
|
10621
|
+
{
|
|
10622
|
+
provider: "Supabase",
|
|
10623
|
+
varName: "SUPABASE_URL",
|
|
10624
|
+
envFile: ".env",
|
|
10625
|
+
needsPrefix: true
|
|
10626
|
+
},
|
|
10627
|
+
{
|
|
10628
|
+
provider: "Supabase",
|
|
10629
|
+
varName: "SUPABASE_PUBLIC_KEY",
|
|
10630
|
+
envFile: ".env",
|
|
10631
|
+
needsPrefix: true
|
|
11545
10632
|
}
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
}
|
|
11553
|
-
|
|
10633
|
+
];
|
|
10634
|
+
var SUPABASE_SECRET_VARS = [
|
|
10635
|
+
{
|
|
10636
|
+
provider: "Supabase",
|
|
10637
|
+
varName: "SUPABASE_SECRET_KEY",
|
|
10638
|
+
envFile: "supabase/functions/.env"
|
|
10639
|
+
},
|
|
10640
|
+
{
|
|
10641
|
+
provider: "Supabase",
|
|
10642
|
+
varName: "SUPABASE_DB_URL",
|
|
10643
|
+
envFile: "supabase/functions/.env"
|
|
10644
|
+
}
|
|
10645
|
+
];
|
|
10646
|
+
var VERCEL_VARS = [
|
|
10647
|
+
{ provider: "Vercel", varName: "VERCEL_TOKEN", envFile: ".env.local" },
|
|
10648
|
+
{ provider: "Vercel", varName: "VERCEL_ORG_ID", envFile: ".env.local" },
|
|
10649
|
+
{ provider: "Vercel", varName: "VERCEL_PROJECT_ID", envFile: ".env.local" }
|
|
10650
|
+
];
|
|
10651
|
+
function readEnvValue(envPath, varName) {
|
|
11554
10652
|
if (!pathExists(envPath)) return null;
|
|
11555
10653
|
const content = readSync(envPath, { format: "text" });
|
|
11556
10654
|
if (typeof content !== "string") return null;
|
|
@@ -11558,520 +10656,230 @@ function readEnvValue2(envPath, varName) {
|
|
|
11558
10656
|
const trimmed = line.trim();
|
|
11559
10657
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
11560
10658
|
if (trimmed.startsWith(`${varName}=`)) {
|
|
11561
|
-
|
|
11562
|
-
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
11563
|
-
val = val.slice(1, -1);
|
|
11564
|
-
}
|
|
11565
|
-
return val || null;
|
|
10659
|
+
return trimmed.substring(`${varName}=`.length).trim();
|
|
11566
10660
|
}
|
|
11567
10661
|
}
|
|
11568
10662
|
return null;
|
|
11569
10663
|
}
|
|
11570
|
-
function
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
10664
|
+
function isProviderRelevant(ctx, provider) {
|
|
10665
|
+
switch (provider) {
|
|
10666
|
+
case "Firebase":
|
|
10667
|
+
return pathExists(joinPath(ctx.appDir, "firebase.json")) || pathExists(joinPath(ctx.projectRoot, "firebase.json")) || pathExists(joinPath(ctx.projectRoot, ".firebaserc"));
|
|
10668
|
+
case "Supabase":
|
|
10669
|
+
return pathExists(joinPath(ctx.appDir, "supabase")) || pathExists(joinPath(ctx.appDir, "supabase", "config.toml"));
|
|
10670
|
+
case "Vercel":
|
|
10671
|
+
return pathExists(joinPath(ctx.appDir, "vercel.json"));
|
|
10672
|
+
default:
|
|
10673
|
+
return false;
|
|
10674
|
+
}
|
|
11576
10675
|
}
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
async run(ctx) {
|
|
11604
|
-
const results = [];
|
|
11605
|
-
const framework = ctx.app?.framework ?? "vite";
|
|
11606
|
-
const prefix = framework === "nextjs" ? "NEXT_PUBLIC_" : "VITE_";
|
|
11607
|
-
const envPath = joinPath(ctx.appDir, ".env");
|
|
11608
|
-
const functionsEnvPath = findFunctionsEnv(ctx);
|
|
11609
|
-
const pk = readEnvValue2(envPath, `${prefix}STRIPE_PUBLISHABLE_KEY`);
|
|
11610
|
-
let pkMode = null;
|
|
11611
|
-
if (pk) {
|
|
11612
|
-
if (pk.startsWith("pk_test_") || pk.startsWith("pk_live_")) {
|
|
11613
|
-
pkMode = pk.startsWith("pk_test_") ? "test" : "live";
|
|
11614
|
-
results.push({
|
|
11615
|
-
name: "Publishable key",
|
|
11616
|
-
status: "pass",
|
|
11617
|
-
message: `Valid (${pkMode} mode)`
|
|
11618
|
-
});
|
|
11619
|
-
} else {
|
|
11620
|
-
results.push({
|
|
11621
|
-
name: "Publishable key",
|
|
11622
|
-
status: "fail",
|
|
11623
|
-
message: "Invalid format \u2014 must start with pk_test_ or pk_live_"
|
|
11624
|
-
});
|
|
11625
|
-
}
|
|
11626
|
-
} else {
|
|
11627
|
-
results.push({
|
|
11628
|
-
name: "Publishable key",
|
|
11629
|
-
status: "fail",
|
|
11630
|
-
message: "Missing in .env"
|
|
11631
|
-
});
|
|
11632
|
-
}
|
|
11633
|
-
let skMode = null;
|
|
11634
|
-
if (functionsEnvPath) {
|
|
11635
|
-
const sk = readEnvValue2(functionsEnvPath, "STRIPE_SECRET_KEY");
|
|
11636
|
-
if (sk) {
|
|
11637
|
-
if (sk.startsWith("sk_test_") || sk.startsWith("sk_live_") || sk.startsWith("rk_test_") || sk.startsWith("rk_live_")) {
|
|
11638
|
-
skMode = sk.includes("_test_") ? "test" : "live";
|
|
11639
|
-
results.push({
|
|
11640
|
-
name: "Secret key",
|
|
11641
|
-
status: "pass",
|
|
11642
|
-
message: `Valid (${skMode} mode)`
|
|
11643
|
-
});
|
|
11644
|
-
} else {
|
|
11645
|
-
results.push({
|
|
11646
|
-
name: "Secret key",
|
|
11647
|
-
status: "fail",
|
|
11648
|
-
message: "STRIPE_SECRET_KEY has invalid format"
|
|
11649
|
-
});
|
|
11650
|
-
}
|
|
11651
|
-
} else {
|
|
11652
|
-
results.push({
|
|
11653
|
-
name: "Secret key",
|
|
11654
|
-
status: "warn",
|
|
11655
|
-
message: "Not found in functions/.env"
|
|
11656
|
-
});
|
|
11657
|
-
}
|
|
11658
|
-
} else {
|
|
11659
|
-
results.push({
|
|
11660
|
-
name: "Secret key",
|
|
11661
|
-
status: "warn",
|
|
11662
|
-
message: "No functions/.env found"
|
|
11663
|
-
});
|
|
11664
|
-
}
|
|
11665
|
-
if (functionsEnvPath) {
|
|
11666
|
-
const wh = readEnvValue2(functionsEnvPath, "STRIPE_WEBHOOK_SECRET");
|
|
11667
|
-
if (wh) {
|
|
11668
|
-
if (wh.startsWith("whsec_")) {
|
|
11669
|
-
results.push({
|
|
11670
|
-
name: "Webhook secret",
|
|
11671
|
-
status: "pass",
|
|
11672
|
-
message: "Valid format"
|
|
11673
|
-
});
|
|
11674
|
-
} else {
|
|
11675
|
-
results.push({
|
|
11676
|
-
name: "Webhook secret",
|
|
11677
|
-
status: "fail",
|
|
11678
|
-
message: "STRIPE_WEBHOOK_SECRET has invalid format"
|
|
11679
|
-
});
|
|
11680
|
-
}
|
|
11681
|
-
} else {
|
|
11682
|
-
results.push({
|
|
11683
|
-
name: "Webhook secret",
|
|
11684
|
-
status: "warn",
|
|
11685
|
-
message: "Not found \u2014 webhooks won't verify"
|
|
11686
|
-
});
|
|
11687
|
-
}
|
|
11688
|
-
}
|
|
11689
|
-
if (pkMode && skMode) {
|
|
11690
|
-
if (pkMode !== skMode) {
|
|
11691
|
-
results.push({
|
|
11692
|
-
name: "Key mode",
|
|
11693
|
-
status: "warn",
|
|
11694
|
-
message: `Publishable key is ${pkMode} but secret key is ${skMode}`
|
|
11695
|
-
});
|
|
11696
|
-
} else {
|
|
11697
|
-
results.push({
|
|
11698
|
-
name: "Key mode",
|
|
11699
|
-
status: "pass",
|
|
11700
|
-
message: `Both keys are ${pkMode}`
|
|
11701
|
-
});
|
|
11702
|
-
}
|
|
11703
|
-
}
|
|
11704
|
-
return results;
|
|
11705
|
-
}
|
|
11706
|
-
};
|
|
10676
|
+
function validateRequiredEnvVars(ctx) {
|
|
10677
|
+
const missing = [];
|
|
10678
|
+
const framework = ctx.app?.framework === "nextjs" ? "nextjs" : "vite";
|
|
10679
|
+
const prefix = framework === "nextjs" ? "NEXT_PUBLIC_" : "VITE_";
|
|
10680
|
+
const requirements = [];
|
|
10681
|
+
if (isProviderRelevant(ctx, "Firebase")) {
|
|
10682
|
+
requirements.push(...FIREBASE_VARS);
|
|
10683
|
+
}
|
|
10684
|
+
if (isProviderRelevant(ctx, "Supabase")) {
|
|
10685
|
+
requirements.push(...SUPABASE_VARS);
|
|
10686
|
+
const sbFunctionsEnv = joinPath(
|
|
10687
|
+
ctx.appDir,
|
|
10688
|
+
"supabase",
|
|
10689
|
+
"functions",
|
|
10690
|
+
".env"
|
|
10691
|
+
);
|
|
10692
|
+
const altFunctionsEnv = joinPath(ctx.appDir, "functions", ".env");
|
|
10693
|
+
if (pathExists(joinPath(ctx.appDir, "supabase", "functions")) || pathExists(sbFunctionsEnv)) {
|
|
10694
|
+
requirements.push(...SUPABASE_SECRET_VARS);
|
|
10695
|
+
} else if (pathExists(altFunctionsEnv)) {
|
|
10696
|
+
requirements.push({
|
|
10697
|
+
provider: "Supabase",
|
|
10698
|
+
varName: "SUPABASE_SECRET_KEY",
|
|
10699
|
+
envFile: "functions/.env"
|
|
10700
|
+
});
|
|
10701
|
+
}
|
|
11707
10702
|
}
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
|
|
11712
|
-
|
|
11713
|
-
|
|
11714
|
-
|
|
11715
|
-
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
|
|
11723
|
-
name: "Authentication",
|
|
11724
|
-
isRelevant(ctx) {
|
|
11725
|
-
const pkgPath = joinPath(ctx.appDir, "package.json");
|
|
11726
|
-
if (pathExists(pkgPath)) {
|
|
11727
|
-
const content = readSync(pkgPath, { format: "text" });
|
|
11728
|
-
if (typeof content === "string" && content.includes("@donotdev/auth"))
|
|
11729
|
-
return true;
|
|
11730
|
-
}
|
|
11731
|
-
return false;
|
|
11732
|
-
},
|
|
11733
|
-
async run(ctx) {
|
|
11734
|
-
const results = [];
|
|
11735
|
-
results.push({
|
|
11736
|
-
name: "@donotdev/auth",
|
|
11737
|
-
status: "pass",
|
|
11738
|
-
message: "Installed"
|
|
10703
|
+
if (isProviderRelevant(ctx, "Vercel")) {
|
|
10704
|
+
requirements.push(...VERCEL_VARS);
|
|
10705
|
+
}
|
|
10706
|
+
for (const req of requirements) {
|
|
10707
|
+
const actualVarName = req.needsPrefix ? `${prefix}${req.varName}` : req.varName;
|
|
10708
|
+
const envFilePath = joinPath(ctx.appDir, req.envFile);
|
|
10709
|
+
if (req.varName === "SUPABASE_PUBLIC_KEY") {
|
|
10710
|
+
const pkValue = readEnvValue(envFilePath, actualVarName);
|
|
10711
|
+
const anonValue = readEnvValue(envFilePath, `${prefix}SUPABASE_ANON_KEY`);
|
|
10712
|
+
if ((!pkValue || pkValue === "") && (!anonValue || anonValue === "")) {
|
|
10713
|
+
missing.push({
|
|
10714
|
+
provider: req.provider,
|
|
10715
|
+
varName: actualVarName,
|
|
10716
|
+
envFile: req.envFile,
|
|
10717
|
+
status: pathExists(envFilePath) ? "empty" : "missing"
|
|
11739
10718
|
});
|
|
11740
|
-
const candidates = [
|
|
11741
|
-
joinPath(ctx.appDir, "src", "providers.ts"),
|
|
11742
|
-
joinPath(ctx.appDir, "src", "providers.tsx"),
|
|
11743
|
-
joinPath(ctx.appDir, "src", "config", "providers.ts"),
|
|
11744
|
-
joinPath(ctx.appDir, "src", "lib", "providers.ts")
|
|
11745
|
-
];
|
|
11746
|
-
const providerFile = candidates.find((c) => pathExists(c));
|
|
11747
|
-
if (providerFile) {
|
|
11748
|
-
results.push({
|
|
11749
|
-
name: "Providers config",
|
|
11750
|
-
status: "pass",
|
|
11751
|
-
message: `Found: ${providerFile.split("/").slice(-2).join("/")}`
|
|
11752
|
-
});
|
|
11753
|
-
const content = readSync(providerFile, { format: "text" });
|
|
11754
|
-
if (typeof content === "string") {
|
|
11755
|
-
const providers = [];
|
|
11756
|
-
if (content.includes("email") || content.includes("Email"))
|
|
11757
|
-
providers.push("email");
|
|
11758
|
-
if (content.includes("google") || content.includes("Google"))
|
|
11759
|
-
providers.push("google");
|
|
11760
|
-
if (content.includes("github") || content.includes("GitHub"))
|
|
11761
|
-
providers.push("github");
|
|
11762
|
-
if (content.includes("apple") || content.includes("Apple"))
|
|
11763
|
-
providers.push("apple");
|
|
11764
|
-
if (providers.length > 0) {
|
|
11765
|
-
results.push({
|
|
11766
|
-
name: "Auth providers",
|
|
11767
|
-
status: "pass",
|
|
11768
|
-
message: `Configured: ${providers.join(", ")}`
|
|
11769
|
-
});
|
|
11770
|
-
}
|
|
11771
|
-
}
|
|
11772
|
-
} else {
|
|
11773
|
-
results.push({
|
|
11774
|
-
name: "Providers config",
|
|
11775
|
-
status: "warn",
|
|
11776
|
-
message: "No providers.ts found \u2014 auth may not work"
|
|
11777
|
-
});
|
|
11778
|
-
}
|
|
11779
|
-
const hasFirebase = pathExists(joinPath(ctx.projectRoot, ".firebaserc"));
|
|
11780
|
-
const hasSupabase = pathExists(joinPath(ctx.appDir, "supabase"));
|
|
11781
|
-
if (hasFirebase) {
|
|
11782
|
-
results.push({
|
|
11783
|
-
name: "Backend",
|
|
11784
|
-
status: "pass",
|
|
11785
|
-
message: "Firebase Auth (verify providers are enabled in console)",
|
|
11786
|
-
detail: "Run dndev setup auth for setup coaching"
|
|
11787
|
-
});
|
|
11788
|
-
} else if (hasSupabase) {
|
|
11789
|
-
results.push({
|
|
11790
|
-
name: "Backend",
|
|
11791
|
-
status: "pass",
|
|
11792
|
-
message: "Supabase Auth (verify providers are enabled in dashboard)",
|
|
11793
|
-
detail: "Run dndev setup auth for setup coaching"
|
|
11794
|
-
});
|
|
11795
|
-
} else {
|
|
11796
|
-
results.push({
|
|
11797
|
-
name: "Backend",
|
|
11798
|
-
status: "warn",
|
|
11799
|
-
message: "No backend detected for auth"
|
|
11800
|
-
});
|
|
11801
|
-
}
|
|
11802
|
-
return results;
|
|
11803
|
-
}
|
|
11804
|
-
};
|
|
11805
|
-
}
|
|
11806
|
-
});
|
|
11807
|
-
|
|
11808
|
-
// packages/tooling/src/cli/doctor/doctor.ts
|
|
11809
|
-
var doctor_exports = {};
|
|
11810
|
-
__export(doctor_exports, {
|
|
11811
|
-
default: () => doctor_default,
|
|
11812
|
-
main: () => main4
|
|
11813
|
-
});
|
|
11814
|
-
function renderResults(allResults, verbose) {
|
|
11815
|
-
const lines = [];
|
|
11816
|
-
for (const { checkName, results } of allResults) {
|
|
11817
|
-
lines.push(checkName);
|
|
11818
|
-
for (const result of results) {
|
|
11819
|
-
const icon = STATUS_ICONS[result.status];
|
|
11820
|
-
lines.push(` ${icon} ${result.name}: ${result.message}`);
|
|
11821
|
-
if (verbose && result.detail) {
|
|
11822
|
-
lines.push(` ${result.detail}`);
|
|
11823
10719
|
}
|
|
10720
|
+
continue;
|
|
11824
10721
|
}
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
}
|
|
11841
|
-
} catch {
|
|
10722
|
+
const value = readEnvValue(envFilePath, actualVarName);
|
|
10723
|
+
if (value === null) {
|
|
10724
|
+
missing.push({
|
|
10725
|
+
provider: req.provider,
|
|
10726
|
+
varName: actualVarName,
|
|
10727
|
+
envFile: req.envFile,
|
|
10728
|
+
status: pathExists(envFilePath) ? "missing" : "missing"
|
|
10729
|
+
});
|
|
10730
|
+
} else if (value === "") {
|
|
10731
|
+
missing.push({
|
|
10732
|
+
provider: req.provider,
|
|
10733
|
+
varName: actualVarName,
|
|
10734
|
+
envFile: req.envFile,
|
|
10735
|
+
status: "empty"
|
|
10736
|
+
});
|
|
11842
10737
|
}
|
|
11843
10738
|
}
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
);
|
|
11857
|
-
Se("Doctor aborted.");
|
|
11858
|
-
return 1;
|
|
10739
|
+
return missing;
|
|
10740
|
+
}
|
|
10741
|
+
function validateAllApps(apps, _topology, projectRoot) {
|
|
10742
|
+
const results = [];
|
|
10743
|
+
for (const app of apps) {
|
|
10744
|
+
const ctx = {
|
|
10745
|
+
projectRoot,
|
|
10746
|
+
appDir: app.path,
|
|
10747
|
+
app
|
|
10748
|
+
};
|
|
10749
|
+
const missing = validateRequiredEnvVars(ctx);
|
|
10750
|
+
results.push({ app, missing });
|
|
11859
10751
|
}
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
10752
|
+
return results;
|
|
10753
|
+
}
|
|
10754
|
+
function printAllValidationResults(results, multiApp) {
|
|
10755
|
+
const allMissing = [];
|
|
10756
|
+
for (const { app, missing } of results) {
|
|
10757
|
+
for (const m2 of missing) {
|
|
10758
|
+
allMissing.push({ appName: app.name, m: m2 });
|
|
11867
10759
|
}
|
|
11868
10760
|
}
|
|
11869
|
-
if (
|
|
11870
|
-
log.
|
|
11871
|
-
|
|
11872
|
-
return 0;
|
|
10761
|
+
if (allMissing.length === 0) {
|
|
10762
|
+
log.success("Credentials OK");
|
|
10763
|
+
return true;
|
|
11873
10764
|
}
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
for (const { results } of allResults) {
|
|
11879
|
-
for (const r2 of results) {
|
|
11880
|
-
if (r2.status === "pass") passes++;
|
|
11881
|
-
else if (r2.status === "warn") warnings++;
|
|
11882
|
-
else if (r2.status === "fail") fails++;
|
|
11883
|
-
}
|
|
11884
|
-
}
|
|
11885
|
-
const totalChecks = passes + warnings + fails;
|
|
11886
|
-
const summaryParts = [`${passes}/${totalChecks} passed`];
|
|
11887
|
-
if (warnings > 0) summaryParts.push(`${warnings} warning(s)`);
|
|
11888
|
-
if (fails > 0) summaryParts.push(`${fails} failure(s)`);
|
|
11889
|
-
const exitCode = hasFail ? 1 : 0;
|
|
11890
|
-
Se(
|
|
11891
|
-
hasFail ? `Health check failed: ${summaryParts.join(", ")}` : `All clear: ${summaryParts.join(", ")}`
|
|
11892
|
-
);
|
|
11893
|
-
return exitCode;
|
|
11894
|
-
}
|
|
11895
|
-
var CHECK_REGISTRY, STATUS_ICONS, doctor_default;
|
|
11896
|
-
var init_doctor = __esm({
|
|
11897
|
-
"packages/tooling/src/cli/doctor/doctor.ts"() {
|
|
11898
|
-
"use strict";
|
|
11899
|
-
init_utils();
|
|
11900
|
-
init_cli_output();
|
|
11901
|
-
init_app_selector();
|
|
11902
|
-
init_pathResolver();
|
|
11903
|
-
CHECK_REGISTRY = [
|
|
11904
|
-
{ id: "env", load: async () => (await Promise.resolve().then(() => (init_check_env(), check_env_exports))).envCheck },
|
|
11905
|
-
{
|
|
11906
|
-
id: "firebase",
|
|
11907
|
-
load: async () => (await Promise.resolve().then(() => (init_check_firebase(), check_firebase_exports))).firebaseCheck
|
|
11908
|
-
},
|
|
11909
|
-
{
|
|
11910
|
-
id: "supabase",
|
|
11911
|
-
load: async () => (await Promise.resolve().then(() => (init_check_supabase(), check_supabase_exports))).supabaseCheck
|
|
11912
|
-
},
|
|
11913
|
-
{
|
|
11914
|
-
id: "stripe",
|
|
11915
|
-
load: async () => (await Promise.resolve().then(() => (init_check_stripe(), check_stripe_exports))).stripeCheck
|
|
11916
|
-
},
|
|
11917
|
-
{ id: "auth", load: async () => (await Promise.resolve().then(() => (init_check_auth(), check_auth_exports))).authCheck }
|
|
11918
|
-
];
|
|
11919
|
-
STATUS_ICONS = {
|
|
11920
|
-
pass: "\u2705",
|
|
11921
|
-
// green check
|
|
11922
|
-
warn: "\u26A0\uFE0F",
|
|
11923
|
-
// warning
|
|
11924
|
-
fail: "\u274C"
|
|
11925
|
-
// red x
|
|
11926
|
-
};
|
|
11927
|
-
doctor_default = main4;
|
|
10765
|
+
for (const { appName, m: m2 } of allMissing) {
|
|
10766
|
+
const prefix = multiApp ? `${appName}: ` : "";
|
|
10767
|
+
const detail = m2.status === "empty" ? `empty in ${m2.envFile}` : `missing \u2014 ${m2.envFile}`;
|
|
10768
|
+
log.error(` ${prefix}${m2.varName} (${detail})`);
|
|
11928
10769
|
}
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
init_utils();
|
|
11933
|
-
|
|
11934
|
-
// packages/tooling/src/index.ts
|
|
11935
|
-
init_utils();
|
|
11936
|
-
|
|
11937
|
-
// packages/tooling/src/cli/index.ts
|
|
11938
|
-
init_utils();
|
|
10770
|
+
log.warn(`Run 'dndev coach' to see where to get them.`);
|
|
10771
|
+
return false;
|
|
10772
|
+
}
|
|
11939
10773
|
|
|
11940
10774
|
// packages/tooling/src/cli/setup/setup.ts
|
|
11941
|
-
init_utils();
|
|
11942
|
-
init_cli_output();
|
|
11943
|
-
init_cli_input();
|
|
11944
|
-
init_app_selector();
|
|
11945
|
-
init_pathResolver();
|
|
11946
10775
|
var WIZARD_REGISTRY = {
|
|
11947
10776
|
firebase: async () => (await Promise.resolve().then(() => (init_firebase(), firebase_exports))).firebaseWizard,
|
|
11948
10777
|
supabase: async () => (await Promise.resolve().then(() => (init_supabase(), supabase_exports))).supabaseWizard,
|
|
11949
|
-
vercel: async () => (await Promise.resolve().then(() => (init_vercel(), vercel_exports))).vercelWizard
|
|
11950
|
-
stripe: async () => (await Promise.resolve().then(() => (init_stripe(), stripe_exports))).stripeWizard,
|
|
11951
|
-
oauth: async () => (await Promise.resolve().then(() => (init_oauth(), oauth_exports))).oauthWizard,
|
|
11952
|
-
auth: async () => (await Promise.resolve().then(() => (init_auth(), auth_exports))).authWizard
|
|
10778
|
+
vercel: async () => (await Promise.resolve().then(() => (init_vercel(), vercel_exports))).vercelWizard
|
|
11953
10779
|
};
|
|
11954
|
-
var WIZARD_ORDER = [
|
|
11955
|
-
|
|
11956
|
-
"supabase",
|
|
11957
|
-
"vercel",
|
|
11958
|
-
"stripe",
|
|
11959
|
-
"auth",
|
|
11960
|
-
"oauth"
|
|
11961
|
-
];
|
|
11962
|
-
var STATUS_ICONS2 = {
|
|
10780
|
+
var WIZARD_ORDER = ["firebase", "supabase", "vercel"];
|
|
10781
|
+
var STATUS_ICONS = {
|
|
11963
10782
|
success: "\u2705",
|
|
11964
|
-
// green check
|
|
11965
10783
|
skipped: "\u23ED\uFE0F",
|
|
11966
|
-
// skip
|
|
11967
10784
|
failed: "\u274C",
|
|
11968
|
-
// red x
|
|
11969
10785
|
"needs-manual": "\u{1F449}"
|
|
11970
|
-
// pointing right
|
|
11971
10786
|
};
|
|
11972
|
-
function
|
|
11973
|
-
const
|
|
11974
|
-
|
|
11975
|
-
|
|
10787
|
+
function renderResults(results, multiApp) {
|
|
10788
|
+
for (const { appName, result } of results) {
|
|
10789
|
+
if (multiApp) {
|
|
10790
|
+
log.info(`
|
|
10791
|
+
${appName} \u2014 ${result.provider}:`);
|
|
10792
|
+
}
|
|
11976
10793
|
for (const step of result.steps) {
|
|
11977
|
-
const icon =
|
|
11978
|
-
|
|
10794
|
+
const icon = STATUS_ICONS[step.status];
|
|
10795
|
+
log.info(` ${icon} ${step.name}: ${step.message}`);
|
|
11979
10796
|
}
|
|
11980
|
-
lines.push("");
|
|
11981
10797
|
}
|
|
11982
|
-
Me(lines.join("\n"), "Setup Summary");
|
|
11983
10798
|
}
|
|
11984
|
-
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
let appDir = projectRoot;
|
|
11988
|
-
let app = null;
|
|
11989
|
-
const appsDir = joinPath(projectRoot, "apps");
|
|
11990
|
-
if (pathExists(appsDir)) {
|
|
11991
|
-
try {
|
|
11992
|
-
app = await selectApp(projectRoot, options.app);
|
|
11993
|
-
if (app) {
|
|
11994
|
-
appDir = app.path;
|
|
11995
|
-
}
|
|
11996
|
-
} catch {
|
|
11997
|
-
}
|
|
11998
|
-
}
|
|
11999
|
-
const ctx = {
|
|
10799
|
+
function buildSetupContext(app, projectRoot, topology, options) {
|
|
10800
|
+
const backendApp = findBackendApp(topology, app.name);
|
|
10801
|
+
return {
|
|
12000
10802
|
projectRoot,
|
|
12001
|
-
appDir,
|
|
10803
|
+
appDir: app.path,
|
|
12002
10804
|
app,
|
|
12003
10805
|
verbose: options.verbose,
|
|
12004
|
-
dryRun: options.dryRun
|
|
10806
|
+
dryRun: options.dryRun,
|
|
10807
|
+
allApps: topology.apps,
|
|
10808
|
+
backendApp
|
|
12005
10809
|
};
|
|
12006
|
-
|
|
12007
|
-
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
|
|
12018
|
-
|
|
10810
|
+
}
|
|
10811
|
+
async function main4(options = {}) {
|
|
10812
|
+
const projectRoot = process.cwd();
|
|
10813
|
+
Ie("DoNotDev Setup");
|
|
10814
|
+
const topology = analyzeProjectTopology(projectRoot);
|
|
10815
|
+
let apps = topology.apps;
|
|
10816
|
+
if (apps.length === 0) {
|
|
10817
|
+
apps = [
|
|
10818
|
+
{
|
|
10819
|
+
name: "root",
|
|
10820
|
+
packageName: "root",
|
|
10821
|
+
path: projectRoot,
|
|
10822
|
+
packageJsonPath: joinPath(projectRoot, "package.json"),
|
|
10823
|
+
framework: "vite",
|
|
10824
|
+
hasFunctions: false
|
|
10825
|
+
}
|
|
10826
|
+
];
|
|
10827
|
+
}
|
|
10828
|
+
const multiApp = apps.length > 1;
|
|
10829
|
+
const validationResults = validateAllApps(apps, topology, projectRoot);
|
|
10830
|
+
const allValid = printAllValidationResults(validationResults, multiApp);
|
|
10831
|
+
if (!allValid) {
|
|
10832
|
+
Se("Fix missing values, then re-run.");
|
|
10833
|
+
return 1;
|
|
10834
|
+
}
|
|
10835
|
+
const allResults = [];
|
|
10836
|
+
for (const app of apps) {
|
|
10837
|
+
const ctx = buildSetupContext(app, projectRoot, topology, options);
|
|
10838
|
+
let wizardIds;
|
|
10839
|
+
if (options.provider) {
|
|
10840
|
+
const id = options.provider.toLowerCase();
|
|
10841
|
+
if (!WIZARD_REGISTRY[id]) {
|
|
10842
|
+
log.error(`Unknown provider: ${options.provider}`);
|
|
10843
|
+
Se("Setup aborted.");
|
|
10844
|
+
return 1;
|
|
10845
|
+
}
|
|
10846
|
+
const wizard = await WIZARD_REGISTRY[id]();
|
|
10847
|
+
wizardIds = wizard.isRelevant(ctx) ? [id] : [];
|
|
10848
|
+
} else {
|
|
10849
|
+
wizardIds = [];
|
|
10850
|
+
for (const id of WIZARD_ORDER) {
|
|
10851
|
+
const loader = WIZARD_REGISTRY[id];
|
|
10852
|
+
if (!loader) continue;
|
|
10853
|
+
const wizard = await loader();
|
|
10854
|
+
if (wizard.isRelevant(ctx)) {
|
|
10855
|
+
wizardIds.push(id);
|
|
10856
|
+
}
|
|
10857
|
+
}
|
|
10858
|
+
}
|
|
10859
|
+
for (const id of wizardIds) {
|
|
12019
10860
|
const loader = WIZARD_REGISTRY[id];
|
|
12020
10861
|
if (!loader) continue;
|
|
12021
10862
|
const wizard = await loader();
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
}
|
|
12025
|
-
}
|
|
12026
|
-
if (relevant.length === 0) {
|
|
12027
|
-
log.warn("No providers detected in this project.");
|
|
12028
|
-
log.info(
|
|
12029
|
-
`Available providers: ${Object.keys(WIZARD_REGISTRY).join(", ")}`
|
|
12030
|
-
);
|
|
12031
|
-
log.info("Run: dndev setup <provider>");
|
|
12032
|
-
Se("Nothing to set up.");
|
|
12033
|
-
return 0;
|
|
12034
|
-
}
|
|
12035
|
-
const selected = await askForMultiSelection(
|
|
12036
|
-
"Which providers do you want to set up?",
|
|
12037
|
-
relevant.map((r2) => ({
|
|
12038
|
-
title: r2.wizard.name,
|
|
12039
|
-
value: r2.id,
|
|
12040
|
-
hint: "detected"
|
|
12041
|
-
}))
|
|
12042
|
-
);
|
|
12043
|
-
if (selected.length === 0) {
|
|
12044
|
-
Se("No providers selected.");
|
|
12045
|
-
return 0;
|
|
10863
|
+
const result = await wizard.run(ctx);
|
|
10864
|
+
allResults.push({ appName: app.name, result });
|
|
12046
10865
|
}
|
|
12047
|
-
wizardIds = selected;
|
|
12048
10866
|
}
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
log.info(`
|
|
12054
|
-
Setting up ${id}...`);
|
|
12055
|
-
const wizard = await loader();
|
|
12056
|
-
const result = await wizard.run(ctx);
|
|
12057
|
-
results.push(result);
|
|
12058
|
-
}
|
|
12059
|
-
renderSummary(results);
|
|
12060
|
-
if (!options.skipDoctor) {
|
|
12061
|
-
log.info("\nRunning health checks...");
|
|
12062
|
-
try {
|
|
12063
|
-
const { main: doctor } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
12064
|
-
await doctor({ app: options.app, verbose: options.verbose });
|
|
12065
|
-
} catch {
|
|
12066
|
-
log.warn("Doctor check skipped (module not available).");
|
|
12067
|
-
}
|
|
10867
|
+
if (allResults.length === 0) {
|
|
10868
|
+
log.warn("No providers detected. Run: dndev setup <provider>");
|
|
10869
|
+
Se("Nothing to set up.");
|
|
10870
|
+
return 0;
|
|
12068
10871
|
}
|
|
12069
|
-
|
|
12070
|
-
|
|
10872
|
+
renderResults(allResults, multiApp);
|
|
10873
|
+
const hasFailures = allResults.some(
|
|
10874
|
+
(r2) => r2.result.overallStatus === "failed"
|
|
10875
|
+
);
|
|
10876
|
+
Se(
|
|
10877
|
+
hasFailures ? "Setup incomplete \u2014 see errors above." : "Setup complete."
|
|
10878
|
+
);
|
|
12071
10879
|
return hasFailures ? 1 : 0;
|
|
12072
10880
|
}
|
|
12073
10881
|
export {
|
|
12074
|
-
|
|
10882
|
+
main4 as main
|
|
12075
10883
|
};
|
|
12076
10884
|
/*! Bundled license information:
|
|
12077
10885
|
|