@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.
Files changed (121) hide show
  1. package/LICENSE +112 -0
  2. package/PUBLIC-API.md +31 -0
  3. package/README.md +522 -2
  4. package/dist/.source-hash +1 -0
  5. package/dist/cache-tags.d.ts +2 -0
  6. package/dist/cache-tags.js +12 -0
  7. package/dist/clean.d.ts +1 -0
  8. package/dist/clean.js +1 -0
  9. package/dist/code-version.d.ts +29 -0
  10. package/dist/code-version.js +48 -0
  11. package/dist/file.d.ts +1 -0
  12. package/dist/file.js +1 -0
  13. package/dist/i18n-seo.d.ts +1 -0
  14. package/dist/i18n-seo.js +1 -0
  15. package/dist/image.d.ts +11 -0
  16. package/dist/image.js +22 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +3 -0
  19. package/dist/index.react-server.d.ts +3 -0
  20. package/dist/index.react-server.js +12 -0
  21. package/dist/link.d.ts +10 -0
  22. package/dist/link.js +8 -0
  23. package/dist/preview/index.d.ts +29 -0
  24. package/dist/preview/index.js +24 -0
  25. package/dist/preview/internal.d.ts +61 -0
  26. package/dist/preview/internal.js +97 -0
  27. package/dist/preview/preview-request-identity.d.ts +4 -0
  28. package/dist/preview/preview-request-identity.js +63 -0
  29. package/dist/preview/provenance-config.d.ts +42 -0
  30. package/dist/preview/provenance-config.js +132 -0
  31. package/dist/preview/provenance-frame-builder.d.ts +6 -0
  32. package/dist/preview/provenance-frame-builder.js +10 -0
  33. package/dist/preview/provenance-response.d.ts +5 -0
  34. package/dist/preview/provenance-response.js +9 -0
  35. package/dist/preview/provenance-runtime-adapter.d.ts +9 -0
  36. package/dist/preview/provenance-runtime-adapter.js +42 -0
  37. package/dist/preview/render-frame-provenance.d.ts +23 -0
  38. package/dist/preview/render-frame-provenance.js +47 -0
  39. package/dist/preview/route-authoring.d.ts +3 -0
  40. package/dist/preview/route-authoring.js +80 -0
  41. package/dist/preview/route-context.d.ts +3 -0
  42. package/dist/preview/route-context.js +38 -0
  43. package/dist/preview/route-disable.d.ts +7 -0
  44. package/dist/preview/route-disable.js +63 -0
  45. package/dist/preview/route-document-provenance.d.ts +23 -0
  46. package/dist/preview/route-document-provenance.js +46 -0
  47. package/dist/preview/route-errors.d.ts +1 -0
  48. package/dist/preview/route-errors.js +1 -0
  49. package/dist/preview/route-handler.d.ts +36 -0
  50. package/dist/preview/route-handler.js +139 -0
  51. package/dist/preview/route-initial.d.ts +9 -0
  52. package/dist/preview/route-initial.js +141 -0
  53. package/dist/preview/route-provenance-runtime.d.ts +34 -0
  54. package/dist/preview/route-provenance-runtime.js +90 -0
  55. package/dist/preview/route-token.d.ts +6 -0
  56. package/dist/preview/route-token.js +46 -0
  57. package/dist/preview/server-preview-internals.d.ts +3 -0
  58. package/dist/preview/server-preview-internals.js +3 -0
  59. package/dist/preview/slice-locale.d.ts +5 -0
  60. package/dist/preview/slice-locale.js +15 -0
  61. package/dist/preview-error-surface.d.ts +7 -0
  62. package/dist/preview-error-surface.js +24 -0
  63. package/dist/preview-exit.d.ts +7 -0
  64. package/dist/preview-exit.js +71 -0
  65. package/dist/preview-metadata.d.ts +15 -0
  66. package/dist/preview-metadata.js +13 -0
  67. package/dist/preview-mode-latch.d.ts +133 -0
  68. package/dist/preview-mode-latch.js +231 -0
  69. package/dist/preview-nav-location.d.ts +12 -0
  70. package/dist/preview-nav-location.js +149 -0
  71. package/dist/preview-nav.d.ts +94 -0
  72. package/dist/preview-nav.js +523 -0
  73. package/dist/preview-refresh-coordinator.d.ts +26 -0
  74. package/dist/preview-refresh-coordinator.js +93 -0
  75. package/dist/preview-render-error.d.ts +11 -0
  76. package/dist/preview-render-error.js +36 -0
  77. package/dist/preview-render-recovery.d.ts +9 -0
  78. package/dist/preview-render-recovery.js +42 -0
  79. package/dist/preview-session-recovery.d.ts +1 -0
  80. package/dist/preview-session-recovery.js +1 -0
  81. package/dist/preview-standalone-host.d.ts +3 -0
  82. package/dist/preview-standalone-host.js +55 -0
  83. package/dist/preview-text.d.ts +2 -0
  84. package/dist/preview-text.js +1 -0
  85. package/dist/preview-view-bootstrap.d.ts +5 -0
  86. package/dist/preview-view-bootstrap.js +13 -0
  87. package/dist/public-delivery.d.ts +6 -0
  88. package/dist/public-delivery.js +7 -0
  89. package/dist/query-fetch-options.d.ts +7 -0
  90. package/dist/query-fetch-options.js +193 -0
  91. package/dist/query.d.ts +2 -0
  92. package/dist/query.js +1 -0
  93. package/dist/rendering.d.ts +33 -0
  94. package/dist/rendering.js +42 -0
  95. package/dist/revalidate.d.ts +12 -0
  96. package/dist/revalidate.js +33 -0
  97. package/dist/rich-text.d.ts +2 -0
  98. package/dist/rich-text.js +1 -0
  99. package/dist/server-runtime.d.ts +208 -0
  100. package/dist/server-runtime.js +1584 -0
  101. package/dist/server.d.ts +8 -0
  102. package/dist/server.js +6 -0
  103. package/dist/slice-zone.d.ts +2 -0
  104. package/dist/slice-zone.js +1 -0
  105. package/dist/storystick-component-types.d.ts +26 -0
  106. package/dist/storystick-component-types.js +1 -0
  107. package/dist/storystick-component.d.ts +10 -0
  108. package/dist/storystick-component.js +45 -0
  109. package/dist/storystick-error-recovery.d.ts +12 -0
  110. package/dist/storystick-error-recovery.js +11 -0
  111. package/dist/storystick-preview-runtime.d.ts +30 -0
  112. package/dist/storystick-preview-runtime.js +561 -0
  113. package/dist/storystick.d.ts +24 -0
  114. package/dist/storystick.js +23 -0
  115. package/dist/testing.d.ts +9 -0
  116. package/dist/testing.js +40 -0
  117. package/dist/video.d.ts +1 -0
  118. package/dist/video.js +1 -0
  119. package/package.json +128 -3
  120. package/recipes/README.md +91 -0
  121. 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-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
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
+ }