@cimplify/sdk 0.53.0 → 0.55.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 (43) hide show
  1. package/dist/advanced.d.mts +1 -1
  2. package/dist/advanced.d.ts +1 -1
  3. package/dist/advanced.js +20 -20
  4. package/dist/advanced.mjs +1 -1
  5. package/dist/{chunk-EJUKGJTZ.js → chunk-6W3AH4QW.js} +2 -2
  6. package/dist/{chunk-NEK7CVE2.mjs → chunk-F4WS3OIF.mjs} +1 -1
  7. package/dist/{chunk-B3Y4C4A7.mjs → chunk-I4IXPQIX.mjs} +7 -4
  8. package/dist/{chunk-YJLOOC3L.js → chunk-JGBDWEPJ.js} +7 -4
  9. package/dist/chunk-JYPLT56O.js +272 -0
  10. package/dist/{chunk-IJ32BXKZ.js → chunk-MW7ICTVK.js} +35 -35
  11. package/dist/{chunk-6QZQQRBB.mjs → chunk-SQ7U3BWY.mjs} +1 -1
  12. package/dist/chunk-XYI4NXWG.mjs +259 -0
  13. package/dist/{client-D1Gknspz.d.mts → client-Bhvlelij.d.mts} +1 -1
  14. package/dist/{client-Bj2apl_y.d.mts → client-DKg-5OWu.d.mts} +16 -1
  15. package/dist/{client-306peWZ0.d.ts → client-Dfg_hmkP.d.ts} +16 -1
  16. package/dist/{client-C2bKMy5g.d.ts → client-DlGJqSDd.d.ts} +1 -1
  17. package/dist/index.d.mts +18 -3
  18. package/dist/index.d.ts +18 -3
  19. package/dist/index.js +160 -72
  20. package/dist/index.mjs +91 -3
  21. package/dist/react.d.mts +52 -5
  22. package/dist/react.d.ts +52 -5
  23. package/dist/react.js +592 -512
  24. package/dist/react.mjs +136 -58
  25. package/dist/server.d.mts +59 -35
  26. package/dist/server.d.ts +59 -35
  27. package/dist/server.js +160 -79
  28. package/dist/server.mjs +153 -78
  29. package/dist/{ads-C2c2Aald.d.mts → sign-in-TL01-awQ.d.mts} +17 -1
  30. package/dist/{ads-C2c2Aald.d.ts → sign-in-TL01-awQ.d.ts} +17 -1
  31. package/dist/styles.css +1 -1
  32. package/dist/testing/suite.d.mts +2 -2
  33. package/dist/testing/suite.d.ts +2 -2
  34. package/dist/testing/suite.js +22 -22
  35. package/dist/testing/suite.mjs +3 -3
  36. package/dist/testing.d.mts +2 -2
  37. package/dist/testing.d.ts +2 -2
  38. package/dist/testing.js +78 -78
  39. package/dist/testing.mjs +4 -4
  40. package/package.json +2 -1
  41. package/registry/account.json +1 -1
  42. package/dist/chunk-MN4PNKJA.js +0 -129
  43. package/dist/chunk-NRDRVZ62.mjs +0 -119
package/dist/server.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { ac as CimplifyClient } from './client-306peWZ0.js';
2
- export { J as CacheOptions, c7 as ReadRequestOptions, ct as Result } from './client-306peWZ0.js';
1
+ import { ac as CimplifyClient } from './client-Dfg_hmkP.js';
2
+ export { J as CacheOptions, c7 as ReadRequestOptions, ct as Result } from './client-Dfg_hmkP.js';
3
3
  export { Q as Category, T as CimplifyError, U as Collection, aX as Product, b9 as ProductWithDetails } from './product-B_kS4Oxa.js';
4
+ import { JWTVerifyResult } from 'jose';
4
5
  import './payment-sn-yGL7v.js';
5
6
 
6
7
  interface ServerClientOptions {
@@ -145,26 +146,26 @@ type CacheLifeDefault = typeof CACHE_LIFE_DEFAULT;
145
146
  type CacheLifeProbe = typeof CACHE_LIFE_PROBE;
146
147
 
147
148
  /** Next 16 cacheLife profile — a built-in name (`'max'`/`'hours'`/…) or `{expire: secs}`. */
148
- type RevalidateProfile$1 = string | {
149
+ type RevalidateProfile = string | {
149
150
  expire: number;
150
151
  };
151
- declare function revalidateProducts(profile?: RevalidateProfile$1): Promise<void>;
152
- declare function revalidateProduct(id: string, profile?: RevalidateProfile$1): Promise<void>;
153
- declare function revalidateCategories(profile?: RevalidateProfile$1): Promise<void>;
154
- declare function revalidateCategory(id: string, profile?: RevalidateProfile$1): Promise<void>;
155
- declare function revalidateCollections(profile?: RevalidateProfile$1): Promise<void>;
156
- declare function revalidateCollection(id: string, profile?: RevalidateProfile$1): Promise<void>;
157
- declare function revalidateBusiness(profile?: RevalidateProfile$1): Promise<void>;
158
- declare function revalidateBrand(profile?: RevalidateProfile$1): Promise<void>;
159
- declare function revalidateLocations(profile?: RevalidateProfile$1): Promise<void>;
160
- declare function revalidateLocation(id: string, profile?: RevalidateProfile$1): Promise<void>;
161
- declare function revalidatePricing(profile?: RevalidateProfile$1): Promise<void>;
162
- declare function revalidateAddOns(profile?: RevalidateProfile$1): Promise<void>;
163
- declare function revalidateAddOn(id: string, profile?: RevalidateProfile$1): Promise<void>;
164
- declare function revalidateSubscriptions(profile?: RevalidateProfile$1): Promise<void>;
165
- declare function revalidateSubscription(id: string, profile?: RevalidateProfile$1): Promise<void>;
166
- declare function revalidateStock(productId?: string, profile?: RevalidateProfile$1): Promise<void>;
167
- declare function revalidateByTag(tag: string, profile?: RevalidateProfile$1): Promise<void>;
152
+ declare function revalidateProducts(profile?: RevalidateProfile): Promise<void>;
153
+ declare function revalidateProduct(id: string, profile?: RevalidateProfile): Promise<void>;
154
+ declare function revalidateCategories(profile?: RevalidateProfile): Promise<void>;
155
+ declare function revalidateCategory(id: string, profile?: RevalidateProfile): Promise<void>;
156
+ declare function revalidateCollections(profile?: RevalidateProfile): Promise<void>;
157
+ declare function revalidateCollection(id: string, profile?: RevalidateProfile): Promise<void>;
158
+ declare function revalidateBusiness(profile?: RevalidateProfile): Promise<void>;
159
+ declare function revalidateBrand(profile?: RevalidateProfile): Promise<void>;
160
+ declare function revalidateLocations(profile?: RevalidateProfile): Promise<void>;
161
+ declare function revalidateLocation(id: string, profile?: RevalidateProfile): Promise<void>;
162
+ declare function revalidatePricing(profile?: RevalidateProfile): Promise<void>;
163
+ declare function revalidateAddOns(profile?: RevalidateProfile): Promise<void>;
164
+ declare function revalidateAddOn(id: string, profile?: RevalidateProfile): Promise<void>;
165
+ declare function revalidateSubscriptions(profile?: RevalidateProfile): Promise<void>;
166
+ declare function revalidateSubscription(id: string, profile?: RevalidateProfile): Promise<void>;
167
+ declare function revalidateStock(productId?: string, profile?: RevalidateProfile): Promise<void>;
168
+ declare function revalidateByTag(tag: string, profile?: RevalidateProfile): Promise<void>;
168
169
 
169
170
  declare function updateProducts(): Promise<void>;
170
171
  declare function updateProduct(id: string): Promise<void>;
@@ -185,20 +186,43 @@ declare function updateStock(productId?: string): Promise<void>;
185
186
  declare function updateByTag(tag: string): Promise<void>;
186
187
  declare function refreshPage(): Promise<void>;
187
188
 
188
- /** Next 16 cacheLife profile — a built-in name (`'max'`/`'hours'`/…) or `{expire: secs}`. */
189
- type RevalidateProfile = string | {
190
- expire: number;
191
- };
192
- interface RevalidateRouteOptions {
193
- /** Defaults to `process.env.CIMPLIFY_REVALIDATE_SECRET`. */
194
- secret?: string;
195
- /** Defaults to a lazy import of `next/cache.revalidateTag`. Override for tests. */
196
- revalidateTag?: (tag: string, profile: RevalidateProfile) => void;
197
- /** Defaults to `Date.now`. Override for tests. */
198
- now?: () => number;
199
- /** Profile used when the request body doesn't include one. Defaults to `'max'`. */
200
- defaultProfile?: RevalidateProfile;
189
+ interface OidcConfig {
190
+ authUrl?: string;
191
+ clientId: string;
192
+ cookieName?: string;
193
+ cookieDomain?: string;
194
+ }
195
+ interface CimplifySession {
196
+ sub: string;
197
+ name?: string;
198
+ email?: string;
199
+ emailVerified?: boolean;
200
+ phoneNumber?: string;
201
+ phoneNumberVerified?: boolean;
202
+ exp: number;
203
+ iat: number;
204
+ }
205
+ interface CodeExchangeOptions extends OidcConfig {
206
+ code: string;
207
+ codeVerifier: string;
208
+ redirectUri: string;
209
+ }
210
+ interface CodeExchangeResult {
211
+ accessToken: string;
212
+ idToken?: string;
213
+ refreshToken?: string;
214
+ expiresIn: number;
215
+ scope: string;
216
+ }
217
+ declare function exchangeCode(opts: CodeExchangeOptions): Promise<CodeExchangeResult>;
218
+ declare function verifyIdToken(cfg: OidcConfig, idToken: string): Promise<JWTVerifyResult>;
219
+ declare function buildSessionCookie(cfg: OidcConfig, idToken: string, maxAgeSeconds: number): string;
220
+ declare function buildSignoutCookie(cfg: OidcConfig): string;
221
+ interface CallbackHandlerOptions extends OidcConfig {
222
+ redirectUri: string;
201
223
  }
202
- declare function revalidateRouteHandler(req: Request, options?: RevalidateRouteOptions): Promise<Response>;
224
+ declare function handleOidcCallback(req: Request, opts: CallbackHandlerOptions): Promise<Response>;
225
+ declare function handleSessionRequest(req: Request, cfg: OidcConfig): Promise<Response>;
226
+ declare function getSessionFromCookieHeader(cfg: OidcConfig, cookieHeader: string | null | undefined): Promise<CimplifySession | null>;
203
227
 
204
- export { CACHE_LIFE_DEFAULT, CACHE_LIFE_PROBE, type CacheLifeDefault, type CacheLifeProbe, CimplifyClient, type RevalidateProfile$1 as RevalidateProfile, type RevalidateRouteOptions, type RevalidateProfile as RevalidateRouteProfile, type ServerClientOptions, getServerClient, refreshPage, revalidateAddOn, revalidateAddOns, revalidateBrand, revalidateBusiness, revalidateByTag, revalidateCategories, revalidateCategory, revalidateCollection, revalidateCollections, revalidateLocation, revalidateLocations, revalidatePricing, revalidateProduct, revalidateProducts, revalidateRouteHandler, revalidateStock, revalidateSubscription, revalidateSubscriptions, tags, updateAddOn, updateAddOns, updateBrand, updateBusiness, updateByTag, updateCategories, updateCategory, updateCollection, updateCollections, updateLocation, updateLocations, updatePricing, updateProduct, updateProducts, updateStock, updateSubscription, updateSubscriptions };
228
+ export { CACHE_LIFE_DEFAULT, CACHE_LIFE_PROBE, type CacheLifeDefault, type CacheLifeProbe, type CallbackHandlerOptions, CimplifyClient, type CimplifySession, type CodeExchangeOptions, type CodeExchangeResult, type OidcConfig, type RevalidateProfile, type ServerClientOptions, buildSessionCookie, buildSignoutCookie, exchangeCode, getServerClient, getSessionFromCookieHeader, handleOidcCallback, handleSessionRequest, refreshPage, revalidateAddOn, revalidateAddOns, revalidateBrand, revalidateBusiness, revalidateByTag, revalidateCategories, revalidateCategory, revalidateCollection, revalidateCollections, revalidateLocation, revalidateLocations, revalidatePricing, revalidateProduct, revalidateProducts, revalidateStock, revalidateSubscription, revalidateSubscriptions, tags, updateAddOn, updateAddOns, updateBrand, updateBusiness, updateByTag, updateCategories, updateCategory, updateCollection, updateCollections, updateLocation, updateLocations, updatePricing, updateProduct, updateProducts, updateStock, updateSubscription, updateSubscriptions, verifyIdToken };
package/dist/server.js CHANGED
@@ -1,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var chunkIJ32BXKZ_js = require('./chunk-IJ32BXKZ.js');
4
- require('./chunk-YJLOOC3L.js');
3
+ var chunkMW7ICTVK_js = require('./chunk-MW7ICTVK.js');
4
+ require('./chunk-JGBDWEPJ.js');
5
5
  require('./chunk-7Y2O3E4D.js');
6
6
  var chunkXA3ZNR75_js = require('./chunk-XA3ZNR75.js');
7
7
  require('./chunk-OWW5GUSB.js');
8
8
  var react = require('react');
9
+ var jose = require('jose');
9
10
 
10
11
  var DEFAULT_PROD_URL = "https://storefronts.cimplify.io";
11
12
  var DEFAULT_DEV_URL = "http://127.0.0.1:8787";
@@ -25,7 +26,7 @@ function readEnv(...keys) {
25
26
  var getServerClient = react.cache((opts = {}) => {
26
27
  const baseUrl = opts.apiUrl ?? readEnv("CIMPLIFY_API_URL", "NEXT_PUBLIC_CIMPLIFY_API_URL") ?? defaultBaseUrl();
27
28
  const publicKey = opts.secretKey ?? readEnv("CIMPLIFY_SECRET_KEY", "NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY") ?? "mock-dev";
28
- const client = chunkIJ32BXKZ_js.createCimplifyClient({
29
+ const client = chunkMW7ICTVK_js.createCimplifyClient({
29
30
  baseUrl,
30
31
  publicKey,
31
32
  suppressPublicKeyWarning: true
@@ -233,90 +234,164 @@ async function refreshPage() {
233
234
  const fn = await getRefresh();
234
235
  fn();
235
236
  }
236
-
237
- // src/server/revalidate-route.ts
238
- var TIMESTAMP_HEADER = "x-cimplify-timestamp";
239
- var SIGNATURE_HEADER = "x-cimplify-signature";
240
- var SIGNATURE_PREFIX = "sha256=";
241
- var MAX_SKEW_MS = 5 * 60 * 1e3;
242
- var SECRET_ENV = "CIMPLIFY_REVALIDATE_SECRET";
243
- var DEFAULT_PROFILE2 = CACHE_LIFE_DEFAULT;
244
- async function revalidateRouteHandler(req, options = {}) {
245
- const secret = options.secret ?? envSecret();
246
- if (!secret) return text(`revalidate disabled: ${SECRET_ENV} not set`, 500);
247
- const timestamp = req.headers.get(TIMESTAMP_HEADER);
248
- const signature = req.headers.get(SIGNATURE_HEADER);
249
- if (!timestamp || !signature) return text("missing auth headers", 401);
250
- const ts = Number.parseInt(timestamp, 10);
251
- const now = options.now ?? Date.now;
252
- if (!Number.isFinite(ts) || Math.abs(now() - ts) > MAX_SKEW_MS) {
253
- return text("stale or invalid timestamp", 401);
237
+ var DEFAULT_AUTH_URL = "https://auth.cimplify.io";
238
+ var SESSION_COOKIE = "cimplify_session";
239
+ var discoveryCache = /* @__PURE__ */ new Map();
240
+ var jwksCache = /* @__PURE__ */ new Map();
241
+ function authUrl(cfg) {
242
+ return (cfg.authUrl ?? DEFAULT_AUTH_URL).replace(/\/$/, "");
243
+ }
244
+ function cookieName(cfg) {
245
+ return cfg.cookieName ?? SESSION_COOKIE;
246
+ }
247
+ async function discovery(cfg) {
248
+ const base = authUrl(cfg);
249
+ let p = discoveryCache.get(base);
250
+ if (!p) {
251
+ p = fetch(`${base}/.well-known/openid-configuration`, {
252
+ next: { revalidate: 3600 }
253
+ }).then((r) => {
254
+ if (!r.ok) throw new Error(`oidc discovery failed: ${r.status}`);
255
+ return r.json();
256
+ });
257
+ discoveryCache.set(base, p);
258
+ }
259
+ return p;
260
+ }
261
+ async function jwks(cfg) {
262
+ const doc = await discovery(cfg);
263
+ let set = jwksCache.get(doc.jwks_uri);
264
+ if (!set) {
265
+ set = jose.createRemoteJWKSet(new URL(doc.jwks_uri));
266
+ jwksCache.set(doc.jwks_uri, set);
254
267
  }
255
- const body = await req.text();
256
- if (!await verifyHmac(secret, `${timestamp}.${body}`, signature)) {
257
- return text("invalid signature", 401);
268
+ return { set, issuer: doc.issuer };
269
+ }
270
+ async function exchangeCode(opts) {
271
+ const doc = await discovery(opts);
272
+ const body = new URLSearchParams({
273
+ grant_type: "authorization_code",
274
+ code: opts.code,
275
+ code_verifier: opts.codeVerifier,
276
+ redirect_uri: opts.redirectUri,
277
+ client_id: opts.clientId
278
+ });
279
+ const res = await fetch(doc.token_endpoint, {
280
+ method: "POST",
281
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
282
+ body: body.toString()
283
+ });
284
+ if (!res.ok) {
285
+ const text = await res.text().catch(() => "");
286
+ throw new Error(`token exchange failed (${res.status}): ${text}`);
258
287
  }
259
- let parsed;
288
+ const payload = await res.json();
289
+ return {
290
+ accessToken: payload.access_token,
291
+ idToken: payload.id_token,
292
+ refreshToken: payload.refresh_token,
293
+ expiresIn: payload.expires_in,
294
+ scope: payload.scope
295
+ };
296
+ }
297
+ async function verifyIdToken(cfg, idToken) {
298
+ const { set, issuer } = await jwks(cfg);
299
+ return jose.jwtVerify(idToken, set, {
300
+ issuer,
301
+ audience: cfg.clientId
302
+ });
303
+ }
304
+ function payloadToSession(payload) {
305
+ return {
306
+ sub: String(payload.sub ?? ""),
307
+ name: payload.name,
308
+ email: payload.email,
309
+ emailVerified: payload.email_verified,
310
+ phoneNumber: payload.phone_number,
311
+ phoneNumberVerified: payload.phone_number_verified,
312
+ exp: Number(payload.exp ?? 0),
313
+ iat: Number(payload.iat ?? 0)
314
+ };
315
+ }
316
+ function buildSessionCookie(cfg, idToken, maxAgeSeconds) {
317
+ const name = cookieName(cfg);
318
+ const parts = [
319
+ `${name}=${idToken}`,
320
+ "Path=/",
321
+ "HttpOnly",
322
+ "Secure",
323
+ "SameSite=Lax",
324
+ `Max-Age=${maxAgeSeconds}`
325
+ ];
326
+ if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
327
+ return parts.join("; ");
328
+ }
329
+ function buildSignoutCookie(cfg) {
330
+ const name = cookieName(cfg);
331
+ const parts = [`${name}=`, "Path=/", "HttpOnly", "Secure", "SameSite=Lax", "Max-Age=0"];
332
+ if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
333
+ return parts.join("; ");
334
+ }
335
+ async function handleOidcCallback(req, opts) {
336
+ let body;
260
337
  try {
261
- parsed = JSON.parse(body);
338
+ body = await req.json();
262
339
  } catch {
263
- return text("invalid json", 400);
340
+ return Response.json({ error: "invalid_json" }, { status: 400 });
264
341
  }
265
- const tags2 = Array.isArray(parsed.tags) ? parsed.tags.filter((t) => typeof t === "string" && t.length > 0) : [];
266
- if (tags2.length === 0) return text("no tags", 400);
267
- const profile = parseProfile(parsed.profile) ?? options.defaultProfile ?? DEFAULT_PROFILE2;
268
- const revalidate2 = options.revalidateTag ?? await loadRevalidateTag();
269
- for (const tag of tags2) revalidate2(tag, profile);
270
- return Response.json({ ok: true, revalidated: tags2.length, profile });
271
- }
272
- function parseProfile(raw) {
273
- if (typeof raw === "string" && raw.length > 0) return raw;
274
- if (raw && typeof raw === "object" && "expire" in raw && typeof raw.expire === "number") {
275
- return { expire: raw.expire };
342
+ if (!body.code || !body.codeVerifier) {
343
+ return Response.json({ error: "missing_code_or_verifier" }, { status: 400 });
276
344
  }
277
- return void 0;
278
- }
279
- var cachedRevalidateTag = null;
280
- async function loadRevalidateTag() {
281
- if (cachedRevalidateTag) return cachedRevalidateTag;
282
- const specifier = "next/cache";
283
- const mod = await import(
284
- /* webpackIgnore: true */
285
- /* @vite-ignore */
286
- specifier
287
- );
288
- cachedRevalidateTag = mod.revalidateTag;
289
- return cachedRevalidateTag;
290
- }
291
- async function verifyHmac(secret, payload, signatureHeader) {
292
- if (!signatureHeader.startsWith(SIGNATURE_PREFIX)) return false;
293
- const providedBytes = hexToBytes(signatureHeader.slice(SIGNATURE_PREFIX.length));
294
- if (!providedBytes) return false;
295
- const enc = new TextEncoder();
296
- const key = await crypto.subtle.importKey(
297
- "raw",
298
- enc.encode(secret),
299
- { name: "HMAC", hash: "SHA-256" },
300
- false,
301
- ["verify"]
302
- );
303
- return crypto.subtle.verify("HMAC", key, providedBytes, enc.encode(payload));
304
- }
305
- function hexToBytes(hex) {
306
- if (hex.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(hex)) return null;
307
- const buf = new ArrayBuffer(hex.length / 2);
308
- const out = new Uint8Array(buf);
309
- for (let i = 0; i < hex.length; i += 2) {
310
- out[i / 2] = Number.parseInt(hex.slice(i, i + 2), 16);
345
+ let tokens;
346
+ try {
347
+ tokens = await exchangeCode({
348
+ ...opts,
349
+ code: body.code,
350
+ codeVerifier: body.codeVerifier
351
+ });
352
+ } catch (e) {
353
+ return Response.json({ error: "exchange_failed", detail: String(e) }, { status: 400 });
354
+ }
355
+ if (!tokens.idToken) {
356
+ return Response.json({ error: "missing_id_token" }, { status: 400 });
311
357
  }
312
- return out;
358
+ try {
359
+ await verifyIdToken(opts, tokens.idToken);
360
+ } catch (e) {
361
+ return Response.json({ error: "id_token_invalid", detail: String(e) }, { status: 401 });
362
+ }
363
+ const cookie = buildSessionCookie(opts, tokens.idToken, tokens.expiresIn);
364
+ return new Response(JSON.stringify({ ok: true }), {
365
+ status: 200,
366
+ headers: { "Content-Type": "application/json", "Set-Cookie": cookie }
367
+ });
313
368
  }
314
- function envSecret() {
315
- const proc = globalThis.process;
316
- return proc?.env?.[SECRET_ENV];
369
+ async function handleSessionRequest(req, cfg) {
370
+ const session = await getSessionFromCookieHeader(cfg, req.headers.get("cookie"));
371
+ if (!session) {
372
+ return new Response(JSON.stringify({ sub: null }), {
373
+ status: 200,
374
+ headers: { "Content-Type": "application/json", "Cache-Control": "no-store" }
375
+ });
376
+ }
377
+ return new Response(JSON.stringify(session), {
378
+ status: 200,
379
+ headers: { "Content-Type": "application/json", "Cache-Control": "no-store" }
380
+ });
317
381
  }
318
- function text(message, status) {
319
- return new Response(message, { status, headers: { "content-type": "text/plain" } });
382
+ async function getSessionFromCookieHeader(cfg, cookieHeader) {
383
+ if (!cookieHeader) return null;
384
+ const name = cookieName(cfg);
385
+ const match = cookieHeader.split(/;\s*/).find((p) => p.startsWith(`${name}=`));
386
+ if (!match) return null;
387
+ const token = match.slice(name.length + 1);
388
+ if (!token) return null;
389
+ try {
390
+ const { payload } = await verifyIdToken(cfg, token);
391
+ return payloadToSession(payload);
392
+ } catch {
393
+ return null;
394
+ }
320
395
  }
321
396
 
322
397
  Object.defineProperty(exports, "CimplifyError", {
@@ -325,7 +400,13 @@ Object.defineProperty(exports, "CimplifyError", {
325
400
  });
326
401
  exports.CACHE_LIFE_DEFAULT = CACHE_LIFE_DEFAULT;
327
402
  exports.CACHE_LIFE_PROBE = CACHE_LIFE_PROBE;
403
+ exports.buildSessionCookie = buildSessionCookie;
404
+ exports.buildSignoutCookie = buildSignoutCookie;
405
+ exports.exchangeCode = exchangeCode;
328
406
  exports.getServerClient = getServerClient;
407
+ exports.getSessionFromCookieHeader = getSessionFromCookieHeader;
408
+ exports.handleOidcCallback = handleOidcCallback;
409
+ exports.handleSessionRequest = handleSessionRequest;
329
410
  exports.refreshPage = refreshPage;
330
411
  exports.revalidateAddOn = revalidateAddOn;
331
412
  exports.revalidateAddOns = revalidateAddOns;
@@ -341,7 +422,6 @@ exports.revalidateLocations = revalidateLocations;
341
422
  exports.revalidatePricing = revalidatePricing;
342
423
  exports.revalidateProduct = revalidateProduct;
343
424
  exports.revalidateProducts = revalidateProducts;
344
- exports.revalidateRouteHandler = revalidateRouteHandler;
345
425
  exports.revalidateStock = revalidateStock;
346
426
  exports.revalidateSubscription = revalidateSubscription;
347
427
  exports.revalidateSubscriptions = revalidateSubscriptions;
@@ -363,3 +443,4 @@ exports.updateProducts = updateProducts;
363
443
  exports.updateStock = updateStock;
364
444
  exports.updateSubscription = updateSubscription;
365
445
  exports.updateSubscriptions = updateSubscriptions;
446
+ exports.verifyIdToken = verifyIdToken;
package/dist/server.mjs CHANGED
@@ -1,9 +1,10 @@
1
- import { createCimplifyClient } from './chunk-6QZQQRBB.mjs';
2
- import './chunk-B3Y4C4A7.mjs';
1
+ import { createCimplifyClient } from './chunk-SQ7U3BWY.mjs';
2
+ import './chunk-I4IXPQIX.mjs';
3
3
  import './chunk-TD3AY34U.mjs';
4
4
  export { CimplifyError } from './chunk-AMZXALF6.mjs';
5
5
  import './chunk-3G6RQLXK.mjs';
6
6
  import { cache } from 'react';
7
+ import { jwtVerify, createRemoteJWKSet } from 'jose';
7
8
 
8
9
  var DEFAULT_PROD_URL = "https://storefronts.cimplify.io";
9
10
  var DEFAULT_DEV_URL = "http://127.0.0.1:8787";
@@ -231,90 +232,164 @@ async function refreshPage() {
231
232
  const fn = await getRefresh();
232
233
  fn();
233
234
  }
234
-
235
- // src/server/revalidate-route.ts
236
- var TIMESTAMP_HEADER = "x-cimplify-timestamp";
237
- var SIGNATURE_HEADER = "x-cimplify-signature";
238
- var SIGNATURE_PREFIX = "sha256=";
239
- var MAX_SKEW_MS = 5 * 60 * 1e3;
240
- var SECRET_ENV = "CIMPLIFY_REVALIDATE_SECRET";
241
- var DEFAULT_PROFILE2 = CACHE_LIFE_DEFAULT;
242
- async function revalidateRouteHandler(req, options = {}) {
243
- const secret = options.secret ?? envSecret();
244
- if (!secret) return text(`revalidate disabled: ${SECRET_ENV} not set`, 500);
245
- const timestamp = req.headers.get(TIMESTAMP_HEADER);
246
- const signature = req.headers.get(SIGNATURE_HEADER);
247
- if (!timestamp || !signature) return text("missing auth headers", 401);
248
- const ts = Number.parseInt(timestamp, 10);
249
- const now = options.now ?? Date.now;
250
- if (!Number.isFinite(ts) || Math.abs(now() - ts) > MAX_SKEW_MS) {
251
- return text("stale or invalid timestamp", 401);
235
+ var DEFAULT_AUTH_URL = "https://auth.cimplify.io";
236
+ var SESSION_COOKIE = "cimplify_session";
237
+ var discoveryCache = /* @__PURE__ */ new Map();
238
+ var jwksCache = /* @__PURE__ */ new Map();
239
+ function authUrl(cfg) {
240
+ return (cfg.authUrl ?? DEFAULT_AUTH_URL).replace(/\/$/, "");
241
+ }
242
+ function cookieName(cfg) {
243
+ return cfg.cookieName ?? SESSION_COOKIE;
244
+ }
245
+ async function discovery(cfg) {
246
+ const base = authUrl(cfg);
247
+ let p = discoveryCache.get(base);
248
+ if (!p) {
249
+ p = fetch(`${base}/.well-known/openid-configuration`, {
250
+ next: { revalidate: 3600 }
251
+ }).then((r) => {
252
+ if (!r.ok) throw new Error(`oidc discovery failed: ${r.status}`);
253
+ return r.json();
254
+ });
255
+ discoveryCache.set(base, p);
256
+ }
257
+ return p;
258
+ }
259
+ async function jwks(cfg) {
260
+ const doc = await discovery(cfg);
261
+ let set = jwksCache.get(doc.jwks_uri);
262
+ if (!set) {
263
+ set = createRemoteJWKSet(new URL(doc.jwks_uri));
264
+ jwksCache.set(doc.jwks_uri, set);
252
265
  }
253
- const body = await req.text();
254
- if (!await verifyHmac(secret, `${timestamp}.${body}`, signature)) {
255
- return text("invalid signature", 401);
266
+ return { set, issuer: doc.issuer };
267
+ }
268
+ async function exchangeCode(opts) {
269
+ const doc = await discovery(opts);
270
+ const body = new URLSearchParams({
271
+ grant_type: "authorization_code",
272
+ code: opts.code,
273
+ code_verifier: opts.codeVerifier,
274
+ redirect_uri: opts.redirectUri,
275
+ client_id: opts.clientId
276
+ });
277
+ const res = await fetch(doc.token_endpoint, {
278
+ method: "POST",
279
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
280
+ body: body.toString()
281
+ });
282
+ if (!res.ok) {
283
+ const text = await res.text().catch(() => "");
284
+ throw new Error(`token exchange failed (${res.status}): ${text}`);
256
285
  }
257
- let parsed;
286
+ const payload = await res.json();
287
+ return {
288
+ accessToken: payload.access_token,
289
+ idToken: payload.id_token,
290
+ refreshToken: payload.refresh_token,
291
+ expiresIn: payload.expires_in,
292
+ scope: payload.scope
293
+ };
294
+ }
295
+ async function verifyIdToken(cfg, idToken) {
296
+ const { set, issuer } = await jwks(cfg);
297
+ return jwtVerify(idToken, set, {
298
+ issuer,
299
+ audience: cfg.clientId
300
+ });
301
+ }
302
+ function payloadToSession(payload) {
303
+ return {
304
+ sub: String(payload.sub ?? ""),
305
+ name: payload.name,
306
+ email: payload.email,
307
+ emailVerified: payload.email_verified,
308
+ phoneNumber: payload.phone_number,
309
+ phoneNumberVerified: payload.phone_number_verified,
310
+ exp: Number(payload.exp ?? 0),
311
+ iat: Number(payload.iat ?? 0)
312
+ };
313
+ }
314
+ function buildSessionCookie(cfg, idToken, maxAgeSeconds) {
315
+ const name = cookieName(cfg);
316
+ const parts = [
317
+ `${name}=${idToken}`,
318
+ "Path=/",
319
+ "HttpOnly",
320
+ "Secure",
321
+ "SameSite=Lax",
322
+ `Max-Age=${maxAgeSeconds}`
323
+ ];
324
+ if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
325
+ return parts.join("; ");
326
+ }
327
+ function buildSignoutCookie(cfg) {
328
+ const name = cookieName(cfg);
329
+ const parts = [`${name}=`, "Path=/", "HttpOnly", "Secure", "SameSite=Lax", "Max-Age=0"];
330
+ if (cfg.cookieDomain) parts.push(`Domain=${cfg.cookieDomain}`);
331
+ return parts.join("; ");
332
+ }
333
+ async function handleOidcCallback(req, opts) {
334
+ let body;
258
335
  try {
259
- parsed = JSON.parse(body);
336
+ body = await req.json();
260
337
  } catch {
261
- return text("invalid json", 400);
338
+ return Response.json({ error: "invalid_json" }, { status: 400 });
262
339
  }
263
- const tags2 = Array.isArray(parsed.tags) ? parsed.tags.filter((t) => typeof t === "string" && t.length > 0) : [];
264
- if (tags2.length === 0) return text("no tags", 400);
265
- const profile = parseProfile(parsed.profile) ?? options.defaultProfile ?? DEFAULT_PROFILE2;
266
- const revalidate2 = options.revalidateTag ?? await loadRevalidateTag();
267
- for (const tag of tags2) revalidate2(tag, profile);
268
- return Response.json({ ok: true, revalidated: tags2.length, profile });
269
- }
270
- function parseProfile(raw) {
271
- if (typeof raw === "string" && raw.length > 0) return raw;
272
- if (raw && typeof raw === "object" && "expire" in raw && typeof raw.expire === "number") {
273
- return { expire: raw.expire };
340
+ if (!body.code || !body.codeVerifier) {
341
+ return Response.json({ error: "missing_code_or_verifier" }, { status: 400 });
274
342
  }
275
- return void 0;
276
- }
277
- var cachedRevalidateTag = null;
278
- async function loadRevalidateTag() {
279
- if (cachedRevalidateTag) return cachedRevalidateTag;
280
- const specifier = "next/cache";
281
- const mod = await import(
282
- /* webpackIgnore: true */
283
- /* @vite-ignore */
284
- specifier
285
- );
286
- cachedRevalidateTag = mod.revalidateTag;
287
- return cachedRevalidateTag;
288
- }
289
- async function verifyHmac(secret, payload, signatureHeader) {
290
- if (!signatureHeader.startsWith(SIGNATURE_PREFIX)) return false;
291
- const providedBytes = hexToBytes(signatureHeader.slice(SIGNATURE_PREFIX.length));
292
- if (!providedBytes) return false;
293
- const enc = new TextEncoder();
294
- const key = await crypto.subtle.importKey(
295
- "raw",
296
- enc.encode(secret),
297
- { name: "HMAC", hash: "SHA-256" },
298
- false,
299
- ["verify"]
300
- );
301
- return crypto.subtle.verify("HMAC", key, providedBytes, enc.encode(payload));
302
- }
303
- function hexToBytes(hex) {
304
- if (hex.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(hex)) return null;
305
- const buf = new ArrayBuffer(hex.length / 2);
306
- const out = new Uint8Array(buf);
307
- for (let i = 0; i < hex.length; i += 2) {
308
- out[i / 2] = Number.parseInt(hex.slice(i, i + 2), 16);
343
+ let tokens;
344
+ try {
345
+ tokens = await exchangeCode({
346
+ ...opts,
347
+ code: body.code,
348
+ codeVerifier: body.codeVerifier
349
+ });
350
+ } catch (e) {
351
+ return Response.json({ error: "exchange_failed", detail: String(e) }, { status: 400 });
352
+ }
353
+ if (!tokens.idToken) {
354
+ return Response.json({ error: "missing_id_token" }, { status: 400 });
309
355
  }
310
- return out;
356
+ try {
357
+ await verifyIdToken(opts, tokens.idToken);
358
+ } catch (e) {
359
+ return Response.json({ error: "id_token_invalid", detail: String(e) }, { status: 401 });
360
+ }
361
+ const cookie = buildSessionCookie(opts, tokens.idToken, tokens.expiresIn);
362
+ return new Response(JSON.stringify({ ok: true }), {
363
+ status: 200,
364
+ headers: { "Content-Type": "application/json", "Set-Cookie": cookie }
365
+ });
311
366
  }
312
- function envSecret() {
313
- const proc = globalThis.process;
314
- return proc?.env?.[SECRET_ENV];
367
+ async function handleSessionRequest(req, cfg) {
368
+ const session = await getSessionFromCookieHeader(cfg, req.headers.get("cookie"));
369
+ if (!session) {
370
+ return new Response(JSON.stringify({ sub: null }), {
371
+ status: 200,
372
+ headers: { "Content-Type": "application/json", "Cache-Control": "no-store" }
373
+ });
374
+ }
375
+ return new Response(JSON.stringify(session), {
376
+ status: 200,
377
+ headers: { "Content-Type": "application/json", "Cache-Control": "no-store" }
378
+ });
315
379
  }
316
- function text(message, status) {
317
- return new Response(message, { status, headers: { "content-type": "text/plain" } });
380
+ async function getSessionFromCookieHeader(cfg, cookieHeader) {
381
+ if (!cookieHeader) return null;
382
+ const name = cookieName(cfg);
383
+ const match = cookieHeader.split(/;\s*/).find((p) => p.startsWith(`${name}=`));
384
+ if (!match) return null;
385
+ const token = match.slice(name.length + 1);
386
+ if (!token) return null;
387
+ try {
388
+ const { payload } = await verifyIdToken(cfg, token);
389
+ return payloadToSession(payload);
390
+ } catch {
391
+ return null;
392
+ }
318
393
  }
319
394
 
320
- export { CACHE_LIFE_DEFAULT, CACHE_LIFE_PROBE, getServerClient, refreshPage, revalidateAddOn, revalidateAddOns, revalidateBrand, revalidateBusiness, revalidateByTag, revalidateCategories, revalidateCategory, revalidateCollection, revalidateCollections, revalidateLocation, revalidateLocations, revalidatePricing, revalidateProduct, revalidateProducts, revalidateRouteHandler, revalidateStock, revalidateSubscription, revalidateSubscriptions, tags, updateAddOn, updateAddOns, updateBrand, updateBusiness, updateByTag, updateCategories, updateCategory, updateCollection, updateCollections, updateLocation, updateLocations, updatePricing, updateProduct, updateProducts, updateStock, updateSubscription, updateSubscriptions };
395
+ export { CACHE_LIFE_DEFAULT, CACHE_LIFE_PROBE, buildSessionCookie, buildSignoutCookie, exchangeCode, getServerClient, getSessionFromCookieHeader, handleOidcCallback, handleSessionRequest, refreshPage, revalidateAddOn, revalidateAddOns, revalidateBrand, revalidateBusiness, revalidateByTag, revalidateCategories, revalidateCategory, revalidateCollection, revalidateCollections, revalidateLocation, revalidateLocations, revalidatePricing, revalidateProduct, revalidateProducts, revalidateStock, revalidateSubscription, revalidateSubscriptions, tags, updateAddOn, updateAddOns, updateBrand, updateBusiness, updateByTag, updateCategories, updateCategory, updateCollection, updateCollections, updateLocation, updateLocations, updatePricing, updateProduct, updateProducts, updateStock, updateSubscription, updateSubscriptions, verifyIdToken };