betterstart-cli 0.0.117 → 0.0.119

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.
Files changed (87) hide show
  1. package/dist/assets/adapters/next/templates/init/admin-globals.css +154 -38
  2. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-grid-row.tsx +33 -1
  3. package/dist/assets/adapters/next/templates/init/components/shared/media/media-gallery-dialog.tsx +3 -3
  4. package/dist/assets/adapters/next/templates/init/components/shared/media/media-preview.tsx +3 -1
  5. package/dist/assets/adapters/next/templates/init/hooks/use-field-error-visible.ts +25 -0
  6. package/dist/assets/adapters/next/templates/init/hooks/use-media.ts +1 -1
  7. package/dist/assets/adapters/next/templates/init/hooks/use-upload.ts +11 -5
  8. package/dist/assets/adapters/next/templates/init/lib/actions/audit/cleanup-audit-logs.ts +1 -0
  9. package/dist/assets/adapters/next/templates/init/lib/actions/audit/query-audit-logs.ts +2 -2
  10. package/dist/assets/adapters/next/templates/init/lib/actions/audit/record-audit-event.ts +1 -2
  11. package/dist/assets/adapters/next/templates/init/lib/actions/auth/client.ts +4 -1
  12. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/get-entity-versions.ts +5 -1
  13. package/dist/assets/adapters/next/templates/init/lib/actions/forms/get-all-form-settings.ts +1 -1
  14. package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +2 -1
  15. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media-bulk.ts +1 -0
  16. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media.ts +1 -0
  17. package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +2 -4
  18. package/dist/assets/adapters/next/templates/init/lib/actions/profile/change-own-password.ts +1 -0
  19. package/dist/assets/adapters/next/templates/init/lib/actions/profile/update-email.ts +1 -0
  20. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-files.ts +1 -0
  21. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-media-from-url.ts +16 -6
  22. package/dist/assets/adapters/next/templates/init/lib/actions/users/change-user-password.ts +1 -0
  23. package/dist/assets/adapters/next/templates/init/lib/actions/users/create-user.ts +2 -1
  24. package/dist/assets/adapters/next/templates/init/lib/actions/users/delete-user.ts +1 -0
  25. package/dist/assets/adapters/next/templates/init/lib/actions/users/types.ts +1 -1
  26. package/dist/assets/adapters/next/templates/init/lib/actions/users/update-user-role.ts +1 -0
  27. package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +12 -4
  28. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/registry.ts +4 -4
  29. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +3 -7
  30. package/dist/assets/adapters/next/templates/init/pages/forgot-password-form.tsx +5 -8
  31. package/dist/assets/adapters/next/templates/init/pages/forgot-password-page-skeleton.tsx +2 -2
  32. package/dist/assets/adapters/next/templates/init/pages/login-form.tsx +7 -9
  33. package/dist/assets/adapters/next/templates/init/pages/login-page-skeleton.tsx +2 -2
  34. package/dist/assets/adapters/next/templates/init/pages/reset-password-form.tsx +8 -16
  35. package/dist/assets/adapters/next/templates/init/pages/reset-password-page-skeleton.tsx +2 -2
  36. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-detail-row.tsx +1 -1
  37. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-table.tsx +1 -6
  38. package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-table.tsx +2 -7
  39. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-table.tsx +1 -6
  40. package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +1 -1
  41. package/dist/assets/adapters/next/templates/init/public/placeholder.png +0 -0
  42. package/dist/assets/adapters/next/templates/init/types/index.ts +2 -0
  43. package/dist/assets/adapters/next/templates/init/utils/audit/normalize-comparable-value.ts +4 -2
  44. package/dist/assets/adapters/next/templates/init/utils/date/format-action-date.ts +12 -0
  45. package/dist/assets/adapters/next/templates/init/utils/dev-mode/dev-mode-json-schemas.ts +66 -0
  46. package/dist/assets/adapters/next/templates/init/utils/dev-mode/parse-dev-mode-lifecycle-hooks.ts +11 -0
  47. package/dist/assets/adapters/next/templates/init/utils/dev-mode/parse-dev-mode-snippets.ts +9 -0
  48. package/dist/assets/adapters/next/templates/init/utils/editor/set-task-item-checked.ts +13 -0
  49. package/dist/assets/adapters/next/templates/init/utils/editor/update-nodes-attr.ts +2 -1
  50. package/dist/assets/adapters/next/templates/init/utils/email/email-theme.ts +13 -0
  51. package/dist/assets/adapters/next/templates/init/utils/email/render-form-submission-rows.ts +3 -2
  52. package/dist/assets/adapters/next/templates/init/utils/email/render-notification-email.ts +7 -6
  53. package/dist/assets/adapters/next/templates/init/utils/email/render-thank-you-email.ts +5 -4
  54. package/dist/assets/adapters/next/templates/init/utils/error/read-string-property.ts +4 -2
  55. package/dist/assets/adapters/next/templates/init/utils/error/recognize.ts +2 -4
  56. package/dist/assets/adapters/next/templates/init/utils/error/to-action-error.ts +0 -1
  57. package/dist/assets/adapters/next/templates/init/utils/form/clone-default-value.ts +4 -2
  58. package/dist/assets/adapters/next/templates/init/utils/shared/is-record.ts +3 -0
  59. package/dist/assets/adapters/next/templates/init/utils/table/default-get-id.ts +3 -2
  60. package/dist/assets/shared-assets/react-admin/custom/content-editor/editor-toolbar.tsx +1 -1
  61. package/dist/assets/shared-assets/react-admin/custom/content-editor/slash-command-menu.tsx +5 -3
  62. package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode.tsx +1 -1
  63. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node.tsx +3 -1
  64. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/task-item-node/task-item-node-extension.tsx +6 -15
  65. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +1 -6
  66. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu.tsx +1 -6
  67. package/dist/assets/shared-assets/react-admin/custom/date-range-picker.tsx +9 -2
  68. package/dist/assets/shared-assets/react-admin/custom/gallery-field.tsx +3 -3
  69. package/dist/assets/shared-assets/react-admin/custom/media-field.tsx +2 -2
  70. package/dist/assets/shared-assets/react-admin/custom/nested-object-list-field.tsx +3 -1
  71. package/dist/assets/shared-assets/react-admin/custom/progressive-blur.tsx +3 -1
  72. package/dist/assets/shared-assets/react-admin/ui/badge.tsx +1 -2
  73. package/dist/assets/shared-assets/react-admin/ui/dropdown-menu.tsx +20 -23
  74. package/dist/assets/shared-assets/react-admin/ui/form.tsx +6 -3
  75. package/dist/assets/shared-assets/react-admin/ui/input.tsx +1 -1
  76. package/dist/assets/shared-assets/react-admin/ui/native-select.tsx +1 -1
  77. package/dist/assets/shared-assets/react-admin/ui/navigation-menu.tsx +1 -1
  78. package/dist/assets/shared-assets/react-admin/ui/select.tsx +1 -1
  79. package/dist/assets/shared-assets/react-admin/ui/textarea.tsx +1 -1
  80. package/dist/{chunk-FGEVDA53.js → chunk-BNHFSHPE.js} +12 -1
  81. package/dist/chunk-BNHFSHPE.js.map +1 -0
  82. package/dist/cli.js +909 -598
  83. package/dist/cli.js.map +1 -1
  84. package/dist/{read-namespaced-template-KUENIIDC.js → read-namespaced-template-WYIGUH7S.js} +2 -2
  85. package/package.json +1 -1
  86. package/dist/chunk-FGEVDA53.js.map +0 -1
  87. /package/dist/{read-namespaced-template-KUENIIDC.js.map → read-namespaced-template-WYIGUH7S.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  MAIN_CSS_CANDIDATES,
22
22
  PROXY_CONVENTION_FILE_NAMES,
23
23
  PROXY_FILE_NAME,
24
+ PUBLIC_ASSET_FILE_NAMES,
24
25
  R2_ENV_KEYS,
25
26
  RAILWAY_BUCKET_ENV_KEYS,
26
27
  REDACTED,
@@ -69,6 +70,7 @@ import {
69
70
  resolveCommandCwd,
70
71
  resolveProjectEnvVar,
71
72
  restoreFile,
73
+ safeCopyFile,
72
74
  safeIdentifier,
73
75
  safeWriteFile,
74
76
  singularize,
@@ -86,7 +88,7 @@ import {
86
88
  trimDotSlash,
87
89
  usesIdentifier,
88
90
  validateAdminNamespace
89
- } from "./chunk-FGEVDA53.js";
91
+ } from "./chunk-BNHFSHPE.js";
90
92
 
91
93
  // cli.ts
92
94
  import * as p66 from "@clack/prompts";
@@ -1255,32 +1257,32 @@ function collectInvalidSchemaFieldTypeErrors(fields, errors) {
1255
1257
  }
1256
1258
 
1257
1259
  // core-engine/schema/schema-reader/collect-slot-area-errors.ts
1258
- function collectSlotAreaErrors(value, path113, errors) {
1260
+ function collectSlotAreaErrors(value, path114, errors) {
1259
1261
  if (!isRecord(value)) {
1260
- errors.push(`${path113} must be an object with a "fields" array.`);
1262
+ errors.push(`${path114} must be an object with a "fields" array.`);
1261
1263
  return;
1262
1264
  }
1263
1265
  const fields = value.fields;
1264
1266
  if (!Array.isArray(fields)) {
1265
- errors.push(`${path113}.fields must be an array.`);
1267
+ errors.push(`${path114}.fields must be an array.`);
1266
1268
  return;
1267
1269
  }
1268
1270
  for (const field of fields) {
1269
1271
  const name = isRecord(field) && isNonEmptyString(field.name) ? field.name : "unnamed";
1270
- walkSlot(field, `${path113}.fields.${name}`, errors);
1272
+ walkSlot(field, `${path114}.fields.${name}`, errors);
1271
1273
  }
1272
1274
  }
1273
1275
 
1274
1276
  // core-engine/schema/schema-reader/collect-slot-layout-errors.ts
1275
- function collectSlotLayoutErrors(value, path113, errors) {
1277
+ function collectSlotLayoutErrors(value, path114, errors) {
1276
1278
  if (!isRecord(value)) {
1277
- errors.push(`${path113} must be an object with "main" and/or "sidebar" field groups.`);
1279
+ errors.push(`${path114} must be an object with "main" and/or "sidebar" field groups.`);
1278
1280
  return;
1279
1281
  }
1280
1282
  const validKeys = /* @__PURE__ */ new Set(["main", "sidebar"]);
1281
1283
  for (const key of Object.keys(value)) {
1282
1284
  if (!validKeys.has(key)) {
1283
- errors.push(`${path113} has unsupported key "${key}". Expected "main" or "sidebar".`);
1285
+ errors.push(`${path114} has unsupported key "${key}". Expected "main" or "sidebar".`);
1284
1286
  }
1285
1287
  }
1286
1288
  const areas = [
@@ -1291,10 +1293,10 @@ function collectSlotLayoutErrors(value, path113, errors) {
1291
1293
  for (const [name, area] of areas) {
1292
1294
  if (area === void 0) continue;
1293
1295
  hasArea = true;
1294
- collectSlotAreaErrors(area, `${path113}.${name}`, errors);
1296
+ collectSlotAreaErrors(area, `${path114}.${name}`, errors);
1295
1297
  }
1296
1298
  if (!hasArea) {
1297
- errors.push(`${path113} must define at least one of "main" or "sidebar".`);
1299
+ errors.push(`${path114} must define at least one of "main" or "sidebar".`);
1298
1300
  }
1299
1301
  }
1300
1302
 
@@ -3738,7 +3740,7 @@ function buildEditsForSourceFile(sourceFile, filePath, plan) {
3738
3740
  }
3739
3741
 
3740
3742
  // core-engine/snapshots/ast-substitution/collect-preview-changes.ts
3741
- function collectPreviewChanges(path113, beforeContent, afterContent) {
3743
+ function collectPreviewChanges(path114, beforeContent, afterContent) {
3742
3744
  const beforeLines = beforeContent.split("\n");
3743
3745
  const afterLines = afterContent.split("\n");
3744
3746
  const maxLength = Math.max(beforeLines.length, afterLines.length);
@@ -3750,7 +3752,7 @@ function collectPreviewChanges(path113, beforeContent, afterContent) {
3750
3752
  continue;
3751
3753
  }
3752
3754
  changes.push({
3753
- path: path113,
3755
+ path: path114,
3754
3756
  line: index + 1,
3755
3757
  before: before.trim(),
3756
3758
  after: after.trim()
@@ -4609,9 +4611,9 @@ function renderErrorMessageLineLayoutTemplate({
4609
4611
  indent,
4610
4612
  pathExpression: pathExpression2
4611
4613
  }) {
4612
- return `${indent}{getFieldErrorMessage(form.formState.errors, ${pathExpression2}) ? (
4614
+ return `${indent}{getFieldErrorMessage(form.formState, watchedValues, revealErrors, ${pathExpression2}) ? (
4613
4615
  ${indent} <p className="text-sm text-destructive">
4614
- ${indent} {getFieldErrorMessage(form.formState.errors, ${pathExpression2})}
4616
+ ${indent} {getFieldErrorMessage(form.formState, watchedValues, revealErrors, ${pathExpression2})}
4615
4617
  ${indent} </p>
4616
4618
  ${indent}) : null}`;
4617
4619
  }
@@ -5380,19 +5382,51 @@ ${innerJSX}
5380
5382
 
5381
5383
  // adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/build-field-error-helper.ts
5382
5384
  function renderBuildFieldErrorHelperSegmentTemplate() {
5383
- return `function getFieldErrorMessage(errors: FieldErrors<FormValues>, path: string): string | undefined {
5384
- let current: unknown = errors
5385
+ return `function readFormPath(source: unknown, path: string): unknown {
5386
+ let current: unknown = source
5385
5387
  for (const segment of path.split('.')) {
5386
5388
  if (!current || typeof current !== 'object') {
5387
5389
  return undefined
5388
5390
  }
5389
5391
  current = (current as Record<string, unknown>)[segment]
5390
5392
  }
5391
- if (current && typeof current === 'object' && 'message' in current) {
5392
- const message = (current as { message?: unknown }).message
5393
- return typeof message === 'string' ? message : undefined
5393
+ return current
5394
+ }
5395
+
5396
+ function hasFieldValue(value: unknown): boolean {
5397
+ if (value === null || value === undefined) {
5398
+ return false
5399
+ }
5400
+ if (typeof value === 'string') {
5401
+ return value.trim().length > 0
5402
+ }
5403
+ if (Array.isArray(value)) {
5404
+ return value.length > 0
5394
5405
  }
5395
- return undefined
5406
+ return true
5407
+ }
5408
+
5409
+ function getFieldErrorMessage(
5410
+ formState: FormState<FormValues>,
5411
+ values: unknown,
5412
+ revealErrors: boolean,
5413
+ path: string
5414
+ ): string | undefined {
5415
+ const error = readFormPath(formState.errors, path)
5416
+ const message =
5417
+ error && typeof error === 'object' && 'message' in error
5418
+ ? (error as { message?: unknown }).message
5419
+ : undefined
5420
+ if (typeof message !== 'string') {
5421
+ return undefined
5422
+ }
5423
+ if (revealErrors) {
5424
+ return message
5425
+ }
5426
+ if (readFormPath(formState.touchedFields, path) !== true) {
5427
+ return undefined
5428
+ }
5429
+ return hasFieldValue(readFormPath(values, path)) ? message : undefined
5396
5430
  }`;
5397
5431
  }
5398
5432
 
@@ -5484,18 +5518,24 @@ function ${pPascal}FormInner() {
5484
5518
  defaultValues: {
5485
5519
  ${pDefaults}
5486
5520
  },
5521
+ mode: 'onBlur'
5487
5522
  })
5523
+ const watchedValues = useWatch({ control: form.control })
5524
+ const [stepAttempted, setStepAttempted] = React.useState(false)
5525
+ const revealErrors = form.formState.isSubmitted || stepAttempted
5488
5526
 
5489
5527
  ${pFieldArraySetup}${pWatchSetup}
5490
5528
  async function handleNext() {
5491
5529
  const stepFields = STEPS[currentStep].fields as (keyof FormValues)[]
5492
5530
  const isValid = await form.trigger(stepFields, { shouldFocus: true })
5531
+ setStepAttempted(!isValid)
5493
5532
  if (isValid) {
5494
5533
  setCurrentStep(currentStep + 1)
5495
5534
  }
5496
5535
  }
5497
5536
 
5498
5537
  function handleBack() {
5538
+ setStepAttempted(false)
5499
5539
  setCurrentStep(currentStep - 1)
5500
5540
  }
5501
5541
 
@@ -5666,7 +5706,7 @@ function buildMultiStepFormComponentSource(schema, options = {}) {
5666
5706
  const listFields = getListFields(allFields);
5667
5707
  const hasListFields = listFields.length > 0;
5668
5708
  const { setup: watchSetup } = buildWatchDecls(allFields);
5669
- const rhfImport = hasListFields ? `import { Controller, useFieldArray, useForm, type FieldErrors } from 'react-hook-form'` : `import { Controller, useForm, type FieldErrors } from 'react-hook-form'`;
5709
+ const rhfImport = hasListFields ? `import { Controller, useFieldArray, useForm, useWatch, type FormState } from 'react-hook-form'` : `import { Controller, useForm, useWatch, type FormState } from 'react-hook-form'`;
5670
5710
  const fieldArraySetup = hasListFields ? `
5671
5711
  ${buildFieldArrayDecls(listFields)}
5672
5712
  ` : "";
@@ -5741,7 +5781,10 @@ export function ${pascal}Form() {
5741
5781
  defaultValues: {
5742
5782
  ${defaults}
5743
5783
  },
5784
+ mode: 'onBlur'
5744
5785
  })
5786
+ const watchedValues = useWatch({ control: form.control })
5787
+ const revealErrors = form.formState.isSubmitted
5745
5788
  ${fieldArraySetup}${watchSetup}
5746
5789
  function onSubmit(values: FormValues) {
5747
5790
  startSubmitTransition(async () => {
@@ -5806,7 +5849,7 @@ function buildSingleStepFormComponentSource(schema, options = {}) {
5806
5849
  const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
5807
5850
  const redirectUrl = schema.redirectUrl;
5808
5851
  const successHandler = redirectUrl ? `window.location.href = ${JSON.stringify(redirectUrl)}` : "setSubmitted(true)";
5809
- const rhfImport = hasListFields ? `import { Controller, useFieldArray, useForm, type FieldErrors } from 'react-hook-form'` : `import { Controller, useForm, type FieldErrors } from 'react-hook-form'`;
5852
+ const rhfImport = hasListFields ? `import { Controller, useFieldArray, useForm, useWatch, type FormState } from 'react-hook-form'` : `import { Controller, useForm, useWatch, type FormState } from 'react-hook-form'`;
5810
5853
  const fieldArraySetup = hasListFields ? `
5811
5854
  ${buildFieldArrayDecls(listFields)}
5812
5855
  ` : "";
@@ -6072,10 +6115,10 @@ function renderCreateDevModeIntegrationArtifactImportsTemplate({
6072
6115
  }) {
6073
6116
  return `import type {
6074
6117
  DevModeIntegration,
6075
- DevModeIntegrationMetadata,
6076
- DevModeLifecycleHookExample,
6077
- DevModeSnippet
6118
+ DevModeIntegrationMetadata
6078
6119
  } from '${adminImportAlias}/components/shared/dev-mode/dev-mode-types'
6120
+ import { parseDevModeLifecycleHooks } from '${adminImportAlias}/utils/dev-mode/parse-dev-mode-lifecycle-hooks'
6121
+ import { parseDevModeSnippets } from '${adminImportAlias}/utils/dev-mode/parse-dev-mode-snippets'
6079
6122
 
6080
6123
  export const ${exportName} = {
6081
6124
  schemaName: ${stringify},
@@ -6087,12 +6130,12 @@ export async function ${loadExportName}(): Promise<DevModeIntegration> {
6087
6130
  const [${join}] = await Promise.all([
6088
6131
  ${dynamicImports}
6089
6132
  ])
6090
- const snippets = [
6133
+ const snippets = parseDevModeSnippets([
6091
6134
  ${snippetValues}
6092
- ] as DevModeSnippet[]
6093
- const lifecycleHooks = [
6135
+ ])
6136
+ const lifecycleHooks = parseDevModeLifecycleHooks([
6094
6137
  ${lifecycleHookValues}
6095
- ] as DevModeLifecycleHookExample[]
6138
+ ])
6096
6139
 
6097
6140
  return {
6098
6141
  ...${exportName},
@@ -7568,12 +7611,7 @@ export function ${pascal}SubmissionsTable<TValue>({
7568
7611
  key={row.id}
7569
7612
  data-state={row.getIsSelected() ? 'selected' : undefined}
7570
7613
  className="cursor-pointer hover:bg-muted/50"
7571
- onClick={(e) => {
7572
- const target = e.target as HTMLElement
7573
- if (!e.currentTarget.contains(target)) return
7574
- if (target.closest('button, a, input, [role="checkbox"]')) return
7575
- onViewSubmission(row.original.id)
7576
- }}
7614
+ onActivate={() => onViewSubmission(row.original.id)}
7577
7615
  >
7578
7616
  {row.getVisibleCells().map((cell) => {
7579
7617
  const meta = cell.column.columnDef.meta as Record<string, unknown> | undefined
@@ -9433,10 +9471,11 @@ import {
9433
9471
  get${ctxSingular}SlugRetryLimit,
9434
9472
  is${ctxSingular}SlugConflict,
9435
9473
  resolveUnique${ctxSingular}Slug,
9436
- ${snapshotImport}
9474
+ ${snapshotImport},
9475
+ to${ctxSingular}
9437
9476
  } from './helpers'
9438
9477
  ${lifecycleHookImport2}
9439
- import type { ${ctxSingular}CreateInput, ${ctxSingular}CreateResult, ${ctxSingular} } from './types'${markdownImport}
9478
+ import type { ${ctxSingular}CreateInput, ${ctxSingular}CreateResult } from './types'${markdownImport}
9440
9479
 
9441
9480
  export async function create${ctxSingular}(input: ${ctxSingular}CreateInput): Promise<${ctxSingular}CreateResult> {
9442
9481
  const actor = await requireRole([UserRole.ADMIN, UserRole.EDITOR])
@@ -9445,7 +9484,7 @@ export async function create${ctxSingular}(input: ${ctxSingular}CreateInput): Pr
9445
9484
  const actorId = actor.id
9446
9485
  const now = new Date().toISOString()
9447
9486
  const auditRequestMetadata = await getAuditRequestMetadata()
9448
- const changedFields = getTouchedFieldNames(input as unknown as Record<string, unknown>)
9487
+ const changedFields = getTouchedFieldNames(input)
9449
9488
  const lifecycleContext = ${createContext}
9450
9489
  ${beforeHook2}
9451
9490
  ${createBeforePublishBlock}
@@ -9508,7 +9547,7 @@ ${ctxCreateMappings},${ctxHasHtmlOutputContent}${ctxHasDraftContent}
9508
9547
  typeof created${ctxSingular}Id === 'string'
9509
9548
  ? await get${ctxSingular}ById(created${ctxSingular}Id)
9510
9549
  : null
9511
- const created${ctxSingular}Data = created${ctxSingular} ?? (result[0] as unknown as ${ctxSingular})
9550
+ const created${ctxSingular}Data = created${ctxSingular} ?? to${ctxSingular}(result[0])
9512
9551
  const created${ctxSingular}Context = ${createResultContext}
9513
9552
  ${afterHook2}
9514
9553
  ${createAfterPublishBlock}
@@ -9530,21 +9569,18 @@ function genCreateContent(ctx) {
9530
9569
  const kebabSingular = toKebabCase(ctx.singular);
9531
9570
  const slugSourceValue = ctx.slugSourceField ? `input.${ctx.slugSourceField}` : "undefined";
9532
9571
  const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
9533
- const snapshotData = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(createdRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(createdRow as unknown as ${ctx.Singular})`;
9572
+ const snapshotData = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(createdRow, tx)` : `build${ctx.Singular}VersionSnapshot(createdRow)`;
9534
9573
  const markdownImport = ctx.hasHtmlOutput ? `
9535
9574
  import { renderMarkdownSync } from './markdown'` : "";
9536
- const createContext = lifecycleContext(
9537
- ctx.plural,
9538
- `,
9539
- input: input as unknown as Record<string, unknown>,
9540
- changedFields`
9541
- );
9575
+ const createContext = lifecycleContext(ctx.plural, `,
9576
+ input,
9577
+ changedFields`);
9542
9578
  const createResultContext = lifecycleContext(
9543
9579
  ctx.plural,
9544
9580
  `,
9545
9581
  entityId: created${ctx.Singular}Id,
9546
- input: input as unknown as Record<string, unknown>,
9547
- data: created${ctx.Singular}Data as unknown as Record<string, unknown>,
9582
+ input,
9583
+ data: created${ctx.Singular}Data,
9548
9584
  changedFields`
9549
9585
  );
9550
9586
  const createBeforePublishBlock = ctx.hasDraft ? `
@@ -9792,7 +9828,7 @@ export async function deleteBulk${ctxPlural}(ids: string[]): Promise<${ctxSingul
9792
9828
  return tx.delete(${ctxTableVar}).where(inArray(${ctxTableVar}.id, ids)).returning()
9793
9829
  })
9794
9830
  const deletedRowsById = new Map(
9795
- deletedRows.map((row) => [row.id, row as unknown as Record<string, unknown>])
9831
+ deletedRows.map((row) => [row.id, row])
9796
9832
  )
9797
9833
  ${ctxCacheInvalidationFn}(${ctxCamelPlural}CacheTags.all)
9798
9834
  for (const id of ids) {
@@ -9899,7 +9935,7 @@ export async function delete${ctxSingular}(id: string): Promise<${ctxSingular}De
9899
9935
  function renderGenDeleteContentTemplate() {
9900
9936
  return `{
9901
9937
  ...lifecycleContext,
9902
- data: deletedRow as unknown as Record<string, unknown> | undefined
9938
+ data: deletedRow
9903
9939
  }`;
9904
9940
  }
9905
9941
  function renderGenDeleteContentRenderer(request) {
@@ -10061,12 +10097,13 @@ function genGetByIdContent(ctx) {
10061
10097
  const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
10062
10098
  const drizzle = ["eq"];
10063
10099
  const sortedDrizzle = [...new Set(drizzle)].sort();
10064
- const byIdHelperImports = ["formatActionDate"];
10100
+ const byIdHelperImports = [];
10065
10101
  if (ctx.hasSelectFields) byIdHelperImports.push(`resolve${ctx.Singular}SelectFields`);
10066
10102
  if (ctx.hasListRels) byIdHelperImports.push(`populate${ctx.Singular}ListRelationships`);
10067
10103
  if (ctx.hasMediaFields) byIdHelperImports.push(`resolve${ctx.Singular}MediaFields`);
10068
- const populateImport = byIdHelperImports.length > 0 ? `
10069
- import { ${byIdHelperImports.join(", ")} } from './helpers'` : "";
10104
+ const populateImport = `
10105
+ import { formatActionDate } from '@admin/utils/date/format-action-date'` + (byIdHelperImports.length > 0 ? `
10106
+ import { ${byIdHelperImports.join(", ")} } from './helpers'` : "");
10070
10107
  return renderGenGetByIdContentServerActionTemplate({
10071
10108
  join: dbImports.join(", "),
10072
10109
  joinText: sortedDrizzle.join(", "),
@@ -10133,12 +10170,13 @@ function genGetBySlugContent(ctx) {
10133
10170
  const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
10134
10171
  const drizzle = ["eq"];
10135
10172
  const sortedDrizzle = [...new Set(drizzle)].sort();
10136
- const bySlugHelperImports = ["formatActionDate"];
10173
+ const bySlugHelperImports = [];
10137
10174
  if (ctx.hasSelectFields) bySlugHelperImports.push(`resolve${ctx.Singular}SelectFields`);
10138
10175
  if (ctx.hasListRels) bySlugHelperImports.push(`populate${ctx.Singular}ListRelationships`);
10139
10176
  if (ctx.hasMediaFields) bySlugHelperImports.push(`resolve${ctx.Singular}MediaFields`);
10140
- const populateImport = bySlugHelperImports.length > 0 ? `
10141
- import { ${bySlugHelperImports.join(", ")} } from './helpers'` : "";
10177
+ const populateImport = `
10178
+ import { formatActionDate } from '@admin/utils/date/format-action-date'` + (bySlugHelperImports.length > 0 ? `
10179
+ import { ${bySlugHelperImports.join(", ")} } from './helpers'` : "");
10142
10180
  return renderGenGetBySlugContentServerActionTemplate({
10143
10181
  join: dbImports.join(", "),
10144
10182
  joinText: sortedDrizzle.join(", "),
@@ -10223,15 +10261,11 @@ ${ctxSearchBlock}${ctxFilterConditions}
10223
10261
  ? Math.max(0, rawOffset)
10224
10262
  : 0
10225
10263
  const isPaginated = typeof limit === 'number'
10226
- let results: unknown[]
10227
- if (isPaginated) {
10228
- const paginatedQuery = offset > 0
10229
- ? orderedQuery.limit(limit).offset(offset)
10230
- : orderedQuery.limit(limit)
10231
- results = await paginatedQuery
10232
- } else {
10233
- results = await orderedQuery
10234
- }
10264
+ const results = isPaginated
10265
+ ? offset > 0
10266
+ ? await orderedQuery.limit(limit).offset(offset)
10267
+ : await orderedQuery.limit(limit)
10268
+ : await orderedQuery
10235
10269
 
10236
10270
  const total = isPaginated
10237
10271
  ? Number((await db.select({ count: sql\`count(*)\` }).from(${ctxTableVar})${ctxWhere})[0]?.count ?? 0)
@@ -10256,13 +10290,14 @@ function genGetPluralContent(ctx) {
10256
10290
  drizzle.push("sql");
10257
10291
  if (ctx.hasRelationships) drizzle.push("eq");
10258
10292
  const sortedDrizzle = [...new Set(drizzle)].sort();
10259
- const typeImports = [`${ctx.Plural}Page`, `${ctx.Plural}Query`, `${ctx.Singular}`];
10260
- const helperImports = ["formatActionDate"];
10293
+ const typeImports = [`${ctx.Plural}Page`, `${ctx.Plural}Query`];
10294
+ const helperImports = [];
10261
10295
  if (ctx.hasSelectFields) helperImports.push(`resolve${ctx.Singular}SelectFields`);
10262
10296
  if (ctx.hasListRels) helperImports.push(`populate${ctx.Singular}ListRelationships`);
10263
10297
  if (ctx.hasMediaFields) helperImports.push(`resolve${ctx.Singular}MediaFields`);
10264
- const populateImport = helperImports.length > 0 ? `
10265
- import { ${helperImports.join(", ")} } from './helpers'` : "";
10298
+ const populateImport = `
10299
+ import { formatActionDate } from '@admin/utils/date/format-action-date'` + (helperImports.length > 0 ? `
10300
+ import { ${helperImports.join(", ")} } from './helpers'` : "");
10266
10301
  const dateRangeHelper = hasDateRangeFilters ? `
10267
10302
 
10268
10303
  ${renderExclusiveDateUpperBoundHelper()}` : "";
@@ -10330,7 +10365,14 @@ export async function get${ctxSingular}SelectOptions(
10330
10365
  .where(eq(${ctxSelectOptionsTableVar}.fieldName, fieldName))
10331
10366
  .orderBy(asc(${ctxSelectOptionsTableVar}.label))
10332
10367
 
10333
- return rows as ${ctxSingular}SelectOption[]
10368
+ return rows.map((row) => ({
10369
+ id: row.id,
10370
+ fieldName,
10371
+ label: row.label,
10372
+ value: row.value,
10373
+ createdAt: row.createdAt,
10374
+ updatedAt: row.updatedAt
10375
+ }))
10334
10376
  } catch (error) {
10335
10377
  console.error('Error fetching ${ctxSingularText} select options:', error)
10336
10378
  return []
@@ -10383,120 +10425,91 @@ function genGetVersionsContent(ctx) {
10383
10425
  });
10384
10426
  }
10385
10427
 
10386
- // adapters/next/templates/renderers/generators/actions/action-helpers/build-format-action-date-source.ts
10387
- function renderBuildFormatActionDateSourceDateTemplate({
10388
- optionsExportedExport
10389
- }) {
10390
- return `${optionsExportedExport}function formatActionDate(value: unknown): string {
10391
- if (typeof value !== 'string') return ''
10392
- const date = new Date(value)
10393
- if (Number.isNaN(date.getTime())) return ''
10394
-
10395
- return date.toLocaleDateString('en-US', {
10396
- month: 'short',
10397
- day: '2-digit',
10398
- year: 'numeric',
10399
- timeZone: 'UTC'
10400
- })
10401
- }`;
10402
- }
10403
-
10404
- // adapters/next/generators/actions/action-helpers/build-format-action-date-source.ts
10405
- function buildFormatActionDateSource(options) {
10406
- return renderBuildFormatActionDateSourceDateTemplate({
10407
- optionsExportedExport: options.exported ? "export " : ""
10408
- });
10409
- }
10410
-
10411
10428
  // adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-resolve-media-function.ts
10412
10429
  function renderResolveMediaFunctionIdsTemplate({
10413
10430
  ctxSingular,
10414
- collectSingle,
10415
- collectArrayContent,
10416
- map,
10417
- arrayFieldsContent,
10418
- assignSingle,
10419
- assignArrayContent
10431
+ collectStatements,
10432
+ listResolverBlock,
10433
+ assignments
10420
10434
  }) {
10421
- return `export async function resolve${ctxSingular}MediaFields(rows: ${ctxSingular}[]): Promise<${ctxSingular}[]> {
10422
- if (rows.length === 0) return rows
10423
-
10435
+ return `export async function resolve${ctxSingular}MediaFields(rows: ${ctxSingular}MediaResolvable[]): Promise<${ctxSingular}[]> {
10424
10436
  const ids = new Set<string>()
10425
- ${collectSingle}${collectArrayContent}
10426
-
10427
- if (ids.size === 0) {
10428
- for (const row of rows) {
10429
- ${map}${arrayFieldsContent}
10430
- }
10431
- return rows
10437
+ for (const row of rows) {
10438
+ ${collectStatements}
10432
10439
  }
10433
10440
 
10434
- const mediaRows = await db.select().from(adminMedia).where(inArray(adminMedia.id, [...ids]))
10435
- const mediaMap = new Map<string, AdminMedia>(mediaRows.map(m => [m.id, m]))
10441
+ const mediaRows =
10442
+ ids.size === 0
10443
+ ? []
10444
+ : await db.select().from(adminMedia).where(inArray(adminMedia.id, [...ids]))
10445
+ const mediaMap = new Map<string, AdminMedia>(mediaRows.map((media) => [media.id, media]))
10436
10446
 
10437
- for (const row of rows) {
10438
- ${assignSingle}${assignArrayContent}
10439
- }
10447
+ function resolveMedia(reference: string | null): AdminMedia | null {
10448
+ if (!reference || reference.startsWith('http')) return null
10449
+ const media = mediaMap.get(reference)
10450
+ if (!media) return null
10440
10451
 
10441
- return rows
10452
+ return {
10453
+ ...media,
10454
+ createdAtFormatted: formatActionDate(media.createdAt),
10455
+ updatedAtFormatted: formatActionDate(media.updatedAt)
10456
+ }
10457
+ }
10458
+ ${listResolverBlock}
10459
+ return rows.map((row) => ({
10460
+ ...row,
10461
+ ${assignments}
10462
+ }))
10442
10463
  }`;
10443
10464
  }
10465
+ function renderResolveMediaListResolverTemplate() {
10466
+ return `
10467
+ function resolveMediaList(references: string[]): AdminMedia[] {
10468
+ return references
10469
+ .map((reference) => resolveMedia(reference))
10470
+ .filter((media): media is AdminMedia => media !== null)
10471
+ }
10472
+ `;
10473
+ }
10474
+ function renderResolveMediaFunctionRenderer(request) {
10475
+ switch (request.kind) {
10476
+ case "renderResolveMediaFunctionIdsTemplate":
10477
+ return renderResolveMediaFunctionIdsTemplate(request.props);
10478
+ case "renderResolveMediaListResolverTemplate":
10479
+ return renderResolveMediaListResolverTemplate();
10480
+ }
10481
+ throw new Error("Unsupported renderer request");
10482
+ }
10444
10483
 
10445
10484
  // adapters/next/generators/actions/entity-file-contents/generate-resolve-media-function.ts
10446
10485
  function generateResolveMediaFunction(ctx) {
10447
10486
  const singleFields = ctx.mediaFields.map((f) => f.name);
10448
10487
  const arrayFields = ctx.galleryFields.map((f) => f.name);
10449
- const collectSingle = singleFields.map(
10450
- (name) => ` for (const row of rows) {
10451
- const val = row.${name}
10452
- if (val && typeof val === 'string' && !val.startsWith('http')) ids.add(val)
10453
- }`
10454
- ).join("\n");
10455
- const collectArray = arrayFields.map(
10456
- (name) => ` for (const row of rows) {
10457
- const arr = row.${name}
10458
- if (Array.isArray(arr)) for (const id of arr) { if (id && !id.startsWith('http')) ids.add(id) }
10488
+ const collectStatements = [
10489
+ ...singleFields.map(
10490
+ (name) => ` if (row.${name} && !row.${name}.startsWith('http')) ids.add(row.${name})`
10491
+ ),
10492
+ ...arrayFields.map(
10493
+ (name) => ` for (const id of row.${name}) {
10494
+ if (id && !id.startsWith('http')) ids.add(id)
10459
10495
  }`
10460
- ).join("\n");
10461
- const assignSingle = singleFields.map(
10462
- (name) => ` row.${name}Media = row.${name} && !row.${name}.startsWith('http')
10463
- ? (() => {
10464
- const media = mediaMap.get(row.${name})
10465
- if (!media) return null
10466
- return {
10467
- ...media,
10468
- createdAtFormatted: formatActionDate(media.createdAt),
10469
- updatedAtFormatted: formatActionDate(media.updatedAt)
10470
- }
10471
- })()
10472
- : null`
10473
- ).join("\n");
10474
- const assignArray = arrayFields.map(
10475
- (name) => ` row.${name}Media = Array.isArray(row.${name})
10476
- ? row.${name}
10477
- .map((id: string) => {
10478
- const media = mediaMap.get(id)
10479
- if (!media) return null
10480
- return {
10481
- ...media,
10482
- createdAtFormatted: formatActionDate(media.createdAt),
10483
- updatedAtFormatted: formatActionDate(media.updatedAt)
10484
- }
10485
- })
10486
- .filter(Boolean) as AdminMedia[]
10487
- : []`
10488
- ).join("\n");
10489
- return renderResolveMediaFunctionIdsTemplate({
10490
- ctxSingular: ctx.Singular,
10491
- collectSingle,
10492
- collectArrayContent: collectArray ? `
10493
- ${collectArray}` : "",
10494
- map: singleFields.map((name) => ` row.${name}Media = null`).join("\n"),
10495
- arrayFieldsContent: arrayFields.length > 0 ? `
10496
- ${arrayFields.map((name) => ` row.${name}Media = []`).join("\n")}` : "",
10497
- assignSingle,
10498
- assignArrayContent: assignArray ? `
10499
- ${assignArray}` : ""
10496
+ )
10497
+ ].join("\n");
10498
+ const assignments = [
10499
+ ...singleFields.map((name) => ` ${name}Media: resolveMedia(row.${name})`),
10500
+ ...arrayFields.map((name) => ` ${name}Media: resolveMediaList(row.${name})`)
10501
+ ].join(",\n");
10502
+ return renderResolveMediaFunctionRenderer({
10503
+ kind: "renderResolveMediaFunctionIdsTemplate",
10504
+ props: {
10505
+ ctxSingular: ctx.Singular,
10506
+ collectStatements,
10507
+ listResolverBlock: arrayFields.length > 0 ? renderResolveMediaFunctionRenderer({
10508
+ kind: "renderResolveMediaListResolverTemplate",
10509
+ props: {}
10510
+ }) : "",
10511
+ assignments
10512
+ }
10500
10513
  });
10501
10514
  }
10502
10515
 
@@ -10519,12 +10532,8 @@ function renderResolveSelectFieldsSourceDynamicRowsTemplate({
10519
10532
  }
10520
10533
  `;
10521
10534
  }
10522
- function renderResolveSelectFieldsSourceStaticSelectOptionLabelsTemplate({
10523
- staticLabelMaps,
10524
- exportedExport,
10525
- singular,
10526
- dynamicRowsBlock,
10527
- assignments
10535
+ function renderSelectOptionLabelMapsTemplate({
10536
+ staticLabelMaps
10528
10537
  }) {
10529
10538
  return `const STATIC_SELECT_OPTION_LABELS = {
10530
10539
  ${staticLabelMaps}
@@ -10537,7 +10546,56 @@ function cloneSelectOptionLabelMaps(): Record<string, Record<string, string>> {
10537
10546
  { ...labels }
10538
10547
  ])
10539
10548
  )
10549
+ }`;
10550
+ }
10551
+ function renderResolveSelectFieldsSourceStaticSelectOptionLabelsTemplate({
10552
+ staticLabelMaps,
10553
+ exportedExport,
10554
+ singular,
10555
+ inputType,
10556
+ outputType,
10557
+ dynamicRowsBlock,
10558
+ labelDeclarations,
10559
+ assignments
10560
+ }) {
10561
+ return `${renderSelectOptionLabelMapsTemplate({ staticLabelMaps })}
10562
+
10563
+ function toSelectOptionValues(
10564
+ values: string[],
10565
+ labels: Record<string, string>
10566
+ ): SelectOptionValue[] {
10567
+ return values
10568
+ .filter((item) => item.length > 0)
10569
+ .map((item) => ({
10570
+ label: labels[item] ?? item,
10571
+ value: item
10572
+ }))
10573
+ }
10574
+
10575
+ ${exportedExport}async function resolve${singular}SelectFields(
10576
+ rows: ${inputType}[]
10577
+ ): Promise<${outputType}[]> {
10578
+ if (rows.length === 0) return []
10579
+
10580
+ const labelMaps = cloneSelectOptionLabelMaps()
10581
+ ${dynamicRowsBlock}
10582
+ ${labelDeclarations}
10583
+
10584
+ return rows.map((row) => ({
10585
+ ...row,
10586
+ ${assignments}
10587
+ }))
10588
+ }`;
10540
10589
  }
10590
+ function renderResolveSelectFieldsSourceNestedTemplate({
10591
+ staticLabelMaps,
10592
+ exportedExport,
10593
+ singular,
10594
+ rowType,
10595
+ dynamicRowsBlock,
10596
+ assignments
10597
+ }) {
10598
+ return `${renderSelectOptionLabelMapsTemplate({ staticLabelMaps })}
10541
10599
 
10542
10600
  function toSelectOptionValues(value: unknown, labels: Record<string, string>): SelectOptionValue[] {
10543
10601
  const values = Array.isArray(value) ? value : value ? [value] : []
@@ -10566,25 +10624,25 @@ function resolveSelectFieldPath(
10566
10624
  const value = source[fieldName]
10567
10625
  if (Array.isArray(value)) {
10568
10626
  for (const item of value) {
10569
- if (item && typeof item === 'object') {
10570
- resolveSelectFieldPath(item as Record<string, unknown>, rest, labels)
10627
+ if (isRecord(item)) {
10628
+ resolveSelectFieldPath(item, rest, labels)
10571
10629
  }
10572
10630
  }
10573
10631
  return
10574
10632
  }
10575
10633
 
10576
- if (value && typeof value === 'object') {
10577
- resolveSelectFieldPath(value as Record<string, unknown>, rest, labels)
10634
+ if (isRecord(value)) {
10635
+ resolveSelectFieldPath(value, rest, labels)
10578
10636
  }
10579
10637
  }
10580
10638
 
10581
- ${exportedExport}async function resolve${singular}SelectFields(rows: ${singular}[]): Promise<${singular}[]> {
10639
+ ${exportedExport}async function resolve${singular}SelectFields(rows: ${rowType}[]): Promise<${rowType}[]> {
10582
10640
  if (rows.length === 0) return rows
10583
10641
 
10584
10642
  const labelMaps = cloneSelectOptionLabelMaps()
10585
10643
  ${dynamicRowsBlock}
10586
10644
  for (const row of rows) {
10587
- const source = row as unknown as Record<string, unknown>
10645
+ const source: Record<string, unknown> = row
10588
10646
  ${assignments}
10589
10647
  }
10590
10648
 
@@ -10597,6 +10655,8 @@ function renderSelectFieldsResolverRenderer(request) {
10597
10655
  return renderResolveSelectFieldsSourceDynamicRowsTemplate(request.props);
10598
10656
  case "renderResolveSelectFieldsSourceStaticSelectOptionLabelsTemplate":
10599
10657
  return renderResolveSelectFieldsSourceStaticSelectOptionLabelsTemplate(request.props);
10658
+ case "renderResolveSelectFieldsSourceNestedTemplate":
10659
+ return renderResolveSelectFieldsSourceNestedTemplate(request.props);
10600
10660
  }
10601
10661
  throw new Error("Unsupported renderer request");
10602
10662
  }
@@ -10607,6 +10667,7 @@ function generateResolveSelectFieldsSource({
10607
10667
  selectFields,
10608
10668
  selectOptionsTableVar,
10609
10669
  hasCreatableSelectFields,
10670
+ hasMediaFields,
10610
10671
  exported
10611
10672
  }) {
10612
10673
  const staticLabelMaps = selectFields.map((readField) => {
@@ -10620,17 +10681,47 @@ function generateResolveSelectFieldsSource({
10620
10681
  selectOptionsTableVar
10621
10682
  }
10622
10683
  }) : "";
10623
- const assignments = selectFields.map((readField) => {
10624
- const key = readField.path.join(".");
10625
- return ` resolveSelectFieldPath(source, ${JSON.stringify(readField.path)}, labelMaps[${JSON.stringify(key)}] ?? {})`;
10626
- }).join("\n");
10684
+ const hasNestedSelectFields = selectFields.some((readField) => readField.path.length > 1);
10685
+ const resolvedType = hasMediaFields ? `${Singular}MediaResolvable` : Singular;
10686
+ if (hasNestedSelectFields) {
10687
+ const assignments2 = selectFields.map((readField) => {
10688
+ const key = readField.path.join(".");
10689
+ return ` resolveSelectFieldPath(source, ${JSON.stringify(readField.path)}, labelMaps[${JSON.stringify(key)}] ?? {})`;
10690
+ }).join("\n");
10691
+ return renderSelectFieldsResolverRenderer({
10692
+ kind: "renderResolveSelectFieldsSourceNestedTemplate",
10693
+ props: {
10694
+ staticLabelMaps,
10695
+ exportedExport: exported ? "export " : "",
10696
+ singular: Singular,
10697
+ rowType: resolvedType,
10698
+ dynamicRowsBlock,
10699
+ assignments: assignments2
10700
+ }
10701
+ });
10702
+ }
10703
+ const labelVariables = new Map(
10704
+ selectFields.map((readField) => [
10705
+ readField.path[0],
10706
+ `${toCamelCase(singularize(readField.path[0]))}Labels`
10707
+ ])
10708
+ );
10709
+ const labelDeclarations = [...labelVariables].map(
10710
+ ([fieldName, variable]) => ` const ${variable} = labelMaps[${JSON.stringify(fieldName)}] ?? {}`
10711
+ ).join("\n");
10712
+ const assignments = [...labelVariables].map(
10713
+ ([fieldName, variable]) => ` ${fieldName}: toSelectOptionValues(row.${fieldName}, ${variable})`
10714
+ ).join(",\n");
10627
10715
  return renderSelectFieldsResolverRenderer({
10628
10716
  kind: "renderResolveSelectFieldsSourceStaticSelectOptionLabelsTemplate",
10629
10717
  props: {
10630
10718
  staticLabelMaps,
10631
10719
  exportedExport: exported ? "export " : "",
10632
10720
  singular: Singular,
10721
+ inputType: `${Singular}SelectResolvable`,
10722
+ outputType: resolvedType,
10633
10723
  dynamicRowsBlock,
10724
+ labelDeclarations,
10634
10725
  assignments
10635
10726
  }
10636
10727
  });
@@ -10643,6 +10734,7 @@ function generateResolveSelectFieldsFunction(ctx) {
10643
10734
  selectFields: ctx.selectFields,
10644
10735
  selectOptionsTableVar: ctx.selectOptionsTableVar,
10645
10736
  hasCreatableSelectFields: ctx.hasCreatableSelectFields,
10737
+ hasMediaFields: ctx.hasMediaFields,
10646
10738
  exported: true
10647
10739
  });
10648
10740
  }
@@ -10675,11 +10767,10 @@ export function get${ctxSingular}SlugRetryLimit(): number {
10675
10767
  }
10676
10768
 
10677
10769
  export function is${ctxSingular}SlugConflict(error: unknown): boolean {
10678
- if (typeof error !== 'object' || error === null) return false
10679
- const record = error as Record<string, unknown>
10680
- if (record.code !== '23505') return false
10681
- const constraint = typeof record.constraint === 'string' ? record.constraint : ''
10682
- const message = typeof record.message === 'string' ? record.message : ''
10770
+ if (!isRecord(error)) return false
10771
+ if (error.code !== '23505') return false
10772
+ const constraint = typeof error.constraint === 'string' ? error.constraint : ''
10773
+ const message = typeof error.message === 'string' ? error.message : ''
10683
10774
  return constraint === SLUG_CONSTRAINT_NAME || message.includes(SLUG_CONSTRAINT_NAME)
10684
10775
  }
10685
10776
 
@@ -10728,6 +10819,59 @@ function generateSlugHelpers(ctx) {
10728
10819
  });
10729
10820
  }
10730
10821
 
10822
+ // adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-to-entity-function.ts
10823
+ function renderToEntityFunctionTemplate({
10824
+ ctxSingular,
10825
+ ctxTableVar,
10826
+ fieldMappings
10827
+ }) {
10828
+ return `export function to${ctxSingular}(row: typeof ${ctxTableVar}.$inferSelect): ${ctxSingular} {
10829
+ return {
10830
+ ${fieldMappings}
10831
+ }
10832
+ }`;
10833
+ }
10834
+
10835
+ // adapters/next/generators/actions/entity-file-contents/generate-to-entity-function.ts
10836
+ function generateToEntityFunction({
10837
+ Singular,
10838
+ tableVar,
10839
+ allDbFields,
10840
+ htmlOutputFields,
10841
+ m2mFields,
10842
+ mediaFields,
10843
+ galleryFields
10844
+ }) {
10845
+ const rowExpression = (field) => {
10846
+ if (field.type === "relationship") return field.multiple ? "[]" : "null";
10847
+ if (field.type === "select") {
10848
+ return field.multiple ? `(row.${field.name} ?? []).map((value) => ({ label: value, value }))` : `row.${field.name} ? [{ label: row.${field.name}, value: row.${field.name} }] : []`;
10849
+ }
10850
+ return `row.${field.name}`;
10851
+ };
10852
+ const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
10853
+ const hasFormattedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted");
10854
+ const timestampMappings = hasTimestampFields && !hasFormattedTimestampFields ? [
10855
+ " createdAtFormatted: formatActionDate(row.createdAt)",
10856
+ " updatedAtFormatted: formatActionDate(row.updatedAt)"
10857
+ ] : [];
10858
+ const fieldMappings = [
10859
+ ...allDbFields.map((field) => ` ${quotePropertyName(field.name)}: ${rowExpression(field)}`),
10860
+ ...htmlOutputFields.map((field) => ` ${field.name}Html: row.${field.name}Html ?? ''`),
10861
+ ...m2mFields.map((field) => ` ${quotePropertyName(field.name)}: []`),
10862
+ ...mediaFields.map((field) => ` ${quotePropertyName(`${field.name}Media`)}: null`),
10863
+ ...galleryFields.map((field) => ` ${quotePropertyName(`${field.name}Media`)}: []`),
10864
+ ...timestampMappings,
10865
+ " createdByUser: null",
10866
+ " updatedByUser: null"
10867
+ ].join(",\n");
10868
+ return renderToEntityFunctionTemplate({
10869
+ ctxSingular: Singular,
10870
+ ctxTableVar: tableVar,
10871
+ fieldMappings
10872
+ });
10873
+ }
10874
+
10731
10875
  // adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-version-snapshot-helpers.ts
10732
10876
  function renderVersionSnapshotHelpersRowsTemplate({
10733
10877
  fieldName,
@@ -10780,7 +10924,7 @@ const VERSION_RESTORE_KEYS = [${restoreKeys}] as const
10780
10924
  const VERSION_M2M_KEYS = [${m2mKeys}] as const
10781
10925
 
10782
10926
  export function build${ctxSingular}VersionSnapshot(row: Partial<${ctxSingular}> | Record<string, unknown>): Record<string, unknown> {
10783
- const source = row as unknown as Record<string, unknown>
10927
+ const source: Record<string, unknown> = row
10784
10928
  const snapshot: Record<string, unknown> = {}
10785
10929
 
10786
10930
  for (const key of VERSION_SNAPSHOT_KEYS) {
@@ -10895,12 +11039,11 @@ function genHelpersContent(ctx) {
10895
11039
  if (ctx.hasCreatableSelectFields) {
10896
11040
  schemaImports.add(ctx.selectOptionsTableVar);
10897
11041
  }
10898
- if (ctx.hasSlug) {
10899
- schemaImports.add(ctx.tableVar);
10900
- }
11042
+ schemaImports.add(ctx.tableVar);
10901
11043
  if (ctx.hasM2M || ctx.hasListRels || ctx.hasMediaFields || ctx.hasCreatableSelectFields || ctx.hasSlug) {
10902
11044
  lines.push(`import db from '@admin/db'`);
10903
11045
  }
11046
+ lines.push(`import { formatActionDate } from '@admin/utils/date/format-action-date'`);
10904
11047
  const tables = [...schemaImports].sort();
10905
11048
  if (tables.length > 0) {
10906
11049
  lines.push(`import { ${tables.join(", ")} } from '@admin/db/schema'`);
@@ -10914,11 +11057,17 @@ function genHelpersContent(ctx) {
10914
11057
  if (ctx.hasSlug) {
10915
11058
  lines.push(`import { slugify } from '@admin/utils/validation/slugify'`);
10916
11059
  }
10917
- const typeImports = ctx.hasSelectFields ? `${ctx.Singular}, SelectOptionValue` : ctx.Singular;
11060
+ if (ctx.hasSlug || ctx.hasNestedSelectFields || ctx.hasListRels) {
11061
+ lines.push(`import { isRecord } from '@admin/utils/shared/is-record'`);
11062
+ }
11063
+ const typeImports = [
11064
+ ctx.Singular,
11065
+ ...ctx.hasMediaFields ? [`${ctx.Singular}MediaResolvable`] : [],
11066
+ ...ctx.hasSelectFields && !ctx.hasNestedSelectFields ? [`${ctx.Singular}SelectResolvable`] : [],
11067
+ ...ctx.hasSelectFields ? ["SelectOptionValue"] : []
11068
+ ].join(", ");
10918
11069
  lines.push(`import type { ${typeImports} } from './types'`);
10919
11070
  lines.push("");
10920
- lines.push(buildFormatActionDateSource({ exported: true }));
10921
- lines.push("");
10922
11071
  if (ctx.hasSlug) {
10923
11072
  lines.push(generateSlugHelpers(ctx));
10924
11073
  lines.push("");
@@ -10932,6 +11081,18 @@ function genHelpersContent(ctx) {
10932
11081
  lines.push(generateResolveMediaFunction(ctx));
10933
11082
  lines.push("");
10934
11083
  }
11084
+ lines.push(
11085
+ generateToEntityFunction({
11086
+ Singular: ctx.Singular,
11087
+ tableVar: ctx.tableVar,
11088
+ allDbFields: ctx.allDbFields,
11089
+ htmlOutputFields: ctx.htmlOutputFields,
11090
+ m2mFields: ctx.m2mFields,
11091
+ mediaFields: ctx.mediaFields,
11092
+ galleryFields: ctx.galleryFields
11093
+ })
11094
+ );
11095
+ lines.push("");
10935
11096
  if (ctx.hasSelectFields) {
10936
11097
  lines.push(generateResolveSelectFieldsFunction(ctx));
10937
11098
  lines.push("");
@@ -11162,10 +11323,12 @@ import { ${ctxCamelPlural}CacheTags } from './types'
11162
11323
  import { get${ctxSingular}ById } from './get-${kebabSingular}-by-id'
11163
11324
  import {
11164
11325
  build${ctxSingular}RestoreData,
11165
- ${snapshotImport}
11326
+ ${snapshotImport},
11327
+ to${ctxSingular}
11166
11328
  } from './helpers'
11167
11329
  ${lifecycleHookImport2}
11168
- import type { ${ctxSingular}UpdateResult, ${ctxSingular} } from './types'
11330
+ import { isRecord } from '@admin/utils/shared/is-record'
11331
+ import type { ${ctxSingular}UpdateResult } from './types'
11169
11332
 
11170
11333
  export async function restore${ctxSingular}Version(
11171
11334
  versionId: string
@@ -11184,7 +11347,7 @@ export async function restore${ctxSingular}Version(
11184
11347
 
11185
11348
  if (!versionRow) throw new Error('${ctxSingular} version not found')
11186
11349
 
11187
- const versionData = versionRow.data as Record<string, unknown>
11350
+ const versionData = isRecord(versionRow.data) ? versionRow.data : {}
11188
11351
  const restoreData = build${ctxSingular}RestoreData(versionData)
11189
11352
  const auditRequestMetadata = await getAuditRequestMetadata()
11190
11353
  const lifecycleContext = ${restoreContext}
@@ -11222,7 +11385,7 @@ ${restoreM2MContent}
11222
11385
 
11223
11386
  return {
11224
11387
  success: true,
11225
- ${ctxCamelSingular}: restored${ctxSingular} ?? (result[0] as unknown as ${ctxSingular})
11388
+ ${ctxCamelSingular}: restored${ctxSingular} ?? to${ctxSingular}(result[0])
11226
11389
  }
11227
11390
  } catch (error) {
11228
11391
  console.error('Error restoring ${ctxSingularText} version:', error)
@@ -11234,7 +11397,7 @@ ${restoreM2MContent}
11234
11397
  function renderGenRestoreContentTemplate({ ctxSingular }) {
11235
11398
  return `{
11236
11399
  ...lifecycleContext,
11237
- data: (restored${ctxSingular} ?? result[0]) as unknown as Record<string, unknown>
11400
+ data: restored${ctxSingular} ?? to${ctxSingular}(result[0])
11238
11401
  }`;
11239
11402
  }
11240
11403
  function renderGenRestoreContentRenderer(request) {
@@ -11300,7 +11463,7 @@ function genRestoreContent(ctx) {
11300
11463
  metadata: { restoredFromVersion: versionRow.version }`
11301
11464
  );
11302
11465
  const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
11303
- const currentSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(currentRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(currentRow as unknown as ${ctx.Singular})`;
11466
+ const currentSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(currentRow, tx)` : `build${ctx.Singular}VersionSnapshot(currentRow)`;
11304
11467
  const dbImports = [
11305
11468
  "entityVersions",
11306
11469
  ctx.tableVar,
@@ -11467,10 +11630,11 @@ import {
11467
11630
  is${ctxSingular}SlugConflict,
11468
11631
  resolveUnique${ctxSingular}Slug,
11469
11632
  ${snapshotImport},
11470
- has${ctxSingular}VersionChanges
11633
+ has${ctxSingular}VersionChanges,
11634
+ to${ctxSingular}
11471
11635
  } from './helpers'
11472
11636
  ${lifecycleHookImport2}
11473
- import type { ${ctxSingular}UpdateInput, ${ctxSingular}UpdateResult, ${ctxSingular} } from './types'${markdownImport}
11637
+ import type { ${ctxSingular}UpdateInput, ${ctxSingular}UpdateResult } from './types'${markdownImport}
11474
11638
 
11475
11639
  export async function update${ctxSingular}(input: ${ctxSingular}UpdateInput): Promise<${ctxSingular}UpdateResult> {
11476
11640
  const actor = await requireRole([UserRole.ADMIN, UserRole.EDITOR])
@@ -11531,10 +11695,7 @@ ${updateBeforePublishBlock}
11531
11695
  }
11532
11696
  }
11533
11697
  ${htmlUpdateBlock}
11534
- changedFields = getChangedFieldNames(
11535
- previousRow as unknown as Record<string, unknown>,
11536
- processedData
11537
- )
11698
+ changedFields = getChangedFieldNames(previousRow, processedData)
11538
11699
  result = await db.transaction(async (tx) => {
11539
11700
  const previousSnapshot = ${previousSnapshot}
11540
11701
  const nextSnapshot = {
@@ -11574,7 +11735,7 @@ ${htmlUpdateBlock}
11574
11735
  ${ctxCacheInvalidationFn}(${ctxCamelPlural}CacheTags.byId(id))
11575
11736
  ${ctxCacheInvalidationFn}(entityVersionsCacheTags.for('${ctxPlural}', id))
11576
11737
  const updated${ctxSingular} = await get${ctxSingular}ById(id)
11577
- const updated${ctxSingular}Data = updated${ctxSingular} ?? (result[0] as unknown as ${ctxSingular})
11738
+ const updated${ctxSingular}Data = updated${ctxSingular} ?? to${ctxSingular}(result[0])
11578
11739
  const updated${ctxSingular}Context = ${updateResultContext}
11579
11740
  ${updateAfterPublishBlock}
11580
11741
  ${afterHook2}
@@ -11596,7 +11757,7 @@ function genUpdateContent(ctx) {
11596
11757
  const kebabSingular = toKebabCase(ctx.singular);
11597
11758
  const slugSourceValue = ctx.slugSourceField ? `updateData.${ctx.slugSourceField} ?? previousRow.${ctx.slugSourceField}` : "undefined";
11598
11759
  const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
11599
- const previousSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(previousRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(previousRow as unknown as ${ctx.Singular})`;
11760
+ const previousSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(previousRow, tx)` : `build${ctx.Singular}VersionSnapshot(previousRow)`;
11600
11761
  const markdownImport = ctx.hasHtmlOutput ? `
11601
11762
  import { renderMarkdownSync } from './markdown'` : "";
11602
11763
  const htmlUpdateBlock = ctx.hasHtmlOutput ? `
@@ -11609,14 +11770,14 @@ import { renderMarkdownSync } from './markdown'` : "";
11609
11770
  ctx.plural,
11610
11771
  `,
11611
11772
  entityId: id,
11612
- input: updateData as unknown as Record<string, unknown>`
11773
+ input: updateData`
11613
11774
  );
11614
11775
  const updateResultContext = lifecycleContext(
11615
11776
  ctx.plural,
11616
11777
  `,
11617
11778
  entityId: id,
11618
- input: updateData as unknown as Record<string, unknown>,
11619
- data: updated${ctx.Singular}Data as unknown as Record<string, unknown>,
11779
+ input: updateData,
11780
+ data: updated${ctx.Singular}Data,
11620
11781
  changedFields`
11621
11782
  );
11622
11783
  const updateBeforePublishBlock = ctx.hasDraft ? `
@@ -12132,7 +12293,7 @@ ${selects}
12132
12293
 
12133
12294
  // adapters/next/templates/renderers/generators/actions/action-helpers/build-read-select-option-type.ts
12134
12295
  function renderBuildReadSelectOptionTypeComponentTemplate() {
12135
- return `export interface SelectOptionValue {
12296
+ return `export type SelectOptionValue = {
12136
12297
  label: string
12137
12298
  value: string
12138
12299
  }`;
@@ -12237,19 +12398,13 @@ ${[regularSelects, relSelects, ...extraSelects].filter(Boolean).join(",\n")}
12237
12398
  // adapters/next/templates/renderers/generators/actions/action-helpers/build-result-mapping.ts
12238
12399
  function renderBuildResultMappingResultTemplate({
12239
12400
  plural,
12240
- rowDeclarations,
12241
12401
  rowMappings
12242
12402
  }) {
12243
12403
  return `
12244
12404
 
12245
- const mapped${plural} = results.map((rawRow) => {
12246
- const row = rawRow as Record<string, unknown>
12247
- ${rowDeclarations}
12248
-
12249
- return {
12405
+ const mapped${plural} = results.map((row) => ({
12250
12406
  ${rowMappings}
12251
- }
12252
- })`;
12407
+ }))`;
12253
12408
  }
12254
12409
  function renderBuildResultMappingResultDetailsTemplate({
12255
12410
  mapBlock,
@@ -12260,7 +12415,7 @@ function renderBuildResultMappingResultDetailsTemplate({
12260
12415
  return `${mapBlock}
12261
12416
 
12262
12417
  const populated${plural} = await Promise.all(
12263
- mapped${plural}.map(record => populate${singular}ListRelationships(record as ${singular}))
12418
+ mapped${plural}.map((record) => populate${singular}ListRelationships(record))
12264
12419
  )
12265
12420
 
12266
12421
  return {
@@ -12271,13 +12426,12 @@ function renderBuildResultMappingResultDetailsTemplate({
12271
12426
  function renderBuildResultMappingResultDetailsBranchTemplate({
12272
12427
  mapBlock,
12273
12428
  camelPlural,
12274
- plural,
12275
- singular
12429
+ plural
12276
12430
  }) {
12277
12431
  return `${mapBlock}
12278
12432
 
12279
12433
  return {
12280
- ${camelPlural}: mapped${plural} as unknown as ${singular}[],
12434
+ ${camelPlural}: mapped${plural},
12281
12435
  total
12282
12436
  }`;
12283
12437
  }
@@ -12298,40 +12452,58 @@ function relationshipMappingExpression(field, valueExpression) {
12298
12452
  return isUserRelationshipTarget(field.relationship) ? `${valueExpression}?.id ? { id: ${valueExpression}.id, name: ${valueExpression}.name ?? undefined, email: ${valueExpression}.email ?? undefined } : null` : `${valueExpression}?.id ? { id: ${valueExpression}.id, name: ${valueExpression}.name ?? undefined, title: ${valueExpression}.title ?? undefined, slug: ${valueExpression}.slug ?? undefined, label: ${valueExpression}.label ?? undefined } : null`;
12299
12453
  }
12300
12454
 
12301
- // adapters/next/generators/actions/action-helpers/relationship-row-type.ts
12302
- function relationshipRowType(field) {
12303
- return isUserRelationshipTarget(field.relationship) ? "{ id?: string | null; name?: string | null; email?: string | null }" : "{ id?: string | null; name?: string | null; title?: string | null; slug?: string | null; label?: string | null }";
12455
+ // adapters/next/generators/actions/action-helpers/build-row-mapping-entries.ts
12456
+ function buildRowMappingEntries({
12457
+ allDbFields,
12458
+ htmlOutputFields,
12459
+ includeHtmlValues,
12460
+ m2mEntries,
12461
+ indent
12462
+ }) {
12463
+ const excludedHtmlSources = new Set(
12464
+ includeHtmlValues ? [] : htmlOutputFields.map((field) => field.name)
12465
+ );
12466
+ const valueExpression = (field) => {
12467
+ if (excludedHtmlSources.has(field.name)) return "null";
12468
+ if (field.type === "relationship" && !field.multiple) {
12469
+ return relationshipMappingExpression(field, `row.${field.name}`);
12470
+ }
12471
+ if (field.type === "select") {
12472
+ return field.multiple ? `row.${field.name} ?? []` : `row.${field.name} ? [row.${field.name}] : []`;
12473
+ }
12474
+ return `row.${field.name}`;
12475
+ };
12476
+ const timestampEntries = allDbFields.some((field) => field.name === "createdAtFormatted") ? [] : [
12477
+ `${indent}createdAtFormatted: formatActionDate(row.createdAt)`,
12478
+ `${indent}updatedAtFormatted: formatActionDate(row.updatedAt)`
12479
+ ];
12480
+ return [
12481
+ ...allDbFields.map(
12482
+ (field) => `${indent}${quotePropertyName(field.name)}: ${valueExpression(field)}`
12483
+ ),
12484
+ ...htmlOutputFields.map(
12485
+ (field) => `${indent}${field.name}Html: ${includeHtmlValues ? `row.${field.name}Html ?? ''` : "''"}`
12486
+ ),
12487
+ ...m2mEntries.map((entry) => `${indent}${entry}`),
12488
+ ...timestampEntries,
12489
+ `${indent}createdByUser: row.createdByUser?.id ? { id: row.createdByUser.id, name: row.createdByUser.name, email: row.createdByUser.email } : null`,
12490
+ `${indent}updatedByUser: row.updatedByUser?.id ? { id: row.updatedByUser.id, name: row.updatedByUser.name, email: row.updatedByUser.email } : null`
12491
+ ];
12304
12492
  }
12305
12493
 
12306
12494
  // adapters/next/generators/actions/action-helpers/build-result-mapping.ts
12307
- function buildResultMapping(allDbFields, relationshipFields, Plural, camelPlural, Singular, hasListRels = false) {
12308
- const relationshipDeclarations = relationshipFields.map(
12309
- (f) => ` const ${f.name} = row.${f.name} as ${relationshipRowType(f)} | null | undefined`
12310
- ).join("\n");
12311
- const rowDeclarations = [
12312
- relationshipDeclarations,
12313
- ` const createdByUser = row.createdByUser as { id?: string | null; name?: string | null; email?: string | null } | null | undefined`,
12314
- ` const updatedByUser = row.updatedByUser as { id?: string | null; name?: string | null; email?: string | null } | null | undefined`
12315
- ].filter(Boolean).join("\n");
12316
- const mappedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted") ? [] : [
12317
- ` createdAtFormatted: formatActionDate(row.createdAt)`,
12318
- ` updatedAtFormatted: formatActionDate(row.updatedAt)`
12319
- ];
12320
- const rowMappings = allDbFields.map((f) => {
12321
- if (f.type === "relationship" && !f.multiple) {
12322
- return ` ${f.name}: ${relationshipMappingExpression(f, f.name)}`;
12323
- }
12324
- return ` ${f.name}: row.${f.name}`;
12325
- }).concat([
12326
- ...mappedTimestampFields,
12327
- ` createdByUser: createdByUser?.id ? { id: createdByUser.id, name: createdByUser.name ?? '', email: createdByUser.email ?? '' } : null`,
12328
- ` updatedByUser: updatedByUser?.id ? { id: updatedByUser.id, name: updatedByUser.name ?? '', email: updatedByUser.email ?? '' } : null`
12329
- ]).join(",\n");
12495
+ function buildResultMapping(allDbFields, htmlOutputFields, includeHtmlValues, m2mEntries, Plural, camelPlural, Singular, hasListRels = false) {
12496
+ const rowMappings = buildRowMappingEntries({
12497
+ allDbFields,
12498
+ htmlOutputFields,
12499
+ includeHtmlValues,
12500
+ m2mEntries,
12501
+ indent: " "
12502
+ }).join(",\n");
12330
12503
  const mapBlock = renderBuildResultMappingRenderer({
12331
12504
  kind: "renderBuildResultMappingResultTemplate",
12332
12505
  props: {
12333
12506
  plural: Plural,
12334
- rowDeclarations,
12335
12507
  rowMappings
12336
12508
  }
12337
12509
  });
@@ -12351,41 +12523,29 @@ function buildResultMapping(allDbFields, relationshipFields, Plural, camelPlural
12351
12523
  props: {
12352
12524
  mapBlock,
12353
12525
  camelPlural,
12354
- plural: Plural,
12355
- singular: Singular
12526
+ plural: Plural
12356
12527
  }
12357
12528
  });
12358
12529
  }
12359
12530
 
12360
12531
  // adapters/next/generators/actions/action-helpers/build-single-row-mapping.ts
12361
- function buildSingleRowMapping(allDbFields, _relationshipFields, typeName, htmlFields = []) {
12362
- const fieldMappings = allDbFields.map((f) => {
12363
- if (f.type === "relationship" && !f.multiple) {
12364
- return ` ${f.name}: ${relationshipMappingExpression(f, `row.${f.name}`)}`;
12365
- }
12366
- return ` ${f.name}: row.${f.name}`;
12367
- });
12368
- const htmlMappings = htmlFields.map((f) => ` ${f.name}Html: row.${f.name}Html`);
12369
- const singleTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted") ? [] : [
12370
- ` createdAtFormatted: formatActionDate(row.createdAt)`,
12371
- ` updatedAtFormatted: formatActionDate(row.updatedAt)`
12372
- ];
12373
- const mappings = [
12374
- ...fieldMappings,
12375
- ...htmlMappings,
12376
- ...singleTimestampFields,
12377
- ` createdByUser: row.createdByUser?.id ? { id: row.createdByUser.id, name: row.createdByUser.name, email: row.createdByUser.email } : null`,
12378
- ` updatedByUser: row.updatedByUser?.id ? { id: row.updatedByUser.id, name: row.updatedByUser.name, email: row.updatedByUser.email } : null`
12379
- ].join(",\n");
12532
+ function buildSingleRowMapping(allDbFields, htmlOutputFields = [], m2mEntries = []) {
12533
+ const mappings = buildRowMappingEntries({
12534
+ allDbFields,
12535
+ htmlOutputFields,
12536
+ includeHtmlValues: true,
12537
+ m2mEntries,
12538
+ indent: " "
12539
+ }).join(",\n");
12380
12540
  return `{
12381
12541
  ${mappings}
12382
- } as unknown as ${typeName}`;
12542
+ }`;
12383
12543
  }
12384
12544
 
12385
12545
  // adapters/next/generators/actions/action-helpers/collect-read-select-fields.ts
12386
- function collectReadSelectFields(fields, path113 = []) {
12546
+ function collectReadSelectFields(fields, path114 = []) {
12387
12547
  const matches = fields.flatMap((field) => {
12388
- const currentPath = [...path113, field.name];
12548
+ const currentPath = [...path114, field.name];
12389
12549
  const matches2 = field.type === "select" ? [{ field, path: currentPath }] : [];
12390
12550
  if (field.fields) {
12391
12551
  matches2.push(...collectReadSelectFields(field.fields, currentPath));
@@ -12450,21 +12610,23 @@ function renderPopulateListRelsFunctionResultTemplate({
12450
12610
  qRelFieldName,
12451
12611
  qRelTable
12452
12612
  }) {
12453
- return ` const ${v}Ids = record.${qListFieldName} && Array.isArray(record.${qListFieldName})
12454
- ? (record.${qListFieldName} as Record<string, unknown>[])
12455
- .map((item) => item.${qRelFieldName})
12456
- .filter((id) => id != null && id !== '')
12457
- .map((id) => String(id))
12613
+ return ` const ${v}Items = Array.isArray(source.${qListFieldName})
12614
+ ? source.${qListFieldName}.filter(isRecord)
12458
12615
  : []
12459
12616
 
12617
+ const ${v}Ids = ${v}Items
12618
+ .map((item) => item.${qRelFieldName})
12619
+ .filter((id) => id != null && id !== '')
12620
+ .map((id) => String(id))
12621
+
12460
12622
  const ${v}Results = ${v}Ids.length > 0
12461
12623
  ? await db.select().from(${qRelTable}).where(inArray(${qRelTable}.id, ${v}Ids))
12462
12624
  : []
12463
12625
 
12464
12626
  const ${v}Map = new Map(${v}Results.map((r) => [r.id, r]))
12465
12627
 
12466
- if (record.${qListFieldName} && Array.isArray(record.${qListFieldName})) {
12467
- record.${qListFieldName} = (record.${qListFieldName} as Record<string, unknown>[]).map((item) => {
12628
+ if (${v}Items.length > 0) {
12629
+ source.${qListFieldName} = ${v}Items.map((item) => {
12468
12630
  const relId = item.${qRelFieldName} ? String(item.${qRelFieldName}) : null
12469
12631
  return {
12470
12632
  ...item,
@@ -12478,7 +12640,10 @@ function renderPopulateListRelsFunctionContentTemplate({
12478
12640
  join
12479
12641
  }) {
12480
12642
  return `
12481
- async function populate${singular}ListRelationships(record: ${singular}): Promise<${singular}> {
12643
+ async function populate${singular}ListRelationships<Row extends Record<string, unknown>>(
12644
+ record: Row
12645
+ ): Promise<Row> {
12646
+ const source: Record<string, unknown> = record
12482
12647
  ${join}
12483
12648
 
12484
12649
  return record
@@ -12952,6 +13117,7 @@ function buildEntityContext(schema, nextMajorVersion) {
12952
13117
  const hasCreatableSelectFields = creatableSelectFields.length > 0;
12953
13118
  const selectFields = collectReadSelectFields(allDbFields);
12954
13119
  const hasSelectFields = selectFields.length > 0;
13120
+ const hasNestedSelectFields = selectFields.some((readField) => readField.path.length > 1);
12955
13121
  const dateRangeFilterFields = new Set(
12956
13122
  resolvedFilters.filter((filter) => filter.type === "date-range").map((filter) => filter.field)
12957
13123
  );
@@ -12995,19 +13161,31 @@ import type { AdminMedia } from '@admin/types'
12995
13161
  const timestampFields = hasTimestampFields && !hasFormattedTimestampFields ? "\n createdAtFormatted: string\n updatedAtFormatted: string" : "";
12996
13162
  const readSelectOptionType = buildReadSelectOptionType(selectFields);
12997
13163
  const relationshipDataTypes = buildRelationshipDataTypes(allDbFields);
13164
+ const mediaCompanionKeys = [...mediaFields, ...galleryFields].map((f) => JSON.stringify(`${f.name}Media`)).join(" | ");
13165
+ const mediaResolvableType = hasMediaFields ? `
13166
+
13167
+ export type ${Singular}MediaResolvable = Omit<${Singular}, ${mediaCompanionKeys}>` : "";
13168
+ const selectResolvableBase = hasMediaFields ? `${Singular}MediaResolvable` : Singular;
13169
+ const topLevelSelectKeys = selectFields.map((readField) => JSON.stringify(readField.path[0])).join(" | ");
13170
+ const selectResolvableFields = selectFields.map((readField) => ` ${quotePropertyName(readField.path[0])}: string[]`).join("\n");
13171
+ const selectResolvableType = hasSelectFields && !hasNestedSelectFields ? `
13172
+
13173
+ export type ${Singular}SelectResolvable = Omit<${selectResolvableBase}, ${topLevelSelectKeys}> & {
13174
+ ${selectResolvableFields}
13175
+ }` : "";
12998
13176
  const dataInterface = `${mediaTypeImport}${buildAuthorshipUserType()}${readSelectOptionType ? `
12999
13177
 
13000
13178
  ${readSelectOptionType}` : ""}${relationshipDataTypes ? `
13001
13179
 
13002
13180
  ${relationshipDataTypes}` : ""}
13003
13181
 
13004
- export interface ${Singular} {
13182
+ export type ${Singular} = {
13005
13183
  ${dataFields}${htmlFieldTypes ? `
13006
13184
  ${htmlFieldTypes}` : ""}${m2mFieldTypes ? `
13007
13185
  ${m2mFieldTypes}` : ""}${mediaCompanionTypes ? `
13008
13186
  ${mediaCompanionTypes}` : ""}${timestampFields}
13009
13187
  ${buildAuthorshipDataFields()}
13010
- }`;
13188
+ }${mediaResolvableType}${selectResolvableType}`;
13011
13189
  const responseInterface = `export interface ${Plural}Page {
13012
13190
  ${camelPlural}: ${Singular}[]
13013
13191
  total: number
@@ -13033,12 +13211,12 @@ ${filtersInterfaceFields}
13033
13211
  const createInterfaceFields = createFields.map(
13034
13212
  (f) => ` ${quotePropertyName(f.name)}${f.required && f.name !== "slug" ? "" : "?"}: ${getInputFieldType(f)}`
13035
13213
  ).join("\n");
13036
- const createInterface = `export interface ${Singular}CreateInput {
13214
+ const createInterface = `export type ${Singular}CreateInput = {
13037
13215
  ${createInterfaceFields}${hasDraft ? `
13038
13216
  published?: boolean` : ""}
13039
13217
  }`;
13040
13218
  const updateInterfaceFields = createFields.map((f) => ` ${quotePropertyName(f.name)}?: ${getInputFieldType(f)}`).join("\n");
13041
- const updateInterface = `export interface ${Singular}UpdateInput {
13219
+ const updateInterface = `export type ${Singular}UpdateInput = {
13042
13220
  id: string
13043
13221
  ${updateInterfaceFields}${hasDraft ? `
13044
13222
  published?: boolean` : ""}
@@ -13096,9 +13274,12 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
13096
13274
  )
13097
13275
  }
13098
13276
  ` : "";
13277
+ const m2mMappingEntries = m2mFields.map((f) => `${quotePropertyName(f.name)}: []`);
13099
13278
  const baseResultMapping = buildResultMapping(
13100
13279
  allDbFields,
13101
- relationshipFields,
13280
+ htmlOutputFields,
13281
+ true,
13282
+ m2mMappingEntries,
13102
13283
  Plural,
13103
13284
  camelPlural,
13104
13285
  Singular,
@@ -13107,8 +13288,10 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
13107
13288
  const selectResultMapping = hasSelectFields ? wrapWithSelectResolution(baseResultMapping, camelPlural, Singular) : baseResultMapping;
13108
13289
  const resultMapping = hasMediaFields ? wrapWithMediaResolution(selectResultMapping, camelPlural, Singular) : selectResultMapping;
13109
13290
  const baseListResultMapping = hasHtmlOutput ? buildResultMapping(
13110
- listDbFields,
13111
- relationshipFields,
13291
+ allDbFields,
13292
+ htmlOutputFields,
13293
+ false,
13294
+ m2mMappingEntries,
13112
13295
  Plural,
13113
13296
  camelPlural,
13114
13297
  Singular,
@@ -13123,12 +13306,7 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
13123
13306
  const htmlCreateMappings = htmlOutputFields.map((f) => ` ${f.name}Html`).join(",\n");
13124
13307
  const cacheTag = `${plural}:all`;
13125
13308
  const baseSingleRowReturn = (() => {
13126
- const singleRowMapping = buildSingleRowMapping(
13127
- allDbFields,
13128
- relationshipFields,
13129
- Singular,
13130
- htmlOutputFields
13131
- );
13309
+ const singleRowMapping = buildSingleRowMapping(allDbFields, htmlOutputFields, m2mMappingEntries);
13132
13310
  if (hasRelationships && hasListRels) {
13133
13311
  return `const row = result[0]
13134
13312
  return await populate${Singular}ListRelationships(${singleRowMapping})`;
@@ -13180,12 +13358,14 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
13180
13358
  hasSearch,
13181
13359
  hasFilters,
13182
13360
  hasSelectFields,
13361
+ hasNestedSelectFields,
13183
13362
  hasCreatableSelectFields,
13184
13363
  searchFields,
13185
13364
  htmlOutputFields,
13186
13365
  selectFields,
13187
13366
  creatableSelectFields,
13188
13367
  m2mFields,
13368
+ allDbFields,
13189
13369
  filterableFields,
13190
13370
  relTableImports,
13191
13371
  listRelTableImports,
@@ -13968,7 +14148,7 @@ function renderFirstColumnDefLayoutGenerateAuthorshipValueTemplate({
13968
14148
  aria-label="Select row"
13969
14149
  />
13970
14150
  {label ? (
13971
- <span className="text-sm font-medium truncate max-w-[300px]" title={actor?.email}>
14151
+ <span className="text-sm font-medium truncate max-w-table-cell" title={actor?.email}>
13972
14152
  {label}
13973
14153
  </span>
13974
14154
  ) : (
@@ -14079,7 +14259,7 @@ function renderEmailColumnCell({ columnAccessorKey }) {
14079
14259
  onCheckedChange={(value) => row.toggleSelected(!!value)}
14080
14260
  aria-label="Select row"
14081
14261
  />
14082
- <span className="text-sm font-medium truncate max-w-[300px]">{email}</span>
14262
+ <span className="text-sm font-medium truncate max-w-table-cell">{email}</span>
14083
14263
  </div>
14084
14264
  )
14085
14265
  }`;
@@ -14168,7 +14348,7 @@ function renderSelectLabelCell({
14168
14348
  onCheckedChange={(value) => row.toggleSelected(!!value)}
14169
14349
  aria-label="Select row"
14170
14350
  />
14171
- <span className="truncate max-w-[300px]">
14351
+ <span className="truncate max-w-table-cell">
14172
14352
  {label || 'Unavailable'}
14173
14353
  </span>
14174
14354
  </div>
@@ -14189,7 +14369,7 @@ function renderRelationshipLabelCell({
14189
14369
  onCheckedChange={(value) => row.toggleSelected(!!value)}
14190
14370
  aria-label="Select row"
14191
14371
  />
14192
- <span className="truncate max-w-[300px]">
14372
+ <span className="truncate max-w-table-cell">
14193
14373
  {label || 'Unavailable'}
14194
14374
  </span>
14195
14375
  </div>
@@ -14206,7 +14386,7 @@ function renderPlainValueCell({ columnAccessorKey }) {
14206
14386
  onCheckedChange={(value) => row.toggleSelected(!!value)}
14207
14387
  aria-label="Select row"
14208
14388
  />
14209
- <span className="truncate max-w-[300px]">
14389
+ <span className="truncate max-w-table-cell">
14210
14390
  {value === null || value === undefined ? 'Unavailable' : String(value)}
14211
14391
  </span>
14212
14392
  </div>
@@ -15592,6 +15772,119 @@ function buildDefaultValues2(flatFields, dataSource = "initialData", sourceField
15592
15772
  }).join(",\n");
15593
15773
  }
15594
15774
 
15775
+ // adapters/next/generators/form/field-jsx-nested/empty-nested-field-value.ts
15776
+ function emptyNestedFieldValue(field) {
15777
+ if ((field.type === "group" || field.type === "section") && field.fields?.length) {
15778
+ return objectValueForFields(field.fields);
15779
+ }
15780
+ if (field.type === "list" || field.type === "gallery") return "[]";
15781
+ if (field.type === "relationship" && field.multiple) return "[]";
15782
+ if (field.type === "select" && field.multiple) return "[]";
15783
+ if (field.type === "boolean") return "false";
15784
+ if (field.type === "number" || field.type === "decimal") return field.required ? "0" : "undefined";
15785
+ return "''";
15786
+ }
15787
+
15788
+ // adapters/next/generators/form/field-jsx-nested/object-entries-for-fields.ts
15789
+ function objectEntriesForFields(fields) {
15790
+ return fields.flatMap((field) => {
15791
+ const entries = [`${quotePropertyName(field.name)}: ${emptyNestedFieldValue(field)}`];
15792
+ if (field.hasIcon) {
15793
+ entries.push(`${quotePropertyName(`${field.name}Icon`)}: ''`);
15794
+ }
15795
+ return entries;
15796
+ });
15797
+ }
15798
+
15799
+ // adapters/next/generators/form/field-jsx-nested/object-value-for-fields.ts
15800
+ function objectValueForFields(fields) {
15801
+ return `{${objectEntriesForFields(fields).join(", ")}}`;
15802
+ }
15803
+
15804
+ // adapters/next/generators/form/field-jsx-nested/required-leaf-paths.ts
15805
+ function requiredLeafPaths(fields, prefix = []) {
15806
+ return fields.flatMap((field) => {
15807
+ if (field.hidden) return [];
15808
+ const path114 = [...prefix, field.name];
15809
+ if ((field.type === "group" || field.type === "section") && field.fields?.length) {
15810
+ return requiredLeafPaths(field.fields, path114);
15811
+ }
15812
+ if (field.required) return [path114.join(".")];
15813
+ return [];
15814
+ });
15815
+ }
15816
+
15817
+ // adapters/next/generators/form/field-jsx-nested/validation-trigger-expression.ts
15818
+ function validationTriggerExpression(basePath, requiredPaths) {
15819
+ if (requiredPaths.length === 0) return `\`${basePath}.\${expandedIndex}\` as never`;
15820
+ const paths = requiredPaths.map((path114) => `\`${basePath}.\${expandedIndex}.${path114}\``).join(", ");
15821
+ return `[${paths}] as never`;
15822
+ }
15823
+
15824
+ // adapters/next/templates/renderers/generators/form/form-shared/build-list-field-handlers.ts
15825
+ function renderListFieldHandlersTemplate({
15826
+ fieldName,
15827
+ pascalFieldName,
15828
+ itemName,
15829
+ validateExpandedItemExpression,
15830
+ defaultItem
15831
+ }) {
15832
+ return ` async function isExpanded${itemName}Valid() {
15833
+ if (!${fieldName}Expanded) return true
15834
+
15835
+ const expandedIndex = Number(${fieldName}Expanded.replace('item-', '')) - 1
15836
+ if (expandedIndex < 0) return true
15837
+
15838
+ return form.trigger(${validateExpandedItemExpression})
15839
+ }
15840
+
15841
+ async function add${itemName}() {
15842
+ if (!(await isExpanded${itemName}Valid())) return
15843
+
15844
+ ${fieldName}FieldArray.append(${defaultItem})
15845
+ set${pascalFieldName}Expanded(\`item-\${${fieldName}FieldArray.fields.length + 1}\`)
15846
+ }
15847
+
15848
+ async function changeExpanded${itemName}(nextValue: string[]) {
15849
+ const nextExpanded = nextValue[0] ?? ''
15850
+ const needsValidation = Boolean(${fieldName}Expanded && nextExpanded && nextExpanded !== ${fieldName}Expanded)
15851
+ if (needsValidation && !(await isExpanded${itemName}Valid())) return
15852
+
15853
+ set${pascalFieldName}Expanded(nextExpanded)
15854
+ }
15855
+
15856
+ function remove${itemName}(index: number) {
15857
+ if (isPending) return
15858
+ ${fieldName}FieldArray.remove(index)
15859
+ }`;
15860
+ }
15861
+
15862
+ // adapters/next/generators/form/form-shared/build-list-field-handlers.ts
15863
+ function buildListFieldHandlers(fields) {
15864
+ return fields.map((field) => {
15865
+ const itemName = toPascalCase(singularize(field.name));
15866
+ const pascalFieldName = toPascalCase(field.name);
15867
+ return {
15868
+ names: [
15869
+ `isExpanded${itemName}Valid`,
15870
+ `add${itemName}`,
15871
+ `changeExpanded${itemName}`,
15872
+ `remove${itemName}`
15873
+ ],
15874
+ source: renderListFieldHandlersTemplate({
15875
+ fieldName: field.name,
15876
+ pascalFieldName,
15877
+ itemName,
15878
+ validateExpandedItemExpression: validationTriggerExpression(
15879
+ field.name,
15880
+ requiredLeafPaths(field.fields ?? [])
15881
+ ),
15882
+ defaultItem: objectValueForFields(field.fields ?? [])
15883
+ })
15884
+ };
15885
+ });
15886
+ }
15887
+
15595
15888
  // adapters/next/templates/renderers/generators/form/form-shared/build-ui-imports.ts
15596
15889
  function renderBuildUiImportsImportsTemplate({ join }) {
15597
15890
  return `import {
@@ -16071,7 +16364,7 @@ function renderFormLayoutDetailsBranchTemplate() {
16071
16364
  className={cn(
16072
16365
  'grid grid-cols-1 gap-4 items-start h-full',
16073
16366
  {
16074
- 'grid-cols-[1fr_360px]': hasVisibleSidebarFields
16367
+ 'grid-cols-entity-form': hasVisibleSidebarFields
16075
16368
  }
16076
16369
  )}
16077
16370
  >`;
@@ -16120,6 +16413,7 @@ function renderFormClientModuleTemplate({
16120
16413
  specComponentName,
16121
16414
  hookName,
16122
16415
  tabStateDestructure,
16416
+ listFieldHandlers,
16123
16417
  body
16124
16418
  }) {
16125
16419
  return `'use client'
@@ -16131,7 +16425,7 @@ interface ${specComponentName}Props {
16131
16425
  }
16132
16426
 
16133
16427
  export function ${specComponentName}({ state }: ${specComponentName}Props) {
16134
- ${tabStateDestructure} return (
16428
+ ${tabStateDestructure}${listFieldHandlers} return (
16135
16429
  ${body}
16136
16430
  )
16137
16431
  }
@@ -16145,6 +16439,7 @@ function renderEntityFormContent({
16145
16439
  topLevelTabsFieldTabTab,
16146
16440
  contentStateDestructure,
16147
16441
  contentSidebarVisibilityState,
16442
+ listFieldHandlers,
16148
16443
  schemaName,
16149
16444
  hasDraftInitialData,
16150
16445
  topLevelTabsFieldClassName,
@@ -16163,7 +16458,7 @@ export function ${contentComponentName}({ state${topLevelTabsFieldTabTab} }: ${c
16163
16458
  const {
16164
16459
  ${contentStateDestructure}
16165
16460
  } = state
16166
- ${contentSidebarVisibilityState}
16461
+ ${contentSidebarVisibilityState}${listFieldHandlers}
16167
16462
  return (
16168
16463
  <Form {...form}>
16169
16464
  <form autoComplete="off" id="${schemaName}-form" onSubmit={form.handleSubmit((values) => onSubmit(values${hasDraftInitialData}), handleErrors)} ${topLevelTabsFieldClassName}>
@@ -16231,7 +16526,7 @@ function renderFormStaticOptionsTemplate({
16231
16526
  return ` const [${fieldName}Open, set${fieldPascal}Open] = React.useState(false)
16232
16527
  const [${fieldName}Search, set${fieldPascal}Search] = React.useState('')
16233
16528
  const [create${fieldPascal}OptionPending, startCreate${fieldPascal}OptionTransition] = React.useTransition()
16234
- const { data: ${fieldName}CreatedOptions = [] as ${singular}SelectOption[] } = useQuery<${singular}SelectOption[]>({
16529
+ const { data: ${fieldName}CreatedOptions = [] } = useQuery<${singular}SelectOption[]>({
16235
16530
  queryKey: ['${schemaName}', 'select-options', '${fieldName}'],
16236
16531
  queryFn: () => get${singular}SelectOptions('${fieldName}')
16237
16532
  })
@@ -16730,8 +17025,16 @@ function buildEntityFormArtifacts({
16730
17025
  hookReturnNames,
16731
17026
  contentStateDestructure,
16732
17027
  sidebarVisibilityState,
17028
+ listFieldHandlers,
16733
17029
  formBodyJSX
16734
17030
  }) {
17031
+ const handlersUsedIn = (body) => listFieldHandlers.filter((handler) => handler.names.some((name) => usesIdentifier(body, name))).map((handler) => handler.source).join("\n\n");
17032
+ const withHandlerBlock = (handlers) => handlers ? `${handlers}
17033
+
17034
+ ` : "";
17035
+ const withHandlerSection = (handlers) => handlers ? `
17036
+ ${handlers}
17037
+ ` : "";
16735
17038
  const needsCn = hasRelationship || hasSelectCombobox || shouldGuardSidebarByTab;
16736
17039
  const metadataOffsetConst = showMetadataWidget ? "const SCROLL_BORDER_OFFSET = 8;\n\n" : "";
16737
17040
  const metadataScrollState = showMetadataWidget ? " const hasScrolled = usePageScrollThreshold(SCROLL_BORDER_OFFSET)\n" : "";
@@ -16779,7 +17082,11 @@ ${topLevelTabComponentImports}` : ""}` : renderEntityFormContentRenderer({
16779
17082
  });
16780
17083
  const contentSidebarVisibilityState = topLevelTabsField ? "" : sidebarVisibilityState;
16781
17084
  const topLevelTabComponentFiles = topLevelTabComponents.map((spec) => {
16782
- const tabStateNames = hookReturnNames.filter((name) => usesIdentifier(spec.body, name));
17085
+ const tabListFieldHandlers = handlersUsedIn(spec.body);
17086
+ const tabBodyWithHandlers = `${tabListFieldHandlers}${spec.body}`;
17087
+ const tabStateNames = hookReturnNames.filter(
17088
+ (name) => usesIdentifier(tabBodyWithHandlers, name)
17089
+ );
16783
17090
  const tabStateDestructure = tabStateNames.length > 0 ? renderEntityFormContentRenderer({
16784
17091
  kind: "renderFormGeneratedValueTemplate",
16785
17092
  props: {
@@ -16803,6 +17110,7 @@ ${topLevelTabComponentImports}` : ""}` : renderEntityFormContentRenderer({
16803
17110
  specComponentName: spec.componentName,
16804
17111
  hookName,
16805
17112
  tabStateDestructure,
17113
+ listFieldHandlers: withHandlerBlock(tabListFieldHandlers),
16806
17114
  body: spec.body
16807
17115
  }
16808
17116
  })
@@ -16818,6 +17126,7 @@ ${topLevelTabComponentImports}` : ""}` : renderEntityFormContentRenderer({
16818
17126
  topLevelTabsFieldTabTab: topLevelTabsField ? ", tab" : "",
16819
17127
  contentStateDestructure,
16820
17128
  contentSidebarVisibilityState,
17129
+ listFieldHandlers: withHandlerSection(handlersUsedIn(formBodyJSX)),
16821
17130
  schemaName: schema.name,
16822
17131
  hasDraftInitialData: hasDraft ? ", initialData?.published ?? false" : "",
16823
17132
  topLevelTabsFieldClassName: topLevelTabsField ? 'className="h-full"' : 'className="space-y-6 h-full"',
@@ -16886,9 +17195,7 @@ function renderListFieldCardContentTemplate({
16886
17195
  formItemProps: formItemProps2,
16887
17196
  fieldName,
16888
17197
  toLowerCase,
16889
- validateExpandedItemExpression,
16890
- defaultItem,
16891
- pascalFieldName,
17198
+ itemName,
16892
17199
  singularLabel,
16893
17200
  fieldLabelFieldLabel,
16894
17201
  label,
@@ -16905,17 +17212,7 @@ ${indent} <p>No ${toLowerCase} added yet.</p>
16905
17212
  ${indent} <Button
16906
17213
  ${indent} type="button"
16907
17214
  ${indent} variant="outline"
16908
- ${indent} onClick={async () => {
16909
- ${indent} if (${fieldName}Expanded) {
16910
- ${indent} const expandedIndex = Number(${fieldName}Expanded.replace('item-', '')) - 1
16911
- ${indent} if (expandedIndex >= 0) {
16912
- ${indent} const isExpandedItemValid = await form.trigger(${validateExpandedItemExpression})
16913
- ${indent} if (!isExpandedItemValid) return
16914
- ${indent} }
16915
- ${indent} }
16916
- ${indent} ${fieldName}FieldArray.append(${defaultItem})
16917
- ${indent} set${pascalFieldName}Expanded(\`item-\${${fieldName}FieldArray.fields.length + 1}\`)
16918
- ${indent} }}
17215
+ ${indent} onClick={add${itemName}}
16919
17216
  ${indent} disabled={isPending}
16920
17217
  ${indent} >
16921
17218
  ${indent} <Plus className="size-3" />
@@ -16940,17 +17237,7 @@ ${indent} />
16940
17237
  ${indent} <Button
16941
17238
  ${indent} type="button"
16942
17239
  ${indent} variant="outline"
16943
- ${indent} onClick={async () => {
16944
- ${indent} if (${fieldName}Expanded) {
16945
- ${indent} const expandedIndex = Number(${fieldName}Expanded.replace('item-', '')) - 1
16946
- ${indent} if (expandedIndex >= 0) {
16947
- ${indent} const isExpandedItemValid = await form.trigger(${validateExpandedItemExpression})
16948
- ${indent} if (!isExpandedItemValid) return
16949
- ${indent} }
16950
- ${indent} }
16951
- ${indent} ${fieldName}FieldArray.append(${defaultItem})
16952
- ${indent} set${pascalFieldName}Expanded(\`item-\${${fieldName}FieldArray.fields.length + 1}\`)
16953
- ${indent} }}
17240
+ ${indent} onClick={add${itemName}}
16954
17241
  ${indent} disabled={isPending${fieldMaxItemsFieldName}}
16955
17242
  ${indent} >
16956
17243
  ${indent} <Plus className="size-3" />
@@ -16960,17 +17247,7 @@ ${indent} </div>
16960
17247
 
16961
17248
  ${indent} <Accordion
16962
17249
  ${indent} value={${fieldName}Expanded ? [${fieldName}Expanded] : []}
16963
- ${indent} onValueChange={async (nextValue) => {
16964
- ${indent} const nextExpanded = nextValue[0] ?? ''
16965
- ${indent} if (${fieldName}Expanded && nextExpanded && nextExpanded !== ${fieldName}Expanded) {
16966
- ${indent} const expandedIndex = Number(${fieldName}Expanded.replace('item-', '')) - 1
16967
- ${indent} if (expandedIndex >= 0) {
16968
- ${indent} const isExpandedItemValid = await form.trigger(${validateExpandedItemExpression})
16969
- ${indent} if (!isExpandedItemValid) return
16970
- ${indent} }
16971
- ${indent} }
16972
- ${indent} set${pascalFieldName}Expanded(nextExpanded)
16973
- ${indent} }}
17250
+ ${indent} onValueChange={changeExpanded${itemName}}
16974
17251
  ${indent} >
16975
17252
  ${indent} {${fieldName}FieldArray.fields.map((item, index) => (
16976
17253
  ${indent} <AccordionItem key={item.id} value={\`item-\${index + 1}\`}>
@@ -16984,10 +17261,7 @@ ${indent} variant="ghost"
16984
17261
  ${indent} size="icon-sm"
16985
17262
  ${indent} className="absolute right-10 top-1/2 -translate-y-1/2 shrink-0"
16986
17263
  ${indent} aria-label="Remove ${singularLabel}"
16987
- ${indent} onClick={() => {
16988
- ${indent} if (isPending) return
16989
- ${indent} ${fieldName}FieldArray.remove(index)
16990
- ${indent} }}
17264
+ ${indent} onClick={() => remove${itemName}(index)}
16991
17265
  ${indent} disabled={isPending}
16992
17266
  ${indent} >
16993
17267
  ${indent} <X />
@@ -17034,35 +17308,6 @@ function findTitlePath(fields) {
17034
17308
  return null;
17035
17309
  }
17036
17310
 
17037
- // adapters/next/generators/form/field-jsx-nested/empty-nested-field-value.ts
17038
- function emptyNestedFieldValue(field) {
17039
- if ((field.type === "group" || field.type === "section") && field.fields?.length) {
17040
- return objectValueForFields(field.fields);
17041
- }
17042
- if (field.type === "list" || field.type === "gallery") return "[]";
17043
- if (field.type === "relationship" && field.multiple) return "[]";
17044
- if (field.type === "select" && field.multiple) return "[]";
17045
- if (field.type === "boolean") return "false";
17046
- if (field.type === "number" || field.type === "decimal") return field.required ? "0" : "undefined";
17047
- return "''";
17048
- }
17049
-
17050
- // adapters/next/generators/form/field-jsx-nested/object-entries-for-fields.ts
17051
- function objectEntriesForFields(fields) {
17052
- return fields.flatMap((field) => {
17053
- const entries = [`${quotePropertyName(field.name)}: ${emptyNestedFieldValue(field)}`];
17054
- if (field.hasIcon) {
17055
- entries.push(`${quotePropertyName(`${field.name}Icon`)}: ''`);
17056
- }
17057
- return entries;
17058
- });
17059
- }
17060
-
17061
- // adapters/next/generators/form/field-jsx-nested/object-value-for-fields.ts
17062
- function objectValueForFields(fields) {
17063
- return `{${objectEntriesForFields(fields).join(", ")}}`;
17064
- }
17065
-
17066
17311
  // adapters/next/generators/form/form-shared/has-visible-label.ts
17067
17312
  function hasVisibleLabel(field) {
17068
17313
  return typeof field.label === "string" ? field.label.trim().length > 0 : Boolean(field.label);
@@ -17238,16 +17483,16 @@ function renderNestedFieldRenderer(request) {
17238
17483
  }
17239
17484
 
17240
17485
  // adapters/next/generators/form/field-jsx-nested/path-expression.ts
17241
- function pathExpression(path113) {
17242
- return `\`${path113.map((part) => typeof part === "string" ? part : `\${${part.expression}}`).join(".")}\``;
17486
+ function pathExpression(path114) {
17487
+ return `\`${path114.map((part) => typeof part === "string" ? part : `\${${part.expression}}`).join(".")}\``;
17243
17488
  }
17244
17489
 
17245
17490
  // adapters/next/generators/form/field-jsx-nested/path-name-prop.ts
17246
- function pathNameProp(path113) {
17247
- if (path113.every((part) => typeof part === "string")) {
17248
- return `"${path113.map((part) => part).join(".")}"`;
17491
+ function pathNameProp(path114) {
17492
+ if (path114.every((part) => typeof part === "string")) {
17493
+ return `"${path114.map((part) => part).join(".")}"`;
17249
17494
  }
17250
- return `{${pathExpression(path113)}}`;
17495
+ return `{${pathExpression(path114)}}`;
17251
17496
  }
17252
17497
 
17253
17498
  // adapters/next/templates/renderers/generators/form/field-jsx-nested/render-nested-object-list-field.ts
@@ -17301,21 +17546,8 @@ function renderNestedObjectListFieldRenderer(request) {
17301
17546
  throw new Error("Unsupported renderer request");
17302
17547
  }
17303
17548
 
17304
- // adapters/next/generators/form/field-jsx-nested/required-leaf-paths.ts
17305
- function requiredLeafPaths(fields, prefix = []) {
17306
- return fields.flatMap((field) => {
17307
- if (field.hidden) return [];
17308
- const path113 = [...prefix, field.name];
17309
- if ((field.type === "group" || field.type === "section") && field.fields?.length) {
17310
- return requiredLeafPaths(field.fields, path113);
17311
- }
17312
- if (field.required) return [path113.join(".")];
17313
- return [];
17314
- });
17315
- }
17316
-
17317
17549
  // adapters/next/generators/form/field-jsx-nested/render-nested-object-list-field.ts
17318
- function renderNestedObjectListField(field, indent, label, path113, depth) {
17550
+ function renderNestedObjectListField(field, indent, label, path114, depth) {
17319
17551
  const singularLabel = singularize(label);
17320
17552
  const itemIndexVar = `${safeIdentifier(field.name, "nestedList")}Index${depth}`;
17321
17553
  const titlePath = findTitlePath(field.fields ?? []);
@@ -17325,7 +17557,7 @@ function renderNestedObjectListField(field, indent, label, path113, depth) {
17325
17557
  props: {
17326
17558
  indent,
17327
17559
  itemIndexVar,
17328
- pathString: path113.map((part) => typeof part === "string" ? part : `\${${part.expression}}`).join("."),
17560
+ pathString: path114.map((part) => typeof part === "string" ? part : `\${${part.expression}}`).join("."),
17329
17561
  titlePathSuffix,
17330
17562
  singularLabel
17331
17563
  }
@@ -17334,7 +17566,7 @@ function renderNestedObjectListField(field, indent, label, path113, depth) {
17334
17566
  (child) => renderNestedField(
17335
17567
  child,
17336
17568
  `${indent} `,
17337
- [...path113, { expression: itemIndexVar }, child.name],
17569
+ [...path114, { expression: itemIndexVar }, child.name],
17338
17570
  depth + 1
17339
17571
  )
17340
17572
  ).filter(Boolean).join("\n");
@@ -17352,7 +17584,7 @@ ${indent} validatePaths={${JSON.stringify(validatePaths)}}` : "";
17352
17584
  kind: "renderNestedObjectListFieldNestedObjectListFieldTemplate",
17353
17585
  props: {
17354
17586
  indent,
17355
- pathExpression: pathExpression(path113),
17587
+ pathExpression: pathExpression(path114),
17356
17588
  stringify: JSON.stringify(label),
17357
17589
  stringifySerializedValue: JSON.stringify(singularLabel),
17358
17590
  defaultItem,
@@ -17391,10 +17623,10 @@ ${indent}/>`;
17391
17623
  }
17392
17624
 
17393
17625
  // adapters/next/generators/form/field-jsx-nested/render-text-input-field.ts
17394
- function renderTextInputField(field, indent, label, nestedHint, path113) {
17626
+ function renderTextInputField(field, indent, label, nestedHint, path114) {
17395
17627
  return renderTextInputFieldFormFieldTemplate({
17396
17628
  indent,
17397
- pathNameProp: pathNameProp(path113),
17629
+ pathNameProp: pathNameProp(path114),
17398
17630
  formItemProps: formItemProps(field),
17399
17631
  labelWithDescription: labelWithDescription(
17400
17632
  formLabel(field, label),
@@ -17406,11 +17638,11 @@ function renderTextInputField(field, indent, label, nestedHint, path113) {
17406
17638
  }
17407
17639
 
17408
17640
  // adapters/next/generators/form/field-jsx-nested/render-nested-field.ts
17409
- function renderNestedField(field, indent, path113, depth) {
17641
+ function renderNestedField(field, indent, path114, depth) {
17410
17642
  const nestedLabel = field.label || field.name;
17411
17643
  const nestedHint = field.hint ? `<FormDescription>${field.hint}</FormDescription>` : "";
17412
17644
  if ((field.type === "group" || field.type === "section") && field.fields?.length) {
17413
- const groupFields = field.fields.map((child) => renderNestedField(child, `${indent} `, [...path113, child.name], depth)).filter(Boolean).join("\n");
17645
+ const groupFields = field.fields.map((child) => renderNestedField(child, `${indent} `, [...path114, child.name], depth)).filter(Boolean).join("\n");
17414
17646
  if (!groupFields) return "";
17415
17647
  const heading = nestedLabel && nestedLabel !== field.name ? `${indent}<h3 className="text-base font-medium">${nestedLabel}</h3>
17416
17648
  ` : "";
@@ -17426,7 +17658,7 @@ function renderNestedField(field, indent, path113, depth) {
17426
17658
  });
17427
17659
  }
17428
17660
  if (field.type === "list" && field.fields?.length) {
17429
- return renderNestedObjectListField(field, indent, nestedLabel, path113, depth);
17661
+ return renderNestedObjectListField(field, indent, nestedLabel, path114, depth);
17430
17662
  }
17431
17663
  if (field.type === "list") {
17432
17664
  const hideLabelProp = field.label ? "" : `
@@ -17437,7 +17669,7 @@ ${indent} description={${JSON.stringify(field.hint)}}` : "";
17437
17669
  kind: "renderNestedFieldDynamicListFieldTemplate",
17438
17670
  props: {
17439
17671
  indent,
17440
- pathExpression: pathExpression(path113),
17672
+ pathExpression: pathExpression(path114),
17441
17673
  nestedLabel,
17442
17674
  hideLabelProp,
17443
17675
  descriptionProp,
@@ -17451,7 +17683,7 @@ ${indent} maxItems={${field.maxItems}}` : ""
17451
17683
  kind: "renderNestedFieldFormFieldTemplate",
17452
17684
  props: {
17453
17685
  indent,
17454
- pathNameProp: pathNameProp(path113),
17686
+ pathNameProp: pathNameProp(path114),
17455
17687
  formItemProps: formItemProps(field, "flex flex-row items-start space-x-3 space-y-0"),
17456
17688
  labelWithDescription: labelWithDescription(
17457
17689
  `<FormLabel>${nestedLabel}</FormLabel>`,
@@ -17467,7 +17699,7 @@ ${indent} maxItems={${field.maxItems}}` : ""
17467
17699
  kind: "renderNestedFieldFormFieldDetailsTemplate",
17468
17700
  props: {
17469
17701
  indent,
17470
- pathNameProp: pathNameProp(path113),
17702
+ pathNameProp: pathNameProp(path114),
17471
17703
  formItemProps: formItemProps(field),
17472
17704
  labelWithDescription: labelWithDescription(
17473
17705
  formLabel(field, nestedLabel),
@@ -17483,7 +17715,7 @@ ${indent} maxItems={${field.maxItems}}` : ""
17483
17715
  kind: "renderNestedFieldFormFieldDetailsBranchTemplate",
17484
17716
  props: {
17485
17717
  indent,
17486
- pathNameProp: pathNameProp(path113),
17718
+ pathNameProp: pathNameProp(path114),
17487
17719
  formItemProps: formItemProps(field),
17488
17720
  labelWithDescription: labelWithDescription(
17489
17721
  formLabel(field, nestedLabel),
@@ -17501,7 +17733,7 @@ ${indent} maxItems={${field.maxItems}}` : ""
17501
17733
  kind: "renderNestedFieldFormFieldDetailsBranchBodyTemplate",
17502
17734
  props: {
17503
17735
  indent,
17504
- pathNameProp: pathNameProp(path113),
17736
+ pathNameProp: pathNameProp(path114),
17505
17737
  formItemProps: formItemProps(field),
17506
17738
  labelWithDescription: labelWithDescription(
17507
17739
  formLabel(field, nestedLabel),
@@ -17514,14 +17746,7 @@ ${indent} maxItems={${field.maxItems}}` : ""
17514
17746
  }
17515
17747
  });
17516
17748
  }
17517
- return renderTextInputField(field, indent, nestedLabel, nestedHint, path113);
17518
- }
17519
-
17520
- // adapters/next/generators/form/field-jsx-nested/validation-trigger-expression.ts
17521
- function validationTriggerExpression(basePath, requiredPaths) {
17522
- if (requiredPaths.length === 0) return `\`${basePath}.\${expandedIndex}\` as never`;
17523
- const paths = requiredPaths.map((path113) => `\`${basePath}.\${expandedIndex}.${path113}\``).join(", ");
17524
- return `[${paths}] as never`;
17749
+ return renderTextInputField(field, indent, nestedLabel, nestedHint, path114);
17525
17750
  }
17526
17751
 
17527
17752
  // adapters/next/generators/form/field-jsx-nested/render-list-field.ts
@@ -17546,7 +17771,7 @@ ${indent} maxItems={${field.maxItems}}` : ""
17546
17771
  });
17547
17772
  }
17548
17773
  const singularLabel = singularize(label);
17549
- const pascalFieldName = toPascalCase(field.name);
17774
+ const itemName = toPascalCase(singularize(field.name));
17550
17775
  const titlePath = findTitlePath(field.fields);
17551
17776
  const accordionTitle = titlePath ? `{String(form.watch(\`${field.name}.\${index}.${titlePath.join(".")}\` as never) || \`${singularLabel} \${index + 1}\`)}` : `${singularLabel} {index + 1}`;
17552
17777
  const nestedFieldsJSX = field.fields.map(
@@ -17557,11 +17782,6 @@ ${indent} maxItems={${field.maxItems}}` : ""
17557
17782
  0
17558
17783
  )
17559
17784
  ).join("\n");
17560
- const defaultItem = objectValueForFields(field.fields);
17561
- const validateExpandedItemExpression = validationTriggerExpression(
17562
- field.name,
17563
- requiredLeafPaths(field.fields)
17564
- );
17565
17785
  return renderListFieldRenderer({
17566
17786
  kind: "renderListFieldCardContentTemplate",
17567
17787
  props: {
@@ -17569,9 +17789,7 @@ ${indent} maxItems={${field.maxItems}}` : ""
17569
17789
  formItemProps: formItemProps(field),
17570
17790
  fieldName: field.name,
17571
17791
  toLowerCase: label.toLowerCase(),
17572
- validateExpandedItemExpression,
17573
- defaultItem,
17574
- pascalFieldName,
17792
+ itemName,
17575
17793
  singularLabel,
17576
17794
  fieldLabelFieldLabel: field.label ? "text-foreground" : "sr-only",
17577
17795
  label,
@@ -18019,7 +18237,7 @@ function renderMarkdownField(field, indent, label, hintJSX, context) {
18019
18237
  `${indent} `
18020
18238
  ),
18021
18239
  onChange,
18022
- fillControlClass: fillControlClass(field, "min-h-[300px]"),
18240
+ fillControlClass: fillControlClass(field, "min-h-entity-editor"),
18023
18241
  toLowerCase: label.toLowerCase()
18024
18242
  }
18025
18243
  });
@@ -18467,7 +18685,7 @@ function renderRichtextField(field, indent, label, hintJSX, context) {
18467
18685
  `${indent} `
18468
18686
  ),
18469
18687
  onChange,
18470
- fillControlClass: fillControlClass(field, "min-h-[300px]"),
18688
+ fillControlClass: fillControlClass(field, "min-h-entity-editor"),
18471
18689
  toLowerCase: label.toLowerCase()
18472
18690
  }
18473
18691
  });
@@ -19385,7 +19603,7 @@ function buildEntityFormLayout({
19385
19603
  return renderEntityFormContentRenderer({
19386
19604
  kind: "renderFormCardContentGridTemplate",
19387
19605
  props: {
19388
- tabSidebarEntriesGrid: tabSidebarEntries.length > 0 ? "grid-cols-[1fr_360px]" : "grid-cols-1",
19606
+ tabSidebarEntriesGrid: tabSidebarEntries.length > 0 ? "grid-cols-entity-form" : "grid-cols-1",
19389
19607
  tabMainFieldsJsx: tabMainFieldsJSX,
19390
19608
  sidebarColumn
19391
19609
  }
@@ -19441,7 +19659,7 @@ function buildEntityFormLayout({
19441
19659
  const sidebarVisibilityState = shouldGuardSidebarByTab ? `
19442
19660
  const hasVisibleSidebarFields = ${sidebarTabNames.map((tabName) => `activeTab === ${JSON.stringify(tabName)}`).join(" || ")}
19443
19661
  ` : "";
19444
- const formGridOpen = shouldGuardSidebarByTab ? renderEntityFormContentRenderer({ kind: "renderFormLayoutDetailsBranchTemplate" }) : ` <div className="grid ${hasSidebarFields ? "grid-cols-[1fr_360px]" : "grid-cols-1"} gap-4 items-start h-full">`;
19662
+ const formGridOpen = shouldGuardSidebarByTab ? renderEntityFormContentRenderer({ kind: "renderFormLayoutDetailsBranchTemplate" }) : ` <div className="grid ${hasSidebarFields ? "grid-cols-entity-form" : "grid-cols-1"} gap-4 items-start h-full">`;
19445
19663
  const sidebarCardJSX = !hasSidebarFields ? "" : shouldGuardSidebarByTab ? renderEntityFormContentRenderer({
19446
19664
  kind: "renderFormContentSidebarColumnTemplate",
19447
19665
  props: {
@@ -19943,6 +20161,7 @@ ${fieldArrayHooks}
19943
20161
  hookReturnNames,
19944
20162
  contentStateDestructure,
19945
20163
  sidebarVisibilityState,
20164
+ listFieldHandlers: buildListFieldHandlers(listFieldsWithNested),
19946
20165
  formBodyJSX
19947
20166
  });
19948
20167
  }
@@ -21649,12 +21868,7 @@ ${hasEdit ? " const router = useRouter()\n" : ""} const [{
21649
21868
  }
21650
21869
  function renderTableRowClickHandler({ editRoutePath }) {
21651
21870
  return `
21652
- onClick={(e) => {
21653
- const target = e.target as HTMLElement
21654
- if (!e.currentTarget.contains(target)) return
21655
- if (target.closest('button, a, input, [role="checkbox"]')) return
21656
- router.push(\`${editRoutePath}/\${row.original.id}/edit\`)
21657
- }}`;
21871
+ onActivate={() => router.push(\`${editRoutePath}/\${row.original.id}/edit\`)}`;
21658
21872
  }
21659
21873
  function renderTableRenderer(request) {
21660
21874
  switch (request.kind) {
@@ -21880,7 +22094,6 @@ function renderSingleActionsServerActionTemplate({
21880
22094
  hasSelectFieldsSelectOptionValue,
21881
22095
  authorshipAliasBlock,
21882
22096
  singletonId,
21883
- formatActionDateSource,
21884
22097
  selectResolutionFunctions,
21885
22098
  cacheLifeLine,
21886
22099
  selectClause,
@@ -21897,12 +22110,11 @@ import { alias } from 'drizzle-orm/pg-core'
21897
22110
  ${cacheReadImport}
21898
22111
  import { ${cacheTagsVar} } from './types'
21899
22112
  import type { ${singular}${hasSelectFieldsSelectOptionValue} } from './types'
22113
+ import { formatActionDate } from '@admin/utils/date/format-action-date'
21900
22114
 
21901
22115
  ${authorshipAliasBlock}
21902
22116
 
21903
22117
  const SINGLETON_ID = '${singletonId}'
21904
-
21905
- ${formatActionDateSource}
21906
22118
  ${selectResolutionFunctions}
21907
22119
  export async function get${singular}(): Promise<${singular} | null> {
21908
22120
  'use cache'${cacheLifeLine}
@@ -21967,8 +22179,9 @@ import { getChangedFieldNames } from '@admin/utils/audit/get-changed-field-names
21967
22179
  import { getTouchedFieldNames } from '@admin/utils/audit/get-touched-field-names'
21968
22180
  import { ${cacheInvalidationFn} } from 'next/cache'
21969
22181
  import { get${singular} } from './get-${kebabSingular}'
22182
+ import { to${singular} } from './to-${kebabSingular}'
21970
22183
  import { ${cacheTagsVar} } from './types'
21971
- import type { ${singular}UpsertInput, ${singular}UpsertResult, ${singular} } from './types'${markdownImport}
22184
+ import type { ${singular}UpsertInput, ${singular}UpsertResult } from './types'${markdownImport}
21972
22185
 
21973
22186
  const SINGLETON_ID = '${singletonId}'
21974
22187
 
@@ -22011,7 +22224,7 @@ ${htmlUpsertBlock}
22011
22224
  .where(eq(${tableVar}.id, SINGLETON_ID))
22012
22225
  .limit(1)
22013
22226
  const changedFields = previousRow
22014
- ? getChangedFieldNames(previousRow as unknown as Record<string, unknown>, processedData)
22227
+ ? getChangedFieldNames(previousRow, processedData)
22015
22228
  : getTouchedFieldNames(processedData)
22016
22229
 
22017
22230
  const lifecycleContext = {
@@ -22054,12 +22267,12 @@ ${m2mWriteStatementsContent}
22054
22267
  const saved${singular} = await get${singular}()
22055
22268
  runAfterHooks(previousRow ? 'afterUpdate' : 'afterCreate', {
22056
22269
  ...lifecycleContext,
22057
- data: (saved${singular} ?? result[0]) as unknown as Record<string, unknown>
22270
+ data: saved${singular} ?? to${singular}(result[0])
22058
22271
  })
22059
22272
 
22060
22273
  return {
22061
22274
  success: true,
22062
- ${camelSingular}: saved${singular} ?? (result[0] as unknown as ${singular})
22275
+ ${camelSingular}: saved${singular} ?? to${singular}(result[0])
22063
22276
  }
22064
22277
  } catch (error) {
22065
22278
  console.error('Error upserting ${singularText}:', error)
@@ -22088,6 +22301,27 @@ export { get${singular} } from './get-${kebabSingular}'
22088
22301
  export { upsert${singular} } from './upsert-${kebabSingular}'${selectOptionFunctionExports}
22089
22302
  `;
22090
22303
  }
22304
+ function renderSingleActionsSelectResolvableTypeTemplate({
22305
+ singular,
22306
+ omittedKeys,
22307
+ resolvableFields
22308
+ }) {
22309
+ return `export type ${singular}SelectResolvable = Omit<${singular}, ${omittedKeys}> & {
22310
+ ${resolvableFields}
22311
+ }`;
22312
+ }
22313
+ function renderSingleActionsToSingleTemplate({
22314
+ singular,
22315
+ tableVar,
22316
+ toEntityFunction
22317
+ }) {
22318
+ return `import type { ${singular} } from './types'
22319
+ import type { ${tableVar} } from '@admin/db/schema'
22320
+ import { formatActionDate } from '@admin/utils/date/format-action-date'
22321
+
22322
+ ${toEntityFunction}
22323
+ `;
22324
+ }
22091
22325
  function renderSingleActionsSingleActionsRenderer(request) {
22092
22326
  switch (request.kind) {
22093
22327
  case "renderSingleActionsContentTemplate":
@@ -22096,6 +22330,10 @@ function renderSingleActionsSingleActionsRenderer(request) {
22096
22330
  return renderSingleActionsRowsTemplate(request.props);
22097
22331
  case "renderSingleActionsServerActionTemplate":
22098
22332
  return renderSingleActionsServerActionTemplate(request.props);
22333
+ case "renderSingleActionsSelectResolvableTypeTemplate":
22334
+ return renderSingleActionsSelectResolvableTypeTemplate(request.props);
22335
+ case "renderSingleActionsToSingleTemplate":
22336
+ return renderSingleActionsToSingleTemplate(request.props);
22099
22337
  case "renderSingleActionsContentDetailsTemplate":
22100
22338
  return renderSingleActionsContentDetailsTemplate(request.props);
22101
22339
  case "renderSingleActionsServerActionSerializedValueTemplate":
@@ -22198,6 +22436,15 @@ function generateSingleActions(schema, actionsDir, options = {}) {
22198
22436
  selectOptionsTableVar: `${tableVar}SelectOptions`
22199
22437
  };
22200
22438
  const relationshipDataTypes = buildRelationshipDataTypes(allDbFields);
22439
+ const hasNestedSelectFields = selectFields.some((readField) => readField.path.length > 1);
22440
+ const selectResolvableType = hasSelectFields && !hasNestedSelectFields ? renderSingleActionsSingleActionsRenderer({
22441
+ kind: "renderSingleActionsSelectResolvableTypeTemplate",
22442
+ props: {
22443
+ singular: Singular,
22444
+ omittedKeys: selectFields.map((readField) => JSON.stringify(readField.path[0])).join(" | "),
22445
+ resolvableFields: selectFields.map((readField) => ` ${quotePropertyName(readField.path[0])}: string[]`).join("\n")
22446
+ }
22447
+ }) : null;
22201
22448
  const typesContent = renderSingleActionsSingleActionsRenderer({
22202
22449
  kind: "renderSingleActionsContentTemplate",
22203
22450
  props: {
@@ -22205,12 +22452,13 @@ function generateSingleActions(schema, actionsDir, options = {}) {
22205
22452
  buildAuthorshipUserType(),
22206
22453
  buildReadSelectOptionType(selectFields),
22207
22454
  relationshipDataTypes,
22208
- `export interface ${Singular} {
22455
+ `export type ${Singular} = {
22209
22456
  ${dataFields}${htmlFieldTypes ? `
22210
22457
  ${htmlFieldTypes}` : ""}${m2mFieldTypes ? `
22211
22458
  ${m2mFieldTypes}` : ""}${timestampFields}
22212
22459
  ${buildAuthorshipDataFields()}
22213
22460
  }`,
22461
+ selectResolvableType,
22214
22462
  `export interface ${Singular}UpsertInput {
22215
22463
  ${allUpsertInterfaceFields}
22216
22464
  }`,
@@ -22242,12 +22490,11 @@ ${allUpsertInterfaceFields}
22242
22490
  authorshipSelects,
22243
22491
  authorshipJoins
22244
22492
  );
22245
- const singleRowMapping = buildSingleRowMapping(
22246
- allDbFields,
22247
- relationshipFields,
22248
- `${Singular}`,
22249
- htmlOutputFields
22250
- );
22493
+ const m2mMappingEntries = m2mFields.map((field) => {
22494
+ const { relationIdCol } = getSingleM2MContext(schema.name, field);
22495
+ return `${quotePropertyName(field.name)}: ${field.name}Rows.map((relationRow) => relationRow.${relationIdCol})`;
22496
+ });
22497
+ const singleRowMapping = buildSingleRowMapping(allDbFields, htmlOutputFields, m2mMappingEntries);
22251
22498
  const m2mReadQueries = m2mFields.map((field) => {
22252
22499
  const { junctionVar, schemaIdCol, relationIdCol } = getSingleM2MContext(schema.name, field);
22253
22500
  return renderSingleActionsSingleActionsRenderer({
@@ -22260,19 +22507,13 @@ ${allUpsertInterfaceFields}
22260
22507
  }
22261
22508
  });
22262
22509
  }).join("\n");
22263
- const m2mAssignments = m2mFields.map((field) => {
22264
- const { relationIdCol } = getSingleM2MContext(schema.name, field);
22265
- return ` singleRow.${field.name} = ${field.name}Rows.map((relationRow) => relationRow.${relationIdCol})`;
22266
- }).join("\n");
22267
22510
  const m2mReadBlock = hasM2M ? `
22268
- ${m2mReadQueries}
22269
- ${m2mAssignments}` : "";
22270
- const singleRowReturn = hasSelectFields ? `const row = result[0]
22271
- const singleRow = ${singleRowMapping}${m2mReadBlock}
22511
+ ${m2mReadQueries}` : "";
22512
+ const singleRowReturn = hasSelectFields ? `const row = result[0]${m2mReadBlock}
22513
+ const singleRow = ${singleRowMapping}
22272
22514
  const [resolvedSelectRow] = await resolve${Singular}SelectFields([singleRow])
22273
- return resolvedSelectRow` : `const row = result[0]
22274
- const singleRow = ${singleRowMapping}${m2mReadBlock}
22275
- return singleRow`;
22515
+ return resolvedSelectRow` : `const row = result[0]${m2mReadBlock}
22516
+ return ${singleRowMapping}`;
22276
22517
  const relationshipTableImports = relationshipFields.filter((field) => !isUserRelationshipTarget(field.relationship)).map((field) => toCamelCase(field.relationship));
22277
22518
  const m2mJunctionImports = m2mFields.map(
22278
22519
  (field) => getSingleM2MContext(schema.name, field).junctionVar
@@ -22287,7 +22528,7 @@ ${m2mAssignments}` : "";
22287
22528
  ])
22288
22529
  ).sort();
22289
22530
  const selectResolutionFunctions = hasSelectFields ? `
22290
- ${generateResolveSelectFieldsSource({ Singular, selectFields, selectOptionsTableVar: `${tableVar}SelectOptions`, hasCreatableSelectFields, exported: false })}
22531
+ ${generateResolveSelectFieldsSource({ Singular, selectFields, selectOptionsTableVar: `${tableVar}SelectOptions`, hasCreatableSelectFields, hasMediaFields: false, exported: false })}
22291
22532
  ` : "";
22292
22533
  const getContent = renderSingleActionsSingleActionsRenderer({
22293
22534
  kind: "renderSingleActionsServerActionTemplate",
@@ -22299,7 +22540,6 @@ ${generateResolveSelectFieldsSource({ Singular, selectFields, selectOptionsTable
22299
22540
  hasSelectFieldsSelectOptionValue: hasSelectFields ? ", SelectOptionValue" : "",
22300
22541
  authorshipAliasBlock: buildAuthorshipAliasBlock(),
22301
22542
  singletonId,
22302
- formatActionDateSource: buildFormatActionDateSource({ exported: false }),
22303
22543
  selectResolutionFunctions,
22304
22544
  cacheLifeLine,
22305
22545
  selectClause,
@@ -22376,8 +22616,25 @@ ${m2mWriteStatements}
22376
22616
  selectOptionFunctionExports
22377
22617
  }
22378
22618
  });
22619
+ const toSingleContent = renderSingleActionsSingleActionsRenderer({
22620
+ kind: "renderSingleActionsToSingleTemplate",
22621
+ props: {
22622
+ singular: Singular,
22623
+ tableVar,
22624
+ toEntityFunction: generateToEntityFunction({
22625
+ Singular,
22626
+ tableVar,
22627
+ allDbFields,
22628
+ htmlOutputFields,
22629
+ m2mFields,
22630
+ mediaFields: [],
22631
+ galleryFields: []
22632
+ })
22633
+ }
22634
+ });
22379
22635
  const files = [
22380
22636
  { name: "types.ts", content: typesContent },
22637
+ { name: `to-${kebabSingular}.ts`, content: toSingleContent },
22381
22638
  ...hasHtmlOutput ? [{ name: "markdown.ts", content: genMarkdownRendererContent() }] : [],
22382
22639
  { name: `get-${kebabSingular}.ts`, content: getContent },
22383
22640
  ...hasCreatableSelectFields ? [
@@ -22711,7 +22968,7 @@ function renderBuildGroupCreatableSelectStateStaticOptionsTemplate({
22711
22968
  return ` const [${fieldName}Open, set${fieldPascal}Open] = React.useState(false)
22712
22969
  const [${fieldName}Search, set${fieldPascal}Search] = React.useState('')
22713
22970
  const [create${fieldPascal}OptionPending, startCreate${fieldPascal}OptionTransition] = React.useTransition()
22714
- const { data: ${fieldName}CreatedOptions = [] as ${singular}SelectOption[] } = useQuery<${singular}SelectOption[]>({
22971
+ const { data: ${fieldName}CreatedOptions = [] } = useQuery<${singular}SelectOption[]>({
22715
22972
  queryKey: ['${schemaName}', 'select-options', '${fieldName}'],
22716
22973
  queryFn: () => get${singular}SelectOptions('${fieldName}')
22717
22974
  })
@@ -22894,6 +23151,7 @@ function generateCardComponent(group2, schema, analysis, allFlatFields) {
22894
23151
  defaultValueFromSourceNames
22895
23152
  );
22896
23153
  const fieldArrayHooks = buildGroupFieldArrayHooks(analysis);
23154
+ const listFieldHandlers = buildListFieldHandlers(analysis.listFieldsWithNested).filter((handler) => handler.names.some((name) => usesIdentifier(fieldsJSX, name))).map((handler) => handler.source).join("\n\n");
22897
23155
  const savedValueName = `saved${Singular}`;
22898
23156
  const resetValues = buildDefaultValues2(group2.flatFields, savedValueName, allFlatFields).replace(
22899
23157
  /^ {6}/gm,
@@ -22939,9 +23197,9 @@ ${defaultValueFromSyncFunctions}
22939
23197
  fieldArrayHooksContent: fieldArrayHooks ? `
22940
23198
  ${fieldArrayHooks}
22941
23199
  ` : "",
22942
- creatableSelectHandlersContent: creatableSelectHandlers ? `${creatableSelectHandlers}
23200
+ creatableSelectHandlersContent: [creatableSelectHandlers, listFieldHandlers].filter(Boolean).map((block) => `${block}
22943
23201
 
22944
- ` : "",
23202
+ `).join(""),
22945
23203
  descriptionLine,
22946
23204
  fieldsJsx: fieldsJSX,
22947
23205
  groupHintText: group2.hint ? `
@@ -29285,7 +29543,7 @@ ${validationErrors.map((error) => ` - ${error}`).join("\n")}`
29285
29543
  import * as p61 from "@clack/prompts";
29286
29544
  import { execFileSync as execFileSync3 } from "child_process";
29287
29545
  import fs79 from "fs";
29288
- import path92 from "path";
29546
+ import path93 from "path";
29289
29547
 
29290
29548
  // adapters/next/config/detect/detect-project.ts
29291
29549
  import fs52 from "fs";
@@ -29703,10 +29961,14 @@ function addStorageIntegration(integrations2, provider) {
29703
29961
 
29704
29962
  // adapters/next/init/providers/prompt-deploy-provider.ts
29705
29963
  import * as p48 from "@clack/prompts";
29706
- async function promptDeployProvider(initialValue = "none") {
29964
+ async function promptDeployProvider() {
29707
29965
  const provider = await p48.select({
29708
29966
  message: "Deploy this project",
29709
29967
  options: [
29968
+ {
29969
+ value: "none",
29970
+ label: "Not now"
29971
+ },
29710
29972
  {
29711
29973
  value: "vercel",
29712
29974
  label: "Vercel"
@@ -29714,13 +29976,9 @@ async function promptDeployProvider(initialValue = "none") {
29714
29976
  {
29715
29977
  value: "railway",
29716
29978
  label: "Railway"
29717
- },
29718
- {
29719
- value: "none",
29720
- label: "Not now"
29721
29979
  }
29722
29980
  ],
29723
- initialValue
29981
+ initialValue: "none"
29724
29982
  });
29725
29983
  if (p48.isCancel(provider)) {
29726
29984
  p48.cancel("Setup cancelled.");
@@ -31451,6 +31709,7 @@ function scaffoldComponents({ cwd, config }) {
31451
31709
  "utils/date/date-range-end-time.ts",
31452
31710
  "utils/date/date-range-input-format.ts",
31453
31711
  "utils/date/date-range-start-time.ts",
31712
+ "utils/date/format-action-date.ts",
31454
31713
  "utils/date/format-date-range-input-date.ts",
31455
31714
  "utils/date/format-date-range-param-date.ts",
31456
31715
  "utils/date/format-date-range-trigger-date.ts",
@@ -31461,6 +31720,9 @@ function scaffoldComponents({ cwd, config }) {
31461
31720
  "utils/date/parse-date-input-value.ts",
31462
31721
  "utils/date/parse-editable-date-range-date.ts",
31463
31722
  "utils/dev-mode/code-block-height.ts",
31723
+ "utils/dev-mode/dev-mode-json-schemas.ts",
31724
+ "utils/dev-mode/parse-dev-mode-lifecycle-hooks.ts",
31725
+ "utils/dev-mode/parse-dev-mode-snippets.ts",
31464
31726
  "utils/error/read-string-property.ts",
31465
31727
  "utils/error/recognize.ts",
31466
31728
  "utils/error/to-action-error.ts",
@@ -31627,6 +31889,7 @@ function scaffoldComponents({ cwd, config }) {
31627
31889
  "utils/editor/set-active-table-column-alignment.ts",
31628
31890
  "utils/editor/set-element-attribute.ts",
31629
31891
  "utils/editor/set-markdown-link-at-cursor.ts",
31892
+ "utils/editor/set-task-item-checked.ts",
31630
31893
  "utils/editor/show-table-part-preview.ts",
31631
31894
  "utils/editor/slash-commands.ts",
31632
31895
  "utils/editor/slash-menu-state.ts",
@@ -31641,6 +31904,7 @@ function scaffoldComponents({ cwd, config }) {
31641
31904
  "utils/editor/transform-selected-markdown-lines.ts",
31642
31905
  "utils/editor/update-nodes-attr.ts",
31643
31906
  "utils/editor/update-selected-content-editor-math.ts",
31907
+ "utils/email/email-theme.ts",
31644
31908
  "utils/email/escape-html.ts",
31645
31909
  "utils/email/form-email-delivery-input.ts",
31646
31910
  "utils/email/format-email-value.ts",
@@ -31675,6 +31939,7 @@ function scaffoldComponents({ cwd, config }) {
31675
31939
  "utils/seo/generate-article-schema.ts",
31676
31940
  "utils/seo/schema-to-json.ts",
31677
31941
  "utils/shared/cn.ts",
31942
+ "utils/shared/is-record.ts",
31678
31943
  "utils/storage/build-local-storage-key.ts",
31679
31944
  "utils/storage/sanitize-filename.ts",
31680
31945
  "utils/table/default-get-id.ts",
@@ -31779,6 +32044,7 @@ function scaffoldComponents({ cwd, config }) {
31779
32044
  write("hooks/use-users.ts", readTemplate("hooks/use-users.ts"));
31780
32045
  write("hooks/use-webhooks.ts", readTemplate("hooks/use-webhooks.ts"));
31781
32046
  write("hooks/use-failed-image-url.ts", readTemplate("hooks/use-failed-image-url.ts"));
32047
+ write("hooks/use-field-error-visible.ts", readTemplate("hooks/use-field-error-visible.ts"));
31782
32048
  write("hooks/use-media.ts", readTemplate("hooks/use-media.ts"));
31783
32049
  write("hooks/use-entity-versions.ts", readTemplate("hooks/use-entity-versions.ts"));
31784
32050
  write("hooks/use-media-filters-bar.ts", readTemplate("hooks/use-media-filters-bar.ts"));
@@ -33148,15 +33414,24 @@ function scaffoldProxy({ cwd, config }) {
33148
33414
  return { status: "created", path: relPath };
33149
33415
  }
33150
33416
 
33417
+ // adapters/next/init/scaffolders/public-assets.ts
33418
+ import path79 from "path";
33419
+ function scaffoldPublicAssets(cwd) {
33420
+ const sourceDir = resolveCliAssetPath("adapters", "next", "templates", "init", "public");
33421
+ return PUBLIC_ASSET_FILE_NAMES.filter(
33422
+ (fileName) => safeCopyFile(path79.join(sourceDir, fileName), path79.resolve(cwd, "public", fileName))
33423
+ ).map((fileName) => path79.join("public", fileName));
33424
+ }
33425
+
33151
33426
  // adapters/next/init/scaffolders/tailwind/scaffold-tailwind.ts
33152
33427
  import fs67 from "fs";
33153
33428
 
33154
33429
  // adapters/next/main-css.ts
33155
33430
  import fs66 from "fs";
33156
- import path79 from "path";
33431
+ import path80 from "path";
33157
33432
  function findMainCss(cwd) {
33158
33433
  for (const candidate of MAIN_CSS_CANDIDATES) {
33159
- const filePath = path79.join(cwd, candidate);
33434
+ const filePath = path80.join(cwd, candidate);
33160
33435
  if (fs66.existsSync(filePath)) return filePath;
33161
33436
  }
33162
33437
  return void 0;
@@ -33301,7 +33576,7 @@ ${renderAdminShadowInputUtility()}
33301
33576
 
33302
33577
  // adapters/next/init/scaffolders/tsconfig/scaffold-tsconfig.ts
33303
33578
  import fs68 from "fs";
33304
- import path80 from "path";
33579
+ import path81 from "path";
33305
33580
 
33306
33581
  // adapters/next/init/scaffolders/tsconfig/create-admin-path-aliases.ts
33307
33582
  function createAdminPathAliases(config) {
@@ -33325,7 +33600,7 @@ function createAdminPathAliases(config) {
33325
33600
 
33326
33601
  // adapters/next/init/scaffolders/tsconfig/scaffold-tsconfig.ts
33327
33602
  function scaffoldTsconfig(cwd, config) {
33328
- const tsconfigPath = path80.join(cwd, "tsconfig.json");
33603
+ const tsconfigPath = path81.join(cwd, "tsconfig.json");
33329
33604
  const added = [];
33330
33605
  const skipped = [];
33331
33606
  if (!fs68.existsSync(tsconfigPath)) {
@@ -33621,9 +33896,9 @@ async function ensureVercelAuth(runner, cwd, options) {
33621
33896
 
33622
33897
  // adapters/next/init/vercel/env-guard.ts
33623
33898
  import fs69 from "fs";
33624
- import path81 from "path";
33899
+ import path82 from "path";
33625
33900
  function guardEnvLocal(cwd) {
33626
- const envPath = path81.join(cwd, ".env.local");
33901
+ const envPath = path82.join(cwd, ".env.local");
33627
33902
  let original;
33628
33903
  try {
33629
33904
  original = fs69.readFileSync(envPath, "utf-8");
@@ -33699,14 +33974,14 @@ import pc9 from "picocolors";
33699
33974
 
33700
33975
  // adapters/next/init/vercel/project/create-and-link-project.ts
33701
33976
  import fs71 from "fs";
33702
- import path83 from "path";
33977
+ import path84 from "path";
33703
33978
 
33704
33979
  // adapters/next/init/vercel/project/read-linked-project-json.ts
33705
33980
  import fs70 from "fs";
33706
- import path82 from "path";
33981
+ import path83 from "path";
33707
33982
  function readLinkedProjectJson(cwd) {
33708
33983
  try {
33709
- const projectJsonPath = path82.join(cwd, ".vercel", "project.json");
33984
+ const projectJsonPath = path83.join(cwd, ".vercel", "project.json");
33710
33985
  if (!fs70.existsSync(projectJsonPath)) return void 0;
33711
33986
  const parsed = JSON.parse(fs70.readFileSync(projectJsonPath, "utf-8"));
33712
33987
  if (!isRecord(parsed)) return void 0;
@@ -33781,7 +34056,7 @@ ${add.stderr}`)) continue;
33781
34056
  break;
33782
34057
  }
33783
34058
  try {
33784
- fs71.rmSync(path83.join(cwd, ".vercel", "project.json"), { force: true });
34059
+ fs71.rmSync(path84.join(cwd, ".vercel", "project.json"), { force: true });
33785
34060
  } catch {
33786
34061
  }
33787
34062
  let link = await runVercel(
@@ -33900,10 +34175,10 @@ ${result.stderr}`
33900
34175
  // adapters/next/init/vercel/env-pull.ts
33901
34176
  import fs72 from "fs";
33902
34177
  import os from "os";
33903
- import path84 from "path";
34178
+ import path85 from "path";
33904
34179
  async function pullVercelEnvValue(runner, cwd, read, env, environment = "development") {
33905
- const tmpDir = fs72.mkdtempSync(path84.join(os.tmpdir(), "betterstart-vercel-"));
33906
- const tmpEnv = path84.join(tmpDir, ".env.pull");
34180
+ const tmpDir = fs72.mkdtempSync(path85.join(os.tmpdir(), "betterstart-vercel-"));
34181
+ const tmpEnv = path85.join(tmpDir, ".env.pull");
33907
34182
  try {
33908
34183
  const pull = await runVercel(
33909
34184
  runner,
@@ -34130,9 +34405,9 @@ ${deploy.stderr}`, DETAIL_MAX_LINES)
34130
34405
 
34131
34406
  // adapters/next/init/vercel/deploy/ensure-vercel-json-framework.ts
34132
34407
  import fs73 from "fs";
34133
- import path85 from "path";
34408
+ import path86 from "path";
34134
34409
  function ensureVercelJsonFramework(cwd) {
34135
- const vercelJsonPath = path85.join(cwd, "vercel.json");
34410
+ const vercelJsonPath = path86.join(cwd, "vercel.json");
34136
34411
  if (fs73.existsSync(vercelJsonPath)) {
34137
34412
  return "exists";
34138
34413
  }
@@ -34146,9 +34421,9 @@ function ensureVercelJsonFramework(cwd) {
34146
34421
  }
34147
34422
 
34148
34423
  // adapters/next/init/vercel/deploy/collect-deploy-env-vars.ts
34149
- import path86 from "path";
34424
+ import path87 from "path";
34150
34425
  function collectDeployEnvVars(cwd, existingProductionKeys) {
34151
- const local = parseDotenvFile(path86.join(cwd, ".env.local"));
34426
+ const local = parseDotenvFile(path87.join(cwd, ".env.local"));
34152
34427
  const vars = [];
34153
34428
  for (const [key, value] of local) {
34154
34429
  if (VERCEL_ENV_SYNC_SKIP_KEYS.has(key)) continue;
@@ -34547,7 +34822,7 @@ ${stderr}`;
34547
34822
  // adapters/next/commands/init/run-seed-script.ts
34548
34823
  import { spawn as spawn7 } from "child_process";
34549
34824
  import fs74 from "fs";
34550
- import path87 from "path";
34825
+ import path88 from "path";
34551
34826
 
34552
34827
  // adapters/next/templates/renderers/commands/seed/build-seed-script.ts
34553
34828
  function renderBuildSeedScriptEnvFileTemplate({
@@ -34727,8 +35002,8 @@ function buildSeedScript(authBasePath = "/api/admin/auth") {
34727
35002
 
34728
35003
  // adapters/next/commands/init/run-seed-script.ts
34729
35004
  function runSeedScript(cwd, adminDir, authBasePath, envOverrides) {
34730
- const scriptsDir = path87.join(cwd, adminDir, "scripts");
34731
- const seedPath = path87.join(scriptsDir, "seed.ts");
35005
+ const scriptsDir = path88.join(cwd, adminDir, "scripts");
35006
+ const seedPath = path88.join(scriptsDir, "seed.ts");
34732
35007
  if (!fs74.existsSync(scriptsDir)) {
34733
35008
  fs74.mkdirSync(scriptsDir, { recursive: true });
34734
35009
  }
@@ -34743,7 +35018,7 @@ function runSeedScript(cwd, adminDir, authBasePath, envOverrides) {
34743
35018
  }
34744
35019
  };
34745
35020
  return new Promise((resolve) => {
34746
- const tsxBin = path87.join(cwd, "node_modules", ".bin", "tsx");
35021
+ const tsxBin = path88.join(cwd, "node_modules", ".bin", "tsx");
34747
35022
  const child = spawn7(tsxBin, [seedPath], {
34748
35023
  cwd,
34749
35024
  stdio: "pipe",
@@ -34814,9 +35089,9 @@ function formatAdminIdentity(admin) {
34814
35089
 
34815
35090
  // adapters/next/commands/init/has-db-url.ts
34816
35091
  import fs75 from "fs";
34817
- import path88 from "path";
35092
+ import path89 from "path";
34818
35093
  function hasDbUrl(cwd) {
34819
- const envPath = path88.join(cwd, ".env.local");
35094
+ const envPath = path89.join(cwd, ".env.local");
34820
35095
  if (!fs75.existsSync(envPath)) return false;
34821
35096
  const content = fs75.readFileSync(envPath, "utf-8");
34822
35097
  for (const line of content.split("\n")) {
@@ -34881,7 +35156,7 @@ function readExistingDbUrl(cwd) {
34881
35156
 
34882
35157
  // adapters/next/commands/init/remove-existing-admin-paths.ts
34883
35158
  import fs76 from "fs";
34884
- import path89 from "path";
35159
+ import path90 from "path";
34885
35160
 
34886
35161
  // adapters/next/commands/init/normalize-namespace-for-removal.ts
34887
35162
  function normalizeNamespaceForRemoval(value) {
@@ -34909,14 +35184,14 @@ function removeExistingAdminPaths(cwd, namespaces) {
34909
35184
  const nukeFiles = [CONFIG_FILE_NAME, "ADMIN.md", "drizzle.config.ts"];
34910
35185
  let removed = 0;
34911
35186
  for (const dir of nukeDirs) {
34912
- const fullPath = path89.resolve(cwd, dir);
35187
+ const fullPath = path90.resolve(cwd, dir);
34913
35188
  if (fs76.existsSync(fullPath)) {
34914
35189
  fs76.rmSync(fullPath, { recursive: true, force: true });
34915
35190
  removed++;
34916
35191
  }
34917
35192
  }
34918
35193
  for (const file of nukeFiles) {
34919
- const fullPath = path89.resolve(cwd, file);
35194
+ const fullPath = path90.resolve(cwd, file);
34920
35195
  if (fs76.existsSync(fullPath)) {
34921
35196
  fs76.unlinkSync(fullPath);
34922
35197
  removed++;
@@ -34957,11 +35232,11 @@ function renderInitBanner() {
34957
35232
 
34958
35233
  // adapters/next/commands/init/resolve-force-init-namespaces.ts
34959
35234
  import fs78 from "fs";
34960
- import path91 from "path";
35235
+ import path92 from "path";
34961
35236
 
34962
35237
  // adapters/next/commands/init/read-existing-config-namespace.ts
34963
35238
  import fs77 from "fs";
34964
- import path90 from "path";
35239
+ import path91 from "path";
34965
35240
 
34966
35241
  // adapters/next/commands/init/read-namespace-from-config-source.ts
34967
35242
  function readNamespaceFromConfigSource(source) {
@@ -34971,7 +35246,7 @@ function readNamespaceFromConfigSource(source) {
34971
35246
 
34972
35247
  // adapters/next/commands/init/read-existing-config-namespace.ts
34973
35248
  async function readExistingConfigNamespace(cwd) {
34974
- const configPath = path90.resolve(cwd, CONFIG_FILE_NAME);
35249
+ const configPath = path91.resolve(cwd, CONFIG_FILE_NAME);
34975
35250
  if (!fs77.existsSync(configPath)) {
34976
35251
  return;
34977
35252
  }
@@ -34990,7 +35265,7 @@ async function readExistingConfigNamespace(cwd) {
34990
35265
  // adapters/next/commands/init/resolve-force-init-namespaces.ts
34991
35266
  async function resolveForceInitNamespaces(cwd, targetNamespace) {
34992
35267
  const namespaces = /* @__PURE__ */ new Set([validateAdminNamespace(targetNamespace)]);
34993
- const hasConfig = fs78.existsSync(path91.resolve(cwd, CONFIG_FILE_NAME));
35268
+ const hasConfig = fs78.existsSync(path92.resolve(cwd, CONFIG_FILE_NAME));
34994
35269
  const existingNamespace = await readExistingConfigNamespace(cwd);
34995
35270
  if (existingNamespace) {
34996
35271
  namespaces.add(existingNamespace);
@@ -35281,7 +35556,7 @@ async function runInitCommandInternal(name, options, jsonContext) {
35281
35556
  exitInit("validation", message, "INVALID_OPTIONS");
35282
35557
  }
35283
35558
  let cwd = process.cwd();
35284
- let projectName = path92.basename(cwd);
35559
+ let projectName = path93.basename(cwd);
35285
35560
  let forceMode = Boolean(options.force);
35286
35561
  let namespace = DEFAULT_ADMIN_NAMESPACE;
35287
35562
  if (options.namespace) {
@@ -35390,7 +35665,7 @@ async function runInitCommandInternal(name, options, jsonContext) {
35390
35665
  }
35391
35666
  pm = pmChoice;
35392
35667
  }
35393
- const displayName = freshProject.projectName === "." ? path92.basename(cwd) : freshProject.projectName;
35668
+ const displayName = freshProject.projectName === "." ? path93.basename(cwd) : freshProject.projectName;
35394
35669
  projectName = displayName;
35395
35670
  const { bin, prefix } = createNextAppCommand();
35396
35671
  const cnaArgs = [
@@ -35428,10 +35703,10 @@ async function runInitCommandInternal(name, options, jsonContext) {
35428
35703
  );
35429
35704
  exitInit("project", createNextAppResult.error, "CREATE_NEXT_APP_FAILED");
35430
35705
  }
35431
- cwd = path92.resolve(cwd, freshProject.projectName);
35432
- const hasPackageJson = fs79.existsSync(path92.join(cwd, "package.json"));
35706
+ cwd = path93.resolve(cwd, freshProject.projectName);
35707
+ const hasPackageJson = fs79.existsSync(path93.join(cwd, "package.json"));
35433
35708
  const hasNextConfig = ["next.config.ts", "next.config.js", "next.config.mjs"].some(
35434
- (f) => fs79.existsSync(path92.join(cwd, f))
35709
+ (f) => fs79.existsSync(path93.join(cwd, f))
35435
35710
  );
35436
35711
  if (!hasPackageJson || !hasNextConfig) {
35437
35712
  createNextAppSpinner.stop(`Failed to create Next.js app: ${displayName}`);
@@ -35752,6 +36027,8 @@ async function runInitCommandInternal(name, options, jsonContext) {
35752
36027
  scaffoldAuth({ cwd, config });
35753
36028
  s.message("Components");
35754
36029
  scaffoldComponents({ cwd, config });
36030
+ s.message("Static assets");
36031
+ scaffoldPublicAssets(cwd);
35755
36032
  s.message("Pages & layouts");
35756
36033
  scaffoldLayout({ cwd, config });
35757
36034
  s.message("API routes");
@@ -35773,10 +36050,10 @@ async function runInitCommandInternal(name, options, jsonContext) {
35773
36050
  `Existing ${proxyResult.path} left in place \u2014 add the admin session-cookie redirect to it so logged-out visitors never render the admin routes.`
35774
36051
  );
35775
36052
  }
35776
- const drizzleConfigPath = path92.join(cwd, "drizzle.config.ts");
36053
+ const drizzleConfigPath = path93.join(cwd, "drizzle.config.ts");
35777
36054
  if (!dbFiles.includes("drizzle.config.ts") && fs79.existsSync(drizzleConfigPath)) {
35778
36055
  if (forceMode) {
35779
- const { readNamespacedTemplate } = await import("./read-namespaced-template-KUENIIDC.js");
36056
+ const { readNamespacedTemplate } = await import("./read-namespaced-template-WYIGUH7S.js");
35780
36057
  fs79.writeFileSync(
35781
36058
  drizzleConfigPath,
35782
36059
  readNamespacedTemplate("drizzle.config.ts", namespace),
@@ -35789,7 +36066,7 @@ async function runInitCommandInternal(name, options, jsonContext) {
35789
36066
  initialValue: true
35790
36067
  });
35791
36068
  if (!p61.isCancel(overwrite) && overwrite) {
35792
- const { readNamespacedTemplate } = await import("./read-namespaced-template-KUENIIDC.js");
36069
+ const { readNamespacedTemplate } = await import("./read-namespaced-template-WYIGUH7S.js");
35793
36070
  fs79.writeFileSync(
35794
36071
  drizzleConfigPath,
35795
36072
  readNamespacedTemplate("drizzle.config.ts", namespace),
@@ -36089,8 +36366,7 @@ Run manually: ${pc18.cyan(pmExecCommand(pm, `betterstart seed`))}`,
36089
36366
  } else if (options.yes) {
36090
36367
  deployProvider = "none";
36091
36368
  } else {
36092
- const initialDeployProvider = railwaySessionPromise ? "railway" : readLinkedProjectId(cwd) ? "vercel" : "none";
36093
- deployProvider = await promptDeployProvider(initialDeployProvider);
36369
+ deployProvider = await promptDeployProvider();
36094
36370
  }
36095
36371
  let deployedUrl;
36096
36372
  if (deployProvider === "vercel") {
@@ -36207,7 +36483,7 @@ async function runInitCommand(name, options) {
36207
36483
 
36208
36484
  // adapters/next/commands/list-integrations.ts
36209
36485
  import * as p62 from "@clack/prompts";
36210
- import path93 from "path";
36486
+ import path94 from "path";
36211
36487
 
36212
36488
  // adapters/next/integration-runtime/list-available-integrations.ts
36213
36489
  function listAvailableIntegrations() {
@@ -36216,7 +36492,7 @@ function listAvailableIntegrations() {
36216
36492
 
36217
36493
  // adapters/next/commands/list-integrations.ts
36218
36494
  async function runListIntegrationsCommand(options) {
36219
- const cwd = options.cwd ? path93.resolve(options.cwd) : process.cwd();
36495
+ const cwd = options.cwd ? path94.resolve(options.cwd) : process.cwd();
36220
36496
  if (options.json) {
36221
36497
  let installed2;
36222
36498
  try {
@@ -36252,7 +36528,7 @@ async function runListIntegrationsCommand(options) {
36252
36528
 
36253
36529
  // adapters/next/commands/list-presets.ts
36254
36530
  import * as p63 from "@clack/prompts";
36255
- import path94 from "path";
36531
+ import path95 from "path";
36256
36532
 
36257
36533
  // adapters/next/preset-runtime/list-available-presets.ts
36258
36534
  function listAvailablePresets() {
@@ -36261,7 +36537,7 @@ function listAvailablePresets() {
36261
36537
 
36262
36538
  // adapters/next/commands/list-presets.ts
36263
36539
  async function runListPresetsCommand(options) {
36264
- const cwd = options.cwd ? path94.resolve(options.cwd) : process.cwd();
36540
+ const cwd = options.cwd ? path95.resolve(options.cwd) : process.cwd();
36265
36541
  if (options.json) {
36266
36542
  let installed2;
36267
36543
  try {
@@ -36295,7 +36571,7 @@ async function runListPresetsCommand(options) {
36295
36571
 
36296
36572
  // adapters/next/commands/update-component/get-static-asset-component-entries.ts
36297
36573
  import fs80 from "fs";
36298
- import path95 from "path";
36574
+ import path96 from "path";
36299
36575
  function getStaticAssetComponentEntries(assetDirectory) {
36300
36576
  const assetDir = resolveCliAssetPath("shared-assets", "react-admin", assetDirectory);
36301
36577
  if (!fs80.existsSync(assetDir)) return [];
@@ -36312,12 +36588,12 @@ function getStaticAssetComponentEntries(assetDirectory) {
36312
36588
  continue;
36313
36589
  }
36314
36590
  const indexFile = ["index.tsx", "index.ts"].find(
36315
- (file) => fs80.existsSync(path95.join(assetDir, entry.name, file))
36591
+ (file) => fs80.existsSync(path96.join(assetDir, entry.name, file))
36316
36592
  );
36317
36593
  if (indexFile) {
36318
36594
  components.push({
36319
36595
  name: entry.name,
36320
- file: path95.join(entry.name, indexFile)
36596
+ file: path96.join(entry.name, indexFile)
36321
36597
  });
36322
36598
  }
36323
36599
  }
@@ -36885,6 +37161,10 @@ var TEMPLATE_REGISTRY = {
36885
37161
  content: ({ cwd, config }) => adminDataTemplate(detectProjectName(cwd), config.frameworkConfig.next.namespace)
36886
37162
  },
36887
37163
  cn: { relPath: "utils/shared/cn.ts", content: () => readTemplate("utils/shared/cn.ts") },
37164
+ "shared-is-record": {
37165
+ relPath: "utils/shared/is-record.ts",
37166
+ content: () => readTemplate("utils/shared/is-record.ts")
37167
+ },
36888
37168
  "auth-can-access-admin": {
36889
37169
  relPath: "utils/auth/can-access-admin.ts",
36890
37170
  content: () => readTemplate("utils/auth/can-access-admin.ts")
@@ -36933,6 +37213,10 @@ var TEMPLATE_REGISTRY = {
36933
37213
  relPath: "utils/date/date-range-start-time.ts",
36934
37214
  content: () => readTemplate("utils/date/date-range-start-time.ts")
36935
37215
  },
37216
+ "date-format-action-date": {
37217
+ relPath: "utils/date/format-action-date.ts",
37218
+ content: () => readTemplate("utils/date/format-action-date.ts")
37219
+ },
36936
37220
  "date-format-date-range-input-date": {
36937
37221
  relPath: "utils/date/format-date-range-input-date.ts",
36938
37222
  content: () => readTemplate("utils/date/format-date-range-input-date.ts")
@@ -37669,6 +37953,10 @@ var TEMPLATE_REGISTRY = {
37669
37953
  relPath: "utils/editor/transform-selected-markdown-lines.ts",
37670
37954
  content: () => readTemplate("utils/editor/transform-selected-markdown-lines.ts")
37671
37955
  },
37956
+ "editor-set-task-item-checked": {
37957
+ relPath: "utils/editor/set-task-item-checked.ts",
37958
+ content: () => readTemplate("utils/editor/set-task-item-checked.ts")
37959
+ },
37672
37960
  "editor-update-nodes-attr": {
37673
37961
  relPath: "utils/editor/update-nodes-attr.ts",
37674
37962
  content: () => readTemplate("utils/editor/update-nodes-attr.ts")
@@ -37689,6 +37977,10 @@ var TEMPLATE_REGISTRY = {
37689
37977
  relPath: "utils/editor/table-input.ts",
37690
37978
  content: () => readTemplate("utils/editor/table-input.ts")
37691
37979
  },
37980
+ "email-email-theme": {
37981
+ relPath: "utils/email/email-theme.ts",
37982
+ content: () => readTemplate("utils/email/email-theme.ts")
37983
+ },
37692
37984
  "email-escape-html": {
37693
37985
  relPath: "utils/email/escape-html.ts",
37694
37986
  content: () => readTemplate("utils/email/escape-html.ts")
@@ -37721,6 +38013,10 @@ var TEMPLATE_REGISTRY = {
37721
38013
  relPath: "utils/email/render-thank-you-email.ts",
37722
38014
  content: () => readTemplate("utils/email/render-thank-you-email.ts")
37723
38015
  },
38016
+ "use-field-error-visible": {
38017
+ relPath: "hooks/use-field-error-visible.ts",
38018
+ content: () => readTemplate("hooks/use-field-error-visible.ts")
38019
+ },
37724
38020
  "form-clone-default-value": {
37725
38021
  relPath: "utils/form/clone-default-value.ts",
37726
38022
  content: () => readTemplate("utils/form/clone-default-value.ts")
@@ -37949,6 +38245,20 @@ var TEMPLATE_REGISTRY = {
37949
38245
  relPath: "utils/dev-mode/code-block-height.ts",
37950
38246
  content: () => readTemplate("utils/dev-mode/code-block-height.ts")
37951
38247
  },
38248
+ "dev-mode-json-schemas-utils": {
38249
+ relPath: "utils/dev-mode/dev-mode-json-schemas.ts",
38250
+ content: () => readTemplate("utils/dev-mode/dev-mode-json-schemas.ts")
38251
+ },
38252
+ "dev-mode-parse-lifecycle-hooks-utils": {
38253
+ relPath: "utils/dev-mode/parse-dev-mode-lifecycle-hooks.ts",
38254
+ content: () => readTemplate("utils/dev-mode/parse-dev-mode-lifecycle-hooks.ts"),
38255
+ dependencies: ["dev-mode-json-schemas-utils"]
38256
+ },
38257
+ "dev-mode-parse-snippets-utils": {
38258
+ relPath: "utils/dev-mode/parse-dev-mode-snippets.ts",
38259
+ content: () => readTemplate("utils/dev-mode/parse-dev-mode-snippets.ts"),
38260
+ dependencies: ["dev-mode-json-schemas-utils"]
38261
+ },
37952
38262
  "lifecycle-hooks": {
37953
38263
  relPath: "lib/lifecycle-hooks/index.ts",
37954
38264
  content: () => readTemplate("lib/lifecycle-hooks/index.ts"),
@@ -39076,16 +39386,16 @@ async function listInstallableChoices(cwd) {
39076
39386
  }
39077
39387
 
39078
39388
  // adapters/next/commands/menu-choices/list-schema-choices.ts
39079
- import path96 from "path";
39389
+ import path97 from "path";
39080
39390
  async function listSchemaChoices(cwd) {
39081
39391
  const config = await resolveConfigOrExit(cwd);
39082
39392
  const paths = resolveProjectPaths(config);
39083
- return listSchemaNames(path96.join(cwd, ...paths.schemasDir.split("/")));
39393
+ return listSchemaNames(path97.join(cwd, ...paths.schemasDir.split("/")));
39084
39394
  }
39085
39395
 
39086
39396
  // adapters/next/commands/remove-schema/run-remove-schema-command.ts
39087
39397
  import * as clack2 from "@clack/prompts";
39088
- import path97 from "path";
39398
+ import path98 from "path";
39089
39399
 
39090
39400
  // core-engine/snapshots/store/delete-snapshot.ts
39091
39401
  import fs81 from "fs";
@@ -39125,7 +39435,7 @@ function resolveSchemaOwnerForRemoval(cwd, schemaName) {
39125
39435
  // adapters/next/commands/remove-schema/run-remove-schema-command.ts
39126
39436
  async function runRemoveSchemaCommand(schemaName, options) {
39127
39437
  const owner = resolveSchemaOwnerForRemoval(
39128
- options.cwd ? path97.resolve(options.cwd) : process.cwd(),
39438
+ options.cwd ? path98.resolve(options.cwd) : process.cwd(),
39129
39439
  schemaName
39130
39440
  );
39131
39441
  if (owner === "core") {
@@ -39138,7 +39448,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
39138
39448
  clack2.log.error(`"${schemaName}" is owned by ${owner}. Remove the owning preset instead.`);
39139
39449
  process.exit(1);
39140
39450
  }
39141
- const cwd = options.cwd ? path97.resolve(options.cwd) : process.cwd();
39451
+ const cwd = options.cwd ? path98.resolve(options.cwd) : process.cwd();
39142
39452
  const config = await resolveConfigOrExit(cwd);
39143
39453
  const paths = resolveProjectPaths(config);
39144
39454
  const manifest = loadManifest(cwd, schemaName);
@@ -39174,7 +39484,7 @@ async function runRemoveSchemaCommand(schemaName, options) {
39174
39484
  }
39175
39485
  const loaded = (() => {
39176
39486
  try {
39177
- return loadSchema(path97.join(cwd, ...paths.schemasDir.split("/")), schemaName);
39487
+ return loadSchema(path98.join(cwd, ...paths.schemasDir.split("/")), schemaName);
39178
39488
  } catch {
39179
39489
  return null;
39180
39490
  }
@@ -39219,7 +39529,7 @@ Schema JSON preserved.`
39219
39529
 
39220
39530
  // adapters/next/commands/remove.ts
39221
39531
  import * as p64 from "@clack/prompts";
39222
- import path101 from "path";
39532
+ import path102 from "path";
39223
39533
 
39224
39534
  // adapters/next/init/scaffolders/dependencies/build-remove-args.ts
39225
39535
  function buildRemoveArgs(pm, deps, dev) {
@@ -39263,11 +39573,11 @@ async function removeDependenciesAsync({
39263
39573
  }
39264
39574
 
39265
39575
  // adapters/next/integration-runtime/find-blocking-integration-dependencies.ts
39266
- import path99 from "path";
39576
+ import path100 from "path";
39267
39577
 
39268
39578
  // adapters/next/integration-runtime/schema-manifest-contains-mailchimp-imports.ts
39269
39579
  import fs83 from "fs";
39270
- import path98 from "path";
39580
+ import path99 from "path";
39271
39581
  function schemaManifestContainsMailchimpImports(cwd, config, schemaName) {
39272
39582
  const manifest = loadManifest(cwd, schemaName);
39273
39583
  if (!manifest) {
@@ -39284,7 +39594,7 @@ function schemaManifestContainsMailchimpImports(cwd, config, schemaName) {
39284
39594
  ...manifest.skipped
39285
39595
  ]);
39286
39596
  return liveManifestPaths.some((filePath) => {
39287
- const fullPath = path98.join(cwd, ...filePath.split("/"));
39597
+ const fullPath = path99.join(cwd, ...filePath.split("/"));
39288
39598
  if (!fs83.existsSync(fullPath) || !fs83.statSync(fullPath).isFile()) {
39289
39599
  return false;
39290
39600
  }
@@ -39297,7 +39607,7 @@ function schemaManifestContainsMailchimpImports(cwd, config, schemaName) {
39297
39607
  function findBlockingIntegrationDependencies(cwd, config, integrationId) {
39298
39608
  const blockers = [];
39299
39609
  const paths = resolveProjectPaths(config);
39300
- const schemasDir = path99.join(cwd, ...paths.schemasDir.split("/"));
39610
+ const schemasDir = path100.join(cwd, ...paths.schemasDir.split("/"));
39301
39611
  const ownership = loadSchemaOwnershipIndex(cwd);
39302
39612
  for (const schemaName of listSchemaNames(schemasDir)) {
39303
39613
  if (ownership.schemas[schemaName] !== "user") {
@@ -39488,7 +39798,7 @@ function findBlockingSchemaDependencies(cwd, config, ownedSchemas) {
39488
39798
 
39489
39799
  // adapters/next/preset-runtime/remove-preset-schemas.ts
39490
39800
  import fs85 from "fs";
39491
- import path100 from "path";
39801
+ import path101 from "path";
39492
39802
 
39493
39803
  // preset-engine/ownership/remove-schema-owner.ts
39494
39804
  function removeSchemaOwner(cwd, schemaName) {
@@ -39529,8 +39839,8 @@ function removePresetSchemas(cwd, config, manifest) {
39529
39839
  }
39530
39840
  deleteSnapshot(cwd, schemaName);
39531
39841
  }
39532
- const schemaPath = path100.posix.join(paths.schemasDir, `${schemaName}.json`);
39533
- const formsSchemaPath = path100.posix.join(paths.schemasDir, "forms", `${schemaName}.json`);
39842
+ const schemaPath = path101.posix.join(paths.schemasDir, `${schemaName}.json`);
39843
+ const formsSchemaPath = path101.posix.join(paths.schemasDir, "forms", `${schemaName}.json`);
39534
39844
  if (removePath(cwd, schemaPath)) {
39535
39845
  deletedPaths.push(schemaPath);
39536
39846
  }
@@ -39662,7 +39972,7 @@ async function runRemoveCommand(items, options) {
39662
39972
  );
39663
39973
  process.exit(1);
39664
39974
  }
39665
- const cwd = options.cwd ? path101.resolve(options.cwd) : process.cwd();
39975
+ const cwd = options.cwd ? path102.resolve(options.cwd) : process.cwd();
39666
39976
  const config = await resolveConfigOrExit(cwd);
39667
39977
  const pm = detectPackageManager(cwd);
39668
39978
  if (!options.force) {
@@ -39715,9 +40025,9 @@ async function runRemoveCommand(items, options) {
39715
40025
  // adapters/next/commands/seed/run-seed-command.ts
39716
40026
  import * as clack3 from "@clack/prompts";
39717
40027
  import fs86 from "fs";
39718
- import path102 from "path";
40028
+ import path103 from "path";
39719
40029
  async function runSeedCommand(options) {
39720
- const cwd = options.cwd ? path102.resolve(options.cwd) : process.cwd();
40030
+ const cwd = options.cwd ? path103.resolve(options.cwd) : process.cwd();
39721
40031
  clack3.intro("BetterStart Seed");
39722
40032
  let config;
39723
40033
  try {
@@ -39793,15 +40103,15 @@ async function runSeedCommand(options) {
39793
40103
  }
39794
40104
  name = nameInput;
39795
40105
  }
39796
- const scriptsDir = path102.join(cwd, adminDir, "scripts");
39797
- const seedPath = path102.join(scriptsDir, "seed.ts");
40106
+ const scriptsDir = path103.join(cwd, adminDir, "scripts");
40107
+ const seedPath = path103.join(scriptsDir, "seed.ts");
39798
40108
  if (!fs86.existsSync(scriptsDir)) {
39799
40109
  fs86.mkdirSync(scriptsDir, { recursive: true });
39800
40110
  }
39801
40111
  const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
39802
40112
  fs86.writeFileSync(seedPath, buildSeedScript(`${namespace.apiPath}/auth`), "utf-8");
39803
40113
  const { execFile: execFile2 } = await import("child_process");
39804
- const tsxBin = path102.join(cwd, "node_modules", ".bin", "tsx");
40114
+ const tsxBin = path103.join(cwd, "node_modules", ".bin", "tsx");
39805
40115
  const runSeed2 = (overwrite) => new Promise((resolve, reject) => {
39806
40116
  execFile2(
39807
40117
  tsxBin,
@@ -39867,7 +40177,7 @@ async function runSeedCommand(options) {
39867
40177
  clack3.log.error(errMsg);
39868
40178
  clack3.log.info("You can run the seed script manually:");
39869
40179
  clack3.log.info(
39870
- ` SEED_EMAIL="${email}" SEED_PASSWORD="..." npx tsx ${path102.relative(cwd, seedPath)}`
40180
+ ` SEED_EMAIL="${email}" SEED_PASSWORD="..." npx tsx ${path103.relative(cwd, seedPath)}`
39871
40181
  );
39872
40182
  clack3.outro("");
39873
40183
  process.exit(1);
@@ -39884,12 +40194,12 @@ async function runSeedCommand(options) {
39884
40194
 
39885
40195
  // adapters/next/commands/uninstall/run-uninstall-command.ts
39886
40196
  import * as p65 from "@clack/prompts";
39887
- import path104 from "path";
40197
+ import path105 from "path";
39888
40198
  import pc19 from "picocolors";
39889
40199
 
39890
40200
  // adapters/next/commands/uninstall/build-uninstall-plan.ts
39891
40201
  import fs91 from "fs";
39892
- import path103 from "path";
40202
+ import path104 from "path";
39893
40203
 
39894
40204
  // adapters/next/commands/uninstall-cleaners/clean-css.ts
39895
40205
  import fs87 from "fs";
@@ -40008,13 +40318,13 @@ function isCLICreatedOxcConfig(configPath) {
40008
40318
  function buildUninstallPlan(cwd, namespaceValue) {
40009
40319
  const steps = [];
40010
40320
  const namespace = resolveAdminNamespace(namespaceValue);
40011
- const hasSrc = fs91.existsSync(path103.join(cwd, "src"));
40321
+ const hasSrc = fs91.existsSync(path104.join(cwd, "src"));
40012
40322
  const appBase = hasSrc ? "src/app" : "app";
40013
40323
  const dirs = [];
40014
- const adminDir = path103.join(cwd, namespace.segment);
40015
- const legacyAdminDir = path103.join(cwd, "admin");
40016
- const adminRouteGroup = path103.join(cwd, appBase, namespace.routeGroup);
40017
- const legacyAdminRouteGroup = path103.join(cwd, appBase, "(admin)");
40324
+ const adminDir = path104.join(cwd, namespace.segment);
40325
+ const legacyAdminDir = path104.join(cwd, "admin");
40326
+ const adminRouteGroup = path104.join(cwd, appBase, namespace.routeGroup);
40327
+ const legacyAdminRouteGroup = path104.join(cwd, appBase, "(admin)");
40018
40328
  if (fs91.existsSync(adminDir)) dirs.push(`${namespace.segment}/`);
40019
40329
  if (namespace.segment !== "admin" && fs91.existsSync(legacyAdminDir)) dirs.push("admin/");
40020
40330
  if (fs91.existsSync(adminRouteGroup)) dirs.push(`${appBase}/${namespace.routeGroup}/`);
@@ -40042,9 +40352,9 @@ function buildUninstallPlan(cwd, namespaceValue) {
40042
40352
  const configFiles = [];
40043
40353
  const configPaths = [];
40044
40354
  const candidates = [
40045
- [CONFIG_FILE_NAME, path103.join(cwd, CONFIG_FILE_NAME)],
40046
- ["drizzle.config.ts", path103.join(cwd, "drizzle.config.ts")],
40047
- ["ADMIN.md", path103.join(cwd, "ADMIN.md")]
40355
+ [CONFIG_FILE_NAME, path104.join(cwd, CONFIG_FILE_NAME)],
40356
+ ["drizzle.config.ts", path104.join(cwd, "drizzle.config.ts")],
40357
+ ["ADMIN.md", path104.join(cwd, "ADMIN.md")]
40048
40358
  ];
40049
40359
  for (const [label, fullPath] of candidates) {
40050
40360
  if (fs91.existsSync(fullPath)) {
@@ -40053,7 +40363,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
40053
40363
  }
40054
40364
  }
40055
40365
  for (const fileName of [".oxfmtrc.json", ".oxlintrc.json"]) {
40056
- const configPath = path103.join(cwd, fileName);
40366
+ const configPath = path104.join(cwd, fileName);
40057
40367
  if (isCLICreatedOxcConfig(configPath)) {
40058
40368
  configFiles.push(`${fileName} (CLI-created)`);
40059
40369
  configPaths.push(configPath);
@@ -40072,7 +40382,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
40072
40382
  }
40073
40383
  });
40074
40384
  }
40075
- const tsconfigPath = path103.join(cwd, "tsconfig.json");
40385
+ const tsconfigPath = path104.join(cwd, "tsconfig.json");
40076
40386
  if (fs91.existsSync(tsconfigPath)) {
40077
40387
  const content = fs91.readFileSync(tsconfigPath, "utf-8");
40078
40388
  const aliasMatches = [
@@ -40099,7 +40409,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
40099
40409
  (l) => new RegExp(`^@source\\s+"[^"]*(?:admin|${namespace.segment})[^"]*";\\s*$`).test(l)
40100
40410
  );
40101
40411
  if (sourceLines.length > 0) {
40102
- const relCss = path103.relative(cwd, cssFile);
40412
+ const relCss = path104.relative(cwd, cssFile);
40103
40413
  steps.push({
40104
40414
  label: `CSS @source lines (${relCss})`,
40105
40415
  items: [`@source lines in ${relCss}`],
@@ -40111,7 +40421,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
40111
40421
  });
40112
40422
  }
40113
40423
  }
40114
- const envPath = path103.join(cwd, ".env.local");
40424
+ const envPath = path104.join(cwd, ".env.local");
40115
40425
  if (fs91.existsSync(envPath)) {
40116
40426
  const envContent = fs91.readFileSync(envPath, "utf-8");
40117
40427
  const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
@@ -40132,7 +40442,7 @@ function buildUninstallPlan(cwd, namespaceValue) {
40132
40442
 
40133
40443
  // adapters/next/commands/uninstall/run-uninstall-command.ts
40134
40444
  async function runUninstallCommand(options) {
40135
- const cwd = options.cwd ? path104.resolve(options.cwd) : process.cwd();
40445
+ const cwd = options.cwd ? path105.resolve(options.cwd) : process.cwd();
40136
40446
  p65.intro(pc19.bgRed(pc19.white(" BetterStart Uninstall ")));
40137
40447
  let namespace = DEFAULT_ADMIN_NAMESPACE;
40138
40448
  try {
@@ -40177,7 +40487,7 @@ async function runUninstallCommand(options) {
40177
40487
  // adapters/next/commands/update-component/run-update-command.ts
40178
40488
  import * as clack8 from "@clack/prompts";
40179
40489
  import fs97 from "fs";
40180
- import path110 from "path";
40490
+ import path111 from "path";
40181
40491
 
40182
40492
  // adapters/next/integration-runtime/sync-installed-integration-manifests.ts
40183
40493
  function syncInstalledIntegrationManifests(cwd, config) {
@@ -40208,7 +40518,7 @@ function applyNamespaceToTemplateEntry(entry, config, cwd) {
40208
40518
 
40209
40519
  // adapters/next/commands/update-component/copy-namespaced-directory.ts
40210
40520
  import fs93 from "fs";
40211
- import path105 from "path";
40521
+ import path106 from "path";
40212
40522
  import fsExtra from "fs-extra";
40213
40523
 
40214
40524
  // adapters/next/commands/update-component/write-namespaced-file.ts
@@ -40226,38 +40536,38 @@ function copyNamespacedDirectory(srcDir, destDir, namespace) {
40226
40536
  const entries = fs93.readdirSync(srcDir, { withFileTypes: true });
40227
40537
  for (const entry of entries) {
40228
40538
  const namespacedName = applyAdminNamespaceToPath(entry.name, namespace);
40229
- const srcPath = path105.join(srcDir, entry.name);
40230
- const destPath = path105.join(destDir, namespacedName);
40539
+ const srcPath = path106.join(srcDir, entry.name);
40540
+ const destPath = path106.join(destDir, namespacedName);
40231
40541
  if (entry.isDirectory()) {
40232
40542
  fsExtra.ensureDirSync(destPath);
40233
40543
  copyNamespacedDirectory(srcPath, destPath, namespace);
40234
40544
  continue;
40235
40545
  }
40236
- fsExtra.ensureDirSync(path105.dirname(destPath));
40546
+ fsExtra.ensureDirSync(path106.dirname(destPath));
40237
40547
  writeNamespacedFile(srcPath, destPath, namespace);
40238
40548
  }
40239
40549
  }
40240
40550
 
40241
40551
  // adapters/next/commands/update-component/find-static-asset-file.ts
40242
40552
  import fs94 from "fs";
40243
- import path106 from "path";
40553
+ import path107 from "path";
40244
40554
  function findStaticAssetFile(assetDir, componentName) {
40245
40555
  if (!fs94.existsSync(assetDir)) return void 0;
40246
40556
  const isNestedComponentName = /[\\/]/.test(componentName);
40247
- const nestedComponentName = componentName.split(/[\\/]/).filter(Boolean).join(path106.sep);
40248
- if (isNestedComponentName && nestedComponentName && !path106.isAbsolute(componentName) && !nestedComponentName.split(path106.sep).includes("..")) {
40557
+ const nestedComponentName = componentName.split(/[\\/]/).filter(Boolean).join(path107.sep);
40558
+ if (isNestedComponentName && nestedComponentName && !path107.isAbsolute(componentName) && !nestedComponentName.split(path107.sep).includes("..")) {
40249
40559
  for (const extension of [".tsx", ".ts"]) {
40250
40560
  const relPath = `${nestedComponentName}${extension}`;
40251
- const filePath = path106.join(assetDir, relPath);
40561
+ const filePath = path107.join(assetDir, relPath);
40252
40562
  if (fs94.existsSync(filePath) && fs94.statSync(filePath).isFile()) {
40253
40563
  return relPath;
40254
40564
  }
40255
40565
  }
40256
40566
  }
40257
- if (!isNestedComponentName && !componentName.includes("..") && !path106.isAbsolute(componentName)) {
40567
+ if (!isNestedComponentName && !componentName.includes("..") && !path107.isAbsolute(componentName)) {
40258
40568
  for (const extension of [".tsx", ".ts"]) {
40259
- const relPath = path106.join(componentName, `index${extension}`);
40260
- const filePath = path106.join(assetDir, relPath);
40569
+ const relPath = path107.join(componentName, `index${extension}`);
40570
+ const filePath = path107.join(assetDir, relPath);
40261
40571
  if (fs94.existsSync(filePath) && fs94.statSync(filePath).isFile()) {
40262
40572
  return relPath;
40263
40573
  }
@@ -40306,7 +40616,7 @@ function normalizeShadcnPresetOnly(value) {
40306
40616
  import * as clack6 from "@clack/prompts";
40307
40617
  import { execFileSync as execFileSync4 } from "child_process";
40308
40618
  import fs96 from "fs";
40309
- import path109 from "path";
40619
+ import path110 from "path";
40310
40620
 
40311
40621
  // adapters/next/commands/update-component/create-admin-shadcn-components-json.ts
40312
40622
  function createAdminShadcnComponentsJson(config) {
@@ -40337,7 +40647,7 @@ function createAdminShadcnComponentsJson(config) {
40337
40647
  }
40338
40648
 
40339
40649
  // adapters/next/commands/update-component/get-host-project-files-to-restore.ts
40340
- import path107 from "path";
40650
+ import path108 from "path";
40341
40651
  function getHostProjectFilesToRestore(cwd) {
40342
40652
  const hostRelativePaths = [
40343
40653
  "app/layout.tsx",
@@ -40351,16 +40661,16 @@ function getHostProjectFilesToRestore(cwd) {
40351
40661
  "app/globals.css",
40352
40662
  "src/app/globals.css"
40353
40663
  ];
40354
- return hostRelativePaths.map((relativePath) => path107.join(cwd, relativePath));
40664
+ return hostRelativePaths.map((relativePath) => path108.join(cwd, relativePath));
40355
40665
  }
40356
40666
 
40357
40667
  // adapters/next/commands/update-component/resolve-local-shadcn-bin.ts
40358
40668
  import * as clack5 from "@clack/prompts";
40359
40669
  import fs95 from "fs";
40360
- import path108 from "path";
40670
+ import path109 from "path";
40361
40671
  function resolveLocalShadcnBin(cwd) {
40362
40672
  const binName = process.platform === "win32" ? "shadcn.cmd" : "shadcn";
40363
- const shadcnBin = path108.join(cwd, "node_modules", ".bin", binName);
40673
+ const shadcnBin = path109.join(cwd, "node_modules", ".bin", binName);
40364
40674
  if (!fs95.existsSync(shadcnBin)) {
40365
40675
  clack5.cancel(
40366
40676
  `shadcn is not installed in this project. Run 'betterstart update-deps' and try again.`
@@ -40378,13 +40688,13 @@ function runShadcnPresetUpdate({
40378
40688
  only
40379
40689
  }) {
40380
40690
  const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
40381
- const adminGlobalsPath = path109.join(cwd, config.paths.admin, namespace.globalsFile);
40382
- const componentsJsonPath = path109.join(cwd, "components.json");
40691
+ const adminGlobalsPath = path110.join(cwd, config.paths.admin, namespace.globalsFile);
40692
+ const componentsJsonPath = path110.join(cwd, "components.json");
40383
40693
  const shadcnBackupPath = `${componentsJsonPath}.bak`;
40384
40694
  const restoreAfterApplyPaths = [
40385
40695
  componentsJsonPath,
40386
40696
  shadcnBackupPath,
40387
- path109.join(cwd, config.paths.admin, "lib", "utils.ts"),
40697
+ path110.join(cwd, config.paths.admin, "lib", "utils.ts"),
40388
40698
  ...getHostProjectFilesToRestore(cwd)
40389
40699
  ];
40390
40700
  if (!preset) {
@@ -40393,7 +40703,7 @@ function runShadcnPresetUpdate({
40393
40703
  }
40394
40704
  if (!fs96.existsSync(adminGlobalsPath)) {
40395
40705
  clack6.cancel(
40396
- `Admin globals file not found at ${path109.relative(cwd, adminGlobalsPath)}. Run 'betterstart update admin-globals' first.`
40706
+ `Admin globals file not found at ${path110.relative(cwd, adminGlobalsPath)}. Run 'betterstart update admin-globals' first.`
40397
40707
  );
40398
40708
  process.exit(1);
40399
40709
  }
@@ -40403,7 +40713,7 @@ function runShadcnPresetUpdate({
40403
40713
  snapshot: captureFile(filePath)
40404
40714
  }));
40405
40715
  clack6.intro("BetterStart Shadcn Preset");
40406
- clack6.log.info(`Applying preset to ${path109.join(config.paths.admin, "components/ui")}`);
40716
+ clack6.log.info(`Applying preset to ${path110.join(config.paths.admin, "components/ui")}`);
40407
40717
  let failed = false;
40408
40718
  try {
40409
40719
  fs96.writeFileSync(
@@ -40459,7 +40769,7 @@ function validateShadcnPresetOptions(components, options) {
40459
40769
 
40460
40770
  // adapters/next/commands/update-component/run-update-command.ts
40461
40771
  async function runUpdateCommand(components, options) {
40462
- const cwd = options.cwd ? path110.resolve(options.cwd) : process.cwd();
40772
+ const cwd = options.cwd ? path111.resolve(options.cwd) : process.cwd();
40463
40773
  const normalizedOnly = normalizeShadcnPresetOnly(options.only);
40464
40774
  validateShadcnPresetOptions(components, options);
40465
40775
  if (options.json && !options.list) {
@@ -40520,7 +40830,7 @@ async function runUpdateCommand(components, options) {
40520
40830
  return;
40521
40831
  }
40522
40832
  const config = await resolveConfigOrExit(cwd);
40523
- const admin = path110.resolve(cwd, config.paths.admin);
40833
+ const admin = path111.resolve(cwd, config.paths.admin);
40524
40834
  if (!fs97.existsSync(admin)) {
40525
40835
  clack8.cancel(
40526
40836
  `Admin directory not found at ${config.paths.admin}. Run 'betterstart init' first.`
@@ -40575,7 +40885,7 @@ async function runUpdateCommand(components, options) {
40575
40885
  }
40576
40886
  const { relPath, content } = applyNamespaceToTemplateEntry(entry, config, cwd);
40577
40887
  const baseDir = entry.base === "cwd" ? cwd : admin;
40578
- const destPath = path110.join(baseDir, relPath);
40888
+ const destPath = path111.join(baseDir, relPath);
40579
40889
  if (entry.preserveExisting && fs97.existsSync(destPath)) {
40580
40890
  clack8.log.info(`Preserved ${relPath}`);
40581
40891
  updatedTemplateNames.add(name);
@@ -40585,7 +40895,7 @@ async function runUpdateCommand(components, options) {
40585
40895
  pendingWrites.push({
40586
40896
  displayPath: relPath,
40587
40897
  write: () => {
40588
- fsExtra2.ensureDirSync(path110.dirname(destPath));
40898
+ fsExtra2.ensureDirSync(path111.dirname(destPath));
40589
40899
  fs97.writeFileSync(destPath, content, "utf-8");
40590
40900
  clack8.log.success(`Updated ${relPath}`);
40591
40901
  }
@@ -40617,20 +40927,20 @@ async function runUpdateCommand(components, options) {
40617
40927
  }
40618
40928
  const namespace = config.frameworkConfig.next.namespace;
40619
40929
  const namespacedAssetFile = applyAdminNamespaceToPath(assetFile, namespace);
40620
- const destPath = path110.join(admin, "components", assetDirectory, namespacedAssetFile);
40930
+ const destPath = path111.join(admin, "components", assetDirectory, namespacedAssetFile);
40621
40931
  pendingWrites.push({
40622
40932
  displayPath: `components/${assetDirectory}/${namespacedAssetFile}`,
40623
40933
  write: () => {
40624
- fsExtra2.ensureDirSync(path110.dirname(destPath));
40625
- writeNamespacedFile(path110.join(assetDir, assetFile), destPath, namespace);
40934
+ fsExtra2.ensureDirSync(path111.dirname(destPath));
40935
+ writeNamespacedFile(path111.join(assetDir, assetFile), destPath, namespace);
40626
40936
  clack8.log.success(`Updated components/${assetDirectory}/${namespacedAssetFile}`);
40627
40937
  }
40628
40938
  });
40629
40939
  if (assetDirectory === "custom") {
40630
- const assetSubdir = path110.join(assetDir, name);
40940
+ const assetSubdir = path111.join(assetDir, name);
40631
40941
  if (fs97.existsSync(assetSubdir) && fs97.statSync(assetSubdir).isDirectory()) {
40632
40942
  const namespacedName = applyAdminNamespaceToPath(name, namespace);
40633
- const destSubdir = path110.join(admin, "components", assetDirectory, namespacedName);
40943
+ const destSubdir = path111.join(admin, "components", assetDirectory, namespacedName);
40634
40944
  pendingWrites.push({
40635
40945
  displayPath: `components/${assetDirectory}/${namespacedName}/ (template files)`,
40636
40946
  write: () => {
@@ -40665,19 +40975,19 @@ async function runUpdateCommand(components, options) {
40665
40975
  "content-editor"
40666
40976
  );
40667
40977
  const namespace = config.frameworkConfig.next.namespace;
40668
- const destBaseDir = path110.join(admin, "components", "custom", "content-editor");
40978
+ const destBaseDir = path111.join(admin, "components", "custom", "content-editor");
40669
40979
  if (!fs97.existsSync(srcBaseDir)) {
40670
40980
  return false;
40671
40981
  }
40672
40982
  const dirsToCopy = [];
40673
40983
  for (const directory of TIPTAP_CONTENT_EDITOR_DIRECTORIES) {
40674
- const srcDir = path110.join(srcBaseDir, directory);
40984
+ const srcDir = path111.join(srcBaseDir, directory);
40675
40985
  if (!fs97.existsSync(srcDir)) {
40676
40986
  continue;
40677
40987
  }
40678
40988
  dirsToCopy.push({
40679
40989
  srcDir,
40680
- destDir: path110.join(destBaseDir, applyAdminNamespaceToPath(directory, namespace))
40990
+ destDir: path111.join(destBaseDir, applyAdminNamespaceToPath(directory, namespace))
40681
40991
  });
40682
40992
  }
40683
40993
  if (dirsToCopy.length === 0) {
@@ -40691,7 +41001,7 @@ async function runUpdateCommand(components, options) {
40691
41001
  copyNamespacedDirectory(srcDir, destDir, namespace);
40692
41002
  }
40693
41003
  clack8.log.success("Updated components/custom/content-editor/tiptap-*/ (template files)");
40694
- removePath(admin, path110.join(admin, "components", "custom", "tiptap"));
41004
+ removePath(admin, path111.join(admin, "components", "custom", "tiptap"));
40695
41005
  }
40696
41006
  });
40697
41007
  updatedStaticNames.add(key);
@@ -40770,6 +41080,7 @@ async function runUpdateCommand(components, options) {
40770
41080
  entry.write();
40771
41081
  }
40772
41082
  }
41083
+ scaffoldPublicAssets(cwd);
40773
41084
  syncInstalledPresetManifests(cwd, config);
40774
41085
  syncInstalledIntegrationManifests(cwd, config);
40775
41086
  const projectPackageJson = readProjectPackageJson(cwd);
@@ -40788,7 +41099,7 @@ async function runUpdateCommand(components, options) {
40788
41099
 
40789
41100
  // adapters/next/commands/update-deps.ts
40790
41101
  import * as clack9 from "@clack/prompts";
40791
- import path111 from "path";
41102
+ import path112 from "path";
40792
41103
 
40793
41104
  // adapters/next/integration-runtime/get-installed-integrations.ts
40794
41105
  function getInstalledIntegrations(config) {
@@ -40802,7 +41113,7 @@ function getInstalledPresets(config) {
40802
41113
 
40803
41114
  // adapters/next/commands/update-deps.ts
40804
41115
  async function runUpdateDepsCommand(options) {
40805
- const cwd = options.cwd ? path111.resolve(options.cwd) : process.cwd();
41116
+ const cwd = options.cwd ? path112.resolve(options.cwd) : process.cwd();
40806
41117
  clack9.intro("BetterStart Update Dependencies");
40807
41118
  const pm = detectPackageManager(cwd);
40808
41119
  clack9.log.info(`Package manager: ${pm}`);
@@ -40838,16 +41149,16 @@ async function runUpdateDepsCommand(options) {
40838
41149
  // adapters/next/commands/update-styles.ts
40839
41150
  import * as clack10 from "@clack/prompts";
40840
41151
  import fs98 from "fs";
40841
- import path112 from "path";
41152
+ import path113 from "path";
40842
41153
  async function runUpdateStylesCommand(options) {
40843
- const cwd = options.cwd ? path112.resolve(options.cwd) : process.cwd();
41154
+ const cwd = options.cwd ? path113.resolve(options.cwd) : process.cwd();
40844
41155
  clack10.intro("BetterStart Update Styles");
40845
41156
  const config = await resolveConfigOrExit(cwd);
40846
41157
  const adminDir = config.paths.admin;
40847
41158
  const namespace = resolveAdminNamespace(config.frameworkConfig.next.namespace);
40848
- const targetPath = path112.join(cwd, adminDir, namespace.globalsFile);
41159
+ const targetPath = path113.join(cwd, adminDir, namespace.globalsFile);
40849
41160
  if (!fs98.existsSync(targetPath)) {
40850
- clack10.cancel(`${namespace.globalsFile} not found at ${path112.relative(cwd, targetPath)}`);
41161
+ clack10.cancel(`${namespace.globalsFile} not found at ${path113.relative(cwd, targetPath)}`);
40851
41162
  process.exit(1);
40852
41163
  }
40853
41164
  fs98.writeFileSync(
@@ -40855,7 +41166,7 @@ async function runUpdateStylesCommand(options) {
40855
41166
  applyAdminNamespaceToContent(readTemplate("admin-globals.css"), namespace.segment),
40856
41167
  "utf-8"
40857
41168
  );
40858
- clack10.log.success(`Updated ${path112.relative(cwd, targetPath)}`);
41169
+ clack10.log.success(`Updated ${path113.relative(cwd, targetPath)}`);
40859
41170
  clack10.outro("Styles updated");
40860
41171
  }
40861
41172