@reblu/site-client 5.8.0 → 5.10.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.
package/dist/index.d.cts CHANGED
@@ -1,6 +1,35 @@
1
1
  import * as _reblu_site_contracts from '@reblu/site-contracts';
2
2
  import { AcademyCourseSort, PaginationMeta, PageType, PagesListSort, ShopSort, TrustBadgeType } from '@reblu/site-contracts';
3
3
 
4
+ /**
5
+ * Cache adapter — the seam that severs the SDK from any framework's caching
6
+ * model (design doc D4 / §3.2). The client owns *when* to cache (a per-call
7
+ * `RebluCachePolicy`); the adapter owns *how* (the framework-specific
8
+ * `RequestInit` fields). `@reblu/site-client` ships the framework-agnostic
9
+ * `PlainCacheAdapter`; `@reblu/site-next` (REB-418) supplies a `NextCacheAdapter`
10
+ * that returns `{ next: { revalidate } }`.
11
+ */
12
+ interface RebluCachePolicy {
13
+ /**
14
+ * Seconds to revalidate. `undefined` → use the adapter's default; `0`/`false`
15
+ * → never cache (always fetch fresh).
16
+ */
17
+ revalidate?: number | false;
18
+ }
19
+ interface RebluCacheAdapter {
20
+ /** Map a per-call cache policy to framework-specific `fetch` `RequestInit` fields. */
21
+ resolveRequestInit(policy: RebluCachePolicy): RequestInit;
22
+ }
23
+ /**
24
+ * Default adapter — plain `fetch` cache semantics that work in Node, edge,
25
+ * browser and tests. No `next`, no `server-only`.
26
+ */
27
+ declare class PlainCacheAdapter implements RebluCacheAdapter {
28
+ private readonly defaultRevalidate;
29
+ constructor(defaultRevalidate?: number | false);
30
+ resolveRequestInit(policy: RebluCachePolicy): RequestInit;
31
+ }
32
+
4
33
  /**
5
34
  * The shape every list method returns. Unlike demo-site's old bare-array return,
6
35
  * the SDK surfaces `meta` so pagination is never silently dropped (design doc
@@ -118,33 +147,31 @@ interface AcademyEnrollmentRequestResult {
118
147
  }
119
148
 
120
149
  /**
121
- * Cache adapter — the seam that severs the SDK from any framework's caching
122
- * model (design doc D4 / §3.2). The client owns *when* to cache (a per-call
123
- * `RebluCachePolicy`); the adapter owns *how* (the framework-specific
124
- * `RequestInit` fields). `@reblu/site-client` ships the framework-agnostic
125
- * `PlainCacheAdapter`; `@reblu/site-next` (REB-418) supplies a `NextCacheAdapter`
126
- * that returns `{ next: { revalidate } }`.
150
+ * Header carrying the visitor IP from a SITE server to base-api (REB-1005).
151
+ * base-api keys its per-visitor limit on public writes on it, and trusts it
152
+ * only behind a valid API key.
127
153
  */
128
- interface RebluCachePolicy {
129
- /**
130
- * Seconds to revalidate. `undefined` → use the adapter's default; `0`/`false`
131
- * → never cache (always fetch fresh).
132
- */
133
- revalidate?: number | false;
134
- }
135
- interface RebluCacheAdapter {
136
- /** Map a per-call cache policy to framework-specific `fetch` `RequestInit` fields. */
137
- resolveRequestInit(policy: RebluCachePolicy): RequestInit;
138
- }
154
+ declare const VISITOR_IP_HEADER = "x-reblu-visitor-ip";
139
155
  /**
140
- * Default adapter — plain `fetch` cache semantics that work in Node, edge,
141
- * browser and tests. No `next`, no `server-only`.
156
+ * Per-call options for a write (REB-1005).
157
+ *
158
+ * - `visitorIp` — the visitor's IP when a SITE calls the SDK server-side, sent
159
+ * as `x-reblu-visitor-ip`. Do NOT rely on forwarding `x-forwarded-for`: on
160
+ * Vercel the SITE→base-api hop gets it overwritten with the SITE function's
161
+ * egress IP. Read it from the INCOMING request with
162
+ * {@link visitorIpFromHeaders}.
163
+ * - `headers` — other extra headers (e.g. `user-agent`). They can never set
164
+ * `x-reblu-visitor-ip` nor replace `X-Reblu-Api-Key`, `X-Reblu-Api-Version`
165
+ * or `Content-Type`.
142
166
  */
143
- declare class PlainCacheAdapter implements RebluCacheAdapter {
144
- private readonly defaultRevalidate;
145
- constructor(defaultRevalidate?: number | false);
146
- resolveRequestInit(policy: RebluCachePolicy): RequestInit;
167
+ interface RebluMutationOptions {
168
+ visitorIp?: string;
169
+ headers?: Record<string, string>;
147
170
  }
171
+ /** The visitor IP of an incoming request: first `x-forwarded-for` entry, else `x-real-ip`. */
172
+ declare function visitorIpFromHeaders(headers: {
173
+ get(name: string): string | null;
174
+ }): string | undefined;
148
175
 
149
176
  /**
150
177
  * The `details` shape `/api/site/contact-form` and `/api/site/leads` attach on a
@@ -364,26 +391,26 @@ declare function createRebluClient(config: RebluClientConfig): {
364
391
  checkout: (body: _reblu_site_contracts.ShopCheckoutInput) => Promise<_reblu_site_contracts.ShopCheckoutSession>;
365
392
  validateCart: (body: _reblu_site_contracts.ShopValidateCartInput) => Promise<_reblu_site_contracts.ShopCartValidation>;
366
393
  applyDiscount: (body: _reblu_site_contracts.ShopApplyDiscountInput) => Promise<_reblu_site_contracts.ShopDiscountApplication>;
367
- checkEmail: (body: _reblu_site_contracts.ShopCheckEmailInput) => Promise<_reblu_site_contracts.ShopEmailCheck>;
394
+ checkEmail: (body: _reblu_site_contracts.ShopCheckEmailInput, options?: RebluMutationOptions) => Promise<_reblu_site_contracts.ShopEmailCheck>;
368
395
  order: (sessionId: string, cache?: RebluCachePolicy) => Promise<_reblu_site_contracts.ShopOrder>;
369
396
  };
370
397
  academy: {
371
398
  courses: (params?: AcademyCourseListParams, cache?: RebluCachePolicy) => Promise<ListResult<_reblu_site_contracts.AcademyCourseSummary>>;
372
399
  bySlug: (slug: string, cache?: RebluCachePolicy) => Promise<_reblu_site_contracts.AcademyCourseDetail>;
373
400
  categories: (cache?: RebluCachePolicy) => Promise<ListResult<_reblu_site_contracts.AcademyCategoryPublic>>;
374
- enrollmentRequest: (body: AcademyEnrollmentRequestInput) => Promise<AcademyEnrollmentRequestResult>;
401
+ enrollmentRequest: (body: AcademyEnrollmentRequestInput, options?: RebluMutationOptions) => Promise<AcademyEnrollmentRequestResult>;
375
402
  };
376
403
  contactForm: {
377
- submit: (body: _reblu_site_contracts.ContactFormInput) => Promise<_reblu_site_contracts.ContactFormSubmission>;
404
+ submit: (body: _reblu_site_contracts.ContactFormInput, options?: RebluMutationOptions) => Promise<_reblu_site_contracts.ContactFormSubmission>;
378
405
  };
379
406
  leads: {
380
407
  create: (body: _reblu_site_contracts.LeadInput) => Promise<_reblu_site_contracts.LeadSubmission>;
381
408
  };
382
409
  dataRequests: {
383
- submit: (body: _reblu_site_contracts.DataRequestInput) => Promise<_reblu_site_contracts.DataRequestSubmission>;
410
+ submit: (body: _reblu_site_contracts.DataRequestInput, options?: RebluMutationOptions) => Promise<_reblu_site_contracts.DataRequestSubmission>;
384
411
  };
385
412
  };
386
413
  /** The assembled client returned by {@link createRebluClient}. */
387
414
  type RebluClient = ReturnType<typeof createRebluClient>;
388
415
 
389
- export { type AcademyCourseListParams, type AcademyEnrollmentRequestInput, type AcademyEnrollmentRequestResult, AmbiguousPageSlugError, ApiError, type ApiErrorBody, type ApiErrorDetails, type BlogListParams, DEFAULT_CHECKOUT_REDIRECT_HOSTS, type FeaturedPagesOptions, type ListResult, type PageBySlugOptions, type PageSlugCandidate, type PagesListParams, PlainCacheAdapter, type RebluCacheAdapter, type RebluCachePolicy, type RebluClient, type RebluClientConfig, type ShopProductsParams, type TrustBadgeListParams, UnsafeCheckoutRedirectError, createRebluClient, isSafeCheckoutRedirectUrl };
416
+ export { type AcademyCourseListParams, type AcademyEnrollmentRequestInput, type AcademyEnrollmentRequestResult, AmbiguousPageSlugError, ApiError, type ApiErrorBody, type ApiErrorDetails, type BlogListParams, DEFAULT_CHECKOUT_REDIRECT_HOSTS, type FeaturedPagesOptions, type ListResult, type PageBySlugOptions, type PageSlugCandidate, type PagesListParams, PlainCacheAdapter, type RebluCacheAdapter, type RebluCachePolicy, type RebluClient, type RebluClientConfig, type RebluMutationOptions, type ShopProductsParams, type TrustBadgeListParams, UnsafeCheckoutRedirectError, VISITOR_IP_HEADER, createRebluClient, isSafeCheckoutRedirectUrl, visitorIpFromHeaders };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,35 @@
1
1
  import * as _reblu_site_contracts from '@reblu/site-contracts';
2
2
  import { AcademyCourseSort, PaginationMeta, PageType, PagesListSort, ShopSort, TrustBadgeType } from '@reblu/site-contracts';
3
3
 
4
+ /**
5
+ * Cache adapter — the seam that severs the SDK from any framework's caching
6
+ * model (design doc D4 / §3.2). The client owns *when* to cache (a per-call
7
+ * `RebluCachePolicy`); the adapter owns *how* (the framework-specific
8
+ * `RequestInit` fields). `@reblu/site-client` ships the framework-agnostic
9
+ * `PlainCacheAdapter`; `@reblu/site-next` (REB-418) supplies a `NextCacheAdapter`
10
+ * that returns `{ next: { revalidate } }`.
11
+ */
12
+ interface RebluCachePolicy {
13
+ /**
14
+ * Seconds to revalidate. `undefined` → use the adapter's default; `0`/`false`
15
+ * → never cache (always fetch fresh).
16
+ */
17
+ revalidate?: number | false;
18
+ }
19
+ interface RebluCacheAdapter {
20
+ /** Map a per-call cache policy to framework-specific `fetch` `RequestInit` fields. */
21
+ resolveRequestInit(policy: RebluCachePolicy): RequestInit;
22
+ }
23
+ /**
24
+ * Default adapter — plain `fetch` cache semantics that work in Node, edge,
25
+ * browser and tests. No `next`, no `server-only`.
26
+ */
27
+ declare class PlainCacheAdapter implements RebluCacheAdapter {
28
+ private readonly defaultRevalidate;
29
+ constructor(defaultRevalidate?: number | false);
30
+ resolveRequestInit(policy: RebluCachePolicy): RequestInit;
31
+ }
32
+
4
33
  /**
5
34
  * The shape every list method returns. Unlike demo-site's old bare-array return,
6
35
  * the SDK surfaces `meta` so pagination is never silently dropped (design doc
@@ -118,33 +147,31 @@ interface AcademyEnrollmentRequestResult {
118
147
  }
119
148
 
120
149
  /**
121
- * Cache adapter — the seam that severs the SDK from any framework's caching
122
- * model (design doc D4 / §3.2). The client owns *when* to cache (a per-call
123
- * `RebluCachePolicy`); the adapter owns *how* (the framework-specific
124
- * `RequestInit` fields). `@reblu/site-client` ships the framework-agnostic
125
- * `PlainCacheAdapter`; `@reblu/site-next` (REB-418) supplies a `NextCacheAdapter`
126
- * that returns `{ next: { revalidate } }`.
150
+ * Header carrying the visitor IP from a SITE server to base-api (REB-1005).
151
+ * base-api keys its per-visitor limit on public writes on it, and trusts it
152
+ * only behind a valid API key.
127
153
  */
128
- interface RebluCachePolicy {
129
- /**
130
- * Seconds to revalidate. `undefined` → use the adapter's default; `0`/`false`
131
- * → never cache (always fetch fresh).
132
- */
133
- revalidate?: number | false;
134
- }
135
- interface RebluCacheAdapter {
136
- /** Map a per-call cache policy to framework-specific `fetch` `RequestInit` fields. */
137
- resolveRequestInit(policy: RebluCachePolicy): RequestInit;
138
- }
154
+ declare const VISITOR_IP_HEADER = "x-reblu-visitor-ip";
139
155
  /**
140
- * Default adapter — plain `fetch` cache semantics that work in Node, edge,
141
- * browser and tests. No `next`, no `server-only`.
156
+ * Per-call options for a write (REB-1005).
157
+ *
158
+ * - `visitorIp` — the visitor's IP when a SITE calls the SDK server-side, sent
159
+ * as `x-reblu-visitor-ip`. Do NOT rely on forwarding `x-forwarded-for`: on
160
+ * Vercel the SITE→base-api hop gets it overwritten with the SITE function's
161
+ * egress IP. Read it from the INCOMING request with
162
+ * {@link visitorIpFromHeaders}.
163
+ * - `headers` — other extra headers (e.g. `user-agent`). They can never set
164
+ * `x-reblu-visitor-ip` nor replace `X-Reblu-Api-Key`, `X-Reblu-Api-Version`
165
+ * or `Content-Type`.
142
166
  */
143
- declare class PlainCacheAdapter implements RebluCacheAdapter {
144
- private readonly defaultRevalidate;
145
- constructor(defaultRevalidate?: number | false);
146
- resolveRequestInit(policy: RebluCachePolicy): RequestInit;
167
+ interface RebluMutationOptions {
168
+ visitorIp?: string;
169
+ headers?: Record<string, string>;
147
170
  }
171
+ /** The visitor IP of an incoming request: first `x-forwarded-for` entry, else `x-real-ip`. */
172
+ declare function visitorIpFromHeaders(headers: {
173
+ get(name: string): string | null;
174
+ }): string | undefined;
148
175
 
149
176
  /**
150
177
  * The `details` shape `/api/site/contact-form` and `/api/site/leads` attach on a
@@ -364,26 +391,26 @@ declare function createRebluClient(config: RebluClientConfig): {
364
391
  checkout: (body: _reblu_site_contracts.ShopCheckoutInput) => Promise<_reblu_site_contracts.ShopCheckoutSession>;
365
392
  validateCart: (body: _reblu_site_contracts.ShopValidateCartInput) => Promise<_reblu_site_contracts.ShopCartValidation>;
366
393
  applyDiscount: (body: _reblu_site_contracts.ShopApplyDiscountInput) => Promise<_reblu_site_contracts.ShopDiscountApplication>;
367
- checkEmail: (body: _reblu_site_contracts.ShopCheckEmailInput) => Promise<_reblu_site_contracts.ShopEmailCheck>;
394
+ checkEmail: (body: _reblu_site_contracts.ShopCheckEmailInput, options?: RebluMutationOptions) => Promise<_reblu_site_contracts.ShopEmailCheck>;
368
395
  order: (sessionId: string, cache?: RebluCachePolicy) => Promise<_reblu_site_contracts.ShopOrder>;
369
396
  };
370
397
  academy: {
371
398
  courses: (params?: AcademyCourseListParams, cache?: RebluCachePolicy) => Promise<ListResult<_reblu_site_contracts.AcademyCourseSummary>>;
372
399
  bySlug: (slug: string, cache?: RebluCachePolicy) => Promise<_reblu_site_contracts.AcademyCourseDetail>;
373
400
  categories: (cache?: RebluCachePolicy) => Promise<ListResult<_reblu_site_contracts.AcademyCategoryPublic>>;
374
- enrollmentRequest: (body: AcademyEnrollmentRequestInput) => Promise<AcademyEnrollmentRequestResult>;
401
+ enrollmentRequest: (body: AcademyEnrollmentRequestInput, options?: RebluMutationOptions) => Promise<AcademyEnrollmentRequestResult>;
375
402
  };
376
403
  contactForm: {
377
- submit: (body: _reblu_site_contracts.ContactFormInput) => Promise<_reblu_site_contracts.ContactFormSubmission>;
404
+ submit: (body: _reblu_site_contracts.ContactFormInput, options?: RebluMutationOptions) => Promise<_reblu_site_contracts.ContactFormSubmission>;
378
405
  };
379
406
  leads: {
380
407
  create: (body: _reblu_site_contracts.LeadInput) => Promise<_reblu_site_contracts.LeadSubmission>;
381
408
  };
382
409
  dataRequests: {
383
- submit: (body: _reblu_site_contracts.DataRequestInput) => Promise<_reblu_site_contracts.DataRequestSubmission>;
410
+ submit: (body: _reblu_site_contracts.DataRequestInput, options?: RebluMutationOptions) => Promise<_reblu_site_contracts.DataRequestSubmission>;
384
411
  };
385
412
  };
386
413
  /** The assembled client returned by {@link createRebluClient}. */
387
414
  type RebluClient = ReturnType<typeof createRebluClient>;
388
415
 
389
- export { type AcademyCourseListParams, type AcademyEnrollmentRequestInput, type AcademyEnrollmentRequestResult, AmbiguousPageSlugError, ApiError, type ApiErrorBody, type ApiErrorDetails, type BlogListParams, DEFAULT_CHECKOUT_REDIRECT_HOSTS, type FeaturedPagesOptions, type ListResult, type PageBySlugOptions, type PageSlugCandidate, type PagesListParams, PlainCacheAdapter, type RebluCacheAdapter, type RebluCachePolicy, type RebluClient, type RebluClientConfig, type ShopProductsParams, type TrustBadgeListParams, UnsafeCheckoutRedirectError, createRebluClient, isSafeCheckoutRedirectUrl };
416
+ export { type AcademyCourseListParams, type AcademyEnrollmentRequestInput, type AcademyEnrollmentRequestResult, AmbiguousPageSlugError, ApiError, type ApiErrorBody, type ApiErrorDetails, type BlogListParams, DEFAULT_CHECKOUT_REDIRECT_HOSTS, type FeaturedPagesOptions, type ListResult, type PageBySlugOptions, type PageSlugCandidate, type PagesListParams, PlainCacheAdapter, type RebluCacheAdapter, type RebluCachePolicy, type RebluClient, type RebluClientConfig, type RebluMutationOptions, type ShopProductsParams, type TrustBadgeListParams, UnsafeCheckoutRedirectError, VISITOR_IP_HEADER, createRebluClient, isSafeCheckoutRedirectUrl, visitorIpFromHeaders };
package/dist/index.js CHANGED
@@ -164,11 +164,33 @@ async function requestList(ctx, path, opts) {
164
164
  const body = await request(ctx, path, opts);
165
165
  return { data: body.data, meta: body.meta };
166
166
  }
167
- async function requestMutation(ctx, path, body) {
167
+ var VISITOR_IP_HEADER = "x-reblu-visitor-ip";
168
+ function visitorIpFromHeaders(headers) {
169
+ return headers.get("x-forwarded-for")?.split(",")[0]?.trim() || headers.get("x-real-ip")?.trim() || void 0;
170
+ }
171
+ var RESERVED_HEADERS = /* @__PURE__ */ new Set([
172
+ "x-reblu-api-key",
173
+ "x-reblu-api-version",
174
+ "content-type",
175
+ VISITOR_IP_HEADER
176
+ ]);
177
+ function extraHeaders(options) {
178
+ if (!options?.headers && !options?.visitorIp) return void 0;
179
+ const safe = {};
180
+ for (const [name, value] of Object.entries(options.headers ?? {})) {
181
+ if (!RESERVED_HEADERS.has(name.toLowerCase())) safe[name] = value;
182
+ }
183
+ const visitorIp = options.visitorIp?.trim();
184
+ if (visitorIp) safe[VISITOR_IP_HEADER] = visitorIp;
185
+ return safe;
186
+ }
187
+ async function requestMutation(ctx, path, body, options) {
188
+ const headers = extraHeaders(options);
168
189
  const envelope = await request(ctx, path, {
169
190
  method: "POST",
170
191
  body: JSON.stringify(body),
171
- cachePolicy: { revalidate: false }
192
+ cachePolicy: { revalidate: false },
193
+ ...headers ? { headers } : {}
172
194
  });
173
195
  return envelope.data;
174
196
  }
@@ -197,12 +219,21 @@ function makeAcademyNamespace(ctx) {
197
219
  * was new (a request row was created) or already known (a sign-in link was
198
220
  * sent and NO request row exists). Never present the returned message as
199
221
  * confirmation that a request was recorded — it is not one.
222
+ *
223
+ * Server-side, pass `options.visitorIp` (from the incoming request, see
224
+ * `visitorIpFromHeaders`): base-api keys this route's per-IP limit on it
225
+ * and, without it, throttles every visitor of the SITE in one shared
226
+ * tenant-level bucket (REB-1006).
200
227
  */
201
- enrollmentRequest: (body) => request(ctx, "/api/site/academy/enrollment-requests", {
202
- method: "POST",
203
- body: JSON.stringify(body),
204
- cachePolicy: { revalidate: false }
205
- })
228
+ enrollmentRequest: (body, options) => {
229
+ const headers = extraHeaders(options);
230
+ return request(ctx, "/api/site/academy/enrollment-requests", {
231
+ method: "POST",
232
+ body: JSON.stringify(body),
233
+ cachePolicy: { revalidate: false },
234
+ ...headers ? { headers } : {}
235
+ });
236
+ }
206
237
  };
207
238
  }
208
239
 
@@ -242,8 +273,18 @@ function makeConfigNamespace(ctx) {
242
273
  // src/domains/contact-form.ts
243
274
  function makeContactFormNamespace(ctx) {
244
275
  return {
245
- /** Submit a contact form. Returns the created lead acknowledgement. */
246
- submit: (body) => requestMutation(ctx, "/api/site/contact-form", body)
276
+ /**
277
+ * Submit a contact form. Returns the created lead acknowledgement.
278
+ * Server-side (a Server Action / Route Handler), pass `options.visitorIp`
279
+ * (from the incoming request, see `visitorIpFromHeaders`) so base-api's
280
+ * per-IP limit (REB-1005) applies to the real visitor.
281
+ */
282
+ submit: (body, options) => requestMutation(
283
+ ctx,
284
+ "/api/site/contact-form",
285
+ body,
286
+ options
287
+ )
247
288
  };
248
289
  }
249
290
 
@@ -257,11 +298,17 @@ function makeCtasNamespace(ctx) {
257
298
  // src/domains/data-requests.ts
258
299
  function makeDataRequestsNamespace(ctx) {
259
300
  return {
260
- /** Submit a data-subject request. Returns its acknowledgement with the 72h deadline. */
261
- submit: (body) => requestMutation(
301
+ /**
302
+ * Submit a data-subject request. Returns its acknowledgement with the 72h
303
+ * deadline. Server-side, pass `options.visitorIp` (from the incoming
304
+ * request, see `visitorIpFromHeaders`) so base-api's per-IP limit
305
+ * (REB-1005) sees the real visitor.
306
+ */
307
+ submit: (body, options) => requestMutation(
262
308
  ctx,
263
309
  "/api/site/data-requests",
264
- body
310
+ body,
311
+ options
265
312
  )
266
313
  };
267
314
  }
@@ -399,8 +446,18 @@ function makeShopNamespace(ctx) {
399
446
  * branch UI on `exists`; the checkout always offers «Iniciar sesión o
400
447
  * continuar como invitado» and the server links the order to an existing
401
448
  * account after payment. Removed in the next major.
449
+ *
450
+ * Server-side, pass `options.visitorIp` (from the incoming request, see
451
+ * `visitorIpFromHeaders`): base-api keys this route's per-IP limit on it
452
+ * and, without it, throttles every visitor of the SITE in one shared
453
+ * tenant-level bucket (REB-1006).
402
454
  */
403
- checkEmail: (body) => requestMutation(ctx, "/api/site/shop/check-email", body),
455
+ checkEmail: (body, options) => requestMutation(
456
+ ctx,
457
+ "/api/site/shop/check-email",
458
+ body,
459
+ options
460
+ ),
404
461
  /**
405
462
  * Look up a confirmed (or still-pending) order by its Stripe Checkout
406
463
  * session id — the order-confirmation flow (REB-829). `GET`, so it goes
@@ -459,6 +516,6 @@ function createRebluClient(config) {
459
516
  };
460
517
  }
461
518
 
462
- export { AmbiguousPageSlugError, ApiError, DEFAULT_CHECKOUT_REDIRECT_HOSTS, PlainCacheAdapter, UnsafeCheckoutRedirectError, createRebluClient, isSafeCheckoutRedirectUrl };
519
+ export { AmbiguousPageSlugError, ApiError, DEFAULT_CHECKOUT_REDIRECT_HOSTS, PlainCacheAdapter, UnsafeCheckoutRedirectError, VISITOR_IP_HEADER, createRebluClient, isSafeCheckoutRedirectUrl, visitorIpFromHeaders };
463
520
  //# sourceMappingURL=index.js.map
464
521
  //# sourceMappingURL=index.js.map