betterstart-cli 0.0.117 → 0.0.119

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/assets/adapters/next/templates/init/admin-globals.css +154 -38
  2. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-grid-row.tsx +33 -1
  3. package/dist/assets/adapters/next/templates/init/components/shared/media/media-gallery-dialog.tsx +3 -3
  4. package/dist/assets/adapters/next/templates/init/components/shared/media/media-preview.tsx +3 -1
  5. package/dist/assets/adapters/next/templates/init/hooks/use-field-error-visible.ts +25 -0
  6. package/dist/assets/adapters/next/templates/init/hooks/use-media.ts +1 -1
  7. package/dist/assets/adapters/next/templates/init/hooks/use-upload.ts +11 -5
  8. package/dist/assets/adapters/next/templates/init/lib/actions/audit/cleanup-audit-logs.ts +1 -0
  9. package/dist/assets/adapters/next/templates/init/lib/actions/audit/query-audit-logs.ts +2 -2
  10. package/dist/assets/adapters/next/templates/init/lib/actions/audit/record-audit-event.ts +1 -2
  11. package/dist/assets/adapters/next/templates/init/lib/actions/auth/client.ts +4 -1
  12. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/get-entity-versions.ts +5 -1
  13. package/dist/assets/adapters/next/templates/init/lib/actions/forms/get-all-form-settings.ts +1 -1
  14. package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +2 -1
  15. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media-bulk.ts +1 -0
  16. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media.ts +1 -0
  17. package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +2 -4
  18. package/dist/assets/adapters/next/templates/init/lib/actions/profile/change-own-password.ts +1 -0
  19. package/dist/assets/adapters/next/templates/init/lib/actions/profile/update-email.ts +1 -0
  20. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-files.ts +1 -0
  21. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-media-from-url.ts +16 -6
  22. package/dist/assets/adapters/next/templates/init/lib/actions/users/change-user-password.ts +1 -0
  23. package/dist/assets/adapters/next/templates/init/lib/actions/users/create-user.ts +2 -1
  24. package/dist/assets/adapters/next/templates/init/lib/actions/users/delete-user.ts +1 -0
  25. package/dist/assets/adapters/next/templates/init/lib/actions/users/types.ts +1 -1
  26. package/dist/assets/adapters/next/templates/init/lib/actions/users/update-user-role.ts +1 -0
  27. package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +12 -4
  28. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/registry.ts +4 -4
  29. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +3 -7
  30. package/dist/assets/adapters/next/templates/init/pages/forgot-password-form.tsx +5 -8
  31. package/dist/assets/adapters/next/templates/init/pages/forgot-password-page-skeleton.tsx +2 -2
  32. package/dist/assets/adapters/next/templates/init/pages/login-form.tsx +7 -9
  33. package/dist/assets/adapters/next/templates/init/pages/login-page-skeleton.tsx +2 -2
  34. package/dist/assets/adapters/next/templates/init/pages/reset-password-form.tsx +8 -16
  35. package/dist/assets/adapters/next/templates/init/pages/reset-password-page-skeleton.tsx +2 -2
  36. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-detail-row.tsx +1 -1
  37. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-table.tsx +1 -6
  38. package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-table.tsx +2 -7
  39. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-table.tsx +1 -6
  40. package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +1 -1
  41. package/dist/assets/adapters/next/templates/init/public/placeholder.png +0 -0
  42. package/dist/assets/adapters/next/templates/init/types/index.ts +2 -0
  43. package/dist/assets/adapters/next/templates/init/utils/audit/normalize-comparable-value.ts +4 -2
  44. package/dist/assets/adapters/next/templates/init/utils/date/format-action-date.ts +12 -0
  45. package/dist/assets/adapters/next/templates/init/utils/dev-mode/dev-mode-json-schemas.ts +66 -0
  46. package/dist/assets/adapters/next/templates/init/utils/dev-mode/parse-dev-mode-lifecycle-hooks.ts +11 -0
  47. package/dist/assets/adapters/next/templates/init/utils/dev-mode/parse-dev-mode-snippets.ts +9 -0
  48. package/dist/assets/adapters/next/templates/init/utils/editor/set-task-item-checked.ts +13 -0
  49. package/dist/assets/adapters/next/templates/init/utils/editor/update-nodes-attr.ts +2 -1
  50. package/dist/assets/adapters/next/templates/init/utils/email/email-theme.ts +13 -0
  51. package/dist/assets/adapters/next/templates/init/utils/email/render-form-submission-rows.ts +3 -2
  52. package/dist/assets/adapters/next/templates/init/utils/email/render-notification-email.ts +7 -6
  53. package/dist/assets/adapters/next/templates/init/utils/email/render-thank-you-email.ts +5 -4
  54. package/dist/assets/adapters/next/templates/init/utils/error/read-string-property.ts +4 -2
  55. package/dist/assets/adapters/next/templates/init/utils/error/recognize.ts +2 -4
  56. package/dist/assets/adapters/next/templates/init/utils/error/to-action-error.ts +0 -1
  57. package/dist/assets/adapters/next/templates/init/utils/form/clone-default-value.ts +4 -2
  58. package/dist/assets/adapters/next/templates/init/utils/shared/is-record.ts +3 -0
  59. package/dist/assets/adapters/next/templates/init/utils/table/default-get-id.ts +3 -2
  60. package/dist/assets/shared-assets/react-admin/custom/content-editor/editor-toolbar.tsx +1 -1
  61. package/dist/assets/shared-assets/react-admin/custom/content-editor/slash-command-menu.tsx +5 -3
  62. package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode.tsx +1 -1
  63. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node.tsx +3 -1
  64. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/task-item-node/task-item-node-extension.tsx +6 -15
  65. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +1 -6
  66. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu.tsx +1 -6
  67. package/dist/assets/shared-assets/react-admin/custom/date-range-picker.tsx +9 -2
  68. package/dist/assets/shared-assets/react-admin/custom/gallery-field.tsx +3 -3
  69. package/dist/assets/shared-assets/react-admin/custom/media-field.tsx +2 -2
  70. package/dist/assets/shared-assets/react-admin/custom/nested-object-list-field.tsx +3 -1
  71. package/dist/assets/shared-assets/react-admin/custom/progressive-blur.tsx +3 -1
  72. package/dist/assets/shared-assets/react-admin/ui/badge.tsx +1 -2
  73. package/dist/assets/shared-assets/react-admin/ui/dropdown-menu.tsx +20 -23
  74. package/dist/assets/shared-assets/react-admin/ui/form.tsx +6 -3
  75. package/dist/assets/shared-assets/react-admin/ui/input.tsx +1 -1
  76. package/dist/assets/shared-assets/react-admin/ui/native-select.tsx +1 -1
  77. package/dist/assets/shared-assets/react-admin/ui/navigation-menu.tsx +1 -1
  78. package/dist/assets/shared-assets/react-admin/ui/select.tsx +1 -1
  79. package/dist/assets/shared-assets/react-admin/ui/textarea.tsx +1 -1
  80. package/dist/{chunk-FGEVDA53.js → chunk-BNHFSHPE.js} +12 -1
  81. package/dist/chunk-BNHFSHPE.js.map +1 -0
  82. package/dist/cli.js +909 -598
  83. package/dist/cli.js.map +1 -1
  84. package/dist/{read-namespaced-template-KUENIIDC.js → read-namespaced-template-WYIGUH7S.js} +2 -2
  85. package/package.json +1 -1
  86. package/dist/chunk-FGEVDA53.js.map +0 -1
  87. /package/dist/{read-namespaced-template-KUENIIDC.js.map → read-namespaced-template-WYIGUH7S.js.map} +0 -0
@@ -1,8 +1,10 @@
1
+ import { isRecord } from '@admin/utils/shared/is-record'
2
+
1
3
  export function cloneDefaultValue(value: unknown): unknown {
2
4
  if (Array.isArray(value)) return value.map(cloneDefaultValue)
3
5
 
4
- if (value && typeof value === 'object') {
5
- const clonedEntries = Object.entries(value as Record<string, unknown>).map(
6
+ if (isRecord(value)) {
7
+ const clonedEntries = Object.entries(value).map(
6
8
  ([key, childValue]) => [key, cloneDefaultValue(childValue)] as const
7
9
  )
8
10
  return Object.fromEntries(clonedEntries)
@@ -0,0 +1,3 @@
1
+ export function isRecord(value: unknown): value is Record<string, unknown> {
2
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
3
+ }
@@ -1,6 +1,7 @@
1
1
  import type { RowData } from '@tanstack/react-table'
2
+ import { isRecord } from '@admin/utils/shared/is-record'
2
3
 
3
4
  export function defaultGetId<TData extends RowData>(row: TData): string | null | undefined {
4
- const id = (row as { id?: unknown }).id
5
- return typeof id === 'string' ? id : null
5
+ if (!isRecord(row)) return null
6
+ return typeof row.id === 'string' ? row.id : null
6
7
  }
@@ -15,7 +15,7 @@ export function EditorToolbar({
15
15
  role="toolbar"
16
16
  aria-label={ariaLabel}
17
17
  className={cn(
18
- 'sticky top-0 z-10 flex min-h-12 w-full items-center gap-1 overflow-x-auto overscroll-x-contain border-b border-border bg-card px-2 [scrollbar-width:none] max-[480px]:absolute max-[480px]:top-auto max-[480px]:h-[calc(2.75rem+env(safe-area-inset-bottom,0px))] max-[480px]:flex-nowrap max-[480px]:justify-start max-[480px]:border-t max-[480px]:border-b-0 max-[480px]:pb-[env(safe-area-inset-bottom,0px)] [&::-webkit-scrollbar]:hidden',
18
+ 'sticky top-0 z-10 flex min-h-12 w-full items-center gap-1 overflow-x-auto overscroll-x-contain border-b border-border bg-card px-2 [scrollbar-width:none] max-xs:absolute max-xs:top-auto max-xs:h-[calc(2.75rem+env(safe-area-inset-bottom,0px))] max-xs:flex-nowrap max-xs:justify-start max-xs:border-t max-xs:border-b-0 max-xs:pb-[env(safe-area-inset-bottom,0px)] [&::-webkit-scrollbar]:hidden',
19
19
  className
20
20
  )}
21
21
  >
@@ -33,6 +33,10 @@ export function SlashCommandMenu({
33
33
  searchQuery: string
34
34
  }) {
35
35
  const activeItemRef = React.useRef<HTMLDivElement | null>(null)
36
+
37
+ function assignActiveItem(node: HTMLDivElement | null) {
38
+ activeItemRef.current = node
39
+ }
36
40
  const searchInputRef = React.useRef<HTMLInputElement | null>(null)
37
41
  const activeCommandId = commands[activeIndex]?.id
38
42
 
@@ -159,9 +163,7 @@ export function SlashCommandMenu({
159
163
  index={index}
160
164
  key={command.id}
161
165
  data-active={isActive ? 'true' : undefined}
162
- ref={(node) => {
163
- if (isActive) activeItemRef.current = node
164
- }}
166
+ ref={isActive ? assignActiveItem : undefined}
165
167
  onMouseDown={(event) => event.preventDefault()}
166
168
  onMouseEnter={() => onActiveIndexChange(index)}
167
169
  value={command}
@@ -120,7 +120,7 @@ export function SourceMode({
120
120
  return (
121
121
  <div
122
122
  className={cn(
123
- 'content-editor-wrapper relative flex max-h-[90vh] min-h-[240px] resize-y flex-col overflow-hidden rounded-md border bg-background',
123
+ 'content-editor-wrapper relative flex max-h-[90vh] min-h-source-editor resize-y flex-col overflow-hidden rounded-md border bg-background',
124
124
  { 'opacity-50': disabled },
125
125
  className
126
126
  )}
@@ -14,6 +14,8 @@ import { cn } from '@admin/utils/shared/cn'
14
14
  import { NodeViewWrapper } from '@tiptap/react'
15
15
  import NextImage from 'next/image'
16
16
 
17
+ const EDITOR_IMAGE_SIZES = '768px'
18
+
17
19
  export const RemovableImageNode: React.FC<NodeViewProps> = (props) => {
18
20
  const { editor, node } = props
19
21
  const src = getStringAttr(node.attrs.src)
@@ -118,7 +120,7 @@ export const RemovableImageNode: React.FC<NodeViewProps> = (props) => {
118
120
  alt={alt}
119
121
  title={title || undefined}
120
122
  fill
121
- sizes="768px"
123
+ sizes={EDITOR_IMAGE_SIZES}
122
124
  unoptimized
123
125
  className="!m-0 !h-full !w-full !max-w-full object-contain"
124
126
  onLoad={handleImageLoad}
@@ -5,6 +5,7 @@ import { getTaskItemCheckboxLabel } from '@admin/utils/editor/get-task-item-chec
5
5
  import { hasOwnAttribute } from '@admin/utils/editor/has-own-attribute'
6
6
  import { isTaskItemChecked } from '@admin/utils/editor/is-task-item-checked'
7
7
  import { setElementAttribute } from '@admin/utils/editor/set-element-attribute'
8
+ import { setTaskItemChecked } from '@admin/utils/editor/set-task-item-checked'
8
9
  import { getRenderedAttributes } from '@tiptap/core'
9
10
  import { TaskItem } from '@tiptap/extension-list'
10
11
  import { createRoot } from 'react-dom/client'
@@ -20,7 +21,7 @@ export const ContentEditorTaskItem = TaskItem.extend({
20
21
  const checkboxMount = document.createElement('span')
21
22
  const content = document.createElement('div')
22
23
  const checkboxRoot = createRoot(checkboxMount)
23
- const staticAttributes = this.options.HTMLAttributes as Record<string, unknown>
24
+ const staticAttributes: Record<string, unknown> = this.options.HTMLAttributes
24
25
 
25
26
  checkboxContainer.contentEditable = 'false'
26
27
  checkboxContainer.className = 'content-editor-task-item-checkbox'
@@ -52,17 +53,7 @@ export const ContentEditorTaskItem = TaskItem.extend({
52
53
  editor
53
54
  .chain()
54
55
  .focus(undefined, { scrollIntoView: false })
55
- .command(({ tr }) => {
56
- const position = getPos()
57
- if (typeof position !== 'number') return false
58
-
59
- const taskItem = tr.doc.nodeAt(position)
60
- tr.setNodeMarkup(position, undefined, {
61
- ...taskItem?.attrs,
62
- checked
63
- })
64
- return true
65
- })
56
+ .command(({ tr }) => setTaskItemChecked(tr, getPos(), checked))
66
57
  .run()
67
58
  return
68
59
  }
@@ -89,7 +80,7 @@ export const ContentEditorTaskItem = TaskItem.extend({
89
80
  listItem.dataset.checked = String(renderedChecked)
90
81
  }
91
82
 
92
- applyAttributes(HTMLAttributes as Record<string, unknown>)
83
+ applyAttributes(HTMLAttributes)
93
84
  renderCheckbox()
94
85
 
95
86
  let prevRenderedAttributeKeys = new Set(Object.keys(HTMLAttributes))
@@ -104,10 +95,10 @@ export const ContentEditorTaskItem = TaskItem.extend({
104
95
  renderedChecked = isTaskItemChecked(updatedNode)
105
96
 
106
97
  const extensionAttributes = editor.extensionManager.attributes
107
- const newHTMLAttributes = getRenderedAttributes(
98
+ const newHTMLAttributes: Record<string, unknown> = getRenderedAttributes(
108
99
  updatedNode,
109
100
  extensionAttributes
110
- ) as Record<string, unknown>
101
+ )
111
102
  const newKeys = new Set(Object.keys(newHTMLAttributes))
112
103
 
113
104
  prevRenderedAttributeKeys.forEach((key) => {
@@ -93,12 +93,7 @@ export function HeadingDropdownMenu({
93
93
  }
94
94
  ></DropdownMenuTrigger>
95
95
 
96
- <DropdownMenuContent
97
- align="start"
98
- className="w-auto min-w-40"
99
- finalFocus={false}
100
- portalled={false}
101
- >
96
+ <DropdownMenuContent align="start" className="w-auto min-w-40" finalFocus={false}>
102
97
  <DropdownMenuGroup>
103
98
  {levels.map((level) => (
104
99
  <HeadingDropdownMenuItem key={`heading-${level}`} editor={editor} level={level} />
@@ -83,12 +83,7 @@ export function ListDropdownMenu({
83
83
  <ChevronDownIcon className="tiptap-button-dropdown-small" />
84
84
  </DropdownMenuTrigger>
85
85
 
86
- <DropdownMenuContent
87
- align="start"
88
- className="w-auto min-w-40"
89
- finalFocus={false}
90
- portalled={false}
91
- >
86
+ <DropdownMenuContent align="start" className="w-auto min-w-40" finalFocus={false}>
92
87
  <DropdownMenuGroup>
93
88
  {filteredLists.map((option) => (
94
89
  <ListDropdownMenuItem
@@ -132,14 +132,21 @@ export function DateRangePicker({
132
132
  >
133
133
  <PopoverTrigger
134
134
  render={
135
- <Button variant="outline" className={cn('w-[206px]', className)} disabled={disabled} />
135
+ <Button
136
+ variant="outline"
137
+ className={cn('w-date-range-trigger', className)}
138
+ disabled={disabled}
139
+ />
136
140
  }
137
141
  >
138
142
  <CalendarIcon />
139
143
  <span className="min-w-0 flex-1 truncate text-left tabular-nums">{triggerLabel}</span>
140
144
  <ChevronDown />
141
145
  </PopoverTrigger>
142
- <PopoverContent className="w-[282px] gap-0 overflow-hidden rounded-sm p-0" align="start">
146
+ <PopoverContent
147
+ className="w-date-range-popover gap-0 overflow-hidden rounded-sm p-0"
148
+ align="start"
149
+ >
143
150
  <Calendar
144
151
  mode="range"
145
152
  month={calendarMonth}
@@ -189,7 +189,7 @@ export function GalleryField({
189
189
  >
190
190
  <CarouselContent className="-ml-3">
191
191
  {canAdd && !disabled ? (
192
- <CarouselItem className="basis-[184px] pl-3">
192
+ <CarouselItem className="basis-gallery-item pl-3">
193
193
  <Card className="h-full" onClick={() => setOpen(true)}>
194
194
  <CardContent className="flex cursor-pointer flex-col p-2">
195
195
  <div className="flex aspect-square size-full flex-col items-center justify-center gap-1 overflow-hidden rounded-sm border border-border bg-background text-muted-foreground transition-colors hover:text-foreground">
@@ -208,7 +208,7 @@ export function GalleryField({
208
208
  {value.map((id) => {
209
209
  const item = mediaMap.get(id)
210
210
  return (
211
- <CarouselItem key={id} className="basis-[184px] pl-3">
211
+ <CarouselItem key={id} className="basis-gallery-item pl-3">
212
212
  <SortableGalleryItem id={id} disabled={disabled}>
213
213
  {item ? (
214
214
  <MediaField
@@ -243,7 +243,7 @@ export function GalleryField({
243
243
  </div>
244
244
  <DragOverlay>
245
245
  {activeId ? (
246
- <div className="w-[184px] scale-[0.98] cursor-grabbing opacity-95">
246
+ <div className="w-gallery-item scale-[0.98] cursor-grabbing opacity-95">
247
247
  {activeItem ? (
248
248
  <MediaField
249
249
  value={activeId}
@@ -102,7 +102,7 @@ export function MediaField({
102
102
  data-media-field-action="true"
103
103
  variant="outline"
104
104
  onClick={handleChangeImage}
105
- className="w-[100px] border-primary/10"
105
+ className="w-media-thumb border-primary/10"
106
106
  >
107
107
  Change
108
108
  </Button>
@@ -111,7 +111,7 @@ export function MediaField({
111
111
  data-media-field-action="true"
112
112
  variant="default"
113
113
  onClick={handleRemove}
114
- className="w-[100px]"
114
+ className="w-media-thumb"
115
115
  >
116
116
  Remove
117
117
  </Button>
@@ -13,6 +13,7 @@ import { FormDescription, FormField, FormItem, FormLabel } from '@admin/componen
13
13
  import { cloneDefaultValue } from '@admin/utils/form/clone-default-value'
14
14
  import { createListItemKey } from '@admin/utils/form/create-list-item-key'
15
15
  import { cn } from '@admin/utils/shared/cn'
16
+ import { isRecord } from '@admin/utils/shared/is-record'
16
17
  import { Plus, X } from 'lucide-react'
17
18
  import { useFormContext, useWatch } from 'react-hook-form'
18
19
 
@@ -75,7 +76,8 @@ export function NestedObjectListField({
75
76
  if (!isExpandedItemValid) return
76
77
  }
77
78
 
78
- const nextValue = cloneDefaultValue(defaultValue) as Record<string, unknown>
79
+ const clonedDefaultValue = cloneDefaultValue(defaultValue)
80
+ const nextValue = isRecord(clonedDefaultValue) ? clonedDefaultValue : {}
79
81
  const nextItems = [...items, nextValue]
80
82
  setValue(name, nextItems, {
81
83
  shouldDirty: true,
@@ -5,6 +5,8 @@ import { usePageBoundaryBlurVisibility } from '@admin/hooks/use-page-boundary-bl
5
5
  import { cn } from '@admin/utils/shared/cn'
6
6
  import { motion } from 'motion/react'
7
7
 
8
+ const DEFAULT_PROGRESSIVE_BLUR_HEIGHT = '150px'
9
+
8
10
  type ProgressiveBlurProps = React.ComponentProps<typeof motion.div> & {
9
11
  backgroundColor?: string
10
12
  position?: 'top' | 'bottom'
@@ -18,7 +20,7 @@ function ProgressiveBlur({
18
20
  style,
19
21
  backgroundColor = 'var(--background)',
20
22
  position = 'top',
21
- height = '150px',
23
+ height = DEFAULT_PROGRESSIVE_BLUR_HEIGHT,
22
24
  blurAmount = '0',
23
25
  scrollAware = true,
24
26
  ...props
@@ -13,8 +13,7 @@ const badgeVariants = cva(
13
13
  secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',
14
14
  destructive:
15
15
  'bg-destructive/10 text-destructive focus-visible:ring-destructive/20 [a]:hover:bg-destructive/20',
16
- success:
17
- 'bg-emerald-500/10 text-emerald-700 focus-visible:ring-emerald-500/20 [a]:hover:bg-emerald-500/20',
16
+ success: 'bg-success/10 text-success focus-visible:ring-success/20 [a]:hover:bg-success/20',
18
17
  outline:
19
18
  'border-border bg-input/30 text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',
20
19
  ghost: 'hover:bg-muted hover:text-muted-foreground',
@@ -22,33 +22,30 @@ function DropdownMenuContent({
22
22
  alignOffset = 0,
23
23
  side = 'bottom',
24
24
  sideOffset = 4,
25
- portalled = true,
26
25
  className,
27
26
  ...props
28
27
  }: MenuPrimitive.Popup.Props &
29
- Pick<MenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'> & {
30
- portalled?: boolean
31
- }) {
32
- const content = (
33
- <MenuPrimitive.Positioner
34
- className="isolate z-50 outline-none"
35
- align={align}
36
- alignOffset={alignOffset}
37
- side={side}
38
- sideOffset={sideOffset}
39
- >
40
- <MenuPrimitive.Popup
41
- data-slot="dropdown-menu-content"
42
- className={cn(
43
- 'cn-menu-target cn-menu-translucent z-50 max-h-(--available-height) w-(--anchor-width) min-w-48 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-2xl bg-popover p-1 text-popover-foreground shadow-2xl ring-1 ring-foreground/5 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95',
44
- className
45
- )}
46
- {...props}
47
- />
48
- </MenuPrimitive.Positioner>
28
+ Pick<MenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
29
+ return (
30
+ <MenuPrimitive.Portal>
31
+ <MenuPrimitive.Positioner
32
+ className="isolate z-50 outline-none"
33
+ align={align}
34
+ alignOffset={alignOffset}
35
+ side={side}
36
+ sideOffset={sideOffset}
37
+ >
38
+ <MenuPrimitive.Popup
39
+ data-slot="dropdown-menu-content"
40
+ className={cn(
41
+ 'cn-menu-target cn-menu-translucent z-50 max-h-(--available-height) w-(--anchor-width) min-w-48 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-2xl bg-popover p-1 text-popover-foreground shadow-2xl ring-1 ring-foreground/5 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95',
42
+ className
43
+ )}
44
+ {...props}
45
+ />
46
+ </MenuPrimitive.Positioner>
47
+ </MenuPrimitive.Portal>
49
48
  )
50
-
51
- return portalled ? <MenuPrimitive.Portal>{content}</MenuPrimitive.Portal> : content
52
49
  }
53
50
 
54
51
  function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
@@ -3,6 +3,7 @@
3
3
  import * as React from 'react'
4
4
  import type { ControllerProps, FieldPath, FieldValues } from 'react-hook-form'
5
5
  import { Label } from '@admin/components/ui/label'
6
+ import { useFieldErrorVisible } from '@admin/hooks/use-field-error-visible'
6
7
  import { cn } from '@admin/utils/shared/cn'
7
8
  import { Controller, FormProvider, useFormContext } from 'react-hook-form'
8
9
 
@@ -33,7 +34,8 @@ const FormField = <
33
34
  const useFormField = () => {
34
35
  const fieldContext = React.useContext(FormFieldContext)
35
36
  const itemContext = React.useContext(FormItemContext)
36
- const { getFieldState, formState } = useFormContext()
37
+ const form = useFormContext()
38
+ const isErrorVisible = useFieldErrorVisible(form, fieldContext?.name ?? '')
37
39
 
38
40
  if (!fieldContext) {
39
41
  throw new Error('useFormField should be used within <FormField>')
@@ -43,7 +45,7 @@ const useFormField = () => {
43
45
  throw new Error('useFormField should be used within <FormItem>')
44
46
  }
45
47
 
46
- const fieldState = getFieldState(fieldContext.name, formState)
48
+ const fieldState = form.getFieldState(fieldContext.name, form.formState)
47
49
 
48
50
  const { id } = itemContext
49
51
 
@@ -53,7 +55,8 @@ const useFormField = () => {
53
55
  formItemId: `${id}-form-item`,
54
56
  formDescriptionId: `${id}-form-item-description`,
55
57
  formMessageId: `${id}-form-item-message`,
56
- ...fieldState
58
+ ...fieldState,
59
+ error: isErrorVisible ? fieldState.error : undefined
57
60
  }
58
61
  }
59
62
 
@@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
8
8
  type={type}
9
9
  data-slot="input"
10
10
  className={cn(
11
- 'h-9 w-full min-w-0 rounded-4xl border border-input bg-input/30 px-3 py-1 text-sm transition-colors outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20',
11
+ 'h-9 w-full min-w-0 rounded-4xl border border-input bg-input/30 px-3 py-1 text-sm transition-colors outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-placeholder focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20',
12
12
  className
13
13
  )}
14
14
  {...props}
@@ -19,7 +19,7 @@ function NativeSelect({ className, size = 'default', ...props }: NativeSelectPro
19
19
  <select
20
20
  data-slot="native-select"
21
21
  data-size={size}
22
- className="h-9 w-full min-w-0 appearance-none rounded-4xl border border-input bg-input/30 py-1 pr-8 pl-3 text-sm transition-colors outline-none select-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20 data-[size=sm]:h-8"
22
+ className="h-9 w-full min-w-0 appearance-none rounded-4xl border border-input bg-input/30 py-1 pr-8 pl-3 text-sm transition-colors outline-none select-none selection:bg-primary selection:text-primary-foreground placeholder:text-placeholder focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20 data-[size=sm]:h-8"
23
23
  {...props}
24
24
  />
25
25
  <ChevronDownIcon
@@ -108,7 +108,7 @@ function NavigationMenuPositioner({
108
108
  )}
109
109
  {...props}
110
110
  >
111
- <NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease] xs:w-(--popup-width) relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-2xl bg-popover text-popover-foreground shadow ring-1 ring-foreground/5 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:scale-90 data-starting-style:opacity-0">
111
+ <NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease] relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-2xl bg-popover text-popover-foreground shadow ring-1 ring-foreground/5 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:scale-90 data-starting-style:opacity-0 xs:w-(--popup-width)">
112
112
  <NavigationMenuPrimitive.Viewport className="relative size-full overflow-hidden" />
113
113
  </NavigationMenuPrimitive.Popup>
114
114
  </NavigationMenuPrimitive.Positioner>
@@ -40,7 +40,7 @@ function SelectTrigger({
40
40
  data-slot="select-trigger"
41
41
  data-size={size}
42
42
  className={cn(
43
- "flex w-fit items-center justify-between gap-1.5 rounded-4xl border border-input bg-input/30 px-3 py-2 text-sm whitespace-nowrap transition-colors outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
43
+ "flex w-fit items-center justify-between gap-1.5 rounded-4xl border border-input bg-input/30 px-3 py-2 text-sm whitespace-nowrap transition-colors outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20 data-placeholder:text-placeholder data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
44
44
  className
45
45
  )}
46
46
  {...props}
@@ -6,7 +6,7 @@ function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
6
6
  <textarea
7
7
  data-slot="textarea"
8
8
  className={cn(
9
- 'flex field-sizing-content min-h-16 w-full resize-none rounded-xl border border-input bg-input/30 px-3 py-3 text-sm transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20',
9
+ 'flex field-sizing-content min-h-16 w-full resize-none rounded-xl border border-input bg-input/30 px-3 py-3 text-sm transition-colors outline-none placeholder:text-placeholder focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20',
10
10
  className
11
11
  )}
12
12
  {...props}
@@ -182,6 +182,14 @@ function safeWriteFile(filePath, content, force = false) {
182
182
  fs.writeFileSync(filePath, content, "utf-8");
183
183
  return true;
184
184
  }
185
+ function safeCopyFile(src, dest, force = false) {
186
+ if (!force && fs.existsSync(dest)) {
187
+ return false;
188
+ }
189
+ ensureDir(path.dirname(dest));
190
+ fs.copyFileSync(src, dest);
191
+ return true;
192
+ }
185
193
  function createGeneratedFile(filePath, content) {
186
194
  return {
187
195
  path: filePath.split(path.sep).join("/"),
@@ -499,6 +507,7 @@ var R2_ENV_KEYS = [
499
507
  "BETTERSTART_R2_BUCKET_NAME",
500
508
  "BETTERSTART_R2_PUBLIC_URL"
501
509
  ];
510
+ var PUBLIC_ASSET_FILE_NAMES = ["placeholder.png"];
502
511
  var PROXY_FILE_NAME = "proxy.ts";
503
512
  var PROXY_CONVENTION_FILE_NAMES = [
504
513
  "proxy.ts",
@@ -730,6 +739,7 @@ export {
730
739
  hashContent,
731
740
  ensureDir,
732
741
  safeWriteFile,
742
+ safeCopyFile,
733
743
  createGeneratedFile,
734
744
  toStrictJson,
735
745
  parseDotenvFile,
@@ -763,6 +773,7 @@ export {
763
773
  TIPTAP_CONTENT_EDITOR_DIRECTORIES,
764
774
  RAILWAY_BUCKET_ENV_KEYS,
765
775
  R2_ENV_KEYS,
776
+ PUBLIC_ASSET_FILE_NAMES,
766
777
  PROXY_FILE_NAME,
767
778
  PROXY_CONVENTION_FILE_NAMES,
768
779
  REMOVABLE_NAMESPACE_PATTERN,
@@ -781,4 +792,4 @@ export {
781
792
  replaceAdminDashToken,
782
793
  applyAdminNamespaceToContent
783
794
  };
784
- //# sourceMappingURL=chunk-FGEVDA53.js.map
795
+ //# sourceMappingURL=chunk-BNHFSHPE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../adapters/next/template-reader/read-template.ts","../utils/paths.ts","../constants/cli.ts","../constants/paths.ts","../utils/files.ts","../utils/text.ts","../adapters/next/config/namespace/protect-admin-role-literals.ts","../constants/scaffolding.ts","../adapters/next/config/namespace/protect-existing-namespace-literals.ts","../constants/patterns.ts","../adapters/next/config/namespace/is-external-module-specifier.ts","../adapters/next/config/namespace/protect-external-module-specifiers.ts","../adapters/next/config/namespace/replace-admin-camel-token.ts","../adapters/next/config/namespace/replace-admin-dash-token.ts","../adapters/next/config/namespace/replace-admin-pascal-token.ts","../adapters/next/config/namespace/replace-admin-screaming-token.ts","../adapters/next/config/namespace/validate-admin-namespace.ts","../adapters/next/config/namespace/resolve-admin-namespace.ts","../adapters/next/config/namespace/apply-admin-namespace-to-content.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport { resolveCliAssetPath } from '@cli-utils/paths.js'\n\nexport function readTemplate(relativePath: string): string {\n return fs.readFileSync(\n path.join(resolveCliAssetPath('adapters', 'next', 'templates', 'init'), relativePath),\n 'utf-8'\n )\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { CommandOptions } from '@cli-types/core-engine/commands.js'\nimport type { CliPackageJson } from '@cli-types/core-engine/utils.js'\nimport type { Command } from 'commander'\nimport { CLI_PACKAGE_NAME } from '@cli-constants/cli.js'\nimport { BETTERSTART_DIR } from '@cli-constants/paths.js'\nimport { findUpwards } from '@cli-utils/files.js'\n\nexport function betterstartDir(cwd: string, ...segments: string[]): string {\n return path.join(cwd, BETTERSTART_DIR, ...segments)\n}\n\nexport function toPosixPath(value: string): string {\n return value.replace(/\\\\/g, '/')\n}\n\nexport function trimDotSlash(value: string): string {\n return value.replace(/^[.][/\\\\]/, '')\n}\n\nexport function normalizePosixDir(value: string): string {\n return trimDotSlash(toPosixPath(value)).replace(/\\/+$/, '')\n}\n\nexport function toProjectAbsolutePath(cwd: string, filePath: string): string {\n return path.isAbsolute(filePath) ? filePath : path.join(cwd, ...filePath.split('/'))\n}\n\nexport function readLocalProjectFile(cwd: string, filePath: string): string | null {\n const fullPath = toProjectAbsolutePath(cwd, filePath)\n return fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf-8') : null\n}\n\nexport function isInsideDir(child: string, parent: string): boolean {\n const relative = path.relative(parent, child)\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))\n}\n\nexport function removePath(cwd: string, filePath: string): boolean {\n const fullPath = toProjectAbsolutePath(cwd, filePath)\n const existed = fs.existsSync(fullPath)\n fs.rmSync(fullPath, { recursive: true, force: true })\n return existed\n}\n\nexport function cleanupEmptyDirs(\n cwd: string,\n deletedPaths: string[],\n stopRoots: Iterable<string>\n): void {\n const projectRoot = path.resolve(cwd)\n const stops = new Set<string>([projectRoot, ...stopRoots])\n\n for (const deletedPath of deletedPaths) {\n let currentDir = path.dirname(toProjectAbsolutePath(cwd, deletedPath))\n\n while (isInsideDir(currentDir, projectRoot) && !stops.has(currentDir)) {\n if (!fs.existsSync(currentDir)) {\n currentDir = path.dirname(currentDir)\n continue\n }\n\n if (fs.readdirSync(currentDir).length > 0) {\n break\n }\n\n fs.rmdirSync(currentDir)\n currentDir = path.dirname(currentDir)\n }\n }\n}\n\nfunction findCliPackage(): { dir: string; pkg: CliPackageJson } | null {\n const start = path.dirname(fileURLToPath(import.meta.url))\n\n return (\n findUpwards(start, (dir) => {\n const pkgPath = path.join(dir, 'package.json')\n if (!fs.existsSync(pkgPath)) return undefined\n\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as CliPackageJson\n return pkg.name === CLI_PACKAGE_NAME ? { dir, pkg } : undefined\n } catch {\n return undefined\n }\n }) ?? null\n )\n}\n\nexport function findCliRoot(): string {\n const found = findCliPackage()\n if (found) {\n return found.dir\n }\n\n // Fallback: assume 2 levels up from dist/\n return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')\n}\n\nexport function getCurrentCliVersion(): string {\n return findCliPackage()?.pkg.version ?? '0.0.0'\n}\n\nexport function resolveCliAssetPath(...segments: string[]): string {\n const root = findCliRoot()\n const builtPath = path.join(root, 'dist', 'assets', ...segments)\n if (fs.existsSync(builtPath)) {\n return builtPath\n }\n\n return path.join(root, ...segments)\n}\n\nexport function resolveCommandCwd(command: Command): string {\n const options = command.opts<CommandOptions>()\n return typeof options.cwd === 'string' ? path.resolve(options.cwd) : process.cwd()\n}\n","export const CLI_PACKAGE_NAME = 'betterstart-cli'\nexport const REDACTED = '[redacted]'\n","import type { PackageManager } from '@cli-types/core-engine/utils.js'\n\nexport const ADMIN_CONTAINER_ROUTE_GROUP = '(container)'\nexport const BETTERSTART_DIR = '.betterstart'\nexport const CONFIG_FILE_NAME = 'betterstart.config.ts'\nexport const DEVELOPMENT_ENV_FILES = [\n '.env.development.local',\n '.env.local',\n '.env.development',\n '.env'\n] as const\nexport const LOCKFILE_MAP: Record<string, PackageManager> = {\n 'pnpm-lock.yaml': 'pnpm',\n 'package-lock.json': 'npm',\n 'yarn.lock': 'yarn',\n 'bun.lockb': 'bun',\n 'bun.lock': 'bun'\n}\n","import crypto from 'node:crypto'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { parseEnv } from 'node:util'\nimport type { EnvSection, ProjectEnvValue } from '@cli-types/core-engine/env.js'\nimport type { GeneratedFile } from '@cli-types/core-engine/schema.js'\nimport type { FileSnapshot } from '@cli-types/core-engine/utils.js'\nimport { DEVELOPMENT_ENV_FILES } from '@cli-constants/paths.js'\nimport { normalizeLineEndings } from '@cli-utils/text.js'\nimport fse from 'fs-extra'\n\n/**\n * Walks from `startDir` to the filesystem root inclusive, returning the first\n * defined `visit` result. Inclusive matters: a walk that stops one level early\n * silently ignores a `package.json` or lockfile sitting at the root.\n */\nexport function findUpwards<T>(\n startDir: string,\n visit: (dir: string) => T | undefined\n): T | undefined {\n let dir = path.resolve(startDir)\n\n for (;;) {\n const found = visit(dir)\n if (found !== undefined) return found\n\n const parent = path.dirname(dir)\n if (parent === dir) return undefined\n dir = parent\n }\n}\n\nexport function hashContent(content: string): string {\n return `sha256-${crypto.createHash('sha256').update(normalizeLineEndings(content)).digest('hex')}`\n}\n\nexport function ensureDir(dirPath: string): void {\n fse.ensureDirSync(dirPath)\n}\n\nexport function safeWriteFile(filePath: string, content: string, force = false): boolean {\n if (!force && fs.existsSync(filePath)) {\n return false\n }\n ensureDir(path.dirname(filePath))\n fs.writeFileSync(filePath, content, 'utf-8')\n return true\n}\n\nexport function safeCopyFile(src: string, dest: string, force = false): boolean {\n if (!force && fs.existsSync(dest)) {\n return false\n }\n ensureDir(path.dirname(dest))\n fs.copyFileSync(src, dest)\n return true\n}\n\nexport function copyTemplateDir(\n srcDir: string,\n destDir: string,\n force = false\n): { written: string[]; skipped: string[] } {\n const written: string[] = []\n const skipped: string[] = []\n\n function walk(currentSrc: string, currentDest: string): void {\n const entries = fs.readdirSync(currentSrc, { withFileTypes: true })\n for (const entry of entries) {\n const srcPath = path.join(currentSrc, entry.name)\n const destPath = path.join(currentDest, entry.name)\n\n if (entry.isDirectory()) {\n walk(srcPath, destPath)\n } else {\n if (safeCopyFile(srcPath, destPath, force)) {\n written.push(destPath)\n } else {\n skipped.push(destPath)\n }\n }\n }\n }\n\n walk(srcDir, destDir)\n return { written, skipped }\n}\n\nexport function appendToFile(filePath: string, content: string, marker: string): boolean {\n if (fs.existsSync(filePath)) {\n const existing = fs.readFileSync(filePath, 'utf-8')\n if (existing.includes(marker)) {\n return false\n }\n fs.writeFileSync(filePath, `${existing.trimEnd()}\\n${content}\\n`, 'utf-8')\n } else {\n ensureDir(path.dirname(filePath))\n fs.writeFileSync(filePath, `${content}\\n`, 'utf-8')\n }\n return true\n}\n\n/**\n * Snapshot manifests, skip lists, and conflict paths are all keyed by these\n * strings, so a Windows `\\` here would make a project's snapshots unreadable on\n * any other machine.\n */\nexport function createGeneratedFile(filePath: string, content: string): GeneratedFile {\n return {\n path: filePath.split(path.sep).join('/'),\n content\n }\n}\n\n// Next.js and TypeScript both emit `tsconfig.json` with comments and trailing commas.\nexport function stripJsonComments(input: string): string {\n let result = ''\n let i = 0\n while (i < input.length) {\n if (input[i] === '\"') {\n let j = i + 1\n while (j < input.length) {\n if (input[j] === '\\\\') {\n j += 2\n continue\n }\n if (input[j] === '\"') {\n j++\n break\n }\n j++\n }\n result += input.slice(i, j)\n i = j\n } else if (input[i] === '/' && input[i + 1] === '/') {\n const nl = input.indexOf('\\n', i)\n i = nl === -1 ? input.length : nl\n } else if (input[i] === '/' && input[i + 1] === '*') {\n const end = input.indexOf('*/', i + 2)\n i = end === -1 ? input.length : end + 2\n } else {\n result += input[i]\n i++\n }\n }\n return result\n}\n\nexport function toStrictJson(input: string): string {\n return stripJsonComments(input).replace(/,\\s*([\\]}])/g, '$1')\n}\n\n/**\n * `node:util`'s parseEnv is the single owner of .env syntax here. A hand-rolled\n * splitter previously read `KEY=\"value\" # comment` back as `value\" # comment`\n * and understood neither `export` prefixes nor multi-line values.\n */\nexport function parseDotenvFile(filePath: string): Map<string, string> {\n if (!fs.existsSync(filePath)) return new Map()\n\n try {\n const parsed = Object.entries(parseEnv(fs.readFileSync(filePath, 'utf-8')))\n return new Map(\n parsed.filter((entry): entry is [string, string] => typeof entry[1] === 'string')\n )\n } catch {\n return new Map()\n }\n}\n\nexport function readEnvVar(cwd: string, key: string): string | undefined {\n return parseDotenvFile(path.join(cwd, '.env.local')).get(key)\n}\n\n/** Reads DEVELOPMENT_ENV_FILES in Next.js's development-file precedence order. */\nexport function resolveProjectEnvVar(cwd: string, key: string): ProjectEnvValue | undefined {\n for (const envFile of DEVELOPMENT_ENV_FILES) {\n const value = parseDotenvFile(path.join(cwd, envFile)).get(key)?.trim()\n if (value) return { source: envFile, value }\n }\n\n return undefined\n}\n\nexport function readProjectEnvVar(cwd: string, key: string): string | undefined {\n return resolveProjectEnvVar(cwd, key)?.value\n}\n\nexport function appendEnvVars(\n cwd: string,\n sections: EnvSection[],\n overwrite?: Set<string>\n): { added: string[]; skipped: string[]; updated: string[] } {\n const envPath = path.join(cwd, '.env.local')\n let existing = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf-8') : ''\n\n const existingKeys = new Set(\n existing\n .split('\\n')\n .filter((line) => line.trim() && !line.trim().startsWith('#'))\n .map((line) => line.split('=')[0]?.trim())\n .filter(Boolean)\n )\n\n const added: string[] = []\n const skipped: string[] = []\n const updated: string[] = []\n const lines: string[] = []\n\n if (overwrite) {\n for (const section of sections) {\n for (const v of section.vars) {\n if (overwrite.has(v.key) && existingKeys.has(v.key)) {\n const pattern = new RegExp(`^${v.key}=.*$`, 'm')\n const replacement = v.comment\n ? `${v.key}=\"${v.value}\" # ${v.comment}`\n : `${v.key}=\"${v.value}\"`\n existing = existing.replace(pattern, replacement)\n updated.push(v.key)\n }\n }\n }\n }\n\n if (existing.trim()) {\n lines.push('')\n }\n\n for (const section of sections) {\n const sectionVars = section.vars.filter((v) => {\n if (existingKeys.has(v.key)) {\n if (!updated.includes(v.key)) skipped.push(v.key)\n return false\n }\n added.push(v.key)\n return true\n })\n\n if (sectionVars.length === 0) continue\n\n lines.push(`# ${section.header}`)\n for (const v of sectionVars) {\n const line = v.comment ? `${v.key}=\"${v.value}\" # ${v.comment}` : `${v.key}=\"${v.value}\"`\n lines.push(line)\n }\n lines.push('')\n }\n\n if (added.length > 0 || updated.length > 0) {\n const header = existing.trim()\n ? ''\n : '# ============================================\\n# BetterStart Admin\\n# ============================================\\n'\n const content = existing.trim()\n ? `${existing.trimEnd()}\\n${lines.join('\\n')}`\n : header + lines.join('\\n')\n fs.writeFileSync(envPath, content)\n }\n\n return { added, skipped, updated }\n}\n\nexport function removeEnvVars(cwd: string, keys: string[]): string[] {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath) || keys.length === 0) {\n return []\n }\n\n const keySet = new Set(keys)\n const removed: string[] = []\n const filteredLines = fs\n .readFileSync(envPath, 'utf-8')\n .split('\\n')\n .filter((line) => {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#') || !trimmed.includes('=')) {\n return true\n }\n\n const [key] = trimmed.split('=')\n const normalizedKey = key?.trim()\n if (normalizedKey && keySet.has(normalizedKey)) {\n removed.push(normalizedKey)\n return false\n }\n\n return true\n })\n\n fs.writeFileSync(envPath, `${filteredLines.join('\\n').trimEnd()}\\n`, 'utf-8')\n return removed\n}\n\nexport function captureFile(filePath: string): FileSnapshot {\n if (!fs.existsSync(filePath)) {\n return { existed: false }\n }\n\n return { existed: true, content: fs.readFileSync(filePath, 'utf-8') }\n}\n\nexport function restoreFile(filePath: string, snapshot: FileSnapshot): void {\n if (snapshot.existed) {\n fs.writeFileSync(filePath, snapshot.content ?? '', 'utf-8')\n return\n }\n\n if (fs.existsSync(filePath)) {\n fs.rmSync(filePath, { force: true })\n }\n}\n\nexport function readNonEmptyEnvVar(cwd: string, key: string): string | undefined {\n const value = readProjectEnvVar(cwd, key)?.trim()\n return value ? value : undefined\n}\n","import { stripVTControlCharacters } from 'node:util'\n/**\n * `stripVTControlCharacters` also removes OSC and other C1 sequences, which a\n * CSI-only regex leaves behind on CLIs that emit terminal hyperlinks.\n * `stripCarriageReturns` additionally flattens the `\\r` a progress-spinner child\n * process uses to repaint one line, so line-based filters see a single line.\n */\nexport function stripAnsi(text: string, options: { stripCarriageReturns?: boolean } = {}): string {\n const stripped = stripVTControlCharacters(text)\n return options.stripCarriageReturns ? stripped.replaceAll('\\r', '') : stripped\n}\n\nexport function toPascalCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nexport function toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nexport function singularize(str: string): string {\n if (str.endsWith('ies')) return `${str.slice(0, -3)}y`\n if (str.endsWith('ves')) return `${str.slice(0, -3)}f`\n if (\n str.endsWith('sses') ||\n str.endsWith('xes') ||\n str.endsWith('ches') ||\n str.endsWith('shes') ||\n str.endsWith('zes')\n )\n return str.slice(0, -2)\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\n\nexport function pluralize(str: string): string {\n if (str.endsWith('s') && !str.endsWith('ss')) return str\n if (str.endsWith('y') && !['ay', 'ey', 'iy', 'oy', 'uy'].some((v) => str.endsWith(v)))\n return `${str.slice(0, -1)}ies`\n if (str.endsWith('s') || str.endsWith('x') || str.endsWith('ch') || str.endsWith('sh'))\n return `${str}es`\n return `${str}s`\n}\n\nexport function toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\nexport function toScreamingSnake(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toUpperCase()\n}\n\nexport function quotePropertyName(name: string): string {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`\n}\n\nexport function humanizeName(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ')\n}\n\nexport function singularizeLabel(label: string): string {\n const words = label.split(' ')\n const lastWord = words[words.length - 1]\n words[words.length - 1] = singularize(lastWord.toLowerCase())\n words[words.length - 1] =\n words[words.length - 1].charAt(0).toUpperCase() + words[words.length - 1].slice(1)\n return words.join(' ')\n}\n\n/**\n * Escapes `\\r` and `\\n` as well as the quote character: a raw newline inside an\n * emitted single- or double-quoted literal is a syntax error, so a schema label\n * containing one would otherwise emit a file that does not parse.\n */\nexport function quoteLiteral(value: string, quote = \"'\"): string {\n const escaped = value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(new RegExp(escapeRegExp(quote), 'g'), `\\\\${quote}`)\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n')\n\n return `${quote}${escaped}${quote}`\n}\n\nexport function escapeTemplateText(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/`/g, '\\\\`').replace(/\\$\\{/g, '\\\\${')\n}\n\nexport function normalizeLineEndings(content: string): string {\n return content.replace(/\\r\\n/g, '\\n')\n}\n\nexport function escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function hasConflictMarkers(content: string): boolean {\n return /^(<{7}|={7}|>{7})( |$)/m.test(content)\n}\n\nexport function splitLines(content: string): string[] {\n return normalizeLineEndings(content).split('\\n')\n}\n\nexport function normalizeWhitespace(value: string): string {\n return value.trim().replace(/\\s+/g, ' ')\n}\n\nexport function escapeJsx(str: string): string {\n return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\nexport function escapeAttribute(str: string): string {\n return escapeJsx(str).replace(/\"/g, '&quot;')\n}\n\nexport function findNextNonEmptyLine(lines: string[], startIndex: number): string | null {\n for (let i = startIndex; i < lines.length; i++) {\n const trimmed = lines[i]!.trim()\n if (trimmed !== '') return trimmed\n }\n return null\n}\n\nexport function levenshtein(a: string, b: string): number {\n const matrix = Array.from({ length: a.length + 1 }, () => new Array<number>(b.length + 1).fill(0))\n\n for (let i = 0; i <= a.length; i++) matrix[i]![0] = i\n for (let j = 0; j <= b.length; j++) matrix[0]![j] = j\n\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1\n matrix[i]![j] = Math.min(\n matrix[i - 1]![j]! + 1,\n matrix[i]![j - 1]! + 1,\n matrix[i - 1]![j - 1]! + cost\n )\n }\n }\n\n return matrix[a.length]![b.length]!\n}\n\nexport function toTitleCase(value: string): string {\n return normalizeWhitespace(value)\n .split(' ')\n .map((word) => (word ? `${word.charAt(0).toUpperCase()}${word.slice(1).toLowerCase()}` : word))\n .join(' ')\n}\n\nexport function slugify(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/['\"]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .replace(/-+/g, '-')\n}\n\nexport function usesIdentifier(source: string, identifier: string): boolean {\n return new RegExp(`\\\\b${escapeRegExp(identifier)}\\\\b`).test(source)\n}\n\nexport function detectIndent(raw: string): string | number {\n const indentMatch = raw.match(/^[ \\t]+(?=\")/m)\n return indentMatch?.[0] ?? 2\n}\n\nexport function jsString(value: string): string {\n return JSON.stringify(value)\n}\n\nexport function safeIdentifier(value: string, fallback: string): string {\n const pascal = toPascalCase(value).replace(/[^A-Za-z0-9_$]/g, '')\n const base = pascal ? `${pascal.charAt(0).toLowerCase()}${pascal.slice(1)}` : fallback\n return /^[A-Za-z_$]/.test(base) ? base : fallback\n}\n","export function protectAdminRoleLiterals(content: string): {\n content: string\n restore: (value: string) => string\n} {\n const protectedValues = [\n 'UserRole.ADMIN',\n \"'admin'\",\n '\"admin\"',\n '`admin`',\n '>Admin</SelectItem>',\n 'Manage admin users and roles'\n ]\n\n const replacements: Array<[string, string]> = []\n let protectedContent = content\n\n for (const [index, value] of protectedValues.entries()) {\n if (!protectedContent.includes(value)) {\n continue\n }\n\n const token = `__BETTERSTART_NAMESPACE_PROTECTED_${index}__`\n protectedContent = protectedContent.replaceAll(value, token)\n replacements.push([token, value])\n }\n\n return {\n content: protectedContent,\n restore(value: string): string {\n let restored = value\n for (const [token, original] of replacements) {\n restored = restored.replaceAll(token, original)\n }\n return restored\n }\n }\n}\n","export const DEFAULT_ADMIN_NAMESPACE = 'admin'\nexport const DEPRECATED_ADMIN_PATH_ALIAS_SUFFIXES = ['/data/*', '/auth', '/auth/middleware']\nexport const BETTERSTART_ASSET_HOST = 'assets.betterstart.dev'\nexport const LEGACY_DEFAULT_AUTH_URL = 'http://localhost:3000'\nexport const DATABASE_URL_PLACEHOLDER = 'postgresql://...'\nexport const DEFAULT_DEV_PORT = 4242\nexport const MAIN_CSS_CANDIDATES = [\n 'src/app/globals.css',\n 'app/globals.css',\n 'src/app/global.css',\n 'app/global.css',\n 'src/app/app.css',\n 'app/app.css',\n 'src/globals.css',\n 'globals.css'\n]\nexport const CONFIG_IMPORT_SHIM = 'const defineConfig = <T>(config: T): T => config'\nexport const TIPTAP_CONTENT_EDITOR_DIRECTORIES = ['tiptap-extension', 'tiptap-node', 'tiptap-ui']\nexport const RAILWAY_BUCKET_ENV_KEYS = [\n 'BETTERSTART_RAILWAY_BUCKET_ENDPOINT',\n 'BETTERSTART_RAILWAY_BUCKET_ACCESS_KEY_ID',\n 'BETTERSTART_RAILWAY_BUCKET_SECRET_ACCESS_KEY',\n 'BETTERSTART_RAILWAY_BUCKET_NAME',\n 'BETTERSTART_RAILWAY_BUCKET_REGION',\n 'BETTERSTART_RAILWAY_BUCKET_URL_STYLE'\n] as const\nexport const R2_ENV_KEYS = [\n 'BETTERSTART_R2_ACCOUNT_ID',\n 'BETTERSTART_R2_ACCESS_KEY_ID',\n 'BETTERSTART_R2_SECRET_ACCESS_KEY',\n 'BETTERSTART_R2_BUCKET_NAME',\n 'BETTERSTART_R2_PUBLIC_URL'\n] as const\nexport const PUBLIC_ASSET_FILE_NAMES = ['placeholder.png'] as const\nexport const PROXY_FILE_NAME = 'proxy.ts'\nexport const PROXY_CONVENTION_FILE_NAMES = [\n 'proxy.ts',\n 'proxy.tsx',\n 'proxy.js',\n 'proxy.jsx',\n 'middleware.ts',\n 'middleware.tsx',\n 'middleware.js',\n 'middleware.jsx'\n] as const\n","import type { AdminNamespace } from '@cli-types/next-adapter/config.js'\nimport { DEFAULT_ADMIN_NAMESPACE } from '@cli-constants/scaffolding.js'\n\nexport function protectExistingNamespaceLiterals(\n value: string,\n namespace: AdminNamespace\n): {\n value: string\n restore: (output: string) => string\n} {\n if (namespace.segment === DEFAULT_ADMIN_NAMESPACE) {\n return {\n value,\n restore(output: string): string {\n return output\n }\n }\n }\n\n const literals = Array.from(\n new Set([\n namespace.alias,\n namespace.apiPath,\n namespace.routePath,\n namespace.routeGroup,\n namespace.cssRootClass,\n namespace.globalsFile,\n `${namespace.segment}/`,\n `${namespace.segment}-`,\n namespace.screaming,\n namespace.pascal,\n namespace.camel\n ])\n ).sort((a, b) => b.length - a.length)\n\n const replacements: Array<[string, string]> = []\n let protectedValue = value\n\n for (const [index, literal] of literals.entries()) {\n if (!protectedValue.includes(literal)) {\n continue\n }\n\n const token = `__BSTART_NS_${index}__`\n protectedValue = protectedValue.replaceAll(literal, token)\n replacements.push([token, literal])\n }\n\n return {\n value: protectedValue,\n restore(output: string): string {\n let restored = output\n for (const [token, literal] of replacements) {\n restored = restored.replaceAll(token, literal)\n }\n return restored\n }\n }\n}\n","export const REMOVABLE_NAMESPACE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nexport const SCHEMA_NAME_PATTERN = /^[a-z][a-zA-Z0-9-]*$/\nexport const NAMESPACE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/\nexport const MODULE_SPECIFIER_PATTERN =\n /(\\bfrom\\s*|\\bimport\\s*|\\brequire\\s*\\(\\s*|\\bimport\\s*\\(\\s*)(['\"])([^'\"\\n]+)\\2/g\nexport const EXTERNAL_PACKAGE_PATTERN =\n /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*(?:\\/[^'\"]*)?$/\nexport const DEV_PORT_FLAG_PATTERN = /(?:^|\\s)(?:--port(?:=|\\s+)|-p(?:=|\\s+)?)(\\d+)(?=\\s|$)/\nexport const DEV_PORT_ENV_PATTERN = /(?:^|\\s)PORT=(\\d+)(?=\\s|$)/\nexport const LOCAL_PROTOCOL_PATTERN = /^(workspace|link|file|portal):/\nexport const CONFIG_IMPORT_PATTERN =\n /^import\\s+\\{[^}]*\\bdefineConfig\\b[^}]*\\}\\s+from\\s+['\"]betterstart-cli['\"];?[^\\S\\n]*$/m\nexport const CONFIG_OBJECT_PATTERNS = [\n /\\b(?:const|let|var)\\s+\\w+\\s*:\\s*NextConfig\\s*=\\s*\\{/g,\n /\\b(?:const|let|var)\\s+nextConfig\\s*=\\s*\\{/g,\n /\\b(?:const|let|var)\\s+\\w+\\s*:\\s*NextConfig\\s*=\\s*(?:[A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*)*\\(\\s*)+\\{/g,\n /\\b(?:const|let|var)\\s+nextConfig\\s*=\\s*(?:[A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*)*\\(\\s*)+\\{/g,\n /export\\s+default\\s+\\{/g,\n /export\\s+default\\s+(?:[A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*)*\\(\\s*)+\\{/g,\n /module\\.exports\\s*=\\s*\\{/g,\n /module\\.exports\\s*=\\s*(?:[A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*)*\\(\\s*)+\\{/g\n]\n/**\n * On accounts without the Neon integration installed, the piped (non-TTY) `integration add` opens\n * the accept-terms page in a browser and polls until the user accepts, printing the URL in a\n * \"Visit this URL if the browser does not open\" line — the only signal that it is waiting.\n */\nexport const ACCEPT_TERMS_URL_PATTERN =\n /https:\\/\\/vercel\\.com\\/\\S+\\/integrations\\/accept-terms\\/\\S+/i\n/** Printed by the Vercel CLI once its accept-terms polling succeeds. */\nexport const TERMS_ACCEPTED_PATTERN = /terms accepted/i\n","import { EXTERNAL_PACKAGE_PATTERN } from '@cli-constants/patterns.js'\nimport { DEFAULT_ADMIN_NAMESPACE } from '@cli-constants/scaffolding.js'\n\nexport function isExternalModuleSpecifier(specifier: string): boolean {\n if (specifier.startsWith('.') || specifier.startsWith('/')) {\n return false\n }\n\n if (new RegExp(`^@${DEFAULT_ADMIN_NAMESPACE}(?:/|$)`).test(specifier)) {\n return false\n }\n\n return EXTERNAL_PACKAGE_PATTERN.test(specifier)\n}\n","import { MODULE_SPECIFIER_PATTERN } from '@cli-constants/patterns.js'\nimport { isExternalModuleSpecifier } from './is-external-module-specifier.js'\n\nexport function protectExternalModuleSpecifiers(content: string): {\n content: string\n restore: (value: string) => string\n} {\n const replacements: Array<[string, string]> = []\n\n const protectedContent = content.replace(\n MODULE_SPECIFIER_PATTERN,\n (match, prefix: string, quote: string, specifier: string) => {\n if (!isExternalModuleSpecifier(specifier)) {\n return match\n }\n\n const token = `__BETTERSTART_EXTERNAL_MODULE_${replacements.length}__`\n replacements.push([token, specifier])\n return `${prefix}${quote}${token}${quote}`\n }\n )\n\n return {\n content: protectedContent,\n restore(value: string): string {\n let restored = value\n for (const [token, specifier] of replacements) {\n restored = restored.replaceAll(token, specifier)\n }\n return restored\n }\n }\n}\n","import type { AdminNamespace } from '@cli-types/next-adapter/config.js'\n\nexport function replaceAdminCamelToken(value: string, namespace: AdminNamespace): string {\n return value.replace(/\\badmin(?=[A-Z])/g, namespace.camel)\n}\n","import type { AdminNamespace } from '@cli-types/next-adapter/config.js'\n\nexport function replaceAdminDashToken(value: string, namespace: AdminNamespace): string {\n return value.replaceAll('admin-', `${namespace.segment}-`)\n}\n","import type { AdminNamespace } from '@cli-types/next-adapter/config.js'\n\nexport function replaceAdminPascalToken(value: string, namespace: AdminNamespace): string {\n return value.replaceAll('Admin', namespace.pascal)\n}\n","import type { AdminNamespace } from '@cli-types/next-adapter/config.js'\n\nexport function replaceAdminScreamingToken(value: string, namespace: AdminNamespace): string {\n return value.replaceAll('ADMIN_', `${namespace.screaming}_`)\n}\n","import { NAMESPACE_PATTERN } from '@cli-constants/patterns.js'\n\nexport function validateAdminNamespace(value: string): string {\n const segment = value.trim()\n\n if (!NAMESPACE_PATTERN.test(segment)) {\n throw new Error(\n 'Namespace must be one lowercase kebab-case segment starting with a letter, for example \"admin\" or \"admin-panel\".'\n )\n }\n\n return segment\n}\n","import type { AdminNamespace } from '@cli-types/next-adapter/config.js'\nimport { DEFAULT_ADMIN_NAMESPACE } from '@cli-constants/scaffolding.js'\nimport { toCamelCase, toPascalCase, toScreamingSnake } from '@cli-utils/text.js'\nimport { validateAdminNamespace } from './validate-admin-namespace.js'\n\nexport function resolveAdminNamespace(value = DEFAULT_ADMIN_NAMESPACE): AdminNamespace {\n const segment = validateAdminNamespace(value)\n const pascal = toPascalCase(segment)\n\n return {\n segment,\n alias: `@${segment}`,\n camel: toCamelCase(segment),\n pascal,\n screaming: toScreamingSnake(segment),\n routePath: `/${segment}`,\n apiPath: `/api/${segment}`,\n cssRootClass: `${segment}-root`,\n globalsFile: `${segment}-globals.css`,\n routeGroup: `(${segment})`\n }\n}\n","import { protectAdminRoleLiterals } from './protect-admin-role-literals.js'\nimport { protectExistingNamespaceLiterals } from './protect-existing-namespace-literals.js'\nimport { protectExternalModuleSpecifiers } from './protect-external-module-specifiers.js'\nimport { replaceAdminCamelToken } from './replace-admin-camel-token.js'\nimport { replaceAdminDashToken } from './replace-admin-dash-token.js'\nimport { replaceAdminPascalToken } from './replace-admin-pascal-token.js'\nimport { replaceAdminScreamingToken } from './replace-admin-screaming-token.js'\nimport { resolveAdminNamespace } from './resolve-admin-namespace.js'\n\nexport function applyAdminNamespaceToContent(content: string, namespaceValue: string): string {\n const namespace = resolveAdminNamespace(namespaceValue)\n const { content: externalSafeContent, restore: restoreExternalModules } =\n protectExternalModuleSpecifiers(content)\n const { content: protectedContent, restore } = protectAdminRoleLiterals(externalSafeContent)\n\n const canonicalContent = protectedContent\n .replaceAll('MediaListParams', `${namespace.pascal}MediaQuery`)\n .replaceAll('MediaListResult', `${namespace.pascal}MediaPage`)\n .replaceAll(\n `${namespace.pascal}MediaQuery, ${namespace.pascal}MediaPage`,\n `${namespace.pascal}MediaPage, ${namespace.pascal}MediaQuery`\n )\n .replaceAll('UserData', 'User')\n .replaceAll('UsersResponse', 'UsersPage')\n .replaceAll('SettingData', 'Setting')\n .replaceAll('UpsertSettingInput', 'SettingUpsertInput')\n .replaceAll('UpsertSettingResult', 'SettingUpsertResult')\n .replace(\n /import\\s+\\{\\s*admin\\s*\\}\\s+from\\s+(['\"])@admin\\/utils\\/app\\/admin\\1/g,\n (_match, quote: string) =>\n `import { ${namespace.camel} } from ${quote}${namespace.alias}/utils/app/${namespace.camel}${quote}`\n )\n .replace(/\\badmin(?=\\.name\\b)/g, namespace.camel)\n .replaceAll('@admin/auth/middleware', `${namespace.alias}/auth/session`)\n .replaceAll('@admin/auth/auth', `${namespace.alias}/auth/server`)\n .replaceAll('@admin/auth/client', `${namespace.alias}/auth/client`)\n .replace(/@admin\\/auth(?=['\"`\\s)]|$)/g, `${namespace.alias}/auth/server`)\n .replace(/(\\bimport\\b[^\\n]*\\bfrom\\s+)'\\.\\/auth'/g, \"$1'./server'\")\n .replace(/@admin(?=\\/|$)/g, namespace.alias)\n .replace(/\\/api\\/admin(?=\\/|['\"`]|$)/g, namespace.apiPath)\n .replace(/(^|\\/)admin(?=\\/|['\"`]|$)/g, `$1${namespace.segment}`)\n .replaceAll('(admin)', namespace.routeGroup)\n\n const protectedNamespace = protectExistingNamespaceLiterals(canonicalContent, namespace)\n const namespacedContent = replaceAdminCamelToken(\n replaceAdminPascalToken(\n replaceAdminScreamingToken(\n replaceAdminDashToken(protectedNamespace.value, namespace),\n namespace\n ),\n namespace\n ),\n namespace\n )\n\n return restoreExternalModules(restore(protectedNamespace.restore(namespacedContent)))\n}\n"],"mappings":"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","names":["fs","path","fs","path","path","fs","fs","path"]}