@stacksjs/defaults 0.75.231 → 0.75.233

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 (41) hide show
  1. package/ai/skills/stacks-native/CATALOG.md +4 -4
  2. package/ai/skills/stacks-storage/SKILL.md +43 -0
  3. package/ai/skills/stacks-testing/SKILL.md +38 -10
  4. package/functions/dashboard-form.test.ts +41 -0
  5. package/functions/dashboard-form.ts +30 -0
  6. package/functions/dashboard-list.test.ts +228 -0
  7. package/functions/dashboard-list.ts +257 -0
  8. package/ide/vscode/package.json +1 -1
  9. package/package.json +2 -2
  10. package/project/storage/framework/types/browser-composables.d.ts +56 -0
  11. package/resources/components/Dashboard/Commerce/CommerceCategoriesDashboard.stx +2 -7
  12. package/resources/components/Dashboard/Commerce/CommerceCategoryDialog.stx +2 -4
  13. package/resources/components/Dashboard/Commerce/CommerceCouponDialog.stx +2 -4
  14. package/resources/components/Dashboard/Commerce/CommerceCouponsDashboard.stx +2 -7
  15. package/resources/components/Dashboard/Commerce/CommerceCustomerDialog.stx +2 -4
  16. package/resources/components/Dashboard/Commerce/CommerceCustomersDashboard.stx +2 -7
  17. package/resources/components/Dashboard/Commerce/CommerceGiftCardDialog.stx +2 -4
  18. package/resources/components/Dashboard/Commerce/CommerceGiftCardsDashboard.stx +2 -7
  19. package/resources/components/Dashboard/Commerce/CommerceManufacturerDialog.stx +2 -4
  20. package/resources/components/Dashboard/Commerce/CommerceOrderDialog.stx +2 -4
  21. package/resources/components/Dashboard/Commerce/CommerceOrdersDashboard.stx +2 -7
  22. package/resources/components/Dashboard/Commerce/CommerceProductDialog.stx +2 -4
  23. package/resources/components/Dashboard/Commerce/CommerceProductsDashboard.stx +2 -7
  24. package/resources/components/Dashboard/Commerce/CommerceReviewEditDialog.stx +2 -4
  25. package/resources/components/Dashboard/Commerce/CommerceTaxDialog.stx +2 -4
  26. package/resources/components/Dashboard/Commerce/CommerceUnitDialog.stx +2 -4
  27. package/resources/components/Dashboard/Commerce/CommerceVariantDialog.stx +2 -4
  28. package/resources/components/Dashboard/Commerce/Delivery/CouriersDashboard.stx +45 -92
  29. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesDashboard.stx +46 -92
  30. package/resources/components/Dashboard/Commerce/Delivery/LicenseKeysDashboard.stx +46 -92
  31. package/resources/components/Dashboard/Commerce/Delivery/ShippingRatesDashboard.stx +44 -90
  32. package/resources/components/Dashboard/Commerce/Delivery/ShippingZonesDashboard.stx +45 -91
  33. package/resources/components/Dashboard/Commerce/PrintDeviceDialog.stx +2 -4
  34. package/resources/components/Dashboard/Commerce/PrintDevicesDashboard.stx +2 -7
  35. package/resources/components/Dashboard/Commerce/ProductWaitlistEntryDialog.stx +2 -4
  36. package/resources/components/Dashboard/Commerce/RestaurantWaitlistEntryDialog.stx +2 -4
  37. package/resources/components/Dashboard/Marketing/AbandonedCartsDashboard.stx +2 -9
  38. package/resources/components/Dashboard/Marketing/CampaignsDashboard.stx +2 -9
  39. package/resources/components/Dashboard/Marketing/MarketingListsDashboard.stx +2 -9
  40. package/resources/components/Dashboard/Marketing/SocialPostsDashboard.stx +2 -9
  41. package/resources/plugins/preloader.ts +9 -1
@@ -1,5 +1,6 @@
1
1
  <script client>
2
2
  import { dashboardApi } from '../../../../../functions/dashboard-api'
3
+ import { useRecordsDashboard } from '../../../../../functions/dashboard-list'
3
4
  import { pushToast } from '../../../../../functions/toasts'
4
5
  import { formatCurrency, minorToInput } from '@stacksjs/commerce/money'
5
6
 
@@ -28,22 +29,47 @@ interface ShippingRatePayload {
28
29
  rate: number
29
30
  }
30
31
 
31
- const records = state<ShippingRateRecord[]>([])
32
+ function matchesQuery(records: ShippingRateRecord[], query: string): ShippingRateRecord[] {
33
+ return records.filter(record => [
34
+ record.shipping_method?.name,
35
+ record.shipping_zone?.name,
36
+ record.weight_from,
37
+ record.weight_to,
38
+ minorToInput(record.rate, 'USD'),
39
+ ].some(value => String(value ?? '').toLowerCase().includes(query)))
40
+ }
41
+
42
+ const {
43
+ records,
44
+ loading,
45
+ loadError,
46
+ search,
47
+ page,
48
+ perPage,
49
+ editorOpen,
50
+ editorMode,
51
+ editing,
52
+ saving,
53
+ editorError,
54
+ deleting,
55
+ deleteBusy,
56
+ deleteError,
57
+ filteredRecords,
58
+ paginatedRecords,
59
+ goToPage,
60
+ handleSearch,
61
+ openCreate,
62
+ openEdit,
63
+ closeEditor,
64
+ requestDelete,
65
+ closeDelete,
66
+ upsert,
67
+ remove,
68
+ clampPage,
69
+ } = useRecordsDashboard<ShippingRateRecord>({ filter: matchesQuery })
70
+
32
71
  const methods = state<ShippingResourceOption[]>([])
33
72
  const zones = state<ShippingResourceOption[]>([])
34
- const loading = state(true)
35
- const loadError = state('')
36
- const search = state('')
37
- const page = state(1)
38
- const perPage = state(10)
39
- const editorOpen = state(false)
40
- const editorMode = state<'create' | 'edit'>('create')
41
- const editing = state<ShippingRateRecord | null>(null)
42
- const saving = state(false)
43
- const editorError = state('')
44
- const deleting = state<ShippingRateRecord | null>(null)
45
- const deleteBusy = state(false)
46
- const deleteError = state('')
47
73
 
48
74
  function methodFor(id: number): ShippingResourceOption | undefined {
49
75
  return methods().find(method => method.id === id)
@@ -61,24 +87,6 @@ function withRelations(record: ShippingRateRecord): ShippingRateRecord {
61
87
  }
62
88
  }
63
89
 
64
- function filteredRecords(): ShippingRateRecord[] {
65
- const query = search().trim().toLowerCase()
66
- if (!query)
67
- return records()
68
- return records().filter(record => [
69
- record.shipping_method?.name,
70
- record.shipping_zone?.name,
71
- record.weight_from,
72
- record.weight_to,
73
- minorToInput(record.rate, 'USD'),
74
- ].some(value => String(value ?? '').toLowerCase().includes(query)))
75
- }
76
-
77
- function paginatedRecords(): ShippingRateRecord[] {
78
- const start = (page() - 1) * perPage()
79
- return filteredRecords().slice(start, start + perPage())
80
- }
81
-
82
90
  function uniqueZoneCount(): number {
83
91
  return new Set(records().map(record => record.shipping_zone_id)).size
84
92
  }
@@ -114,9 +122,7 @@ async function loadRates(): Promise<void> {
114
122
  methods.set(methodData)
115
123
  zones.set(zoneData)
116
124
  records.set(rateData.map(withRelations))
117
- const lastPage = Math.max(1, Math.ceil(filteredRecords().length / perPage()))
118
- if (page() > lastPage)
119
- page.set(lastPage)
125
+ clampPage()
120
126
  }
121
127
  catch (error) {
122
128
  loadError.set(error instanceof Error ? error.message : String(error))
@@ -127,33 +133,6 @@ async function loadRates(): Promise<void> {
127
133
  }
128
134
  }
129
135
 
130
- function handleSearch(value: string): void {
131
- search.set(value)
132
- page.set(1)
133
- }
134
-
135
- function openCreate(): void {
136
- editing.set(null)
137
- editorMode.set('create')
138
- editorError.set('')
139
- editorOpen.set(true)
140
- }
141
-
142
- function openEdit(record: ShippingRateRecord): void {
143
- editing.set(record)
144
- editorMode.set('edit')
145
- editorError.set('')
146
- editorOpen.set(true)
147
- }
148
-
149
- function closeEditor(): void {
150
- if (saving())
151
- return
152
- editorOpen.set(false)
153
- editing.set(null)
154
- editorError.set('')
155
- }
156
-
157
136
  function setEditorError(message: string): void {
158
137
  editorError.set(message)
159
138
  }
@@ -173,14 +152,7 @@ async function saveRate(payload: ShippingRatePayload): Promise<void> {
173
152
  },
174
153
  )
175
154
  const hydrated = withRelations(updated)
176
- if (current) {
177
- records.set(records().map(record => record.id === current.id ? hydrated : record))
178
- }
179
- else {
180
- const nextRecords = [...records(), hydrated]
181
- records.set(nextRecords)
182
- page.set(Math.max(1, Math.ceil(nextRecords.length / perPage())))
183
- }
155
+ upsert(hydrated, current)
184
156
  editorOpen.set(false)
185
157
  editing.set(null)
186
158
  pushToast('success', current ? 'Shipping rate updated' : 'Shipping rate added', {
@@ -195,18 +167,6 @@ async function saveRate(payload: ShippingRatePayload): Promise<void> {
195
167
  }
196
168
  }
197
169
 
198
- function requestDelete(record: ShippingRateRecord): void {
199
- deleting.set(record)
200
- deleteError.set('')
201
- }
202
-
203
- function closeDelete(): void {
204
- if (deleteBusy())
205
- return
206
- deleting.set(null)
207
- deleteError.set('')
208
- }
209
-
210
170
  async function confirmDelete(): Promise<void> {
211
171
  const current = deleting()
212
172
  if (!current)
@@ -217,11 +177,9 @@ async function confirmDelete(): Promise<void> {
217
177
  await dashboardApi(`/api/dashboard/commerce/shipping-rates/${current.id}`, {
218
178
  method: 'DELETE',
219
179
  })
220
- records.set(records().filter(record => record.id !== current.id))
180
+ remove(current)
221
181
  deleting.set(null)
222
- const lastPage = Math.max(1, Math.ceil(filteredRecords().length / perPage()))
223
- if (page() > lastPage)
224
- page.set(lastPage)
182
+ clampPage()
225
183
  pushToast('success', 'Shipping rate deleted', {
226
184
  detail: `${current.shipping_method?.name || 'Method'} for ${current.shipping_zone?.name || 'zone'}`,
227
185
  })
@@ -234,10 +192,6 @@ async function confirmDelete(): Promise<void> {
234
192
  }
235
193
  }
236
194
 
237
- function goToPage(value: number): void {
238
- page.set(value)
239
- }
240
-
241
195
  onMount(() => {
242
196
  void loadRates()
243
197
  })
@@ -1,5 +1,6 @@
1
1
  <script client>
2
2
  import { dashboardApi } from '../../../../../functions/dashboard-api'
3
+ import { useRecordsDashboard } from '../../../../../functions/dashboard-list'
3
4
  import { pushToast } from '../../../../../functions/toasts'
4
5
 
5
6
  type SerializedList = string | string[] | null | undefined
@@ -30,21 +31,47 @@ interface ShippingZonePayload {
30
31
  status: 'active' | 'inactive' | 'draft'
31
32
  }
32
33
 
33
- const records = state<ShippingZoneRecord[]>([])
34
+ function matchesQuery(records: ShippingZoneRecord[], query: string): ShippingZoneRecord[] {
35
+ return records.filter(record => [
36
+ record.name,
37
+ record.status,
38
+ record.shipping_method?.name,
39
+ ...listTokens(record.countries),
40
+ ...listTokens(record.regions),
41
+ ...listTokens(record.postal_codes),
42
+ ].some(value => String(value || '').toLowerCase().includes(query)))
43
+ }
44
+
45
+ const {
46
+ records,
47
+ loading,
48
+ loadError,
49
+ search,
50
+ page,
51
+ perPage,
52
+ editorOpen,
53
+ editorMode,
54
+ editing,
55
+ saving,
56
+ editorError,
57
+ deleting,
58
+ deleteBusy,
59
+ deleteError,
60
+ filteredRecords,
61
+ paginatedRecords,
62
+ goToPage,
63
+ handleSearch,
64
+ openCreate,
65
+ openEdit,
66
+ closeEditor,
67
+ requestDelete,
68
+ closeDelete,
69
+ upsert,
70
+ remove,
71
+ clampPage,
72
+ } = useRecordsDashboard<ShippingZoneRecord>({ filter: matchesQuery })
73
+
34
74
  const methods = state<ShippingMethodOption[]>([])
35
- const loading = state(true)
36
- const loadError = state('')
37
- const search = state('')
38
- const page = state(1)
39
- const perPage = state(10)
40
- const editorOpen = state(false)
41
- const editorMode = state<'create' | 'edit'>('create')
42
- const editing = state<ShippingZoneRecord | null>(null)
43
- const saving = state(false)
44
- const editorError = state('')
45
- const deleting = state<ShippingZoneRecord | null>(null)
46
- const deleteBusy = state(false)
47
- const deleteError = state('')
48
75
 
49
76
  function listTokens(value: SerializedList): string[] {
50
77
  if (Array.isArray(value))
@@ -73,25 +100,6 @@ function withMethod(record: ShippingZoneRecord): ShippingZoneRecord {
73
100
  }
74
101
  }
75
102
 
76
- function filteredRecords(): ShippingZoneRecord[] {
77
- const query = search().trim().toLowerCase()
78
- if (!query)
79
- return records()
80
- return records().filter(record => [
81
- record.name,
82
- record.status,
83
- record.shipping_method?.name,
84
- ...listTokens(record.countries),
85
- ...listTokens(record.regions),
86
- ...listTokens(record.postal_codes),
87
- ].some(value => String(value || '').toLowerCase().includes(query)))
88
- }
89
-
90
- function paginatedRecords(): ShippingZoneRecord[] {
91
- const start = (page() - 1) * perPage()
92
- return filteredRecords().slice(start, start + perPage())
93
- }
94
-
95
103
  function uniqueCount(field: 'countries' | 'regions'): number {
96
104
  return new Set(records().flatMap(record => listTokens(record[field]))).size
97
105
  }
@@ -122,9 +130,7 @@ async function loadZones(): Promise<void> {
122
130
  throw new TypeError('Shipping zone resources were not returned as arrays.')
123
131
  methods.set(methodData)
124
132
  records.set(zoneData.map(withMethod))
125
- const lastPage = Math.max(1, Math.ceil(filteredRecords().length / perPage()))
126
- if (page() > lastPage)
127
- page.set(lastPage)
133
+ clampPage()
128
134
  }
129
135
  catch (error) {
130
136
  loadError.set(error instanceof Error ? error.message : String(error))
@@ -135,33 +141,6 @@ async function loadZones(): Promise<void> {
135
141
  }
136
142
  }
137
143
 
138
- function handleSearch(value: string): void {
139
- search.set(value)
140
- page.set(1)
141
- }
142
-
143
- function openCreate(): void {
144
- editing.set(null)
145
- editorMode.set('create')
146
- editorError.set('')
147
- editorOpen.set(true)
148
- }
149
-
150
- function openEdit(record: ShippingZoneRecord): void {
151
- editing.set(record)
152
- editorMode.set('edit')
153
- editorError.set('')
154
- editorOpen.set(true)
155
- }
156
-
157
- function closeEditor(): void {
158
- if (saving())
159
- return
160
- editorOpen.set(false)
161
- editing.set(null)
162
- editorError.set('')
163
- }
164
-
165
144
  function setEditorError(message: string): void {
166
145
  editorError.set(message)
167
146
  }
@@ -181,14 +160,7 @@ async function saveZone(payload: ShippingZonePayload): Promise<void> {
181
160
  },
182
161
  )
183
162
  const hydrated = withMethod(updated)
184
- if (current) {
185
- records.set(records().map(record => record.id === current.id ? hydrated : record))
186
- }
187
- else {
188
- const nextRecords = [...records(), hydrated]
189
- records.set(nextRecords)
190
- page.set(Math.max(1, Math.ceil(nextRecords.length / perPage())))
191
- }
163
+ upsert(hydrated, current)
192
164
  editorOpen.set(false)
193
165
  editing.set(null)
194
166
  pushToast('success', current ? 'Shipping zone updated' : 'Shipping zone added', {
@@ -203,18 +175,6 @@ async function saveZone(payload: ShippingZonePayload): Promise<void> {
203
175
  }
204
176
  }
205
177
 
206
- function requestDelete(record: ShippingZoneRecord): void {
207
- deleting.set(record)
208
- deleteError.set('')
209
- }
210
-
211
- function closeDelete(): void {
212
- if (deleteBusy())
213
- return
214
- deleting.set(null)
215
- deleteError.set('')
216
- }
217
-
218
178
  async function confirmDelete(): Promise<void> {
219
179
  const current = deleting()
220
180
  if (!current)
@@ -225,11 +185,9 @@ async function confirmDelete(): Promise<void> {
225
185
  await dashboardApi(`/api/dashboard/commerce/shipping-zones/${current.id}`, {
226
186
  method: 'DELETE',
227
187
  })
228
- records.set(records().filter(record => record.id !== current.id))
188
+ remove(current)
229
189
  deleting.set(null)
230
- const lastPage = Math.max(1, Math.ceil(filteredRecords().length / perPage()))
231
- if (page() > lastPage)
232
- page.set(lastPage)
190
+ clampPage()
233
191
  pushToast('success', 'Shipping zone deleted', { detail: current.name })
234
192
  }
235
193
  catch (error) {
@@ -240,10 +198,6 @@ async function confirmDelete(): Promise<void> {
240
198
  }
241
199
  }
242
200
 
243
- function goToPage(value: number): void {
244
- page.set(value)
245
- }
246
-
247
201
  onMount(() => {
248
202
  void loadZones()
249
203
  })
@@ -1,4 +1,5 @@
1
1
  <script client>
2
+ import { formErrorMessages } from '../../../../functions/dashboard-form'
2
3
  import type {
3
4
  PrintDeviceRecord,
4
5
  PrintDeviceStatus,
@@ -51,10 +52,7 @@ function submit(): void {
51
52
  }
52
53
 
53
54
  function errorMessages(): string[] {
54
- return Object.entries(errors()).map(([field, message]) => {
55
- const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
56
- return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
57
- })
55
+ return formErrorMessages(errors())
58
56
  }
59
57
  </script>
60
58
 
@@ -6,6 +6,7 @@ import type {
6
6
  } from '../../../../app/Actions/Dashboard/Commerce/print-device-records'
7
7
  import { DashboardApiError, dashboardApi } from '../../../../functions/dashboard-api'
8
8
  import { pushToast } from '../../../../functions/toasts'
9
+ import { pageControls } from '../../../../functions/dashboard-list'
9
10
 
10
11
  interface PrintDevicesResponse {
11
12
  records: PrintDeviceRecord[]
@@ -234,13 +235,7 @@ async function deletePrintDevice(): Promise<void> {
234
235
  }
235
236
  }
236
237
 
237
- function previousPage(): void {
238
- page.set(Math.max(1, page() - 1))
239
- }
240
-
241
- function nextPage(): void {
242
- page.set(Math.min(pageCount(), page() + 1))
243
- }
238
+ const { previousPage, nextPage } = pageControls(page, pageCount)
244
239
 
245
240
  onMount(() => {
246
241
  void loadPrintDevices()
@@ -1,5 +1,6 @@
1
1
  <script client>
2
2
  import type { ProductWaitlistOptions, ProductWaitlistRecord, ProductWaitlistWritePayload } from '../../../../app/Actions/Dashboard/Commerce/product-waitlist-records'
3
+ import { formErrorMessages } from '../../../../functions/dashboard-form'
3
4
 
4
5
  type DialogMode = 'add' | 'edit'
5
6
 
@@ -94,10 +95,7 @@ function submitForm(): void {
94
95
  }
95
96
 
96
97
  function errorMessages(): string[] {
97
- return Object.entries(errors()).map(([field, message]) => {
98
- const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
99
- return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
100
- })
98
+ return formErrorMessages(errors())
101
99
  }
102
100
  </script>
103
101
 
@@ -1,6 +1,7 @@
1
1
  <script client>
2
2
  import type { RestaurantWaitlistOptions, RestaurantWaitlistRecord, RestaurantWaitlistWritePayload } from '../../../../app/Actions/Dashboard/Commerce/restaurant-waitlist-records'
3
3
  import { restaurantWaitlistDateTimeLocal, restaurantWaitlistTimestamp } from '../../../../app/Actions/Dashboard/Commerce/restaurant-waitlist-records'
4
+ import { formErrorMessages } from '../../../../functions/dashboard-form'
4
5
 
5
6
  type DialogMode = 'add' | 'edit'
6
7
 
@@ -104,10 +105,7 @@ function submitForm(): void {
104
105
  }
105
106
 
106
107
  function errorMessages(): string[] {
107
- return Object.entries(errors()).map(([field, message]) => {
108
- const label = field.replace(/([a-z])([A-Z])/g, '$1 $2').replaceAll('_', ' ')
109
- return `${label.charAt(0).toUpperCase()}${label.slice(1)}: ${message}`
110
- })
108
+ return formErrorMessages(errors())
111
109
  }
112
110
  </script>
113
111
 
@@ -8,6 +8,7 @@ import type {
8
8
  import { formatCurrency } from '@stacksjs/commerce/money'
9
9
  import { dashboardApi } from '../../../../functions/dashboard-api'
10
10
  import { pushToast } from '../../../../functions/toasts'
11
+ import { pageControls } from '../../../../functions/dashboard-list'
11
12
 
12
13
  const emptySummary: AbandonedCartSummary = {
13
14
  open: 0,
@@ -162,15 +163,7 @@ async function createCampaign(payload: Record<string, unknown>): Promise<void> {
162
163
  }
163
164
  }
164
165
 
165
- function previousPage(): void {
166
- if (page() > 1)
167
- page.set(page() - 1)
168
- }
169
-
170
- function nextPage(): void {
171
- if (page() < totalPages())
172
- page.set(page() + 1)
173
- }
166
+ const { previousPage, nextPage } = pageControls(page, totalPages)
174
167
 
175
168
  onMount(() => {
176
169
  void loadCarts()
@@ -7,6 +7,7 @@ import type {
7
7
  import type { CampaignDeliveryOperation } from '../../../../app/Actions/Dashboard/Marketing/campaign-delivery'
8
8
  import { dashboardApi } from '../../../../functions/dashboard-api'
9
9
  import { pushToast } from '../../../../functions/toasts'
10
+ import { pageControls } from '../../../../functions/dashboard-list'
10
11
 
11
12
  interface CampaignIndexResponse {
12
13
  records: CampaignRecord[]
@@ -271,15 +272,7 @@ async function confirmDelivery(payload: { scheduledAt?: string }): Promise<void>
271
272
  }
272
273
  }
273
274
 
274
- function previousPage(): void {
275
- if (page() > 1)
276
- page.set(page() - 1)
277
- }
278
-
279
- function nextPage(): void {
280
- if (page() < totalPages())
281
- page.set(page() + 1)
282
- }
275
+ const { previousPage, nextPage } = pageControls(page, totalPages)
283
276
 
284
277
  onMount(() => {
285
278
  void loadCampaigns()
@@ -5,6 +5,7 @@ import type {
5
5
  } from '../../../../app/Actions/Dashboard/Marketing/marketing-list-records'
6
6
  import { dashboardApi } from '../../../../functions/dashboard-api'
7
7
  import { pushToast } from '../../../../functions/toasts'
8
+ import { pageControls } from '../../../../functions/dashboard-list'
8
9
 
9
10
  interface MarketingListIndexResponse {
10
11
  records: MarketingListRecord[]
@@ -193,15 +194,7 @@ async function deleteList(): Promise<void> {
193
194
  }
194
195
  }
195
196
 
196
- function previousPage(): void {
197
- if (page() > 1)
198
- page.set(page() - 1)
199
- }
200
-
201
- function nextPage(): void {
202
- if (page() < totalPages())
203
- page.set(page() + 1)
204
- }
197
+ const { previousPage, nextPage } = pageControls(page, totalPages)
205
198
 
206
199
  onMount(() => {
207
200
  void loadLists()
@@ -6,6 +6,7 @@ import type {
6
6
  } from '../../../../app/Actions/Dashboard/Marketing/social-post-records'
7
7
  import { dashboardApi } from '../../../../functions/dashboard-api'
8
8
  import { pushToast } from '../../../../functions/toasts'
9
+ import { pageControls } from '../../../../functions/dashboard-list'
9
10
 
10
11
  interface SocialPostIndexResponse {
11
12
  records: SocialPostRecord[]
@@ -186,15 +187,7 @@ async function deletePost(): Promise<void> {
186
187
  }
187
188
  }
188
189
 
189
- function previousPage(): void {
190
- if (page() > 1)
191
- page.set(page() - 1)
192
- }
193
-
194
- function nextPage(): void {
195
- if (page() < totalPages())
196
- page.set(page() + 1)
197
- }
190
+ const { previousPage, nextPage } = pageControls(page, totalPages)
198
191
 
199
192
  onMount(() => {
200
193
  void loadPosts()
@@ -88,7 +88,15 @@ const isRepl = !process.argv[1]
88
88
  // otherwise valid. Postinstall scripts are bootstrap work and must stay independent
89
89
  // of the application runtime preloader.
90
90
  const isPostinstall = process.env.npm_lifecycle_event === 'postinstall'
91
- const skipPreloader = isRepl || isPostinstall || (args.length > 0 && fastCommands.some(cmd => args[0] === cmd || args[0].startsWith(`${cmd}:`)))
91
+ // runAction starts these framework files directly, with flags rather than a
92
+ // Buddy command in argv[2]. They only inspect/release repository metadata.
93
+ // Match the framework's source and published layouts, never an app action
94
+ // which happens to have the same basename and needs its application globals.
95
+ const entrypoint = (process.argv[1] ?? '').replaceAll('\\', '/')
96
+ const repositoryAction = '(?:release|bump|generate/lib-entries)\\.[jt]s'
97
+ const isRepositoryAction = new RegExp(`(?:^|/)storage/framework/core/actions/src/${repositoryAction}$`).test(entrypoint)
98
+ || new RegExp(`(?:^|/)(?:node_modules|pantry)/@stacksjs/actions/(?:src|dist(?:/src)?)/${repositoryAction}$`).test(entrypoint)
99
+ const skipPreloader = isRepl || isPostinstall || isRepositoryAction || (args.length > 0 && fastCommands.some(cmd => args[0] === cmd || args[0].startsWith(`${cmd}:`)))
92
100
 
93
101
  if (!skipPreloader) {
94
102
  // Detect production/deployment commands and set environment accordingly BEFORE loading env files