betterstart-cli 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/copyable-code-block.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-code-mirror.tsx +11 -5
- package/dist/assets/adapters/next/templates/init/lib/actions/media/types.ts +9 -1
- package/dist/assets/adapters/next/templates/init/types/index.ts +2 -0
- package/dist/cli.js +88 -11
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/copyable-code-block.tsx
CHANGED
|
@@ -66,7 +66,7 @@ export function CopyableCodeBlock({ label, code, language, tabs }: CopyableCodeB
|
|
|
66
66
|
|
|
67
67
|
{codeTabs.map((tab) => (
|
|
68
68
|
<TabsContent key={tab.id} value={tab.id} className="min-h-0 overflow-auto">
|
|
69
|
-
<CardContent className="p-0 overflow-auto">
|
|
69
|
+
<CardContent className="p-0 overflow-auto select-text">
|
|
70
70
|
<React.Suspense fallback={<PlainCodeFallback code={tab.code} />}>
|
|
71
71
|
<LazyCodeMirror code={tab.code} language={tab.language} theme={codeTheme} />
|
|
72
72
|
</React.Suspense>
|
|
@@ -92,7 +92,7 @@ export function CopyableCodeBlock({ label, code, language, tabs }: CopyableCodeB
|
|
|
92
92
|
{isCopied ? <Check /> : <Copy />}
|
|
93
93
|
</Button>
|
|
94
94
|
</CardHeader>
|
|
95
|
-
<CardContent className="p-0 overflow-auto">
|
|
95
|
+
<CardContent className="p-0 overflow-auto select-text">
|
|
96
96
|
<React.Suspense fallback={<PlainCodeFallback code={code} />}>
|
|
97
97
|
<LazyCodeMirror code={code} language={language} theme={codeTheme} />
|
|
98
98
|
</React.Suspense>
|
package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-code-mirror.tsx
CHANGED
|
@@ -19,10 +19,20 @@ const compactCodeTheme = EditorView.theme({
|
|
|
19
19
|
'&': {
|
|
20
20
|
fontSize: '12px'
|
|
21
21
|
},
|
|
22
|
+
'.cm-editor': {
|
|
23
|
+
userSelect: 'text'
|
|
24
|
+
},
|
|
22
25
|
'.cm-content': {
|
|
26
|
+
userSelect: 'text',
|
|
23
27
|
padding: '10px 0 14px'
|
|
24
28
|
},
|
|
29
|
+
'.cm-scroller': {
|
|
30
|
+
userSelect: 'text',
|
|
31
|
+
fontFamily:
|
|
32
|
+
'ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace'
|
|
33
|
+
},
|
|
25
34
|
'.cm-gutters': {
|
|
35
|
+
userSelect: 'none',
|
|
26
36
|
padding: '0 0 14px'
|
|
27
37
|
},
|
|
28
38
|
'.cm-content, .cm-gutters': {
|
|
@@ -33,10 +43,6 @@ const compactCodeTheme = EditorView.theme({
|
|
|
33
43
|
},
|
|
34
44
|
'.cm-line': {
|
|
35
45
|
padding: '0 16px'
|
|
36
|
-
},
|
|
37
|
-
'.cm-scroller': {
|
|
38
|
-
fontFamily:
|
|
39
|
-
'ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace'
|
|
40
46
|
}
|
|
41
47
|
})
|
|
42
48
|
|
|
@@ -58,8 +64,8 @@ export default function DevModeCodeMirror({ code, language, theme }: DevModeCode
|
|
|
58
64
|
return (
|
|
59
65
|
<CodeMirror
|
|
60
66
|
value={code}
|
|
61
|
-
editable={false}
|
|
62
67
|
readOnly
|
|
68
|
+
className="select-text"
|
|
63
69
|
basicSetup={codeMirrorSetup}
|
|
64
70
|
extensions={extensions}
|
|
65
71
|
theme={theme === 'dark' ? githubDark : githubLight}
|
|
@@ -2,7 +2,15 @@ import type { AdminMedia } from '@admin/types'
|
|
|
2
2
|
|
|
3
3
|
export type CreateMediaInput = Omit<
|
|
4
4
|
AdminMedia,
|
|
5
|
-
|
|
5
|
+
| 'id'
|
|
6
|
+
| 'createdAt'
|
|
7
|
+
| 'updatedAt'
|
|
8
|
+
| 'createdAtFormatted'
|
|
9
|
+
| 'updatedAtFormatted'
|
|
10
|
+
| 'createdBy'
|
|
11
|
+
| 'updatedBy'
|
|
12
|
+
| 'createdByUser'
|
|
13
|
+
| 'updatedByUser'
|
|
6
14
|
>
|
|
7
15
|
|
|
8
16
|
export interface CreateMediaResult {
|
package/dist/cli.js
CHANGED
|
@@ -3892,12 +3892,17 @@ function buildResultMapping(allDbFields, relationshipFields, Plural, camelPlural
|
|
|
3892
3892
|
` const createdByUser = row.createdByUser as { id?: string | null; name?: string | null; email?: string | null } | null | undefined`,
|
|
3893
3893
|
` const updatedByUser = row.updatedByUser as { id?: string | null; name?: string | null; email?: string | null } | null | undefined`
|
|
3894
3894
|
].filter(Boolean).join("\n");
|
|
3895
|
+
const mappedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted") ? [] : [
|
|
3896
|
+
` createdAtFormatted: formatActionDate(row.createdAt)`,
|
|
3897
|
+
` updatedAtFormatted: formatActionDate(row.updatedAt)`
|
|
3898
|
+
];
|
|
3895
3899
|
const rowMappings = allDbFields.map((f) => {
|
|
3896
3900
|
if (f.type === "relationship" && !f.multiple) {
|
|
3897
3901
|
return ` ${f.name}: ${f.name}?.id ? { id: ${f.name}.id, name: ${f.name}.name ?? undefined, title: ${f.name}.title ?? undefined, slug: ${f.name}.slug ?? undefined, label: ${f.name}.label ?? undefined } : null`;
|
|
3898
3902
|
}
|
|
3899
3903
|
return ` ${f.name}: row.${f.name}`;
|
|
3900
3904
|
}).concat([
|
|
3905
|
+
...mappedTimestampFields,
|
|
3901
3906
|
` createdByUser: createdByUser?.id ? { id: createdByUser.id, name: createdByUser.name ?? '', email: createdByUser.email ?? '' } : null`,
|
|
3902
3907
|
` updatedByUser: updatedByUser?.id ? { id: updatedByUser.id, name: updatedByUser.name ?? '', email: updatedByUser.email ?? '' } : null`
|
|
3903
3908
|
]).join(",\n");
|
|
@@ -3938,9 +3943,14 @@ function buildSingleRowMapping(allDbFields, _relationshipFields, typeName, htmlF
|
|
|
3938
3943
|
return ` ${f.name}: row.${f.name}`;
|
|
3939
3944
|
});
|
|
3940
3945
|
const htmlMappings = htmlFields.map((f) => ` ${f.name}Html: row.${f.name}Html`);
|
|
3946
|
+
const singleTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted") ? [] : [
|
|
3947
|
+
` createdAtFormatted: formatActionDate(row.createdAt)`,
|
|
3948
|
+
` updatedAtFormatted: formatActionDate(row.updatedAt)`
|
|
3949
|
+
];
|
|
3941
3950
|
const mappings = [
|
|
3942
3951
|
...fieldMappings,
|
|
3943
3952
|
...htmlMappings,
|
|
3953
|
+
...singleTimestampFields,
|
|
3944
3954
|
` createdByUser: row.createdByUser?.id ? { id: row.createdByUser.id, name: row.createdByUser.name, email: row.createdByUser.email } : null`,
|
|
3945
3955
|
` updatedByUser: row.updatedByUser?.id ? { id: row.updatedByUser.id, name: row.updatedByUser.name, email: row.updatedByUser.email } : null`
|
|
3946
3956
|
].join(",\n");
|
|
@@ -4172,6 +4182,7 @@ var SINGLE_ACTION_FIELD_EXCLUSIONS = /* @__PURE__ */ new Set(["id", "createdAt",
|
|
|
4172
4182
|
var DEFAULT_ADMIN_IMPORT_ALIAS = "@admin";
|
|
4173
4183
|
var SAMPLE_UUID = "00000000-0000-4000-8000-000000000001";
|
|
4174
4184
|
var SINGLETON_ID = "00000000-0000-0000-0000-000000000001";
|
|
4185
|
+
var SAMPLE_FORMATTED_TIMESTAMP = "Jan 01, 2026";
|
|
4175
4186
|
function isActionField(field, exclusions) {
|
|
4176
4187
|
return !field.primaryKey && !exclusions.has(field.name) && !isAuthorshipFieldName(field.name) && !isLayoutField(field.type);
|
|
4177
4188
|
}
|
|
@@ -4354,6 +4365,8 @@ function sampleAdminMedia() {
|
|
|
4354
4365
|
tags: ["example"],
|
|
4355
4366
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
4356
4367
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
4368
|
+
createdAtFormatted: SAMPLE_FORMATTED_TIMESTAMP,
|
|
4369
|
+
updatedAtFormatted: SAMPLE_FORMATTED_TIMESTAMP,
|
|
4357
4370
|
createdBy: "user-id",
|
|
4358
4371
|
updatedBy: "user-id"
|
|
4359
4372
|
};
|
|
@@ -4392,7 +4405,7 @@ function createEntityDataObject(schema) {
|
|
|
4392
4405
|
return field.type === "image" || field.type === "video" || field.type === "media";
|
|
4393
4406
|
});
|
|
4394
4407
|
const galleryFields = regularDbFields.filter((field) => field.type === "gallery");
|
|
4395
|
-
return {
|
|
4408
|
+
return addFormattedTimestamps({
|
|
4396
4409
|
...Object.fromEntries(allDbFields.map((field) => [field.name, sampleSchemaOutputValue(field)])),
|
|
4397
4410
|
...Object.fromEntries(
|
|
4398
4411
|
htmlOutputFields.map((field) => [
|
|
@@ -4407,7 +4420,17 @@ function createEntityDataObject(schema) {
|
|
|
4407
4420
|
),
|
|
4408
4421
|
createdByUser: sampleAdminUserSummary(),
|
|
4409
4422
|
updatedByUser: sampleAdminUserSummary()
|
|
4410
|
-
};
|
|
4423
|
+
});
|
|
4424
|
+
}
|
|
4425
|
+
function addFormattedTimestamps(data) {
|
|
4426
|
+
const output = { ...data };
|
|
4427
|
+
if (typeof output.createdAt === "string") {
|
|
4428
|
+
output.createdAtFormatted = SAMPLE_FORMATTED_TIMESTAMP;
|
|
4429
|
+
}
|
|
4430
|
+
if (typeof output.updatedAt === "string") {
|
|
4431
|
+
output.updatedAtFormatted = SAMPLE_FORMATTED_TIMESTAMP;
|
|
4432
|
+
}
|
|
4433
|
+
return output;
|
|
4411
4434
|
}
|
|
4412
4435
|
function getSingleAllDbFields(schema) {
|
|
4413
4436
|
const dbFields = flattenFields(schema.fields).filter(
|
|
@@ -4430,7 +4453,7 @@ function getSingleAllDbFields(schema) {
|
|
|
4430
4453
|
function createSingleDataObject(schema) {
|
|
4431
4454
|
const dbFields = getSingleAllDbFields(schema);
|
|
4432
4455
|
const htmlOutputFields = getHtmlOutputFields(dbFields);
|
|
4433
|
-
return {
|
|
4456
|
+
return addFormattedTimestamps({
|
|
4434
4457
|
...Object.fromEntries(dbFields.map((field) => [field.name, sampleSingleOutputValue(field)])),
|
|
4435
4458
|
...Object.fromEntries(
|
|
4436
4459
|
htmlOutputFields.map((field) => [
|
|
@@ -4440,7 +4463,7 @@ function createSingleDataObject(schema) {
|
|
|
4440
4463
|
),
|
|
4441
4464
|
createdByUser: sampleAdminUserSummary(),
|
|
4442
4465
|
updatedByUser: sampleAdminUserSummary()
|
|
4443
|
-
};
|
|
4466
|
+
});
|
|
4444
4467
|
}
|
|
4445
4468
|
function createFormSubmissionObject(fields) {
|
|
4446
4469
|
return {
|
|
@@ -8021,6 +8044,19 @@ function genHelpersContent(ctx) {
|
|
|
8021
8044
|
lines.push(`import type { AdminMedia } from '@admin/types'`);
|
|
8022
8045
|
}
|
|
8023
8046
|
lines.push(`import type { ${ctx.Singular} } from './types'`);
|
|
8047
|
+
lines.push("");
|
|
8048
|
+
lines.push(`export function formatActionDate(value: unknown): string {
|
|
8049
|
+
if (typeof value !== 'string') return ''
|
|
8050
|
+
const date = new Date(value)
|
|
8051
|
+
if (Number.isNaN(date.getTime())) return ''
|
|
8052
|
+
|
|
8053
|
+
return date.toLocaleDateString('en-US', {
|
|
8054
|
+
month: 'short',
|
|
8055
|
+
day: '2-digit',
|
|
8056
|
+
year: 'numeric',
|
|
8057
|
+
timeZone: 'UTC'
|
|
8058
|
+
})
|
|
8059
|
+
}`);
|
|
8024
8060
|
lines.push("");
|
|
8025
8061
|
if (ctx.hasListRels) {
|
|
8026
8062
|
const exportedFn = ctx.populateListRelsFn.replace("async function", "export async function").trim();
|
|
@@ -8133,10 +8169,32 @@ function generateResolveMediaFunction(ctx) {
|
|
|
8133
8169
|
}`
|
|
8134
8170
|
).join("\n");
|
|
8135
8171
|
const assignSingle = singleFields.map(
|
|
8136
|
-
(name) => ` row.${name}Media =
|
|
8172
|
+
(name) => ` row.${name}Media = row.${name} && !row.${name}.startsWith('http')
|
|
8173
|
+
? (() => {
|
|
8174
|
+
const media = mediaMap.get(row.${name})
|
|
8175
|
+
if (!media) return null
|
|
8176
|
+
return {
|
|
8177
|
+
...media,
|
|
8178
|
+
createdAtFormatted: formatActionDate(media.createdAt),
|
|
8179
|
+
updatedAtFormatted: formatActionDate(media.updatedAt)
|
|
8180
|
+
}
|
|
8181
|
+
})()
|
|
8182
|
+
: null`
|
|
8137
8183
|
).join("\n");
|
|
8138
8184
|
const assignArray = arrayFields.map(
|
|
8139
|
-
(name) => ` row.${name}Media = Array.isArray(row.${name})
|
|
8185
|
+
(name) => ` row.${name}Media = Array.isArray(row.${name})
|
|
8186
|
+
? row.${name}
|
|
8187
|
+
.map((id: string) => {
|
|
8188
|
+
const media = mediaMap.get(id)
|
|
8189
|
+
if (!media) return null
|
|
8190
|
+
return {
|
|
8191
|
+
...media,
|
|
8192
|
+
createdAtFormatted: formatActionDate(media.createdAt),
|
|
8193
|
+
updatedAtFormatted: formatActionDate(media.updatedAt)
|
|
8194
|
+
}
|
|
8195
|
+
})
|
|
8196
|
+
.filter(Boolean) as AdminMedia[]
|
|
8197
|
+
: []`
|
|
8140
8198
|
).join("\n");
|
|
8141
8199
|
return `export async function resolve${ctx.Singular}MediaFields(rows: ${ctx.Singular}[]): Promise<${ctx.Singular}[]> {
|
|
8142
8200
|
if (rows.length === 0) return rows
|
|
@@ -8176,7 +8234,7 @@ function genGetPluralContent(ctx) {
|
|
|
8176
8234
|
if (ctx.hasRelationships) drizzle.push("eq");
|
|
8177
8235
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8178
8236
|
const typeImports = [`${ctx.Plural}Page`, `${ctx.Plural}Query`, `${ctx.Singular}`];
|
|
8179
|
-
const helperImports = [];
|
|
8237
|
+
const helperImports = ["formatActionDate"];
|
|
8180
8238
|
if (ctx.hasListRels) helperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8181
8239
|
if (ctx.hasMediaFields) helperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8182
8240
|
const populateImport = helperImports.length > 0 ? `
|
|
@@ -8266,7 +8324,7 @@ function genGetByIdContent(ctx) {
|
|
|
8266
8324
|
const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
|
|
8267
8325
|
const drizzle = ["eq"];
|
|
8268
8326
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8269
|
-
const byIdHelperImports = [];
|
|
8327
|
+
const byIdHelperImports = ["formatActionDate"];
|
|
8270
8328
|
if (ctx.hasListRels) byIdHelperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8271
8329
|
if (ctx.hasMediaFields) byIdHelperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8272
8330
|
const populateImport = byIdHelperImports.length > 0 ? `
|
|
@@ -8304,7 +8362,7 @@ function genGetBySlugContent(ctx) {
|
|
|
8304
8362
|
const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
|
|
8305
8363
|
const drizzle = ["eq"];
|
|
8306
8364
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8307
|
-
const bySlugHelperImports = [];
|
|
8365
|
+
const bySlugHelperImports = ["formatActionDate"];
|
|
8308
8366
|
if (ctx.hasListRels) bySlugHelperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8309
8367
|
if (ctx.hasMediaFields) bySlugHelperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8310
8368
|
const populateImport = bySlugHelperImports.length > 0 ? `
|
|
@@ -9788,13 +9846,16 @@ function buildEntityContext(schema, nextMajorVersion) {
|
|
|
9788
9846
|
const mediaTypeImport = hasMediaFields ? `
|
|
9789
9847
|
import type { AdminMedia } from '@admin/types'
|
|
9790
9848
|
` : "";
|
|
9849
|
+
const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
|
|
9850
|
+
const hasFormattedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted");
|
|
9851
|
+
const timestampFields = hasTimestampFields && !hasFormattedTimestampFields ? "\n createdAtFormatted: string\n updatedAtFormatted: string" : "";
|
|
9791
9852
|
const dataInterface = `${mediaTypeImport}${buildAuthorshipUserType()}
|
|
9792
9853
|
|
|
9793
9854
|
export interface ${Singular} {
|
|
9794
9855
|
${dataFields}${htmlFieldTypes ? `
|
|
9795
9856
|
${htmlFieldTypes}` : ""}${m2mFieldTypes ? `
|
|
9796
9857
|
${m2mFieldTypes}` : ""}${mediaCompanionTypes ? `
|
|
9797
|
-
${mediaCompanionTypes}` : ""}
|
|
9858
|
+
${mediaCompanionTypes}` : ""}${timestampFields}
|
|
9798
9859
|
${buildAuthorshipDataFields()}
|
|
9799
9860
|
}`;
|
|
9800
9861
|
const responseInterface = `export interface ${Plural}Page {
|
|
@@ -10071,6 +10132,9 @@ function generateSingleActions(schema, actionsDir, options = {}) {
|
|
|
10071
10132
|
(f) => ` ${quotePropertyName(f.name)}: ${getFieldType(f, "output")}${f.required || f.primaryKey ? "" : " | null"}`
|
|
10072
10133
|
).join("\n");
|
|
10073
10134
|
const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join("\n");
|
|
10135
|
+
const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
|
|
10136
|
+
const hasFormattedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted");
|
|
10137
|
+
const timestampFields = hasTimestampFields && !hasFormattedTimestampFields ? "\n createdAtFormatted: string\n updatedAtFormatted: string" : "";
|
|
10074
10138
|
const upsertInterfaceFields = upsertFields.map((f) => ` ${quotePropertyName(f.name)}?: ${getFieldType(f, "input")}`).join("\n");
|
|
10075
10139
|
const fieldMeta = upsertFields.map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`).join(",\n ");
|
|
10076
10140
|
const cacheTag = `${schema.name}:all`;
|
|
@@ -10096,7 +10160,7 @@ function generateSingleActions(schema, actionsDir, options = {}) {
|
|
|
10096
10160
|
buildAuthorshipUserType(),
|
|
10097
10161
|
`export interface ${Singular} {
|
|
10098
10162
|
${dataFields}${htmlFieldTypes ? `
|
|
10099
|
-
${htmlFieldTypes}` : ""}
|
|
10163
|
+
${htmlFieldTypes}` : ""}${timestampFields}
|
|
10100
10164
|
${buildAuthorshipDataFields()}
|
|
10101
10165
|
}`,
|
|
10102
10166
|
`export interface ${Singular}UpsertInput {
|
|
@@ -10138,6 +10202,19 @@ ${buildAuthorshipAliasBlock()}
|
|
|
10138
10202
|
|
|
10139
10203
|
const SINGLETON_ID = '${singletonId}'
|
|
10140
10204
|
|
|
10205
|
+
function formatActionDate(value: unknown): string {
|
|
10206
|
+
if (typeof value !== 'string') return ''
|
|
10207
|
+
const date = new Date(value)
|
|
10208
|
+
if (Number.isNaN(date.getTime())) return ''
|
|
10209
|
+
|
|
10210
|
+
return date.toLocaleDateString('en-US', {
|
|
10211
|
+
month: 'short',
|
|
10212
|
+
day: '2-digit',
|
|
10213
|
+
year: 'numeric',
|
|
10214
|
+
timeZone: 'UTC'
|
|
10215
|
+
})
|
|
10216
|
+
}
|
|
10217
|
+
|
|
10141
10218
|
export async function get${Singular}(): Promise<${Singular} | null> {
|
|
10142
10219
|
'use cache'${cacheLifeLine}
|
|
10143
10220
|
cacheTag(${cacheTagsVar}.all)
|