@ghentcdh/create-crouton 0.0.1-alpha.39 → 0.0.1-alpha.44

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/index.js CHANGED
@@ -18854,25 +18854,38 @@ var transformDataSource = (data) => {
18854
18854
  };
18855
18855
  var DataSourceSchema = DataSourceShape.transform(transformDataSource);
18856
18856
 
18857
+ // ../crouton-core/src/lib/data-source/Security.schema.ts
18858
+ var SecuritySchema = external_exports.union([
18859
+ external_exports.object({ public: external_exports.literal(true) }),
18860
+ external_exports.object({ guard: external_exports.union([external_exports.string(), external_exports.array(external_exports.string()).min(1)]) })
18861
+ ]);
18862
+
18857
18863
  // ../crouton-core/src/lib/data-source/Operations.schema.ts
18864
+ var OpEntry = external_exports.union([
18865
+ external_exports.boolean(),
18866
+ external_exports.object({ security: SecuritySchema.optional() })
18867
+ ]);
18858
18868
  var BoolOrUpsertSchema = external_exports.union([
18859
18869
  external_exports.boolean(),
18860
- external_exports.object({ upsertOn: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]) })
18870
+ external_exports.object({
18871
+ upsertOn: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]),
18872
+ security: SecuritySchema.optional()
18873
+ })
18861
18874
  ]);
18862
18875
  var JsonOperationsSchema = external_exports.object({
18863
- findAll: external_exports.boolean().default(true),
18876
+ findAll: OpEntry.default(true),
18864
18877
  // default: true — only explicit `false` disables it
18865
- findOne: external_exports.boolean().default(true),
18878
+ findOne: OpEntry.default(true),
18866
18879
  // default: true
18867
- create: external_exports.boolean().default(true),
18880
+ create: OpEntry.default(true),
18868
18881
  // default: true
18869
- update: external_exports.boolean().default(true),
18882
+ update: OpEntry.default(true),
18870
18883
  // default: true
18871
- patch: external_exports.boolean().default(true),
18884
+ patch: OpEntry.default(true),
18872
18885
  // default: true
18873
18886
  upsert: BoolOrUpsertSchema.default(false),
18874
18887
  // default: disabled; `true` throws at load time — must be `{ upsertOn }`
18875
- delete: external_exports.boolean().default(true)
18888
+ delete: OpEntry.default(true)
18876
18889
  // default: true
18877
18890
  });
18878
18891
 
@@ -19002,6 +19015,57 @@ var CalculatedColumnSchema = external_exports.object({
19002
19015
  fieldInput: FieldInputSchema.optional()
19003
19016
  }).transform(normalizeLabel);
19004
19017
 
19018
+ // ../crouton-core/src/lib/resource/ColumnType.schema.ts
19019
+ var ColumnTypeShorthandSchema = external_exports.enum([
19020
+ "string",
19021
+ "number",
19022
+ "integer",
19023
+ "boolean",
19024
+ "date",
19025
+ "date-time",
19026
+ "object",
19027
+ "array"
19028
+ ]);
19029
+ var JsonSchemaFragmentSchema = external_exports.lazy(
19030
+ () => external_exports.object({
19031
+ type: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]).optional(),
19032
+ format: external_exports.string().optional(),
19033
+ enum: external_exports.array(external_exports.unknown()).optional(),
19034
+ const: external_exports.unknown().optional(),
19035
+ nullable: external_exports.boolean().optional(),
19036
+ properties: external_exports.record(external_exports.string(), JsonSchemaFragmentSchema).optional(),
19037
+ required: external_exports.array(external_exports.string()).optional(),
19038
+ items: JsonSchemaFragmentSchema.optional(),
19039
+ additionalProperties: external_exports.union([external_exports.boolean(), JsonSchemaFragmentSchema]).optional(),
19040
+ title: external_exports.string().optional(),
19041
+ description: external_exports.string().optional(),
19042
+ default: external_exports.unknown().optional(),
19043
+ minimum: external_exports.number().optional(),
19044
+ maximum: external_exports.number().optional(),
19045
+ minLength: external_exports.number().optional(),
19046
+ maxLength: external_exports.number().optional(),
19047
+ pattern: external_exports.string().optional()
19048
+ }).catchall(external_exports.unknown())
19049
+ );
19050
+ var ColumnTypeSchema = external_exports.union([
19051
+ ColumnTypeShorthandSchema,
19052
+ JsonSchemaFragmentSchema
19053
+ ]);
19054
+ var SHORTHAND_FRAGMENTS = {
19055
+ string: { type: "string" },
19056
+ number: { type: "number" },
19057
+ integer: { type: "integer" },
19058
+ boolean: { type: "boolean" },
19059
+ date: { type: "string", format: "date" },
19060
+ "date-time": { type: "string", format: "date-time" },
19061
+ object: { type: "object" },
19062
+ array: { type: "array" }
19063
+ };
19064
+ var NESTED_SHORTHANDS = {
19065
+ date: SHORTHAND_FRAGMENTS.date,
19066
+ "date-time": SHORTHAND_FRAGMENTS["date-time"]
19067
+ };
19068
+
19005
19069
  // ../crouton-core/src/lib/resource/Column.ts
19006
19070
  var WhenConditionSchema = external_exports.object({
19007
19071
  field: external_exports.string(),
@@ -19056,6 +19120,41 @@ var JsonColumnSchema = external_exports.object({
19056
19120
  // default: false — exactly one column should set this
19057
19121
  showInLookup: external_exports.boolean().default(false),
19058
19122
  // default: false
19123
+ /**
19124
+ * Data type of the column, as a shorthand name (`"string"`, `"integer"`, …)
19125
+ * or a full JSON Schema fragment:
19126
+ *
19127
+ * ```json
19128
+ * "type": {
19129
+ * "type": "object",
19130
+ * "properties": { "id": { "type": "string" }, "name": { "type": "string" } }
19131
+ * }
19132
+ * ```
19133
+ *
19134
+ * Required on every column of a `kind: "custom"` resource, where it is the
19135
+ * only source of the resource's json_schema. Optional on a `prisma`
19136
+ * resource, whose schema is derived from the Zod model.
19137
+ */
19138
+ type: ColumnTypeSchema.optional(),
19139
+ /**
19140
+ * Whether the form requires a value.
19141
+ *
19142
+ * A prisma resource derives `required` from its Zod model, so this is an
19143
+ * override in either direction: `true` adds the column to the form schema's
19144
+ * `required` array, `false` removes it, and omitting it leaves the model's
19145
+ * answer alone. A `kind: "custom"` resource has no model, so this is the only
19146
+ * way to mark one of its fields required.
19147
+ *
19148
+ * Applies to the **form** view only — a required filter input would make the
19149
+ * filter panel unsubmittable, and the table and view schemas are read-only.
19150
+ * Ignored on the id column and on columns that are neither createable nor
19151
+ * updateable, since the form cannot supply a value for those.
19152
+ */
19153
+ required: external_exports.boolean().optional(),
19154
+ /**
19155
+ * @deprecated Use `type` instead. Retained because it is still consumed by
19156
+ * the boolean predicate and the schema-less sub-resource view builder.
19157
+ */
19059
19158
  columnType: external_exports.string().default("string"),
19060
19159
  // default: 'string'
19061
19160
  fieldInput: FieldInputSchema.optional(),
@@ -19092,6 +19191,22 @@ var JsonColumnSchema = external_exports.object({
19092
19191
  // per-sub-column overrides, only used with `extend`
19093
19192
  });
19094
19193
 
19194
+ // ../crouton-core/src/lib/resource/ParentRef.schema.ts
19195
+ var ParentRefSchema = external_exports.object({
19196
+ /** Route segment of the parent, e.g. `"group"`. */
19197
+ route: external_exports.string(),
19198
+ /**
19199
+ * Name of the path parameter carrying the parent id, e.g. `"groupId"`.
19200
+ * Avoid `"id"` — that is the child's own id in `/:id` routes.
19201
+ */
19202
+ param: external_exports.string().default("parentId"),
19203
+ /** Type of the parent id, used to coerce the path param. Defaults to `'string'`. */
19204
+ idType: external_exports.enum(["string", "number"]).optional()
19205
+ });
19206
+
19207
+ // ../crouton-core/src/lib/resource/ResourceKind.ts
19208
+ var ResourceKindSchema = external_exports.enum(["prisma", "custom"]).default("prisma");
19209
+
19095
19210
  // ../crouton-core/src/lib/resource/Sidebar.schema.ts
19096
19211
  var SidebarGroupSchema = zod_default.object({
19097
19212
  /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */
@@ -19234,24 +19349,46 @@ var ResourceJsonShape = external_exports.object({
19234
19349
  schemaVersion: external_exports.number().int().positive().optional(),
19235
19350
  /** When `true`, the resource lives in the repo but is NOT loaded/served (work in progress). */
19236
19351
  draft: external_exports.boolean().optional().default(false),
19352
+ /**
19353
+ * Where the data comes from. `prisma` (the default) is backed by a Prisma
19354
+ * model plus a `schema.ts`; `custom` is configuration only and the developer
19355
+ * supplies a `repository.ts`. See `./ResourceKind`.
19356
+ */
19357
+ kind: ResourceKindSchema,
19237
19358
  name: external_exports.string(),
19238
19359
  // required — unique id, used as the frontend form id
19239
19360
  route: external_exports.string(),
19240
19361
  // required — URL segment for generated endpoints
19241
- model: external_exports.string(),
19242
- // required — Prisma model name
19362
+ /**
19363
+ * Prisma model name. Required when `kind` is `prisma` (enforced by the
19364
+ * refinement on `ResourceJsonSchema`), and must be absent when `kind` is
19365
+ * `custom` — there is no Prisma delegate to address.
19366
+ */
19367
+ model: external_exports.string().optional(),
19243
19368
  tag: external_exports.string(),
19244
19369
  // required — OpenAPI tag
19245
19370
  title: external_exports.string().optional(),
19246
19371
  // no computed default — used as UI display title
19247
19372
  table: external_exports.string().optional(),
19248
19373
  // default: same as `model`
19374
+ /**
19375
+ * Type of the resource's primary key, used to coerce `:id` route params.
19376
+ * Written by codegen from the Prisma model; defaults to `'string'`.
19377
+ */
19378
+ idType: external_exports.enum(["string", "number"]).optional(),
19249
19379
  database: external_exports.string().optional(),
19250
19380
  // default: project's default data source
19381
+ /**
19382
+ * Mount this resource under a parent route instead of at the top level —
19383
+ * see `./ParentRef.schema`. Only valid on a `kind: "custom"` resource.
19384
+ */
19385
+ parent: ParentRefSchema.optional(),
19251
19386
  sidebar: SidebarSchema.default(SidebarSchema.parse({})),
19252
19387
  // default: shown, alphabetically ordered, ungrouped
19253
19388
  display: JsonDisplaySchema.default(JsonDisplaySchema.parse({})),
19254
19389
  // default: { mode: 'modal', customComponent: null }
19390
+ /** Global security block — applies to every operation unless overridden per-operation. */
19391
+ security: SecuritySchema.optional(),
19255
19392
  operations: JsonOperationsSchema,
19256
19393
  // required key — but every sub-field defaults to enabled
19257
19394
  columns: ColumnsSchema.default(ColumnsSchema.parse({})),
@@ -19272,7 +19409,58 @@ var ResourceJsonShape = external_exports.object({
19272
19409
  */
19273
19410
  include: external_exports.array(JsonIncludeEntrySchema).default([])
19274
19411
  });
19275
- var ResourceJsonSchema = ResourceJsonShape.transform((obj) => {
19412
+ var refineByKind = (obj, ctx) => {
19413
+ if (obj.kind === "custom") {
19414
+ if (obj.model !== void 0) {
19415
+ ctx.addIssue({
19416
+ code: "custom",
19417
+ path: ["model"],
19418
+ message: 'A custom resource has no Prisma model. Remove "model" \u2014 data access comes from repository.ts.'
19419
+ });
19420
+ }
19421
+ if (obj.calculatedColumns?.length) {
19422
+ ctx.addIssue({
19423
+ code: "custom",
19424
+ path: ["calculatedColumns"],
19425
+ message: "calculatedColumns run raw SQL against a database table and are not supported on a custom resource. Compute the value in repository.ts instead."
19426
+ });
19427
+ }
19428
+ for (const [id, col] of Object.entries(obj.columns ?? {})) {
19429
+ if (col.fieldInput?.format === "relation" || col.fieldInput?.type === "autocomplete") {
19430
+ continue;
19431
+ }
19432
+ if (col.type === void 0) {
19433
+ ctx.addIssue({
19434
+ code: "custom",
19435
+ path: ["columns", id, "type"],
19436
+ message: `Column "${id}" needs a "type": a custom resource has no schema.ts, so its json_schema is built from the column types.`
19437
+ });
19438
+ }
19439
+ }
19440
+ if (obj.parent && obj.parent.param === "id") {
19441
+ ctx.addIssue({
19442
+ code: "custom",
19443
+ path: ["parent", "param"],
19444
+ message: `parent.param cannot be "id" \u2014 that is the child's own id in /:id routes. Use something like "groupId".`
19445
+ });
19446
+ }
19447
+ } else if (obj.parent !== void 0) {
19448
+ ctx.addIssue({
19449
+ code: "custom",
19450
+ path: ["parent"],
19451
+ message: '"parent" is only supported on a custom resource. A prisma resource is nested by declaring a relation column on its parent.'
19452
+ });
19453
+ } else if (obj.model === void 0) {
19454
+ ctx.addIssue({
19455
+ code: "custom",
19456
+ path: ["model"],
19457
+ message: '"model" is required for a prisma-backed resource. Set "kind": "custom" for a resource with no Prisma model.'
19458
+ });
19459
+ }
19460
+ };
19461
+ var ResourceJsonSchema = ResourceJsonShape.superRefine(
19462
+ refineByKind
19463
+ ).transform((obj) => {
19276
19464
  const title = obj.title ?? labelFromId(obj.name);
19277
19465
  const schemaVersion = obj.schemaVersion ?? BASELINE_RESOURCE_VERSION;
19278
19466
  return {
@@ -19290,7 +19478,7 @@ var RulesetSchema = external_exports.object({
19290
19478
  hideIdInView: external_exports.boolean().default(true),
19291
19479
  hideTimestamps: external_exports.boolean().default(true),
19292
19480
  hideForeignKeys: external_exports.boolean().default(true),
19293
- includeRelations: external_exports.boolean().default(false),
19481
+ includeRelations: external_exports.boolean().default(true),
19294
19482
  hideRelationsInTable: external_exports.boolean().default(true),
19295
19483
  showRelationsInForm: external_exports.boolean().default(true),
19296
19484
  enumValueLabel: external_exports.boolean().default(true),
@@ -19299,6 +19487,14 @@ var RulesetSchema = external_exports.object({
19299
19487
  JsonOperationsSchema.parse({})
19300
19488
  )
19301
19489
  });
19490
+ var I18nConfigSchema = external_exports.object({
19491
+ /** Default / fallback language. */
19492
+ defaultLanguage: external_exports.string().default("en"),
19493
+ /** All supported language codes. */
19494
+ languages: external_exports.array(external_exports.string()).min(1),
19495
+ /** Directory containing `<lang>.json` bundles, relative to project root. */
19496
+ translationsDir: external_exports.string().default("translations")
19497
+ });
19302
19498
  var CroutonConfigSchema = external_exports.object({
19303
19499
  /**
19304
19500
  * Application title served to the frontend via `GET /_app/layout`.
@@ -19328,7 +19524,9 @@ var CroutonConfigSchema = external_exports.object({
19328
19524
  * Whether form fields are saved automatically as the user edits them.
19329
19525
  * @default true
19330
19526
  */
19331
- autoSave: external_exports.boolean().default(true)
19527
+ autoSave: external_exports.boolean().default(true),
19528
+ /** Optional i18n / translation configuration. */
19529
+ i18n: I18nConfigSchema.optional()
19332
19530
  });
19333
19531
 
19334
19532
  // ../crouton-core/src/lib/view/view.schema.ts
@@ -19346,6 +19544,36 @@ var ViewConfigSchema = external_exports.object({
19346
19544
  defaultSort: external_exports.string().optional()
19347
19545
  });
19348
19546
 
19547
+ // ../crouton-core/src/lib/i18n/Translations.schema.ts
19548
+ var NestedStringRecord = external_exports.lazy(
19549
+ () => external_exports.record(external_exports.string(), external_exports.union([external_exports.string(), NestedStringRecord]))
19550
+ );
19551
+ var TranslationBundleSchema = external_exports.object({
19552
+ app: external_exports.object({
19553
+ title: external_exports.string().optional()
19554
+ }).optional(),
19555
+ sidebarGroups: external_exports.record(external_exports.string(), external_exports.string()).optional(),
19556
+ resources: external_exports.record(
19557
+ external_exports.string(),
19558
+ external_exports.object({
19559
+ title: external_exports.string().optional(),
19560
+ sidebar: external_exports.string().optional(),
19561
+ columns: external_exports.record(external_exports.string(), external_exports.string()).optional(),
19562
+ actions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
19563
+ subResources: external_exports.record(
19564
+ external_exports.string(),
19565
+ external_exports.object({
19566
+ title: external_exports.string().optional(),
19567
+ columns: external_exports.record(external_exports.string(), external_exports.string()).optional()
19568
+ }).optional()
19569
+ ).optional()
19570
+ }).optional()
19571
+ ).optional(),
19572
+ enums: external_exports.record(external_exports.string(), external_exports.record(external_exports.string(), external_exports.string())).optional(),
19573
+ ui: NestedStringRecord.optional(),
19574
+ validation: external_exports.record(external_exports.string(), external_exports.string()).optional()
19575
+ }).passthrough();
19576
+
19349
19577
  // ../crouton-codegen/src/util.ts
19350
19578
  import { access } from "fs/promises";
19351
19579
 
@@ -19603,21 +19831,30 @@ var runCreate = async (name, opts) => {
19603
19831
  M2.info(`Using pnpm ${pnpmVersion}`);
19604
19832
  }
19605
19833
  const dbUrl = await resolveDbUrl(opts);
19834
+ const postgres = opts.docker !== false ? await resolvePostgres(opts) : false;
19606
19835
  const dbName = name.replace(/[^a-zA-Z0-9]/g, "_");
19836
+ const appName = prefix || name;
19607
19837
  const tokens = {
19608
19838
  name,
19609
19839
  Name: toTitle(name),
19610
- version: true ? "0.0.1-alpha.39" : "latest",
19840
+ version: true ? "0.0.1-alpha.44" : "latest",
19611
19841
  year: String((/* @__PURE__ */ new Date()).getFullYear()),
19612
19842
  pmRun: pm === "npm" ? "npm run" : pm,
19613
19843
  urlEnv: "DATABASE_URL",
19614
19844
  dbUrl: dbUrl || `postgresql://crouton:crouton@localhost:5432/${dbName}?schema=public`,
19615
- dbName
19845
+ dbName,
19846
+ appName,
19847
+ frontendPort: "4200",
19848
+ backendPort: "3000"
19616
19849
  };
19617
19850
  if (layout === "nx") {
19618
19851
  tokens["nx"] = "true";
19619
- tokens["backendApp"] = "backend";
19620
- tokens["frontendApp"] = "frontend";
19852
+ tokens["backendApp"] = `${appName}-backend`;
19853
+ tokens["frontendApp"] = `${appName}-frontend`;
19854
+ tokens["workspaceRoot"] = prefix || ".";
19855
+ tokens["dockerfileDev"] = prefix ? `${prefix}/Dockerfile.dev` : "Dockerfile.dev";
19856
+ tokens["envFile"] = prefix ? `${prefix}/.env` : ".env";
19857
+ tokens["generatedGlob"] = prefix ? `${prefix}/generated/default` : "generated/default";
19621
19858
  if (prefix) {
19622
19859
  tokens["prefix"] = prefix;
19623
19860
  tokens["appsRoot"] = `${prefix}/apps`;
@@ -19633,10 +19870,23 @@ var runCreate = async (name, opts) => {
19633
19870
  tokens["generatedTypesPath"] = "generated/default/types/src";
19634
19871
  tokens["generatedClientPath"] = "generated/default/client";
19635
19872
  }
19873
+ } else {
19874
+ tokens["regular"] = "true";
19875
+ tokens["dockerfileDev"] = "Dockerfile.dev";
19876
+ tokens["envFile"] = ".env";
19636
19877
  }
19637
19878
  if (frontend) {
19638
19879
  tokens["frontend"] = "true";
19639
19880
  }
19881
+ if (layout === "nx" && frontend) {
19882
+ tokens["nxFrontend"] = "true";
19883
+ }
19884
+ if (layout === "nx" && !frontend) {
19885
+ tokens["nxBackendOnly"] = "true";
19886
+ }
19887
+ if (postgres) {
19888
+ tokens["postgres"] = "true";
19889
+ }
19640
19890
  const templateRoot = resolveTemplateDir();
19641
19891
  const skipPaths = !frontend ? ["apps/frontend"] : [];
19642
19892
  if (layout === "nx") {
@@ -19659,12 +19909,12 @@ var runCreate = async (name, opts) => {
19659
19909
  );
19660
19910
  files.push(...workspaceFiles);
19661
19911
  if (opts.docker !== false) {
19662
- const dockerDir = resolve2(templateRoot, "docker");
19663
- const dockerFiles = await loadAndRenderTemplates(
19664
- dockerDir,
19665
- "",
19912
+ const dockerFiles = await renderDockerTemplates(
19913
+ templateRoot,
19666
19914
  tokens,
19667
- targetDir
19915
+ targetDir,
19916
+ workspaceTarget,
19917
+ { postgres }
19668
19918
  );
19669
19919
  files.push(...dockerFiles);
19670
19920
  }
@@ -19701,13 +19951,12 @@ var runCreate = async (name, opts) => {
19701
19951
  skipPaths
19702
19952
  );
19703
19953
  if (opts.docker !== false) {
19704
- const dockerTokens = { ...tokens, regular: "true" };
19705
- const dockerDir = resolve2(templateRoot, "docker");
19706
- const dockerFiles = await loadAndRenderTemplates(
19707
- dockerDir,
19708
- "",
19709
- dockerTokens,
19710
- targetDir
19954
+ const dockerFiles = await renderDockerTemplates(
19955
+ templateRoot,
19956
+ tokens,
19957
+ targetDir,
19958
+ targetDir,
19959
+ { postgres }
19711
19960
  );
19712
19961
  files.push(...dockerFiles);
19713
19962
  }
@@ -19736,7 +19985,7 @@ var runCreate = async (name, opts) => {
19736
19985
  const prefixFlag = prefix ? ` --prefix ${prefix}` : "";
19737
19986
  Me(
19738
19987
  [
19739
- opts.docker !== false ? "docker compose up -d # start postgres" : null,
19988
+ opts.docker !== false && postgres ? "docker compose up -d # start postgres" : null,
19740
19989
  `${pmRun} prisma:migrate # create initial migration`,
19741
19990
  `crouton update resources${prefixFlag} # generate resource CRUD`,
19742
19991
  `${pmRun} dev # start dev server`
@@ -19752,6 +20001,78 @@ var runCreate = async (name, opts) => {
19752
20001
  throw err;
19753
20002
  }
19754
20003
  };
20004
+ var renderDockerTemplates = async (templateRoot, tokens, targetDir, workspaceTarget, opts) => {
20005
+ const dockerDir = resolve2(templateRoot, "docker");
20006
+ const files = [];
20007
+ const composeYml = render(
20008
+ await loadTemplate(dockerDir, "compose.yml.tmpl"),
20009
+ tokens
20010
+ );
20011
+ files.push({ path: resolve2(targetDir, "compose.yml"), contents: composeYml });
20012
+ const composeApp = render(
20013
+ await loadTemplate(dockerDir, "compose.app.tmpl"),
20014
+ tokens
20015
+ );
20016
+ files.push({
20017
+ path: resolve2(targetDir, `compose.app.${tokens["appName"]}.yml`),
20018
+ contents: composeApp
20019
+ });
20020
+ if (opts.postgres) {
20021
+ const composeInfra = render(
20022
+ await loadTemplate(dockerDir, "compose.infra.yml.tmpl"),
20023
+ tokens
20024
+ );
20025
+ files.push({
20026
+ path: resolve2(targetDir, "compose.infra.yml"),
20027
+ contents: composeInfra
20028
+ });
20029
+ const envInfra = render(
20030
+ await loadTemplate(dockerDir, ".env.infra.tmpl"),
20031
+ tokens
20032
+ );
20033
+ files.push({
20034
+ path: resolve2(targetDir, ".env.infra"),
20035
+ contents: envInfra
20036
+ });
20037
+ const envInfraExample = render(
20038
+ await loadTemplate(dockerDir, ".env.infra.example.tmpl"),
20039
+ tokens
20040
+ );
20041
+ files.push({
20042
+ path: resolve2(targetDir, ".env.infra.example"),
20043
+ contents: envInfraExample
20044
+ });
20045
+ files.push({
20046
+ path: resolve2(targetDir, "docker/init-data/.gitkeep"),
20047
+ contents: ""
20048
+ });
20049
+ }
20050
+ const dockerfileDev = render(
20051
+ await loadTemplate(dockerDir, "Dockerfile.dev.tmpl"),
20052
+ tokens
20053
+ );
20054
+ files.push({
20055
+ path: resolve2(workspaceTarget, "Dockerfile.dev"),
20056
+ contents: dockerfileDev
20057
+ });
20058
+ const dockerfileProd = render(
20059
+ await loadTemplate(dockerDir, "Dockerfile.prod.tmpl"),
20060
+ tokens
20061
+ );
20062
+ files.push({
20063
+ path: resolve2(workspaceTarget, "Dockerfile.prod"),
20064
+ contents: dockerfileProd
20065
+ });
20066
+ const dockerignore = render(
20067
+ await loadTemplate(dockerDir, ".dockerignore.tmpl"),
20068
+ tokens
20069
+ );
20070
+ files.push({
20071
+ path: resolve2(targetDir, ".dockerignore"),
20072
+ contents: dockerignore
20073
+ });
20074
+ return files;
20075
+ };
19755
20076
  var postScaffold = async (opts, targetDir, pm, dbUrl, prefix) => {
19756
20077
  if (opts.git !== false) {
19757
20078
  const s = Y2();
@@ -19864,6 +20185,16 @@ var resolveDbUrl = async (opts) => {
19864
20185
  );
19865
20186
  return url2.trim();
19866
20187
  };
20188
+ var resolvePostgres = async (opts) => {
20189
+ if (opts.yes) return opts.postgres;
20190
+ if (!opts.postgres) return false;
20191
+ return assertNotCancel(
20192
+ await ye({
20193
+ message: "Run PostgreSQL in Docker?",
20194
+ initialValue: true
20195
+ })
20196
+ );
20197
+ };
19867
20198
  var loadAndRenderTemplates = async (templateDir, subPath, tokens, targetDir, skipPaths = []) => {
19868
20199
  const files = [];
19869
20200
  const dir = subPath ? resolve2(templateDir, subPath) : templateDir;
@@ -19892,7 +20223,7 @@ var loadAndRenderTemplates = async (templateDir, subPath, tokens, targetDir, ski
19892
20223
  };
19893
20224
 
19894
20225
  // src/index.ts
19895
- var program2 = new Command("create-crouton").description("Scaffold a new crouton project").version("0.0.1").argument("[name]", "project name", "my-crouton-app").option("--nx", "use Nx monorepo layout").option("--no-nx", "use regular (non-Nx) layout").option("--no-frontend", "skip frontend app generation").option("--sample", "include sample resource").option("--pm <manager>", "package manager (pnpm | npm | yarn | bun)").option("--no-install", "skip dependency installation").option("--no-git", "skip git init").option("--prefix <name>", "nest apps/config under a subfolder (Nx only)").option("--no-docker", "skip Docker file generation").option("-y, --yes", "accept all defaults (non-interactive)").option("--force", "overwrite existing files").option("--db-url <url>", "database connection URL (e.g. postgresql://user:pass@localhost:5432/db)").action(async (name, opts) => {
20226
+ var program2 = new Command("create-crouton").description("Scaffold a new crouton project").version("0.0.1").argument("[name]", "project name", "my-crouton-app").option("--nx", "use Nx monorepo layout").option("--no-nx", "use regular (non-Nx) layout").option("--no-frontend", "skip frontend app generation").option("--sample", "include sample resource").option("--pm <manager>", "package manager (pnpm | npm | yarn | bun)").option("--no-install", "skip dependency installation").option("--no-git", "skip git init").option("--prefix <name>", "nest apps/config under a subfolder (Nx only)").option("--no-docker", "skip Docker file generation").option("--no-postgres", "skip PostgreSQL in Docker (use external DB)").option("-y, --yes", "accept all defaults (non-interactive)").option("--force", "overwrite existing files").option("--db-url <url>", "database connection URL (e.g. postgresql://user:pass@localhost:5432/db)").action(async (name, opts) => {
19896
20227
  try {
19897
20228
  await runCreate(name, opts);
19898
20229
  } catch (err) {