@kyro-cms/core 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/dist/{WebhookService-BznDc2AT.d.ts → WebhookService-BCpW2dyL.d.ts} +1 -1
  2. package/dist/{WebhookService-mZZ75syh.d.cts → WebhookService-DxYSFvNg.d.cts} +1 -1
  3. package/dist/api-handler.cjs +52 -0
  4. package/dist/api-handler.cjs.map +1 -0
  5. package/dist/api-handler.d.cts +9 -0
  6. package/dist/api-handler.d.ts +9 -0
  7. package/dist/api-handler.js +46 -0
  8. package/dist/api-handler.js.map +1 -0
  9. package/dist/{base-Hu6ij8sZ.d.ts → base-DvvNqnM-.d.cts} +16 -5
  10. package/dist/{base-Db9LkB1N.d.cts → base-eVegJ_Pr.d.ts} +16 -5
  11. package/dist/bootstrap-DGJ3N7SO.js +6 -0
  12. package/dist/{bootstrap-LL6O7PWO.js.map → bootstrap-DGJ3N7SO.js.map} +1 -1
  13. package/dist/bootstrap-O5UGUTYU.cjs +31 -0
  14. package/dist/{bootstrap-BMWVB2T6.cjs.map → bootstrap-O5UGUTYU.cjs.map} +1 -1
  15. package/dist/{chunk-QKOFKITP.js → chunk-2HFJUUFZ.js} +3 -11
  16. package/dist/chunk-2HFJUUFZ.js.map +1 -0
  17. package/dist/chunk-2SJATAN4.js +5514 -0
  18. package/dist/chunk-2SJATAN4.js.map +1 -0
  19. package/dist/{chunk-DIC236EW.js → chunk-342BJNBI.js} +167 -24
  20. package/dist/chunk-342BJNBI.js.map +1 -0
  21. package/dist/{chunk-OUGKLCYF.js → chunk-3AJE4SEG.js} +4 -3
  22. package/dist/chunk-3AJE4SEG.js.map +1 -0
  23. package/dist/chunk-6LPNEC6D.js +617 -0
  24. package/dist/chunk-6LPNEC6D.js.map +1 -0
  25. package/dist/{chunk-BXMWDUED.js → chunk-A4USRVTQ.js} +2 -2
  26. package/dist/chunk-A4USRVTQ.js.map +1 -0
  27. package/dist/chunk-ADLJSJSN.cjs +13 -0
  28. package/dist/chunk-ADLJSJSN.cjs.map +1 -0
  29. package/dist/chunk-ATBOUGQP.cjs +513 -0
  30. package/dist/chunk-ATBOUGQP.cjs.map +1 -0
  31. package/dist/{chunk-KB6QF4HO.js → chunk-B76I67F3.js} +246 -141
  32. package/dist/chunk-B76I67F3.js.map +1 -0
  33. package/dist/chunk-BQ2T4WRS.js +140 -0
  34. package/dist/chunk-BQ2T4WRS.js.map +1 -0
  35. package/dist/chunk-CZ3HWX2X.cjs +622 -0
  36. package/dist/chunk-CZ3HWX2X.cjs.map +1 -0
  37. package/dist/{chunk-PNBZZ76A.cjs → chunk-DAIBBBOL.cjs} +246 -140
  38. package/dist/chunk-DAIBBBOL.cjs.map +1 -0
  39. package/dist/{chunk-U74F3YZU.js → chunk-DBUYB32X.js} +15 -3
  40. package/dist/chunk-DBUYB32X.js.map +1 -0
  41. package/dist/chunk-DLHUQO25.cjs +1746 -0
  42. package/dist/chunk-DLHUQO25.cjs.map +1 -0
  43. package/dist/{chunk-GE5DMB44.js → chunk-E3BZLMX6.js} +55 -49
  44. package/dist/chunk-E3BZLMX6.js.map +1 -0
  45. package/dist/{chunk-44BF6ALS.cjs → chunk-H4XCAPA6.cjs} +55 -49
  46. package/dist/chunk-H4XCAPA6.cjs.map +1 -0
  47. package/dist/{chunk-VIONYQ2K.cjs → chunk-IBG6V56E.cjs} +16 -32
  48. package/dist/chunk-IBG6V56E.cjs.map +1 -0
  49. package/dist/{chunk-LIJVWQKU.cjs → chunk-IX3ABYKZ.cjs} +43 -31
  50. package/dist/chunk-IX3ABYKZ.cjs.map +1 -0
  51. package/dist/chunk-JYGIFBBS.cjs +146 -0
  52. package/dist/chunk-JYGIFBBS.cjs.map +1 -0
  53. package/dist/{chunk-42JPONZU.cjs → chunk-K7JPTH3G.cjs} +17 -16
  54. package/dist/chunk-K7JPTH3G.cjs.map +1 -0
  55. package/dist/{chunk-RLTG4YZM.cjs → chunk-KOCTZKPV.cjs} +2 -2
  56. package/dist/chunk-KOCTZKPV.cjs.map +1 -0
  57. package/dist/chunk-MMYAIYHJ.cjs +5538 -0
  58. package/dist/chunk-MMYAIYHJ.cjs.map +1 -0
  59. package/dist/{chunk-EWP5AT6A.cjs → chunk-N4H37VN4.cjs} +2 -11
  60. package/dist/chunk-N4H37VN4.cjs.map +1 -0
  61. package/dist/chunk-P2YW545G.js +11 -0
  62. package/dist/chunk-P2YW545G.js.map +1 -0
  63. package/dist/chunk-Q23JB3KL.js +488 -0
  64. package/dist/chunk-Q23JB3KL.js.map +1 -0
  65. package/dist/{chunk-E5X75WNB.js → chunk-QXIQWPAP.js} +14 -30
  66. package/dist/chunk-QXIQWPAP.js.map +1 -0
  67. package/dist/chunk-R3XIBBAW.cjs +34 -0
  68. package/dist/chunk-R3XIBBAW.cjs.map +1 -0
  69. package/dist/{chunk-KWGNR4HM.js → chunk-REK7AYOC.js} +82 -9
  70. package/dist/chunk-REK7AYOC.js.map +1 -0
  71. package/dist/chunk-RGIQKTZ7.js +68 -0
  72. package/dist/chunk-RGIQKTZ7.js.map +1 -0
  73. package/dist/chunk-RYDGMBIG.js +1737 -0
  74. package/dist/chunk-RYDGMBIG.js.map +1 -0
  75. package/dist/chunk-SDMNUYVU.js +30 -0
  76. package/dist/chunk-SDMNUYVU.js.map +1 -0
  77. package/dist/chunk-VEI5KQVC.cjs +1246 -0
  78. package/dist/chunk-VEI5KQVC.cjs.map +1 -0
  79. package/dist/{chunk-FTSSDDZQ.cjs → chunk-VJT6P4N6.cjs} +82 -9
  80. package/dist/chunk-VJT6P4N6.cjs.map +1 -0
  81. package/dist/{chunk-HT6VE4NW.cjs → chunk-W3KPQX7V.cjs} +168 -25
  82. package/dist/chunk-W3KPQX7V.cjs.map +1 -0
  83. package/dist/{chunk-LTRCYJAG.js → chunk-WOWUL7ZY.js} +3 -2
  84. package/dist/chunk-WOWUL7ZY.js.map +1 -0
  85. package/dist/{chunk-7YITG2US.cjs → chunk-WQBRWOQT.cjs} +3 -2
  86. package/dist/chunk-WQBRWOQT.cjs.map +1 -0
  87. package/dist/chunk-X3CU27OO.cjs +78 -0
  88. package/dist/chunk-X3CU27OO.cjs.map +1 -0
  89. package/dist/chunk-XIXGJGQW.js +1228 -0
  90. package/dist/chunk-XIXGJGQW.js.map +1 -0
  91. package/dist/cli/index.cjs +2 -2
  92. package/dist/cli/index.js +2 -2
  93. package/dist/client.cjs +23 -13
  94. package/dist/client.d.cts +4 -2
  95. package/dist/client.d.ts +4 -2
  96. package/dist/client.js +3 -1
  97. package/dist/drizzle/index.cjs +20 -19
  98. package/dist/drizzle/index.d.cts +28 -7
  99. package/dist/drizzle/index.d.ts +28 -7
  100. package/dist/drizzle/index.js +5 -4
  101. package/dist/fields/index.cjs +105 -0
  102. package/dist/fields/index.cjs.map +1 -0
  103. package/dist/fields/index.d.cts +27 -0
  104. package/dist/fields/index.d.ts +27 -0
  105. package/dist/fields/index.js +4 -0
  106. package/dist/fields/index.js.map +1 -0
  107. package/dist/graphql/index.cjs +4 -3
  108. package/dist/graphql/index.d.cts +3 -2
  109. package/dist/graphql/index.d.ts +3 -2
  110. package/dist/graphql/index.js +2 -1
  111. package/dist/{index-Ci6r4xnN.d.ts → index-CLp-DRKA.d.ts} +2 -1
  112. package/dist/{index-11MDNKce.d.cts → index-DfO7G4kN.d.cts} +2 -1
  113. package/dist/index.cjs +2621 -6672
  114. package/dist/index.cjs.map +1 -1
  115. package/dist/index.d.cts +136 -47
  116. package/dist/index.d.ts +136 -47
  117. package/dist/index.js +2333 -6546
  118. package/dist/index.js.map +1 -1
  119. package/dist/integration.cjs +68 -0
  120. package/dist/integration.cjs.map +1 -0
  121. package/dist/integration.d.cts +27 -0
  122. package/dist/integration.d.ts +27 -0
  123. package/dist/integration.js +61 -0
  124. package/dist/integration.js.map +1 -0
  125. package/dist/mongodb/index.cjs +4 -4
  126. package/dist/mongodb/index.d.cts +20 -6
  127. package/dist/mongodb/index.d.ts +20 -6
  128. package/dist/mongodb/index.js +2 -2
  129. package/dist/postgres-auth-adapter-7F3ECO7I.js +5 -0
  130. package/dist/{postgres-auth-adapter-OTRWSTT5.js.map → postgres-auth-adapter-7F3ECO7I.js.map} +1 -1
  131. package/dist/postgres-auth-adapter-Z463NYJZ.cjs +14 -0
  132. package/dist/{postgres-auth-adapter-EVRPO7BQ.cjs.map → postgres-auth-adapter-Z463NYJZ.cjs.map} +1 -1
  133. package/dist/redis-adapter-LPUWLE4Y.cjs +13 -0
  134. package/dist/{redis-adapter-E7PMN5HW.cjs.map → redis-adapter-LPUWLE4Y.cjs.map} +1 -1
  135. package/dist/redis-adapter-THYDCGQR.js +4 -0
  136. package/dist/{redis-adapter-HOO67RBQ.js.map → redis-adapter-THYDCGQR.js.map} +1 -1
  137. package/dist/rest/index.cjs +8 -5
  138. package/dist/rest/index.d.cts +6 -3
  139. package/dist/rest/index.d.ts +6 -3
  140. package/dist/rest/index.js +6 -3
  141. package/dist/{schema-CNB2DDTX.js → schema-6Q4W6AE6.js} +3 -3
  142. package/dist/{schema-CNB2DDTX.js.map → schema-6Q4W6AE6.js.map} +1 -1
  143. package/dist/{schema-Y777CQQS.cjs → schema-TIYTCIKX.cjs} +14 -14
  144. package/dist/{schema-Y777CQQS.cjs.map → schema-TIYTCIKX.cjs.map} +1 -1
  145. package/dist/templates/index.cjs +27 -23
  146. package/dist/templates/index.d.cts +8 -2
  147. package/dist/templates/index.d.ts +8 -2
  148. package/dist/templates/index.js +1 -1
  149. package/dist/trpc/index.cjs +12 -11
  150. package/dist/trpc/index.d.cts +3 -2
  151. package/dist/trpc/index.d.ts +3 -2
  152. package/dist/trpc/index.js +3 -2
  153. package/dist/{types-kGfsGdos.d.cts → types-Bs1up4yP.d.ts} +76 -244
  154. package/dist/{types-1u353OHN.d.ts → types-Da83JLDk.d.cts} +6 -2
  155. package/dist/{types-1u353OHN.d.cts → types-Da83JLDk.d.ts} +6 -2
  156. package/dist/{types-kGfsGdos.d.ts → types-J3R9nVsZ.d.cts} +76 -244
  157. package/dist/types-VtjUxIMp.d.cts +246 -0
  158. package/dist/types-VtjUxIMp.d.ts +246 -0
  159. package/package.json +16 -9
  160. package/dist/bootstrap-BMWVB2T6.cjs +0 -31
  161. package/dist/bootstrap-LL6O7PWO.js +0 -6
  162. package/dist/chunk-42JPONZU.cjs.map +0 -1
  163. package/dist/chunk-44BF6ALS.cjs.map +0 -1
  164. package/dist/chunk-4M5PHMUE.cjs +0 -947
  165. package/dist/chunk-4M5PHMUE.cjs.map +0 -1
  166. package/dist/chunk-6MSSF46R.js +0 -941
  167. package/dist/chunk-6MSSF46R.js.map +0 -1
  168. package/dist/chunk-7YITG2US.cjs.map +0 -1
  169. package/dist/chunk-BTOE3VUK.js +0 -330
  170. package/dist/chunk-BTOE3VUK.js.map +0 -1
  171. package/dist/chunk-BXMWDUED.js.map +0 -1
  172. package/dist/chunk-DIC236EW.js.map +0 -1
  173. package/dist/chunk-E5X75WNB.js.map +0 -1
  174. package/dist/chunk-E63IF3MD.cjs +0 -951
  175. package/dist/chunk-E63IF3MD.cjs.map +0 -1
  176. package/dist/chunk-EWP5AT6A.cjs.map +0 -1
  177. package/dist/chunk-FTSSDDZQ.cjs.map +0 -1
  178. package/dist/chunk-GE5DMB44.js.map +0 -1
  179. package/dist/chunk-GVFB5C6O.cjs +0 -345
  180. package/dist/chunk-GVFB5C6O.cjs.map +0 -1
  181. package/dist/chunk-HT6VE4NW.cjs.map +0 -1
  182. package/dist/chunk-HVSQDZZJ.cjs +0 -765
  183. package/dist/chunk-HVSQDZZJ.cjs.map +0 -1
  184. package/dist/chunk-HYC4GNHX.js +0 -758
  185. package/dist/chunk-HYC4GNHX.js.map +0 -1
  186. package/dist/chunk-KB6QF4HO.js.map +0 -1
  187. package/dist/chunk-KWGNR4HM.js.map +0 -1
  188. package/dist/chunk-LIJVWQKU.cjs.map +0 -1
  189. package/dist/chunk-LTRCYJAG.js.map +0 -1
  190. package/dist/chunk-OUGKLCYF.js.map +0 -1
  191. package/dist/chunk-PNBZZ76A.cjs.map +0 -1
  192. package/dist/chunk-QKOFKITP.js.map +0 -1
  193. package/dist/chunk-RLTG4YZM.cjs.map +0 -1
  194. package/dist/chunk-RRYXQMZG.js +0 -935
  195. package/dist/chunk-RRYXQMZG.js.map +0 -1
  196. package/dist/chunk-U74F3YZU.js.map +0 -1
  197. package/dist/chunk-VIONYQ2K.cjs.map +0 -1
  198. package/dist/postgres-auth-adapter-EVRPO7BQ.cjs +0 -14
  199. package/dist/postgres-auth-adapter-OTRWSTT5.js +0 -5
  200. package/dist/redis-adapter-E7PMN5HW.cjs +0 -13
  201. package/dist/redis-adapter-HOO67RBQ.js +0 -4
@@ -1,758 +0,0 @@
1
- import { settings } from './chunk-YT7HXXVN.js';
2
- import nodemailer from 'nodemailer';
3
-
4
- // src/config/ConfigService.ts
5
- var ConfigService = class _ConfigService {
6
- db;
7
- cache = {};
8
- static SENSITIVE_KEYS = [
9
- "storage.s3.secret_access_key",
10
- "storage.r2.secret_access_key",
11
- "storage.gcs.private_key",
12
- "storage.backblaze.application_key",
13
- "storage.wasabi.secret_access_key",
14
- "storage.ftp.password",
15
- "storage.bunny.api_key",
16
- "storage.cloudinary.api_secret",
17
- "storage.imgix.sign_key",
18
- "email.smtp.pass",
19
- "auth.jwt_secret",
20
- "auth.github_secret",
21
- "auth.google_secret",
22
- "auth.app_secret",
23
- "database.url",
24
- "redis.url",
25
- "auth.admin_password"
26
- ];
27
- constructor(db) {
28
- this.db = db;
29
- }
30
- /**
31
- * Initialize the service by loading all settings from the database
32
- */
33
- async load() {
34
- try {
35
- const allSettings = await this.db.select().from(settings);
36
- this.cache = allSettings.reduce((acc, row) => {
37
- acc[row.key] = row.value;
38
- return acc;
39
- }, {});
40
- } catch (error) {
41
- console.warn(
42
- "ConfigService: Could not load settings from database, using environment fallbacks.",
43
- error
44
- );
45
- }
46
- }
47
- /**
48
- * Get a settings value with environment fallback
49
- */
50
- get(key, envKey, defaultValue) {
51
- if (this.cache[key]) return this.cache[key];
52
- if (envKey && process.env[envKey]) return process.env[envKey];
53
- return defaultValue;
54
- }
55
- /**
56
- * Get storage configuration
57
- */
58
- getStorageConfig() {
59
- return {
60
- type: this.get("storage.type", "STORAGE_TYPE", "local"),
61
- s3: {
62
- bucket: this.get("storage.s3.bucket", "STORAGE_BUCKET"),
63
- region: this.get("storage.s3.region", "STORAGE_REGION", "us-east-1"),
64
- accessKeyId: this.get(
65
- "storage.s3.access_key_id",
66
- "STORAGE_ACCESS_KEY_ID"
67
- ),
68
- secretAccessKey: this.get(
69
- "storage.s3.secret_access_key",
70
- "STORAGE_SECRET_ACCESS_KEY"
71
- ),
72
- endpoint: this.get("storage.s3.endpoint", "STORAGE_ENDPOINT"),
73
- cdnUrl: this.get("storage.s3.cdn_url", "STORAGE_CDN_URL"),
74
- prefix: this.get("storage.s3.prefix", "STORAGE_PREFIX")
75
- },
76
- r2: {
77
- accountId: this.get("storage.r2.account_id", "R2_ACCOUNT_ID"),
78
- accessKeyId: this.get("storage.r2.access_key_id", "R2_ACCESS_KEY_ID"),
79
- secretAccessKey: this.get(
80
- "storage.r2.secret_access_key",
81
- "R2_SECRET_ACCESS_KEY"
82
- ),
83
- bucket: this.get("storage.r2.bucket", "R2_BUCKET"),
84
- cdnUrl: this.get("storage.r2.cdn_url", "R2_CDN_URL"),
85
- prefix: this.get("storage.r2.prefix", "R2_PREFIX")
86
- },
87
- gcs: {
88
- bucket: this.get("storage.gcs.bucket", "GCS_BUCKET"),
89
- projectId: this.get("storage.gcs.project_id", "GCS_PROJECT_ID"),
90
- clientEmail: this.get("storage.gcs.client_email", "GCS_CLIENT_EMAIL"),
91
- privateKey: this.get("storage.gcs.private_key", "GCS_PRIVATE_KEY"),
92
- cdnUrl: this.get("storage.gcs.cdn_url", "GCS_CDN_URL"),
93
- prefix: this.get("storage.gcs.prefix", "GCS_PREFIX")
94
- },
95
- digitalocean: {
96
- bucket: this.get("storage.digitalocean.bucket", "DO_BUCKET"),
97
- region: this.get("storage.digitalocean.region", "DO_REGION", "nyc3"),
98
- accessKeyId: this.get(
99
- "storage.digitalocean.access_key_id",
100
- "DO_ACCESS_KEY_ID"
101
- ),
102
- secretAccessKey: this.get(
103
- "storage.digitalocean.secret_access_key",
104
- "DO_SECRET_ACCESS_KEY"
105
- ),
106
- cdnUrl: this.get("storage.digitalocean.cdn_url", "DO_CDN_URL"),
107
- prefix: this.get("storage.digitalocean.prefix", "DO_PREFIX")
108
- },
109
- backblaze: {
110
- bucket: this.get("storage.backblaze.bucket", "BB_BUCKET"),
111
- accountId: this.get("storage.backblaze.account_id", "BB_ACCOUNT_ID"),
112
- applicationKeyId: this.get(
113
- "storage.backblaze.application_key_id",
114
- "BB_APPLICATION_KEY_ID"
115
- ),
116
- applicationKey: this.get(
117
- "storage.backblaze.application_key",
118
- "BB_APPLICATION_KEY"
119
- ),
120
- cdnUrl: this.get("storage.backblaze.cdn_url", "BB_CDN_URL"),
121
- prefix: this.get("storage.backblaze.prefix", "BB_PREFIX")
122
- },
123
- wasabi: {
124
- bucket: this.get("storage.wasabi.bucket", "WASABI_BUCKET"),
125
- region: this.get("storage.wasabi.region", "WASABI_REGION", "us-east-1"),
126
- accessKeyId: this.get(
127
- "storage.wasabi.access_key_id",
128
- "WASABI_ACCESS_KEY_ID"
129
- ),
130
- secretAccessKey: this.get(
131
- "storage.wasabi.secret_access_key",
132
- "WASABI_SECRET_ACCESS_KEY"
133
- ),
134
- cdnUrl: this.get("storage.wasabi.cdn_url", "WASABI_CDN_URL"),
135
- prefix: this.get("storage.wasabi.prefix", "WASABI_PREFIX")
136
- },
137
- bunny: {
138
- storageZone: this.get(
139
- "storage.bunny.storage_zone",
140
- "BUNNY_STORAGE_ZONE"
141
- ),
142
- apiKey: this.get("storage.bunny.api_key", "BUNNY_API_KEY"),
143
- cdnUrl: this.get("storage.bunny.cdn_url", "BUNNY_CDN_URL"),
144
- prefix: this.get("storage.bunny.prefix", "BUNNY_PREFIX")
145
- },
146
- ftp: {
147
- host: this.get("storage.ftp.host", "FTP_HOST"),
148
- port: parseInt(this.get("storage.ftp.port", "FTP_PORT", "21"), 10),
149
- user: this.get("storage.ftp.user", "FTP_USER"),
150
- password: this.get("storage.ftp.password", "FTP_PASSWORD"),
151
- secure: this.get("storage.ftp.secure", "FTP_SECURE") === "true",
152
- baseUrl: this.get("storage.ftp.base_url", "FTP_BASE_URL"),
153
- prefix: this.get("storage.ftp.prefix", "FTP_PREFIX")
154
- },
155
- cloudinary: {
156
- cloudName: this.get(
157
- "storage.cloudinary.cloud_name",
158
- "CLOUDINARY_CLOUD_NAME"
159
- ),
160
- apiKey: this.get("storage.cloudinary.api_key", "CLOUDINARY_API_KEY"),
161
- apiSecret: this.get(
162
- "storage.cloudinary.api_secret",
163
- "CLOUDINARY_API_SECRET"
164
- ),
165
- folder: this.get("storage.cloudinary.folder", "CLOUDINARY_FOLDER")
166
- },
167
- imgix: {
168
- domain: this.get("storage.imgix.domain", "IMGIX_DOMAIN"),
169
- signKey: this.get("storage.imgix.sign_key", "IMGIX_SIGN_KEY")
170
- },
171
- local: {
172
- uploadDir: this.get("storage.local.dir", "STORAGE_LOCAL_DIR"),
173
- baseUrl: this.get("storage.local.url", "STORAGE_LOCAL_URL", "/uploads")
174
- }
175
- };
176
- }
177
- /**
178
- * Get email configuration
179
- */
180
- getEmailConfig() {
181
- return {
182
- provider: this.get("email.provider", "EMAIL_PROVIDER", "smtp"),
183
- host: this.get("email.smtp.host", "SMTP_HOST"),
184
- port: parseInt(this.get("email.smtp.port", "SMTP_PORT", "587"), 10),
185
- secure: this.get("email.smtp.secure", "SMTP_SECURE") === "true",
186
- user: this.get("email.smtp.user", "SMTP_USER"),
187
- pass: this.get("email.smtp.pass", "SMTP_PASS"),
188
- from: this.get("email.smtp.from", "SMTP_FROM", "noreply@example.com"),
189
- fromName: this.get("email.smtp.from_name", "SMTP_FROM_NAME", "Kyro CMS"),
190
- replyTo: this.get("email.smtp.reply_to", "SMTP_REPLY_TO")
191
- };
192
- }
193
- /**
194
- * Mask sensitive values for display
195
- */
196
- maskSensitive(key, value) {
197
- if (!value) return value;
198
- if (_ConfigService.SENSITIVE_KEYS.includes(key)) {
199
- return "********";
200
- }
201
- return value;
202
- }
203
- /**
204
- * Update a setting in the database
205
- */
206
- async set(key, value, description) {
207
- await this.db.insert(settings).values({
208
- key,
209
- value,
210
- description,
211
- updatedAt: /* @__PURE__ */ new Date()
212
- }).onConflictDoUpdate({
213
- target: [settings.key],
214
- set: { value, description, updatedAt: /* @__PURE__ */ new Date() }
215
- });
216
- this.cache[key] = value;
217
- }
218
- };
219
- var defaultTemplates = {
220
- verifyEmail: (link, userName = "User") => ({
221
- subject: "Verify your email address",
222
- html: `
223
- <!DOCTYPE html>
224
- <html>
225
- <head>
226
- <meta charset="utf-8">
227
- <meta name="viewport" content="width=device-width, initial-scale=1">
228
- <title>Verify Email</title>
229
- <style>
230
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
231
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
232
- .button { display: inline-block; padding: 12px 24px; background: #0b1222; color: white; text-decoration: none; border-radius: 6px; font-weight: 600; }
233
- .footer { margin-top: 30px; font-size: 12px; color: #666; }
234
- </style>
235
- </head>
236
- <body>
237
- <div class="container">
238
- <h1>Welcome, ${userName}!</h1>
239
- <p>Please verify your email address by clicking the button below:</p>
240
- <p style="text-align: center; margin: 30px 0;">
241
- <a href="${link}" class="button">Verify Email</a>
242
- </p>
243
- <p>Or copy and paste this link into your browser:</p>
244
- <p style="word-break: break-all; color: #666;">${link}</p>
245
- <p>This link will expire in 24 hours.</p>
246
- <div class="footer">
247
- <p>If you didn't create an account, you can safely ignore this email.</p>
248
- </div>
249
- </div>
250
- </body>
251
- </html>
252
- `,
253
- text: `Welcome ${userName}!
254
-
255
- Please verify your email by clicking this link: ${link}
256
-
257
- This link will expire in 24 hours.
258
-
259
- If you didn't create an account, you can safely ignore this email.`
260
- }),
261
- resetPassword: (link, userName = "User") => ({
262
- subject: "Reset your password",
263
- html: `
264
- <!DOCTYPE html>
265
- <html>
266
- <head>
267
- <meta charset="utf-8">
268
- <meta name="viewport" content="width=device-width, initial-scale=1">
269
- <title>Reset Password</title>
270
- <style>
271
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
272
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
273
- .button { display: inline-block; padding: 12px 24px; background: #dc2626; color: white; text-decoration: none; border-radius: 6px; font-weight: 600; }
274
- .warning { background: #fef3c7; border: 1px solid #f59e0b; padding: 12px; border-radius: 6px; margin: 20px 0; }
275
- .footer { margin-top: 30px; font-size: 12px; color: #666; }
276
- </style>
277
- </head>
278
- <body>
279
- <div class="container">
280
- <h1>Password Reset Request</h1>
281
- <p>Hello ${userName},</p>
282
- <p>We received a request to reset your password. Click the button below to create a new password:</p>
283
- <p style="text-align: center; margin: 30px 0;">
284
- <a href="${link}" class="button">Reset Password</a>
285
- </p>
286
- <p>Or copy and paste this link into your browser:</p>
287
- <p style="word-break: break-all; color: #666;">${link}</p>
288
- <div class="warning">
289
- <strong>\u26A0\uFE0F Important:</strong> This link will expire in 1 hour. If you didn't request a password reset, please ignore this email or contact support if you have concerns.
290
- </div>
291
- <div class="footer">
292
- <p>For security reasons, please don't share this email with anyone.</p>
293
- </div>
294
- </div>
295
- </body>
296
- </html>
297
- `,
298
- text: `Password Reset Request
299
-
300
- Hello ${userName},
301
-
302
- We received a request to reset your password. Click this link to create a new password: ${link}
303
-
304
- This link will expire in 1 hour.
305
-
306
- If you didn't request a password reset, please ignore this email.`
307
- }),
308
- welcome: (userName = "User") => ({
309
- subject: "Welcome to Kyro CMS",
310
- html: `
311
- <!DOCTYPE html>
312
- <html>
313
- <head>
314
- <meta charset="utf-8">
315
- <meta name="viewport" content="width=device-width, initial-scale=1">
316
- <title>Welcome</title>
317
- <style>
318
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
319
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
320
- .button { display: inline-block; padding: 12px 24px; background: #0b1222; color: white; text-decoration: none; border-radius: 6px; font-weight: 600; }
321
- </style>
322
- </head>
323
- <body>
324
- <div class="container">
325
- <h1>Welcome to Kyro CMS, ${userName}!</h1>
326
- <p>Your account has been created successfully.</p>
327
- <p>You can now:</p>
328
- <ul>
329
- <li>Manage your content collections</li>
330
- <li>Upload and organize media</li>
331
- <li>Configure settings</li>
332
- <li>And much more...</li>
333
- </ul>
334
- <p style="text-align: center; margin: 30px 0;">
335
- <a href="#" class="button">Get Started</a>
336
- </p>
337
- <p>If you have any questions, feel free to reach out to our support team.</p>
338
- </div>
339
- </body>
340
- </html>
341
- `,
342
- text: `Welcome to Kyro CMS, ${userName}!
343
-
344
- Your account has been created successfully.
345
-
346
- You can now:
347
- - Manage your content collections
348
- - Upload and organize media
349
- - Configure settings
350
- - And much more...
351
-
352
- Get started by logging into your dashboard.`
353
- }),
354
- accountLocked: (attempts, duration, userName = "User") => ({
355
- subject: "Account Security Alert - Account Locked",
356
- html: `
357
- <!DOCTYPE html>
358
- <html>
359
- <head>
360
- <meta charset="utf-8">
361
- <meta name="viewport" content="width=device-width, initial-scale=1">
362
- <title>Account Locked</title>
363
- <style>
364
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
365
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
366
- .alert { background: #fef2f2; border: 1px solid #ef4444; padding: 16px; border-radius: 8px; margin: 20px 0; }
367
- .footer { margin-top: 30px; font-size: 12px; color: #666; }
368
- </style>
369
- </head>
370
- <body>
371
- <div class="container">
372
- <h1>Account Security Alert</h1>
373
- <p>Hello ${userName},</p>
374
- <div class="alert">
375
- <p><strong>\u26A0\uFE0F Your account has been temporarily locked due to multiple failed login attempts.</strong></p>
376
- <p>Failed attempts: ${attempts}</p>
377
- <p>Lockout duration: ${Math.round(duration / 6e4)} minutes</p>
378
- </div>
379
- <p>Your account will automatically unlock after the lockout period expires.</p>
380
- <p>If this wasn't you, we recommend:</p>
381
- <ul>
382
- <li>Using a strong, unique password</li>
383
- <li>Enabling two-factor authentication (coming soon)</li>
384
- <li>Reviewing your recent account activity</li>
385
- </ul>
386
- <div class="footer">
387
- <p>If you need immediate assistance, please contact support.</p>
388
- </div>
389
- </div>
390
- </body>
391
- </html>
392
- `,
393
- text: `Account Security Alert
394
-
395
- Hello ${userName},
396
-
397
- Your account has been temporarily locked due to multiple failed login attempts (${attempts}).
398
-
399
- Lockout duration: ${Math.round(duration / 6e4)} minutes
400
-
401
- Your account will automatically unlock after this period.
402
-
403
- If this wasn't you, we recommend using a strong, unique password.`
404
- }),
405
- passwordChanged: (userName = "User") => ({
406
- subject: "Your password has been changed",
407
- html: `
408
- <!DOCTYPE html>
409
- <html>
410
- <head>
411
- <meta charset="utf-8">
412
- <meta name="viewport" content="width=device-width, initial-scale=1">
413
- <title>Password Changed</title>
414
- <style>
415
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
416
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
417
- .info { background: #f0fdf4; border: 1px solid #22c55e; padding: 12px; border-radius: 6px; margin: 20px 0; }
418
- </style>
419
- </head>
420
- <body>
421
- <div class="container">
422
- <h1>Password Changed</h1>
423
- <p>Hello ${userName},</p>
424
- <div class="info">
425
- <p>Your password was recently changed.</p>
426
- </div>
427
- <p>If you did this, you can safely ignore this email.</p>
428
- <p><strong>If you didn't change your password</strong>, please contact our support team immediately as your account may have been compromised.</p>
429
- </div>
430
- </body>
431
- </html>
432
- `,
433
- text: `Password Changed
434
-
435
- Hello ${userName},
436
-
437
- Your password was recently changed.
438
-
439
- If you did this, you can safely ignore this email.
440
-
441
- If you didn't change your password, please contact support immediately.`
442
- }),
443
- newLogin: (location, time, userName = "User") => ({
444
- subject: "New login to your account",
445
- html: `
446
- <!DOCTYPE html>
447
- <html>
448
- <head>
449
- <meta charset="utf-8">
450
- <meta name="viewport" content="width=device-width, initial-scale=1">
451
- <title>New Login</title>
452
- <style>
453
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
454
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
455
- .info-box { background: #f8fafc; border: 1px solid #e2e8f0; padding: 16px; border-radius: 8px; margin: 20px 0; }
456
- .footer { margin-top: 30px; font-size: 12px; color: #666; }
457
- </style>
458
- </head>
459
- <body>
460
- <div class="container">
461
- <h1>New Login Detected</h1>
462
- <p>Hello ${userName},</p>
463
- <p>We detected a new login to your account:</p>
464
- <div class="info-box">
465
- <p><strong>Location:</strong> ${location}</p>
466
- <p><strong>Time:</strong> ${time}</p>
467
- </div>
468
- <p><strong>If this was you</strong>, no action is needed.</p>
469
- <p><strong>If this wasn't you</strong>, your account may be compromised. Please:</p>
470
- <ol>
471
- <li>Change your password immediately</li>
472
- <li>Review your recent account activity</li>
473
- <li>Contact support if needed</li>
474
- </ol>
475
- <div class="footer">
476
- <p>This is an automated security notification.</p>
477
- </div>
478
- </div>
479
- </body>
480
- </html>
481
- `,
482
- text: `New Login Detected
483
-
484
- Hello ${userName},
485
-
486
- We detected a new login to your account:
487
-
488
- Location: ${location}
489
- Time: ${time}
490
-
491
- If this wasn't you, please change your password immediately and contact support.`
492
- })
493
- };
494
- var EmailTransport = class _EmailTransport {
495
- transporter;
496
- config;
497
- templates;
498
- constructor(config, templates) {
499
- this.config = config;
500
- this.templates = { ...defaultTemplates, ...templates };
501
- if (config.provider === "smtp" && config.smtp) {
502
- this.transporter = nodemailer.createTransport({
503
- host: config.smtp.host,
504
- port: config.smtp.port,
505
- secure: config.smtp.secure,
506
- auth: config.smtp.auth
507
- });
508
- } else if (config.provider === "ses" && config.ses) {
509
- this.transporter = nodemailer.createTransport({
510
- host: `email-smtp.${config.ses.region}.amazonaws.com`,
511
- port: 587,
512
- secure: false,
513
- auth: {
514
- user: config.ses.accessKeyId,
515
- pass: config.ses.secretAccessKey
516
- }
517
- });
518
- }
519
- }
520
- async send(options) {
521
- const { provider, from, fromName, replyTo: configReplyTo } = this.config;
522
- const fromFull = `"${fromName || "Kyro CMS"}" <${from}>`;
523
- const replyTo = options.replyTo || configReplyTo;
524
- console.log(`[EmailTransport] Sending email via ${provider}...`);
525
- console.log(`[EmailTransport] To: ${Array.isArray(options.to) ? options.to.join(", ") : options.to}`);
526
- console.log(`[EmailTransport] Subject: ${options.subject}`);
527
- try {
528
- let result;
529
- switch (provider) {
530
- case "smtp":
531
- case "ses":
532
- if (!this.transporter)
533
- throw new Error(`${provider} transporter not initialized`);
534
- result = await this.transporter.sendMail({
535
- from: fromFull,
536
- to: Array.isArray(options.to) ? options.to.join(", ") : options.to,
537
- subject: options.subject,
538
- html: options.html,
539
- text: options.text,
540
- replyTo
541
- });
542
- break;
543
- case "resend":
544
- result = await this.sendViaResend(fromFull, options, replyTo);
545
- break;
546
- case "sendgrid":
547
- result = await this.sendViaSendGrid(fromFull, options, replyTo);
548
- break;
549
- case "mailgun":
550
- result = await this.sendViaMailgun(fromFull, options, replyTo);
551
- break;
552
- default:
553
- throw new Error(`Unsupported email provider: ${provider}`);
554
- }
555
- console.log(`[EmailTransport] Success! Provider response received.`);
556
- return result;
557
- } catch (error) {
558
- console.error(`[EmailTransport] FAILED to send email:`, error.message);
559
- if (error.response) {
560
- console.error(`[EmailTransport] Provider Error Detail:`, JSON.stringify(error.response, null, 2));
561
- }
562
- throw error;
563
- }
564
- }
565
- async sendViaResend(from, options, replyTo) {
566
- const apiKey = this.config.resend?.apiKey;
567
- if (!apiKey) throw new Error("Resend API Key missing");
568
- const body = {
569
- from,
570
- to: options.to,
571
- subject: options.subject,
572
- html: options.html,
573
- text: options.text,
574
- reply_to: replyTo
575
- };
576
- console.log(`[EmailTransport] Calling Resend API...`);
577
- const resp = await fetch("https://api.resend.com/emails", {
578
- method: "POST",
579
- headers: {
580
- Authorization: `Bearer ${apiKey}`,
581
- "Content-Type": "application/json"
582
- },
583
- body: JSON.stringify(body)
584
- });
585
- if (!resp.ok) {
586
- const error = await resp.json();
587
- throw new Error(`Resend Error: ${JSON.stringify(error)}`);
588
- }
589
- return resp.json();
590
- }
591
- async sendViaSendGrid(from, options, replyTo) {
592
- const apiKey = this.config.sendgrid?.apiKey;
593
- if (!apiKey) throw new Error("SendGrid API Key missing");
594
- const body = {
595
- personalizations: [
596
- { to: Array.isArray(options.to) ? options.to.map((email) => ({ email })) : [{ email: options.to }] }
597
- ],
598
- from: { email: from.match(/<(.+)>/)?.[1] || from, name: from.match(/"(.+)"/)?.[1] },
599
- subject: options.subject,
600
- content: [
601
- { type: "text/plain", value: options.text || "" },
602
- { type: "text/html", value: options.html }
603
- ],
604
- reply_to: replyTo ? { email: replyTo } : void 0
605
- };
606
- console.log(`[EmailTransport] Calling SendGrid API...`);
607
- const resp = await fetch("https://api.sendgrid.com/v3/mail/send", {
608
- method: "POST",
609
- headers: {
610
- Authorization: `Bearer ${apiKey}`,
611
- "Content-Type": "application/json"
612
- },
613
- body: JSON.stringify(body)
614
- });
615
- if (!resp.ok) {
616
- const error = await resp.json();
617
- throw new Error(`SendGrid Error: ${JSON.stringify(error)}`);
618
- }
619
- return { success: true };
620
- }
621
- async sendViaMailgun(from, options, replyTo) {
622
- const { apiKey, domain, region } = this.config.mailgun || {};
623
- if (!apiKey || !domain) throw new Error("Mailgun config missing");
624
- const base = region === "eu" ? "api.eu.mailgun.net" : "api.mailgun.net";
625
- const auth = btoa(`api:${apiKey}`);
626
- const formData = new URLSearchParams();
627
- formData.append("from", from);
628
- const to = Array.isArray(options.to) ? options.to.join(", ") : options.to;
629
- formData.append("to", to);
630
- formData.append("subject", options.subject);
631
- formData.append("html", options.html);
632
- if (options.text) formData.append("text", options.text);
633
- if (replyTo) formData.append("h:Reply-To", replyTo);
634
- console.log(`[EmailTransport] Calling Mailgun API (${region || "us"})...`);
635
- const resp = await fetch(`https://${base}/v3/${domain}/messages`, {
636
- method: "POST",
637
- headers: {
638
- Authorization: `Basic ${auth}`,
639
- "Content-Type": "application/x-www-form-urlencoded"
640
- },
641
- body: formData
642
- });
643
- if (!resp.ok) {
644
- const error = await resp.json();
645
- throw new Error(`Mailgun Error: ${JSON.stringify(error)}`);
646
- }
647
- return resp.json();
648
- }
649
- getTemplates() {
650
- return this.templates;
651
- }
652
- async verifyConnection() {
653
- if (this.transporter) {
654
- try {
655
- await this.transporter.verify();
656
- return true;
657
- } catch {
658
- return false;
659
- }
660
- }
661
- return !!(this.config.resend?.apiKey || this.config.sendgrid?.apiKey || this.config.mailgun?.apiKey);
662
- }
663
- static async fromConfig(db) {
664
- const configService = new ConfigService(db);
665
- await configService.load();
666
- const config = configService.getEmailConfig();
667
- if (!config.provider) {
668
- return this.fromEnv();
669
- }
670
- const transformed = {
671
- provider: config.provider || "smtp",
672
- from: config.from || "noreply@example.com",
673
- fromName: config.fromName,
674
- replyTo: config.replyTo,
675
- smtp: config.provider === "smtp" ? {
676
- host: config.host || "",
677
- port: config.port || 587,
678
- secure: config.secure || false,
679
- auth: { user: config.user || "", pass: config.pass || "" }
680
- } : void 0,
681
- resend: config.provider === "resend" ? { apiKey: config.pass || "" } : void 0,
682
- sendgrid: config.provider === "sendgrid" ? { apiKey: config.pass || "" } : void 0,
683
- mailgun: config.provider === "mailgun" ? {
684
- apiKey: config.pass || "",
685
- domain: config.host || "",
686
- region: config.secure ? "eu" : "us"
687
- } : void 0,
688
- ses: config.provider === "ses" ? {
689
- accessKeyId: config.user || "",
690
- secretAccessKey: config.pass || "",
691
- region: config.host || "us-east-1"
692
- } : void 0
693
- };
694
- return new _EmailTransport(transformed);
695
- }
696
- static fromEnv() {
697
- const provider = process.env.EMAIL_PROVIDER || "smtp";
698
- const from = process.env.SMTP_FROM || process.env.DEFAULT_FROM || "noreply@example.com";
699
- const fromName = process.env.SMTP_FROM_NAME || "Kyro CMS";
700
- const replyTo = process.env.SMTP_REPLY_TO;
701
- if (provider === "smtp") {
702
- const host = process.env.SMTP_HOST;
703
- const user = process.env.SMTP_USER;
704
- const pass = process.env.SMTP_PASS;
705
- if (!host || !user || !pass) return null;
706
- return new _EmailTransport({
707
- provider: "smtp",
708
- from,
709
- fromName,
710
- replyTo,
711
- smtp: {
712
- host,
713
- port: parseInt(process.env.SMTP_PORT || "587", 10),
714
- secure: process.env.SMTP_SECURE === "true",
715
- auth: { user, pass }
716
- }
717
- });
718
- }
719
- if (provider === "resend") {
720
- const apiKey = process.env.RESEND_API_KEY || process.env.SMTP_PASS;
721
- if (!apiKey) return null;
722
- return new _EmailTransport({ provider: "resend", from, fromName, replyTo, resend: { apiKey } });
723
- }
724
- if (provider === "sendgrid") {
725
- const apiKey = process.env.SENDGRID_API_KEY || process.env.SMTP_PASS;
726
- if (!apiKey) return null;
727
- return new _EmailTransport({ provider: "sendgrid", from, fromName, replyTo, sendgrid: { apiKey } });
728
- }
729
- if (provider === "mailgun") {
730
- const apiKey = process.env.MAILGUN_API_KEY || process.env.SMTP_PASS;
731
- const domain = process.env.MAILGUN_DOMAIN || process.env.SMTP_HOST;
732
- if (!apiKey || !domain) return null;
733
- return new _EmailTransport({
734
- provider: "mailgun",
735
- from,
736
- fromName,
737
- replyTo,
738
- mailgun: {
739
- apiKey,
740
- domain,
741
- region: process.env.MAILGUN_REGION || (process.env.SMTP_SECURE === "true" ? "eu" : "us")
742
- }
743
- });
744
- }
745
- if (provider === "ses") {
746
- const accessKeyId = process.env.AWS_ACCESS_KEY_ID || process.env.SMTP_USER;
747
- const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY || process.env.SMTP_PASS;
748
- const region = process.env.AWS_REGION || process.env.SMTP_HOST || "us-east-1";
749
- if (!accessKeyId || !secretAccessKey) return null;
750
- return new _EmailTransport({ provider: "ses", from, fromName, replyTo, ses: { accessKeyId, secretAccessKey, region } });
751
- }
752
- return null;
753
- }
754
- };
755
-
756
- export { ConfigService, EmailTransport };
757
- //# sourceMappingURL=chunk-HYC4GNHX.js.map
758
- //# sourceMappingURL=chunk-HYC4GNHX.js.map