@sixtyninecommerce/client 0.23.1 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/admin/forms.js +19 -0
- package/dist/admin/forms.js.map +1 -1
- package/dist/admin/http.d.ts +9 -0
- package/dist/admin/http.d.ts.map +1 -1
- package/dist/admin/http.js +3 -0
- package/dist/admin/http.js.map +1 -1
- package/dist/admin/index.d.ts +63 -0
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +67 -0
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/redirects.d.ts +6 -0
- package/dist/admin/redirects.d.ts.map +1 -1
- package/dist/admin/redirects.js +12 -0
- package/dist/admin/redirects.js.map +1 -1
- package/dist/admin/types.d.ts +63 -0
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/cache-tags.d.ts +19 -0
- package/dist/cache-tags.d.ts.map +1 -1
- package/dist/cache-tags.js +19 -0
- package/dist/cache-tags.js.map +1 -1
- package/dist/client.d.ts +17 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +17 -0
- package/dist/client.js.map +1 -1
- package/dist/commerce/age-verification.js +3 -3
- package/dist/commerce/age-verification.js.map +1 -1
- package/dist/commerce/branding.js +7 -0
- package/dist/commerce/branding.js.map +1 -1
- package/dist/commerce/cart.js +25 -0
- package/dist/commerce/cart.js.map +1 -1
- package/dist/commerce/checkout.d.ts +68 -0
- package/dist/commerce/checkout.d.ts.map +1 -1
- package/dist/commerce/checkout.js +83 -0
- package/dist/commerce/checkout.js.map +1 -1
- package/dist/commerce/customer.d.ts +58 -0
- package/dist/commerce/customer.d.ts.map +1 -1
- package/dist/commerce/customer.js +65 -0
- package/dist/commerce/customer.js.map +1 -1
- package/dist/commerce/index.d.ts +17 -1
- package/dist/commerce/index.d.ts.map +1 -1
- package/dist/commerce/pickup-location-parser.d.ts +18 -0
- package/dist/commerce/pickup-location-parser.d.ts.map +1 -1
- package/dist/commerce/pickup-location-parser.js +28 -0
- package/dist/commerce/pickup-location-parser.js.map +1 -1
- package/dist/commerce/placement-error.d.ts +52 -0
- package/dist/commerce/placement-error.d.ts.map +1 -1
- package/dist/commerce/placement-error.js +87 -0
- package/dist/commerce/placement-error.js.map +1 -1
- package/dist/commerce/products.d.ts +48 -0
- package/dist/commerce/products.d.ts.map +1 -1
- package/dist/commerce/products.js +95 -2
- package/dist/commerce/products.js.map +1 -1
- package/dist/commerce/queries.d.ts +114 -27
- package/dist/commerce/queries.d.ts.map +1 -1
- package/dist/commerce/queries.js +219 -1
- package/dist/commerce/queries.js.map +1 -1
- package/dist/commerce/quotes.js +33 -0
- package/dist/commerce/quotes.js.map +1 -1
- package/dist/commerce/saved-lists.d.ts +7 -7
- package/dist/commerce/saved-lists.d.ts.map +1 -1
- package/dist/commerce/saved-lists.js +1 -1
- package/dist/commerce/search.js +3 -0
- package/dist/commerce/search.js.map +1 -1
- package/dist/commerce/shipping.js +3 -3
- package/dist/commerce/shipping.js.map +1 -1
- package/dist/commerce/stock-notifications.d.ts +11 -0
- package/dist/commerce/stock-notifications.d.ts.map +1 -1
- package/dist/commerce/stock-notifications.js +11 -0
- package/dist/commerce/stock-notifications.js.map +1 -1
- package/dist/commerce/subscriptions.d.ts +32 -8
- package/dist/commerce/subscriptions.d.ts.map +1 -1
- package/dist/commerce/subscriptions.js +90 -2
- package/dist/commerce/subscriptions.js.map +1 -1
- package/dist/commerce/vat-validation.js +4 -4
- package/dist/commerce/vat-validation.js.map +1 -1
- package/dist/constants.d.ts +31 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +32 -0
- package/dist/constants.js.map +1 -1
- package/dist/content/asset-urls.d.ts +50 -0
- package/dist/content/asset-urls.d.ts.map +1 -1
- package/dist/content/asset-urls.js +92 -0
- package/dist/content/asset-urls.js.map +1 -1
- package/dist/content/assets.d.ts +15 -0
- package/dist/content/assets.d.ts.map +1 -1
- package/dist/content/assets.js +15 -0
- package/dist/content/assets.js.map +1 -1
- package/dist/content/collection-pages.d.ts +5 -0
- package/dist/content/collection-pages.d.ts.map +1 -1
- package/dist/content/collection-pages.js +8 -0
- package/dist/content/collection-pages.js.map +1 -1
- package/dist/content/collections.d.ts +14 -0
- package/dist/content/collections.d.ts.map +1 -1
- package/dist/content/collections.js +16 -0
- package/dist/content/collections.js.map +1 -1
- package/dist/content/filtered-products.d.ts +18 -0
- package/dist/content/filtered-products.d.ts.map +1 -1
- package/dist/content/filtered-products.js +16 -0
- package/dist/content/filtered-products.js.map +1 -1
- package/dist/content/form-field-types.d.ts +6 -0
- package/dist/content/form-field-types.d.ts.map +1 -1
- package/dist/content/form-field-types.js +12 -0
- package/dist/content/form-field-types.js.map +1 -1
- package/dist/content/forms.d.ts +16 -0
- package/dist/content/forms.d.ts.map +1 -1
- package/dist/content/forms.js +23 -0
- package/dist/content/forms.js.map +1 -1
- package/dist/content/items.d.ts +26 -0
- package/dist/content/items.d.ts.map +1 -1
- package/dist/content/items.js +33 -0
- package/dist/content/items.js.map +1 -1
- package/dist/content/resolve.js +6 -0
- package/dist/content/resolve.js.map +1 -1
- package/dist/content/sitemap.d.ts +5 -0
- package/dist/content/sitemap.d.ts.map +1 -1
- package/dist/content/sitemap.js +5 -0
- package/dist/content/sitemap.js.map +1 -1
- package/dist/core/context.js +6 -0
- package/dist/core/context.js.map +1 -1
- package/dist/core/headers.js +2 -0
- package/dist/core/headers.js.map +1 -1
- package/dist/core/http.d.ts +8 -0
- package/dist/core/http.d.ts.map +1 -1
- package/dist/core/http.js +89 -1
- package/dist/core/http.js.map +1 -1
- package/dist/credit/credit-status.js +2 -2
- package/dist/credit/credit-status.js.map +1 -1
- package/dist/credit/payment-terms.js +2 -2
- package/dist/credit/payment-terms.js.map +1 -1
- package/dist/currency/exchange.d.ts +11 -0
- package/dist/currency/exchange.d.ts.map +1 -1
- package/dist/currency/exchange.js +11 -0
- package/dist/currency/exchange.js.map +1 -1
- package/dist/errors.d.ts +50 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +50 -3
- package/dist/errors.js.map +1 -1
- package/dist/events/envelope.d.ts +36 -0
- package/dist/events/envelope.d.ts.map +1 -1
- package/dist/events/envelope.js +12 -0
- package/dist/events/envelope.js.map +1 -1
- package/dist/events/index.d.ts +13 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +13 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/payloads.d.ts +19 -0
- package/dist/events/payloads.d.ts.map +1 -1
- package/dist/events/payloads.js +12 -0
- package/dist/events/payloads.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/media/index.js +2 -0
- package/dist/media/index.js.map +1 -1
- package/dist/media/urls.d.ts +52 -0
- package/dist/media/urls.d.ts.map +1 -1
- package/dist/media/urls.js +38 -0
- package/dist/media/urls.js.map +1 -1
- package/dist/media/video.d.ts +16 -0
- package/dist/media/video.d.ts.map +1 -1
- package/dist/media/video.js +16 -0
- package/dist/media/video.js.map +1 -1
- package/dist/next/artifact-handler.d.ts +22 -0
- package/dist/next/artifact-handler.d.ts.map +1 -1
- package/dist/next/artifact-handler.js +22 -0
- package/dist/next/artifact-handler.js.map +1 -1
- package/dist/next/event-revalidate-handler.d.ts +67 -0
- package/dist/next/event-revalidate-handler.d.ts.map +1 -1
- package/dist/next/event-revalidate-handler.js +48 -0
- package/dist/next/event-revalidate-handler.js.map +1 -1
- package/dist/next/index.d.ts +6 -0
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +6 -0
- package/dist/next/index.js.map +1 -1
- package/dist/next/json-ld.d.ts +9 -0
- package/dist/next/json-ld.d.ts.map +1 -1
- package/dist/next/json-ld.js +9 -0
- package/dist/next/json-ld.js.map +1 -1
- package/dist/next/metadata.d.ts +18 -0
- package/dist/next/metadata.d.ts.map +1 -1
- package/dist/next/metadata.js +21 -0
- package/dist/next/metadata.js.map +1 -1
- package/dist/next/redirect-middleware.d.ts +39 -0
- package/dist/next/redirect-middleware.d.ts.map +1 -1
- package/dist/next/redirect-middleware.js +32 -0
- package/dist/next/redirect-middleware.js.map +1 -1
- package/dist/next/revalidate-handler.d.ts +30 -0
- package/dist/next/revalidate-handler.d.ts.map +1 -1
- package/dist/next/revalidate-handler.js +22 -0
- package/dist/next/revalidate-handler.js.map +1 -1
- package/dist/order-scope.d.ts +27 -0
- package/dist/order-scope.d.ts.map +1 -1
- package/dist/order-scope.js +29 -0
- package/dist/order-scope.js.map +1 -1
- package/dist/pricing/format.d.ts +17 -0
- package/dist/pricing/format.d.ts.map +1 -1
- package/dist/pricing/format.js +19 -0
- package/dist/pricing/format.js.map +1 -1
- package/dist/pricing/index.d.ts +8 -1
- package/dist/pricing/index.d.ts.map +1 -1
- package/dist/pricing/index.js +18 -2
- package/dist/pricing/index.js.map +1 -1
- package/dist/pricing/tax-display.d.ts +77 -0
- package/dist/pricing/tax-display.d.ts.map +1 -1
- package/dist/pricing/tax-display.js +85 -0
- package/dist/pricing/tax-display.js.map +1 -1
- package/dist/pricing/tiers.d.ts +9 -0
- package/dist/pricing/tiers.d.ts.map +1 -1
- package/dist/pricing/tiers.js +9 -0
- package/dist/pricing/tiers.js.map +1 -1
- package/dist/pricing/validation.d.ts +56 -1
- package/dist/pricing/validation.d.ts.map +1 -1
- package/dist/pricing/validation.js +61 -0
- package/dist/pricing/validation.js.map +1 -1
- package/dist/redirects/index.d.ts +1 -0
- package/dist/redirects/index.d.ts.map +1 -1
- package/dist/redirects/index.js +1 -0
- package/dist/redirects/index.js.map +1 -1
- package/dist/redirects/store.d.ts +20 -0
- package/dist/redirects/store.d.ts.map +1 -1
- package/dist/redirects/store.js +57 -0
- package/dist/redirects/store.js.map +1 -1
- package/dist/redirects/types.d.ts +24 -0
- package/dist/redirects/types.d.ts.map +1 -1
- package/dist/redirects/types.js +1 -0
- package/dist/redirects/types.js.map +1 -1
- package/dist/revalidation/event-plan.d.ts +48 -0
- package/dist/revalidation/event-plan.d.ts.map +1 -1
- package/dist/revalidation/event-plan.js +61 -0
- package/dist/revalidation/event-plan.js.map +1 -1
- package/dist/revalidation/event-verify.d.ts +25 -0
- package/dist/revalidation/event-verify.d.ts.map +1 -1
- package/dist/revalidation/event-verify.js +27 -0
- package/dist/revalidation/event-verify.js.map +1 -1
- package/dist/revalidation/types.d.ts +20 -0
- package/dist/revalidation/types.d.ts.map +1 -1
- package/dist/revalidation/types.js +10 -0
- package/dist/revalidation/types.js.map +1 -1
- package/dist/revalidation/url-context.d.ts +25 -0
- package/dist/revalidation/url-context.d.ts.map +1 -1
- package/dist/revalidation/url-context.js +17 -0
- package/dist/revalidation/url-context.js.map +1 -1
- package/dist/revalidation/verify.d.ts +8 -0
- package/dist/revalidation/verify.d.ts.map +1 -1
- package/dist/revalidation/verify.js +8 -0
- package/dist/revalidation/verify.js.map +1 -1
- package/dist/seo/ai.d.ts +17 -0
- package/dist/seo/ai.d.ts.map +1 -1
- package/dist/seo/ai.js +12 -0
- package/dist/seo/ai.js.map +1 -1
- package/dist/seo/alternates.js +13 -0
- package/dist/seo/alternates.js.map +1 -1
- package/dist/seo/artifacts.d.ts +13 -0
- package/dist/seo/artifacts.d.ts.map +1 -1
- package/dist/seo/artifacts.js +19 -0
- package/dist/seo/artifacts.js.map +1 -1
- package/dist/seo/canonical.d.ts +15 -0
- package/dist/seo/canonical.d.ts.map +1 -1
- package/dist/seo/canonical.js +24 -0
- package/dist/seo/canonical.js.map +1 -1
- package/dist/seo/index.js +6 -0
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/json-ld.d.ts +13 -0
- package/dist/seo/json-ld.d.ts.map +1 -1
- package/dist/seo/json-ld.js +32 -0
- package/dist/seo/json-ld.js.map +1 -1
- package/dist/seo/locale-tag.d.ts +31 -0
- package/dist/seo/locale-tag.d.ts.map +1 -1
- package/dist/seo/locale-tag.js +31 -0
- package/dist/seo/locale-tag.js.map +1 -1
- package/dist/seo/meta-tags.d.ts +29 -0
- package/dist/seo/meta-tags.d.ts.map +1 -1
- package/dist/seo/meta-tags.js +28 -0
- package/dist/seo/meta-tags.js.map +1 -1
- package/dist/seo/metadata-parser.d.ts +24 -0
- package/dist/seo/metadata-parser.d.ts.map +1 -1
- package/dist/seo/metadata-parser.js +38 -0
- package/dist/seo/metadata-parser.js.map +1 -1
- package/dist/seo/metadata-types.d.ts +16 -0
- package/dist/seo/metadata-types.d.ts.map +1 -1
- package/dist/seo/product-path.d.ts +96 -0
- package/dist/seo/product-path.d.ts.map +1 -1
- package/dist/seo/product-path.js +96 -0
- package/dist/seo/product-path.js.map +1 -1
- package/dist/seo/robots.d.ts +17 -0
- package/dist/seo/robots.d.ts.map +1 -1
- package/dist/seo/robots.js +12 -0
- package/dist/seo/robots.js.map +1 -1
- package/dist/seo/types.d.ts +39 -0
- package/dist/seo/types.d.ts.map +1 -1
- package/dist/seo/url-builder.d.ts +31 -0
- package/dist/seo/url-builder.d.ts.map +1 -1
- package/dist/seo/url-builder.js +36 -0
- package/dist/seo/url-builder.js.map +1 -1
- package/dist/types.d.ts +1283 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,14 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for the legacy platform → storefront revalidation webhook
|
|
3
|
+
* (snake_case, matching the platform's merchant-webhook convention). The
|
|
4
|
+
* platform no longer sends it: its sender is retired, and storefronts receive
|
|
5
|
+
* platform events through `createEventRevalidateHandler`. The raw body is
|
|
6
|
+
* HMAC-SHA256-signed with the per-channel revalidation secret:
|
|
7
|
+
* `X-Webhook-Signature: sha256=<hex>` + `X-Webhook-Event: <event>`.
|
|
8
|
+
* Replay protection lives INSIDE the signed body: `occurred_at` (reject
|
|
9
|
+
* outside the tolerance window) and `id` (delivery UUID — idempotency key).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated The legacy SEO revalidation webhook body. Platform event
|
|
13
|
+
* deliveries use `PlatformEventEnvelope` (`@sixtyninecommerce/client/events`).
|
|
14
|
+
*/
|
|
1
15
|
export interface RevalidateWebhookPayload {
|
|
16
|
+
/** Delivery UUID — dedupe on this if you process deliveries statefully. */
|
|
2
17
|
id: string;
|
|
18
|
+
/** e.g. 'seo.paths_changed.event' */
|
|
3
19
|
event: string;
|
|
4
20
|
channel_code: string;
|
|
21
|
+
/** ISO-8601 dispatch time — inside the signed body for replay checks. */
|
|
5
22
|
occurred_at: string;
|
|
6
23
|
entity: {
|
|
7
24
|
type: string;
|
|
8
25
|
id: string | null;
|
|
9
26
|
};
|
|
27
|
+
/** Locale-expanded storefront-relative paths (e.g. "/nl/schoenen/rood"). */
|
|
10
28
|
paths: string[];
|
|
29
|
+
/** revalidateTag targets (e.g. "seo-artifact" for the artifact proxies). */
|
|
11
30
|
tags: string[];
|
|
31
|
+
/** 'all' → revalidate the whole layout instead of per-path. */
|
|
12
32
|
scope: 'paths' | 'all';
|
|
13
33
|
}
|
|
14
34
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/revalidation/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/revalidation/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,2EAA2E;IAC3E,EAAE,EAAE,MAAM,CAAC;IACX,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC5C,4EAA4E;IAC5E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4EAA4E;IAC5E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,+DAA+D;IAC/D,KAAK,EAAE,OAAO,GAAG,KAAK,CAAC;CACxB"}
|
|
@@ -1,2 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for the legacy platform → storefront revalidation webhook
|
|
3
|
+
* (snake_case, matching the platform's merchant-webhook convention). The
|
|
4
|
+
* platform no longer sends it: its sender is retired, and storefronts receive
|
|
5
|
+
* platform events through `createEventRevalidateHandler`. The raw body is
|
|
6
|
+
* HMAC-SHA256-signed with the per-channel revalidation secret:
|
|
7
|
+
* `X-Webhook-Signature: sha256=<hex>` + `X-Webhook-Event: <event>`.
|
|
8
|
+
* Replay protection lives INSIDE the signed body: `occurred_at` (reject
|
|
9
|
+
* outside the tolerance window) and `id` (delivery UUID — idempotency key).
|
|
10
|
+
*/
|
|
1
11
|
export {};
|
|
2
12
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/revalidation/types.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/revalidation/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -1,17 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a revalidator needs to turn a channel-relative, locale-unprefixed event
|
|
3
|
+
* path into the storefront's own URL: the channel's URL rule set, and every
|
|
4
|
+
* language the storefront serves.
|
|
5
|
+
*/
|
|
1
6
|
import type { ChannelUrlSettingsChangedV1 } from '../events/payloads.js';
|
|
2
7
|
import { type UrlStrategyConfig } from '../seo/url-builder.js';
|
|
3
8
|
import type { StorefrontClient } from '../types.js';
|
|
4
9
|
export interface UrlContext {
|
|
10
|
+
/** How the channel composes URLs — the same config the SEO module builds canonicals from. */
|
|
5
11
|
readonly config: UrlStrategyConfig;
|
|
12
|
+
/**
|
|
13
|
+
* Every language the storefront serves. A path an event states for "every
|
|
14
|
+
* locale" is expanded over this list; the default language is always added.
|
|
15
|
+
*/
|
|
6
16
|
readonly locales: readonly string[];
|
|
7
17
|
}
|
|
18
|
+
/** A lazily-read {@link UrlContext}, optionally able to drop a cached value. */
|
|
8
19
|
export interface UrlContextSource {
|
|
9
20
|
(): UrlContext | Promise<UrlContext>;
|
|
21
|
+
/** Called after `channel.url_settings_changed`, so the next read is fresh. */
|
|
10
22
|
invalidate?(): void;
|
|
11
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* A {@link UrlContextSource} backed by the client's `activeChannel` query —
|
|
26
|
+
* fresh custom fields AND `availableLanguageCodes`, which the client's startup
|
|
27
|
+
* channel snapshot does not carry. Read on first use and cached; a failed read
|
|
28
|
+
* is not cached, so the next delivery retries it. Accepts a client promise so a
|
|
29
|
+
* route module needs no top-level `await`.
|
|
30
|
+
*/
|
|
12
31
|
export declare function urlContextFromClient(client: Pick<StorefrontClient, 'commerce'> | Promise<Pick<StorefrontClient, 'commerce'>>): UrlContextSource & {
|
|
13
32
|
invalidate(): void;
|
|
14
33
|
};
|
|
34
|
+
/** The URL-shaping half of a `channel.url_settings_changed` payload. */
|
|
15
35
|
export type ChannelUrlRuleSet = Omit<ChannelUrlSettingsChangedV1, 'channel_id' | 'changed'>;
|
|
36
|
+
/**
|
|
37
|
+
* The {@link UrlContext} a `channel.url_settings_changed` payload states — the
|
|
38
|
+
* channel's complete rule set AFTER the change — or `null` when it cannot be
|
|
39
|
+
* used as one: no storefront origin, or a truncated language/prefix list.
|
|
40
|
+
*/
|
|
16
41
|
export declare function urlContextFromChannelSettings(settings: ChannelUrlRuleSet): UrlContext | null;
|
|
17
42
|
//# sourceMappingURL=url-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-context.d.ts","sourceRoot":"","sources":["../../src/revalidation/url-context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"url-context.d.ts","sourceRoot":"","sources":["../../src/revalidation/url-context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,KAAK,iBAAiB,EAA0B,MAAM,uBAAuB,CAAC;AACvF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,8EAA8E;IAC9E,UAAU,CAAC,IAAI,IAAI,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC,GACvF,gBAAgB,GAAG;IAAE,UAAU,IAAI,IAAI,CAAA;CAAE,CAwB3C;AAED,wEAAwE;AACxE,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,2BAA2B,EAAE,YAAY,GAAG,SAAS,CAAC,CAAC;AAE5F;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,UAAU,GAAG,IAAI,CAwB5F"}
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a revalidator needs to turn a channel-relative, locale-unprefixed event
|
|
3
|
+
* path into the storefront's own URL: the channel's URL rule set, and every
|
|
4
|
+
* language the storefront serves.
|
|
5
|
+
*/
|
|
1
6
|
import { urlStrategyFromChannel } from '../seo/url-builder.js';
|
|
7
|
+
/**
|
|
8
|
+
* A {@link UrlContextSource} backed by the client's `activeChannel` query —
|
|
9
|
+
* fresh custom fields AND `availableLanguageCodes`, which the client's startup
|
|
10
|
+
* channel snapshot does not carry. Read on first use and cached; a failed read
|
|
11
|
+
* is not cached, so the next delivery retries it. Accepts a client promise so a
|
|
12
|
+
* route module needs no top-level `await`.
|
|
13
|
+
*/
|
|
2
14
|
export function urlContextFromClient(client) {
|
|
3
15
|
let cached = null;
|
|
4
16
|
const source = () => {
|
|
@@ -24,6 +36,11 @@ export function urlContextFromClient(client) {
|
|
|
24
36
|
},
|
|
25
37
|
});
|
|
26
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* The {@link UrlContext} a `channel.url_settings_changed` payload states — the
|
|
41
|
+
* channel's complete rule set AFTER the change — or `null` when it cannot be
|
|
42
|
+
* used as one: no storefront origin, or a truncated language/prefix list.
|
|
43
|
+
*/
|
|
27
44
|
export function urlContextFromChannelSettings(settings) {
|
|
28
45
|
if (settings.storefront_url === null ||
|
|
29
46
|
settings.available_language_codes_truncated ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-context.js","sourceRoot":"","sources":["../../src/revalidation/url-context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"url-context.js","sourceRoot":"","sources":["../../src/revalidation/url-context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAA0B,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAoBvF;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAwF;IAExF,IAAI,MAAM,GAA+B,IAAI,CAAC;IAE9C,MAAM,MAAM,GAAG,GAAwB,EAAE;QACvC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;YAC3D,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAC3D,OAAO;gBACL,MAAM,EAAE,sBAAsB,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,mBAAmB,CAAC;gBACjF,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,sBAAsB,CAAC;aAC7C,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,MAAM,GAAG,IAAI,CAAC;QACd,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;YACd,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM,GAAG,IAAI,CAAC;QACrC,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE;QAC3B,UAAU;YACR,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAKD;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAA2B;IACvE,IACE,QAAQ,CAAC,cAAc,KAAK,IAAI;QAChC,QAAQ,CAAC,kCAAkC;QAC3C,QAAQ,CAAC,wCAAwC,EACjD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,SAAS,GAAG,QAAQ,CAAC,8BAA8B,CAAC;IAC1D,OAAO;QACL,MAAM,EAAE;YACN,aAAa,EAAE,QAAQ,CAAC,cAAc;YACtC,iBAAiB,EAAE,QAAQ,CAAC,mBAAmB;YAC/C,sBAAsB,EAAE,QAAQ,CAAC,yBAAyB;YAC1D,mBAAmB,EAAE,QAAQ,CAAC,qBAAqB;YACnD,kBAAkB,EAAE,QAAQ,CAAC,oBAAoB;YACjD,kBAAkB,EAAE,QAAQ,CAAC,oBAAoB;YACjD,8BAA8B,EAC5B,SAAS,CAAC,MAAM,GAAG,CAAC;gBAClB,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;gBAC5E,CAAC,CAAC,IAAI;SACX;QACD,OAAO,EAAE,CAAC,GAAG,QAAQ,CAAC,wBAAwB,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
|
@@ -1,2 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMAC verification for platform webhooks, on Web Crypto so it runs in Node
|
|
3
|
+
* 18+, edge runtimes, and workers alike (hence async).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Verify an `X-Webhook-Signature: sha256=<hex>` header against the RAW
|
|
7
|
+
* request body. Constant-time via `crypto.subtle.verify`.
|
|
8
|
+
*/
|
|
1
9
|
export declare function verifyWebhookSignature(rawBody: string, signatureHeader: string | null | undefined, secret: string): Promise<boolean>;
|
|
2
10
|
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/revalidation/verify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/revalidation/verify.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC1C,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CAgBlB"}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMAC verification for platform webhooks, on Web Crypto so it runs in Node
|
|
3
|
+
* 18+, edge runtimes, and workers alike (hence async).
|
|
4
|
+
*/
|
|
1
5
|
function hexToBytes(hex) {
|
|
2
6
|
if (hex.length % 2 !== 0 || /[^0-9a-f]/i.test(hex))
|
|
3
7
|
return null;
|
|
@@ -7,6 +11,10 @@ function hexToBytes(hex) {
|
|
|
7
11
|
}
|
|
8
12
|
return bytes;
|
|
9
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Verify an `X-Webhook-Signature: sha256=<hex>` header against the RAW
|
|
16
|
+
* request body. Constant-time via `crypto.subtle.verify`.
|
|
17
|
+
*/
|
|
10
18
|
export async function verifyWebhookSignature(rawBody, signatureHeader, secret) {
|
|
11
19
|
if (!signatureHeader || !secret)
|
|
12
20
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/revalidation/verify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/revalidation/verify.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAChE,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAe,EACf,eAA0C,EAC1C,MAAc;IAEd,IAAI,CAAC,eAAe,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAE9C,MAAM,GAAG,GAAG,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC;IAC/F,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAExD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CACvC,KAAK,EACL,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EACtB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EACjC,KAAK,EACL,CAAC,QAAQ,CAAC,CACX,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/E,CAAC"}
|
package/dist/seo/ai.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI / LLM-facing helpers: per-entity `<meta name="ai-summary">` content and
|
|
3
|
+
* `llms.txt` bullet rendering.
|
|
4
|
+
*/
|
|
1
5
|
import type { CmsItemMetadata, CollectionMetadata, ProductMetadata } from './metadata-types.js';
|
|
2
6
|
import type { CmsItemForSeo, CollectionForSeo, ProductForSeo } from './types.js';
|
|
3
7
|
export type AiSummaryInput = {
|
|
@@ -10,6 +14,11 @@ export type AiSummaryInput = {
|
|
|
10
14
|
kind: 'cms';
|
|
11
15
|
metadata: CmsItemMetadata | null;
|
|
12
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Returns the AI summary text or `null` when none is configured. Storefronts
|
|
19
|
+
* use this to render the `<meta name="ai-summary">` head tag and the embedded
|
|
20
|
+
* `<section data-ai-summary>` element.
|
|
21
|
+
*/
|
|
13
22
|
export declare function aiSummaryFor(input: AiSummaryInput): string | null;
|
|
14
23
|
export type LlmsTxtEntryInput = ({
|
|
15
24
|
kind: 'product';
|
|
@@ -24,9 +33,17 @@ export type LlmsTxtEntryInput = ({
|
|
|
24
33
|
cms: CmsItemForSeo;
|
|
25
34
|
metadata: CmsItemMetadata | null;
|
|
26
35
|
}) & {
|
|
36
|
+
/** Resolved canonical URL of the page. The `.md` suffix is appended. */
|
|
27
37
|
url: string;
|
|
38
|
+
/** Display name used as the bullet label. */
|
|
28
39
|
name: string;
|
|
40
|
+
/** Optional fallback HTML description (stripped + truncated when no AI summary). */
|
|
29
41
|
description?: string;
|
|
30
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Render one markdown bullet line for the channel's `/llms.txt` file.
|
|
45
|
+
* Format: `- [name](url.md): summary`. The storefront aggregates these
|
|
46
|
+
* across entities; the SDK only renders one row at a time.
|
|
47
|
+
*/
|
|
31
48
|
export declare function llmsTxtEntryFor(input: LlmsTxtEntryInput): string;
|
|
32
49
|
//# sourceMappingURL=ai.d.ts.map
|
package/dist/seo/ai.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/seo/ai.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/seo/ai.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAChG,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAcjF,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,CAAC;AActD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAGjE;AAED,MAAM,MAAM,iBAAiB,GAAG,CAC5B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAAE,GACzF;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,CACxE,GAAG;IACF,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAShE"}
|
package/dist/seo/ai.js
CHANGED
|
@@ -15,13 +15,24 @@ function summaryOf(input) {
|
|
|
15
15
|
case 'cms':
|
|
16
16
|
return input.metadata?.aiSummary ?? null;
|
|
17
17
|
case 'collection':
|
|
18
|
+
// Collections carry no dedicated AI summary; fall back to SEO description.
|
|
18
19
|
return input.metadata?.seoDescription ?? null;
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns the AI summary text or `null` when none is configured. Storefronts
|
|
24
|
+
* use this to render the `<meta name="ai-summary">` head tag and the embedded
|
|
25
|
+
* `<section data-ai-summary>` element.
|
|
26
|
+
*/
|
|
21
27
|
export function aiSummaryFor(input) {
|
|
22
28
|
const value = summaryOf(input)?.trim();
|
|
23
29
|
return value && value.length > 0 ? value : null;
|
|
24
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Render one markdown bullet line for the channel's `/llms.txt` file.
|
|
33
|
+
* Format: `- [name](url.md): summary`. The storefront aggregates these
|
|
34
|
+
* across entities; the SDK only renders one row at a time.
|
|
35
|
+
*/
|
|
25
36
|
export function llmsTxtEntryFor(input) {
|
|
26
37
|
const summary = aiSummaryFor(input)?.trim() ??
|
|
27
38
|
input.metadata?.seoDescription?.trim() ??
|
|
@@ -32,6 +43,7 @@ export function llmsTxtEntryFor(input) {
|
|
|
32
43
|
: `- [${input.name}](${urlWithSuffix})`;
|
|
33
44
|
}
|
|
34
45
|
function appendMdSuffix(url) {
|
|
46
|
+
// Preserve query/hash if present.
|
|
35
47
|
const hashIdx = url.indexOf('#');
|
|
36
48
|
const queryIdx = url.indexOf('?');
|
|
37
49
|
const tailIdx = hashIdx === -1 ? queryIdx : queryIdx === -1 ? hashIdx : Math.min(hashIdx, queryIdx);
|
package/dist/seo/ai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/seo/ai.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,GAAG,UAAU,CAAC;AAC/B,MAAM,aAAa,GAAG,MAAM,CAAC;AAE7B,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5E,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,GAAW;IAC1C,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC;AACjD,CAAC;AAOD,SAAS,SAAS,CAAC,KAAqB;IACtC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,IAAI,IAAI,CAAC;QAC5C,KAAK,KAAK;YACR,OAAO,KAAK,CAAC,QAAQ,EAAE,SAAS,IAAI,IAAI,CAAC;QAC3C,KAAK,YAAY;
|
|
1
|
+
{"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/seo/ai.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,GAAG,UAAU,CAAC;AAC/B,MAAM,aAAa,GAAG,MAAM,CAAC;AAE7B,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5E,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,GAAW;IAC1C,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC;AACjD,CAAC;AAOD,SAAS,SAAS,CAAC,KAAqB;IACtC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,IAAI,IAAI,CAAC;QAC5C,KAAK,KAAK;YACR,OAAO,KAAK,CAAC,QAAQ,EAAE,SAAS,IAAI,IAAI,CAAC;QAC3C,KAAK,YAAY;YACf,2EAA2E;YAC3E,OAAO,KAAK,CAAC,QAAQ,EAAE,cAAc,IAAI,IAAI,CAAC;IAClD,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAqB;IAChD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACvC,OAAO,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAeD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAwB;IACtD,MAAM,OAAO,GACX,YAAY,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE;QAC3B,KAAK,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE;QACtC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChD,OAAO,OAAO;QACZ,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,aAAa,MAAM,OAAO,EAAE;QACnD,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,aAAa,GAAG,CAAC;AAC5C,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,kCAAkC;IAClC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,OAAO,GACX,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtF,IAAI,OAAO,KAAK,CAAC,CAAC;QAAE,OAAO,GAAG,GAAG,KAAK,CAAC;IACvC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;AAC5D,CAAC"}
|
package/dist/seo/alternates.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { canonicalFor } from './canonical.js';
|
|
2
2
|
import { toBcp47 } from './locale-tag.js';
|
|
3
|
+
/**
|
|
4
|
+
* Languages an entity actually has a translation for. Google prefers hreflang
|
|
5
|
+
* pairs that resolve, so we only emit one row per existing translation.
|
|
6
|
+
*/
|
|
3
7
|
function translatedLanguagesFor(entity) {
|
|
4
8
|
switch (entity.kind) {
|
|
5
9
|
case 'product': {
|
|
6
10
|
const fromProduct = (entity.translations ?? []).map((t) => t.languageCode);
|
|
11
|
+
// Root canonical slugs come from collections — if the canonical root
|
|
12
|
+
// has a translation in a language the product doesn't, we still can't
|
|
13
|
+
// reliably build that variant. Stick with product translations as the
|
|
14
|
+
// source of truth for what languages to emit.
|
|
7
15
|
return fromProduct;
|
|
8
16
|
}
|
|
9
17
|
case 'collection':
|
|
@@ -14,9 +22,14 @@ function translatedLanguagesFor(entity) {
|
|
|
14
22
|
}
|
|
15
23
|
export function alternatesFor(cfg, entity) {
|
|
16
24
|
const languages = Array.from(new Set(translatedLanguagesFor(entity)));
|
|
25
|
+
// Always include the default language — if the entity has no translations
|
|
26
|
+
// at all we still want `x-default` to point somewhere sensible.
|
|
17
27
|
if (!languages.includes(cfg.defaultLanguageCode)) {
|
|
18
28
|
languages.unshift(cfg.defaultLanguageCode);
|
|
19
29
|
}
|
|
30
|
+
// `hreflang` must be BCP 47 — a raw `en_GB` makes Google drop the tag. The
|
|
31
|
+
// untouched Vendure code rides along in `languageCode` for the consumers that
|
|
32
|
+
// need that spelling (OpenGraph, and matching per-entity overrides).
|
|
20
33
|
const rows = languages.map((lang) => ({
|
|
21
34
|
hreflang: toBcp47(lang),
|
|
22
35
|
href: canonicalFor(cfg, entity, lang),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alternates.js","sourceRoot":"","sources":["../../src/seo/alternates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"alternates.js","sourceRoot":"","sources":["../../src/seo/alternates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI1C;;;GAGG;AACH,SAAS,sBAAsB,CAAC,MAAsB;IACpD,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;YAC3E,qEAAqE;YACrE,sEAAsE;YACtE,sEAAsE;YACtE,8CAA8C;YAC9C,OAAO,WAAW,CAAC;QACrB,CAAC;QACD,KAAK,YAAY;YACf,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAChE,KAAK,KAAK;YACR,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAsB,EAAE,MAAsB;IAC1E,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACtE,0EAA0E;IAC1E,gEAAgE;IAChE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACjD,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC7C,CAAC;IACD,2EAA2E;IAC3E,8EAA8E;IAC9E,qEAAqE;IACrE,MAAM,IAAI,GAAmB,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACpD,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC;QACvB,IAAI,EAAE,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC;QACrC,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC,CAAC;IACJ,IAAI,CAAC,IAAI,CAAC;QACR,QAAQ,EAAE,WAAW;QACrB,IAAI,EAAE,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,mBAAmB,CAAC;KACzD,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/seo/artifacts.d.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform artifact URLs + the 404 beacon. The platform renders sitemap.xml,
|
|
3
|
+
* robots.txt, llms.txt and the IndexNow key file per channel; the storefront
|
|
4
|
+
* proxies them on its own origin (see `@sixtyninecommerce/client/next`'s
|
|
5
|
+
* `createSeoArtifactHandler`).
|
|
6
|
+
*/
|
|
1
7
|
import type { StoreContext } from '../types.js';
|
|
2
8
|
export interface SeoArtifactUrls {
|
|
9
|
+
/** Platform URL of the sitemap index, or of one child file when `childFile` is given. */
|
|
3
10
|
sitemapUrl(childFile?: string): string;
|
|
4
11
|
robotsUrl(): string;
|
|
5
12
|
llmsTxtUrl(): string;
|
|
13
|
+
/** Key file for IndexNow ownership verification — proxy it at /{key}.txt. */
|
|
6
14
|
indexnowKeyUrl(): string;
|
|
7
15
|
}
|
|
8
16
|
export declare function createArtifactUrls(ctx: StoreContext): SeoArtifactUrls;
|
|
17
|
+
/**
|
|
18
|
+
* Fire-and-forget 404 report — call from the storefront's not-found handler
|
|
19
|
+
* so the platform can suggest redirects for dead URLs. Never throws, never
|
|
20
|
+
* blocks rendering; deduped per process/session.
|
|
21
|
+
*/
|
|
9
22
|
export declare function reportNotFound(ctx: StoreContext, path: string, options?: {
|
|
10
23
|
referrer?: string;
|
|
11
24
|
}): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/seo/artifacts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/seo/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC,SAAS,IAAI,MAAM,CAAC;IACpB,UAAU,IAAI,MAAM,CAAC;IACrB,6EAA6E;IAC7E,cAAc,IAAI,MAAM,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,eAAe,CAkBrE;AAYD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9B,IAAI,CA0BN"}
|
package/dist/seo/artifacts.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform artifact URLs + the 404 beacon. The platform renders sitemap.xml,
|
|
3
|
+
* robots.txt, llms.txt and the IndexNow key file per channel; the storefront
|
|
4
|
+
* proxies them on its own origin (see `@sixtyninecommerce/client/next`'s
|
|
5
|
+
* `createSeoArtifactHandler`).
|
|
6
|
+
*/
|
|
1
7
|
export function createArtifactUrls(ctx) {
|
|
2
8
|
const base = `${ctx.pluginsUrl}/seo/artifacts/${encodeURIComponent(ctx.channel.code)}`;
|
|
3
9
|
return {
|
|
@@ -18,8 +24,19 @@ export function createArtifactUrls(ctx) {
|
|
|
18
24
|
};
|
|
19
25
|
}
|
|
20
26
|
const BEACON_TIMEOUT_MS = 2_000;
|
|
27
|
+
/**
|
|
28
|
+
* Per-process dedup set, capped so a long-lived server process being crawled
|
|
29
|
+
* for random URLs can't grow it without bound. Past the cap the set resets:
|
|
30
|
+
* occasional re-reports are fine (the platform aggregates), unbounded memory
|
|
31
|
+
* is not.
|
|
32
|
+
*/
|
|
21
33
|
const MAX_REPORTED_PATHS = 5_000;
|
|
22
34
|
const reportedPaths = new Set();
|
|
35
|
+
/**
|
|
36
|
+
* Fire-and-forget 404 report — call from the storefront's not-found handler
|
|
37
|
+
* so the platform can suggest redirects for dead URLs. Never throws, never
|
|
38
|
+
* blocks rendering; deduped per process/session.
|
|
39
|
+
*/
|
|
23
40
|
export function reportNotFound(ctx, path, options) {
|
|
24
41
|
if (!path.startsWith('/') || path.length > 2000 || reportedPaths.has(path)) {
|
|
25
42
|
return;
|
|
@@ -40,9 +57,11 @@ export function reportNotFound(ctx, path, options) {
|
|
|
40
57
|
signal: AbortSignal.timeout(BEACON_TIMEOUT_MS),
|
|
41
58
|
})
|
|
42
59
|
.catch(() => {
|
|
60
|
+
// beacon — silence is the contract
|
|
43
61
|
});
|
|
44
62
|
}
|
|
45
63
|
catch {
|
|
64
|
+
// even synchronous failures (bad ctx.fetch) must not surface
|
|
46
65
|
}
|
|
47
66
|
}
|
|
48
67
|
//# sourceMappingURL=artifacts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/seo/artifacts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/seo/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,UAAU,kBAAkB,CAAC,GAAiB;IAClD,MAAM,IAAI,GAAG,GAAG,GAAG,CAAC,UAAU,kBAAkB,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IACvF,OAAO;QACL,UAAU,CAAC,SAAkB;YAC3B,OAAO,SAAS;gBACd,CAAC,CAAC,GAAG,IAAI,aAAa,kBAAkB,CAAC,SAAS,CAAC,EAAE;gBACrD,CAAC,CAAC,GAAG,IAAI,cAAc,CAAC;QAC5B,CAAC;QACD,SAAS;YACP,OAAO,GAAG,IAAI,aAAa,CAAC;QAC9B,CAAC;QACD,UAAU;YACR,OAAO,GAAG,IAAI,WAAW,CAAC;QAC5B,CAAC;QACD,cAAc;YACZ,OAAO,GAAG,IAAI,mBAAmB,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAChC;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACjC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;AAExC;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAiB,EACjB,IAAY,EACZ,OAA+B;IAE/B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3E,OAAO;IACT,CAAC;IACD,IAAI,aAAa,CAAC,IAAI,IAAI,kBAAkB,EAAE,CAAC;QAC7C,aAAa,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IACD,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAExB,IAAI,CAAC;QACH,KAAK,GAAG;aACL,KAAK,CAAC,GAAG,GAAG,CAAC,UAAU,wBAAwB,EAAE;YAChD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,cAAc,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE;aAC/B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,IAAI,EAAE,CAAC;YACnE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,iBAAiB,CAAC;SAC/C,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,mCAAmC;QACrC,CAAC,CAAC,CAAC;IACP,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;IAC/D,CAAC;AACH,CAAC"}
|
package/dist/seo/canonical.d.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import type { CollectionForSeo, ProductForSeo, SeoEntityInput } from './types.js';
|
|
2
2
|
import { type UrlStrategyConfig } from './url-builder.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pick the canonical root collection for a product, or null when it has none —
|
|
5
|
+
* in which case the caller uses the flat product path.
|
|
6
|
+
*
|
|
7
|
+
* Selection is delegated to `pickCanonicalRootIndex` so this, the routes
|
|
8
|
+
* manifest in `services/plugins` and the BreadcrumbList in `json-ld.ts` cannot
|
|
9
|
+
* drift apart; the collection id is the tiebreak everywhere, because it is the
|
|
10
|
+
* only value that means the same thing on both sides in every language.
|
|
11
|
+
*
|
|
12
|
+
* Exported for the breadcrumb builder, which used to hand-roll its own sort
|
|
13
|
+
* with no tiebreak: on two canonical roots at equal `position` it kept Shop-API
|
|
14
|
+
* order while this picked the lowest slug, so one page could name one root in
|
|
15
|
+
* its BreadcrumbList and a different one in `<link rel="canonical">` — the very
|
|
16
|
+
* divergence this module exists to end.
|
|
17
|
+
*/
|
|
3
18
|
export declare function pickCanonicalRoot(product: ProductForSeo): CollectionForSeo | null;
|
|
4
19
|
export declare function canonicalFor(cfg: UrlStrategyConfig, entity: SeoEntityInput, locale?: string): string;
|
|
5
20
|
//# sourceMappingURL=canonical.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/seo/canonical.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiB,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,EAA+B,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/seo/canonical.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiB,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,EAA+B,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEvF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,gBAAgB,GAAG,IAAI,CAQjF;AA4ED,wBAAgB,YAAY,CAC1B,GAAG,EAAE,iBAAiB,EACtB,MAAM,EAAE,cAAc,EACtB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAUR"}
|
package/dist/seo/canonical.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { isUserFacingRoot, normalizeProductPathSegment, pickCanonicalRootIndex, } from './product-path.js';
|
|
2
2
|
import { buildUrl, commercePrefixFor } from './url-builder.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pick the canonical root collection for a product, or null when it has none —
|
|
5
|
+
* in which case the caller uses the flat product path.
|
|
6
|
+
*
|
|
7
|
+
* Selection is delegated to `pickCanonicalRootIndex` so this, the routes
|
|
8
|
+
* manifest in `services/plugins` and the BreadcrumbList in `json-ld.ts` cannot
|
|
9
|
+
* drift apart; the collection id is the tiebreak everywhere, because it is the
|
|
10
|
+
* only value that means the same thing on both sides in every language.
|
|
11
|
+
*
|
|
12
|
+
* Exported for the breadcrumb builder, which used to hand-roll its own sort
|
|
13
|
+
* with no tiebreak: on two canonical roots at equal `position` it kept Shop-API
|
|
14
|
+
* order while this picked the lowest slug, so one page could name one root in
|
|
15
|
+
* its BreadcrumbList and a different one in `<link rel="canonical">` — the very
|
|
16
|
+
* divergence this module exists to end.
|
|
17
|
+
*/
|
|
3
18
|
export function pickCanonicalRoot(product) {
|
|
4
19
|
const candidates = product.collections.filter((c) => c.customFields?.isCanonical === true && isUserFacingRoot(c));
|
|
5
20
|
const index = pickCanonicalRootIndex(candidates.map((c) => ({ position: c.position ?? 0, tiebreak: String(c.id) })));
|
|
@@ -16,6 +31,11 @@ function pickTranslatedSlug(translations, fallback, locale, defaultLanguageCode)
|
|
|
16
31
|
}
|
|
17
32
|
function canonicalForProduct(cfg, product, locale) {
|
|
18
33
|
const productSlug = pickTranslatedSlug(product.translations, product.slug, locale, cfg.defaultLanguageCode);
|
|
34
|
+
// The commerce prefix applies to products and collections, never to CMS —
|
|
35
|
+
// the same rule `RoutesService.applyCommercePrefix` applies to the manifest.
|
|
36
|
+
// Without it here, a channel with a prefix got `/store/products/x` in its
|
|
37
|
+
// sitemap and `/products/x` in its <link rel="canonical">: two URLs for one
|
|
38
|
+
// page, one of them a 404 — the divergence this is meant to end.
|
|
19
39
|
const prefix = commercePrefixFor(cfg, locale);
|
|
20
40
|
const root = pickCanonicalRoot(product);
|
|
21
41
|
if (!root) {
|
|
@@ -25,6 +45,10 @@ function canonicalForProduct(cfg, product, locale) {
|
|
|
25
45
|
return buildUrl(cfg, [prefix, rootSlug, productSlug], locale);
|
|
26
46
|
}
|
|
27
47
|
function canonicalForCollection(cfg, collection, locale) {
|
|
48
|
+
// Non-routable roots / subtrees shouldn't emit URLs — callers can detect
|
|
49
|
+
// this by comparing canonical to the empty-path form or by checking
|
|
50
|
+
// `collection.customFields.isRoutable` themselves. We still return a string
|
|
51
|
+
// pointing at the storefront root so `<link rel="canonical">` is never empty.
|
|
28
52
|
if (collection.customFields?.isRoutable === false) {
|
|
29
53
|
return buildUrl(cfg, [], locale);
|
|
30
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/seo/canonical.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAA0B,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/seo/canonical.ts"],"names":[],"mappings":"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"}
|
package/dist/seo/index.js
CHANGED
|
@@ -8,6 +8,8 @@ import { composePerBotDirectives } from './robots.js';
|
|
|
8
8
|
import { buildUrl, readUrlStrategy } from './url-builder.js';
|
|
9
9
|
export function createSeoModule(ctx) {
|
|
10
10
|
const artifacts = createArtifactUrls(ctx);
|
|
11
|
+
// The SAME resolver the media module uses, so an og:image and an <img> src
|
|
12
|
+
// for one asset can never disagree.
|
|
11
13
|
const resolveAssetUrl = createContextAssetUrlResolver(ctx);
|
|
12
14
|
return {
|
|
13
15
|
sitemapUrl: artifacts.sitemapUrl,
|
|
@@ -44,6 +46,10 @@ export function createSeoModule(ctx) {
|
|
|
44
46
|
return metaTagsFor({ cfg, channel: ctx.channel, resolveAssetUrl }, entity);
|
|
45
47
|
},
|
|
46
48
|
robotsDirectiveFor(entity) {
|
|
49
|
+
// Per-bot AI directives (resolvedBotDirectives) are a product-only feature.
|
|
50
|
+
// Product → full per-bot composition. Collection / CMS → no per-bot AI
|
|
51
|
+
// surface, but the page-level index/follow is still derived from the
|
|
52
|
+
// parsed metaRobots so a noindex/nofollow page is reported correctly.
|
|
47
53
|
if (entity.kind === 'product') {
|
|
48
54
|
if (entity.metadata === null) {
|
|
49
55
|
return {
|
package/dist/seo/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE7D,MAAM,UAAU,eAAe,CAAC,GAAiB;IAC/C,MAAM,SAAS,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"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"}
|
package/dist/seo/json-ld.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema.org JSON-LD composers (Product, BreadcrumbList, FAQPage). The
|
|
3
|
+
* Product composer is defensive — required fields are emitted only when
|
|
4
|
+
* available, optional fields are skipped entirely when null rather than
|
|
5
|
+
* emitted as `null` (Google's Rich Results validator rejects `null` values).
|
|
6
|
+
*/
|
|
1
7
|
import type { AssetUrlResolver } from '../media/urls.js';
|
|
2
8
|
import type { Asset } from '../types.js';
|
|
3
9
|
import type { ProductSeoExtras } from './meta-tags.js';
|
|
@@ -5,6 +11,7 @@ import type { BreadcrumbOverrideEntry, ProductMetadata, QAPair } from './metadat
|
|
|
5
11
|
import type { ProductForSeo } from './types.js';
|
|
6
12
|
import type { UrlStrategyConfig } from './url-builder.js';
|
|
7
13
|
export interface ProductJsonLdInput {
|
|
14
|
+
/** Turns stored asset KEYS into absolute URLs; see `createAssetUrlResolver`. */
|
|
8
15
|
resolveAssetUrl: AssetUrlResolver;
|
|
9
16
|
product: ProductForSeo;
|
|
10
17
|
metadata: ProductMetadata | null;
|
|
@@ -29,9 +36,15 @@ export interface PageJsonLdInput {
|
|
|
29
36
|
title: string;
|
|
30
37
|
description: string;
|
|
31
38
|
image: Asset | null;
|
|
39
|
+
/** Turns stored asset KEYS into absolute URLs; see `createAssetUrlResolver`. */
|
|
32
40
|
resolveAssetUrl: AssetUrlResolver;
|
|
33
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* `CollectionPage` JSON-LD for a collection / category landing page. Optional
|
|
44
|
+
* fields are omitted (not emitted as `null`) so Google's validator stays happy.
|
|
45
|
+
*/
|
|
34
46
|
export declare function composeCollectionJsonLd(input: PageJsonLdInput): Record<string, unknown>;
|
|
47
|
+
/** `WebPage` JSON-LD for a CMS content / marketing page. */
|
|
35
48
|
export declare function composeCmsJsonLd(input: PageJsonLdInput): Record<string, unknown>;
|
|
36
49
|
export declare function composeFaqJsonLd(pairs: ReadonlyArray<QAPair>): Record<string, unknown>;
|
|
37
50
|
//# sourceMappingURL=json-ld.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../../src/seo/json-ld.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../../src/seo/json-ld.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAuB1D,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,eAAe,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyDvF;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,iBAAiB,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;CAClD;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkB7F;AAqCD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,gFAAgF;IAChF,eAAe,EAAE,gBAAgB,CAAC;CACnC;AAQD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWvF;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWhF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUtF"}
|