@praxium/sdk 0.3.56 → 0.3.66

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.
package/README.md CHANGED
@@ -2,14 +2,19 @@
2
2
 
3
3
  Official TypeScript SDK for the [Praxium](https://praxium.nl) platform API. Build tenant websites that display practice data (team, services, FAQ, opening hours) with full locale support.
4
4
 
5
- ## Installation
5
+ - [Quick Start](#quick-start) — Installation and usage examples
6
+ - [Configuration](#configuration) — Environment variables and tenant routing
7
+ - [Available Methods](#available-methods) — All API endpoints
8
+ - [Error Handling](#error-handling) — Typed error classes
9
+ - [Webhooks](#webhooks) — React to entity changes (ISR revalidation, cache busting, etc.)
10
+ - [Contributing](#contributing) — Development commands
11
+
12
+ ## Quick Start
6
13
 
7
14
  ```bash
8
15
  npm install @praxium/sdk
9
16
  ```
10
17
 
11
- ## Quick Start
12
-
13
18
  ### Locale-Specific Mode
14
19
 
15
20
  Pass a locale to get pre-resolved labels and values in that language:
@@ -72,6 +77,32 @@ const result = await client.submitContactForm({
72
77
  // → { success: true, emailStatus: 'sent' }
73
78
  ```
74
79
 
80
+ ## Configuration
81
+
82
+ Your website needs two environment variables to connect to the Praxium platform, plus an optional third for webhook-based cache revalidation:
83
+
84
+ **Required:**
85
+
86
+ | Variable | Purpose | Example |
87
+ |----------|---------|---------|
88
+ | `PRAXIUM_API_URL` | Your tenant's admin portal URL. The SDK sends API requests to this host. | `https://ijfysio.admin.praxium.nl` |
89
+ | `PRAXIUM_API_KEY` | HMAC API key for authentication. Generated in the admin portal under API Profiles. The tenant slug is embedded in the key — no need to configure it separately. | `hmac_v1_ijfysio_default_17..._abc...` |
90
+
91
+ **Optional (only if using ISR revalidation webhooks):**
92
+
93
+ | Variable | Purpose | Example |
94
+ |----------|---------|---------|
95
+ | `PRAXIUM_WEBHOOK_SECRET` | Shared secret for webhook signature verification. Only needed if you want the platform to notify your site when data changes (team, FAQ, opening hours). See [Webhooks](#webhooks). | (32+ character random string) |
96
+
97
+ ```bash
98
+ # .env.local
99
+ PRAXIUM_API_URL="https://mypractice.admin.praxium.nl"
100
+ PRAXIUM_API_KEY="hmac_v1_mypractice_default_1234567890_abcdef..."
101
+ PRAXIUM_WEBHOOK_SECRET="your-webhook-secret-from-admin-portal" # optional
102
+ ```
103
+
104
+ > **How tenant routing works:** Each tenant has its own admin subdomain (`{slug}.admin.praxium.nl`). The platform identifies your tenant from both the hostname AND the API key's embedded slug, cross-validating them for security. You don't need to configure the tenant slug separately — it's derived from your API key automatically.
105
+
75
106
  ## Available Methods
76
107
 
77
108
  | Method | Description |
@@ -118,21 +149,39 @@ try {
118
149
  | `PraxiumRateLimitError` | 429 | Too many requests |
119
150
  | `PraxiumError` | Other | Base class for all errors |
120
151
 
121
- ## Next.js ISR Revalidation
152
+ ## Webhooks
153
+
154
+ When an admin updates data (team, FAQ, opening hours), the platform sends an HMAC-signed webhook to your registered endpoint. You can use this to react to entity changes in any way your application needs.
155
+
156
+ **Common use cases:**
122
157
 
123
- For websites using Next.js [ISR (Incremental Static Regeneration)](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration), the SDK provides a webhook handler for on-demand cache revalidation. When an admin updates data (team, FAQ, opening hours), the platform sends an HMAC-signed webhook to your revalidation endpoint. The handler verifies the signature and calls `revalidatePath()` for the affected pages.
158
+ | Use Case | What you do on entity change |
159
+ |----------|------------------------------|
160
+ | **ISR revalidation** | Call `revalidatePath()` to refresh cached pages |
161
+ | **Search index** | Re-index changed entities in your search engine |
162
+ | **CDN cache** | Purge cached API responses or assets |
163
+
164
+ **Prerequisites:**
165
+
166
+ 1. Register your webhook endpoint URL in the admin portal (Settings → Webhooks)
167
+ 2. Set `PRAXIUM_WEBHOOK_SECRET` to the shared secret from the admin portal
168
+
169
+ All webhook handlers include HMAC-SHA256 signature verification, timestamp-based replay protection (5-minute window), and timing-safe comparison.
170
+
171
+ ### Next.js ISR Revalidation
172
+
173
+ The SDK provides a ready-made handler for Next.js [ISR](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration) revalidation. It verifies the webhook signature and calls `revalidatePath()` for the affected pages.
124
174
 
125
175
  The `pathMap` is fully customizable — you define which pages to revalidate for each entity based on your website's routing structure:
126
176
 
127
177
  ```typescript
128
178
  // app/api/revalidate/route.ts
129
- import { createRevalidationHandler } from '@praxium/sdk/revalidation'
179
+ import { createRevalidationHandler } from '@praxium/sdk/webhooks'
130
180
 
131
181
  export const POST = createRevalidationHandler({
132
- secret: process.env.PRAXIUM_REVALIDATION_SECRET!,
182
+ secret: process.env.PRAXIUM_WEBHOOK_SECRET!,
133
183
  // Map platform entities to YOUR website's page paths.
134
- // These are specific to your project's routing structure
135
- // adjust the paths to match your pages.
184
+ // Adjust the paths to match your project's routing structure.
136
185
  pathMap: {
137
186
  'team': ['/nl/team', '/en/team'],
138
187
  'rates': ['/nl/tarieven', '/en/rates'],
@@ -143,9 +192,35 @@ export const POST = createRevalidationHandler({
143
192
  })
144
193
  ```
145
194
 
146
- **Prerequisites:** Register your revalidation endpoint URL in the admin portal (Settings → Webhooks) before the platform can send webhook events to your website.
195
+ Requires `next` as a peer dependency.
196
+
197
+ ### Custom Webhook Handler
198
+
199
+ For non-Next.js use cases or custom logic, use `processWebhook()` to verify the signature and extract the changed entity:
200
+
201
+ ```typescript
202
+ // Example: invalidate a Redis cache on entity change
203
+ import { processWebhook, WEBHOOK_SIGNATURE_HEADER } from '@praxium/sdk/webhooks'
204
+
205
+ export async function POST(request: Request) {
206
+ const body = await request.text()
207
+
208
+ const result = await processWebhook({
209
+ body,
210
+ signature: request.headers.get(WEBHOOK_SIGNATURE_HEADER)!,
211
+ secret: process.env.PRAXIUM_WEBHOOK_SECRET!,
212
+ })
213
+
214
+ if (!result.valid) {
215
+ return new Response(result.error, { status: 401 })
216
+ }
217
+
218
+ // result.entity = 'team' | 'faq' | 'rates' | ...
219
+ await redis.del(`cache:${result.entity}`)
147
220
 
148
- The handler includes HMAC-SHA256 signature verification, timestamp-based replay protection (5-minute window), and timing-safe comparison. Requires `next` as a peer dependency.
221
+ return new Response('OK')
222
+ }
223
+ ```
149
224
 
150
225
  ## Contributing
151
226
 
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Praxium Webhook Utilities
3
+ *
4
+ * Process and verify webhooks sent by the Praxium platform when entity
5
+ * data changes (team, FAQ, opening hours, etc.).
6
+ *
7
+ * Two levels of abstraction:
8
+ *
9
+ * **`processWebhook()`** — Framework-agnostic. Verifies HMAC signature,
10
+ * checks timestamp freshness, parses the body, and returns the entity
11
+ * that changed. Use this with Express, Fastify, or any custom handler.
12
+ *
13
+ * **`createRevalidationHandler()`** — Next.js-specific. Wraps processWebhook
14
+ * with path resolution and `revalidatePath()` calls. Returns a ready-made
15
+ * route handler for `app/api/revalidate/route.ts`.
16
+ *
17
+ * Signature scheme (H6):
18
+ * X-Praxium-Signature: t={unix_timestamp},sha256={HMAC-SHA256(secret, timestamp.body)}
19
+ *
20
+ * Security features:
21
+ * - HMAC-SHA256 signature verification (secret never sent in body)
22
+ * - Timestamp-based replay protection (default 5-minute window)
23
+ * - Timing-safe signature comparison (prevents timing side-channel attacks)
24
+ * - Web Crypto API (platform-agnostic: Edge, Node.js, browser)
25
+ *
26
+ * @example
27
+ * // Framework-agnostic (Express, Fastify, etc.):
28
+ * import { processWebhook } from '@praxium/sdk/webhooks'
29
+ *
30
+ * const result = await processWebhook({
31
+ * body: rawBody,
32
+ * signature: req.headers['x-praxium-signature'],
33
+ * secret: process.env.PRAXIUM_WEBHOOK_SECRET!,
34
+ * })
35
+ * if (result.valid) console.log('Entity changed:', result.entity)
36
+ *
37
+ * @example
38
+ * // Next.js ISR revalidation:
39
+ * import { createRevalidationHandler } from '@praxium/sdk/webhooks'
40
+ *
41
+ * export const POST = createRevalidationHandler({
42
+ * secret: process.env.PRAXIUM_WEBHOOK_SECRET!,
43
+ * pathMap: { 'team': ['/nl/team', '/en/team'] },
44
+ * })
45
+ */
46
+ /** Header name for the HMAC signature */
47
+ declare const WEBHOOK_SIGNATURE_HEADER = "X-Praxium-Signature";
48
+ /** Input for processWebhook() */
49
+ interface ProcessWebhookInput {
50
+ /** Raw request body as string */
51
+ body: string;
52
+ /** Value of the X-Praxium-Signature header */
53
+ signature: string;
54
+ /** Shared secret for HMAC verification */
55
+ secret: string;
56
+ /** Maximum age of request timestamp in milliseconds (default: 5 minutes) */
57
+ maxTimestampAge?: number;
58
+ }
59
+ /** Successful webhook processing result */
60
+ interface WebhookSuccess {
61
+ valid: true;
62
+ /** Entity type that changed (e.g., 'team', 'rates', 'faq') */
63
+ entity: string | undefined;
64
+ }
65
+ /** Failed webhook processing result */
66
+ interface WebhookFailure {
67
+ valid: false;
68
+ /** Human-readable error description */
69
+ error: string;
70
+ }
71
+ /** Result of processWebhook() */
72
+ type WebhookResult = WebhookSuccess | WebhookFailure;
73
+ /** Configuration for createRevalidationHandler() */
74
+ interface RevalidationConfig {
75
+ /** Shared secret for HMAC signature verification */
76
+ secret: string;
77
+ /** Maximum age of request timestamp in milliseconds (default: 5 minutes) */
78
+ maxTimestampAge?: number;
79
+ /**
80
+ * Entity → full paths to revalidate (including locale prefix).
81
+ *
82
+ * Paths are specific to YOUR website's routing structure.
83
+ * When a webhook arrives with `{ entity: 'team' }`, the handler looks up
84
+ * `pathMap['team']` and calls `revalidatePath()` for each path.
85
+ *
86
+ * Unknown entities fall back to revalidating ALL registered paths.
87
+ *
88
+ * @example
89
+ * pathMap: {
90
+ * 'team': ['/nl/team', '/en/team'],
91
+ * 'rates': ['/nl/tarieven', '/en/rates'],
92
+ * 'opening-hours': ['/nl', '/en'],
93
+ * }
94
+ */
95
+ pathMap: Record<string, string[]>;
96
+ }
97
+ /**
98
+ * Process and verify a Praxium platform webhook.
99
+ *
100
+ * Verifies the HMAC-SHA256 signature, checks timestamp freshness (replay
101
+ * protection), and parses the webhook body to extract the changed entity.
102
+ *
103
+ * Use this for custom webhook handling in any framework (Express, Fastify,
104
+ * Deno, etc.). For Next.js ISR revalidation, use createRevalidationHandler()
105
+ * which wraps this with path resolution and revalidatePath() calls.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * import { processWebhook } from '@praxium/sdk/webhooks'
110
+ *
111
+ * const result = await processWebhook({
112
+ * body: rawBody,
113
+ * signature: req.headers['x-praxium-signature'],
114
+ * secret: process.env.PRAXIUM_WEBHOOK_SECRET!,
115
+ * })
116
+ *
117
+ * if (result.valid) {
118
+ * await redis.del(`cache:${result.entity}`)
119
+ * }
120
+ * ```
121
+ */
122
+ declare function processWebhook(input: ProcessWebhookInput): Promise<WebhookResult>;
123
+ /**
124
+ * Resolve entity to revalidation paths using the pathMap.
125
+ *
126
+ * Resolution priority:
127
+ * 1. pathMap[entity] → pre-computed paths for this entity
128
+ * 2. Unknown/missing entity → deduplicated union of ALL pathMap values
129
+ */
130
+ declare function resolveRevalidationPaths(entity: string | undefined, pathMap: Record<string, string[]>): {
131
+ paths: string[];
132
+ fallback: boolean;
133
+ };
134
+ /**
135
+ * Creates a Next.js route handler that revalidates ISR pages
136
+ * when triggered by a Praxium platform webhook.
137
+ *
138
+ * Wraps processWebhook() with path resolution and revalidatePath() calls.
139
+ * Returns a Fetch API handler `(request: Request) => Promise<Response>`
140
+ * compatible with Next.js App Router route exports.
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * // app/api/revalidate/route.ts
145
+ * import { createRevalidationHandler } from '@praxium/sdk/webhooks'
146
+ *
147
+ * export const POST = createRevalidationHandler({
148
+ * secret: process.env.PRAXIUM_WEBHOOK_SECRET!,
149
+ * pathMap: {
150
+ * 'team': ['/nl/team', '/en/team'],
151
+ * 'rates': ['/nl/tarieven', '/en/rates'],
152
+ * 'faq': ['/nl/faq', '/en/faq'],
153
+ * 'opening-hours': ['/nl', '/en'],
154
+ * },
155
+ * })
156
+ * ```
157
+ */
158
+ declare function createRevalidationHandler(config: RevalidationConfig): (request: Request) => Promise<Response>;
159
+
160
+ export { type ProcessWebhookInput, type RevalidationConfig, WEBHOOK_SIGNATURE_HEADER, type WebhookFailure, type WebhookResult, type WebhookSuccess, createRevalidationHandler, processWebhook, resolveRevalidationPaths };
@@ -1,5 +1,5 @@
1
- // src/revalidation.ts
2
- var SIGNATURE_HEADER = "X-Praxium-Signature";
1
+ // src/webhooks.ts
2
+ var WEBHOOK_SIGNATURE_HEADER = "X-Praxium-Signature";
3
3
  var DEFAULT_MAX_TIMESTAMP_AGE_MS = 5 * 60 * 1e3;
4
4
  var CLOCK_SKEW_TOLERANCE_MS = 5 * 60 * 1e3;
5
5
  async function computeHmacSignature(secret, payload) {
@@ -46,6 +46,36 @@ function parseSignatureHeader(headerValue) {
46
46
  signature: signatureMatch[1]
47
47
  };
48
48
  }
49
+ async function processWebhook(input) {
50
+ const {
51
+ body,
52
+ signature: signatureHeader,
53
+ secret,
54
+ maxTimestampAge = DEFAULT_MAX_TIMESTAMP_AGE_MS
55
+ } = input;
56
+ const parsed = parseSignatureHeader(signatureHeader);
57
+ if (!parsed) {
58
+ return { valid: false, error: "Invalid signature format" };
59
+ }
60
+ const requestAgeMs = Date.now() - parsed.timestamp * 1e3;
61
+ if (requestAgeMs < -CLOCK_SKEW_TOLERANCE_MS) {
62
+ return { valid: false, error: "Request timestamp is in the future" };
63
+ }
64
+ if (requestAgeMs > maxTimestampAge) {
65
+ return { valid: false, error: "Request timestamp expired" };
66
+ }
67
+ const payload = `${parsed.timestamp}.${body}`;
68
+ const expectedSignature = await computeHmacSignature(secret, payload);
69
+ if (!isSecretValid(parsed.signature, expectedSignature)) {
70
+ return { valid: false, error: "Invalid signature" };
71
+ }
72
+ try {
73
+ const parsedBody = body ? JSON.parse(body) : {};
74
+ return { valid: true, entity: parsedBody.entity };
75
+ } catch {
76
+ return { valid: false, error: "Invalid JSON body" };
77
+ }
78
+ }
49
79
  function resolveRevalidationPaths(entity, pathMap) {
50
80
  if (entity && pathMap[entity]) {
51
81
  return { paths: pathMap[entity], fallback: false };
@@ -54,60 +84,32 @@ function resolveRevalidationPaths(entity, pathMap) {
54
84
  return { paths: allPaths, fallback: true };
55
85
  }
56
86
  function createRevalidationHandler(config) {
57
- const maxTimestampAge = config.maxTimestampAge ?? DEFAULT_MAX_TIMESTAMP_AGE_MS;
58
87
  return async (request) => {
59
- const signatureHeader = request.headers.get(SIGNATURE_HEADER);
88
+ const signatureHeader = request.headers.get(WEBHOOK_SIGNATURE_HEADER);
60
89
  if (!signatureHeader) {
61
90
  return Response.json(
62
- { error: `Missing ${SIGNATURE_HEADER} header` },
63
- { status: 401 }
64
- );
65
- }
66
- const parsed = parseSignatureHeader(signatureHeader);
67
- if (!parsed) {
68
- return Response.json(
69
- { error: "Invalid signature format" },
70
- { status: 401 }
71
- );
72
- }
73
- const requestAgeMs = Date.now() - parsed.timestamp * 1e3;
74
- if (requestAgeMs < -CLOCK_SKEW_TOLERANCE_MS) {
75
- return Response.json(
76
- { error: "Request timestamp is in the future" },
77
- { status: 401 }
78
- );
79
- }
80
- if (requestAgeMs > maxTimestampAge) {
81
- return Response.json(
82
- { error: "Request timestamp expired" },
91
+ { error: `Missing ${WEBHOOK_SIGNATURE_HEADER} header` },
83
92
  { status: 401 }
84
93
  );
85
94
  }
86
95
  const rawBody = await request.text();
87
- const payload = `${parsed.timestamp}.${rawBody}`;
88
- const expectedSignature = await computeHmacSignature(
89
- config.secret,
90
- payload
91
- );
92
- if (!isSecretValid(parsed.signature, expectedSignature)) {
93
- return Response.json(
94
- { error: "Invalid signature" },
95
- { status: 401 }
96
- );
97
- }
98
- let body;
99
- try {
100
- body = rawBody ? JSON.parse(rawBody) : {};
101
- } catch {
102
- return Response.json({ error: "Invalid JSON body" }, { status: 400 });
96
+ const result = await processWebhook({
97
+ body: rawBody,
98
+ signature: signatureHeader,
99
+ secret: config.secret,
100
+ maxTimestampAge: config.maxTimestampAge
101
+ });
102
+ if (!result.valid) {
103
+ const status = result.error === "Invalid JSON body" ? 400 : 401;
104
+ return Response.json({ error: result.error }, { status });
103
105
  }
104
106
  const { paths, fallback } = resolveRevalidationPaths(
105
- body.entity,
107
+ result.entity,
106
108
  config.pathMap
107
109
  );
108
110
  if (fallback) {
109
111
  console.warn(
110
- `[Revalidation] Unknown entity "${body.entity ?? "(none)"}" \u2014 falling back to full revalidation (${paths.length} paths)`
112
+ `[Webhook] Unknown entity "${result.entity ?? "(none)"}" \u2014 falling back to full revalidation (${paths.length} paths)`
111
113
  );
112
114
  }
113
115
  try {
@@ -125,6 +127,8 @@ function createRevalidationHandler(config) {
125
127
  };
126
128
  }
127
129
  export {
130
+ WEBHOOK_SIGNATURE_HEADER,
128
131
  createRevalidationHandler,
132
+ processWebhook,
129
133
  resolveRevalidationPaths
130
134
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxium/sdk",
3
- "version": "0.3.56",
3
+ "version": "0.3.66",
4
4
  "description": "Official TypeScript SDK for the Praxium platform API",
5
5
  "type": "module",
6
6
  "exports": {
@@ -8,9 +8,9 @@
8
8
  "import": "./dist/index.js",
9
9
  "types": "./dist/index.d.ts"
10
10
  },
11
- "./revalidation": {
12
- "import": "./dist/revalidation.js",
13
- "types": "./dist/revalidation.d.ts"
11
+ "./webhooks": {
12
+ "import": "./dist/webhooks.js",
13
+ "types": "./dist/webhooks.d.ts"
14
14
  }
15
15
  },
16
16
  "files": [
@@ -18,8 +18,8 @@
18
18
  ],
19
19
  "scripts": {
20
20
  "generate": "openapi-ts",
21
- "build": "tsup src/index.ts src/revalidation.ts --format esm --dts --clean --external next",
22
- "typecheck": "tsc --noEmit",
21
+ "build": "tsup",
22
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
23
23
  "test": "vitest run",
24
24
  "test:watch": "vitest"
25
25
  },
@@ -1,95 +0,0 @@
1
- /**
2
- * ISR Revalidation Handler for Tenant Websites
3
- *
4
- * When admin updates data in the platform, a webhook triggers
5
- * revalidation on the tenant's public website. This handler
6
- * validates the HMAC signature and calls Next.js revalidatePath().
7
- *
8
- * Architecture (entity-driven, three-layer path agnosticism):
9
- * - Monolith sends { entity } — knows WHAT changed, not WHERE
10
- * - SDK looks up pathMap[entity] — pure lookup + security, path-agnostic
11
- * - Tenant website provides pathMap — owns WHERE pages live (locale-prefixed)
12
- *
13
- * Signature scheme (H6):
14
- * X-Praxium-Signature: t={unix_timestamp},sha256={HMAC-SHA256(secret, timestamp.body)}
15
- *
16
- * Security features:
17
- * - HMAC-SHA256 signature verification (secret never sent in body)
18
- * - Timestamp-based replay protection (default 5-minute window)
19
- * - Timing-safe signature comparison (prevents timing side-channel attacks)
20
- * - Web Crypto API (platform-agnostic: Edge, Node.js, browser)
21
- *
22
- * Usage in tenant website's `app/api/revalidate/route.ts`:
23
- *
24
- * ```ts
25
- * import { createRevalidationHandler } from '@praxium/sdk/revalidation'
26
- *
27
- * export const POST = createRevalidationHandler({
28
- * secret: process.env.PRAXIUM_REVALIDATION_SECRET!,
29
- * pathMap: {
30
- * 'team': ['/nl/team', '/en/team'],
31
- * 'rates': ['/nl/tarieven', '/en/rates'],
32
- * 'faq': ['/nl/faq', '/en/faq'],
33
- * 'opening-hours': ['/nl', '/en'],
34
- * 'all': ['/nl', '/en'],
35
- * },
36
- * })
37
- * ```
38
- */
39
- interface RevalidationConfig {
40
- /** Shared secret for HMAC signature verification */
41
- secret: string;
42
- /** Maximum age of request timestamp in milliseconds (default: 5 minutes) */
43
- maxTimestampAge?: number;
44
- /**
45
- * Entity → full paths to revalidate (including locale prefix).
46
- *
47
- * Paths are pre-computed by the tenant website — SDK does no path manipulation.
48
- * Each tenant configures its own paths based on its URL structure and locales.
49
- *
50
- * When a webhook arrives with `{ entity: 'team' }`, the SDK looks up
51
- * `pathMap['team']` and calls `revalidatePath()` for each path.
52
- *
53
- * Unknown entities fall back to revalidating ALL registered paths (union of
54
- * all pathMap values) with a console warning.
55
- *
56
- * @example
57
- * pathMap: {
58
- * 'team': ['/nl/team', '/en/team'],
59
- * 'rates': ['/nl/tarieven', '/en/rates'],
60
- * 'opening-hours': ['/nl', '/en'],
61
- * }
62
- */
63
- pathMap: Record<string, string[]>;
64
- }
65
- /**
66
- * Resolve entity to revalidation paths using the tenant's pathMap.
67
- *
68
- * The SDK is path-agnostic — it performs a pure lookup against the
69
- * tenant-provided pathMap. Paths are pre-computed by the tenant website
70
- * including locale prefixes (e.g., '/nl/tarieven', '/en/rates').
71
- *
72
- * Resolution priority:
73
- * 1. pathMap[entity] → pre-computed paths for this entity
74
- * 2. Unknown/missing entity → deduplicated union of ALL pathMap values
75
- * (full site revalidation as safe fallback)
76
- *
77
- * @returns paths to revalidate and whether fallback was used
78
- */
79
- declare function resolveRevalidationPaths(entity: string | undefined, pathMap: Record<string, string[]>): {
80
- paths: string[];
81
- fallback: boolean;
82
- };
83
- /**
84
- * Creates a Next.js route handler that revalidates ISR pages
85
- * when triggered by the Praxium platform webhook.
86
- *
87
- * Authentication uses HMAC-SHA256 signature verification with
88
- * timestamp-based replay protection (H6 security scheme).
89
- *
90
- * Path resolution is entity-driven: the monolith sends `{ entity }`,
91
- * the SDK looks up `pathMap[entity]` for pre-computed full paths.
92
- */
93
- declare function createRevalidationHandler(config: RevalidationConfig): (request: Request) => Promise<Response>;
94
-
95
- export { createRevalidationHandler, resolveRevalidationPaths };