betterstart-cli 0.0.99 → 0.0.100

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 (66) hide show
  1. package/dist/assets/adapters/next/templates/init/api/upload-route.ts +2 -1
  2. package/dist/assets/adapters/next/templates/init/components/layouts/admin-settings-sidebar.tsx +2 -2
  3. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sign-out.tsx +27 -8
  4. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table.tsx +3 -1
  5. package/dist/assets/adapters/next/templates/init/components/shared/delete-dialog.tsx +3 -2
  6. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-version-restore-dialog.tsx +4 -3
  7. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-button.tsx +5 -2
  8. package/dist/assets/adapters/next/templates/init/components/shared/media/edit-media-dialog-content.tsx +11 -5
  9. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-dialog.tsx +6 -4
  10. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-drawer.tsx +12 -8
  11. package/dist/assets/adapters/next/templates/init/components/shared/media/media-empty-state.tsx +6 -5
  12. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-pagination.tsx +1 -1
  13. package/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx +5 -3
  14. package/dist/assets/adapters/next/templates/init/components/shared/search-input.tsx +2 -0
  15. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-dialog.tsx +12 -7
  16. package/dist/assets/adapters/next/templates/init/hooks/use-entity-versions.ts +2 -1
  17. package/dist/assets/adapters/next/templates/init/lib/actions/audit/cleanup-audit-logs.ts +2 -1
  18. package/dist/assets/adapters/next/templates/init/lib/actions/forms/upsert-form-settings.ts +2 -1
  19. package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +2 -1
  20. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media-bulk.ts +2 -1
  21. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media.ts +2 -1
  22. package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +2 -1
  23. package/dist/assets/adapters/next/templates/init/lib/actions/profile/change-own-password.ts +2 -1
  24. package/dist/assets/adapters/next/templates/init/lib/actions/profile/update-email.ts +2 -1
  25. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-media-from-url.ts +2 -2
  26. package/dist/assets/adapters/next/templates/init/lib/actions/users/change-user-password.ts +2 -1
  27. package/dist/assets/adapters/next/templates/init/lib/actions/users/create-user.ts +2 -1
  28. package/dist/assets/adapters/next/templates/init/lib/actions/users/delete-user.ts +2 -1
  29. package/dist/assets/adapters/next/templates/init/lib/actions/users/update-user-role.ts +2 -1
  30. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/create-webhook.ts +2 -1
  31. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/delete-webhook.ts +2 -1
  32. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhook-secret.ts +2 -1
  33. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/regenerate-webhook-secret.ts +2 -1
  34. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/send-test-webhook.ts +2 -1
  35. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/update-webhook.ts +2 -1
  36. package/dist/assets/adapters/next/templates/init/pages/forgot-password-form.tsx +7 -7
  37. package/dist/assets/adapters/next/templates/init/pages/login-form.tsx +7 -7
  38. package/dist/assets/adapters/next/templates/init/pages/login-page.tsx +1 -1
  39. package/dist/assets/adapters/next/templates/init/pages/media/media-page-content.tsx +5 -4
  40. package/dist/assets/adapters/next/templates/init/pages/profile/profile-form.tsx +13 -10
  41. package/dist/assets/adapters/next/templates/init/pages/reset-password-form.tsx +5 -5
  42. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-table.tsx +3 -1
  43. package/dist/assets/adapters/next/templates/init/pages/settings/forms/form-notifications-drawer.tsx +10 -5
  44. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/delete-webhook-dialog.tsx +19 -10
  45. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-actions.tsx +9 -4
  46. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-endpoint-dialog.tsx +26 -20
  47. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-page-content.tsx +4 -4
  48. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-table.tsx +3 -1
  49. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-table.tsx +3 -1
  50. package/dist/assets/adapters/next/templates/init/pages/users/change-password-dialog.tsx +6 -5
  51. package/dist/assets/adapters/next/templates/init/pages/users/create-user-dialog.tsx +5 -5
  52. package/dist/assets/adapters/next/templates/init/pages/users/delete-user-dialog.tsx +6 -4
  53. package/dist/assets/adapters/next/templates/init/pages/users/edit-role-dialog.tsx +9 -5
  54. package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +1 -1
  55. package/dist/assets/adapters/next/templates/init/utils/error/action-error.ts +35 -0
  56. package/dist/assets/shared-assets/react-admin/schema.json +8 -0
  57. package/dist/assets/shared-assets/react-admin/ui/sonner.tsx +3 -8
  58. package/dist/assets/shared-assets/react-admin/ui/spinner.tsx +1 -1
  59. package/dist/{chunk-SO2CAJFC.js → chunk-45Z6XDG5.js} +418 -79
  60. package/dist/chunk-45Z6XDG5.js.map +1 -0
  61. package/dist/cli.js +2027 -2391
  62. package/dist/cli.js.map +1 -1
  63. package/dist/{template-reader-XMWPFYIK.js → template-reader-J6G7N5V6.js} +2 -2
  64. package/package.json +1 -1
  65. package/dist/chunk-SO2CAJFC.js.map +0 -1
  66. /package/dist/{template-reader-XMWPFYIK.js.map → template-reader-J6G7N5V6.js.map} +0 -0
@@ -1,58 +1,407 @@
1
1
  // adapters/next/template-reader.ts
2
+ import fs3 from "fs";
3
+ import path3 from "path";
4
+
5
+ // utils/paths.ts
2
6
  import fs2 from "fs";
3
7
  import path2 from "path";
4
-
5
- // core-engine/utils/cli-root.ts
6
- import fs from "fs";
7
- import path from "path";
8
8
  import { fileURLToPath } from "url";
9
9
 
10
10
  // constants/cli.ts
11
11
  var CLI_PACKAGE_NAME = "betterstart-cli";
12
12
  var REDACTED = "[redacted]";
13
13
 
14
- // core-engine/utils/cli-root.ts
15
- function findCliPackage() {
16
- let dir = path.dirname(fileURLToPath(import.meta.url));
14
+ // constants/paths.ts
15
+ var BETTERSTART_DIR = ".betterstart";
16
+ var CONFIG_FILE_NAME = "betterstart.config.ts";
17
+ var DEVELOPMENT_ENV_FILES = [
18
+ ".env.development.local",
19
+ ".env.local",
20
+ ".env.development",
21
+ ".env"
22
+ ];
23
+ var LOCKFILE_MAP = {
24
+ "pnpm-lock.yaml": "pnpm",
25
+ "package-lock.json": "npm",
26
+ "yarn.lock": "yarn",
27
+ "bun.lockb": "bun",
28
+ "bun.lock": "bun"
29
+ };
30
+
31
+ // utils/files.ts
32
+ import crypto from "crypto";
33
+ import fs from "fs";
34
+ import path from "path";
35
+ import { parseEnv } from "util";
36
+
37
+ // utils/text.ts
38
+ import { stripVTControlCharacters } from "util";
39
+ function stripAnsi(text, options = {}) {
40
+ const stripped = stripVTControlCharacters(text);
41
+ return options.stripCarriageReturns ? stripped.replaceAll("\r", "") : stripped;
42
+ }
43
+ function toPascalCase(str) {
44
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
45
+ }
46
+ function toCamelCase(str) {
47
+ const p = toPascalCase(str);
48
+ return p.charAt(0).toLowerCase() + p.slice(1);
49
+ }
50
+ function singularize(str) {
51
+ if (str.endsWith("ies")) return `${str.slice(0, -3)}y`;
52
+ if (str.endsWith("ves")) return `${str.slice(0, -3)}f`;
53
+ if (str.endsWith("sses") || str.endsWith("xes") || str.endsWith("ches") || str.endsWith("shes") || str.endsWith("zes"))
54
+ return str.slice(0, -2);
55
+ if (str.endsWith("s") && !str.endsWith("ss")) return str.slice(0, -1);
56
+ return str;
57
+ }
58
+ function pluralize(str) {
59
+ if (str.endsWith("s") && !str.endsWith("ss")) return str;
60
+ if (str.endsWith("y") && !["ay", "ey", "iy", "oy", "uy"].some((v) => str.endsWith(v)))
61
+ return `${str.slice(0, -1)}ies`;
62
+ if (str.endsWith("s") || str.endsWith("x") || str.endsWith("ch") || str.endsWith("sh"))
63
+ return `${str}es`;
64
+ return `${str}s`;
65
+ }
66
+ function toKebabCase(str) {
67
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
68
+ }
69
+ function toScreamingSnake(str) {
70
+ return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[\s-]+/g, "_").toUpperCase();
71
+ }
72
+ function quotePropertyName(name) {
73
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`;
74
+ }
75
+ function humanizeName(name) {
76
+ return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim().split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
77
+ }
78
+ function singularizeLabel(label) {
79
+ const words = label.split(" ");
80
+ const lastWord = words[words.length - 1];
81
+ words[words.length - 1] = singularize(lastWord.toLowerCase());
82
+ words[words.length - 1] = words[words.length - 1].charAt(0).toUpperCase() + words[words.length - 1].slice(1);
83
+ return words.join(" ");
84
+ }
85
+ function quoteLiteral(value, quote = "'") {
86
+ const escaped = value.replace(/\\/g, "\\\\").replace(new RegExp(escapeRegExp(quote), "g"), `\\${quote}`).replace(/\r/g, "\\r").replace(/\n/g, "\\n");
87
+ return `${quote}${escaped}${quote}`;
88
+ }
89
+ function escapeTemplateText(value) {
90
+ return value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
91
+ }
92
+ function normalizeLineEndings(content) {
93
+ return content.replace(/\r\n/g, "\n");
94
+ }
95
+ function escapeRegExp(value) {
96
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
97
+ }
98
+ function hasConflictMarkers(content) {
99
+ return /^(<{7}|={7}|>{7})( |$)/m.test(content);
100
+ }
101
+ function splitLines(content) {
102
+ return normalizeLineEndings(content).split("\n");
103
+ }
104
+ function normalizeWhitespace(value) {
105
+ return value.trim().replace(/\s+/g, " ");
106
+ }
107
+ function escapeJsx(str) {
108
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
109
+ }
110
+ function escapeAttribute(str) {
111
+ return escapeJsx(str).replace(/"/g, "&quot;");
112
+ }
113
+ function findNextNonEmptyLine(lines, startIndex) {
114
+ for (let i = startIndex; i < lines.length; i++) {
115
+ const trimmed = lines[i].trim();
116
+ if (trimmed !== "") return trimmed;
117
+ }
118
+ return null;
119
+ }
120
+ function levenshtein(a, b) {
121
+ const matrix = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
122
+ for (let i = 0; i <= a.length; i++) matrix[i][0] = i;
123
+ for (let j = 0; j <= b.length; j++) matrix[0][j] = j;
124
+ for (let i = 1; i <= a.length; i++) {
125
+ for (let j = 1; j <= b.length; j++) {
126
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
127
+ matrix[i][j] = Math.min(
128
+ matrix[i - 1][j] + 1,
129
+ matrix[i][j - 1] + 1,
130
+ matrix[i - 1][j - 1] + cost
131
+ );
132
+ }
133
+ }
134
+ return matrix[a.length][b.length];
135
+ }
136
+ function toTitleCase(value) {
137
+ return normalizeWhitespace(value).split(" ").map((word) => word ? `${word.charAt(0).toUpperCase()}${word.slice(1).toLowerCase()}` : word).join(" ");
138
+ }
139
+ function slugify(value) {
140
+ return value.trim().toLowerCase().replace(/['"]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-+/g, "-");
141
+ }
142
+
143
+ // utils/files.ts
144
+ import fse from "fs-extra";
145
+ function findUpwards(startDir, visit) {
146
+ let dir = path.resolve(startDir);
17
147
  for (; ; ) {
18
- const pkgPath = path.join(dir, "package.json");
19
- if (fs.existsSync(pkgPath)) {
20
- try {
21
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
22
- if (pkg.name === CLI_PACKAGE_NAME) {
23
- return { dir, pkg };
148
+ const found = visit(dir);
149
+ if (found !== void 0) return found;
150
+ const parent = path.dirname(dir);
151
+ if (parent === dir) return void 0;
152
+ dir = parent;
153
+ }
154
+ }
155
+ function hashContent(content) {
156
+ return `sha256-${crypto.createHash("sha256").update(normalizeLineEndings(content)).digest("hex")}`;
157
+ }
158
+ function ensureDir(dirPath) {
159
+ fse.ensureDirSync(dirPath);
160
+ }
161
+ function safeWriteFile(filePath, content, force = false) {
162
+ if (!force && fs.existsSync(filePath)) {
163
+ return false;
164
+ }
165
+ ensureDir(path.dirname(filePath));
166
+ fs.writeFileSync(filePath, content, "utf-8");
167
+ return true;
168
+ }
169
+ function createGeneratedFile(filePath, content) {
170
+ return {
171
+ path: filePath.split(path.sep).join("/"),
172
+ content
173
+ };
174
+ }
175
+ function stripJsonComments(input) {
176
+ let result = "";
177
+ let i = 0;
178
+ while (i < input.length) {
179
+ if (input[i] === '"') {
180
+ let j = i + 1;
181
+ while (j < input.length) {
182
+ if (input[j] === "\\") {
183
+ j += 2;
184
+ continue;
185
+ }
186
+ if (input[j] === '"') {
187
+ j++;
188
+ break;
189
+ }
190
+ j++;
191
+ }
192
+ result += input.slice(i, j);
193
+ i = j;
194
+ } else if (input[i] === "/" && input[i + 1] === "/") {
195
+ const nl = input.indexOf("\n", i);
196
+ i = nl === -1 ? input.length : nl;
197
+ } else if (input[i] === "/" && input[i + 1] === "*") {
198
+ const end = input.indexOf("*/", i + 2);
199
+ i = end === -1 ? input.length : end + 2;
200
+ } else {
201
+ result += input[i];
202
+ i++;
203
+ }
204
+ }
205
+ return result;
206
+ }
207
+ function toStrictJson(input) {
208
+ return stripJsonComments(input).replace(/,\s*([\]}])/g, "$1");
209
+ }
210
+ function parseDotenvFile(filePath) {
211
+ if (!fs.existsSync(filePath)) return /* @__PURE__ */ new Map();
212
+ try {
213
+ const parsed = Object.entries(parseEnv(fs.readFileSync(filePath, "utf-8")));
214
+ return new Map(
215
+ parsed.filter((entry) => typeof entry[1] === "string")
216
+ );
217
+ } catch {
218
+ return /* @__PURE__ */ new Map();
219
+ }
220
+ }
221
+ function readEnvVar(cwd, key) {
222
+ return parseDotenvFile(path.join(cwd, ".env.local")).get(key);
223
+ }
224
+ function resolveProjectEnvVar(cwd, key) {
225
+ for (const envFile of DEVELOPMENT_ENV_FILES) {
226
+ const value = parseDotenvFile(path.join(cwd, envFile)).get(key)?.trim();
227
+ if (value) return { source: envFile, value };
228
+ }
229
+ return void 0;
230
+ }
231
+ function readProjectEnvVar(cwd, key) {
232
+ return resolveProjectEnvVar(cwd, key)?.value;
233
+ }
234
+ function appendEnvVars(cwd, sections, overwrite) {
235
+ const envPath = path.join(cwd, ".env.local");
236
+ let existing = fs.existsSync(envPath) ? fs.readFileSync(envPath, "utf-8") : "";
237
+ const existingKeys = new Set(
238
+ existing.split("\n").filter((line) => line.trim() && !line.trim().startsWith("#")).map((line) => line.split("=")[0]?.trim()).filter(Boolean)
239
+ );
240
+ const added = [];
241
+ const skipped = [];
242
+ const updated = [];
243
+ const lines = [];
244
+ if (overwrite) {
245
+ for (const section of sections) {
246
+ for (const v of section.vars) {
247
+ if (overwrite.has(v.key) && existingKeys.has(v.key)) {
248
+ const pattern = new RegExp(`^${v.key}=.*$`, "m");
249
+ const replacement = v.comment ? `${v.key}="${v.value}" # ${v.comment}` : `${v.key}="${v.value}"`;
250
+ existing = existing.replace(pattern, replacement);
251
+ updated.push(v.key);
24
252
  }
25
- } catch {
26
253
  }
27
254
  }
28
- const parentDir = path.dirname(dir);
29
- if (parentDir === dir) {
30
- return null;
255
+ }
256
+ if (existing.trim()) {
257
+ lines.push("");
258
+ }
259
+ for (const section of sections) {
260
+ const sectionVars = section.vars.filter((v) => {
261
+ if (existingKeys.has(v.key)) {
262
+ if (!updated.includes(v.key)) skipped.push(v.key);
263
+ return false;
264
+ }
265
+ added.push(v.key);
266
+ return true;
267
+ });
268
+ if (sectionVars.length === 0) continue;
269
+ lines.push(`# ${section.header}`);
270
+ for (const v of sectionVars) {
271
+ const line = v.comment ? `${v.key}="${v.value}" # ${v.comment}` : `${v.key}="${v.value}"`;
272
+ lines.push(line);
31
273
  }
32
- dir = parentDir;
274
+ lines.push("");
275
+ }
276
+ if (added.length > 0 || updated.length > 0) {
277
+ const header = existing.trim() ? "" : "# ============================================\n# BetterStart Admin\n# ============================================\n";
278
+ const content = existing.trim() ? `${existing.trimEnd()}
279
+ ${lines.join("\n")}` : header + lines.join("\n");
280
+ fs.writeFileSync(envPath, content);
33
281
  }
282
+ return { added, skipped, updated };
283
+ }
284
+ function removeEnvVars(cwd, keys) {
285
+ const envPath = path.join(cwd, ".env.local");
286
+ if (!fs.existsSync(envPath) || keys.length === 0) {
287
+ return [];
288
+ }
289
+ const keySet = new Set(keys);
290
+ const removed = [];
291
+ const filteredLines = fs.readFileSync(envPath, "utf-8").split("\n").filter((line) => {
292
+ const trimmed = line.trim();
293
+ if (!trimmed || trimmed.startsWith("#") || !trimmed.includes("=")) {
294
+ return true;
295
+ }
296
+ const [key] = trimmed.split("=");
297
+ const normalizedKey = key?.trim();
298
+ if (normalizedKey && keySet.has(normalizedKey)) {
299
+ removed.push(normalizedKey);
300
+ return false;
301
+ }
302
+ return true;
303
+ });
304
+ fs.writeFileSync(envPath, `${filteredLines.join("\n").trimEnd()}
305
+ `, "utf-8");
306
+ return removed;
307
+ }
308
+ function captureFile(filePath) {
309
+ if (!fs.existsSync(filePath)) {
310
+ return { existed: false };
311
+ }
312
+ return { existed: true, content: fs.readFileSync(filePath, "utf-8") };
313
+ }
314
+ function restoreFile(filePath, snapshot) {
315
+ if (snapshot.existed) {
316
+ fs.writeFileSync(filePath, snapshot.content ?? "", "utf-8");
317
+ return;
318
+ }
319
+ if (fs.existsSync(filePath)) {
320
+ fs.rmSync(filePath, { force: true });
321
+ }
322
+ }
323
+
324
+ // utils/paths.ts
325
+ function betterstartDir(cwd, ...segments) {
326
+ return path2.join(cwd, BETTERSTART_DIR, ...segments);
327
+ }
328
+ function toPosixPath(value) {
329
+ return value.replace(/\\/g, "/");
330
+ }
331
+ function trimDotSlash(value) {
332
+ return value.replace(/^[.][/\\]/, "");
333
+ }
334
+ function normalizePosixDir(value) {
335
+ return trimDotSlash(toPosixPath(value)).replace(/\/+$/, "");
336
+ }
337
+ function toProjectAbsolutePath(cwd, filePath) {
338
+ return path2.isAbsolute(filePath) ? filePath : path2.join(cwd, ...filePath.split("/"));
339
+ }
340
+ function readLocalProjectFile(cwd, filePath) {
341
+ const fullPath = toProjectAbsolutePath(cwd, filePath);
342
+ return fs2.existsSync(fullPath) ? fs2.readFileSync(fullPath, "utf-8") : null;
343
+ }
344
+ function isInsideDir(child, parent) {
345
+ const relative = path2.relative(parent, child);
346
+ return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
347
+ }
348
+ function removePath(cwd, filePath) {
349
+ const fullPath = toProjectAbsolutePath(cwd, filePath);
350
+ const existed = fs2.existsSync(fullPath);
351
+ fs2.rmSync(fullPath, { recursive: true, force: true });
352
+ return existed;
353
+ }
354
+ function cleanupEmptyDirs(cwd, deletedPaths, stopRoots) {
355
+ const projectRoot = path2.resolve(cwd);
356
+ const stops = /* @__PURE__ */ new Set([projectRoot, ...stopRoots]);
357
+ for (const deletedPath of deletedPaths) {
358
+ let currentDir = path2.dirname(toProjectAbsolutePath(cwd, deletedPath));
359
+ while (isInsideDir(currentDir, projectRoot) && !stops.has(currentDir)) {
360
+ if (!fs2.existsSync(currentDir)) {
361
+ currentDir = path2.dirname(currentDir);
362
+ continue;
363
+ }
364
+ if (fs2.readdirSync(currentDir).length > 0) {
365
+ break;
366
+ }
367
+ fs2.rmdirSync(currentDir);
368
+ currentDir = path2.dirname(currentDir);
369
+ }
370
+ }
371
+ }
372
+ function findCliPackage() {
373
+ const start = path2.dirname(fileURLToPath(import.meta.url));
374
+ return findUpwards(start, (dir) => {
375
+ const pkgPath = path2.join(dir, "package.json");
376
+ if (!fs2.existsSync(pkgPath)) return void 0;
377
+ try {
378
+ const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
379
+ return pkg.name === CLI_PACKAGE_NAME ? { dir, pkg } : void 0;
380
+ } catch {
381
+ return void 0;
382
+ }
383
+ }) ?? null;
34
384
  }
35
385
  function findCliRoot() {
36
386
  const found = findCliPackage();
37
387
  if (found) {
38
388
  return found.dir;
39
389
  }
40
- return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
390
+ return path2.resolve(path2.dirname(fileURLToPath(import.meta.url)), "..", "..");
41
391
  }
42
392
  function getCurrentCliVersion() {
43
393
  return findCliPackage()?.pkg.version ?? "0.0.0";
44
394
  }
45
395
  function resolveCliAssetPath(...segments) {
46
396
  const root = findCliRoot();
47
- const builtPath = path.join(root, "dist", "assets", ...segments);
48
- if (fs.existsSync(builtPath)) {
397
+ const builtPath = path2.join(root, "dist", "assets", ...segments);
398
+ if (fs2.existsSync(builtPath)) {
49
399
  return builtPath;
50
400
  }
51
- return path.join(root, ...segments);
401
+ return path2.join(root, ...segments);
52
402
  }
53
403
 
54
404
  // constants/patterns.ts
55
- var ANSI_ESCAPE_PATTERN = /\u001B\[[0-?]*[ -/]*[@-~]/g;
56
405
  var REMOVABLE_NAMESPACE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
57
406
  var SCHEMA_NAME_PATTERN = /^[a-z][a-zA-Z0-9-]*$/;
58
407
  var NAMESPACE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
@@ -157,53 +506,6 @@ var R2_ENV_KEYS = [
157
506
  "BETTERSTART_R2_PUBLIC_URL"
158
507
  ];
159
508
 
160
- // core-engine/utils/string.ts
161
- function toPascalCase(str) {
162
- return str.replace(/([a-z])([A-Z])/g, "$1-$2").split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
163
- }
164
- function toCamelCase(str) {
165
- const p = toPascalCase(str);
166
- return p.charAt(0).toLowerCase() + p.slice(1);
167
- }
168
- function singularize(str) {
169
- if (str.endsWith("ies")) return `${str.slice(0, -3)}y`;
170
- if (str.endsWith("ves")) return `${str.slice(0, -3)}f`;
171
- if (str.endsWith("sses") || str.endsWith("xes") || str.endsWith("ches") || str.endsWith("shes") || str.endsWith("zes"))
172
- return str.slice(0, -2);
173
- if (str.endsWith("s") && !str.endsWith("ss")) return str.slice(0, -1);
174
- return str;
175
- }
176
- function pluralize(str) {
177
- if (str.endsWith("s") && !str.endsWith("ss")) return str;
178
- if (str.endsWith("y") && !["ay", "ey", "iy", "oy", "uy"].some((v) => str.endsWith(v)))
179
- return `${str.slice(0, -1)}ies`;
180
- if (str.endsWith("s") || str.endsWith("x") || str.endsWith("ch") || str.endsWith("sh"))
181
- return `${str}es`;
182
- return `${str}s`;
183
- }
184
- function toKebabCase(str) {
185
- return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
186
- }
187
- function toScreamingSnake(str) {
188
- return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[\s-]+/g, "_").toUpperCase();
189
- }
190
- function quotePropertyName(name) {
191
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`;
192
- }
193
- function singularizeLabel(label) {
194
- const words = label.split(" ");
195
- const lastWord = words[words.length - 1];
196
- words[words.length - 1] = singularize(lastWord.toLowerCase());
197
- words[words.length - 1] = words[words.length - 1].charAt(0).toUpperCase() + words[words.length - 1].slice(1);
198
- return words.join(" ");
199
- }
200
- function singleQuote(value) {
201
- return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
202
- }
203
- function escapeTemplateText(value) {
204
- return value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
205
- }
206
-
207
509
  // adapters/next/config/namespace.ts
208
510
  function validateAdminNamespace(value) {
209
511
  const segment = value.trim();
@@ -418,8 +720,8 @@ function applyAdminNamespaceToContent(content, namespaceValue) {
418
720
 
419
721
  // adapters/next/template-reader.ts
420
722
  function readTemplate(relativePath) {
421
- return fs2.readFileSync(
422
- path2.join(resolveCliAssetPath("adapters", "next", "templates", "init"), relativePath),
723
+ return fs3.readFileSync(
724
+ path3.join(resolveCliAssetPath("adapters", "next", "templates", "init"), relativePath),
423
725
  "utf-8"
424
726
  );
425
727
  }
@@ -443,15 +745,57 @@ function namespacedTemplatePath(relativePath, namespace) {
443
745
  }
444
746
 
445
747
  export {
748
+ BETTERSTART_DIR,
749
+ CONFIG_FILE_NAME,
750
+ LOCKFILE_MAP,
751
+ stripAnsi,
446
752
  toPascalCase,
447
753
  toCamelCase,
448
754
  singularize,
449
755
  pluralize,
450
756
  toKebabCase,
451
757
  quotePropertyName,
758
+ humanizeName,
452
759
  singularizeLabel,
453
- singleQuote,
760
+ quoteLiteral,
454
761
  escapeTemplateText,
762
+ normalizeLineEndings,
763
+ escapeRegExp,
764
+ hasConflictMarkers,
765
+ splitLines,
766
+ normalizeWhitespace,
767
+ escapeJsx,
768
+ escapeAttribute,
769
+ findNextNonEmptyLine,
770
+ levenshtein,
771
+ toTitleCase,
772
+ slugify,
773
+ findUpwards,
774
+ hashContent,
775
+ ensureDir,
776
+ safeWriteFile,
777
+ createGeneratedFile,
778
+ toStrictJson,
779
+ parseDotenvFile,
780
+ readEnvVar,
781
+ resolveProjectEnvVar,
782
+ readProjectEnvVar,
783
+ appendEnvVars,
784
+ removeEnvVars,
785
+ captureFile,
786
+ restoreFile,
787
+ CLI_PACKAGE_NAME,
788
+ REDACTED,
789
+ betterstartDir,
790
+ toPosixPath,
791
+ trimDotSlash,
792
+ normalizePosixDir,
793
+ toProjectAbsolutePath,
794
+ readLocalProjectFile,
795
+ removePath,
796
+ cleanupEmptyDirs,
797
+ getCurrentCliVersion,
798
+ resolveCliAssetPath,
455
799
  DEFAULT_ADMIN_NAMESPACE,
456
800
  ADMIN_THEME_BLOCK,
457
801
  ADMIN_SHADOW_INPUT_UTILITY,
@@ -465,7 +809,6 @@ export {
465
809
  TIPTAP_CONTENT_EDITOR_DIRECTORIES,
466
810
  RAILWAY_BUCKET_ENV_KEYS,
467
811
  R2_ENV_KEYS,
468
- ANSI_ESCAPE_PATTERN,
469
812
  REMOVABLE_NAMESPACE_PATTERN,
470
813
  SCHEMA_NAME_PATTERN,
471
814
  DEV_PORT_FLAG_PATTERN,
@@ -482,13 +825,9 @@ export {
482
825
  deriveMigrationsDir,
483
826
  applyAdminNamespaceToPath,
484
827
  applyAdminNamespaceToContent,
485
- CLI_PACKAGE_NAME,
486
- REDACTED,
487
- getCurrentCliVersion,
488
- resolveCliAssetPath,
489
828
  readTemplate,
490
829
  applyNextCacheApiForVersion,
491
830
  readNamespacedTemplate,
492
831
  namespacedTemplatePath
493
832
  };
494
- //# sourceMappingURL=chunk-SO2CAJFC.js.map
833
+ //# sourceMappingURL=chunk-45Z6XDG5.js.map