@riverbankcms/sdk 0.7.0 → 0.7.3

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 (184) hide show
  1. package/README.md +229 -0
  2. package/dist/cli/index.js +42 -95
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/init-docs/content/agents-section.md +50 -0
  5. package/dist/cli/init-docs/content/cli-reference.md +574 -0
  6. package/dist/cli/init-docs/content/content-management.md +384 -0
  7. package/dist/cli/init-docs/content/context-brand.md +125 -0
  8. package/dist/cli/init-docs/content/context-brief.md +77 -0
  9. package/dist/cli/init-docs/content/context-knowledge.md +111 -0
  10. package/dist/cli/init-docs/content/getting-started.md +130 -0
  11. package/dist/cli/init-docs/content/site-workflows-readme.md +96 -0
  12. package/dist/cli/init-docs/content/workflow-add-block.md +228 -0
  13. package/dist/cli/init-docs/content/workflow-create-page.md +193 -0
  14. package/dist/cli/init-docs/content/workflow-publish.md +280 -0
  15. package/dist/client/bookings.d.mts +2 -0
  16. package/dist/client/bookings.d.ts +2 -0
  17. package/dist/client/bookings.js +2956 -104
  18. package/dist/client/bookings.js.map +1 -1
  19. package/dist/client/bookings.mjs +2929 -70
  20. package/dist/client/bookings.mjs.map +1 -1
  21. package/dist/client/client.d.mts +2 -2
  22. package/dist/client/client.d.ts +2 -2
  23. package/dist/client/client.js +602 -68
  24. package/dist/client/client.js.map +1 -1
  25. package/dist/client/client.mjs +602 -68
  26. package/dist/client/client.mjs.map +1 -1
  27. package/dist/client/hooks.d.mts +2 -2
  28. package/dist/client/hooks.d.ts +2 -2
  29. package/dist/client/rendering/client.js +3070 -259
  30. package/dist/client/rendering/client.js.map +1 -1
  31. package/dist/client/rendering/client.mjs +3212 -395
  32. package/dist/client/rendering/client.mjs.map +1 -1
  33. package/dist/client/spam-protection.d.mts +55 -0
  34. package/dist/client/spam-protection.d.ts +55 -0
  35. package/dist/client/spam-protection.js +2915 -0
  36. package/dist/client/spam-protection.js.map +1 -0
  37. package/dist/client/spam-protection.mjs +2893 -0
  38. package/dist/client/spam-protection.mjs.map +1 -0
  39. package/dist/client/{usePage-BiOReg0_.d.ts → usePage-BYmJCCm1.d.ts} +132 -11
  40. package/dist/client/{usePage-BXjk8BhD.d.mts → usePage-DZtrWajy.d.mts} +132 -11
  41. package/dist/server/{Layout-wBtJLTVX.d.ts → Layout-Yluyb6sK.d.ts} +1 -1
  42. package/dist/server/{Layout-B7cvis7r.d.mts → Layout-qWLdVm5-.d.mts} +1 -1
  43. package/dist/server/chunk-2IZ6S225.js +122 -0
  44. package/dist/server/chunk-2IZ6S225.js.map +1 -0
  45. package/dist/server/chunk-4CV4JOE5.js +27 -0
  46. package/dist/server/chunk-4CV4JOE5.js.map +1 -0
  47. package/dist/server/chunk-5LRR64Y6.mjs +72 -0
  48. package/dist/server/chunk-5LRR64Y6.mjs.map +1 -0
  49. package/dist/server/chunk-NBTRDLCM.js +72 -0
  50. package/dist/server/chunk-NBTRDLCM.js.map +1 -0
  51. package/dist/server/chunk-NFEGQTCC.mjs +27 -0
  52. package/dist/server/{chunk-7FIJSGHU.mjs → chunk-NFQLH5IA.mjs} +856 -74
  53. package/dist/server/chunk-NFQLH5IA.mjs.map +1 -0
  54. package/dist/server/chunk-PPHZV6YD.mjs +122 -0
  55. package/dist/server/chunk-PPHZV6YD.mjs.map +1 -0
  56. package/dist/server/{chunk-P7UVAMK6.js → chunk-VLXTNB2C.js} +866 -84
  57. package/dist/server/chunk-VLXTNB2C.js.map +1 -0
  58. package/dist/server/{components-CMMwDXTW.d.mts → components-DNHfSCML.d.mts} +3 -3
  59. package/dist/server/{components-CICSJyp_.d.ts → components-Di5ME6He.d.ts} +3 -3
  60. package/dist/server/components.d.mts +5 -5
  61. package/dist/server/components.d.ts +5 -5
  62. package/dist/server/components.js +1 -1
  63. package/dist/server/components.mjs +1 -1
  64. package/dist/server/config-validation.js +1 -1
  65. package/dist/server/config-validation.mjs +1 -1
  66. package/dist/server/config.js +1 -1
  67. package/dist/server/config.mjs +1 -1
  68. package/dist/server/data.d.mts +2 -2
  69. package/dist/server/data.d.ts +2 -2
  70. package/dist/server/data.js +1 -1
  71. package/dist/server/data.mjs +1 -1
  72. package/dist/server/env.d.mts +109 -0
  73. package/dist/server/env.d.ts +109 -0
  74. package/dist/server/env.js +14 -0
  75. package/dist/server/env.js.map +1 -0
  76. package/dist/server/env.mjs +14 -0
  77. package/dist/server/{index-DI_qlYx3.d.mts → index--Oyunk_B.d.mts} +2 -2
  78. package/dist/server/{index-BTwWvSBu.d.ts → index-C9Ra8dza.d.ts} +2 -2
  79. package/dist/server/{index-Bucs6UqG.d.mts → index-Clm3skz_.d.mts} +1 -1
  80. package/dist/server/{index-Cp7tJuRt.d.ts → index-DLvNddi-.d.ts} +1 -1
  81. package/dist/server/index.d.mts +216 -5
  82. package/dist/server/index.d.ts +216 -5
  83. package/dist/server/index.js +301 -4
  84. package/dist/server/index.js.map +1 -1
  85. package/dist/server/index.mjs +301 -4
  86. package/dist/server/index.mjs.map +1 -1
  87. package/dist/server/{loadContent-DmgpFcFC.d.ts → loadContent-D7LQwI0o.d.ts} +3 -3
  88. package/dist/server/{loadContent-C-YYUKQa.d.mts → loadContent-DVfuBLiZ.d.mts} +3 -3
  89. package/dist/server/{loadPage-IDGVDFBB.js → loadPage-AXNAERDS.js} +2 -2
  90. package/dist/server/{loadPage-IDGVDFBB.js.map → loadPage-AXNAERDS.js.map} +1 -1
  91. package/dist/server/{loadPage-DP3nrHBi.d.ts → loadPage-BmYJCe_V.d.ts} +2 -2
  92. package/dist/server/{loadPage-B8mQUUSo.d.mts → loadPage-BucnLHmE.d.mts} +2 -2
  93. package/dist/server/{loadPage-DNQTTRHL.mjs → loadPage-XR7ORQ2E.mjs} +2 -2
  94. package/dist/server/loadPage-XR7ORQ2E.mjs.map +1 -0
  95. package/dist/server/metadata.d.mts +4 -4
  96. package/dist/server/metadata.d.ts +4 -4
  97. package/dist/server/metadata.js +1 -1
  98. package/dist/server/metadata.mjs +1 -1
  99. package/dist/server/navigation.d.mts +2 -2
  100. package/dist/server/navigation.d.ts +2 -2
  101. package/dist/server/navigation.js +1 -1
  102. package/dist/server/navigation.mjs +1 -1
  103. package/dist/server/next/revalidate.d.mts +66 -0
  104. package/dist/server/next/revalidate.d.ts +66 -0
  105. package/dist/server/next/revalidate.js +60 -0
  106. package/dist/server/next/revalidate.js.map +1 -0
  107. package/dist/server/next/revalidate.mjs +60 -0
  108. package/dist/server/next/revalidate.mjs.map +1 -0
  109. package/dist/server/next/tags.d.mts +81 -0
  110. package/dist/server/next/tags.d.ts +81 -0
  111. package/dist/server/next/tags.js +36 -0
  112. package/dist/server/next/tags.js.map +1 -0
  113. package/dist/server/next/tags.mjs +36 -0
  114. package/dist/server/next/tags.mjs.map +1 -0
  115. package/dist/server/next.d.mts +164 -6
  116. package/dist/server/next.d.ts +164 -6
  117. package/dist/server/next.js +79 -11
  118. package/dist/server/next.js.map +1 -1
  119. package/dist/server/next.mjs +76 -8
  120. package/dist/server/next.mjs.map +1 -1
  121. package/dist/server/rendering/server.d.mts +4 -4
  122. package/dist/server/rendering/server.d.ts +4 -4
  123. package/dist/server/rendering/server.js +1 -1
  124. package/dist/server/rendering/server.mjs +1 -1
  125. package/dist/server/rendering.d.mts +7 -7
  126. package/dist/server/rendering.d.ts +7 -7
  127. package/dist/server/rendering.js +3 -3
  128. package/dist/server/rendering.js.map +1 -1
  129. package/dist/server/rendering.mjs +4 -4
  130. package/dist/server/routing.d.mts +3 -3
  131. package/dist/server/routing.d.ts +3 -3
  132. package/dist/server/routing.js +2 -2
  133. package/dist/server/routing.mjs +2 -2
  134. package/dist/server/server.d.mts +5 -5
  135. package/dist/server/server.d.ts +5 -5
  136. package/dist/server/server.js +5 -5
  137. package/dist/server/server.js.map +1 -1
  138. package/dist/server/server.mjs +5 -5
  139. package/dist/server/theme-bridge.js +1 -1
  140. package/dist/server/theme-bridge.mjs +1 -1
  141. package/dist/server/theme.js +1 -1
  142. package/dist/server/theme.mjs +1 -1
  143. package/dist/server/{types-BvcJU7zk.d.ts → types-BRQyLrQU.d.ts} +132 -11
  144. package/dist/server/{types-Dsu9wsUh.d.mts → types-BSV6Vc-P.d.mts} +2 -2
  145. package/dist/server/{types-1cLz0vnq.d.mts → types-C-LShyIg.d.mts} +132 -11
  146. package/dist/server/{types-CVykEqXN.d.ts → types-Dt98DeYa.d.ts} +2 -2
  147. package/dist/server/webhooks.d.mts +81 -0
  148. package/dist/server/webhooks.d.ts +81 -0
  149. package/dist/server/webhooks.js +12 -0
  150. package/dist/server/webhooks.js.map +1 -0
  151. package/dist/server/webhooks.mjs +12 -0
  152. package/dist/server/webhooks.mjs.map +1 -0
  153. package/package.json +29 -3
  154. package/dist/client/resolver-BhueZVxZ.d.mts +0 -61
  155. package/dist/client/resolver-BhueZVxZ.d.ts +0 -61
  156. package/dist/client/usePage--fGlyrgj.d.mts +0 -6439
  157. package/dist/client/usePage-BBcFCxOU.d.ts +0 -6297
  158. package/dist/client/usePage-BC8Q2E3t.d.mts +0 -6431
  159. package/dist/client/usePage-BTPnCuWC.d.mts +0 -6511
  160. package/dist/client/usePage-BafOS9UT.d.mts +0 -6512
  161. package/dist/client/usePage-BcjWPXvh.d.mts +0 -6388
  162. package/dist/client/usePage-Bnx-kA6x.d.mts +0 -6670
  163. package/dist/client/usePage-BvKAa3Zw.d.mts +0 -366
  164. package/dist/client/usePage-BvKAa3Zw.d.ts +0 -366
  165. package/dist/client/usePage-BydHcMYB.d.mts +0 -6297
  166. package/dist/client/usePage-C3ZKNwY7.d.mts +0 -6393
  167. package/dist/client/usePage-CE7X5NcN.d.ts +0 -6439
  168. package/dist/client/usePage-CHEybPMD.d.ts +0 -6429
  169. package/dist/client/usePage-CrKw1H6Y.d.ts +0 -6338
  170. package/dist/client/usePage-CyYpOJud.d.ts +0 -6388
  171. package/dist/client/usePage-D4fxZbRR.d.mts +0 -6429
  172. package/dist/client/usePage-DMI8ImsU.d.mts +0 -6338
  173. package/dist/client/usePage-DoPI6b8V.d.ts +0 -6511
  174. package/dist/client/usePage-DpRNZUtP.d.ts +0 -6431
  175. package/dist/client/usePage-QNWArrVO.d.ts +0 -6670
  176. package/dist/client/usePage-fBgPB6Oq.d.ts +0 -6512
  177. package/dist/client/usePage-gpVaeWDy.d.ts +0 -6393
  178. package/dist/server/chunk-7FIJSGHU.mjs.map +0 -1
  179. package/dist/server/chunk-BJTO5JO5.mjs +0 -11
  180. package/dist/server/chunk-DGUM43GV.js +0 -11
  181. package/dist/server/chunk-DGUM43GV.js.map +0 -1
  182. package/dist/server/chunk-P7UVAMK6.js.map +0 -1
  183. /package/dist/server/{chunk-BJTO5JO5.mjs.map → chunk-NFEGQTCC.mjs.map} +0 -0
  184. /package/dist/server/{loadPage-DNQTTRHL.mjs.map → env.mjs.map} +0 -0
@@ -0,0 +1,72 @@
1
+ // src/webhooks/verify.ts
2
+ import crypto from "crypto";
3
+ import { z } from "zod";
4
+ var WebhookEventSchema = z.enum([
5
+ "page.published",
6
+ "entry.published",
7
+ "navigation.updated",
8
+ "theme.updated",
9
+ "site.settings_updated"
10
+ ]);
11
+ var PagePublishedDataSchema = z.object({
12
+ pageId: z.string(),
13
+ path: z.string(),
14
+ slug: z.string().optional()
15
+ });
16
+ var EntryPublishedDataSchema = z.object({
17
+ entryId: z.string(),
18
+ path: z.string(),
19
+ contentType: z.string()
20
+ });
21
+ var NavigationUpdatedDataSchema = z.object({
22
+ menuId: z.string().optional()
23
+ });
24
+ var EmptyDataSchema = z.object({});
25
+ var WebhookDataSchema = z.union([
26
+ PagePublishedDataSchema,
27
+ EntryPublishedDataSchema,
28
+ NavigationUpdatedDataSchema,
29
+ EmptyDataSchema
30
+ ]);
31
+ var WebhookPayloadSchema = z.object({
32
+ /** Event type */
33
+ event: WebhookEventSchema,
34
+ /** ISO timestamp of when the event occurred */
35
+ timestamp: z.string(),
36
+ /** Site ID that triggered the event */
37
+ siteId: z.string(),
38
+ /** Event-specific data (shape depends on event type) */
39
+ data: z.record(z.string(), z.unknown()),
40
+ /** Cache invalidation tags (for tag-based revalidation) */
41
+ tags: z.array(z.string()).optional()
42
+ });
43
+ function verifyWebhookSignature(payload, signature, secret) {
44
+ const expectedSignature = crypto.createHmac("sha256", secret).update(payload).digest("hex");
45
+ if (signature.length !== expectedSignature.length) {
46
+ return false;
47
+ }
48
+ return crypto.timingSafeEqual(
49
+ Buffer.from(signature),
50
+ Buffer.from(expectedSignature)
51
+ );
52
+ }
53
+ function parseWebhookPayload(body) {
54
+ let parsed;
55
+ try {
56
+ parsed = JSON.parse(body);
57
+ } catch {
58
+ return { success: false, error: "Invalid JSON" };
59
+ }
60
+ const result = WebhookPayloadSchema.safeParse(parsed);
61
+ if (!result.success) {
62
+ return { success: false, error: `Invalid payload: ${result.error.message}` };
63
+ }
64
+ return { success: true, payload: result.data };
65
+ }
66
+
67
+ export {
68
+ WebhookPayloadSchema,
69
+ verifyWebhookSignature,
70
+ parseWebhookPayload
71
+ };
72
+ //# sourceMappingURL=chunk-5LRR64Y6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/webhooks/verify.ts"],"sourcesContent":["/**\n * Webhook verification utilities for Riverbank SDK\n *\n * Provides framework-agnostic webhook signature verification and payload parsing.\n */\n\nimport crypto from 'crypto';\nimport { z } from 'zod';\n\n// ============================================================================\n// Webhook Event Types\n// ============================================================================\n\n/**\n * Supported webhook event types.\n * Keep in sync with apps/dashboard/src/lib/db/helpers/webhooks.ts\n */\nexport const WebhookEventSchema = z.enum([\n 'page.published',\n 'entry.published',\n 'navigation.updated',\n 'theme.updated',\n 'site.settings_updated',\n]);\n\nexport type WebhookEvent = z.infer<typeof WebhookEventSchema>;\n\n// ============================================================================\n// Event-Specific Data Schemas\n// ============================================================================\n\n/** Data for page.published events */\nexport const PagePublishedDataSchema = z.object({\n pageId: z.string(),\n path: z.string(),\n slug: z.string().optional(),\n});\n\n/** Data for entry.published events */\nexport const EntryPublishedDataSchema = z.object({\n entryId: z.string(),\n path: z.string(),\n contentType: z.string(),\n});\n\n/** Data for navigation.updated events */\nexport const NavigationUpdatedDataSchema = z.object({\n menuId: z.string().optional(),\n});\n\n/** Data for theme.updated and site.settings_updated events (empty) */\nexport const EmptyDataSchema = z.object({});\n\n/**\n * Combined data schema that accepts any valid event data.\n * The actual shape depends on the event type.\n */\nexport const WebhookDataSchema = z.union([\n PagePublishedDataSchema,\n EntryPublishedDataSchema,\n NavigationUpdatedDataSchema,\n EmptyDataSchema,\n]);\n\nexport type PagePublishedData = z.infer<typeof PagePublishedDataSchema>;\nexport type EntryPublishedData = z.infer<typeof EntryPublishedDataSchema>;\nexport type NavigationUpdatedData = z.infer<typeof NavigationUpdatedDataSchema>;\n\n// ============================================================================\n// Webhook Payload Schema\n// ============================================================================\n\n/**\n * Zod schema for webhook payload validation.\n */\nexport const WebhookPayloadSchema = z.object({\n /** Event type */\n event: WebhookEventSchema,\n /** ISO timestamp of when the event occurred */\n timestamp: z.string(),\n /** Site ID that triggered the event */\n siteId: z.string(),\n /** Event-specific data (shape depends on event type) */\n data: z.record(z.string(), z.unknown()),\n /** Cache invalidation tags (for tag-based revalidation) */\n tags: z.array(z.string()).optional(),\n});\n\n/**\n * Webhook payload structure sent by the CMS.\n */\nexport type WebhookPayload = z.infer<typeof WebhookPayloadSchema>;\n\n/**\n * Type-safe webhook payload with discriminated data based on event type.\n */\nexport type TypedWebhookPayload =\n | { event: 'page.published'; data: PagePublishedData; siteId: string; timestamp: string; tags?: string[] }\n | { event: 'entry.published'; data: EntryPublishedData; siteId: string; timestamp: string; tags?: string[] }\n | { event: 'navigation.updated'; data: NavigationUpdatedData; siteId: string; timestamp: string; tags?: string[] }\n | { event: 'theme.updated'; data: Record<string, never>; siteId: string; timestamp: string; tags?: string[] }\n | { event: 'site.settings_updated'; data: Record<string, never>; siteId: string; timestamp: string; tags?: string[] };\n\n/**\n * Verify a webhook signature using HMAC-SHA256.\n *\n * Uses timing-safe comparison to prevent timing attacks.\n *\n * @param payload - The raw request body as a string\n * @param signature - The X-Riverbank-Signature header value\n * @param secret - The webhook signing secret (RIVERBANK_WEBHOOK_SECRET)\n * @returns true if signature is valid, false otherwise\n *\n * @example\n * ```ts\n * const body = await request.text();\n * const signature = request.headers.get('x-riverbank-signature');\n * const secret = process.env.RIVERBANK_WEBHOOK_SECRET;\n *\n * if (!verifyWebhookSignature(body, signature, secret)) {\n * return new Response('Invalid signature', { status: 401 });\n * }\n * ```\n */\nexport function verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = crypto\n .createHmac('sha256', secret)\n .update(payload)\n .digest('hex');\n\n // Length check before timing-safe comparison\n // timingSafeEqual throws if lengths differ\n if (signature.length !== expectedSignature.length) {\n return false;\n }\n\n // Timing-safe comparison to prevent timing attacks\n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n );\n}\n\n/**\n * Result type for webhook payload parsing.\n */\nexport type ParseWebhookResult =\n | { success: true; payload: WebhookPayload }\n | { success: false; error: string };\n\n/**\n * Parse and validate a webhook payload from the request body.\n *\n * Uses Zod schema validation to ensure the payload has the expected structure.\n *\n * @param body - The raw request body as a string\n * @returns A result object with either the validated payload or an error message\n *\n * @example\n * ```ts\n * const body = await request.text();\n * const result = parseWebhookPayload(body);\n * if (!result.success) {\n * return new Response(result.error, { status: 400 });\n * }\n * console.log(`Received ${result.payload.event} for site ${result.payload.siteId}`);\n * ```\n */\nexport function parseWebhookPayload(body: string): ParseWebhookResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n return { success: false, error: 'Invalid JSON' };\n }\n\n const result = WebhookPayloadSchema.safeParse(parsed);\n if (!result.success) {\n return { success: false, error: `Invalid payload: ${result.error.message}` };\n }\n\n return { success: true, payload: result.data };\n}\n"],"mappings":";AAMA,OAAO,YAAY;AACnB,SAAS,SAAS;AAUX,IAAM,qBAAqB,EAAE,KAAK;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AASM,IAAM,0BAA0B,EAAE,OAAO;AAAA,EAC9C,QAAQ,EAAE,OAAO;AAAA,EACjB,MAAM,EAAE,OAAO;AAAA,EACf,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAGM,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,SAAS,EAAE,OAAO;AAAA,EAClB,MAAM,EAAE,OAAO;AAAA,EACf,aAAa,EAAE,OAAO;AACxB,CAAC;AAGM,IAAM,8BAA8B,EAAE,OAAO;AAAA,EAClD,QAAQ,EAAE,OAAO,EAAE,SAAS;AAC9B,CAAC;AAGM,IAAM,kBAAkB,EAAE,OAAO,CAAC,CAAC;AAMnC,IAAM,oBAAoB,EAAE,MAAM;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAaM,IAAM,uBAAuB,EAAE,OAAO;AAAA;AAAA,EAE3C,OAAO;AAAA;AAAA,EAEP,WAAW,EAAE,OAAO;AAAA;AAAA,EAEpB,QAAQ,EAAE,OAAO;AAAA;AAAA,EAEjB,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;AAAA;AAAA,EAEtC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AACrC,CAAC;AAsCM,SAAS,uBACd,SACA,WACA,QACS;AACT,QAAM,oBAAoB,OACvB,WAAW,UAAU,MAAM,EAC3B,OAAO,OAAO,EACd,OAAO,KAAK;AAIf,MAAI,UAAU,WAAW,kBAAkB,QAAQ;AACjD,WAAO;AAAA,EACT;AAGA,SAAO,OAAO;AAAA,IACZ,OAAO,KAAK,SAAS;AAAA,IACrB,OAAO,KAAK,iBAAiB;AAAA,EAC/B;AACF;AA2BO,SAAS,oBAAoB,MAAkC;AACpE,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AACN,WAAO,EAAE,SAAS,OAAO,OAAO,eAAe;AAAA,EACjD;AAEA,QAAM,SAAS,qBAAqB,UAAU,MAAM;AACpD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,EAAE,SAAS,OAAO,OAAO,oBAAoB,OAAO,MAAM,OAAO,GAAG;AAAA,EAC7E;AAEA,SAAO,EAAE,SAAS,MAAM,SAAS,OAAO,KAAK;AAC/C;","names":[]}
@@ -0,0 +1,72 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/webhooks/verify.ts
2
+ var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto);
3
+ var _zod = require('zod');
4
+ var WebhookEventSchema = _zod.z.enum([
5
+ "page.published",
6
+ "entry.published",
7
+ "navigation.updated",
8
+ "theme.updated",
9
+ "site.settings_updated"
10
+ ]);
11
+ var PagePublishedDataSchema = _zod.z.object({
12
+ pageId: _zod.z.string(),
13
+ path: _zod.z.string(),
14
+ slug: _zod.z.string().optional()
15
+ });
16
+ var EntryPublishedDataSchema = _zod.z.object({
17
+ entryId: _zod.z.string(),
18
+ path: _zod.z.string(),
19
+ contentType: _zod.z.string()
20
+ });
21
+ var NavigationUpdatedDataSchema = _zod.z.object({
22
+ menuId: _zod.z.string().optional()
23
+ });
24
+ var EmptyDataSchema = _zod.z.object({});
25
+ var WebhookDataSchema = _zod.z.union([
26
+ PagePublishedDataSchema,
27
+ EntryPublishedDataSchema,
28
+ NavigationUpdatedDataSchema,
29
+ EmptyDataSchema
30
+ ]);
31
+ var WebhookPayloadSchema = _zod.z.object({
32
+ /** Event type */
33
+ event: WebhookEventSchema,
34
+ /** ISO timestamp of when the event occurred */
35
+ timestamp: _zod.z.string(),
36
+ /** Site ID that triggered the event */
37
+ siteId: _zod.z.string(),
38
+ /** Event-specific data (shape depends on event type) */
39
+ data: _zod.z.record(_zod.z.string(), _zod.z.unknown()),
40
+ /** Cache invalidation tags (for tag-based revalidation) */
41
+ tags: _zod.z.array(_zod.z.string()).optional()
42
+ });
43
+ function verifyWebhookSignature(payload, signature, secret) {
44
+ const expectedSignature = _crypto2.default.createHmac("sha256", secret).update(payload).digest("hex");
45
+ if (signature.length !== expectedSignature.length) {
46
+ return false;
47
+ }
48
+ return _crypto2.default.timingSafeEqual(
49
+ Buffer.from(signature),
50
+ Buffer.from(expectedSignature)
51
+ );
52
+ }
53
+ function parseWebhookPayload(body) {
54
+ let parsed;
55
+ try {
56
+ parsed = JSON.parse(body);
57
+ } catch (e) {
58
+ return { success: false, error: "Invalid JSON" };
59
+ }
60
+ const result = WebhookPayloadSchema.safeParse(parsed);
61
+ if (!result.success) {
62
+ return { success: false, error: `Invalid payload: ${result.error.message}` };
63
+ }
64
+ return { success: true, payload: result.data };
65
+ }
66
+
67
+
68
+
69
+
70
+
71
+ exports.WebhookPayloadSchema = WebhookPayloadSchema; exports.verifyWebhookSignature = verifyWebhookSignature; exports.parseWebhookPayload = parseWebhookPayload;
72
+ //# sourceMappingURL=chunk-NBTRDLCM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-NBTRDLCM.js","../../src/webhooks/verify.ts"],"names":[],"mappings":"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","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-NBTRDLCM.js","sourcesContent":[null,"/**\n * Webhook verification utilities for Riverbank SDK\n *\n * Provides framework-agnostic webhook signature verification and payload parsing.\n */\n\nimport crypto from 'crypto';\nimport { z } from 'zod';\n\n// ============================================================================\n// Webhook Event Types\n// ============================================================================\n\n/**\n * Supported webhook event types.\n * Keep in sync with apps/dashboard/src/lib/db/helpers/webhooks.ts\n */\nexport const WebhookEventSchema = z.enum([\n 'page.published',\n 'entry.published',\n 'navigation.updated',\n 'theme.updated',\n 'site.settings_updated',\n]);\n\nexport type WebhookEvent = z.infer<typeof WebhookEventSchema>;\n\n// ============================================================================\n// Event-Specific Data Schemas\n// ============================================================================\n\n/** Data for page.published events */\nexport const PagePublishedDataSchema = z.object({\n pageId: z.string(),\n path: z.string(),\n slug: z.string().optional(),\n});\n\n/** Data for entry.published events */\nexport const EntryPublishedDataSchema = z.object({\n entryId: z.string(),\n path: z.string(),\n contentType: z.string(),\n});\n\n/** Data for navigation.updated events */\nexport const NavigationUpdatedDataSchema = z.object({\n menuId: z.string().optional(),\n});\n\n/** Data for theme.updated and site.settings_updated events (empty) */\nexport const EmptyDataSchema = z.object({});\n\n/**\n * Combined data schema that accepts any valid event data.\n * The actual shape depends on the event type.\n */\nexport const WebhookDataSchema = z.union([\n PagePublishedDataSchema,\n EntryPublishedDataSchema,\n NavigationUpdatedDataSchema,\n EmptyDataSchema,\n]);\n\nexport type PagePublishedData = z.infer<typeof PagePublishedDataSchema>;\nexport type EntryPublishedData = z.infer<typeof EntryPublishedDataSchema>;\nexport type NavigationUpdatedData = z.infer<typeof NavigationUpdatedDataSchema>;\n\n// ============================================================================\n// Webhook Payload Schema\n// ============================================================================\n\n/**\n * Zod schema for webhook payload validation.\n */\nexport const WebhookPayloadSchema = z.object({\n /** Event type */\n event: WebhookEventSchema,\n /** ISO timestamp of when the event occurred */\n timestamp: z.string(),\n /** Site ID that triggered the event */\n siteId: z.string(),\n /** Event-specific data (shape depends on event type) */\n data: z.record(z.string(), z.unknown()),\n /** Cache invalidation tags (for tag-based revalidation) */\n tags: z.array(z.string()).optional(),\n});\n\n/**\n * Webhook payload structure sent by the CMS.\n */\nexport type WebhookPayload = z.infer<typeof WebhookPayloadSchema>;\n\n/**\n * Type-safe webhook payload with discriminated data based on event type.\n */\nexport type TypedWebhookPayload =\n | { event: 'page.published'; data: PagePublishedData; siteId: string; timestamp: string; tags?: string[] }\n | { event: 'entry.published'; data: EntryPublishedData; siteId: string; timestamp: string; tags?: string[] }\n | { event: 'navigation.updated'; data: NavigationUpdatedData; siteId: string; timestamp: string; tags?: string[] }\n | { event: 'theme.updated'; data: Record<string, never>; siteId: string; timestamp: string; tags?: string[] }\n | { event: 'site.settings_updated'; data: Record<string, never>; siteId: string; timestamp: string; tags?: string[] };\n\n/**\n * Verify a webhook signature using HMAC-SHA256.\n *\n * Uses timing-safe comparison to prevent timing attacks.\n *\n * @param payload - The raw request body as a string\n * @param signature - The X-Riverbank-Signature header value\n * @param secret - The webhook signing secret (RIVERBANK_WEBHOOK_SECRET)\n * @returns true if signature is valid, false otherwise\n *\n * @example\n * ```ts\n * const body = await request.text();\n * const signature = request.headers.get('x-riverbank-signature');\n * const secret = process.env.RIVERBANK_WEBHOOK_SECRET;\n *\n * if (!verifyWebhookSignature(body, signature, secret)) {\n * return new Response('Invalid signature', { status: 401 });\n * }\n * ```\n */\nexport function verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = crypto\n .createHmac('sha256', secret)\n .update(payload)\n .digest('hex');\n\n // Length check before timing-safe comparison\n // timingSafeEqual throws if lengths differ\n if (signature.length !== expectedSignature.length) {\n return false;\n }\n\n // Timing-safe comparison to prevent timing attacks\n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n );\n}\n\n/**\n * Result type for webhook payload parsing.\n */\nexport type ParseWebhookResult =\n | { success: true; payload: WebhookPayload }\n | { success: false; error: string };\n\n/**\n * Parse and validate a webhook payload from the request body.\n *\n * Uses Zod schema validation to ensure the payload has the expected structure.\n *\n * @param body - The raw request body as a string\n * @returns A result object with either the validated payload or an error message\n *\n * @example\n * ```ts\n * const body = await request.text();\n * const result = parseWebhookPayload(body);\n * if (!result.success) {\n * return new Response(result.error, { status: 400 });\n * }\n * console.log(`Received ${result.payload.event} for site ${result.payload.siteId}`);\n * ```\n */\nexport function parseWebhookPayload(body: string): ParseWebhookResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n return { success: false, error: 'Invalid JSON' };\n }\n\n const result = WebhookPayloadSchema.safeParse(parsed);\n if (!result.success) {\n return { success: false, error: `Invalid payload: ${result.error.message}` };\n }\n\n return { success: true, payload: result.data };\n}\n"]}
@@ -0,0 +1,27 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __esm = (fn, res) => function __init() {
6
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
+ };
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ export {
23
+ __esm,
24
+ __export,
25
+ __toCommonJS
26
+ };
27
+ //# sourceMappingURL=chunk-NFEGQTCC.mjs.map