flamefront 0.1.7 → 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.7",
3
+ "version": "0.1.8",
4
4
  "private": false,
5
5
  "description": "Typed centralized route manifests for Octane.",
6
6
  "license": "MIT",
@@ -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 = () => {