@donotdev/cli 0.0.16 → 0.0.18
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 +38 -26
- package/dist/bin/commands/bump.js +9 -2
- package/dist/bin/commands/create-app.js +185 -81
- package/dist/bin/commands/create-project.js +186 -85
- package/dist/bin/commands/deploy.js +51 -20
- package/dist/bin/commands/doctor.js +249 -56
- package/dist/bin/commands/emu.js +18 -20
- package/dist/bin/commands/make-admin.js +30 -10
- package/dist/bin/commands/setup.js +512 -122
- package/dist/bin/commands/type-check.d.ts.map +1 -1
- package/dist/bin/commands/type-check.js +7 -3
- package/dist/bin/commands/type-check.js.map +1 -1
- package/dist/bin/dndev.js +9 -6
- package/dist/bin/donotdev.js +35 -20
- package/dist/index.js +262 -129
- package/package.json +1 -1
- package/templates/root-consumer/.claude/commands/brainstorm.md.example +15 -1
- package/templates/root-consumer/.claude/commands/build.md.example +24 -2
- package/templates/root-consumer/.claude/commands/design.md.example +17 -0
- package/templates/root-consumer/.claude/commands/polish.md.example +17 -0
- package/templates/root-consumer/AI.md.example +50 -18
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +6 -6
- package/templates/root-consumer/guides/dndev/INDEX.md.example +2 -2
- package/templates/root-consumer/guides/dndev/SETUP_AUTH.md.example +13 -6
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +149 -1086
- package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +68 -16
- package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +6 -111
- package/templates/root-consumer/guides/dndev/SETUP_PAGES.md.example +64 -0
- package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +123 -32
- package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +108 -91
- package/templates/root-consumer/guides/dndev/advanced/EMULATORS.md.example +2 -2
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +1 -1
- package/dist/bin/commands/firebase-setup.d.ts +0 -6
- package/dist/bin/commands/firebase-setup.d.ts.map +0 -1
- package/dist/bin/commands/firebase-setup.js +0 -7
- package/dist/bin/commands/firebase-setup.js.map +0 -1
- package/dist/bin/commands/supabase-setup.d.ts +0 -6
- package/dist/bin/commands/supabase-setup.d.ts.map +0 -1
- package/dist/bin/commands/supabase-setup.js +0 -7
- package/dist/bin/commands/supabase-setup.js.map +0 -1
- package/templates/functions-firebase/functions-firebase/README.md.example +0 -123
- package/templates/functions-firebase/functions-firebase/build.mjs.example +0 -5
- package/templates/functions-firebase/functions-firebase/src/auth/getCustomClaims.ts.example +0 -19
- package/templates/functions-firebase/functions-firebase/src/auth/getUserAuthStatus.ts.example +0 -21
- package/templates/functions-firebase/functions-firebase/src/auth/index.ts.example +0 -11
- package/templates/functions-firebase/functions-firebase/src/auth/removeCustomClaims.ts.example +0 -21
- package/templates/functions-firebase/functions-firebase/src/auth/setCustomClaims.ts.example +0 -21
- package/templates/functions-firebase/functions-firebase/src/billing/handleStripeWebhook.ts.example +0 -24
- package/templates/functions-firebase/functions-firebase/src/billing/index.ts.example +0 -10
- package/templates/functions-firebase/functions-firebase/src/billing/processPaymentSuccess.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/billing/refreshSubscriptionStatus.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/index.ts.example +0 -39
- package/templates/functions-firebase/functions-firebase/src/oauth/checkGitHubAccess.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/disconnect.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/exchangeToken.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/getConnections.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/grantGitHubAccess.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/index.ts.example +0 -17
- package/templates/functions-firebase/functions-firebase/src/oauth/refreshToken.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/oauth/revokeGitHubAccess.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/tsconfig.json.example +0 -21
- package/templates/functions-vercel/functions-vercel/README.md.example +0 -116
- package/templates/functions-vercel/functions-vercel/build.mjs.example +0 -52
- package/templates/functions-vercel/functions-vercel/src/api/auth/getCustomClaims.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/auth/getUserAuthStatus.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/auth/removeCustomClaims.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/auth/setCustomClaims.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/billing/handleStripeWebhook.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/billing/processPaymentSuccess.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/billing/refreshSubscriptionStatus.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/createEntity.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/deleteEntity.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/getEntity.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/listEntities.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/crud/updateEntity.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/checkGitHubAccess.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/disconnect.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/exchangeToken.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/getConnections.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/grantGitHubAccess.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/refreshToken.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/src/api/oauth/revokeGitHubAccess.ts.example +0 -20
- package/templates/functions-vercel/functions-vercel/tsconfig.json.example +0 -21
- package/templates/functions-vercel/functions-vercel/vercel.json.example +0 -14
- package/templates/github/github/workflows/firebase-deploy.yml.example +0 -79
- /package/templates/functions-firebase/{functions-firebase/.env.example.example → .env.example} +0 -0
- /package/templates/functions-vercel/{functions-vercel/.env.example.example → .env.example} +0 -0
|
@@ -8394,7 +8394,11 @@ function getMatrixPath(mode) {
|
|
|
8394
8394
|
const executionMode = mode || detectExecutionMode();
|
|
8395
8395
|
if (executionMode === "development") {
|
|
8396
8396
|
const templatesRoot = getTemplatesRoot();
|
|
8397
|
-
const devPath = normalizePath(
|
|
8397
|
+
const devPath = normalizePath(
|
|
8398
|
+
templatesRoot,
|
|
8399
|
+
"..",
|
|
8400
|
+
"dependencies-matrix.json"
|
|
8401
|
+
);
|
|
8398
8402
|
if (pathExists(devPath)) {
|
|
8399
8403
|
return devPath;
|
|
8400
8404
|
}
|
|
@@ -8471,34 +8475,67 @@ var APP_QUESTIONNAIRE = [
|
|
|
8471
8475
|
]
|
|
8472
8476
|
},
|
|
8473
8477
|
{
|
|
8474
|
-
id: "
|
|
8475
|
-
question: "
|
|
8476
|
-
type: "
|
|
8477
|
-
|
|
8478
|
+
id: "host",
|
|
8479
|
+
question: "Where will you host?",
|
|
8480
|
+
type: "select",
|
|
8481
|
+
condition: (answers) => answers.framework !== "expo",
|
|
8482
|
+
defaultValue: (answers) => {
|
|
8483
|
+
return answers.framework === "nextjs" ? "vercel" : "none";
|
|
8484
|
+
},
|
|
8485
|
+
choices: [
|
|
8486
|
+
{ title: "None \u2014 no hosting config", value: "none" },
|
|
8487
|
+
{ title: "Vercel \u2014 edge CDN + serverless", value: "vercel" },
|
|
8488
|
+
{ title: "Firebase Hosting \u2014 Google CDN", value: "firebase" }
|
|
8489
|
+
]
|
|
8490
|
+
},
|
|
8491
|
+
{
|
|
8492
|
+
id: "functions",
|
|
8493
|
+
question: "Serverless functions?",
|
|
8494
|
+
type: "select",
|
|
8495
|
+
defaultValue: "none",
|
|
8496
|
+
// Choices filtered dynamically based on host
|
|
8497
|
+
choices: [
|
|
8498
|
+
{ title: "None", value: "none" },
|
|
8499
|
+
{ title: "Vercel Functions \u2014 edge + node.js", value: "vercel" },
|
|
8500
|
+
{ title: "Firebase Functions \u2014 Google Cloud", value: "firebase" },
|
|
8501
|
+
{ title: "Supabase Edge Functions \u2014 Deno", value: "supabase" }
|
|
8502
|
+
],
|
|
8503
|
+
choicesFilter: (answers) => {
|
|
8504
|
+
const host = answers.host ?? "none";
|
|
8505
|
+
const framework = answers.framework;
|
|
8506
|
+
if (framework === "expo") return ["none", "firebase", "supabase"];
|
|
8507
|
+
if (host === "firebase") return ["none", "firebase"];
|
|
8508
|
+
if (host === "vercel") return ["none", "vercel", "supabase"];
|
|
8509
|
+
return ["none", "vercel", "firebase", "supabase"];
|
|
8510
|
+
}
|
|
8478
8511
|
},
|
|
8479
8512
|
{
|
|
8480
|
-
id: "
|
|
8481
|
-
question: "
|
|
8513
|
+
id: "backend",
|
|
8514
|
+
question: "Backend / BaaS provider?",
|
|
8482
8515
|
type: "select",
|
|
8483
|
-
dependsOn: "needsBackend",
|
|
8484
|
-
condition: (answers) => answers.needsBackend === true,
|
|
8485
8516
|
defaultValue: (answers) => {
|
|
8486
|
-
|
|
8517
|
+
if (answers.functions === "firebase") return "firebase";
|
|
8518
|
+
if (answers.functions === "supabase") return "supabase";
|
|
8519
|
+
return "none";
|
|
8487
8520
|
},
|
|
8488
8521
|
choices: [
|
|
8522
|
+
{ title: "None \u2014 frontend only", value: "none" },
|
|
8489
8523
|
{
|
|
8490
|
-
title: "Firebase \u2014
|
|
8524
|
+
title: "Firebase \u2014 Auth + Firestore + Storage",
|
|
8491
8525
|
value: "firebase"
|
|
8492
8526
|
},
|
|
8493
|
-
{
|
|
8494
|
-
title: "Vercel \u2014 Serverless functions (edge + node.js)",
|
|
8495
|
-
value: "vercel"
|
|
8496
|
-
},
|
|
8497
8527
|
{
|
|
8498
8528
|
title: "Supabase \u2014 Postgres + Auth + Storage",
|
|
8499
8529
|
value: "supabase"
|
|
8500
8530
|
}
|
|
8501
|
-
]
|
|
8531
|
+
],
|
|
8532
|
+
choicesFilter: (answers) => {
|
|
8533
|
+
const functions = answers.functions ?? "none";
|
|
8534
|
+
if (functions === "firebase") return ["none", "firebase"];
|
|
8535
|
+
if (functions === "supabase") return ["none", "supabase"];
|
|
8536
|
+
if (functions === "vercel") return ["none"];
|
|
8537
|
+
return ["none", "firebase", "supabase"];
|
|
8538
|
+
}
|
|
8502
8539
|
}
|
|
8503
8540
|
];
|
|
8504
8541
|
var PROJECT_QUESTIONNAIRE = [
|
|
@@ -8516,12 +8553,13 @@ var PROJECT_QUESTIONNAIRE = [
|
|
|
8516
8553
|
}
|
|
8517
8554
|
];
|
|
8518
8555
|
function aggregateRequirements(answers) {
|
|
8556
|
+
const hasBackend = answers.backend && answers.backend !== "none" || answers.functions && answers.functions !== "none";
|
|
8519
8557
|
const requirements = {
|
|
8520
8558
|
entities: [],
|
|
8521
8559
|
// Entities created in apps/<app>/entities/ (v1), root entities/ for v2
|
|
8522
8560
|
billing: true,
|
|
8523
8561
|
// Always on (useStripeBillingSafe handles missing package)
|
|
8524
|
-
backend:
|
|
8562
|
+
backend: hasBackend,
|
|
8525
8563
|
features: [],
|
|
8526
8564
|
template: "vite",
|
|
8527
8565
|
// Only Vite for now
|
|
@@ -8545,6 +8583,10 @@ async function runQuestionnaire(questions, initialAnswers, showWIP, askFor) {
|
|
|
8545
8583
|
if (!showWIP) {
|
|
8546
8584
|
choices = choices.filter((choice) => !choice.wip);
|
|
8547
8585
|
}
|
|
8586
|
+
if (question.choicesFilter) {
|
|
8587
|
+
const allowed = question.choicesFilter(answers);
|
|
8588
|
+
choices = choices.filter((c) => allowed.includes(c.value));
|
|
8589
|
+
}
|
|
8548
8590
|
if (choices.length === 0) continue;
|
|
8549
8591
|
answer = await askFor.selection(question.question, choices);
|
|
8550
8592
|
break;
|
|
@@ -8745,34 +8787,22 @@ init_pathResolver();
|
|
|
8745
8787
|
|
|
8746
8788
|
// packages/tooling/src/scaffolding/scaffold-matrix.ts
|
|
8747
8789
|
init_utils();
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
{ builder: "nextjs", backend: "none", baseTemplate: "app-next", overlay: null, deployConfig: null, functionsTemplate: null },
|
|
8754
|
-
{ builder: "nextjs", backend: "firebase", baseTemplate: "app-next", overlay: "overlay-firebase", deployConfig: "firebase", functionsTemplate: "functions-firebase" },
|
|
8755
|
-
{ builder: "nextjs", backend: "supabase", baseTemplate: "app-next", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate: "functions-supabase" },
|
|
8756
|
-
{ builder: "nextjs", backend: "vercel", baseTemplate: "app-next", overlay: "overlay-vercel", deployConfig: "vercel-vercel", functionsTemplate: "functions-vercel" },
|
|
8757
|
-
{ builder: "expo", backend: "none", baseTemplate: "app-expo", overlay: null, deployConfig: null, functionsTemplate: null },
|
|
8758
|
-
{ builder: "expo", backend: "firebase", baseTemplate: "app-expo", overlay: "overlay-firebase", deployConfig: null, functionsTemplate: "functions-firebase" },
|
|
8759
|
-
{ builder: "expo", backend: "supabase", baseTemplate: "app-expo", overlay: "overlay-supabase", deployConfig: null, functionsTemplate: "functions-supabase" },
|
|
8760
|
-
{ builder: "demo", backend: "none", baseTemplate: "app-demo", overlay: null, deployConfig: null, functionsTemplate: null }
|
|
8761
|
-
];
|
|
8762
|
-
function comboKey(builder, backend) {
|
|
8763
|
-
return `${builder}-${backend}`;
|
|
8764
|
-
}
|
|
8765
|
-
var ROWS_BY_KEY = /* @__PURE__ */ new Map();
|
|
8766
|
-
for (const row of MATRIX) {
|
|
8767
|
-
ROWS_BY_KEY.set(comboKey(row.builder, row.backend), row);
|
|
8790
|
+
function resolveDeployConfig(host, backend) {
|
|
8791
|
+
if (host === "none") return null;
|
|
8792
|
+
if (host === "firebase") return "firebase";
|
|
8793
|
+
if (backend === "supabase") return "vercel-supabase";
|
|
8794
|
+
return "vercel-vercel";
|
|
8768
8795
|
}
|
|
8769
|
-
function
|
|
8770
|
-
const
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8796
|
+
function getScaffoldParts(builder, host, functions, backend) {
|
|
8797
|
+
const baseTemplate = builder === "nextjs" ? "app-next" : builder === "demo" ? "app-demo" : `app-${builder}`;
|
|
8798
|
+
return {
|
|
8799
|
+
builder,
|
|
8800
|
+
backend,
|
|
8801
|
+
baseTemplate,
|
|
8802
|
+
overlay: backend !== "none" ? `overlay-${backend}` : null,
|
|
8803
|
+
deployConfig: resolveDeployConfig(host, backend),
|
|
8804
|
+
functionsTemplate: functions !== "none" ? `functions-${functions}` : null
|
|
8805
|
+
};
|
|
8776
8806
|
}
|
|
8777
8807
|
|
|
8778
8808
|
// packages/tooling/src/scaffolding/create-app.ts
|
|
@@ -8812,11 +8842,15 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
8812
8842
|
input: askForInput
|
|
8813
8843
|
});
|
|
8814
8844
|
const requirements = aggregateRequirements(answers);
|
|
8815
|
-
const
|
|
8845
|
+
const framework = answers.framework || "vite";
|
|
8846
|
+
const host2 = answers.host || "none";
|
|
8847
|
+
const functions2 = answers.functions || "none";
|
|
8848
|
+
const backend2 = answers.backend || "none";
|
|
8816
8849
|
appConfig = {
|
|
8817
|
-
template:
|
|
8818
|
-
|
|
8819
|
-
|
|
8850
|
+
template: framework,
|
|
8851
|
+
host: host2,
|
|
8852
|
+
functions: functions2,
|
|
8853
|
+
backend: backend2,
|
|
8820
8854
|
needsCRUD: true,
|
|
8821
8855
|
// Always on
|
|
8822
8856
|
selectedEntities: [],
|
|
@@ -8862,12 +8896,14 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
8862
8896
|
s.start(`Creating app: ${appName}`);
|
|
8863
8897
|
await ensureDir(appDir);
|
|
8864
8898
|
const builder = appTemplate;
|
|
8865
|
-
const
|
|
8866
|
-
const
|
|
8899
|
+
const host = appConfig.host ?? "none";
|
|
8900
|
+
const functions = appConfig.functions ?? "none";
|
|
8901
|
+
const backend = appConfig.backend ?? "none";
|
|
8902
|
+
const row = getScaffoldParts(builder, host, functions, backend);
|
|
8867
8903
|
const templateDir = row.baseTemplate;
|
|
8868
8904
|
const firebaseProjectId = (appConfig?.firebaseProjectId ?? "").trim() || appName.toLowerCase().replace(/\s+/g, "-");
|
|
8869
8905
|
const firebaseRegion = appConfig?.firebaseRegion ?? "europe-west1";
|
|
8870
|
-
const backendPlatform =
|
|
8906
|
+
const backendPlatform = backend !== "none" ? backend : "firebase";
|
|
8871
8907
|
const deployConfig = row.deployConfig;
|
|
8872
8908
|
const replacements = {
|
|
8873
8909
|
projectName: appName,
|
|
@@ -8926,13 +8962,16 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
8926
8962
|
const variantFile = `src/config/providers.${appTemplate}.ts.example`;
|
|
8927
8963
|
if (overlayFiles.includes(variantFile)) continue;
|
|
8928
8964
|
}
|
|
8929
|
-
const providersVariant = file.match(
|
|
8965
|
+
const providersVariant = file.match(
|
|
8966
|
+
/^src\/config\/providers\.(\w+)\.ts\.example$/
|
|
8967
|
+
);
|
|
8930
8968
|
if (providersVariant) {
|
|
8931
8969
|
if (providersVariant[1] !== appTemplate) continue;
|
|
8932
8970
|
const destPath2 = joinPath(appDir, "src/config/providers.ts");
|
|
8933
8971
|
await ensureDir(getDirname(destPath2));
|
|
8934
8972
|
await copy(joinPath(overlayDir, file), destPath2, { overwrite: true });
|
|
8935
|
-
if (await isTextFile(destPath2))
|
|
8973
|
+
if (await isTextFile(destPath2))
|
|
8974
|
+
await replacePlaceholders(destPath2, replacements);
|
|
8936
8975
|
continue;
|
|
8937
8976
|
}
|
|
8938
8977
|
const sourcePath = joinPath(overlayDir, file);
|
|
@@ -8957,16 +8996,28 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
8957
8996
|
}
|
|
8958
8997
|
if (deployConfig === "vercel-supabase") {
|
|
8959
8998
|
const vercelPath = joinPath(appDir, "vercel.json");
|
|
8960
|
-
const headersFragmentPath = joinPath(
|
|
8999
|
+
const headersFragmentPath = joinPath(
|
|
9000
|
+
overlayDir,
|
|
9001
|
+
"vercel.headers.example"
|
|
9002
|
+
);
|
|
8961
9003
|
const fullVercelPath = joinPath(overlayDir, "vercel.json.example");
|
|
8962
9004
|
if (pathExists(vercelPath) && pathExists(headersFragmentPath)) {
|
|
8963
9005
|
const vercelJson = readSync(vercelPath, { format: "json" });
|
|
8964
|
-
const headersFragment = readSync(headersFragmentPath, {
|
|
8965
|
-
|
|
8966
|
-
|
|
9006
|
+
const headersFragment = readSync(headersFragmentPath, {
|
|
9007
|
+
format: "json"
|
|
9008
|
+
});
|
|
9009
|
+
vercelJson.headers = [
|
|
9010
|
+
...vercelJson.headers ?? [],
|
|
9011
|
+
...headersFragment
|
|
9012
|
+
];
|
|
9013
|
+
await write(vercelPath, vercelJson, {
|
|
9014
|
+
format: "json",
|
|
9015
|
+
overwrite: true
|
|
9016
|
+
});
|
|
8967
9017
|
} else if (pathExists(fullVercelPath)) {
|
|
8968
9018
|
await copy(fullVercelPath, vercelPath);
|
|
8969
|
-
if (await isTextFile(vercelPath))
|
|
9019
|
+
if (await isTextFile(vercelPath))
|
|
9020
|
+
await replacePlaceholders(vercelPath, replacements);
|
|
8970
9021
|
}
|
|
8971
9022
|
}
|
|
8972
9023
|
}
|
|
@@ -8986,9 +9037,13 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
8986
9037
|
});
|
|
8987
9038
|
if (row.functionsTemplate) {
|
|
8988
9039
|
const functionsTemplateName = row.functionsTemplate;
|
|
8989
|
-
const functionsTemplateExists = pathExists(
|
|
9040
|
+
const functionsTemplateExists = pathExists(
|
|
9041
|
+
joinPath(templatesRoot, functionsTemplateName)
|
|
9042
|
+
);
|
|
8990
9043
|
if (!functionsTemplateExists) {
|
|
8991
|
-
log.warn(
|
|
9044
|
+
log.warn(
|
|
9045
|
+
`Functions template "${functionsTemplateName}" not found \u2014 skipping functions scaffolding.`
|
|
9046
|
+
);
|
|
8992
9047
|
} else {
|
|
8993
9048
|
const isSupabaseFunctions = functionsTemplateName === "functions-supabase";
|
|
8994
9049
|
const functionsRootDir = isSupabaseFunctions ? appDir : joinPath(appDir, "functions");
|
|
@@ -8996,7 +9051,10 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
8996
9051
|
const functionsPackageJson = generatePackageJson(
|
|
8997
9052
|
functionsTemplateName,
|
|
8998
9053
|
executionMode,
|
|
8999
|
-
{
|
|
9054
|
+
{
|
|
9055
|
+
appName,
|
|
9056
|
+
platform: row.functionsTemplate.replace("functions-", "")
|
|
9057
|
+
}
|
|
9000
9058
|
);
|
|
9001
9059
|
const packageJsonPath2 = joinPath(functionsRootDir, "package.json");
|
|
9002
9060
|
await ensureDir(functionsRootDir);
|
|
@@ -9032,13 +9090,19 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
9032
9090
|
}
|
|
9033
9091
|
const deploymentTemplateDir = joinPath(templatesRoot, "root-consumer");
|
|
9034
9092
|
if (deployConfig === "firebase") {
|
|
9035
|
-
const firebaseJsonSource = joinPath(
|
|
9093
|
+
const firebaseJsonSource = joinPath(
|
|
9094
|
+
deploymentTemplateDir,
|
|
9095
|
+
"firebase.json.example"
|
|
9096
|
+
);
|
|
9036
9097
|
if (pathExists(firebaseJsonSource)) {
|
|
9037
9098
|
await copy(firebaseJsonSource, joinPath(appDir, "firebase.json"));
|
|
9038
9099
|
const firebaseJsonDest = joinPath(appDir, "firebase.json");
|
|
9039
|
-
if (await isTextFile(firebaseJsonDest))
|
|
9100
|
+
if (await isTextFile(firebaseJsonDest))
|
|
9101
|
+
await replacePlaceholders(firebaseJsonDest, replacements);
|
|
9040
9102
|
if (appTemplate === "nextjs") {
|
|
9041
|
-
const firebaseJson = readSync(firebaseJsonDest, {
|
|
9103
|
+
const firebaseJson = readSync(firebaseJsonDest, {
|
|
9104
|
+
format: "json"
|
|
9105
|
+
});
|
|
9042
9106
|
if (firebaseJson.hosting?.rewrites) {
|
|
9043
9107
|
firebaseJson.hosting.rewrites = firebaseJson.hosting.rewrites.filter(
|
|
9044
9108
|
(r2) => r2.destination !== "/index.html"
|
|
@@ -9047,17 +9111,28 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
9047
9111
|
if (firebaseJson.hosting) {
|
|
9048
9112
|
firebaseJson.hosting.public = "out";
|
|
9049
9113
|
}
|
|
9050
|
-
await write(firebaseJsonDest, firebaseJson, {
|
|
9114
|
+
await write(firebaseJsonDest, firebaseJson, {
|
|
9115
|
+
format: "json",
|
|
9116
|
+
overwrite: true
|
|
9117
|
+
});
|
|
9051
9118
|
}
|
|
9052
9119
|
}
|
|
9053
|
-
const firebasercSource = joinPath(
|
|
9120
|
+
const firebasercSource = joinPath(
|
|
9121
|
+
deploymentTemplateDir,
|
|
9122
|
+
".firebaserc.example"
|
|
9123
|
+
);
|
|
9054
9124
|
if (pathExists(firebasercSource)) {
|
|
9055
9125
|
await copy(firebasercSource, joinPath(appDir, ".firebaserc"));
|
|
9056
9126
|
const firebasercDest = joinPath(appDir, ".firebaserc");
|
|
9057
|
-
if (await isTextFile(firebasercDest))
|
|
9127
|
+
if (await isTextFile(firebasercDest))
|
|
9128
|
+
await replacePlaceholders(firebasercDest, replacements);
|
|
9058
9129
|
}
|
|
9059
9130
|
if (row.functionsTemplate === "functions-firebase") {
|
|
9060
|
-
for (const example of [
|
|
9131
|
+
for (const example of [
|
|
9132
|
+
"firestore.rules.example",
|
|
9133
|
+
"firestore.indexes.json.example",
|
|
9134
|
+
"storage.rules.example"
|
|
9135
|
+
]) {
|
|
9061
9136
|
const src = joinPath(deploymentTemplateDir, example);
|
|
9062
9137
|
if (pathExists(src)) {
|
|
9063
9138
|
await copy(src, joinPath(appDir, example.replace(".example", "")));
|
|
@@ -9073,11 +9148,22 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
9073
9148
|
{
|
|
9074
9149
|
source: "functions",
|
|
9075
9150
|
codebase: "default",
|
|
9076
|
-
ignore: [
|
|
9151
|
+
ignore: [
|
|
9152
|
+
"node_modules",
|
|
9153
|
+
".git",
|
|
9154
|
+
"firebase-debug.log",
|
|
9155
|
+
"firebase-debug.*.log",
|
|
9156
|
+
"**/.*",
|
|
9157
|
+
"**/*.test.ts",
|
|
9158
|
+
"**/__tests__/**"
|
|
9159
|
+
],
|
|
9077
9160
|
runtime: "nodejs22"
|
|
9078
9161
|
}
|
|
9079
9162
|
],
|
|
9080
|
-
firestore: {
|
|
9163
|
+
firestore: {
|
|
9164
|
+
rules: "firestore.rules",
|
|
9165
|
+
indexes: "firestore.indexes.json"
|
|
9166
|
+
},
|
|
9081
9167
|
storage: { rules: "storage.rules" },
|
|
9082
9168
|
emulators: {
|
|
9083
9169
|
auth: { port: 9099 },
|
|
@@ -9087,15 +9173,26 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
9087
9173
|
ui: { enabled: true, port: 4e3 }
|
|
9088
9174
|
}
|
|
9089
9175
|
};
|
|
9090
|
-
await write(firebaseJsonPath, expoFirebaseJson, {
|
|
9176
|
+
await write(firebaseJsonPath, expoFirebaseJson, {
|
|
9177
|
+
format: "json",
|
|
9178
|
+
overwrite: true
|
|
9179
|
+
});
|
|
9091
9180
|
}
|
|
9092
|
-
const firebasercSource = joinPath(
|
|
9181
|
+
const firebasercSource = joinPath(
|
|
9182
|
+
deploymentTemplateDir,
|
|
9183
|
+
".firebaserc.example"
|
|
9184
|
+
);
|
|
9093
9185
|
const firebasercDest = joinPath(appDir, ".firebaserc");
|
|
9094
9186
|
if (pathExists(firebasercSource) && !pathExists(firebasercDest)) {
|
|
9095
9187
|
await copy(firebasercSource, firebasercDest);
|
|
9096
|
-
if (await isTextFile(firebasercDest))
|
|
9097
|
-
|
|
9098
|
-
|
|
9188
|
+
if (await isTextFile(firebasercDest))
|
|
9189
|
+
await replacePlaceholders(firebasercDest, replacements);
|
|
9190
|
+
}
|
|
9191
|
+
for (const example of [
|
|
9192
|
+
"firestore.rules.example",
|
|
9193
|
+
"firestore.indexes.json.example",
|
|
9194
|
+
"storage.rules.example"
|
|
9195
|
+
]) {
|
|
9099
9196
|
const src = joinPath(deploymentTemplateDir, example);
|
|
9100
9197
|
const dest = joinPath(appDir, example.replace(".example", ""));
|
|
9101
9198
|
if (pathExists(src) && !pathExists(dest)) {
|
|
@@ -9104,11 +9201,15 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
9104
9201
|
}
|
|
9105
9202
|
}
|
|
9106
9203
|
if (deployConfig === "vercel-vercel") {
|
|
9107
|
-
const vercelJsonSource = joinPath(
|
|
9204
|
+
const vercelJsonSource = joinPath(
|
|
9205
|
+
deploymentTemplateDir,
|
|
9206
|
+
"vercel.json.example"
|
|
9207
|
+
);
|
|
9108
9208
|
if (pathExists(vercelJsonSource)) {
|
|
9109
9209
|
await copy(vercelJsonSource, joinPath(appDir, "vercel.json"));
|
|
9110
9210
|
const vercelJsonDest = joinPath(appDir, "vercel.json");
|
|
9111
|
-
if (await isTextFile(vercelJsonDest))
|
|
9211
|
+
if (await isTextFile(vercelJsonDest))
|
|
9212
|
+
await replacePlaceholders(vercelJsonDest, replacements);
|
|
9112
9213
|
}
|
|
9113
9214
|
}
|
|
9114
9215
|
const backendInfo = row.functionsTemplate ? ` with ${row.functionsTemplate.replace("functions-", "")} functions` : "";
|
|
@@ -9140,11 +9241,13 @@ Happy coding!`,
|
|
|
9140
9241
|
}
|
|
9141
9242
|
async function main(options) {
|
|
9142
9243
|
try {
|
|
9143
|
-
const hasExplicitFlags = options?.builder !== void 0 || options?.functions !== void 0;
|
|
9244
|
+
const hasExplicitFlags = options?.builder !== void 0 || options?.host !== void 0 || options?.functions !== void 0 || options?.backend !== void 0;
|
|
9144
9245
|
if (hasExplicitFlags && options?.name) {
|
|
9145
9246
|
const appName = options.name;
|
|
9146
9247
|
const builder = options.builder || "vite";
|
|
9147
|
-
const
|
|
9248
|
+
const hostOpt = options.host ?? "none";
|
|
9249
|
+
const functionsOpt = options.functions ?? "none";
|
|
9250
|
+
const backendOpt = options.backend ?? "none";
|
|
9148
9251
|
if (!isValidFileName(appName)) {
|
|
9149
9252
|
throw new Error(
|
|
9150
9253
|
`Invalid app name "${appName}". Use only letters, numbers, dashes (-), and underscores (_).`
|
|
@@ -9157,8 +9260,9 @@ async function main(options) {
|
|
|
9157
9260
|
}
|
|
9158
9261
|
const appConfig = {
|
|
9159
9262
|
template: builder === "next" ? "nextjs" : builder === "expo" ? "expo" : "vite",
|
|
9160
|
-
|
|
9161
|
-
|
|
9263
|
+
host: hostOpt,
|
|
9264
|
+
functions: functionsOpt,
|
|
9265
|
+
backend: backendOpt,
|
|
9162
9266
|
needsCRUD: true,
|
|
9163
9267
|
selectedEntities: [],
|
|
9164
9268
|
userAuth: "social",
|