@storystick/next 0.0.0-stage → 0.2.0-rc.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/LICENSE +112 -0
- package/PUBLIC-API.md +31 -0
- package/README.md +522 -2
- package/dist/.source-hash +1 -0
- package/dist/cache-tags.d.ts +2 -0
- package/dist/cache-tags.js +12 -0
- package/dist/clean.d.ts +1 -0
- package/dist/clean.js +1 -0
- package/dist/code-version.d.ts +29 -0
- package/dist/code-version.js +48 -0
- package/dist/file.d.ts +1 -0
- package/dist/file.js +1 -0
- package/dist/i18n-seo.d.ts +1 -0
- package/dist/i18n-seo.js +1 -0
- package/dist/image.d.ts +11 -0
- package/dist/image.js +22 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.react-server.d.ts +3 -0
- package/dist/index.react-server.js +12 -0
- package/dist/link.d.ts +10 -0
- package/dist/link.js +8 -0
- package/dist/preview/index.d.ts +29 -0
- package/dist/preview/index.js +24 -0
- package/dist/preview/internal.d.ts +61 -0
- package/dist/preview/internal.js +97 -0
- package/dist/preview/preview-request-identity.d.ts +4 -0
- package/dist/preview/preview-request-identity.js +63 -0
- package/dist/preview/provenance-config.d.ts +42 -0
- package/dist/preview/provenance-config.js +132 -0
- package/dist/preview/provenance-frame-builder.d.ts +6 -0
- package/dist/preview/provenance-frame-builder.js +10 -0
- package/dist/preview/provenance-response.d.ts +5 -0
- package/dist/preview/provenance-response.js +9 -0
- package/dist/preview/provenance-runtime-adapter.d.ts +9 -0
- package/dist/preview/provenance-runtime-adapter.js +42 -0
- package/dist/preview/render-frame-provenance.d.ts +23 -0
- package/dist/preview/render-frame-provenance.js +47 -0
- package/dist/preview/route-authoring.d.ts +3 -0
- package/dist/preview/route-authoring.js +80 -0
- package/dist/preview/route-context.d.ts +3 -0
- package/dist/preview/route-context.js +38 -0
- package/dist/preview/route-disable.d.ts +7 -0
- package/dist/preview/route-disable.js +63 -0
- package/dist/preview/route-document-provenance.d.ts +23 -0
- package/dist/preview/route-document-provenance.js +46 -0
- package/dist/preview/route-errors.d.ts +1 -0
- package/dist/preview/route-errors.js +1 -0
- package/dist/preview/route-handler.d.ts +36 -0
- package/dist/preview/route-handler.js +139 -0
- package/dist/preview/route-initial.d.ts +9 -0
- package/dist/preview/route-initial.js +141 -0
- package/dist/preview/route-provenance-runtime.d.ts +34 -0
- package/dist/preview/route-provenance-runtime.js +90 -0
- package/dist/preview/route-token.d.ts +6 -0
- package/dist/preview/route-token.js +46 -0
- package/dist/preview/server-preview-internals.d.ts +3 -0
- package/dist/preview/server-preview-internals.js +3 -0
- package/dist/preview/slice-locale.d.ts +5 -0
- package/dist/preview/slice-locale.js +15 -0
- package/dist/preview-error-surface.d.ts +7 -0
- package/dist/preview-error-surface.js +24 -0
- package/dist/preview-exit.d.ts +7 -0
- package/dist/preview-exit.js +71 -0
- package/dist/preview-metadata.d.ts +15 -0
- package/dist/preview-metadata.js +13 -0
- package/dist/preview-mode-latch.d.ts +133 -0
- package/dist/preview-mode-latch.js +231 -0
- package/dist/preview-nav-location.d.ts +12 -0
- package/dist/preview-nav-location.js +149 -0
- package/dist/preview-nav.d.ts +94 -0
- package/dist/preview-nav.js +523 -0
- package/dist/preview-refresh-coordinator.d.ts +26 -0
- package/dist/preview-refresh-coordinator.js +93 -0
- package/dist/preview-render-error.d.ts +11 -0
- package/dist/preview-render-error.js +36 -0
- package/dist/preview-render-recovery.d.ts +9 -0
- package/dist/preview-render-recovery.js +42 -0
- package/dist/preview-session-recovery.d.ts +1 -0
- package/dist/preview-session-recovery.js +1 -0
- package/dist/preview-standalone-host.d.ts +3 -0
- package/dist/preview-standalone-host.js +55 -0
- package/dist/preview-text.d.ts +2 -0
- package/dist/preview-text.js +1 -0
- package/dist/preview-view-bootstrap.d.ts +5 -0
- package/dist/preview-view-bootstrap.js +13 -0
- package/dist/public-delivery.d.ts +6 -0
- package/dist/public-delivery.js +7 -0
- package/dist/query-fetch-options.d.ts +7 -0
- package/dist/query-fetch-options.js +193 -0
- package/dist/query.d.ts +2 -0
- package/dist/query.js +1 -0
- package/dist/rendering.d.ts +33 -0
- package/dist/rendering.js +42 -0
- package/dist/revalidate.d.ts +12 -0
- package/dist/revalidate.js +33 -0
- package/dist/rich-text.d.ts +2 -0
- package/dist/rich-text.js +1 -0
- package/dist/server-runtime.d.ts +208 -0
- package/dist/server-runtime.js +1584 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +6 -0
- package/dist/slice-zone.d.ts +2 -0
- package/dist/slice-zone.js +1 -0
- package/dist/storystick-component-types.d.ts +26 -0
- package/dist/storystick-component-types.js +1 -0
- package/dist/storystick-component.d.ts +10 -0
- package/dist/storystick-component.js +45 -0
- package/dist/storystick-error-recovery.d.ts +12 -0
- package/dist/storystick-error-recovery.js +11 -0
- package/dist/storystick-preview-runtime.d.ts +30 -0
- package/dist/storystick-preview-runtime.js +561 -0
- package/dist/storystick.d.ts +24 -0
- package/dist/storystick.js +23 -0
- package/dist/testing.d.ts +9 -0
- package/dist/testing.js +40 -0
- package/dist/video.d.ts +1 -0
- package/dist/video.js +1 -0
- package/package.json +128 -3
- package/recipes/README.md +91 -0
- package/recipes/resource-mirror.ts +49 -0
package/dist/video.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { StorystickVideo, resolveVideo, } from '@storystick/react/video';
|
package/package.json
CHANGED
|
@@ -1,6 +1,131 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storystick/next",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0-rc.0",
|
|
4
|
+
"license": "FSL-1.1-MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"react-server": "./dist/index.react-server.js",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./preview-text": {
|
|
15
|
+
"types": "./dist/preview-text.d.ts",
|
|
16
|
+
"import": "./dist/preview-text.js"
|
|
17
|
+
},
|
|
18
|
+
"./image": {
|
|
19
|
+
"types": "./dist/image.d.ts",
|
|
20
|
+
"import": "./dist/image.js"
|
|
21
|
+
},
|
|
22
|
+
"./file": {
|
|
23
|
+
"types": "./dist/file.d.ts",
|
|
24
|
+
"import": "./dist/file.js"
|
|
25
|
+
},
|
|
26
|
+
"./video": {
|
|
27
|
+
"types": "./dist/video.d.ts",
|
|
28
|
+
"import": "./dist/video.js",
|
|
29
|
+
"default": "./dist/video.js"
|
|
30
|
+
},
|
|
31
|
+
"./link": {
|
|
32
|
+
"types": "./dist/link.d.ts",
|
|
33
|
+
"import": "./dist/link.js"
|
|
34
|
+
},
|
|
35
|
+
"./query": {
|
|
36
|
+
"types": "./dist/query.d.ts",
|
|
37
|
+
"import": "./dist/query.js"
|
|
38
|
+
},
|
|
39
|
+
"./rich-text": {
|
|
40
|
+
"types": "./dist/rich-text.d.ts",
|
|
41
|
+
"import": "./dist/rich-text.js"
|
|
42
|
+
},
|
|
43
|
+
"./slice-zone": {
|
|
44
|
+
"types": "./dist/slice-zone.d.ts",
|
|
45
|
+
"import": "./dist/slice-zone.js"
|
|
46
|
+
},
|
|
47
|
+
"./revalidate": {
|
|
48
|
+
"types": "./dist/revalidate.d.ts",
|
|
49
|
+
"import": "./dist/revalidate.js"
|
|
50
|
+
},
|
|
51
|
+
"./preview-nav": {
|
|
52
|
+
"types": "./dist/preview-nav.d.ts",
|
|
53
|
+
"import": "./dist/preview-nav.js"
|
|
54
|
+
},
|
|
55
|
+
"./preview-nav-location": {
|
|
56
|
+
"types": "./dist/preview-nav-location.d.ts",
|
|
57
|
+
"import": "./dist/preview-nav-location.js"
|
|
58
|
+
},
|
|
59
|
+
"./preview": {
|
|
60
|
+
"types": "./dist/preview/index.d.ts",
|
|
61
|
+
"import": "./dist/preview/index.js"
|
|
62
|
+
},
|
|
63
|
+
"./testing": {
|
|
64
|
+
"types": "./dist/testing.d.ts",
|
|
65
|
+
"import": "./dist/testing.js"
|
|
66
|
+
},
|
|
67
|
+
"./server": {
|
|
68
|
+
"types": "./dist/server.d.ts",
|
|
69
|
+
"import": "./dist/server.js"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"files": [
|
|
73
|
+
"dist",
|
|
74
|
+
"recipes",
|
|
75
|
+
"LICENSE",
|
|
76
|
+
"README.md",
|
|
77
|
+
"PUBLIC-API.md"
|
|
78
|
+
],
|
|
79
|
+
"publishConfig": {
|
|
80
|
+
"access": "public",
|
|
81
|
+
"provenance": false,
|
|
82
|
+
"tag": "beta"
|
|
83
|
+
},
|
|
84
|
+
"peerDependencies": {
|
|
85
|
+
"next": "^15.5.28",
|
|
86
|
+
"react": "^19.2.8",
|
|
87
|
+
"react-dom": "^19.2.8"
|
|
88
|
+
},
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"server-only": "^0.0.1",
|
|
91
|
+
"@storystick/media": "0.2.0-rc.0",
|
|
92
|
+
"@storystick/client": "0.2.0-rc.0",
|
|
93
|
+
"@storystick/types": "0.1.0-rc.0",
|
|
94
|
+
"@storystick/react": "0.2.0-rc.0",
|
|
95
|
+
"@storystick/preview": "0.2.0-rc.0"
|
|
96
|
+
},
|
|
97
|
+
"devDependencies": {
|
|
98
|
+
"@testing-library/react": "^16.3.2",
|
|
99
|
+
"@types/node": "^22.13.10",
|
|
100
|
+
"@types/react": "^19.2.18",
|
|
101
|
+
"@types/react-dom": "^19.2.5",
|
|
102
|
+
"fast-check": "^4.7.0",
|
|
103
|
+
"jsdom": "^29.0.2",
|
|
104
|
+
"next": "15.5.28",
|
|
105
|
+
"react": "^19.2.8",
|
|
106
|
+
"react-dom": "^19.2.8",
|
|
107
|
+
"typescript": "^5.8.2",
|
|
108
|
+
"vitest": "^3.1.1",
|
|
109
|
+
"sharp": "0.35.5"
|
|
110
|
+
},
|
|
111
|
+
"engines": {
|
|
112
|
+
"node": ">=24.19.0 <25"
|
|
113
|
+
},
|
|
114
|
+
"repository": {
|
|
115
|
+
"type": "git",
|
|
116
|
+
"url": "git+https://github.com/withstorystick/storystick.git",
|
|
117
|
+
"directory": "packages/next"
|
|
118
|
+
},
|
|
119
|
+
"homepage": "https://storystick.app",
|
|
120
|
+
"bugs": {
|
|
121
|
+
"url": "https://storystick.app"
|
|
122
|
+
},
|
|
123
|
+
"scripts": {
|
|
124
|
+
"build": "node ../../scripts/package-dist.mjs clean && tsc && node ../../scripts/package-dist.mjs seal",
|
|
125
|
+
"test": "vitest run",
|
|
126
|
+
"test:types": "tsc -p tsconfig.type-tests.json --noEmit",
|
|
127
|
+
"test:dist-fresh": "node ../../scripts/package-dist.mjs assert",
|
|
128
|
+
"test:watch": "vitest",
|
|
129
|
+
"test:recipes": "tsc -p tsconfig.recipes.json --noEmit"
|
|
130
|
+
}
|
|
6
131
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Published language routes and explicit resource mirrors
|
|
2
|
+
|
|
3
|
+
These recipes use the generated query schema and the C4a publication selector.
|
|
4
|
+
They do not implement a second translation selector in application code.
|
|
5
|
+
|
|
6
|
+
## Prefix routing (one or several languages)
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
const site = createSite({ definition, siteUrl: 'https://example.com' })
|
|
10
|
+
const route = await site.resolvePage(props)
|
|
11
|
+
const languages = site.alternates(route)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The project owns enabled locales and prefix settings. Render the language switch
|
|
15
|
+
from `languages`: EN `/resources/security` may correspond to FR
|
|
16
|
+
`/fr/ressources/securite`. Do not replace a prefix on the current pathname.
|
|
17
|
+
Unpublished or removed languages are absent. `site.params()`, `site.metadata()`
|
|
18
|
+
and `site.sitemap()` use actual publications. Historical redirects remain
|
|
19
|
+
server-owned, including translated parents and renamed segments.
|
|
20
|
+
|
|
21
|
+
## One domain per language
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
const site = createSite({
|
|
25
|
+
definition,
|
|
26
|
+
siteUrl: 'https://example.fr',
|
|
27
|
+
domainLocale: 'fr',
|
|
28
|
+
publicOrigins: {
|
|
29
|
+
en: 'https://example.com',
|
|
30
|
+
fr: 'https://example.fr',
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Deploy the same definition with `domainLocale: 'en'` on the English origin.
|
|
36
|
+
`domainLocale` explicitly binds an unprefixed pathname to a language; it does
|
|
37
|
+
not change the project default or publication availability. Origins must be
|
|
38
|
+
distinct HTTP(S) origins without paths, credentials, queries or fragments.
|
|
39
|
+
Configure an origin for every enabled language. An incomplete domain map fails
|
|
40
|
+
explicitly; it never points a missing language at the current host.
|
|
41
|
+
|
|
42
|
+
The French deployment resolves `/ressources/securite` in FR. Its static params
|
|
43
|
+
and sitemap contain French publications only; hreflang includes the real English
|
|
44
|
+
URL. Compound links and rich-text marks use the selected destination publication
|
|
45
|
+
and carry this plain configuration across JSON/RSC boundaries. `site.alternates`
|
|
46
|
+
and `site.metadata` use the same address mapping. Historical redirects are
|
|
47
|
+
mapped to the destination language's origin.
|
|
48
|
+
|
|
49
|
+
No implicit Host lookup or unconditional Next dynamic API is added. For a custom
|
|
50
|
+
multi-host router, select a configured deployment explicitly outside this helper;
|
|
51
|
+
do not pass an unchecked Host header as an origin. Domain/DNS administration and
|
|
52
|
+
the Studio Preview origin configuration are separate deployment work. Existing
|
|
53
|
+
project pathname collision constraints still apply.
|
|
54
|
+
|
|
55
|
+
## Opt-in resource mirror: French UI, English publication
|
|
56
|
+
|
|
57
|
+
`resource-mirror.ts` is a compiled, tested customer recipe. Replace its synthetic
|
|
58
|
+
`ResourceSchema` with the generated resource story for your site.
|
|
59
|
+
|
|
60
|
+
1. Load the resource list through `resourceCollection(client, 'fr')`. The server
|
|
61
|
+
selects FR when published, otherwise its configured publication fallback,
|
|
62
|
+
once per identity **before** filtering, sorting or pagination. Use
|
|
63
|
+
`mirrorHref(row.resolvedPathname, 'fr', routing)` only on this opted-in mirror
|
|
64
|
+
surface. Ordinary document links keep linking to the actual publication.
|
|
65
|
+
2. In the mirror page, call `resolveResourceMirror(client, site.resolvePage,
|
|
66
|
+
{ uiLocale: 'fr', pathname })`, with the **canonical resource path** (strip
|
|
67
|
+
the application's language prefix using `resolveLocalePathname`, if used).
|
|
68
|
+
Handle null as not-found and the returned route's redirect/not-found outcome
|
|
69
|
+
with the normal Next handlers. Cache this loader per render when sharing it
|
|
70
|
+
between the page and `generateMetadata`.
|
|
71
|
+
3. Render the returned `document`, preserving its link sidecars selected for FR
|
|
72
|
+
navigation. Set the interface container's `lang` to `uiLocale` and the resource
|
|
73
|
+
body's `lang` to `contentLocale`. An EN fallback body remains English.
|
|
74
|
+
4. Call `site.metadata(result.route)` for the actual publication's canonical,
|
|
75
|
+
hreflang and robots. An EN fallback yields the EN canonical and no invented
|
|
76
|
+
FR alternate. The synthetic mirror is not added to `site.sitemap()`.
|
|
77
|
+
5. Publish FR: the same collection now selects the FR publication instead of EN.
|
|
78
|
+
Its actual translated path and canonical replace the fallback entry. If the
|
|
79
|
+
new FR slug differs, the old synthetic mirror URL returns not-found; no
|
|
80
|
+
translation identity is inferred from a matching old slug. Add a deliberate
|
|
81
|
+
application redirect only if that is part of the site's URL policy.
|
|
82
|
+
|
|
83
|
+
This recipe is for public reads. It rejects incomplete/non-public selection and
|
|
84
|
+
ambiguous mirror paths. A service error propagates; it never permits switching
|
|
85
|
+
to another language or exposing a draft. The metadata route read also verifies
|
|
86
|
+
document, language and snapshot identity when available. The returned document
|
|
87
|
+
is the selected Query V2 result, not a re-read of its body in a different locale.
|
|
88
|
+
Use ordinary Preview routes for Studio editing.
|
|
89
|
+
|
|
90
|
+
Run `pnpm --filter @storystick/next exec tsc -p tsconfig.recipes.json --noEmit`
|
|
91
|
+
and the `resource-mirror.test.ts` tests to verify the recipe without a live site.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Client, QueryFieldType, QuerySchemaDefinition, QueryStoryType, ResolvedRoute } from '@storystick/client'
|
|
2
|
+
import { publicHrefForLocale, type LocaleRoutingSettings } from '@storystick/client/locale-routing'
|
|
3
|
+
|
|
4
|
+
/** Synthetic generated schema shape. Replace it with your generated resource story. */
|
|
5
|
+
export type ResourceSchema = QuerySchemaDefinition<{
|
|
6
|
+
resource: QueryStoryType<{ title: string }, { title: QueryFieldType<string, 'is', true> }, false, false, true>
|
|
7
|
+
}>
|
|
8
|
+
|
|
9
|
+
export function resourceCollection(client: Client<ResourceSchema>, uiLocale: string) {
|
|
10
|
+
// The server chooses ONE publication per identity BEFORE filtering or paging.
|
|
11
|
+
return client.query('resource').selectAll().locale(uiLocale).publicationFallback('configured')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Opt-in mirror address. This is an app route, never an hreflang publication. */
|
|
15
|
+
export function mirrorHref(pathname: string, uiLocale: string, routing: LocaleRoutingSettings): string {
|
|
16
|
+
return publicHrefForLocale(pathname, uiLocale, routing)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function resolveResourceMirror(
|
|
20
|
+
client: Client<ResourceSchema>,
|
|
21
|
+
resolvePublication: (input: { pathname: string; locale: string }) => Promise<ResolvedRoute>,
|
|
22
|
+
input: { pathname: string; uiLocale: string },
|
|
23
|
+
) {
|
|
24
|
+
const result = await resourceCollection(client, input.uiLocale)
|
|
25
|
+
.where((_, { route }) => route.pathname.is(input.pathname))
|
|
26
|
+
.page({ first: 2 }).execute()
|
|
27
|
+
if (result.exactness !== 'exact' || result.meta.scope.kind !== 'activePublication') {
|
|
28
|
+
throw new Error('Resource mirrors require an exact public publication read.')
|
|
29
|
+
}
|
|
30
|
+
if (result.data.length === 0) return null
|
|
31
|
+
if (result.data.length !== 1) throw new Error('Several resource identities own this mirror path.')
|
|
32
|
+
const selected = result.data[0]!
|
|
33
|
+
const contentLocale = selected._locale?.code
|
|
34
|
+
if (!contentLocale || selected.resolvedPathname === undefined) throw new Error('Missing publication address.')
|
|
35
|
+
|
|
36
|
+
// Reuse the publication's own route facts and SEO; never forge a French route.
|
|
37
|
+
// A failure propagates. It does not authorize another language or a draft.
|
|
38
|
+
const route = await resolvePublication({ pathname: selected.resolvedPathname, locale: contentLocale })
|
|
39
|
+
if (route.type !== 'document') return { uiLocale: input.uiLocale, contentLocale, route }
|
|
40
|
+
if (route.document.documentId !== selected.documentId || route.localeContext.locale !== contentLocale ||
|
|
41
|
+
(route.document.snapshotId !== undefined && selected.snapshotId !== undefined && route.document.snapshotId !== selected.snapshotId)) {
|
|
42
|
+
throw new Error('The resource publication changed during route resolution.')
|
|
43
|
+
}
|
|
44
|
+
// Render the selection made for the UI locale: its C4b link sidecars retain
|
|
45
|
+
// French navigation even when the resource body is an English publication.
|
|
46
|
+
return { uiLocale: input.uiLocale, contentLocale, document: selected,
|
|
47
|
+
reason: contentLocale === input.uiLocale ? 'requested' as const : 'fallback' as const,
|
|
48
|
+
route }
|
|
49
|
+
}
|