betterstart-cli 0.0.98 → 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-AIQWGMU7.js → chunk-45Z6XDG5.js} +419 -83
  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-F2VFSDKV.js → template-reader-J6G7N5V6.js} +2 -2
  64. package/package.json +1 -1
  65. package/dist/chunk-AIQWGMU7.js.map +0 -1
  66. /package/dist/{template-reader-F2VFSDKV.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();
@@ -401,10 +703,7 @@ function applyAdminNamespaceToContent(content, namespaceValue) {
401
703
  ).replaceAll("UserData", "User").replaceAll("UsersResponse", "UsersPage").replaceAll("SettingData", "Setting").replaceAll("UpsertSettingInput", "SettingUpsertInput").replaceAll("UpsertSettingResult", "SettingUpsertResult").replace(/\bAdminThemeProvider\b/g, `${namespace.pascal}ThemeProvider`).replace(/\bAdminThemeContext\b/g, `${namespace.pascal}ThemeContext`).replace(
402
704
  /import\s+\{\s*admin\s*\}\s+from\s+(['"])@admin\/utils\/app\/admin\1/g,
403
705
  (_match, quote) => `import { ${namespace.camel} } from ${quote}${namespace.alias}/utils/app/${namespace.camel}${quote}`
404
- ).replace(/\badmin(?=\.name\b)/g, namespace.camel).replaceAll("@admin/auth/middleware", `${namespace.alias}/auth/session`).replaceAll("@admin/auth/auth", `${namespace.alias}/auth/server`).replaceAll("@admin/auth/client", `${namespace.alias}/auth/client`).replace(/@admin\/auth(?=['"`\s)]|$)/g, `${namespace.alias}/auth/server`).replaceAll(
405
- "import { auth, type User } from './auth'",
406
- "import { auth, type User } from './server'"
407
- ).replace(/@admin(?=\/|$)/g, namespace.alias).replace(/\/api\/admin(?=\/|['"`]|$)/g, namespace.apiPath).replace(/(^|\/)admin(?=\/|['"`]|$)/g, `$1${namespace.segment}`).replaceAll("(admin)", namespace.routeGroup);
706
+ ).replace(/\badmin(?=\.name\b)/g, namespace.camel).replaceAll("@admin/auth/middleware", `${namespace.alias}/auth/session`).replaceAll("@admin/auth/auth", `${namespace.alias}/auth/server`).replaceAll("@admin/auth/client", `${namespace.alias}/auth/client`).replace(/@admin\/auth(?=['"`\s)]|$)/g, `${namespace.alias}/auth/server`).replace(/(\bimport\b[^\n]*\bfrom\s+)'\.\/auth'/g, "$1'./server'").replace(/@admin(?=\/|$)/g, namespace.alias).replace(/\/api\/admin(?=\/|['"`]|$)/g, namespace.apiPath).replace(/(^|\/)admin(?=\/|['"`]|$)/g, `$1${namespace.segment}`).replaceAll("(admin)", namespace.routeGroup);
408
707
  const protectedNamespace = protectExistingNamespaceLiterals(canonicalContent, namespace);
409
708
  const namespacedContent = replaceAdminCamelToken(
410
709
  replaceAdminPascalToken(
@@ -421,8 +720,8 @@ function applyAdminNamespaceToContent(content, namespaceValue) {
421
720
 
422
721
  // adapters/next/template-reader.ts
423
722
  function readTemplate(relativePath) {
424
- return fs2.readFileSync(
425
- path2.join(resolveCliAssetPath("adapters", "next", "templates", "init"), relativePath),
723
+ return fs3.readFileSync(
724
+ path3.join(resolveCliAssetPath("adapters", "next", "templates", "init"), relativePath),
426
725
  "utf-8"
427
726
  );
428
727
  }
@@ -446,15 +745,57 @@ function namespacedTemplatePath(relativePath, namespace) {
446
745
  }
447
746
 
448
747
  export {
748
+ BETTERSTART_DIR,
749
+ CONFIG_FILE_NAME,
750
+ LOCKFILE_MAP,
751
+ stripAnsi,
449
752
  toPascalCase,
450
753
  toCamelCase,
451
754
  singularize,
452
755
  pluralize,
453
756
  toKebabCase,
454
757
  quotePropertyName,
758
+ humanizeName,
455
759
  singularizeLabel,
456
- singleQuote,
760
+ quoteLiteral,
457
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,
458
799
  DEFAULT_ADMIN_NAMESPACE,
459
800
  ADMIN_THEME_BLOCK,
460
801
  ADMIN_SHADOW_INPUT_UTILITY,
@@ -468,7 +809,6 @@ export {
468
809
  TIPTAP_CONTENT_EDITOR_DIRECTORIES,
469
810
  RAILWAY_BUCKET_ENV_KEYS,
470
811
  R2_ENV_KEYS,
471
- ANSI_ESCAPE_PATTERN,
472
812
  REMOVABLE_NAMESPACE_PATTERN,
473
813
  SCHEMA_NAME_PATTERN,
474
814
  DEV_PORT_FLAG_PATTERN,
@@ -485,13 +825,9 @@ export {
485
825
  deriveMigrationsDir,
486
826
  applyAdminNamespaceToPath,
487
827
  applyAdminNamespaceToContent,
488
- CLI_PACKAGE_NAME,
489
- REDACTED,
490
- getCurrentCliVersion,
491
- resolveCliAssetPath,
492
828
  readTemplate,
493
829
  applyNextCacheApiForVersion,
494
830
  readNamespacedTemplate,
495
831
  namespacedTemplatePath
496
832
  };
497
- //# sourceMappingURL=chunk-AIQWGMU7.js.map
833
+ //# sourceMappingURL=chunk-45Z6XDG5.js.map