@jami-studio/core 0.92.21 → 0.92.23

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.
@@ -1,5 +1,17 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.92.23
4
+
5
+ ### Patch Changes
6
+
7
+ - df6be1b: Fix authed deep links 404ing on unified workspace deployments: the Cloudflare worker's static-app-shell fallback fetched an unprefixed "/index.html" from the shared ASSETS binding, but workspace apps serve their shell under the app base path (/dispatch/index.html) — so after sign-in, client-route navigations like /dispatch/overview leaked h3's JSON 404 instead of the SPA shell. The fallback now tries the base-path-prefixed shell first and falls back to the root shell for single-app deployments.
8
+
9
+ ## 0.92.22
10
+
11
+ ### Patch Changes
12
+
13
+ - be9682d: Fix permanently hanging framework routes on Cloudflare Workers: nitro doesn't await async plugins, so plugin-init and default-bootstrap promises are created during an app's first request — when that request responds before they settle (e.g. an auth route that doesn't match the pending inits' paths), workerd freezes their pending I/O forever and every later request's readiness gate awaits a promise that can never settle (observed: authed action requests hanging >90s after a get-session request initialized the app). Init promises are now tied to the creating request's lifetime via ctx.waitUntil, and readiness-gate awaits are bounded (20s) on workerd so a frozen init degrades to a retryable response instead of a permanent hang.
14
+
3
15
  ## 0.92.21
4
16
 
5
17
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.92.21",
3
+ "version": "0.92.23",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/studio-jami/jami-studio#readme",
6
6
  "bugs": {
@@ -1201,13 +1201,27 @@ async function fetchStaticAppShell(request, env) {
1201
1201
  if (!env?.ASSETS || !isStaticAppShellRequest(request)) return null;
1202
1202
  const basePath = getAppBasePath();
1203
1203
  const p = stripAppBasePath(new URL(request.url).pathname);
1204
- const shellRequest = requestWithPathname(
1205
- requestWithMethod(request, "GET"),
1206
- "/index.html",
1207
- );
1204
+ // Workspace deployments serve each app's static files under its base path
1205
+ // (/dispatch/index.html on the unified origin) — an unprefixed
1206
+ // "/index.html" 404s against the shared ASSETS binding and authed deep
1207
+ // links (e.g. /dispatch/overview) leaked h3's JSON 404 instead of the SPA
1208
+ // shell. Try the base-path-prefixed shell first, fall back to the root
1209
+ // shell for single-app deployments.
1208
1210
  let response;
1209
1211
  try {
1210
- response = await env.ASSETS.fetch(shellRequest);
1212
+ if (basePath) {
1213
+ response = await env.ASSETS.fetch(
1214
+ requestWithPathname(
1215
+ requestWithMethod(request, "GET"),
1216
+ basePath + "/index.html",
1217
+ ),
1218
+ );
1219
+ }
1220
+ if (!response || response.status === 404) {
1221
+ response = await env.ASSETS.fetch(
1222
+ requestWithPathname(requestWithMethod(request, "GET"), "/index.html"),
1223
+ );
1224
+ }
1211
1225
  } catch {
1212
1226
  return null;
1213
1227
  }
@@ -17,6 +17,7 @@ import { setResponseHeader, setResponseStatus } from "h3";
17
17
  import { getMissingDefaultPlugins } from "../deploy/route-discovery.js";
18
18
  import { getConfiguredAppBasePath } from "./app-base-path.js";
19
19
  import { captureError } from "./capture-error.js";
20
+ import { isCloudflareRuntime } from "../shared/runtime.js";
20
21
 
21
22
  const BOOTSTRAPPED = new WeakSet<object>();
22
23
  const IN_BOOTSTRAP = new WeakSet<object>();
@@ -44,6 +45,56 @@ function pathMatchesPrefix(reqPath: string, prefix: string): boolean {
44
45
  return reqPath === prefix || reqPath.startsWith(prefix + "/");
45
46
  }
46
47
 
48
+ /**
49
+ * Cloudflare Workers (workerd) cancels pending I/O owned by a request the
50
+ * moment its response returns — a promise created during request A that
51
+ * hasn't settled by then FREEZES forever. Plugin-init and bootstrap promises
52
+ * are created during an app's first request and awaited by later requests'
53
+ * readiness gates, so an early-responding first request (e.g. an auth route
54
+ * that doesn't match the pending inits' paths) permanently wedges every
55
+ * later framework-route request. Tie the promise to the creating request's
56
+ * `waitUntil` so its I/O stays alive until it settles.
57
+ */
58
+ function extendRequestLifetimeOverInit(promise: Promise<unknown>): void {
59
+ try {
60
+ (
61
+ globalThis as {
62
+ __cf_ctx?: { waitUntil?: (p: Promise<unknown>) => void };
63
+ }
64
+ ).__cf_ctx?.waitUntil?.(promise);
65
+ } catch {
66
+ /* not on Cloudflare or ctx unavailable — nothing to extend */
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Bound a readiness-gate await on workerd. Insurance against any init
72
+ * promise that still froze (e.g. created before __cf_ctx existed): a
73
+ * bounded wait turns a permanently hung request into a slow one that
74
+ * proceeds — the route either works (init actually finished) or 404/503s
75
+ * (retryable) instead of hanging until the runtime kills the request.
76
+ */
77
+ async function awaitBounded(promise: Promise<unknown>): Promise<void> {
78
+ if (!isCloudflareRuntime()) {
79
+ await promise;
80
+ return;
81
+ }
82
+ let timer: ReturnType<typeof setTimeout> | undefined;
83
+ const timeout = new Promise<void>((resolve) => {
84
+ timer = setTimeout(() => {
85
+ console.warn(
86
+ "[agent-native] readiness gate timed out waiting for plugin init (20s) — proceeding; the init promise may have been frozen by a prior request's completion",
87
+ );
88
+ resolve();
89
+ }, 20_000);
90
+ });
91
+ try {
92
+ await Promise.race([promise, timeout]);
93
+ } finally {
94
+ if (timer) clearTimeout(timer);
95
+ }
96
+ }
97
+
47
98
  function supportsAppBasePathMount(path: string): boolean {
48
99
  return (
49
100
  pathMatchesPrefix(path, FRAMEWORK_PREFIX) ||
@@ -143,6 +194,9 @@ export function getH3App(nitroApp: any): H3AppShim {
143
194
  });
144
195
  },
145
196
  );
197
+ extendRequestLifetimeOverInit(
198
+ nitroApp[BOOTSTRAP_PROMISE_KEY] as Promise<unknown>,
199
+ );
146
200
 
147
201
  // Readiness gate: Nitro v3 doesn't await async plugins, so routes
148
202
  // registered inside an async plugin may not exist when the first
@@ -257,7 +311,7 @@ async function awaitFrameworkRoutesReadyForRequest(
257
311
  ): Promise<void> {
258
312
  if (!nitroApp) return;
259
313
  const bootstrapPromise = nitroApp[BOOTSTRAP_PROMISE_KEY];
260
- if (bootstrapPromise) await bootstrapPromise;
314
+ if (bootstrapPromise) await awaitBounded(bootstrapPromise);
261
315
  await awaitPluginsReady(nitroApp, reqPath);
262
316
  }
263
317
 
@@ -306,6 +360,7 @@ export function trackPluginInit(
306
360
  promise: safe,
307
361
  paths: options.paths?.filter(Boolean),
308
362
  };
363
+ extendRequestLifetimeOverInit(safe);
309
364
  const existing = nitroApp[PLUGIN_READY_KEY] as PluginReadyEntry[] | undefined;
310
365
  if (existing) {
311
366
  existing.push(entry);
@@ -426,7 +481,7 @@ export async function awaitPluginsReady(
426
481
  : entries;
427
482
 
428
483
  if (relevant.length) {
429
- await Promise.all(relevant.map((entry) => entry.promise));
484
+ await Promise.all(relevant.map((entry) => awaitBounded(entry.promise)));
430
485
  const completed = new Set(relevant);
431
486
  const latest =
432
487
  (nitroApp[PLUGIN_READY_KEY] as PluginReadyEntry[] | undefined) ?? [];
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":"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"}
@@ -1017,13 +1017,27 @@ async function fetchStaticAppShell(request, env) {
1017
1017
  if (!env?.ASSETS || !isStaticAppShellRequest(request)) return null;
1018
1018
  const basePath = getAppBasePath();
1019
1019
  const p = stripAppBasePath(new URL(request.url).pathname);
1020
- const shellRequest = requestWithPathname(
1021
- requestWithMethod(request, "GET"),
1022
- "/index.html",
1023
- );
1020
+ // Workspace deployments serve each app's static files under its base path
1021
+ // (/dispatch/index.html on the unified origin) — an unprefixed
1022
+ // "/index.html" 404s against the shared ASSETS binding and authed deep
1023
+ // links (e.g. /dispatch/overview) leaked h3's JSON 404 instead of the SPA
1024
+ // shell. Try the base-path-prefixed shell first, fall back to the root
1025
+ // shell for single-app deployments.
1024
1026
  let response;
1025
1027
  try {
1026
- response = await env.ASSETS.fetch(shellRequest);
1028
+ if (basePath) {
1029
+ response = await env.ASSETS.fetch(
1030
+ requestWithPathname(
1031
+ requestWithMethod(request, "GET"),
1032
+ basePath + "/index.html",
1033
+ ),
1034
+ );
1035
+ }
1036
+ if (!response || response.status === 404) {
1037
+ response = await env.ASSETS.fetch(
1038
+ requestWithPathname(requestWithMethod(request, "GET"), "/index.html"),
1039
+ );
1040
+ }
1027
1041
  } catch {
1028
1042
  return null;
1029
1043
  }