@timbenniks/contentstack-platform-sdk 0.1.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 (244) hide show
  1. package/dist/auth/index.cjs +607 -0
  2. package/dist/auth/index.cjs.map +1 -0
  3. package/dist/auth/index.d.cts +108 -0
  4. package/dist/auth/index.d.ts +108 -0
  5. package/dist/auth/index.mjs +25 -0
  6. package/dist/auth/index.mjs.map +1 -0
  7. package/dist/brandkit/index.cjs +525 -0
  8. package/dist/brandkit/index.cjs.map +1 -0
  9. package/dist/brandkit/index.d.cts +95 -0
  10. package/dist/brandkit/index.d.ts +95 -0
  11. package/dist/brandkit/index.mjs +11 -0
  12. package/dist/brandkit/index.mjs.map +1 -0
  13. package/dist/chunk-3C6J2BDB.mjs +84 -0
  14. package/dist/chunk-3C6J2BDB.mjs.map +1 -0
  15. package/dist/chunk-3KE63N3I.mjs +64 -0
  16. package/dist/chunk-3KE63N3I.mjs.map +1 -0
  17. package/dist/chunk-4CJ4IVPJ.mjs +212 -0
  18. package/dist/chunk-4CJ4IVPJ.mjs.map +1 -0
  19. package/dist/chunk-4JFUI7MJ.mjs +368 -0
  20. package/dist/chunk-4JFUI7MJ.mjs.map +1 -0
  21. package/dist/chunk-7VFGD32I.mjs +26 -0
  22. package/dist/chunk-7VFGD32I.mjs.map +1 -0
  23. package/dist/chunk-ARPJDW3A.mjs +44 -0
  24. package/dist/chunk-ARPJDW3A.mjs.map +1 -0
  25. package/dist/chunk-AVJHCFRK.mjs +52 -0
  26. package/dist/chunk-AVJHCFRK.mjs.map +1 -0
  27. package/dist/chunk-BK2IBTQS.mjs +131 -0
  28. package/dist/chunk-BK2IBTQS.mjs.map +1 -0
  29. package/dist/chunk-BUZ6CQHE.mjs +75 -0
  30. package/dist/chunk-BUZ6CQHE.mjs.map +1 -0
  31. package/dist/chunk-CKMAOWBQ.mjs +379 -0
  32. package/dist/chunk-CKMAOWBQ.mjs.map +1 -0
  33. package/dist/chunk-DJQLN4TR.mjs +1 -0
  34. package/dist/chunk-DJQLN4TR.mjs.map +1 -0
  35. package/dist/chunk-DMERADWM.mjs +67 -0
  36. package/dist/chunk-DMERADWM.mjs.map +1 -0
  37. package/dist/chunk-EREPKWTW.mjs +926 -0
  38. package/dist/chunk-EREPKWTW.mjs.map +1 -0
  39. package/dist/chunk-FQP4PB5X.mjs +88 -0
  40. package/dist/chunk-FQP4PB5X.mjs.map +1 -0
  41. package/dist/chunk-GNPQJBFX.mjs +144 -0
  42. package/dist/chunk-GNPQJBFX.mjs.map +1 -0
  43. package/dist/chunk-GOSB24M6.mjs +87 -0
  44. package/dist/chunk-GOSB24M6.mjs.map +1 -0
  45. package/dist/chunk-JL2E3EOT.mjs +255 -0
  46. package/dist/chunk-JL2E3EOT.mjs.map +1 -0
  47. package/dist/chunk-JYGZBKTH.mjs +222 -0
  48. package/dist/chunk-JYGZBKTH.mjs.map +1 -0
  49. package/dist/chunk-JZE2W7VW.mjs +52 -0
  50. package/dist/chunk-JZE2W7VW.mjs.map +1 -0
  51. package/dist/chunk-K76DKSHJ.mjs +18 -0
  52. package/dist/chunk-K76DKSHJ.mjs.map +1 -0
  53. package/dist/chunk-KLVIROVU.mjs +232 -0
  54. package/dist/chunk-KLVIROVU.mjs.map +1 -0
  55. package/dist/chunk-LPVVA5J3.mjs +18 -0
  56. package/dist/chunk-LPVVA5J3.mjs.map +1 -0
  57. package/dist/chunk-NKLOZ5VI.mjs +112 -0
  58. package/dist/chunk-NKLOZ5VI.mjs.map +1 -0
  59. package/dist/chunk-QGA4WBDC.mjs +7 -0
  60. package/dist/chunk-QGA4WBDC.mjs.map +1 -0
  61. package/dist/chunk-QW7TVYOA.mjs +56 -0
  62. package/dist/chunk-QW7TVYOA.mjs.map +1 -0
  63. package/dist/chunk-SU5QEKYW.mjs +83 -0
  64. package/dist/chunk-SU5QEKYW.mjs.map +1 -0
  65. package/dist/chunk-T5A2E2RI.mjs +654 -0
  66. package/dist/chunk-T5A2E2RI.mjs.map +1 -0
  67. package/dist/chunk-T5OIJQK7.mjs +116 -0
  68. package/dist/chunk-T5OIJQK7.mjs.map +1 -0
  69. package/dist/chunk-VW7DD6HV.mjs +253 -0
  70. package/dist/chunk-VW7DD6HV.mjs.map +1 -0
  71. package/dist/chunk-XH7NLHGW.mjs +133 -0
  72. package/dist/chunk-XH7NLHGW.mjs.map +1 -0
  73. package/dist/client-DJ5haQGd.d.cts +22 -0
  74. package/dist/client-DwVGVSQz.d.ts +22 -0
  75. package/dist/cma/index.cjs +1349 -0
  76. package/dist/cma/index.cjs.map +1 -0
  77. package/dist/cma/index.d.cts +22 -0
  78. package/dist/cma/index.d.ts +22 -0
  79. package/dist/cma/index.mjs +70 -0
  80. package/dist/cma/index.mjs.map +1 -0
  81. package/dist/errors-CAw-IRCP.d.cts +65 -0
  82. package/dist/errors-CAw-IRCP.d.ts +65 -0
  83. package/dist/generative-ai/index.cjs +401 -0
  84. package/dist/generative-ai/index.cjs.map +1 -0
  85. package/dist/generative-ai/index.d.cts +31 -0
  86. package/dist/generative-ai/index.d.ts +31 -0
  87. package/dist/generative-ai/index.mjs +10 -0
  88. package/dist/generative-ai/index.mjs.map +1 -0
  89. package/dist/images/index.cjs +185 -0
  90. package/dist/images/index.cjs.map +1 -0
  91. package/dist/images/index.d.cts +27 -0
  92. package/dist/images/index.d.ts +27 -0
  93. package/dist/images/index.mjs +8 -0
  94. package/dist/images/index.mjs.map +1 -0
  95. package/dist/index.cjs +2909 -0
  96. package/dist/index.cjs.map +1 -0
  97. package/dist/index.d.cts +30 -0
  98. package/dist/index.d.ts +30 -0
  99. package/dist/index.mjs +153 -0
  100. package/dist/index.mjs.map +1 -0
  101. package/dist/knowledge-vault/index.cjs +413 -0
  102. package/dist/knowledge-vault/index.cjs.map +1 -0
  103. package/dist/knowledge-vault/index.d.cts +49 -0
  104. package/dist/knowledge-vault/index.d.ts +49 -0
  105. package/dist/knowledge-vault/index.mjs +10 -0
  106. package/dist/knowledge-vault/index.mjs.map +1 -0
  107. package/dist/launch/index.cjs +624 -0
  108. package/dist/launch/index.cjs.map +1 -0
  109. package/dist/launch/index.d.cts +169 -0
  110. package/dist/launch/index.d.ts +169 -0
  111. package/dist/launch/index.mjs +11 -0
  112. package/dist/launch/index.mjs.map +1 -0
  113. package/dist/react/auth/index.cjs +113 -0
  114. package/dist/react/auth/index.cjs.map +1 -0
  115. package/dist/react/auth/index.d.cts +33 -0
  116. package/dist/react/auth/index.d.ts +33 -0
  117. package/dist/react/auth/index.mjs +13 -0
  118. package/dist/react/auth/index.mjs.map +1 -0
  119. package/dist/react/content/index.cjs +113 -0
  120. package/dist/react/content/index.cjs.map +1 -0
  121. package/dist/react/content/index.d.cts +25 -0
  122. package/dist/react/content/index.d.ts +25 -0
  123. package/dist/react/content/index.mjs +7 -0
  124. package/dist/react/content/index.mjs.map +1 -0
  125. package/dist/react/hooks/index.cjs +2097 -0
  126. package/dist/react/hooks/index.cjs.map +1 -0
  127. package/dist/react/hooks/index.d.cts +77 -0
  128. package/dist/react/hooks/index.d.ts +77 -0
  129. package/dist/react/hooks/index.mjs +46 -0
  130. package/dist/react/hooks/index.mjs.map +1 -0
  131. package/dist/react/index.cjs +2307 -0
  132. package/dist/react/index.cjs.map +1 -0
  133. package/dist/react/index.d.cts +16 -0
  134. package/dist/react/index.d.ts +16 -0
  135. package/dist/react/index.mjs +67 -0
  136. package/dist/react/index.mjs.map +1 -0
  137. package/dist/react/provider/index.cjs +83 -0
  138. package/dist/react/provider/index.cjs.map +1 -0
  139. package/dist/react/provider/index.d.cts +30 -0
  140. package/dist/react/provider/index.d.ts +30 -0
  141. package/dist/react/provider/index.mjs +11 -0
  142. package/dist/react/provider/index.mjs.map +1 -0
  143. package/dist/regions/index.cjs +171 -0
  144. package/dist/regions/index.cjs.map +1 -0
  145. package/dist/regions/index.d.cts +55 -0
  146. package/dist/regions/index.d.ts +55 -0
  147. package/dist/regions/index.mjs +13 -0
  148. package/dist/regions/index.mjs.map +1 -0
  149. package/dist/request-builders-BxeolQIw.d.ts +735 -0
  150. package/dist/request-builders-C2IG1LUo.d.cts +735 -0
  151. package/dist/rte/index.cjs +683 -0
  152. package/dist/rte/index.cjs.map +1 -0
  153. package/dist/rte/index.d.cts +33 -0
  154. package/dist/rte/index.d.ts +33 -0
  155. package/dist/rte/index.mjs +17 -0
  156. package/dist/rte/index.mjs.map +1 -0
  157. package/dist/server/index.cjs +917 -0
  158. package/dist/server/index.cjs.map +1 -0
  159. package/dist/server/index.d.cts +6 -0
  160. package/dist/server/index.d.ts +6 -0
  161. package/dist/server/index.mjs +45 -0
  162. package/dist/server/index.mjs.map +1 -0
  163. package/dist/server/middleware/index.cjs +614 -0
  164. package/dist/server/middleware/index.cjs.map +1 -0
  165. package/dist/server/middleware/index.d.cts +77 -0
  166. package/dist/server/middleware/index.d.ts +77 -0
  167. package/dist/server/middleware/index.mjs +27 -0
  168. package/dist/server/middleware/index.mjs.map +1 -0
  169. package/dist/server/proxy/index.cjs +329 -0
  170. package/dist/server/proxy/index.cjs.map +1 -0
  171. package/dist/server/proxy/index.d.cts +143 -0
  172. package/dist/server/proxy/index.d.ts +143 -0
  173. package/dist/server/proxy/index.mjs +29 -0
  174. package/dist/server/proxy/index.mjs.map +1 -0
  175. package/dist/server/webhooks/index.cjs +131 -0
  176. package/dist/server/webhooks/index.cjs.map +1 -0
  177. package/dist/server/webhooks/index.d.cts +230 -0
  178. package/dist/server/webhooks/index.d.ts +230 -0
  179. package/dist/server/webhooks/index.mjs +23 -0
  180. package/dist/server/webhooks/index.mjs.map +1 -0
  181. package/dist/types-6D9VR7pT.d.cts +26 -0
  182. package/dist/types-AelT0rFJ.d.cts +21 -0
  183. package/dist/types-AelT0rFJ.d.ts +21 -0
  184. package/dist/types-Bu5yCgmw.d.ts +26 -0
  185. package/dist/types-DgixK-ll.d.cts +23 -0
  186. package/dist/types-DgixK-ll.d.ts +23 -0
  187. package/dist/types-DrMwdlH9.d.cts +245 -0
  188. package/dist/types-DrMwdlH9.d.ts +245 -0
  189. package/dist/ui/css/index.cjs +31 -0
  190. package/dist/ui/css/index.cjs.map +1 -0
  191. package/dist/ui/css/index.d.cts +15 -0
  192. package/dist/ui/css/index.d.ts +15 -0
  193. package/dist/ui/css/index.mjs +7 -0
  194. package/dist/ui/css/index.mjs.map +1 -0
  195. package/dist/ui/index.cjs +368 -0
  196. package/dist/ui/index.cjs.map +1 -0
  197. package/dist/ui/index.d.cts +4 -0
  198. package/dist/ui/index.d.ts +4 -0
  199. package/dist/ui/index.mjs +33 -0
  200. package/dist/ui/index.mjs.map +1 -0
  201. package/dist/ui/theme/index.cjs +105 -0
  202. package/dist/ui/theme/index.cjs.map +1 -0
  203. package/dist/ui/theme/index.d.cts +33 -0
  204. package/dist/ui/theme/index.d.ts +33 -0
  205. package/dist/ui/theme/index.mjs +15 -0
  206. package/dist/ui/theme/index.mjs.map +1 -0
  207. package/dist/ui/tokens/index.cjs +286 -0
  208. package/dist/ui/tokens/index.cjs.map +1 -0
  209. package/dist/ui/tokens/index.d.cts +54 -0
  210. package/dist/ui/tokens/index.d.ts +54 -0
  211. package/dist/ui/tokens/index.mjs +17 -0
  212. package/dist/ui/tokens/index.mjs.map +1 -0
  213. package/dist/ui/tokens.css +408 -0
  214. package/dist/vue/auth/index.cjs +141 -0
  215. package/dist/vue/auth/index.cjs.map +1 -0
  216. package/dist/vue/auth/index.d.cts +78 -0
  217. package/dist/vue/auth/index.d.ts +78 -0
  218. package/dist/vue/auth/index.mjs +13 -0
  219. package/dist/vue/auth/index.mjs.map +1 -0
  220. package/dist/vue/composables/index.cjs +2108 -0
  221. package/dist/vue/composables/index.cjs.map +1 -0
  222. package/dist/vue/composables/index.d.cts +78 -0
  223. package/dist/vue/composables/index.d.ts +78 -0
  224. package/dist/vue/composables/index.mjs +46 -0
  225. package/dist/vue/composables/index.mjs.map +1 -0
  226. package/dist/vue/content/index.cjs +142 -0
  227. package/dist/vue/content/index.cjs.map +1 -0
  228. package/dist/vue/content/index.d.cts +47 -0
  229. package/dist/vue/content/index.d.ts +47 -0
  230. package/dist/vue/content/index.mjs +7 -0
  231. package/dist/vue/content/index.mjs.map +1 -0
  232. package/dist/vue/index.cjs +2389 -0
  233. package/dist/vue/index.cjs.map +1 -0
  234. package/dist/vue/index.d.cts +16 -0
  235. package/dist/vue/index.d.ts +16 -0
  236. package/dist/vue/index.mjs +69 -0
  237. package/dist/vue/index.mjs.map +1 -0
  238. package/dist/vue/provider/index.cjs +97 -0
  239. package/dist/vue/provider/index.cjs.map +1 -0
  240. package/dist/vue/provider/index.d.cts +90 -0
  241. package/dist/vue/provider/index.d.ts +90 -0
  242. package/dist/vue/provider/index.mjs +13 -0
  243. package/dist/vue/provider/index.mjs.map +1 -0
  244. package/package.json +195 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/proxy/index.ts","../../../src/regions/endpoints.ts","../../../src/regions/resolver.ts","../../../src/server/proxy/proxy-base.ts","../../../src/server/proxy/rate-limiter.ts","../../../src/server/proxy/scope-guard.ts","../../../src/server/proxy/cma-proxy.ts","../../../src/server/proxy/launch-proxy.ts","../../../src/server/proxy/brandkit-proxy.ts"],"sourcesContent":["export type { CMAProxyConfig, CMAScope } from \"./types.js\"\nexport { createCMAProxy } from \"./cma-proxy.js\"\nexport { resolveScope, checkScope } from \"./scope-guard.js\"\nexport type { LaunchProxyConfig } from \"./launch-proxy.js\"\nexport { createLaunchProxy } from \"./launch-proxy.js\"\nexport type { BrandKitProxyConfig } from \"./brandkit-proxy.js\"\nexport { createBrandKitProxy } from \"./brandkit-proxy.js\"\n","import {\n type ContentstackEndpoints as UpstreamEndpoints,\n getContentstackEndpoints,\n getRegionForString,\n} from \"@timbenniks/contentstack-endpoints\"\nimport type { ContentstackEndpoints, ContentstackRegion } from \"./resolver.js\"\n\n/** Brand Kit endpoints not available in upstream package — maintained locally */\nconst BRAND_KIT_URLS: Record<ContentstackRegion, { brandKit: string; brandKitAI: string }> = {\n us: {\n brandKit: \"https://brand-kits-api.contentstack.com\",\n brandKitAI: \"https://ai.contentstack.com/brand-kits\",\n },\n eu: {\n brandKit: \"https://eu-brand-kits-api.contentstack.com\",\n brandKitAI: \"https://eu-ai.contentstack.com/brand-kits\",\n },\n au: {\n brandKit: \"https://au-brand-kits-api.contentstack.com\",\n brandKitAI: \"https://au-ai.contentstack.com/brand-kits\",\n },\n \"azure-na\": {\n brandKit: \"https://azure-na-brand-kits-api.contentstack.com\",\n brandKitAI: \"https://azure-na-ai.contentstack.com/brand-kits\",\n },\n \"azure-eu\": {\n brandKit: \"https://azure-eu-brand-kits-api.contentstack.com\",\n brandKitAI: \"https://azure-eu-ai.contentstack.com/brand-kits\",\n },\n \"gcp-na\": {\n brandKit: \"https://gcp-na-brand-kits-api.contentstack.com\",\n brandKitAI: \"https://gcp-na-ai.contentstack.com/brand-kits\",\n },\n \"gcp-eu\": {\n brandKit: \"https://gcp-eu-brand-kits-api.contentstack.com\",\n brandKitAI: \"https://gcp-eu-ai.contentstack.com/brand-kits\",\n },\n}\n\nfunction mapEndpoints(\n upstream: UpstreamEndpoints,\n region: ContentstackRegion,\n hostsOnly: boolean,\n): ContentstackEndpoints {\n const bk = BRAND_KIT_URLS[region]\n const stripProtocol = (url: string) => url.replace(/^https?:\\/\\//, \"\")\n\n return Object.freeze({\n cma: upstream.contentManagement ?? \"\",\n cda: upstream.contentDelivery ?? \"\",\n graphql: upstream.graphqlDelivery ?? \"\",\n images: upstream.images ?? \"\",\n app: upstream.application ?? \"\",\n preview: upstream.preview ?? \"\",\n graphqlPreview: upstream.graphqlPreview ?? \"\",\n launch: upstream.launch ?? \"\",\n personalizeEdge: upstream.personalizeEdge ?? \"\",\n brandKit: hostsOnly ? stripProtocol(bk.brandKit) : bk.brandKit,\n brandKitAI: hostsOnly ? stripProtocol(bk.brandKitAI) : bk.brandKitAI,\n })\n}\n\nconst ALL_REGIONS: ContentstackRegion[] = [\n \"us\",\n \"eu\",\n \"au\",\n \"azure-na\",\n \"azure-eu\",\n \"gcp-na\",\n \"gcp-eu\",\n]\n\nfunction buildEndpointMap(): Record<ContentstackRegion, ContentstackEndpoints> {\n const map = {} as Record<ContentstackRegion, ContentstackEndpoints>\n for (const region of ALL_REGIONS) {\n map[region] = mapEndpoints(getContentstackEndpoints(region), region, false)\n }\n return Object.freeze(map)\n}\n\nfunction buildHostMap(): Record<ContentstackRegion, ContentstackEndpoints> {\n const map = {} as Record<ContentstackRegion, ContentstackEndpoints>\n for (const region of ALL_REGIONS) {\n map[region] = mapEndpoints(getContentstackEndpoints(region, true), region, true)\n }\n return Object.freeze(map)\n}\n\nexport const ENDPOINT_MAP = buildEndpointMap()\nexport const HOST_MAP = buildHostMap()\n\n/** Check if a string is a valid region via the upstream package */\nexport function isValidRegion(input: string): boolean {\n return getRegionForString(input) !== undefined\n}\n\n/** Map of extra aliases our SDK supports beyond what the upstream package handles */\nexport const EXTRA_ALIASES: Record<string, ContentstackRegion> = {\n \"north-america\": \"us\",\n europe: \"eu\",\n australia: \"au\",\n}\n","import { ContentstackConfigError } from \"../http/errors.js\"\nimport { ENDPOINT_MAP, EXTRA_ALIASES, HOST_MAP, isValidRegion } from \"./endpoints.js\"\n\n/** All 7 Contentstack regions */\nexport type ContentstackRegion = \"us\" | \"eu\" | \"au\" | \"azure-na\" | \"azure-eu\" | \"gcp-na\" | \"gcp-eu\"\n\n/** Resolved endpoint URLs for a region */\nexport interface ContentstackEndpoints {\n /** CMA base URL, e.g. \"https://api.contentstack.io\" */\n cma: string\n /** CDA REST base URL, e.g. \"https://cdn.contentstack.io\" */\n cda: string\n /** GraphQL CDA endpoint */\n graphql: string\n /** Asset/image delivery base URL */\n images: string\n /** Application URL (for OAuth), e.g. \"https://app.contentstack.com\" */\n app: string\n /** Preview API base URL */\n preview: string\n /** GraphQL preview endpoint */\n graphqlPreview: string\n /** Launch API base URL */\n launch: string\n /** Personalize edge endpoint */\n personalizeEdge: string\n /** Brand Kit Management API base URL */\n brandKit: string\n /** Brand Kit GenAI and Knowledge Vault base URL */\n brandKitAI: string\n}\n\nconst VALID_REGIONS = new Set<string>(Object.keys(ENDPOINT_MAP))\n\n/**\n * Resolve all API endpoints for a Contentstack region.\n *\n * @example\n * ```ts\n * const endpoints = resolveEndpoints(\"eu\");\n * // endpoints.cma === \"https://eu-api.contentstack.com\"\n * // endpoints.app === \"https://eu-app.contentstack.com\"\n * ```\n */\nexport function resolveEndpoints(region: ContentstackRegion): ContentstackEndpoints {\n return ENDPOINT_MAP[region]\n}\n\n/**\n * Resolve endpoints with https:// stripped (for SDK host parameters).\n *\n * @example\n * ```ts\n * const hosts = resolveHosts(\"eu\");\n * // hosts.cda === \"eu-cdn.contentstack.com\"\n * ```\n */\nexport function resolveHosts(region: ContentstackRegion): ContentstackEndpoints {\n return HOST_MAP[region]\n}\n\n/**\n * Normalize region aliases: \"na\" → \"us\", \"NA\" → \"us\", etc.\n * Case-insensitive. Throws ContentstackConfigError for unknown regions.\n */\nexport function normalizeRegion(input: string): ContentstackRegion {\n const lower = input.toLowerCase().trim()\n\n if (VALID_REGIONS.has(lower)) {\n return lower as ContentstackRegion\n }\n\n // Check extra aliases our SDK supports (north-america, europe, australia)\n const extraAlias = EXTRA_ALIASES[lower]\n if (extraAlias) {\n return extraAlias\n }\n\n // Check aliases handled by the upstream package (na, us, aws-na, etc.)\n if (isValidRegion(lower)) {\n // The upstream package recognized it — map back to our canonical region\n // \"na\" and \"us\" both map to the NA region which we call \"us\"\n if (lower === \"na\" || lower === \"aws-na\" || lower === \"aws_na\") return \"us\"\n if (lower === \"aws-eu\" || lower === \"aws_eu\") return \"eu\"\n if (lower === \"aws-au\" || lower === \"aws_au\") return \"au\"\n if (lower === \"azure_na\") return \"azure-na\"\n if (lower === \"azure_eu\") return \"azure-eu\"\n if (lower === \"gcp_na\") return \"gcp-na\"\n if (lower === \"gcp_eu\") return \"gcp-eu\"\n }\n\n const validRegions = [...VALID_REGIONS].join(\", \")\n const validAliases = [...Object.keys(EXTRA_ALIASES), \"na\", \"aws-na\", \"aws-eu\", \"aws-au\"].join(\n \", \",\n )\n throw new ContentstackConfigError(\n `Unknown region \"${input}\". Valid regions: ${validRegions}. Aliases: ${validAliases}.`,\n )\n}\n\nexport { ContentstackConfigError }\n","/**\n * Shared proxy infrastructure for Contentstack API proxies.\n *\n * Both the CMA proxy and Launch proxy build on these helpers to avoid\n * duplicating auth checks, URL parsing, body extraction, and fetch logic.\n */\n\nexport interface BaseProxyConfig {\n getAccessToken: (request: Request) => Promise<string | null>\n basePath: string\n timeout: number\n}\n\nexport interface ProxyRequestContext {\n token: string\n apiPath: string\n search: string\n method: string\n body: ArrayBuffer | undefined\n request: Request\n}\n\n/** Return a JSON error response with the given message and HTTP status. */\nexport function jsonErrorResponse(error: string, status: number): Response {\n return new Response(JSON.stringify({ error }), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n })\n}\n\n/**\n * Create the shared proxy pipeline: auth check → URL parse → body extract.\n *\n * The `handleRequest` callback receives a validated context and is responsible\n * for building headers, constructing the target URL, and forwarding the request.\n */\nexport function createBaseProxy(\n config: BaseProxyConfig,\n handleRequest: (ctx: ProxyRequestContext) => Promise<Response>,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n const token = await config.getAccessToken(request)\n if (!token) {\n return jsonErrorResponse(\"Unauthorized\", 401)\n }\n\n const url = new URL(request.url)\n const apiPath = url.pathname.replace(config.basePath, \"\")\n\n const body =\n [\"GET\", \"HEAD\"].includes(request.method) || request.body === null\n ? undefined\n : await request.arrayBuffer()\n\n return handleRequest({\n token,\n apiPath,\n search: url.search,\n method: request.method,\n body,\n request,\n })\n }\n}\n\n/**\n * Forward a request to an upstream API and stream the response back.\n *\n * Returns a 502 \"Bad Gateway\" response on any fetch failure (network error, timeout).\n */\nexport async function forwardRequest(\n url: string,\n method: string,\n headers: Record<string, string>,\n body: ArrayBuffer | undefined,\n timeout: number,\n): Promise<Response> {\n try {\n const upstream = await fetch(url, {\n method,\n headers,\n body,\n signal: AbortSignal.timeout(timeout),\n })\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\": upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n })\n } catch {\n return jsonErrorResponse(\"Bad Gateway\", 502)\n }\n}\n","interface RateWindow {\n count: number\n windowStart: number\n}\n\n/**\n * Create a simple in-memory sliding window rate limiter.\n *\n * Each unique key (typically an access token) gets its own counter\n * that resets after the window expires.\n *\n * @param maxRequests - Maximum requests allowed per window\n * @param windowMs - Window duration in milliseconds (default: 60000)\n */\nexport function createRateLimiter(maxRequests: number, windowMs = 60_000) {\n const windows = new Map<string, RateWindow>()\n\n return {\n /**\n * Check if the request is within rate limits.\n * @returns `true` if the request is allowed, `false` if rate limited.\n */\n check(key: string): boolean {\n const now = Date.now()\n const window = windows.get(key)\n\n // Clean stale entries on each check\n for (const [k, w] of windows) {\n if (now - w.windowStart > windowMs) {\n windows.delete(k)\n }\n }\n\n if (!window || now - window.windowStart > windowMs) {\n windows.set(key, { count: 1, windowStart: now })\n return true\n }\n\n window.count++\n return window.count <= maxRequests\n },\n }\n}\n","import type { CMAScope } from \"./types.js\"\n\nconst READ_METHODS = new Set([\"GET\", \"HEAD\"])\n\n/**\n * Resolve the required CMA scope for a given HTTP method and path.\n *\n * Path matching checks for known segments. The order matters:\n * `/entries` is checked before `/content_types` because entry URLs\n * like `/content_types/blog/entries` contain both.\n *\n * @returns The required scope, or `null` if the path is unrecognized.\n */\nexport function resolveScope(method: string, path: string): CMAScope | null {\n const isRead = READ_METHODS.has(method.toUpperCase())\n const suffix = isRead ? \":read\" : \":write\"\n const segments = path.split(\"/\")\n\n if (segments.includes(\"entries\")) return `entries${suffix}` as CMAScope\n if (segments.includes(\"content_types\")) return `content-types${suffix}` as CMAScope\n if (segments.includes(\"assets\")) return `assets${suffix}` as CMAScope\n if (segments.includes(\"environments\")) return \"environments:read\"\n if (segments.includes(\"locales\")) return \"locales:read\"\n if (segments.includes(\"releases\")) return `releases${suffix}` as CMAScope\n if (segments.includes(\"taxonomies\")) return `taxonomies${suffix}` as CMAScope\n if (segments.includes(\"workflows\")) return `workflows${suffix}` as CMAScope\n if (segments.includes(\"webhooks\")) return `webhooks${suffix}` as CMAScope\n\n return null\n}\n\n/**\n * Check whether a required scope is present in the allowed scopes list.\n *\n * @returns An error message if the scope is not allowed, or `null` if permitted.\n */\nexport function checkScope(required: CMAScope, allowed: CMAScope[]): string | null {\n if (allowed.includes(required)) return null\n return `Scope \"${required}\" is not allowed. Allowed scopes: ${allowed.join(\", \")}`\n}\n","import { resolveEndpoints } from \"../../index.js\"\nimport { createBaseProxy, forwardRequest, jsonErrorResponse } from \"./proxy-base.js\"\nimport { createRateLimiter } from \"./rate-limiter.js\"\nimport { checkScope, resolveScope } from \"./scope-guard.js\"\nimport type { CMAProxyConfig } from \"./types.js\"\n\n/**\n * Create a CMA proxy handler that forwards requests to Contentstack.\n *\n * The returned function accepts a standard `Request` and returns a `Response`,\n * making it compatible with Next.js route handlers, Deno/Bun servers, and\n * any framework that uses the Web API Request/Response model.\n *\n * @example\n * ```ts\n * // app/api/cma/[...path]/route.ts\n * const proxy = createCMAProxy({\n * region: \"us\",\n * apiKey: \"your-api-key\",\n * getAccessToken: async (req) => {\n * const session = await auth()\n * return session?.accessToken ?? null\n * },\n * })\n *\n * export const GET = proxy\n * export const POST = proxy\n * export const PUT = proxy\n * export const DELETE = proxy\n * ```\n */\nexport function createCMAProxy(config: CMAProxyConfig): (request: Request) => Promise<Response> {\n const endpoints = resolveEndpoints(config.region)\n const cmaBase = `${endpoints.cma}/v3`\n const timeout = config.timeout ?? 30_000\n const rateLimiter = config.rateLimit ? createRateLimiter(config.rateLimit) : null\n\n return createBaseProxy(\n {\n getAccessToken: config.getAccessToken,\n basePath: config.basePath ?? \"/api/cma\",\n timeout,\n },\n async (ctx) => {\n if (rateLimiter && !rateLimiter.check(ctx.token)) {\n return jsonErrorResponse(\"Too Many Requests\", 429)\n }\n\n if (config.allowedScopes) {\n const scope = resolveScope(ctx.method, ctx.apiPath)\n if (!scope) {\n if ((config.unmappedScopeBehavior ?? \"deny\") === \"deny\") {\n return jsonErrorResponse(\n `No scope mapping found for \"${ctx.method} ${ctx.apiPath}\". Add a mapping or set unmappedScopeBehavior: \"allow\".`,\n 403,\n )\n }\n } else {\n const rejection = checkScope(scope, config.allowedScopes)\n if (rejection) {\n return jsonErrorResponse(rejection, 403)\n }\n }\n }\n\n const headers: Record<string, string> = {\n api_key: config.apiKey,\n authorization: `Bearer ${ctx.token}`,\n }\n const contentType = ctx.request.headers.get(\"content-type\")\n if (contentType) {\n headers[\"content-type\"] = contentType\n }\n\n return forwardRequest(\n cmaBase + ctx.apiPath + ctx.search,\n ctx.method,\n headers,\n ctx.body,\n timeout,\n )\n },\n )\n}\n","import { resolveEndpoints } from \"../../index.js\"\nimport type { ContentstackRegion } from \"../../index.js\"\nimport { createBaseProxy, forwardRequest } from \"./proxy-base.js\"\n\nexport interface LaunchProxyConfig {\n /** Contentstack region */\n region: ContentstackRegion\n /** Organization UID — required for all Launch API calls */\n organizationUid: string\n /** Callback to retrieve the user's access token from the request */\n getAccessToken: (request: Request) => Promise<string | null>\n /** URL prefix to strip when extracting the Launch API path (default: \"/api/launch\") */\n basePath?: string\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number\n}\n\n/**\n * Create a Launch API proxy handler that forwards requests to Contentstack Launch.\n *\n * The returned function accepts a standard `Request` and returns a `Response`,\n * making it compatible with Next.js route handlers, Deno/Bun servers, and\n * any framework that uses the Web API Request/Response model.\n *\n * @example\n * ```ts\n * // app/api/launch/[...path]/route.ts\n * const proxy = createLaunchProxy({\n * region: \"us\",\n * organizationUid: \"org-uid\",\n * getAccessToken: async () => {\n * const session = await auth()\n * return session?.accessToken ?? null\n * },\n * })\n *\n * export const GET = proxy\n * export const POST = proxy\n * export const PUT = proxy\n * export const DELETE = proxy\n * ```\n */\nexport function createLaunchProxy(\n config: LaunchProxyConfig,\n): (request: Request) => Promise<Response> {\n const endpoints = resolveEndpoints(config.region)\n const launchBase = endpoints.launch\n const timeout = config.timeout ?? 30_000\n\n return createBaseProxy(\n {\n getAccessToken: config.getAccessToken,\n basePath: config.basePath ?? \"/api/launch\",\n timeout,\n },\n async (ctx) => {\n const headers: Record<string, string> = {\n authorization: `Bearer ${ctx.token}`,\n organization_uid: config.organizationUid,\n \"content-type\": \"application/json\",\n }\n\n return forwardRequest(\n launchBase + ctx.apiPath + ctx.search,\n ctx.method,\n headers,\n ctx.body,\n timeout,\n )\n },\n )\n}\n","import { resolveEndpoints } from \"../../index.js\"\nimport type { ContentstackRegion } from \"../../index.js\"\nimport { createBaseProxy, forwardRequest, jsonErrorResponse } from \"./proxy-base.js\"\n\nexport interface BrandKitProxyConfig {\n /** Contentstack region */\n region: ContentstackRegion\n /** Organization UID — required for all Brand Kit API calls */\n organizationUid: string\n /** Brand Kit UID — required for all Brand Kit API calls */\n brandKitUid: string\n /** Callback to retrieve the user's access token from the request */\n getAccessToken: (request: Request) => Promise<string | null>\n /** URL prefix to strip when extracting the API path (default: \"/api/brandkit\") */\n basePath?: string\n /** Restrict operations: \"read\" allows GET only, \"manage\" allows all methods */\n allowedOperations?: (\"read\" | \"manage\")[]\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number\n}\n\n/**\n * Create a Brand Kit proxy handler that forwards requests to Contentstack\n * Brand Kit Management, Knowledge Vault, and Generative AI APIs.\n *\n * Routes are determined by path:\n * - Paths containing `/knowledge-vault` or `/generative-ai` → brandKitAI base URL\n * - All other paths (brand kits, voice profiles) → brandKit base URL\n *\n * @example\n * ```ts\n * // app/api/brandkit/[...path]/route.ts\n * const proxy = createBrandKitProxy({\n * region: \"us\",\n * organizationUid: \"org-uid\",\n * brandKitUid: \"bk-uid\",\n * getAccessToken: async () => {\n * const session = await auth()\n * return session?.accessToken ?? null\n * },\n * })\n *\n * export const GET = proxy\n * export const POST = proxy\n * export const PUT = proxy\n * export const DELETE = proxy\n * ```\n */\nexport function createBrandKitProxy(\n config: BrandKitProxyConfig,\n): (request: Request) => Promise<Response> {\n const endpoints = resolveEndpoints(config.region)\n const brandKitBase = endpoints.brandKit\n const brandKitAIBase = endpoints.brandKitAI\n const timeout = config.timeout ?? 30_000\n\n return createBaseProxy(\n {\n getAccessToken: config.getAccessToken,\n basePath: config.basePath ?? \"/api/brandkit\",\n timeout,\n },\n async (ctx) => {\n if (config.allowedOperations?.length) {\n const hasManage = config.allowedOperations.includes(\"manage\")\n if (!hasManage && ![\"GET\", \"HEAD\"].includes(ctx.method)) {\n return jsonErrorResponse(\"Forbidden: read-only mode\", 403)\n }\n }\n\n const headers: Record<string, string> = {\n authorization: `Bearer ${ctx.token}`,\n organization_uid: config.organizationUid,\n brand_kit_uid: config.brandKitUid,\n \"content-type\": \"application/json\",\n }\n\n const isAIPath =\n ctx.apiPath.includes(\"/knowledge-vault\") || ctx.apiPath.includes(\"/generative-ai\")\n const baseUrl = isAIPath ? brandKitAIBase : brandKitBase\n\n return forwardRequest(\n baseUrl + ctx.apiPath + ctx.search,\n ctx.method,\n headers,\n ctx.body,\n timeout,\n )\n },\n )\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,143 @@
1
+ import { ContentstackRegion } from '../../regions/index.cjs';
2
+
3
+ type CMAScope = "entries:read" | "entries:write" | "content-types:read" | "content-types:write" | "assets:read" | "assets:write" | "environments:read" | "locales:read" | "releases:read" | "releases:write" | "taxonomies:read" | "taxonomies:write" | "workflows:read" | "workflows:write" | "webhooks:read" | "webhooks:write";
4
+ interface CMAProxyConfig {
5
+ region: ContentstackRegion;
6
+ apiKey: string;
7
+ getAccessToken: (request: Request) => Promise<string | null>;
8
+ basePath?: string;
9
+ allowedScopes?: CMAScope[];
10
+ unmappedScopeBehavior?: "allow" | "deny";
11
+ rateLimit?: number;
12
+ timeout?: number;
13
+ }
14
+
15
+ /**
16
+ * Create a CMA proxy handler that forwards requests to Contentstack.
17
+ *
18
+ * The returned function accepts a standard `Request` and returns a `Response`,
19
+ * making it compatible with Next.js route handlers, Deno/Bun servers, and
20
+ * any framework that uses the Web API Request/Response model.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // app/api/cma/[...path]/route.ts
25
+ * const proxy = createCMAProxy({
26
+ * region: "us",
27
+ * apiKey: "your-api-key",
28
+ * getAccessToken: async (req) => {
29
+ * const session = await auth()
30
+ * return session?.accessToken ?? null
31
+ * },
32
+ * })
33
+ *
34
+ * export const GET = proxy
35
+ * export const POST = proxy
36
+ * export const PUT = proxy
37
+ * export const DELETE = proxy
38
+ * ```
39
+ */
40
+ declare function createCMAProxy(config: CMAProxyConfig): (request: Request) => Promise<Response>;
41
+
42
+ /**
43
+ * Resolve the required CMA scope for a given HTTP method and path.
44
+ *
45
+ * Path matching checks for known segments. The order matters:
46
+ * `/entries` is checked before `/content_types` because entry URLs
47
+ * like `/content_types/blog/entries` contain both.
48
+ *
49
+ * @returns The required scope, or `null` if the path is unrecognized.
50
+ */
51
+ declare function resolveScope(method: string, path: string): CMAScope | null;
52
+ /**
53
+ * Check whether a required scope is present in the allowed scopes list.
54
+ *
55
+ * @returns An error message if the scope is not allowed, or `null` if permitted.
56
+ */
57
+ declare function checkScope(required: CMAScope, allowed: CMAScope[]): string | null;
58
+
59
+ interface LaunchProxyConfig {
60
+ /** Contentstack region */
61
+ region: ContentstackRegion;
62
+ /** Organization UID — required for all Launch API calls */
63
+ organizationUid: string;
64
+ /** Callback to retrieve the user's access token from the request */
65
+ getAccessToken: (request: Request) => Promise<string | null>;
66
+ /** URL prefix to strip when extracting the Launch API path (default: "/api/launch") */
67
+ basePath?: string;
68
+ /** Request timeout in milliseconds (default: 30000) */
69
+ timeout?: number;
70
+ }
71
+ /**
72
+ * Create a Launch API proxy handler that forwards requests to Contentstack Launch.
73
+ *
74
+ * The returned function accepts a standard `Request` and returns a `Response`,
75
+ * making it compatible with Next.js route handlers, Deno/Bun servers, and
76
+ * any framework that uses the Web API Request/Response model.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * // app/api/launch/[...path]/route.ts
81
+ * const proxy = createLaunchProxy({
82
+ * region: "us",
83
+ * organizationUid: "org-uid",
84
+ * getAccessToken: async () => {
85
+ * const session = await auth()
86
+ * return session?.accessToken ?? null
87
+ * },
88
+ * })
89
+ *
90
+ * export const GET = proxy
91
+ * export const POST = proxy
92
+ * export const PUT = proxy
93
+ * export const DELETE = proxy
94
+ * ```
95
+ */
96
+ declare function createLaunchProxy(config: LaunchProxyConfig): (request: Request) => Promise<Response>;
97
+
98
+ interface BrandKitProxyConfig {
99
+ /** Contentstack region */
100
+ region: ContentstackRegion;
101
+ /** Organization UID — required for all Brand Kit API calls */
102
+ organizationUid: string;
103
+ /** Brand Kit UID — required for all Brand Kit API calls */
104
+ brandKitUid: string;
105
+ /** Callback to retrieve the user's access token from the request */
106
+ getAccessToken: (request: Request) => Promise<string | null>;
107
+ /** URL prefix to strip when extracting the API path (default: "/api/brandkit") */
108
+ basePath?: string;
109
+ /** Restrict operations: "read" allows GET only, "manage" allows all methods */
110
+ allowedOperations?: ("read" | "manage")[];
111
+ /** Request timeout in milliseconds (default: 30000) */
112
+ timeout?: number;
113
+ }
114
+ /**
115
+ * Create a Brand Kit proxy handler that forwards requests to Contentstack
116
+ * Brand Kit Management, Knowledge Vault, and Generative AI APIs.
117
+ *
118
+ * Routes are determined by path:
119
+ * - Paths containing `/knowledge-vault` or `/generative-ai` → brandKitAI base URL
120
+ * - All other paths (brand kits, voice profiles) → brandKit base URL
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * // app/api/brandkit/[...path]/route.ts
125
+ * const proxy = createBrandKitProxy({
126
+ * region: "us",
127
+ * organizationUid: "org-uid",
128
+ * brandKitUid: "bk-uid",
129
+ * getAccessToken: async () => {
130
+ * const session = await auth()
131
+ * return session?.accessToken ?? null
132
+ * },
133
+ * })
134
+ *
135
+ * export const GET = proxy
136
+ * export const POST = proxy
137
+ * export const PUT = proxy
138
+ * export const DELETE = proxy
139
+ * ```
140
+ */
141
+ declare function createBrandKitProxy(config: BrandKitProxyConfig): (request: Request) => Promise<Response>;
142
+
143
+ export { type BrandKitProxyConfig, type CMAProxyConfig, type CMAScope, type LaunchProxyConfig, checkScope, createBrandKitProxy, createCMAProxy, createLaunchProxy, resolveScope };
@@ -0,0 +1,143 @@
1
+ import { ContentstackRegion } from '../../regions/index.js';
2
+
3
+ type CMAScope = "entries:read" | "entries:write" | "content-types:read" | "content-types:write" | "assets:read" | "assets:write" | "environments:read" | "locales:read" | "releases:read" | "releases:write" | "taxonomies:read" | "taxonomies:write" | "workflows:read" | "workflows:write" | "webhooks:read" | "webhooks:write";
4
+ interface CMAProxyConfig {
5
+ region: ContentstackRegion;
6
+ apiKey: string;
7
+ getAccessToken: (request: Request) => Promise<string | null>;
8
+ basePath?: string;
9
+ allowedScopes?: CMAScope[];
10
+ unmappedScopeBehavior?: "allow" | "deny";
11
+ rateLimit?: number;
12
+ timeout?: number;
13
+ }
14
+
15
+ /**
16
+ * Create a CMA proxy handler that forwards requests to Contentstack.
17
+ *
18
+ * The returned function accepts a standard `Request` and returns a `Response`,
19
+ * making it compatible with Next.js route handlers, Deno/Bun servers, and
20
+ * any framework that uses the Web API Request/Response model.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // app/api/cma/[...path]/route.ts
25
+ * const proxy = createCMAProxy({
26
+ * region: "us",
27
+ * apiKey: "your-api-key",
28
+ * getAccessToken: async (req) => {
29
+ * const session = await auth()
30
+ * return session?.accessToken ?? null
31
+ * },
32
+ * })
33
+ *
34
+ * export const GET = proxy
35
+ * export const POST = proxy
36
+ * export const PUT = proxy
37
+ * export const DELETE = proxy
38
+ * ```
39
+ */
40
+ declare function createCMAProxy(config: CMAProxyConfig): (request: Request) => Promise<Response>;
41
+
42
+ /**
43
+ * Resolve the required CMA scope for a given HTTP method and path.
44
+ *
45
+ * Path matching checks for known segments. The order matters:
46
+ * `/entries` is checked before `/content_types` because entry URLs
47
+ * like `/content_types/blog/entries` contain both.
48
+ *
49
+ * @returns The required scope, or `null` if the path is unrecognized.
50
+ */
51
+ declare function resolveScope(method: string, path: string): CMAScope | null;
52
+ /**
53
+ * Check whether a required scope is present in the allowed scopes list.
54
+ *
55
+ * @returns An error message if the scope is not allowed, or `null` if permitted.
56
+ */
57
+ declare function checkScope(required: CMAScope, allowed: CMAScope[]): string | null;
58
+
59
+ interface LaunchProxyConfig {
60
+ /** Contentstack region */
61
+ region: ContentstackRegion;
62
+ /** Organization UID — required for all Launch API calls */
63
+ organizationUid: string;
64
+ /** Callback to retrieve the user's access token from the request */
65
+ getAccessToken: (request: Request) => Promise<string | null>;
66
+ /** URL prefix to strip when extracting the Launch API path (default: "/api/launch") */
67
+ basePath?: string;
68
+ /** Request timeout in milliseconds (default: 30000) */
69
+ timeout?: number;
70
+ }
71
+ /**
72
+ * Create a Launch API proxy handler that forwards requests to Contentstack Launch.
73
+ *
74
+ * The returned function accepts a standard `Request` and returns a `Response`,
75
+ * making it compatible with Next.js route handlers, Deno/Bun servers, and
76
+ * any framework that uses the Web API Request/Response model.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * // app/api/launch/[...path]/route.ts
81
+ * const proxy = createLaunchProxy({
82
+ * region: "us",
83
+ * organizationUid: "org-uid",
84
+ * getAccessToken: async () => {
85
+ * const session = await auth()
86
+ * return session?.accessToken ?? null
87
+ * },
88
+ * })
89
+ *
90
+ * export const GET = proxy
91
+ * export const POST = proxy
92
+ * export const PUT = proxy
93
+ * export const DELETE = proxy
94
+ * ```
95
+ */
96
+ declare function createLaunchProxy(config: LaunchProxyConfig): (request: Request) => Promise<Response>;
97
+
98
+ interface BrandKitProxyConfig {
99
+ /** Contentstack region */
100
+ region: ContentstackRegion;
101
+ /** Organization UID — required for all Brand Kit API calls */
102
+ organizationUid: string;
103
+ /** Brand Kit UID — required for all Brand Kit API calls */
104
+ brandKitUid: string;
105
+ /** Callback to retrieve the user's access token from the request */
106
+ getAccessToken: (request: Request) => Promise<string | null>;
107
+ /** URL prefix to strip when extracting the API path (default: "/api/brandkit") */
108
+ basePath?: string;
109
+ /** Restrict operations: "read" allows GET only, "manage" allows all methods */
110
+ allowedOperations?: ("read" | "manage")[];
111
+ /** Request timeout in milliseconds (default: 30000) */
112
+ timeout?: number;
113
+ }
114
+ /**
115
+ * Create a Brand Kit proxy handler that forwards requests to Contentstack
116
+ * Brand Kit Management, Knowledge Vault, and Generative AI APIs.
117
+ *
118
+ * Routes are determined by path:
119
+ * - Paths containing `/knowledge-vault` or `/generative-ai` → brandKitAI base URL
120
+ * - All other paths (brand kits, voice profiles) → brandKit base URL
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * // app/api/brandkit/[...path]/route.ts
125
+ * const proxy = createBrandKitProxy({
126
+ * region: "us",
127
+ * organizationUid: "org-uid",
128
+ * brandKitUid: "bk-uid",
129
+ * getAccessToken: async () => {
130
+ * const session = await auth()
131
+ * return session?.accessToken ?? null
132
+ * },
133
+ * })
134
+ *
135
+ * export const GET = proxy
136
+ * export const POST = proxy
137
+ * export const PUT = proxy
138
+ * export const DELETE = proxy
139
+ * ```
140
+ */
141
+ declare function createBrandKitProxy(config: BrandKitProxyConfig): (request: Request) => Promise<Response>;
142
+
143
+ export { type BrandKitProxyConfig, type CMAProxyConfig, type CMAScope, type LaunchProxyConfig, checkScope, createBrandKitProxy, createCMAProxy, createLaunchProxy, resolveScope };
@@ -0,0 +1,29 @@
1
+ import {
2
+ checkScope,
3
+ createBrandKitProxy,
4
+ createCMAProxy,
5
+ createLaunchProxy,
6
+ resolveScope
7
+ } from "../../chunk-JYGZBKTH.mjs";
8
+ import "../../chunk-7VFGD32I.mjs";
9
+ import "../../chunk-T5A2E2RI.mjs";
10
+ import "../../chunk-VW7DD6HV.mjs";
11
+ import "../../chunk-DJQLN4TR.mjs";
12
+ import "../../chunk-XH7NLHGW.mjs";
13
+ import "../../chunk-AVJHCFRK.mjs";
14
+ import "../../chunk-EREPKWTW.mjs";
15
+ import "../../chunk-GNPQJBFX.mjs";
16
+ import "../../chunk-KLVIROVU.mjs";
17
+ import "../../chunk-JZE2W7VW.mjs";
18
+ import "../../chunk-3KE63N3I.mjs";
19
+ import "../../chunk-4CJ4IVPJ.mjs";
20
+ import "../../chunk-BK2IBTQS.mjs";
21
+ import "../../chunk-DMERADWM.mjs";
22
+ export {
23
+ checkScope,
24
+ createBrandKitProxy,
25
+ createCMAProxy,
26
+ createLaunchProxy,
27
+ resolveScope
28
+ };
29
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/server/webhooks/index.ts
21
+ var webhooks_exports = {};
22
+ __export(webhooks_exports, {
23
+ createWebhookHandler: () => createWebhookHandler,
24
+ verifyWebhookSignature: () => verifyWebhookSignature
25
+ });
26
+ module.exports = __toCommonJS(webhooks_exports);
27
+
28
+ // src/server/webhooks/verify.ts
29
+ function hexDecode(hex) {
30
+ const bytes = new Uint8Array(hex.length / 2);
31
+ for (let i = 0; i < hex.length; i += 2) {
32
+ bytes[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);
33
+ }
34
+ return bytes;
35
+ }
36
+ function timingSafeEqual(a, b) {
37
+ if (a.length !== b.length) return false;
38
+ let result = 0;
39
+ for (let i = 0; i < a.length; i++) {
40
+ result |= (a[i] ?? 0) ^ (b[i] ?? 0);
41
+ }
42
+ return result === 0;
43
+ }
44
+ async function verifyWebhookSignature(body, signature, secret) {
45
+ const encoder = new TextEncoder();
46
+ const key = await globalThis.crypto.subtle.importKey(
47
+ "raw",
48
+ encoder.encode(secret),
49
+ { name: "HMAC", hash: "SHA-256" },
50
+ false,
51
+ ["sign"]
52
+ );
53
+ const expectedBuffer = await globalThis.crypto.subtle.sign("HMAC", key, encoder.encode(body));
54
+ const expectedBytes = new Uint8Array(expectedBuffer);
55
+ const signatureBytes = hexDecode(signature);
56
+ return timingSafeEqual(expectedBytes, signatureBytes);
57
+ }
58
+
59
+ // src/http/errors.ts
60
+ var ContentstackError = class extends Error {
61
+ name = "ContentstackError";
62
+ status;
63
+ errorCode;
64
+ errors;
65
+ requestPath;
66
+ constructor(message, options) {
67
+ super(message, options?.cause ? { cause: options.cause } : void 0);
68
+ this.status = options?.status;
69
+ this.errorCode = options?.errorCode;
70
+ this.errors = options?.errors;
71
+ this.requestPath = options?.requestPath;
72
+ }
73
+ };
74
+ var ContentstackAuthError = class extends ContentstackError {
75
+ name = "ContentstackAuthError";
76
+ status = 401;
77
+ };
78
+
79
+ // src/server/webhooks/handler.ts
80
+ var SIGNATURE_HEADER = "x-contentstack-request-signature";
81
+ function parseWebhookBody(body) {
82
+ const raw = JSON.parse(body);
83
+ const module2 = raw.module;
84
+ const event = raw.event;
85
+ const type = `${module2}.${event}`;
86
+ return {
87
+ ...raw,
88
+ type,
89
+ module: module2,
90
+ event
91
+ };
92
+ }
93
+ function createWebhookHandler(config) {
94
+ return {
95
+ /**
96
+ * Read the request body, verify the signature, and return a typed event.
97
+ * Throws `ContentstackAuthError` if the signature is missing or invalid.
98
+ */
99
+ async verify(request) {
100
+ const body = await request.text();
101
+ const signature = request.headers.get(SIGNATURE_HEADER);
102
+ if (!signature) {
103
+ throw new ContentstackAuthError("Missing webhook signature header", {
104
+ status: 401,
105
+ requestPath: new URL(request.url).pathname
106
+ });
107
+ }
108
+ const valid = await verifyWebhookSignature(body, signature, config.secret);
109
+ if (!valid) {
110
+ throw new ContentstackAuthError("Invalid webhook signature", {
111
+ status: 401,
112
+ requestPath: new URL(request.url).pathname
113
+ });
114
+ }
115
+ return parseWebhookBody(body);
116
+ },
117
+ /**
118
+ * Read the request body and return a typed event without verifying the signature.
119
+ */
120
+ async parse(request) {
121
+ const body = await request.text();
122
+ return parseWebhookBody(body);
123
+ }
124
+ };
125
+ }
126
+ // Annotate the CommonJS export names for ESM import in node:
127
+ 0 && (module.exports = {
128
+ createWebhookHandler,
129
+ verifyWebhookSignature
130
+ });
131
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/webhooks/index.ts","../../../src/server/webhooks/verify.ts","../../../src/http/errors.ts","../../../src/server/webhooks/handler.ts"],"sourcesContent":["export type {\n WebhookHandlerConfig,\n WebhookEvent,\n BaseWebhookEvent,\n EntryPublishEvent,\n EntryUnpublishEvent,\n EntryUpdateEvent,\n EntryCreateEvent,\n EntryDeleteEvent,\n AssetPublishEvent,\n AssetUnpublishEvent,\n AssetDeleteEvent,\n ContentTypeCreateEvent,\n ContentTypeUpdateEvent,\n ContentTypeDeleteEvent,\n} from \"./types.js\"\nexport { verifyWebhookSignature } from \"./verify.js\"\nexport { createWebhookHandler } from \"./handler.js\"\n","/**\n * Webhook signature verification using HMAC-SHA256.\n * Uses the Web Crypto API for cross-runtime compatibility (Node 18+, Deno, Bun, edge).\n */\n\nfunction hexEncode(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n let hex = \"\"\n for (const byte of bytes) {\n hex += byte.toString(16).padStart(2, \"0\")\n }\n return hex\n}\n\nfunction hexDecode(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16)\n }\n return bytes\n}\n\n/**\n * Constant-time comparison of two byte arrays.\n * Prevents timing attacks by always comparing all bytes regardless of mismatch.\n */\nfunction timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false\n let result = 0\n for (let i = 0; i < a.length; i++) {\n result |= (a[i] ?? 0) ^ (b[i] ?? 0)\n }\n return result === 0\n}\n\n/**\n * Verify a Contentstack webhook signature using HMAC-SHA256.\n *\n * @param body - The raw request body string\n * @param signature - The hex-encoded signature from the `X-Contentstack-Request-Signature` header\n * @param secret - The webhook secret configured in Contentstack\n * @returns `true` if the signature is valid\n */\nexport async function verifyWebhookSignature(\n body: string,\n signature: string,\n secret: string,\n): Promise<boolean> {\n const encoder = new TextEncoder()\n const key = await globalThis.crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n )\n\n const expectedBuffer = await globalThis.crypto.subtle.sign(\"HMAC\", key, encoder.encode(body))\n const expectedBytes = new Uint8Array(expectedBuffer)\n const signatureBytes = hexDecode(signature)\n\n return timingSafeEqual(expectedBytes, signatureBytes)\n}\n","/**\n * Base error class for all Contentstack SDK errors.\n * Every error includes an actionable message and relevant context.\n */\nexport class ContentstackError extends Error {\n override readonly name: string = \"ContentstackError\"\n readonly status?: number\n readonly errorCode?: number\n readonly errors?: Record<string, string[]>\n readonly requestPath?: string\n\n constructor(\n message: string,\n options?: {\n status?: number\n errorCode?: number\n errors?: Record<string, string[]>\n requestPath?: string\n cause?: Error\n },\n ) {\n super(message, options?.cause ? { cause: options.cause } : undefined)\n this.status = options?.status\n this.errorCode = options?.errorCode\n this.errors = options?.errors\n this.requestPath = options?.requestPath\n }\n}\n\nexport class ContentstackAuthError extends ContentstackError {\n override readonly name = \"ContentstackAuthError\"\n override readonly status = 401\n}\n\nexport class ContentstackForbiddenError extends ContentstackError {\n override readonly name = \"ContentstackForbiddenError\"\n override readonly status = 403\n}\n\nexport class ContentstackNotFoundError extends ContentstackError {\n override readonly name = \"ContentstackNotFoundError\"\n override readonly status = 404\n}\n\nexport class ContentstackValidationError extends ContentstackError {\n override readonly name = \"ContentstackValidationError\"\n override readonly status: number\n\n constructor(\n message: string,\n options?: {\n status?: number\n errorCode?: number\n errors?: Record<string, string[]>\n requestPath?: string\n cause?: Error\n },\n ) {\n super(message, options)\n this.status = options?.status ?? 400\n }\n}\n\nexport class ContentstackInvalidApiKeyError extends ContentstackError {\n override readonly name = \"ContentstackInvalidApiKeyError\"\n override readonly status = 412\n}\n\nexport class ContentstackRateLimitError extends ContentstackError {\n override readonly name = \"ContentstackRateLimitError\"\n override readonly status = 429\n readonly retryAfter?: number\n\n constructor(\n message: string,\n options?: {\n errorCode?: number\n errors?: Record<string, string[]>\n requestPath?: string\n cause?: Error\n retryAfter?: number\n },\n ) {\n super(message, { ...options, status: 429 })\n this.retryAfter = options?.retryAfter\n }\n}\n\nexport class ContentstackServerError extends ContentstackError {\n override readonly name = \"ContentstackServerError\"\n}\n\nexport class ContentstackConfigError extends ContentstackError {\n override readonly name = \"ContentstackConfigError\"\n}\n","import { ContentstackAuthError } from \"../../index.js\"\nimport type { WebhookEvent, WebhookHandlerConfig } from \"./types.js\"\nimport { verifyWebhookSignature } from \"./verify.js\"\n\nconst SIGNATURE_HEADER = \"x-contentstack-request-signature\"\n\nfunction parseWebhookBody(body: string): WebhookEvent {\n const raw = JSON.parse(body) as Record<string, unknown>\n const module = raw.module as string\n const event = raw.event as string\n const type = `${module}.${event}`\n\n return {\n ...raw,\n type,\n module,\n event,\n } as WebhookEvent\n}\n\n/**\n * Create a webhook handler with signature verification and typed event parsing.\n *\n * @example\n * ```ts\n * const handler = createWebhookHandler({ secret: process.env.WEBHOOK_SECRET })\n *\n * // In a route handler:\n * const event = await handler.verify(request)\n * if (event.type === \"entry.publish\") {\n * console.log(event.data.entry.uid)\n * }\n * ```\n */\nexport function createWebhookHandler(config: WebhookHandlerConfig) {\n return {\n /**\n * Read the request body, verify the signature, and return a typed event.\n * Throws `ContentstackAuthError` if the signature is missing or invalid.\n */\n async verify(request: Request): Promise<WebhookEvent> {\n const body = await request.text()\n const signature = request.headers.get(SIGNATURE_HEADER)\n\n if (!signature) {\n throw new ContentstackAuthError(\"Missing webhook signature header\", {\n status: 401,\n requestPath: new URL(request.url).pathname,\n })\n }\n\n const valid = await verifyWebhookSignature(body, signature, config.secret)\n if (!valid) {\n throw new ContentstackAuthError(\"Invalid webhook signature\", {\n status: 401,\n requestPath: new URL(request.url).pathname,\n })\n }\n\n return parseWebhookBody(body)\n },\n\n /**\n * Read the request body and return a typed event without verifying the signature.\n */\n async parse(request: Request): Promise<WebhookEvent> {\n const body = await request.text()\n return parseWebhookBody(body)\n },\n }\n}\n"],"mappings":"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","names":["module"]}