'use strict';

var chunkHPN5R3K2_js = require('./chunk-HPN5R3K2.js');
var chunkXA3ZNR75_js = require('./chunk-XA3ZNR75.js');

// src/store-credit.ts
var StoreCreditQueries = class {
  constructor(client) {
    this.client = client;
  }
  /**
   * The shopper's available store-credit balance, in the business's default
   * currency. Requires a signed-in customer; returns an error otherwise.
   */
  async balance() {
    return chunkHPN5R3K2_js.safe(this.client.get("/api/v1/store-credit/balance"));
  }
};

// src/activity.ts
var VISITOR_ID_STORAGE_KEY = "cimplify_visitor_id";
var SESSION_STARTED_STORAGE_KEY = "cimplify_session_started_at";
var ActivityService = class {
  constructor(client) {
    this.client = client;
  }
  /**
   * Record session start (landing, referrer, UTM, device). Fire-and-forget,
   * at most once per tab session; called automatically by the track* methods.
   */
  startSession() {
    if (typeof window === "undefined") return;
    let alreadyStarted = null;
    try {
      alreadyStarted = sessionStorage.getItem(SESSION_STARTED_STORAGE_KEY);
    } catch {
    }
    if (alreadyStarted) return;
    const startedAt = (/* @__PURE__ */ new Date()).toISOString();
    try {
      sessionStorage.setItem(SESSION_STARTED_STORAGE_KEY, startedAt);
    } catch {
    }
    this.client.post("/api/v1/activity/session", this.buildSessionPayload(startedAt)).catch(() => {
    });
  }
  buildSessionPayload(startedAt) {
    const params = new URLSearchParams(window.location.search);
    const utm = (key) => params.get(`utm_${key}`) || void 0;
    const { visitorId, isNewVisitor } = resolveVisitor();
    let timezone;
    try {
      timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
    } catch {
    }
    return {
      started_at: startedAt,
      landing_page: window.location.pathname,
      landing_url: window.location.href,
      referrer_url: document.referrer || void 0,
      utm_source: utm("source"),
      utm_medium: utm("medium"),
      utm_campaign: utm("campaign"),
      utm_term: utm("term"),
      utm_content: utm("content"),
      screen_width: window.screen?.width,
      screen_height: window.screen?.height,
      viewport_width: window.innerWidth,
      viewport_height: window.innerHeight,
      pixel_density: window.devicePixelRatio,
      language: navigator.language,
      timezone,
      fingerprint: visitorId,
      is_new_visitor: isNewVisitor
    };
  }
  trackProductView(productId, options = {}) {
    const event = {
      type: "product_view",
      product_id: productId,
      product_name: options.productName,
      category_id: options.categoryId,
      price: options.price,
      page_path: options.pagePath ?? currentPath()
    };
    this.sendEvents([event]);
  }
  trackCategoryView(categoryId, options = {}) {
    const event = {
      type: "category_view",
      category_id: categoryId,
      category_name: options.categoryName,
      page_path: options.pagePath ?? currentPath()
    };
    this.sendEvents([event]);
  }
  async getState() {
    return chunkHPN5R3K2_js.safe(this.client.get("/api/v1/activity/state"));
  }
  async getRecommendations(options) {
    const params = new URLSearchParams();
    if (options?.location_id) params.set("location_id", options.location_id);
    if (options?.limit) params.set("limit", String(options.limit));
    const query = params.toString();
    const path = query ? `/api/v1/activity/recommendations?${query}` : "/api/v1/activity/recommendations";
    return chunkHPN5R3K2_js.safe(this.client.get(path));
  }
  async dismissMessage(code) {
    return chunkHPN5R3K2_js.safe(
      this.client.post("/api/v1/activity/messages/dismiss", { code })
    );
  }
  sendEvents(events) {
    this.startSession();
    this.client.post("/api/v1/activity/events", { events }).catch(() => {
    });
  }
};
function currentPath() {
  if (typeof window !== "undefined") {
    return window.location.pathname;
  }
  return void 0;
}
function resolveVisitor() {
  try {
    const existing = localStorage.getItem(VISITOR_ID_STORAGE_KEY);
    if (existing) {
      return { visitorId: existing, isNewVisitor: false };
    }
    const visitorId = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : `v_${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
    localStorage.setItem(VISITOR_ID_STORAGE_KEY, visitorId);
    return { visitorId, isNewVisitor: true };
  } catch {
    return {};
  }
}

// src/subscriptions.ts
var SubscriptionService = class {
  constructor(client) {
    this.client = client;
  }
  async list() {
    return chunkHPN5R3K2_js.safe(this.client.get("/api/v1/subscriptions"));
  }
  async get(id) {
    const encodedId = encodeURIComponent(id);
    return chunkHPN5R3K2_js.safe(this.client.get(`/api/v1/subscriptions/${encodedId}`));
  }
  async cancel(id, reason, opts) {
    const encodedId = encodeURIComponent(id);
    const idempotencyKey = opts?.idempotencyKey ?? chunkHPN5R3K2_js.generateIdempotencyKey();
    return chunkHPN5R3K2_js.safe(
      this.client.post(
        `/api/v1/subscriptions/${encodedId}/cancel`,
        { reason },
        { idempotencyKey }
      )
    );
  }
  async pause(id) {
    const encodedId = encodeURIComponent(id);
    return chunkHPN5R3K2_js.safe(
      this.client.post(`/api/v1/subscriptions/${encodedId}/pause`)
    );
  }
  async resume(id) {
    const encodedId = encodeURIComponent(id);
    return chunkHPN5R3K2_js.safe(
      this.client.post(`/api/v1/subscriptions/${encodedId}/resume`)
    );
  }
  async skipNextRenewal(id, opts) {
    const encodedId = encodeURIComponent(id);
    const idempotencyKey = opts?.idempotencyKey ?? chunkHPN5R3K2_js.generateIdempotencyKey();
    return chunkHPN5R3K2_js.safe(
      this.client.post(
        `/api/v1/subscriptions/${encodedId}/skip`,
        void 0,
        { idempotencyKey }
      )
    );
  }
};

// src/uploads.ts
var UploadService = class {
  constructor(client) {
    this.client = client;
  }
  async init(filename, contentType, sizeBytes, opts) {
    const idempotencyKey = opts?.idempotencyKey ?? chunkHPN5R3K2_js.generateIdempotencyKey();
    return chunkHPN5R3K2_js.safe(
      this.client.post(
        "/api/v1/uploads/init",
        {
          filename,
          content_type: contentType,
          size_bytes: sizeBytes
        },
        { idempotencyKey }
      )
    );
  }
  async confirm(uploadId) {
    return chunkHPN5R3K2_js.safe(
      this.client.post("/api/v1/uploads/confirm", {
        upload_id: uploadId
      })
    );
  }
  async upload(file) {
    const initResult = await this.init(file.name, file.type, file.size);
    if (!initResult.ok) return initResult;
    const { upload_id, upload_url } = initResult.value;
    try {
      const uploadResponse = await fetch(upload_url, {
        method: "PUT",
        body: file,
        headers: { "Content-Type": file.type }
      });
      if (!uploadResponse.ok) {
        return {
          ok: false,
          error: new chunkXA3ZNR75_js.CimplifyError(
            "UPLOAD_FAILED",
            `Upload failed with status ${uploadResponse.status}`,
            true
          )
        };
      }
    } catch (error) {
      return {
        ok: false,
        error: new chunkXA3ZNR75_js.CimplifyError(
          "UPLOAD_FAILED",
          error instanceof Error ? error.message : "Upload failed",
          true
        )
      };
    }
    return this.confirm(upload_id);
  }
};

// src/places.ts
var PlacesService = class {
  constructor(client) {
    this.client = client;
  }
  async autocomplete(input, sessionToken) {
    return chunkHPN5R3K2_js.safe(
      this.client.post("/api/v1/places/autocomplete", {
        input,
        sessionToken
      })
    );
  }
  async details(placeId, sessionToken) {
    return chunkHPN5R3K2_js.safe(
      this.client.post("/api/v1/places/details", {
        place_id: placeId,
        sessionToken
      })
    );
  }
};

// src/delivery.ts
var DeliveryService = class {
  constructor(client) {
    this.client = client;
  }
  async getFee(dropoffLat, dropoffLng, country) {
    const params = new URLSearchParams();
    params.set("dropoff_lat", String(dropoffLat));
    params.set("dropoff_lng", String(dropoffLng));
    if (country) params.set("country", country);
    return chunkHPN5R3K2_js.safe(
      this.client.get(`/api/v1/delivery/fee?${params.toString()}`)
    );
  }
  /** The full delivery menu for an address. Pass the selected option's
   * `rate_id` as `delivery_rate_id` when processing checkout. */
  async getOptions(dropoffLat, dropoffLng, opts) {
    const params = new URLSearchParams();
    params.set("dropoff_lat", String(dropoffLat));
    params.set("dropoff_lng", String(dropoffLng));
    if (opts?.country) params.set("country", opts.country);
    if (opts?.orderValue != null) params.set("order_value", String(opts.orderValue));
    return chunkHPN5R3K2_js.safe(
      this.client.get(`/api/v1/delivery/options?${params.toString()}`)
    );
  }
};

// src/support.ts
var SupportService = class {
  constructor(client) {
    this.client = client;
  }
  /** Open (or resume) the customer's widget conversation. */
  async openConversation(opts) {
    const idempotencyKey = opts?.idempotencyKey ?? chunkHPN5R3K2_js.generateIdempotencyKey();
    return chunkHPN5R3K2_js.safe(
      this.client.post("/api/v1/support/conversation", void 0, {
        idempotencyKey
      })
    );
  }
  /** Send a message in the active conversation. */
  async sendMessage(content, opts) {
    const idempotencyKey = opts?.idempotencyKey ?? chunkHPN5R3K2_js.generateIdempotencyKey();
    return chunkHPN5R3K2_js.safe(
      this.client.post(
        "/api/v1/support/conversation/messages",
        { content },
        { idempotencyKey }
      )
    );
  }
  /** Poll for new messages since the given cursor. */
  async getMessages(options = {}) {
    const params = new URLSearchParams();
    if (options.after) params.set("after", options.after);
    if (options.limit) params.set("limit", String(options.limit));
    const query = params.toString();
    const path = query ? `/api/v1/support/conversation/messages?${query}` : "/api/v1/support/conversation/messages";
    return chunkHPN5R3K2_js.safe(this.client.get(path));
  }
};

// src/internal/events.ts
function createClientEvents() {
  const listeners = /* @__PURE__ */ new Map();
  return {
    on(name, listener) {
      let set = listeners.get(name);
      if (!set) {
        set = /* @__PURE__ */ new Set();
        listeners.set(name, set);
      }
      set.add(listener);
      return () => {
        set?.delete(listener);
      };
    },
    off(name, listener) {
      listeners.get(name)?.delete(listener);
    },
    emit(name, payload) {
      const set = listeners.get(name);
      if (!set) return;
      const snapshot = Array.from(set);
      for (const listener of snapshot) {
        try {
          listener(payload);
        } catch (err) {
          console.error(`[Cimplify] event listener for "${name}" threw:`, err);
        }
      }
    }
  };
}

// src/client.ts
var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
var ORDER_TOKEN_PREFIX = "cimplify_ot_";
var SESSION_TOKEN_HEADER = "x-session-token";
var ORDER_TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
var DEFAULT_TIMEOUT_MS = 5e3;
var DEFAULT_MAX_RETRIES = 3;
var DEFAULT_RETRY_DELAY_MS = 1e3;
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
function nextInit(cacheOptions) {
  if (!cacheOptions) return {};
  const next = {};
  if (cacheOptions.revalidate !== void 0) next.revalidate = cacheOptions.revalidate;
  if (cacheOptions.tags && cacheOptions.tags.length > 0) next.tags = [...cacheOptions.tags];
  if (next.revalidate === void 0 && !next.tags) return {};
  return { next };
}
function mergeOptionHeaders(base, opts) {
  if (!opts) return base;
  const merged = { ...base };
  if (opts.headers) {
    for (const [k, v] of Object.entries(opts.headers)) {
      merged[k] = v;
    }
  }
  if (opts.idempotencyKey) {
    merged["Idempotency-Key"] = opts.idempotencyKey;
  }
  return merged;
}
function isRetryable(error) {
  if (error instanceof TypeError && error.message.includes("fetch")) {
    return true;
  }
  if (error instanceof DOMException && error.name === "AbortError") {
    return true;
  }
  if (error instanceof chunkXA3ZNR75_js.CimplifyError) {
    return error.retryable;
  }
  return false;
}
function toNetworkError(error, isTestMode) {
  if (error instanceof DOMException && error.name === "AbortError") {
    return chunkXA3ZNR75_js.enrichError(
      new chunkXA3ZNR75_js.CimplifyError(
        chunkXA3ZNR75_js.ErrorCode.TIMEOUT,
        "Request timed out. Please check your connection and try again.",
        true
      ),
      { isTestMode }
    );
  }
  if (error instanceof TypeError && error.message.includes("fetch")) {
    return chunkXA3ZNR75_js.enrichError(
      new chunkXA3ZNR75_js.CimplifyError(
        chunkXA3ZNR75_js.ErrorCode.NETWORK_ERROR,
        "Network error. Please check your internet connection.",
        true
      ),
      { isTestMode }
    );
  }
  if (error instanceof chunkXA3ZNR75_js.CimplifyError) {
    return chunkXA3ZNR75_js.enrichError(error, { isTestMode });
  }
  return chunkXA3ZNR75_js.enrichError(
    new chunkXA3ZNR75_js.CimplifyError(
      chunkXA3ZNR75_js.ErrorCode.UNKNOWN_ERROR,
      error instanceof Error ? error.message : "An unknown error occurred",
      false
    ),
    { isTestMode }
  );
}
function deriveUrls() {
  const hostname = typeof window !== "undefined" ? window.location.hostname : "";
  if (hostname === "localhost" || hostname === "127.0.0.1") {
    const protocol = window.location.protocol;
    return {
      baseUrl: `${protocol}//${hostname}:8082`,
      linkApiUrl: `${protocol}//${hostname}:8080`
    };
  }
  return {
    baseUrl: "https://storefronts.cimplify.io",
    linkApiUrl: "https://api.cimplify.io"
  };
}
function normalizeUrl(url) {
  const trimmed = url.trim();
  if (!trimmed) return trimmed;
  return trimmed.replace(/\/+$/, "");
}
function getEnvPublicKey() {
  try {
    const env = globalThis.process;
    return env?.env.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || void 0;
  } catch {
    return void 0;
  }
}
var CimplifyClient = class {
  constructor(config = {}) {
    this.accessToken = null;
    this.sessionToken = null;
    this.context = {};
    this.businessId = null;
    this.businessIdResolvePromise = null;
    this.inflightRequests = /* @__PURE__ */ new Map();
    /**
     * App-level event channel. Subscribe to surface mutation rollbacks, outbox
     * activity, and dead-letter notifications to consumer code (toasts,
     * Sentry, analytics, etc.). The SDK emits but never auto-consumes — the
     * consumer decides how to react.
     */
    this.events = createClientEvents();
    this.publicKey = config.publicKey || getEnvPublicKey() || "";
    const urls = deriveUrls();
    this.baseUrl = config.baseUrl ? normalizeUrl(config.baseUrl) : urls.baseUrl;
    this.linkApiUrl = config.linkApiUrl ? normalizeUrl(config.linkApiUrl) : urls.linkApiUrl;
    this.credentials = config.credentials || "include";
    this.timeout = config.timeout ?? DEFAULT_TIMEOUT_MS;
    this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
    this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
    this.hooks = config.hooks ?? {};
    this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
    this.sessionToken = this.loadSessionToken();
    if (!this.publicKey && !config.suppressPublicKeyWarning) {
      console.warn(
        '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "cpk_..." } to createCimplifyClient().'
      );
    }
  }
  buildUrl(base, path) {
    const url = `${base}${path}`;
    const locationId = this.context.location_id;
    if (!locationId) return url;
    const separator = url.includes("?") ? "&" : "?";
    return `${url}${separator}location_id=${encodeURIComponent(locationId)}`;
  }
  getAccessToken() {
    return this.accessToken;
  }
  getPublicKey() {
    return this.publicKey;
  }
  getBaseUrl() {
    return this.baseUrl;
  }
  getLinkApiUrl() {
    return this.linkApiUrl;
  }
  getCredentialsMode() {
    return this.credentials;
  }
  isTestMode() {
    return this.publicKey.trim().startsWith("cpk_test_");
  }
  setAccessToken(token) {
    const previous = this.accessToken;
    this.accessToken = token;
    this.hooks.onSessionChange?.({
      previousToken: previous,
      newToken: token,
      source: "manual"
    });
  }
  clearSession() {
    const previous = this.accessToken;
    this.accessToken = null;
    this.sessionToken = null;
    if (typeof window !== "undefined" && window.localStorage) {
      localStorage.removeItem(SESSION_TOKEN_STORAGE_KEY);
    }
    this.hooks.onSessionChange?.({
      previousToken: previous,
      newToken: null,
      source: "clear"
    });
  }
  setOrderToken(orderId, token) {
    if (typeof window !== "undefined" && window.localStorage) {
      try {
        const entry = JSON.stringify({ token, storedAt: Date.now() });
        localStorage.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, entry);
      } catch {
      }
    }
  }
  getOrderToken(orderId) {
    if (typeof window !== "undefined" && window.localStorage) {
      try {
        const raw = localStorage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
        if (!raw) return null;
        const entry = JSON.parse(raw);
        if (Date.now() - entry.storedAt > ORDER_TOKEN_TTL_MS) {
          localStorage.removeItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
          return null;
        }
        return entry.token;
      } catch {
        return null;
      }
    }
    return null;
  }
  clearOrderTokens() {
    if (typeof window !== "undefined" && window.localStorage) {
      const keysToRemove = [];
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key?.startsWith(ORDER_TOKEN_PREFIX)) {
          keysToRemove.push(key);
        }
      }
      keysToRemove.forEach((k) => localStorage.removeItem(k));
    }
  }
  setLocationId(locationId) {
    if (locationId) {
      this.context.location_id = locationId;
    } else {
      delete this.context.location_id;
    }
  }
  getLocationId() {
    return this.context.location_id ?? null;
  }
  setBusinessId(businessId) {
    const normalized = businessId.trim();
    if (!normalized) {
      return;
    }
    this.businessId = normalized;
  }
  getBusinessId() {
    return this.businessId;
  }
  async resolveBusinessId() {
    if (this.businessId) {
      return this.businessId;
    }
    if (this.businessIdResolvePromise) {
      return this.businessIdResolvePromise;
    }
    this.businessIdResolvePromise = (async () => {
      const result = await this.business.getInfo();
      if (!result.ok || !result.value?.id) {
        throw new chunkXA3ZNR75_js.CimplifyError(
          chunkXA3ZNR75_js.ErrorCode.NOT_FOUND,
          "Unable to resolve business ID from the current public key.",
          true
        );
      }
      this.businessId = result.value.id;
      return result.value.id;
    })();
    try {
      return await this.businessIdResolvePromise;
    } finally {
      this.businessIdResolvePromise = null;
    }
  }
  async authedFetch(url, options) {
    return this.resilientFetch(url, options);
  }
  loadSessionToken() {
    if (typeof window !== "undefined" && window.localStorage) {
      return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
    }
    return null;
  }
  saveSessionToken(token) {
    if (typeof window !== "undefined" && window.localStorage) {
      try {
        localStorage.setItem(SESSION_TOKEN_STORAGE_KEY, token);
      } catch {
      }
    }
  }
  captureSessionToken(response) {
    const token = response.headers.get(SESSION_TOKEN_HEADER);
    if (token && token !== this.sessionToken) {
      this.sessionToken = token;
      this.saveSessionToken(token);
    }
  }
  getHeaders() {
    const headers = {
      "Content-Type": "application/json"
    };
    const trimmedPublicKey = this.publicKey.trim();
    if (trimmedPublicKey) {
      headers["X-API-Key"] = trimmedPublicKey;
    }
    if (this.accessToken) {
      headers["Authorization"] = `Bearer ${this.accessToken}`;
    }
    if (this.sessionToken) {
      headers[SESSION_TOKEN_HEADER] = this.sessionToken;
    }
    if (typeof window !== "undefined") {
      headers["X-Storefront-Host"] = window.location.host;
      const preview = new URLSearchParams(window.location.search).get("preview");
      if (preview) {
        headers["X-Storefront-Preview"] = preview;
      }
    }
    return headers;
  }
  async resilientFetch(url, options) {
    const method = options.method || "GET";
    const path = url.replace(this.baseUrl, "").replace(this.linkApiUrl, "");
    const startTime = Date.now();
    let retryCount = 0;
    const context = {
      method,
      path,
      url,
      body: options.body ? JSON.parse(options.body) : void 0,
      startTime
    };
    this.hooks.onRequestStart?.(context);
    let lastError;
    for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
      try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), this.timeout);
        const response = await this.fetchImpl(url, {
          ...options,
          signal: controller.signal
        });
        clearTimeout(timeoutId);
        this.captureSessionToken(response);
        if (response.ok) {
          this.hooks.onRequestSuccess?.({
            ...context,
            status: response.status,
            durationMs: Date.now() - startTime
          });
          return response;
        }
        if ((response.status === 429 || response.status === 503) && attempt < this.maxRetries) {
          retryCount++;
          const retryAfter = response.headers.get("Retry-After");
          const delay = retryAfter ? Math.min(parseInt(retryAfter, 10) * 1e3, 3e4) || this.retryDelay * Math.pow(2, attempt) : this.retryDelay * Math.pow(2, attempt);
          this.hooks.onRetry?.({
            ...context,
            attempt: retryCount,
            delayMs: delay,
            error: new Error(`Retryable: ${response.status}`)
          });
          await sleep(delay);
          continue;
        }
        if (response.status >= 400 && response.status < 500) {
          this.hooks.onRequestError?.({
            ...context,
            error: new chunkXA3ZNR75_js.CimplifyError(
              `HTTP_${response.status}`,
              `Request failed with status ${response.status}`,
              false
            ),
            status: response.status,
            durationMs: Date.now() - startTime,
            retryCount,
            retryable: false
          });
          return response;
        }
        if (response.status >= 500 && attempt < this.maxRetries) {
          retryCount++;
          const delay = this.retryDelay * Math.pow(2, attempt);
          this.hooks.onRetry?.({
            ...context,
            attempt: retryCount,
            delayMs: delay,
            error: new Error(`Server error: ${response.status}`)
          });
          await sleep(delay);
          continue;
        }
        this.hooks.onRequestError?.({
          ...context,
          error: new chunkXA3ZNR75_js.CimplifyError(
            "SERVER_ERROR",
            `Server error ${response.status} after ${retryCount} retries`,
            false
          ),
          status: response.status,
          durationMs: Date.now() - startTime,
          retryCount,
          retryable: false
        });
        return response;
      } catch (error) {
        lastError = error;
        const networkError = toNetworkError(error, this.isTestMode());
        const errorRetryable = isRetryable(error);
        if (!errorRetryable || attempt >= this.maxRetries) {
          this.hooks.onRequestError?.({
            ...context,
            error: networkError,
            durationMs: Date.now() - startTime,
            retryCount,
            retryable: errorRetryable
          });
          throw networkError;
        }
        retryCount++;
        const delay = this.retryDelay * Math.pow(2, attempt);
        this.hooks.onRetry?.({
          ...context,
          attempt: retryCount,
          delayMs: delay,
          error: networkError
        });
        await sleep(delay);
      }
    }
    const finalError = toNetworkError(lastError, this.isTestMode());
    this.hooks.onRequestError?.({
      ...context,
      error: finalError,
      durationMs: Date.now() - startTime,
      retryCount,
      retryable: false
    });
    throw finalError;
  }
  getDedupeKey(type, payload, cacheOptions) {
    const cacheKey = cacheOptions ? `|${JSON.stringify(cacheOptions)}` : "";
    return `${type}:${JSON.stringify(payload)}${cacheKey}`;
  }
  async deduplicatedRequest(key, requestFn) {
    const existing = this.inflightRequests.get(key);
    if (existing) {
      return existing;
    }
    const request = requestFn().finally(() => {
      this.inflightRequests.delete(key);
    });
    this.inflightRequests.set(key, request);
    return request;
  }
  async get(path, opts) {
    const key = this.getDedupeKey("get", path, opts?.cacheOptions);
    return this.deduplicatedRequest(key, async () => {
      const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
        method: "GET",
        credentials: this.credentials,
        headers: this.getHeaders(),
        ...nextInit(opts?.cacheOptions)
      });
      return this.handleRestResponse(response);
    });
  }
  async post(path, body, opts) {
    const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
      method: "POST",
      credentials: this.credentials,
      headers: mergeOptionHeaders(this.getHeaders(), opts),
      body: body ? JSON.stringify(body) : void 0
    });
    return this.handleRestResponse(response);
  }
  async patch(path, body, opts) {
    const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
      method: "PATCH",
      credentials: this.credentials,
      headers: mergeOptionHeaders(this.getHeaders(), opts),
      body: body ? JSON.stringify(body) : void 0
    });
    return this.handleRestResponse(response);
  }
  async delete(path, opts) {
    const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
      method: "DELETE",
      credentials: this.credentials,
      headers: mergeOptionHeaders(this.getHeaders(), opts)
    });
    return this.handleRestResponse(response);
  }
  async linkGet(path, opts) {
    const key = this.getDedupeKey("linkGet", path, opts?.cacheOptions);
    return this.deduplicatedRequest(key, async () => {
      const response = await this.authedFetch(`${this.linkApiUrl}${path}`, {
        method: "GET",
        credentials: this.credentials,
        headers: this.getHeaders(),
        ...nextInit(opts?.cacheOptions)
      });
      return this.handleRestResponse(response);
    });
  }
  async linkPost(path, body, opts) {
    const response = await this.authedFetch(`${this.linkApiUrl}${path}`, {
      method: "POST",
      credentials: this.credentials,
      headers: mergeOptionHeaders(this.getHeaders(), opts),
      body: body ? JSON.stringify(body) : void 0
    });
    return this.handleRestResponse(response);
  }
  async linkDelete(path, opts) {
    const response = await this.authedFetch(`${this.linkApiUrl}${path}`, {
      method: "DELETE",
      credentials: this.credentials,
      headers: mergeOptionHeaders(this.getHeaders(), opts)
    });
    return this.handleRestResponse(response);
  }
  async handleRestResponse(response) {
    const json = await response.json();
    if (!response.ok) {
      const errorCode = typeof json.error === "object" && json.error?.error_code || typeof json.error === "object" && json.error?.code || "API_ERROR";
      const errorMessage = typeof json.error === "object" && json.error?.error_message || typeof json.error === "object" && json.error?.message || typeof json.error === "string" && json.error || typeof json.message === "string" && json.message || "An error occurred";
      const retryable = typeof json.error === "object" && typeof json.error?.retryable === "boolean" ? json.error.retryable : false;
      if (errorCode === "IDEMPOTENCY_MISMATCH") {
        const originalCreatedAt = typeof json.error === "object" && json.error?.original_created_at || "";
        throw new chunkXA3ZNR75_js.IdempotencyMismatchError(errorMessage, originalCreatedAt);
      }
      const error = chunkXA3ZNR75_js.enrichError(
        new chunkXA3ZNR75_js.CimplifyError(
          errorCode,
          errorMessage,
          retryable
        ),
        { isTestMode: this.isTestMode() }
      );
      if ((response.status === 401 || error.code === chunkXA3ZNR75_js.ErrorCode.UNAUTHORIZED) && this.accessToken) {
        console.warn(
          "[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
        );
      }
      throw error;
    }
    if (json?.success === false || json?.error?.code || json?.error?.message) {
      const error = chunkXA3ZNR75_js.enrichError(
        new chunkXA3ZNR75_js.CimplifyError(
          json.error?.code || "API_ERROR",
          json.error?.message || "An error occurred",
          json.error?.retryable || false
        ),
        { isTestMode: this.isTestMode() }
      );
      throw error;
    }
    if (json?.data !== void 0) {
      return json.data;
    }
    return json;
  }
  get catalogue() {
    if (!this._catalogue) {
      this._catalogue = new chunkHPN5R3K2_js.CatalogueQueries(this);
    }
    return this._catalogue;
  }
  get cart() {
    if (!this._cart) {
      this._cart = new chunkHPN5R3K2_js.CartOperations(this);
    }
    return this._cart;
  }
  get checkout() {
    if (!this._checkout) {
      this._checkout = new chunkHPN5R3K2_js.CheckoutService(this);
    }
    return this._checkout;
  }
  get orders() {
    if (!this._orders) {
      this._orders = new chunkHPN5R3K2_js.OrderQueries(this);
    }
    return this._orders;
  }
  get storeCredit() {
    if (!this._storeCredit) {
      this._storeCredit = new StoreCreditQueries(this);
    }
    return this._storeCredit;
  }
  get subscriptions() {
    if (!this._subscriptions) {
      this._subscriptions = new SubscriptionService(this);
    }
    return this._subscriptions;
  }
  get uploads() {
    if (!this._uploads) {
      this._uploads = new UploadService(this);
    }
    return this._uploads;
  }
  get places() {
    if (!this._places) {
      this._places = new PlacesService(this);
    }
    return this._places;
  }
  get link() {
    if (!this._link) {
      this._link = new chunkHPN5R3K2_js.LinkService(this);
    }
    return this._link;
  }
  get auth() {
    if (!this._auth) {
      this._auth = new chunkHPN5R3K2_js.AuthService(this);
    }
    return this._auth;
  }
  get business() {
    if (!this._business) {
      this._business = new chunkHPN5R3K2_js.BusinessService(this);
    }
    return this._business;
  }
  get inventory() {
    if (!this._inventory) {
      this._inventory = new chunkHPN5R3K2_js.InventoryService(this);
    }
    return this._inventory;
  }
  get scheduling() {
    if (!this._scheduling) {
      this._scheduling = new chunkHPN5R3K2_js.SchedulingService(this);
    }
    return this._scheduling;
  }
  get lite() {
    if (!this._lite) {
      this._lite = new chunkHPN5R3K2_js.LiteService(this);
    }
    return this._lite;
  }
  get fx() {
    if (!this._fx) {
      this._fx = new chunkHPN5R3K2_js.FxService(this);
    }
    return this._fx;
  }
  get activity() {
    if (!this._activity) {
      this._activity = new ActivityService(this);
    }
    return this._activity;
  }
  get delivery() {
    if (!this._delivery) {
      this._delivery = new DeliveryService(this);
    }
    return this._delivery;
  }
  get support() {
    if (!this._support) {
      this._support = new SupportService(this);
    }
    return this._support;
  }
  buildWsUrl(path) {
    const protocol = this.baseUrl.startsWith("https") ? "wss:" : "ws:";
    const host = this.baseUrl.replace(/^https?:\/\//, "");
    const params = new URLSearchParams();
    if (this.publicKey) params.set("api_key", this.publicKey);
    if (this.sessionToken) params.set("session_token", this.sessionToken);
    const query = params.toString();
    return `${protocol}//${host}${path}${query ? `?${query}` : ""}`;
  }
  elements(businessId, options) {
    if (businessId) {
      this.setBusinessId(businessId);
    }
    return chunkHPN5R3K2_js.createElements(this, businessId ?? this.businessId ?? void 0, options);
  }
};
function createCimplifyClient(config = {}) {
  return new CimplifyClient(config);
}

exports.ActivityService = ActivityService;
exports.CimplifyClient = CimplifyClient;
exports.DeliveryService = DeliveryService;
exports.PlacesService = PlacesService;
exports.StoreCreditQueries = StoreCreditQueries;
exports.SubscriptionService = SubscriptionService;
exports.SupportService = SupportService;
exports.UploadService = UploadService;
exports.createCimplifyClient = createCimplifyClient;
