@sonicjs-cms/core 2.18.1 → 3.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/admin-documents-form.template-KN7JF66Q.cjs +19 -0
- package/dist/{admin-layout-catalyst.template-UMTIN66R.js.map → admin-documents-form.template-KN7JF66Q.cjs.map} +1 -1
- package/dist/admin-documents-form.template-NLSI6Z42.js +6 -0
- package/dist/{admin-layout-catalyst.template-HFD37TY5.cjs.map → admin-documents-form.template-NLSI6Z42.js.map} +1 -1
- package/dist/admin-layout-catalyst.template-WHJGSWWD.js +7 -0
- package/dist/admin-layout-catalyst.template-WHJGSWWD.js.map +1 -0
- package/dist/admin-layout-catalyst.template-ZK5HD545.cjs +17 -0
- package/dist/admin-layout-catalyst.template-ZK5HD545.cjs.map +1 -0
- package/dist/app-Bo0X1OWX.d.ts +1268 -0
- package/dist/app-Do66yCcV.d.cts +1268 -0
- package/dist/cache-DDARE4QE.js +4 -0
- package/dist/cache-DDARE4QE.js.map +1 -0
- package/dist/cache-LVYS4BPL.cjs +33 -0
- package/dist/cache-LVYS4BPL.cjs.map +1 -0
- package/dist/chunk-2CB4KY7I.cjs +771 -0
- package/dist/chunk-2CB4KY7I.cjs.map +1 -0
- package/dist/{chunk-55RDMDOP.js → chunk-3TB6AT6X.js} +148 -55
- package/dist/chunk-3TB6AT6X.js.map +1 -0
- package/dist/{chunk-ON5ZMSU4.js → chunk-6JQOUUOB.js} +3 -3
- package/dist/chunk-6JQOUUOB.js.map +1 -0
- package/dist/chunk-6OUHGKFD.js +387 -0
- package/dist/chunk-6OUHGKFD.js.map +1 -0
- package/dist/{chunk-DSUJ5YQH.cjs → chunk-AAWNRBRB.cjs} +537 -92
- package/dist/chunk-AAWNRBRB.cjs.map +1 -0
- package/dist/chunk-AI663NBO.js +821 -0
- package/dist/chunk-AI663NBO.js.map +1 -0
- package/dist/chunk-BDDABDAB.cjs +1149 -0
- package/dist/chunk-BDDABDAB.cjs.map +1 -0
- package/dist/chunk-BLMTL57B.js +767 -0
- package/dist/chunk-BLMTL57B.js.map +1 -0
- package/dist/chunk-DNQCEKUK.cjs +327 -0
- package/dist/chunk-DNQCEKUK.cjs.map +1 -0
- package/dist/chunk-DSA4UX5B.cjs +276 -0
- package/dist/chunk-DSA4UX5B.cjs.map +1 -0
- package/dist/chunk-EF2NQUIQ.js +323 -0
- package/dist/chunk-EF2NQUIQ.js.map +1 -0
- package/dist/chunk-GCDZZNIN.js +192 -0
- package/dist/chunk-GCDZZNIN.js.map +1 -0
- package/dist/{chunk-ABB34XUS.cjs → chunk-H2AXVCLS.cjs} +667 -19
- package/dist/chunk-H2AXVCLS.cjs.map +1 -0
- package/dist/{chunk-XWIA3HVX.js → chunk-HDWE5FRJ.js} +6 -1249
- package/dist/chunk-HDWE5FRJ.js.map +1 -0
- package/dist/chunk-HIKBY7MS.cjs +70 -0
- package/dist/chunk-HIKBY7MS.cjs.map +1 -0
- package/dist/chunk-IESEVHXL.js +66 -0
- package/dist/chunk-IESEVHXL.js.map +1 -0
- package/dist/chunk-IVPRUGTY.js +242 -0
- package/dist/chunk-IVPRUGTY.js.map +1 -0
- package/dist/{chunk-SQ6FNXU2.cjs → chunk-IXUHXTHW.cjs} +2 -151
- package/dist/chunk-IXUHXTHW.cjs.map +1 -0
- package/dist/chunk-J6JTWD2A.cjs +100 -0
- package/dist/chunk-J6JTWD2A.cjs.map +1 -0
- package/dist/chunk-JEQ7FLOD.cjs +199 -0
- package/dist/chunk-JEQ7FLOD.cjs.map +1 -0
- package/dist/chunk-K25XHMM3.js +566 -0
- package/dist/chunk-K25XHMM3.js.map +1 -0
- package/dist/chunk-LRZIAW7U.cjs +158 -0
- package/dist/chunk-LRZIAW7U.cjs.map +1 -0
- package/dist/{chunk-OHYBNCVL.cjs → chunk-MVIZJOO5.cjs} +10 -1256
- package/dist/chunk-MVIZJOO5.cjs.map +1 -0
- package/dist/{chunk-UYJ6TJHX.cjs → chunk-NAVPFIG5.cjs} +148 -55
- package/dist/chunk-NAVPFIG5.cjs.map +1 -0
- package/dist/chunk-NLJVSER2.js +273 -0
- package/dist/chunk-NLJVSER2.js.map +1 -0
- package/dist/chunk-NMPEMSU4.js +154 -0
- package/dist/chunk-NMPEMSU4.js.map +1 -0
- package/dist/chunk-NUKJ54GA.cjs +245 -0
- package/dist/chunk-NUKJ54GA.cjs.map +1 -0
- package/dist/{chunk-T3Q5V33G.cjs → chunk-QAYFOER6.cjs} +621 -829
- package/dist/chunk-QAYFOER6.cjs.map +1 -0
- package/dist/{chunk-MGFRZO24.js → chunk-QZGABF2M.js} +3 -149
- package/dist/chunk-QZGABF2M.js.map +1 -0
- package/dist/chunk-RNZFGN4R.js +88 -0
- package/dist/chunk-RNZFGN4R.js.map +1 -0
- package/dist/chunk-RZ6H7OZK.js +1134 -0
- package/dist/chunk-RZ6H7OZK.js.map +1 -0
- package/dist/{chunk-XXDFQERJ.js → chunk-VD2EA3WT.js} +7192 -9806
- package/dist/chunk-VD2EA3WT.js.map +1 -0
- package/dist/{chunk-SXXTQETM.cjs → chunk-VXE42MYF.cjs} +8722 -11323
- package/dist/chunk-VXE42MYF.cjs.map +1 -0
- package/dist/{chunk-4ZSNJDLS.cjs → chunk-WULONYGB.cjs} +9 -9
- package/dist/chunk-WULONYGB.cjs.map +1 -0
- package/dist/chunk-XW56B23A.cjs +408 -0
- package/dist/chunk-XW56B23A.cjs.map +1 -0
- package/dist/chunk-YA3TJ65D.cjs +575 -0
- package/dist/chunk-YA3TJ65D.cjs.map +1 -0
- package/dist/{chunk-TFNTM3OA.js → chunk-YHSQVQXX.js} +645 -15
- package/dist/chunk-YHSQVQXX.js.map +1 -0
- package/dist/chunk-YP7GW2G5.cjs +866 -0
- package/dist/chunk-YP7GW2G5.cjs.map +1 -0
- package/dist/{chunk-QFWHAFEO.js → chunk-ZEZ245PW.js} +148 -858
- package/dist/chunk-ZEZ245PW.js.map +1 -0
- package/dist/{chunk-EW5NOBVU.js → chunk-ZGGXCFR6.js} +611 -817
- package/dist/chunk-ZGGXCFR6.js.map +1 -0
- package/dist/{collection-config-B4PG-AaF.d.cts → collection-config-JgHOpFCG.d.cts} +30 -2
- package/dist/{collection-config-B4PG-AaF.d.ts → collection-config-JgHOpFCG.d.ts} +30 -2
- package/dist/config-HFXANXCC.js +6 -0
- package/dist/config-HFXANXCC.js.map +1 -0
- package/dist/config-ON6FNMYX.cjs +19 -0
- package/dist/config-ON6FNMYX.cjs.map +1 -0
- package/dist/define-plugin-BzNHc1ZI.d.ts +1321 -0
- package/dist/define-plugin-IWDKYaVm.d.cts +1321 -0
- package/dist/document-projection-TDWRJX3Z.cjs +13 -0
- package/dist/document-projection-TDWRJX3Z.cjs.map +1 -0
- package/dist/document-projection-YYMC6I4U.js +4 -0
- package/dist/document-projection-YYMC6I4U.js.map +1 -0
- package/dist/index.cjs +13735 -4329
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +329 -492
- package/dist/index.d.ts +329 -492
- package/dist/index.js +13386 -3999
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +36 -32
- package/dist/middleware.d.cts +69 -7
- package/dist/middleware.d.ts +69 -7
- package/dist/middleware.js +7 -3
- package/dist/migrations-NJJWQUKK.cjs +13 -0
- package/dist/{migrations-IYNTWDC6.cjs.map → migrations-NJJWQUKK.cjs.map} +1 -1
- package/dist/migrations-WCAVBD7C.js +4 -0
- package/dist/{migrations-R337UD46.js.map → migrations-WCAVBD7C.js.map} +1 -1
- package/dist/{plugin-bootstrap-DfVerYV4.d.cts → plugin-bootstrap-B8ThJU21.d.cts} +4315 -1661
- package/dist/{plugin-bootstrap-P_ciLp_C.d.ts → plugin-bootstrap-qu8hJgUt.d.ts} +4315 -1661
- package/dist/plugins.cjs +171 -12
- package/dist/plugins.d.cts +36 -2
- package/dist/plugins.d.ts +36 -2
- package/dist/plugins.js +5 -2
- package/dist/rbac-O73MFKDA.js +5 -0
- package/dist/rbac-O73MFKDA.js.map +1 -0
- package/dist/rbac-VONLJJKB.cjs +14 -0
- package/dist/rbac-VONLJJKB.cjs.map +1 -0
- package/dist/routes.cjs +41 -45
- package/dist/routes.d.cts +56 -146
- package/dist/routes.d.ts +56 -146
- package/dist/routes.js +17 -9
- package/dist/services.cjs +39 -72
- package/dist/services.d.cts +79 -54
- package/dist/services.d.ts +79 -54
- package/dist/services.js +6 -3
- package/dist/templates.cjs +17 -29
- package/dist/templates.d.cts +1 -66
- package/dist/templates.d.ts +1 -66
- package/dist/templates.js +3 -3
- package/dist/types-Dea1eNxU.d.cts +286 -0
- package/dist/types-Dea1eNxU.d.ts +286 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils.cjs +18 -17
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +2 -1
- package/migrations/0001_core.sql +184 -0
- package/migrations/0002_documents.sql +163 -0
- package/package.json +12 -7
- package/dist/admin-layout-catalyst.template-HFD37TY5.cjs +0 -17
- package/dist/admin-layout-catalyst.template-UMTIN66R.js +0 -7
- package/dist/app-C9esKLmh.d.cts +0 -112
- package/dist/app-C9esKLmh.d.ts +0 -112
- package/dist/chunk-4R3NOOL3.js +0 -2217
- package/dist/chunk-4R3NOOL3.js.map +0 -1
- package/dist/chunk-4ZSNJDLS.cjs.map +0 -1
- package/dist/chunk-55RDMDOP.js.map +0 -1
- package/dist/chunk-635JAMSE.cjs +0 -653
- package/dist/chunk-635JAMSE.cjs.map +0 -1
- package/dist/chunk-ABB34XUS.cjs.map +0 -1
- package/dist/chunk-C54YUA23.cjs +0 -2219
- package/dist/chunk-C54YUA23.cjs.map +0 -1
- package/dist/chunk-DSUJ5YQH.cjs.map +0 -1
- package/dist/chunk-EW5NOBVU.js.map +0 -1
- package/dist/chunk-EXNEW5US.js +0 -648
- package/dist/chunk-EXNEW5US.js.map +0 -1
- package/dist/chunk-I2H5NGJQ.js +0 -692
- package/dist/chunk-I2H5NGJQ.js.map +0 -1
- package/dist/chunk-MGFRZO24.js.map +0 -1
- package/dist/chunk-OHYBNCVL.cjs.map +0 -1
- package/dist/chunk-ON5ZMSU4.js.map +0 -1
- package/dist/chunk-QFWHAFEO.js.map +0 -1
- package/dist/chunk-SQ6FNXU2.cjs.map +0 -1
- package/dist/chunk-SXXTQETM.cjs.map +0 -1
- package/dist/chunk-T3Q5V33G.cjs.map +0 -1
- package/dist/chunk-TFNTM3OA.js.map +0 -1
- package/dist/chunk-UYJ6TJHX.cjs.map +0 -1
- package/dist/chunk-WAEQXGCX.cjs +0 -1898
- package/dist/chunk-WAEQXGCX.cjs.map +0 -1
- package/dist/chunk-XWIA3HVX.js.map +0 -1
- package/dist/chunk-XXDFQERJ.js.map +0 -1
- package/dist/migrations-IYNTWDC6.cjs +0 -13
- package/dist/migrations-R337UD46.js +0 -4
- package/dist/plugin-manager-BoM3Q7o7.d.cts +0 -328
- package/dist/plugin-manager-Efx9RyDX.d.ts +0 -328
- package/migrations/001_initial_schema.sql +0 -170
- package/migrations/002_faq_plugin.sql +0 -86
- package/migrations/003_stage5_enhancements.sql +0 -121
- package/migrations/004_stage6_user_management.sql +0 -183
- package/migrations/005_stage7_workflow_automation.sql +0 -294
- package/migrations/006_plugin_system.sql +0 -155
- package/migrations/007_demo_login_plugin.sql +0 -23
- package/migrations/008_fix_slug_validation.sql +0 -22
- package/migrations/009_system_logging.sql +0 -57
- package/migrations/011_config_managed_collections.sql +0 -15
- package/migrations/012_testimonials_plugin.sql +0 -80
- package/migrations/013_code_examples_plugin.sql +0 -177
- package/migrations/014_fix_plugin_registry.sql +0 -88
- package/migrations/015_add_remaining_plugins.sql +0 -89
- package/migrations/016_remove_duplicate_cache_plugin.sql +0 -17
- package/migrations/017_auth_configurable_fields.sql +0 -49
- package/migrations/018_settings_table.sql +0 -23
- package/migrations/019_remove_blog_posts_collection.sql +0 -15
- package/migrations/020_add_email_plugin.sql +0 -22
- package/migrations/021_add_magic_link_auth_plugin.sql +0 -42
- package/migrations/022_add_tinymce_plugin.sql +0 -25
- package/migrations/023_add_easy_mdx_plugin.sql +0 -25
- package/migrations/024_add_quill_editor_plugin.sql +0 -25
- package/migrations/025_add_easymde_plugin.sql +0 -25
- package/migrations/026_add_otp_login.sql +0 -42
- package/migrations/027_fix_slug_field_type.sql +0 -18
- package/migrations/028_fix_slug_field_type_in_schemas.sql +0 -30
- package/migrations/029_add_forms_system.sql +0 -184
- package/migrations/030_add_turnstile_to_forms.sql +0 -14
- package/migrations/031_ai_search_plugin.sql +0 -45
- package/migrations/032_user_profiles.sql +0 -37
- package/migrations/033_form_content_integration.sql +0 -19
- package/migrations/034_security_audit_plugin.sql +0 -27
- package/migrations/035_user_profiles_data_column.sql +0 -16
- package/migrations/036_analytics_events.sql +0 -22
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// package.json
|
|
2
|
+
var package_default = {
|
|
3
|
+
name: "@sonicjs-cms/core",
|
|
4
|
+
version: "3.0.0-beta.2",
|
|
5
|
+
description: "Core framework for SonicJS headless CMS - Edge-first, TypeScript-native CMS built for Cloudflare Workers",
|
|
6
|
+
type: "module",
|
|
7
|
+
main: "./dist/index.cjs",
|
|
8
|
+
module: "./dist/index.js",
|
|
9
|
+
types: "./dist/index.d.ts",
|
|
10
|
+
bin: {
|
|
11
|
+
"sonicjs-db-reset": "./bin/db-reset.js"
|
|
12
|
+
},
|
|
13
|
+
exports: {
|
|
14
|
+
".": {
|
|
15
|
+
types: "./dist/index.d.ts",
|
|
16
|
+
import: "./dist/index.js",
|
|
17
|
+
require: "./dist/index.cjs"
|
|
18
|
+
},
|
|
19
|
+
"./services": {
|
|
20
|
+
types: "./dist/services.d.ts",
|
|
21
|
+
import: "./dist/services.js",
|
|
22
|
+
require: "./dist/services.cjs"
|
|
23
|
+
},
|
|
24
|
+
"./middleware": {
|
|
25
|
+
types: "./dist/middleware.d.ts",
|
|
26
|
+
import: "./dist/middleware.js",
|
|
27
|
+
require: "./dist/middleware.cjs"
|
|
28
|
+
},
|
|
29
|
+
"./routes": {
|
|
30
|
+
types: "./dist/routes.d.ts",
|
|
31
|
+
import: "./dist/routes.js",
|
|
32
|
+
require: "./dist/routes.cjs"
|
|
33
|
+
},
|
|
34
|
+
"./templates": {
|
|
35
|
+
types: "./dist/templates.d.ts",
|
|
36
|
+
import: "./dist/templates.js",
|
|
37
|
+
require: "./dist/templates.cjs"
|
|
38
|
+
},
|
|
39
|
+
"./plugins": {
|
|
40
|
+
types: "./dist/plugins.d.ts",
|
|
41
|
+
import: "./dist/plugins.js",
|
|
42
|
+
require: "./dist/plugins.cjs"
|
|
43
|
+
},
|
|
44
|
+
"./utils": {
|
|
45
|
+
types: "./dist/utils.d.ts",
|
|
46
|
+
import: "./dist/utils.js",
|
|
47
|
+
require: "./dist/utils.cjs"
|
|
48
|
+
},
|
|
49
|
+
"./types": {
|
|
50
|
+
types: "./dist/types.d.ts",
|
|
51
|
+
import: "./dist/types.js",
|
|
52
|
+
require: "./dist/types.cjs"
|
|
53
|
+
},
|
|
54
|
+
"./package.json": "./package.json"
|
|
55
|
+
},
|
|
56
|
+
files: [
|
|
57
|
+
"bin",
|
|
58
|
+
"dist",
|
|
59
|
+
"migrations",
|
|
60
|
+
"README.md",
|
|
61
|
+
"LICENSE"
|
|
62
|
+
],
|
|
63
|
+
scripts: {
|
|
64
|
+
"generate:migrations": "npx tsx scripts/generate-migrations.ts",
|
|
65
|
+
prebuild: "npm run generate:migrations",
|
|
66
|
+
build: "tsup",
|
|
67
|
+
dev: "tsup --watch",
|
|
68
|
+
"type-check": "tsc --noEmit",
|
|
69
|
+
lint: "eslint src/",
|
|
70
|
+
"lint:fix": "eslint src/ --fix",
|
|
71
|
+
test: "vitest run",
|
|
72
|
+
"test:cov": "vitest run --coverage",
|
|
73
|
+
"test:watch": "vitest",
|
|
74
|
+
prepublishOnly: "npm run build",
|
|
75
|
+
prepare: "npm run build"
|
|
76
|
+
},
|
|
77
|
+
keywords: [
|
|
78
|
+
"cms",
|
|
79
|
+
"headless-cms",
|
|
80
|
+
"cloudflare",
|
|
81
|
+
"workers",
|
|
82
|
+
"edge",
|
|
83
|
+
"typescript",
|
|
84
|
+
"hono",
|
|
85
|
+
"content-management",
|
|
86
|
+
"api",
|
|
87
|
+
"sonicjs"
|
|
88
|
+
],
|
|
89
|
+
author: "SonicJS Team",
|
|
90
|
+
license: "MIT",
|
|
91
|
+
repository: {
|
|
92
|
+
type: "git",
|
|
93
|
+
url: "git+https://github.com/sonicjs/sonicjs.git",
|
|
94
|
+
directory: "packages/core"
|
|
95
|
+
},
|
|
96
|
+
bugs: {
|
|
97
|
+
url: "https://github.com/sonicjs/sonicjs/issues"
|
|
98
|
+
},
|
|
99
|
+
homepage: "https://sonicjs.com",
|
|
100
|
+
peerDependencies: {
|
|
101
|
+
"@cloudflare/workers-types": "^4.0.0",
|
|
102
|
+
"drizzle-orm": "^0.44.0",
|
|
103
|
+
hono: "^4.0.0",
|
|
104
|
+
zod: "^3.0.0 || ^4.0.0"
|
|
105
|
+
},
|
|
106
|
+
dependencies: {
|
|
107
|
+
"@cf-wasm/resvg": "^0.3.3",
|
|
108
|
+
"better-auth": "^1.6.13",
|
|
109
|
+
"better-auth-cloudflare": "^0.3.0",
|
|
110
|
+
"csv-parse": "^6.2.1",
|
|
111
|
+
"drizzle-zod": "^0.8.3",
|
|
112
|
+
"highlight.js": "^11.11.1",
|
|
113
|
+
linkedom: "^0.18.12",
|
|
114
|
+
marked: "^16.4.1",
|
|
115
|
+
"qrcode-svg": "^1.1.0",
|
|
116
|
+
semver: "^7.7.3",
|
|
117
|
+
"tiny-lru": "^13.0.0"
|
|
118
|
+
},
|
|
119
|
+
devDependencies: {
|
|
120
|
+
"@cloudflare/workers-types": "^4.20251014.0",
|
|
121
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
122
|
+
"@types/node": "^24.9.2",
|
|
123
|
+
"@types/qrcode-svg": "^1.1.5",
|
|
124
|
+
"@typescript-eslint/eslint-plugin": "^8.50.0",
|
|
125
|
+
"@typescript-eslint/parser": "^8.50.0",
|
|
126
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
127
|
+
"better-sqlite3": "^12.10.0",
|
|
128
|
+
"drizzle-orm": "^0.45.2",
|
|
129
|
+
eslint: "^9.39.2",
|
|
130
|
+
glob: "^10.5.0",
|
|
131
|
+
hono: "^4.12.26",
|
|
132
|
+
tsup: "^8.5.0",
|
|
133
|
+
typescript: "^5.9.3",
|
|
134
|
+
vitest: "^4.1.9",
|
|
135
|
+
zod: "^4.1.12"
|
|
136
|
+
},
|
|
137
|
+
engines: {
|
|
138
|
+
node: ">=18.0.0"
|
|
139
|
+
},
|
|
140
|
+
publishConfig: {
|
|
141
|
+
access: "public",
|
|
142
|
+
registry: "https://registry.npmjs.org/"
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// src/utils/version.ts
|
|
147
|
+
var SONICJS_VERSION = package_default.version;
|
|
148
|
+
function getCoreVersion() {
|
|
149
|
+
return SONICJS_VERSION;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export { SONICJS_VERSION, getCoreVersion, package_default };
|
|
153
|
+
//# sourceMappingURL=chunk-NMPEMSU4.js.map
|
|
154
|
+
//# sourceMappingURL=chunk-NMPEMSU4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../package.json","../src/utils/version.ts"],"names":[],"mappings":"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","file":"chunk-NMPEMSU4.js","sourcesContent":["{\n \"name\": \"@sonicjs-cms/core\",\n \"version\": \"3.0.0-beta.2\",\n \"description\": \"Core framework for SonicJS headless CMS - Edge-first, TypeScript-native CMS built for Cloudflare Workers\",\n \"type\": \"module\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"sonicjs-db-reset\": \"./bin/db-reset.js\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./services\": {\n \"types\": \"./dist/services.d.ts\",\n \"import\": \"./dist/services.js\",\n \"require\": \"./dist/services.cjs\"\n },\n \"./middleware\": {\n \"types\": \"./dist/middleware.d.ts\",\n \"import\": \"./dist/middleware.js\",\n \"require\": \"./dist/middleware.cjs\"\n },\n \"./routes\": {\n \"types\": \"./dist/routes.d.ts\",\n \"import\": \"./dist/routes.js\",\n \"require\": \"./dist/routes.cjs\"\n },\n \"./templates\": {\n \"types\": \"./dist/templates.d.ts\",\n \"import\": \"./dist/templates.js\",\n \"require\": \"./dist/templates.cjs\"\n },\n \"./plugins\": {\n \"types\": \"./dist/plugins.d.ts\",\n \"import\": \"./dist/plugins.js\",\n \"require\": \"./dist/plugins.cjs\"\n },\n \"./utils\": {\n \"types\": \"./dist/utils.d.ts\",\n \"import\": \"./dist/utils.js\",\n \"require\": \"./dist/utils.cjs\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"import\": \"./dist/types.js\",\n \"require\": \"./dist/types.cjs\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"bin\",\n \"dist\",\n \"migrations\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"generate:migrations\": \"npx tsx scripts/generate-migrations.ts\",\n \"prebuild\": \"npm run generate:migrations\",\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"type-check\": \"tsc --noEmit\",\n \"lint\": \"eslint src/\",\n \"lint:fix\": \"eslint src/ --fix\",\n \"test\": \"vitest run\",\n \"test:cov\": \"vitest run --coverage\",\n \"test:watch\": \"vitest\",\n \"prepublishOnly\": \"npm run build\",\n \"prepare\": \"npm run build\"\n },\n \"keywords\": [\n \"cms\",\n \"headless-cms\",\n \"cloudflare\",\n \"workers\",\n \"edge\",\n \"typescript\",\n \"hono\",\n \"content-management\",\n \"api\",\n \"sonicjs\"\n ],\n \"author\": \"SonicJS Team\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/sonicjs/sonicjs.git\",\n \"directory\": \"packages/core\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/sonicjs/sonicjs/issues\"\n },\n \"homepage\": \"https://sonicjs.com\",\n \"peerDependencies\": {\n \"@cloudflare/workers-types\": \"^4.0.0\",\n \"drizzle-orm\": \"^0.44.0\",\n \"hono\": \"^4.0.0\",\n \"zod\": \"^3.0.0 || ^4.0.0\"\n },\n \"dependencies\": {\n \"@cf-wasm/resvg\": \"^0.3.3\",\n \"better-auth\": \"^1.6.13\",\n \"better-auth-cloudflare\": \"^0.3.0\",\n \"csv-parse\": \"^6.2.1\",\n \"drizzle-zod\": \"^0.8.3\",\n \"highlight.js\": \"^11.11.1\",\n \"linkedom\": \"^0.18.12\",\n \"marked\": \"^16.4.1\",\n \"qrcode-svg\": \"^1.1.0\",\n \"semver\": \"^7.7.3\",\n \"tiny-lru\": \"^13.0.0\"\n },\n \"devDependencies\": {\n \"@cloudflare/workers-types\": \"^4.20251014.0\",\n \"@types/better-sqlite3\": \"^7.6.13\",\n \"@types/node\": \"^24.9.2\",\n \"@types/qrcode-svg\": \"^1.1.5\",\n \"@typescript-eslint/eslint-plugin\": \"^8.50.0\",\n \"@typescript-eslint/parser\": \"^8.50.0\",\n \"@vitest/coverage-v8\": \"^4.1.9\",\n \"better-sqlite3\": \"^12.10.0\",\n \"drizzle-orm\": \"^0.45.2\",\n \"eslint\": \"^9.39.2\",\n \"glob\": \"^10.5.0\",\n \"hono\": \"^4.12.26\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^4.1.9\",\n \"zod\": \"^4.1.12\"\n },\n \"engines\": {\n \"node\": \">=18.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"registry\": \"https://registry.npmjs.org/\"\n }\n}\n","/**\n * Version utility\n *\n * Provides the current version of @sonicjs-cms/core package\n */\n\nimport pkg from '../../package.json'\n\nexport const SONICJS_VERSION = pkg.version\n\n/**\n * Get the current SonicJS core version\n */\nexport function getCoreVersion(): string {\n return SONICJS_VERSION\n}\n"]}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkHIKBY7MS_cjs = require('./chunk-HIKBY7MS.cjs');
|
|
4
|
+
var chunkYP7GW2G5_cjs = require('./chunk-YP7GW2G5.cjs');
|
|
5
|
+
var betterAuth = require('better-auth');
|
|
6
|
+
var betterAuthCloudflare = require('better-auth-cloudflare');
|
|
7
|
+
var crypto$1 = require('better-auth/crypto');
|
|
8
|
+
var api = require('better-auth/api');
|
|
9
|
+
var magicLink = require('better-auth/plugins/magic-link');
|
|
10
|
+
var emailOtp = require('better-auth/plugins/email-otp');
|
|
11
|
+
var organization = require('better-auth/plugins/organization');
|
|
12
|
+
var d1 = require('drizzle-orm/d1');
|
|
13
|
+
|
|
14
|
+
async function sendViaEmailPlugin(db, to, subject, html) {
|
|
15
|
+
try {
|
|
16
|
+
const row = await db.prepare("SELECT settings FROM plugins WHERE id = 'email'").first();
|
|
17
|
+
if (row?.settings) {
|
|
18
|
+
const { apiKey, fromEmail, fromName } = JSON.parse(row.settings);
|
|
19
|
+
if (apiKey && fromEmail) {
|
|
20
|
+
await fetch("https://api.resend.com/emails", {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
from: `${fromName ?? "SonicJS"} <${fromEmail}>`,
|
|
25
|
+
to: [to],
|
|
26
|
+
subject,
|
|
27
|
+
html
|
|
28
|
+
})
|
|
29
|
+
});
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
console.log(`[email-dev] To:${to} | Subject:${subject}`);
|
|
36
|
+
}
|
|
37
|
+
async function verifyLegacyPbkdf2(password, stored) {
|
|
38
|
+
const parts = stored.split(":");
|
|
39
|
+
if (parts.length !== 4) return false;
|
|
40
|
+
const iterations = parseInt(parts[1], 10);
|
|
41
|
+
const saltBytes = parts[2].match(/.{2}/g);
|
|
42
|
+
if (!saltBytes || !Number.isFinite(iterations)) return false;
|
|
43
|
+
const salt = new Uint8Array(saltBytes.map((b) => parseInt(b, 16)));
|
|
44
|
+
const km = await crypto.subtle.importKey("raw", new TextEncoder().encode(password), "PBKDF2", false, ["deriveBits"]);
|
|
45
|
+
const bits = await crypto.subtle.deriveBits({ name: "PBKDF2", salt, iterations, hash: "SHA-256" }, km, 256);
|
|
46
|
+
const actual = Array.from(new Uint8Array(bits)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
47
|
+
const expected = parts[3];
|
|
48
|
+
if (actual.length !== expected.length) return false;
|
|
49
|
+
let diff = 0;
|
|
50
|
+
for (let i = 0; i < actual.length; i++) diff |= actual.charCodeAt(i) ^ expected.charCodeAt(i);
|
|
51
|
+
return diff === 0;
|
|
52
|
+
}
|
|
53
|
+
function getDefaultAuthOptions(env, requestBaseURL) {
|
|
54
|
+
const db = d1.drizzle(env.DB);
|
|
55
|
+
return {
|
|
56
|
+
secret: env.BETTER_AUTH_SECRET,
|
|
57
|
+
baseURL: env.BETTER_AUTH_URL || requestBaseURL,
|
|
58
|
+
appName: "SonicJS",
|
|
59
|
+
...betterAuthCloudflare.withCloudflare(
|
|
60
|
+
{
|
|
61
|
+
autoDetectIpAddress: true,
|
|
62
|
+
geolocationTracking: false,
|
|
63
|
+
cf: {},
|
|
64
|
+
d1: {
|
|
65
|
+
db,
|
|
66
|
+
options: {
|
|
67
|
+
// Keys MUST match modelName values — BA resolves by modelName, not by JS variable name.
|
|
68
|
+
schema: { auth_user: chunkYP7GW2G5_cjs.authUser, auth_session: chunkYP7GW2G5_cjs.authSession, auth_account: chunkYP7GW2G5_cjs.authAccount, auth_verification: chunkYP7GW2G5_cjs.authVerification, auth_tenant: chunkYP7GW2G5_cjs.authTenant, auth_tenant_member: chunkYP7GW2G5_cjs.authTenantMember, auth_tenant_invitation: chunkYP7GW2G5_cjs.authTenantInvitation, auth_tenant_team: chunkYP7GW2G5_cjs.authTenantTeam }
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
kv: env.CACHE_KV
|
|
72
|
+
// session secondary storage → getSession skips D1
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
basePath: "/auth",
|
|
76
|
+
emailAndPassword: {
|
|
77
|
+
enabled: true,
|
|
78
|
+
autoSignIn: true,
|
|
79
|
+
// Transparent migration of SonicJS legacy PBKDF2 hashes: verify against
|
|
80
|
+
// the old format on login, then re-hash to scrypt and persist. No
|
|
81
|
+
// mass-rehash, no forced password resets.
|
|
82
|
+
password: {
|
|
83
|
+
verify: async ({ hash, password }) => {
|
|
84
|
+
if (hash.startsWith("pbkdf2:")) {
|
|
85
|
+
const ok = await verifyLegacyPbkdf2(password, hash);
|
|
86
|
+
if (ok) {
|
|
87
|
+
const upgraded = await crypto$1.hashPassword(password);
|
|
88
|
+
await env.DB.prepare(
|
|
89
|
+
"UPDATE auth_account SET password = ?, updated_at = ? WHERE password = ? AND provider_id = 'credential'"
|
|
90
|
+
).bind(upgraded, Math.floor(Date.now() / 1e3), hash).run();
|
|
91
|
+
}
|
|
92
|
+
return ok;
|
|
93
|
+
}
|
|
94
|
+
return crypto$1.verifyPassword({ hash, password });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
user: {
|
|
99
|
+
modelName: "auth_user",
|
|
100
|
+
// Field-mapping values are Drizzle *property keys* (camelCase), which
|
|
101
|
+
// already match Better Auth's defaults for emailVerified/createdAt/
|
|
102
|
+
// updatedAt. Only `image` differs (SonicJS uses `avatar`).
|
|
103
|
+
fields: {
|
|
104
|
+
image: "avatar"
|
|
105
|
+
},
|
|
106
|
+
additionalFields: {
|
|
107
|
+
role: { type: "string", required: false, defaultValue: "viewer", input: false },
|
|
108
|
+
firstName: { type: "string", required: false, defaultValue: "", input: true },
|
|
109
|
+
lastName: { type: "string", required: false, defaultValue: "", input: true },
|
|
110
|
+
isSuperAdmin: { type: "boolean", required: false, defaultValue: false, input: false }
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
session: {
|
|
114
|
+
modelName: "auth_session",
|
|
115
|
+
// Drizzle property keys already match Better Auth defaults (userId,
|
|
116
|
+
// expiresAt, ipAddress, …) — no field overrides needed.
|
|
117
|
+
expiresIn: 60 * 60 * 24 * 7,
|
|
118
|
+
// 7 days
|
|
119
|
+
updateAge: 60 * 60 * 24
|
|
120
|
+
// refresh once per day
|
|
121
|
+
},
|
|
122
|
+
account: { modelName: "auth_account" },
|
|
123
|
+
verification: { modelName: "auth_verification" },
|
|
124
|
+
databaseHooks: {
|
|
125
|
+
user: {
|
|
126
|
+
create: {
|
|
127
|
+
before: async (userData) => {
|
|
128
|
+
const isFirst = await chunkHIKBY7MS_cjs.isFirstUserRegistration(env.DB);
|
|
129
|
+
if (!isFirst) {
|
|
130
|
+
const enabled = await chunkHIKBY7MS_cjs.isRegistrationEnabled(env.DB);
|
|
131
|
+
if (!enabled) {
|
|
132
|
+
throw new api.APIError("BAD_REQUEST", { message: "Registration is currently disabled." });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const d = userData;
|
|
136
|
+
const name = (d.name ?? "User").toString();
|
|
137
|
+
const parts = name.trim().split(/\s+/);
|
|
138
|
+
const firstName = d.firstName || parts[0] || "User";
|
|
139
|
+
const lastName = d.lastName || parts.slice(1).join(" ") || firstName;
|
|
140
|
+
return { data: { ...userData, name, firstName, lastName, role: "viewer" } };
|
|
141
|
+
},
|
|
142
|
+
after: async (user) => {
|
|
143
|
+
try {
|
|
144
|
+
const { RbacService } = await import('./rbac-VONLJJKB.cjs');
|
|
145
|
+
const rbac = new RbacService(env.DB);
|
|
146
|
+
const roleName = await rbac.countPortalAdmins(user.id) === 0 ? "admin" : "viewer";
|
|
147
|
+
await rbac.addUserRoleByName(user.id, roleName);
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
),
|
|
156
|
+
// ── Phase 4: BA-native login methods ─────────────────────────────────────
|
|
157
|
+
// Magic-link and Email-OTP replace the standalone SonicJS plugins that
|
|
158
|
+
// minted JWT cookies. Social providers replace the bespoke oauth-providers
|
|
159
|
+
// plugin. All are gated on the relevant env vars / email service config
|
|
160
|
+
// so they activate only when configured.
|
|
161
|
+
plugins: [
|
|
162
|
+
// Magic-link passwordless auth. Sends a one-time link to the user's inbox;
|
|
163
|
+
// the link resolves to a BA session. Requires a working email service.
|
|
164
|
+
magicLink.magicLink({
|
|
165
|
+
sendMagicLink: async ({ email, url }, _request) => {
|
|
166
|
+
await sendViaEmailPlugin(
|
|
167
|
+
env.DB,
|
|
168
|
+
email,
|
|
169
|
+
"Your sign-in link",
|
|
170
|
+
`<div style="font-family:sans-serif;max-width:600px">
|
|
171
|
+
<h2>Sign in to SonicJS</h2>
|
|
172
|
+
<p>Click the link below to sign in. Expires in 15 minutes.</p>
|
|
173
|
+
<p><a href="${url}" style="background:#465FFF;color:#fff;padding:12px 24px;border-radius:6px;text-decoration:none">Sign in</a></p>
|
|
174
|
+
<p style="color:#666;font-size:12px">Or copy: ${url}</p>
|
|
175
|
+
</div>`
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
expiresIn: 15 * 60
|
|
179
|
+
}),
|
|
180
|
+
// Email OTP — 6-digit code sent to inbox. Replaces the otp-login-plugin.
|
|
181
|
+
emailOtp.emailOTP({
|
|
182
|
+
sendVerificationOTP: async (params, _request) => {
|
|
183
|
+
await sendViaEmailPlugin(
|
|
184
|
+
env.DB,
|
|
185
|
+
params.email,
|
|
186
|
+
"Your sign-in code",
|
|
187
|
+
`<div style="font-family:sans-serif;max-width:600px">
|
|
188
|
+
<h2>Your one-time code</h2>
|
|
189
|
+
<p style="font-size:36px;font-weight:bold;letter-spacing:8px;color:#465FFF">${params.otp}</p>
|
|
190
|
+
<p style="color:#666">Expires in 10 minutes. Do not share this code.</p>
|
|
191
|
+
</div>`
|
|
192
|
+
);
|
|
193
|
+
},
|
|
194
|
+
otpLength: 6,
|
|
195
|
+
expiresIn: 10 * 60
|
|
196
|
+
}),
|
|
197
|
+
organization.organization({
|
|
198
|
+
schema: {
|
|
199
|
+
organization: {
|
|
200
|
+
modelName: "auth_tenant",
|
|
201
|
+
additionalFields: {
|
|
202
|
+
status: { type: "string", required: false, defaultValue: "active", input: true },
|
|
203
|
+
domain: { type: "string", required: false, input: true },
|
|
204
|
+
notes: { type: "string", required: false, defaultValue: "", input: true }
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
member: {
|
|
208
|
+
modelName: "auth_tenant_member",
|
|
209
|
+
fields: { organizationId: "tenant_id" }
|
|
210
|
+
},
|
|
211
|
+
invitation: {
|
|
212
|
+
modelName: "auth_tenant_invitation",
|
|
213
|
+
fields: { organizationId: "tenant_id" }
|
|
214
|
+
},
|
|
215
|
+
team: {
|
|
216
|
+
modelName: "auth_tenant_team",
|
|
217
|
+
fields: { organizationId: "tenant_id" }
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
],
|
|
222
|
+
// ── Phase 4: Social providers ─────────────────────────────────────────
|
|
223
|
+
// Activated when the relevant env vars are set. Replaces the bespoke
|
|
224
|
+
// oauth-providers SonicJS plugin. Set via wrangler secret put / .dev.vars.
|
|
225
|
+
socialProviders: {
|
|
226
|
+
...env.GITHUB_CLIENT_ID && env.GITHUB_CLIENT_SECRET ? { github: { clientId: env.GITHUB_CLIENT_ID, clientSecret: env.GITHUB_CLIENT_SECRET } } : {},
|
|
227
|
+
...env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET ? { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET } } : {}
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function createAuth(env, extendBetterAuth, requestBaseURL) {
|
|
232
|
+
if (!env.BETTER_AUTH_SECRET || env.BETTER_AUTH_SECRET.length < 16) {
|
|
233
|
+
throw new Error(
|
|
234
|
+
"BETTER_AUTH_SECRET is missing or too short. Set it as a Wrangler secret (wrangler secret put BETTER_AUTH_SECRET) or in a gitignored .dev.vars for local dev. Refusing to initialize auth without a strong signing secret."
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
const defaults = getDefaultAuthOptions(env, requestBaseURL);
|
|
238
|
+
const options = extendBetterAuth ? extendBetterAuth(defaults) : defaults;
|
|
239
|
+
return betterAuth.betterAuth(options);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
exports.createAuth = createAuth;
|
|
243
|
+
exports.getDefaultAuthOptions = getDefaultAuthOptions;
|
|
244
|
+
//# sourceMappingURL=chunk-NUKJ54GA.cjs.map
|
|
245
|
+
//# sourceMappingURL=chunk-NUKJ54GA.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth/config.ts"],"names":["drizzle","withCloudflare","authUser","authSession","authAccount","authVerification","authTenant","authTenantMember","authTenantInvitation","authTenantTeam","baHashPassword","baVerifyPassword","isFirstUserRegistration","isRegistrationEnabled","APIError","magicLink","emailOTP","organization","betterAuth"],"mappings":";;;;;;;;;;;;;AAeA,eAAe,kBAAA,CACb,EAAA,EACA,EAAA,EACA,OAAA,EACA,IAAA,EACe;AACf,EAAA,IAAI;AACF,IAAA,MAAM,MAAO,MAAM,EAAA,CAChB,OAAA,CAAQ,iDAAiD,EACzD,KAAA,EAAM;AACT,IAAA,IAAI,KAAK,QAAA,EAAU;AACjB,MAAA,MAAM,EAAE,QAAQ,SAAA,EAAW,QAAA,KAAa,IAAA,CAAK,KAAA,CAAM,IAAI,QAAQ,CAAA;AAG/D,MAAA,IAAI,UAAU,SAAA,EAAW;AACvB,QAAA,MAAM,MAAM,+BAAA,EAAiC;AAAA,UAC3C,MAAA,EAAQ,MAAA;AAAA,UACR,SAAS,EAAE,aAAA,EAAe,UAAU,MAAM,CAAA,CAAA,EAAI,gBAAgB,kBAAA,EAAmB;AAAA,UACjF,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,YACnB,IAAA,EAAM,CAAA,EAAG,QAAA,IAAY,SAAS,KAAK,SAAS,CAAA,CAAA,CAAA;AAAA,YAC5C,EAAA,EAAI,CAAC,EAAE,CAAA;AAAA,YACP,OAAA;AAAA,YACA;AAAA,WACD;AAAA,SACF,CAAA;AACD,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAAgC;AACxC,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,eAAA,EAAkB,EAAE,CAAA,WAAA,EAAc,OAAO,CAAA,CAAE,CAAA;AACzD;AAmBA,eAAe,kBAAA,CAAmB,UAAkB,MAAA,EAAkC;AACpF,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAC9B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAC/B,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,KAAA,CAAM,CAAC,GAAI,EAAE,CAAA;AACzC,EAAA,MAAM,SAAA,GAAY,KAAA,CAAM,CAAC,CAAA,CAAG,MAAM,OAAO,CAAA;AACzC,EAAA,IAAI,CAAC,SAAA,IAAa,CAAC,OAAO,QAAA,CAAS,UAAU,GAAG,OAAO,KAAA;AACvD,EAAA,MAAM,IAAA,GAAO,IAAI,UAAA,CAAW,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,KAAM,QAAA,CAAS,CAAA,EAAG,EAAE,CAAC,CAAC,CAAA;AACjE,EAAA,MAAM,KAAK,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA,CAAU,OAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,QAAQ,CAAA,EAAG,QAAA,EAAU,KAAA,EAAO,CAAC,YAAY,CAAC,CAAA;AACnH,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,MAAA,CAAO,WAAW,EAAE,IAAA,EAAM,QAAA,EAAU,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,SAAA,EAAU,EAAG,IAAI,GAAG,CAAA;AAC1G,EAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,IAAI,WAAW,IAAI,CAAC,EAAE,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA;AACnG,EAAA,MAAM,QAAA,GAAW,MAAM,CAAC,CAAA;AACxB,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,QAAA,CAAS,MAAA,EAAQ,OAAO,KAAA;AAC9C,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,CAAA,EAAA,EAAK,IAAA,IAAQ,MAAA,CAAO,UAAA,CAAW,CAAC,CAAA,GAAI,QAAA,CAAS,WAAW,CAAC,CAAA;AAC5F,EAAA,OAAO,IAAA,KAAS,CAAA;AAClB;AAMO,SAAS,qBAAA,CAAsB,KAAe,cAAA,EAAyB;AAC5E,EAAA,MAAM,EAAA,GAAKA,UAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAEzB,EAAA,OAAO;AAAA,IACL,QAAQ,GAAA,CAAI,kBAAA;AAAA,IACZ,OAAA,EAAS,IAAI,eAAA,IAAmB,cAAA;AAAA,IAChC,OAAA,EAAS,SAAA;AAAA,IACT,GAAGC,mCAAA;AAAA,MACD;AAAA,QACE,mBAAA,EAAqB,IAAA;AAAA,QACrB,mBAAA,EAAqB,KAAA;AAAA,QACrB,IAAI,EAAC;AAAA,QACL,EAAA,EAAI;AAAA,UACF,EAAA;AAAA,UACA,OAAA,EAAS;AAAA;AAAA,YAEP,QAAQ,EAAE,SAAA,EAAWC,0BAAA,EAAU,YAAA,EAAcC,+BAAa,YAAA,EAAcC,6BAAA,EAAa,iBAAA,EAAmBC,kCAAA,EAAkB,aAAaC,4BAAA,EAAY,kBAAA,EAAoBC,oCAAkB,sBAAA,EAAwBC,sCAAA,EAAsB,kBAAkBC,gCAAA;AAAe;AAC1Q,SACF;AAAA,QACA,IAAI,GAAA,CAAI;AAAA;AAAA,OACV;AAAA,MACA;AAAA,QACE,QAAA,EAAU,OAAA;AAAA,QACV,gBAAA,EAAkB;AAAA,UAChB,OAAA,EAAS,IAAA;AAAA,UACT,UAAA,EAAY,IAAA;AAAA;AAAA;AAAA;AAAA,UAIZ,QAAA,EAAU;AAAA,YACR,MAAA,EAAQ,OAAO,EAAE,IAAA,EAAM,UAAS,KAA0C;AACxE,cAAA,IAAI,IAAA,CAAK,UAAA,CAAW,SAAS,CAAA,EAAG;AAC9B,gBAAA,MAAM,EAAA,GAAK,MAAM,kBAAA,CAAmB,QAAA,EAAU,IAAI,CAAA;AAClD,gBAAA,IAAI,EAAA,EAAI;AACN,kBAAA,MAAM,QAAA,GAAW,MAAMC,qBAAA,CAAe,QAAQ,CAAA;AAC9C,kBAAA,MAAM,IAAI,EAAA,CAAG,OAAA;AAAA,oBACX;AAAA,mBACF,CACG,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,EAAI,GAAI,GAAI,CAAA,EAAG,IAAI,CAAA,CAClD,GAAA,EAAI;AAAA,gBACT;AACA,gBAAA,OAAO,EAAA;AAAA,cACT;AACA,cAAA,OAAOC,uBAAA,CAAiB,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AAAA,YAC5C;AAAA;AACF,SACF;AAAA,QACA,IAAA,EAAM;AAAA,UACJ,SAAA,EAAW,WAAA;AAAA;AAAA;AAAA;AAAA,UAIX,MAAA,EAAQ;AAAA,YACN,KAAA,EAAO;AAAA,WACT;AAAA,UACA,gBAAA,EAAkB;AAAA,YAChB,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,KAAA,EAAO,YAAA,EAAc,QAAA,EAAU,KAAA,EAAO,KAAA,EAAM;AAAA,YAC9E,SAAA,EAAW,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,KAAA,EAAO,YAAA,EAAc,EAAA,EAAI,KAAA,EAAO,IAAA,EAAK;AAAA,YAC5E,QAAA,EAAU,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,KAAA,EAAO,YAAA,EAAc,EAAA,EAAI,KAAA,EAAO,IAAA,EAAK;AAAA,YAC3E,YAAA,EAAc,EAAE,IAAA,EAAM,SAAA,EAAW,UAAU,KAAA,EAAO,YAAA,EAAc,KAAA,EAAO,KAAA,EAAO,KAAA;AAAM;AACtF,SACF;AAAA,QACA,OAAA,EAAS;AAAA,UACP,SAAA,EAAW,cAAA;AAAA;AAAA;AAAA,UAGX,SAAA,EAAW,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,CAAA;AAAA;AAAA,UAC1B,SAAA,EAAW,KAAK,EAAA,GAAK;AAAA;AAAA,SACvB;AAAA,QACA,OAAA,EAAS,EAAE,SAAA,EAAW,cAAA,EAAe;AAAA,QACrC,YAAA,EAAc,EAAE,SAAA,EAAW,mBAAA,EAAoB;AAAA,QAC/C,aAAA,EAAe;AAAA,UACb,IAAA,EAAM;AAAA,YACJ,MAAA,EAAQ;AAAA,cACN,MAAA,EAAQ,OAAO,QAAA,KAAsC;AACnD,gBAAA,MAAM,OAAA,GAAU,MAAMC,yCAAA,CAAwB,GAAA,CAAI,EAAE,CAAA;AACpD,gBAAA,IAAI,CAAC,OAAA,EAAS;AACZ,kBAAA,MAAM,OAAA,GAAU,MAAMC,uCAAA,CAAsB,GAAA,CAAI,EAAE,CAAA;AAClD,kBAAA,IAAI,CAAC,OAAA,EAAS;AACZ,oBAAA,MAAM,IAAIC,YAAA,CAAS,aAAA,EAAe,EAAE,OAAA,EAAS,uCAAuC,CAAA;AAAA,kBACtF;AAAA,gBACF;AACA,gBAAA,MAAM,CAAA,GAAI,QAAA;AAGV,gBAAA,MAAM,IAAA,GAAA,CAAQ,CAAA,CAAE,IAAA,IAAQ,MAAA,EAAQ,QAAA,EAAS;AACzC,gBAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,EAAK,CAAE,MAAM,KAAK,CAAA;AAGrC,gBAAA,MAAM,SAAA,GAAY,CAAA,CAAE,SAAA,IAAa,KAAA,CAAM,CAAC,CAAA,IAAK,MAAA;AAC7C,gBAAA,MAAM,QAAA,GAAW,EAAE,QAAA,IAAY,KAAA,CAAM,MAAM,CAAC,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,IAAK,SAAA;AAC3D,gBAAA,OAAO,EAAE,IAAA,EAAM,EAAE,GAAG,QAAA,EAAU,MAAM,SAAA,EAAW,QAAA,EAAU,IAAA,EAAM,QAAA,EAAS,EAAE;AAAA,cAC5E,CAAA;AAAA,cACA,KAAA,EAAO,OAAO,IAAA,KAAyB;AAIrC,gBAAA,IAAI;AAIF,kBAAA,MAAM,EAAE,WAAA,EAAY,GAAI,MAAM,OAAO,qBAAkB,CAAA;AACvD,kBAAA,MAAM,IAAA,GAAO,IAAI,WAAA,CAAY,GAAA,CAAI,EAAE,CAAA;AACnC,kBAAA,MAAM,QAAA,GAAY,MAAM,IAAA,CAAK,iBAAA,CAAkB,KAAK,EAAE,CAAA,KAAO,IAAI,OAAA,GAAU,QAAA;AAC3E,kBAAA,MAAM,IAAA,CAAK,iBAAA,CAAkB,IAAA,CAAK,EAAA,EAAI,QAAQ,CAAA;AAAA,gBAChD,CAAA,CAAA,MAAQ;AAAA,gBAER;AAAA,cACF;AAAA;AACF;AACF;AACF;AACF,KACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA,OAAA,EAAS;AAAA;AAAA;AAAA,MAGPC,mBAAA,CAAU;AAAA,QACR,eAAe,OAAO,EAAE,KAAA,EAAO,GAAA,IAAuC,QAAA,KAAkB;AACtF,UAAA,MAAM,kBAAA;AAAA,YACJ,GAAA,CAAI,EAAA;AAAA,YAAI,KAAA;AAAA,YACR,mBAAA;AAAA,YACA,CAAA;AAAA;AAAA;AAAA,0BAAA,EAGgB,GAAG,CAAA;AAAA,4DAAA,EAC+B,GAAG,CAAA;AAAA,kBAAA;AAAA,WAEvD;AAAA,QACF,CAAA;AAAA,QACA,WAAW,EAAA,GAAK;AAAA,OACjB,CAAA;AAAA;AAAA,MAGDC,iBAAA,CAAS;AAAA,QACP,mBAAA,EAAqB,OAAO,MAAA,EAAsD,QAAA,KAAkB;AAClG,UAAA,MAAM,kBAAA;AAAA,YACJ,GAAA,CAAI,EAAA;AAAA,YAAI,MAAA,CAAO,KAAA;AAAA,YACf,mBAAA;AAAA,YACA,CAAA;AAAA;AAAA,0FAAA,EAEgF,OAAO,GAAG,CAAA;AAAA;AAAA,kBAAA;AAAA,WAG5F;AAAA,QACF,CAAA;AAAA,QACA,SAAA,EAAW,CAAA;AAAA,QACX,WAAW,EAAA,GAAK;AAAA,OACjB,CAAA;AAAA,MAEDC,yBAAA,CAAa;AAAA,QACX,MAAA,EAAQ;AAAA,UACN,YAAA,EAAc;AAAA,YACZ,SAAA,EAAW,aAAA;AAAA,YACX,gBAAA,EAAkB;AAAA,cAChB,MAAA,EAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,KAAA,EAAO,YAAA,EAAc,QAAA,EAAU,KAAA,EAAO,IAAA,EAAK;AAAA,cAC/E,QAAQ,EAAE,IAAA,EAAM,UAAU,QAAA,EAAU,KAAA,EAAO,OAAO,IAAA,EAAK;AAAA,cACvD,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,KAAA,EAAO,YAAA,EAAc,EAAA,EAAI,KAAA,EAAO,IAAA;AAAK;AAC1E,WACF;AAAA,UACA,MAAA,EAAQ;AAAA,YACN,SAAA,EAAW,oBAAA;AAAA,YACX,MAAA,EAAQ,EAAE,cAAA,EAAgB,WAAA;AAAY,WACxC;AAAA,UACA,UAAA,EAAY;AAAA,YACV,SAAA,EAAW,wBAAA;AAAA,YACX,MAAA,EAAQ,EAAE,cAAA,EAAgB,WAAA;AAAY,WACxC;AAAA,UACA,IAAA,EAAM;AAAA,YACJ,SAAA,EAAW,kBAAA;AAAA,YACX,MAAA,EAAQ,EAAE,cAAA,EAAgB,WAAA;AAAY;AACxC;AACF,OACD;AAAA,KACH;AAAA;AAAA;AAAA;AAAA,IAKA,eAAA,EAAiB;AAAA,MACf,GAAI,GAAA,CAAI,gBAAA,IAAoB,GAAA,CAAI,oBAAA,GAC5B,EAAE,MAAA,EAAQ,EAAE,QAAA,EAAU,GAAA,CAAI,kBAAkB,YAAA,EAAc,GAAA,CAAI,oBAAA,EAAqB,KACnF,EAAC;AAAA,MACL,GAAI,GAAA,CAAI,gBAAA,IAAoB,GAAA,CAAI,oBAAA,GAC5B,EAAE,MAAA,EAAQ,EAAE,QAAA,EAAU,GAAA,CAAI,kBAAkB,YAAA,EAAc,GAAA,CAAI,oBAAA,EAAqB,KACnF;AAAC;AACP,GACF;AACF;AAMO,SAAS,UAAA,CAAW,GAAA,EAAe,gBAAA,EAAqC,cAAA,EAAyB;AAItG,EAAA,IAAI,CAAC,GAAA,CAAI,kBAAA,IAAsB,GAAA,CAAI,kBAAA,CAAmB,SAAS,EAAA,EAAI;AACjE,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAGF;AAAA,EACF;AACA,EAAA,MAAM,QAAA,GAAW,qBAAA,CAAsB,GAAA,EAAK,cAAc,CAAA;AAC1D,EAAA,MAAM,OAAA,GAAU,gBAAA,GAAmB,gBAAA,CAAiB,QAAQ,CAAA,GAAI,QAAA;AAChE,EAAA,OAAOC,sBAAW,OAA2C,CAAA;AAC/D","file":"chunk-NUKJ54GA.cjs","sourcesContent":["/**\n * Better Auth configuration for SonicJS — via the better-auth-cloudflare shim.\n *\n * A fresh auth instance is built per request (Workers lifecycle). The existing\n * `auth_user` table is used as Better Auth's user model. Legacy SonicJS PBKDF2\n * hashes are verified and transparently upgraded to scrypt on first login. KV\n * (CACHE_KV) is used as session secondary storage so getSession does not hit D1\n * on every request.\n *\n * Extend via config.auth.extendBetterAuth in createSonicJSApp() to add social\n * providers, magic link, 2FA, etc.\n */\n/** Send an email via the SonicJS email plugin (Resend).\n * Loads apiKey/fromEmail/fromName from the `plugins` table at runtime.\n * Falls back to console.log when the plugin is unconfigured (local dev). */\nasync function sendViaEmailPlugin(\n db: D1Database,\n to: string,\n subject: string,\n html: string\n): Promise<void> {\n try {\n const row = (await db\n .prepare(\"SELECT settings FROM plugins WHERE id = 'email'\")\n .first()) as { settings: string } | null\n if (row?.settings) {\n const { apiKey, fromEmail, fromName } = JSON.parse(row.settings) as {\n apiKey?: string; fromEmail?: string; fromName?: string\n }\n if (apiKey && fromEmail) {\n await fetch('https://api.resend.com/emails', {\n method: 'POST',\n headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n from: `${fromName ?? 'SonicJS'} <${fromEmail}>`,\n to: [to],\n subject,\n html,\n }),\n })\n return\n }\n }\n } catch { /* fall through to dev log */ }\n console.log(`[email-dev] To:${to} | Subject:${subject}`)\n}\n\nimport { betterAuth } from 'better-auth'\nimport { withCloudflare } from 'better-auth-cloudflare'\nimport { hashPassword as baHashPassword, verifyPassword as baVerifyPassword } from 'better-auth/crypto'\nimport { APIError } from 'better-auth/api'\nimport { magicLink } from 'better-auth/plugins/magic-link'\nimport { emailOTP } from 'better-auth/plugins/email-otp'\nimport { organization } from 'better-auth/plugins/organization'\nimport { drizzle } from 'drizzle-orm/d1'\nimport { authUser, authSession, authAccount, authVerification, authTenant, authTenantMember, authTenantInvitation, authTenantTeam } from '../db/schema'\nimport { isRegistrationEnabled, isFirstUserRegistration } from '../services/auth-validation'\nimport type { Bindings } from '../app'\n\n/**\n * Verify a password against a SonicJS legacy PBKDF2 hash:\n * pbkdf2:<iterations>:<saltHex>:<hashHex> (PBKDF2-SHA256, 256-bit)\n * Mirrors AuthManager.verifyPassword in middleware/auth.ts.\n */\nasync function verifyLegacyPbkdf2(password: string, stored: string): Promise<boolean> {\n const parts = stored.split(':')\n if (parts.length !== 4) return false\n const iterations = parseInt(parts[1]!, 10)\n const saltBytes = parts[2]!.match(/.{2}/g)\n if (!saltBytes || !Number.isFinite(iterations)) return false\n const salt = new Uint8Array(saltBytes.map((b) => parseInt(b, 16)))\n const km = await crypto.subtle.importKey('raw', new TextEncoder().encode(password), 'PBKDF2', false, ['deriveBits'])\n const bits = await crypto.subtle.deriveBits({ name: 'PBKDF2', salt, iterations, hash: 'SHA-256' }, km, 256)\n const actual = Array.from(new Uint8Array(bits)).map((b) => b.toString(16).padStart(2, '0')).join('')\n const expected = parts[3]!\n if (actual.length !== expected.length) return false\n let diff = 0\n for (let i = 0; i < actual.length; i++) diff |= actual.charCodeAt(i) ^ expected.charCodeAt(i)\n return diff === 0\n}\n\n/**\n * Build the default Better Auth options used by SonicJS (through the CF shim).\n * Exported so apps can extend via config.auth.extendBetterAuth.\n */\nexport function getDefaultAuthOptions(env: Bindings, requestBaseURL?: string) {\n const db = drizzle(env.DB)\n\n return {\n secret: env.BETTER_AUTH_SECRET,\n baseURL: env.BETTER_AUTH_URL || requestBaseURL,\n appName: 'SonicJS',\n ...withCloudflare(\n {\n autoDetectIpAddress: true,\n geolocationTracking: false,\n cf: {},\n d1: {\n db,\n options: {\n // Keys MUST match modelName values — BA resolves by modelName, not by JS variable name.\n schema: { auth_user: authUser, auth_session: authSession, auth_account: authAccount, auth_verification: authVerification, auth_tenant: authTenant, auth_tenant_member: authTenantMember, auth_tenant_invitation: authTenantInvitation, auth_tenant_team: authTenantTeam },\n },\n },\n kv: env.CACHE_KV, // session secondary storage → getSession skips D1\n },\n {\n basePath: '/auth',\n emailAndPassword: {\n enabled: true,\n autoSignIn: true,\n // Transparent migration of SonicJS legacy PBKDF2 hashes: verify against\n // the old format on login, then re-hash to scrypt and persist. No\n // mass-rehash, no forced password resets.\n password: {\n verify: async ({ hash, password }: { hash: string; password: string }) => {\n if (hash.startsWith('pbkdf2:')) {\n const ok = await verifyLegacyPbkdf2(password, hash)\n if (ok) {\n const upgraded = await baHashPassword(password)\n await env.DB.prepare(\n \"UPDATE auth_account SET password = ?, updated_at = ? WHERE password = ? AND provider_id = 'credential'\"\n )\n .bind(upgraded, Math.floor(Date.now() / 1000), hash)\n .run()\n }\n return ok\n }\n return baVerifyPassword({ hash, password })\n },\n },\n },\n user: {\n modelName: 'auth_user',\n // Field-mapping values are Drizzle *property keys* (camelCase), which\n // already match Better Auth's defaults for emailVerified/createdAt/\n // updatedAt. Only `image` differs (SonicJS uses `avatar`).\n fields: {\n image: 'avatar',\n },\n additionalFields: {\n role: { type: 'string', required: false, defaultValue: 'viewer', input: false },\n firstName: { type: 'string', required: false, defaultValue: '', input: true },\n lastName: { type: 'string', required: false, defaultValue: '', input: true },\n isSuperAdmin: { type: 'boolean', required: false, defaultValue: false, input: false },\n },\n },\n session: {\n modelName: 'auth_session',\n // Drizzle property keys already match Better Auth defaults (userId,\n // expiresAt, ipAddress, …) — no field overrides needed.\n expiresIn: 60 * 60 * 24 * 7, // 7 days\n updateAge: 60 * 60 * 24, // refresh once per day\n },\n account: { modelName: 'auth_account' },\n verification: { modelName: 'auth_verification' },\n databaseHooks: {\n user: {\n create: {\n before: async (userData: Record<string, unknown>) => {\n const isFirst = await isFirstUserRegistration(env.DB)\n if (!isFirst) {\n const enabled = await isRegistrationEnabled(env.DB)\n if (!enabled) {\n throw new APIError('BAD_REQUEST', { message: 'Registration is currently disabled.' })\n }\n }\n const d = userData as {\n name?: string; email?: string; firstName?: string; lastName?: string\n }\n const name = (d.name ?? 'User').toString()\n const parts = name.trim().split(/\\s+/)\n // Prefer explicitly-provided fields (registration form); fall back\n // to values derived from name/email.\n const firstName = d.firstName || parts[0] || 'User'\n const lastName = d.lastName || parts.slice(1).join(' ') || firstName\n return { data: { ...userData, name, firstName, lastName, role: 'viewer' } }\n },\n after: async (user: { id: string }) => {\n // Assign dynamic RBAC membership. The first real user receives\n // Administrator so fresh installs can enter the portal; later\n // self-registered users receive Viewer.\n try {\n // RBAC roles/assignments are document-backed (services/rbac.ts).\n // First real portal admin → Administrator; later users → Viewer.\n // setUserRoles (via addUserRoleByName) also projects auth_user.role.\n const { RbacService } = await import('../services/rbac')\n const rbac = new RbacService(env.DB)\n const roleName = (await rbac.countPortalAdmins(user.id)) === 0 ? 'admin' : 'viewer'\n await rbac.addUserRoleByName(user.id, roleName)\n } catch {\n /* rbac docs may not be seeded yet on older schemas — non-fatal */\n }\n },\n },\n },\n },\n }\n ),\n\n // ── Phase 4: BA-native login methods ─────────────────────────────────────\n // Magic-link and Email-OTP replace the standalone SonicJS plugins that\n // minted JWT cookies. Social providers replace the bespoke oauth-providers\n // plugin. All are gated on the relevant env vars / email service config\n // so they activate only when configured.\n\n plugins: [\n // Magic-link passwordless auth. Sends a one-time link to the user's inbox;\n // the link resolves to a BA session. Requires a working email service.\n magicLink({\n sendMagicLink: async ({ email, url }: { email: string; url: string }, _request: any) => {\n await sendViaEmailPlugin(\n env.DB, email,\n 'Your sign-in link',\n `<div style=\"font-family:sans-serif;max-width:600px\">\n <h2>Sign in to SonicJS</h2>\n <p>Click the link below to sign in. Expires in 15 minutes.</p>\n <p><a href=\"${url}\" style=\"background:#465FFF;color:#fff;padding:12px 24px;border-radius:6px;text-decoration:none\">Sign in</a></p>\n <p style=\"color:#666;font-size:12px\">Or copy: ${url}</p>\n </div>`\n )\n },\n expiresIn: 15 * 60,\n }),\n\n // Email OTP — 6-digit code sent to inbox. Replaces the otp-login-plugin.\n emailOTP({\n sendVerificationOTP: async (params: { email: string; otp: string; type: string }, _request: any) => {\n await sendViaEmailPlugin(\n env.DB, params.email,\n 'Your sign-in code',\n `<div style=\"font-family:sans-serif;max-width:600px\">\n <h2>Your one-time code</h2>\n <p style=\"font-size:36px;font-weight:bold;letter-spacing:8px;color:#465FFF\">${params.otp}</p>\n <p style=\"color:#666\">Expires in 10 minutes. Do not share this code.</p>\n </div>`\n )\n },\n otpLength: 6,\n expiresIn: 10 * 60,\n }),\n\n organization({\n schema: {\n organization: {\n modelName: 'auth_tenant',\n additionalFields: {\n status: { type: 'string', required: false, defaultValue: 'active', input: true },\n domain: { type: 'string', required: false, input: true },\n notes: { type: 'string', required: false, defaultValue: '', input: true },\n },\n },\n member: {\n modelName: 'auth_tenant_member',\n fields: { organizationId: 'tenant_id' },\n },\n invitation: {\n modelName: 'auth_tenant_invitation',\n fields: { organizationId: 'tenant_id' },\n },\n team: {\n modelName: 'auth_tenant_team',\n fields: { organizationId: 'tenant_id' },\n },\n },\n }),\n ],\n\n // ── Phase 4: Social providers ─────────────────────────────────────────\n // Activated when the relevant env vars are set. Replaces the bespoke\n // oauth-providers SonicJS plugin. Set via wrangler secret put / .dev.vars.\n socialProviders: {\n ...(env.GITHUB_CLIENT_ID && env.GITHUB_CLIENT_SECRET\n ? { github: { clientId: env.GITHUB_CLIENT_ID, clientSecret: env.GITHUB_CLIENT_SECRET } }\n : {}),\n ...(env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET\n ? { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET } }\n : {}),\n },\n }\n}\n\nexport type BetterAuthDefaultOptions = ReturnType<typeof getDefaultAuthOptions>\nexport type ExtendBetterAuth = (opts: BetterAuthDefaultOptions) => BetterAuthDefaultOptions\n\n/** Create a Better Auth instance for this request. */\nexport function createAuth(env: Bindings, extendBetterAuth?: ExtendBetterAuth, requestBaseURL?: string) {\n // Hard-fail rather than sign sessions with an undefined/blank secret. The\n // secret must be provided via `wrangler secret put BETTER_AUTH_SECRET`\n // (prod/preview) or a gitignored `.dev.vars` (local) — never committed.\n if (!env.BETTER_AUTH_SECRET || env.BETTER_AUTH_SECRET.length < 16) {\n throw new Error(\n 'BETTER_AUTH_SECRET is missing or too short. Set it as a Wrangler secret ' +\n '(wrangler secret put BETTER_AUTH_SECRET) or in a gitignored .dev.vars for local dev. ' +\n 'Refusing to initialize auth without a strong signing secret.'\n )\n }\n const defaults = getDefaultAuthOptions(env, requestBaseURL)\n const options = extendBetterAuth ? extendBetterAuth(defaults) : defaults\n return betterAuth(options as Parameters<typeof betterAuth>[0])\n}\n\nexport type SonicJSAuth = ReturnType<typeof createAuth>\n"]}
|