@django-stack/cli 0.9.0 → 0.11.0
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/dist/bin.js +65 -20
- package/dist/index.d.ts +24 -9
- package/dist/index.js +1 -1
- package/dist/{production-M2SsuuBb.js → production-WThC1aS2.js} +267 -30
- package/package.json +1 -1
- package/templates/backend/Dockerfile +7 -2
- package/templates/backend/config/settings.py +13 -0
- package/templates/backend/config/urls.py +11 -0
- package/templates/backend/content/admin.py +14 -5
- package/templates/backend/content/models.py +2 -2
- package/templates/backend/content/tests/test_api.py +15 -3
- package/templates/backend/pyproject.toml +1 -1
- package/templates/base/.github/workflows/deploy.yml +10 -1
- package/templates/base/AGENTS.md +86 -8
- package/templates/base/Caddyfile +24 -0
- package/templates/base/README.md +74 -6
- package/templates/base/SECURITY.md +2 -0
- package/templates/base/compose.yaml +28 -2
- package/templates/base/env.example +37 -0
- package/templates/frontend-astro/AGENTS.md +3 -3
- package/templates/frontend-astro/Dockerfile +6 -3
- package/templates/frontend-astro/astro.config.mjs +16 -5
- package/templates/frontend-astro/package.json +1 -1
- package/templates/frontend-astro/pnpm-workspace.yaml +17 -0
- package/templates/frontend-astro/src/components/ContactForm.astro +19 -3
- package/templates/frontend-astro/src/middleware.ts +9 -1
- package/templates/frontend-next/AGENTS.md +3 -3
- package/templates/frontend-next/Dockerfile +5 -2
- package/templates/frontend-next/package.json +3 -3
- package/templates/frontend-next/pnpm-workspace.yaml +11 -0
- package/templates/frontend-next/src/app/[...path]/page.tsx +2 -1
- package/templates/frontend-next/src/components/ContactForm.tsx +14 -3
- package/templates/frontend-next/src/instrumentation.ts +12 -0
- package/templates/frontend-next/src/proxy.ts +4 -1
- package/templates/frontend-nuxt/AGENTS.md +3 -3
- package/templates/frontend-nuxt/Dockerfile +5 -2
- package/templates/frontend-nuxt/nuxt.config.ts +7 -3
- package/templates/frontend-nuxt/package.json +2 -2
- package/templates/frontend-nuxt/pnpm-workspace.yaml +13 -0
- package/templates/frontend-nuxt/server/plugins/errors.ts +14 -0
- package/templates/frontend-nuxt/server/routes/_content/layout.get.ts +4 -0
- package/templates/frontend-nuxt/src/components/ContactForm.vue +15 -2
- package/templates/frontend-sveltekit/AGENTS.md +3 -3
- package/templates/frontend-sveltekit/Dockerfile +6 -3
- package/templates/frontend-sveltekit/package.json +2 -2
- package/templates/frontend-sveltekit/pnpm-workspace.yaml +11 -0
- package/templates/frontend-sveltekit/src/hooks.server.ts +13 -1
- package/templates/frontend-sveltekit/src/lib/components/ContactForm.svelte +15 -2
- package/templates/frontend-sveltekit/src/routes/+layout.server.ts +3 -0
- package/templates/frontend-sveltekit/src/routes/[...path]/+page.svelte +1 -1
- package/templates/frontend-sveltekit/vite.config.ts +10 -3
- package/templates/frontend-templates/template.json +5 -0
- package/templates/frontend-templates/website/__init__.py +0 -0
- package/templates/frontend-templates/website/apps.py +6 -0
- package/templates/frontend-templates/website/context_processors.py +16 -0
- package/templates/frontend-templates/website/forms.py +20 -0
- package/templates/frontend-templates/website/static/website/favicon.svg +1 -0
- package/templates/frontend-templates/website/static/website/global.css +232 -0
- package/templates/frontend-templates/website/templates/website/404.html +10 -0
- package/templates/frontend-templates/website/templates/website/base.html +44 -0
- package/templates/frontend-templates/website/templates/website/blocks/call_to_action.html +5 -0
- package/templates/frontend-templates/website/templates/website/blocks/image.html +4 -0
- package/templates/frontend-templates/website/templates/website/blocks/quote.html +4 -0
- package/templates/frontend-templates/website/templates/website/blocks/text.html +2 -0
- package/templates/frontend-templates/website/templates/website/home.html +8 -0
- package/templates/frontend-templates/website/templates/website/includes/contact_form.html +21 -0
- package/templates/frontend-templates/website/templates/website/includes/post_card.html +9 -0
- package/templates/frontend-templates/website/templates/website/includes/post_list.html +11 -0
- package/templates/frontend-templates/website/templates/website/page.html +10 -0
- package/templates/frontend-templates/website/templates/website/post.html +20 -0
- package/templates/frontend-templates/website/templates/website/post_list.html +11 -0
- package/templates/frontend-templates/website/templates/website/robots.txt +5 -0
- package/templates/frontend-templates/website/templates/website/rss.xml +16 -0
- package/templates/frontend-templates/website/templates/website/sitemap.xml +8 -0
- package/templates/frontend-templates/website/tests/__init__.py +0 -0
- package/templates/frontend-templates/website/tests/test_site.py +102 -0
- package/templates/frontend-templates/website/urls.py +17 -0
- package/templates/frontend-templates/website/views.py +176 -0
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as envPorts, A as compose, B as NAMED_PRESETS, C as PACKAGE_NAME, D as RUN_DOMAIN, E as CAPTCHA_APP, F as projectUrls, H as PROMPT_ORDER, I as readLocalRun, J as resolvePreset, K as encodePreset, L as readProject, M as findProjectDirectory, N as parseProfiles, O as RUN_ENV, P as projectStack, Q as describeMove, R as runningServices, S as CLI_VERSION, T as generateSecret, U as STACK_OPTIONS, V as NODE_FRONTENDS, W as applies, X as DEV_PORTS, Y as stackOption, Z as chooseFreePorts, _ as umamiEnv, a as LOCAL_S3, at as isDockerDown, b as validateProjectName, c as localS3, ct as setEnvValues, et as portValues, f as relativeDirectory, g as toProjectName, h as timeZones, it as dockerRunning, j as composeOutput, k as activeProject, l as lockBackend, m as setNotificationsApp, n as productionEnv$1, nt as checkTools, o as cacheEnv, ot as parseEnv, p as scaffold, q as pendingChoices, r as validateDomain, rt as dockerNotRunning, s as frontendPackageManager, st as quoteEnvValue, t as missingS3, tt as runDoctor, u as lockFrontend, v as updateFrontendLock, w as generateProjectSecrets, x as validateTimeZone, y as usesValkey, z as DEFAULT_STACK } from "./production-WThC1aS2.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { basename, delimiter, dirname, join, posix, relative, resolve, sep } from "node:path";
|
|
@@ -3930,7 +3930,8 @@ function choices(key, stack = {}) {
|
|
|
3930
3930
|
/**
|
|
3931
3931
|
* The stack from, in order of precedence, the flags, the preset, the prompts
|
|
3932
3932
|
* and the defaults. `askDatabase` asks for the Postgres version together with
|
|
3933
|
-
* the external database choice; it returns the version,
|
|
3933
|
+
* the external database choice; it returns the version, and the URL for
|
|
3934
|
+
* production when there is one.
|
|
3934
3935
|
*/
|
|
3935
3936
|
async function chooseStack(options, interactive, askDatabase) {
|
|
3936
3937
|
let preset;
|
|
@@ -3949,10 +3950,9 @@ async function chooseStack(options, interactive, askDatabase) {
|
|
|
3949
3950
|
else if (!interactive || !applies(key, stack)) continue;
|
|
3950
3951
|
else if (key === "postgres" && askDatabase && !options.databaseUrl) {
|
|
3951
3952
|
const answer = await askDatabase(stack[key]);
|
|
3952
|
-
if (
|
|
3953
|
-
|
|
3954
|
-
} else
|
|
3955
|
-
else {
|
|
3953
|
+
if (answer.databaseUrl) databaseUrl = answer.databaseUrl;
|
|
3954
|
+
stack[key] = answer.postgres;
|
|
3955
|
+
} else {
|
|
3956
3956
|
const initialValue = key === "storage" && stack.media === "s3" ? "s3" : stack[key];
|
|
3957
3957
|
stack[key] = unwrap(await p.select({
|
|
3958
3958
|
message: option.message,
|
|
@@ -4018,19 +4018,31 @@ async function init(directoryArgument, options) {
|
|
|
4018
4018
|
label: `Bundled Postgres, ${value.label.toLowerCase()}`
|
|
4019
4019
|
})), {
|
|
4020
4020
|
value: "external",
|
|
4021
|
-
label: "External Postgres",
|
|
4022
|
-
hint: "a URL to your
|
|
4021
|
+
label: "External Postgres in production",
|
|
4022
|
+
hint: "a URL to your server; development runs the bundled one"
|
|
4023
4023
|
}]
|
|
4024
4024
|
}));
|
|
4025
4025
|
if (choice !== "external") return { postgres: choice };
|
|
4026
|
-
|
|
4027
|
-
message: "Postgres URL",
|
|
4026
|
+
const databaseUrl = unwrap(await p.text({
|
|
4027
|
+
message: "Postgres URL for production",
|
|
4028
4028
|
placeholder: "postgres://user:password@host:5432/name",
|
|
4029
4029
|
validate: (value) => value?.startsWith("postgres") ? void 0 : "Enter a postgres:// URL."
|
|
4030
|
-
}))
|
|
4030
|
+
}));
|
|
4031
|
+
return {
|
|
4032
|
+
postgres: unwrap(await p.select({
|
|
4033
|
+
message: "Its Postgres version",
|
|
4034
|
+
initialValue: initial,
|
|
4035
|
+
options: choices("postgres")
|
|
4036
|
+
})),
|
|
4037
|
+
databaseUrl
|
|
4038
|
+
};
|
|
4031
4039
|
});
|
|
4032
4040
|
const stack = chosen.stack;
|
|
4033
4041
|
const databaseUrl = options.databaseUrl ?? chosen.databaseUrl;
|
|
4042
|
+
if (!applies("analytics", stack) && stack.analytics !== "off") {
|
|
4043
|
+
if (options.fromCli("analytics")) fail("--analytics umami needs a frontend: a headless project has no pages to count.");
|
|
4044
|
+
stack.analytics = "off";
|
|
4045
|
+
}
|
|
4034
4046
|
const pending = pendingChoices(stack);
|
|
4035
4047
|
const unavailable = pending.filter((item) => !item.isDefault);
|
|
4036
4048
|
if (unavailable.length) fail(`${unavailable.map((item) => item.choice).join(", ")} ${unavailable.length > 1 ? "are" : "is"} not available yet. Leave ${unavailable.length > 1 ? "them" : "it"} at the default.`);
|
|
@@ -4066,10 +4078,13 @@ async function init(directoryArgument, options) {
|
|
|
4066
4078
|
frontend: stack.frontend,
|
|
4067
4079
|
demoContent,
|
|
4068
4080
|
databaseUrl,
|
|
4081
|
+
postgres: stack.postgres,
|
|
4069
4082
|
localS3: stack.storage === "s3",
|
|
4070
4083
|
analytics: stack.analytics === "umami",
|
|
4071
4084
|
cache: stack.cache,
|
|
4072
4085
|
notifications: stack.notifications === "on",
|
|
4086
|
+
captcha: stack.captcha === "on",
|
|
4087
|
+
packageManager: stack.packageManager,
|
|
4073
4088
|
errors: stack.errors,
|
|
4074
4089
|
tasks: stack.tasks,
|
|
4075
4090
|
preset: encodePreset(stack),
|
|
@@ -4087,6 +4102,16 @@ async function init(directoryArgument, options) {
|
|
|
4087
4102
|
if (lockBackend(target)) spinner.stop(`Locked the backend dependencies in ${pc.bold("backend/uv.lock")}`);
|
|
4088
4103
|
else spinner.error("Could not lock the backend dependencies. The image build resolves them instead.");
|
|
4089
4104
|
}
|
|
4105
|
+
if (NODE_FRONTENDS.includes(stack.frontend)) {
|
|
4106
|
+
const lockfile = {
|
|
4107
|
+
pnpm: "pnpm-lock.yaml",
|
|
4108
|
+
npm: "package-lock.json",
|
|
4109
|
+
bun: "bun.lock"
|
|
4110
|
+
}[stack.packageManager];
|
|
4111
|
+
spinner.start(`Locking the frontend dependencies with ${stack.packageManager}`);
|
|
4112
|
+
if (lockFrontend(target, stack.packageManager)) spinner.stop(`Locked the frontend dependencies in ${pc.bold(`frontend/${lockfile}`)}`);
|
|
4113
|
+
else spinner.error("Could not lock the frontend dependencies. The image build resolves them instead.");
|
|
4114
|
+
}
|
|
4090
4115
|
if (options.git && has("git")) try {
|
|
4091
4116
|
execFileSync("git", ["init", "--quiet"], {
|
|
4092
4117
|
cwd: target,
|
|
@@ -4115,7 +4140,7 @@ async function init(directoryArgument, options) {
|
|
|
4115
4140
|
command(`cd ${relativeDirectory(target)}`),
|
|
4116
4141
|
command(startCommand),
|
|
4117
4142
|
"",
|
|
4118
|
-
`${pc.bold("Site")} ${url(`http://localhost:${ports.ports.SITE_PORT}`)}`,
|
|
4143
|
+
stack.frontend === "headless" ? `${pc.bold("API")} ${url(`http://localhost:${ports.ports.SITE_PORT}/api/`)}` : `${pc.bold("Site")} ${url(`http://localhost:${ports.ports.SITE_PORT}`)}`,
|
|
4119
4144
|
`${pc.bold("Admin")} ${url(`http://localhost:${ports.ports.SITE_PORT}/admin/`)}`,
|
|
4120
4145
|
`${pc.bold("Mail")} ${url(`http://localhost:${ports.ports.MAIL_PORT}`)}`,
|
|
4121
4146
|
"",
|
|
@@ -4512,7 +4537,8 @@ const SWITCHABLE = [
|
|
|
4512
4537
|
"media",
|
|
4513
4538
|
"cache",
|
|
4514
4539
|
"tasks",
|
|
4515
|
-
"notifications"
|
|
4540
|
+
"notifications",
|
|
4541
|
+
"captcha"
|
|
4516
4542
|
];
|
|
4517
4543
|
const EMPTY_S3 = Object.fromEntries(Object.keys(LOCAL_S3).map((key) => [key, key === "S3_CREATE_BUCKET" ? "0" : ""]));
|
|
4518
4544
|
/**
|
|
@@ -4528,6 +4554,7 @@ function applyStack(envText, env, from, to) {
|
|
|
4528
4554
|
if (from[key] === to[key]) continue;
|
|
4529
4555
|
const value = option.values.find((candidate) => candidate.value === to[key]);
|
|
4530
4556
|
if (!value) throw new Error(`${JSON.stringify(to[key])} is not a ${option.key}.`);
|
|
4557
|
+
if (key === "postgres") throw new Error("--postgres can't change on an existing project: a new major version needs a backup and a restore. See the docs on backups.");
|
|
4531
4558
|
if (!SWITCHABLE.includes(key) || !value.generated) throw new Error(`${option.flag} ${to[key]} can't be set on an existing project in this version yet.`);
|
|
4532
4559
|
if (key === "storage") {
|
|
4533
4560
|
if (profiles.includes("prod")) throw new Error("--storage only changes development; this .env runs the prod profile.");
|
|
@@ -4580,6 +4607,10 @@ function applyStack(envText, env, from, to) {
|
|
|
4580
4607
|
}
|
|
4581
4608
|
}
|
|
4582
4609
|
if (key === "notifications") changes.push(to.notifications === "on" ? "Notifications are on: content_studio.notifications is in INSTALLED_APPS." : "Notifications are off: content_studio.notifications is out of INSTALLED_APPS; its tables stay.");
|
|
4610
|
+
if (key === "captcha") {
|
|
4611
|
+
text = setEnvValues(text, { CAPTCHA: to.captcha });
|
|
4612
|
+
changes.push(to.captcha === "on" ? "The captcha of the contact form is on." : "The captcha is off: public forms need no captcha token.");
|
|
4613
|
+
}
|
|
4583
4614
|
if (key === "media") changes.push(to.media === "s3" ? "Uploads in production go to S3; dstack settings asks for the S3 settings." : "Uploads in production stay on the server.");
|
|
4584
4615
|
}
|
|
4585
4616
|
return {
|
|
@@ -4622,7 +4653,8 @@ function ensureRunEnv(project) {
|
|
|
4622
4653
|
if (!existsSync(path)) {
|
|
4623
4654
|
const result = productionEnv$1(readFileSync(join(project.directory, ".env"), "utf8"), {
|
|
4624
4655
|
domain: RUN_DOMAIN,
|
|
4625
|
-
emailUrl: "console://"
|
|
4656
|
+
emailUrl: "console://",
|
|
4657
|
+
bundledDatabase: true
|
|
4626
4658
|
});
|
|
4627
4659
|
writeFileSync(path, result.text, { mode: 384 });
|
|
4628
4660
|
p.log.success(`Wrote ${pc.bold(RUN_ENV)}: the prod profile at ${url(`https://${RUN_DOMAIN}`)}, with its own secrets and data.`);
|
|
@@ -4678,7 +4710,8 @@ async function dev(options) {
|
|
|
4678
4710
|
intro("Develop");
|
|
4679
4711
|
project = await freeDevPorts(project);
|
|
4680
4712
|
urlsNote(project, "Starting");
|
|
4681
|
-
|
|
4713
|
+
const reloads = project.services.frontend ? "backend/ and frontend/" : "backend/";
|
|
4714
|
+
p.log.message(pc.dim(`Changes in ${reloads} reload. Press Ctrl+C to stop.`));
|
|
4682
4715
|
exitWith(compose(project, ["up", ...options.build ? ["--build"] : []]));
|
|
4683
4716
|
}
|
|
4684
4717
|
/** `dstack stop`: stop the containers of the project and of its local run; volumes and data stay. */
|
|
@@ -4827,6 +4860,10 @@ async function types(options) {
|
|
|
4827
4860
|
"--file",
|
|
4828
4861
|
"openapi.json"
|
|
4829
4862
|
], false)) !== 0) fail("The backend could not write its schema.");
|
|
4863
|
+
if (!project.services.frontend) {
|
|
4864
|
+
p.outro(`Wrote ${pc.bold("backend/openapi.json")}`);
|
|
4865
|
+
return;
|
|
4866
|
+
}
|
|
4830
4867
|
const generate = [
|
|
4831
4868
|
"npx",
|
|
4832
4869
|
"headless",
|
|
@@ -4914,7 +4951,7 @@ function checkSteps(project, tests) {
|
|
|
4914
4951
|
],
|
|
4915
4952
|
devOnly: true
|
|
4916
4953
|
});
|
|
4917
|
-
return steps.filter((step) => !(step.devOnly && project.prod));
|
|
4954
|
+
return steps.filter((step) => !(step.devOnly && project.prod) && (step.service !== "frontend" || project.services.frontend));
|
|
4918
4955
|
}
|
|
4919
4956
|
/** `dstack check`: the doctor's checks, Django's checks, the linters and, with --tests, the tests. */
|
|
4920
4957
|
async function check(options) {
|
|
@@ -4998,6 +5035,11 @@ async function update(options) {
|
|
|
4998
5035
|
}).status !== 0) fail("uv could not update backend/uv.lock.");
|
|
4999
5036
|
p.log.success(options.all ? "Updated backend/uv.lock" : "Updated django-stack in backend/uv.lock");
|
|
5000
5037
|
} else if (existsSync(lock)) p.log.warn("uv is not installed, so backend/uv.lock stays as it is: https://docs.astral.sh/uv/");
|
|
5038
|
+
if (frontendPackageManager(project.directory)) {
|
|
5039
|
+
const lockfile = updateFrontendLock(project.directory, options.all);
|
|
5040
|
+
if (!lockfile) fail("The package manager could not update the frontend's lockfile.");
|
|
5041
|
+
p.log.success(options.all ? `Updated frontend/${lockfile}` : `Updated the @django-stack packages in frontend/${lockfile}`);
|
|
5042
|
+
}
|
|
5001
5043
|
for (const target of targets) {
|
|
5002
5044
|
if (compose(target, ["pull", "--ignore-buildable"]) !== 0) fail("Pulling the images failed.");
|
|
5003
5045
|
const build = [
|
|
@@ -5007,8 +5049,8 @@ async function update(options) {
|
|
|
5007
5049
|
];
|
|
5008
5050
|
if (compose(target, build) !== 0) fail("Building the images failed.");
|
|
5009
5051
|
}
|
|
5010
|
-
const volume = project.prod ? void 0 : nodeModulesVolume(project);
|
|
5011
|
-
if (volume) {
|
|
5052
|
+
const volume = project.prod || !project.services.frontend ? void 0 : nodeModulesVolume(project);
|
|
5053
|
+
if (volume && project.services.frontend) {
|
|
5012
5054
|
compose(project, [
|
|
5013
5055
|
"rm",
|
|
5014
5056
|
"--stop",
|
|
@@ -5058,6 +5100,9 @@ async function config(options) {
|
|
|
5058
5100
|
if (!existsSync(compose) || !/^ {2}umami:/m.test(readFileSync(compose, "utf8"))) fail("compose.yaml has no umami service. Add it as the analytics docs describe, then run this again.");
|
|
5059
5101
|
}
|
|
5060
5102
|
const settingsPath = join(project.directory, "backend", "config", "settings.py");
|
|
5103
|
+
if (next.captcha === "on" && current.captcha !== "on") {
|
|
5104
|
+
if (!existsSync(settingsPath) || !CAPTCHA_APP.test(readFileSync(settingsPath, "utf8"))) fail("The backend has no django_stack.contrib.captcha. Add it and the widget as the captcha docs describe, then run this again.");
|
|
5105
|
+
}
|
|
5061
5106
|
let settingsText;
|
|
5062
5107
|
if (next.notifications !== current.notifications) {
|
|
5063
5108
|
if (!existsSync(settingsPath)) fail("This project has no backend/config/settings.py.");
|
|
@@ -5288,7 +5333,7 @@ function createProgram() {
|
|
|
5288
5333
|
styleArgumentText: (text) => pc.yellow(text),
|
|
5289
5334
|
styleDescriptionText: (text) => text
|
|
5290
5335
|
}).configureOutput({ outputError: (text, write) => write(pc.red(text)) });
|
|
5291
|
-
const initCommand = program.command("init").alias("create").description("Create a project").argument("[directory]", "Where to create the project").option("--name <name>", "The project name (default: from the directory)").option("--preset <preset>", `A preset code from a previous init, or ${Object.keys(NAMED_PRESETS).join(", ")}`).option("--database-url <url>", "
|
|
5336
|
+
const initCommand = program.command("init").alias("create").description("Create a project").argument("[directory]", "Where to create the project").option("--name <name>", "The project name (default: from the directory)").option("--preset <preset>", `A preset code from a previous init, or ${Object.keys(NAMED_PRESETS).join(", ")}`).option("--database-url <url>", "An external Postgres for production; development runs the bundled one").option("--time-zone <zone>", "The time zone of the backend, such as Europe/Amsterdam (default: UTC)").addOption(new Option("--local-s3", "Same as --storage s3").hideHelp()).option("--no-demo-content", "Start with an empty site").option("--no-git", "Don't create a git repository").option("--start", "Run `docker compose up` when done").option("-y, --yes", "Accept the defaults without asking").addOption(new Option("--link <repository>", "Take the packages from a DjangoStack checkout").hideHelp()).action((directory, options, cmd) => init(directory, {
|
|
5292
5337
|
...options,
|
|
5293
5338
|
installPrompt: program.opts().installPrompt,
|
|
5294
5339
|
fromCli: (option) => cmd.getOptionValueSource(option) === "cli"
|
|
@@ -5301,7 +5346,7 @@ function createProgram() {
|
|
|
5301
5346
|
program.command("logs").description("Show the logs of the services").argument("[services...]", "Only these services, such as backend").addOption(dirOption()).option("--no-follow", "Print the logs and exit").option("-n, --tail <lines>", "Only the last lines of each service").action(logs);
|
|
5302
5347
|
program.command("status").description("Show the containers and whether the database, cache, worker and backups are healthy").addOption(dirOption()).action(status);
|
|
5303
5348
|
program.command("check").description("Check the project: setup, Django checks, migrations and linters").addOption(dirOption()).option("--tests", "Run the backend and frontend tests too").action(check);
|
|
5304
|
-
program.command("update").description("Pull and rebuild the images and update the DjangoStack packages").addOption(dirOption()).option("--all", "Update every
|
|
5349
|
+
program.command("update").description("Pull and rebuild the images and update the DjangoStack packages").addOption(dirOption()).option("--all", "Update every package in the lockfiles, not only DjangoStack's").option("--no-cache", "Rebuild the images from scratch").option("--no-restart", "Don't restart what was running").action(update);
|
|
5305
5350
|
const configCommand = program.command("config").description("Change the stack options of a project").addOption(dirOption()).option("-y, --yes", "Don't ask; change only what the flags set").action((options, cmd) => config({
|
|
5306
5351
|
...options,
|
|
5307
5352
|
fromCli: (option) => cmd.getOptionValueSource(option) === "cli"
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ interface ProductionOptions {
|
|
|
20
20
|
emailUrl?: string;
|
|
21
21
|
/** Where uploads go: `s3` asks for the S3 settings (the `media` stack option). */
|
|
22
22
|
media?: string;
|
|
23
|
+
/** Keep the bundled database even with PRODUCTION_DATABASE_URL: the local run on this machine. */
|
|
24
|
+
bundledDatabase?: boolean;
|
|
23
25
|
}
|
|
24
26
|
interface ProductionEnv {
|
|
25
27
|
text: string;
|
|
@@ -54,12 +56,12 @@ export declare const STACK_OPTIONS: readonly [{
|
|
|
54
56
|
readonly value: "headless";
|
|
55
57
|
readonly label: "Headless";
|
|
56
58
|
readonly hint: "just the API and the admin";
|
|
57
|
-
readonly generated:
|
|
59
|
+
readonly generated: true;
|
|
58
60
|
}, {
|
|
59
61
|
readonly value: "templates";
|
|
60
62
|
readonly label: "Django templates";
|
|
61
63
|
readonly hint: "no Node, Django renders the site";
|
|
62
|
-
readonly generated:
|
|
64
|
+
readonly generated: true;
|
|
63
65
|
}, {
|
|
64
66
|
readonly value: "nuxt";
|
|
65
67
|
readonly label: "Nuxt";
|
|
@@ -86,7 +88,7 @@ export declare const STACK_OPTIONS: readonly [{
|
|
|
86
88
|
readonly value: "latest";
|
|
87
89
|
readonly label: "Latest";
|
|
88
90
|
readonly hint: "Postgres 18";
|
|
89
|
-
readonly generated:
|
|
91
|
+
readonly generated: true;
|
|
90
92
|
}];
|
|
91
93
|
}, {
|
|
92
94
|
readonly key: "analytics";
|
|
@@ -174,7 +176,7 @@ export declare const STACK_OPTIONS: readonly [{
|
|
|
174
176
|
readonly value: "on";
|
|
175
177
|
readonly label: "On";
|
|
176
178
|
readonly hint: "proof of work, no tracking";
|
|
177
|
-
readonly generated:
|
|
179
|
+
readonly generated: true;
|
|
178
180
|
}, {
|
|
179
181
|
readonly value: "off";
|
|
180
182
|
readonly label: "Off";
|
|
@@ -206,7 +208,8 @@ export declare const STACK_OPTIONS: readonly [{
|
|
|
206
208
|
readonly values: readonly [{
|
|
207
209
|
readonly value: "pnpm";
|
|
208
210
|
readonly label: "pnpm";
|
|
209
|
-
readonly
|
|
211
|
+
readonly hint: "with a day's delay on new releases";
|
|
212
|
+
readonly generated: true;
|
|
210
213
|
}, {
|
|
211
214
|
readonly value: "npm";
|
|
212
215
|
readonly label: "npm";
|
|
@@ -214,7 +217,8 @@ export declare const STACK_OPTIONS: readonly [{
|
|
|
214
217
|
}, {
|
|
215
218
|
readonly value: "bun";
|
|
216
219
|
readonly label: "Bun";
|
|
217
|
-
readonly
|
|
220
|
+
readonly hint: "for installs; the frontend runs on Node.js";
|
|
221
|
+
readonly generated: true;
|
|
218
222
|
}];
|
|
219
223
|
}, {
|
|
220
224
|
readonly key: "media";
|
|
@@ -247,8 +251,8 @@ export declare const STACK_OPTIONS: readonly [{
|
|
|
247
251
|
}, {
|
|
248
252
|
readonly value: "sentry";
|
|
249
253
|
readonly label: "Sentry";
|
|
250
|
-
readonly hint: "
|
|
251
|
-
readonly generated:
|
|
254
|
+
readonly hint: "sentry.io, with SENTRY_DSN";
|
|
255
|
+
readonly generated: true;
|
|
252
256
|
}, {
|
|
253
257
|
readonly value: "off";
|
|
254
258
|
readonly label: "Off";
|
|
@@ -288,14 +292,23 @@ interface ScaffoldOptions {
|
|
|
288
292
|
frontend: Frontend;
|
|
289
293
|
/** Demo pages and posts on the first start. */
|
|
290
294
|
demoContent: boolean;
|
|
291
|
-
/**
|
|
295
|
+
/**
|
|
296
|
+
* An external Postgres URL for production, saved as PRODUCTION_DATABASE_URL;
|
|
297
|
+
* development runs the bundled Postgres either way.
|
|
298
|
+
*/
|
|
292
299
|
databaseUrl?: string;
|
|
300
|
+
/** The bundled Postgres's version, and the backend's Postgres client; stable by default. */
|
|
301
|
+
postgres?: Stack["postgres"];
|
|
293
302
|
/** Store uploads in the local S3 service in development, like S3 in production. */
|
|
294
303
|
localS3?: boolean;
|
|
295
304
|
/** Page analytics with the bundled Umami (the `analytics` profile). */
|
|
296
305
|
analytics?: boolean;
|
|
297
306
|
/** Content Studio's notifications app; on by default. */
|
|
298
307
|
notifications?: boolean;
|
|
308
|
+
/** The captcha of the contact form; on by default. */
|
|
309
|
+
captcha?: boolean;
|
|
310
|
+
/** The frontend's package manager; pnpm by default. */
|
|
311
|
+
packageManager?: PackageManager;
|
|
299
312
|
/** How errors are reported in production; by email by default. */
|
|
300
313
|
errors?: Stack["errors"];
|
|
301
314
|
/** The cache backend; the database by default. */
|
|
@@ -313,6 +326,8 @@ interface ScaffoldOptions {
|
|
|
313
326
|
/** Where the templates are; the ones in the package by default. */
|
|
314
327
|
templatesDir?: string;
|
|
315
328
|
}
|
|
329
|
+
/** A package manager of the frontend. */
|
|
330
|
+
type PackageManager = Stack["packageManager"];
|
|
316
331
|
interface ScaffoldResult {
|
|
317
332
|
directory: string;
|
|
318
333
|
adminUsername: string;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { z as DEFAULT_STACK, i as FRONTENDS, B as NAMED_PRESETS, U as STACK_OPTIONS, S as VERSION, o as cacheEnv, G as decodePreset, K as encodePreset, w as generateProjectSecrets, T as generateSecret, d as normalizeDatabaseUrl, ot as parseEnv, q as pendingChoices, n as productionEnv, J as resolvePreset, tt as runDoctor, p as scaffold, ct as setEnvValues, m as setNotificationsApp, g as toProjectName, y as usesValkey, r as validateDomain, b as validateProjectName } from "./production-WThC1aS2.js";
|