@donotdev/cli 0.0.18 → 0.0.20
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 +42 -55
- package/dist/bin/commands/bump.js +5 -2
- package/dist/bin/commands/coach.js +8177 -0
- package/dist/bin/commands/create-app.js +6 -6
- package/dist/bin/commands/create-project.js +23 -9
- package/dist/bin/commands/deploy.js +99 -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 +524 -1713
- package/dist/bin/commands/staging.js +17870 -0
- package/dist/bin/commands/sync-secrets.js +2 -11
- package/dist/bin/commands/type-check.js +7738 -1712
- package/dist/bin/dndev.js +868 -199
- package/dist/bin/donotdev.js +868 -199
- package/dist/index.js +127 -67
- package/package.json +1 -1
- package/templates/app-demo/index.html.example +147 -10
- package/templates/app-demo/public/apple-touch-icon.png.example +0 -0
- package/templates/app-demo/public/favicon.svg.example +1 -0
- package/templates/app-demo/public/icon-192x192.png.example +0 -0
- package/templates/app-demo/public/icon-512x512.png.example +0 -0
- package/templates/app-demo/src/App.tsx.example +7 -11
- package/templates/app-demo/src/config/app.ts.example +13 -48
- package/templates/app-demo/src/entities/booking.ts.example +75 -0
- package/templates/app-demo/src/entities/onboarding.ts.example +160 -0
- package/templates/app-demo/src/entities/product.ts.example +50 -0
- package/templates/app-demo/src/entities/quote.ts.example +70 -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 +41 -0
- package/templates/app-demo/src/pages/ConditionalFormPage.tsx.example +88 -0
- package/templates/app-demo/src/pages/DashboardPage.tsx.example +17 -0
- package/templates/app-demo/src/pages/HomePage.tsx.example +339 -60
- package/templates/app-demo/src/pages/OnboardingPage.tsx.example +47 -0
- package/templates/app-demo/src/pages/PricingPage.tsx.example +41 -0
- package/templates/app-demo/src/pages/ProductsPage.tsx.example +19 -0
- package/templates/app-demo/src/pages/ProfilePage.tsx.example +18 -0
- package/templates/app-demo/src/pages/SettingsPage.tsx.example +17 -0
- package/templates/app-demo/src/pages/ShowcaseDetailPage.tsx.example +118 -0
- package/templates/app-demo/src/pages/ShowcasePage.tsx.example +93 -0
- package/templates/app-demo/src/pages/components/ComponentRenderer.tsx.example +147 -51
- package/templates/app-demo/src/pages/components/ComponentsData.tsx.example +103 -21
- package/templates/app-demo/src/pages/components/componentConfig.ts.example +139 -59
- package/templates/app-demo/src/pages/legal/LegalPage.tsx.example +25 -0
- package/templates/app-demo/src/pages/legal/PrivacyPage.tsx.example +23 -0
- package/templates/app-demo/src/pages/legal/TermsPage.tsx.example +23 -0
- package/templates/app-demo/src/themes.css.example +289 -77
- package/templates/app-demo/stats.html.example +4949 -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-next/src/locales/home_en.json.example +6 -6
- package/templates/app-vite/src/locales/home_en.json.example +6 -6
- 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/AI.md.example +4 -3
- 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 +19 -15
- 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/advanced/COOKIE_REFERENCE.md.example +252 -252
- package/templates/root-consumer/guides/dndev/advanced/VERSION_CONTROL.md.example +174 -174
- package/templates/root-consumer/guides/dndev/essences_reference.css.example +119 -2
- 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
|
@@ -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" });
|
|
@@ -9694,6 +9660,9 @@ function roleToSqlCondition(role) {
|
|
|
9694
9660
|
case "super":
|
|
9695
9661
|
return "(auth.jwt()->'app_metadata'->>'role') = 'super'";
|
|
9696
9662
|
default:
|
|
9663
|
+
log.warn(
|
|
9664
|
+
`Unknown access role "${role}" \u2014 defaulting to deny (false). Use guest|user|admin|super.`
|
|
9665
|
+
);
|
|
9697
9666
|
return "false";
|
|
9698
9667
|
}
|
|
9699
9668
|
}
|
|
@@ -10288,30 +10257,32 @@ async function main3(options = {}) {
|
|
|
10288
10257
|
const supabaseUrl = existingConfig.url;
|
|
10289
10258
|
log.success(`Supabase URL: ${supabaseUrl}`);
|
|
10290
10259
|
const secretKey = detectSecretKey(appDir);
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10260
|
+
const dbUrl = detectDbUrl(appDir);
|
|
10261
|
+
if (secretKey) log.success("Secret key detected");
|
|
10262
|
+
else log.error("Missing SUPABASE_SECRET_KEY in supabase/functions/.env");
|
|
10263
|
+
if (dbUrl) log.success("DB URL detected");
|
|
10264
|
+
else log.error("Missing SUPABASE_DB_URL in supabase/functions/.env");
|
|
10265
|
+
if (!secretKey || !dbUrl) {
|
|
10294
10266
|
const functionsEnvPath = joinPath(supabaseDir, "functions", ".env");
|
|
10267
|
+
const missing = [];
|
|
10268
|
+
if (!secretKey) missing.push(" SUPABASE_SECRET_KEY=your-service-role-key");
|
|
10269
|
+
if (!dbUrl)
|
|
10270
|
+
missing.push(
|
|
10271
|
+
" SUPABASE_DB_URL=postgresql://postgres:...@db.<ref>.supabase.co:5432/postgres"
|
|
10272
|
+
);
|
|
10295
10273
|
Me(
|
|
10296
10274
|
[
|
|
10297
10275
|
`Fill in ${functionsEnvPath}:`,
|
|
10298
|
-
|
|
10276
|
+
...missing,
|
|
10299
10277
|
"",
|
|
10300
|
-
"Get
|
|
10278
|
+
"Get these from: https://supabase.com/dashboard > Settings > Database",
|
|
10301
10279
|
"",
|
|
10302
|
-
"
|
|
10280
|
+
"Then re-run: dndev setup supabase"
|
|
10303
10281
|
].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)}`
|
|
10282
|
+
"Missing Credentials"
|
|
10314
10283
|
);
|
|
10284
|
+
Se("Setup aborted.");
|
|
10285
|
+
return;
|
|
10315
10286
|
}
|
|
10316
10287
|
const entitiesDir = joinPath(projectRoot, "entities");
|
|
10317
10288
|
const hasEntities = pathExists(entitiesDir) && pathExists(joinPath(entitiesDir, "index.ts"));
|
|
@@ -10364,25 +10335,21 @@ async function main3(options = {}) {
|
|
|
10364
10335
|
}
|
|
10365
10336
|
}
|
|
10366
10337
|
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
|
-
}
|
|
10338
|
+
const shouldPush = await askForConfirmation(
|
|
10339
|
+
"Push migrations to remote database?",
|
|
10340
|
+
true
|
|
10341
|
+
);
|
|
10342
|
+
if (shouldPush) {
|
|
10343
|
+
const s = Y2();
|
|
10344
|
+
s.start("Pushing migrations...");
|
|
10345
|
+
try {
|
|
10346
|
+
await executeMigration({ supabaseDir, dbUrl });
|
|
10347
|
+
s.stop("Migrations pushed successfully");
|
|
10348
|
+
migrationsPushed = true;
|
|
10349
|
+
} catch (error2) {
|
|
10350
|
+
s.stop("Failed to push migrations");
|
|
10351
|
+
log.error(`${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
10352
|
+
log.info("Apply manually via the Supabase Dashboard SQL Editor.");
|
|
10386
10353
|
}
|
|
10387
10354
|
}
|
|
10388
10355
|
try {
|
|
@@ -10441,96 +10408,121 @@ var init_supabase = __esm({
|
|
|
10441
10408
|
async run(ctx) {
|
|
10442
10409
|
const steps = [];
|
|
10443
10410
|
const framework = ctx.app?.framework === "nextjs" ? "nextjs" : "vite";
|
|
10411
|
+
const supabaseDir = joinPath(ctx.appDir, "supabase");
|
|
10444
10412
|
const existingConfig = detectPublicConfig(ctx.appDir, framework);
|
|
10445
10413
|
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
10414
|
steps.push({
|
|
10461
10415
|
name: "Credentials",
|
|
10462
10416
|
status: "failed",
|
|
10463
|
-
message: "Missing Supabase
|
|
10464
|
-
coachingTopic: "supabase-credentials"
|
|
10417
|
+
message: "Missing Supabase URL or public key in .env"
|
|
10465
10418
|
});
|
|
10466
10419
|
return { provider: "supabase", steps, overallStatus: "failed" };
|
|
10467
10420
|
}
|
|
10468
|
-
const supabaseUrl = existingConfig.url;
|
|
10469
|
-
steps.push({
|
|
10470
|
-
name: "Public credentials",
|
|
10471
|
-
status: "success",
|
|
10472
|
-
message: `URL: ${supabaseUrl}`
|
|
10473
|
-
});
|
|
10474
10421
|
const secretKey = detectSecretKey(ctx.appDir);
|
|
10475
|
-
|
|
10422
|
+
const dbUrl = detectDbUrl(ctx.appDir);
|
|
10423
|
+
const missingSecrets = [];
|
|
10424
|
+
if (!secretKey) missingSecrets.push("SUPABASE_SECRET_KEY");
|
|
10425
|
+
if (!dbUrl) missingSecrets.push("SUPABASE_DB_URL");
|
|
10426
|
+
if (missingSecrets.length > 0) {
|
|
10476
10427
|
steps.push({
|
|
10477
|
-
name: "
|
|
10478
|
-
status: "
|
|
10479
|
-
message:
|
|
10428
|
+
name: "Credentials",
|
|
10429
|
+
status: "failed",
|
|
10430
|
+
message: `Missing in functions/.env: ${missingSecrets.join(", ")}`
|
|
10480
10431
|
});
|
|
10432
|
+
return { provider: "supabase", steps, overallStatus: "failed" };
|
|
10433
|
+
}
|
|
10434
|
+
steps.push({
|
|
10435
|
+
name: "Credentials",
|
|
10436
|
+
status: "success",
|
|
10437
|
+
message: `${existingConfig.url}`
|
|
10438
|
+
});
|
|
10439
|
+
const entitiesDir = joinPath(ctx.projectRoot, "entities");
|
|
10440
|
+
const hasEntities = pathExists(entitiesDir) && pathExists(joinPath(entitiesDir, "index.ts"));
|
|
10441
|
+
let generatedEntityFile = null;
|
|
10442
|
+
if (hasEntities) {
|
|
10443
|
+
try {
|
|
10444
|
+
const { SqlGenerator: SqlGenerator2 } = await Promise.resolve().then(() => (init_sql_generator(), sql_generator_exports));
|
|
10445
|
+
const generator = new SqlGenerator2({
|
|
10446
|
+
entityDir: entitiesDir,
|
|
10447
|
+
outputDir: joinPath(supabaseDir, "migrations"),
|
|
10448
|
+
singleFile: true
|
|
10449
|
+
});
|
|
10450
|
+
const s = Y2();
|
|
10451
|
+
s.start("Generating SQL from entities...");
|
|
10452
|
+
const result = await generator.run();
|
|
10453
|
+
if (result.success) {
|
|
10454
|
+
s.stop("SQL generated");
|
|
10455
|
+
generatedEntityFile = result.generatedFiles[0] ?? null;
|
|
10456
|
+
steps.push({
|
|
10457
|
+
name: "SQL generation",
|
|
10458
|
+
status: "success",
|
|
10459
|
+
message: `${result.filesGenerated} migration file(s)`
|
|
10460
|
+
});
|
|
10461
|
+
} else {
|
|
10462
|
+
s.stop("SQL generation failed");
|
|
10463
|
+
steps.push({
|
|
10464
|
+
name: "SQL generation",
|
|
10465
|
+
status: "failed",
|
|
10466
|
+
message: "Generator returned failure"
|
|
10467
|
+
});
|
|
10468
|
+
}
|
|
10469
|
+
} catch (error2) {
|
|
10470
|
+
steps.push({
|
|
10471
|
+
name: "SQL generation",
|
|
10472
|
+
status: "failed",
|
|
10473
|
+
message: getErrorMessage(error2)
|
|
10474
|
+
});
|
|
10475
|
+
}
|
|
10481
10476
|
} 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
10477
|
steps.push({
|
|
10494
|
-
name: "
|
|
10495
|
-
status: "
|
|
10496
|
-
message: "
|
|
10497
|
-
coachingTopic: "supabase-secret-key"
|
|
10478
|
+
name: "SQL generation",
|
|
10479
|
+
status: "skipped",
|
|
10480
|
+
message: "No entities/ directory"
|
|
10498
10481
|
});
|
|
10499
10482
|
}
|
|
10500
|
-
if (
|
|
10483
|
+
if (generatedEntityFile) {
|
|
10484
|
+
try {
|
|
10485
|
+
await cleanupOldEntityMigrations(supabaseDir, generatedEntityFile);
|
|
10486
|
+
} catch {
|
|
10487
|
+
}
|
|
10488
|
+
}
|
|
10489
|
+
const migrationsDir = joinPath(supabaseDir, "migrations");
|
|
10490
|
+
if (pathExists(migrationsDir)) {
|
|
10491
|
+
const s = Y2();
|
|
10492
|
+
s.start("Pushing migrations...");
|
|
10501
10493
|
try {
|
|
10502
|
-
|
|
10503
|
-
|
|
10494
|
+
await executeMigration({ supabaseDir, dbUrl });
|
|
10495
|
+
s.stop("Migrations pushed");
|
|
10504
10496
|
steps.push({
|
|
10505
|
-
name: "
|
|
10497
|
+
name: "DB migrations",
|
|
10506
10498
|
status: "success",
|
|
10507
|
-
message: "
|
|
10499
|
+
message: "All migrations applied"
|
|
10508
10500
|
});
|
|
10509
|
-
} catch (
|
|
10501
|
+
} catch (error2) {
|
|
10502
|
+
s.stop("Migration push failed");
|
|
10510
10503
|
steps.push({
|
|
10511
|
-
name: "
|
|
10504
|
+
name: "DB migrations",
|
|
10512
10505
|
status: "failed",
|
|
10513
|
-
message: getErrorMessage(
|
|
10506
|
+
message: getErrorMessage(error2)
|
|
10507
|
+
});
|
|
10508
|
+
}
|
|
10509
|
+
}
|
|
10510
|
+
if (hasEntities) {
|
|
10511
|
+
try {
|
|
10512
|
+
await generateCrudFunction(supabaseDir, ctx.projectRoot);
|
|
10513
|
+
steps.push({
|
|
10514
|
+
name: "CRUD function",
|
|
10515
|
+
status: "success",
|
|
10516
|
+
message: "Entity imports patched"
|
|
10517
|
+
});
|
|
10518
|
+
} catch (error2) {
|
|
10519
|
+
steps.push({
|
|
10520
|
+
name: "CRUD function",
|
|
10521
|
+
status: "failed",
|
|
10522
|
+
message: getErrorMessage(error2)
|
|
10514
10523
|
});
|
|
10515
10524
|
}
|
|
10516
|
-
} else {
|
|
10517
|
-
steps.push({ name: "CLI link", status: "skipped", message: "Dry run" });
|
|
10518
10525
|
}
|
|
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
10526
|
return {
|
|
10535
10527
|
provider: "supabase",
|
|
10536
10528
|
steps,
|
|
@@ -10546,27 +10538,13 @@ var vercel_exports = {};
|
|
|
10546
10538
|
__export(vercel_exports, {
|
|
10547
10539
|
vercelWizard: () => vercelWizard
|
|
10548
10540
|
});
|
|
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
10541
|
var vercelWizard;
|
|
10562
10542
|
var init_vercel = __esm({
|
|
10563
10543
|
"packages/tooling/src/cli/setup/vercel.ts"() {
|
|
10564
10544
|
"use strict";
|
|
10565
10545
|
init_utils();
|
|
10566
10546
|
init_cli_output();
|
|
10567
|
-
init_cli_output();
|
|
10568
10547
|
init_pathResolver();
|
|
10569
|
-
init_error_handling();
|
|
10570
10548
|
init_types();
|
|
10571
10549
|
init_vercel_token();
|
|
10572
10550
|
vercelWizard = {
|
|
@@ -10577,108 +10555,22 @@ var init_vercel = __esm({
|
|
|
10577
10555
|
},
|
|
10578
10556
|
async run(ctx) {
|
|
10579
10557
|
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");
|
|
10558
|
+
const result = resolveVercelCredentials(ctx.appDir);
|
|
10559
|
+
if (result.credentials) {
|
|
10560
|
+
log.success("Vercel credentials detected");
|
|
10594
10561
|
steps.push({
|
|
10595
|
-
name: "
|
|
10562
|
+
name: "Credentials",
|
|
10596
10563
|
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"
|
|
10564
|
+
message: "VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID found"
|
|
10663
10565
|
});
|
|
10664
10566
|
} else {
|
|
10567
|
+
log.error(`Missing in .env.local: ${result.missing.join(", ")}`);
|
|
10665
10568
|
steps.push({
|
|
10666
|
-
name: "
|
|
10667
|
-
status: "
|
|
10668
|
-
message: "
|
|
10569
|
+
name: "Credentials",
|
|
10570
|
+
status: "failed",
|
|
10571
|
+
message: `Missing: ${result.missing.join(", ")}`
|
|
10669
10572
|
});
|
|
10670
10573
|
}
|
|
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
10574
|
return {
|
|
10683
10575
|
provider: "vercel",
|
|
10684
10576
|
steps,
|
|
@@ -10689,868 +10581,77 @@ var init_vercel = __esm({
|
|
|
10689
10581
|
}
|
|
10690
10582
|
});
|
|
10691
10583
|
|
|
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
|
-
});
|
|
10886
|
-
|
|
10887
|
-
// packages/tooling/src/cli/setup/oauth.ts
|
|
10888
|
-
var oauth_exports = {};
|
|
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
|
-
});
|
|
11031
|
-
|
|
11032
|
-
// packages/tooling/src/cli/setup/auth.ts
|
|
11033
|
-
var auth_exports = {};
|
|
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
|
-
});
|
|
10584
|
+
// packages/cli/src/bin/commands/setup.ts
|
|
10585
|
+
init_utils();
|
|
11158
10586
|
|
|
11159
|
-
// packages/tooling/src/
|
|
11160
|
-
|
|
11161
|
-
__export(check_env_exports, {
|
|
11162
|
-
envCheck: () => envCheck,
|
|
11163
|
-
parseEnvFile: () => parseEnvFile
|
|
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
|
-
});
|
|
10587
|
+
// packages/tooling/src/index.ts
|
|
10588
|
+
init_utils();
|
|
11269
10589
|
|
|
11270
|
-
// packages/tooling/src/cli/
|
|
11271
|
-
|
|
11272
|
-
__export(check_firebase_exports, {
|
|
11273
|
-
firebaseCheck: () => firebaseCheck
|
|
11274
|
-
});
|
|
11275
|
-
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
11276
|
-
var firebaseCheck;
|
|
11277
|
-
var init_check_firebase = __esm({
|
|
11278
|
-
"packages/tooling/src/cli/doctor/check-firebase.ts"() {
|
|
11279
|
-
"use strict";
|
|
11280
|
-
init_utils();
|
|
11281
|
-
init_pathResolver();
|
|
11282
|
-
firebaseCheck = {
|
|
11283
|
-
id: "firebase",
|
|
11284
|
-
name: "Firebase",
|
|
11285
|
-
isRelevant(ctx) {
|
|
11286
|
-
return pathExists(joinPath(ctx.appDir, "firebase.json")) || pathExists(joinPath(ctx.projectRoot, "firebase.json")) || pathExists(joinPath(ctx.projectRoot, ".firebaserc"));
|
|
11287
|
-
},
|
|
11288
|
-
async run(ctx) {
|
|
11289
|
-
const results = [];
|
|
11290
|
-
try {
|
|
11291
|
-
const result = spawnSync3("firebase", ["--version"], {
|
|
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
|
-
};
|
|
11407
|
-
}
|
|
11408
|
-
});
|
|
10590
|
+
// packages/tooling/src/cli/index.ts
|
|
10591
|
+
init_utils();
|
|
11409
10592
|
|
|
11410
|
-
// packages/tooling/src/cli/
|
|
11411
|
-
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
11416
|
-
var supabaseCheck;
|
|
11417
|
-
var init_check_supabase = __esm({
|
|
11418
|
-
"packages/tooling/src/cli/doctor/check-supabase.ts"() {
|
|
11419
|
-
"use strict";
|
|
11420
|
-
init_utils();
|
|
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
|
-
};
|
|
11545
|
-
}
|
|
11546
|
-
});
|
|
10593
|
+
// packages/tooling/src/cli/setup/setup.ts
|
|
10594
|
+
init_utils();
|
|
10595
|
+
init_cli_output();
|
|
10596
|
+
init_pathResolver();
|
|
10597
|
+
init_cross_app_detection();
|
|
11547
10598
|
|
|
11548
|
-
// packages/tooling/src/cli/
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
10599
|
+
// packages/tooling/src/cli/setup/validate-env.ts
|
|
10600
|
+
init_utils();
|
|
10601
|
+
init_pathResolver();
|
|
10602
|
+
init_cli_output();
|
|
10603
|
+
var FIREBASE_VARS = [
|
|
10604
|
+
{
|
|
10605
|
+
provider: "Firebase",
|
|
10606
|
+
varName: "FIREBASE_API_KEY",
|
|
10607
|
+
envFile: ".env",
|
|
10608
|
+
needsPrefix: true
|
|
10609
|
+
},
|
|
10610
|
+
{
|
|
10611
|
+
provider: "Firebase",
|
|
10612
|
+
varName: "FIREBASE_PROJECT_ID",
|
|
10613
|
+
envFile: ".env",
|
|
10614
|
+
needsPrefix: true
|
|
10615
|
+
},
|
|
10616
|
+
{
|
|
10617
|
+
provider: "Firebase",
|
|
10618
|
+
varName: "FIREBASE_AUTH_DOMAIN",
|
|
10619
|
+
envFile: ".env",
|
|
10620
|
+
needsPrefix: true
|
|
10621
|
+
}
|
|
10622
|
+
];
|
|
10623
|
+
var SUPABASE_VARS = [
|
|
10624
|
+
{
|
|
10625
|
+
provider: "Supabase",
|
|
10626
|
+
varName: "SUPABASE_URL",
|
|
10627
|
+
envFile: ".env",
|
|
10628
|
+
needsPrefix: true
|
|
10629
|
+
},
|
|
10630
|
+
{
|
|
10631
|
+
provider: "Supabase",
|
|
10632
|
+
varName: "SUPABASE_PUBLIC_KEY",
|
|
10633
|
+
envFile: ".env",
|
|
10634
|
+
needsPrefix: true
|
|
10635
|
+
}
|
|
10636
|
+
];
|
|
10637
|
+
var SUPABASE_SECRET_VARS = [
|
|
10638
|
+
{
|
|
10639
|
+
provider: "Supabase",
|
|
10640
|
+
varName: "SUPABASE_SECRET_KEY",
|
|
10641
|
+
envFile: "supabase/functions/.env"
|
|
10642
|
+
},
|
|
10643
|
+
{
|
|
10644
|
+
provider: "Supabase",
|
|
10645
|
+
varName: "SUPABASE_DB_URL",
|
|
10646
|
+
envFile: "supabase/functions/.env"
|
|
10647
|
+
}
|
|
10648
|
+
];
|
|
10649
|
+
var VERCEL_VARS = [
|
|
10650
|
+
{ provider: "Vercel", varName: "VERCEL_TOKEN", envFile: ".env.local" },
|
|
10651
|
+
{ provider: "Vercel", varName: "VERCEL_ORG_ID", envFile: ".env.local" },
|
|
10652
|
+
{ provider: "Vercel", varName: "VERCEL_PROJECT_ID", envFile: ".env.local" }
|
|
10653
|
+
];
|
|
10654
|
+
function readEnvValue(envPath, varName) {
|
|
11554
10655
|
if (!pathExists(envPath)) return null;
|
|
11555
10656
|
const content = readSync(envPath, { format: "text" });
|
|
11556
10657
|
if (typeof content !== "string") return null;
|
|
@@ -11558,520 +10659,230 @@ function readEnvValue2(envPath, varName) {
|
|
|
11558
10659
|
const trimmed = line.trim();
|
|
11559
10660
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
11560
10661
|
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;
|
|
10662
|
+
return trimmed.substring(`${varName}=`.length).trim();
|
|
11566
10663
|
}
|
|
11567
10664
|
}
|
|
11568
10665
|
return null;
|
|
11569
10666
|
}
|
|
11570
|
-
function
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
10667
|
+
function isProviderRelevant(ctx, provider) {
|
|
10668
|
+
switch (provider) {
|
|
10669
|
+
case "Firebase":
|
|
10670
|
+
return pathExists(joinPath(ctx.appDir, "firebase.json")) || pathExists(joinPath(ctx.projectRoot, "firebase.json")) || pathExists(joinPath(ctx.projectRoot, ".firebaserc"));
|
|
10671
|
+
case "Supabase":
|
|
10672
|
+
return pathExists(joinPath(ctx.appDir, "supabase")) || pathExists(joinPath(ctx.appDir, "supabase", "config.toml"));
|
|
10673
|
+
case "Vercel":
|
|
10674
|
+
return pathExists(joinPath(ctx.appDir, "vercel.json"));
|
|
10675
|
+
default:
|
|
10676
|
+
return false;
|
|
10677
|
+
}
|
|
11576
10678
|
}
|
|
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
|
-
};
|
|
10679
|
+
function validateRequiredEnvVars(ctx) {
|
|
10680
|
+
const missing = [];
|
|
10681
|
+
const framework = ctx.app?.framework === "nextjs" ? "nextjs" : "vite";
|
|
10682
|
+
const prefix = framework === "nextjs" ? "NEXT_PUBLIC_" : "VITE_";
|
|
10683
|
+
const requirements = [];
|
|
10684
|
+
if (isProviderRelevant(ctx, "Firebase")) {
|
|
10685
|
+
requirements.push(...FIREBASE_VARS);
|
|
10686
|
+
}
|
|
10687
|
+
if (isProviderRelevant(ctx, "Supabase")) {
|
|
10688
|
+
requirements.push(...SUPABASE_VARS);
|
|
10689
|
+
const sbFunctionsEnv = joinPath(
|
|
10690
|
+
ctx.appDir,
|
|
10691
|
+
"supabase",
|
|
10692
|
+
"functions",
|
|
10693
|
+
".env"
|
|
10694
|
+
);
|
|
10695
|
+
const altFunctionsEnv = joinPath(ctx.appDir, "functions", ".env");
|
|
10696
|
+
if (pathExists(joinPath(ctx.appDir, "supabase", "functions")) || pathExists(sbFunctionsEnv)) {
|
|
10697
|
+
requirements.push(...SUPABASE_SECRET_VARS);
|
|
10698
|
+
} else if (pathExists(altFunctionsEnv)) {
|
|
10699
|
+
requirements.push({
|
|
10700
|
+
provider: "Supabase",
|
|
10701
|
+
varName: "SUPABASE_SECRET_KEY",
|
|
10702
|
+
envFile: "functions/.env"
|
|
10703
|
+
});
|
|
10704
|
+
}
|
|
11707
10705
|
}
|
|
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"
|
|
10706
|
+
if (isProviderRelevant(ctx, "Vercel")) {
|
|
10707
|
+
requirements.push(...VERCEL_VARS);
|
|
10708
|
+
}
|
|
10709
|
+
for (const req of requirements) {
|
|
10710
|
+
const actualVarName = req.needsPrefix ? `${prefix}${req.varName}` : req.varName;
|
|
10711
|
+
const envFilePath = joinPath(ctx.appDir, req.envFile);
|
|
10712
|
+
if (req.varName === "SUPABASE_PUBLIC_KEY") {
|
|
10713
|
+
const pkValue = readEnvValue(envFilePath, actualVarName);
|
|
10714
|
+
const anonValue = readEnvValue(envFilePath, `${prefix}SUPABASE_ANON_KEY`);
|
|
10715
|
+
if ((!pkValue || pkValue === "") && (!anonValue || anonValue === "")) {
|
|
10716
|
+
missing.push({
|
|
10717
|
+
provider: req.provider,
|
|
10718
|
+
varName: actualVarName,
|
|
10719
|
+
envFile: req.envFile,
|
|
10720
|
+
status: pathExists(envFilePath) ? "empty" : "missing"
|
|
11739
10721
|
});
|
|
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
10722
|
}
|
|
10723
|
+
continue;
|
|
11824
10724
|
}
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
}
|
|
11841
|
-
} catch {
|
|
10725
|
+
const value = readEnvValue(envFilePath, actualVarName);
|
|
10726
|
+
if (value === null) {
|
|
10727
|
+
missing.push({
|
|
10728
|
+
provider: req.provider,
|
|
10729
|
+
varName: actualVarName,
|
|
10730
|
+
envFile: req.envFile,
|
|
10731
|
+
status: pathExists(envFilePath) ? "missing" : "missing"
|
|
10732
|
+
});
|
|
10733
|
+
} else if (value === "") {
|
|
10734
|
+
missing.push({
|
|
10735
|
+
provider: req.provider,
|
|
10736
|
+
varName: actualVarName,
|
|
10737
|
+
envFile: req.envFile,
|
|
10738
|
+
status: "empty"
|
|
10739
|
+
});
|
|
11842
10740
|
}
|
|
11843
10741
|
}
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
);
|
|
11857
|
-
Se("Doctor aborted.");
|
|
11858
|
-
return 1;
|
|
10742
|
+
return missing;
|
|
10743
|
+
}
|
|
10744
|
+
function validateAllApps(apps, _topology, projectRoot) {
|
|
10745
|
+
const results = [];
|
|
10746
|
+
for (const app of apps) {
|
|
10747
|
+
const ctx = {
|
|
10748
|
+
projectRoot,
|
|
10749
|
+
appDir: app.path,
|
|
10750
|
+
app
|
|
10751
|
+
};
|
|
10752
|
+
const missing = validateRequiredEnvVars(ctx);
|
|
10753
|
+
results.push({ app, missing });
|
|
11859
10754
|
}
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
10755
|
+
return results;
|
|
10756
|
+
}
|
|
10757
|
+
function printAllValidationResults(results, multiApp) {
|
|
10758
|
+
const allMissing = [];
|
|
10759
|
+
for (const { app, missing } of results) {
|
|
10760
|
+
for (const m2 of missing) {
|
|
10761
|
+
allMissing.push({ appName: app.name, m: m2 });
|
|
11867
10762
|
}
|
|
11868
10763
|
}
|
|
11869
|
-
if (
|
|
11870
|
-
log.
|
|
11871
|
-
|
|
11872
|
-
return 0;
|
|
10764
|
+
if (allMissing.length === 0) {
|
|
10765
|
+
log.success("Credentials OK");
|
|
10766
|
+
return true;
|
|
11873
10767
|
}
|
|
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;
|
|
10768
|
+
for (const { appName, m: m2 } of allMissing) {
|
|
10769
|
+
const prefix = multiApp ? `${appName}: ` : "";
|
|
10770
|
+
const detail = m2.status === "empty" ? `empty in ${m2.envFile}` : `missing \u2014 ${m2.envFile}`;
|
|
10771
|
+
log.error(` ${prefix}${m2.varName} (${detail})`);
|
|
11928
10772
|
}
|
|
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();
|
|
10773
|
+
log.warn(`Run 'dndev coach' to see where to get them.`);
|
|
10774
|
+
return false;
|
|
10775
|
+
}
|
|
11939
10776
|
|
|
11940
10777
|
// 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
10778
|
var WIZARD_REGISTRY = {
|
|
11947
10779
|
firebase: async () => (await Promise.resolve().then(() => (init_firebase(), firebase_exports))).firebaseWizard,
|
|
11948
10780
|
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
|
|
10781
|
+
vercel: async () => (await Promise.resolve().then(() => (init_vercel(), vercel_exports))).vercelWizard
|
|
11953
10782
|
};
|
|
11954
|
-
var WIZARD_ORDER = [
|
|
11955
|
-
|
|
11956
|
-
"supabase",
|
|
11957
|
-
"vercel",
|
|
11958
|
-
"stripe",
|
|
11959
|
-
"auth",
|
|
11960
|
-
"oauth"
|
|
11961
|
-
];
|
|
11962
|
-
var STATUS_ICONS2 = {
|
|
10783
|
+
var WIZARD_ORDER = ["firebase", "supabase", "vercel"];
|
|
10784
|
+
var STATUS_ICONS = {
|
|
11963
10785
|
success: "\u2705",
|
|
11964
|
-
// green check
|
|
11965
10786
|
skipped: "\u23ED\uFE0F",
|
|
11966
|
-
// skip
|
|
11967
10787
|
failed: "\u274C",
|
|
11968
|
-
// red x
|
|
11969
10788
|
"needs-manual": "\u{1F449}"
|
|
11970
|
-
// pointing right
|
|
11971
10789
|
};
|
|
11972
|
-
function
|
|
11973
|
-
const
|
|
11974
|
-
|
|
11975
|
-
|
|
10790
|
+
function renderResults(results, multiApp) {
|
|
10791
|
+
for (const { appName, result } of results) {
|
|
10792
|
+
if (multiApp) {
|
|
10793
|
+
log.info(`
|
|
10794
|
+
${appName} \u2014 ${result.provider}:`);
|
|
10795
|
+
}
|
|
11976
10796
|
for (const step of result.steps) {
|
|
11977
|
-
const icon =
|
|
11978
|
-
|
|
10797
|
+
const icon = STATUS_ICONS[step.status];
|
|
10798
|
+
log.info(` ${icon} ${step.name}: ${step.message}`);
|
|
11979
10799
|
}
|
|
11980
|
-
lines.push("");
|
|
11981
10800
|
}
|
|
11982
|
-
Me(lines.join("\n"), "Setup Summary");
|
|
11983
10801
|
}
|
|
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 = {
|
|
10802
|
+
function buildSetupContext(app, projectRoot, topology, options) {
|
|
10803
|
+
const backendApp = findBackendApp(topology, app.name);
|
|
10804
|
+
return {
|
|
12000
10805
|
projectRoot,
|
|
12001
|
-
appDir,
|
|
10806
|
+
appDir: app.path,
|
|
12002
10807
|
app,
|
|
12003
10808
|
verbose: options.verbose,
|
|
12004
|
-
dryRun: options.dryRun
|
|
10809
|
+
dryRun: options.dryRun,
|
|
10810
|
+
allApps: topology.apps,
|
|
10811
|
+
backendApp
|
|
12005
10812
|
};
|
|
12006
|
-
|
|
12007
|
-
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
|
|
12018
|
-
|
|
10813
|
+
}
|
|
10814
|
+
async function main4(options = {}) {
|
|
10815
|
+
const projectRoot = process.cwd();
|
|
10816
|
+
Ie("DoNotDev Setup");
|
|
10817
|
+
const topology = analyzeProjectTopology(projectRoot);
|
|
10818
|
+
let apps = topology.apps;
|
|
10819
|
+
if (apps.length === 0) {
|
|
10820
|
+
apps = [
|
|
10821
|
+
{
|
|
10822
|
+
name: "root",
|
|
10823
|
+
packageName: "root",
|
|
10824
|
+
path: projectRoot,
|
|
10825
|
+
packageJsonPath: joinPath(projectRoot, "package.json"),
|
|
10826
|
+
framework: "vite",
|
|
10827
|
+
hasFunctions: false
|
|
10828
|
+
}
|
|
10829
|
+
];
|
|
10830
|
+
}
|
|
10831
|
+
const multiApp = apps.length > 1;
|
|
10832
|
+
const validationResults = validateAllApps(apps, topology, projectRoot);
|
|
10833
|
+
const allValid = printAllValidationResults(validationResults, multiApp);
|
|
10834
|
+
if (!allValid) {
|
|
10835
|
+
Se("Fix missing values, then re-run.");
|
|
10836
|
+
return 1;
|
|
10837
|
+
}
|
|
10838
|
+
const allResults = [];
|
|
10839
|
+
for (const app of apps) {
|
|
10840
|
+
const ctx = buildSetupContext(app, projectRoot, topology, options);
|
|
10841
|
+
let wizardIds;
|
|
10842
|
+
if (options.provider) {
|
|
10843
|
+
const id = options.provider.toLowerCase();
|
|
10844
|
+
if (!WIZARD_REGISTRY[id]) {
|
|
10845
|
+
log.error(`Unknown provider: ${options.provider}`);
|
|
10846
|
+
Se("Setup aborted.");
|
|
10847
|
+
return 1;
|
|
10848
|
+
}
|
|
10849
|
+
const wizard = await WIZARD_REGISTRY[id]();
|
|
10850
|
+
wizardIds = wizard.isRelevant(ctx) ? [id] : [];
|
|
10851
|
+
} else {
|
|
10852
|
+
wizardIds = [];
|
|
10853
|
+
for (const id of WIZARD_ORDER) {
|
|
10854
|
+
const loader = WIZARD_REGISTRY[id];
|
|
10855
|
+
if (!loader) continue;
|
|
10856
|
+
const wizard = await loader();
|
|
10857
|
+
if (wizard.isRelevant(ctx)) {
|
|
10858
|
+
wizardIds.push(id);
|
|
10859
|
+
}
|
|
10860
|
+
}
|
|
10861
|
+
}
|
|
10862
|
+
for (const id of wizardIds) {
|
|
12019
10863
|
const loader = WIZARD_REGISTRY[id];
|
|
12020
10864
|
if (!loader) continue;
|
|
12021
10865
|
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;
|
|
10866
|
+
const result = await wizard.run(ctx);
|
|
10867
|
+
allResults.push({ appName: app.name, result });
|
|
12046
10868
|
}
|
|
12047
|
-
wizardIds = selected;
|
|
12048
10869
|
}
|
|
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
|
-
}
|
|
10870
|
+
if (allResults.length === 0) {
|
|
10871
|
+
log.warn("No providers detected. Run: dndev setup <provider>");
|
|
10872
|
+
Se("Nothing to set up.");
|
|
10873
|
+
return 0;
|
|
12068
10874
|
}
|
|
12069
|
-
|
|
12070
|
-
|
|
10875
|
+
renderResults(allResults, multiApp);
|
|
10876
|
+
const hasFailures = allResults.some(
|
|
10877
|
+
(r2) => r2.result.overallStatus === "failed"
|
|
10878
|
+
);
|
|
10879
|
+
Se(
|
|
10880
|
+
hasFailures ? "Setup incomplete \u2014 see errors above." : "Setup complete."
|
|
10881
|
+
);
|
|
12071
10882
|
return hasFailures ? 1 : 0;
|
|
12072
10883
|
}
|
|
12073
10884
|
export {
|
|
12074
|
-
|
|
10885
|
+
main4 as main
|
|
12075
10886
|
};
|
|
12076
10887
|
/*! Bundled license information:
|
|
12077
10888
|
|