alepha 0.22.0 → 0.24.0

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 (869) hide show
  1. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  2. package/assets/swagger-ui/swagger-ui-standalone-preset.js +1 -1
  3. package/dist/api/audits/index.browser.js +49 -52
  4. package/dist/api/audits/index.browser.js.map +1 -1
  5. package/dist/api/audits/index.d.ts +629 -565
  6. package/dist/api/audits/index.d.ts.map +1 -1
  7. package/dist/api/audits/index.js +206 -98
  8. package/dist/api/audits/index.js.map +1 -1
  9. package/dist/api/files/index.browser.js +44 -44
  10. package/dist/api/files/index.browser.js.map +1 -1
  11. package/dist/api/files/index.d.ts +292 -293
  12. package/dist/api/files/index.d.ts.map +1 -1
  13. package/dist/api/files/index.js +61 -64
  14. package/dist/api/files/index.js.map +1 -1
  15. package/dist/api/jobs/index.browser.js +61 -59
  16. package/dist/api/jobs/index.browser.js.map +1 -1
  17. package/dist/api/jobs/index.d.ts +546 -347
  18. package/dist/api/jobs/index.d.ts.map +1 -1
  19. package/dist/api/jobs/index.js +165 -86
  20. package/dist/api/jobs/index.js.map +1 -1
  21. package/dist/api/keys/index.d.ts +242 -230
  22. package/dist/api/keys/index.d.ts.map +1 -1
  23. package/dist/api/keys/index.js +63 -66
  24. package/dist/api/keys/index.js.map +1 -1
  25. package/dist/api/notifications/index.browser.js +40 -38
  26. package/dist/api/notifications/index.browser.js.map +1 -1
  27. package/dist/api/notifications/index.d.ts +339 -209
  28. package/dist/api/notifications/index.d.ts.map +1 -1
  29. package/dist/api/notifications/index.js +108 -60
  30. package/dist/api/notifications/index.js.map +1 -1
  31. package/dist/api/oauth/index.d.ts +190 -78
  32. package/dist/api/oauth/index.d.ts.map +1 -1
  33. package/dist/api/oauth/index.js +290 -68
  34. package/dist/api/oauth/index.js.map +1 -1
  35. package/dist/api/organizations/index.browser.js +14 -14
  36. package/dist/api/organizations/index.browser.js.map +1 -1
  37. package/dist/api/organizations/index.d.ts +158 -134
  38. package/dist/api/organizations/index.d.ts.map +1 -1
  39. package/dist/api/organizations/index.js +18 -18
  40. package/dist/api/organizations/index.js.map +1 -1
  41. package/dist/api/parameters/index.browser.js +74 -53
  42. package/dist/api/parameters/index.browser.js.map +1 -1
  43. package/dist/api/parameters/index.d.ts +607 -513
  44. package/dist/api/parameters/index.d.ts.map +1 -1
  45. package/dist/api/parameters/index.js +205 -127
  46. package/dist/api/parameters/index.js.map +1 -1
  47. package/dist/api/payments/index.d.ts +652 -449
  48. package/dist/api/payments/index.d.ts.map +1 -1
  49. package/dist/api/payments/index.js +159 -93
  50. package/dist/api/payments/index.js.map +1 -1
  51. package/dist/api/subscriptions/index.d.ts +1032 -762
  52. package/dist/api/subscriptions/index.d.ts.map +1 -1
  53. package/dist/api/subscriptions/index.js +166 -185
  54. package/dist/api/subscriptions/index.js.map +1 -1
  55. package/dist/api/users/index.browser.js +48 -71
  56. package/dist/api/users/index.browser.js.map +1 -1
  57. package/dist/api/users/index.d.ts +1297 -1109
  58. package/dist/api/users/index.d.ts.map +1 -1
  59. package/dist/api/users/index.js +454 -369
  60. package/dist/api/users/index.js.map +1 -1
  61. package/dist/api/verifications/index.browser.js +17 -17
  62. package/dist/api/verifications/index.browser.js.map +1 -1
  63. package/dist/api/verifications/index.d.ts +169 -157
  64. package/dist/api/verifications/index.d.ts.map +1 -1
  65. package/dist/api/verifications/index.js +47 -95
  66. package/dist/api/verifications/index.js.map +1 -1
  67. package/dist/background/index.d.ts +0 -1
  68. package/dist/background/index.d.ts.map +1 -1
  69. package/dist/background/index.js.map +1 -1
  70. package/dist/background/index.workerd.js.map +1 -1
  71. package/dist/batch/index.d.ts +0 -1
  72. package/dist/batch/index.d.ts.map +1 -1
  73. package/dist/batch/index.js.map +1 -1
  74. package/dist/bin/index.js +1 -1
  75. package/dist/bin/index.js.map +1 -1
  76. package/dist/bucket/index.d.ts +27 -32
  77. package/dist/bucket/index.d.ts.map +1 -1
  78. package/dist/bucket/index.js +56 -26
  79. package/dist/bucket/index.js.map +1 -1
  80. package/dist/bucket/index.workerd.js +52 -24
  81. package/dist/bucket/index.workerd.js.map +1 -1
  82. package/dist/cache/core/index.d.ts +4 -6
  83. package/dist/cache/core/index.d.ts.map +1 -1
  84. package/dist/cache/core/index.js +4 -10
  85. package/dist/cache/core/index.js.map +1 -1
  86. package/dist/cache/core/index.workerd.js +4 -10
  87. package/dist/cache/core/index.workerd.js.map +1 -1
  88. package/dist/cache/database/index.d.ts +22 -23
  89. package/dist/cache/database/index.d.ts.map +1 -1
  90. package/dist/cache/database/index.js +11 -20
  91. package/dist/cache/database/index.js.map +1 -1
  92. package/dist/cache/redis/index.d.ts +3 -4
  93. package/dist/cache/redis/index.d.ts.map +1 -1
  94. package/dist/cache/redis/index.js +2 -2
  95. package/dist/cache/redis/index.js.map +1 -1
  96. package/dist/captcha/index.d.ts.map +1 -1
  97. package/dist/captcha/index.js +4 -4
  98. package/dist/captcha/index.js.map +1 -1
  99. package/dist/cli/config/index.d.ts +0 -1
  100. package/dist/cli/config/index.d.ts.map +1 -1
  101. package/dist/cli/core/index.d.ts +244 -475
  102. package/dist/cli/core/index.d.ts.map +1 -1
  103. package/dist/cli/core/index.js +308 -383
  104. package/dist/cli/core/index.js.map +1 -1
  105. package/dist/cli/devtools/index.d.ts +3 -9
  106. package/dist/cli/devtools/index.d.ts.map +1 -1
  107. package/dist/cli/devtools/index.js +3 -3
  108. package/dist/cli/devtools/index.js.map +1 -1
  109. package/dist/cli/i18n/index.d.ts +20 -39
  110. package/dist/cli/i18n/index.d.ts.map +1 -1
  111. package/dist/cli/i18n/index.js +51 -17
  112. package/dist/cli/i18n/index.js.map +1 -1
  113. package/dist/cli/platform/index.d.ts +89 -82
  114. package/dist/cli/platform/index.d.ts.map +1 -1
  115. package/dist/cli/platform/index.js +27 -33
  116. package/dist/cli/platform/index.js.map +1 -1
  117. package/dist/cli/platform-lib/index.d.ts +383 -410
  118. package/dist/cli/platform-lib/index.d.ts.map +1 -1
  119. package/dist/cli/platform-lib/index.js +300 -258
  120. package/dist/cli/platform-lib/index.js.map +1 -1
  121. package/dist/cli/vendor/index.d.ts +17 -41
  122. package/dist/cli/vendor/index.d.ts.map +1 -1
  123. package/dist/cli/vendor/index.js +10 -13
  124. package/dist/cli/vendor/index.js.map +1 -1
  125. package/dist/command/index.d.ts +82 -194
  126. package/dist/command/index.d.ts.map +1 -1
  127. package/dist/command/index.js +160 -563
  128. package/dist/command/index.js.map +1 -1
  129. package/dist/core/index.browser.js +845 -859
  130. package/dist/core/index.browser.js.map +1 -1
  131. package/dist/core/index.d.ts +787 -527
  132. package/dist/core/index.d.ts.map +1 -1
  133. package/dist/core/index.js +845 -859
  134. package/dist/core/index.js.map +1 -1
  135. package/dist/core/index.native.js +845 -859
  136. package/dist/core/index.native.js.map +1 -1
  137. package/dist/core/index.workerd.js +845 -859
  138. package/dist/core/index.workerd.js.map +1 -1
  139. package/dist/crypto/index.browser.js +1 -1
  140. package/dist/crypto/index.browser.js.map +1 -1
  141. package/dist/crypto/index.d.ts +3 -4
  142. package/dist/crypto/index.d.ts.map +1 -1
  143. package/dist/crypto/index.js +6 -3
  144. package/dist/crypto/index.js.map +1 -1
  145. package/dist/datetime/index.d.ts +12 -2
  146. package/dist/datetime/index.d.ts.map +1 -1
  147. package/dist/datetime/index.js +6 -1
  148. package/dist/datetime/index.js.map +1 -1
  149. package/dist/email/brevo/index.d.ts +0 -1
  150. package/dist/email/brevo/index.d.ts.map +1 -1
  151. package/dist/email/brevo/index.js +4 -4
  152. package/dist/email/brevo/index.js.map +1 -1
  153. package/dist/email/cloudflare/index.d.ts +0 -1
  154. package/dist/email/cloudflare/index.d.ts.map +1 -1
  155. package/dist/email/cloudflare/index.js +2 -2
  156. package/dist/email/cloudflare/index.js.map +1 -1
  157. package/dist/email/core/index.d.ts +15 -7
  158. package/dist/email/core/index.d.ts.map +1 -1
  159. package/dist/email/core/index.js +14 -5
  160. package/dist/email/core/index.js.map +1 -1
  161. package/dist/email/core/index.workerd.js +5 -1
  162. package/dist/email/core/index.workerd.js.map +1 -1
  163. package/dist/email/smtp/index.d.ts +8 -9
  164. package/dist/email/smtp/index.d.ts.map +1 -1
  165. package/dist/email/smtp/index.js +702 -479
  166. package/dist/email/smtp/index.js.map +1 -1
  167. package/dist/fake/index.d.ts +1580 -1238
  168. package/dist/fake/index.d.ts.map +1 -1
  169. package/dist/fake/index.js +11728 -32131
  170. package/dist/fake/index.js.map +1 -1
  171. package/dist/lock/core/index.d.ts +13 -9
  172. package/dist/lock/core/index.d.ts.map +1 -1
  173. package/dist/lock/core/index.js +5 -5
  174. package/dist/lock/core/index.js.map +1 -1
  175. package/dist/lock/redis/index.d.ts +0 -1
  176. package/dist/lock/redis/index.d.ts.map +1 -1
  177. package/dist/lock/redis/index.js.map +1 -1
  178. package/dist/logger/index.d.ts +81 -69
  179. package/dist/logger/index.d.ts.map +1 -1
  180. package/dist/logger/index.js +123 -56
  181. package/dist/logger/index.js.map +1 -1
  182. package/dist/mcp/index.d.ts +36 -90
  183. package/dist/mcp/index.d.ts.map +1 -1
  184. package/dist/mcp/index.js +65 -70
  185. package/dist/mcp/index.js.map +1 -1
  186. package/dist/orm/core/index.browser.js +54 -40
  187. package/dist/orm/core/index.browser.js.map +1 -1
  188. package/dist/orm/core/index.bun.js +140 -106
  189. package/dist/orm/core/index.bun.js.map +1 -1
  190. package/dist/orm/core/index.d.ts +145 -150
  191. package/dist/orm/core/index.d.ts.map +1 -1
  192. package/dist/orm/core/index.js +144 -109
  193. package/dist/orm/core/index.js.map +1 -1
  194. package/dist/orm/postgres/index.bun.js +64 -54
  195. package/dist/orm/postgres/index.bun.js.map +1 -1
  196. package/dist/orm/postgres/index.d.ts +36 -76
  197. package/dist/orm/postgres/index.d.ts.map +1 -1
  198. package/dist/orm/postgres/index.js +67 -57
  199. package/dist/orm/postgres/index.js.map +1 -1
  200. package/dist/queue/core/index.d.ts +62 -75
  201. package/dist/queue/core/index.d.ts.map +1 -1
  202. package/dist/queue/core/index.js +48 -71
  203. package/dist/queue/core/index.js.map +1 -1
  204. package/dist/queue/core/index.workerd.js +48 -71
  205. package/dist/queue/core/index.workerd.js.map +1 -1
  206. package/dist/queue/redis/index.d.ts +3 -4
  207. package/dist/queue/redis/index.d.ts.map +1 -1
  208. package/dist/queue/redis/index.js +2 -2
  209. package/dist/queue/redis/index.js.map +1 -1
  210. package/dist/react/auth/index.browser.js.map +1 -1
  211. package/dist/react/auth/index.d.ts +7 -4
  212. package/dist/react/auth/index.d.ts.map +1 -1
  213. package/dist/react/auth/index.js.map +1 -1
  214. package/dist/react/core/index.d.ts +87 -5
  215. package/dist/react/core/index.d.ts.map +1 -1
  216. package/dist/react/core/index.js +170 -23
  217. package/dist/react/core/index.js.map +1 -1
  218. package/dist/react/form/index.d.ts +4 -6
  219. package/dist/react/form/index.d.ts.map +1 -1
  220. package/dist/react/form/index.js +107 -71
  221. package/dist/react/form/index.js.map +1 -1
  222. package/dist/react/head/index.browser.js.map +1 -1
  223. package/dist/react/head/index.d.ts +0 -1
  224. package/dist/react/head/index.d.ts.map +1 -1
  225. package/dist/react/head/index.js.map +1 -1
  226. package/dist/react/i18n/index.d.ts +47 -5
  227. package/dist/react/i18n/index.d.ts.map +1 -1
  228. package/dist/react/i18n/index.js +116 -12
  229. package/dist/react/i18n/index.js.map +1 -1
  230. package/dist/react/intro/index.d.ts +1 -4
  231. package/dist/react/intro/index.d.ts.map +1 -1
  232. package/dist/react/intro/index.js.map +1 -1
  233. package/dist/react/router/index.browser.js +188 -29
  234. package/dist/react/router/index.browser.js.map +1 -1
  235. package/dist/react/router/index.d.ts +480 -372
  236. package/dist/react/router/index.d.ts.map +1 -1
  237. package/dist/react/router/index.js +261 -47
  238. package/dist/react/router/index.js.map +1 -1
  239. package/dist/react/sitemap/index.browser.js +35 -0
  240. package/dist/react/sitemap/index.browser.js.map +1 -0
  241. package/dist/react/sitemap/index.d.ts +91 -0
  242. package/dist/react/sitemap/index.d.ts.map +1 -0
  243. package/dist/react/sitemap/index.js +131 -0
  244. package/dist/react/sitemap/index.js.map +1 -0
  245. package/dist/react/testing/index.d.ts +4 -5
  246. package/dist/react/testing/index.d.ts.map +1 -1
  247. package/dist/react/testing/index.js +41 -15
  248. package/dist/react/testing/index.js.map +1 -1
  249. package/dist/react/testing/{chunk-BpyX8vjI.js → rolldown-runtime-Bl3dcgcQ.js} +1 -1
  250. package/dist/react/ui/index.d.ts +35 -34
  251. package/dist/react/ui/index.d.ts.map +1 -1
  252. package/dist/react/ui/index.js +12 -17
  253. package/dist/react/ui/index.js.map +1 -1
  254. package/dist/redis/index.bun.js +5 -5
  255. package/dist/redis/index.bun.js.map +1 -1
  256. package/dist/redis/index.d.ts +6 -7
  257. package/dist/redis/index.d.ts.map +1 -1
  258. package/dist/redis/index.js +6 -6
  259. package/dist/redis/index.js.map +1 -1
  260. package/dist/retry/index.d.ts +0 -1
  261. package/dist/retry/index.d.ts.map +1 -1
  262. package/dist/retry/index.js.map +1 -1
  263. package/dist/router/index.d.ts.map +1 -1
  264. package/dist/router/index.js.map +1 -1
  265. package/dist/scheduler/index.d.ts +4 -12
  266. package/dist/scheduler/index.d.ts.map +1 -1
  267. package/dist/scheduler/index.js +9 -4
  268. package/dist/scheduler/index.js.map +1 -1
  269. package/dist/scheduler/index.workerd.js +9 -4
  270. package/dist/scheduler/index.workerd.js.map +1 -1
  271. package/dist/security/index.browser.js +30 -28
  272. package/dist/security/index.browser.js.map +1 -1
  273. package/dist/security/index.d.ts +113 -44
  274. package/dist/security/index.d.ts.map +1 -1
  275. package/dist/security/index.js +452 -37
  276. package/dist/security/index.js.map +1 -1
  277. package/dist/server/auth/index.browser.js +19 -19
  278. package/dist/server/auth/index.browser.js.map +1 -1
  279. package/dist/server/auth/index.d.ts +215 -187
  280. package/dist/server/auth/index.d.ts.map +1 -1
  281. package/dist/server/auth/index.js +1145 -86
  282. package/dist/server/auth/index.js.map +1 -1
  283. package/dist/server/cookies/index.browser.js +103 -5
  284. package/dist/server/cookies/index.browser.js.map +1 -1
  285. package/dist/server/cookies/index.d.ts +86 -4
  286. package/dist/server/cookies/index.d.ts.map +1 -1
  287. package/dist/server/cookies/index.js +121 -8
  288. package/dist/server/cookies/index.js.map +1 -1
  289. package/dist/server/core/index.browser.js +22 -27
  290. package/dist/server/core/index.browser.js.map +1 -1
  291. package/dist/server/core/index.d.ts +134 -85
  292. package/dist/server/core/index.d.ts.map +1 -1
  293. package/dist/server/core/index.js +130 -118
  294. package/dist/server/core/index.js.map +1 -1
  295. package/dist/server/cors/index.d.ts +9 -10
  296. package/dist/server/cors/index.d.ts.map +1 -1
  297. package/dist/server/cors/index.js +14 -26
  298. package/dist/server/cors/index.js.map +1 -1
  299. package/dist/server/etag/index.d.ts +2 -3
  300. package/dist/server/etag/index.d.ts.map +1 -1
  301. package/dist/server/etag/index.js.map +1 -1
  302. package/dist/server/health/index.d.ts +18 -19
  303. package/dist/server/health/index.d.ts.map +1 -1
  304. package/dist/server/health/index.js +6 -6
  305. package/dist/server/health/index.js.map +1 -1
  306. package/dist/server/links/index.browser.js +15 -18
  307. package/dist/server/links/index.browser.js.map +1 -1
  308. package/dist/server/links/index.d.ts +66 -67
  309. package/dist/server/links/index.d.ts.map +1 -1
  310. package/dist/server/links/index.js +29 -32
  311. package/dist/server/links/index.js.map +1 -1
  312. package/dist/server/metrics/index.d.ts +0 -1
  313. package/dist/server/metrics/index.d.ts.map +1 -1
  314. package/dist/server/metrics/index.js +10 -3
  315. package/dist/server/metrics/index.js.map +1 -1
  316. package/dist/server/proxy/index.d.ts +0 -1
  317. package/dist/server/proxy/index.d.ts.map +1 -1
  318. package/dist/server/proxy/index.js.map +1 -1
  319. package/dist/server/rate-limit/index.d.ts +8 -9
  320. package/dist/server/rate-limit/index.d.ts.map +1 -1
  321. package/dist/server/rate-limit/index.js +6 -12
  322. package/dist/server/rate-limit/index.js.map +1 -1
  323. package/dist/server/static/index.d.ts +0 -1
  324. package/dist/server/static/index.d.ts.map +1 -1
  325. package/dist/server/static/index.js.map +1 -1
  326. package/dist/server/swagger/index.d.ts +4 -4
  327. package/dist/server/swagger/index.d.ts.map +1 -1
  328. package/dist/server/swagger/index.js +37 -25
  329. package/dist/server/swagger/index.js.map +1 -1
  330. package/dist/sms/index.d.ts +0 -1
  331. package/dist/sms/index.d.ts.map +1 -1
  332. package/dist/sms/index.js.map +1 -1
  333. package/dist/system/index.browser.js.map +1 -1
  334. package/dist/system/index.d.ts +0 -1
  335. package/dist/system/index.d.ts.map +1 -1
  336. package/dist/system/index.js +2 -1
  337. package/dist/system/index.js.map +1 -1
  338. package/dist/system/index.workerd.js.map +1 -1
  339. package/dist/topic/core/index.d.ts +19 -20
  340. package/dist/topic/core/index.d.ts.map +1 -1
  341. package/dist/topic/core/index.js +8 -8
  342. package/dist/topic/core/index.js.map +1 -1
  343. package/dist/topic/redis/index.d.ts +3 -4
  344. package/dist/topic/redis/index.d.ts.map +1 -1
  345. package/dist/topic/redis/index.js +2 -2
  346. package/dist/topic/redis/index.js.map +1 -1
  347. package/package.json +36 -36
  348. package/src/api/audits/__tests__/AuditJobs.spec.ts +83 -0
  349. package/src/api/audits/__tests__/AuditService.spec.ts +139 -1
  350. package/src/api/audits/controllers/AdminAuditController.ts +41 -41
  351. package/src/api/audits/entities/audits.ts +22 -22
  352. package/src/api/audits/index.ts +6 -1
  353. package/src/api/audits/jobs/AuditJobs.ts +29 -0
  354. package/src/api/audits/parameters/AuditParameters.ts +51 -0
  355. package/src/api/audits/primitives/$audit.ts +24 -0
  356. package/src/api/audits/schemas/auditQuerySchema.ts +13 -13
  357. package/src/api/audits/schemas/createAuditSchema.ts +18 -18
  358. package/src/api/audits/services/AuditService.ts +79 -7
  359. package/src/api/files/__tests__/FileController.spec.ts +5 -5
  360. package/src/api/files/__tests__/FileJobs.spec.ts +6 -0
  361. package/src/api/files/controllers/FileController.ts +25 -25
  362. package/src/api/files/entities/files.ts +15 -15
  363. package/src/api/files/schemas/fileCreatorSummarySchema.ts +7 -7
  364. package/src/api/files/schemas/fileQuerySchema.ts +9 -9
  365. package/src/api/files/schemas/fileResourceSchema.ts +7 -9
  366. package/src/api/files/schemas/storageStatsSchema.ts +13 -13
  367. package/src/api/jobs/__tests__/$job-hardening.spec.ts +289 -0
  368. package/src/api/jobs/__tests__/$job.spec.ts +18 -18
  369. package/src/api/jobs/controllers/AdminJobController.ts +8 -8
  370. package/src/api/jobs/entities/jobExecutionEntity.ts +29 -19
  371. package/src/api/jobs/providers/JobProvider.ts +128 -12
  372. package/src/api/jobs/providers/JobQueueProvider.ts +2 -2
  373. package/src/api/jobs/schemas/jobConfigAtom.ts +22 -22
  374. package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +6 -6
  375. package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +11 -15
  376. package/src/api/jobs/schemas/jobRegistrationSchema.ts +20 -19
  377. package/src/api/jobs/schemas/triggerJobSchema.ts +3 -3
  378. package/src/api/jobs/services/JobService.ts +6 -6
  379. package/src/api/keys/__tests__/ApiKeyService.spec.ts +2 -2
  380. package/src/api/keys/controllers/AdminApiKeyController.ts +10 -10
  381. package/src/api/keys/entities/apiKeyEntity.ts +15 -15
  382. package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +4 -4
  383. package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +15 -15
  384. package/src/api/keys/schemas/createApiKeyBodySchema.ts +5 -5
  385. package/src/api/keys/schemas/createApiKeyResponseSchema.ts +9 -9
  386. package/src/api/keys/schemas/listApiKeyResponseSchema.ts +13 -13
  387. package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +3 -3
  388. package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +3 -3
  389. package/src/api/notifications/__tests__/AlephaApiNotifications.spec.ts +2 -2
  390. package/src/api/notifications/controllers/AdminNotificationController.ts +38 -14
  391. package/src/api/notifications/jobs/NotificationJobs.ts +7 -6
  392. package/src/api/notifications/primitives/$notification.ts +43 -4
  393. package/src/api/notifications/schemas/notificationContactPreferencesSchema.ts +4 -4
  394. package/src/api/notifications/schemas/notificationContactSchema.ts +7 -7
  395. package/src/api/notifications/schemas/notificationDetailResourceSchema.ts +9 -11
  396. package/src/api/notifications/schemas/notificationPayloadSchema.ts +11 -9
  397. package/src/api/notifications/schemas/notificationQuerySchema.ts +6 -6
  398. package/src/api/notifications/schemas/notificationResourceSchema.ts +14 -14
  399. package/src/api/notifications/services/NotificationSenderService.ts +38 -2
  400. package/src/api/oauth/__tests__/OAuthClientService.spec.ts +42 -0
  401. package/src/api/oauth/__tests__/OAuthController.spec.ts +128 -0
  402. package/src/api/oauth/controllers/OAuthController.ts +132 -12
  403. package/src/api/oauth/entities/oauthClientEntity.ts +29 -12
  404. package/src/api/oauth/helpers/oauthMetadata.ts +1 -0
  405. package/src/api/oauth/helpers/oidcMetadata.ts +19 -0
  406. package/src/api/oauth/index.ts +1 -0
  407. package/src/api/oauth/schemas/authorizeDecisionBodySchema.ts +12 -11
  408. package/src/api/oauth/schemas/authorizeQuerySchema.ts +12 -10
  409. package/src/api/oauth/schemas/registerClientBodySchema.ts +10 -11
  410. package/src/api/oauth/schemas/tokenRequestBodySchema.ts +9 -8
  411. package/src/api/oauth/services/OAuthClientService.ts +228 -15
  412. package/src/api/organizations/controllers/AdminOrganizationController.ts +8 -8
  413. package/src/api/organizations/entities/organizations.ts +6 -6
  414. package/src/api/organizations/schemas/createOrganizationSchema.ts +5 -5
  415. package/src/api/organizations/schemas/organizationQuerySchema.ts +4 -4
  416. package/src/api/organizations/schemas/updateOrganizationSchema.ts +1 -2
  417. package/src/api/parameters/__tests__/$parameter.spec.ts +229 -50
  418. package/src/api/parameters/controllers/AdminParameterController.ts +9 -12
  419. package/src/api/parameters/entities/parameters.ts +29 -16
  420. package/src/api/parameters/primitives/$parameter.ts +3 -3
  421. package/src/api/parameters/schemas/activateParameterBodySchema.ts +4 -4
  422. package/src/api/parameters/schemas/createParameterVersionBodySchema.ts +15 -15
  423. package/src/api/parameters/schemas/parameterCreatorSummarySchema.ts +7 -7
  424. package/src/api/parameters/schemas/parameterCurrentResponseSchema.ts +7 -7
  425. package/src/api/parameters/schemas/parameterHistoryResponseSchema.ts +3 -3
  426. package/src/api/parameters/schemas/parameterNameParamSchema.ts +2 -3
  427. package/src/api/parameters/schemas/parameterNamesResponseSchema.ts +3 -3
  428. package/src/api/parameters/schemas/parameterResponseSchema.ts +3 -3
  429. package/src/api/parameters/schemas/parameterStatusSchema.ts +2 -2
  430. package/src/api/parameters/schemas/parameterTreeNodeSchema.ts +6 -6
  431. package/src/api/parameters/schemas/parameterVersionParamSchema.ts +5 -6
  432. package/src/api/parameters/schemas/parameterVersionResponseSchema.ts +3 -3
  433. package/src/api/parameters/schemas/rollbackParameterBodySchema.ts +6 -9
  434. package/src/api/parameters/services/ParameterProvider.ts +152 -65
  435. package/src/api/payments/controllers/AdminPaymentController.ts +7 -7
  436. package/src/api/payments/controllers/MockCheckoutController.ts +79 -28
  437. package/src/api/payments/controllers/PaymentController.ts +4 -4
  438. package/src/api/payments/entities/paymentIntents.ts +11 -11
  439. package/src/api/payments/entities/paymentMethods.ts +11 -11
  440. package/src/api/payments/entities/refunds.ts +9 -9
  441. package/src/api/payments/providers/PaymentProvider.ts +18 -0
  442. package/src/api/payments/schemas/intentSchemas.ts +25 -25
  443. package/src/api/payments/schemas/paymentMethodSchemas.ts +3 -3
  444. package/src/api/payments/services/PaymentService.ts +60 -3
  445. package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +14 -0
  446. package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +11 -11
  447. package/src/api/subscriptions/controllers/SubscriptionController.ts +5 -4
  448. package/src/api/subscriptions/entities/subscriptionEvents.ts +15 -15
  449. package/src/api/subscriptions/entities/subscriptions.ts +22 -22
  450. package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +22 -22
  451. package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +4 -4
  452. package/src/api/subscriptions/schemas/changePlanSchema.ts +5 -5
  453. package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +14 -7
  454. package/src/api/subscriptions/schemas/entitlementsSchema.ts +10 -10
  455. package/src/api/subscriptions/schemas/mrrSchema.ts +9 -9
  456. package/src/api/subscriptions/schemas/planDefinitionSchema.ts +21 -21
  457. package/src/api/subscriptions/schemas/planResourceSchema.ts +19 -19
  458. package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +8 -8
  459. package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +7 -7
  460. package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +17 -17
  461. package/src/api/subscriptions/services/SubscriptionConfig.ts +2 -2
  462. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +11 -11
  463. package/src/api/users/atoms/realmAuthSettingsAtom.ts +111 -119
  464. package/src/api/users/controllers/AdminIdentityController.ts +29 -19
  465. package/src/api/users/controllers/AdminSessionController.ts +37 -27
  466. package/src/api/users/controllers/AdminUserController.ts +75 -53
  467. package/src/api/users/controllers/MySessionController.ts +125 -0
  468. package/src/api/users/controllers/RealmController.ts +9 -9
  469. package/src/api/users/controllers/UserController.ts +55 -55
  470. package/src/api/users/entities/identities.ts +8 -8
  471. package/src/api/users/entities/sessions.ts +17 -17
  472. package/src/api/users/entities/users.ts +17 -17
  473. package/src/api/users/index.ts +3 -0
  474. package/src/api/users/notifications/UserNotifications.ts +76 -24
  475. package/src/api/users/primitives/$realm.ts +12 -0
  476. package/src/api/users/schemas/completePasswordResetRequestSchema.ts +8 -12
  477. package/src/api/users/schemas/completeRegistrationRequestSchema.ts +17 -20
  478. package/src/api/users/schemas/createUserSchema.ts +2 -2
  479. package/src/api/users/schemas/identityQuerySchema.ts +4 -4
  480. package/src/api/users/schemas/identityResourceSchema.ts +3 -2
  481. package/src/api/users/schemas/loginSchema.ts +4 -4
  482. package/src/api/users/schemas/passwordResetIntentResponseSchema.ts +6 -8
  483. package/src/api/users/schemas/realmConfigSchema.ts +10 -10
  484. package/src/api/users/schemas/registerQuerySchema.ts +6 -6
  485. package/src/api/users/schemas/registerRequestSchema.ts +21 -43
  486. package/src/api/users/schemas/registerResponseSchema.ts +2 -2
  487. package/src/api/users/schemas/registerSchema.ts +13 -31
  488. package/src/api/users/schemas/registrationIntentResponseSchema.ts +19 -23
  489. package/src/api/users/schemas/resetPasswordSchema.ts +10 -17
  490. package/src/api/users/schemas/sessionQuerySchema.ts +3 -3
  491. package/src/api/users/schemas/sessionResourceSchema.ts +25 -25
  492. package/src/api/users/schemas/updateUserSchema.ts +3 -4
  493. package/src/api/users/schemas/userQuerySchema.ts +7 -7
  494. package/src/api/users/services/RegistrationService.ts +25 -11
  495. package/src/api/users/services/UserService.ts +12 -6
  496. package/src/api/verifications/__tests__/CodeVerification.spec.ts +63 -101
  497. package/src/api/verifications/__tests__/LinkVerification.spec.ts +23 -92
  498. package/src/api/verifications/controllers/VerificationController.ts +13 -27
  499. package/src/api/verifications/entities/verifications.ts +13 -14
  500. package/src/api/verifications/schemas/requestVerificationCodeResponseSchema.ts +17 -14
  501. package/src/api/verifications/schemas/validateVerificationCodeResponseSchema.ts +9 -10
  502. package/src/api/verifications/schemas/verificationSettingsSchema.ts +65 -66
  503. package/src/api/verifications/schemas/verificationTypeEnumSchema.ts +2 -2
  504. package/src/api/verifications/services/VerificationService.ts +12 -0
  505. package/src/background/__tests__/BackgroundTaskProvider.spec.ts +36 -0
  506. package/src/batch/__tests__/$batch.spec.ts +22 -22
  507. package/src/batch/__tests__/startup-buffering.spec.ts +9 -9
  508. package/src/bin/index.ts +1 -1
  509. package/src/bucket/__tests__/TenantScopedBucket.spec.ts +60 -0
  510. package/src/bucket/providers/LocalFileStorageProvider.ts +14 -6
  511. package/src/bucket/providers/MemoryFileStorageProvider.ts +18 -7
  512. package/src/bucket/providers/R2FileStorageProvider.ts +14 -6
  513. package/src/bucket/providers/S3FileStorageProvider.ts +31 -15
  514. package/src/cache/core/primitives/$cache.ts +7 -10
  515. package/src/cache/database/entities/cacheEntries.ts +16 -27
  516. package/src/cache/database/providers/DatabaseCacheProvider.ts +15 -13
  517. package/src/cache/redis/providers/RedisCacheProvider.ts +6 -6
  518. package/src/captcha/providers/TurnstileCaptchaProvider.ts +4 -4
  519. package/src/cli/core/__tests__/BuildCloudflareTask.spec.ts +178 -0
  520. package/src/cli/core/__tests__/BuildDockerTask.spec.ts +0 -2
  521. package/src/cli/core/__tests__/DbCommand.spec.ts +108 -0
  522. package/src/cli/core/atoms/appEntryOptions.ts +5 -5
  523. package/src/cli/core/atoms/buildOptions.ts +76 -88
  524. package/src/cli/core/atoms/changelogOptions.ts +3 -3
  525. package/src/cli/core/atoms/devOptions.ts +3 -3
  526. package/src/cli/core/commands/build.ts +36 -49
  527. package/src/cli/core/commands/db.ts +171 -83
  528. package/src/cli/core/commands/dev.ts +8 -8
  529. package/src/cli/core/commands/gen/changelog.ts +12 -14
  530. package/src/cli/core/commands/gen/env.ts +6 -6
  531. package/src/cli/core/commands/gen/openapi.ts +6 -6
  532. package/src/cli/core/commands/init.ts +28 -33
  533. package/src/cli/core/commands/pack.ts +10 -10
  534. package/src/cli/core/commands/root.ts +7 -8
  535. package/src/cli/core/commands/test.ts +17 -20
  536. package/src/cli/core/index.ts +0 -3
  537. package/src/cli/core/tasks/BuildCloudflareTask.ts +138 -245
  538. package/src/cli/core/tasks/BuildPrerenderTask.ts +44 -7
  539. package/src/cli/core/templates/apiHelloResponseSchemaTs.ts +4 -4
  540. package/src/cli/devtools/atoms/devtoolsOptions.ts +6 -6
  541. package/src/cli/i18n/__tests__/I18nCheckService.spec.ts +48 -0
  542. package/src/cli/i18n/atoms/i18nOptions.ts +8 -8
  543. package/src/cli/i18n/services/I18nCheckService.ts +65 -11
  544. package/src/cli/platform/commands/SecretsCommand.ts +24 -25
  545. package/src/cli/platform/commands/platform.ts +40 -46
  546. package/src/cli/platform/index.ts +1 -1
  547. package/src/cli/platform-lib/__tests__/CloudflareAdapter.spec.ts +0 -4
  548. package/src/cli/platform-lib/__tests__/PlatformInspector.spec.ts +10 -3
  549. package/src/cli/platform-lib/__tests__/VercelAdapter.spec.ts +0 -2
  550. package/src/cli/platform-lib/adapters/CloudflareAdapter.ts +141 -50
  551. package/src/cli/platform-lib/adapters/VercelAdapter.ts +6 -11
  552. package/src/cli/platform-lib/atoms/platformOptions.ts +46 -25
  553. package/src/cli/platform-lib/schemas/cloudflare.ts +87 -87
  554. package/src/cli/platform-lib/schemas/platform.ts +51 -51
  555. package/src/cli/platform-lib/schemas/vercel.ts +28 -28
  556. package/src/cli/platform-lib/services/CloudflareApi.ts +5 -5
  557. package/src/cli/platform-lib/services/VercelApi.ts +4 -4
  558. package/src/cli/platform-lib/services/VercelCli.ts +6 -15
  559. package/src/cli/platform-lib/services/WranglerApi.ts +6 -15
  560. package/src/cli/vendor/atoms/vendorOptions.ts +9 -9
  561. package/src/cli/vendor/commands/VendorCommand.ts +11 -12
  562. package/src/command/__tests__/$command.spec.ts +82 -83
  563. package/src/command/__tests__/Asker.spec.ts +6 -13
  564. package/src/command/__tests__/CliProvider.spec.ts +136 -149
  565. package/src/command/__tests__/Runner.spec.ts +86 -110
  566. package/src/command/helpers/Asker.ts +23 -58
  567. package/src/command/helpers/Runner.ts +34 -110
  568. package/src/command/index.ts +4 -9
  569. package/src/command/primitives/$command.ts +10 -10
  570. package/src/command/providers/CliProvider.ts +183 -161
  571. package/src/core/Alepha.ts +62 -13
  572. package/src/core/__tests__/$atom.spec.ts +52 -3
  573. package/src/core/__tests__/$computed.spec.ts +129 -0
  574. package/src/core/__tests__/$env.spec.ts +13 -13
  575. package/src/core/__tests__/$inject.spec.ts +4 -4
  576. package/src/core/__tests__/$module.spec.ts +1 -1
  577. package/src/core/__tests__/Alepha-graph.spec.ts +1 -1
  578. package/src/core/__tests__/Alepha-parseEnv.spec.ts +32 -32
  579. package/src/core/__tests__/Alepha-start.spec.ts +3 -3
  580. package/src/core/__tests__/CodecManager.spec.ts +113 -94
  581. package/src/core/__tests__/KeylessJsonSchemaCodec.spec.ts +138 -138
  582. package/src/core/__tests__/SchemaValidator.spec.ts +43 -44
  583. package/src/core/__tests__/StateManager.persist.browser.spec.ts +87 -0
  584. package/src/core/__tests__/StateManager.spec.ts +423 -0
  585. package/src/core/__tests__/TypeBox-usecases.spec.ts +8 -8
  586. package/src/core/__tests__/TypeProvider.spec.ts +314 -309
  587. package/src/core/__tests__/dump.spec.ts +6 -6
  588. package/src/core/__tests__/pagination.spec.ts +4 -4
  589. package/src/core/__tests__/scoped-after-start.spec.ts +43 -0
  590. package/src/core/errors/TypeBoxError.ts +10 -4
  591. package/src/core/helpers/FileLike.ts +5 -5
  592. package/src/core/helpers/coerceStrings.ts +70 -0
  593. package/src/core/helpers/jsonSchemaToZod.ts +112 -0
  594. package/src/core/index.shared.ts +4 -1
  595. package/src/core/primitives/$atom.ts +95 -27
  596. package/src/core/primitives/$computed.ts +148 -0
  597. package/src/core/primitives/$env.ts +5 -5
  598. package/src/core/primitives/$state.ts +1 -1
  599. package/src/core/providers/AlsProvider.ts +26 -0
  600. package/src/core/providers/CodecManager.ts +1 -2
  601. package/src/core/providers/JsonSchemaCodec.ts +1 -2
  602. package/src/core/providers/KeylessJsonSchemaCodec.ts +82 -57
  603. package/src/core/providers/SchemaValidator.ts +48 -158
  604. package/src/core/providers/StateManager.ts +383 -9
  605. package/src/core/providers/TypeProvider.ts +80 -734
  606. package/src/core/providers/ZodProvider.ts +380 -0
  607. package/src/core/providers/zodAugment.ts +69 -0
  608. package/src/core/schemas/pageQuerySchema.ts +19 -21
  609. package/src/core/schemas/pageSchema.ts +47 -57
  610. package/src/crypto/__tests__/SecretProvider.spec.ts +31 -0
  611. package/src/crypto/providers/SecretProvider.ts +16 -10
  612. package/src/datetime/primitives/$throttle.ts +6 -1
  613. package/src/email/brevo/providers/BrevoEmailProvider.ts +4 -4
  614. package/src/email/cloudflare/providers/CloudflareEmailProvider.ts +6 -6
  615. package/src/email/core/index.ts +7 -2
  616. package/src/email/core/primitives/$email.ts +5 -1
  617. package/src/email/core/providers/LocalEmailProvider.ts +5 -5
  618. package/src/email/smtp/providers/NodemailerEmailProvider.ts +41 -52
  619. package/src/fake/__tests__/FakeProvider.spec.ts +110 -110
  620. package/src/fake/__tests__/keyName.example.ts +21 -21
  621. package/src/fake/__tests__/keyName.spec.ts +41 -41
  622. package/src/fake/__tests__/module.example.ts +8 -8
  623. package/src/fake/providers/FakeProvider.ts +122 -121
  624. package/src/lock/core/__tests__/lock-mutual-exclusion.spec.ts +44 -0
  625. package/src/lock/core/index.ts +1 -0
  626. package/src/lock/core/primitives/$lock.ts +13 -6
  627. package/src/logger/__tests__/CliFormatterProvider.spec.ts +76 -0
  628. package/src/logger/__tests__/Logger.spec.ts +49 -0
  629. package/src/logger/index.ts +25 -18
  630. package/src/logger/providers/CliFormatterProvider.ts +75 -0
  631. package/src/logger/schemas/logEntrySchema.ts +10 -10
  632. package/src/logger/services/Logger.ts +18 -0
  633. package/src/mcp/__tests__/$prompt.spec.ts +21 -23
  634. package/src/mcp/__tests__/$tool.spec.ts +22 -22
  635. package/src/mcp/__tests__/McpServerProvider.spec.ts +82 -11
  636. package/src/mcp/__tests__/StreamableHttpMcpTransport.spec.ts +2 -2
  637. package/src/mcp/__tests__/integration.spec.ts +33 -33
  638. package/src/mcp/primitives/$prompt.ts +11 -9
  639. package/src/mcp/primitives/$tool.ts +27 -86
  640. package/src/mcp/providers/McpServerProvider.ts +55 -0
  641. package/src/mcp/transports/StreamableHttpMcpTransport.ts +7 -7
  642. package/src/orm/__tests__/$repository-tests.ts +133 -27
  643. package/src/orm/__tests__/$repository.spec.ts +23 -0
  644. package/src/orm/__tests__/$transactional-tests.ts +4 -4
  645. package/src/orm/__tests__/ModelBuilder-tests.ts +28 -28
  646. package/src/orm/__tests__/ModelBuilder.spec.ts +124 -106
  647. package/src/orm/__tests__/QueryManager.spec.ts +5 -5
  648. package/src/orm/__tests__/delete-returning-tests.ts +11 -11
  649. package/src/orm/__tests__/deletedAt-tests.ts +3 -3
  650. package/src/orm/__tests__/enums.spec.ts +29 -25
  651. package/src/orm/__tests__/execute-tests.ts +8 -8
  652. package/src/orm/__tests__/fixtures/bigEntitySchema.ts +48 -48
  653. package/src/orm/__tests__/fixtures/userEntitySchema.ts +6 -6
  654. package/src/orm/__tests__/joins-tests.ts +30 -30
  655. package/src/orm/__tests__/organization-tests.ts +105 -3
  656. package/src/orm/__tests__/organization.spec.ts +46 -0
  657. package/src/orm/__tests__/orm-errors.spec.ts +10 -10
  658. package/src/orm/__tests__/orm-next-tests.ts +29 -29
  659. package/src/orm/__tests__/orm-showcase-tests.ts +9 -9
  660. package/src/orm/__tests__/primaryKey.spec.ts +4 -4
  661. package/src/orm/__tests__/query-date-encoding-tests.ts +17 -17
  662. package/src/orm/__tests__/ref-auto-onDelete.spec.ts +14 -14
  663. package/src/orm/__tests__/references.spec.ts +7 -7
  664. package/src/orm/__tests__/security.spec.ts +17 -17
  665. package/src/orm/__tests__/string-operators-tests.ts +5 -5
  666. package/src/orm/__tests__/timestamps-tests.ts +14 -14
  667. package/src/orm/__tests__/validation-tests.ts +5 -5
  668. package/src/orm/core/__tests__/BunSqliteProvider.bun.spec.ts +8 -8
  669. package/src/orm/core/constants/PG_SYMBOLS.ts +13 -1
  670. package/src/orm/core/entities/alephaSequences.ts +8 -8
  671. package/src/orm/core/helpers/pgAttr.ts +4 -4
  672. package/src/orm/core/primitives/$entity.ts +10 -6
  673. package/src/orm/core/providers/DatabaseTypeProvider.ts +46 -53
  674. package/src/orm/core/providers/drivers/BunSqliteProvider.ts +8 -8
  675. package/src/orm/core/providers/drivers/CloudflareD1Provider.ts +3 -5
  676. package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +8 -8
  677. package/src/orm/core/schemas/databaseEnvSchema.ts +4 -4
  678. package/src/orm/core/schemas/insertSchema.ts +14 -18
  679. package/src/orm/core/schemas/legacyIdSchema.ts +2 -2
  680. package/src/orm/core/schemas/updateSchema.ts +10 -16
  681. package/src/orm/core/services/PgRelationManager.ts +2 -2
  682. package/src/orm/core/services/QueryManager.ts +13 -2
  683. package/src/orm/core/services/Repository.ts +88 -33
  684. package/src/orm/core/services/SqliteModelBuilder.ts +38 -45
  685. package/src/orm/postgres/__tests__/BunPostgresProvider.bun.spec.ts +4 -4
  686. package/src/orm/postgres/providers/CloudflareHyperdriveProvider.ts +4 -6
  687. package/src/orm/postgres/schemas/postgresEnvSchema.ts +6 -6
  688. package/src/orm/postgres/services/PostgresModelBuilder.ts +127 -114
  689. package/src/queue/core/__tests__/$consumer.spec.ts +4 -4
  690. package/src/queue/core/__tests__/WorkerProvider.spec.ts +4 -4
  691. package/src/queue/core/__tests__/shared.ts +6 -6
  692. package/src/queue/core/primitives/$consumer.ts +5 -5
  693. package/src/queue/core/primitives/$queue.ts +44 -61
  694. package/src/queue/core/providers/CloudflareQueueProvider.ts +6 -0
  695. package/src/queue/core/providers/WorkerProvider.ts +17 -14
  696. package/src/queue/redis/providers/RedisQueueProvider.ts +3 -3
  697. package/src/react/core/__tests__/ErrorBoundary.browser.spec.tsx +92 -0
  698. package/src/react/core/__tests__/Router.spec.tsx +4 -4
  699. package/src/react/core/__tests__/useComputed.browser.spec.tsx +192 -0
  700. package/src/react/core/__tests__/useQuery.browser.spec.tsx +48 -0
  701. package/src/react/core/__tests__/useSelector.browser.spec.tsx +105 -0
  702. package/src/react/core/__tests__/useStore.browser.spec.tsx +113 -0
  703. package/src/react/core/components/ErrorBoundary.tsx +42 -0
  704. package/src/react/core/hooks/useAction.ts +56 -19
  705. package/src/react/core/hooks/useComputed.ts +91 -0
  706. package/src/react/core/hooks/useSelector.ts +67 -0
  707. package/src/react/core/hooks/useStore.ts +36 -17
  708. package/src/react/core/index.ts +3 -0
  709. package/src/react/core/utils/shallowEqual.ts +36 -0
  710. package/src/react/form/__tests__/FormModel-submit-loading.spec.ts +71 -0
  711. package/src/react/form/__tests__/form-submitting-reactive.browser.spec.tsx +96 -0
  712. package/src/react/form/__tests__/useForm.browser.spec.tsx +54 -54
  713. package/src/react/form/errors/FormValidationError.ts +0 -2
  714. package/src/react/form/hooks/useForm.ts +19 -4
  715. package/src/react/form/hooks/useFormQuerySync.ts +0 -0
  716. package/src/react/form/services/FormModel.ts +124 -86
  717. package/src/react/form/services/parseField.ts +66 -27
  718. package/src/react/i18n/__tests__/I18nProvider.spec.ts +89 -0
  719. package/src/react/i18n/__tests__/Localize.spec.tsx +1 -1
  720. package/src/react/i18n/__tests__/locale-routing.spec.ts +107 -0
  721. package/src/react/i18n/providers/I18nProvider.ts +173 -14
  722. package/src/react/router/__tests__/$page.browser.spec.tsx +19 -19
  723. package/src/react/router/__tests__/$page.spec.tsx +21 -21
  724. package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +87 -1
  725. package/src/react/router/__tests__/RouterLocaleProvider.spec.ts +127 -0
  726. package/src/react/router/atoms/ssrManifestAtom.ts +16 -16
  727. package/src/react/router/components/NestedView.tsx +11 -3
  728. package/src/react/router/hooks/useQueryParams.ts +1 -1
  729. package/src/react/router/index.browser.ts +4 -0
  730. package/src/react/router/index.shared.ts +1 -0
  731. package/src/react/router/index.ts +9 -0
  732. package/src/react/router/primitives/$page.ts +2 -2
  733. package/src/react/router/providers/ReactBrowserProvider.ts +64 -13
  734. package/src/react/router/providers/ReactBrowserRouterProvider.ts +15 -1
  735. package/src/react/router/providers/ReactPageProvider.ts +38 -13
  736. package/src/react/router/providers/ReactServerProvider.ts +105 -16
  737. package/src/react/router/providers/RootComponentsProvider.ts +13 -0
  738. package/src/react/router/providers/RouterLocaleProvider.ts +125 -0
  739. package/src/react/router/providers/__tests__/RootComponentsProvider.spec.ts +15 -0
  740. package/src/react/router/providers/__tests__/rootComponents.ssr.browser.spec.tsx +67 -0
  741. package/src/react/sitemap/__tests__/$sitemap.spec.ts +131 -0
  742. package/src/react/sitemap/index.browser.ts +21 -0
  743. package/src/react/sitemap/index.ts +25 -0
  744. package/src/react/sitemap/primitives/$sitemap.browser.ts +26 -0
  745. package/src/react/sitemap/primitives/$sitemap.ts +196 -0
  746. package/src/react/ui/atoms/uiAtom.ts +6 -6
  747. package/src/react/ui/atoms/uiThemeListAtom.ts +7 -7
  748. package/src/react/ui/hooks/useColorMode.ts +11 -4
  749. package/src/react/ui/services/SchemaControl.ts +4 -4
  750. package/src/redis/providers/BunRedisProvider.ts +19 -11
  751. package/src/redis/providers/NodeRedisProvider.ts +3 -3
  752. package/src/scheduler/primitives/$scheduler.ts +21 -8
  753. package/src/security/__tests__/assertRealmScope.spec.ts +29 -0
  754. package/src/security/atoms/currentTenantAtom.ts +6 -6
  755. package/src/security/atoms/currentUserAtom.ts +2 -2
  756. package/src/security/primitives/$issuer.ts +24 -2
  757. package/src/security/providers/JwtProvider.ts +100 -0
  758. package/src/security/providers/SecurityProvider.ts +43 -2
  759. package/src/security/schemas/permissionSchema.ts +19 -19
  760. package/src/security/schemas/roleSchema.ts +22 -28
  761. package/src/security/schemas/userAccountInfoSchema.ts +47 -37
  762. package/src/server/auth/__tests__/appleClientSecret.spec.ts +34 -0
  763. package/src/server/auth/__tests__/federationRedirectReplay.spec.ts +44 -0
  764. package/src/server/auth/helpers/appleClientSecret.ts +24 -0
  765. package/src/server/auth/helpers/jtiReplayGuard.ts +41 -0
  766. package/src/server/auth/helpers/safeRedirectPath.ts +19 -0
  767. package/src/server/auth/index.ts +1 -0
  768. package/src/server/auth/primitives/$auth.ts +6 -6
  769. package/src/server/auth/primitives/$authApple.ts +10 -10
  770. package/src/server/auth/primitives/$authFacebook.ts +10 -10
  771. package/src/server/auth/primitives/$authFranceConnect.ts +10 -10
  772. package/src/server/auth/primitives/$authGithub.ts +10 -10
  773. package/src/server/auth/primitives/$authGoogle.ts +10 -10
  774. package/src/server/auth/primitives/$authMicrosoft.ts +14 -14
  775. package/src/server/auth/providers/ServerAuthProvider.ts +67 -52
  776. package/src/server/auth/schemas/authenticationProviderSchema.ts +9 -12
  777. package/src/server/auth/schemas/tokenResponseSchema.ts +2 -2
  778. package/src/server/auth/schemas/tokensSchema.ts +16 -16
  779. package/src/server/auth/schemas/userinfoResponseSchema.ts +3 -3
  780. package/src/server/cookies/__tests__/AtomCookieBinding.spec.ts +80 -0
  781. package/src/server/cookies/__tests__/AtomCookiePersistence.browser.spec.ts +169 -0
  782. package/src/server/cookies/__tests__/AtomCookiePersistence.spec.ts +294 -0
  783. package/src/server/cookies/__tests__/ServerCookiesProvider.spec.ts +82 -12
  784. package/src/server/cookies/index.browser.ts +4 -1
  785. package/src/server/cookies/index.ts +8 -1
  786. package/src/server/cookies/primitives/$cookie.browser.ts +1 -1
  787. package/src/server/cookies/primitives/$cookie.ts +16 -0
  788. package/src/server/cookies/providers/AtomCookiePersistence.browser.ts +133 -0
  789. package/src/server/cookies/providers/AtomCookiePersistence.ts +148 -0
  790. package/src/server/cookies/providers/ServerCookiesProvider.ts +32 -4
  791. package/src/server/cookies/services/CookieParser.ts +6 -1
  792. package/src/server/core/__tests__/$action.spec.ts +13 -13
  793. package/src/server/core/__tests__/$middleware.spec.ts +10 -10
  794. package/src/server/core/__tests__/$route.spec.ts +9 -9
  795. package/src/server/core/__tests__/$sse.spec.ts +26 -26
  796. package/src/server/core/__tests__/BunHttpServerProvider.bun.spec.ts +6 -6
  797. package/src/server/core/__tests__/HttpClient.spec.ts +2 -2
  798. package/src/server/core/__tests__/NodeHttpServerProvider.spec.ts +15 -3
  799. package/src/server/core/__tests__/ServerBodyParserProvider.spec.ts +14 -14
  800. package/src/server/core/__tests__/ServerMultipartProvider.spec.ts +33 -33
  801. package/src/server/core/__tests__/ServerRouterProvider-errorHandler.spec.ts +5 -1
  802. package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +25 -25
  803. package/src/server/core/__tests__/ServerRouterProvider-serializationError.spec.ts +9 -5
  804. package/src/server/core/__tests__/ServerRouterProvider-validationError.spec.ts +56 -24
  805. package/src/server/core/errors/ValidationError.ts +6 -3
  806. package/src/server/core/helpers/isMultipart.ts +2 -1
  807. package/src/server/core/index.ts +5 -2
  808. package/src/server/core/interfaces/ServerRequest.ts +14 -14
  809. package/src/server/core/primitives/$action.ts +26 -36
  810. package/src/server/core/primitives/$route.ts +27 -0
  811. package/src/server/core/primitives/$sse.ts +3 -3
  812. package/src/server/core/providers/BunHttpServerProvider.ts +8 -9
  813. package/src/server/core/providers/NodeHttpServerProvider.ts +8 -9
  814. package/src/server/core/providers/ServerBodyParserProvider.ts +20 -12
  815. package/src/server/core/providers/ServerCompressProvider.ts +9 -10
  816. package/src/server/core/providers/ServerHelmetProvider.ts +26 -27
  817. package/src/server/core/providers/ServerMultipartProvider.ts +19 -19
  818. package/src/server/core/providers/ServerRouterProvider.ts +44 -15
  819. package/src/server/core/schemas/errorSchema.ts +20 -25
  820. package/src/server/core/schemas/okSchema.ts +9 -14
  821. package/src/server/core/services/HttpClient.ts +13 -1
  822. package/src/server/core/services/ServerRequestParser.ts +6 -6
  823. package/src/server/cors/providers/ServerCorsProvider.ts +26 -28
  824. package/src/server/health/schemas/healthSchema.ts +6 -6
  825. package/src/server/links/__tests__/$remote.spec.ts +3 -3
  826. package/src/server/links/__tests__/BatchEndpoint.spec.ts +9 -9
  827. package/src/server/links/__tests__/LinkProvider.spec.ts +9 -9
  828. package/src/server/links/__tests__/ServerLinksProvider.spec.ts +23 -23
  829. package/src/server/links/__tests__/fixtures/CrudApp.ts +21 -21
  830. package/src/server/links/atoms/apiLinksAtom.ts +2 -2
  831. package/src/server/links/atoms/linkOptionsAtom.ts +6 -6
  832. package/src/server/links/primitives/$remote.ts +3 -3
  833. package/src/server/links/providers/LinkProvider.ts +3 -3
  834. package/src/server/links/providers/ServerLinksProvider.ts +20 -20
  835. package/src/server/links/schemas/apiLinksResponseSchema.ts +23 -23
  836. package/src/server/proxy/__tests__/$proxy.spec.ts +9 -9
  837. package/src/server/proxy/providers/ServerProxyProvider.ts +5 -0
  838. package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +18 -20
  839. package/src/server/swagger/__tests__/$swagger.spec.ts +91 -94
  840. package/src/server/swagger/__tests__/ui.spec.ts +3 -3
  841. package/src/server/swagger/providers/ServerSwaggerProvider.ts +66 -43
  842. package/src/system/__tests__/NodeShellProvider.spec.ts +46 -0
  843. package/src/system/providers/NodeShellProvider.ts +4 -1
  844. package/src/topic/core/__tests__/$subscriber.spec.ts +4 -4
  845. package/src/topic/core/__tests__/shared.ts +8 -8
  846. package/src/topic/core/primitives/$subscriber.ts +5 -5
  847. package/src/topic/core/primitives/$topic.ts +14 -14
  848. package/src/topic/redis/providers/RedisTopicProvider.ts +3 -3
  849. package/dist/container/core/index.d.ts +0 -236
  850. package/dist/container/core/index.d.ts.map +0 -1
  851. package/dist/container/core/index.js +0 -231
  852. package/dist/container/core/index.js.map +0 -1
  853. package/dist/container/core/index.workerd.js +0 -192
  854. package/dist/container/core/index.workerd.js.map +0 -1
  855. package/src/cli/core/tasks/BuildSitemapTask.ts +0 -130
  856. package/src/command/helpers/PrettyAsker.ts +0 -256
  857. package/src/command/helpers/PrettyPrint.ts +0 -332
  858. package/src/container/core/__tests__/$container.spec.ts +0 -83
  859. package/src/container/core/index.ts +0 -50
  860. package/src/container/core/index.workerd.ts +0 -53
  861. package/src/container/core/interfaces/ContainerOptions.ts +0 -69
  862. package/src/container/core/primitives/$container.ts +0 -100
  863. package/src/container/core/providers/CloudflareContainerProvider.ts +0 -70
  864. package/src/container/core/providers/ContainerProvider.ts +0 -92
  865. package/src/container/core/providers/MockContainerProvider.ts +0 -62
  866. package/src/container/core/providers/NodeContainerProvider.ts +0 -53
  867. package/src/core/__tests__/jsonSchemaToTypeBox.spec.ts +0 -771
  868. package/src/core/helpers/jsonSchemaToTypeBox.ts +0 -359
  869. /package/dist/orm/core/{chunk-B4FMCO8f.js → rolldown-runtime-B4FMCO8f.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/react/head/helpers/SeoExpander.ts","../../../src/react/head/providers/HeadProvider.ts","../../../src/react/head/primitives/$head.ts","../../../src/react/head/providers/BrowserHeadProvider.ts","../../../src/react/head/providers/ServerHeadProvider.ts","../../../src/react/head/hooks/useHead.ts","../../../src/react/head/index.ts"],"sourcesContent":["import type { Head, HeadMeta } from \"../interfaces/Head.ts\";\n\n/**\n * Expands Head configuration into SEO meta tags.\n *\n * Generates:\n * - `<meta name=\"description\">` from head.description\n * - `<meta property=\"og:*\">` OpenGraph tags\n * - `<meta name=\"twitter:*\">` Twitter Card tags\n *\n * @example\n * ```ts\n * const helper = new SeoExpander();\n * const { meta, link } = helper.expand({\n * title: \"My App\",\n * description: \"Build amazing apps\",\n * image: \"https://example.com/og.png\",\n * url: \"https://example.com/\",\n * });\n * ```\n */\nexport class SeoExpander {\n public expand(head: Head): {\n meta: HeadMeta[];\n link: Array<{ rel: string; href: string }>;\n } {\n const meta: HeadMeta[] = [];\n const link: Array<{ rel: string; href: string }> = [];\n\n // Only expand SEO if there's meaningful content beyond just title\n const hasSeoContent =\n head.description ||\n head.image ||\n head.url ||\n head.siteName ||\n head.locale ||\n head.type ||\n head.og ||\n head.twitter;\n\n if (!hasSeoContent) {\n return { meta, link };\n }\n\n // Base description\n if (head.description) {\n meta.push({ name: \"description\", content: head.description });\n }\n\n // Canonical URL\n if (head.url) {\n link.push({ rel: \"canonical\", href: head.url });\n }\n\n // OpenGraph tags\n this.expandOpenGraph(head, meta);\n\n // Twitter Card tags\n this.expandTwitter(head, meta);\n\n return { meta, link };\n }\n\n protected expandOpenGraph(head: Head, meta: HeadMeta[]): void {\n const ogTitle = head.og?.title ?? head.title;\n const ogDescription = head.og?.description ?? head.description;\n const ogImage = head.og?.image ?? head.image;\n\n if (head.type || ogTitle) {\n meta.push({ property: \"og:type\", content: head.type ?? \"website\" });\n }\n if (head.url) {\n meta.push({ property: \"og:url\", content: head.url });\n }\n if (ogTitle) {\n meta.push({ property: \"og:title\", content: ogTitle });\n }\n if (ogDescription) {\n meta.push({ property: \"og:description\", content: ogDescription });\n }\n if (ogImage) {\n meta.push({ property: \"og:image\", content: ogImage });\n if (head.imageWidth) {\n meta.push({\n property: \"og:image:width\",\n content: String(head.imageWidth),\n });\n }\n if (head.imageHeight) {\n meta.push({\n property: \"og:image:height\",\n content: String(head.imageHeight),\n });\n }\n if (head.imageAlt) {\n meta.push({ property: \"og:image:alt\", content: head.imageAlt });\n }\n }\n if (head.siteName) {\n meta.push({ property: \"og:site_name\", content: head.siteName });\n }\n if (head.locale) {\n meta.push({ property: \"og:locale\", content: head.locale });\n }\n }\n\n protected expandTwitter(head: Head, meta: HeadMeta[]): void {\n const twitterTitle = head.twitter?.title ?? head.title;\n const twitterDescription = head.twitter?.description ?? head.description;\n const twitterImage = head.twitter?.image ?? head.image;\n\n if (head.twitter?.card || twitterTitle || twitterImage) {\n meta.push({\n name: \"twitter:card\",\n content:\n head.twitter?.card ??\n (twitterImage ? \"summary_large_image\" : \"summary\"),\n });\n }\n if (head.url) {\n meta.push({ name: \"twitter:url\", content: head.url });\n }\n if (twitterTitle) {\n meta.push({ name: \"twitter:title\", content: twitterTitle });\n }\n if (twitterDescription) {\n meta.push({ name: \"twitter:description\", content: twitterDescription });\n }\n if (twitterImage) {\n meta.push({ name: \"twitter:image\", content: twitterImage });\n if (head.imageAlt) {\n meta.push({ name: \"twitter:image:alt\", content: head.imageAlt });\n }\n }\n if (head.twitter?.site) {\n meta.push({ name: \"twitter:site\", content: head.twitter.site });\n }\n if (head.twitter?.creator) {\n meta.push({ name: \"twitter:creator\", content: head.twitter.creator });\n }\n }\n}\n","import { $inject } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { SeoExpander } from \"../helpers/SeoExpander.ts\";\nimport type { Head } from \"../interfaces/Head.ts\";\n\n/**\n * Provides methods to fill and merge head information into the application state.\n *\n * Used both on server and client side to manage document head.\n *\n * @see {@link SeoExpander}\n * @see {@link ServerHeadProvider}\n * @see {@link BrowserHeadProvider}\n */\nexport class HeadProvider {\n protected readonly log = $logger();\n protected readonly seoExpander = $inject(SeoExpander);\n\n public global?: Array<Head | (() => Head)> = [];\n\n /**\n * Track if we've warned about page-level htmlAttributes to avoid spam.\n */\n protected warnedAboutHtmlAttributes = false;\n\n /**\n * Resolve global head configuration (from $head primitives only).\n *\n * This is used to get htmlAttributes early, before page loaders run.\n * Only htmlAttributes from global $head are allowed; page-level htmlAttributes\n * are ignored for early streaming optimization.\n *\n * @returns Merged global head with htmlAttributes\n */\n public resolveGlobalHead(): Head {\n const head: Head = {\n htmlAttributes: { lang: \"en\" },\n };\n\n for (const h of this.global ?? []) {\n const resolved = typeof h === \"function\" ? h() : h;\n if (resolved.htmlAttributes) {\n head.htmlAttributes = {\n ...head.htmlAttributes,\n ...resolved.htmlAttributes,\n };\n }\n }\n\n return head;\n }\n\n /**\n * Fully resolve all global $head entries (functions re-evaluated, objects kept as-is).\n *\n * Unlike resolveGlobalHead() which only extracts htmlAttributes for streaming,\n * this resolves all head properties (meta, link, script, htmlAttributes, etc.).\n *\n * Used by BrowserHeadProvider.refreshGlobalHead() to re-apply global head to the DOM.\n */\n public resolveGlobal(): Head {\n let head: Head = {};\n\n for (const h of this.global ?? []) {\n const resolved = typeof h === \"function\" ? h() : h;\n const { meta, link } = this.seoExpander.expand(resolved);\n head = {\n ...head,\n ...resolved,\n meta: [...(head.meta ?? []), ...meta, ...(resolved.meta ?? [])],\n link: [...(head.link ?? []), ...link, ...(resolved.link ?? [])],\n script: [...(head.script ?? []), ...(resolved.script ?? [])],\n };\n }\n\n return head;\n }\n\n public fillHead(state: HeadState) {\n state.head = {\n ...state.head,\n };\n\n for (const h of this.global ?? []) {\n const head = typeof h === \"function\" ? h() : h;\n this.mergeHead(state, head);\n }\n\n for (const layer of state.layers) {\n if (layer.route?.head && !layer.error) {\n this.fillHeadByPage(layer.route, state, layer.props ?? {});\n }\n }\n\n // Defaults if none were set by global $head or page head\n state.head.title ??= \"App\";\n state.head.htmlAttributes = {\n lang: \"en\",\n ...state.head.htmlAttributes,\n };\n }\n\n protected mergeHead(state: HeadState, head: Head): void {\n // Expand SEO fields into meta tags\n const { meta, link } = this.seoExpander.expand(head);\n state.head = {\n ...state.head,\n ...head,\n meta: [...(state.head.meta ?? []), ...meta, ...(head.meta ?? [])],\n link: [...(state.head.link ?? []), ...link, ...(head.link ?? [])],\n script: [...(state.head.script ?? []), ...(head.script ?? [])],\n };\n }\n\n protected fillHeadByPage(\n page: HeadRoute,\n state: HeadState,\n props: Record<string, any>,\n ): void {\n if (!page.head) {\n return;\n }\n\n state.head ??= {};\n\n const head =\n typeof page.head === \"function\"\n ? page.head(props, state.head)\n : page.head;\n\n // Expand SEO fields into meta tags\n const { meta, link } = this.seoExpander.expand(head);\n state.head.meta = [...(state.head.meta ?? []), ...meta];\n state.head.link = [...(state.head.link ?? []), ...link];\n\n if (head.title) {\n state.head ??= {};\n\n if (state.head.titleSeparator) {\n state.head.title = `${head.title}${state.head.titleSeparator}${state.head.title}`;\n } else {\n state.head.title = head.title;\n }\n\n state.head.titleSeparator = head.titleSeparator;\n }\n\n // htmlAttributes from pages are ignored for early streaming optimization.\n // Only global $head can set htmlAttributes.\n if (head.htmlAttributes && !this.warnedAboutHtmlAttributes) {\n this.warnedAboutHtmlAttributes = true;\n this.log.warn(\n \"Page-level htmlAttributes are ignored. Use global $head() for htmlAttributes instead, \" +\n \"as they are sent before page loaders run for early streaming optimization.\",\n );\n }\n\n if (head.bodyAttributes) {\n state.head.bodyAttributes = {\n ...state.head.bodyAttributes,\n ...head.bodyAttributes,\n };\n }\n\n if (head.meta) {\n state.head.meta = [...(state.head.meta ?? []), ...(head.meta ?? [])];\n }\n\n if (head.link) {\n state.head.link = [...(state.head.link ?? []), ...(head.link ?? [])];\n }\n\n if (head.script) {\n state.head.script = [\n ...(state.head.script ?? []),\n ...(head.script ?? []),\n ];\n }\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Minimal route interface for head processing.\n * Avoids circular dependency with alepha/react/router.\n */\ninterface HeadRoute {\n head?: Head | ((props: Record<string, any>, previous?: Head) => Head);\n}\n\n/**\n * Minimal state interface for head processing.\n * Avoids circular dependency with alepha/react/router.\n */\ninterface HeadState {\n head: Head;\n layers: Array<{\n route?: HeadRoute;\n props?: Record<string, any>;\n error?: Error;\n }>;\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport type { Head } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"../providers/HeadProvider.ts\";\n\n/**\n * Set global `<head>` options for the application.\n */\nexport const $head = (options: HeadPrimitiveOptions) => {\n return createPrimitive(HeadPrimitive, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type HeadPrimitiveOptions = Head | (() => Head);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class HeadPrimitive extends Primitive<HeadPrimitiveOptions> {\n protected readonly provider = $inject(HeadProvider);\n protected onInit() {\n this.provider.global = [...(this.provider.global ?? []), this.options];\n }\n}\n\n$head[KIND] = HeadPrimitive;\n","import { $inject, Alepha } from \"alepha\";\nimport type { Head, HeadMeta } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"./HeadProvider.ts\";\n\n/**\n * Browser-side head provider that manages document head elements.\n *\n * Used by ReactBrowserProvider and ReactBrowserRouterProvider to update\n * document title, meta tags, and other head elements during client-side\n * navigation.\n */\nexport class BrowserHeadProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly headProvider = $inject(HeadProvider);\n\n protected get document(): Document {\n return window.document;\n }\n\n /**\n * Fill head state from route configurations and render to document.\n * Combines fillHead from HeadProvider with renderHead to the DOM.\n *\n * Only runs in browser environment - no-op on server.\n */\n public fillAndRenderHead(state: { head: Head; layers: Array<any> }): void {\n // Skip on server-side\n if (!this.alepha.isBrowser()) {\n return;\n }\n\n this.headProvider.fillHead(state as any);\n if (state.head) {\n this.renderHead(this.document, state.head);\n }\n }\n\n /**\n * Re-evaluate all global $head entries and apply the result to the DOM.\n *\n * Call this when something that affects global $head output changes at runtime\n * (e.g., theme switch). Page-level head (title, meta from routes) is not touched.\n */\n public refreshGlobalHead(): void {\n const head = this.headProvider.resolveGlobal();\n this.renderHead(this.document, head);\n }\n\n public getHead(document: Document): Head {\n return {\n get title() {\n return document.title;\n },\n get htmlAttributes() {\n const attrs: Record<string, string> = {};\n for (const attr of document.documentElement.attributes) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n },\n get bodyAttributes() {\n const attrs: Record<string, string> = {};\n for (const attr of document.body.attributes) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n },\n get meta() {\n const metas: HeadMeta[] = [];\n // Get meta tags with name attribute\n for (const meta of document.head.querySelectorAll(\"meta[name]\")) {\n const name = meta.getAttribute(\"name\");\n const content = meta.getAttribute(\"content\");\n if (name && content) {\n metas.push({ name, content });\n }\n }\n // Get meta tags with property attribute (OpenGraph)\n for (const meta of document.head.querySelectorAll(\"meta[property]\")) {\n const property = meta.getAttribute(\"property\");\n const content = meta.getAttribute(\"content\");\n if (property && content) {\n metas.push({ property, content });\n }\n }\n return metas;\n },\n };\n }\n\n public renderHead(document: Document, head: Head): void {\n if (head.title) {\n document.title = head.title;\n }\n\n if (head.bodyAttributes) {\n for (const [key, value] of Object.entries(head.bodyAttributes)) {\n if (value) {\n document.body.setAttribute(key, value);\n } else {\n document.body.removeAttribute(key);\n }\n }\n }\n\n if (head.htmlAttributes) {\n for (const [key, value] of Object.entries(head.htmlAttributes)) {\n if (value) {\n document.documentElement.setAttribute(key, value);\n } else {\n document.documentElement.removeAttribute(key);\n }\n }\n }\n\n if (head.meta) {\n for (const it of head.meta) {\n this.renderMetaTag(document, it);\n }\n }\n\n if (head.link) {\n for (const it of head.link) {\n const { rel, href } = it;\n let link = document.querySelector(`link[rel=\"${rel}\"][href=\"${href}\"]`);\n if (!link) {\n link = document.createElement(\"link\");\n link.setAttribute(\"rel\", rel);\n link.setAttribute(\"href\", href);\n if (it.type) {\n link.setAttribute(\"type\", it.type);\n }\n if (it.as) {\n link.setAttribute(\"as\", it.as);\n }\n if (it.crossorigin != null) {\n link.setAttribute(\"crossorigin\", \"\");\n }\n if (it.media) {\n link.setAttribute(\"media\", it.media);\n }\n if (it.sizes) {\n link.setAttribute(\"sizes\", it.sizes);\n }\n if (it.hreflang) {\n link.setAttribute(\"hreflang\", it.hreflang);\n }\n document.head.appendChild(link);\n }\n }\n }\n\n if (head.script) {\n for (const it of head.script) {\n this.renderScriptTag(document, it);\n }\n }\n }\n\n protected renderScriptTag(\n document: Document,\n script:\n | string\n | (Record<string, string | boolean | undefined> & { content?: string }),\n ): void {\n // Plain string → inline script. Dedupe by exact content match against\n // any existing inline script (handles SSR-emitted globals that would\n // otherwise be re-appended on hydration).\n if (typeof script === \"string\") {\n if (this.findInlineScriptByContent(document, script)) return;\n const el = document.createElement(\"script\");\n el.textContent = script;\n document.head.appendChild(el);\n return;\n }\n\n const { content, ...attrs } = script;\n\n // src-based scripts: dedupe by src attribute (existing behaviour).\n if (attrs.src) {\n if (document.querySelector(`script[src=\"${attrs.src}\"]`)) return;\n } else if (typeof attrs.id === \"string\") {\n // id-based dedupe — single source of truth per id.\n if (document.querySelector(`script#${CSS.escape(attrs.id)}`)) return;\n } else if (content) {\n // Inline scripts with `content` and no src/id: fall back to content match.\n if (this.findInlineScriptByContent(document, content)) return;\n }\n\n const el = document.createElement(\"script\");\n for (const [key, value] of Object.entries(attrs)) {\n if (value === true) {\n el.setAttribute(key, \"\");\n } else if (value !== undefined && value !== false) {\n el.setAttribute(key, String(value));\n }\n }\n if (content) {\n el.textContent = content;\n }\n document.head.appendChild(el);\n }\n\n /**\n * Find an existing inline `<script>` tag (no `src`) with matching textContent.\n * Used to make `renderScriptTag` idempotent across hydration + navigation,\n * so SSR-emitted global scripts aren't re-appended client-side.\n */\n protected findInlineScriptByContent(\n document: Document,\n content: string,\n ): Element | null {\n for (const existing of document.head.querySelectorAll(\n \"script:not([src])\",\n )) {\n if (existing.textContent === content) return existing;\n }\n return null;\n }\n\n protected renderMetaTag(document: Document, meta: HeadMeta): void {\n const { content } = meta;\n\n // Handle OpenGraph tags (property attribute)\n if (meta.property) {\n const existing = document.querySelector(\n `meta[property=\"${meta.property}\"]`,\n );\n if (existing) {\n existing.setAttribute(\"content\", content);\n } else {\n const newMeta = document.createElement(\"meta\");\n newMeta.setAttribute(\"property\", meta.property);\n newMeta.setAttribute(\"content\", content);\n document.head.appendChild(newMeta);\n }\n return;\n }\n\n // Handle standard meta tags (name attribute)\n if (meta.name) {\n const existing = document.querySelector(`meta[name=\"${meta.name}\"]`);\n if (existing) {\n existing.setAttribute(\"content\", content);\n } else {\n const newMeta = document.createElement(\"meta\");\n newMeta.setAttribute(\"name\", meta.name);\n newMeta.setAttribute(\"content\", content);\n document.head.appendChild(newMeta);\n }\n }\n }\n}\n","import { $inject } from \"alepha\";\nimport type { Head, SimpleHead } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"./HeadProvider.ts\";\n\n/**\n * Server-side head provider that fills head content from route configurations.\n *\n * Used by ReactServerProvider to collect title, meta tags, and other head\n * elements which are then rendered by ReactServerTemplateProvider.\n */\nexport class ServerHeadProvider {\n protected readonly headProvider = $inject(HeadProvider);\n\n /**\n * Resolve global head configuration (htmlAttributes only).\n *\n * Used for early streaming optimization - htmlAttributes can be sent\n * before page loaders run since they come from global $head only.\n */\n public resolveGlobalHead(): Head {\n return this.headProvider.resolveGlobalHead();\n }\n\n /**\n * Fill head state from route configurations.\n * Delegates to HeadProvider to merge head data from all route layers.\n */\n public fillHead(state: { head: SimpleHead; layers: Array<any> }): void {\n this.headProvider.fillHead(state as any);\n }\n}\n","import { Alepha } from \"alepha\";\nimport { useInject } from \"alepha/react\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport type { Head } from \"../interfaces/Head.ts\";\nimport { BrowserHeadProvider } from \"../providers/BrowserHeadProvider.ts\";\n\n/**\n * ```tsx\n * const App = () => {\n * const [head, setHead] = useHead({\n * // will set the document title on the first render\n * title: \"My App\",\n * });\n *\n * return (\n * // This will update the document title when the button is clicked\n * <button onClick={() => setHead({ title: \"Change Title\" })}>\n * Change Title {head.title}\n * </button>\n * );\n * }\n * ```\n */\nexport const useHead = (options?: UseHeadOptions): UseHeadReturn => {\n const alepha = useInject(Alepha);\n\n const current = useMemo(() => {\n if (!alepha.isBrowser()) {\n return {};\n }\n\n return alepha.inject(BrowserHeadProvider).getHead(window.document);\n }, []);\n\n const setHead = useCallback((head?: Head | ((previous?: Head) => Head)) => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n const headProvider = alepha.inject(BrowserHeadProvider);\n const resolved =\n typeof head === \"function\"\n ? head(headProvider.getHead(window.document))\n : head || {};\n headProvider.renderHead(window.document, resolved);\n }, []);\n\n useEffect(() => {\n if (options) {\n setHead(options);\n }\n }, []);\n\n return [current, setHead];\n};\n\nexport type UseHeadOptions = Head | ((previous?: Head) => Head);\n\nexport type UseHeadReturn = [\n Head,\n (head?: Head | ((previous?: Head) => Head)) => void,\n];\n","import { $module } from \"alepha\";\nimport { AlephaReact } from \"alepha/react\";\nimport { SeoExpander } from \"./helpers/SeoExpander.ts\";\nimport { $head } from \"./primitives/$head.ts\";\nimport { BrowserHeadProvider } from \"./providers/BrowserHeadProvider.ts\";\nimport { HeadProvider } from \"./providers/HeadProvider.ts\";\nimport { ServerHeadProvider } from \"./providers/ServerHeadProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./helpers/SeoExpander.ts\";\nexport * from \"./hooks/useHead.ts\";\nexport * from \"./interfaces/Head.ts\";\nexport * from \"./primitives/$head.ts\";\nexport * from \"./providers/BrowserHeadProvider.ts\";\nexport * from \"./providers/ServerHeadProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * HTML head element management.\n *\n * **Features:**\n * - Title, meta tags, and links\n * - SEO optimization\n * - Social media tags\n *\n * @module alepha.react.head\n */\nexport const AlephaReactHead = $module({\n name: \"alepha.react.head\",\n primitives: [$head],\n services: [\n AlephaReact,\n BrowserHeadProvider,\n HeadProvider,\n SeoExpander,\n ServerHeadProvider,\n ],\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAqBA,IAAa,cAAb,MAAyB;CACvB,OAAc,MAGZ;EACA,MAAM,OAAmB,CAAC;EAC1B,MAAM,OAA6C,CAAC;EAapD,IAAI,EATF,KAAK,eACL,KAAK,SACL,KAAK,OACL,KAAK,YACL,KAAK,UACL,KAAK,QACL,KAAK,MACL,KAAK,UAGL,OAAO;GAAE;GAAM;EAAK;EAItB,IAAI,KAAK,aACP,KAAK,KAAK;GAAE,MAAM;GAAe,SAAS,KAAK;EAAY,CAAC;EAI9D,IAAI,KAAK,KACP,KAAK,KAAK;GAAE,KAAK;GAAa,MAAM,KAAK;EAAI,CAAC;EAIhD,KAAK,gBAAgB,MAAM,IAAI;EAG/B,KAAK,cAAc,MAAM,IAAI;EAE7B,OAAO;GAAE;GAAM;EAAK;CACtB;CAEA,gBAA0B,MAAY,MAAwB;EAC5D,MAAM,UAAU,KAAK,IAAI,SAAS,KAAK;EACvC,MAAM,gBAAgB,KAAK,IAAI,eAAe,KAAK;EACnD,MAAM,UAAU,KAAK,IAAI,SAAS,KAAK;EAEvC,IAAI,KAAK,QAAQ,SACf,KAAK,KAAK;GAAE,UAAU;GAAW,SAAS,KAAK,QAAQ;EAAU,CAAC;EAEpE,IAAI,KAAK,KACP,KAAK,KAAK;GAAE,UAAU;GAAU,SAAS,KAAK;EAAI,CAAC;EAErD,IAAI,SACF,KAAK,KAAK;GAAE,UAAU;GAAY,SAAS;EAAQ,CAAC;EAEtD,IAAI,eACF,KAAK,KAAK;GAAE,UAAU;GAAkB,SAAS;EAAc,CAAC;EAElE,IAAI,SAAS;GACX,KAAK,KAAK;IAAE,UAAU;IAAY,SAAS;GAAQ,CAAC;GACpD,IAAI,KAAK,YACP,KAAK,KAAK;IACR,UAAU;IACV,SAAS,OAAO,KAAK,UAAU;GACjC,CAAC;GAEH,IAAI,KAAK,aACP,KAAK,KAAK;IACR,UAAU;IACV,SAAS,OAAO,KAAK,WAAW;GAClC,CAAC;GAEH,IAAI,KAAK,UACP,KAAK,KAAK;IAAE,UAAU;IAAgB,SAAS,KAAK;GAAS,CAAC;EAElE;EACA,IAAI,KAAK,UACP,KAAK,KAAK;GAAE,UAAU;GAAgB,SAAS,KAAK;EAAS,CAAC;EAEhE,IAAI,KAAK,QACP,KAAK,KAAK;GAAE,UAAU;GAAa,SAAS,KAAK;EAAO,CAAC;CAE7D;CAEA,cAAwB,MAAY,MAAwB;EAC1D,MAAM,eAAe,KAAK,SAAS,SAAS,KAAK;EACjD,MAAM,qBAAqB,KAAK,SAAS,eAAe,KAAK;EAC7D,MAAM,eAAe,KAAK,SAAS,SAAS,KAAK;EAEjD,IAAI,KAAK,SAAS,QAAQ,gBAAgB,cACxC,KAAK,KAAK;GACR,MAAM;GACN,SACE,KAAK,SAAS,SACb,eAAe,wBAAwB;EAC5C,CAAC;EAEH,IAAI,KAAK,KACP,KAAK,KAAK;GAAE,MAAM;GAAe,SAAS,KAAK;EAAI,CAAC;EAEtD,IAAI,cACF,KAAK,KAAK;GAAE,MAAM;GAAiB,SAAS;EAAa,CAAC;EAE5D,IAAI,oBACF,KAAK,KAAK;GAAE,MAAM;GAAuB,SAAS;EAAmB,CAAC;EAExE,IAAI,cAAc;GAChB,KAAK,KAAK;IAAE,MAAM;IAAiB,SAAS;GAAa,CAAC;GAC1D,IAAI,KAAK,UACP,KAAK,KAAK;IAAE,MAAM;IAAqB,SAAS,KAAK;GAAS,CAAC;EAEnE;EACA,IAAI,KAAK,SAAS,MAChB,KAAK,KAAK;GAAE,MAAM;GAAgB,SAAS,KAAK,QAAQ;EAAK,CAAC;EAEhE,IAAI,KAAK,SAAS,SAChB,KAAK,KAAK;GAAE,MAAM;GAAmB,SAAS,KAAK,QAAQ;EAAQ,CAAC;CAExE;AACF;;;;;;;;;;;;AC/HA,IAAa,eAAb,MAA0B;CACxB,MAAyB,QAAQ;CACjC,cAAiC,QAAQ,WAAW;CAEpD,SAA6C,CAAC;;;;CAK9C,4BAAsC;;;;;;;;;;CAWtC,oBAAiC;EAC/B,MAAM,OAAa,EACjB,gBAAgB,EAAE,MAAM,KAAK,EAC/B;EAEA,KAAK,MAAM,KAAK,KAAK,UAAU,CAAC,GAAG;GACjC,MAAM,WAAW,OAAO,MAAM,aAAa,EAAE,IAAI;GACjD,IAAI,SAAS,gBACX,KAAK,iBAAiB;IACpB,GAAG,KAAK;IACR,GAAG,SAAS;GACd;EAEJ;EAEA,OAAO;CACT;;;;;;;;;CAUA,gBAA6B;EAC3B,IAAI,OAAa,CAAC;EAElB,KAAK,MAAM,KAAK,KAAK,UAAU,CAAC,GAAG;GACjC,MAAM,WAAW,OAAO,MAAM,aAAa,EAAE,IAAI;GACjD,MAAM,EAAE,MAAM,SAAS,KAAK,YAAY,OAAO,QAAQ;GACvD,OAAO;IACL,GAAG;IACH,GAAG;IACH,MAAM;KAAC,GAAI,KAAK,QAAQ,CAAC;KAAI,GAAG;KAAM,GAAI,SAAS,QAAQ,CAAC;IAAE;IAC9D,MAAM;KAAC,GAAI,KAAK,QAAQ,CAAC;KAAI,GAAG;KAAM,GAAI,SAAS,QAAQ,CAAC;IAAE;IAC9D,QAAQ,CAAC,GAAI,KAAK,UAAU,CAAC,GAAI,GAAI,SAAS,UAAU,CAAC,CAAE;GAC7D;EACF;EAEA,OAAO;CACT;CAEA,SAAgB,OAAkB;EAChC,MAAM,OAAO,EACX,GAAG,MAAM,KACX;EAEA,KAAK,MAAM,KAAK,KAAK,UAAU,CAAC,GAAG;GACjC,MAAM,OAAO,OAAO,MAAM,aAAa,EAAE,IAAI;GAC7C,KAAK,UAAU,OAAO,IAAI;EAC5B;EAEA,KAAK,MAAM,SAAS,MAAM,QACxB,IAAI,MAAM,OAAO,QAAQ,CAAC,MAAM,OAC9B,KAAK,eAAe,MAAM,OAAO,OAAO,MAAM,SAAS,CAAC,CAAC;EAK7D,MAAM,KAAK,UAAU;EACrB,MAAM,KAAK,iBAAiB;GAC1B,MAAM;GACN,GAAG,MAAM,KAAK;EAChB;CACF;CAEA,UAAoB,OAAkB,MAAkB;EAEtD,MAAM,EAAE,MAAM,SAAS,KAAK,YAAY,OAAO,IAAI;EACnD,MAAM,OAAO;GACX,GAAG,MAAM;GACT,GAAG;GACH,MAAM;IAAC,GAAI,MAAM,KAAK,QAAQ,CAAC;IAAI,GAAG;IAAM,GAAI,KAAK,QAAQ,CAAC;GAAE;GAChE,MAAM;IAAC,GAAI,MAAM,KAAK,QAAQ,CAAC;IAAI,GAAG;IAAM,GAAI,KAAK,QAAQ,CAAC;GAAE;GAChE,QAAQ,CAAC,GAAI,MAAM,KAAK,UAAU,CAAC,GAAI,GAAI,KAAK,UAAU,CAAC,CAAE;EAC/D;CACF;CAEA,eACE,MACA,OACA,OACM;EACN,IAAI,CAAC,KAAK,MACR;EAGF,MAAM,SAAS,CAAC;EAEhB,MAAM,OACJ,OAAO,KAAK,SAAS,aACjB,KAAK,KAAK,OAAO,MAAM,IAAI,IAC3B,KAAK;EAGX,MAAM,EAAE,MAAM,SAAS,KAAK,YAAY,OAAO,IAAI;EACnD,MAAM,KAAK,OAAO,CAAC,GAAI,MAAM,KAAK,QAAQ,CAAC,GAAI,GAAG,IAAI;EACtD,MAAM,KAAK,OAAO,CAAC,GAAI,MAAM,KAAK,QAAQ,CAAC,GAAI,GAAG,IAAI;EAEtD,IAAI,KAAK,OAAO;GACd,MAAM,SAAS,CAAC;GAEhB,IAAI,MAAM,KAAK,gBACb,MAAM,KAAK,QAAQ,GAAG,KAAK,QAAQ,MAAM,KAAK,iBAAiB,MAAM,KAAK;QAE1E,MAAM,KAAK,QAAQ,KAAK;GAG1B,MAAM,KAAK,iBAAiB,KAAK;EACnC;EAIA,IAAI,KAAK,kBAAkB,CAAC,KAAK,2BAA2B;GAC1D,KAAK,4BAA4B;GACjC,KAAK,IAAI,KACP,kKAEF;EACF;EAEA,IAAI,KAAK,gBACP,MAAM,KAAK,iBAAiB;GAC1B,GAAG,MAAM,KAAK;GACd,GAAG,KAAK;EACV;EAGF,IAAI,KAAK,MACP,MAAM,KAAK,OAAO,CAAC,GAAI,MAAM,KAAK,QAAQ,CAAC,GAAI,GAAI,KAAK,QAAQ,CAAC,CAAE;EAGrE,IAAI,KAAK,MACP,MAAM,KAAK,OAAO,CAAC,GAAI,MAAM,KAAK,QAAQ,CAAC,GAAI,GAAI,KAAK,QAAQ,CAAC,CAAE;EAGrE,IAAI,KAAK,QACP,MAAM,KAAK,SAAS,CAClB,GAAI,MAAM,KAAK,UAAU,CAAC,GAC1B,GAAI,KAAK,UAAU,CAAC,CACtB;CAEJ;AACF;;;;;;AC5KA,MAAa,SAAS,YAAkC;CACtD,OAAO,gBAAgB,eAAe,OAAO;AAC/C;AAQA,IAAa,gBAAb,cAAmC,UAAgC;CACjE,WAA8B,QAAQ,YAAY;CAClD,SAAmB;EACjB,KAAK,SAAS,SAAS,CAAC,GAAI,KAAK,SAAS,UAAU,CAAC,GAAI,KAAK,OAAO;CACvE;AACF;AAEA,MAAM,QAAQ;;;;;;;;;;ACbd,IAAa,sBAAb,MAAiC;CAC/B,SAA4B,QAAQ,MAAM;CAC1C,eAAkC,QAAQ,YAAY;CAEtD,IAAc,WAAqB;EACjC,OAAO,OAAO;CAChB;;;;;;;CAQA,kBAAyB,OAAiD;EAExE,IAAI,CAAC,KAAK,OAAO,UAAU,GACzB;EAGF,KAAK,aAAa,SAAS,KAAY;EACvC,IAAI,MAAM,MACR,KAAK,WAAW,KAAK,UAAU,MAAM,IAAI;CAE7C;;;;;;;CAQA,oBAAiC;EAC/B,MAAM,OAAO,KAAK,aAAa,cAAc;EAC7C,KAAK,WAAW,KAAK,UAAU,IAAI;CACrC;CAEA,QAAe,UAA0B;EACvC,OAAO;GACL,IAAI,QAAQ;IACV,OAAO,SAAS;GAClB;GACA,IAAI,iBAAiB;IACnB,MAAM,QAAgC,CAAC;IACvC,KAAK,MAAM,QAAQ,SAAS,gBAAgB,YAC1C,MAAM,KAAK,QAAQ,KAAK;IAE1B,OAAO;GACT;GACA,IAAI,iBAAiB;IACnB,MAAM,QAAgC,CAAC;IACvC,KAAK,MAAM,QAAQ,SAAS,KAAK,YAC/B,MAAM,KAAK,QAAQ,KAAK;IAE1B,OAAO;GACT;GACA,IAAI,OAAO;IACT,MAAM,QAAoB,CAAC;IAE3B,KAAK,MAAM,QAAQ,SAAS,KAAK,iBAAiB,YAAY,GAAG;KAC/D,MAAM,OAAO,KAAK,aAAa,MAAM;KACrC,MAAM,UAAU,KAAK,aAAa,SAAS;KAC3C,IAAI,QAAQ,SACV,MAAM,KAAK;MAAE;MAAM;KAAQ,CAAC;IAEhC;IAEA,KAAK,MAAM,QAAQ,SAAS,KAAK,iBAAiB,gBAAgB,GAAG;KACnE,MAAM,WAAW,KAAK,aAAa,UAAU;KAC7C,MAAM,UAAU,KAAK,aAAa,SAAS;KAC3C,IAAI,YAAY,SACd,MAAM,KAAK;MAAE;MAAU;KAAQ,CAAC;IAEpC;IACA,OAAO;GACT;EACF;CACF;CAEA,WAAkB,UAAoB,MAAkB;EACtD,IAAI,KAAK,OACP,SAAS,QAAQ,KAAK;EAGxB,IAAI,KAAK,gBACP,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,cAAc,GAC3D,IAAI,OACF,SAAS,KAAK,aAAa,KAAK,KAAK;OAErC,SAAS,KAAK,gBAAgB,GAAG;EAKvC,IAAI,KAAK,gBACP,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,cAAc,GAC3D,IAAI,OACF,SAAS,gBAAgB,aAAa,KAAK,KAAK;OAEhD,SAAS,gBAAgB,gBAAgB,GAAG;EAKlD,IAAI,KAAK,MACP,KAAK,MAAM,MAAM,KAAK,MACpB,KAAK,cAAc,UAAU,EAAE;EAInC,IAAI,KAAK,MACP,KAAK,MAAM,MAAM,KAAK,MAAM;GAC1B,MAAM,EAAE,KAAK,SAAS;GACtB,IAAI,OAAO,SAAS,cAAc,aAAa,IAAI,WAAW,KAAK,GAAG;GACtE,IAAI,CAAC,MAAM;IACT,OAAO,SAAS,cAAc,MAAM;IACpC,KAAK,aAAa,OAAO,GAAG;IAC5B,KAAK,aAAa,QAAQ,IAAI;IAC9B,IAAI,GAAG,MACL,KAAK,aAAa,QAAQ,GAAG,IAAI;IAEnC,IAAI,GAAG,IACL,KAAK,aAAa,MAAM,GAAG,EAAE;IAE/B,IAAI,GAAG,eAAe,MACpB,KAAK,aAAa,eAAe,EAAE;IAErC,IAAI,GAAG,OACL,KAAK,aAAa,SAAS,GAAG,KAAK;IAErC,IAAI,GAAG,OACL,KAAK,aAAa,SAAS,GAAG,KAAK;IAErC,IAAI,GAAG,UACL,KAAK,aAAa,YAAY,GAAG,QAAQ;IAE3C,SAAS,KAAK,YAAY,IAAI;GAChC;EACF;EAGF,IAAI,KAAK,QACP,KAAK,MAAM,MAAM,KAAK,QACpB,KAAK,gBAAgB,UAAU,EAAE;CAGvC;CAEA,gBACE,UACA,QAGM;EAIN,IAAI,OAAO,WAAW,UAAU;GAC9B,IAAI,KAAK,0BAA0B,UAAU,MAAM,GAAG;GACtD,MAAM,KAAK,SAAS,cAAc,QAAQ;GAC1C,GAAG,cAAc;GACjB,SAAS,KAAK,YAAY,EAAE;GAC5B;EACF;EAEA,MAAM,EAAE,SAAS,GAAG,UAAU;EAG9B,IAAI,MAAM;OACJ,SAAS,cAAc,eAAe,MAAM,IAAI,GAAG,GAAG;EAAA,OACrD,IAAI,OAAO,MAAM,OAAO;OAEzB,SAAS,cAAc,UAAU,IAAI,OAAO,MAAM,EAAE,GAAG,GAAG;EAAA,OACzD,IAAI;OAEL,KAAK,0BAA0B,UAAU,OAAO,GAAG;EAAA;EAGzD,MAAM,KAAK,SAAS,cAAc,QAAQ;EAC1C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,IAAI,UAAU,MACZ,GAAG,aAAa,KAAK,EAAE;OAClB,IAAI,UAAU,KAAA,KAAa,UAAU,OAC1C,GAAG,aAAa,KAAK,OAAO,KAAK,CAAC;EAGtC,IAAI,SACF,GAAG,cAAc;EAEnB,SAAS,KAAK,YAAY,EAAE;CAC9B;;;;;;CAOA,0BACE,UACA,SACgB;EAChB,KAAK,MAAM,YAAY,SAAS,KAAK,iBACnC,mBACF,GACE,IAAI,SAAS,gBAAgB,SAAS,OAAO;EAE/C,OAAO;CACT;CAEA,cAAwB,UAAoB,MAAsB;EAChE,MAAM,EAAE,YAAY;EAGpB,IAAI,KAAK,UAAU;GACjB,MAAM,WAAW,SAAS,cACxB,kBAAkB,KAAK,SAAS,GAClC;GACA,IAAI,UACF,SAAS,aAAa,WAAW,OAAO;QACnC;IACL,MAAM,UAAU,SAAS,cAAc,MAAM;IAC7C,QAAQ,aAAa,YAAY,KAAK,QAAQ;IAC9C,QAAQ,aAAa,WAAW,OAAO;IACvC,SAAS,KAAK,YAAY,OAAO;GACnC;GACA;EACF;EAGA,IAAI,KAAK,MAAM;GACb,MAAM,WAAW,SAAS,cAAc,cAAc,KAAK,KAAK,GAAG;GACnE,IAAI,UACF,SAAS,aAAa,WAAW,OAAO;QACnC;IACL,MAAM,UAAU,SAAS,cAAc,MAAM;IAC7C,QAAQ,aAAa,QAAQ,KAAK,IAAI;IACtC,QAAQ,aAAa,WAAW,OAAO;IACvC,SAAS,KAAK,YAAY,OAAO;GACnC;EACF;CACF;AACF;;;;;;;;;AClPA,IAAa,qBAAb,MAAgC;CAC9B,eAAkC,QAAQ,YAAY;;;;;;;CAQtD,oBAAiC;EAC/B,OAAO,KAAK,aAAa,kBAAkB;CAC7C;;;;;CAMA,SAAgB,OAAuD;EACrE,KAAK,aAAa,SAAS,KAAY;CACzC;AACF;;;;;;;;;;;;;;;;;;;;ACPA,MAAa,WAAW,YAA4C;CAClE,MAAM,SAAS,UAAU,MAAM;CAE/B,MAAM,UAAU,cAAc;EAC5B,IAAI,CAAC,OAAO,UAAU,GACpB,OAAO,CAAC;EAGV,OAAO,OAAO,OAAO,mBAAmB,EAAE,QAAQ,OAAO,QAAQ;CACnE,GAAG,CAAC,CAAC;CAEL,MAAM,UAAU,aAAa,SAA8C;EACzE,IAAI,CAAC,OAAO,UAAU,GACpB;EAGF,MAAM,eAAe,OAAO,OAAO,mBAAmB;EACtD,MAAM,WACJ,OAAO,SAAS,aACZ,KAAK,aAAa,QAAQ,OAAO,QAAQ,CAAC,IAC1C,QAAQ,CAAC;EACf,aAAa,WAAW,OAAO,UAAU,QAAQ;CACnD,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,IAAI,SACF,QAAQ,OAAO;CAEnB,GAAG,CAAC,CAAC;CAEL,OAAO,CAAC,SAAS,OAAO;AAC1B;;;;;;;;;;;;;ACzBA,MAAa,kBAAkB,QAAQ;CACrC,MAAM;CACN,YAAY,CAAC,KAAK;CAClB,UAAU;EACR;EACA;EACA;EACA;EACA;CACF;AACF,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/react/head/helpers/SeoExpander.ts","../../../src/react/head/providers/HeadProvider.ts","../../../src/react/head/primitives/$head.ts","../../../src/react/head/providers/BrowserHeadProvider.ts","../../../src/react/head/providers/ServerHeadProvider.ts","../../../src/react/head/hooks/useHead.ts","../../../src/react/head/index.ts"],"sourcesContent":["import type { Head, HeadMeta } from \"../interfaces/Head.ts\";\n\n/**\n * Expands Head configuration into SEO meta tags.\n *\n * Generates:\n * - `<meta name=\"description\">` from head.description\n * - `<meta property=\"og:*\">` OpenGraph tags\n * - `<meta name=\"twitter:*\">` Twitter Card tags\n *\n * @example\n * ```ts\n * const helper = new SeoExpander();\n * const { meta, link } = helper.expand({\n * title: \"My App\",\n * description: \"Build amazing apps\",\n * image: \"https://example.com/og.png\",\n * url: \"https://example.com/\",\n * });\n * ```\n */\nexport class SeoExpander {\n public expand(head: Head): {\n meta: HeadMeta[];\n link: Array<{ rel: string; href: string }>;\n } {\n const meta: HeadMeta[] = [];\n const link: Array<{ rel: string; href: string }> = [];\n\n // Only expand SEO if there's meaningful content beyond just title\n const hasSeoContent =\n head.description ||\n head.image ||\n head.url ||\n head.siteName ||\n head.locale ||\n head.type ||\n head.og ||\n head.twitter;\n\n if (!hasSeoContent) {\n return { meta, link };\n }\n\n // Base description\n if (head.description) {\n meta.push({ name: \"description\", content: head.description });\n }\n\n // Canonical URL\n if (head.url) {\n link.push({ rel: \"canonical\", href: head.url });\n }\n\n // OpenGraph tags\n this.expandOpenGraph(head, meta);\n\n // Twitter Card tags\n this.expandTwitter(head, meta);\n\n return { meta, link };\n }\n\n protected expandOpenGraph(head: Head, meta: HeadMeta[]): void {\n const ogTitle = head.og?.title ?? head.title;\n const ogDescription = head.og?.description ?? head.description;\n const ogImage = head.og?.image ?? head.image;\n\n if (head.type || ogTitle) {\n meta.push({ property: \"og:type\", content: head.type ?? \"website\" });\n }\n if (head.url) {\n meta.push({ property: \"og:url\", content: head.url });\n }\n if (ogTitle) {\n meta.push({ property: \"og:title\", content: ogTitle });\n }\n if (ogDescription) {\n meta.push({ property: \"og:description\", content: ogDescription });\n }\n if (ogImage) {\n meta.push({ property: \"og:image\", content: ogImage });\n if (head.imageWidth) {\n meta.push({\n property: \"og:image:width\",\n content: String(head.imageWidth),\n });\n }\n if (head.imageHeight) {\n meta.push({\n property: \"og:image:height\",\n content: String(head.imageHeight),\n });\n }\n if (head.imageAlt) {\n meta.push({ property: \"og:image:alt\", content: head.imageAlt });\n }\n }\n if (head.siteName) {\n meta.push({ property: \"og:site_name\", content: head.siteName });\n }\n if (head.locale) {\n meta.push({ property: \"og:locale\", content: head.locale });\n }\n }\n\n protected expandTwitter(head: Head, meta: HeadMeta[]): void {\n const twitterTitle = head.twitter?.title ?? head.title;\n const twitterDescription = head.twitter?.description ?? head.description;\n const twitterImage = head.twitter?.image ?? head.image;\n\n if (head.twitter?.card || twitterTitle || twitterImage) {\n meta.push({\n name: \"twitter:card\",\n content:\n head.twitter?.card ??\n (twitterImage ? \"summary_large_image\" : \"summary\"),\n });\n }\n if (head.url) {\n meta.push({ name: \"twitter:url\", content: head.url });\n }\n if (twitterTitle) {\n meta.push({ name: \"twitter:title\", content: twitterTitle });\n }\n if (twitterDescription) {\n meta.push({ name: \"twitter:description\", content: twitterDescription });\n }\n if (twitterImage) {\n meta.push({ name: \"twitter:image\", content: twitterImage });\n if (head.imageAlt) {\n meta.push({ name: \"twitter:image:alt\", content: head.imageAlt });\n }\n }\n if (head.twitter?.site) {\n meta.push({ name: \"twitter:site\", content: head.twitter.site });\n }\n if (head.twitter?.creator) {\n meta.push({ name: \"twitter:creator\", content: head.twitter.creator });\n }\n }\n}\n","import { $inject } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { SeoExpander } from \"../helpers/SeoExpander.ts\";\nimport type { Head } from \"../interfaces/Head.ts\";\n\n/**\n * Provides methods to fill and merge head information into the application state.\n *\n * Used both on server and client side to manage document head.\n *\n * @see {@link SeoExpander}\n * @see {@link ServerHeadProvider}\n * @see {@link BrowserHeadProvider}\n */\nexport class HeadProvider {\n protected readonly log = $logger();\n protected readonly seoExpander = $inject(SeoExpander);\n\n public global?: Array<Head | (() => Head)> = [];\n\n /**\n * Track if we've warned about page-level htmlAttributes to avoid spam.\n */\n protected warnedAboutHtmlAttributes = false;\n\n /**\n * Resolve global head configuration (from $head primitives only).\n *\n * This is used to get htmlAttributes early, before page loaders run.\n * Only htmlAttributes from global $head are allowed; page-level htmlAttributes\n * are ignored for early streaming optimization.\n *\n * @returns Merged global head with htmlAttributes\n */\n public resolveGlobalHead(): Head {\n const head: Head = {\n htmlAttributes: { lang: \"en\" },\n };\n\n for (const h of this.global ?? []) {\n const resolved = typeof h === \"function\" ? h() : h;\n if (resolved.htmlAttributes) {\n head.htmlAttributes = {\n ...head.htmlAttributes,\n ...resolved.htmlAttributes,\n };\n }\n }\n\n return head;\n }\n\n /**\n * Fully resolve all global $head entries (functions re-evaluated, objects kept as-is).\n *\n * Unlike resolveGlobalHead() which only extracts htmlAttributes for streaming,\n * this resolves all head properties (meta, link, script, htmlAttributes, etc.).\n *\n * Used by BrowserHeadProvider.refreshGlobalHead() to re-apply global head to the DOM.\n */\n public resolveGlobal(): Head {\n let head: Head = {};\n\n for (const h of this.global ?? []) {\n const resolved = typeof h === \"function\" ? h() : h;\n const { meta, link } = this.seoExpander.expand(resolved);\n head = {\n ...head,\n ...resolved,\n meta: [...(head.meta ?? []), ...meta, ...(resolved.meta ?? [])],\n link: [...(head.link ?? []), ...link, ...(resolved.link ?? [])],\n script: [...(head.script ?? []), ...(resolved.script ?? [])],\n };\n }\n\n return head;\n }\n\n public fillHead(state: HeadState) {\n state.head = {\n ...state.head,\n };\n\n for (const h of this.global ?? []) {\n const head = typeof h === \"function\" ? h() : h;\n this.mergeHead(state, head);\n }\n\n for (const layer of state.layers) {\n if (layer.route?.head && !layer.error) {\n this.fillHeadByPage(layer.route, state, layer.props ?? {});\n }\n }\n\n // Defaults if none were set by global $head or page head\n state.head.title ??= \"App\";\n state.head.htmlAttributes = {\n lang: \"en\",\n ...state.head.htmlAttributes,\n };\n }\n\n protected mergeHead(state: HeadState, head: Head): void {\n // Expand SEO fields into meta tags\n const { meta, link } = this.seoExpander.expand(head);\n state.head = {\n ...state.head,\n ...head,\n meta: [...(state.head.meta ?? []), ...meta, ...(head.meta ?? [])],\n link: [...(state.head.link ?? []), ...link, ...(head.link ?? [])],\n script: [...(state.head.script ?? []), ...(head.script ?? [])],\n };\n }\n\n protected fillHeadByPage(\n page: HeadRoute,\n state: HeadState,\n props: Record<string, any>,\n ): void {\n if (!page.head) {\n return;\n }\n\n state.head ??= {};\n\n const head =\n typeof page.head === \"function\"\n ? page.head(props, state.head)\n : page.head;\n\n // Expand SEO fields into meta tags\n const { meta, link } = this.seoExpander.expand(head);\n state.head.meta = [...(state.head.meta ?? []), ...meta];\n state.head.link = [...(state.head.link ?? []), ...link];\n\n if (head.title) {\n state.head ??= {};\n\n if (state.head.titleSeparator) {\n state.head.title = `${head.title}${state.head.titleSeparator}${state.head.title}`;\n } else {\n state.head.title = head.title;\n }\n\n state.head.titleSeparator = head.titleSeparator;\n }\n\n // htmlAttributes from pages are ignored for early streaming optimization.\n // Only global $head can set htmlAttributes.\n if (head.htmlAttributes && !this.warnedAboutHtmlAttributes) {\n this.warnedAboutHtmlAttributes = true;\n this.log.warn(\n \"Page-level htmlAttributes are ignored. Use global $head() for htmlAttributes instead, \" +\n \"as they are sent before page loaders run for early streaming optimization.\",\n );\n }\n\n if (head.bodyAttributes) {\n state.head.bodyAttributes = {\n ...state.head.bodyAttributes,\n ...head.bodyAttributes,\n };\n }\n\n if (head.meta) {\n state.head.meta = [...(state.head.meta ?? []), ...(head.meta ?? [])];\n }\n\n if (head.link) {\n state.head.link = [...(state.head.link ?? []), ...(head.link ?? [])];\n }\n\n if (head.script) {\n state.head.script = [\n ...(state.head.script ?? []),\n ...(head.script ?? []),\n ];\n }\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Minimal route interface for head processing.\n * Avoids circular dependency with alepha/react/router.\n */\ninterface HeadRoute {\n head?: Head | ((props: Record<string, any>, previous?: Head) => Head);\n}\n\n/**\n * Minimal state interface for head processing.\n * Avoids circular dependency with alepha/react/router.\n */\ninterface HeadState {\n head: Head;\n layers: Array<{\n route?: HeadRoute;\n props?: Record<string, any>;\n error?: Error;\n }>;\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport type { Head } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"../providers/HeadProvider.ts\";\n\n/**\n * Set global `<head>` options for the application.\n */\nexport const $head = (options: HeadPrimitiveOptions) => {\n return createPrimitive(HeadPrimitive, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type HeadPrimitiveOptions = Head | (() => Head);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class HeadPrimitive extends Primitive<HeadPrimitiveOptions> {\n protected readonly provider = $inject(HeadProvider);\n protected onInit() {\n this.provider.global = [...(this.provider.global ?? []), this.options];\n }\n}\n\n$head[KIND] = HeadPrimitive;\n","import { $inject, Alepha } from \"alepha\";\nimport type { Head, HeadMeta } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"./HeadProvider.ts\";\n\n/**\n * Browser-side head provider that manages document head elements.\n *\n * Used by ReactBrowserProvider and ReactBrowserRouterProvider to update\n * document title, meta tags, and other head elements during client-side\n * navigation.\n */\nexport class BrowserHeadProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly headProvider = $inject(HeadProvider);\n\n protected get document(): Document {\n return window.document;\n }\n\n /**\n * Fill head state from route configurations and render to document.\n * Combines fillHead from HeadProvider with renderHead to the DOM.\n *\n * Only runs in browser environment - no-op on server.\n */\n public fillAndRenderHead(state: { head: Head; layers: Array<any> }): void {\n // Skip on server-side\n if (!this.alepha.isBrowser()) {\n return;\n }\n\n this.headProvider.fillHead(state as any);\n if (state.head) {\n this.renderHead(this.document, state.head);\n }\n }\n\n /**\n * Re-evaluate all global $head entries and apply the result to the DOM.\n *\n * Call this when something that affects global $head output changes at runtime\n * (e.g., theme switch). Page-level head (title, meta from routes) is not touched.\n */\n public refreshGlobalHead(): void {\n const head = this.headProvider.resolveGlobal();\n this.renderHead(this.document, head);\n }\n\n public getHead(document: Document): Head {\n return {\n get title() {\n return document.title;\n },\n get htmlAttributes() {\n const attrs: Record<string, string> = {};\n for (const attr of document.documentElement.attributes) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n },\n get bodyAttributes() {\n const attrs: Record<string, string> = {};\n for (const attr of document.body.attributes) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n },\n get meta() {\n const metas: HeadMeta[] = [];\n // Get meta tags with name attribute\n for (const meta of document.head.querySelectorAll(\"meta[name]\")) {\n const name = meta.getAttribute(\"name\");\n const content = meta.getAttribute(\"content\");\n if (name && content) {\n metas.push({ name, content });\n }\n }\n // Get meta tags with property attribute (OpenGraph)\n for (const meta of document.head.querySelectorAll(\"meta[property]\")) {\n const property = meta.getAttribute(\"property\");\n const content = meta.getAttribute(\"content\");\n if (property && content) {\n metas.push({ property, content });\n }\n }\n return metas;\n },\n };\n }\n\n public renderHead(document: Document, head: Head): void {\n if (head.title) {\n document.title = head.title;\n }\n\n if (head.bodyAttributes) {\n for (const [key, value] of Object.entries(head.bodyAttributes)) {\n if (value) {\n document.body.setAttribute(key, value);\n } else {\n document.body.removeAttribute(key);\n }\n }\n }\n\n if (head.htmlAttributes) {\n for (const [key, value] of Object.entries(head.htmlAttributes)) {\n if (value) {\n document.documentElement.setAttribute(key, value);\n } else {\n document.documentElement.removeAttribute(key);\n }\n }\n }\n\n if (head.meta) {\n for (const it of head.meta) {\n this.renderMetaTag(document, it);\n }\n }\n\n if (head.link) {\n for (const it of head.link) {\n const { rel, href } = it;\n let link = document.querySelector(`link[rel=\"${rel}\"][href=\"${href}\"]`);\n if (!link) {\n link = document.createElement(\"link\");\n link.setAttribute(\"rel\", rel);\n link.setAttribute(\"href\", href);\n if (it.type) {\n link.setAttribute(\"type\", it.type);\n }\n if (it.as) {\n link.setAttribute(\"as\", it.as);\n }\n if (it.crossorigin != null) {\n link.setAttribute(\"crossorigin\", \"\");\n }\n if (it.media) {\n link.setAttribute(\"media\", it.media);\n }\n if (it.sizes) {\n link.setAttribute(\"sizes\", it.sizes);\n }\n if (it.hreflang) {\n link.setAttribute(\"hreflang\", it.hreflang);\n }\n document.head.appendChild(link);\n }\n }\n }\n\n if (head.script) {\n for (const it of head.script) {\n this.renderScriptTag(document, it);\n }\n }\n }\n\n protected renderScriptTag(\n document: Document,\n script:\n | string\n | (Record<string, string | boolean | undefined> & { content?: string }),\n ): void {\n // Plain string → inline script. Dedupe by exact content match against\n // any existing inline script (handles SSR-emitted globals that would\n // otherwise be re-appended on hydration).\n if (typeof script === \"string\") {\n if (this.findInlineScriptByContent(document, script)) return;\n const el = document.createElement(\"script\");\n el.textContent = script;\n document.head.appendChild(el);\n return;\n }\n\n const { content, ...attrs } = script;\n\n // src-based scripts: dedupe by src attribute (existing behaviour).\n if (attrs.src) {\n if (document.querySelector(`script[src=\"${attrs.src}\"]`)) return;\n } else if (typeof attrs.id === \"string\") {\n // id-based dedupe — single source of truth per id.\n if (document.querySelector(`script#${CSS.escape(attrs.id)}`)) return;\n } else if (content) {\n // Inline scripts with `content` and no src/id: fall back to content match.\n if (this.findInlineScriptByContent(document, content)) return;\n }\n\n const el = document.createElement(\"script\");\n for (const [key, value] of Object.entries(attrs)) {\n if (value === true) {\n el.setAttribute(key, \"\");\n } else if (value !== undefined && value !== false) {\n el.setAttribute(key, String(value));\n }\n }\n if (content) {\n el.textContent = content;\n }\n document.head.appendChild(el);\n }\n\n /**\n * Find an existing inline `<script>` tag (no `src`) with matching textContent.\n * Used to make `renderScriptTag` idempotent across hydration + navigation,\n * so SSR-emitted global scripts aren't re-appended client-side.\n */\n protected findInlineScriptByContent(\n document: Document,\n content: string,\n ): Element | null {\n for (const existing of document.head.querySelectorAll(\n \"script:not([src])\",\n )) {\n if (existing.textContent === content) return existing;\n }\n return null;\n }\n\n protected renderMetaTag(document: Document, meta: HeadMeta): void {\n const { content } = meta;\n\n // Handle OpenGraph tags (property attribute)\n if (meta.property) {\n const existing = document.querySelector(\n `meta[property=\"${meta.property}\"]`,\n );\n if (existing) {\n existing.setAttribute(\"content\", content);\n } else {\n const newMeta = document.createElement(\"meta\");\n newMeta.setAttribute(\"property\", meta.property);\n newMeta.setAttribute(\"content\", content);\n document.head.appendChild(newMeta);\n }\n return;\n }\n\n // Handle standard meta tags (name attribute)\n if (meta.name) {\n const existing = document.querySelector(`meta[name=\"${meta.name}\"]`);\n if (existing) {\n existing.setAttribute(\"content\", content);\n } else {\n const newMeta = document.createElement(\"meta\");\n newMeta.setAttribute(\"name\", meta.name);\n newMeta.setAttribute(\"content\", content);\n document.head.appendChild(newMeta);\n }\n }\n }\n}\n","import { $inject } from \"alepha\";\nimport type { Head, SimpleHead } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"./HeadProvider.ts\";\n\n/**\n * Server-side head provider that fills head content from route configurations.\n *\n * Used by ReactServerProvider to collect title, meta tags, and other head\n * elements which are then rendered by ReactServerTemplateProvider.\n */\nexport class ServerHeadProvider {\n protected readonly headProvider = $inject(HeadProvider);\n\n /**\n * Resolve global head configuration (htmlAttributes only).\n *\n * Used for early streaming optimization - htmlAttributes can be sent\n * before page loaders run since they come from global $head only.\n */\n public resolveGlobalHead(): Head {\n return this.headProvider.resolveGlobalHead();\n }\n\n /**\n * Fill head state from route configurations.\n * Delegates to HeadProvider to merge head data from all route layers.\n */\n public fillHead(state: { head: SimpleHead; layers: Array<any> }): void {\n this.headProvider.fillHead(state as any);\n }\n}\n","import { Alepha } from \"alepha\";\nimport { useInject } from \"alepha/react\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport type { Head } from \"../interfaces/Head.ts\";\nimport { BrowserHeadProvider } from \"../providers/BrowserHeadProvider.ts\";\n\n/**\n * ```tsx\n * const App = () => {\n * const [head, setHead] = useHead({\n * // will set the document title on the first render\n * title: \"My App\",\n * });\n *\n * return (\n * // This will update the document title when the button is clicked\n * <button onClick={() => setHead({ title: \"Change Title\" })}>\n * Change Title {head.title}\n * </button>\n * );\n * }\n * ```\n */\nexport const useHead = (options?: UseHeadOptions): UseHeadReturn => {\n const alepha = useInject(Alepha);\n\n const current = useMemo(() => {\n if (!alepha.isBrowser()) {\n return {};\n }\n\n return alepha.inject(BrowserHeadProvider).getHead(window.document);\n }, []);\n\n const setHead = useCallback((head?: Head | ((previous?: Head) => Head)) => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n const headProvider = alepha.inject(BrowserHeadProvider);\n const resolved =\n typeof head === \"function\"\n ? head(headProvider.getHead(window.document))\n : head || {};\n headProvider.renderHead(window.document, resolved);\n }, []);\n\n useEffect(() => {\n if (options) {\n setHead(options);\n }\n }, []);\n\n return [current, setHead];\n};\n\nexport type UseHeadOptions = Head | ((previous?: Head) => Head);\n\nexport type UseHeadReturn = [\n Head,\n (head?: Head | ((previous?: Head) => Head)) => void,\n];\n","import { $module } from \"alepha\";\nimport { AlephaReact } from \"alepha/react\";\nimport { SeoExpander } from \"./helpers/SeoExpander.ts\";\nimport { $head } from \"./primitives/$head.ts\";\nimport { BrowserHeadProvider } from \"./providers/BrowserHeadProvider.ts\";\nimport { HeadProvider } from \"./providers/HeadProvider.ts\";\nimport { ServerHeadProvider } from \"./providers/ServerHeadProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./helpers/SeoExpander.ts\";\nexport * from \"./hooks/useHead.ts\";\nexport * from \"./interfaces/Head.ts\";\nexport * from \"./primitives/$head.ts\";\nexport * from \"./providers/BrowserHeadProvider.ts\";\nexport * from \"./providers/ServerHeadProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * HTML head element management.\n *\n * **Features:**\n * - Title, meta tags, and links\n * - SEO optimization\n * - Social media tags\n *\n * @module alepha.react.head\n */\nexport const AlephaReactHead = $module({\n name: \"alepha.react.head\",\n primitives: [$head],\n services: [\n AlephaReact,\n BrowserHeadProvider,\n HeadProvider,\n SeoExpander,\n ServerHeadProvider,\n ],\n});\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { Alepha, Async, KIND, Primitive, TypeBoxError } from "alepha";
2
2
  import { DateTime, DateTimeProvider } from "alepha/datetime";
3
-
3
+ import { RouterLocaleProvider } from "alepha/react/router";
4
4
  //#region ../../src/react/i18n/components/Localize.d.ts
5
5
  interface LocalizeProps {
6
6
  value: string | number | Date | DateTime | TypeBoxError;
@@ -62,18 +62,18 @@ interface TranslateProps {
62
62
  * <Translate k="cart.items" args={[String(count)]} fallback="Items" />
63
63
  * ```
64
64
  */
65
- declare const Translate: (props: TranslateProps) => import("react/jsx-runtime").JSX.Element;
65
+ declare const Translate: (props: TranslateProps) => import("react").JSX.Element;
66
66
  /**
67
67
  * Terse alias for {@link Translate} — handy in dense JSX such as nav labels.
68
68
  */
69
- declare const Tr: (props: TranslateProps) => import("react/jsx-runtime").JSX.Element;
69
+ declare const Tr: typeof Translate;
70
70
  //#endregion
71
71
  //#region ../../src/react/i18n/providers/I18nProvider.d.ts
72
72
  declare class I18nProvider<S extends object, K extends keyof ServiceDictionary<S>> {
73
73
  protected log: import("alepha/logger").Logger;
74
74
  protected alepha: Alepha;
75
75
  protected dateTimeProvider: DateTimeProvider;
76
- protected cookie: import("alepha/server/cookies").AbstractCookiePrimitive<import("typebox").TString>;
76
+ protected cookie: import("alepha/server/cookies").AbstractCookiePrimitive<import("zod").ZodString>;
77
77
  readonly registry: Array<{
78
78
  target: string;
79
79
  name: string;
@@ -83,7 +83,17 @@ declare class I18nProvider<S extends object, K extends keyof ServiceDictionary<S
83
83
  }>;
84
84
  options: {
85
85
  fallbackLang: string;
86
+ autoDetect: boolean;
87
+ routing: "none" | "prefix";
86
88
  };
89
+ /**
90
+ * Lazily-resolved locale-prefix router integration. Present only when both
91
+ * the router module is registered AND `routing: "prefix"` was configured —
92
+ * otherwise i18n stays fully standalone.
93
+ */
94
+ protected localeProviderResolved: boolean;
95
+ protected localeProviderRef?: RouterLocaleProvider;
96
+ protected get localeProvider(): RouterLocaleProvider | undefined;
87
97
  dateFormat: {
88
98
  format: (value: Date) => string;
89
99
  };
@@ -92,9 +102,41 @@ declare class I18nProvider<S extends object, K extends keyof ServiceDictionary<S
92
102
  };
93
103
  get languages(): string[];
94
104
  constructor();
105
+ /**
106
+ * Configure locale-prefix routing on the router, before the SSR routes are
107
+ * registered (`priority: "first"` runs ahead of the router's own `configure`
108
+ * hook). No-op unless `routing: "prefix"` and the router module is present.
109
+ */
110
+ protected readonly onConfigure: import("alepha").HookPrimitive<"configure">;
95
111
  protected readonly onRender: import("alepha").HookPrimitive<"server:onRequest">;
112
+ /**
113
+ * Detects the language carried by the request URL when `routing: "prefix"` is
114
+ * active. Returns the locale for any URL (the prefixed one for `/fr/...`, the
115
+ * default for an unprefixed path), or `undefined` when prefix routing is off.
116
+ */
117
+ protected detectUrlLocale(pathname: string | undefined): string | undefined;
118
+ /**
119
+ * Resolves the UI language for an incoming server request.
120
+ *
121
+ * Priority:
122
+ * 0. the URL locale prefix (`routing: "prefix"`) — the URL is the source of
123
+ * truth and wins over everything, with no redirect;
124
+ * 1. the `lang` cookie — a language the user manually selected;
125
+ * 2. the `Accept-Language` header (when `autoDetect` is enabled) — but only
126
+ * when the detected language is actually registered, so we never switch to
127
+ * a locale we have no dictionary for. A region-qualified header (`en-US`)
128
+ * matches an exact registration first, then its base language (`en`);
129
+ * 3. `fallbackLang`.
130
+ */
131
+ protected resolveRequestLang(cookieLang: string | undefined, headerLang: string | undefined, urlLocale?: string): string;
96
132
  protected readonly onStart: import("alepha").HookPrimitive<"start">;
97
133
  protected refreshLocale(): void;
134
+ /**
135
+ * Activates a language: lazily loads its dictionaries (browser), updates the
136
+ * lang state, and refreshes the locale-bound formatters. Does NOT persist a
137
+ * cookie or navigate — that is the caller's concern.
138
+ */
139
+ protected applyLang: (lang: string) => Promise<void>;
98
140
  setLang: (lang: string) => Promise<void>;
99
141
  protected readonly mutate: import("alepha").HookPrimitive<"state:mutate">;
100
142
  get fallbackLang(): string;
@@ -191,7 +233,7 @@ declare class DictionaryPrimitive<T extends Record<string, string>> extends Prim
191
233
  * Hook to access the i18n service.
192
234
  */
193
235
  declare const useI18n: <S extends object, K extends keyof ServiceDictionary<S>>() => I18nProvider<S, K>;
194
- type ServiceDictionary<T extends object> = { [K in keyof T]: T[K] extends DictionaryPrimitive<infer U> ? U : never };
236
+ type ServiceDictionary<T extends object> = { [K in keyof T]: T[K] extends DictionaryPrimitive<infer U> ? U : never; };
195
237
  //#endregion
196
238
  //#region ../../src/react/i18n/index.d.ts
197
239
  declare module "alepha" {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/i18n/components/Localize.tsx","../../../src/react/i18n/components/Translate.tsx","../../../src/react/i18n/providers/I18nProvider.ts","../../../src/react/i18n/primitives/$dictionary.ts","../../../src/react/i18n/hooks/useI18n.ts","../../../src/react/i18n/index.ts"],"mappings":";;;;UAIiB,aAAA;EACf,KAAA,oBAAyB,IAAA,GAAO,QAAA,GAAW,YAAA;EAD5B;;;;EAMf,MAAA,GAAS,IAAA,CAAK,mBAAA;EAL6B;;;;;;;;;EAe3C,IAAA,wBAA4B,IAAA,CAAK,qBAAA;EAVxB;;;;;EAgBT,QAAA;AAAA;AAAA,cAGI,QAAA,GAAY,KAAoB,EAAb,aAAa;;;UC3BrB,cAAA;;;;EAIf,CAAA;EDF4B;;;ECM5B,IAAA;EDL2C;;;;ECU3C,QAAA;AAAA;;;;;;;;;;;;ADWQ;AACT;;;;AAEqC;;cCOzB,SAAA,GAAa,KAAA,EAAO,cAAc,iCAAA,GAAA,CAAA,OAAA;;AAlC/C;;cA0Ca,EAAA,GAAE,KAAA,EARkB,cAAc,iCAAA,GAAA,CAAA,OAAA;;;cC9BlC,YAAA,mCAEK,iBAAA,CAAkB,CAAA;EAAA,UAExB,GAAA,0BAAG,MAAA;EAAA,UACH,MAAA,EAAM,MAAA;EAAA,UACN,gBAAA,EAAgB,gBAAA;EAAA,UAEhB,MAAA,kCAAM,uBAAA,mBAAA,OAAA;EAAA,SAMA,QAAA,EAAU,KAAA;IACxB,MAAA;IACA,IAAA;IACA,IAAA;IACA,MAAA,QAAc,OAAA,CAAQ,MAAA;IACtB,YAAA,EAAc,MAAA;EAAA;EAGhB,OAAA;;;EAIO,UAAA;IAAc,MAAA,GAAS,KAAA,EAAO,IAAA;EAAA;EAG9B,YAAA;IAAgB,MAAA,GAAS,KAAA;EAAA;EAAA,IAGrB,SAAA;;qBAcQ,QAAA,mBAAQ,aAAA;EAAA,mBAQR,OAAA,mBAAO,aAAA;EAAA,UA6BhB,aAAA;EAOH,OAAA,GAAiB,IAAA,aAAY,OAAA;EAAA,mBAiBjB,MAAA,mBAAM,aAAA;EAAA,IAwBd,YAAA;EAAA,IASA,IAAA;EAIJ,SAAA,GAAa,GAAA,UAAa,IAAA;EAAA,SAoBjB,CAAA,GACd,KAAA,EAAO,gBAAA,EACP,OAAA,GAAS,mBAAA;ED1KI;;;;;;EAAA,SC4OC,EAAA,GACd,GAAA,QAAW,iBAAA,CAAkB,CAAA,EAAG,CAAA,mBAChC,OAAA;IACE,IAAA;IACA,OAAA;EAAA;EAAA,UAUM,MAAA,CAAO,IAAA,UAAc,IAAA;AAAA;AAAA,KASrB,gBAAA,qBAAqC,IAAA,GAAO,QAAA,GAAW,YAAA;AAAA,UAElD,mBAAA;EDnOS;;;;ECwOxB,MAAA,GAAS,IAAA,CAAK,mBAAA;EDhOH;;;;;;;;;EC0OX,IAAA,wBAA4B,IAAA,CAAK,qBAAqB;;;;AAhRxD;;EAsRE,QAAA;AAAA;;;;;AFxRF;;;;;;;;;;;;;;;;;;;;;;AAsBU;AACT;;;;AAEqC;;cGKzB,WAAA;EAAA,WAAyB,MAAA,kBAAsB,OAAA,EACjD,0BAAA,CAA2B,CAAA,IACnC,mBAAA,CAAoB,CAAA;EAAA;;UAMN,0BAAA,WAAqC,MAAA;EACpD,IAAA;EACA,IAAA;EACA,IAAA,QAAY,KAAA;IAAQ,OAAA,EAAS,CAAA;EAAA;AAAA;AAAA,cAKlB,mBAAA,WACD,MAAA,0BACF,SAAA,CAAU,0BAAA,CAA2B,CAAA;EAAA,UACnC,QAAA,EAAQ,YAAA;EAAA,UACR,MAAA;AAAA;;;;;AHlDZ;cIGa,OAAA,qCAEK,iBAAA,CAAkB,CAAA,QAC/B,YAAA,CAAa,CAAA,EAAG,CAAA;AAAA,KAKT,iBAAA,mCACE,CAAA,GAAI,CAAA,CAAE,CAAA,UAAW,mBAAA,YAA+B,CAAA;;;;YCC3C,KAAA;IACf,wBAAwB;EAAA;AAAA;;;;;;;;;;;cAgBf,eAAA,mBAAe,OAAA,kBAAA,MAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/i18n/components/Localize.tsx","../../../src/react/i18n/components/Translate.tsx","../../../src/react/i18n/providers/I18nProvider.ts","../../../src/react/i18n/primitives/$dictionary.ts","../../../src/react/i18n/hooks/useI18n.ts","../../../src/react/i18n/index.ts"],"mappings":";;;;UAIiB;EACf,yBAAyB,OAAO,WAAW;;;;;EAK3C,SAAS,KAAK;;;;;;;;;;EAUd,4BAA4B,KAAK;;;;;;EAMjC;;cAGI,WAAQ,OAAW;;;UC3BR;;;;EAIf;;;;EAIA;;;;;EAKA;;;;;;;;;;;;;;;;;;;;cAqBW,YAAS,OAAW,mCAAc,IAAA;;;;cAQlC,WAAE;;;cCnCF,aACX,kBACA,gBAAgB,kBAAkB;YAExB,6BAAG;YACH,QAAM;YACN,kBAAgB;YAEhB,wCAAM,sCAAA;WAMA,UAAU;IACxB;IACA;IACA;IACA,cAAc,QAAQ;IACtB,cAAc;;EAGhB;IACE;IACA;IACA;;;;;;;YA6BQ;YACA,oBAAoB;gBAChB,kBAAkB;EAUzB;IAAc,SAAS,OAAO;;EAG9B;IAAgB,SAAS;;MAGrB;EAUX;;;;;;qBASmB,8BAAW;qBAeX,2BAAQ;;;;;;YAoBjB,gBAAgB;;;;;;;;;;;;;;YAqBhB,mBACR,gCACA,gCACA;qBAsBiB,0BAAO;YAgChB;;;;;;YAYA,YAAS,iBAAsB;EAalC,UAAO,iBAAsB;qBAoBjB,yBAAM;MAsCd;MASA;EAIJ,YAAS,aAAe;WAoBf,IAAC,OACR,kBAAgB,UACd;;;;;;;WAkEK,KAAE,WACL,kBAAkB,GAAG,oBAAkB;IAEhD;IACA;;YAUM,OAAO,cAAc;;KASrB,qCAAqC,OAAO,WAAW;UAElD;;;;;EAKf,SAAS,KAAK;;;;;;;;;;EAUd,4BAA4B,KAAK;;;;;;EAMjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCzZW;GAAe,UAAU,wBAAsB,SACjD,2BAA2B,KACnC,oBAAoB;;;UAMN,2BAA2B,UAAU;EACpD;EACA;EACA,YAAY;IAAQ,SAAS;;;cAKlB,oBACX,UAAU,gCACF,UAAU,2BAA2B;YACnC,UAAQ;YACR;;;;;;;cC/CC,UACX,kBACA,gBAAgB,kBAAkB,SAC/B,aAAa,GAAG;KAKT,kBAAkB,uBAC3B,WAAW,IAAI,EAAE,WAAW,0BAA0B,KAAK;;;;YCC3C;IACf;;;;;;;;;;;;;cAgBS,kCAAe,yBAAA"}
@@ -1,6 +1,7 @@
1
- import { $hook, $inject, $module, Alepha, KIND, Primitive, TypeBoxError, TypeProvider, createPrimitive, t } from "alepha";
1
+ import { $hook, $inject, $module, Alepha, KIND, Primitive, TypeBoxError, TypeProvider, createPrimitive, z } from "alepha";
2
2
  import { DateTimeProvider } from "alepha/datetime";
3
3
  import { $logger } from "alepha/logger";
4
+ import { RouterLocaleProvider } from "alepha/react/router";
4
5
  import { $cookie } from "alepha/server/cookies";
5
6
  import { useInject, useStore } from "alepha/react";
6
7
  import { Fragment, jsx } from "react/jsx-runtime";
@@ -11,11 +12,46 @@ var I18nProvider = class {
11
12
  dateTimeProvider = $inject(DateTimeProvider);
12
13
  cookie = $cookie({
13
14
  name: "lang",
14
- schema: t.text(),
15
+ schema: z.text(),
15
16
  ttl: [1, "year"]
16
17
  });
17
18
  registry = [];
18
- options = { fallbackLang: "en" };
19
+ options = {
20
+ fallbackLang: "en",
21
+ /**
22
+ * When true (the default), the UI language for a first-time visitor (one
23
+ * with no `lang` cookie) is detected server-side from the `Accept-Language`
24
+ * header. A manually-selected language (the cookie) always takes
25
+ * precedence, so this never overrides an explicit user choice. Set to false
26
+ * to always start in `fallbackLang` regardless of the browser's preferred
27
+ * language.
28
+ */
29
+ autoDetect: true,
30
+ /**
31
+ * URL strategy for languages:
32
+ * - `"none"` (default): language lives in a cookie; URLs are not localized.
33
+ * - `"prefix"`: each non-default language gets a path prefix (`/fr/about`),
34
+ * making every language a distinct, crawlable URL for SEO. The default
35
+ * language (`fallbackLang`) stays unprefixed. Requires the router module.
36
+ * The URL becomes the source of truth for language (it wins over the
37
+ * cookie / `Accept-Language`), and there is no automatic redirect.
38
+ */
39
+ routing: "none"
40
+ };
41
+ /**
42
+ * Lazily-resolved locale-prefix router integration. Present only when both
43
+ * the router module is registered AND `routing: "prefix"` was configured —
44
+ * otherwise i18n stays fully standalone.
45
+ */
46
+ localeProviderResolved = false;
47
+ localeProviderRef;
48
+ get localeProvider() {
49
+ if (!this.localeProviderResolved) {
50
+ this.localeProviderResolved = true;
51
+ if (this.alepha.has(RouterLocaleProvider)) this.localeProviderRef = this.alepha.inject(RouterLocaleProvider);
52
+ }
53
+ return this.localeProviderRef;
54
+ }
19
55
  dateFormat = new Intl.DateTimeFormat(this.lang);
20
56
  numberFormat = new Intl.NumberFormat(this.lang);
21
57
  get languages() {
@@ -26,19 +62,69 @@ var I18nProvider = class {
26
62
  constructor() {
27
63
  this.refreshLocale();
28
64
  }
65
+ /**
66
+ * Configure locale-prefix routing on the router, before the SSR routes are
67
+ * registered (`priority: "first"` runs ahead of the router's own `configure`
68
+ * hook). No-op unless `routing: "prefix"` and the router module is present.
69
+ */
70
+ onConfigure = $hook({
71
+ on: "configure",
72
+ priority: "first",
73
+ handler: () => {
74
+ const localeProvider = this.localeProvider;
75
+ if (this.options.routing === "prefix" && localeProvider) localeProvider.configure({
76
+ enabled: true,
77
+ defaultLocale: this.fallbackLang,
78
+ locales: this.languages
79
+ });
80
+ }
81
+ });
29
82
  onRender = $hook({
30
83
  on: "server:onRequest",
31
84
  priority: "last",
32
85
  handler: async ({ request }) => {
33
- this.alepha.store.set("alepha.react.i18n.lang", this.cookie.get(request));
86
+ this.alepha.store.set("alepha.react.i18n.lang", this.resolveRequestLang(this.cookie.get(request), request.language, this.detectUrlLocale(request.url?.pathname)));
34
87
  }
35
88
  });
89
+ /**
90
+ * Detects the language carried by the request URL when `routing: "prefix"` is
91
+ * active. Returns the locale for any URL (the prefixed one for `/fr/...`, the
92
+ * default for an unprefixed path), or `undefined` when prefix routing is off.
93
+ */
94
+ detectUrlLocale(pathname) {
95
+ const localeProvider = this.localeProvider;
96
+ if (localeProvider?.enabled && pathname) return localeProvider.detect(pathname).locale || void 0;
97
+ }
98
+ /**
99
+ * Resolves the UI language for an incoming server request.
100
+ *
101
+ * Priority:
102
+ * 0. the URL locale prefix (`routing: "prefix"`) — the URL is the source of
103
+ * truth and wins over everything, with no redirect;
104
+ * 1. the `lang` cookie — a language the user manually selected;
105
+ * 2. the `Accept-Language` header (when `autoDetect` is enabled) — but only
106
+ * when the detected language is actually registered, so we never switch to
107
+ * a locale we have no dictionary for. A region-qualified header (`en-US`)
108
+ * matches an exact registration first, then its base language (`en`);
109
+ * 3. `fallbackLang`.
110
+ */
111
+ resolveRequestLang(cookieLang, headerLang, urlLocale) {
112
+ if (urlLocale) return urlLocale;
113
+ if (cookieLang) return cookieLang;
114
+ if (this.options.autoDetect && headerLang) {
115
+ const registered = this.languages;
116
+ for (const candidate of [headerLang, headerLang.split("-")[0]]) if (registered.includes(candidate)) return candidate;
117
+ }
118
+ return this.fallbackLang;
119
+ }
36
120
  onStart = $hook({
37
121
  on: "start",
38
122
  handler: async () => {
39
123
  if (this.alepha.isBrowser()) {
40
- const cookieLang = this.cookie.get();
41
- if (cookieLang) this.alepha.store.set("alepha.react.i18n.lang", cookieLang);
124
+ if (!this.localeProvider?.enabled) {
125
+ const cookieLang = this.cookie.get();
126
+ if (cookieLang) this.alepha.store.set("alepha.react.i18n.lang", cookieLang);
127
+ }
42
128
  for (const item of this.registry) if (item.lang === this.lang || item.lang === this.fallbackLang) {
43
129
  this.log.trace("Loading language", {
44
130
  lang: item.lang,
@@ -58,20 +144,38 @@ var I18nProvider = class {
58
144
  this.dateTimeProvider.setLocale(this.lang);
59
145
  TypeProvider.setLocale(this.lang);
60
146
  }
61
- setLang = async (lang) => {
147
+ /**
148
+ * Activates a language: lazily loads its dictionaries (browser), updates the
149
+ * lang state, and refreshes the locale-bound formatters. Does NOT persist a
150
+ * cookie or navigate — that is the caller's concern.
151
+ */
152
+ applyLang = async (lang) => {
62
153
  if (this.alepha.isBrowser()) {
63
- for (const item of this.registry) if (lang === item.lang) {
64
- if (Object.keys(item.translations).length > 0) continue;
65
- item.translations = await item.loader();
66
- }
67
- this.cookie.set(lang);
154
+ for (const item of this.registry) if (lang === item.lang && Object.keys(item.translations).length === 0) item.translations = await item.loader();
68
155
  }
69
156
  this.alepha.store.set("alepha.react.i18n.lang", lang);
70
157
  this.refreshLocale();
71
158
  };
159
+ setLang = async (lang) => {
160
+ const localeProvider = this.localeProvider;
161
+ if (localeProvider?.enabled) {
162
+ const { ReactRouter } = await import("alepha/react/router");
163
+ const router = this.alepha.inject(ReactRouter);
164
+ const canonical = localeProvider.detect(router.pathname).pathname;
165
+ await router.push(localeProvider.withPrefix(canonical, lang));
166
+ return;
167
+ }
168
+ await this.applyLang(lang);
169
+ if (this.alepha.isBrowser()) this.cookie.set(lang);
170
+ };
72
171
  mutate = $hook({
73
172
  on: "state:mutate",
74
173
  handler: async ({ key, value }) => {
174
+ if (key === "alepha.react.router.locale" && this.localeProvider?.enabled) {
175
+ const lang = value || this.fallbackLang;
176
+ if (lang !== this.lang) await this.applyLang(lang);
177
+ return;
178
+ }
75
179
  if (key === "alepha.react.i18n.lang" && this.alepha.isBrowser()) {
76
180
  let hasChanged = false;
77
181
  for (const item of this.registry) if (value === item.lang) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/react/i18n/providers/I18nProvider.ts","../../../src/react/i18n/primitives/$dictionary.ts","../../../src/react/i18n/hooks/useI18n.ts","../../../src/react/i18n/components/Localize.tsx","../../../src/react/i18n/components/Translate.tsx","../../../src/react/i18n/index.ts"],"sourcesContent":["import { $hook, $inject, Alepha, TypeBoxError, TypeProvider, t } from \"alepha\";\nimport { type DateTime, DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $cookie } from \"alepha/server/cookies\";\nimport type { ServiceDictionary } from \"../hooks/useI18n.ts\";\n\nexport class I18nProvider<\n S extends object,\n K extends keyof ServiceDictionary<S>,\n> {\n protected log = $logger();\n protected alepha = $inject(Alepha);\n protected dateTimeProvider = $inject(DateTimeProvider);\n\n protected cookie = $cookie({\n name: \"lang\",\n schema: t.text(),\n ttl: [1, \"year\"],\n });\n\n public readonly registry: Array<{\n target: string;\n name: string;\n lang: string;\n loader: () => Promise<Record<string, string>>;\n translations: Record<string, string>;\n }> = [];\n\n options = {\n fallbackLang: \"en\",\n };\n\n public dateFormat: { format: (value: Date) => string } =\n new Intl.DateTimeFormat(this.lang);\n\n public numberFormat: { format: (value: number) => string } =\n new Intl.NumberFormat(this.lang);\n\n public get languages() {\n const languages = new Set<string>();\n\n for (const item of this.registry) {\n languages.add(item.lang);\n }\n\n return Array.from(languages);\n }\n\n constructor() {\n this.refreshLocale();\n }\n\n protected readonly onRender = $hook({\n on: \"server:onRequest\",\n priority: \"last\",\n handler: async ({ request }) => {\n this.alepha.store.set(\"alepha.react.i18n.lang\", this.cookie.get(request));\n },\n });\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n if (this.alepha.isBrowser()) {\n // get cookie lang\n const cookieLang = this.cookie.get();\n if (cookieLang) {\n this.alepha.store.set(\"alepha.react.i18n.lang\", cookieLang);\n }\n\n for (const item of this.registry) {\n if (item.lang === this.lang || item.lang === this.fallbackLang) {\n this.log.trace(\"Loading language\", {\n lang: item.lang,\n name: item.name,\n target: item.target,\n });\n item.translations = await item.loader();\n }\n }\n return;\n }\n\n for (const item of this.registry) {\n item.translations = await item.loader();\n }\n },\n });\n\n protected refreshLocale() {\n this.numberFormat = new Intl.NumberFormat(this.lang);\n this.dateFormat = new Intl.DateTimeFormat(this.lang);\n this.dateTimeProvider.setLocale(this.lang);\n TypeProvider.setLocale(this.lang);\n }\n\n public setLang = async (lang: string) => {\n if (this.alepha.isBrowser()) {\n for (const item of this.registry) {\n if (lang === item.lang) {\n if (Object.keys(item.translations).length > 0) {\n continue; // already loaded\n }\n item.translations = await item.loader();\n }\n }\n this.cookie.set(lang);\n }\n\n this.alepha.store.set(\"alepha.react.i18n.lang\", lang);\n this.refreshLocale();\n };\n\n protected readonly mutate = $hook({\n on: \"state:mutate\",\n handler: async ({ key, value }) => {\n if (key === \"alepha.react.i18n.lang\" && this.alepha.isBrowser()) {\n let hasChanged = false;\n for (const item of this.registry) {\n if (value === item.lang) {\n if (Object.keys(item.translations).length > 0) {\n continue; // already loaded\n }\n item.translations = await item.loader();\n hasChanged = true;\n }\n }\n\n this.refreshLocale();\n\n if (hasChanged) {\n this.alepha.store.set(\"alepha.react.i18n.lang\", value);\n }\n }\n },\n });\n\n public get fallbackLang(): string {\n const configured = this.options.fallbackLang;\n const hasDict = this.registry.some((item) => item.lang === configured);\n if (hasDict) {\n return configured;\n }\n return this.registry[0]?.lang ?? configured;\n }\n\n public get lang(): string {\n return this.alepha.store.get(\"alepha.react.i18n.lang\") || this.fallbackLang;\n }\n\n public translate = (key: string, args: string[] = []) => {\n for (const item of this.registry) {\n if (item.lang === this.lang) {\n if (item.translations[key]) {\n return this.render(item.translations[key], args); // append lang for fallback\n }\n }\n }\n\n for (const item of this.registry) {\n if (item.lang === this.fallbackLang) {\n if (item.translations[key]) {\n return this.render(item.translations[key], args); // append lang for fallback\n }\n }\n }\n\n return key; // fallback to the key itself if not found\n };\n\n public readonly l = (\n value: I18nLocalizeType,\n options: I18nLocalizeOptions = {},\n ) => {\n // Handle numbers\n if (typeof value === \"number\" && !options.date) {\n return new Intl.NumberFormat(this.lang, options.number).format(value);\n }\n\n // Handle dates\n if (\n value instanceof Date ||\n this.dateTimeProvider.isDateTime(value) ||\n (typeof value === \"string\" && options.date) ||\n (typeof value === \"number\" && options.date)\n ) {\n // convert to DateTime with locale applied\n let dt = this.dateTimeProvider.of(value);\n\n // apply timezone if specified\n if (options.timezone) {\n dt = dt.tz(options.timezone);\n }\n\n // format using dayjs format string\n if (typeof options.date === \"string\") {\n if (options.date === \"fromNow\") {\n return dt.locale(this.lang).fromNow();\n }\n return dt.locale(this.lang).format(options.date);\n }\n\n // format using Intl.DateTimeFormatOptions\n if (options.date) {\n return new Intl.DateTimeFormat(\n this.lang,\n options.timezone\n ? { ...options.date, timeZone: options.timezone }\n : options.date,\n ).format(dt.toDate());\n }\n\n // default formatting with timezone\n if (options.timezone) {\n return new Intl.DateTimeFormat(this.lang, {\n timeZone: options.timezone,\n }).format(dt.toDate());\n }\n\n // default formatting\n return new Intl.DateTimeFormat(this.lang).format(dt.toDate());\n }\n\n // handle TypeBox errors\n if (value instanceof TypeBoxError) {\n return TypeProvider.translateError(value, this.lang);\n }\n\n // return string values as-is\n return value;\n };\n\n /**\n * Look up `key` in the registered dictionaries. The `(string & {})` arm\n * keeps autocomplete for the typed dictionary keys while allowing shared\n * library components to pass arbitrary string keys (with a `default`\n * fallback) without casting to `as never`.\n */\n public readonly tr = (\n key: keyof ServiceDictionary<S>[K] | (string & {}),\n options: {\n args?: string[];\n default?: string;\n } = {},\n ) => {\n const translation = this.translate(key as string, options.args || []);\n if (translation === (key as string) && options.default) {\n return options.default;\n }\n return translation;\n };\n\n protected render(item: string, args: string[]): string {\n let result = item;\n for (let i = 0; i < args.length; i++) {\n result = result.replace(`$${i + 1}`, args[i]);\n }\n return result;\n }\n}\n\nexport type I18nLocalizeType = string | number | Date | DateTime | TypeBoxError;\n\nexport interface I18nLocalizeOptions {\n /**\n * Options for number formatting (when value is a number)\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat\n */\n number?: Intl.NumberFormatOptions;\n /**\n * Options for date formatting (when value is a Date or DateTime)\n * Can be:\n * - A dayjs format string (e.g., \"LLL\", \"YYYY-MM-DD\", \"dddd, MMMM D YYYY\")\n * - \"fromNow\" for relative time (e.g., \"2 hours ago\")\n * - Intl.DateTimeFormatOptions for native formatting\n * @see https://day.js.org/docs/en/display/format\n * @see https://day.js.org/docs/en/display/from-now\n */\n date?: string | \"fromNow\" | Intl.DateTimeFormatOptions;\n /**\n * Timezone to display dates in (when value is a Date or DateTime)\n * Uses IANA timezone names (e.g., \"America/New_York\", \"Europe/Paris\", \"Asia/Tokyo\")\n * @see https://day.js.org/docs/en/timezone/timezone\n */\n timezone?: string;\n}\n","import { $inject, type Async, createPrimitive, KIND, Primitive } from \"alepha\";\nimport { I18nProvider } from \"../providers/I18nProvider.ts\";\n\n/**\n * Register a dictionary entry for translations.\n *\n * It allows you to define a set of translations for a specific language.\n * Entry can be lazy-loaded, which is useful for large dictionaries or when translations are not needed immediately.\n *\n * @example\n * ```ts\n * import { $dictionary } from \"alepha/react/i18n\";\n *\n * const Example = () => {\n * const { tr } = useI18n<App, \"en\">();\n * return <div>{tr(\"hello\")}</div>; //\n * }\n *\n * class App {\n *\n * en = $dictionary({\n * // { default: { hello: \"Hey\" } }\n * lazy: () => import(\"./translations/en.ts\"),\n * });\n *\n * home = $page({\n * path: \"/\",\n * component: Example,\n * })\n * }\n *\n * run(App);\n * ```\n */\nexport const $dictionary = <T extends Record<string, string>>(\n options: DictionaryPrimitiveOptions<T>,\n): DictionaryPrimitive<T> => {\n return createPrimitive(DictionaryPrimitive<T>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface DictionaryPrimitiveOptions<T extends Record<string, string>> {\n lang?: string;\n name?: string;\n lazy: () => Async<{ default: T }>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class DictionaryPrimitive<\n T extends Record<string, string>,\n> extends Primitive<DictionaryPrimitiveOptions<T>> {\n protected provider = $inject(I18nProvider);\n protected onInit() {\n this.provider.registry.push({\n target: this.config.service.name,\n name: this.options.name ?? this.config.propertyKey,\n lang: this.options.lang ?? this.config.propertyKey,\n loader: async () => {\n const mod = await this.options.lazy();\n return mod.default;\n },\n translations: {},\n });\n }\n}\n\n$dictionary[KIND] = DictionaryPrimitive;\n","import { useInject, useStore } from \"alepha/react\";\nimport type { DictionaryPrimitive } from \"../primitives/$dictionary.ts\";\nimport { I18nProvider } from \"../providers/I18nProvider.ts\";\n\n/**\n * Hook to access the i18n service.\n */\nexport const useI18n = <\n S extends object,\n K extends keyof ServiceDictionary<S>,\n>(): I18nProvider<S, K> => {\n useStore(\"alepha.react.i18n.lang\");\n return useInject(I18nProvider<S, K>);\n};\n\nexport type ServiceDictionary<T extends object> = {\n [K in keyof T]: T[K] extends DictionaryPrimitive<infer U> ? U : never;\n};\n","import type { TypeBoxError } from \"alepha\";\nimport type { DateTime } from \"alepha/datetime\";\nimport { useI18n } from \"../hooks/useI18n.ts\";\n\nexport interface LocalizeProps {\n value: string | number | Date | DateTime | TypeBoxError;\n /**\n * Options for number formatting (when value is a number)\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat\n */\n number?: Intl.NumberFormatOptions;\n /**\n * Options for date formatting (when value is a Date or DateTime)\n * Can be:\n * - A dayjs format string (e.g., \"LLL\", \"YYYY-MM-DD\", \"dddd, MMMM D YYYY\")\n * - \"fromNow\" for relative time (e.g., \"2 hours ago\")\n * - Intl.DateTimeFormatOptions for native formatting\n * @see https://day.js.org/docs/en/display/format\n * @see https://day.js.org/docs/en/display/from-now\n */\n date?: string | \"fromNow\" | Intl.DateTimeFormatOptions;\n /**\n * Timezone to display dates in (when value is a Date or DateTime)\n * Uses IANA timezone names (e.g., \"America/New_York\", \"Europe/Paris\", \"Asia/Tokyo\")\n * @see https://day.js.org/docs/en/timezone/timezone\n */\n timezone?: string;\n}\n\nconst Localize = (props: LocalizeProps) => {\n const i18n = useI18n();\n return i18n.l(props.value, props);\n};\n\nexport default Localize;\n","import { useI18n } from \"../hooks/useI18n.ts\";\n\nexport interface TranslateProps {\n /**\n * Dictionary key to look up — the same key you would pass to `tr(...)`.\n */\n k: string;\n /**\n * Positional substitutions for `$1`, `$2`, … placeholders in the entry.\n */\n args?: string[];\n /**\n * Shown when the key is missing from every registered dictionary (otherwise\n * the raw key is rendered, matching `tr`'s behaviour).\n */\n fallback?: string;\n}\n\n/**\n * Renders a translated dictionary entry as a reactive text node.\n *\n * `tr(...)` is a hook, so it can only be called inside a component body. Use\n * `<Translate>` wherever a *node* is expected instead — a prop, a `children`\n * slot, or route metadata such as a nav-shell `label`. Because it subscribes to\n * {@link useI18n} it re-renders on a language switch, unlike a string resolved\n * once at module/initialisation time.\n *\n * Sibling of {@link Localize}: `Localize` formats a value (number, date,\n * error); `Translate` looks up a key.\n *\n * @example\n * ```tsx\n * nav: { label: <Translate k=\"admin.nav.users\" /> }\n * <Translate k=\"cart.items\" args={[String(count)]} fallback=\"Items\" />\n * ```\n */\nexport const Translate = (props: TranslateProps) => {\n const { tr } = useI18n();\n return <>{tr(props.k, { args: props.args, default: props.fallback })}</>;\n};\n\n/**\n * Terse alias for {@link Translate} — handy in dense JSX such as nav labels.\n */\nexport const Tr = Translate;\n\nexport default Translate;\n","import { $module } from \"alepha\";\nimport { $dictionary } from \"./primitives/$dictionary.ts\";\nimport { I18nProvider } from \"./providers/I18nProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type { LocalizeProps } from \"./components/Localize.tsx\";\nexport { default as Localize } from \"./components/Localize.tsx\";\nexport type { TranslateProps } from \"./components/Translate.tsx\";\nexport { default as Translate, Tr } from \"./components/Translate.tsx\";\nexport * from \"./hooks/useI18n.ts\";\nexport * from \"./primitives/$dictionary.ts\";\nexport * from \"./providers/I18nProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n export interface State {\n \"alepha.react.i18n.lang\"?: string;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Multi-language support.\n *\n * **Features:**\n * - Translation loading\n * - Locale detection\n * - Pluralization\n *\n * @module alepha.react.i18n\n */\nexport const AlephaReactI18n = $module({\n name: \"alepha.react.i18n\",\n primitives: [$dictionary],\n services: [I18nProvider],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/react/i18n/providers/I18nProvider.ts","../../../src/react/i18n/primitives/$dictionary.ts","../../../src/react/i18n/hooks/useI18n.ts","../../../src/react/i18n/components/Localize.tsx","../../../src/react/i18n/components/Translate.tsx","../../../src/react/i18n/index.ts"],"sourcesContent":["import { $hook, $inject, Alepha, TypeBoxError, TypeProvider, z } from \"alepha\";\nimport { type DateTime, DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\n// Locale-prefix routing is optional: the router module (one-directional\n// dependency, `i18n → router`) is only consulted when it is also registered.\nimport { RouterLocaleProvider } from \"alepha/react/router\";\nimport { $cookie } from \"alepha/server/cookies\";\nimport type { ServiceDictionary } from \"../hooks/useI18n.ts\";\n\nexport class I18nProvider<\n S extends object,\n K extends keyof ServiceDictionary<S>,\n> {\n protected log = $logger();\n protected alepha = $inject(Alepha);\n protected dateTimeProvider = $inject(DateTimeProvider);\n\n protected cookie = $cookie({\n name: \"lang\",\n schema: z.text(),\n ttl: [1, \"year\"],\n });\n\n public readonly registry: Array<{\n target: string;\n name: string;\n lang: string;\n loader: () => Promise<Record<string, string>>;\n translations: Record<string, string>;\n }> = [];\n\n options: {\n fallbackLang: string;\n autoDetect: boolean;\n routing: \"none\" | \"prefix\";\n } = {\n fallbackLang: \"en\",\n /**\n * When true (the default), the UI language for a first-time visitor (one\n * with no `lang` cookie) is detected server-side from the `Accept-Language`\n * header. A manually-selected language (the cookie) always takes\n * precedence, so this never overrides an explicit user choice. Set to false\n * to always start in `fallbackLang` regardless of the browser's preferred\n * language.\n */\n autoDetect: true,\n /**\n * URL strategy for languages:\n * - `\"none\"` (default): language lives in a cookie; URLs are not localized.\n * - `\"prefix\"`: each non-default language gets a path prefix (`/fr/about`),\n * making every language a distinct, crawlable URL for SEO. The default\n * language (`fallbackLang`) stays unprefixed. Requires the router module.\n * The URL becomes the source of truth for language (it wins over the\n * cookie / `Accept-Language`), and there is no automatic redirect.\n */\n routing: \"none\",\n };\n\n /**\n * Lazily-resolved locale-prefix router integration. Present only when both\n * the router module is registered AND `routing: \"prefix\"` was configured —\n * otherwise i18n stays fully standalone.\n */\n protected localeProviderResolved = false;\n protected localeProviderRef?: RouterLocaleProvider;\n protected get localeProvider(): RouterLocaleProvider | undefined {\n if (!this.localeProviderResolved) {\n this.localeProviderResolved = true;\n if (this.alepha.has(RouterLocaleProvider)) {\n this.localeProviderRef = this.alepha.inject(RouterLocaleProvider);\n }\n }\n return this.localeProviderRef;\n }\n\n public dateFormat: { format: (value: Date) => string } =\n new Intl.DateTimeFormat(this.lang);\n\n public numberFormat: { format: (value: number) => string } =\n new Intl.NumberFormat(this.lang);\n\n public get languages() {\n const languages = new Set<string>();\n\n for (const item of this.registry) {\n languages.add(item.lang);\n }\n\n return Array.from(languages);\n }\n\n constructor() {\n this.refreshLocale();\n }\n\n /**\n * Configure locale-prefix routing on the router, before the SSR routes are\n * registered (`priority: \"first\"` runs ahead of the router's own `configure`\n * hook). No-op unless `routing: \"prefix\"` and the router module is present.\n */\n protected readonly onConfigure = $hook({\n on: \"configure\",\n priority: \"first\",\n handler: () => {\n const localeProvider = this.localeProvider;\n if (this.options.routing === \"prefix\" && localeProvider) {\n localeProvider.configure({\n enabled: true,\n defaultLocale: this.fallbackLang,\n locales: this.languages,\n });\n }\n },\n });\n\n protected readonly onRender = $hook({\n on: \"server:onRequest\",\n priority: \"last\",\n handler: async ({ request }) => {\n this.alepha.store.set(\n \"alepha.react.i18n.lang\",\n this.resolveRequestLang(\n this.cookie.get(request),\n request.language,\n this.detectUrlLocale(request.url?.pathname),\n ),\n );\n },\n });\n\n /**\n * Detects the language carried by the request URL when `routing: \"prefix\"` is\n * active. Returns the locale for any URL (the prefixed one for `/fr/...`, the\n * default for an unprefixed path), or `undefined` when prefix routing is off.\n */\n protected detectUrlLocale(pathname: string | undefined): string | undefined {\n const localeProvider = this.localeProvider;\n if (localeProvider?.enabled && pathname) {\n return localeProvider.detect(pathname).locale || undefined;\n }\n return undefined;\n }\n\n /**\n * Resolves the UI language for an incoming server request.\n *\n * Priority:\n * 0. the URL locale prefix (`routing: \"prefix\"`) — the URL is the source of\n * truth and wins over everything, with no redirect;\n * 1. the `lang` cookie — a language the user manually selected;\n * 2. the `Accept-Language` header (when `autoDetect` is enabled) — but only\n * when the detected language is actually registered, so we never switch to\n * a locale we have no dictionary for. A region-qualified header (`en-US`)\n * matches an exact registration first, then its base language (`en`);\n * 3. `fallbackLang`.\n */\n protected resolveRequestLang(\n cookieLang: string | undefined,\n headerLang: string | undefined,\n urlLocale?: string,\n ): string {\n if (urlLocale) {\n return urlLocale;\n }\n\n if (cookieLang) {\n return cookieLang;\n }\n\n if (this.options.autoDetect && headerLang) {\n const registered = this.languages;\n for (const candidate of [headerLang, headerLang.split(\"-\")[0]]) {\n if (registered.includes(candidate)) {\n return candidate;\n }\n }\n }\n\n return this.fallbackLang;\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n if (this.alepha.isBrowser()) {\n // In prefix mode the URL (hydrated into the lang state by the server)\n // is the source of truth, so the cookie must not override it.\n if (!this.localeProvider?.enabled) {\n const cookieLang = this.cookie.get();\n if (cookieLang) {\n this.alepha.store.set(\"alepha.react.i18n.lang\", cookieLang);\n }\n }\n\n for (const item of this.registry) {\n if (item.lang === this.lang || item.lang === this.fallbackLang) {\n this.log.trace(\"Loading language\", {\n lang: item.lang,\n name: item.name,\n target: item.target,\n });\n item.translations = await item.loader();\n }\n }\n return;\n }\n\n for (const item of this.registry) {\n item.translations = await item.loader();\n }\n },\n });\n\n protected refreshLocale() {\n this.numberFormat = new Intl.NumberFormat(this.lang);\n this.dateFormat = new Intl.DateTimeFormat(this.lang);\n this.dateTimeProvider.setLocale(this.lang);\n TypeProvider.setLocale(this.lang);\n }\n\n /**\n * Activates a language: lazily loads its dictionaries (browser), updates the\n * lang state, and refreshes the locale-bound formatters. Does NOT persist a\n * cookie or navigate — that is the caller's concern.\n */\n protected applyLang = async (lang: string) => {\n if (this.alepha.isBrowser()) {\n for (const item of this.registry) {\n if (lang === item.lang && Object.keys(item.translations).length === 0) {\n item.translations = await item.loader();\n }\n }\n }\n\n this.alepha.store.set(\"alepha.react.i18n.lang\", lang);\n this.refreshLocale();\n };\n\n public setLang = async (lang: string) => {\n const localeProvider = this.localeProvider;\n if (localeProvider?.enabled) {\n // The URL is the source of truth: switching language means navigating to\n // the same page under the new locale prefix. Dictionaries and formatters\n // are then activated via the resulting `alepha.react.router.locale`\n // change (see the `mutate` hook). No cookie is written in prefix mode.\n const { ReactRouter } = await import(\"alepha/react/router\");\n const router = this.alepha.inject(ReactRouter);\n const canonical = localeProvider.detect(router.pathname).pathname;\n await router.push(localeProvider.withPrefix(canonical, lang));\n return;\n }\n\n await this.applyLang(lang);\n if (this.alepha.isBrowser()) {\n this.cookie.set(lang);\n }\n };\n\n protected readonly mutate = $hook({\n on: \"state:mutate\",\n handler: async ({ key, value }) => {\n // Prefix-mode navigation changed the active locale (set by the router) →\n // activate the matching language (loads dictionaries, refreshes\n // formatters, and re-renders consumers via the lang state).\n if (\n key === \"alepha.react.router.locale\" &&\n this.localeProvider?.enabled\n ) {\n const lang = (value as string) || this.fallbackLang;\n if (lang !== this.lang) {\n await this.applyLang(lang);\n }\n return;\n }\n\n if (key === \"alepha.react.i18n.lang\" && this.alepha.isBrowser()) {\n let hasChanged = false;\n for (const item of this.registry) {\n if (value === item.lang) {\n if (Object.keys(item.translations).length > 0) {\n continue; // already loaded\n }\n item.translations = await item.loader();\n hasChanged = true;\n }\n }\n\n this.refreshLocale();\n\n if (hasChanged) {\n this.alepha.store.set(\"alepha.react.i18n.lang\", value);\n }\n }\n },\n });\n\n public get fallbackLang(): string {\n const configured = this.options.fallbackLang;\n const hasDict = this.registry.some((item) => item.lang === configured);\n if (hasDict) {\n return configured;\n }\n return this.registry[0]?.lang ?? configured;\n }\n\n public get lang(): string {\n return this.alepha.store.get(\"alepha.react.i18n.lang\") || this.fallbackLang;\n }\n\n public translate = (key: string, args: string[] = []) => {\n for (const item of this.registry) {\n if (item.lang === this.lang) {\n if (item.translations[key]) {\n return this.render(item.translations[key], args); // append lang for fallback\n }\n }\n }\n\n for (const item of this.registry) {\n if (item.lang === this.fallbackLang) {\n if (item.translations[key]) {\n return this.render(item.translations[key], args); // append lang for fallback\n }\n }\n }\n\n return key; // fallback to the key itself if not found\n };\n\n public readonly l = (\n value: I18nLocalizeType,\n options: I18nLocalizeOptions = {},\n ) => {\n // Handle numbers\n if (typeof value === \"number\" && !options.date) {\n return new Intl.NumberFormat(this.lang, options.number).format(value);\n }\n\n // Handle dates\n if (\n value instanceof Date ||\n this.dateTimeProvider.isDateTime(value) ||\n (typeof value === \"string\" && options.date) ||\n (typeof value === \"number\" && options.date)\n ) {\n // convert to DateTime with locale applied\n let dt = this.dateTimeProvider.of(value);\n\n // apply timezone if specified\n if (options.timezone) {\n dt = dt.tz(options.timezone);\n }\n\n // format using dayjs format string\n if (typeof options.date === \"string\") {\n if (options.date === \"fromNow\") {\n return dt.locale(this.lang).fromNow();\n }\n return dt.locale(this.lang).format(options.date);\n }\n\n // format using Intl.DateTimeFormatOptions\n if (options.date) {\n return new Intl.DateTimeFormat(\n this.lang,\n options.timezone\n ? { ...options.date, timeZone: options.timezone }\n : options.date,\n ).format(dt.toDate());\n }\n\n // default formatting with timezone\n if (options.timezone) {\n return new Intl.DateTimeFormat(this.lang, {\n timeZone: options.timezone,\n }).format(dt.toDate());\n }\n\n // default formatting\n return new Intl.DateTimeFormat(this.lang).format(dt.toDate());\n }\n\n // handle TypeBox errors\n if (value instanceof TypeBoxError) {\n return TypeProvider.translateError(value, this.lang);\n }\n\n // return string values as-is\n return value;\n };\n\n /**\n * Look up `key` in the registered dictionaries. The `(string & {})` arm\n * keeps autocomplete for the typed dictionary keys while allowing shared\n * library components to pass arbitrary string keys (with a `default`\n * fallback) without casting to `as never`.\n */\n public readonly tr = (\n key: keyof ServiceDictionary<S>[K] | (string & {}),\n options: {\n args?: string[];\n default?: string;\n } = {},\n ) => {\n const translation = this.translate(key as string, options.args || []);\n if (translation === (key as string) && options.default) {\n return options.default;\n }\n return translation;\n };\n\n protected render(item: string, args: string[]): string {\n let result = item;\n for (let i = 0; i < args.length; i++) {\n result = result.replace(`$${i + 1}`, args[i]);\n }\n return result;\n }\n}\n\nexport type I18nLocalizeType = string | number | Date | DateTime | TypeBoxError;\n\nexport interface I18nLocalizeOptions {\n /**\n * Options for number formatting (when value is a number)\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat\n */\n number?: Intl.NumberFormatOptions;\n /**\n * Options for date formatting (when value is a Date or DateTime)\n * Can be:\n * - A dayjs format string (e.g., \"LLL\", \"YYYY-MM-DD\", \"dddd, MMMM D YYYY\")\n * - \"fromNow\" for relative time (e.g., \"2 hours ago\")\n * - Intl.DateTimeFormatOptions for native formatting\n * @see https://day.js.org/docs/en/display/format\n * @see https://day.js.org/docs/en/display/from-now\n */\n date?: string | \"fromNow\" | Intl.DateTimeFormatOptions;\n /**\n * Timezone to display dates in (when value is a Date or DateTime)\n * Uses IANA timezone names (e.g., \"America/New_York\", \"Europe/Paris\", \"Asia/Tokyo\")\n * @see https://day.js.org/docs/en/timezone/timezone\n */\n timezone?: string;\n}\n","import { $inject, type Async, createPrimitive, KIND, Primitive } from \"alepha\";\nimport { I18nProvider } from \"../providers/I18nProvider.ts\";\n\n/**\n * Register a dictionary entry for translations.\n *\n * It allows you to define a set of translations for a specific language.\n * Entry can be lazy-loaded, which is useful for large dictionaries or when translations are not needed immediately.\n *\n * @example\n * ```ts\n * import { $dictionary } from \"alepha/react/i18n\";\n *\n * const Example = () => {\n * const { tr } = useI18n<App, \"en\">();\n * return <div>{tr(\"hello\")}</div>; //\n * }\n *\n * class App {\n *\n * en = $dictionary({\n * // { default: { hello: \"Hey\" } }\n * lazy: () => import(\"./translations/en.ts\"),\n * });\n *\n * home = $page({\n * path: \"/\",\n * component: Example,\n * })\n * }\n *\n * run(App);\n * ```\n */\nexport const $dictionary = <T extends Record<string, string>>(\n options: DictionaryPrimitiveOptions<T>,\n): DictionaryPrimitive<T> => {\n return createPrimitive(DictionaryPrimitive<T>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface DictionaryPrimitiveOptions<T extends Record<string, string>> {\n lang?: string;\n name?: string;\n lazy: () => Async<{ default: T }>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class DictionaryPrimitive<\n T extends Record<string, string>,\n> extends Primitive<DictionaryPrimitiveOptions<T>> {\n protected provider = $inject(I18nProvider);\n protected onInit() {\n this.provider.registry.push({\n target: this.config.service.name,\n name: this.options.name ?? this.config.propertyKey,\n lang: this.options.lang ?? this.config.propertyKey,\n loader: async () => {\n const mod = await this.options.lazy();\n return mod.default;\n },\n translations: {},\n });\n }\n}\n\n$dictionary[KIND] = DictionaryPrimitive;\n","import { useInject, useStore } from \"alepha/react\";\nimport type { DictionaryPrimitive } from \"../primitives/$dictionary.ts\";\nimport { I18nProvider } from \"../providers/I18nProvider.ts\";\n\n/**\n * Hook to access the i18n service.\n */\nexport const useI18n = <\n S extends object,\n K extends keyof ServiceDictionary<S>,\n>(): I18nProvider<S, K> => {\n useStore(\"alepha.react.i18n.lang\");\n return useInject(I18nProvider<S, K>);\n};\n\nexport type ServiceDictionary<T extends object> = {\n [K in keyof T]: T[K] extends DictionaryPrimitive<infer U> ? U : never;\n};\n","import type { TypeBoxError } from \"alepha\";\nimport type { DateTime } from \"alepha/datetime\";\nimport { useI18n } from \"../hooks/useI18n.ts\";\n\nexport interface LocalizeProps {\n value: string | number | Date | DateTime | TypeBoxError;\n /**\n * Options for number formatting (when value is a number)\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat\n */\n number?: Intl.NumberFormatOptions;\n /**\n * Options for date formatting (when value is a Date or DateTime)\n * Can be:\n * - A dayjs format string (e.g., \"LLL\", \"YYYY-MM-DD\", \"dddd, MMMM D YYYY\")\n * - \"fromNow\" for relative time (e.g., \"2 hours ago\")\n * - Intl.DateTimeFormatOptions for native formatting\n * @see https://day.js.org/docs/en/display/format\n * @see https://day.js.org/docs/en/display/from-now\n */\n date?: string | \"fromNow\" | Intl.DateTimeFormatOptions;\n /**\n * Timezone to display dates in (when value is a Date or DateTime)\n * Uses IANA timezone names (e.g., \"America/New_York\", \"Europe/Paris\", \"Asia/Tokyo\")\n * @see https://day.js.org/docs/en/timezone/timezone\n */\n timezone?: string;\n}\n\nconst Localize = (props: LocalizeProps) => {\n const i18n = useI18n();\n return i18n.l(props.value, props);\n};\n\nexport default Localize;\n","import { useI18n } from \"../hooks/useI18n.ts\";\n\nexport interface TranslateProps {\n /**\n * Dictionary key to look up — the same key you would pass to `tr(...)`.\n */\n k: string;\n /**\n * Positional substitutions for `$1`, `$2`, … placeholders in the entry.\n */\n args?: string[];\n /**\n * Shown when the key is missing from every registered dictionary (otherwise\n * the raw key is rendered, matching `tr`'s behaviour).\n */\n fallback?: string;\n}\n\n/**\n * Renders a translated dictionary entry as a reactive text node.\n *\n * `tr(...)` is a hook, so it can only be called inside a component body. Use\n * `<Translate>` wherever a *node* is expected instead — a prop, a `children`\n * slot, or route metadata such as a nav-shell `label`. Because it subscribes to\n * {@link useI18n} it re-renders on a language switch, unlike a string resolved\n * once at module/initialisation time.\n *\n * Sibling of {@link Localize}: `Localize` formats a value (number, date,\n * error); `Translate` looks up a key.\n *\n * @example\n * ```tsx\n * nav: { label: <Translate k=\"admin.nav.users\" /> }\n * <Translate k=\"cart.items\" args={[String(count)]} fallback=\"Items\" />\n * ```\n */\nexport const Translate = (props: TranslateProps) => {\n const { tr } = useI18n();\n return <>{tr(props.k, { args: props.args, default: props.fallback })}</>;\n};\n\n/**\n * Terse alias for {@link Translate} — handy in dense JSX such as nav labels.\n */\nexport const Tr = Translate;\n\nexport default Translate;\n","import { $module } from \"alepha\";\nimport { $dictionary } from \"./primitives/$dictionary.ts\";\nimport { I18nProvider } from \"./providers/I18nProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type { LocalizeProps } from \"./components/Localize.tsx\";\nexport { default as Localize } from \"./components/Localize.tsx\";\nexport type { TranslateProps } from \"./components/Translate.tsx\";\nexport { default as Translate, Tr } from \"./components/Translate.tsx\";\nexport * from \"./hooks/useI18n.ts\";\nexport * from \"./primitives/$dictionary.ts\";\nexport * from \"./providers/I18nProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n export interface State {\n \"alepha.react.i18n.lang\"?: string;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Multi-language support.\n *\n * **Features:**\n * - Translation loading\n * - Locale detection\n * - Pluralization\n *\n * @module alepha.react.i18n\n */\nexport const AlephaReactI18n = $module({\n name: \"alepha.react.i18n\",\n primitives: [$dictionary],\n services: [I18nProvider],\n});\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { ReactNode } from "react";
2
-
3
2
  //#region ../../src/react/intro/components/GettingStarted.d.ts
4
3
  type GettingStartedStep = {
5
4
  num: string;
@@ -31,9 +30,7 @@ type GettingStartedProps = {
31
30
  /**
32
31
  * A welcome component displayed when creating a new Alepha application.
33
32
  */
34
- declare const GettingStarted: ({
35
- welcome
36
- }: GettingStartedProps) => import("react/jsx-runtime").JSX.Element;
33
+ declare const GettingStarted: ({ welcome }: GettingStartedProps) => import("react").JSX.Element;
37
34
  //#endregion
38
35
  export { GettingStarted, type GettingStartedSlide, type GettingStartedStep };
39
36
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/intro/components/GettingStarted.tsx"],"mappings":";;;KAMY,kBAAA;EACV,GAAA;EACA,IAAA,EAAM,SAAS;AAAA;AAAA,KAGL,mBAAA;EACV,IAAA;EACA,GAAA;EACA,MAAA;EACA,KAAA,GAAQ,kBAAkB;EAC1B,KAAA;IAAU,KAAA;IAAe,IAAA;EAAA;AAAA;AAAA,KAGf,qBAAA;EACV,OAAA;EACA,UAAU;AAAA;AAAA,KAGA,mBAAA;EATF;;;;;AACqB;EAe7B,OAAA,GAAU,qBAAqB;AAAA;;;AAVrB;cA6CN,cAAA;EAAkB;AAAA,GAAa,mBAAmB,iCAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/intro/components/GettingStarted.tsx"],"mappings":";;KAMY;EACV;EACA,MAAM;;KAGI;EACV;EACA;EACA;EACA,QAAQ;EACR;IAAU;IAAe;;;KAGf;EACV;EACA;;KAGU;;;;;;;EAOV,UAAU;;;;;cAmCN,mBAAc,WAAiB,wCAAmB,IAAA"}