ReviewOS

also looking at this

theopenfarm/openfarm.ing

fix: restore demo catalog with native migration safeguards

#41
Merged chris wants to merge codex/catalog-soft-delete-recovery into main
15 files +438 -183
app/Commands/CatalogSync.tsmodified+50-18
Changes to app/Commands/CatalogSync.ts
@@ -1,6 +1,7 @@
11import type { CLI } from '@stacksjs/types'
22import process from 'node:process'
33import { log } from '@stacksjs/cli'
4import { bootAppListeners } from '@stacksjs/events'
45import { ExitCode } from '@stacksjs/types'
56import Detection from '../Models/Detection'
67import Drone from '../Models/Drone'
@@ -22,7 +23,7 @@ import { features } from '../Support/content/features'
2223import { useCases } from '../Support/content/use-cases'
2324
2425/**
25 * `buddy catalog:sync` — publish the catalog and the demonstration field.
26 * `buddy catalog:sync`, publish the catalog and the demonstration field.
2627 *
2728 * Writes everything the site and the public API serve:
2829 *
@@ -38,14 +39,15 @@ import { useCases } from '../Support/content/use-cases'
3839 * dataset whose figures are quoted in the copy, so it has to come out
3940 * identical on every machine. Publishing it is a deploy step, not a seed.
4041 *
41 * Re-running is safe. Every table is truncated first, so this is also how a
42 * content edit reaches production: `preStart` runs it on every deploy.
42 * Re-running keeps the reserved demo identities and replaces their derived
43 * observations. `preStart` runs this on every deploy.
4344 */
4445export default function (cli: CLI) {
4546 cli
4647 .command('catalog:sync', 'Publish the capability catalog and the demonstration field into the database')
4748 .action(async () => {
4849 try {
50 await bootAppListeners({ base: process.cwd() })
4951 await syncCatalog()
5052 log.success(`Catalog synced: ${features.length} capabilities, ${useCases.length} use cases, and the demonstration field.`)
5153 }
@@ -92,11 +94,9 @@ async function syncCatalog(): Promise<void> {
9294 * that farmers have accounts: the deploy runs this on every release, and a
9395 * truncate would take a customer's fields and flights with it. The catalog
9496 * tables are wholly derived from the content modules and can be replaced;
95 * the demonstration records are found by their own slug and removed
96 * individually, children first so nothing is orphaned.
97 * the reserved demonstration identities are kept. Their derived mission
98 * observations are replaced, children first so nothing is orphaned.
9799 */
98 await UseCase.truncate()
99 await Feature.truncate()
100100
101101 /*
102102 * What `buddy imagery:attach` published outlives the rewrite.
@@ -112,7 +112,19 @@ async function syncCatalog(): Promise<void> {
112112 */
113113 let publishedImagery: Record<string, unknown> | null = null
114114
115 const demoFarm = await Farm.where('slug', DEMO_FARM.slug).first()
115 const demoFarm = await Farm.withTrashed().where('slug', DEMO_FARM.slug).first()
116 const demoField = await Field.withTrashed().where('slug', DEMO_FIELD.slug).first()
117 const demoDrone = await Drone.where('callsign', 'OF-K12').first()
118 if (demoFarm && demoFarm.user_id != null)
119 throw new Error('The reserved demonstration farm belongs to an account; refusing to overwrite it')
120 for (const record of [demoField, demoDrone]) {
121 if (record && (!demoFarm || Number(record.farm_id) !== Number(demoFarm.id)))
122 throw new Error('A reserved demonstration identity belongs to another farm; refusing to overwrite it')
123 }
124
125 // Ownership checks finish before the first destructive catalog write.
126 await UseCase.truncate()
127 await Feature.truncate()
116128 if (demoFarm?.id) {
117129 const farmId = Number(demoFarm.id)
118130 const missions = await Mission.where('farm_id', farmId).get()
@@ -133,9 +145,6 @@ async function syncCatalog(): Promise<void> {
133145 }
134146
135147 await Mission.where('farm_id', farmId).delete()
136 await Field.where('farm_id', farmId).delete()
137 await Drone.where('farm_id', farmId).delete()
138 await Farm.where('id', farmId).delete()
139148 }
140149
141150 await Feature.createMany(features.map(f => ({
@@ -170,15 +179,23 @@ async function syncCatalog(): Promise<void> {
170179 })))
171180
172181 // The demonstration field.
173 const farm = await Farm.create({
182 const farmData = {
174183 name: DEMO_FARM.name,
175184 slug: DEMO_FARM.slug,
176185 region: DEMO_FARM.region,
177186 segment: DEMO_FARM.segment,
178187 hectares: DEMO_FARM.hectares,
179 }) as Record<string, any>
188 }
189 if (demoFarm) {
190 if (demoFarm.deleted_at != null)
191 await Farm.restore(Number(demoFarm.id))
192 await Farm.update(Number(demoFarm.id), farmData)
193 }
194 const farm = (demoFarm ? await Farm.find(Number(demoFarm.id)) : await Farm.create(farmData))
195 if (!farm)
196 throw new Error('The demonstration farm could not be read after publication')
180197
181 const drone = await Drone.create({
198 const droneData = {
182199 callsign: 'OF-K12',
183200 model: 'Scout',
184201 payload: 'multispectral',
@@ -187,9 +204,14 @@ async function syncCatalog(): Promise<void> {
187204 battery_percent: 100,
188205 flight_hours: 412,
189206 farm_id: farm.id,
190 }) as Record<string, any>
207 } as const
208 if (demoDrone)
209 await Drone.update(Number(demoDrone.id), droneData)
210 const drone = (demoDrone ? await Drone.find(Number(demoDrone.id)) : await Drone.create(droneData))
211 if (!drone)
212 throw new Error('The demonstration aircraft could not be read after publication')
191213
192 const field = await Field.create({
214 const fieldData = {
193215 name: DEMO_FIELD.name,
194216 slug: DEMO_FIELD.slug,
195217 crop: DEMO_FIELD.crop,
@@ -199,7 +221,15 @@ async function syncCatalog(): Promise<void> {
199221 longitude: DEMO_FIELD.longitude,
200222 boundary: JSON.stringify(DEMO_BOUNDARY),
201223 farm_id: farm.id,
202 }) as Record<string, any>
224 } as const
225 if (demoField) {
226 if (demoField.deleted_at != null)
227 await Field.restore(Number(demoField.id))
228 await Field.update(Number(demoField.id), fieldData)
229 }
230 const field = (demoField ? await Field.find(Number(demoField.id)) : await Field.create(fieldData))
231 if (!field)
232 throw new Error('The demonstration field could not be read after publication')
203233
204234 const detections = demoDetections()
205235 const zones = demoZones(detections)
@@ -217,7 +247,9 @@ async function syncCatalog(): Promise<void> {
217247 field_id: field.id,
218248 drone_id: drone.id,
219249 ...publishedImagery,
220 }) as Record<string, any>
250 })
251 if (!mission)
252 throw new Error('The demonstration mission could not be read after publication')
221253
222254 await Detection.createMany(detections.map(d => ({
223255 kind: d.kind,
bun.lockmodified+89-88
Changes to bun.lock
@@ -5,8 +5,9 @@
55 "": {
66 "name": "openfarming",
77 "dependencies": {
8 "stacks": "^0.75.299",
8 "stacks": "^0.75.301",
99 "ts-images": "^0.2.12",
10 "ts-pantry": "0.11.126",
1011 },
1112 "devDependencies": {
1213 "@iconify-json/hugeicons": "^1.2.33",
@@ -22,7 +23,7 @@
2223 "name": "hello-world-fx",
2324 "version": "0.70.163",
2425 "devDependencies": {
25 "stacks": "^0.75.299",
26 "stacks": "^0.75.301",
2627 },
2728 },
2829 },
@@ -46,31 +47,31 @@
4647
4748 "@loghq/stacks": ["@loghq/stacks@0.2.6", "", {}, "sha512-7E4v4nWUDgKuuyFZwa5VZxuRGewMGwAcclCAcm+fm36rGdWnLx6TTdRwMhADlzAYw3nCRyljpnVrViiExQ0UDg=="],
4849
49 "@stacksjs/action-runner": ["@stacksjs/action-runner@0.75.299", "", { "dependencies": { "@stacksjs/enums": "0.75.299", "@stacksjs/types": "0.75.299" } }, "sha512-mb8QMa7Ke1F0DJe8VUGXmNC811hinkuC6ojX/AN4HF0qln6yvqgQlTSs0NFjGEp6tLmiD8vxMotEK6PLfzR4Vg=="],
50 "@stacksjs/action-runner": ["@stacksjs/action-runner@0.75.301", "", { "dependencies": { "@stacksjs/enums": "0.75.301", "@stacksjs/types": "0.75.301" } }, "sha512-y8C1movFiFQcT5DqXlFO9gdrvFfcY0f4bdIpLqHjwJjKyB41qV1oqvlGLpG8NoXgfqN2WriidnKVV7jWyclMDQ=="],
5051
51 "@stacksjs/actions": ["@stacksjs/actions@0.75.299", "", { "dependencies": { "@stacksjs/action-runner": "0.75.299", "@stacksjs/ai": "0.75.299", "@stacksjs/analytics": "0.75.299", "@stacksjs/api": "0.75.299", "@stacksjs/auth": "0.75.299", "@stacksjs/build": "0.75.299", "@stacksjs/bumpx": "^0.2.26", "@stacksjs/bunpress": "^0.2.15", "@stacksjs/cli": "0.75.299", "@stacksjs/cloud": "0.75.299", "@stacksjs/cms": "0.75.299", "@stacksjs/components": "0.2.687", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/desktop-build": "0.75.299", "@stacksjs/dns": "0.75.299", "@stacksjs/enums": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/github": "0.75.299", "@stacksjs/gitit": "^0.2.5", "@stacksjs/i18n": "0.75.299", "@stacksjs/image": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/logsmith": "^0.2.11", "@stacksjs/mobile": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/payments": "0.75.299", "@stacksjs/queue": "0.75.299", "@stacksjs/registry": "0.75.299", "@stacksjs/router": "0.75.299", "@stacksjs/rpx": "^0.11.54", "@stacksjs/scheduler": "0.75.299", "@stacksjs/search-engine": "0.75.299", "@stacksjs/security": "0.75.299", "@stacksjs/server": "0.75.299", "@stacksjs/sites": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/stx": "0.2.687", "@stacksjs/tlsx": "^0.13.19", "@stacksjs/ts-cloud": "^0.16.58", "@stacksjs/ts-md": "^0.1.1", "@stacksjs/tunnel": "0.75.299", "@stacksjs/types": "0.75.299", "@stacksjs/utils": "0.75.299", "@stacksjs/whois": "0.75.299", "bun-plugin-stx": "0.2.687" }, "peerDependencies": { "craft-native": ">=0.0.330", "pickier": "^0.1.75" }, "optionalPeers": ["craft-native", "pickier"] }, "sha512-3b1KohApTPISsU0xl1dXNtBCtNkNox3nIH9dVu/tKXnvlhowy5S6v59gMBeG10ahZX/GFRNKv+6KIC2EYWF7uw=="],
52 "@stacksjs/actions": ["@stacksjs/actions@0.75.301", "", { "dependencies": { "@stacksjs/action-runner": "0.75.301", "@stacksjs/ai": "0.75.301", "@stacksjs/analytics": "0.75.301", "@stacksjs/api": "0.75.301", "@stacksjs/auth": "0.75.301", "@stacksjs/build": "0.75.301", "@stacksjs/bumpx": "^0.2.26", "@stacksjs/bunpress": "^0.2.15", "@stacksjs/cli": "0.75.301", "@stacksjs/cloud": "0.75.301", "@stacksjs/cms": "0.75.301", "@stacksjs/components": "0.2.687", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/desktop-build": "0.75.301", "@stacksjs/dns": "0.75.301", "@stacksjs/enums": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/github": "0.75.301", "@stacksjs/gitit": "^0.2.5", "@stacksjs/i18n": "0.75.301", "@stacksjs/image": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/logsmith": "^0.2.11", "@stacksjs/mobile": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/payments": "0.75.301", "@stacksjs/queue": "0.75.301", "@stacksjs/registry": "0.75.301", "@stacksjs/router": "0.75.301", "@stacksjs/rpx": "^0.11.54", "@stacksjs/scheduler": "0.75.301", "@stacksjs/search-engine": "0.75.301", "@stacksjs/security": "0.75.301", "@stacksjs/server": "0.75.301", "@stacksjs/sites": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/stx": "0.2.687", "@stacksjs/tlsx": "^0.13.19", "@stacksjs/ts-cloud": "^0.16.69", "@stacksjs/ts-md": "^0.1.1", "@stacksjs/tunnel": "0.75.301", "@stacksjs/types": "0.75.301", "@stacksjs/utils": "0.75.301", "@stacksjs/whois": "0.75.301", "bun-plugin-stx": "0.2.687" }, "peerDependencies": { "craft-native": ">=0.0.330", "pickier": "^0.1.75" }, "optionalPeers": ["craft-native", "pickier"] }, "sha512-77vYCBO0ZqU/MmufT49wfSHYQsnhsWCEsf2t2iBDoFzDpfXIqdvTX4qao2qmhscw+0SY6BK82SnYQkokhMtL7Q=="],
5253
53 "@stacksjs/ai": ["@stacksjs/ai@0.75.299", "", { "dependencies": { "@stacksjs/cli": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/router": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/ts-cloud": "^0.16.58" }, "peerDependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.79" }, "optionalPeers": ["@anthropic-ai/claude-agent-sdk"] }, "sha512-AOVYTrC8o7kdb9q8fbg7AGv74rsgqteNIFdam1qOWXUvw+L+IKQGZsV/gPk3cbtwZkLxKxCy0ZwWu0TGhLd4Tg=="],
54 "@stacksjs/ai": ["@stacksjs/ai@0.75.301", "", { "dependencies": { "@stacksjs/cli": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/router": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/ts-cloud": "^0.16.69" }, "peerDependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.79" }, "optionalPeers": ["@anthropic-ai/claude-agent-sdk"] }, "sha512-XGcjI7veaM0xqtVrSckyUeMIhjbbeCTz56lpHFEV3v+BeF3v8pm86Qt2w6m1Tv2FinSZZvUUNnu1XIWM0bq60Q=="],
5455
55 "@stacksjs/alias": ["@stacksjs/alias@0.75.299", "", { "dependencies": { "@stacksjs/path": "0.75.299" } }, "sha512-hA2i3u4hUK9neld7Bo7x4k+Y6tUGILUh5NR3okE12AGfm3hdONGVA5xZAtqx0uK0PShRCxdWqNTdaSHOmoTqvw=="],
56 "@stacksjs/alias": ["@stacksjs/alias@0.75.301", "", { "dependencies": { "@stacksjs/path": "0.75.301" } }, "sha512-4a1QogJ9slNAYqaGA6NltcbmmMl2gFUQ/P/xrr2JGcapcIiPYacudBQ7tefe8CQc8Vj6zP1doJFZFM0Z3IujUQ=="],
5657
57 "@stacksjs/analytics": ["@stacksjs/analytics@0.75.299", "", { "dependencies": { "@stacksjs/database": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/types": "0.75.299" } }, "sha512-AoGv6F+wDl50P0J8fY+fO+xdqc6erphX7x0Afa5lY+WYgv0WeJUETWQ0C4lyrA5OXfkUeFpRw7SebLvnwHo5Nw=="],
58 "@stacksjs/analytics": ["@stacksjs/analytics@0.75.301", "", { "dependencies": { "@stacksjs/database": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/types": "0.75.301" } }, "sha512-b/RrCGEmhReHtmgqOJIfALE74x/fSgIeYLgr2DOQUK8IDqo+/6JIXYntiqEbmiiVMAFj35qXFP3wMD9NJ9B8zg=="],
5859
59 "@stacksjs/api": ["@stacksjs/api@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/path": "0.75.299" }, "peerDependencies": { "@stacksjs/router": "0.75.299" }, "optionalPeers": ["@stacksjs/router"] }, "sha512-M47VZpYI8RAYK/t2thiCgp76gIwq6j6aai5oSlFsoCXHJx1/4qc2Ujp8ZKvs13m1jBawfNffAOXPLseMK6evOA=="],
60 "@stacksjs/api": ["@stacksjs/api@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/path": "0.75.301" }, "peerDependencies": { "@stacksjs/router": "0.75.301" }, "optionalPeers": ["@stacksjs/router"] }, "sha512-qdqbJk20RS3symPIrxajV31WJoaU7AEH1XJ4DYtXrg4e3Whw28fg7czuYR/mY0f58HdwBQq9rF4hFY2Yog+mqg=="],
6061
61 "@stacksjs/arrays": ["@stacksjs/arrays@0.75.299", "", {}, "sha512-rFfsY3mPngqI3wDLUdGhPvpUOuj6CuDkMqoMjyjyt6ZEaF4TKrVKENcZoNemktJDe5/q8s3mVgIJ92H/U67Z3A=="],
62 "@stacksjs/arrays": ["@stacksjs/arrays@0.75.301", "", {}, "sha512-C8xAZ/g3Xq8hjeGfnqft6u/memSNWZvCWBt67sudmQw/AiYpG19ofMJW/FQ4NHi+fCPOT5G8isGSHGzyFsFAyw=="],
6263
63 "@stacksjs/audio": ["@stacksjs/audio@0.75.299", "", { "dependencies": { "@ts-audio/core": "^0.1.2", "ts-video-player": "^0.1.6" } }, "sha512-GDdDzrfk4VZfT8zIgZoWtwv3gsFWBs0+/nNSPz/196EgVyrm4kx6u+/k6sgwGBmx47F/6t2Qgz4eGeTNJlT2ig=="],
64 "@stacksjs/audio": ["@stacksjs/audio@0.75.301", "", { "dependencies": { "@ts-audio/core": "^0.1.2", "ts-video-player": "^0.1.6" } }, "sha512-HywiaafpqFheqX/nF+/yaGEOq8u5LrProo+jyE8RgbF/p2HbySQN4TG8JuKM6SeCBeYJ7ZmmR1nALRA7QpEp2g=="],
6465
65 "@stacksjs/auth": ["@stacksjs/auth@0.75.299", "", { "dependencies": { "@stacksjs/bun-router": "^0.1.24", "@stacksjs/cache": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/email": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/router": "0.75.299", "@stacksjs/security": "0.75.299", "@stacksjs/socials": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/ts-auth": "^0.4.7", "ts-qr-codes": "^0.1.8" } }, "sha512-pQgu2bsN9MXgEpHJv/z2FfI79XuQruadXqrGHN4oJCcFo8i+z8bJm+h4FBs23D4P9+lXWgXCRZhLEh2IGDkj4A=="],
66 "@stacksjs/auth": ["@stacksjs/auth@0.75.301", "", { "dependencies": { "@stacksjs/bun-router": "^0.1.24", "@stacksjs/cache": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/email": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/router": "0.75.301", "@stacksjs/security": "0.75.301", "@stacksjs/socials": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/ts-auth": "^0.4.7", "ts-qr-codes": "^0.1.8" } }, "sha512-+8KWXyOMKs+LU3sYJwHT3j+jTJPqGGbw9+ocw+B1kSd4xoxG70V05eJt4TUee9Pr3djuCmTqxNML0X6WtK5y0A=="],
6667
67 "@stacksjs/browser": ["@stacksjs/browser@0.75.299", "", { "dependencies": { "@stacksjs/composables": "0.75.299", "@stacksjs/datetime": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/stx": "0.2.687", "bun-query-builder": "^0.3.8" }, "peerDependencies": { "@stripe/stripe-js": "^10.0.0" }, "optionalPeers": ["@stripe/stripe-js"] }, "sha512-xMlrC9wv632EeuIfxofetQAuvyVF4fQq6F8cdDIKp9tyLdvTvL3VtWU030xrbsiaJR/q2uyBhQX47QEPV036ug=="],
68 "@stacksjs/browser": ["@stacksjs/browser@0.75.301", "", { "dependencies": { "@stacksjs/composables": "0.75.301", "@stacksjs/datetime": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/stx": "0.2.687", "bun-query-builder": "^0.3.8" }, "peerDependencies": { "@stripe/stripe-js": "^10.0.0" }, "optionalPeers": ["@stripe/stripe-js"] }, "sha512-/hys7EB9jmLn3VAm5VM3qAKz5YREoSZGutC3CxVbcAi5URpKsGYcED5CKpPaxvoOFCM/jo1VGT+k4ewneIm/4A=="],
6869
69 "@stacksjs/browser-extension": ["@stacksjs/browser-extension@0.75.299", "", { "dependencies": { "bun-plugin-stx": "0.2.687", "ts-pantry": "^0.11.126" }, "peerDependencies": { "web-ext": ">=10.7.0" }, "optionalPeers": ["web-ext"] }, "sha512-rhAWNUwD07vFHCgPrs3h+vrBd0HdPjbDXaAfQP5+X4AHYwk5BSK9X5dJBn/H3N29/Xdjc7A+/A87MyTS2niMIA=="],
70 "@stacksjs/browser-extension": ["@stacksjs/browser-extension@0.75.301", "", { "dependencies": { "bun-plugin-stx": "0.2.687", "ts-pantry": "^0.11.126" }, "peerDependencies": { "web-ext": ">=10.7.0" }, "optionalPeers": ["web-ext"] }, "sha512-jl6lmxAqfMDr42iEkZ4echrMjCYiNJR8th7whOZL2Y/8fIDzH1T69ISevfkavalDbt6uR0OBF/7m3zLFt+7G7w=="],
7071
71 "@stacksjs/buddy": ["@stacksjs/buddy@0.75.299", "", { "dependencies": { "@stacksjs/actions": "0.75.299", "@stacksjs/ai": "0.75.299", "@stacksjs/alias": "0.75.299", "@stacksjs/analytics": "0.75.299", "@stacksjs/api": "0.75.299", "@stacksjs/arrays": "0.75.299", "@stacksjs/auth": "0.75.299", "@stacksjs/browser-extension": "0.75.299", "@stacksjs/build": "0.75.299", "@stacksjs/bumpx": "^0.2.26", "@stacksjs/cache": "0.75.299", "@stacksjs/chat": "0.75.299", "@stacksjs/clapp": "^0.2.16", "@stacksjs/cli": "0.75.299", "@stacksjs/cloud": "0.75.299", "@stacksjs/cms": "0.75.299", "@stacksjs/collections": "0.75.299", "@stacksjs/commerce": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/desktop-build": "0.75.299", "@stacksjs/dns": "0.75.299", "@stacksjs/dnsx": "^0.2.3", "@stacksjs/email": "0.75.299", "@stacksjs/enums": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/events": "0.75.299", "@stacksjs/features": "0.75.299", "@stacksjs/git": "0.75.299", "@stacksjs/gitit": "^0.2.5", "@stacksjs/health": "0.75.299", "@stacksjs/httx": "^0.1.10", "@stacksjs/image": "0.75.299", "@stacksjs/lint": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/notifications": "0.75.299", "@stacksjs/objects": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/payments": "0.75.299", "@stacksjs/realtime": "0.75.299", "@stacksjs/router": "0.75.299", "@stacksjs/rpx": "^0.11.54", "@stacksjs/scheduler": "0.75.299", "@stacksjs/search-engine": "0.75.299", "@stacksjs/security": "0.75.299", "@stacksjs/server": "0.75.299", "@stacksjs/sites": "0.75.299", "@stacksjs/skills": "0.75.299", "@stacksjs/socials": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/stx": "0.2.687", "@stacksjs/testing": "0.75.299", "@stacksjs/tinker": "0.75.299", "@stacksjs/tlsx": "^0.13.19", "@stacksjs/ts-cloud": "^0.16.58", "@stacksjs/tunnel": "0.75.299", "@stacksjs/types": "0.75.299", "@stacksjs/ui": "0.75.299", "@stacksjs/utils": "0.75.299", "@stacksjs/validation": "0.75.299", "ajv": "^8.20.0", "ajv-formats": "^3.0.1", "bun-plugin-stx": "0.2.687", "ts-pantry": "^0.11.126" }, "bin": { "bud": "dist/cli.js", "buddy": "dist/cli.js", "stacks": "dist/cli.js" } }, "sha512-ukcj5r6DAx5dbbzuF1TDdwoeOUQSK0jrj8oVP43yHtzT0TrQoarbIBnrpR6yXWijdojVhRv+mz4QI4YN614tlQ=="],
72 "@stacksjs/buddy": ["@stacksjs/buddy@0.75.301", "", { "dependencies": { "@stacksjs/actions": "0.75.301", "@stacksjs/ai": "0.75.301", "@stacksjs/alias": "0.75.301", "@stacksjs/analytics": "0.75.301", "@stacksjs/api": "0.75.301", "@stacksjs/arrays": "0.75.301", "@stacksjs/auth": "0.75.301", "@stacksjs/browser-extension": "0.75.301", "@stacksjs/build": "0.75.301", "@stacksjs/bumpx": "^0.2.26", "@stacksjs/cache": "0.75.301", "@stacksjs/chat": "0.75.301", "@stacksjs/clapp": "^0.2.16", "@stacksjs/cli": "0.75.301", "@stacksjs/cloud": "0.75.301", "@stacksjs/cms": "0.75.301", "@stacksjs/collections": "0.75.301", "@stacksjs/commerce": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/desktop-build": "0.75.301", "@stacksjs/dns": "0.75.301", "@stacksjs/dnsx": "^0.2.3", "@stacksjs/email": "0.75.301", "@stacksjs/enums": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/events": "0.75.301", "@stacksjs/features": "0.75.301", "@stacksjs/git": "0.75.301", "@stacksjs/gitit": "^0.2.5", "@stacksjs/health": "0.75.301", "@stacksjs/httx": "^0.1.10", "@stacksjs/image": "0.75.301", "@stacksjs/lint": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/notifications": "0.75.301", "@stacksjs/objects": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/payments": "0.75.301", "@stacksjs/realtime": "0.75.301", "@stacksjs/router": "0.75.301", "@stacksjs/rpx": "^0.11.54", "@stacksjs/scheduler": "0.75.301", "@stacksjs/search-engine": "0.75.301", "@stacksjs/security": "0.75.301", "@stacksjs/server": "0.75.301", "@stacksjs/sites": "0.75.301", "@stacksjs/skills": "0.75.301", "@stacksjs/socials": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/stx": "0.2.687", "@stacksjs/testing": "0.75.301", "@stacksjs/tinker": "0.75.301", "@stacksjs/tlsx": "^0.13.19", "@stacksjs/ts-cloud": "^0.16.69", "@stacksjs/tunnel": "0.75.301", "@stacksjs/types": "0.75.301", "@stacksjs/ui": "0.75.301", "@stacksjs/utils": "0.75.301", "@stacksjs/validation": "0.75.301", "ajv": "^8.20.0", "ajv-formats": "^3.0.1", "bun-plugin-stx": "0.2.687", "ts-pantry": "^0.11.126" }, "bin": { "bud": "dist/cli.js", "buddy": "dist/cli.js", "stacks": "dist/cli.js" } }, "sha512-lnc80zhuQ2bpkiHU5ifdxxzMBJ9ic3UQ8l6niY74UDisS+wZn1l0F+7snrGnLzghTeWujs3ruwZmzcn1qCI5eA=="],
7273
73 "@stacksjs/build": ["@stacksjs/build@0.75.299", "", { "dependencies": { "@stacksjs/cli": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/storage": "0.75.299", "bun-plugin-dtsx": "^0.11.21" } }, "sha512-5TtfBevZL1rUsKNFvV32djjFiRX5ByrQNJbGDhUVJSTl56smP61dQlZ0Hs3mLg5wdNuxbEh3abtSeqwH2c+8SQ=="],
74 "@stacksjs/build": ["@stacksjs/build@0.75.301", "", { "dependencies": { "@stacksjs/cli": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/storage": "0.75.301", "bun-plugin-dtsx": "^0.11.21" } }, "sha512-7UutuIv/21lGQUBBORcGD7jhANPm+9NzBQ6RGtAXmSFpOXOKgZSpD3HJsI2YK/jC+0h9dK1+/Jpgd6fPQJeRrQ=="],
7475
7576 "@stacksjs/bumpx": ["@stacksjs/bumpx@0.2.27", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0", "@stacksjs/logsmith": "^0.2.6", "bunfig": "^0.15.6" }, "bin": { "bumpx": "./dist/bin/cli.js" } }, "sha512-LOaqknhToQDIey7UwfG9BPZ2CQfK1TfA/mZxpPnxoPKfzTvVWaudKatpw/R3J4+8WuR0V08/olV28lBxI9S7cg=="],
7677
@@ -80,163 +81,163 @@
8081
8182 "@stacksjs/bunpress": ["@stacksjs/bunpress@0.2.25", "", { "dependencies": { "@cwcss/crosswind": "^0.2.16", "@stacksjs/clapp": "^0.2.0", "@stacksjs/stx": "^0.2.550", "@stacksjs/ts-i18n": "^0.1.11", "bunfig": "^0.15.17", "ts-syntax-highlighter": "^0.2.14" }, "peerDependencies": { "@stacksjs/ts-cloud": "^0.7.51" }, "optionalPeers": ["@stacksjs/ts-cloud"], "bin": { "bunpress": "./dist/bin/cli.js" } }, "sha512-4mzXXQlCgMbkFe4Re6jAcKyGE2hSevpPFBbIytBdrrpEhCDl3VR5UH0v6Ei73wh3jkPAtxWBbJu4B7f72nqrsQ=="],
8283
83 "@stacksjs/cache": ["@stacksjs/cache@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/ts-cache": "^0.1.7" } }, "sha512-nozxZLPPZJ8juEtrrxIUI/nNZFARqAc6fukWAgjTlD69MWqza+gFPRHyjRHUdY9lEjl/UYcEq8eyCCBVqp+qrw=="],
84 "@stacksjs/cache": ["@stacksjs/cache@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/ts-cache": "^0.1.7" } }, "sha512-NDuLfPOQQVrdffBR7bjaIPOTIcIc9mS6M7WKMWEpHwUarOrldWQ6V5GZ3UiL5XlUwUe4gOUbxpSa/C06IK+elw=="],
8485
85 "@stacksjs/calendar-api": ["@stacksjs/calendar-api@0.75.299", "", { "dependencies": { "@stacksjs/datetime": "0.75.299", "@stacksjs/stx": "0.2.687" } }, "sha512-R/g2ilKyQ+F+/EPb/LbWuVhDZXZB1sXmU8av4brZm+vWd4cUuoNq/KhvBbnsT2XoBCKTxGU7uFBEmYgDirX7ig=="],
86 "@stacksjs/calendar-api": ["@stacksjs/calendar-api@0.75.301", "", { "dependencies": { "@stacksjs/datetime": "0.75.301", "@stacksjs/stx": "0.2.687" } }, "sha512-/neguF/N3TmVLXTAAJbDg1RI/hrscPqEqX5jT4VbUsN5xwm+Ommn2Wmvn5EH5tVNVLfLJ4nY9VTblUnXs9s3nQ=="],
8687
87 "@stacksjs/charts": ["@stacksjs/charts@0.75.299", "", { "dependencies": { "@ts-charts/format": "^0.2.7", "@ts-charts/scale": "^0.2.7", "@ts-charts/shape": "^0.2.7" } }, "sha512-9C2lY0borTlYgYCkp/SYUWmgYqCzGNLs1epJN2BC9yopYEFnkGx5y8+4jKkP3NumWhGvzlsQUtNEX5YYt6TGoQ=="],
88 "@stacksjs/charts": ["@stacksjs/charts@0.75.301", "", { "dependencies": { "@ts-charts/format": "^0.2.7", "@ts-charts/scale": "^0.2.7", "@ts-charts/shape": "^0.2.7" } }, "sha512-Tjh728cEkkfWb/MRrG7oI+7CHcoXIPBQZ+5O+hqphxGDgo97cHddvNr8pPOQW7i8fUhAnWukS3uI1X44b4jALw=="],
8889
89 "@stacksjs/chat": ["@stacksjs/chat@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/orm": "0.75.299" } }, "sha512-RiWTNgPQpSDAyD7PGdGw/SE+3W3ujhjcYy+dQQTXAJKH0I0W+GdEr/nnbCyLFz4HWlqA+kVmYmmohK+DwIiCRw=="],
90 "@stacksjs/chat": ["@stacksjs/chat@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/orm": "0.75.301" } }, "sha512-/o/1aYB74GMsYhcUHelaxyJfiCDDaScbG4lTj0aNxhbjTKGJ6oNBPRPqZiT2bvJ8ZgdjTLlE8bCVLdTn1QpM2A=="],
9091
9192 "@stacksjs/clapp": ["@stacksjs/clapp@0.2.16", "", {}, "sha512-g/5HUXGxD9QffyPKGdywZODte0DJYwzNhSmrPime1z7TLxWPodJ9IYfIwr2G6Wco+fAQISgaVQUtVf0pUNGV0w=="],
9293
9394 "@stacksjs/clarity": ["@stacksjs/clarity@0.3.33", "", { "dependencies": { "bunfig": "^0.15.6" }, "bin": { "clarity": "./dist/bin/cli.js" } }, "sha512-+5GLKnAI/M/z64UfNLLfQqx/kp+frmRY+NZXYwwGwbrkud/xlsEGDWEExdhqOhqEDMWdb1oafw/ubGAPg1PaFw=="],
9495
95 "@stacksjs/cli": ["@stacksjs/cli@0.75.299", "", { "dependencies": { "@stacksjs/clapp": "^0.2.12", "@stacksjs/collections": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/types": "0.75.299" } }, "sha512-u1TSKzTW1XQypbBLWF3Vhhqq4ouixDs1qSb3wX1k9BBkJoiCD+eK6pC9NJMnOHsce+wFjngIAySXaVEX2lNd4A=="],
96 "@stacksjs/cli": ["@stacksjs/cli@0.75.301", "", { "dependencies": { "@stacksjs/clapp": "^0.2.12", "@stacksjs/collections": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/types": "0.75.301" } }, "sha512-GTHT9KPlclzV7tQHhiptjPQxiaf8eGDuPYymRYntmEKDjTjrPecKR5ltBKUV+AmBSiBQ0Nhd+yiSlNNfNEdWHw=="],
9697
97 "@stacksjs/cloud": ["@stacksjs/cloud@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/ts-cloud": "^0.16.58", "@stacksjs/ts-xml": "^0.1.2" } }, "sha512-JYc1cwd3R6BbA7FrDWPkoxHGWWx91uNnUktsQXek9uDD1rSxBDusnmMD8Bt2PmbxlQy6Q5Fu7Qmu/MWeHI/OFw=="],
98 "@stacksjs/cloud": ["@stacksjs/cloud@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/ts-cloud": "^0.16.69", "@stacksjs/ts-xml": "^0.1.2" } }, "sha512-v9GnvBRg9Ex0ihOcP6Je1lJw6jJ4LOXDofGf350rsQG8ZZ8M8Xu7HH+FneoAimApUloVCxibBx77MCBRAbq7HQ=="],
9899
99 "@stacksjs/cms": ["@stacksjs/cms@0.75.299", "", { "dependencies": { "@stacksjs/database": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/sites": "0.75.299", "@stacksjs/slug": "0.75.299", "@stacksjs/stx": "0.2.687", "@stacksjs/validation": "0.75.299", "ts-medium-editor": "^0.2.0", "ts-slug": "^0.1.2", "ts-spreadsheets": "^0.2.5" } }, "sha512-1C1fBYC4z7YhXgUQ8HTn4J1ZYupsFJYgZ8hmVTml8Zp+Gnb28d1B9wxIP8FCuedsVWL0NwCWk17PG1HF0IfJeQ=="],
100 "@stacksjs/cms": ["@stacksjs/cms@0.75.301", "", { "dependencies": { "@stacksjs/database": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/sites": "0.75.301", "@stacksjs/slug": "0.75.301", "@stacksjs/stx": "0.2.687", "@stacksjs/validation": "0.75.301", "ts-medium-editor": "^0.2.0", "ts-slug": "^0.1.2", "ts-spreadsheets": "^0.2.5" } }, "sha512-yR0IpuaZmA2J/lSnpTpxOWDq3NCg8+RDH/oDMfgu6rbOM2MWp1DaBro0ELbwIVCOVObjYZLbQEABAS2oL3HIVg=="],
100101
101 "@stacksjs/collections": ["@stacksjs/collections@0.75.299", "", { "dependencies": { "ts-collect": "^0.4.3" } }, "sha512-lbJGxOr+Yl969uXIfP671VFsJpdQ9u+RbZyqQrqsLI9aMIdmlrMsFi7DCRsmsFN5vH4soUJX0eznU6p5sipYuw=="],
102 "@stacksjs/collections": ["@stacksjs/collections@0.75.301", "", { "dependencies": { "ts-collect": "^0.4.3" } }, "sha512-/hEut7j4rkKowhTp7FpYZmLOnNfzvNF6uIm6AogWn6Q62UD3RdW4h+3vljEJBO1fMTmbe3JkVpyDdF58GVkO3A=="],
102103
103 "@stacksjs/commerce": ["@stacksjs/commerce@0.75.299", "", { "dependencies": { "@stacksjs/cache": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/events": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/payments": "0.75.299", "@stacksjs/realtime": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/validation": "0.75.299", "ts-spreadsheets": "^0.2.0" } }, "sha512-IARe0K0GWCeto/J/+8JAx1/7imrDB+6ooYehAfOuglZIdBhHg55CGwC0RMJ1u9Ru1Tcv2qci7W4qpdb3rZdjcw=="],
104 "@stacksjs/commerce": ["@stacksjs/commerce@0.75.301", "", { "dependencies": { "@stacksjs/cache": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/events": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/payments": "0.75.301", "@stacksjs/realtime": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/validation": "0.75.301", "ts-spreadsheets": "^0.2.0" } }, "sha512-un6aWkNZ3/O+y5RQui6PWmPhcQp5KNFStBBlbCN2//jQVGVJ7vpthmkpWPGdRxD7V3pS9TAimc1rdvGTtDIR9g=="],
104105
105106 "@stacksjs/components": ["@stacksjs/components@0.2.687", "", { "dependencies": { "@iconify-json/f7": "^1.2.2", "@stacksjs/stx": "0.2.687", "@stacksjs/ts-css": "^0.3.11", "bun-plugin-stx": "0.2.687", "ts-syntax-highlighter": "^0.2.17", "ts-video-player": "^0.1.9" } }, "sha512-sfc3tM0gkX7+8hUoVs6Vy45ljQfdSnYQ+rbDyS66k/IOxsQv1COLM884JvWDy7Wan33jlQ0CKA4qnvgBacSZ6A=="],
106107
107 "@stacksjs/composables": ["@stacksjs/composables@0.75.299", "", { "dependencies": { "@stacksjs/datetime": "0.75.299", "@stacksjs/stx": "0.2.687" } }, "sha512-i0i28pEvIC9ea9mgp7rSaVt57f3D1j5cHCehPLtNjf7nAbQaDiMYTupCJyRcHWsNt1V08HYZ+ZHTFNFLhFIaww=="],
108 "@stacksjs/composables": ["@stacksjs/composables@0.75.301", "", { "dependencies": { "@stacksjs/datetime": "0.75.301", "@stacksjs/stx": "0.2.687" } }, "sha512-IwBkgtDRA9XbVYB46fnF1wY95ixqzavRNESJ9acYCWgBNbx++AQHEex0IZW2ST6Z+6WOh4mBQS17mFIDjWie0Q=="],
108109
109 "@stacksjs/config": ["@stacksjs/config@0.75.299", "", { "dependencies": { "@stacksjs/events": "0.75.299", "@stacksjs/features": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/tunnel": "0.75.299", "ts-pantry": "^0.11.126" } }, "sha512-pySxIvX6zGyPOVtlltF3Yd7HcS6J3jYntgrjzMXVv3t20lQF2v+u7MYXCfu4VuWwrM30/E13smYZi8ROgLA9lQ=="],
110 "@stacksjs/config": ["@stacksjs/config@0.75.301", "", { "dependencies": { "@stacksjs/events": "0.75.301", "@stacksjs/features": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/tunnel": "0.75.301", "ts-pantry": "^0.11.126" } }, "sha512-JmBVO7tm4tIeUi5LNw47GzDdO1NEvgqWkhbd+dPL6oPYma8Cu2AtVqlIRwur9pw2QgQWtAx+CtTGxIj7/t1H3Q=="],
110111
111 "@stacksjs/cron": ["@stacksjs/cron@0.75.299", "", {}, "sha512-DQES/MbeXKMpRVWDxSzSq0USVcqiV0SynO1G74QPEHyceFjqf/z3HzudxeiUeXlli4iz8uJh1qylEh2Y4+/aVA=="],
112 "@stacksjs/cron": ["@stacksjs/cron@0.75.301", "", {}, "sha512-ry3Wh65LF97h3eJA3k0A+pQpe4gTG33h91b2b3hDgJLLxTwjibmxOoteAcpyWDltdkv+gvgAxAQqhQlGqbxlGQ=="],
112113
113 "@stacksjs/database": ["@stacksjs/database@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/faker": "0.75.299", "@stacksjs/features": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/model-meta": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/query-builder": "0.75.299", "@stacksjs/security": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/ts-validation": "^0.5.6", "bun-query-builder": "^0.3.9", "dynamodb-tooling": "^0.3.6" } }, "sha512-3ybn2GhPGJqeoLrxU77Y4bo4tyUmoBwfb9oMpLh9RIbbiGBUwLycmSrVKLXTAZHIKkKJpEqw0AFYPAOdLSmwbw=="],
114 "@stacksjs/database": ["@stacksjs/database@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/faker": "0.75.301", "@stacksjs/features": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/model-meta": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/query-builder": "0.75.301", "@stacksjs/security": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/ts-validation": "^0.5.6", "bun-query-builder": "^0.3.9", "dynamodb-tooling": "^0.3.6" } }, "sha512-ql1oK2eqR0sHWxXUvOM+uE0r09WBOFrtVyLEdJYBrdr3+r+5d+2eRf0UNPVgScKNJ/MEKOCuWTAKDzWrZQ+SQA=="],
114115
115 "@stacksjs/datetime": ["@stacksjs/datetime@0.75.299", "", {}, "sha512-WlsQU8zlJROVgaxhI94R6J+UWifuRPDT22pAmOxkQGywQL7VPHO26so7Sy2C0VxX5O65/njoNVqUPyzq5Cb7ig=="],
116 "@stacksjs/datetime": ["@stacksjs/datetime@0.75.301", "", {}, "sha512-es+io3oLP4bgTXcWTm6EWe07IHdaElNC69511zLhkJjPW92VNQPoPZzPrlA26zPAalim6edv4tb8eS1OU8q2og=="],
116117
117 "@stacksjs/defaults": ["@stacksjs/defaults@0.75.299", "", { "dependencies": { "@iconify-json/f7": "^1.2.2", "@iconify-json/hugeicons": "^1.2.35", "@stacksjs/mobile": "0.75.299", "@stacksjs/sanitizer": "0.2.687", "@stacksjs/stx": "0.2.687", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", "ts-qr-codes": "^0.1.8" } }, "sha512-26y/Loyv5J9yo1nOkrfnSfBBg7QVNSM/x3gxP6KJ4wxy9uk22lwxHQXlBEzHNKnsktbVMdeMCsK7DuQ5c8QNuA=="],
118 "@stacksjs/defaults": ["@stacksjs/defaults@0.75.301", "", { "dependencies": { "@iconify-json/f7": "^1.2.2", "@iconify-json/hugeicons": "^1.2.35", "@stacksjs/mobile": "0.75.301", "@stacksjs/sanitizer": "0.2.687", "@stacksjs/stx": "0.2.687", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", "ts-qr-codes": "^0.1.8" } }, "sha512-Plvbosd6/YNQdsJ5kHbiVFA7NifYZxYgG4GCN0Gr7NTn/W/swz7EPJAscjrDm7fTtxmFFjYJs/WJ3vkAa7NghA=="],
118119
119120 "@stacksjs/desktop": ["@stacksjs/desktop@0.2.687", "", { "dependencies": { "craft-native": ">=0.0.328" } }, "sha512-o5qpyI64AnStCgcZeLijIpiiOYIpn4sbI2IcanzEZECsjRH8mnJTlHRNToOJQp6kr/9FKnYa04Ga7n/mbyJ4LA=="],
120121
121 "@stacksjs/desktop-build": ["@stacksjs/desktop-build@0.75.299", "", { "dependencies": { "craft-native": ">=0.0.330" } }, "sha512-YIoBPV8ENBOFGT2YCVjjiST1/pPhMqHHVWBPqBD64T332oGhp6Kxue5WighgYvOXJVjEs3GcfSZ216SDdxpHag=="],
122 "@stacksjs/desktop-build": ["@stacksjs/desktop-build@0.75.301", "", { "dependencies": { "craft-native": ">=0.0.330" } }, "sha512-OBy9c3ni7k41p2fFHgcfpdblfLpfgzaM2ZCey7CgRy6b2gj9cwPG7nUCo4rEJ5t9QZAcN4r1CrR+7KgoAJBUTA=="],
122123
123 "@stacksjs/dns": ["@stacksjs/dns@0.75.299", "", { "dependencies": { "@stacksjs/action-runner": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/dnsx": "^0.2.3", "@stacksjs/enums": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/ts-cloud": "^0.16.58" } }, "sha512-anAryUs7nfGyUikjAYd37zf+IaHQ+9QB2PhUZX4YwnWPw2bXJO1ZexwLeLsbiTzrI8ss4bLf6+DxYLmO9OcG4w=="],
124 "@stacksjs/dns": ["@stacksjs/dns@0.75.301", "", { "dependencies": { "@stacksjs/action-runner": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/dnsx": "^0.2.3", "@stacksjs/enums": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/ts-cloud": "^0.16.69" } }, "sha512-ST6cm0A3FIPgpCwA2gNHITFhXX0H9QLImu+mvzJ9gBVrXt2fs3AfhNkB/k0LAxDIN1zU7Lro6Daetfcu7/zGOw=="],
124125
125126 "@stacksjs/dnsx": ["@stacksjs/dnsx@0.2.3", "", { "bin": { "dnsx": "./dist/bin/cli.js" } }, "sha512-KoubPLapgNSEOoTJNEL3BV1WIhSHz70Kzyf2i2EM9ZViaNOeHrUOIwG8qRX9D+L/5Njh45LmAG+vwkaJalD1ng=="],
126127
127 "@stacksjs/docs": ["@stacksjs/docs@0.75.299", "", { "dependencies": { "@stacksjs/bunpress": "^0.2.25", "@stacksjs/config": "0.75.299", "@stacksjs/path": "0.75.299" } }, "sha512-Pg5Dv05/6UN3K0gz4YG5AI0UjlCXA7SJNBAB1qVwAD6p/BGUiTLKZJ9H7d6sykZ0Sy18++D4xkrDE1SMAekhXw=="],
128 "@stacksjs/docs": ["@stacksjs/docs@0.75.301", "", { "dependencies": { "@stacksjs/bunpress": "^0.2.25", "@stacksjs/config": "0.75.301", "@stacksjs/path": "0.75.301" } }, "sha512-wDzQdBQPAxJjgnWV/CUdRsytwXw+HGqSfwJuW7fjQ72YO3Hkgh//OzIyXmV4TlEsV2aBVLBnbWPPcbDlV3ZWsg=="],
128129
129130 "@stacksjs/dtsx": ["@stacksjs/dtsx@0.11.21", "", { "dependencies": { "@stacksjs/clapp": "^0.2.16" }, "bin": { "dtsx": "./dist/bin/cli.js" } }, "sha512-H1DyQD1JdnXplHREClZoSDg5iR0OahTkpWm091SQ8pxNth+U3+uMDdZZLKqBRyax82OyQZUxs1XjOTY3tgvFZg=="],
130131
131 "@stacksjs/email": ["@stacksjs/email@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/events": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/mail": "^0.3.11", "@stacksjs/path": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/stx": "0.2.687", "@stacksjs/ts-cloud": "^0.16.58", "@stacksjs/utils": "0.75.299" }, "peerDependencies": { "@stacksjs/queue": "0.75.299" }, "optionalPeers": ["@stacksjs/queue"] }, "sha512-C3xEBPXD2YXSBnODeVDmPYFAmBKIu4IJKSOvVWx0RoZh18Bz8/ojMbXldRzk6VVTtOvzAbbT8zZowQoq2aJaYQ=="],
132 "@stacksjs/email": ["@stacksjs/email@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/events": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/mail": "^0.3.11", "@stacksjs/path": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/stx": "0.2.687", "@stacksjs/ts-cloud": "^0.16.69", "@stacksjs/utils": "0.75.301" }, "peerDependencies": { "@stacksjs/queue": "0.75.301" }, "optionalPeers": ["@stacksjs/queue"] }, "sha512-Ef2HjOun5PXH6n2O+qDUSmV++5/2WxgofpgszsfNusxDVm7qLU4C10pxx5TSd0oeR/Ssq3TlODGCclFmWNxbGg=="],
132133
133 "@stacksjs/enums": ["@stacksjs/enums@0.75.299", "", {}, "sha512-1u/5bEk50orJSrm+hVDZwwrt5kum1kGv1TdN8Nxq/YxwUnDRt6GgA/qHixWFbkM1+gNb4tE3sks8bv5Q+OdqaQ=="],
134 "@stacksjs/enums": ["@stacksjs/enums@0.75.301", "", {}, "sha512-Gv/nrUYPvRyqw7zDmSSwMUO9Ws8QNvbZeI8Ecq5vL6sH2+RoZdk/kuem2LvbslX3VZeArKp6nm1sBHVPTPzArA=="],
134135
135 "@stacksjs/env": ["@stacksjs/env@0.75.299", "", { "dependencies": { "@stacksjs/path": "0.75.299" } }, "sha512-XVgnGTi68mcE1D6i1qfQjFJe8jRPFvn6G4pKYYsSMa1+zNgLZ2umjRbHRpRN6+5S1dObnWQjhUfc7eC3wXRbdw=="],
136 "@stacksjs/env": ["@stacksjs/env@0.75.301", "", { "dependencies": { "@stacksjs/path": "0.75.301" } }, "sha512-7m+U/yo0b9WOHNPw9ZbpeJD1MZbY/KphRVsw6HceS2wU/mwlELjzyoUMD5JCVdS4EGOLznGq8mEw5LbL7xZFUw=="],
136137
137 "@stacksjs/error-handling": ["@stacksjs/error-handling@0.75.299", "", { "dependencies": { "@bughq/sdk": "^0.3.0", "@stacksjs/path": "0.75.299", "@stacksjs/stx": "0.2.687", "@stacksjs/types": "0.75.299", "ts-error-handling": "^0.1.3", "ts-syntax-highlighter": "^0.2.17" } }, "sha512-jjAHWzMuPn7QZ4MCoCE+aJLNSeHQxPECZ9tl1wu4wN9kA1xPUrYSowh0tzTCksVcl71G/oX0t8VYGwRfJLS3gA=="],
138 "@stacksjs/error-handling": ["@stacksjs/error-handling@0.75.301", "", { "dependencies": { "@bughq/sdk": "^0.3.0", "@stacksjs/path": "0.75.301", "@stacksjs/stx": "0.2.687", "@stacksjs/types": "0.75.301", "ts-error-handling": "^0.1.3", "ts-syntax-highlighter": "^0.2.17" } }, "sha512-PaPGi9tCLdnn6AIJY7yMEDdjZ8phVSYou1+WtOaKly5h966j+nvvhFVQdyg/a7oyh+u8pob5BU+3kWZ8MMlySw=="],
138139
139 "@stacksjs/events": ["@stacksjs/events@0.75.299", "", { "dependencies": { "@stacksjs/path": "0.75.299" } }, "sha512-sbCeFPvg+fnnRLaRdM8caOTOUOhRiVCDTasHiQ08i42fHMXrOdiQyV7Gw1x3cLMTpZl+3tnzwuWxHJ/mURWOrA=="],
140 "@stacksjs/events": ["@stacksjs/events@0.75.301", "", { "dependencies": { "@stacksjs/path": "0.75.301" } }, "sha512-N/5YRZzJmVPhQ172XBYsIS8HMQclh2uTM8OfcopFoB5oZpdTuhXobbVQQW73lboHLDz/zSjR5NMLgg5tUZX8uQ=="],
140141
141 "@stacksjs/faker": ["@stacksjs/faker@0.75.299", "", { "dependencies": { "@stacksjs/ts-faker": "^0.1.8" } }, "sha512-T3Qr8rasdgxA+oifuxYiKXTx31lyJVYGkySyN5hXqNdfMwIqzhlFQEmDhmGcNxFfPnPaV/MTOczW5fwmH/thHw=="],
142 "@stacksjs/faker": ["@stacksjs/faker@0.75.301", "", { "dependencies": { "@stacksjs/ts-faker": "^0.1.8" } }, "sha512-7ojyEC2hQLq7mg/POwrJoZO7wqN+yRnAdzT+jhP+mLmogZ3m+DwLGTz+kVx2xB5XhMShqKNhnGBdZIP5hVrtzg=="],
142143
143 "@stacksjs/feature-flags": ["@stacksjs/feature-flags@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299" } }, "sha512-jmqcgKBexOax7BxGSH8YLixKXGHJdPEaGvMd4IhTP98aUWa8aWbfSDQv0kL76MCWfNb7ovklxtyRKklSG4IZsw=="],
144 "@stacksjs/feature-flags": ["@stacksjs/feature-flags@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301" } }, "sha512-1yKmQcxXo9S6vwPN1YIjowae+keZoYp5Nw3Pbs716f9zpLaMQ+e5od0XnFJ9JlXtsX3+nAErymqAKcu3k9drHQ=="],
144145
145 "@stacksjs/features": ["@stacksjs/features@0.75.299", "", { "dependencies": { "@stacksjs/path": "0.75.299" } }, "sha512-QT83i4GRC8mMOxUajSrm26xzZyI/PBar6ri9H3nzeYDOKMd8KJZI+wCgptHd/BFF8vfqYfLEHQ6618h+N6HoXA=="],
146 "@stacksjs/features": ["@stacksjs/features@0.75.301", "", { "dependencies": { "@stacksjs/path": "0.75.301" } }, "sha512-7KgCDmUh5i+tqAqryTBm1I3bcwBROksZJNlHgK5llM5bFIM/ujcEgnDp1usIkNACifNatOtAJozeKx1LerxRMQ=="],
146147
147 "@stacksjs/forms": ["@stacksjs/forms@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/notifications": "0.75.299" } }, "sha512-LmQ+pFTc1u+fj3QsykBqVT8noMkyhJbGyDJ35wkztwMcRZkfWeclRGDrKfpQptupDEPCJ8dvTAXEQwat7qmHpw=="],
148 "@stacksjs/forms": ["@stacksjs/forms@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/notifications": "0.75.301" } }, "sha512-E3n28rr9cEXzixz8lPi1iRo1FhnEjDvkOw4BFMGpXNgk7oCNWQuFJkbdl0PRkXLopmMIFmj7aj6aobp15v7xug=="],
148149
149 "@stacksjs/git": ["@stacksjs/git@0.75.299", "", { "dependencies": { "cz-git": "^1.14.0" } }, "sha512-rvE/T4J0pWLwtgFcInx/Cz+V4ecDKgLeAIQdG1GOAoD7nDTB4dE843o7leb4kxUOgo3OAFr6cN/1IXZld9Zhbw=="],
150 "@stacksjs/git": ["@stacksjs/git@0.75.301", "", { "dependencies": { "cz-git": "^1.14.0" } }, "sha512-LZMhk6kYpHdMotfGurHWXqrI61qK/tpwP9Z83Ho0vXBQ/Xij3hGagcmOf9tviSqyLD1s14MXIxIKbsy7h9/dAw=="],
150151
151 "@stacksjs/github": ["@stacksjs/github@0.75.299", "", {}, "sha512-mnHrwQSVWNHnQdMEPO9x4Av0lweTnux85xJl4b4XJ1KIYDNEvPl2eSwmuMkL2FOzhYoljrKlHUJj/ysJWY+A5g=="],
152 "@stacksjs/github": ["@stacksjs/github@0.75.301", "", {}, "sha512-gxhCB0z/X406hwdYKswIcYDwggcYZWF3wb7sYv4sGq+SpNSIvh8kW+tLjtl584Y/ai7ynA0Ff3YG8mmNpVYD2w=="],
152153
153154 "@stacksjs/gitit": ["@stacksjs/gitit@0.2.5", "", { "bin": { "gitit": "dist/bin/cli.js" } }, "sha512-HI9L1EsWTXG4JxqMlEjujDWovH5UnYqP6Uv9Pll74+vLGEH2OK6FRfarNQgRHBkMyzBx2fjutAHOXrPSCTN8eQ=="],
154155
155156 "@stacksjs/gitlint": ["@stacksjs/gitlint@0.1.8", "", { "hasInstallScript": true, "bin": { "gitlint": "./dist/bin/cli.js" } }, "sha512-lv+Ttwwif0UR0qgRGih8/ePslcrcDLjYybmDOQE7kM2IXoaRZUFh2LhZWHbaICd3ejdGb7MNvY2emiJE7Cs+Wg=="],
156157
157 "@stacksjs/health": ["@stacksjs/health@0.75.299", "", {}, "sha512-EJF6H+2irLF6FnmgG4MpHfQTTRPmRTvHGrHdggEgrHeeUMk9032HqEeVjViGLjQ3x7/n6k0SxCW2yj27S0aF5w=="],
158 "@stacksjs/health": ["@stacksjs/health@0.75.301", "", {}, "sha512-XSCLYsqiAe3UmIT+WWH2Sl1oLg8+ECePzr9DesOO1P0ZM+LDjlViDvuDVRd9d6GXECHEw1z0Is9IZ6KWX6NAcg=="],
158159
159 "@stacksjs/http": ["@stacksjs/http@0.75.299", "", { "dependencies": { "@stacksjs/httx": "^0.1.11" } }, "sha512-VIit9WoF8KIDtl4GIzmJ0IpI6vHe0ChLxuuOusgSA8R0qNFGgDrcLgoEbPcYkiYZvAs/ll0c2lMCvtndBMQC1g=="],
160 "@stacksjs/http": ["@stacksjs/http@0.75.301", "", { "dependencies": { "@stacksjs/httx": "^0.1.11" } }, "sha512-vrhVhtTRs03z6+s18b/KR1uj5N3Q8n5KyTvjNIFe3pVnX723Nickc/7fxaVmVi4+oCe19MMrGRSDh/BsFD8l7g=="],
160161
161162 "@stacksjs/httx": ["@stacksjs/httx@0.1.11", "", { "dependencies": { "ts-error-handling": "^0.1.0" }, "bin": { "httx": "./dist/bin/cli.js", "http": "./dist/bin/cli.js", "https": "./dist/bin/cli.js" } }, "sha512-7Ml5D1NpTl4qadeNNFh0CFXjNnv4rb1+9d2MC159FElVo3SbAGWGpobSnwrjg/SZK10rc9mpeOU3l2LPqvJ9uQ=="],
162163
163 "@stacksjs/i18n": ["@stacksjs/i18n@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/ts-i18n": "^0.1.11" } }, "sha512-dbcIFB0OHQSgeiDFnK/pGRUysKXqtTf5faEoY6XhbRNWJPlv5EEw1mw4YJqDzMZzJvcTLBcEqrjDYpbfXDtnEQ=="],
164 "@stacksjs/i18n": ["@stacksjs/i18n@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/ts-i18n": "^0.1.11" } }, "sha512-OR5P9bqMuQbgXaBe7dIXkKkD0a8uWPr6YexNZEiHkZB6tIBfFXzOkW01tS6AhmmD1nJlY4lXGRouU5bys/+PCA=="],
164165
165 "@stacksjs/image": ["@stacksjs/image@0.75.299", "", { "dependencies": { "@stacksjs/ts-svg": "^0.1.5", "@stacksjs/types": "0.75.299", "ts-images": "^0.2.23" } }, "sha512-scTw42JCX35qDgTAMBLfh+nOjx+SwTncOkvw9vLRWg5SXH1OkEA8ZElYMEFc2m1iSHw2srEv9S90wMqqyeND5Q=="],
166 "@stacksjs/image": ["@stacksjs/image@0.75.301", "", { "dependencies": { "@stacksjs/ts-svg": "^0.1.5", "@stacksjs/types": "0.75.301", "ts-images": "^0.2.23" } }, "sha512-pb6a2uwyd4LHeJnsTGIRjpdu8AX69rPJOLiHBX/OzGudt/qgiiq7p9OpV9nqGw+oHFqj53tKgLRs6Y7aqzgV+g=="],
166167
167 "@stacksjs/lint": ["@stacksjs/lint@0.75.299", "", { "dependencies": { "pickier": "^0.1.77" } }, "sha512-WiqIQRK9fc965PG3kRpjaEONpObwGw+rmQphugt5vcSwpTPFxmRB0QWsrF4W39Bcuu/rw3DdJC2jTEvKuqF3+A=="],
168 "@stacksjs/lint": ["@stacksjs/lint@0.75.301", "", { "dependencies": { "pickier": "^0.1.77" } }, "sha512-AP0lX7z9F5YG8qKA+O/yYU/sKIQH7JOfijIav0vM+3PyUBjf8I2GR/Gw32NpEiaE0OkET5G+RtFLC0eGEaf0qA=="],
168169
169 "@stacksjs/logging": ["@stacksjs/logging@0.75.299", "", { "dependencies": { "@loghq/stacks": "^0.2.6", "@stacksjs/clarity": "^0.3.33", "@stacksjs/config": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/types": "0.75.299" } }, "sha512-AVEJe1PtMy9vj02xgOUUu8ELOLIKG5fWKjMUiyjLS8PUTzAzOKKlKjzlj8gKwDarV0CjhW/6EeC+BYGZfoVlmg=="],
170 "@stacksjs/logging": ["@stacksjs/logging@0.75.301", "", { "dependencies": { "@loghq/stacks": "^0.2.6", "@stacksjs/clarity": "^0.3.33", "@stacksjs/config": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/types": "0.75.301" } }, "sha512-haKF6aifZyKDD/sEZ0iKAUiDstj2hqo1mwcQp6DcKLGGmxftIeSZsKg6yhQSsU54JSxczxYoQyYt+MdMpJb5Ew=="],
170171
171172 "@stacksjs/logsmith": ["@stacksjs/logsmith@0.2.11", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0", "bunfig": "^0.15.6", "pickier": "^0.1.9" }, "bin": { "@stacksjs/logsmith": "./dist/bin/cli.js", "logsmith": "./dist/bin/cli.js" } }, "sha512-wqqAxewpsHVDzpC+IRy+yYyGXGlv1j5GCqYTh8fL7d3LLhnRPN72PEQywM357burtORvdkFHfOzk3Ih1SMvuiw=="],
172173
173174 "@stacksjs/mail": ["@stacksjs/mail@0.3.26", "", {}, "sha512-pwOF08FwykYQ6wGyRXt/f+mhGfdgoTvm5S/coZ+RXjBw4lOE1cL+cO9SaQFvxcpeJTTe+eCDR228vmI0bvRAdw=="],
174175
175 "@stacksjs/mobile": ["@stacksjs/mobile@0.75.299", "", { "dependencies": { "@bughq/sdk": "^0.3.0", "@stacksjs/types": "0.75.299", "craft-native": ">=0.0.330" } }, "sha512-E5dRZfFqA3VPI7JG22Fx7u+YzJVx/vL4ozMKuW+afV9Vb5qIaH92Ym5rT6Zalz/bF5W/VBKBElL5T8/yIgzpkg=="],
176 "@stacksjs/mobile": ["@stacksjs/mobile@0.75.301", "", { "dependencies": { "@bughq/sdk": "^0.3.0", "@stacksjs/types": "0.75.301", "craft-native": ">=0.0.330" } }, "sha512-eYpWiS9g9TcoTMee+b46RMTS3ftP40dgGXV+6iiypGp5+Pfmx5XFh++MDOCvG2DHpVzEtiQmixVQ/LPxGPFIQQ=="],
176177
177 "@stacksjs/model-meta": ["@stacksjs/model-meta@0.75.299", "", { "dependencies": { "@stacksjs/path": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/ts-validation": "^0.5.6", "@stacksjs/types": "0.75.299", "@stacksjs/validation": "0.75.299" } }, "sha512-/059vmpZ4Y2zf2iWiQ7oZswKLu2WEsXbroqPn/3T1t4is6Uk3kOIWdXHnts3+tF6z7gU8N3aQEZ3B3lpJ3IHOQ=="],
178 "@stacksjs/model-meta": ["@stacksjs/model-meta@0.75.301", "", { "dependencies": { "@stacksjs/path": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/ts-validation": "^0.5.6", "@stacksjs/types": "0.75.301", "@stacksjs/validation": "0.75.301" } }, "sha512-c0YO4+uNVxUAcD5Sk4mZw1+JGVIqoj5UwWfJoRWkLWpBBNICG5yEk35Strlc61sC/+D0O909g2dr6c7vCQVB+g=="],
178179
179 "@stacksjs/newsletter": ["@stacksjs/newsletter@0.75.299", "", { "dependencies": { "@stacksjs/database": "0.75.299", "@stacksjs/email": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/queue": "0.75.299" } }, "sha512-y1fiCIJGSABZOhyC5kZ+1MxhOXNAs+b1l9AmF4P9jqd26iChipegE74qNTQRMTRKQ5YL0b/z3Q+svmISin/bVQ=="],
180 "@stacksjs/newsletter": ["@stacksjs/newsletter@0.75.301", "", { "dependencies": { "@stacksjs/database": "0.75.301", "@stacksjs/email": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/queue": "0.75.301" } }, "sha512-2BWl3HQlP3XEs/F7jveb0uU5AYRZIJTO5T1SNvtYvcDOmO7d1Op9anQhMJr6M8K8QsRVkqRZgmChiBCaLMNr9w=="],
180181
181 "@stacksjs/notifications": ["@stacksjs/notifications@0.75.299", "", { "dependencies": { "@stacksjs/chat": "0.75.299", "@stacksjs/cli": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/datetime": "0.75.299", "@stacksjs/email": "0.75.299", "@stacksjs/push": "0.75.299", "@stacksjs/realtime": "0.75.299", "@stacksjs/sms": "0.75.299" } }, "sha512-TZPcvhMihdPpymd/rmBaq6ZTn2vDr+9tPZgme+fZ9zLnyEKGGKrfGvYmYQ99eAawswXiUwTJqxZFrLgf241EOg=="],
182 "@stacksjs/notifications": ["@stacksjs/notifications@0.75.301", "", { "dependencies": { "@stacksjs/chat": "0.75.301", "@stacksjs/cli": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/datetime": "0.75.301", "@stacksjs/email": "0.75.301", "@stacksjs/push": "0.75.301", "@stacksjs/realtime": "0.75.301", "@stacksjs/sms": "0.75.301" } }, "sha512-zgCzaUAdc4keHumW0ES7fuW5N3vggc+ZJCP+wrfFGkwwyB6sZwvibw/Xw6Qw0vhhMcvcWC3q8bKc8zK107OnLw=="],
182183
183 "@stacksjs/objects": ["@stacksjs/objects@0.75.299", "", { "dependencies": { "@stacksjs/utils": "0.75.299", "@stacksjs/validation": "0.75.299" } }, "sha512-k0lKUfU0gDoQycxeLilfqP1UVTioAE7RXpwr0pQFeOBNdgIJUZUjYCkaducgvMUKMYvuxutobA6PWpjXVBg5zA=="],
184 "@stacksjs/objects": ["@stacksjs/objects@0.75.301", "", { "dependencies": { "@stacksjs/utils": "0.75.301", "@stacksjs/validation": "0.75.301" } }, "sha512-1d14UjJWjZzwpEub5wSxNRo0Fx3peKfyy6CAfES+pfPfoe2Y+wepy81Idmgt9ylOs0US4m1CSN3zoXvxCfknog=="],
184185
185 "@stacksjs/orm": ["@stacksjs/orm@0.75.299", "", { "dependencies": { "@stacksjs/cache": "0.75.299", "@stacksjs/cli": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/events": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/model-meta": "0.75.299", "@stacksjs/pagination": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/query-builder": "0.75.299", "@stacksjs/realtime": "0.75.299", "@stacksjs/router": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/ts-validation": "^0.5.6", "@stacksjs/validation": "0.75.299", "bun-query-builder": "^0.3.8" }, "peerDependencies": { "@stacksjs/auth": "0.75.299", "@stacksjs/payments": "0.75.299", "@stacksjs/queue": "0.75.299", "@stacksjs/search-engine": "0.75.299", "stripe": "23.0.0" }, "optionalPeers": ["@stacksjs/auth", "@stacksjs/payments", "@stacksjs/queue", "@stacksjs/search-engine", "stripe"] }, "sha512-IWhkNg9c/MQ416zZdLQFCQvdxmFSfkujPDvTP+pUymAKGdqbNRKnd74dpiATA7/jkwSpQEgyf3EDRDvQBTegNA=="],
186 "@stacksjs/orm": ["@stacksjs/orm@0.75.301", "", { "dependencies": { "@stacksjs/cache": "0.75.301", "@stacksjs/cli": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/events": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/model-meta": "0.75.301", "@stacksjs/pagination": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/query-builder": "0.75.301", "@stacksjs/realtime": "0.75.301", "@stacksjs/router": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/ts-validation": "^0.5.6", "@stacksjs/validation": "0.75.301", "bun-query-builder": "^0.3.8" }, "peerDependencies": { "@stacksjs/auth": "0.75.301", "@stacksjs/payments": "0.75.301", "@stacksjs/queue": "0.75.301", "@stacksjs/search-engine": "0.75.301", "stripe": "23.0.0" }, "optionalPeers": ["@stacksjs/auth", "@stacksjs/payments", "@stacksjs/queue", "@stacksjs/search-engine", "stripe"] }, "sha512-I6bbAobNkL8TG2voPOOYuaK3YrpIHOC7omtrz4AFnRd1XZgr7EoTAsWCQjj7aSZGQJaROH5I94SHZCtSr373zw=="],
186187
187 "@stacksjs/pagination": ["@stacksjs/pagination@0.75.299", "", {}, "sha512-iQFBP0rw7OenuuF+RiD5i/MJPvGfTbw/WN12O79Wm0183cxyfvk3J+4THOdcEqQbmU2S039HzFsIuHXpTD9iHg=="],
188 "@stacksjs/pagination": ["@stacksjs/pagination@0.75.301", "", {}, "sha512-lq0HC49Fv+Wjyq4VDf1YgN5SahqYYtazMFQpARJfvapjJbwH6+M9uydDnXCxD272Jks8NDMBTdsuJmtEkR6MtQ=="],
188189
189 "@stacksjs/path": ["@stacksjs/path@0.75.299", "", {}, "sha512-vYyBpOpkLqqkH/0MN5HOxQR5Kgo8EDFHbY5yHLgDIXkH3Sp2HLbbvmq373wFaRanNO9W7NKJ/bum/rvdZMN4DQ=="],
190 "@stacksjs/path": ["@stacksjs/path@0.75.301", "", {}, "sha512-eJ+OTn0CuEZMrnYM9kxBGepM3sRcVmL37rlHagORrv5sPcD7c7nInWDi9Ku97yEqEMS6bTcW4e4tmAP6c3kOGw=="],
190191
191 "@stacksjs/payments": ["@stacksjs/payments@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/types": "0.75.299" }, "peerDependencies": { "@stripe/stripe-js": "^10.0.0", "stripe": "23.0.0" }, "optionalPeers": ["@stripe/stripe-js", "stripe"] }, "sha512-l6HFHU+Bu8tPtzYDMZiXQTTK9sN7cYGnCqEv3aT1v2w8pagPG9nZoCux6xsujALN8aGzFr50rjwETDN9r/aDVA=="],
192 "@stacksjs/payments": ["@stacksjs/payments@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/types": "0.75.301" }, "peerDependencies": { "@stripe/stripe-js": "^10.0.0", "stripe": "23.0.0" }, "optionalPeers": ["@stripe/stripe-js", "stripe"] }, "sha512-RA2DOVINWSs4R2AJ1dW1JDtjAxmAWopbRWpnWBj2Fkx2VOM5QhCn9X3Zq4KbQmubIzr8PDQTVmwb5gUP5EgIMQ=="],
192193
193 "@stacksjs/push": ["@stacksjs/push@0.75.299", "", { "dependencies": { "@stacksjs/cli": "0.75.299", "@stacksjs/config": "0.75.299" } }, "sha512-xzKlRsu3AWi8j+uN8FCupMgc8B8jOD/DAIxbflMTdeSIs9rhenbLOuq4kLqSkD727pqRLOz81Vj5l35SJ4qAJQ=="],
194 "@stacksjs/push": ["@stacksjs/push@0.75.301", "", { "dependencies": { "@stacksjs/cli": "0.75.301", "@stacksjs/config": "0.75.301" } }, "sha512-tHc/VCQZpHnkO3Hr3Ph3Qk9HtnqUfArDKpqJyGWwrJBj61wbbLa1HxLCnc/pRrXn0Ijb6VqKqxuytjGhU20jeg=="],
194195
195 "@stacksjs/query-builder": ["@stacksjs/query-builder@0.75.299", "", { "dependencies": { "bun-query-builder": "^0.3.17" } }, "sha512-MQnB5uLOrAon4ZFnwvQ+msw1rz0jGCYGh13eHhpyxrusftXKJJ5a0Mye0SVYA9cLgEMzCf3n8loLJLiFG2bTNQ=="],
196 "@stacksjs/query-builder": ["@stacksjs/query-builder@0.75.301", "", { "dependencies": { "bun-query-builder": "^0.3.17" } }, "sha512-c18fWCET0bviNFJFRgnrmy3PgmG4OO5RPod0YDwY/jS8MjhA+8bxPijadHUYxczzb99XOrsZIJl2ufgTWbUMAA=="],
196197
197 "@stacksjs/queue": ["@stacksjs/queue@0.75.299", "", { "dependencies": { "@stacksjs/action-runner": "0.75.299", "@stacksjs/bun-queue": "^0.1.8", "@stacksjs/cache": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/cron": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/path": "0.75.299" }, "peerDependencies": { "@stacksjs/email": "0.75.299", "@stacksjs/router": "0.75.299" }, "optionalPeers": ["@stacksjs/email", "@stacksjs/router"] }, "sha512-egDQDEIV896+1/OkVJXfwdT7Xmr7WWIOmbuA1EsdpcHrpQGret3sYieDeWLluwnRlsUD0RpCpw7brThuH0oQqg=="],
198 "@stacksjs/queue": ["@stacksjs/queue@0.75.301", "", { "dependencies": { "@stacksjs/action-runner": "0.75.301", "@stacksjs/bun-queue": "^0.1.8", "@stacksjs/cache": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/cron": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/path": "0.75.301" }, "peerDependencies": { "@stacksjs/email": "0.75.301", "@stacksjs/router": "0.75.301" }, "optionalPeers": ["@stacksjs/email", "@stacksjs/router"] }, "sha512-K76h82jEq+gAXNGW7rERmhUyLdybvOzzrlu/bsiVgTjnOP/zGSvADyfVwUhpvdxD3QcMFwEpv0XReTZ19KB7jQ=="],
198199
199 "@stacksjs/realtime": ["@stacksjs/realtime@0.75.299", "", { "dependencies": { "@stacksjs/logging": "0.75.299", "@stacksjs/path": "0.75.299", "ts-broadcasting": "^0.0.11" } }, "sha512-DCeCgL9Av/ocnbFHioyCy2jU1bKFPLchhAGTBRSopgmkVHj/u8k7npeTOXmh+IItbaAJOavtjsNlYgVbXoMN6A=="],
200 "@stacksjs/realtime": ["@stacksjs/realtime@0.75.301", "", { "dependencies": { "@stacksjs/logging": "0.75.301", "@stacksjs/path": "0.75.301", "ts-broadcasting": "^0.0.11" } }, "sha512-9SkC6untCdeZxAHwiGbIfMP/N/E51vxBGHa9//vsFPLTfMd5f5RmgmCkeUc1Khb0hBD5vE/FzxN3ZR6Uc0RshQ=="],
200201
201 "@stacksjs/registry": ["@stacksjs/registry@0.75.299", "", { "dependencies": { "@stacksjs/types": "0.75.299" } }, "sha512-FRcgM8WstShnpKjP84Of3Ni7nVh+EdKggVQjw0S/SzVvPJw4DWJ2bZbDSMPkIPftxysOJI7oO9vUVbZKZfVcjg=="],
202 "@stacksjs/registry": ["@stacksjs/registry@0.75.301", "", { "dependencies": { "@stacksjs/types": "0.75.301" } }, "sha512-wynr9FJR1XN/2hqmPT4Soy8z8u+Rciv5vzP/rGgrf+cPlpg3uF3Wcxhp3nNDESXkYxtn0IyPi7Og/lj2V/lBsQ=="],
202203
203 "@stacksjs/repl": ["@stacksjs/repl@0.75.299", "", { "dependencies": { "@stacksjs/tinker": "0.75.299" } }, "sha512-JtcnY7Cfx2rh+0BwN9SUG83WHGkQNHuhAC/voUl30OAtkuXpFiPbMhMNjH4LC1bHYKMsSDGoeKzd21Icup4A9g=="],
204 "@stacksjs/repl": ["@stacksjs/repl@0.75.301", "", { "dependencies": { "@stacksjs/tinker": "0.75.301" } }, "sha512-kIDLi81Gz6fCKQQb5110qEoHqOC/6AdtGg8+bDuV9sf5yMOHo6wPQDmSEX9fETeqYKtn44D2zxMuPoMFJLd++g=="],
204205
205 "@stacksjs/router": ["@stacksjs/router@0.75.299", "", { "dependencies": { "@stacksjs/bun-router": "^0.1.24", "@stacksjs/cache": "0.75.299", "@stacksjs/collections": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/pagination": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/security": "0.75.299", "@stacksjs/storage": "0.75.299", "ts-rate-limiter": "^0.4.10" }, "peerDependencies": { "@stacksjs/api": "0.75.299", "@stacksjs/auth": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/validation": "0.75.299" }, "optionalPeers": ["@stacksjs/api", "@stacksjs/auth", "@stacksjs/database", "@stacksjs/validation"] }, "sha512-GHiVu6dKDe+3JsorAdPsYGfk5pbNxgPmSJ1D0PH3puxc1PhYYOxiWvnh8zSElJMrLnAwdGNtNmsa4YGGOJBt0Q=="],
206 "@stacksjs/router": ["@stacksjs/router@0.75.301", "", { "dependencies": { "@stacksjs/bun-router": "^0.1.24", "@stacksjs/cache": "0.75.301", "@stacksjs/collections": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/pagination": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/security": "0.75.301", "@stacksjs/storage": "0.75.301", "ts-rate-limiter": "^0.4.10" }, "peerDependencies": { "@stacksjs/api": "0.75.301", "@stacksjs/auth": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/validation": "0.75.301" }, "optionalPeers": ["@stacksjs/api", "@stacksjs/auth", "@stacksjs/database", "@stacksjs/validation"] }, "sha512-FR1fm8XahF4E0s4NgY/ztjVb3tXkuDeBfD0MXZB0AF/w4exo7APlojb4d0fN+4GGb3X57zXgQREz2X49tU9nUg=="],
206207
207208 "@stacksjs/rpx": ["@stacksjs/rpx@0.11.54", "", { "dependencies": { "@stacksjs/clapp": "^0.2.10", "@stacksjs/tlsx": "^0.13.19", "ts-images": "^0.2.17" }, "bin": { "rpx": "./dist/bin/cli.js", "reverse-proxy": "./dist/bin/cli.js" } }, "sha512-3njfy0BYCpof1rkuY4slGmHRggLWlJdrnUJMNoou6kfBqXNvm8ANqXgiL/bIlQeIWwidqoo1IOjgPcB/EozNog=="],
208209
209210 "@stacksjs/sanitizer": ["@stacksjs/sanitizer@0.2.687", "", {}, "sha512-S4JdOjW94qtmyiStZ53Q2xmIIkDxw2r0Eqv/PgXi9WcED0wWc/83TbIncSXeRU9NptKAhAw3o4xU1GpofXmXFw=="],
210211
211 "@stacksjs/scheduler": ["@stacksjs/scheduler@0.75.299", "", { "dependencies": { "@stacksjs/action-runner": "0.75.299", "@stacksjs/cli": "0.75.299", "@stacksjs/cron": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/notifications": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/queue": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/types": "0.75.299" } }, "sha512-JYUbYamtF7JapAfLh65Kk6KVyXLGE+X0sABBWM6KgqZi1rQVxELYrSP/+gEKD5Ltil0yl+yWO3TPAq0cEE63Tw=="],
212 "@stacksjs/scheduler": ["@stacksjs/scheduler@0.75.301", "", { "dependencies": { "@stacksjs/action-runner": "0.75.301", "@stacksjs/cli": "0.75.301", "@stacksjs/cron": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/notifications": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/queue": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/types": "0.75.301" } }, "sha512-NBZc7FXAJb3Jx+DS90a39UFRM/m5FLlPS4Kvp1qNt9U+pH3J1xgZdnoQ4tcfRJY6AAIVibdIhEcfhWqN498/8g=="],
212213
213 "@stacksjs/search-engine": ["@stacksjs/search-engine@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299" }, "peerDependencies": { "meilisearch": "^0.62.0" }, "optionalPeers": ["meilisearch"] }, "sha512-d5Zp6PpqP7wj+4gk8Zrvbkw05segcNHMupoEmpkG7GaChRBvqcbSvwK22BoHSpdVfZAUYzhmHkUd6fOh8n+gLw=="],
214 "@stacksjs/search-engine": ["@stacksjs/search-engine@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301" }, "peerDependencies": { "meilisearch": "^0.62.0" }, "optionalPeers": ["meilisearch"] }, "sha512-f19ANZWCFYWXbGJ1rUwU+02oP93x4n4i+G+Jli3qjEYwl/tbYFfXqUYWDzN1EoxQRl3VacBYqMrRyV9SmclqdA=="],
214215
215 "@stacksjs/security": ["@stacksjs/security@0.75.299", "", { "dependencies": { "@stacksjs/config": "0.75.299", "ts-security-crypto": "0.0.2" } }, "sha512-2Nhz8coD4YjvgZ4AeeTob0I2bs47U+mqtGHReVJlbBl+PgFJGbxk1uSTkdc6Jgam1Melie/7opYhkQk15OG+UQ=="],
216 "@stacksjs/security": ["@stacksjs/security@0.75.301", "", { "dependencies": { "@stacksjs/config": "0.75.301", "ts-security-crypto": "0.0.2" } }, "sha512-duDtQF1AQX+ifaEKaOeh6c5sK5fl1GJCYAG38A9Wj+hzuq/HRiaaV6zGJInAC0s81KDOgciE4Cw+3MMkbCl/NA=="],
216217
217 "@stacksjs/server": ["@stacksjs/server@0.75.299", "", { "dependencies": { "@stacksjs/auth": "0.75.299", "@stacksjs/bun-router": "^0.1.24", "@stacksjs/config": "0.75.299", "@stacksjs/events": "0.75.299", "@stacksjs/i18n": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/payments": "0.75.299", "@stacksjs/router": "0.75.299", "@stacksjs/storage": "0.75.299", "bun-plugin-auto-imports": "^0.4.4" } }, "sha512-NIlTu/lEJPlak5po5a9Kt/+ywvx9b3u/i9IEalxAJFERX6W+Cn04089Wc2BagLx/rrIX+KVJzn8ilXEavOGdww=="],
218 "@stacksjs/server": ["@stacksjs/server@0.75.301", "", { "dependencies": { "@stacksjs/auth": "0.75.301", "@stacksjs/bun-router": "^0.1.24", "@stacksjs/config": "0.75.301", "@stacksjs/events": "0.75.301", "@stacksjs/i18n": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/payments": "0.75.301", "@stacksjs/router": "0.75.301", "@stacksjs/storage": "0.75.301", "bun-plugin-auto-imports": "^0.4.4" } }, "sha512-y6GwJ+sX9/fnnw46T5IEe4gwpOo5m7jrISnwFA1E7F+pdUHiIGMieyk1wUHWddx+7A1yPQhGG5Mhqllw6YBVsg=="],
218219
219 "@stacksjs/shell": ["@stacksjs/shell@0.75.299", "", {}, "sha512-QbQusoYwjBQBWQuGMSfbnbELqzQNx9ERFSHpUBpMG+qwnqFld6AfivX0/vU5Y5Y/vo0ot/9KmhvGZDJ/2uIbtw=="],
220 "@stacksjs/shell": ["@stacksjs/shell@0.75.301", "", {}, "sha512-AsjMPTeJqQaJSCuYS8RI5PSKyWNIFYVCKIXUFYpg29GvBv0VTV4QY1pl8+2mcGE/sgwc7nWab+LzZqBGP2JzLQ=="],
220221
221 "@stacksjs/sites": ["@stacksjs/sites@0.75.299", "", { "dependencies": { "@stacksjs/auth": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/router": "0.75.299" }, "peerDependencies": { "@stacksjs/cms": "0.75.299" }, "optionalPeers": ["@stacksjs/cms"] }, "sha512-w+Tk/wJ4MycArWpT/CQ1HW/8tE/8nNxbMsDVgPjMtsmwe1ypcAXVg6vNXprqfy4wqYDozasAyvRfRPl5nIoJ0g=="],
222 "@stacksjs/sites": ["@stacksjs/sites@0.75.301", "", { "dependencies": { "@stacksjs/auth": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/router": "0.75.301" }, "peerDependencies": { "@stacksjs/cms": "0.75.301" }, "optionalPeers": ["@stacksjs/cms"] }, "sha512-6eTIead3ZdYIpNnS65S+um+Ai7Cp+nh8x4MioeHOQl+T5Kwk/lC862Ju+qFJTwLoijmbJR2sjZX1Wu6YN6GWuw=="],
222223
223 "@stacksjs/skills": ["@stacksjs/skills@0.75.299", "", { "dependencies": { "@stacksjs/path": "0.75.299", "@stacksjs/storage": "0.75.299" } }, "sha512-dsTqmihPSqDBbSgVsOWW9xcKDkKgdQWQoNhbbh9Moy0DULWVEwkiH0QnOHUzZXjNBmG/cWjl6qGpWq2r2E3osw=="],
224 "@stacksjs/skills": ["@stacksjs/skills@0.75.301", "", { "dependencies": { "@stacksjs/path": "0.75.301", "@stacksjs/storage": "0.75.301" } }, "sha512-hRuQJTGumzG+k4fjKGT8FbAJdTRdGEkR5vwRBx9cb7dm+Lr6dWGI9jyHUCfYcz09p6702LxalWJqGJISBFD7MQ=="],
224225
225 "@stacksjs/slug": ["@stacksjs/slug@0.75.299", "", { "dependencies": { "@stacksjs/database": "0.75.299", "ts-slug": "^0.1.0" } }, "sha512-XzxzFETgYhip82SdX2BDRnVnFTlrHRhgcGzB5ZjGbuON/w2YbqvnvXQdqjgj0TV2k4SIGl+K7PtHWUm+tzxTKg=="],
226 "@stacksjs/slug": ["@stacksjs/slug@0.75.301", "", { "dependencies": { "@stacksjs/database": "0.75.301", "ts-slug": "^0.1.0" } }, "sha512-Snpht/rM+yOu2MXQNsYdG85nqG2lmlMck2t1+w33fyDRHBbDj5Z0Z3dC+7LksjoG4rSjRiZCd4CE2uhu3UVrqQ=="],
226227
227 "@stacksjs/sms": ["@stacksjs/sms@0.75.299", "", { "dependencies": { "@stacksjs/database": "0.75.299" } }, "sha512-9jVS4NxxFO+XZ06tNiy0TVi51bytz88pE/XqlQhHjRWHlNN5Hi0ZLwZ8mQmPzuYBTmfB0auQr/I0I3dYEjhr9Q=="],
228 "@stacksjs/sms": ["@stacksjs/sms@0.75.301", "", { "dependencies": { "@stacksjs/database": "0.75.301" } }, "sha512-IwqimvH+lGIANPU6XIXPmeuzT3ormIqOeTJqGCAqHtRyLWUR6jMO3Zet/pjqRx94DmnJIBKJZJKCKUJN1zr+nw=="],
228229
229 "@stacksjs/socials": ["@stacksjs/socials@0.75.299", "", { "dependencies": { "@stacksjs/api": "0.75.299", "@stacksjs/composables": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299" } }, "sha512-g4/dIIYQ4QP/5vZ7v0QYcWCMMOzVpXPAWLyAmKLhLzEpfbiZp+r7HMAUwZj2M5N9MF5iO0QSV6+hVBvWWo/KEw=="],
230 "@stacksjs/socials": ["@stacksjs/socials@0.75.301", "", { "dependencies": { "@stacksjs/api": "0.75.301", "@stacksjs/composables": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301" } }, "sha512-/s0REUajiaD1NodLQmMOVNIFZ8rUNSF826w1or/yL4LxMbLYtKUVQPKW/Z+6JfUpmebdZFWGqpD9hgF91xobjQ=="],
230231
231 "@stacksjs/storage": ["@stacksjs/storage@0.75.299", "", { "dependencies": { "@stacksjs/arrays": "0.75.299", "@stacksjs/cli": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/ts-cloud": "^0.16.58", "@stacksjs/ts-xml": "^0.1.0", "ts-images": "^0.2.23" } }, "sha512-XWtqI/riTB6gQAbZKa9NkhBO62KO8/8rVMVdPL6AfGonKQpKn7eULieXUMbe7xUcAuohoip7qYkHFlCjNb0uZQ=="],
232 "@stacksjs/storage": ["@stacksjs/storage@0.75.301", "", { "dependencies": { "@stacksjs/arrays": "0.75.301", "@stacksjs/cli": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/ts-cloud": "^0.16.69", "@stacksjs/ts-xml": "^0.1.0", "ts-images": "^0.2.23" } }, "sha512-IS/jvWl69urizvR6CAmKPNW2GCIZGRUTRSUzDCBV+cpPTnH7QM0aFyrYEjrIk1yWvc5uSn+TIHZt5H93X6KYBA=="],
232233
233 "@stacksjs/strings": ["@stacksjs/strings@0.75.299", "", {}, "sha512-Y/YAM7BubHi9kubRUAknpa++4MPcqYoOi0fCEeh0quT15QDISKwK8I3d0nj5MuXe0lwnaxqlsF+kiyqQynCXLQ=="],
234 "@stacksjs/strings": ["@stacksjs/strings@0.75.301", "", {}, "sha512-SsWsr30HOUZ19GoVfOu1UjwjyDOsnKZ2Dn9rGG+bnWSkfvnfh1Psigf6aHJFmPOedRw2Hwuww1SDgIiGoMBm3A=="],
234235
235236 "@stacksjs/stx": ["@stacksjs/stx@0.2.687", "", { "dependencies": { "@stacksjs/clapp": "^0.2.16", "@stacksjs/desktop": "0.2.687", "@stacksjs/sanitizer": "0.2.687", "@stacksjs/ts-css": "^0.3.11", "@stacksjs/ts-i18n": "^0.1.11", "bun-plugin-stx": "0.2.687", "bunfig": "^0.15.21", "stx-router": "0.2.687", "ts-broadcasting": "^0.0.11", "ts-images": "^0.2.22", "ts-syntax-highlighter": "^0.2.1" }, "bin": { "stx": "./dist/cli.js" } }, "sha512-P1BeSogZivooniK360mhdsrgwTYZbfr4NX3OKu3nrtCSg5zah/h7PjbY9bA+kUAjhyOnmoinaN4Neo6MWu9Piw=="],
236237
237 "@stacksjs/testing": ["@stacksjs/testing@0.75.299", "", { "dependencies": { "@stacksjs/auth": "0.75.299", "@stacksjs/cache": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/email": "0.75.299", "@stacksjs/events": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/router": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/ts-cloud": "^0.16.58", "very-happy-dom": "^0.3.5" } }, "sha512-SqzpNyR6V3O3zk9UMIadWSBdhXoMC7pPkbwZPB9a/F7wdqXemQrgO8rPE/B5aG8+CQh0IeaDwhyLw75QdP5n/w=="],
238 "@stacksjs/testing": ["@stacksjs/testing@0.75.301", "", { "dependencies": { "@stacksjs/auth": "0.75.301", "@stacksjs/cache": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/email": "0.75.301", "@stacksjs/events": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/router": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/ts-cloud": "^0.16.69", "very-happy-dom": "^0.3.5" } }, "sha512-Sz/NqPDh2HlioYHCtiNT0Y6/7LscLU/aAOE4/s1qOgG409kQzPX1ZYqtcYROuAiIhy6A756q7UuE4WsvDsvkRQ=="],
238239
239 "@stacksjs/tinker": ["@stacksjs/tinker@0.75.299", "", {}, "sha512-gxeWeBZJe16A4LNE7HThRzc589MeRxHHSjr3rhGa4qdT55vHEW6ONxBNMRUwQf5/toZVwrTvB24ozyr6/H6yGg=="],
240 "@stacksjs/tinker": ["@stacksjs/tinker@0.75.301", "", {}, "sha512-dV/QLmEdWFiWmXqxwo+Ri/57x6nosu9Sasid6CtGEnMPlXrZeMEDZmNIHg/h84ndNTF91teoEicOnIv4t85zNA=="],
240241
241242 "@stacksjs/tlsx": ["@stacksjs/tlsx@0.13.19", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0" }, "bin": { "tlsx": "./dist/bin/cli.js" } }, "sha512-bgVYWBolcbbTSDk/quZiYWfz3qBZiHl1fp9pqTYaeDHXIHxylRfxDFB3bz7mnEmIYSFq9AXilRNkV401uUSGSw=="],
242243
@@ -272,19 +273,19 @@
272273
273274 "@stacksjs/ts-xml": ["@stacksjs/ts-xml@0.1.2", "", {}, "sha512-G20EuKCmpwWwnXfFlX0kxCXnJ6ocTgBl8lcHkOzmomC8L/Ld+UKeNLlvOQf9ArnS7/SHUQ2+fZpM0t6lhwoyPw=="],
274275
275 "@stacksjs/tunnel": ["@stacksjs/tunnel@0.75.299", "", { "dependencies": { "localtunnels": "^0.2.13" } }, "sha512-2aak22ockinwVxEQLjA6hV4K6kYrbyr6FtXzaLCutdtLFfSSvyFOK6Om+A4fJJfmuZAF6dhpjNdNbjcRu5jg0Q=="],
276 "@stacksjs/tunnel": ["@stacksjs/tunnel@0.75.301", "", { "dependencies": { "localtunnels": "^0.2.13" } }, "sha512-9Cbk6ootxkmEOuZe4YvYKh59m1VSb+AZKE/2PXj/7NSJDZ1ze4hZKHT6ne47QBlMrhsE/fDB34tp/iu6k0vsfQ=="],
276277
277 "@stacksjs/types": ["@stacksjs/types@0.75.299", "", { "dependencies": { "@stacksjs/bunpress": "^0.2.15", "@stacksjs/clapp": "^0.2.12", "@stacksjs/events": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/stx": "0.2.687", "@stacksjs/ts-validation": "^0.5.6", "bun-query-builder": "^0.3.8" }, "peerDependencies": { "meilisearch": "^0.62.0" }, "optionalPeers": ["meilisearch"] }, "sha512-A451yceSx5bhXUkyXWWudruDdeIYJTxkLBpDJB/flyFMnW1F45+cAFXl/ApX+sSKyzKmU5S4RU/gR14jqhCarQ=="],
278 "@stacksjs/types": ["@stacksjs/types@0.75.301", "", { "dependencies": { "@stacksjs/bunpress": "^0.2.15", "@stacksjs/clapp": "^0.2.12", "@stacksjs/events": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/stx": "0.2.687", "@stacksjs/ts-validation": "^0.5.6", "bun-query-builder": "^0.3.8" }, "peerDependencies": { "meilisearch": "^0.62.0" }, "optionalPeers": ["meilisearch"] }, "sha512-2KCK0IrocpHCSTHmXZla44YnLUJUVs4zA5m818+utr9gqdwGMkisqh1LahMsxjV6Bo37jYSbOOtblgKaB3829A=="],
278279
279 "@stacksjs/ui": ["@stacksjs/ui@0.75.299", "", { "dependencies": { "@stacksjs/components": "0.2.687", "@stacksjs/config": "0.75.299", "@stacksjs/ts-css": "^0.3.18" } }, "sha512-YcO3dN11/GrSlIWhVxiXZgUHatW4FQNE95MHxRvp/TtXMCfrrfgNpbUQXbvLmXfMnOXM+r8d4/RCqqRK8Cq5hw=="],
280 "@stacksjs/ui": ["@stacksjs/ui@0.75.301", "", { "dependencies": { "@stacksjs/components": "0.2.687", "@stacksjs/config": "0.75.301", "@stacksjs/ts-css": "^0.3.18" } }, "sha512-immBHO1wby8Zbope7qaUPap5Ec3S1LzfQ/XdOe5a9M+xIdgATsSxG/EB+Pg46XvBwGkAcDn2CAc1SwqNMEkahw=="],
280281
281 "@stacksjs/utils": ["@stacksjs/utils@0.75.299", "", { "dependencies": { "@stacksjs/browser": "0.75.299", "@stacksjs/cli": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/enums": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/types": "0.75.299" } }, "sha512-0dcJWwiWpzrQ50AHc73mWj67GUa6T6WucgTQvvg41fWKeN1sTVFNoqGf2R6f3up1GEcafZK+SrJjRD4X9EmFrg=="],
282 "@stacksjs/utils": ["@stacksjs/utils@0.75.301", "", { "dependencies": { "@stacksjs/browser": "0.75.301", "@stacksjs/cli": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/enums": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/types": "0.75.301" } }, "sha512-Qqi6RJ3iCzYJCHpkLFzKDbw7tWJyg/q51YXd1O7q39T45nURxtUjc0svYQ17x5eirWGC0pLRgQbF4bg8QHCo+Q=="],
282283
283 "@stacksjs/validation": ["@stacksjs/validation@0.75.299", "", { "dependencies": { "@stacksjs/error-handling": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/ts-validation": "^0.5.6", "@stacksjs/types": "0.75.299", "@stacksjs/utils": "0.75.299" }, "peerDependencies": { "@stacksjs/database": "0.75.299" }, "optionalPeers": ["@stacksjs/database"] }, "sha512-cWP/ktdF/BLX8Ec6AZzasYhU65b4oOGNJ4nvyfpXxiU+rxCHxJgLQTB4bQprwJS/XrNxBJLWfkilIispHOzfTw=="],
284 "@stacksjs/validation": ["@stacksjs/validation@0.75.301", "", { "dependencies": { "@stacksjs/error-handling": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/ts-validation": "^0.5.6", "@stacksjs/types": "0.75.301", "@stacksjs/utils": "0.75.301" }, "peerDependencies": { "@stacksjs/database": "0.75.301" }, "optionalPeers": ["@stacksjs/database"] }, "sha512-FYR7E25eFZd/DpCd079MOoPuu7PNXLmrGwjVHgHtgYXdc6VfP6R+nfBdrVvHJw1oVvydXtTXeDHvYYhqJkMziQ=="],
284285
285 "@stacksjs/video": ["@stacksjs/video@0.75.299", "", { "dependencies": { "@ts-videos/mp4": "^0.1.2", "@ts-videos/webm": "^0.1.2", "ts-video-player": "^0.1.3", "ts-videos": "^0.1.2" } }, "sha512-WovsnERkIpQTBS8IuGcUZAHO2QxEmoOxB+HkeVCeg/gaEil+TFno9j4FWw1j2LeHvHQFSAstN8BGSDji/KLC6w=="],
286 "@stacksjs/video": ["@stacksjs/video@0.75.301", "", { "dependencies": { "@ts-videos/mp4": "^0.1.2", "@ts-videos/webm": "^0.1.2", "ts-video-player": "^0.1.3", "ts-videos": "^0.1.2" } }, "sha512-+psjmsM3CL0KAAtHiqM7aH8TSvvH84rnLbEloXl0U2z88FpFULs1gG6GUp2UMXUqjGulvSWpAjSlFkEq/9NoHg=="],
286287
287 "@stacksjs/whois": ["@stacksjs/whois@0.75.299", "", { "dependencies": { "@stacksjs/logging": "0.75.299" } }, "sha512-RhPvKWAXZZ9hUWy77BMFUyZTTSmhuJSu196lOd89fLfK7gTdWtVRrvQTnKJLkMQtYB0AGDDe6vKr81gzmDCq2Q=="],
288 "@stacksjs/whois": ["@stacksjs/whois@0.75.301", "", { "dependencies": { "@stacksjs/logging": "0.75.301" } }, "sha512-1hnh9bG5lRu35si+73DsVPVcOTq6vRm/vuDcl8bsa07dp2ureXZK2LbMxhgg9kzO/dUzJ1e8FARamNTsdXl93Q=="],
288289
289290 "@ts-audio/aac": ["@ts-audio/aac@0.1.2", "", { "peerDependencies": { "@ts-audio/core": "0.1.2" } }, "sha512-9VD0vAuD22Qck6BSn0aX6c0gxqZVNP/ZZGRsAN+vRszBI6qRamfPt/QB/vPpwCLTKjdBZontzmtXSVJhIL0zXA=="],
290291
@@ -400,7 +401,7 @@
400401
401402 "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
402403
403 "stacks": ["stacks@0.75.299", "", { "dependencies": { "@stacksjs/actions": "0.75.299", "@stacksjs/ai": "0.75.299", "@stacksjs/alias": "0.75.299", "@stacksjs/analytics": "0.75.299", "@stacksjs/api": "0.75.299", "@stacksjs/arrays": "0.75.299", "@stacksjs/audio": "0.75.299", "@stacksjs/auth": "0.75.299", "@stacksjs/browser": "0.75.299", "@stacksjs/browser-extension": "0.75.299", "@stacksjs/buddy": "0.75.299", "@stacksjs/build": "0.75.299", "@stacksjs/cache": "0.75.299", "@stacksjs/calendar-api": "0.75.299", "@stacksjs/charts": "0.75.299", "@stacksjs/chat": "0.75.299", "@stacksjs/cli": "0.75.299", "@stacksjs/cloud": "0.75.299", "@stacksjs/cms": "0.75.299", "@stacksjs/collections": "0.75.299", "@stacksjs/commerce": "0.75.299", "@stacksjs/composables": "0.75.299", "@stacksjs/config": "0.75.299", "@stacksjs/cron": "0.75.299", "@stacksjs/database": "0.75.299", "@stacksjs/datetime": "0.75.299", "@stacksjs/defaults": "0.75.299", "@stacksjs/desktop": "0.2.687", "@stacksjs/desktop-build": "0.75.299", "@stacksjs/dns": "0.75.299", "@stacksjs/docs": "0.75.299", "@stacksjs/email": "0.75.299", "@stacksjs/enums": "0.75.299", "@stacksjs/env": "0.75.299", "@stacksjs/error-handling": "0.75.299", "@stacksjs/events": "0.75.299", "@stacksjs/faker": "0.75.299", "@stacksjs/feature-flags": "0.75.299", "@stacksjs/forms": "0.75.299", "@stacksjs/git": "0.75.299", "@stacksjs/github": "0.75.299", "@stacksjs/health": "0.75.299", "@stacksjs/http": "0.75.299", "@stacksjs/i18n": "0.75.299", "@stacksjs/image": "0.75.299", "@stacksjs/lint": "0.75.299", "@stacksjs/logging": "0.75.299", "@stacksjs/mobile": "0.75.299", "@stacksjs/newsletter": "0.75.299", "@stacksjs/notifications": "0.75.299", "@stacksjs/objects": "0.75.299", "@stacksjs/orm": "0.75.299", "@stacksjs/path": "0.75.299", "@stacksjs/payments": "0.75.299", "@stacksjs/push": "0.75.299", "@stacksjs/query-builder": "0.75.299", "@stacksjs/queue": "0.75.299", "@stacksjs/realtime": "0.75.299", "@stacksjs/registry": "0.75.299", "@stacksjs/repl": "0.75.299", "@stacksjs/router": "0.75.299", "@stacksjs/scheduler": "0.75.299", "@stacksjs/search-engine": "0.75.299", "@stacksjs/security": "0.75.299", "@stacksjs/server": "0.75.299", "@stacksjs/shell": "0.75.299", "@stacksjs/sites": "0.75.299", "@stacksjs/skills": "0.75.299", "@stacksjs/slug": "0.75.299", "@stacksjs/sms": "0.75.299", "@stacksjs/socials": "0.75.299", "@stacksjs/storage": "0.75.299", "@stacksjs/strings": "0.75.299", "@stacksjs/testing": "0.75.299", "@stacksjs/tinker": "0.75.299", "@stacksjs/tlsx": "^0.13.19", "@stacksjs/ts-cloud": "^0.16.52", "@stacksjs/tunnel": "0.75.299", "@stacksjs/types": "0.75.299", "@stacksjs/ui": "0.75.299", "@stacksjs/utils": "0.75.299", "@stacksjs/validation": "0.75.299", "@stacksjs/video": "0.75.299", "@stacksjs/whois": "0.75.299", "bun-query-builder": "^0.3.8" } }, "sha512-03bqBC/+ANasgZfM4KfiFCTmqEGhHLhxPdE6TLwGJnGDy96ixc/5W8wcPlmZ4eyt3y3KAHWxx7hxDJ+EPyNVWA=="],
404 "stacks": ["stacks@0.75.301", "", { "dependencies": { "@stacksjs/actions": "0.75.301", "@stacksjs/ai": "0.75.301", "@stacksjs/alias": "0.75.301", "@stacksjs/analytics": "0.75.301", "@stacksjs/api": "0.75.301", "@stacksjs/arrays": "0.75.301", "@stacksjs/audio": "0.75.301", "@stacksjs/auth": "0.75.301", "@stacksjs/browser": "0.75.301", "@stacksjs/browser-extension": "0.75.301", "@stacksjs/buddy": "0.75.301", "@stacksjs/build": "0.75.301", "@stacksjs/cache": "0.75.301", "@stacksjs/calendar-api": "0.75.301", "@stacksjs/charts": "0.75.301", "@stacksjs/chat": "0.75.301", "@stacksjs/cli": "0.75.301", "@stacksjs/cloud": "0.75.301", "@stacksjs/cms": "0.75.301", "@stacksjs/collections": "0.75.301", "@stacksjs/commerce": "0.75.301", "@stacksjs/composables": "0.75.301", "@stacksjs/config": "0.75.301", "@stacksjs/cron": "0.75.301", "@stacksjs/database": "0.75.301", "@stacksjs/datetime": "0.75.301", "@stacksjs/defaults": "0.75.301", "@stacksjs/desktop": "0.2.687", "@stacksjs/desktop-build": "0.75.301", "@stacksjs/dns": "0.75.301", "@stacksjs/docs": "0.75.301", "@stacksjs/email": "0.75.301", "@stacksjs/enums": "0.75.301", "@stacksjs/env": "0.75.301", "@stacksjs/error-handling": "0.75.301", "@stacksjs/events": "0.75.301", "@stacksjs/faker": "0.75.301", "@stacksjs/feature-flags": "0.75.301", "@stacksjs/forms": "0.75.301", "@stacksjs/git": "0.75.301", "@stacksjs/github": "0.75.301", "@stacksjs/health": "0.75.301", "@stacksjs/http": "0.75.301", "@stacksjs/i18n": "0.75.301", "@stacksjs/image": "0.75.301", "@stacksjs/lint": "0.75.301", "@stacksjs/logging": "0.75.301", "@stacksjs/mobile": "0.75.301", "@stacksjs/newsletter": "0.75.301", "@stacksjs/notifications": "0.75.301", "@stacksjs/objects": "0.75.301", "@stacksjs/orm": "0.75.301", "@stacksjs/path": "0.75.301", "@stacksjs/payments": "0.75.301", "@stacksjs/push": "0.75.301", "@stacksjs/query-builder": "0.75.301", "@stacksjs/queue": "0.75.301", "@stacksjs/realtime": "0.75.301", "@stacksjs/registry": "0.75.301", "@stacksjs/repl": "0.75.301", "@stacksjs/router": "0.75.301", "@stacksjs/scheduler": "0.75.301", "@stacksjs/search-engine": "0.75.301", "@stacksjs/security": "0.75.301", "@stacksjs/server": "0.75.301", "@stacksjs/shell": "0.75.301", "@stacksjs/sites": "0.75.301", "@stacksjs/skills": "0.75.301", "@stacksjs/slug": "0.75.301", "@stacksjs/sms": "0.75.301", "@stacksjs/socials": "0.75.301", "@stacksjs/storage": "0.75.301", "@stacksjs/strings": "0.75.301", "@stacksjs/testing": "0.75.301", "@stacksjs/tinker": "0.75.301", "@stacksjs/tlsx": "^0.13.19", "@stacksjs/ts-cloud": "^0.16.69", "@stacksjs/tunnel": "0.75.301", "@stacksjs/types": "0.75.301", "@stacksjs/ui": "0.75.301", "@stacksjs/utils": "0.75.301", "@stacksjs/validation": "0.75.301", "@stacksjs/video": "0.75.301", "@stacksjs/whois": "0.75.301", "bun-query-builder": "^0.3.8" } }, "sha512-XtnJoB1NEla+hJ7854TzljamxYbt7bwe5iBHrMAvaLgKGm+jY9n4x+6VnZbTqclgE9H1hrDpgoQCVI5w9GlzfA=="],
404405
405406 "stacks-framework": ["stacks-framework@workspace:storage/framework"],
406407
config/cloud.tsmodified+25-13
Changes to config/cloud.ts
@@ -3,6 +3,13 @@ import type { CloudConfig as TsCloudConfig } from '@stacksjs/ts-cloud'
33import { servers } from '../cloud/servers'
44import { env } from '@stacksjs/env'
55
6// Each atomic release owns its runtime. The shared server keeps its own Bun.
7const appRuntime = './pantry/.bin/bun'
8const installAppRuntime = 'bun node_modules/ts-pantry/dist/bin/cli.js install bun.sh@1.4.4 --install-dir pantry --quiet'
9const activateAppRuntime = 'export PATH="$PWD/pantry/.bin:/usr/local/bin:/usr/bin:/bin"'
10const checkAppRuntime = `${appRuntime} --eval 'if (Bun.version !== "1.4.4") throw new Error("Application requires Bun 1.4.4"); const child = Bun.spawnSync(["bun", "--version"], { stdout: "pipe", stderr: "pipe", timeout: 10000 }); if (child.exitCode !== 0 || child.stdout.toString().trim() !== "1.4.4") throw new Error("Application child commands require Bun 1.4.4"); console.log("Application Bun " + Bun.version + " including child commands")'`
11const appRuntimePath = './pantry/.bin:/usr/local/bin:/usr/bin:/bin'
12
613/**
714 * Stacks Cloud Configuration
815 *
@@ -728,9 +735,8 @@ export const tsCloud: TsCloudConfig = {
728735 root: '.',
729736 path: '/',
730737 domain: 'openfarm.ing',
731 // ts-cloud prepends the runtime, so this has to be a file bun can
732 // execute — not the ./buddy shell wrapper.
733 start: 'bun storage/framework/runtime/production/serve.js',
738 // Native ts-cloud resolves this release-local executable for systemd.
739 start: `${appRuntime} storage/framework/runtime/production/serve.js`,
734740 port: 3060,
735741 /*
736742 * This site's share of a shared box.
@@ -771,21 +777,26 @@ export const tsCloud: TsCloudConfig = {
771777 // Runs after the repo and the resolved production env are in place and
772778 // before the systemd service starts. Migrate runs ONLY here: the API
773779 // site shares the same SQLite file, so migrating from both would put two
774 // writers on one file. `catalog:sync` replaces the catalog and the
775 // demonstration field and leaves every other row alone, so it is safe to
776 // run against a database farmers have accounts in. It is deliberately
780 // writers on one file. `catalog:sync` restores the reserved demo records
781 // with stable identities, preserves published imagery metadata, and
782 // refuses customer-owned identifier conflicts before changing the catalog.
783 // It is deliberately
777784 // NOT `|| true`, because a deploy that silently ships an empty catalog
778785 // is worse than one that fails loudly.
779786 preStart: [
780 'bun install',
781 'bun node_modules/@stacksjs/buddy/dist/cli.js site:discovery',
787 'bun install --frozen-lockfile',
788 installAppRuntime,
789 activateAppRuntime,
790 checkAppRuntime,
791 `${appRuntime} node_modules/@stacksjs/buddy/dist/cli.js site:discovery`,
782792 'mkdir -p /var/lib/openfarming',
783793 'mkdir -p storage/framework/runtime/production',
784 'bun build --production --target=bun --packages=external app/ProductionServer.ts --outdir storage/framework/runtime/production --entry-naming serve.js',
785 'bun node_modules/@stacksjs/buddy/dist/cli.js migrate || true',
786 'bun node_modules/@stacksjs/buddy/dist/cli.js catalog:sync',
794 `${appRuntime} build --production --target=bun --packages=external app/ProductionServer.ts --outdir storage/framework/runtime/production --entry-naming serve.js`,
795 `${appRuntime} node_modules/@stacksjs/buddy/dist/cli.js migrate`,
796 `${appRuntime} node_modules/@stacksjs/buddy/dist/cli.js catalog:sync`,
787797 ],
788798 env: {
799 PATH: appRuntimePath,
789800 HOST: '127.0.0.1',
790801 APP_ENV: 'production',
791802 NODE_ENV: 'production',
@@ -803,14 +814,15 @@ export const tsCloud: TsCloudConfig = {
803814 // exclusively through the app's same-origin /api proxy.
804815 api: {
805816 root: '.',
806 start: 'bun node_modules/@stacksjs/actions/dist/serve/api.js',
817 start: `${appRuntime} node_modules/@stacksjs/actions/dist/serve/api.js`,
807818 port: 3068,
808819 // The API is the same runtime serving JSON, so it wants the same
809820 // ceiling as `main` above.
810821 memoryHigh: '512M',
811822 memoryMax: '768M',
812 preStart: ['bun install'],
823 preStart: ['bun install --frozen-lockfile', installAppRuntime, activateAppRuntime, checkAppRuntime],
813824 env: {
825 PATH: appRuntimePath,
814826 HOST: '127.0.0.1',
815827 APP_ENV: 'production',
816828 NODE_ENV: 'production',
config/docs.tsmodified+4-6
Changes to config/docs.ts
@@ -8,12 +8,10 @@ import type { BunPressOptions } from '@stacksjs/bunpress'
88 * `public/site.css`, so the documentation and the thing it documents are the
99 * same colour.
1010 *
11 * It goes through `markdown.css` rather than `themeConfig.colors`. The theme
12 * config's `colors`, `fonts`, `cssVars` and `css` keys are typed and
13 * documented, and bunpress's dev server does honour them, but the code path
14 * that renders the STATIC build does not - so setting them themes the site you
15 * develop and not the one you ship. `markdown.css` reaches both. See the
16 * upstream note in `docs/guide/deployment.md`.
11 * The palette, light and dark variants, local font declarations and screenshot
12 * styles share this application stylesheet. BunPress 0.2.25 also delivers
13 * themeConfig colors, fonts, cssVars and css in static builds, including the
14 * nested markdown.themeConfig form. See `docs/guide/deployment.md`.
1715 *
1816 * The theme keys off `--bp-*` variables and scopes dark mode to a `.dark`
1917 * class, so both blocks are written out here in full.
docs/guide/deployment.mdmodified+41-23
Changes to docs/guide/deployment.md
@@ -69,9 +69,9 @@ page list, the capability and use-case catalogs, and the herding scenarios, in E
6969German and Dutch. Account, dashboard, API, login, registration and form-result pages
7070are excluded. Regenerate the files after changing these catalogs during local development.
7171
72This app uses Stacks 0.74.66, whose production server does not mount the newer native
73request-time discovery handler. The generated files use the existing native serialization
74and serving APIs without replacing the production server. They are ignored build output.
72The deployment hook generates these files through the native stx serialization APIs.
73The explicit public-page policy keeps private and account routes out of the published
74sitemaps. Generated discovery files are ignored build output.
7575
7676### Serving the docs
7777
@@ -88,12 +88,9 @@ Two details in `config/cloud.ts` are load bearing:
8888- **`root` points inside `dist/docs`,** because bunpress writes its rendered
8989 output to `<outDir>/.bunpress`.
9090
91The build command is `bun run buddy build:docs`, not `./buddy build:docs`. The
92build action shells out to `bunpress build`, and the only thing that puts that
93binary on PATH is `bun run`, which prepends `node_modules/.bin`. Worse, the
94failure is silent: the action logs "Executable not found" and still exits 0.
95The `&& test -d dist/docs/.bunpress` after it is the guard, so a build that
96quietly produces nothing fails at the build rather than at the packaging.
91Build with `./buddy build docs` or `bun run buddy build:docs`. Stacks resolves
92the project's installed BunPress CLI and propagates a failed build. The deploy
93also checks that `dist/docs/.bunpress` exists before packaging the output.
9794
9895### Theming
9996
@@ -103,16 +100,12 @@ which mattered once the pages filled up with
103100`config/docs.ts` are the tokens from `public/site.css`, so the documentation
104101and the thing it documents are the same colour.
105102
106It goes through `markdown.css` rather than `themeConfig.colors`. The theme
107config's `colors`, `fonts`, `cssVars` and `css` keys are typed and documented,
108and bunpress's dev server honours them, but the code path that renders the
109static build in the version pinned here does not, so setting them themes the
110site you develop and not the one you ship. `markdown.css` reaches both.
111
112There is a related upstream fix: `generateThemeOverrideCss` read only the
113top-level `themeConfig`, while the Stacks config nests it under `markdown`, so
114a nested palette was a silent no-op. Once a bunpress release carries both that
115and the build-path fix, this block can move to `themeConfig` and shrink.
103The palette, light and dark variants, local font declarations and screenshot
104styles live together in the application's `markdown.css`. This is ordinary
105application styling. The pinned BunPress 0.2.25 also supports `themeConfig`
106colors, fonts, CSS variables and raw CSS in static builds. Both top-level
107`themeConfig` and `markdown.themeConfig` reach the shared layout renderer;
108when a key appears in both, the top-level value wins.
116109
117110### Search under `/docs`
118111
@@ -125,12 +118,37 @@ BunPress's source repository, release them, then upgrade this app and rerun the
125118public search regressions, native docs build and browser checks. This changes
126119documentation navigation, not the flight pipeline.
127120
121## Application runtime
122
123Each atomic `main` and `api` release installs Bun 1.4.4 into its own `pantry/`
124directory using the pinned Pantry SDK. The shared host's Bun bootstraps the
125frozen JavaScript dependency install and that native runtime installer. The
126application build, commands and services then use `./pantry/.bin/bun`.
127
128The startup hook exports the release's absolute runtime directory into its
129shell `PATH` and checks both the direct runtime and a real `bun` child before
130discovery, migration or catalog publication. This export matters because service
131environment variables do not configure the deployment hook's shell. Service
132`PATH` also starts with the release's `pantry/.bin`, so its child commands use
133the same runtime. This does not upgrade the shared server's
134Bun or Pantry binaries. A runtime installation or version-check failure stops
135startup.
136
128137## preStart
129138
130`catalog:sync` runs on every deploy through `preStart`, so a content edit in
131`app/Support/content/` ships with the code and needs no separate step. Because
132the sync truncates and rewrites, a deploy also repairs a database whose catalog
133tables have drifted.
139`catalog:sync` publishes content from `app/Support/content/` on every deploy.
140It refreshes the capability and use-case tables, retains the reserved demo farm,
141field and aircraft IDs, and restores soft-deleted demo farm and field records.
142Derived demo missions, detections and treatments are rebuilt. Existing published
143orthomosaic metadata is copied to the new demo mission; customer records remain
144outside the refresh.
145
146The command refuses a reserved demo farm owned by an account, or a reserved
147field or aircraft attached to another farm, before changing business rows.
148[Stacks 0.75.301](https://github.com/stacksjs/stacks/releases/tag/v0.75.301)
149repairs missing owner columns on empty legacy trait pivots during native
150migration. A populated ambiguous pivot fails migration without assigning an
151owner. Migration failures stop startup before catalog publication.
134152
135153## Where the flight pipeline would run
136154
package.jsonmodified+2-1
Changes to package.json
@@ -89,7 +89,8 @@
8989 "craft": "^0.0.19"
9090 },
9191 "dependencies": {
92 "stacks": "^0.75.299",
92 "stacks": "^0.75.301",
93 "ts-pantry": "0.11.126",
9394 "ts-images": "^0.2.12"
9495 },
9596 "workspaces": [
storage/framework/api/package.jsonmodified+5-5
Changes to storage/framework/api/package.json
@@ -8,11 +8,11 @@
88 "prod": "bun --hot run dist/dev.js"
99 },
1010 "dependencies": {
11 "@stacksjs/logging": "^0.75.299",
12 "@stacksjs/queue": "^0.75.299",
13 "@stacksjs/router": "^0.75.299",
14 "@stacksjs/storage": "^0.75.299",
15 "@stacksjs/utils": "^0.75.299"
11 "@stacksjs/logging": "^0.75.301",
12 "@stacksjs/queue": "^0.75.301",
13 "@stacksjs/router": "^0.75.301",
14 "@stacksjs/storage": "^0.75.301",
15 "@stacksjs/utils": "^0.75.301"
1616 },
1717 "workspaces": [
1818 "../core/*"
storage/framework/cloud/package.jsonmodified+11-11
Changes to storage/framework/cloud/package.json
@@ -45,19 +45,19 @@
4545 "deploy": "bun deploy.ts"
4646 },
4747 "dependencies": {
48 "@stacksjs/config": "^0.75.299",
49 "@stacksjs/dns": "^0.75.299",
50 "@stacksjs/logging": "^0.75.299",
51 "@stacksjs/path": "^0.75.299",
52 "@stacksjs/queue": "^0.75.299",
53 "@stacksjs/router": "^0.75.299",
54 "@stacksjs/storage": "^0.75.299",
55 "@stacksjs/utils": "^0.75.299",
56 "@stacksjs/validation": "^0.75.299"
48 "@stacksjs/config": "^0.75.301",
49 "@stacksjs/dns": "^0.75.301",
50 "@stacksjs/logging": "^0.75.301",
51 "@stacksjs/path": "^0.75.301",
52 "@stacksjs/queue": "^0.75.301",
53 "@stacksjs/router": "^0.75.301",
54 "@stacksjs/storage": "^0.75.301",
55 "@stacksjs/utils": "^0.75.301",
56 "@stacksjs/validation": "^0.75.301"
5757 },
5858 "devDependencies": {
59 "@stacksjs/cli": "^0.75.299",
59 "@stacksjs/cli": "^0.75.301",
6060 "better-dx": "catalog:",
61 "@stacksjs/env": "^0.75.299"
61 "@stacksjs/env": "^0.75.301"
6262 }
6363}
storage/framework/docs/package.jsonmodified+7-7
Changes to storage/framework/docs/package.json
@@ -8,12 +8,12 @@
88 "preview": "bunpress preview"
99 },
1010 "dependencies": {
11 "@stacksjs/alias": "^0.75.299",
12 "@stacksjs/cli": "^0.75.299",
13 "@stacksjs/config": "^0.75.299",
14 "@stacksjs/env": "^0.75.299",
15 "@stacksjs/path": "^0.75.299",
16 "@stacksjs/server": "^0.75.299",
17 "@stacksjs/storage": "^0.75.299"
11 "@stacksjs/alias": "^0.75.301",
12 "@stacksjs/cli": "^0.75.301",
13 "@stacksjs/config": "^0.75.301",
14 "@stacksjs/env": "^0.75.301",
15 "@stacksjs/path": "^0.75.301",
16 "@stacksjs/server": "^0.75.301",
17 "@stacksjs/storage": "^0.75.301"
1818 }
1919}
storage/framework/libs/components/stx/package.jsonmodified+1-1
Changes to storage/framework/libs/components/stx/package.json
@@ -42,6 +42,6 @@
4242 "prepublishOnly": "bun run build"
4343 },
4444 "devDependencies": {
45 "stacks": "^0.75.299"
45 "stacks": "^0.75.301"
4646 }
4747}
storage/framework/libs/components/web/package.jsonmodified+1-1
Changes to storage/framework/libs/components/web/package.json
@@ -45,6 +45,6 @@
4545 "prepublishOnly": "bun run build"
4646 },
4747 "devDependencies": {
48 "stacks": "^0.75.299"
48 "stacks": "^0.75.301"
4949 }
5050}
storage/framework/libs/functions/package.jsonmodified+1-1
Changes to storage/framework/libs/functions/package.json
@@ -41,6 +41,6 @@
4141 "prepublishOnly": "bun run build"
4242 },
4343 "devDependencies": {
44 "stacks": "^0.75.299"
44 "stacks": "^0.75.301"
4545 }
4646}
storage/framework/orm/package.jsonmodified+3-3
Changes to storage/framework/orm/package.json
@@ -46,9 +46,9 @@
4646 },
4747 "dependencies": {
4848 "@stacksjs/bun-router": "^0.0.20",
49 "@stacksjs/cache": "^0.75.299",
50 "@stacksjs/database": "^0.75.299",
51 "@stacksjs/error-handling": "^0.75.299"
49 "@stacksjs/cache": "^0.75.301",
50 "@stacksjs/database": "^0.75.301",
51 "@stacksjs/error-handling": "^0.75.301"
5252 },
5353 "devDependencies": {
5454 "better-dx": "catalog:"
storage/framework/server/package.jsonmodified+5-5
Changes to storage/framework/server/package.json
@@ -48,10 +48,10 @@
4848 },
4949 "devDependencies": {
5050 "better-dx": "catalog:",
51 "@stacksjs/logging": "^0.75.299",
52 "@stacksjs/path": "^0.75.299",
53 "@stacksjs/router": "^0.75.299",
54 "@stacksjs/storage": "^0.75.299",
55 "@stacksjs/utils": "^0.75.299"
51 "@stacksjs/logging": "^0.75.301",
52 "@stacksjs/path": "^0.75.301",
53 "@stacksjs/router": "^0.75.301",
54 "@stacksjs/storage": "^0.75.301",
55 "@stacksjs/utils": "^0.75.301"
5656 }
5757}
tests/unit/catalog-persistence.test.tsadded+193-0
Changes to tests/unit/catalog-persistence.test.ts
@@ -0,0 +1,193 @@
1import { Database } from 'bun:sqlite'
2import { expect, test } from 'bun:test'
3import { mkdir, mkdtemp, readFile, rm } from 'node:fs/promises'
4import { tmpdir } from 'node:os'
5import { join, resolve } from 'node:path'
6import { DEMO_FARM, DEMO_FIELD } from '../../app/Support/content/demo-field'
7
8type Row = Record<string, string | number | null>
9const tables = ['users', 'farms', 'fields', 'drones', 'missions', 'detections', 'treatment_maps', 'features', 'use_cases'] as const
10
11test('native catalog publication restores stable demo identities and protects customer data', async () => {
12 const evidence = process.env.CATALOG_PERSISTENCE_EVIDENCE
13 if (evidence) await mkdir(resolve(evidence), { recursive: true, mode: 0o700 })
14 const directory = await mkdtemp(join(evidence ? resolve(evidence) : tmpdir(), 'open-farming-catalog-'))
15 const databasePath = join(directory, 'fixture.sqlite')
16 const env = { ...process.env, APP_ENV: 'test', NODE_ENV: 'test', DB_CONNECTION: 'sqlite', DB_DATABASE_PATH: databasePath }
17 const cwd = resolve(import.meta.dir, '../..')
18 let sequence = 0
19 let complete = false
20 let database: Database | undefined
21 let db: Database
22 function openDatabase(): Database {
23 const connection = new Database(databasePath)
24 connection.run('PRAGMA foreign_keys = ON')
25 return connection
26 }
27
28 async function run(label: string, args: string[], expected = 0): Promise<string> {
29 const file = join(directory, `${sequence++}-${label}.log`)
30 const errors = `${file}.stderr`
31 const child = Bun.spawn([process.execPath, '--no-env-file', ...args], {
32 cwd, env, stdin: 'ignore', stdout: Bun.file(file), stderr: Bun.file(errors),
33 detached: process.platform !== 'win32',
34 })
35 let expired = false
36 const deadline = setTimeout(() => {
37 expired = true
38 if (process.platform !== 'win32') {
39 try { process.kill(-child.pid, 'SIGKILL') }
40 catch { child.kill('SIGKILL') }
41 }
42 else child.kill('SIGKILL')
43 }, 60_000)
44 try {
45 const code = await child.exited
46 const output = await readFile(file, 'utf8') + await readFile(errors, 'utf8')
47 expect(expired, `${label}: ${output}`).toBe(false)
48 expect(code, `${label}: ${output}`).toBe(expected)
49 return output
50 }
51 finally { clearTimeout(deadline) }
52 }
53 async function publish(label: string, expected = 0): Promise<string> {
54 // Do not hold a second SQLite runtime's statements across a writer process.
55 const reopen = database !== undefined
56 database?.close()
57 database = undefined
58 try { return await run(label, ['node_modules/@stacksjs/buddy/dist/cli.js', 'catalog:sync'], expected) }
59 finally { if (reopen) db = database = openDatabase() }
60 }
61
62 function legacyPivots(populated = false): void {
63 database?.close()
64 database = undefined
65 const fixture = openDatabase()
66 try {
67 for (const table of ['taggable_models', 'categorizable_models']) {
68 expect(fixture.query<{ count: number }, []>(`SELECT COUNT(*) AS count FROM ${table}`).get()?.count).toBe(0)
69 fixture.run(`DROP TABLE ${table}`)
70 }
71 fixture.run('CREATE TABLE taggable_models (id INTEGER PRIMARY KEY, tag_id INTEGER NOT NULL, taggable_type TEXT NOT NULL, created_at TEXT, updated_at TEXT)')
72 fixture.run('CREATE TABLE categorizable_models (id INTEGER PRIMARY KEY, category_id INTEGER NOT NULL, categorizable_type TEXT NOT NULL, created_at TEXT, updated_at TEXT)')
73 if (populated) fixture.run("INSERT INTO taggable_models (id, tag_id, taggable_type) VALUES (1, 1, 'Farm')")
74 }
75 finally { fixture.close() }
76 }
77 function inspectPivots() {
78 const fixture = openDatabase()
79 try {
80 return Object.fromEntries(['taggable_models', 'categorizable_models'].map(table => [table, {
81 columns: fixture.query<Row, []>(`PRAGMA table_info(${table})`).all(),
82 rows: fixture.query<Row, []>(`SELECT * FROM ${table} ORDER BY id`).all(),
83 }]))
84 }
85 finally { fixture.close() }
86 }
87
88 try {
89 // Admit the actual native config before allowing the first database write.
90 await run('database-path', ['--eval', `
91const { database } = await import('@stacksjs/config')
92if (database.connections.sqlite.database !== process.env.DB_DATABASE_PATH)
93 throw new Error('Fixture database path mismatch')
94await (await import('@stacksjs/logging')).log.flush()
95process.exit(0)
96`])
97 await run('migrate', ['node_modules/@stacksjs/buddy/dist/cli.js', 'migrate'])
98 // Reproduce the legacy shape through the installed CLI, never installed patches.
99 legacyPivots()
100 await run('migrate-empty-legacy', ['node_modules/@stacksjs/buddy/dist/cli.js', 'migrate'])
101 const repaired = inspectPivots()
102 for (const [table, column] of [['taggable_models', 'taggable_id'], ['categorizable_models', 'categorizable_id']]) {
103 const owner = repaired[table!]!.columns.find(value => value.name === column)
104 expect(owner?.notnull).toBe(1)
105 expect(owner?.dflt_value).toBeNull()
106 expect(repaired[table!]!.rows).toHaveLength(0)
107 }
108 await publish('first')
109 db = database = openDatabase()
110 const rows = (table: typeof tables[number]) => db.query<Row, []>(`SELECT * FROM "${table}" ORDER BY id`).all()
111 function one(table: typeof tables[number], column: string, value: string | number): Row {
112 const row = rows(table).find(row => row[column] === value)
113 if (!row) throw new Error(`Missing fixture ${table}.${column}=${value}`)
114 return row
115 }
116 function copy(table: typeof tables[number], source: Row, changes: Row): number {
117 const values = { ...source, ...changes }
118 delete values.id
119 if ('uuid' in values) values.uuid = crypto.randomUUID()
120 const columns = Object.keys(values)
121 return Number(db.prepare(`INSERT INTO "${table}" (${columns.map(key => `"${key}"`).join(',')}) VALUES (${columns.map(() => '?').join(',')})`).run(...Object.values(values)).lastInsertRowid)
122 }
123 const farm = one('farms', 'slug', DEMO_FARM.slug)
124 const field = one('fields', 'slug', DEMO_FIELD.slug)
125 const drone = one('drones', 'callsign', 'OF-K12')
126 const mission = one('missions', 'farm_id', farm.id!)
127 const identities = { farm: farm.id, field: field.id, drone: drone.id }
128 expect(rows('detections')).toHaveLength(98)
129 expect(rows('treatment_maps')).toHaveLength(1)
130
131 // Raw SQL seeds only this admitted disposable fixture, avoiding user mail hooks.
132 const userId = Number(db.prepare('INSERT INTO users (name, email, password) VALUES (?, ?, ?)').run('Fixture farmer', 'fixture@example.invalid', 'not-an-account-password').lastInsertRowid)
133 const customerFarm = copy('farms', farm, { slug: 'customer-holding', user_id: userId })
134 const customerField = copy('fields', field, { slug: 'customer-field', farm_id: customerFarm })
135 const customerDrone = copy('drones', drone, { callsign: 'CUSTOMER-01', farm_id: customerFarm })
136 const customerMission = copy('missions', mission, { farm_id: customerFarm, field_id: customerField, drone_id: customerDrone })
137 copy('detections', rows('detections')[0]!, { mission_id: customerMission, field_id: customerField })
138 copy('treatment_maps', rows('treatment_maps')[0]!, { mission_id: customerMission, field_id: customerField })
139 const customerRows = () => ({
140 user: one('users', 'id', userId), farm: one('farms', 'id', customerFarm),
141 field: one('fields', 'id', customerField), drone: one('drones', 'id', customerDrone),
142 mission: one('missions', 'id', customerMission),
143 detections: rows('detections').filter(row => row.mission_id === customerMission),
144 treatment: rows('treatment_maps').filter(row => row.mission_id === customerMission),
145 })
146 const customerBefore = customerRows()
147 db.prepare('UPDATE missions SET orthomosaic_url = ?, orthomosaic_bounds = ?, orthomosaic_resolution_cm = ? WHERE id = ?').run('/fixtures/published-stitch.webp', '[12.9,48.7,13,48.8]', 2.5, mission.id!)
148 const assertPublished = () => {
149 expect({ farm: one('farms', 'slug', DEMO_FARM.slug).id, field: one('fields', 'slug', DEMO_FIELD.slug).id, drone: one('drones', 'callsign', 'OF-K12').id }).toEqual(identities)
150 expect(one('farms', 'slug', DEMO_FARM.slug).deleted_at).toBeNull()
151 expect(one('fields', 'slug', DEMO_FIELD.slug).deleted_at).toBeNull()
152 const current = one('missions', 'farm_id', farm.id!)
153 expect([current.orthomosaic_url, current.orthomosaic_bounds, current.orthomosaic_resolution_cm]).toEqual(['/fixtures/published-stitch.webp', '[12.9,48.7,13,48.8]', 2.5])
154 expect(rows('missions').filter(row => row.farm_id === farm.id)).toHaveLength(1)
155 expect(rows('detections').filter(row => row.field_id === field.id)).toHaveLength(98)
156 expect(rows('treatment_maps').filter(row => row.field_id === field.id)).toHaveLength(1)
157 expect(customerRows()).toEqual(customerBefore)
158 }
159 await publish('repeat')
160 assertPublished()
161 db.prepare('UPDATE farms SET deleted_at = ? WHERE id = ?').run('2026-01-01 00:00:00', farm.id!)
162 db.prepare('UPDATE fields SET deleted_at = ? WHERE id = ?').run('2026-01-01 00:00:00', field.id!)
163 await publish('restore')
164 assertPublished()
165
166 const snapshot = () => Object.fromEntries(tables.map(table => [table, rows(table)]))
167 for (const conflict of [
168 { table: 'farms', column: 'user_id', id: farm.id!, value: userId, previous: null },
169 { table: 'fields', column: 'farm_id', id: field.id!, value: customerFarm, previous: farm.id! },
170 { table: 'drones', column: 'farm_id', id: drone.id!, value: customerFarm, previous: farm.id! },
171 ]) {
172 const update = `UPDATE "${conflict.table}" SET "${conflict.column}" = ? WHERE id = ?`
173 db.prepare(update).run(conflict.value, conflict.id)
174 const before = snapshot()
175 const output = await publish(`refuse-${conflict.table}`, 1)
176 expect(output).toContain('refusing to overwrite')
177 expect(snapshot()).toEqual(before)
178 db.prepare(update).run(conflict.previous, conflict.id)
179 }
180 legacyPivots(true)
181 const ambiguous = inspectPivots()
182 const refusal = await run('migrate-populated-legacy', ['node_modules/@stacksjs/buddy/dist/cli.js', 'migrate'], 1)
183 expect(refusal).toContain('Cannot infer taggable_models.taggable_id')
184 expect(inspectPivots()).toEqual(ambiguous)
185 complete = true
186 }
187 catch (error) { throw new Error(`Catalog persistence fixture retained at ${directory}`, { cause: error }) }
188 finally {
189 database?.close()
190 if (complete && !evidence) await rm(directory, { recursive: true })
191 else console.log(`CATALOG_PERSISTENCE_RETAINED ${directory}`)
192 }
193}, 180_000)