@wix/origami-site 0.1.25 → 0.1.26
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/origami-site",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Runs an exported Wix origami site: file-based routing, Wix dynamic pages, popups and build checks. Use with @wix/origami-site-astro or @wix/origami-site-express.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@wix/origami-transforms": "0.1.15",
|
|
52
52
|
"@babel/parser": "^7.25.0",
|
|
53
53
|
"@wix/system-core-components": "^1.3.10",
|
|
54
|
-
"@wix/origami-services": "1.
|
|
54
|
+
"@wix/origami-services": "1.1.0",
|
|
55
55
|
"@wix/services-manager-react": "^1.0.8"
|
|
56
56
|
},
|
|
57
57
|
"exports": {
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"optional": true
|
|
94
94
|
}
|
|
95
95
|
},
|
|
96
|
-
"falconPackageHash": "
|
|
96
|
+
"falconPackageHash": "246a4b184a70a57f10be175d35c87676a58576eb90d0f213c8dac49f"
|
|
97
97
|
}
|
package/src/browser/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export type MountPageOptions = {
|
|
|
7
7
|
popups: Record<string, () => Promise<unknown>>
|
|
8
8
|
seoUriByPageId: Record<string, string>
|
|
9
9
|
beforeMount: () => Promise<unknown>
|
|
10
|
+
/** The site's meta site id, from `VITE_WIX_METASITE_ID`. Services get no site identity without it. */
|
|
11
|
+
siteId?: string
|
|
10
12
|
}
|
|
11
13
|
export function mountPage(element: Element | null, options: MountPageOptions): Promise<() => void>
|
|
12
14
|
/** Cached per page load. Warns once and returns undefined if the block is missing.
|
package/src/browser/index.js
CHANGED
|
@@ -36,7 +36,7 @@ export function readPageData() {
|
|
|
36
36
|
* @param {import('./index.js').MountPageOptions} options
|
|
37
37
|
* @returns {Promise<() => void>}
|
|
38
38
|
*/
|
|
39
|
-
export async function mountPage(element, { pages, beforeMount }) {
|
|
39
|
+
export async function mountPage(element, { pages, beforeMount, siteId }) {
|
|
40
40
|
if (!element) throw new Error('Cannot mount page: root element is missing')
|
|
41
41
|
const data = readPageData()
|
|
42
42
|
const pageKey = data?.page
|
|
@@ -54,7 +54,10 @@ export async function mountPage(element, { pages, beforeMount }) {
|
|
|
54
54
|
}
|
|
55
55
|
// Loading the page registers its globals and own DM configs before services are created.
|
|
56
56
|
const { default: Page } = await loadPage()
|
|
57
|
-
const map = servicesMap({
|
|
57
|
+
const map = servicesMap({
|
|
58
|
+
servicesConfigs: registeredServicesConfigs(), requestConfigs: data?.services ?? {}, url: location.href, siteId,
|
|
59
|
+
userAgent: navigator.userAgent, reducedMotion: globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches,
|
|
60
|
+
})
|
|
58
61
|
sealServicesConfigs()
|
|
59
62
|
const root = createRoot(element)
|
|
60
63
|
// Stage 3: PopupHost belongs inside WixServices so popups share page services.
|
|
@@ -9,6 +9,7 @@ import { normalizeRequestPath } from './urlPath.js'
|
|
|
9
9
|
import { canBePagePath } from './canBePagePath.js'
|
|
10
10
|
import { getAccessToken, runInRequestContext } from './context.js'
|
|
11
11
|
import { errorPage } from './errorPage.js'
|
|
12
|
+
import { pageServicesConfigs } from './pageServicesConfigs.js'
|
|
12
13
|
|
|
13
14
|
/** @type {import('../index.js').AccessSource} */
|
|
14
15
|
export const noAccessRules = { async load() { return new Map() } }
|
|
@@ -77,14 +78,20 @@ export async function createSite(options) {
|
|
|
77
78
|
if (response) return { kind: /** @type {const} */ ('response'), response }
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
|
-
/** @param {
|
|
81
|
+
/** @param {import('@wix/origami-types').SiteRouteTable} current @param {import('./pageServicesConfigs.js').ServedPage} served @param {200 | 404} status
|
|
81
82
|
* @param {import('../index.js').PageData['route']} routeData @param {Record<string, unknown>} services @param {HeadersInit} [headers] */
|
|
82
|
-
async function pageResolution(
|
|
83
|
+
async function pageResolution(current, served, status, routeData, services = {}, headers = {}) {
|
|
84
|
+
/** @type {{ key: string, title: string, itemPath?: string, pageId?: string }} */
|
|
85
|
+
const route = served.kind === 'router' ? served.rolePage : served.route
|
|
83
86
|
const page = { key: route.key, title: route.title, ...(route.itemPath === undefined ? {} : { itemPath: route.itemPath }) }
|
|
84
|
-
// Identity and dynamic-route configs use different services; merge per service if server layers ever overlap.
|
|
85
87
|
const identity = wix.siteId ? { '@wix/viewer-service-environment': { metaSiteId: wix.siteId } } : {}
|
|
88
|
+
// Identity and page configs both set environment fields, so layers merge per service.
|
|
89
|
+
/** @type {Record<string, object>} */
|
|
90
|
+
const configs = {}
|
|
91
|
+
for (const layer of [identity, pageServicesConfigs(current, served), services])
|
|
92
|
+
for (const [key, config] of Object.entries(layer)) configs[key] = { ...configs[key], ...config }
|
|
86
93
|
return {
|
|
87
|
-
kind: /** @type {const} */ ('page'), status, page, data: { page: page.key, route: routeData, services:
|
|
94
|
+
kind: /** @type {const} */ ('page'), status, page, data: { page: page.key, route: routeData, services: configs }, headers: new Headers(headers),
|
|
88
95
|
embeds: embeds ? await embeds.forPage(route.pageId) : noEmbeds,
|
|
89
96
|
}
|
|
90
97
|
}
|
|
@@ -107,7 +114,7 @@ export async function createSite(options) {
|
|
|
107
114
|
const rolePage = answer.kind === 'page' ? pickRolePage(match.route, answer.page) : null
|
|
108
115
|
if (answer.kind === 'page' && !rolePage)
|
|
109
116
|
logger.warn(`The router for /${match.route.prefix} answered page "${answer.page}", which no role page in route.json matches.`)
|
|
110
|
-
if (answer.kind !== 'page' || !rolePage) return pageResolution(current.notFound, 404, { kind: 'notFound', url: path }, {}, noStore)
|
|
117
|
+
if (answer.kind !== 'page' || !rolePage) return pageResolution(current, { kind: 'notFound', route: current.notFound }, 404, { kind: 'notFound', url: path }, {}, noStore)
|
|
111
118
|
const denied = await checkAccess(rolePage, request, context)
|
|
112
119
|
if (denied) {
|
|
113
120
|
// A login redirect is per visitor too. Copy into new headers: Response.redirect()'s are immutable.
|
|
@@ -116,8 +123,10 @@ export async function createSite(options) {
|
|
|
116
123
|
const { status, statusText, body } = denied.response
|
|
117
124
|
return { kind: /** @type {const} */ ('response'), response: new Response(body, { status, statusText, headers }) }
|
|
118
125
|
}
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
const dynamicRoute = { dynamicRouteData: { pageData: answer.data, publicData: answer.publicData } }
|
|
127
|
+
return pageResolution(current, { kind: 'router', rolePage }, 200, { kind: 'router', url: path, role: rolePage.role }, {
|
|
128
|
+
'@wix/viewer-service-dynamic-route': dynamicRoute,
|
|
129
|
+
'@wix/site-service-dynamic-route': dynamicRoute,
|
|
121
130
|
}, noStore)
|
|
122
131
|
}
|
|
123
132
|
return {
|
|
@@ -151,9 +160,9 @@ export async function createSite(options) {
|
|
|
151
160
|
if (match.kind === 'page') {
|
|
152
161
|
const denied = await checkAccess(match.route, request, context)
|
|
153
162
|
if (denied) return denied
|
|
154
|
-
return pageResolution(match.route, 200, { kind: 'page', url: /** @type {string} */ (path) })
|
|
163
|
+
return pageResolution(current, { kind: 'page', route: match.route }, 200, { kind: 'page', url: /** @type {string} */ (path) })
|
|
155
164
|
}
|
|
156
|
-
return pageResolution(current.notFound, 404, { kind: 'notFound', url: path ?? url.pathname })
|
|
165
|
+
return pageResolution(current, { kind: 'notFound', route: current.notFound }, 404, { kind: 'notFound', url: path ?? url.pathname })
|
|
157
166
|
})
|
|
158
167
|
} catch (error) { return errorPage(error, 500, mode, logger) }
|
|
159
168
|
},
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Services know pages by slug, not by Wix page id: a page's last URL segment, a role page's
|
|
2
|
+
// slug, a popup's seoUri. The home page's URL is `/`, so it is `home`.
|
|
3
|
+
const HOME = 'home'
|
|
4
|
+
|
|
5
|
+
/** @param {import('@wix/origami-types').PageRoute} route */
|
|
6
|
+
const pageSlug = route => route.url === '/' ? HOME : route.url.slice(route.url.lastIndexOf('/') + 1)
|
|
7
|
+
|
|
8
|
+
/** @typedef {{ title: string, path: string, popup: boolean, parentPageId?: string }} SitePage */
|
|
9
|
+
|
|
10
|
+
/** @param {import('@wix/origami-types').SiteRouteTable} table */
|
|
11
|
+
function sitePages(table) {
|
|
12
|
+
const slugByUrl = new Map(table.pages.map(route => [route.url, pageSlug(route)]))
|
|
13
|
+
/** @type {Record<string, SitePage>} */
|
|
14
|
+
const pages = {}
|
|
15
|
+
for (const route of table.pages) {
|
|
16
|
+
const parentPageId = slugByUrl.get(route.url.slice(0, route.url.lastIndexOf('/')))
|
|
17
|
+
pages[pageSlug(route)] = { title: route.title, path: route.url.slice(1), popup: false, ...(parentPageId ? { parentPageId } : {}) }
|
|
18
|
+
}
|
|
19
|
+
for (const router of table.routers)
|
|
20
|
+
for (const rolePage of Object.values(router.rolePages)) pages[rolePage.slug] = { title: rolePage.title, path: router.prefix, popup: false }
|
|
21
|
+
for (const popup of table.popups) pages[popup.seoUri] = { title: popup.title, path: popup.seoUri, popup: true }
|
|
22
|
+
return pages
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The page being served: a page route, a router's role page, or the 404 page.
|
|
26
|
+
* @typedef {{ kind: 'page', route: import('@wix/origami-types').PageRoute }
|
|
27
|
+
* | { kind: 'router', rolePage: import('@wix/origami-types').RolePage }
|
|
28
|
+
* | { kind: 'notFound', route: import('@wix/origami-types').SiteNotFoundRoute }} ServedPage */
|
|
29
|
+
|
|
30
|
+
/** @param {ServedPage} served @returns {[string, string]} its slug and title */
|
|
31
|
+
const servedPage = served => served.kind === 'page' ? [pageSlug(served.route), served.route.title]
|
|
32
|
+
: served.kind === 'router' ? [served.rolePage.slug, served.rolePage.title]
|
|
33
|
+
: [served.route.key.slice(served.route.key.lastIndexOf('/') + 1), served.route.title]
|
|
34
|
+
|
|
35
|
+
/** Configs every page gets from the route table: the site's pages, the page being served and the routers.
|
|
36
|
+
* @param {import('@wix/origami-types').SiteRouteTable} table @param {ServedPage} served @returns {Record<string, object>} */
|
|
37
|
+
export function pageServicesConfigs(table, served) {
|
|
38
|
+
const pages = sitePages(table)
|
|
39
|
+
const [currentPageId, title] = servedPage(served)
|
|
40
|
+
const home = pages[HOME]
|
|
41
|
+
const appDefinitionIdBySlug = new Map(table.routers.flatMap(router =>
|
|
42
|
+
Object.values(router.rolePages).map(rolePage => [rolePage.slug, router.config.appDefinitionId])))
|
|
43
|
+
return {
|
|
44
|
+
'@wix/site-service-pages': {
|
|
45
|
+
pages,
|
|
46
|
+
...(home ? { mainPage: { id: HOME, ...home } } : {}),
|
|
47
|
+
currentPage: { id: currentPageId, ...(pages[currentPageId] ?? { title, path: '', popup: false }) },
|
|
48
|
+
},
|
|
49
|
+
...(home ? { '@wix/viewer-service-environment': { mainPageId: HOME } } : {}),
|
|
50
|
+
'@wix/viewer-service-pages': {
|
|
51
|
+
pages: Object.fromEntries(Object.entries(pages).map(([id, { popup: _, ...page }]) => [id, page])),
|
|
52
|
+
currentPageId,
|
|
53
|
+
...(home ? { mainPageId: HOME } : {}),
|
|
54
|
+
},
|
|
55
|
+
'@wix/site-service-url': {
|
|
56
|
+
// As thunderbolt: popups aren't app sections, and a section's URL is `/` and its slug.
|
|
57
|
+
pages: Object.entries(pages).filter(([, page]) => !page.popup).map(([id]) => ({
|
|
58
|
+
id, url: `/${id}`, ...(appDefinitionIdBySlug.has(id) ? { appDefinitionId: appDefinitionIdBySlug.get(id) } : {}),
|
|
59
|
+
})),
|
|
60
|
+
pageIdToPrefix: Object.fromEntries(table.routers.flatMap(router =>
|
|
61
|
+
Object.values(router.rolePages).map(rolePage => [rolePage.slug, router.prefix]))),
|
|
62
|
+
},
|
|
63
|
+
'@wix/site-service-renderer-configuration': {
|
|
64
|
+
routersMap: Object.fromEntries(table.routers.map(router => [router.prefix, {
|
|
65
|
+
prefix: router.prefix, appDefinitionId: router.config.appDefinitionId, extensionId: router.config.extensionId,
|
|
66
|
+
}])),
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
}
|