orionplace-svelte 0.6.1 → 0.7.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 +3 -1
- package/package.json +1 -1
- package/runtime/marketplace.d.mts +5 -0
- package/runtime/marketplace.mjs +13 -1
- package/src/project-readme.mjs +8 -0
- package/templates/src/hooks.server.ts +5 -3
- package/templates/src/lib/components/orionplace/blog/BlogArticle.README.md +2 -0
- package/templates/src/lib/components/orionplace/blog/BlogArticle.svelte +239 -70
- package/templates/src/lib/components/orionplace/products/ProductCard.svelte +17 -0
- package/templates/src/lib/components/orionplace/products/ProductGroup.svelte +6 -0
- package/templates/src/lib/composables/useOrionplacePageSeo.svelte.ts +13 -0
- package/templates/src/lib/layouts/StorefrontPageHead.svelte +8 -0
- package/templates/src/lib/orionplace/navigation.svelte.ts +10 -1
- package/templates/src/lib/utils/orionplace/blogArticleHtml.ts +1 -0
- package/templates/src/lib/utils/orionplace/blogProductPlacements.ts +105 -0
- package/templates/src/lib/utils/orionplace/productStructuredData.ts +220 -0
- package/templates/src/routes/+layout.server.ts +4 -0
- package/templates/src/routes/product/[id]/+page.svelte +41 -14
package/README.md
CHANGED
|
@@ -480,7 +480,9 @@ The corresponding `.cfg` is read on every request. Backend URLs must use HTTPS,
|
|
|
480
480
|
end in `/api`, and belong to `*.orionplace.app`. API methods, query strings, bodies,
|
|
481
481
|
authorization and cookies are forwarded. Backend statuses are retained and cookie
|
|
482
482
|
Domain attributes are removed to bind cookies to the storefront. Gateway responses
|
|
483
|
-
use `Cache-Control: no-store
|
|
483
|
+
use `Cache-Control: no-store`, except public blog images and videos: they keep the
|
|
484
|
+
backend's `private, max-age` rule, so the browser does not download them again on
|
|
485
|
+
every page. Network failures return `502`.
|
|
484
486
|
|
|
485
487
|
A changing request (POST, PUT, PATCH, DELETE) from another site is rejected with
|
|
486
488
|
`403`. A request from the page's own host or the storefront domain passes, and the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orionplace-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "SvelteKit 2 storefront for your Orionplace marketplace: setup CLI, server API gateway, typed store and ready-made catalog, cart, checkout and account components in English and Russian, plus an Android app build.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,6 +37,11 @@ export declare function marketplacePublicOrigin(
|
|
|
37
37
|
tenantDomain?: string,
|
|
38
38
|
): string;
|
|
39
39
|
|
|
40
|
+
export declare function marketplaceCacheControl(
|
|
41
|
+
media: boolean,
|
|
42
|
+
upstream: Response,
|
|
43
|
+
): string;
|
|
44
|
+
|
|
40
45
|
export declare function noindexPathPrefixes(value?: string): string[];
|
|
41
46
|
|
|
42
47
|
export declare function marketplaceNoindexPath(
|
package/runtime/marketplace.mjs
CHANGED
|
@@ -41,6 +41,18 @@ const hostnamePattern =
|
|
|
41
41
|
const blogMediaPattern =
|
|
42
42
|
/^\/ps3\/blog\/posts\/(?:images\/\d+|videos\/\d+(?:\/preview)?)$/;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* API answers are never stored. A media file keeps the backend's own browser
|
|
46
|
+
* cache rule when the backend allows it (a published public blog image:
|
|
47
|
+
* "private, max-age=…"); "private" keeps it out of shared caches.
|
|
48
|
+
*/
|
|
49
|
+
export function marketplaceCacheControl(media, upstream) {
|
|
50
|
+
const value = upstream.headers.get('cache-control') ?? '';
|
|
51
|
+
return media && upstream.ok && /\bprivate\b/i.test(value) && /\bmax-age=\d+/i.test(value) && !/no-store|no-cache/i.test(value)
|
|
52
|
+
? value
|
|
53
|
+
: 'no-store';
|
|
54
|
+
}
|
|
55
|
+
|
|
44
56
|
/** @param {string} pathname */
|
|
45
57
|
export function isMarketplaceMediaPath(pathname) {
|
|
46
58
|
return blogMediaPattern.test(pathname);
|
|
@@ -307,7 +319,7 @@ export async function forwardMarketplace(request, configuration = {}) {
|
|
|
307
319
|
: destination.href,
|
|
308
320
|
);
|
|
309
321
|
}
|
|
310
|
-
responseHeaders.set('Cache-Control',
|
|
322
|
+
responseHeaders.set('Cache-Control', marketplaceCacheControl(media, upstream));
|
|
311
323
|
responseHeaders.set('Vary', 'Host, X-Forwarded-Host, X-Front-Domain');
|
|
312
324
|
// fetch decodes compressed bodies: do not reuse upstream Content-Length/Encoding.
|
|
313
325
|
return new Response(upstream.body, {
|
package/src/project-readme.mjs
CHANGED
|
@@ -403,6 +403,14 @@ for example \`ORIONPLACE_NOINDEX_PATHS="/catalog /category /product"\`. Those
|
|
|
403
403
|
pages answer with \`X-Robots-Tag: noindex, follow\` and the sitemap leaves them
|
|
404
404
|
out; the journal and other pages stay indexable. Leave it empty on a live shop.
|
|
405
405
|
|
|
406
|
+
Every product page carries schema.org product data for Google and Yandex: the
|
|
407
|
+
price, the crossed-out old price, stock, photos, brand, seller, rating and the
|
|
408
|
+
return terms the page shows. To include the return terms, set
|
|
409
|
+
\`ORIONPLACE_SHIPPING_COUNTRIES\` in \`.env\` to the countries you ship to, as
|
|
410
|
+
ISO codes separated by spaces, for example
|
|
411
|
+
\`ORIONPLACE_SHIPPING_COUNTRIES="RU BY"\`; without it the return terms are left
|
|
412
|
+
out. The delivery cost is not included: it depends on the buyer's address.
|
|
413
|
+
|
|
406
414
|
This setup does not add analytics.
|
|
407
415
|
|
|
408
416
|
## Android app
|
|
@@ -12,10 +12,12 @@ function escapeAttribute(value: string) {
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Personalized pages are never shared between visitors or storefront domains.
|
|
15
|
-
* The API gateway, robots.txt and the sitemap set their own
|
|
16
|
-
* requests are left alone
|
|
15
|
+
* The API gateway (/api, /ps3 media), robots.txt and the sitemap set their own
|
|
16
|
+
* headers, so those requests are left alone: public blog images keep the
|
|
17
|
+
* backend's browser cache rule.
|
|
17
18
|
*/
|
|
18
19
|
const ownHeaders = ['/robots.txt', '/sitemap.xml'];
|
|
20
|
+
const gatewayPaths = ['/api/', '/ps3/'];
|
|
19
21
|
|
|
20
22
|
export const handle: Handle = async ({ event, resolve }) => {
|
|
21
23
|
const response = await resolve(event, {
|
|
@@ -26,7 +28,7 @@ export const handle: Handle = async ({ event, resolve }) => {
|
|
|
26
28
|
),
|
|
27
29
|
});
|
|
28
30
|
if (
|
|
29
|
-
!event.url.pathname.startsWith(
|
|
31
|
+
!gatewayPaths.some((path) => event.url.pathname.startsWith(path)) &&
|
|
30
32
|
!ownHeaders.includes(event.url.pathname)
|
|
31
33
|
) {
|
|
32
34
|
response.headers.set('Cache-Control', 'private, no-store');
|
|
@@ -8,6 +8,8 @@ Article videos may come as the backend's own paths (`/ps3/...`). In an Android a
|
|
|
8
8
|
|
|
9
9
|
The cover and the images of the text open larger: a click, Enter or Space on one opens `ProductReviewImageViewer` at that image, with the article's other images a step away and each image's caption (its `figcaption`, else its `title`, else its `alt`) under it. The images get `role="button"`, a keyboard stop and an «Open image» name; a zoom-in cursor marks them. Images inside a link, a button or a product placement keep their own action. The helper is `src/lib/utils/orionplace/blogImageViewer.ts`.
|
|
10
10
|
|
|
11
|
+
Products the author places in the text appear at those positions: an empty block with `data-product-id="12"` shows one product card, `data-product-ids="12,15,9"` a row of up to 24 cards. The block keeps the editor's float or centred style, and `data-product-hidden-badges` (`new`, `popular`, `good-deal`) turns card badges off. Products missing from `related_products` are loaded with `products_search` and `filters.id_in`, up to 35 IDs per request, and stored with `store.setProduct()`; a block whose products are not found stays hidden. Article text styles do not reach the cards, and in a narrow article a floated card stands alone in the middle. The helper is `src/lib/utils/orionplace/blogProductPlacements.ts`.
|
|
12
|
+
|
|
11
13
|
Source: `src/lib/components/orionplace/blog/BlogArticle.svelte`.
|
|
12
14
|
|
|
13
15
|
## Inputs
|