feat: add seed scripts and AI worker
Adds scripts/seed.ts for fresh self-hosted installs, scripts/seed-tenant.ts for cloud provisioner use, and scripts/ai-worker.ts adapted from AHCR with improved theme prompts, name filtering, and WORKER_API_KEY guard. Installs tsx as a dev dependency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Generated
+406
-1
@@ -15,6 +15,7 @@
|
|||||||
"stripe": "^21.0.0"
|
"stripe": "^21.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.58.2",
|
||||||
"@sveltejs/adapter-auto": "^7.0.0",
|
"@sveltejs/adapter-auto": "^7.0.0",
|
||||||
"@sveltejs/adapter-node": "^5.5.4",
|
"@sveltejs/adapter-node": "^5.5.4",
|
||||||
"@sveltejs/kit": "^2.50.2",
|
"@sveltejs/kit": "^2.50.2",
|
||||||
@@ -25,8 +26,10 @@
|
|||||||
"svelte": "^5.54.0",
|
"svelte": "^5.54.0",
|
||||||
"svelte-check": "^4.4.2",
|
"svelte-check": "^4.4.2",
|
||||||
"tailwindcss": "^4.2.2",
|
"tailwindcss": "^4.2.2",
|
||||||
|
"tsx": "^4.21.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vite": "^7.3.1"
|
"vite": "^7.3.1",
|
||||||
|
"vitest": "^4.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@drizzle-team/brocli": {
|
"node_modules/@drizzle-team/brocli": {
|
||||||
@@ -1268,6 +1271,22 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@playwright/test": {
|
||||||
|
"version": "1.58.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz",
|
||||||
|
"integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"playwright": "1.58.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"playwright": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@polka/url": {
|
"node_modules/@polka/url": {
|
||||||
"version": "1.0.0-next.29",
|
"version": "1.0.0-next.29",
|
||||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
|
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
|
||||||
@@ -2188,6 +2207,17 @@
|
|||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/chai": {
|
||||||
|
"version": "5.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
|
||||||
|
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/deep-eql": "*",
|
||||||
|
"assertion-error": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/cookie": {
|
"node_modules/@types/cookie": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||||
@@ -2195,6 +2225,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/deep-eql": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||||
@@ -2249,6 +2286,129 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vitest/expect": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@standard-schema/spec": "^1.1.0",
|
||||||
|
"@types/chai": "^5.2.2",
|
||||||
|
"@vitest/spy": "4.1.2",
|
||||||
|
"@vitest/utils": "4.1.2",
|
||||||
|
"chai": "^6.2.2",
|
||||||
|
"tinyrainbow": "^3.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/mocker": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vitest/spy": "4.1.2",
|
||||||
|
"estree-walker": "^3.0.3",
|
||||||
|
"magic-string": "^0.30.21"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"msw": "^2.4.9",
|
||||||
|
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"msw": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vite": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/mocker/node_modules/estree-walker": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/pretty-format": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tinyrainbow": "^3.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/runner": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vitest/utils": "4.1.2",
|
||||||
|
"pathe": "^2.0.3"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/snapshot": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vitest/pretty-format": "4.1.2",
|
||||||
|
"@vitest/utils": "4.1.2",
|
||||||
|
"magic-string": "^0.30.21",
|
||||||
|
"pathe": "^2.0.3"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/spy": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/utils": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vitest/pretty-format": "4.1.2",
|
||||||
|
"convert-source-map": "^2.0.0",
|
||||||
|
"tinyrainbow": "^3.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.16.0",
|
"version": "8.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||||
@@ -2272,6 +2432,16 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/assertion-error": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/aws-ssl-profiles": {
|
"node_modules/aws-ssl-profiles": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
||||||
@@ -2298,6 +2468,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/chai": {
|
||||||
|
"version": "6.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
|
||||||
|
"integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||||
@@ -2331,6 +2511,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/convert-source-map": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/cookie": {
|
"node_modules/cookie": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||||
@@ -3016,6 +3203,13 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-module-lexer": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.27.4",
|
"version": "0.27.4",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz",
|
||||||
@@ -3083,6 +3277,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/expect-type": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fdir": {
|
"node_modules/fdir": {
|
||||||
"version": "6.5.0",
|
"version": "6.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||||
@@ -3654,6 +3858,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/pathe": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
@@ -3674,6 +3885,53 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/playwright": {
|
||||||
|
"version": "1.58.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
|
||||||
|
"integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"playwright-core": "1.58.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"playwright": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/playwright-core": {
|
||||||
|
"version": "1.58.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
|
||||||
|
"integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"playwright-core": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/playwright/node_modules/fsevents": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.8",
|
"version": "8.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
|
||||||
@@ -3819,6 +4077,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/siginfo": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/sirv": {
|
"node_modules/sirv": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
|
||||||
@@ -3880,6 +4145,20 @@
|
|||||||
"url": "https://github.com/mysqljs/sql-escaper?sponsor=1"
|
"url": "https://github.com/mysqljs/sql-escaper?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stackback": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/std-env": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/stripe": {
|
"node_modules/stripe": {
|
||||||
"version": "21.0.0",
|
"version": "21.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/stripe/-/stripe-21.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/stripe/-/stripe-21.0.0.tgz",
|
||||||
@@ -3983,6 +4262,23 @@
|
|||||||
"url": "https://opencollective.com/webpack"
|
"url": "https://opencollective.com/webpack"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tinybench": {
|
||||||
|
"version": "2.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
|
||||||
|
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/tinyexec": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.15",
|
"version": "0.2.15",
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||||
@@ -4000,6 +4296,16 @@
|
|||||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tinyrainbow": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/totalist": {
|
"node_modules/totalist": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
||||||
@@ -4152,6 +4458,105 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vitest": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@vitest/expect": "4.1.2",
|
||||||
|
"@vitest/mocker": "4.1.2",
|
||||||
|
"@vitest/pretty-format": "4.1.2",
|
||||||
|
"@vitest/runner": "4.1.2",
|
||||||
|
"@vitest/snapshot": "4.1.2",
|
||||||
|
"@vitest/spy": "4.1.2",
|
||||||
|
"@vitest/utils": "4.1.2",
|
||||||
|
"es-module-lexer": "^2.0.0",
|
||||||
|
"expect-type": "^1.3.0",
|
||||||
|
"magic-string": "^0.30.21",
|
||||||
|
"obug": "^2.1.1",
|
||||||
|
"pathe": "^2.0.3",
|
||||||
|
"picomatch": "^4.0.3",
|
||||||
|
"std-env": "^4.0.0-rc.1",
|
||||||
|
"tinybench": "^2.9.0",
|
||||||
|
"tinyexec": "^1.0.2",
|
||||||
|
"tinyglobby": "^0.2.15",
|
||||||
|
"tinyrainbow": "^3.1.0",
|
||||||
|
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
|
||||||
|
"why-is-node-running": "^2.3.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"vitest": "vitest.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@edge-runtime/vm": "*",
|
||||||
|
"@opentelemetry/api": "^1.9.0",
|
||||||
|
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||||
|
"@vitest/browser-playwright": "4.1.2",
|
||||||
|
"@vitest/browser-preview": "4.1.2",
|
||||||
|
"@vitest/browser-webdriverio": "4.1.2",
|
||||||
|
"@vitest/ui": "4.1.2",
|
||||||
|
"happy-dom": "*",
|
||||||
|
"jsdom": "*",
|
||||||
|
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@edge-runtime/vm": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@opentelemetry/api": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@vitest/browser-playwright": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@vitest/browser-preview": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@vitest/browser-webdriverio": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@vitest/ui": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"happy-dom": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"jsdom": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vite": {
|
||||||
|
"optional": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/why-is-node-running": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"siginfo": "^2.0.0",
|
||||||
|
"stackback": "0.0.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"why-is-node-running": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/zimmerframe": {
|
"node_modules/zimmerframe": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
|
||||||
|
|||||||
+4
-1
@@ -12,6 +12,7 @@
|
|||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.58.2",
|
||||||
"@sveltejs/adapter-auto": "^7.0.0",
|
"@sveltejs/adapter-auto": "^7.0.0",
|
||||||
"@sveltejs/adapter-node": "^5.5.4",
|
"@sveltejs/adapter-node": "^5.5.4",
|
||||||
"@sveltejs/kit": "^2.50.2",
|
"@sveltejs/kit": "^2.50.2",
|
||||||
@@ -22,8 +23,10 @@
|
|||||||
"svelte": "^5.54.0",
|
"svelte": "^5.54.0",
|
||||||
"svelte-check": "^4.4.2",
|
"svelte-check": "^4.4.2",
|
||||||
"tailwindcss": "^4.2.2",
|
"tailwindcss": "^4.2.2",
|
||||||
|
"tsx": "^4.21.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vite": "^7.3.1"
|
"vite": "^7.3.1",
|
||||||
|
"vitest": "^4.1.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-rs/argon2": "^2.0.2",
|
"@node-rs/argon2": "^2.0.2",
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/**
|
||||||
|
* FosterFlow AI Worker — runs on a machine with local GPU/Ollama access.
|
||||||
|
* Polls the FosterFlow API for pending AI jobs, processes them through local Ollama,
|
||||||
|
* and posts results back.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* PUBLIC_SITE_URL=https://yourrescue.fosterflow.app WORKER_API_KEY=your-key npx tsx scripts/ai-worker.ts
|
||||||
|
*
|
||||||
|
* Environment variables:
|
||||||
|
* PUBLIC_SITE_URL — FosterFlow base URL (default: http://localhost:5173)
|
||||||
|
* WORKER_API_KEY — Shared secret for authenticating with the FosterFlow API
|
||||||
|
* OLLAMA_URL — Ollama API URL (default: http://localhost:11434)
|
||||||
|
* POLL_INTERVAL — Milliseconds between polls (default: 10000)
|
||||||
|
*
|
||||||
|
* NOTE: Old completed/failed jobs should be cleaned up periodically.
|
||||||
|
* Consider a cron job: DELETE FROM ai_jobs WHERE status IN ('completed','failed') AND completed_at < NOW() - INTERVAL 7 DAY;
|
||||||
|
*/
|
||||||
|
|
||||||
|
const API_URL = process.env.PUBLIC_SITE_URL || 'http://localhost:5173';
|
||||||
|
const WORKER_KEY = process.env.WORKER_API_KEY || '';
|
||||||
|
const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434';
|
||||||
|
const POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL || '10000', 10);
|
||||||
|
|
||||||
|
if (!WORKER_KEY) {
|
||||||
|
console.error('ERROR: WORKER_API_KEY environment variable is required');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchNextJob() {
|
||||||
|
const res = await fetch(`${API_URL}/api/worker/jobs`, {
|
||||||
|
headers: { Authorization: `Bearer ${WORKER_KEY}` }
|
||||||
|
});
|
||||||
|
if (!res.ok) return null;
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function reportResult(jobId: number, output: unknown) {
|
||||||
|
await fetch(`${API_URL}/api/worker/jobs/${jobId}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { Authorization: `Bearer ${WORKER_KEY}`, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ status: 'completed', output })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function reportError(jobId: number, error: string) {
|
||||||
|
await fetch(`${API_URL}/api/worker/jobs/${jobId}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { Authorization: `Bearer ${WORKER_KEY}`, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ status: 'failed', error })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateNames(input: { species: string; theme: string; count: number; existingNames?: string }) {
|
||||||
|
const themes: Record<string, string> = {
|
||||||
|
food: 'food and cooking themed names (like Biscuit, Waffles, Chimichurri, Mochi, Pancake)',
|
||||||
|
disney: 'Disney character themed names (like Simba, Nala, Elsa, Olaf, Stitch)',
|
||||||
|
celebrity: 'celebrity or pop culture themed names (like Bowie, Dolly, Elvis, Beyonce)',
|
||||||
|
nature: 'nature themed names (like Willow, Storm, River, Daisy, Bear)',
|
||||||
|
classic: 'classic pet names (like Max, Bella, Charlie, Luna, Cooper)',
|
||||||
|
funny: 'funny and punny names (like Sir Barks-a-Lot, Bark Twain, Chewbarka, Purrlock Holmes)',
|
||||||
|
random: 'creative and unique names'
|
||||||
|
};
|
||||||
|
|
||||||
|
const themePrompt = themes[input.theme] || themes.random;
|
||||||
|
const count = input.count || 10;
|
||||||
|
|
||||||
|
const prompt = `Generate exactly ${count} creative ${input.species || 'dog'} names. Theme: ${themePrompt}.
|
||||||
|
|
||||||
|
IMPORTANT: These names are ALREADY TAKEN and must NOT be reused: ${input.existingNames || 'none'}
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- Just the names, one per line
|
||||||
|
- No numbers, no explanations, no extra text
|
||||||
|
- Be creative and fun
|
||||||
|
- Mix single names and two-word names
|
||||||
|
- Do NOT repeat any name from the taken list above`;
|
||||||
|
|
||||||
|
const res = await fetch(`${OLLAMA_URL}/api/generate`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: 'gemma2:9b',
|
||||||
|
prompt,
|
||||||
|
stream: false,
|
||||||
|
options: {
|
||||||
|
temperature: 1.2,
|
||||||
|
top_p: 0.95,
|
||||||
|
num_predict: 200
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) throw new Error(`Ollama error: ${res.status}: ${await res.text()}`);
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
const names = (data.response || '')
|
||||||
|
.split('\n')
|
||||||
|
.map((n: string) => n.replace(/^\d+[\.\)]\s*/, '').replace(/^[-*•]\s*/, '').trim())
|
||||||
|
.filter((name: string) => name && name.length > 1 && name.length < 40 && !name.includes(':'))
|
||||||
|
.filter((name: string, index: number, self: string[]) => self.indexOf(name) === index)
|
||||||
|
.slice(0, count);
|
||||||
|
|
||||||
|
return { names };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function poll() {
|
||||||
|
console.log('FosterFlow AI Worker started');
|
||||||
|
console.log(` Polling: ${API_URL} every ${POLL_INTERVAL}ms`);
|
||||||
|
console.log(` Ollama: ${OLLAMA_URL}`);
|
||||||
|
|
||||||
|
// Run immediately on start, then on interval
|
||||||
|
const tick = async () => {
|
||||||
|
try {
|
||||||
|
const job = await fetchNextJob();
|
||||||
|
if (job && job.id) {
|
||||||
|
console.log(`Processing job ${job.id} (${job.type})`);
|
||||||
|
try {
|
||||||
|
if (job.type === 'pet-names') {
|
||||||
|
const result = await generateNames(job.input);
|
||||||
|
await reportResult(job.id, result);
|
||||||
|
console.log(`Job ${job.id} completed`);
|
||||||
|
} else {
|
||||||
|
await reportError(job.id, `Unknown job type: ${job.type}`);
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
await reportError(job.id, err.message);
|
||||||
|
console.error(`Job ${job.id} failed:`, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Connection error — will retry on next interval
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tick();
|
||||||
|
setInterval(tick, POLL_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
poll();
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { drizzle } from 'drizzle-orm/mysql2';
|
||||||
|
import mysql from 'mysql2/promise';
|
||||||
|
import { hash } from '@node-rs/argon2';
|
||||||
|
import * as schema from '../src/lib/server/schema';
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const flags: Record<string, string> = {};
|
||||||
|
for (let i = 0; i < args.length; i += 2) {
|
||||||
|
flags[args[i].replace('--', '')] = args[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function seedTenant() {
|
||||||
|
const { email, name, password, orgName } = flags;
|
||||||
|
if (!email || !name || !password || !orgName) {
|
||||||
|
console.error('Usage: npx tsx scripts/seed-tenant.ts --email X --name X --password X --orgName X');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pool = mysql.createPool({ uri: process.env.DATABASE_URL });
|
||||||
|
const db = drizzle(pool, { schema, mode: 'default' });
|
||||||
|
|
||||||
|
const passwordHash = await hash(password);
|
||||||
|
await db.insert(schema.users).values({
|
||||||
|
email,
|
||||||
|
passwordHash,
|
||||||
|
name,
|
||||||
|
role: 'sysadmin',
|
||||||
|
active: true,
|
||||||
|
mustChangePassword: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const orgConfigDefaults = [
|
||||||
|
{ key: 'branding', value: { primaryColor: '#0d9488', primaryColorLight: '#14b8a6', primaryColorDark: '#0f766e', accentColor: '#f59e0b', accentColorLight: '#fbbf24', accentColorDark: '#d97706', logoUrl: '' } },
|
||||||
|
{ key: 'org_info', value: { name: orgName, tagline: '', city: '', state: '', phone: '', email, facebookUrl: '', instagramUrl: '' } },
|
||||||
|
{ key: 'locale', value: { language: 'en', currency: 'USD', dateFormat: 'MM/DD/YYYY' } },
|
||||||
|
{ key: 'applications', value: { adoptionEnabled: true, fosterEnabled: true, volunteerEnabled: true, surrenderEnabled: true, adoptionFee: 250 } },
|
||||||
|
{ key: 'setup_complete', value: false }
|
||||||
|
];
|
||||||
|
for (const row of orgConfigDefaults) {
|
||||||
|
await db.insert(schema.orgConfig).values({ key: row.key, value: row.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
const intakeSources = ['Owner Surrender', 'Stray', 'Transfer', 'Born in Care', 'Other'];
|
||||||
|
for (const sourceName of intakeSources) {
|
||||||
|
await db.insert(schema.intakeSources).values({ name: sourceName });
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Tenant seeded: ${email} / [password provided] for ${orgName}`);
|
||||||
|
await pool.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
seedTenant().catch(console.error);
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { drizzle } from 'drizzle-orm/mysql2';
|
||||||
|
import mysql from 'mysql2/promise';
|
||||||
|
import { hash } from '@node-rs/argon2';
|
||||||
|
import * as schema from '../src/lib/server/schema';
|
||||||
|
|
||||||
|
async function seed() {
|
||||||
|
const pool = mysql.createPool({ uri: process.env.DATABASE_URL });
|
||||||
|
const db = drizzle(pool, { schema, mode: 'default' });
|
||||||
|
|
||||||
|
console.log('Seeding FosterFlow database...');
|
||||||
|
|
||||||
|
// 1. Create admin user
|
||||||
|
const passwordHash = await hash('changeme');
|
||||||
|
await db.insert(schema.users).values({
|
||||||
|
email: 'admin@example.com',
|
||||||
|
passwordHash,
|
||||||
|
name: 'Admin',
|
||||||
|
role: 'sysadmin',
|
||||||
|
active: true,
|
||||||
|
mustChangePassword: true
|
||||||
|
});
|
||||||
|
console.log('Created admin user (admin@example.com / changeme)');
|
||||||
|
|
||||||
|
// 2. Default org config
|
||||||
|
const orgConfigDefaults = [
|
||||||
|
{ key: 'branding', value: { primaryColor: '#0d9488', primaryColorLight: '#14b8a6', primaryColorDark: '#0f766e', accentColor: '#f59e0b', accentColorLight: '#fbbf24', accentColorDark: '#d97706', logoUrl: '' } },
|
||||||
|
{ key: 'org_info', value: { name: 'My Rescue', tagline: '', city: '', state: '', phone: '', email: '', facebookUrl: '', instagramUrl: '' } },
|
||||||
|
{ key: 'locale', value: { language: 'en', currency: 'USD', dateFormat: 'MM/DD/YYYY' } },
|
||||||
|
{ key: 'applications', value: { adoptionEnabled: true, fosterEnabled: true, volunteerEnabled: true, surrenderEnabled: true, adoptionFee: 250 } },
|
||||||
|
{ key: 'setup_complete', value: false }
|
||||||
|
];
|
||||||
|
for (const row of orgConfigDefaults) {
|
||||||
|
await db.insert(schema.orgConfig).values({ key: row.key, value: row.value });
|
||||||
|
}
|
||||||
|
console.log('Created default org config');
|
||||||
|
|
||||||
|
// 3. Default intake sources
|
||||||
|
const intakeSources = ['Owner Surrender', 'Stray', 'Transfer', 'Born in Care', 'Other'];
|
||||||
|
for (const name of intakeSources) {
|
||||||
|
await db.insert(schema.intakeSources).values({ name });
|
||||||
|
}
|
||||||
|
console.log('Created default intake sources');
|
||||||
|
|
||||||
|
// 4. Default content blocks (placeholder)
|
||||||
|
const contentDefaults = [
|
||||||
|
{ page: 'home', sectionKey: 'hero', content: { title: 'Find Your Forever Friend', subtitle: 'We rescue, rehabilitate, and rehome animals in need.' } },
|
||||||
|
{ page: 'about', sectionKey: 'intro', content: { text: 'Welcome to our rescue! We are dedicated to saving animals in need.' } },
|
||||||
|
{ page: 'adoption-process', sectionKey: 'intro', content: { text: 'Our adoption process is designed to find the best match for both you and our animals.' } },
|
||||||
|
{ page: 'become-a-foster', sectionKey: 'intro', content: { text: 'Fostering saves lives! Learn how you can help by opening your home to an animal in need.' } },
|
||||||
|
{ page: 'how-to-help', sectionKey: 'intro', content: { text: 'There are many ways you can help our rescue mission.' } },
|
||||||
|
{ page: 'volunteer', sectionKey: 'intro', content: { text: 'Volunteers are the backbone of our organization.' } },
|
||||||
|
{ page: 'why-adopt', sectionKey: 'intro', content: { text: 'Adopting a pet changes two lives — yours and theirs.' } }
|
||||||
|
];
|
||||||
|
for (const block of contentDefaults) {
|
||||||
|
await db.insert(schema.contentBlocks).values(block);
|
||||||
|
}
|
||||||
|
console.log('Created default content blocks');
|
||||||
|
|
||||||
|
console.log('\nDone! Log in at /login with admin@example.com / changeme');
|
||||||
|
await pool.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
seed().catch(console.error);
|
||||||
Reference in New Issue
Block a user