betterstart-cli 0.0.103 → 0.0.104

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 (145) hide show
  1. package/dist/assets/adapters/next/templates/renderers/commands/init/banner-art.ts +7 -0
  2. package/dist/assets/adapters/next/templates/renderers/commands/init/verify-database-reachable.ts +30 -0
  3. package/dist/assets/adapters/next/templates/renderers/commands/seed/build-seed-script.ts +171 -0
  4. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-authorship-alias-block.ts +4 -0
  5. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-authorship-data-fields.ts +4 -0
  6. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-format-action-date-source.ts +18 -0
  7. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-read-select-option-type.ts +6 -0
  8. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-relationship-data-types.ts +25 -0
  9. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-result-mapping.ts +62 -0
  10. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/generate-populate-list-rels-function.ts +50 -0
  11. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/build-restore-many-to-many-statements.ts +27 -0
  12. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/build-select-option-types.ts +37 -0
  13. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-bulk-sort-order-content.ts +93 -0
  14. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-create-content.ts +157 -0
  15. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-create-select-option-content.ts +134 -0
  16. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-delete-bulk-content.ts +85 -0
  17. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-delete-content.ts +66 -0
  18. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-distinct-files.ts +45 -0
  19. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-by-id-content.ts +55 -0
  20. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-by-slug-content.ts +55 -0
  21. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-plural-content.ts +106 -0
  22. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-select-options-content.ts +55 -0
  23. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-versions-content.ts +19 -0
  24. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-m2m-files.ts +151 -0
  25. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-restore-content.ts +123 -0
  26. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-update-content.ts +187 -0
  27. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-resolve-media-function.ts +40 -0
  28. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-slug-helpers.ts +73 -0
  29. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-version-snapshot-helpers.ts +104 -0
  30. package/dist/assets/adapters/next/templates/renderers/generators/actions/lifecycle-hook-emissions/lifecycle-context.ts +22 -0
  31. package/dist/assets/adapters/next/templates/renderers/generators/actions/lifecycle-hook-emissions/lifecycle-hook-import.ts +4 -0
  32. package/dist/assets/adapters/next/templates/renderers/generators/actions/markdown-renderer.ts +411 -0
  33. package/dist/assets/adapters/next/templates/renderers/generators/actions/select-fields-resolver.ts +99 -0
  34. package/dist/assets/adapters/next/templates/renderers/generators/actions/single-actions/generate-single-actions.ts +292 -0
  35. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-authorship-value.ts +8 -0
  36. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-column-def.ts +297 -0
  37. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-first-column-def.ts +483 -0
  38. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-image-cell-media.ts +38 -0
  39. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-image-element.ts +22 -0
  40. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-relationship-label.ts +26 -0
  41. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-select-label.ts +17 -0
  42. package/dist/assets/adapters/next/templates/renderers/generators/columns/custom-cell.ts +24 -0
  43. package/dist/assets/adapters/next/templates/renderers/generators/columns/generate-columns.ts +55 -0
  44. package/dist/assets/adapters/next/templates/renderers/generators/create-page.ts +16 -0
  45. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-database.ts +5 -0
  46. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-junction-table.ts +27 -0
  47. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-select-options-table.ts +35 -0
  48. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-table-definition.ts +25 -0
  49. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-entity-dev-mode-snippets.ts +180 -0
  50. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-form-dev-mode-snippets.ts +97 -0
  51. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-single-dev-mode-snippets.ts +60 -0
  52. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/create-dev-mode-integration-artifact.ts +89 -0
  53. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/lifecycle-hook-code.ts +55 -0
  54. package/dist/assets/adapters/next/templates/renderers/generators/edit-page.ts +33 -0
  55. package/dist/assets/adapters/next/templates/renderers/generators/email-template/generate-email-template.ts +248 -0
  56. package/dist/assets/adapters/next/templates/renderers/generators/email-template/generate-field-value.ts +31 -0
  57. package/dist/assets/adapters/next/templates/renderers/generators/emitted-helpers.ts +16 -0
  58. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/generate-icon-postfix.ts +27 -0
  59. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-boolean-field.ts +47 -0
  60. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-creatable-select-field.ts +122 -0
  61. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-date-field.ts +47 -0
  62. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-default-field.ts +53 -0
  63. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-gallery-field.ts +46 -0
  64. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-group-field.ts +16 -0
  65. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-icon-field.ts +31 -0
  66. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-markdown-field.ts +50 -0
  67. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-media-field.ts +47 -0
  68. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-multi-relationship-field.ts +91 -0
  69. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-multi-select-field.ts +219 -0
  70. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-number-field.ts +48 -0
  71. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-richtext-field.ts +50 -0
  72. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-select-field.ts +61 -0
  73. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-separator-field.ts +16 -0
  74. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-single-relationship-field.ts +93 -0
  75. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-textarea-field.ts +53 -0
  76. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-list-field.ts +163 -0
  77. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-nested-field.ts +164 -0
  78. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-nested-object-list-field.ts +59 -0
  79. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-text-input-field.ts +27 -0
  80. package/dist/assets/adapters/next/templates/renderers/generators/form/form-entity/generate-form.ts +822 -0
  81. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/build-default-value-from-sync-functions.ts +41 -0
  82. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/build-ui-imports.ts +58 -0
  83. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/generate-default-value.ts +67 -0
  84. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/generate-nested-list-default-value.ts +13 -0
  85. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/label-with-description.ts +14 -0
  86. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/render-tabs-trigger.ts +18 -0
  87. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/select-read-values-expression.ts +21 -0
  88. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-creatable-select-handlers.ts +67 -0
  89. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-creatable-select-state.ts +29 -0
  90. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-field-array-hooks.ts +13 -0
  91. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-fields-jsx.ts +30 -0
  92. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/generate-card-component.ts +129 -0
  93. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/generate-single-form.ts +66 -0
  94. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-columns/generate-column-def.ts +72 -0
  95. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-columns/generate-columns.ts +89 -0
  96. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-page/generate-page.ts +23 -0
  97. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-page-content.ts +246 -0
  98. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-submission-drawer.ts +216 -0
  99. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-table.ts +273 -0
  100. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-actions/exclusive-date-upper-bound-helper.ts +11 -0
  101. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-actions/generate-form-actions.ts +505 -0
  102. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-multistep/build-component-source.ts +197 -0
  103. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/build-field-error-helper.ts +16 -0
  104. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/error-message-line.ts +13 -0
  105. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-field-jsx.ts +226 -0
  106. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-file-upload-field-jsx.ts +41 -0
  107. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-list-field-jsx.ts +160 -0
  108. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-multiselect-field-jsx.ts +40 -0
  109. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-number-field-jsx.ts +41 -0
  110. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-text-field-jsx.ts +39 -0
  111. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/label-with-description-line.ts +14 -0
  112. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-single/build-single-step-form-component-source.ts +100 -0
  113. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-database.ts +29 -0
  114. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-hook.ts +142 -0
  115. package/dist/assets/adapters/next/templates/renderers/generators/hook/generate-hook.ts +169 -0
  116. package/dist/assets/adapters/next/templates/renderers/generators/hook/generate-single-hook.ts +30 -0
  117. package/dist/assets/adapters/next/templates/renderers/generators/navigation-extract.ts +19 -0
  118. package/dist/assets/adapters/next/templates/renderers/generators/page-content/generate-page-content.ts +419 -0
  119. package/dist/assets/adapters/next/templates/renderers/generators/page.ts +24 -0
  120. package/dist/assets/adapters/next/templates/renderers/generators/row-actions-emitters/build-delete-dialog-source.ts +108 -0
  121. package/dist/assets/adapters/next/templates/renderers/generators/row-actions-emitters/build-row-actions-source.ts +61 -0
  122. package/dist/assets/adapters/next/templates/renderers/generators/single-page.ts +59 -0
  123. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sort-label-expr.ts +9 -0
  124. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sortable-header-button-jsx.ts +20 -0
  125. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sortable-header-def.ts +14 -0
  126. package/dist/assets/adapters/next/templates/renderers/generators/table.ts +284 -0
  127. package/dist/assets/adapters/next/templates/renderers/generators/thankyou-email-template.ts +110 -0
  128. package/dist/assets/adapters/next/templates/renderers/generators/webhook-events/render-extract.ts +14 -0
  129. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/next-config/create-next-config-template.ts +48 -0
  130. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/tailwind/admin-shadow-input-utility.ts +9 -0
  131. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/tailwind/admin-theme-block.ts +42 -0
  132. package/dist/assets/adapters/next/templates/renderers/init/templates/app/admin.ts +12 -0
  133. package/dist/assets/adapters/next/templates/renderers/integration-runtime/render-core-email-provider.ts +27 -0
  134. package/dist/assets/adapters/next/templates/renderers/integration-runtime/render-core-storage-provider.ts +27 -0
  135. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-db-barrel.ts +8 -0
  136. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-navigation-barrel.ts +63 -0
  137. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-webhook-events-barrel.ts +16 -0
  138. package/dist/{chunk-TIJEHWRF.js → chunk-OYU73Q2W.js} +1 -50
  139. package/dist/chunk-OYU73Q2W.js.map +1 -0
  140. package/dist/cli.js +8864 -4010
  141. package/dist/cli.js.map +1 -1
  142. package/dist/{read-namespaced-template-UXU7OCY3.js → read-namespaced-template-EIH2NPDJ.js} +2 -2
  143. package/package.json +1 -1
  144. package/dist/chunk-TIJEHWRF.js.map +0 -1
  145. /package/dist/{read-namespaced-template-UXU7OCY3.js.map → read-namespaced-template-EIH2NPDJ.js.map} +0 -0
@@ -0,0 +1,292 @@
1
+ export function renderSingleActionsContentTemplate({
2
+ buildAuthorshipUserTypeBuildAuthorshipUserType
3
+ }: {
4
+ buildAuthorshipUserTypeBuildAuthorshipUserType: string
5
+ }): string {
6
+ return `${buildAuthorshipUserTypeBuildAuthorshipUserType}\n`
7
+ }
8
+
9
+ export function renderSingleActionsRowsTemplate({
10
+ fieldName,
11
+ relationIdCol,
12
+ junctionVar,
13
+ schemaIdCol
14
+ }: {
15
+ fieldName: string
16
+ relationIdCol: string
17
+ junctionVar: string
18
+ schemaIdCol: string
19
+ }): string {
20
+ return ` const ${fieldName}Rows = await db
21
+ .select({ ${relationIdCol}: ${junctionVar}.${relationIdCol} })
22
+ .from(${junctionVar})
23
+ .where(eq(${junctionVar}.${schemaIdCol}, SINGLETON_ID))`
24
+ }
25
+
26
+ export function renderSingleActionsServerActionTemplate({
27
+ join,
28
+ cacheReadImport,
29
+ cacheTagsVar,
30
+ singular,
31
+ hasSelectFieldsSelectOptionValue,
32
+ authorshipAliasBlock,
33
+ singletonId,
34
+ formatActionDateSource,
35
+ selectResolutionFunctions,
36
+ cacheLifeLine,
37
+ selectClause,
38
+ tableVar,
39
+ singleRowReturn,
40
+ singularText
41
+ }: {
42
+ join: string
43
+ cacheReadImport: string
44
+ cacheTagsVar: string
45
+ singular: string
46
+ hasSelectFieldsSelectOptionValue: string
47
+ authorshipAliasBlock: string
48
+ singletonId: string
49
+ formatActionDateSource: string
50
+ selectResolutionFunctions: string
51
+ cacheLifeLine: string
52
+ selectClause: string
53
+ tableVar: string
54
+ singleRowReturn: string
55
+ singularText: string
56
+ }): string {
57
+ return `'use server'
58
+
59
+ import db from '@admin/db'
60
+ import { ${join} } from '@admin/db/schema'
61
+ import { eq } from 'drizzle-orm'
62
+ import { alias } from 'drizzle-orm/pg-core'
63
+ ${cacheReadImport}
64
+ import { ${cacheTagsVar} } from './types'
65
+ import type { ${singular}${hasSelectFieldsSelectOptionValue} } from './types'
66
+
67
+ ${authorshipAliasBlock}
68
+
69
+ const SINGLETON_ID = '${singletonId}'
70
+
71
+ ${formatActionDateSource}
72
+ ${selectResolutionFunctions}
73
+ export async function get${singular}(): Promise<${singular} | null> {
74
+ 'use cache'${cacheLifeLine}
75
+ cacheTag(${cacheTagsVar}.all)
76
+
77
+ try {
78
+ const result = await ${selectClause}.where(eq(${tableVar}.id, SINGLETON_ID)).limit(1)
79
+ if (result.length === 0) return null
80
+ ${singleRowReturn}
81
+ } catch (error) {
82
+ console.error('Error fetching ${singularText}:', error)
83
+ throw new Error('Failed to fetch ${singularText}')
84
+ }
85
+ }
86
+ `
87
+ }
88
+
89
+ export function renderSingleActionsContentDetailsTemplate({
90
+ junctionVar,
91
+ schemaIdCol,
92
+ inputIdsVar,
93
+ relationIdVar,
94
+ relationIdCol
95
+ }: {
96
+ junctionVar: string
97
+ schemaIdCol: string
98
+ inputIdsVar: string
99
+ relationIdVar: string
100
+ relationIdCol: string
101
+ }): string {
102
+ return ` await tx.delete(${junctionVar}).where(eq(${junctionVar}.${schemaIdCol}, SINGLETON_ID))
103
+ if (${inputIdsVar}.length > 0) {
104
+ await tx.insert(${junctionVar}).values(
105
+ ${inputIdsVar}.map((${relationIdVar}) => ({
106
+ ${schemaIdCol}: SINGLETON_ID,
107
+ ${relationIdCol}: ${relationIdVar}
108
+ }))
109
+ )
110
+ }`
111
+ }
112
+
113
+ export function renderSingleActionsServerActionSerializedValueTemplate({
114
+ join,
115
+ cacheInvalidationFn,
116
+ singular,
117
+ kebabSingular,
118
+ cacheTagsVar,
119
+ markdownImport,
120
+ singletonId,
121
+ fieldMeta,
122
+ m2mInputDeclarationsContent,
123
+ htmlUpsertBlock,
124
+ tableVar,
125
+ schemaName,
126
+ auditCategory,
127
+ stringify,
128
+ m2mWriteStatementsContent,
129
+ camelSingular,
130
+ singularText
131
+ }: {
132
+ join: string
133
+ cacheInvalidationFn: string
134
+ singular: string
135
+ kebabSingular: string
136
+ cacheTagsVar: string
137
+ markdownImport: string
138
+ singletonId: string
139
+ fieldMeta: string
140
+ m2mInputDeclarationsContent: string
141
+ htmlUpsertBlock: string
142
+ tableVar: string
143
+ schemaName: string
144
+ auditCategory: string
145
+ stringify: string
146
+ m2mWriteStatementsContent: string
147
+ camelSingular: string
148
+ singularText: string
149
+ }): string {
150
+ return `'use server'
151
+
152
+ import { requireRole, UserRole } from '@admin/auth/middleware'
153
+ import { getAuditRequestMetadata } from '@admin/actions/audit/get-audit-request-metadata'
154
+ import db from '@admin/db'
155
+ import { ${join} } from '@admin/db/schema'
156
+ import { eq } from 'drizzle-orm'
157
+ import { runAfterHooks, runBeforeHooks } from '@admin/lib/lifecycle-hooks'
158
+ import { getChangedFieldNames } from '@admin/utils/audit/get-changed-field-names'
159
+ import { getTouchedFieldNames } from '@admin/utils/audit/get-touched-field-names'
160
+ import { ${cacheInvalidationFn} } from 'next/cache'
161
+ import { get${singular} } from './get-${kebabSingular}'
162
+ import { ${cacheTagsVar} } from './types'
163
+ import type { ${singular}UpsertInput, ${singular}UpsertResult, ${singular} } from './types'${markdownImport}
164
+
165
+ const SINGLETON_ID = '${singletonId}'
166
+
167
+ export async function upsert${singular}(input: ${singular}UpsertInput): Promise<${singular}UpsertResult> {
168
+ const actor = await requireRole([UserRole.ADMIN, UserRole.EDITOR])
169
+
170
+ try {
171
+ const actorId = actor.id
172
+ const fieldMeta = [
173
+ ${fieldMeta}
174
+ ]
175
+ ${m2mInputDeclarationsContent}
176
+
177
+ const processedData: Record<string, unknown> = {}
178
+ for (const [key, value] of Object.entries(input)) {
179
+ const field = fieldMeta.find(f => f.name === key)
180
+ if (!field) continue
181
+ if (field.type === 'list') {
182
+ processedData[key] = value || []
183
+ } else if (!field.required && ['number', 'decimal'].includes(field.type)) {
184
+ processedData[key] =
185
+ value === undefined ||
186
+ value === null ||
187
+ value === '' ||
188
+ (typeof value === 'number' && Number.isNaN(value))
189
+ ? null
190
+ : value
191
+ } else if (!field.required && ['date', 'timestamp', 'time', 'string', 'email', 'varchar', 'text', 'select', 'relationship'].includes(field.type)) {
192
+ processedData[key] = value && value !== '' ? value : null
193
+ } else {
194
+ processedData[key] = value
195
+ }
196
+ }
197
+ ${htmlUpsertBlock}
198
+ const now = new Date().toISOString()
199
+ const auditRequestMetadata = await getAuditRequestMetadata()
200
+ const [previousRow] = await db
201
+ .select()
202
+ .from(${tableVar})
203
+ .where(eq(${tableVar}.id, SINGLETON_ID))
204
+ .limit(1)
205
+ const changedFields = previousRow
206
+ ? getChangedFieldNames(previousRow as unknown as Record<string, unknown>, processedData)
207
+ : getTouchedFieldNames(processedData)
208
+
209
+ const lifecycleContext = {
210
+ user: actor,
211
+ entityType: '${schemaName}',
212
+ schemaType: 'single' as const,
213
+ auditCategory: '${auditCategory}' as const,
214
+ timestamp: now,
215
+ sourceType: 'admin_ui' as const,
216
+ ipAddress: auditRequestMetadata.ipAddress,
217
+ userAgent: auditRequestMetadata.userAgent,
218
+ entityId: SINGLETON_ID,
219
+ input: processedData,
220
+ changedFields,
221
+ targetLabel: ${stringify}
222
+ }
223
+ await runBeforeHooks(previousRow ? 'beforeUpdate' : 'beforeCreate', lifecycleContext)
224
+
225
+ const result = await db.transaction(async (tx) => {
226
+ const rows = await tx
227
+ .insert(${tableVar})
228
+ .values({
229
+ id: SINGLETON_ID,
230
+ ...processedData,
231
+ createdAt: now,
232
+ updatedAt: now,
233
+ createdBy: actorId,
234
+ updatedBy: actorId
235
+ })
236
+ .onConflictDoUpdate({
237
+ target: ${tableVar}.id,
238
+ set: { ...processedData, updatedAt: now, updatedBy: actorId }
239
+ })
240
+ .returning()
241
+ ${m2mWriteStatementsContent}
242
+ return rows
243
+ })
244
+
245
+ ${cacheInvalidationFn}(${cacheTagsVar}.all)
246
+ const saved${singular} = await get${singular}()
247
+ runAfterHooks(previousRow ? 'afterUpdate' : 'afterCreate', {
248
+ ...lifecycleContext,
249
+ data: (saved${singular} ?? result[0]) as unknown as Record<string, unknown>
250
+ })
251
+
252
+ return {
253
+ success: true,
254
+ ${camelSingular}: saved${singular} ?? (result[0] as unknown as ${singular})
255
+ }
256
+ } catch (error) {
257
+ console.error('Error upserting ${singularText}:', error)
258
+ throw new Error(error instanceof Error ? error.message : 'Failed to save ${singularText}')
259
+ }
260
+ }
261
+ `
262
+ }
263
+
264
+ export function renderSingleActionsContentDetailsBranchTemplate({
265
+ singular,
266
+ kebabSingular
267
+ }: {
268
+ singular: string
269
+ kebabSingular: string
270
+ }): string {
271
+ return `
272
+ export { get${singular}SelectOptions } from './get-${kebabSingular}-select-options'
273
+ export { create${singular}SelectOption } from './create-${kebabSingular}-select-option'
274
+ `
275
+ }
276
+
277
+ export function renderSingleActionsContentDetailsBranchBodyTemplate({
278
+ singular,
279
+ selectOptionTypeExports,
280
+ kebabSingular,
281
+ selectOptionFunctionExports
282
+ }: {
283
+ singular: string
284
+ selectOptionTypeExports: string
285
+ kebabSingular: string
286
+ selectOptionFunctionExports: string
287
+ }): string {
288
+ return `export type { ${singular}, ${singular}UpsertInput, ${singular}UpsertResult${selectOptionTypeExports} } from './types'
289
+ export { get${singular} } from './get-${kebabSingular}'
290
+ export { upsert${singular} } from './upsert-${kebabSingular}'${selectOptionFunctionExports}
291
+ `
292
+ }
@@ -0,0 +1,8 @@
1
+ export function renderAuthorshipValueActorTemplate({
2
+ userAccessor
3
+ }: {
4
+ userAccessor: string
5
+ }): string {
6
+ return `const actor = row.original.${userAccessor}
7
+ const label = actor?.name || actor?.email`
8
+ }
@@ -0,0 +1,297 @@
1
+ export function renderColumnDefTemplate({
2
+ sortLabelExpr,
3
+ sortableHeaderButtonJsx
4
+ }: {
5
+ sortLabelExpr: string
6
+ sortableHeaderButtonJsx: string
7
+ }): string {
8
+ return `header: ({ column }) => {
9
+ ${sortLabelExpr}
10
+ return (
11
+ ${sortableHeaderButtonJsx}
12
+ )
13
+ }`
14
+ }
15
+
16
+ export function renderColumnDefLayoutTemplate({
17
+ generateAuthorshipValue
18
+ }: {
19
+ generateAuthorshipValue: string
20
+ }): string {
21
+ return `cell: ({ row }) => {
22
+ ${generateAuthorshipValue}
23
+ return label ? (
24
+ <div className="text-sm font-medium" title={actor?.email}>
25
+ {label}
26
+ </div>
27
+ ) : (
28
+ <div className="text-muted-foreground">Unavailable</div>
29
+ )
30
+ }`
31
+ }
32
+
33
+ export function renderColumnDefContentTemplate({
34
+ generateImageCellMedia
35
+ }: {
36
+ generateImageCellMedia: string
37
+ }): string {
38
+ return `cell: ({ row }) => {
39
+ ${generateImageCellMedia}
40
+ }`
41
+ }
42
+
43
+ export function renderColumnDefRenderGenerateSelectLabelTemplate({
44
+ columnAccessorKey,
45
+ generateSelectLabel
46
+ }: {
47
+ columnAccessorKey: string
48
+ generateSelectLabel: string
49
+ }): string {
50
+ return `cell: ({ row }) => {
51
+ const value = row.getValue('${columnAccessorKey}')
52
+ ${generateSelectLabel}
53
+ return (
54
+ <Badge variant="outline">
55
+ {label || 'Unavailable'}
56
+ </Badge>
57
+ )
58
+ }`
59
+ }
60
+
61
+ export function renderColumnDefRenderGenerateRelationshipLabelTemplate({
62
+ columnAccessorKey,
63
+ generateRelationshipLabel
64
+ }: {
65
+ columnAccessorKey: string
66
+ generateRelationshipLabel: string
67
+ }): string {
68
+ return `cell: ({ row }) => {
69
+ const value = row.getValue('${columnAccessorKey}')
70
+ ${generateRelationshipLabel}
71
+ return (
72
+ <Badge variant="outline">
73
+ {label || 'Unavailable'}
74
+ </Badge>
75
+ )
76
+ }`
77
+ }
78
+
79
+ export function renderColumnDefRenderDetailsTemplate({
80
+ columnAccessorKey
81
+ }: {
82
+ columnAccessorKey: string
83
+ }): string {
84
+ return `cell: ({ row }) => {
85
+ const value = row.getValue('${columnAccessorKey}')
86
+ return (
87
+ <Badge variant="outline">
88
+ {value === null || value === undefined ? 'Unavailable' : String(value)}
89
+ </Badge>
90
+ )
91
+ }`
92
+ }
93
+
94
+ export function renderColumnDefLayoutDetailsTemplate({
95
+ columnAccessorKey
96
+ }: {
97
+ columnAccessorKey: string
98
+ }): string {
99
+ return `cell: ({ row }) => {
100
+ const date = new Date(row.getValue('${columnAccessorKey}'))
101
+ return (
102
+ <div className="text-sm">
103
+ {date.toLocaleDateString('en-US', {
104
+ month: 'short',
105
+ day: 'numeric',
106
+ year: 'numeric'
107
+ })}
108
+ </div>
109
+ )
110
+ }`
111
+ }
112
+
113
+ export function renderColumnDefLayoutDetailsBranchTemplate({
114
+ columnAccessorKey
115
+ }: {
116
+ columnAccessorKey: string
117
+ }): string {
118
+ return `cell: ({ row }) => {
119
+ const email = row.getValue('${columnAccessorKey}') as string
120
+ return <div className="text-sm font-medium">{email}</div>
121
+ }`
122
+ }
123
+
124
+ export function renderColumnDefLayoutDetailsBranchBodyTemplate({
125
+ columnAccessorKey
126
+ }: {
127
+ columnAccessorKey: string
128
+ }): string {
129
+ return `cell: ({ row }) => {
130
+ const amount = row.getValue('${columnAccessorKey}') as number
131
+ return (
132
+ <div className="text-sm font-medium">
133
+ {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount)}
134
+ </div>
135
+ )
136
+ }`
137
+ }
138
+
139
+ export function renderColumnDefLayoutDetailsBranchBodyFragmentTemplate({
140
+ columnAccessorKey
141
+ }: {
142
+ columnAccessorKey: string
143
+ }): string {
144
+ return `cell: ({ row }) => {
145
+ const value = row.getValue('${columnAccessorKey}') as number
146
+ return <div className="text-sm">{value}</div>
147
+ }`
148
+ }
149
+
150
+ export function renderColumnDefRenderDetailsBranchTemplate({
151
+ columnAccessorKey,
152
+ trueLabel,
153
+ falseLabel
154
+ }: {
155
+ columnAccessorKey: string
156
+ trueLabel: string
157
+ falseLabel: string
158
+ }): string {
159
+ return `cell: ({ row }) => {
160
+ const value = row.getValue('${columnAccessorKey}') as boolean
161
+ return (
162
+ <Badge variant={value ? 'outline' : 'secondary'}>
163
+ {value ? ${trueLabel} : ${falseLabel}}
164
+ </Badge>
165
+ )
166
+ }`
167
+ }
168
+
169
+ export function renderColumnDefLayoutDetailsBranchBodyFragmentSectionTemplate({
170
+ columnAccessorKey
171
+ }: {
172
+ columnAccessorKey: string
173
+ }): string {
174
+ return `cell: ({ row }) => {
175
+ const value = row.getValue('${columnAccessorKey}') as string
176
+ if (!value) return <div className="text-muted-foreground">\u2014</div>
177
+ return (
178
+ <a
179
+ href={value}
180
+ target="_blank"
181
+ rel="noopener noreferrer"
182
+ className="text-sm text-blue-600 hover:text-blue-800 hover:underline dark:text-blue-400 dark:hover:text-blue-300"
183
+ title={value}
184
+ >
185
+ {truncateText(value, 50)}
186
+ </a>
187
+ )
188
+ }`
189
+ }
190
+
191
+ export function renderColumnDefContentDetailsTemplate({
192
+ columnComponent
193
+ }: {
194
+ columnComponent: string
195
+ }): string {
196
+ return `cell: ({ row }) => {
197
+ return <${columnComponent} data={row.original} />
198
+ }`
199
+ }
200
+
201
+ export function renderColumnDefValueTemplate({
202
+ columnAccessorKey,
203
+ generateSelectLabel
204
+ }: {
205
+ columnAccessorKey: string
206
+ generateSelectLabel: string
207
+ }): string {
208
+ return `cell: ({ row }) => {
209
+ const value = row.getValue('${columnAccessorKey}')
210
+ ${generateSelectLabel}
211
+ return <div>{label || 'Unavailable'}</div>
212
+ }`
213
+ }
214
+
215
+ export function renderColumnDefValueGenerateRelationshipLabelTemplate({
216
+ columnAccessorKey,
217
+ generateRelationshipLabel
218
+ }: {
219
+ columnAccessorKey: string
220
+ generateRelationshipLabel: string
221
+ }): string {
222
+ return `cell: ({ row }) => {
223
+ const value = row.getValue('${columnAccessorKey}')
224
+ ${generateRelationshipLabel}
225
+ return <div>{label || 'Unavailable'}</div>
226
+ }`
227
+ }
228
+
229
+ export function renderColumnDefValueDetailsTemplate({
230
+ columnAccessorKey
231
+ }: {
232
+ columnAccessorKey: string
233
+ }): string {
234
+ return `cell: ({ row }) => {
235
+ const value = row.getValue('${columnAccessorKey}')
236
+ return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>
237
+ }`
238
+ }
239
+
240
+ export function renderColumnDefValueGenerateSelectLabelTemplate({
241
+ columnAccessorKey,
242
+ generateSelectLabel
243
+ }: {
244
+ columnAccessorKey: string
245
+ generateSelectLabel: string
246
+ }): string {
247
+ return `cell: ({ row }) => {
248
+ const value = row.getValue('${columnAccessorKey}')
249
+ ${generateSelectLabel}
250
+ return <div>{label || 'Unavailable'}</div>
251
+ }`
252
+ }
253
+
254
+ export function renderColumnDefValueGenerateRelationshipLabelValueTemplate({
255
+ columnAccessorKey,
256
+ generateRelationshipLabel
257
+ }: {
258
+ columnAccessorKey: string
259
+ generateRelationshipLabel: string
260
+ }): string {
261
+ return `cell: ({ row }) => {
262
+ const value = row.getValue('${columnAccessorKey}')
263
+ ${generateRelationshipLabel}
264
+ return <div>{label || 'Unavailable'}</div>
265
+ }`
266
+ }
267
+
268
+ export function renderColumnDefValueDetailsBranchTemplate({
269
+ columnAccessorKey
270
+ }: {
271
+ columnAccessorKey: string
272
+ }): string {
273
+ return `cell: ({ row }) => {
274
+ const value = row.getValue('${columnAccessorKey}')
275
+ return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>
276
+ }`
277
+ }
278
+
279
+ export function renderColumnDefContentBuildColumnSizeTemplate({
280
+ columnAccessorKey,
281
+ columnSize,
282
+ meta,
283
+ headerDef,
284
+ cellDef
285
+ }: {
286
+ columnAccessorKey: string
287
+ columnSize: string
288
+ meta: string
289
+ headerDef: string
290
+ cellDef: string
291
+ }): string {
292
+ return ` {
293
+ accessorKey: '${columnAccessorKey}',
294
+ ${columnSize}${meta}${headerDef},
295
+ ${cellDef}
296
+ }`
297
+ }