@altazion/commerce-sdk-core 26.409.7573 → 26.415.7675

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
@@ -42,7 +42,6 @@ const results = await client.catalog.search({ q: 'chaussures', offset: 0, length
42
42
  ## Fonctionnalités
43
43
 
44
44
  - **Cache SharedWorker + IndexedDB** — mise en cache des réponses, stratègies configurables (`cache-first`, `network-first`, `network-only`)
45
- - **File offline** — les mutations (ajout panier, etc.) sont mises en file et rejouées dès le retour de la connexion
46
45
  - **ConnectivityManager** — détection de connectivité en temps réel avec API d'abonnement
47
46
  - **Dual session** — bascule automatiquement en mode kiosque si le user-agent est `Altazion Device Shell`
48
47
  - **TypeScript** — types complets générés depuis la spécification OpenAPI
@@ -54,7 +53,6 @@ const client = new CommerceClient({
54
53
  baseUrl: 'https://votre-api.altazion.com', // obligatoire
55
54
  siteUrl: 'https://votre-site.com', // URL canonique du site
56
55
  defaultCacheStrategy: 'cache-first', // stratégie de cache par défaut
57
- offlineQueueMaxSize: 50, // taille max de la file offline
58
56
  })
59
57
  ```
60
58
 
@@ -78,7 +76,7 @@ try {
78
76
  await client.cart.addItem('REF-001', 1)
79
77
  } catch (err) {
80
78
  if (err instanceof OfflineError) {
81
- // Opération mise en file pour rejouer plus tard
79
+ // Le terminal est hors ligne : les mutations sont refusées immédiatement
82
80
  } else if (err instanceof AltazionApiError) {
83
81
  console.error(err.status, err.problem)
84
82
  }
package/dist/index.cjs CHANGED
@@ -52,16 +52,6 @@ class CacheError extends Error {
52
52
  this.cause = cause;
53
53
  }
54
54
  }
55
- class QueueFlushError extends Error {
56
- constructor(operationId, apiError) {
57
- super(`Échec du rejeu de l'opération ${operationId} : ${apiError.message}`);
58
- __publicField(this, "failedOperationId");
59
- __publicField(this, "apiError");
60
- this.name = "QueueFlushError";
61
- this.failedOperationId = operationId;
62
- this.apiError = apiError;
63
- }
64
- }
65
55
  class CommerceHttpAdapter {
66
56
  constructor(context) {
67
57
  __publicField(this, "context");
@@ -353,139 +343,6 @@ class CacheStrategy {
353
343
  return data;
354
344
  }
355
345
  }
356
- const DB_NAME = "altazion-queue";
357
- const DB_VERSION = 1;
358
- const STORE_NAME = "operations";
359
- class OfflineQueue {
360
- constructor() {
361
- __publicField(this, "db", null);
362
- __publicField(this, "listeners", /* @__PURE__ */ new Set());
363
- __publicField(this, "counter", 0);
364
- }
365
- /** Abonne un listener aux événements de file. Retourne une fonction de désabonnement. */
366
- subscribe(listener) {
367
- this.listeners.add(listener);
368
- return () => this.listeners.delete(listener);
369
- }
370
- get pendingCount() {
371
- return this.openDb().then(
372
- (db) => new Promise((resolve, reject) => {
373
- const tx = db.transaction(STORE_NAME, "readonly");
374
- const req = tx.objectStore(STORE_NAME).count();
375
- req.onsuccess = () => resolve(req.result);
376
- req.onerror = () => reject(req.error);
377
- })
378
- );
379
- }
380
- async enqueue(method, path, body, headers) {
381
- const operation = {
382
- id: `${Date.now()}-${++this.counter}`,
383
- enqueuedAt: Date.now(),
384
- method,
385
- path,
386
- body,
387
- headers,
388
- attempts: 0
389
- };
390
- const db = await this.openDb();
391
- await this.put(db, operation);
392
- this.emit({ type: "enqueued", operation });
393
- return operation;
394
- }
395
- /**
396
- * Rejoue toutes les opérations en attente dans l'ordre d'enfilage.
397
- * S'arrête sur un conflit (4xx) et émet un événement `conflict`.
398
- */
399
- async flush(http) {
400
- const operations = await this.getAll();
401
- if (operations.length === 0) return;
402
- for (const op of operations) {
403
- try {
404
- op.attempts++;
405
- await http.request(op.path, {
406
- method: op.method,
407
- body: op.body,
408
- headers: op.headers
409
- });
410
- await this.remove(op.id);
411
- } catch (err) {
412
- if (err instanceof AltazionApiError && err.status >= 400 && err.status < 500) {
413
- const flushError = new QueueFlushError(op.id, err);
414
- this.emit({ type: "conflict", operation: op, error: flushError });
415
- return;
416
- }
417
- await this.put(await this.openDb(), op);
418
- return;
419
- }
420
- }
421
- this.emit({ type: "flushed" });
422
- const remaining = await this.pendingCount;
423
- if (remaining === 0) {
424
- this.emit({ type: "emptied" });
425
- }
426
- }
427
- emit(event) {
428
- for (const listener of this.listeners) {
429
- try {
430
- listener(event);
431
- } catch {
432
- }
433
- }
434
- }
435
- openDb() {
436
- return new Promise((resolve, reject) => {
437
- if (this.db) {
438
- resolve(this.db);
439
- return;
440
- }
441
- const request = indexedDB.open(DB_NAME, DB_VERSION);
442
- request.onupgradeneeded = (event) => {
443
- const database = event.target.result;
444
- if (!database.objectStoreNames.contains(STORE_NAME)) {
445
- database.createObjectStore(STORE_NAME, { keyPath: "id" });
446
- }
447
- };
448
- request.onsuccess = (event) => {
449
- this.db = event.target.result;
450
- resolve(this.db);
451
- };
452
- request.onerror = () => reject(request.error);
453
- });
454
- }
455
- put(db, operation) {
456
- return new Promise((resolve, reject) => {
457
- const tx = db.transaction(STORE_NAME, "readwrite");
458
- const req = tx.objectStore(STORE_NAME).put(operation);
459
- req.onsuccess = () => resolve();
460
- req.onerror = () => reject(req.error);
461
- });
462
- }
463
- remove(id) {
464
- return this.openDb().then(
465
- (db) => new Promise((resolve, reject) => {
466
- const tx = db.transaction(STORE_NAME, "readwrite");
467
- const req = tx.objectStore(STORE_NAME).delete(id);
468
- req.onsuccess = () => resolve();
469
- req.onerror = () => reject(req.error);
470
- })
471
- );
472
- }
473
- getAll() {
474
- return this.openDb().then(
475
- (db) => new Promise((resolve, reject) => {
476
- const tx = db.transaction(STORE_NAME, "readonly");
477
- const req = tx.objectStore(STORE_NAME).getAll();
478
- req.onsuccess = () => {
479
- const ops = req.result.sort(
480
- (a, b) => a.enqueuedAt - b.enqueuedAt
481
- );
482
- resolve(ops);
483
- };
484
- req.onerror = () => reject(req.error);
485
- })
486
- );
487
- }
488
- }
489
346
  class BrowserSessionManager {
490
347
  constructor(http, context) {
491
348
  __publicField(this, "http");
@@ -560,10 +417,9 @@ class SessionModule {
560
417
  }
561
418
  }
562
419
  class CartModule {
563
- constructor(http, cache, queue, connectivity) {
420
+ constructor(http, cache, connectivity) {
564
421
  this.http = http;
565
422
  this.cache = cache;
566
- this.queue = queue;
567
423
  this.connectivity = connectivity;
568
424
  }
569
425
  /** Récupère le panier en cours */
@@ -580,48 +436,46 @@ class CartModule {
580
436
  }
581
437
  /** Ajoute un article au panier */
582
438
  async addItem(reference, quantity, options) {
439
+ this.ensureOnline();
583
440
  const body = { reference, quantity, ...options };
584
- if (this.connectivity.isOffline) {
585
- await this.queue.enqueue("POST", "/commerce/api/process/cart/items", body);
586
- return this.cache.execute("cart:current", () => this.http.get("/commerce/api/process/cart"), "network-first");
587
- }
588
441
  const cart = await this.http.post("/commerce/api/process/cart/items", body);
589
442
  await this.cache.execute("cart:current", () => Promise.resolve(cart), "network-first");
590
443
  return cart;
591
444
  }
592
445
  /** Met à jour la quantité d'une ligne */
593
446
  async updateItem(lineId, quantity) {
447
+ this.ensureOnline();
594
448
  const body = { quantity };
595
- if (this.connectivity.isOffline) {
596
- await this.queue.enqueue("PUT", `/commerce/api/process/cart/items/${lineId}`, body);
597
- return this.cache.execute("cart:current", () => this.http.get("/commerce/api/process/cart"), "network-first");
598
- }
599
449
  const cart = await this.http.put(`/commerce/api/process/cart/items/${lineId}`, body);
600
450
  await this.cache.execute("cart:current", () => Promise.resolve(cart), "network-first");
601
451
  return cart;
602
452
  }
603
453
  /** Supprime une ligne du panier */
604
454
  async removeItem(lineId) {
605
- if (this.connectivity.isOffline) {
606
- await this.queue.enqueue("DELETE", `/commerce/api/process/cart/items/${lineId}`);
607
- return this.cache.execute("cart:current", () => this.http.get("/commerce/api/process/cart"), "network-first");
608
- }
455
+ this.ensureOnline();
609
456
  const cart = await this.http.delete(`/commerce/api/process/cart/items/${lineId}`);
610
457
  await this.cache.execute("cart:current", () => Promise.resolve(cart), "network-first");
611
458
  return cart;
612
459
  }
613
460
  /** Applique un coupon */
614
461
  async applyCoupon(code) {
462
+ this.ensureOnline();
615
463
  const cart = await this.http.post("/commerce/api/process/cart/coupons", { code });
616
464
  await this.cache.execute("cart:current", () => Promise.resolve(cart), "network-first");
617
465
  return cart;
618
466
  }
619
467
  /** Retire un coupon */
620
468
  async removeCoupon(code) {
469
+ this.ensureOnline();
621
470
  const cart = await this.http.delete(`/commerce/api/process/cart/coupons/${encodeURIComponent(code)}`);
622
471
  await this.cache.execute("cart:current", () => Promise.resolve(cart), "network-first");
623
472
  return cart;
624
473
  }
474
+ ensureOnline() {
475
+ if (this.connectivity.isOffline) {
476
+ throw new OfflineError("Le terminal est hors ligne, les modifications du panier sont indisponibles");
477
+ }
478
+ }
625
479
  }
626
480
  class CatalogModule {
627
481
  constructor(http, cache) {
@@ -786,18 +640,15 @@ class CommerceClient {
786
640
  __publicField(this, "http");
787
641
  __publicField(this, "workerBridge");
788
642
  __publicField(this, "cacheStrategy");
789
- __publicField(this, "offlineQueue");
790
643
  __publicField(this, "sessionManager");
791
- __publicField(this, "unsubscribeOnline", null);
792
644
  this.context = new CommerceContext(options);
793
645
  this.http = new CommerceHttpAdapter(this.context);
794
646
  this.connectivity = new ConnectivityManager();
795
647
  this.workerBridge = new WorkerBridge();
796
648
  this.cacheStrategy = new CacheStrategy(this.workerBridge, this.http);
797
- this.offlineQueue = new OfflineQueue();
798
649
  this.sessionManager = SessionManagerFactory.create(this.http, this.context);
799
650
  this.session = new SessionModule(this.http, this.cacheStrategy);
800
- this.cart = new CartModule(this.http, this.cacheStrategy, this.offlineQueue, this.connectivity);
651
+ this.cart = new CartModule(this.http, this.cacheStrategy, this.connectivity);
801
652
  this.catalog = new CatalogModule(this.http, this.cacheStrategy);
802
653
  this.shipping = new ShippingModule(this.http, this.cacheStrategy);
803
654
  this.marketing = new MarketingModule(this.http, this.cacheStrategy);
@@ -806,14 +657,8 @@ class CommerceClient {
806
657
  /**
807
658
  * Initialise le SDK :
808
659
  * - Crée la session si nécessaire (mode browser uniquement)
809
- * - Abonne le flush automatique de la file hors-ligne au retour en ligne
810
660
  */
811
661
  async initialize() {
812
- this.unsubscribeOnline = this.connectivity.subscribe(async (status) => {
813
- if (status === "online") {
814
- await this.offlineQueue.flush(this.http);
815
- }
816
- });
817
662
  return this.sessionManager.initialize();
818
663
  }
819
664
  /**
@@ -822,19 +667,6 @@ class CommerceClient {
822
667
  get isOffline() {
823
668
  return this.connectivity.isOffline;
824
669
  }
825
- /**
826
- * Retourne le nombre d'opérations en attente dans la file hors-ligne.
827
- */
828
- get pendingOperationsCount() {
829
- return this.offlineQueue.pendingCount;
830
- }
831
- /**
832
- * Abonne un listener aux événements de la file hors-ligne.
833
- * Retourne une fonction de désabonnement.
834
- */
835
- onQueueEvent(listener) {
836
- return this.offlineQueue.subscribe(listener);
837
- }
838
670
  /**
839
671
  * Force le vidage du cache.
840
672
  */
@@ -845,8 +677,6 @@ class CommerceClient {
845
677
  * Libère les ressources (listeners, worker).
846
678
  */
847
679
  dispose() {
848
- var _a;
849
- (_a = this.unsubscribeOnline) == null ? void 0 : _a.call(this);
850
680
  this.connectivity.dispose();
851
681
  this.workerBridge.dispose();
852
682
  }
@@ -857,5 +687,4 @@ exports.CommerceClient = CommerceClient;
857
687
  exports.CommerceContext = CommerceContext;
858
688
  exports.ConnectivityManager = ConnectivityManager;
859
689
  exports.OfflineError = OfflineError;
860
- exports.QueueFlushError = QueueFlushError;
861
690
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/client/CommerceContext.ts","../src/client/errors.ts","../src/client/CommerceHttpAdapter.ts","../src/connectivity/ConnectivityManager.ts","../src/workers/WorkerBridge.ts","../src/workers/CacheStrategy.ts","../src/offline/OfflineQueue.ts","../src/session/BrowserSessionManager.ts","../src/session/KioskSessionManager.ts","../src/session/SessionManagerFactory.ts","../src/modules/session/index.ts","../src/modules/cart/index.ts","../src/modules/catalog/index.ts","../src/modules/shipping/index.ts","../src/modules/marketing/index.ts","../src/modules/stores/index.ts","../src/client/CommerceClient.ts"],"sourcesContent":["/**\n * Mode d'exécution du SDK.\n * - `browser` : navigateur classique — le SDK gère la création de session et le cookie.\n * - `kiosk` : borne avec \"Altazion Device Shell\" — le browser embarqué gère les cookies.\n */\nexport type CommerceMode = 'browser' | 'kiosk'\n\nexport interface CommerceContextOptions {\n /** URL de base de l'API (ex. : \"https://api.monsite.com\") */\n baseUrl: string\n /** Identifiant ou URL du site web pour la création de session (mode browser) */\n siteUrl?: string\n /**\n * Clé primaire du site (alternative à siteUrl).\n * Requiert aussi rjsId.\n */\n sitePk?: number\n /** Identifiant du tenant RJS (nécessaire avec sitePk) */\n rjsId?: number\n /** Locale par défaut (ex. : \"fr-FR\") */\n locale?: string\n /** Devise par défaut (ex. : \"EUR\") */\n currency?: string\n}\n\n/**\n * Contexte partagé du SDK, instancié une seule fois et transmis\n * à tous les sous-systèmes (HttpAdapter, SessionManager, modules…).\n */\nexport class CommerceContext {\n readonly baseUrl: string\n readonly siteUrl: string | undefined\n readonly sitePk: number | undefined\n readonly rjsId: number | undefined\n readonly locale: string\n readonly currency: string\n readonly mode: CommerceMode\n\n constructor(options: CommerceContextOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.siteUrl = options.siteUrl\n this.sitePk = options.sitePk\n this.rjsId = options.rjsId\n this.locale = options.locale ?? 'fr-FR'\n this.currency = options.currency ?? 'EUR'\n this.mode = CommerceContext.detectMode()\n }\n\n private static detectMode(): CommerceMode {\n if (typeof navigator !== 'undefined' && navigator.userAgent.includes('Altazion Device Shell')) {\n return 'kiosk'\n }\n return 'browser'\n }\n}\n","/**\n * Représentation d'une réponse d'erreur ProblemDetails (RFC 9457)\n * telle que renvoyée par GlobalExceptionFilter.cs\n */\nexport interface ProblemDetails {\n type?: string\n title?: string\n status?: number\n detail?: string\n instance?: string\n [key: string]: unknown\n}\n\n/**\n * Erreur générée par l'API Altazion Commerce (HTTP 4xx / 5xx).\n */\nexport class AltazionApiError extends Error {\n readonly status: number\n readonly problem: ProblemDetails\n\n constructor(status: number, problem: ProblemDetails) {\n super(problem.detail ?? problem.title ?? `HTTP ${status}`)\n this.name = 'AltazionApiError'\n this.status = status\n this.problem = problem\n }\n}\n\n/**\n * Erreur levée lorsque le SDK est hors-ligne et ne peut pas\n * satisfaire la requête depuis le cache.\n */\nexport class OfflineError extends Error {\n constructor(message = 'Le SDK est hors-ligne et aucun cache n\\'est disponible pour cette ressource') {\n super(message)\n this.name = 'OfflineError'\n }\n}\n\n/**\n * Erreur liée à une opération sur le cache (IndexedDB, SharedWorker).\n */\nexport class CacheError extends Error {\n readonly cause: unknown\n\n constructor(message: string, cause?: unknown) {\n super(message)\n this.name = 'CacheError'\n this.cause = cause\n }\n}\n\n/**\n * Erreur levée lors du rejeu de l'OfflineQueue (conflit serveur).\n */\nexport class QueueFlushError extends Error {\n readonly failedOperationId: string\n readonly apiError: AltazionApiError\n\n constructor(operationId: string, apiError: AltazionApiError) {\n super(`Échec du rejeu de l'opération ${operationId} : ${apiError.message}`)\n this.name = 'QueueFlushError'\n this.failedOperationId = operationId\n this.apiError = apiError\n }\n}\n","import { AltazionApiError, type ProblemDetails } from './errors.js'\nimport type { CommerceContext } from './CommerceContext.js'\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n body?: unknown\n headers?: Record<string, string>\n /** Nombre maximum de tentatives réseau (uniquement sur erreurs réseau, jamais sur 4xx) */\n maxRetries?: number\n}\n\n/**\n * Adaptateur HTTP basé sur fetch natif.\n *\n * Responsabilités :\n * - Construction des URLs à partir du baseUrl du contexte\n * - Ajout des headers standard (Content-Type, Accept, locale)\n * - credentials: 'include' pour la transmission automatique des cookies (modes browser et kiosk)\n * - Parse des réponses ProblemDetails en AltazionApiError\n * - Retry limité sur les erreurs réseau (TypeError), jamais sur les 4xx/5xx\n */\nexport class CommerceHttpAdapter {\n private readonly context: CommerceContext\n\n constructor(context: CommerceContext) {\n this.context = context\n }\n\n async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, headers = {}, maxRetries = 2 } = options\n const url = `${this.context.baseUrl}${path}`\n\n const requestHeaders: Record<string, string> = {\n Accept: 'application/json',\n 'Accept-Language': this.context.locale,\n ...headers\n }\n\n if (body !== undefined) {\n requestHeaders['Content-Type'] = 'application/json'\n }\n\n const init: RequestInit = {\n method,\n headers: requestHeaders,\n credentials: 'include',\n body: body !== undefined ? JSON.stringify(body) : undefined\n }\n\n let lastNetworkError: unknown\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetch(url, init)\n return await this.handleResponse<T>(response)\n } catch (err) {\n // AltazionApiError n'est jamais retenté\n if (err instanceof AltazionApiError) throw err\n lastNetworkError = err\n // Petite pause exponentielle avant de réessayer (uniquement sur erreurs réseau)\n if (attempt < maxRetries) {\n await delay(150 * Math.pow(2, attempt))\n }\n }\n }\n\n throw lastNetworkError\n }\n\n private async handleResponse<T>(response: Response): Promise<T> {\n if (response.ok) {\n const contentType = response.headers.get('content-type') ?? ''\n if (response.status === 204 || !contentType.includes('application/json')) {\n return undefined as unknown as T\n }\n return response.json() as Promise<T>\n }\n\n // Tenter de parser un ProblemDetails\n let problem: ProblemDetails = { status: response.status }\n try {\n const contentType = response.headers.get('content-type') ?? ''\n if (contentType.includes('application/json') || contentType.includes('application/problem+json')) {\n problem = await response.json() as ProblemDetails\n problem.status ??= response.status\n }\n } catch {\n // JSON invalide — on garde le problem minimal\n }\n\n throw new AltazionApiError(response.status, problem)\n }\n\n /** Effectue un GET et retourne T */\n get<T>(path: string, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'GET', headers })\n }\n\n /** Effectue un POST avec un body JSON et retourne T */\n post<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'POST', body, headers })\n }\n\n /** Effectue un PUT avec un body JSON et retourne T */\n put<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'PUT', body, headers })\n }\n\n /** Effectue un PATCH avec un body JSON et retourne T */\n patch<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'PATCH', body, headers })\n }\n\n /** Effectue un DELETE et retourne T */\n delete<T>(path: string, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'DELETE', headers })\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","export type ConnectivityStatus = 'online' | 'offline'\n\nexport type ConnectivityListener = (status: ConnectivityStatus) => void\n\n/**\n * Surveille l'état de la connexion réseau.\n *\n * - Utilise navigator.onLine comme valeur initiale\n * - Écoute les événements window 'online' / 'offline'\n * - Permet d'abonner des listeners (pattern observable léger)\n */\nexport class ConnectivityManager {\n private status: ConnectivityStatus\n private readonly listeners = new Set<ConnectivityListener>()\n\n constructor() {\n this.status = this.readOnlineStatus()\n\n if (typeof window !== 'undefined') {\n window.addEventListener('online', this.handleOnline)\n window.addEventListener('offline', this.handleOffline)\n }\n }\n\n get isOnline(): boolean {\n return this.status === 'online'\n }\n\n get isOffline(): boolean {\n return this.status === 'offline'\n }\n\n /**\n * Abonne un listener aux changements de connectivité.\n * Retourne une fonction de désabonnement.\n */\n subscribe(listener: ConnectivityListener): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** Libère les event listeners sur window. */\n dispose(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener('online', this.handleOnline)\n window.removeEventListener('offline', this.handleOffline)\n }\n this.listeners.clear()\n }\n\n private readOnlineStatus(): ConnectivityStatus {\n if (typeof navigator === 'undefined' || navigator.onLine === undefined) {\n return 'online' // SSR / environnement sans navigator : on suppose online\n }\n return navigator.onLine ? 'online' : 'offline'\n }\n\n private readonly handleOnline = (): void => {\n this.status = 'online'\n this.emit('online')\n }\n\n private readonly handleOffline = (): void => {\n this.status = 'offline'\n this.emit('offline')\n }\n\n private emit(status: ConnectivityStatus): void {\n for (const listener of this.listeners) {\n try {\n listener(status)\n } catch {\n // Un listener ne doit pas faire planter les autres\n }\n }\n }\n}\n","import { CacheError } from '../client/errors.js'\n\ninterface PendingRequest {\n resolve: (value: unknown) => void\n reject: (reason: unknown) => void\n}\n\n/**\n * Abstraction du canal de communication avec le SharedWorker de cache.\n *\n * - Utilise un SharedWorker si le navigateur le supporte\n * - Fallback : Map in-memory (données non persistantes, perdues au reload)\n *\n * Chaque appel retourne une Promise, résolue/rejetée via la réponse du worker.\n */\nexport class WorkerBridge {\n private port: MessagePort | null = null\n private readonly pending = new Map<string, PendingRequest>()\n private requestCounter = 0\n private readonly fallback = new Map<string, { data: unknown; expiresAt: number }>()\n private readonly usingFallback: boolean\n\n constructor() {\n this.usingFallback = !this.tryStartWorker()\n }\n\n private tryStartWorker(): boolean {\n if (typeof SharedWorker === 'undefined') return false\n\n try {\n const worker = new SharedWorker(\n new URL('./cache.worker.ts', import.meta.url),\n { type: 'module', name: 'altazion-cache-worker' }\n )\n this.port = worker.port\n this.port.addEventListener('message', this.handleMessage)\n this.port.start()\n return true\n } catch {\n return false\n }\n }\n\n private readonly handleMessage = (event: MessageEvent<{ id: string; result?: unknown; error?: string }>): void => {\n const { id, result, error } = event.data\n const pending = this.pending.get(id)\n if (!pending) return\n this.pending.delete(id)\n\n if (error !== undefined) {\n pending.reject(new CacheError(error))\n } else {\n pending.resolve(result)\n }\n }\n\n private nextId(): string {\n return String(++this.requestCounter)\n }\n\n private send(message: Record<string, unknown>): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (!this.port) {\n reject(new CacheError('Worker non initialisé'))\n return\n }\n const id = this.nextId()\n this.pending.set(id, { resolve, reject })\n this.port.postMessage({ ...message, id })\n })\n }\n\n async get<T>(key: string): Promise<T | null> {\n if (this.usingFallback) {\n const entry = this.fallback.get(key)\n if (!entry || Date.now() > entry.expiresAt) return null\n return entry.data as T\n }\n return this.send({ type: 'GET', key }) as Promise<T | null>\n }\n\n async set(key: string, data: unknown, ttlMs: number): Promise<void> {\n if (this.usingFallback) {\n this.fallback.set(key, { data, expiresAt: Date.now() + ttlMs })\n return\n }\n await this.send({ type: 'SET', key, data, ttl: ttlMs })\n }\n\n async invalidate(pattern: string): Promise<void> {\n if (this.usingFallback) {\n const regex = new RegExp(pattern)\n for (const key of this.fallback.keys()) {\n if (regex.test(key)) this.fallback.delete(key)\n }\n return\n }\n await this.send({ type: 'INVALIDATE', pattern })\n }\n\n async clearAll(): Promise<void> {\n if (this.usingFallback) {\n this.fallback.clear()\n return\n }\n await this.send({ type: 'CLEAR_ALL' })\n }\n\n dispose(): void {\n this.port?.removeEventListener('message', this.handleMessage)\n this.pending.clear()\n }\n}\n","import type { WorkerBridge } from './WorkerBridge.js'\nimport type { CommerceHttpAdapter } from '../client/CommerceHttpAdapter.js'\n\n/**\n * Stratégies de cache disponibles pour les requêtes HTTP.\n */\nexport type CacheStrategyName =\n | 'network-only' // Jamais de cache (mutations)\n | 'network-first' // Réseau, fallback cache si erreur réseau\n | 'cache-first' // Cache, revalidation réseau en background si périmé\n | 'stale-while-revalidate' // Retourne le cache immédiatement + revalide en arrière-plan\n\n/** TTL par stratégie, en millisecondes */\nexport const DEFAULT_TTL: Record<Exclude<CacheStrategyName, 'network-only'>, number> = {\n 'network-first': 30_000, // 30 secondes (session, panier)\n 'cache-first': 5 * 60_000, // 5 minutes (recherche)\n 'stale-while-revalidate': 60 * 60_000 // 1 heure (catalogue)\n}\n\nexport class CacheStrategy {\n constructor(\n private readonly bridge: WorkerBridge,\n private readonly http: CommerceHttpAdapter\n ) {}\n\n /**\n * Exécute la requête selon la stratégie choisie.\n *\n * @param key Clé de cache (généralement le path + params)\n * @param fetcher Fonction qui effectue la requête HTTP\n * @param strategy Stratégie à appliquer\n * @param ttlMs TTL du cache (override la valeur par défaut)\n */\n async execute<T>(\n key: string,\n fetcher: () => Promise<T>,\n strategy: CacheStrategyName,\n ttlMs?: number\n ): Promise<T> {\n switch (strategy) {\n case 'network-only':\n return fetcher()\n\n case 'network-first':\n return this.networkFirst<T>(key, fetcher, ttlMs ?? DEFAULT_TTL['network-first'])\n\n case 'cache-first':\n return this.cacheFirst<T>(key, fetcher, ttlMs ?? DEFAULT_TTL['cache-first'])\n\n case 'stale-while-revalidate':\n return this.staleWhileRevalidate<T>(key, fetcher, ttlMs ?? DEFAULT_TTL['stale-while-revalidate'])\n }\n }\n\n private async networkFirst<T>(key: string, fetcher: () => Promise<T>, ttlMs: number): Promise<T> {\n try {\n const data = await fetcher()\n await this.bridge.set(key, data, ttlMs)\n return data\n } catch (err) {\n // Erreur réseau uniquement (TypeError) : on tente le cache\n if (err instanceof TypeError) {\n const cached = await this.bridge.get<T>(key)\n if (cached !== null) return cached\n }\n throw err\n }\n }\n\n private async cacheFirst<T>(key: string, fetcher: () => Promise<T>, ttlMs: number): Promise<T> {\n const cached = await this.bridge.get<T>(key)\n if (cached !== null) return cached\n\n const data = await fetcher()\n await this.bridge.set(key, data, ttlMs)\n return data\n }\n\n private async staleWhileRevalidate<T>(key: string, fetcher: () => Promise<T>, ttlMs: number): Promise<T> {\n const cached = await this.bridge.get<T>(key)\n\n // Revalidation en arrière-plan (ne bloque pas le résultat)\n const revalidate = fetcher()\n .then((data) => this.bridge.set(key, data, ttlMs))\n .catch(() => { /* Échec silencieux : on garde le cache */ })\n\n if (cached !== null) {\n // On lance la revalidation sans attendre\n void revalidate\n return cached\n }\n\n // Pas de cache : on attend le réseau\n const data = await fetcher()\n await this.bridge.set(key, data, ttlMs)\n return data\n }\n}\n","import type { QueuedOperation } from './QueuedOperation.js'\nimport type { CommerceHttpAdapter } from '../client/CommerceHttpAdapter.js'\nimport { AltazionApiError, QueueFlushError } from '../client/errors.js'\n\nconst DB_NAME = 'altazion-queue'\nconst DB_VERSION = 1\nconst STORE_NAME = 'operations'\n\nexport type QueueEventType = 'enqueued' | 'flushed' | 'conflict' | 'emptied'\n\nexport interface QueueEvent {\n type: QueueEventType\n operation?: QueuedOperation\n error?: QueueFlushError\n}\n\nexport type QueueEventListener = (event: QueueEvent) => void\n\n/**\n * File d'attente persistante (IndexedDB) pour les mutations effectuées hors-ligne.\n *\n * Flux :\n * 1. `enqueue(operation)` — stocke l'opération en IndexedDB\n * 2. Au retour en ligne, `flush()` rejoue les opérations dans l'ordre d'enfilage\n * 3. En cas d'erreur 4xx (conflit) : émet un événement `conflict` et ne retire PAS l'opération\n * 4. En cas de succès : retire l'opération de la file\n */\nexport class OfflineQueue {\n private db: IDBDatabase | null = null\n private readonly listeners = new Set<QueueEventListener>()\n private counter = 0\n\n /** Abonne un listener aux événements de file. Retourne une fonction de désabonnement. */\n subscribe(listener: QueueEventListener): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n get pendingCount(): Promise<number> {\n return this.openDb().then(\n (db) =>\n new Promise<number>((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly')\n const req = tx.objectStore(STORE_NAME).count()\n req.onsuccess = () => resolve(req.result)\n req.onerror = () => reject(req.error)\n })\n )\n }\n\n async enqueue(\n method: QueuedOperation['method'],\n path: string,\n body?: unknown,\n headers?: Record<string, string>\n ): Promise<QueuedOperation> {\n const operation: QueuedOperation = {\n id: `${Date.now()}-${++this.counter}`,\n enqueuedAt: Date.now(),\n method,\n path,\n body,\n headers,\n attempts: 0\n }\n\n const db = await this.openDb()\n await this.put(db, operation)\n this.emit({ type: 'enqueued', operation })\n return operation\n }\n\n /**\n * Rejoue toutes les opérations en attente dans l'ordre d'enfilage.\n * S'arrête sur un conflit (4xx) et émet un événement `conflict`.\n */\n async flush(http: CommerceHttpAdapter): Promise<void> {\n const operations = await this.getAll()\n if (operations.length === 0) return\n\n for (const op of operations) {\n try {\n op.attempts++\n await http.request(op.path, {\n method: op.method,\n body: op.body,\n headers: op.headers\n })\n await this.remove(op.id)\n } catch (err) {\n if (err instanceof AltazionApiError && err.status >= 400 && err.status < 500) {\n const flushError = new QueueFlushError(op.id, err)\n this.emit({ type: 'conflict', operation: op, error: flushError })\n // On arrête le flush pour éviter de rejouer des opérations dépendantes\n return\n }\n // Erreur réseau ou 5xx : on met à jour l'opération et on arrête (ce n'est pas le bon moment)\n await this.put(await this.openDb(), op)\n return\n }\n }\n\n this.emit({ type: 'flushed' })\n\n const remaining = await this.pendingCount\n if (remaining === 0) {\n this.emit({ type: 'emptied' })\n }\n }\n\n private emit(event: QueueEvent): void {\n for (const listener of this.listeners) {\n try { listener(event) } catch { /* isolation */ }\n }\n }\n\n private openDb(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n if (this.db) { resolve(this.db); return }\n\n const request = indexedDB.open(DB_NAME, DB_VERSION)\n\n request.onupgradeneeded = (event) => {\n const database = (event.target as IDBOpenDBRequest).result\n if (!database.objectStoreNames.contains(STORE_NAME)) {\n database.createObjectStore(STORE_NAME, { keyPath: 'id' })\n }\n }\n\n request.onsuccess = (event) => {\n this.db = (event.target as IDBOpenDBRequest).result\n resolve(this.db)\n }\n\n request.onerror = () => reject(request.error)\n })\n }\n\n private put(db: IDBDatabase, operation: QueuedOperation): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite')\n const req = tx.objectStore(STORE_NAME).put(operation)\n req.onsuccess = () => resolve()\n req.onerror = () => reject(req.error)\n })\n }\n\n private remove(id: string): Promise<void> {\n return this.openDb().then(\n (db) =>\n new Promise<void>((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite')\n const req = tx.objectStore(STORE_NAME).delete(id)\n req.onsuccess = () => resolve()\n req.onerror = () => reject(req.error)\n })\n )\n }\n\n private getAll(): Promise<QueuedOperation[]> {\n return this.openDb().then(\n (db) =>\n new Promise<QueuedOperation[]>((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly')\n const req = tx.objectStore(STORE_NAME).getAll()\n req.onsuccess = () => {\n const ops = (req.result as QueuedOperation[]).sort(\n (a, b) => a.enqueuedAt - b.enqueuedAt\n )\n resolve(ops)\n }\n req.onerror = () => reject(req.error)\n })\n )\n }\n}\n","import type { SessionManager } from './SessionManager.js'\nimport type { CommerceHttpAdapter } from '../client/CommerceHttpAdapter.js'\nimport type { CommerceContext } from '../client/CommerceContext.js'\nimport type { SessionInfo } from '../types/index.js'\nimport { AltazionApiError } from '../client/errors.js'\n\n/**\n * Gestionnaire de session pour le mode navigateur classique.\n *\n * Responsabilités :\n * - Appel à POST /commerce/api/sessions/create pour créer la session\n * - La session est identifiée côté serveur via le cookie `altz_session_id`\n * (créé automatiquement par l'API et transmis grâce à credentials:'include')\n */\nexport class BrowserSessionManager implements SessionManager {\n private readonly http: CommerceHttpAdapter\n private readonly context: CommerceContext\n\n constructor(http: CommerceHttpAdapter, context: CommerceContext) {\n this.http = http\n this.context = context\n }\n\n async initialize(): Promise<SessionInfo | null> {\n // Vérifier si une session existe déjà\n try {\n const existing = await this.http.get<SessionInfo>('/commerce/api/sessions/raw')\n return existing\n } catch (err) {\n // 404 = pas de session, on en crée une\n if (err instanceof AltazionApiError && err.status === 404) {\n return this.createSession()\n }\n throw err\n }\n }\n\n async onSessionExpired(): Promise<void> {\n await this.createSession()\n }\n\n private async createSession(): Promise<SessionInfo> {\n const body = this.buildCreationRequest()\n return this.http.post<SessionInfo>('/commerce/api/sessions/create', body)\n }\n\n private buildCreationRequest(): Record<string, unknown> {\n if (this.context.sitePk !== undefined && this.context.rjsId !== undefined) {\n return { sitePk: this.context.sitePk, rjsId: this.context.rjsId }\n }\n if (this.context.siteUrl !== undefined) {\n return { siteUrl: this.context.siteUrl }\n }\n // Fallback : envoyer l'URL courante du navigateur\n const currentUrl = typeof window !== 'undefined' ? window.location.href : undefined\n return { siteUrl: currentUrl }\n }\n}\n","import type { SessionManager } from './SessionManager.js'\nimport type { SessionInfo } from '../types/index.js'\n\n/**\n * Gestionnaire de session pour le mode borne (Altazion Device Shell).\n *\n * Le browser embarqué gère intégralement les cookies de session.\n * Le SDK n'a pas à intervenir : fetch avec credentials:'include' suffit\n * pour que les cookies soient transmis automatiquement.\n *\n * Cette implémentation est un no-op intentionnel.\n */\nexport class KioskSessionManager implements SessionManager {\n async initialize(): Promise<SessionInfo | null> {\n // Le browser embarqué est responsable de la session.\n // Aucune action requise côté SDK.\n return null\n }\n\n async onSessionExpired(): Promise<void> {\n // Le browser embarqué gère le renouvellement de session.\n // Aucune action requise côté SDK.\n }\n}\n","import type { SessionManager } from './SessionManager.js'\nimport { BrowserSessionManager } from './BrowserSessionManager.js'\nimport { KioskSessionManager } from './KioskSessionManager.js'\nimport type { CommerceHttpAdapter } from '../client/CommerceHttpAdapter.js'\nimport type { CommerceContext } from '../client/CommerceContext.js'\n\n/**\n * Instancie le SessionManager adapté au contexte d'exécution.\n *\n * Détection du mode kiosk : présence de \"Altazion Device Shell\" dans le User-Agent.\n * Dans ce cas, le browser embarqué gère entièrement les cookies de session.\n */\nexport class SessionManagerFactory {\n static create(http: CommerceHttpAdapter, context: CommerceContext): SessionManager {\n if (context.mode === 'kiosk') {\n return new KioskSessionManager()\n }\n return new BrowserSessionManager(http, context)\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { SessionInfo } from '../../types/index.js'\n\nexport class SessionModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Récupère les informations de la session en cours */\n getSession(): Promise<SessionInfo> {\n return this.cache.execute(\n 'session:raw',\n () => this.http.get<SessionInfo>('/commerce/api/sessions/raw'),\n 'network-first'\n )\n }\n\n /** Associe un magasin à la session */\n async associateStore(storeGuid: string): Promise<SessionInfo> {\n const result = await this.http.post<SessionInfo>(\n `/commerce/api/sessions/associate/store/${storeGuid}`\n )\n await this.cache.execute('session:raw', () => Promise.resolve(result), 'network-first')\n return result\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { OfflineQueue } from '../../offline/OfflineQueue.js'\nimport type { ConnectivityManager } from '../../connectivity/ConnectivityManager.js'\nimport type { Cart, CartValidationStatus } from '../../types/index.js'\n\nexport class CartModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy,\n private readonly queue: OfflineQueue,\n private readonly connectivity: ConnectivityManager\n ) {}\n\n /** Récupère le panier en cours */\n getCart(): Promise<Cart> {\n return this.cache.execute(\n 'cart:current',\n () => this.http.get<Cart>('/commerce/api/process/cart'),\n 'network-first'\n )\n }\n\n /** Récupère le statut de validation du panier */\n getValidationStatus(): Promise<CartValidationStatus> {\n return this.http.get<CartValidationStatus>('/commerce/api/process/cart/status/check')\n }\n\n /** Ajoute un article au panier */\n async addItem(reference: string, quantity: number, options?: Record<string, unknown>): Promise<Cart> {\n const body = { reference, quantity, ...options }\n if (this.connectivity.isOffline) {\n await this.queue.enqueue('POST', '/commerce/api/process/cart/items', body)\n // Retourner le panier depuis le cache\n return this.cache.execute('cart:current', () => this.http.get<Cart>('/commerce/api/process/cart'), 'network-first')\n }\n const cart = await this.http.post<Cart>('/commerce/api/process/cart/items', body)\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n /** Met à jour la quantité d'une ligne */\n async updateItem(lineId: string, quantity: number): Promise<Cart> {\n const body = { quantity }\n if (this.connectivity.isOffline) {\n await this.queue.enqueue('PUT', `/commerce/api/process/cart/items/${lineId}`, body)\n return this.cache.execute('cart:current', () => this.http.get<Cart>('/commerce/api/process/cart'), 'network-first')\n }\n const cart = await this.http.put<Cart>(`/commerce/api/process/cart/items/${lineId}`, body)\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n /** Supprime une ligne du panier */\n async removeItem(lineId: string): Promise<Cart> {\n if (this.connectivity.isOffline) {\n await this.queue.enqueue('DELETE', `/commerce/api/process/cart/items/${lineId}`)\n return this.cache.execute('cart:current', () => this.http.get<Cart>('/commerce/api/process/cart'), 'network-first')\n }\n const cart = await this.http.delete<Cart>(`/commerce/api/process/cart/items/${lineId}`)\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n /** Applique un coupon */\n async applyCoupon(code: string): Promise<Cart> {\n const cart = await this.http.post<Cart>('/commerce/api/process/cart/coupons', { code })\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n /** Retire un coupon */\n async removeCoupon(code: string): Promise<Cart> {\n const cart = await this.http.delete<Cart>(`/commerce/api/process/cart/coupons/${encodeURIComponent(code)}`)\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { ProductDetails, WebProduct, SearchRequest, SearchResult } from '../../types/index.js'\n\nexport class CatalogModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Récupère le détail d'un produit par sa référence */\n getProduct(reference: string): Promise<ProductDetails> {\n return this.cache.execute(\n `catalog:product:${reference}`,\n () => this.http.get<ProductDetails>(`/commerce/api/pim/products/${encodeURIComponent(reference)}`),\n 'stale-while-revalidate'\n )\n }\n\n /** Récupère une liste de produits par leurs références */\n getProducts(references: string[]): Promise<WebProduct[]> {\n const key = `catalog:products:${references.sort().join(',')}`\n return this.cache.execute(\n key,\n () => this.http.post<WebProduct[]>('/commerce/api/pim/products/batch', { references }),\n 'stale-while-revalidate'\n )\n }\n\n /** Récupère les produits d'une catégorie */\n getCategory(categoryCode: string, pageIndex = 0, pageSize = 20): Promise<SearchResult> {\n const key = `catalog:category:${categoryCode}:${pageIndex}:${pageSize}`\n return this.cache.execute(\n key,\n () => this.http.get<SearchResult>(\n `/commerce/api/pim/categories/${encodeURIComponent(categoryCode)}/products?pageIndex=${pageIndex}&pageSize=${pageSize}`\n ),\n 'stale-while-revalidate'\n )\n }\n\n /** Effectue une recherche full-text */\n search(request: SearchRequest): Promise<SearchResult> {\n const key = `catalog:search:${JSON.stringify(request)}`\n return this.cache.execute(\n key,\n () => this.http.post<SearchResult>('/commerce/api/pim/search', request),\n 'cache-first'\n )\n }\n\n /** Récupère les suggestions de recherche (autocomplete) */\n suggest(query: string): Promise<string[]> {\n return this.cache.execute(\n `catalog:suggest:${query}`,\n () => this.http.get<string[]>(`/commerce/api/pim/search/suggest?q=${encodeURIComponent(query)}`),\n 'cache-first',\n 2 * 60_000 // 2 minutes pour les suggestions\n )\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { ShippingChoiceGroup, ShippingAddress, PickupPoint } from '../../types/index.js'\n\nexport class ShippingModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Récupère les groupes de modes de livraison disponibles pour le panier en cours */\n getAvailableModes(): Promise<ShippingChoiceGroup[]> {\n return this.cache.execute(\n 'shipping:modes',\n () => this.http.get<ShippingChoiceGroup[]>('/commerce/api/process/cart/shipping/modes'),\n 'network-first'\n )\n }\n\n /** Sélectionne un mode de livraison */\n selectMode(shippingModeGuid: string): Promise<void> {\n return this.http.post('/commerce/api/process/cart/shipping/mode', { shippingModeGuid })\n }\n\n /** Met à jour l'adresse de livraison */\n setAddress(address: ShippingAddress): Promise<void> {\n return this.http.put('/commerce/api/process/cart/address/shipping', address)\n }\n\n /** Recherche des points relais à proximité */\n getRelayPoints(postalCode: string, countryCode = 'FR', shippingModeGuid?: string): Promise<PickupPoint[]> {\n const params = new URLSearchParams({ postalCode, countryCode })\n if (shippingModeGuid) params.set('shippingModeGuid', shippingModeGuid)\n const key = `shipping:relays:${postalCode}:${countryCode}:${shippingModeGuid ?? ''}`\n return this.cache.execute(\n key,\n () => this.http.get<PickupPoint[]>(`/commerce/api/process/shipping/relays?${params.toString()}`),\n 'cache-first',\n 10 * 60_000 // 10 minutes\n )\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { MarketingItem } from '../../types/index.js'\n\nexport class MarketingModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Récupère un item marketing par son code */\n getItem(code: string): Promise<MarketingItem> {\n return this.cache.execute(\n `marketing:item:${code}`,\n () => this.http.get<MarketingItem>(`/commerce/api/marketing/items/${encodeURIComponent(code)}`),\n 'stale-while-revalidate'\n )\n }\n\n /** Récupère plusieurs items marketing par leurs codes */\n getItems(codes: string[]): Promise<MarketingItem[]> {\n const key = `marketing:items:${codes.sort().join(',')}`\n return this.cache.execute(\n key,\n () => this.http.post<MarketingItem[]>('/commerce/api/marketing/items/batch', { codes }),\n 'stale-while-revalidate'\n )\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { StoreWithOpeningHours } from '../../types/index.js'\n\nexport class StoresModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Recherche des magasins par coordonnées géographiques */\n findByLocation(latitude: number, longitude: number, radiusKm = 50): Promise<StoreWithOpeningHours[]> {\n const key = `stores:geo:${latitude.toFixed(4)}:${longitude.toFixed(4)}:${radiusKm}`\n return this.cache.execute(\n key,\n () => this.http.get<StoreWithOpeningHours[]>(\n `/commerce/api/stores/locator?lat=${latitude}&lon=${longitude}&radius=${radiusKm}`\n ),\n 'cache-first',\n 15 * 60_000 // 15 minutes\n )\n }\n\n /** Recherche des magasins par code postal */\n findByPostalCode(postalCode: string, countryCode = 'FR'): Promise<StoreWithOpeningHours[]> {\n const key = `stores:postal:${postalCode}:${countryCode}`\n return this.cache.execute(\n key,\n () => this.http.get<StoreWithOpeningHours[]>(\n `/commerce/api/stores/locator?postalCode=${encodeURIComponent(postalCode)}&countryCode=${encodeURIComponent(countryCode)}`\n ),\n 'cache-first',\n 15 * 60_000\n )\n }\n\n /** Récupère le détail d'un magasin par son GUID */\n getStore(storeGuid: string): Promise<StoreWithOpeningHours> {\n return this.cache.execute(\n `stores:detail:${storeGuid}`,\n () => this.http.get<StoreWithOpeningHours>(`/commerce/api/stores/${storeGuid}`),\n 'stale-while-revalidate'\n )\n }\n}\n","import { CommerceContext, type CommerceContextOptions } from './CommerceContext.js'\nimport { CommerceHttpAdapter } from './CommerceHttpAdapter.js'\nimport { ConnectivityManager } from '../connectivity/ConnectivityManager.js'\nimport { WorkerBridge } from '../workers/WorkerBridge.js'\nimport { CacheStrategy } from '../workers/CacheStrategy.js'\nimport { OfflineQueue } from '../offline/OfflineQueue.js'\nimport { SessionManagerFactory } from '../session/SessionManagerFactory.js'\nimport { SessionModule } from '../modules/session/index.js'\nimport { CartModule } from '../modules/cart/index.js'\nimport { CatalogModule } from '../modules/catalog/index.js'\nimport { ShippingModule } from '../modules/shipping/index.js'\nimport { MarketingModule } from '../modules/marketing/index.js'\nimport { StoresModule } from '../modules/stores/index.js'\nimport type { SessionManager } from '../session/SessionManager.js'\nimport type { SessionInfo } from '../types/index.js'\n\nexport { CommerceContext, type CommerceContextOptions } from './CommerceContext.js'\n\n/**\n * Point d'entrée principal du SDK Altazion Commerce.\n *\n * Usage :\n * ```ts\n * const client = new CommerceClient({ baseUrl: 'https://api.monsite.com', siteUrl: window.location.href })\n * await client.initialize()\n *\n * const cart = await client.cart.getCart()\n * ```\n */\nexport class CommerceClient {\n readonly context: CommerceContext\n readonly connectivity: ConnectivityManager\n\n readonly session: SessionModule\n readonly cart: CartModule\n readonly catalog: CatalogModule\n readonly shipping: ShippingModule\n readonly marketing: MarketingModule\n readonly stores: StoresModule\n\n private readonly http: CommerceHttpAdapter\n private readonly workerBridge: WorkerBridge\n private readonly cacheStrategy: CacheStrategy\n private readonly offlineQueue: OfflineQueue\n private readonly sessionManager: SessionManager\n\n private unsubscribeOnline: (() => void) | null = null\n\n constructor(options: CommerceContextOptions) {\n this.context = new CommerceContext(options)\n this.http = new CommerceHttpAdapter(this.context)\n this.connectivity = new ConnectivityManager()\n this.workerBridge = new WorkerBridge()\n this.cacheStrategy = new CacheStrategy(this.workerBridge, this.http)\n this.offlineQueue = new OfflineQueue()\n this.sessionManager = SessionManagerFactory.create(this.http, this.context)\n\n // Modules API\n this.session = new SessionModule(this.http, this.cacheStrategy)\n this.cart = new CartModule(this.http, this.cacheStrategy, this.offlineQueue, this.connectivity)\n this.catalog = new CatalogModule(this.http, this.cacheStrategy)\n this.shipping = new ShippingModule(this.http, this.cacheStrategy)\n this.marketing = new MarketingModule(this.http, this.cacheStrategy)\n this.stores = new StoresModule(this.http, this.cacheStrategy)\n }\n\n /**\n * Initialise le SDK :\n * - Crée la session si nécessaire (mode browser uniquement)\n * - Abonne le flush automatique de la file hors-ligne au retour en ligne\n */\n async initialize(): Promise<SessionInfo | null> {\n // Flush automatique quand on revient en ligne\n this.unsubscribeOnline = this.connectivity.subscribe(async (status) => {\n if (status === 'online') {\n await this.offlineQueue.flush(this.http)\n }\n })\n\n return this.sessionManager.initialize()\n }\n\n /**\n * Retourne vrai si le SDK est hors-ligne.\n */\n get isOffline(): boolean {\n return this.connectivity.isOffline\n }\n\n /**\n * Retourne le nombre d'opérations en attente dans la file hors-ligne.\n */\n get pendingOperationsCount(): Promise<number> {\n return this.offlineQueue.pendingCount\n }\n\n /**\n * Abonne un listener aux événements de la file hors-ligne.\n * Retourne une fonction de désabonnement.\n */\n onQueueEvent(\n listener: Parameters<OfflineQueue['subscribe']>[0]\n ): () => void {\n return this.offlineQueue.subscribe(listener)\n }\n\n /**\n * Force le vidage du cache.\n */\n clearCache(): Promise<void> {\n return this.workerBridge.clearAll()\n }\n\n /**\n * Libère les ressources (listeners, worker).\n */\n dispose(): void {\n this.unsubscribeOnline?.()\n this.connectivity.dispose()\n this.workerBridge.dispose()\n }\n}\n"],"names":["data"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/client/CommerceContext.ts","../src/client/errors.ts","../src/client/CommerceHttpAdapter.ts","../src/connectivity/ConnectivityManager.ts","../src/workers/WorkerBridge.ts","../src/workers/CacheStrategy.ts","../src/session/BrowserSessionManager.ts","../src/session/KioskSessionManager.ts","../src/session/SessionManagerFactory.ts","../src/modules/session/index.ts","../src/modules/cart/index.ts","../src/modules/catalog/index.ts","../src/modules/shipping/index.ts","../src/modules/marketing/index.ts","../src/modules/stores/index.ts","../src/client/CommerceClient.ts"],"sourcesContent":["/**\n * Mode d'exécution du SDK.\n * - `browser` : navigateur classique — le SDK gère la création de session et le cookie.\n * - `kiosk` : borne avec \"Altazion Device Shell\" — le browser embarqué gère les cookies.\n */\nexport type CommerceMode = 'browser' | 'kiosk'\n\nexport interface CommerceContextOptions {\n /** URL de base de l'API (ex. : \"https://api.monsite.com\") */\n baseUrl: string\n /** Identifiant ou URL du site web pour la création de session (mode browser) */\n siteUrl?: string\n /**\n * Clé primaire du site (alternative à siteUrl).\n * Requiert aussi rjsId.\n */\n sitePk?: number\n /** Identifiant du tenant RJS (nécessaire avec sitePk) */\n rjsId?: number\n /** Locale par défaut (ex. : \"fr-FR\") */\n locale?: string\n /** Devise par défaut (ex. : \"EUR\") */\n currency?: string\n}\n\n/**\n * Contexte partagé du SDK, instancié une seule fois et transmis\n * à tous les sous-systèmes (HttpAdapter, SessionManager, modules…).\n */\nexport class CommerceContext {\n readonly baseUrl: string\n readonly siteUrl: string | undefined\n readonly sitePk: number | undefined\n readonly rjsId: number | undefined\n readonly locale: string\n readonly currency: string\n readonly mode: CommerceMode\n\n constructor(options: CommerceContextOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.siteUrl = options.siteUrl\n this.sitePk = options.sitePk\n this.rjsId = options.rjsId\n this.locale = options.locale ?? 'fr-FR'\n this.currency = options.currency ?? 'EUR'\n this.mode = CommerceContext.detectMode()\n }\n\n private static detectMode(): CommerceMode {\n if (typeof navigator !== 'undefined' && navigator.userAgent.includes('Altazion Device Shell')) {\n return 'kiosk'\n }\n return 'browser'\n }\n}\n","/**\n * Représentation d'une réponse d'erreur ProblemDetails (RFC 9457)\n * telle que renvoyée par GlobalExceptionFilter.cs\n */\nexport interface ProblemDetails {\n type?: string\n title?: string\n status?: number\n detail?: string\n instance?: string\n [key: string]: unknown\n}\n\n/**\n * Erreur générée par l'API Altazion Commerce (HTTP 4xx / 5xx).\n */\nexport class AltazionApiError extends Error {\n readonly status: number\n readonly problem: ProblemDetails\n\n constructor(status: number, problem: ProblemDetails) {\n super(problem.detail ?? problem.title ?? `HTTP ${status}`)\n this.name = 'AltazionApiError'\n this.status = status\n this.problem = problem\n }\n}\n\n/**\n * Erreur levée lorsque le SDK est hors-ligne et ne peut pas\n * satisfaire la requête depuis le cache.\n */\nexport class OfflineError extends Error {\n constructor(message = 'Le SDK est hors-ligne et aucun cache n\\'est disponible pour cette ressource') {\n super(message)\n this.name = 'OfflineError'\n }\n}\n\n/**\n * Erreur liée à une opération sur le cache (IndexedDB, SharedWorker).\n */\nexport class CacheError extends Error {\n readonly cause: unknown\n\n constructor(message: string, cause?: unknown) {\n super(message)\n this.name = 'CacheError'\n this.cause = cause\n }\n}\n","import { AltazionApiError, type ProblemDetails } from './errors.js'\nimport type { CommerceContext } from './CommerceContext.js'\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n body?: unknown\n headers?: Record<string, string>\n /** Nombre maximum de tentatives réseau (uniquement sur erreurs réseau, jamais sur 4xx) */\n maxRetries?: number\n}\n\n/**\n * Adaptateur HTTP basé sur fetch natif.\n *\n * Responsabilités :\n * - Construction des URLs à partir du baseUrl du contexte\n * - Ajout des headers standard (Content-Type, Accept, locale)\n * - credentials: 'include' pour la transmission automatique des cookies (modes browser et kiosk)\n * - Parse des réponses ProblemDetails en AltazionApiError\n * - Retry limité sur les erreurs réseau (TypeError), jamais sur les 4xx/5xx\n */\nexport class CommerceHttpAdapter {\n private readonly context: CommerceContext\n\n constructor(context: CommerceContext) {\n this.context = context\n }\n\n async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, headers = {}, maxRetries = 2 } = options\n const url = `${this.context.baseUrl}${path}`\n\n const requestHeaders: Record<string, string> = {\n Accept: 'application/json',\n 'Accept-Language': this.context.locale,\n ...headers\n }\n\n if (body !== undefined) {\n requestHeaders['Content-Type'] = 'application/json'\n }\n\n const init: RequestInit = {\n method,\n headers: requestHeaders,\n credentials: 'include',\n body: body !== undefined ? JSON.stringify(body) : undefined\n }\n\n let lastNetworkError: unknown\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetch(url, init)\n return await this.handleResponse<T>(response)\n } catch (err) {\n // AltazionApiError n'est jamais retenté\n if (err instanceof AltazionApiError) throw err\n lastNetworkError = err\n // Petite pause exponentielle avant de réessayer (uniquement sur erreurs réseau)\n if (attempt < maxRetries) {\n await delay(150 * Math.pow(2, attempt))\n }\n }\n }\n\n throw lastNetworkError\n }\n\n private async handleResponse<T>(response: Response): Promise<T> {\n if (response.ok) {\n const contentType = response.headers.get('content-type') ?? ''\n if (response.status === 204 || !contentType.includes('application/json')) {\n return undefined as unknown as T\n }\n return response.json() as Promise<T>\n }\n\n // Tenter de parser un ProblemDetails\n let problem: ProblemDetails = { status: response.status }\n try {\n const contentType = response.headers.get('content-type') ?? ''\n if (contentType.includes('application/json') || contentType.includes('application/problem+json')) {\n problem = await response.json() as ProblemDetails\n problem.status ??= response.status\n }\n } catch {\n // JSON invalide — on garde le problem minimal\n }\n\n throw new AltazionApiError(response.status, problem)\n }\n\n /** Effectue un GET et retourne T */\n get<T>(path: string, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'GET', headers })\n }\n\n /** Effectue un POST avec un body JSON et retourne T */\n post<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'POST', body, headers })\n }\n\n /** Effectue un PUT avec un body JSON et retourne T */\n put<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'PUT', body, headers })\n }\n\n /** Effectue un PATCH avec un body JSON et retourne T */\n patch<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'PATCH', body, headers })\n }\n\n /** Effectue un DELETE et retourne T */\n delete<T>(path: string, headers?: Record<string, string>): Promise<T> {\n return this.request<T>(path, { method: 'DELETE', headers })\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","export type ConnectivityStatus = 'online' | 'offline'\n\nexport type ConnectivityListener = (status: ConnectivityStatus) => void\n\n/**\n * Surveille l'état de la connexion réseau.\n *\n * - Utilise navigator.onLine comme valeur initiale\n * - Écoute les événements window 'online' / 'offline'\n * - Permet d'abonner des listeners (pattern observable léger)\n */\nexport class ConnectivityManager {\n private status: ConnectivityStatus\n private readonly listeners = new Set<ConnectivityListener>()\n\n constructor() {\n this.status = this.readOnlineStatus()\n\n if (typeof window !== 'undefined') {\n window.addEventListener('online', this.handleOnline)\n window.addEventListener('offline', this.handleOffline)\n }\n }\n\n get isOnline(): boolean {\n return this.status === 'online'\n }\n\n get isOffline(): boolean {\n return this.status === 'offline'\n }\n\n /**\n * Abonne un listener aux changements de connectivité.\n * Retourne une fonction de désabonnement.\n */\n subscribe(listener: ConnectivityListener): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** Libère les event listeners sur window. */\n dispose(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener('online', this.handleOnline)\n window.removeEventListener('offline', this.handleOffline)\n }\n this.listeners.clear()\n }\n\n private readOnlineStatus(): ConnectivityStatus {\n if (typeof navigator === 'undefined' || navigator.onLine === undefined) {\n return 'online' // SSR / environnement sans navigator : on suppose online\n }\n return navigator.onLine ? 'online' : 'offline'\n }\n\n private readonly handleOnline = (): void => {\n this.status = 'online'\n this.emit('online')\n }\n\n private readonly handleOffline = (): void => {\n this.status = 'offline'\n this.emit('offline')\n }\n\n private emit(status: ConnectivityStatus): void {\n for (const listener of this.listeners) {\n try {\n listener(status)\n } catch {\n // Un listener ne doit pas faire planter les autres\n }\n }\n }\n}\n","import { CacheError } from '../client/errors.js'\n\ninterface PendingRequest {\n resolve: (value: unknown) => void\n reject: (reason: unknown) => void\n}\n\n/**\n * Abstraction du canal de communication avec le SharedWorker de cache.\n *\n * - Utilise un SharedWorker si le navigateur le supporte\n * - Fallback : Map in-memory (données non persistantes, perdues au reload)\n *\n * Chaque appel retourne une Promise, résolue/rejetée via la réponse du worker.\n */\nexport class WorkerBridge {\n private port: MessagePort | null = null\n private readonly pending = new Map<string, PendingRequest>()\n private requestCounter = 0\n private readonly fallback = new Map<string, { data: unknown; expiresAt: number }>()\n private readonly usingFallback: boolean\n\n constructor() {\n this.usingFallback = !this.tryStartWorker()\n }\n\n private tryStartWorker(): boolean {\n if (typeof SharedWorker === 'undefined') return false\n\n try {\n const worker = new SharedWorker(\n new URL('./cache.worker.ts', import.meta.url),\n { type: 'module', name: 'altazion-cache-worker' }\n )\n this.port = worker.port\n this.port.addEventListener('message', this.handleMessage)\n this.port.start()\n return true\n } catch {\n return false\n }\n }\n\n private readonly handleMessage = (event: MessageEvent<{ id: string; result?: unknown; error?: string }>): void => {\n const { id, result, error } = event.data\n const pending = this.pending.get(id)\n if (!pending) return\n this.pending.delete(id)\n\n if (error !== undefined) {\n pending.reject(new CacheError(error))\n } else {\n pending.resolve(result)\n }\n }\n\n private nextId(): string {\n return String(++this.requestCounter)\n }\n\n private send(message: Record<string, unknown>): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (!this.port) {\n reject(new CacheError('Worker non initialisé'))\n return\n }\n const id = this.nextId()\n this.pending.set(id, { resolve, reject })\n this.port.postMessage({ ...message, id })\n })\n }\n\n async get<T>(key: string): Promise<T | null> {\n if (this.usingFallback) {\n const entry = this.fallback.get(key)\n if (!entry || Date.now() > entry.expiresAt) return null\n return entry.data as T\n }\n return this.send({ type: 'GET', key }) as Promise<T | null>\n }\n\n async set(key: string, data: unknown, ttlMs: number): Promise<void> {\n if (this.usingFallback) {\n this.fallback.set(key, { data, expiresAt: Date.now() + ttlMs })\n return\n }\n await this.send({ type: 'SET', key, data, ttl: ttlMs })\n }\n\n async invalidate(pattern: string): Promise<void> {\n if (this.usingFallback) {\n const regex = new RegExp(pattern)\n for (const key of this.fallback.keys()) {\n if (regex.test(key)) this.fallback.delete(key)\n }\n return\n }\n await this.send({ type: 'INVALIDATE', pattern })\n }\n\n async clearAll(): Promise<void> {\n if (this.usingFallback) {\n this.fallback.clear()\n return\n }\n await this.send({ type: 'CLEAR_ALL' })\n }\n\n dispose(): void {\n this.port?.removeEventListener('message', this.handleMessage)\n this.pending.clear()\n }\n}\n","import type { WorkerBridge } from './WorkerBridge.js'\nimport type { CommerceHttpAdapter } from '../client/CommerceHttpAdapter.js'\n\n/**\n * Stratégies de cache disponibles pour les requêtes HTTP.\n */\nexport type CacheStrategyName =\n | 'network-only' // Jamais de cache (mutations)\n | 'network-first' // Réseau, fallback cache si erreur réseau\n | 'cache-first' // Cache, revalidation réseau en background si périmé\n | 'stale-while-revalidate' // Retourne le cache immédiatement + revalide en arrière-plan\n\n/** TTL par stratégie, en millisecondes */\nexport const DEFAULT_TTL: Record<Exclude<CacheStrategyName, 'network-only'>, number> = {\n 'network-first': 30_000, // 30 secondes (session, panier)\n 'cache-first': 5 * 60_000, // 5 minutes (recherche)\n 'stale-while-revalidate': 60 * 60_000 // 1 heure (catalogue)\n}\n\nexport class CacheStrategy {\n constructor(\n private readonly bridge: WorkerBridge,\n private readonly http: CommerceHttpAdapter\n ) {}\n\n /**\n * Exécute la requête selon la stratégie choisie.\n *\n * @param key Clé de cache (généralement le path + params)\n * @param fetcher Fonction qui effectue la requête HTTP\n * @param strategy Stratégie à appliquer\n * @param ttlMs TTL du cache (override la valeur par défaut)\n */\n async execute<T>(\n key: string,\n fetcher: () => Promise<T>,\n strategy: CacheStrategyName,\n ttlMs?: number\n ): Promise<T> {\n switch (strategy) {\n case 'network-only':\n return fetcher()\n\n case 'network-first':\n return this.networkFirst<T>(key, fetcher, ttlMs ?? DEFAULT_TTL['network-first'])\n\n case 'cache-first':\n return this.cacheFirst<T>(key, fetcher, ttlMs ?? DEFAULT_TTL['cache-first'])\n\n case 'stale-while-revalidate':\n return this.staleWhileRevalidate<T>(key, fetcher, ttlMs ?? DEFAULT_TTL['stale-while-revalidate'])\n }\n }\n\n private async networkFirst<T>(key: string, fetcher: () => Promise<T>, ttlMs: number): Promise<T> {\n try {\n const data = await fetcher()\n await this.bridge.set(key, data, ttlMs)\n return data\n } catch (err) {\n // Erreur réseau uniquement (TypeError) : on tente le cache\n if (err instanceof TypeError) {\n const cached = await this.bridge.get<T>(key)\n if (cached !== null) return cached\n }\n throw err\n }\n }\n\n private async cacheFirst<T>(key: string, fetcher: () => Promise<T>, ttlMs: number): Promise<T> {\n const cached = await this.bridge.get<T>(key)\n if (cached !== null) return cached\n\n const data = await fetcher()\n await this.bridge.set(key, data, ttlMs)\n return data\n }\n\n private async staleWhileRevalidate<T>(key: string, fetcher: () => Promise<T>, ttlMs: number): Promise<T> {\n const cached = await this.bridge.get<T>(key)\n\n // Revalidation en arrière-plan (ne bloque pas le résultat)\n const revalidate = fetcher()\n .then((data) => this.bridge.set(key, data, ttlMs))\n .catch(() => { /* Échec silencieux : on garde le cache */ })\n\n if (cached !== null) {\n // On lance la revalidation sans attendre\n void revalidate\n return cached\n }\n\n // Pas de cache : on attend le réseau\n const data = await fetcher()\n await this.bridge.set(key, data, ttlMs)\n return data\n }\n}\n","import type { SessionManager } from './SessionManager.js'\nimport type { CommerceHttpAdapter } from '../client/CommerceHttpAdapter.js'\nimport type { CommerceContext } from '../client/CommerceContext.js'\nimport type { SessionInfo } from '../types/index.js'\nimport { AltazionApiError } from '../client/errors.js'\n\n/**\n * Gestionnaire de session pour le mode navigateur classique.\n *\n * Responsabilités :\n * - Appel à POST /commerce/api/sessions/create pour créer la session\n * - La session est identifiée côté serveur via le cookie `altz_session_id`\n * (créé automatiquement par l'API et transmis grâce à credentials:'include')\n */\nexport class BrowserSessionManager implements SessionManager {\n private readonly http: CommerceHttpAdapter\n private readonly context: CommerceContext\n\n constructor(http: CommerceHttpAdapter, context: CommerceContext) {\n this.http = http\n this.context = context\n }\n\n async initialize(): Promise<SessionInfo | null> {\n // Vérifier si une session existe déjà\n try {\n const existing = await this.http.get<SessionInfo>('/commerce/api/sessions/raw')\n return existing\n } catch (err) {\n // 404 = pas de session, on en crée une\n if (err instanceof AltazionApiError && err.status === 404) {\n return this.createSession()\n }\n throw err\n }\n }\n\n async onSessionExpired(): Promise<void> {\n await this.createSession()\n }\n\n private async createSession(): Promise<SessionInfo> {\n const body = this.buildCreationRequest()\n return this.http.post<SessionInfo>('/commerce/api/sessions/create', body)\n }\n\n private buildCreationRequest(): Record<string, unknown> {\n if (this.context.sitePk !== undefined && this.context.rjsId !== undefined) {\n return { sitePk: this.context.sitePk, rjsId: this.context.rjsId }\n }\n if (this.context.siteUrl !== undefined) {\n return { siteUrl: this.context.siteUrl }\n }\n // Fallback : envoyer l'URL courante du navigateur\n const currentUrl = typeof window !== 'undefined' ? window.location.href : undefined\n return { siteUrl: currentUrl }\n }\n}\n","import type { SessionManager } from './SessionManager.js'\nimport type { SessionInfo } from '../types/index.js'\n\n/**\n * Gestionnaire de session pour le mode borne (Altazion Device Shell).\n *\n * Le browser embarqué gère intégralement les cookies de session.\n * Le SDK n'a pas à intervenir : fetch avec credentials:'include' suffit\n * pour que les cookies soient transmis automatiquement.\n *\n * Cette implémentation est un no-op intentionnel.\n */\nexport class KioskSessionManager implements SessionManager {\n async initialize(): Promise<SessionInfo | null> {\n // Le browser embarqué est responsable de la session.\n // Aucune action requise côté SDK.\n return null\n }\n\n async onSessionExpired(): Promise<void> {\n // Le browser embarqué gère le renouvellement de session.\n // Aucune action requise côté SDK.\n }\n}\n","import type { SessionManager } from './SessionManager.js'\nimport { BrowserSessionManager } from './BrowserSessionManager.js'\nimport { KioskSessionManager } from './KioskSessionManager.js'\nimport type { CommerceHttpAdapter } from '../client/CommerceHttpAdapter.js'\nimport type { CommerceContext } from '../client/CommerceContext.js'\n\n/**\n * Instancie le SessionManager adapté au contexte d'exécution.\n *\n * Détection du mode kiosk : présence de \"Altazion Device Shell\" dans le User-Agent.\n * Dans ce cas, le browser embarqué gère entièrement les cookies de session.\n */\nexport class SessionManagerFactory {\n static create(http: CommerceHttpAdapter, context: CommerceContext): SessionManager {\n if (context.mode === 'kiosk') {\n return new KioskSessionManager()\n }\n return new BrowserSessionManager(http, context)\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { SessionInfo } from '../../types/index.js'\n\nexport class SessionModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Récupère les informations de la session en cours */\n getSession(): Promise<SessionInfo> {\n return this.cache.execute(\n 'session:raw',\n () => this.http.get<SessionInfo>('/commerce/api/sessions/raw'),\n 'network-first'\n )\n }\n\n /** Associe un magasin à la session */\n async associateStore(storeGuid: string): Promise<SessionInfo> {\n const result = await this.http.post<SessionInfo>(\n `/commerce/api/sessions/associate/store/${storeGuid}`\n )\n await this.cache.execute('session:raw', () => Promise.resolve(result), 'network-first')\n return result\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport { OfflineError } from '../../client/errors.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { ConnectivityManager } from '../../connectivity/ConnectivityManager.js'\nimport type { Cart, CartValidationStatus } from '../../types/index.js'\n\nexport class CartModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy,\n private readonly connectivity: ConnectivityManager\n ) {}\n\n /** Récupère le panier en cours */\n getCart(): Promise<Cart> {\n return this.cache.execute(\n 'cart:current',\n () => this.http.get<Cart>('/commerce/api/process/cart'),\n 'network-first'\n )\n }\n\n /** Récupère le statut de validation du panier */\n getValidationStatus(): Promise<CartValidationStatus> {\n return this.http.get<CartValidationStatus>('/commerce/api/process/cart/status/check')\n }\n\n /** Ajoute un article au panier */\n async addItem(reference: string, quantity: number, options?: Record<string, unknown>): Promise<Cart> {\n this.ensureOnline()\n const body = { reference, quantity, ...options }\n const cart = await this.http.post<Cart>('/commerce/api/process/cart/items', body)\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n /** Met à jour la quantité d'une ligne */\n async updateItem(lineId: string, quantity: number): Promise<Cart> {\n this.ensureOnline()\n const body = { quantity }\n const cart = await this.http.put<Cart>(`/commerce/api/process/cart/items/${lineId}`, body)\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n /** Supprime une ligne du panier */\n async removeItem(lineId: string): Promise<Cart> {\n this.ensureOnline()\n const cart = await this.http.delete<Cart>(`/commerce/api/process/cart/items/${lineId}`)\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n /** Applique un coupon */\n async applyCoupon(code: string): Promise<Cart> {\n this.ensureOnline()\n const cart = await this.http.post<Cart>('/commerce/api/process/cart/coupons', { code })\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n /** Retire un coupon */\n async removeCoupon(code: string): Promise<Cart> {\n this.ensureOnline()\n const cart = await this.http.delete<Cart>(`/commerce/api/process/cart/coupons/${encodeURIComponent(code)}`)\n await this.cache.execute('cart:current', () => Promise.resolve(cart), 'network-first')\n return cart\n }\n\n private ensureOnline(): void {\n if (this.connectivity.isOffline) {\n throw new OfflineError('Le terminal est hors ligne, les modifications du panier sont indisponibles')\n }\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { ProductDetails, WebProduct, SearchRequest, SearchResult } from '../../types/index.js'\n\nexport class CatalogModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Récupère le détail d'un produit par sa référence */\n getProduct(reference: string): Promise<ProductDetails> {\n return this.cache.execute(\n `catalog:product:${reference}`,\n () => this.http.get<ProductDetails>(`/commerce/api/pim/products/${encodeURIComponent(reference)}`),\n 'stale-while-revalidate'\n )\n }\n\n /** Récupère une liste de produits par leurs références */\n getProducts(references: string[]): Promise<WebProduct[]> {\n const key = `catalog:products:${references.sort().join(',')}`\n return this.cache.execute(\n key,\n () => this.http.post<WebProduct[]>('/commerce/api/pim/products/batch', { references }),\n 'stale-while-revalidate'\n )\n }\n\n /** Récupère les produits d'une catégorie */\n getCategory(categoryCode: string, pageIndex = 0, pageSize = 20): Promise<SearchResult> {\n const key = `catalog:category:${categoryCode}:${pageIndex}:${pageSize}`\n return this.cache.execute(\n key,\n () => this.http.get<SearchResult>(\n `/commerce/api/pim/categories/${encodeURIComponent(categoryCode)}/products?pageIndex=${pageIndex}&pageSize=${pageSize}`\n ),\n 'stale-while-revalidate'\n )\n }\n\n /** Effectue une recherche full-text */\n search(request: SearchRequest): Promise<SearchResult> {\n const key = `catalog:search:${JSON.stringify(request)}`\n return this.cache.execute(\n key,\n () => this.http.post<SearchResult>('/commerce/api/pim/search', request),\n 'cache-first'\n )\n }\n\n /** Récupère les suggestions de recherche (autocomplete) */\n suggest(query: string): Promise<string[]> {\n return this.cache.execute(\n `catalog:suggest:${query}`,\n () => this.http.get<string[]>(`/commerce/api/pim/search/suggest?q=${encodeURIComponent(query)}`),\n 'cache-first',\n 2 * 60_000 // 2 minutes pour les suggestions\n )\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { ShippingChoiceGroup, ShippingAddress, PickupPoint } from '../../types/index.js'\n\nexport class ShippingModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Récupère les groupes de modes de livraison disponibles pour le panier en cours */\n getAvailableModes(): Promise<ShippingChoiceGroup[]> {\n return this.cache.execute(\n 'shipping:modes',\n () => this.http.get<ShippingChoiceGroup[]>('/commerce/api/process/cart/shipping/modes'),\n 'network-first'\n )\n }\n\n /** Sélectionne un mode de livraison */\n selectMode(shippingModeGuid: string): Promise<void> {\n return this.http.post('/commerce/api/process/cart/shipping/mode', { shippingModeGuid })\n }\n\n /** Met à jour l'adresse de livraison */\n setAddress(address: ShippingAddress): Promise<void> {\n return this.http.put('/commerce/api/process/cart/address/shipping', address)\n }\n\n /** Recherche des points relais à proximité */\n getRelayPoints(postalCode: string, countryCode = 'FR', shippingModeGuid?: string): Promise<PickupPoint[]> {\n const params = new URLSearchParams({ postalCode, countryCode })\n if (shippingModeGuid) params.set('shippingModeGuid', shippingModeGuid)\n const key = `shipping:relays:${postalCode}:${countryCode}:${shippingModeGuid ?? ''}`\n return this.cache.execute(\n key,\n () => this.http.get<PickupPoint[]>(`/commerce/api/process/shipping/relays?${params.toString()}`),\n 'cache-first',\n 10 * 60_000 // 10 minutes\n )\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { MarketingItem } from '../../types/index.js'\n\nexport class MarketingModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Récupère un item marketing par son code */\n getItem(code: string): Promise<MarketingItem> {\n return this.cache.execute(\n `marketing:item:${code}`,\n () => this.http.get<MarketingItem>(`/commerce/api/marketing/items/${encodeURIComponent(code)}`),\n 'stale-while-revalidate'\n )\n }\n\n /** Récupère plusieurs items marketing par leurs codes */\n getItems(codes: string[]): Promise<MarketingItem[]> {\n const key = `marketing:items:${codes.sort().join(',')}`\n return this.cache.execute(\n key,\n () => this.http.post<MarketingItem[]>('/commerce/api/marketing/items/batch', { codes }),\n 'stale-while-revalidate'\n )\n }\n}\n","import type { CommerceHttpAdapter } from '../../client/CommerceHttpAdapter.js'\nimport type { CacheStrategy } from '../../workers/CacheStrategy.js'\nimport type { StoreWithOpeningHours } from '../../types/index.js'\n\nexport class StoresModule {\n constructor(\n private readonly http: CommerceHttpAdapter,\n private readonly cache: CacheStrategy\n ) {}\n\n /** Recherche des magasins par coordonnées géographiques */\n findByLocation(latitude: number, longitude: number, radiusKm = 50): Promise<StoreWithOpeningHours[]> {\n const key = `stores:geo:${latitude.toFixed(4)}:${longitude.toFixed(4)}:${radiusKm}`\n return this.cache.execute(\n key,\n () => this.http.get<StoreWithOpeningHours[]>(\n `/commerce/api/stores/locator?lat=${latitude}&lon=${longitude}&radius=${radiusKm}`\n ),\n 'cache-first',\n 15 * 60_000 // 15 minutes\n )\n }\n\n /** Recherche des magasins par code postal */\n findByPostalCode(postalCode: string, countryCode = 'FR'): Promise<StoreWithOpeningHours[]> {\n const key = `stores:postal:${postalCode}:${countryCode}`\n return this.cache.execute(\n key,\n () => this.http.get<StoreWithOpeningHours[]>(\n `/commerce/api/stores/locator?postalCode=${encodeURIComponent(postalCode)}&countryCode=${encodeURIComponent(countryCode)}`\n ),\n 'cache-first',\n 15 * 60_000\n )\n }\n\n /** Récupère le détail d'un magasin par son GUID */\n getStore(storeGuid: string): Promise<StoreWithOpeningHours> {\n return this.cache.execute(\n `stores:detail:${storeGuid}`,\n () => this.http.get<StoreWithOpeningHours>(`/commerce/api/stores/${storeGuid}`),\n 'stale-while-revalidate'\n )\n }\n}\n","import { CommerceContext, type CommerceContextOptions } from './CommerceContext.js'\nimport { CommerceHttpAdapter } from './CommerceHttpAdapter.js'\nimport { ConnectivityManager } from '../connectivity/ConnectivityManager.js'\nimport { WorkerBridge } from '../workers/WorkerBridge.js'\nimport { CacheStrategy } from '../workers/CacheStrategy.js'\nimport { SessionManagerFactory } from '../session/SessionManagerFactory.js'\nimport { SessionModule } from '../modules/session/index.js'\nimport { CartModule } from '../modules/cart/index.js'\nimport { CatalogModule } from '../modules/catalog/index.js'\nimport { ShippingModule } from '../modules/shipping/index.js'\nimport { MarketingModule } from '../modules/marketing/index.js'\nimport { StoresModule } from '../modules/stores/index.js'\nimport type { SessionManager } from '../session/SessionManager.js'\nimport type { SessionInfo } from '../types/index.js'\n\nexport { CommerceContext, type CommerceContextOptions } from './CommerceContext.js'\n\n/**\n * Point d'entrée principal du SDK Altazion Commerce.\n *\n * Usage :\n * ```ts\n * const client = new CommerceClient({ baseUrl: 'https://api.monsite.com', siteUrl: window.location.href })\n * await client.initialize()\n *\n * const cart = await client.cart.getCart()\n * ```\n */\nexport class CommerceClient {\n readonly context: CommerceContext\n readonly connectivity: ConnectivityManager\n\n readonly session: SessionModule\n readonly cart: CartModule\n readonly catalog: CatalogModule\n readonly shipping: ShippingModule\n readonly marketing: MarketingModule\n readonly stores: StoresModule\n\n private readonly http: CommerceHttpAdapter\n private readonly workerBridge: WorkerBridge\n private readonly cacheStrategy: CacheStrategy\n private readonly sessionManager: SessionManager\n\n constructor(options: CommerceContextOptions) {\n this.context = new CommerceContext(options)\n this.http = new CommerceHttpAdapter(this.context)\n this.connectivity = new ConnectivityManager()\n this.workerBridge = new WorkerBridge()\n this.cacheStrategy = new CacheStrategy(this.workerBridge, this.http)\n this.sessionManager = SessionManagerFactory.create(this.http, this.context)\n\n // Modules API\n this.session = new SessionModule(this.http, this.cacheStrategy)\n this.cart = new CartModule(this.http, this.cacheStrategy, this.connectivity)\n this.catalog = new CatalogModule(this.http, this.cacheStrategy)\n this.shipping = new ShippingModule(this.http, this.cacheStrategy)\n this.marketing = new MarketingModule(this.http, this.cacheStrategy)\n this.stores = new StoresModule(this.http, this.cacheStrategy)\n }\n\n /**\n * Initialise le SDK :\n * - Crée la session si nécessaire (mode browser uniquement)\n */\n async initialize(): Promise<SessionInfo | null> {\n return this.sessionManager.initialize()\n }\n\n /**\n * Retourne vrai si le SDK est hors-ligne.\n */\n get isOffline(): boolean {\n return this.connectivity.isOffline\n }\n\n /**\n * Force le vidage du cache.\n */\n clearCache(): Promise<void> {\n return this.workerBridge.clearAll()\n }\n\n /**\n * Libère les ressources (listeners, worker).\n */\n dispose(): void {\n this.connectivity.dispose()\n this.workerBridge.dispose()\n }\n}\n"],"names":["data"],"mappings":"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"}