@decocms/apps-vtex 8.1.0-next.1 → 8.1.0-next.3

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.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * `@decocms/apps-vtex`: a thin, instrumented VTEX client (`createVtexClient`).
3
+ * See ./vtexClient.ts and /next/upstream-clients.
4
+ */
5
+ export { createVtexClient, type VtexCatalogSearchArgs, type VtexClient, type VtexClientConfig, VtexError, type VtexRequestOptions, type VtexResponse, type VtexSearchArgs, } from "./vtexClient.ts";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,cAAc,GACpB,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * `@decocms/apps-vtex`: a thin, instrumented VTEX client (`createVtexClient`).
3
+ * See ./vtexClient.ts and /next/upstream-clients.
4
+ */
5
+ export { createVtexClient, VtexError, } from "./vtexClient.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,gBAAgB,EAIhB,SAAS,GAIV,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Tuning knobs for VTEX request resilience (timeouts, retries, circuit
3
+ * breaker), with the reasoning for each number next to it.
4
+ */
5
+ export interface ResilienceConfig {
6
+ /** Per-attempt timeout in ms. Aborts the socket. */
7
+ perAttemptTimeoutMs: number;
8
+ /** Total time budget across all attempts (incl. backoff) in ms. */
9
+ totalTimeoutMs: number;
10
+ /** Max retries for idempotent requests (attempts = maxRetries + 1). */
11
+ maxRetries: number;
12
+ /** Exponential backoff base in ms. */
13
+ backoffBaseMs: number;
14
+ /** Exponential backoff cap in ms. */
15
+ backoffCapMs: number;
16
+ /** Consecutive failures before the breaker opens. */
17
+ breakerConsecutiveFailures: number;
18
+ /** How long the breaker stays open before half-opening, in ms. */
19
+ breakerOpenCooldownMs: number;
20
+ /** Number of probe requests allowed while half-open. */
21
+ breakerHalfOpenProbes: number;
22
+ /** Max retry tokens per host (token bucket). */
23
+ retryBudgetMax: number;
24
+ /** Token refill rate per second. */
25
+ retryBudgetRefillPerSec: number;
26
+ }
27
+ export declare const DEFAULT_RESILIENCE_CONFIG: ResilienceConfig;
28
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,qCAAqC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,0BAA0B,EAAE,MAAM,CAAC;IACnC,kEAAkE;IAClE,qBAAqB,EAAE,MAAM,CAAC;IAC9B,wDAAwD;IACxD,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gDAAgD;IAChD,cAAc,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,eAAO,MAAM,yBAAyB,EAAE,gBAWvC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Tuning knobs for VTEX request resilience (timeouts, retries, circuit
3
+ * breaker), with the reasoning for each number next to it.
4
+ */
5
+ export const DEFAULT_RESILIENCE_CONFIG = {
6
+ perAttemptTimeoutMs: 8_000,
7
+ totalTimeoutMs: 12_000,
8
+ maxRetries: 2,
9
+ backoffBaseMs: 150,
10
+ backoffCapMs: 1_000,
11
+ breakerConsecutiveFailures: 5,
12
+ breakerOpenCooldownMs: 5_000,
13
+ breakerHalfOpenProbes: 3,
14
+ retryBudgetMax: 20,
15
+ retryBudgetRefillPerSec: 5,
16
+ };
17
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6BH,MAAM,CAAC,MAAM,yBAAyB,GAAqB;IACzD,mBAAmB,EAAE,KAAK;IAC1B,cAAc,EAAE,MAAM;IACtB,UAAU,EAAE,CAAC;IACb,aAAa,EAAE,GAAG;IAClB,YAAY,EAAE,KAAK;IACnB,0BAA0B,EAAE,CAAC;IAC7B,qBAAqB,EAAE,KAAK;IAC5B,qBAAqB,EAAE,CAAC;IACxB,cAAc,EAAE,EAAE;IAClB,uBAAuB,EAAE,CAAC;CAC3B,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Outbound cookie sanitization for VTEX API calls.
3
+ *
4
+ * VTEX's janus gateway strictly enforces RFC 6265: any cookie value containing
5
+ * non-ASCII bytes causes the gateway to return `503 Service Unavailable` with
6
+ * an empty body, before the request reaches the backing service. This is
7
+ * deterministic — a single poisoned cookie (e.g. an analytics tag writing a
8
+ * category name with accents into `document.cookie` without encoding) can
9
+ * break every checkout call for a user.
10
+ *
11
+ * This module provides two filters:
12
+ *
13
+ * - `sanitizeOutboundCookieHeader()` — drops cookies whose value contains
14
+ * non-ASCII bytes or that look malformed. Default for cookie forwarding
15
+ * in `vtexFetchWithCookies`. Safe to apply to any cookie payload.
16
+ *
17
+ * - `extractVtexCookies()` — allowlist mode. Drops anything that isn't on
18
+ * `VTEX_COOKIE_PREFIXES`. Use when calling endpoints that have no business
19
+ * seeing the user's full cookie soup (e.g. logout, masterdata, profile).
20
+ *
21
+ * The allowlist is the canonical list of cookie name prefixes that VTEX APIs
22
+ * actually consume. It lives here so it's the single source of truth for the
23
+ * package — both `getVtexCookies()` (cookies.ts) and
24
+ * `extractVtexCookiesFromHeader()` (authHelpers.ts) delegate to this module.
25
+ */
26
+ /**
27
+ * Cookie name prefixes that are VTEX-relevant and safe to forward to
28
+ * `*.vtexcommercestable.com.br` / `*.myvtex.com` / `secure.<storefront>` APIs.
29
+ */
30
+ export declare const VTEX_COOKIE_PREFIXES: readonly string[];
31
+ export type DropReason = "non_ascii" | "not_in_allowlist" | "malformed";
32
+ export interface DroppedCookie {
33
+ name: string;
34
+ reason: DropReason;
35
+ }
36
+ export interface CookieSanitizeResult {
37
+ /** Cookie header string ready to forward (may be empty). */
38
+ cookies: string;
39
+ /** Cookies that were filtered out, with the reason per cookie. */
40
+ dropped: DroppedCookie[];
41
+ }
42
+ export interface CookieSanitizeOptions {
43
+ /**
44
+ * When true, additionally enforces an allowlist: only cookies whose name
45
+ * starts with one of `VTEX_COOKIE_PREFIXES` are kept.
46
+ * @default false
47
+ */
48
+ allowlist?: boolean;
49
+ }
50
+ /**
51
+ * Filter a `Cookie:` request header so it's safe to forward to a VTEX origin.
52
+ *
53
+ * Drops:
54
+ * - pairs without `=` (malformed)
55
+ * - pairs whose name isn't a valid HTTP token (malformed)
56
+ * - pairs whose value contains non-ASCII bytes (`non_ascii`)
57
+ * - when `opts.allowlist` is true: pairs not on `VTEX_COOKIE_PREFIXES`
58
+ * (`not_in_allowlist`)
59
+ *
60
+ * Returns the cleaned header plus a per-cookie drop report so callers can
61
+ * log/observe which cookies were removed.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const { cookies, dropped } = sanitizeOutboundCookieHeader(
66
+ * request.headers.get("cookie") ?? "",
67
+ * );
68
+ * if (dropped.length) console.warn("[vtex] dropped cookies", dropped);
69
+ * fetch(vtexUrl, { headers: { cookie: cookies } });
70
+ * ```
71
+ */
72
+ export declare function sanitizeOutboundCookieHeader(raw: string, opts?: CookieSanitizeOptions): CookieSanitizeResult;
73
+ /**
74
+ * Allowlist convenience wrapper — keep only VTEX-prefixed, ASCII-clean cookies.
75
+ *
76
+ * Equivalent to `sanitizeOutboundCookieHeader(raw, { allowlist: true }).cookies`.
77
+ */
78
+ export declare function extractVtexCookies(raw: string): string;
79
+ /**
80
+ * Emit a structured `console.warn` for each dropped cookie, deduped by
81
+ * `name+reason` for the lifetime of the worker isolate. Call sites pass an
82
+ * arbitrary `host` label so we can correlate in logs.
83
+ */
84
+ export declare function warnDroppedCookies(dropped: DroppedCookie[], host: string): void;
85
+ /** Reset the dedup set — exposed for tests. */
86
+ export declare function _resetCookieWarnDedupForTests(): void;
87
+ //# sourceMappingURL=cookieSanitizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookieSanitizer.d.ts","sourceRoot":"","sources":["../../src/utils/cookieSanitizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAQjD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,kBAAkB,GAAG,WAAW,CAAC;AAExE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAWD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,qBAA0B,GAC/B,oBAAoB,CAuCtB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AASD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAQ/E;AAED,+CAA+C;AAC/C,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Outbound cookie sanitization for VTEX API calls.
3
+ *
4
+ * VTEX's janus gateway strictly enforces RFC 6265: any cookie value containing
5
+ * non-ASCII bytes causes the gateway to return `503 Service Unavailable` with
6
+ * an empty body, before the request reaches the backing service. This is
7
+ * deterministic — a single poisoned cookie (e.g. an analytics tag writing a
8
+ * category name with accents into `document.cookie` without encoding) can
9
+ * break every checkout call for a user.
10
+ *
11
+ * This module provides two filters:
12
+ *
13
+ * - `sanitizeOutboundCookieHeader()` — drops cookies whose value contains
14
+ * non-ASCII bytes or that look malformed. Default for cookie forwarding
15
+ * in `vtexFetchWithCookies`. Safe to apply to any cookie payload.
16
+ *
17
+ * - `extractVtexCookies()` — allowlist mode. Drops anything that isn't on
18
+ * `VTEX_COOKIE_PREFIXES`. Use when calling endpoints that have no business
19
+ * seeing the user's full cookie soup (e.g. logout, masterdata, profile).
20
+ *
21
+ * The allowlist is the canonical list of cookie name prefixes that VTEX APIs
22
+ * actually consume. It lives here so it's the single source of truth for the
23
+ * package — both `getVtexCookies()` (cookies.ts) and
24
+ * `extractVtexCookiesFromHeader()` (authHelpers.ts) delegate to this module.
25
+ */
26
+ /**
27
+ * Cookie name prefixes that are VTEX-relevant and safe to forward to
28
+ * `*.vtexcommercestable.com.br` / `*.myvtex.com` / `secure.<storefront>` APIs.
29
+ */
30
+ export const VTEX_COOKIE_PREFIXES = [
31
+ "VtexIdclientAutCookie",
32
+ "checkout.vtex.com",
33
+ "CheckoutOrderFormOwnership",
34
+ "vtex_session",
35
+ "vtex_segment",
36
+ "vtex_is_",
37
+ "janus_sid",
38
+ ];
39
+ /**
40
+ * Cookie pairs are `name=value`, where `name` (token) must be visible ASCII
41
+ * with no separators, and `value` must be ASCII (`0x20–0x7E`) per RFC 6265.
42
+ * We intentionally allow `=` inside the value (some VTEX cookies are
43
+ * URL-encoded JWTs).
44
+ */
45
+ const TOKEN_RE = /^[!#$%&'*+\-.0-9A-Z^_`a-z|~]+$/;
46
+ const ASCII_VALUE_RE = /^[\x20-\x7E]*$/;
47
+ /**
48
+ * Filter a `Cookie:` request header so it's safe to forward to a VTEX origin.
49
+ *
50
+ * Drops:
51
+ * - pairs without `=` (malformed)
52
+ * - pairs whose name isn't a valid HTTP token (malformed)
53
+ * - pairs whose value contains non-ASCII bytes (`non_ascii`)
54
+ * - when `opts.allowlist` is true: pairs not on `VTEX_COOKIE_PREFIXES`
55
+ * (`not_in_allowlist`)
56
+ *
57
+ * Returns the cleaned header plus a per-cookie drop report so callers can
58
+ * log/observe which cookies were removed.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * const { cookies, dropped } = sanitizeOutboundCookieHeader(
63
+ * request.headers.get("cookie") ?? "",
64
+ * );
65
+ * if (dropped.length) console.warn("[vtex] dropped cookies", dropped);
66
+ * fetch(vtexUrl, { headers: { cookie: cookies } });
67
+ * ```
68
+ */
69
+ export function sanitizeOutboundCookieHeader(raw, opts = {}) {
70
+ if (!raw)
71
+ return { cookies: "", dropped: [] };
72
+ const kept = [];
73
+ const dropped = [];
74
+ const allowlist = opts.allowlist === true;
75
+ for (const segment of raw.split(";")) {
76
+ const pair = segment.trim();
77
+ if (!pair)
78
+ continue;
79
+ const eq = pair.indexOf("=");
80
+ if (eq <= 0) {
81
+ dropped.push({ name: pair.slice(0, 32), reason: "malformed" });
82
+ continue;
83
+ }
84
+ const name = pair.slice(0, eq);
85
+ const value = pair.slice(eq + 1);
86
+ if (!TOKEN_RE.test(name)) {
87
+ dropped.push({ name, reason: "malformed" });
88
+ continue;
89
+ }
90
+ if (!ASCII_VALUE_RE.test(value)) {
91
+ dropped.push({ name, reason: "non_ascii" });
92
+ continue;
93
+ }
94
+ if (allowlist && !VTEX_COOKIE_PREFIXES.some((p) => name.startsWith(p))) {
95
+ dropped.push({ name, reason: "not_in_allowlist" });
96
+ continue;
97
+ }
98
+ kept.push(`${name}=${value}`);
99
+ }
100
+ return { cookies: kept.join("; "), dropped };
101
+ }
102
+ /**
103
+ * Allowlist convenience wrapper — keep only VTEX-prefixed, ASCII-clean cookies.
104
+ *
105
+ * Equivalent to `sanitizeOutboundCookieHeader(raw, { allowlist: true }).cookies`.
106
+ */
107
+ export function extractVtexCookies(raw) {
108
+ return sanitizeOutboundCookieHeader(raw, { allowlist: true }).cookies;
109
+ }
110
+ /**
111
+ * Track which cookie names we've already warned about to avoid spamming
112
+ * the worker logs. Process-scoped — Cloudflare Workers reset this on each
113
+ * isolate restart, which is exactly the cadence we want.
114
+ */
115
+ const _warned = new Set();
116
+ /**
117
+ * Emit a structured `console.warn` for each dropped cookie, deduped by
118
+ * `name+reason` for the lifetime of the worker isolate. Call sites pass an
119
+ * arbitrary `host` label so we can correlate in logs.
120
+ */
121
+ export function warnDroppedCookies(dropped, host) {
122
+ if (dropped.length === 0)
123
+ return;
124
+ for (const d of dropped) {
125
+ const key = `${host}::${d.name}::${d.reason}`;
126
+ if (_warned.has(key))
127
+ continue;
128
+ _warned.add(key);
129
+ console.warn(`[vtex.cookie.dropped] host=${host} name=${d.name} reason=${d.reason}`);
130
+ }
131
+ }
132
+ /** Reset the dedup set — exposed for tests. */
133
+ export function _resetCookieWarnDedupForTests() {
134
+ _warned.clear();
135
+ }
136
+ //# sourceMappingURL=cookieSanitizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookieSanitizer.js","sourceRoot":"","sources":["../../src/utils/cookieSanitizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * URL-derived operation name router for VTEX API calls.
3
+ *
4
+ * Plugged into `createInstrumentedFetch` (`@decocms/blocks/fetch`) via the
5
+ * `resolveOperation(url, method)` option. The resolved string becomes the
6
+ * span suffix (`vtex.<operation>`) and the `fetch.operation` span +
7
+ * histogram label, so it must be:
8
+ *
9
+ * - low-cardinality (no IDs, slugs, search terms, account names);
10
+ * - stable across deploys (used for alerting + dashboards);
11
+ * - human-debuggable in a trace view.
12
+ *
13
+ * The router is intentionally a flat ordered list of regex matchers,
14
+ * not a tree. Adding/auditing routes is a one-line patch and routes
15
+ * are evaluated in priority order (most specific first). Unknown URLs
16
+ * return `undefined` so the framework falls back to the generic
17
+ * `vtex.fetch` span name — observable, just less specific.
18
+ *
19
+ * Callers that need finer granularity than the URL can express (e.g.
20
+ * `POST /orderForm/{id}/items` is one URL but covers add / update /
21
+ * remove flows) should set `init.operation` explicitly per call; that
22
+ * always wins over the router.
23
+ */
24
+ export declare function vtexOperationRouter(url: string, method: string): string | undefined;
25
+ //# sourceMappingURL=operationRouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operationRouter.d.ts","sourceRoot":"","sources":["../../src/utils/operationRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AA8GH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUnF"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * URL-derived operation name router for VTEX API calls.
3
+ *
4
+ * Plugged into `createInstrumentedFetch` (`@decocms/blocks/fetch`) via the
5
+ * `resolveOperation(url, method)` option. The resolved string becomes the
6
+ * span suffix (`vtex.<operation>`) and the `fetch.operation` span +
7
+ * histogram label, so it must be:
8
+ *
9
+ * - low-cardinality (no IDs, slugs, search terms, account names);
10
+ * - stable across deploys (used for alerting + dashboards);
11
+ * - human-debuggable in a trace view.
12
+ *
13
+ * The router is intentionally a flat ordered list of regex matchers,
14
+ * not a tree. Adding/auditing routes is a one-line patch and routes
15
+ * are evaluated in priority order (most specific first). Unknown URLs
16
+ * return `undefined` so the framework falls back to the generic
17
+ * `vtex.fetch` span name — observable, just less specific.
18
+ *
19
+ * Callers that need finer granularity than the URL can express (e.g.
20
+ * `POST /orderForm/{id}/items` is one URL but covers add / update /
21
+ * remove flows) should set `init.operation` explicitly per call; that
22
+ * always wins over the router.
23
+ */
24
+ const m = (pattern, operation) => ({ pattern, operation });
25
+ /**
26
+ * Ordered list of `(regex, operation)` matchers. The first match wins.
27
+ *
28
+ * Patterns match against the URL pathname (the host is ignored — VTEX
29
+ * spreads the same API surface across `*.vtexcommercestable.*`,
30
+ * `*.myvtex.com`, and storefront origins, all on identical paths).
31
+ *
32
+ * Operation strings are bare (no `vtex.` prefix) — the framework
33
+ * prefixes them with the integration name at span time.
34
+ */
35
+ const MATCHERS = [
36
+ m(/^\/api\/io\/_v\/api\/intelligent-search\/([a-z_-]+)/, (mm) => `intelligent-search.${mm[1]}`),
37
+ m(/^\/_v\/private\/graphql\/v1/, "io.graphql"),
38
+ m(/^\/_v\/segment\//, "io.segment"),
39
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/items\/update/, (_mm, method) => method === "POST" ? "checkout.orderform.items.update" : "checkout.orderform.items"),
40
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/items/, (_mm, method) => {
41
+ if (method === "DELETE")
42
+ return "checkout.orderform.items.remove";
43
+ if (method === "PATCH" || method === "PUT")
44
+ return "checkout.orderform.items.update";
45
+ return "checkout.orderform.items.add";
46
+ }),
47
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/coupons/, "checkout.orderform.coupons"),
48
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/profile/, "checkout.orderform.profile"),
49
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/shippingData/, "checkout.orderform.shipping"),
50
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/paymentData/, "checkout.orderform.payment"),
51
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+/, (_mm, method) => method === "GET" ? "checkout.orderform.get" : "checkout.orderform.update"),
52
+ m(/^\/api\/checkout\/pub\/orderForm(?:\/?$)/, (_mm, method) => method === "POST" ? "checkout.orderform.create" : "checkout.orderform.get"),
53
+ m(/^\/api\/checkout\/pub\/orderForms\/simulation/, "checkout.simulation"),
54
+ m(/^\/api\/checkout\/pub\/regions/, "checkout.regions"),
55
+ m(/^\/api\/checkout\/pub\/postal-code/, "checkout.postal-code"),
56
+ m(/^\/api\/sessions/, (_mm, method) => (method === "POST" ? "sessions.update" : "sessions.get")),
57
+ m(/^\/api\/segments\//, "segments.get"),
58
+ m(/^\/api\/catalog_system\/pub\/portal\/pagetype\//, "catalog.pagetype"),
59
+ m(/^\/api\/catalog_system\/pub\/products\/crossselling\/([^/]+)/, (mm) => `catalog.crossselling.${mm[1]}`),
60
+ m(/^\/api\/catalog_system\/pub\/products\/variations\//, "catalog.products.variations"),
61
+ m(/^\/api\/catalog_system\/pub\/products\/search/, "catalog.products.search"),
62
+ m(/^\/api\/catalog_system\/pub\/facets\/search/, "catalog.facets.search"),
63
+ m(/^\/api\/catalog_system\/pub\/category\/tree/, "catalog.category.tree"),
64
+ m(/^\/api\/catalog_system\/(?:pub|pvt)\/specification/, "catalog.specification"),
65
+ m(/^\/api\/catalog_system\/pub\/brand/, "catalog.brand"),
66
+ m(/^\/api\/catalog_system\/pvt\/sku\//, "catalog.sku"),
67
+ m(/^\/api\/catalog_system\//, "catalog.other"),
68
+ m(/^\/api\/wishlist\//, "wishlist"),
69
+ m(/^\/api\/profile-system\/profile\//, "profile"),
70
+ m(/^\/api\/dataentities\/([^/]+)/, (mm) => `masterdata.${mm[1]}`),
71
+ m(/^\/api\/oms\/user\/orders\/[^/]+\/cancel/, "oms.orders.cancel"),
72
+ m(/^\/api\/oms\/user\/orders/, "oms.orders"),
73
+ m(/^\/api\/oms\/pvt\/orders/, "oms.orders.pvt"),
74
+ m(/^\/api\/vtexid\/pub\/logout/, "vtexid.logout"),
75
+ m(/^\/api\/vtexid\/pub\/authentication\/start/, "vtexid.authentication.start"),
76
+ m(/^\/api\/vtexid\/pub\/authentication\/[a-z]+\/validate/, "vtexid.authentication.validate"),
77
+ m(/^\/api\/vtexid\/pub\/authenticated\/user/, "vtexid.user"),
78
+ m(/^\/api\/vtexid\//, "vtexid.other"),
79
+ m(/^\/api\/events\/v1\//, "events.send"),
80
+ m(/^\/sitemap.*\.xml$/, "sitemap"),
81
+ m(/^\/api\/license-manager/, "license-manager"),
82
+ ];
83
+ /**
84
+ * Resolve an operation name for a VTEX URL. Returns `undefined` if no
85
+ * matcher fires, which causes the framework to fall back to
86
+ * `vtex.fetch`.
87
+ *
88
+ * Designed to be passed directly to `createInstrumentedFetch`:
89
+ *
90
+ * ```ts
91
+ * createInstrumentedFetch({
92
+ * name: "vtex",
93
+ * resolveOperation: vtexOperationRouter,
94
+ * });
95
+ * ```
96
+ */
97
+ /** The URL's pathname; tolerates relative or malformed URLs by stripping `?`/`#`. */
98
+ function extractPathname(url) {
99
+ try {
100
+ return new URL(url).pathname;
101
+ }
102
+ catch {
103
+ const qs = url.indexOf("?");
104
+ const hash = url.indexOf("#");
105
+ const end = [qs, hash].filter((i) => i >= 0).sort((a, b) => a - b)[0];
106
+ return end === undefined ? url : url.slice(0, end);
107
+ }
108
+ }
109
+ export function vtexOperationRouter(url, method) {
110
+ const pathname = extractPathname(url);
111
+ const upperMethod = method.toUpperCase();
112
+ for (const { pattern, operation } of MATCHERS) {
113
+ const match = pathname.match(pattern);
114
+ if (!match)
115
+ continue;
116
+ return typeof operation === "function" ? operation(match, upperMethod) : operation;
117
+ }
118
+ return undefined;
119
+ }
120
+ //# sourceMappingURL=operationRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operationRouter.js","sourceRoot":"","sources":["../../src/utils/operationRouter.ts"],"names":[],"mappings":"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"}