flamefront 0.1.6 → 0.1.8

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": "flamefront",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "private": false,
5
5
  "description": "Typed centralized route manifests for Octane.",
6
6
  "license": "MIT",
@@ -51,38 +51,38 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@alloc/cmd-ts": "^0.17.1",
54
- "@babel/generator": "^8.0.5",
55
- "@babel/parser": "^8.0.5",
56
- "@babel/traverse": "^8.0.5",
57
- "@babel/types": "^8.0.5",
58
- "@remix-run/route-pattern": "^0.24.0",
54
+ "@babel/generator": "^8.0.6",
55
+ "@babel/parser": "^8.0.6",
56
+ "@babel/traverse": "^8.0.6",
57
+ "@babel/types": "^8.0.6",
58
+ "@remix-run/route-pattern": "^0.24.1",
59
59
  "babel-dead-code-elimination": "^2.0.0",
60
- "devalue": "^5.8.2",
60
+ "devalue": "^6.0.0",
61
61
  "satteri": "^0.10.5",
62
- "srvx": "^1.0.4",
62
+ "srvx": "^1.0.5",
63
63
  "vite-plugin-satteri": "^0.3.5"
64
64
  },
65
65
  "devDependencies": {
66
- "@octanejs/remix-router": "^0.1.48",
67
- "@octanejs/vite-plugin": "^0.1.54",
66
+ "@octanejs/remix-router": "^0.1.49",
67
+ "@octanejs/vite-plugin": "^0.1.57",
68
68
  "@stylistic/eslint-plugin": "^5.10.0",
69
- "@tsrx/prettier-plugin": "^0.3.137",
69
+ "@tsrx/prettier-plugin": "^0.4.6",
70
70
  "@types/babel__generator": "^7.27.0",
71
71
  "@types/babel__traverse": "^7.28.0",
72
- "@types/node": "^26.5.1",
73
- "octane": "^0.2.7",
72
+ "@types/node": "^26.6.2",
73
+ "octane": "^0.3.2",
74
74
  "oxc-tsrx": "^0.6.1",
75
- "oxlint": "^1.82.0",
76
- "oxlint-tsgolint": "^7.0.2001",
75
+ "oxlint": "^1.83.0",
76
+ "oxlint-tsgolint": "^7.0.2002",
77
77
  "playwright": "^1.63.0",
78
- "prettier": "^3.9.6",
78
+ "prettier": "^3.9.8",
79
79
  "typescript": "^5.9.3",
80
80
  "vite": "^8.3.0",
81
- "vitest": "^5.0.0"
81
+ "vitest": "^5.0.1"
82
82
  },
83
83
  "peerDependencies": {
84
- "@octanejs/remix-router": ">=0.1.48",
85
- "octane": ">=0.2.7",
84
+ "@octanejs/remix-router": ">=0.1.49",
85
+ "octane": ">=0.3.2",
86
86
  "vite": ">=8.3.0"
87
87
  }
88
88
  }
@@ -77,6 +77,29 @@ function basenamePath(pathname: string, basename: string): string | null {
77
77
  return pathname.slice(basename.length) || "/"
78
78
  }
79
79
 
80
+ function joinBasename(basename: string, pathname: string): string {
81
+ if (basename === "/") {
82
+ return pathname || "/"
83
+ }
84
+
85
+ if (pathname === "/") {
86
+ return basename
87
+ }
88
+
89
+ return `${basename}${pathname.startsWith("/") ? pathname : `/${pathname}`}`
90
+ }
91
+
92
+ /** The static build emits one fragment artifact beside each route document. */
93
+ function staticRouteFragmentPath(routeUrl: URL, basename: string): string {
94
+ const appPathname =
95
+ basenamePath(routeUrl.pathname, basename) ?? routeUrl.pathname
96
+ const pathname = joinBasename(basename, appPathname).replace(/\/+$/, "")
97
+
98
+ return pathname === ""
99
+ ? "/index.fragment.json"
100
+ : `${pathname}/index.fragment.json`
101
+ }
102
+
80
103
  function staticFragmentKey(url: URL, basename: string): string {
81
104
  const pathname = basenamePath(url.pathname, basename) ?? url.pathname
82
105
 
@@ -214,6 +237,49 @@ function fetchRouteFragment(
214
237
  })
215
238
  }
216
239
 
240
+ /**
241
+ * Read the emitted artifact file for a static route. Hosts that cannot serve
242
+ * it — the dev server, or a deployment without generated files — fall back to
243
+ * the live fragment endpoint.
244
+ */
245
+ async function readStaticRouteFragment(
246
+ routeUrl: URL,
247
+ basename: string,
248
+ signal: AbortSignal | undefined,
249
+ ): Promise<RouteFragmentArtifact | undefined> {
250
+ const endpoint = new URL(
251
+ staticRouteFragmentPath(routeUrl, basename),
252
+ routeUrl.origin,
253
+ )
254
+ const response = await globalThis.fetch(endpoint, {
255
+ headers: { Accept: "application/vnd.flamefront.fragment+json" },
256
+ ...(signal ? { signal } : {}),
257
+ })
258
+
259
+ if (!response.ok) {
260
+ return undefined
261
+ }
262
+
263
+ try {
264
+ return assertRouteFragmentArtifact(await response.json())
265
+ } catch {
266
+ return undefined
267
+ }
268
+ }
269
+
270
+ function fetchStaticRouteFragment(
271
+ routeUrl: URL,
272
+ basename: string,
273
+ signal: AbortSignal | undefined,
274
+ ): Promise<RouteFragmentArtifact> {
275
+ const fallback = () => fetchRouteFragment(routeUrl, basename, signal)
276
+
277
+ return readStaticRouteFragment(routeUrl, basename, signal).then(
278
+ (artifact) => artifact ?? fallback(),
279
+ fallback,
280
+ )
281
+ }
282
+
217
283
  export function loadRouteFragment(
218
284
  url: string | URL,
219
285
  routing: RouteFragmentRoutingOptions = {},
@@ -238,11 +304,12 @@ export function loadRouteFragment(
238
304
  let pending = requests.get(requestKey)
239
305
 
240
306
  if (!pending) {
241
- pending = fetchRouteFragment(
242
- routeUrl,
243
- routing.basename ?? "/",
244
- options.signal,
245
- )
307
+ const fetchFragment =
308
+ options.policy === "static"
309
+ ? fetchStaticRouteFragment
310
+ : fetchRouteFragment
311
+
312
+ pending = fetchFragment(routeUrl, routing.basename ?? "/", options.signal)
246
313
  requests.set(requestKey, pending)
247
314
 
248
315
  const evict = () => {
package/src/fragment.tsx CHANGED
@@ -438,9 +438,9 @@ function createShellBoundary(
438
438
  ),
439
439
  }
440
440
  const shell = (
441
- <UNSAFE_RouteContext.Provider value={shellRoute}>
441
+ <UNSAFE_RouteContext value={shellRoute}>
442
442
  <Component {...props} />
443
- </UNSAFE_RouteContext.Provider>
443
+ </UNSAFE_RouteContext>
444
444
  )
445
445
  const body = shellHydrationBoundary(
446
446
  metadata.hydration ?? "full",
@@ -481,13 +481,13 @@ export function createRouteBoundary(
481
481
  function createContextBridge(stateRef: {
482
482
  readonly current: ContextBridgeState
483
483
  }): (props: Record<string, unknown>) => unknown {
484
- const DataRouterProvider = UNSAFE_DataRouterContext.Provider
485
- const DataRouterStateProvider = UNSAFE_DataRouterStateContext.Provider
486
- const FetchersProvider = UNSAFE_FetchersContext.Provider
487
- const LocationProvider = UNSAFE_LocationContext.Provider
488
- const NavigationProvider = UNSAFE_NavigationContext.Provider
489
- const RouteProvider = UNSAFE_RouteContext.Provider
490
- const ViewTransitionProvider = UNSAFE_ViewTransitionContext.Provider
484
+ const DataRouterProvider = UNSAFE_DataRouterContext
485
+ const DataRouterStateProvider = UNSAFE_DataRouterStateContext
486
+ const FetchersProvider = UNSAFE_FetchersContext
487
+ const LocationProvider = UNSAFE_LocationContext
488
+ const NavigationProvider = UNSAFE_NavigationContext
489
+ const RouteProvider = UNSAFE_RouteContext
490
+ const ViewTransitionProvider = UNSAFE_ViewTransitionContext
491
491
 
492
492
  return () => {
493
493
  const { component, contexts } = stateRef.current
@@ -97,7 +97,7 @@ export const defaultOctaneRenderer: OctaneRenderer = {
97
97
  errors: errorsForBoundary(staticContext, matches),
98
98
  }
99
99
  const outletRouter = createStaticRouter([outletRoute], outletContext)
100
- const FragmentBoundaryProvider = routeFragmentBoundaryTarget.Provider
100
+ const FragmentBoundaryProvider = routeFragmentBoundaryTarget
101
101
  const FragmentRoot = () => (
102
102
  <FragmentBoundaryProvider
103
103
  value={options?.includeBoundary ? null : boundary}
@@ -16,14 +16,14 @@ export const RouterDocument: RouterDocumentComponent = (
16
16
  }) => unknown
17
17
 
18
18
  const content = createElement(
19
- routeOutletHtmlContext.Provider,
19
+ routeOutletHtmlContext,
20
20
  { value: props.outletHtml ?? null },
21
21
  createElement(Router, { router: props.router }),
22
22
  )
23
23
 
24
24
  return props.documentAssets
25
25
  ? createElement(
26
- documentAssetsContext.Provider,
26
+ documentAssetsContext,
27
27
  { value: props.documentAssets },
28
28
  content,
29
29
  )