convex-cms 0.0.1

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 (379) hide show
  1. package/dist/cli/commands/admin.d.ts +16 -0
  2. package/dist/cli/commands/admin.d.ts.map +1 -0
  3. package/dist/cli/commands/admin.js +88 -0
  4. package/dist/cli/commands/admin.js.map +1 -0
  5. package/dist/cli/index.d.ts +3 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +18 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/cli/utils/detectConvexUrl.d.ts +13 -0
  10. package/dist/cli/utils/detectConvexUrl.d.ts.map +1 -0
  11. package/dist/cli/utils/detectConvexUrl.js +48 -0
  12. package/dist/cli/utils/detectConvexUrl.js.map +1 -0
  13. package/dist/cli/utils/openBrowser.d.ts +7 -0
  14. package/dist/cli/utils/openBrowser.d.ts.map +1 -0
  15. package/dist/cli/utils/openBrowser.js +17 -0
  16. package/dist/cli/utils/openBrowser.js.map +1 -0
  17. package/dist/client/admin-config.d.ts +126 -0
  18. package/dist/client/admin-config.d.ts.map +1 -0
  19. package/dist/client/admin-config.js +117 -0
  20. package/dist/client/admin-config.js.map +1 -0
  21. package/dist/client/adminApi.d.ts +2273 -0
  22. package/dist/client/adminApi.d.ts.map +1 -0
  23. package/dist/client/adminApi.js +716 -0
  24. package/dist/client/adminApi.js.map +1 -0
  25. package/dist/client/agentTools.d.ts +933 -0
  26. package/dist/client/agentTools.d.ts.map +1 -0
  27. package/dist/client/agentTools.js +1004 -0
  28. package/dist/client/agentTools.js.map +1 -0
  29. package/dist/client/argTypes.d.ts +212 -0
  30. package/dist/client/argTypes.d.ts.map +1 -0
  31. package/dist/client/argTypes.js +5 -0
  32. package/dist/client/argTypes.js.map +1 -0
  33. package/dist/client/field-types.d.ts +55 -0
  34. package/dist/client/field-types.d.ts.map +1 -0
  35. package/dist/client/field-types.js +152 -0
  36. package/dist/client/field-types.js.map +1 -0
  37. package/dist/client/index.d.ts +189 -0
  38. package/dist/client/index.d.ts.map +1 -0
  39. package/dist/client/index.js +668 -0
  40. package/dist/client/index.js.map +1 -0
  41. package/dist/client/queryBuilder.d.ts +765 -0
  42. package/dist/client/queryBuilder.d.ts.map +1 -0
  43. package/dist/client/queryBuilder.js +970 -0
  44. package/dist/client/queryBuilder.js.map +1 -0
  45. package/dist/client/schema/codegen.d.ts +128 -0
  46. package/dist/client/schema/codegen.d.ts.map +1 -0
  47. package/dist/client/schema/codegen.js +318 -0
  48. package/dist/client/schema/codegen.js.map +1 -0
  49. package/dist/client/schema/defineContentType.d.ts +221 -0
  50. package/dist/client/schema/defineContentType.d.ts.map +1 -0
  51. package/dist/client/schema/defineContentType.js +380 -0
  52. package/dist/client/schema/defineContentType.js.map +1 -0
  53. package/dist/client/schema/index.d.ts +85 -0
  54. package/dist/client/schema/index.d.ts.map +1 -0
  55. package/dist/client/schema/index.js +92 -0
  56. package/dist/client/schema/index.js.map +1 -0
  57. package/dist/client/schema/schemaDrift.d.ts +199 -0
  58. package/dist/client/schema/schemaDrift.d.ts.map +1 -0
  59. package/dist/client/schema/schemaDrift.js +340 -0
  60. package/dist/client/schema/schemaDrift.js.map +1 -0
  61. package/dist/client/schema/typedClient.d.ts +401 -0
  62. package/dist/client/schema/typedClient.d.ts.map +1 -0
  63. package/dist/client/schema/typedClient.js +269 -0
  64. package/dist/client/schema/typedClient.js.map +1 -0
  65. package/dist/client/schema/types.d.ts +477 -0
  66. package/dist/client/schema/types.d.ts.map +1 -0
  67. package/dist/client/schema/types.js +39 -0
  68. package/dist/client/schema/types.js.map +1 -0
  69. package/dist/client/types.d.ts +449 -0
  70. package/dist/client/types.d.ts.map +1 -0
  71. package/dist/client/types.js +149 -0
  72. package/dist/client/types.js.map +1 -0
  73. package/dist/client/workflows.d.ts +51 -0
  74. package/dist/client/workflows.d.ts.map +1 -0
  75. package/dist/client/workflows.js +103 -0
  76. package/dist/client/workflows.js.map +1 -0
  77. package/dist/client/wrapper.d.ts +2198 -0
  78. package/dist/client/wrapper.d.ts.map +1 -0
  79. package/dist/client/wrapper.js +2651 -0
  80. package/dist/client/wrapper.js.map +1 -0
  81. package/dist/component/_generated/api.d.ts +124 -0
  82. package/dist/component/_generated/api.d.ts.map +1 -0
  83. package/dist/component/_generated/api.js +31 -0
  84. package/dist/component/_generated/api.js.map +1 -0
  85. package/dist/component/_generated/component.d.ts +4321 -0
  86. package/dist/component/_generated/component.d.ts.map +1 -0
  87. package/dist/component/_generated/component.js +11 -0
  88. package/dist/component/_generated/component.js.map +1 -0
  89. package/dist/component/_generated/dataModel.d.ts +46 -0
  90. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  91. package/dist/component/_generated/dataModel.js +11 -0
  92. package/dist/component/_generated/dataModel.js.map +1 -0
  93. package/dist/component/_generated/server.d.ts +121 -0
  94. package/dist/component/_generated/server.d.ts.map +1 -0
  95. package/dist/component/_generated/server.js +78 -0
  96. package/dist/component/_generated/server.js.map +1 -0
  97. package/dist/component/auditLog.d.ts +410 -0
  98. package/dist/component/auditLog.d.ts.map +1 -0
  99. package/dist/component/auditLog.js +607 -0
  100. package/dist/component/auditLog.js.map +1 -0
  101. package/dist/component/authorization.d.ts +323 -0
  102. package/dist/component/authorization.d.ts.map +1 -0
  103. package/dist/component/authorization.js +464 -0
  104. package/dist/component/authorization.js.map +1 -0
  105. package/dist/component/authorizationHooks.d.ts +184 -0
  106. package/dist/component/authorizationHooks.d.ts.map +1 -0
  107. package/dist/component/authorizationHooks.js +521 -0
  108. package/dist/component/authorizationHooks.js.map +1 -0
  109. package/dist/component/bulkOperations.d.ts +200 -0
  110. package/dist/component/bulkOperations.d.ts.map +1 -0
  111. package/dist/component/bulkOperations.js +568 -0
  112. package/dist/component/bulkOperations.js.map +1 -0
  113. package/dist/component/contentEntries.d.ts +719 -0
  114. package/dist/component/contentEntries.d.ts.map +1 -0
  115. package/dist/component/contentEntries.js +1617 -0
  116. package/dist/component/contentEntries.js.map +1 -0
  117. package/dist/component/contentEntryMutations.d.ts +505 -0
  118. package/dist/component/contentEntryMutations.d.ts.map +1 -0
  119. package/dist/component/contentEntryMutations.js +1009 -0
  120. package/dist/component/contentEntryMutations.js.map +1 -0
  121. package/dist/component/contentEntryValidation.d.ts +115 -0
  122. package/dist/component/contentEntryValidation.d.ts.map +1 -0
  123. package/dist/component/contentEntryValidation.js +546 -0
  124. package/dist/component/contentEntryValidation.js.map +1 -0
  125. package/dist/component/contentLock.d.ts +328 -0
  126. package/dist/component/contentLock.d.ts.map +1 -0
  127. package/dist/component/contentLock.js +471 -0
  128. package/dist/component/contentLock.js.map +1 -0
  129. package/dist/component/contentTypeMigration.d.ts +411 -0
  130. package/dist/component/contentTypeMigration.d.ts.map +1 -0
  131. package/dist/component/contentTypeMigration.js +805 -0
  132. package/dist/component/contentTypeMigration.js.map +1 -0
  133. package/dist/component/contentTypeMutations.d.ts +975 -0
  134. package/dist/component/contentTypeMutations.d.ts.map +1 -0
  135. package/dist/component/contentTypeMutations.js +768 -0
  136. package/dist/component/contentTypeMutations.js.map +1 -0
  137. package/dist/component/contentTypes.d.ts +538 -0
  138. package/dist/component/contentTypes.d.ts.map +1 -0
  139. package/dist/component/contentTypes.js +304 -0
  140. package/dist/component/contentTypes.js.map +1 -0
  141. package/dist/component/convex.config.d.ts +42 -0
  142. package/dist/component/convex.config.d.ts.map +1 -0
  143. package/dist/component/convex.config.js +43 -0
  144. package/dist/component/convex.config.js.map +1 -0
  145. package/dist/component/documentTypes.d.ts +186 -0
  146. package/dist/component/documentTypes.d.ts.map +1 -0
  147. package/dist/component/documentTypes.js +23 -0
  148. package/dist/component/documentTypes.js.map +1 -0
  149. package/dist/component/eventEmitter.d.ts +281 -0
  150. package/dist/component/eventEmitter.d.ts.map +1 -0
  151. package/dist/component/eventEmitter.js +300 -0
  152. package/dist/component/eventEmitter.js.map +1 -0
  153. package/dist/component/exportImport.d.ts +1120 -0
  154. package/dist/component/exportImport.d.ts.map +1 -0
  155. package/dist/component/exportImport.js +931 -0
  156. package/dist/component/exportImport.js.map +1 -0
  157. package/dist/component/index.d.ts +28 -0
  158. package/dist/component/index.d.ts.map +1 -0
  159. package/dist/component/index.js +142 -0
  160. package/dist/component/index.js.map +1 -0
  161. package/dist/component/lib/deepReferenceResolver.d.ts +252 -0
  162. package/dist/component/lib/deepReferenceResolver.d.ts.map +1 -0
  163. package/dist/component/lib/deepReferenceResolver.js +601 -0
  164. package/dist/component/lib/deepReferenceResolver.js.map +1 -0
  165. package/dist/component/lib/errors.d.ts +306 -0
  166. package/dist/component/lib/errors.d.ts.map +1 -0
  167. package/dist/component/lib/errors.js +407 -0
  168. package/dist/component/lib/errors.js.map +1 -0
  169. package/dist/component/lib/index.d.ts +10 -0
  170. package/dist/component/lib/index.d.ts.map +1 -0
  171. package/dist/component/lib/index.js +33 -0
  172. package/dist/component/lib/index.js.map +1 -0
  173. package/dist/component/lib/mediaReferenceResolver.d.ts +217 -0
  174. package/dist/component/lib/mediaReferenceResolver.d.ts.map +1 -0
  175. package/dist/component/lib/mediaReferenceResolver.js +326 -0
  176. package/dist/component/lib/mediaReferenceResolver.js.map +1 -0
  177. package/dist/component/lib/metadataExtractor.d.ts +245 -0
  178. package/dist/component/lib/metadataExtractor.d.ts.map +1 -0
  179. package/dist/component/lib/metadataExtractor.js +548 -0
  180. package/dist/component/lib/metadataExtractor.js.map +1 -0
  181. package/dist/component/lib/mutationAuth.d.ts +95 -0
  182. package/dist/component/lib/mutationAuth.d.ts.map +1 -0
  183. package/dist/component/lib/mutationAuth.js +146 -0
  184. package/dist/component/lib/mutationAuth.js.map +1 -0
  185. package/dist/component/lib/queries.d.ts +17 -0
  186. package/dist/component/lib/queries.d.ts.map +1 -0
  187. package/dist/component/lib/queries.js +49 -0
  188. package/dist/component/lib/queries.js.map +1 -0
  189. package/dist/component/lib/ragContentChunker.d.ts +423 -0
  190. package/dist/component/lib/ragContentChunker.d.ts.map +1 -0
  191. package/dist/component/lib/ragContentChunker.js +897 -0
  192. package/dist/component/lib/ragContentChunker.js.map +1 -0
  193. package/dist/component/lib/referenceResolver.d.ts +175 -0
  194. package/dist/component/lib/referenceResolver.d.ts.map +1 -0
  195. package/dist/component/lib/referenceResolver.js +293 -0
  196. package/dist/component/lib/referenceResolver.js.map +1 -0
  197. package/dist/component/lib/slugGenerator.d.ts +71 -0
  198. package/dist/component/lib/slugGenerator.d.ts.map +1 -0
  199. package/dist/component/lib/slugGenerator.js +207 -0
  200. package/dist/component/lib/slugGenerator.js.map +1 -0
  201. package/dist/component/lib/slugUniqueness.d.ts +131 -0
  202. package/dist/component/lib/slugUniqueness.d.ts.map +1 -0
  203. package/dist/component/lib/slugUniqueness.js +229 -0
  204. package/dist/component/lib/slugUniqueness.js.map +1 -0
  205. package/dist/component/lib/softDelete.d.ts +18 -0
  206. package/dist/component/lib/softDelete.d.ts.map +1 -0
  207. package/dist/component/lib/softDelete.js +29 -0
  208. package/dist/component/lib/softDelete.js.map +1 -0
  209. package/dist/component/localeFallbackChain.d.ts +410 -0
  210. package/dist/component/localeFallbackChain.d.ts.map +1 -0
  211. package/dist/component/localeFallbackChain.js +467 -0
  212. package/dist/component/localeFallbackChain.js.map +1 -0
  213. package/dist/component/localeFields.d.ts +508 -0
  214. package/dist/component/localeFields.d.ts.map +1 -0
  215. package/dist/component/localeFields.js +592 -0
  216. package/dist/component/localeFields.js.map +1 -0
  217. package/dist/component/mediaAssetMutations.d.ts +235 -0
  218. package/dist/component/mediaAssetMutations.d.ts.map +1 -0
  219. package/dist/component/mediaAssetMutations.js +558 -0
  220. package/dist/component/mediaAssetMutations.js.map +1 -0
  221. package/dist/component/mediaAssets.d.ts +168 -0
  222. package/dist/component/mediaAssets.d.ts.map +1 -0
  223. package/dist/component/mediaAssets.js +618 -0
  224. package/dist/component/mediaAssets.js.map +1 -0
  225. package/dist/component/mediaFolderMutations.d.ts +642 -0
  226. package/dist/component/mediaFolderMutations.d.ts.map +1 -0
  227. package/dist/component/mediaFolderMutations.js +849 -0
  228. package/dist/component/mediaFolderMutations.js.map +1 -0
  229. package/dist/component/mediaUploadMutations.d.ts +136 -0
  230. package/dist/component/mediaUploadMutations.d.ts.map +1 -0
  231. package/dist/component/mediaUploadMutations.js +205 -0
  232. package/dist/component/mediaUploadMutations.js.map +1 -0
  233. package/dist/component/mediaVariantMutations.d.ts +468 -0
  234. package/dist/component/mediaVariantMutations.d.ts.map +1 -0
  235. package/dist/component/mediaVariantMutations.js +737 -0
  236. package/dist/component/mediaVariantMutations.js.map +1 -0
  237. package/dist/component/mediaVariants.d.ts +525 -0
  238. package/dist/component/mediaVariants.d.ts.map +1 -0
  239. package/dist/component/mediaVariants.js +661 -0
  240. package/dist/component/mediaVariants.js.map +1 -0
  241. package/dist/component/ragContentIndexer.d.ts +595 -0
  242. package/dist/component/ragContentIndexer.d.ts.map +1 -0
  243. package/dist/component/ragContentIndexer.js +794 -0
  244. package/dist/component/ragContentIndexer.js.map +1 -0
  245. package/dist/component/rateLimitHooks.d.ts +266 -0
  246. package/dist/component/rateLimitHooks.d.ts.map +1 -0
  247. package/dist/component/rateLimitHooks.js +412 -0
  248. package/dist/component/rateLimitHooks.js.map +1 -0
  249. package/dist/component/roles.d.ts +649 -0
  250. package/dist/component/roles.d.ts.map +1 -0
  251. package/dist/component/roles.js +884 -0
  252. package/dist/component/roles.js.map +1 -0
  253. package/dist/component/scheduledPublish.d.ts +182 -0
  254. package/dist/component/scheduledPublish.d.ts.map +1 -0
  255. package/dist/component/scheduledPublish.js +304 -0
  256. package/dist/component/scheduledPublish.js.map +1 -0
  257. package/dist/component/schema.d.ts +4114 -0
  258. package/dist/component/schema.d.ts.map +1 -0
  259. package/dist/component/schema.js +469 -0
  260. package/dist/component/schema.js.map +1 -0
  261. package/dist/component/taxonomies.d.ts +476 -0
  262. package/dist/component/taxonomies.d.ts.map +1 -0
  263. package/dist/component/taxonomies.js +785 -0
  264. package/dist/component/taxonomies.js.map +1 -0
  265. package/dist/component/taxonomyMutations.d.ts +206 -0
  266. package/dist/component/taxonomyMutations.d.ts.map +1 -0
  267. package/dist/component/taxonomyMutations.js +1001 -0
  268. package/dist/component/taxonomyMutations.js.map +1 -0
  269. package/dist/component/trash.d.ts +265 -0
  270. package/dist/component/trash.d.ts.map +1 -0
  271. package/dist/component/trash.js +621 -0
  272. package/dist/component/trash.js.map +1 -0
  273. package/dist/component/types.d.ts +4 -0
  274. package/dist/component/types.d.ts.map +1 -0
  275. package/dist/component/types.js +2 -0
  276. package/dist/component/types.js.map +1 -0
  277. package/dist/component/userContext.d.ts +508 -0
  278. package/dist/component/userContext.d.ts.map +1 -0
  279. package/dist/component/userContext.js +615 -0
  280. package/dist/component/userContext.js.map +1 -0
  281. package/dist/component/validation.d.ts +387 -0
  282. package/dist/component/validation.d.ts.map +1 -0
  283. package/dist/component/validation.js +1052 -0
  284. package/dist/component/validation.js.map +1 -0
  285. package/dist/component/validators.d.ts +4645 -0
  286. package/dist/component/validators.d.ts.map +1 -0
  287. package/dist/component/validators.js +641 -0
  288. package/dist/component/validators.js.map +1 -0
  289. package/dist/component/versionMutations.d.ts +216 -0
  290. package/dist/component/versionMutations.d.ts.map +1 -0
  291. package/dist/component/versionMutations.js +321 -0
  292. package/dist/component/versionMutations.js.map +1 -0
  293. package/dist/component/webhookTrigger.d.ts +770 -0
  294. package/dist/component/webhookTrigger.d.ts.map +1 -0
  295. package/dist/component/webhookTrigger.js +1413 -0
  296. package/dist/component/webhookTrigger.js.map +1 -0
  297. package/dist/react/index.d.ts +316 -0
  298. package/dist/react/index.d.ts.map +1 -0
  299. package/dist/react/index.js +558 -0
  300. package/dist/react/index.js.map +1 -0
  301. package/dist/test.d.ts +2230 -0
  302. package/dist/test.d.ts.map +1 -0
  303. package/dist/test.js +1107 -0
  304. package/dist/test.js.map +1 -0
  305. package/package.json +95 -0
  306. package/src/cli/commands/admin.ts +104 -0
  307. package/src/cli/index.ts +21 -0
  308. package/src/cli/utils/detectConvexUrl.ts +54 -0
  309. package/src/cli/utils/openBrowser.ts +16 -0
  310. package/src/client/admin-config.ts +138 -0
  311. package/src/client/adminApi.ts +942 -0
  312. package/src/client/agentTools.ts +1311 -0
  313. package/src/client/argTypes.ts +316 -0
  314. package/src/client/field-types.ts +187 -0
  315. package/src/client/index.ts +1301 -0
  316. package/src/client/queryBuilder.ts +1100 -0
  317. package/src/client/schema/codegen.ts +500 -0
  318. package/src/client/schema/defineContentType.ts +501 -0
  319. package/src/client/schema/index.ts +169 -0
  320. package/src/client/schema/schemaDrift.ts +574 -0
  321. package/src/client/schema/typedClient.ts +688 -0
  322. package/src/client/schema/types.ts +666 -0
  323. package/src/client/types.ts +723 -0
  324. package/src/client/workflows.ts +141 -0
  325. package/src/client/wrapper.ts +4304 -0
  326. package/src/component/_generated/api.ts +140 -0
  327. package/src/component/_generated/component.ts +5029 -0
  328. package/src/component/_generated/dataModel.ts +60 -0
  329. package/src/component/_generated/server.ts +156 -0
  330. package/src/component/authorization.ts +647 -0
  331. package/src/component/authorizationHooks.ts +668 -0
  332. package/src/component/bulkOperations.ts +687 -0
  333. package/src/component/contentEntries.ts +1976 -0
  334. package/src/component/contentEntryMutations.ts +1223 -0
  335. package/src/component/contentEntryValidation.ts +707 -0
  336. package/src/component/contentLock.ts +550 -0
  337. package/src/component/contentTypeMigration.ts +1064 -0
  338. package/src/component/contentTypeMutations.ts +969 -0
  339. package/src/component/contentTypes.ts +346 -0
  340. package/src/component/convex.config.ts +44 -0
  341. package/src/component/documentTypes.ts +240 -0
  342. package/src/component/eventEmitter.ts +485 -0
  343. package/src/component/exportImport.ts +1169 -0
  344. package/src/component/index.ts +491 -0
  345. package/src/component/lib/deepReferenceResolver.ts +999 -0
  346. package/src/component/lib/errors.ts +816 -0
  347. package/src/component/lib/index.ts +145 -0
  348. package/src/component/lib/mediaReferenceResolver.ts +495 -0
  349. package/src/component/lib/metadataExtractor.ts +792 -0
  350. package/src/component/lib/mutationAuth.ts +199 -0
  351. package/src/component/lib/queries.ts +79 -0
  352. package/src/component/lib/ragContentChunker.ts +1371 -0
  353. package/src/component/lib/referenceResolver.ts +430 -0
  354. package/src/component/lib/slugGenerator.ts +262 -0
  355. package/src/component/lib/slugUniqueness.ts +333 -0
  356. package/src/component/lib/softDelete.ts +44 -0
  357. package/src/component/localeFallbackChain.ts +673 -0
  358. package/src/component/localeFields.ts +896 -0
  359. package/src/component/mediaAssetMutations.ts +725 -0
  360. package/src/component/mediaAssets.ts +932 -0
  361. package/src/component/mediaFolderMutations.ts +1046 -0
  362. package/src/component/mediaUploadMutations.ts +224 -0
  363. package/src/component/mediaVariantMutations.ts +900 -0
  364. package/src/component/mediaVariants.ts +793 -0
  365. package/src/component/ragContentIndexer.ts +1067 -0
  366. package/src/component/rateLimitHooks.ts +572 -0
  367. package/src/component/roles.ts +1360 -0
  368. package/src/component/scheduledPublish.ts +358 -0
  369. package/src/component/schema.ts +617 -0
  370. package/src/component/taxonomies.ts +949 -0
  371. package/src/component/taxonomyMutations.ts +1210 -0
  372. package/src/component/trash.ts +724 -0
  373. package/src/component/userContext.ts +898 -0
  374. package/src/component/validation.ts +1388 -0
  375. package/src/component/validators.ts +949 -0
  376. package/src/component/versionMutations.ts +392 -0
  377. package/src/component/webhookTrigger.ts +1922 -0
  378. package/src/react/index.ts +898 -0
  379. package/src/test.ts +1580 -0
@@ -0,0 +1,673 @@
1
+ /**
2
+ * Locale Fallback Chain Configuration and Utilities
3
+ *
4
+ * This module provides configuration and utility functions for locale fallback chains.
5
+ * When content isn't available in a requested locale, the system falls back through
6
+ * a configured chain until content is found.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * // Configure fallback chains
11
+ * const config: LocaleFallbackConfig = {
12
+ * defaultLocale: "en-US",
13
+ * fallbackChains: {
14
+ * "es-MX": ["es-ES", "en-US"], // Mexican Spanish -> Spain Spanish -> US English
15
+ * "es-ES": ["en-US"], // Spain Spanish -> US English
16
+ * "fr-CA": ["fr-FR", "en-US"], // Canadian French -> France French -> US English
17
+ * "zh-Hans-CN": ["zh-Hans", "en-US"], // Simplified Chinese (China) -> Simplified Chinese -> US English
18
+ * },
19
+ * };
20
+ *
21
+ * // Resolve fallback chain for a locale
22
+ * const chain = resolveFallbackChain("es-MX", config);
23
+ * // Returns: ["es-ES", "en-US", "en-US"] -> deduplicated to ["es-ES", "en-US"]
24
+ * ```
25
+ *
26
+ * @module localeFallbackChain
27
+ */
28
+
29
+ import type { LocaleResolutionOptions } from "./localeFields.js";
30
+
31
+ // =============================================================================
32
+ // Types
33
+ // =============================================================================
34
+
35
+ /**
36
+ * BCP 47 locale code (e.g., "en-US", "zh-Hans", "zh-Hans-CN").
37
+ */
38
+ export type LocaleCode = string;
39
+
40
+ /**
41
+ * Configuration for locale fallback behavior.
42
+ *
43
+ * Defines how the system should resolve content when the requested locale
44
+ * is not available. Fallback chains are tried in order until content is found.
45
+ */
46
+ export interface LocaleFallbackConfig {
47
+ /**
48
+ * The default locale used as the final fallback when all other options are exhausted.
49
+ * This should be the locale with the most complete content.
50
+ *
51
+ * @default "en"
52
+ */
53
+ defaultLocale: LocaleCode;
54
+
55
+ /**
56
+ * Mapping of locale codes to their fallback chains.
57
+ * Each locale can have an ordered array of fallback locales to try.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * fallbackChains: {
62
+ * "es-MX": ["es-ES", "en-US"], // Try Spain Spanish, then US English
63
+ * "es-AR": ["es-ES", "en-US"], // Argentine Spanish also falls back to Spain Spanish
64
+ * "pt-BR": ["pt-PT", "en-US"], // Brazilian Portuguese -> Portugal Portuguese
65
+ * }
66
+ * ```
67
+ */
68
+ fallbackChains?: Record<LocaleCode, LocaleCode[]>;
69
+
70
+ /**
71
+ * Whether to automatically generate fallback chains based on locale hierarchy.
72
+ *
73
+ * When enabled, the system will automatically create fallback chains based on
74
+ * the BCP 47 locale structure:
75
+ * - "zh-Hans-CN" -> ["zh-Hans", "zh", defaultLocale]
76
+ * - "en-US" -> ["en", defaultLocale]
77
+ *
78
+ * Explicit fallbackChains take precedence over auto-generated ones.
79
+ *
80
+ * @default true
81
+ */
82
+ autoGenerateFallbacks?: boolean;
83
+
84
+ /**
85
+ * List of supported locales. If provided, fallback chains will only include
86
+ * locales from this list.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * supportedLocales: ["en-US", "es-ES", "fr-FR", "de-DE"]
91
+ * ```
92
+ */
93
+ supportedLocales?: LocaleCode[];
94
+ }
95
+
96
+ /**
97
+ * Result of resolving a fallback chain for a locale.
98
+ */
99
+ export interface ResolvedFallbackChain {
100
+ /**
101
+ * The original locale that was requested.
102
+ */
103
+ requestedLocale: LocaleCode;
104
+
105
+ /**
106
+ * The complete fallback chain in priority order.
107
+ * Does not include the requested locale itself.
108
+ */
109
+ fallbackChain: LocaleCode[];
110
+
111
+ /**
112
+ * The default locale (final fallback).
113
+ */
114
+ defaultLocale: LocaleCode;
115
+
116
+ /**
117
+ * Whether the chain was auto-generated or explicitly configured.
118
+ */
119
+ isAutoGenerated: boolean;
120
+ }
121
+
122
+ /**
123
+ * Options for building a fallback chain.
124
+ */
125
+ export interface BuildFallbackChainOptions {
126
+ /**
127
+ * Whether to include the default locale in the chain.
128
+ * @default true
129
+ */
130
+ includeDefault?: boolean;
131
+
132
+ /**
133
+ * Whether to deduplicate the chain (remove duplicate locales).
134
+ * @default true
135
+ */
136
+ deduplicate?: boolean;
137
+
138
+ /**
139
+ * Maximum length of the fallback chain.
140
+ * @default 10
141
+ */
142
+ maxLength?: number;
143
+ }
144
+
145
+ // =============================================================================
146
+ // Constants
147
+ // =============================================================================
148
+
149
+ /**
150
+ * Default fallback configuration.
151
+ */
152
+ export const DEFAULT_FALLBACK_CONFIG: Required<LocaleFallbackConfig> = {
153
+ defaultLocale: "en",
154
+ fallbackChains: {},
155
+ autoGenerateFallbacks: true,
156
+ supportedLocales: [],
157
+ };
158
+
159
+ // =============================================================================
160
+ // Locale Parsing Utilities
161
+ // =============================================================================
162
+
163
+ /**
164
+ * Parsed components of a BCP 47 locale code.
165
+ */
166
+ export interface ParsedLocale {
167
+ /**
168
+ * The language code (2-3 lowercase letters).
169
+ * @example "en", "zh", "pt"
170
+ */
171
+ language: string;
172
+
173
+ /**
174
+ * The script code (4 letters, title case), if present.
175
+ * @example "Hans", "Hant", "Latn"
176
+ */
177
+ script?: string;
178
+
179
+ /**
180
+ * The region code (2 uppercase letters), if present.
181
+ * @example "US", "CN", "BR"
182
+ */
183
+ region?: string;
184
+ }
185
+
186
+ /**
187
+ * Parses a BCP 47 locale code into its components.
188
+ *
189
+ * Supports the following formats:
190
+ * - "en" (language only)
191
+ * - "en-US" (language + region)
192
+ * - "zh-Hans" (language + script)
193
+ * - "zh-Hans-CN" (language + script + region)
194
+ *
195
+ * @param locale - The locale code to parse
196
+ * @returns The parsed locale components, or null if invalid
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * parseLocale("en-US");
201
+ * // Returns: { language: "en", region: "US" }
202
+ *
203
+ * parseLocale("zh-Hans-CN");
204
+ * // Returns: { language: "zh", script: "Hans", region: "CN" }
205
+ *
206
+ * parseLocale("invalid");
207
+ * // Returns: null
208
+ * ```
209
+ */
210
+ export function parseLocale(locale: LocaleCode): ParsedLocale | null {
211
+ if (!locale || typeof locale !== "string") {
212
+ return null;
213
+ }
214
+
215
+ // Pattern: language[-Script][-REGION]
216
+ // Language: 2-3 lowercase letters
217
+ // Script: 4 letters, title case (optional)
218
+ // Region: 2 uppercase letters (optional)
219
+ const pattern = /^([a-z]{2,3})(?:-([A-Z][a-z]{3}))?(?:-([A-Z]{2}))?$/;
220
+ const match = locale.match(pattern);
221
+
222
+ if (!match) {
223
+ // Try simpler patterns
224
+ // Just language
225
+ if (/^[a-z]{2,3}$/.test(locale)) {
226
+ return { language: locale };
227
+ }
228
+ return null;
229
+ }
230
+
231
+ const [, language, script, region] = match;
232
+
233
+ const result: ParsedLocale = { language };
234
+ if (script) result.script = script;
235
+ if (region) result.region = region;
236
+
237
+ return result;
238
+ }
239
+
240
+ /**
241
+ * Formats parsed locale components back into a BCP 47 locale code.
242
+ *
243
+ * @param parsed - The parsed locale components
244
+ * @returns The formatted locale code
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * formatLocale({ language: "en", region: "US" });
249
+ * // Returns: "en-US"
250
+ *
251
+ * formatLocale({ language: "zh", script: "Hans", region: "CN" });
252
+ * // Returns: "zh-Hans-CN"
253
+ * ```
254
+ */
255
+ export function formatLocale(parsed: ParsedLocale): LocaleCode {
256
+ let result = parsed.language;
257
+ if (parsed.script) result += `-${parsed.script}`;
258
+ if (parsed.region) result += `-${parsed.region}`;
259
+ return result;
260
+ }
261
+
262
+ /**
263
+ * Generates the locale hierarchy (parent locales) for a given locale.
264
+ *
265
+ * @param locale - The locale to get hierarchy for
266
+ * @returns Array of parent locales from most specific to least specific
267
+ *
268
+ * @example
269
+ * ```typescript
270
+ * getLocaleHierarchy("zh-Hans-CN");
271
+ * // Returns: ["zh-Hans", "zh"]
272
+ *
273
+ * getLocaleHierarchy("en-US");
274
+ * // Returns: ["en"]
275
+ *
276
+ * getLocaleHierarchy("en");
277
+ * // Returns: []
278
+ * ```
279
+ */
280
+ export function getLocaleHierarchy(locale: LocaleCode): LocaleCode[] {
281
+ const parsed = parseLocale(locale);
282
+ if (!parsed) return [];
283
+
284
+ const hierarchy: LocaleCode[] = [];
285
+
286
+ // If we have region, add without region
287
+ if (parsed.region) {
288
+ if (parsed.script) {
289
+ // zh-Hans-CN -> zh-Hans
290
+ hierarchy.push(formatLocale({ language: parsed.language, script: parsed.script }));
291
+ }
292
+ // zh-Hans-CN -> zh, or en-US -> en
293
+ hierarchy.push(parsed.language);
294
+ } else if (parsed.script) {
295
+ // zh-Hans -> zh
296
+ hierarchy.push(parsed.language);
297
+ }
298
+
299
+ return hierarchy;
300
+ }
301
+
302
+ // =============================================================================
303
+ // Fallback Chain Resolution
304
+ // =============================================================================
305
+
306
+ /**
307
+ * Resolves the complete fallback chain for a locale.
308
+ *
309
+ * The resolution order is:
310
+ * 1. Explicit fallback chain from configuration (if defined)
311
+ * 2. Auto-generated hierarchy-based chain (if enabled)
312
+ * 3. Default locale as final fallback
313
+ *
314
+ * @param locale - The locale to resolve the fallback chain for
315
+ * @param config - The fallback configuration
316
+ * @param options - Options for building the chain
317
+ * @returns The resolved fallback chain
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * const config: LocaleFallbackConfig = {
322
+ * defaultLocale: "en-US",
323
+ * fallbackChains: {
324
+ * "es-MX": ["es-ES"],
325
+ * },
326
+ * };
327
+ *
328
+ * // Explicit chain
329
+ * resolveFallbackChain("es-MX", config);
330
+ * // Returns: { requestedLocale: "es-MX", fallbackChain: ["es-ES", "en-US"], ... }
331
+ *
332
+ * // Auto-generated chain
333
+ * resolveFallbackChain("fr-CA", config);
334
+ * // Returns: { requestedLocale: "fr-CA", fallbackChain: ["fr", "en-US"], ... }
335
+ * ```
336
+ */
337
+ export function resolveFallbackChain(
338
+ locale: LocaleCode,
339
+ config: LocaleFallbackConfig = DEFAULT_FALLBACK_CONFIG,
340
+ options: BuildFallbackChainOptions = {}
341
+ ): ResolvedFallbackChain {
342
+ const {
343
+ includeDefault = true,
344
+ deduplicate = true,
345
+ maxLength = 10,
346
+ } = options;
347
+
348
+ const {
349
+ defaultLocale = DEFAULT_FALLBACK_CONFIG.defaultLocale,
350
+ fallbackChains = {},
351
+ autoGenerateFallbacks = true,
352
+ supportedLocales = [],
353
+ } = config;
354
+
355
+ let chain: LocaleCode[] = [];
356
+ let isAutoGenerated = false;
357
+
358
+ // Check for explicit fallback chain
359
+ if (fallbackChains[locale]) {
360
+ chain = [...fallbackChains[locale]];
361
+ } else if (autoGenerateFallbacks) {
362
+ // Auto-generate based on locale hierarchy
363
+ chain = getLocaleHierarchy(locale);
364
+ isAutoGenerated = true;
365
+ }
366
+
367
+ // Add default locale if not already in chain
368
+ if (includeDefault && !chain.includes(defaultLocale)) {
369
+ chain.push(defaultLocale);
370
+ }
371
+
372
+ // Filter to supported locales if specified
373
+ if (supportedLocales.length > 0) {
374
+ chain = chain.filter((l) => supportedLocales.includes(l));
375
+ }
376
+
377
+ // Deduplicate
378
+ if (deduplicate) {
379
+ chain = [...new Set(chain)];
380
+ }
381
+
382
+ // Remove the requested locale itself if present
383
+ chain = chain.filter((l) => l !== locale);
384
+
385
+ // Limit length
386
+ if (chain.length > maxLength) {
387
+ chain = chain.slice(0, maxLength);
388
+ }
389
+
390
+ return {
391
+ requestedLocale: locale,
392
+ fallbackChain: chain,
393
+ defaultLocale,
394
+ isAutoGenerated,
395
+ };
396
+ }
397
+
398
+ /**
399
+ * Gets the fallback chain as a simple array of locale codes.
400
+ *
401
+ * This is a convenience function for use with `getLocalizedValue`.
402
+ *
403
+ * @param locale - The locale to get fallback chain for
404
+ * @param config - The fallback configuration
405
+ * @returns Array of fallback locale codes
406
+ *
407
+ * @example
408
+ * ```typescript
409
+ * const chain = getFallbackChain("es-MX", config);
410
+ * // Returns: ["es-ES", "en-US"]
411
+ *
412
+ * // Use with getLocalizedValue
413
+ * const result = getLocalizedValue(value, {
414
+ * locale: "es-MX",
415
+ * fallbackChain: chain,
416
+ * });
417
+ * ```
418
+ */
419
+ export function getFallbackChain(
420
+ locale: LocaleCode,
421
+ config: LocaleFallbackConfig = DEFAULT_FALLBACK_CONFIG
422
+ ): LocaleCode[] {
423
+ return resolveFallbackChain(locale, config).fallbackChain;
424
+ }
425
+
426
+ // =============================================================================
427
+ // Configuration Utilities
428
+ // =============================================================================
429
+
430
+ /**
431
+ * Creates a LocaleFallbackConfig with defaults applied.
432
+ *
433
+ * @param config - Partial configuration to merge with defaults
434
+ * @returns Complete configuration with defaults
435
+ *
436
+ * @example
437
+ * ```typescript
438
+ * const config = createFallbackConfig({
439
+ * defaultLocale: "en-US",
440
+ * fallbackChains: {
441
+ * "es-MX": ["es-ES"],
442
+ * },
443
+ * });
444
+ * ```
445
+ */
446
+ export function createFallbackConfig(
447
+ config: Partial<LocaleFallbackConfig> = {}
448
+ ): Required<LocaleFallbackConfig> {
449
+ return {
450
+ defaultLocale: config.defaultLocale ?? DEFAULT_FALLBACK_CONFIG.defaultLocale,
451
+ fallbackChains: config.fallbackChains ?? DEFAULT_FALLBACK_CONFIG.fallbackChains,
452
+ autoGenerateFallbacks: config.autoGenerateFallbacks ?? DEFAULT_FALLBACK_CONFIG.autoGenerateFallbacks,
453
+ supportedLocales: config.supportedLocales ?? DEFAULT_FALLBACK_CONFIG.supportedLocales,
454
+ };
455
+ }
456
+
457
+ /**
458
+ * Validates a LocaleFallbackConfig for common issues.
459
+ *
460
+ * @param config - The configuration to validate
461
+ * @returns Array of validation errors (empty if valid)
462
+ *
463
+ * @example
464
+ * ```typescript
465
+ * const errors = validateFallbackConfig({
466
+ * defaultLocale: "en-US",
467
+ * fallbackChains: {
468
+ * "es-MX": ["invalid-locale"],
469
+ * },
470
+ * supportedLocales: ["en-US", "es-ES"],
471
+ * });
472
+ * // Returns: ["Fallback chain for 'es-MX' contains unsupported locale: 'invalid-locale'"]
473
+ * ```
474
+ */
475
+ export function validateFallbackConfig(config: LocaleFallbackConfig): string[] {
476
+ const errors: string[] = [];
477
+ const { defaultLocale, fallbackChains = {}, supportedLocales = [] } = config;
478
+
479
+ // Check default locale
480
+ if (!defaultLocale) {
481
+ errors.push("defaultLocale is required");
482
+ } else if (!parseLocale(defaultLocale)) {
483
+ errors.push(`Invalid defaultLocale format: '${defaultLocale}'`);
484
+ }
485
+
486
+ // Check supported locales include default
487
+ if (supportedLocales.length > 0 && defaultLocale && !supportedLocales.includes(defaultLocale)) {
488
+ errors.push(`defaultLocale '${defaultLocale}' is not in supportedLocales`);
489
+ }
490
+
491
+ // Validate fallback chains
492
+ for (const [locale, chain] of Object.entries(fallbackChains)) {
493
+ // Check locale format
494
+ if (!parseLocale(locale)) {
495
+ errors.push(`Invalid locale format in fallbackChains: '${locale}'`);
496
+ }
497
+
498
+ // Check chain items
499
+ for (const fallback of chain) {
500
+ if (!parseLocale(fallback)) {
501
+ errors.push(`Invalid fallback locale format for '${locale}': '${fallback}'`);
502
+ }
503
+
504
+ // Check against supported locales
505
+ if (supportedLocales.length > 0 && !supportedLocales.includes(fallback)) {
506
+ errors.push(`Fallback chain for '${locale}' contains unsupported locale: '${fallback}'`);
507
+ }
508
+ }
509
+
510
+ // Check for circular references
511
+ if (chain.includes(locale)) {
512
+ errors.push(`Fallback chain for '${locale}' contains self-reference`);
513
+ }
514
+ }
515
+
516
+ // Validate supported locales formats
517
+ for (const locale of supportedLocales) {
518
+ if (!parseLocale(locale)) {
519
+ errors.push(`Invalid locale format in supportedLocales: '${locale}'`);
520
+ }
521
+ }
522
+
523
+ return errors;
524
+ }
525
+
526
+ // =============================================================================
527
+ // Integration with LocaleResolutionOptions
528
+ // =============================================================================
529
+
530
+ /**
531
+ * Builds LocaleResolutionOptions from a locale and fallback configuration.
532
+ *
533
+ * This function creates the options object needed by `getLocalizedValue` and
534
+ * `resolveContentData` from the locale fallback configuration.
535
+ *
536
+ * @param locale - The requested locale
537
+ * @param config - The fallback configuration
538
+ * @returns LocaleResolutionOptions for use with locale resolution functions
539
+ *
540
+ * @example
541
+ * ```typescript
542
+ * const config: LocaleFallbackConfig = {
543
+ * defaultLocale: "en-US",
544
+ * fallbackChains: {
545
+ * "es-MX": ["es-ES"],
546
+ * },
547
+ * };
548
+ *
549
+ * const options = buildLocaleResolutionOptions("es-MX", config);
550
+ * // Returns: {
551
+ * // locale: "es-MX",
552
+ * // fallbackChain: ["es-ES", "en-US"],
553
+ * // defaultLocale: "en-US"
554
+ * // }
555
+ *
556
+ * // Use with getLocalizedValue
557
+ * const result = getLocalizedValue(value, options);
558
+ * ```
559
+ */
560
+ export function buildLocaleResolutionOptions(
561
+ locale: LocaleCode,
562
+ config: LocaleFallbackConfig = DEFAULT_FALLBACK_CONFIG
563
+ ): LocaleResolutionOptions {
564
+ const resolved = resolveFallbackChain(locale, config);
565
+
566
+ return {
567
+ locale,
568
+ fallbackChain: resolved.fallbackChain,
569
+ defaultLocale: resolved.defaultLocale,
570
+ };
571
+ }
572
+
573
+ // =============================================================================
574
+ // Common Fallback Chain Presets
575
+ // =============================================================================
576
+
577
+ /**
578
+ * Preset fallback configurations for common localization scenarios.
579
+ */
580
+ export const FALLBACK_PRESETS = {
581
+ /**
582
+ * Spanish locale family fallback chain.
583
+ * Regional Spanish variants fall back to Spain Spanish, then English.
584
+ */
585
+ spanish: {
586
+ "es-MX": ["es-ES", "en"], // Mexican Spanish
587
+ "es-AR": ["es-ES", "en"], // Argentine Spanish
588
+ "es-CO": ["es-ES", "en"], // Colombian Spanish
589
+ "es-CL": ["es-ES", "en"], // Chilean Spanish
590
+ "es-PE": ["es-ES", "en"], // Peruvian Spanish
591
+ "es-VE": ["es-ES", "en"], // Venezuelan Spanish
592
+ "es-ES": ["en"], // Spain Spanish
593
+ },
594
+
595
+ /**
596
+ * Portuguese locale family fallback chain.
597
+ * Brazilian Portuguese falls back to Portugal Portuguese, then English.
598
+ */
599
+ portuguese: {
600
+ "pt-BR": ["pt-PT", "en"], // Brazilian Portuguese
601
+ "pt-PT": ["en"], // Portugal Portuguese
602
+ },
603
+
604
+ /**
605
+ * Chinese locale family fallback chain.
606
+ * Simplified and Traditional Chinese with regional variants.
607
+ */
608
+ chinese: {
609
+ "zh-Hans-CN": ["zh-Hans", "zh", "en"], // Simplified Chinese (China)
610
+ "zh-Hans-SG": ["zh-Hans", "zh", "en"], // Simplified Chinese (Singapore)
611
+ "zh-Hant-TW": ["zh-Hant", "zh", "en"], // Traditional Chinese (Taiwan)
612
+ "zh-Hant-HK": ["zh-Hant", "zh", "en"], // Traditional Chinese (Hong Kong)
613
+ "zh-Hans": ["zh", "en"], // Simplified Chinese
614
+ "zh-Hant": ["zh", "en"], // Traditional Chinese
615
+ },
616
+
617
+ /**
618
+ * French locale family fallback chain.
619
+ */
620
+ french: {
621
+ "fr-CA": ["fr-FR", "en"], // Canadian French
622
+ "fr-BE": ["fr-FR", "en"], // Belgian French
623
+ "fr-CH": ["fr-FR", "en"], // Swiss French
624
+ "fr-FR": ["en"], // France French
625
+ },
626
+
627
+ /**
628
+ * German locale family fallback chain.
629
+ */
630
+ german: {
631
+ "de-AT": ["de-DE", "en"], // Austrian German
632
+ "de-CH": ["de-DE", "en"], // Swiss German
633
+ "de-DE": ["en"], // Germany German
634
+ },
635
+
636
+ /**
637
+ * English locale family fallback chain.
638
+ */
639
+ english: {
640
+ "en-GB": ["en-US", "en"], // British English
641
+ "en-AU": ["en-GB", "en-US", "en"], // Australian English
642
+ "en-CA": ["en-US", "en"], // Canadian English
643
+ "en-NZ": ["en-AU", "en-GB", "en"], // New Zealand English
644
+ "en-US": ["en"], // US English
645
+ },
646
+ } as const;
647
+
648
+ /**
649
+ * Merges multiple fallback chain presets into a single configuration.
650
+ *
651
+ * @param presets - Array of preset names to merge
652
+ * @returns Combined fallback chains
653
+ *
654
+ * @example
655
+ * ```typescript
656
+ * const chains = mergeFallbackPresets(["spanish", "portuguese"]);
657
+ * // Returns merged chains for both Spanish and Portuguese locales
658
+ * ```
659
+ */
660
+ export function mergeFallbackPresets(
661
+ presets: (keyof typeof FALLBACK_PRESETS)[]
662
+ ): Record<LocaleCode, LocaleCode[]> {
663
+ const merged: Record<LocaleCode, LocaleCode[]> = {};
664
+
665
+ for (const presetName of presets) {
666
+ const preset = FALLBACK_PRESETS[presetName];
667
+ if (preset) {
668
+ Object.assign(merged, preset);
669
+ }
670
+ }
671
+
672
+ return merged;
673
+ }