@agent-native/core 0.48.3 → 0.49.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/dist/agent/context-xray/actions/context-evict.d.ts +1 -1
- package/dist/agent/context-xray/actions/context-pin.d.ts +1 -1
- package/dist/agent/context-xray/actions/context-report.d.ts +4 -4
- package/dist/agent/context-xray/actions/context-restore.d.ts +1 -1
- package/dist/application-state/handlers.d.ts +2 -2
- package/dist/application-state/handlers.d.ts.map +1 -1
- package/dist/cli/app-skill.d.ts +157 -0
- package/dist/cli/app-skill.d.ts.map +1 -0
- package/dist/cli/app-skill.js +17 -7
- package/dist/cli/app-skill.js.map +1 -1
- package/dist/cli/audit-agent-web.d.ts +2 -0
- package/dist/cli/audit-agent-web.d.ts.map +1 -0
- package/dist/cli/code-agent-connector.d.ts +17 -0
- package/dist/cli/code-agent-connector.d.ts.map +1 -0
- package/dist/cli/code.d.ts +66 -0
- package/dist/cli/code.d.ts.map +1 -0
- package/dist/cli/connect.d.ts +168 -0
- package/dist/cli/connect.d.ts.map +1 -0
- package/dist/cli/connect.js +118 -30
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/context-xray-local.d.ts +16 -0
- package/dist/cli/context-xray-local.d.ts.map +1 -0
- package/dist/cli/create-workspace.d.ts +8 -0
- package/dist/cli/create-workspace.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/info.d.ts +2 -0
- package/dist/cli/info.d.ts.map +1 -0
- package/dist/cli/mcp-config-writers.d.ts +108 -0
- package/dist/cli/mcp-config-writers.d.ts.map +1 -0
- package/dist/cli/mcp-config-writers.js +143 -0
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/mcp.d.ts +16 -0
- package/dist/cli/mcp.d.ts.map +1 -0
- package/dist/cli/mcp.js +10 -10
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/migrate.d.ts +38 -0
- package/dist/cli/migrate.d.ts.map +1 -0
- package/dist/cli/plan-local.d.ts +43 -0
- package/dist/cli/plan-local.d.ts.map +1 -0
- package/dist/cli/plan-publish-store.d.ts +62 -0
- package/dist/cli/plan-publish-store.d.ts.map +1 -0
- package/dist/cli/pr-visual-recap-workflow.d.ts +11 -0
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -0
- package/dist/cli/pr-visual-recap-workflow.js +1 -1
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts +453 -0
- package/dist/cli/recap.d.ts.map +1 -0
- package/dist/cli/recap.js +228 -95
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +193 -0
- package/dist/cli/skills.d.ts.map +1 -0
- package/dist/cli/skills.js +518 -177
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/telemetry.d.ts +13 -0
- package/dist/cli/telemetry.d.ts.map +1 -0
- package/dist/cli/telemetry.js +115 -0
- package/dist/cli/telemetry.js.map +1 -0
- package/dist/cli/workspace-dev.d.ts +96 -0
- package/dist/cli/workspace-dev.d.ts.map +1 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +10 -19
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/ErrorBoundary.d.ts.map +1 -1
- package/dist/client/ErrorBoundary.js +34 -1
- package/dist/client/ErrorBoundary.js.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.js +15 -7
- package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
- package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/DiffBlock.js +17 -10
- package/dist/client/blocks/library/DiffBlock.js.map +1 -1
- package/dist/client/blocks/library/annotation-rail.d.ts +5 -0
- package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
- package/dist/client/blocks/library/annotation-rail.js +6 -0
- package/dist/client/blocks/library/annotation-rail.js.map +1 -1
- package/dist/client/blocks/types.d.ts +5 -0
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/route-chunk-recovery.d.ts +17 -0
- package/dist/client/route-chunk-recovery.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery.js +67 -0
- package/dist/client/route-chunk-recovery.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +15 -71
- package/dist/deploy/build.js.map +1 -1
- package/dist/extensions/schema.d.ts +54 -54
- package/dist/extensions/slots/schema.d.ts +13 -13
- package/dist/file-upload/actions/upload-image.d.ts +4 -4
- package/dist/mcp/actions/create-org-service-token.d.ts +1 -1
- package/dist/mcp/actions/list-org-service-tokens.d.ts +7 -7
- package/dist/mcp/build-server.d.ts +12 -12
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/connect-route.js +1 -1
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/mcp/oauth-route.d.ts +10 -0
- package/dist/mcp/oauth-route.d.ts.map +1 -1
- package/dist/mcp/oauth-route.js +34 -3
- package/dist/mcp/oauth-route.js.map +1 -1
- package/dist/mcp/oauth-store.d.ts +15 -1
- package/dist/mcp/oauth-store.d.ts.map +1 -1
- package/dist/mcp/oauth-store.js +60 -4
- package/dist/mcp/oauth-store.js.map +1 -1
- package/dist/mcp/oauth-token.d.ts +3 -1
- package/dist/mcp/oauth-token.d.ts.map +1 -1
- package/dist/mcp/oauth-token.js +78 -6
- package/dist/mcp/oauth-token.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +8 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/observability/routes.d.ts +11 -11
- package/dist/org/handlers.d.ts +7 -11
- package/dist/org/handlers.d.ts.map +1 -1
- package/dist/secrets/schema.d.ts +7 -7
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +8 -5
- package/dist/server/auth.js.map +1 -1
- package/dist/server/csrf.d.ts +1 -1
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +12 -11
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/poll-events.d.ts +1 -1
- package/dist/server/security-headers.d.ts +1 -1
- package/dist/server/security-headers.d.ts.map +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +42 -130
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.d.ts +3 -3
- package/dist/sharing/actions/set-resource-visibility.d.ts +2 -2
- package/dist/sharing/actions/share-resource.d.ts +4 -4
- package/dist/sharing/actions/unshare-resource.d.ts +1 -1
- package/dist/sharing/schema.d.ts +12 -12
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +2 -2
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -6
- package/dist/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +2 -2
- package/dist/workspace-files/schema.d.ts +8 -8
- package/docs/content/external-agents.md +14 -0
- package/docs/content/plan-plugin.md +16 -7
- package/package.json +5 -1
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +2 -2
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -6
- package/src/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/server/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAUH;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAGrE;AAwCD;;;;;GAKG;AACH,wBAAgB,+BAA+B,
|
|
1
|
+
{"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/server/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAUH;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAGrE;AAwCD;;;;;GAKG;AACH,wBAAgB,+BAA+B,8EA6C9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-handler.d.ts","sourceRoot":"","sources":["../../src/server/ssr-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ssr-handler.d.ts","sourceRoot":"","sources":["../../src/server/ssr-handler.ts"],"names":[],"mappings":"AAsCA,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAmVpC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,2FAgE5E"}
|
|
@@ -20,43 +20,10 @@ import { defineEventHandler } from "h3";
|
|
|
20
20
|
import { getSentryClientConfigScript } from "./sentry-config.js";
|
|
21
21
|
import { computeInlineScriptHash } from "./security-headers.js";
|
|
22
22
|
import { getAppBasePathFromViteEnv, stripAppBasePath as canonicalStripAppBasePath, } from "./app-base-path.js";
|
|
23
|
-
import { BETTER_AUTH_COOKIE_PREFIX, COOKIE_NAME, getSession } from "./auth.js";
|
|
24
23
|
import { runWithRequestContext } from "./request-context.js";
|
|
25
|
-
import { requestHasEmbedAuthMarker } from "./embed-session.js";
|
|
26
|
-
import { EMBED_SESSION_COOKIE, EMBED_TOKEN_QUERY_PARAM, } from "../shared/embed-auth.js";
|
|
27
24
|
import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, } from "../shared/social-meta.js";
|
|
28
25
|
import { DEFAULT_SSR_CACHE_HEADERS, DEFAULT_SPECULATION_RULES_PATH, } from "../shared/cache-control.js";
|
|
29
26
|
export { DEFAULT_SSR_CACHE_HEADERS, DEFAULT_SPECULATION_RULES_HEADER, DEFAULT_SSR_CACHE_CONTROL, } from "../shared/cache-control.js";
|
|
30
|
-
const ANONYMOUS_SESSION_COOKIE_NAMES = new Set(["an_docs_session"]);
|
|
31
|
-
const BETTER_AUTH_SESSION_COOKIE_RE = /\.session_(?:token|data)$/;
|
|
32
|
-
/**
|
|
33
|
-
* Read the active org for a request without forcing every template to bundle
|
|
34
|
-
* the org module. Mirrors what `core-routes-plugin` does for action handlers.
|
|
35
|
-
*
|
|
36
|
-
* Fast path: when the session already carries a valid orgId (backfilled by
|
|
37
|
-
* backfillSessionOrg during getSession), return it directly — no additional
|
|
38
|
-
* org_members round trip. Only when the session has no orgId do we fall
|
|
39
|
-
* through to getOrgContext for the full membership lookup.
|
|
40
|
-
*/
|
|
41
|
-
async function readOrgIdForEvent(event, session) {
|
|
42
|
-
// Reuse orgId already resolved by backfillSessionOrg inside getSession.
|
|
43
|
-
const sessionOrgId = typeof session?.orgId === "string" && session.orgId.trim()
|
|
44
|
-
? session.orgId.trim()
|
|
45
|
-
: undefined;
|
|
46
|
-
if (sessionOrgId)
|
|
47
|
-
return sessionOrgId;
|
|
48
|
-
// No orgId on the session — full org_members lookup needed.
|
|
49
|
-
// getOrgContext is per-event memoized, so this is at most one DB read
|
|
50
|
-
// even if other request code calls getOrgContext independently.
|
|
51
|
-
try {
|
|
52
|
-
const { getOrgContext } = await import("../org/context.js");
|
|
53
|
-
const ctx = await getOrgContext(event);
|
|
54
|
-
return ctx?.orgId ?? undefined;
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
return undefined;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
27
|
function getAppBasePath() {
|
|
61
28
|
return getAppBasePathFromViteEnv();
|
|
62
29
|
}
|
|
@@ -162,37 +129,6 @@ function injectDefaultSocialImageMeta(html, imageUrl) {
|
|
|
162
129
|
return html;
|
|
163
130
|
return html.slice(0, headCloseIdx) + tags.join("") + html.slice(headCloseIdx);
|
|
164
131
|
}
|
|
165
|
-
function requestHasAuthSignal(event) {
|
|
166
|
-
const headers = event.req.headers;
|
|
167
|
-
return Boolean(headers.get("authorization") ||
|
|
168
|
-
requestHasAuthenticatedCookie(headers.get("cookie")) ||
|
|
169
|
-
event.url.searchParams.has(EMBED_TOKEN_QUERY_PARAM) ||
|
|
170
|
-
event.url.searchParams.has("_session") ||
|
|
171
|
-
requestHasEmbedAuthMarker(event));
|
|
172
|
-
}
|
|
173
|
-
function requestHasAuthenticatedCookie(cookieHeader) {
|
|
174
|
-
if (!cookieHeader)
|
|
175
|
-
return false;
|
|
176
|
-
return cookieHeader
|
|
177
|
-
.split(";")
|
|
178
|
-
.map((cookie) => cookie.trim().split("=", 1)[0]?.trim())
|
|
179
|
-
.filter((name) => Boolean(name))
|
|
180
|
-
.some(isAuthenticatedCookieName);
|
|
181
|
-
}
|
|
182
|
-
function isAuthenticatedCookieName(name) {
|
|
183
|
-
if (ANONYMOUS_SESSION_COOKIE_NAMES.has(name))
|
|
184
|
-
return false;
|
|
185
|
-
const bareName = name.replace(/^__(?:Secure|Host)-/, "");
|
|
186
|
-
return (bareName === COOKIE_NAME ||
|
|
187
|
-
bareName === EMBED_SESSION_COOKIE ||
|
|
188
|
-
bareName === "an_session" ||
|
|
189
|
-
bareName === "an_session_workspace" ||
|
|
190
|
-
bareName.startsWith("an_session_") ||
|
|
191
|
-
bareName === `${BETTER_AUTH_COOKIE_PREFIX}.session_token` ||
|
|
192
|
-
bareName === `${BETTER_AUTH_COOKIE_PREFIX}.session_data` ||
|
|
193
|
-
BETTER_AUTH_SESSION_COOKIE_RE.test(bareName));
|
|
194
|
-
}
|
|
195
|
-
const PRIVATE_NO_STORE = "private, no-store";
|
|
196
132
|
function isSsrHtmlOrDataResponse(headers, status, pathname) {
|
|
197
133
|
if (status < 200 || status >= 400)
|
|
198
134
|
return false;
|
|
@@ -202,47 +138,36 @@ function isSsrHtmlOrDataResponse(headers, status, pathname) {
|
|
|
202
138
|
return pathname.endsWith(".data") && contentType.includes("text/x-script");
|
|
203
139
|
}
|
|
204
140
|
/**
|
|
205
|
-
* Apply the
|
|
206
|
-
*
|
|
207
|
-
* Anonymous requests (no auth signal on the incoming request) get the public
|
|
208
|
-
* stale-while-revalidate default so the CDN can serve shared app-shell HTML
|
|
209
|
-
* and React Router loader data to every unauthenticated visitor without
|
|
210
|
-
* hammering origin.
|
|
211
|
-
*
|
|
212
|
-
* Authenticated requests must never be publicly CDN-cached: the loader may
|
|
213
|
-
* have embedded session-personalized data. If the route already returned a
|
|
214
|
-
* Cache-Control header we respect it; otherwise we fall back to
|
|
215
|
-
* `private, no-store` so the browser re-fetches but no shared cache stores
|
|
216
|
-
* the response.
|
|
141
|
+
* Apply the SSR cache policy to the response headers.
|
|
217
142
|
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
143
|
+
* ┌──────────────────────────────────────────────────────────────────────────┐
|
|
144
|
+
* │ SSR IS A PUBLIC, HARD-CDN-CACHED SHELL — SERVED IDENTICALLY TO EVERYONE. │
|
|
145
|
+
* │ │
|
|
146
|
+
* │ Every SSR HTML / React Router `.data` response gets the same public │
|
|
147
|
+
* │ stale-while-revalidate policy for ALL visitors, authenticated or not, so │
|
|
148
|
+
* │ the edge serves one shared copy and never stampedes origin. │
|
|
149
|
+
* │ │
|
|
150
|
+
* │ DO NOT reintroduce per-user / cookie-based cache variation here (no │
|
|
151
|
+
* │ `private`, no `no-store`, no `Vary: Cookie`, no "authenticated → don't │
|
|
152
|
+
* │ cache" branch). That makes pages uncacheable for every logged-in visitor, │
|
|
153
|
+
* │ which is slow and expensive — exactly the regression this guardrail │
|
|
154
|
+
* │ prevents. The reason it is SAFE to hard-cache is that the SSR response is │
|
|
155
|
+
* │ impersonal: `createH3SSRHandler` renders without reading the request's │
|
|
156
|
+
* │ session/cookies, so there is no per-user data baked into the HTML. ALL │
|
|
157
|
+
* │ per-user state (who's logged in, private records, access checks) is │
|
|
158
|
+
* │ resolved CLIENT-SIDE after load. Keep it that way: if you need the SSR │
|
|
159
|
+
* │ output to differ per user, the fix is to move that work client-side, not │
|
|
160
|
+
* │ to disable caching here. │
|
|
161
|
+
* └──────────────────────────────────────────────────────────────────────────┘
|
|
221
162
|
*/
|
|
222
|
-
function applyDefaultSsrCacheHeader(headers, status, pathname
|
|
163
|
+
function applyDefaultSsrCacheHeader(headers, status, pathname) {
|
|
223
164
|
if (!isSsrHtmlOrDataResponse(headers, status, pathname))
|
|
224
165
|
return;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// potentially personalized response.
|
|
231
|
-
const existingCc = headers.get("cache-control") ?? "";
|
|
232
|
-
if (!existingCc.includes("public")) {
|
|
233
|
-
headers.set("cache-control", PRIVATE_NO_STORE);
|
|
234
|
-
}
|
|
235
|
-
// Never propagate CDN-specific cache headers on authenticated responses,
|
|
236
|
-
// regardless of what the route set.
|
|
237
|
-
headers.delete("cdn-cache-control");
|
|
238
|
-
headers.delete("netlify-cdn-cache-control");
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
// Netlify Functions/proxies are not cached by default, and production docs
|
|
242
|
-
// requests often carry stale auth/doc cookies. Keep all three cache headers:
|
|
243
|
-
// Cache-Control for browsers, CDN-Cache-Control for generic CDNs, and
|
|
244
|
-
// Netlify-CDN-Cache-Control (with durable) so Netlify's shared cache actually
|
|
245
|
-
// serves SSR HTML/.data instead of forwarding every request to origin.
|
|
166
|
+
// Netlify Functions/proxies are not cached by default. Set all three cache
|
|
167
|
+
// headers: Cache-Control for browsers, CDN-Cache-Control for generic CDNs,
|
|
168
|
+
// and Netlify-CDN-Cache-Control (with durable) so Netlify's shared cache
|
|
169
|
+
// actually serves SSR HTML/.data from the edge instead of forwarding every
|
|
170
|
+
// request to origin — for every visitor, authenticated or not.
|
|
246
171
|
for (const [name, value] of Object.entries(DEFAULT_SSR_CACHE_HEADERS)) {
|
|
247
172
|
headers.set(name, value);
|
|
248
173
|
}
|
|
@@ -346,10 +271,10 @@ function isFrameworkOrAssetPath(pathname) {
|
|
|
346
271
|
pathname === "/favicon.png" ||
|
|
347
272
|
(/\.\w+$/.test(pathname) && !pathname.endsWith(".data")));
|
|
348
273
|
}
|
|
349
|
-
async function rewriteMountedResponse(response, basePath, pathname, requestUrl
|
|
274
|
+
async function rewriteMountedResponse(response, basePath, pathname, requestUrl) {
|
|
350
275
|
const sentryClientConfigScript = getSentryClientConfigScript();
|
|
351
276
|
const headers = new Headers(response.headers);
|
|
352
|
-
applyDefaultSsrCacheHeader(headers, response.status, pathname
|
|
277
|
+
applyDefaultSsrCacheHeader(headers, response.status, pathname);
|
|
353
278
|
applyDefaultSpeculationRulesHeader(headers, response.status, basePath);
|
|
354
279
|
const location = headers.get("location");
|
|
355
280
|
if (location?.startsWith("/") && !location.startsWith("//")) {
|
|
@@ -386,31 +311,18 @@ export function createH3SSRHandler(getBuild) {
|
|
|
386
311
|
}
|
|
387
312
|
try {
|
|
388
313
|
const request = requestWithPathname(event.req, p, basePath);
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
//
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
// Auth lookup failures must not break SSR; treat as unauthenticated.
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
// readOrgIdForEvent fast-paths when session.orgId is already backfilled
|
|
405
|
-
// (the common case), avoiding a duplicate org_members query. A second
|
|
406
|
-
// query only fires for authenticated users whose session has no orgId.
|
|
407
|
-
const orgId = session?.email
|
|
408
|
-
? await readOrgIdForEvent(event, session)
|
|
409
|
-
: undefined;
|
|
410
|
-
const ctx = {
|
|
411
|
-
userEmail: session?.email ?? undefined,
|
|
412
|
-
orgId,
|
|
413
|
-
};
|
|
314
|
+
// SSR renders an IMPERSONAL public shell — we deliberately do NOT read the
|
|
315
|
+
// request's session/cookies here, and pin an explicitly anonymous request
|
|
316
|
+
// context. That keeps the SSR HTML/.data identical for every visitor so it
|
|
317
|
+
// can be hard-cached at the CDN for everyone (see applyDefaultSsrCacheHeader).
|
|
318
|
+
//
|
|
319
|
+
// Consequence: SSR loaders that call `getRequestUserEmail()` / `accessFilter()`
|
|
320
|
+
// always see the unauthenticated branch and render public content only. Any
|
|
321
|
+
// per-user view (private records, share-grant access, who's logged in) MUST
|
|
322
|
+
// be resolved CLIENT-SIDE after load, never baked into SSR. Do not re-pin the
|
|
323
|
+
// session here to "fix" a per-user page — that silently makes the page
|
|
324
|
+
// uncacheable and/or leaks one user's data into another's cached copy.
|
|
325
|
+
const ctx = { userEmail: undefined, orgId: undefined };
|
|
414
326
|
if (request.method === "HEAD") {
|
|
415
327
|
const getRequest = new Request(request.url, {
|
|
416
328
|
method: "GET",
|
|
@@ -422,9 +334,9 @@ export function createH3SSRHandler(getBuild) {
|
|
|
422
334
|
status: response.status,
|
|
423
335
|
statusText: response.statusText,
|
|
424
336
|
headers: response.headers,
|
|
425
|
-
}), basePath, p, request.url
|
|
337
|
+
}), basePath, p, request.url);
|
|
426
338
|
}
|
|
427
|
-
return await rewriteMountedResponse(await runWithRequestContext(ctx, () => handler(request)), basePath, p, request.url
|
|
339
|
+
return await rewriteMountedResponse(await runWithRequestContext(ctx, () => handler(request)), basePath, p, request.url);
|
|
428
340
|
}
|
|
429
341
|
catch (err) {
|
|
430
342
|
// Log the full stack server-side, but never leak it to the client.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-handler.js","sourceRoot":"","sources":["../../src/server/ssr-handler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared SSR catch-all handler for React Router framework mode.\n *\n * Templates wire this up via:\n *\n * // server/routes/[...page].get.ts\n * import { createH3SSRHandler } from \"@agent-native/core/server/ssr-handler\";\n * export default createH3SSRHandler(\n * () => import(\"virtual:react-router/server-build\"),\n * );\n *\n * The `getBuild` callback MUST live in the template's own source so Vite's\n * @react-router/dev plugin can resolve the `virtual:` module. Pulling the\n * import into core (e.g. via a re-export) puts it in node_modules where\n * Vite's SSR externalizer leaves it untouched and Node's ESM loader rejects\n * the unknown scheme — silently 302'ing every request to \"/\".\n */\nimport { createRequestHandler } from \"react-router\";\nimport { defineEventHandler, type H3Event } from \"h3\";\nimport { getSentryClientConfigScript } from \"./sentry-config.js\";\nimport { computeInlineScriptHash } from \"./security-headers.js\";\nimport {\n getAppBasePathFromViteEnv,\n stripAppBasePath as canonicalStripAppBasePath,\n} from \"./app-base-path.js\";\nimport { BETTER_AUTH_COOKIE_PREFIX, COOKIE_NAME, getSession } from \"./auth.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport { requestHasEmbedAuthMarker } from \"./embed-session.js\";\nimport {\n EMBED_SESSION_COOKIE,\n EMBED_TOKEN_QUERY_PARAM,\n} from \"../shared/embed-auth.js\";\nimport {\n AGENT_NATIVE_SOCIAL_IMAGE_ALT,\n AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT,\n AGENT_NATIVE_SOCIAL_IMAGE_PATH,\n AGENT_NATIVE_SOCIAL_IMAGE_TYPE,\n AGENT_NATIVE_SOCIAL_IMAGE_WIDTH,\n} from \"../shared/social-meta.js\";\nimport {\n DEFAULT_SSR_CACHE_HEADERS,\n DEFAULT_SPECULATION_RULES_PATH,\n} from \"../shared/cache-control.js\";\n\nexport {\n DEFAULT_SSR_CACHE_HEADERS,\n DEFAULT_SPECULATION_RULES_HEADER,\n DEFAULT_SSR_CACHE_CONTROL,\n} from \"../shared/cache-control.js\";\nconst ANONYMOUS_SESSION_COOKIE_NAMES = new Set([\"an_docs_session\"]);\nconst BETTER_AUTH_SESSION_COOKIE_RE = /\\.session_(?:token|data)$/;\n\n/**\n * Read the active org for a request without forcing every template to bundle\n * the org module. Mirrors what `core-routes-plugin` does for action handlers.\n *\n * Fast path: when the session already carries a valid orgId (backfilled by\n * backfillSessionOrg during getSession), return it directly — no additional\n * org_members round trip. Only when the session has no orgId do we fall\n * through to getOrgContext for the full membership lookup.\n */\nasync function readOrgIdForEvent(\n event: H3Event,\n session: Awaited<ReturnType<typeof getSession>>,\n): Promise<string | undefined> {\n // Reuse orgId already resolved by backfillSessionOrg inside getSession.\n const sessionOrgId =\n typeof session?.orgId === \"string\" && session.orgId.trim()\n ? session.orgId.trim()\n : undefined;\n if (sessionOrgId) return sessionOrgId;\n\n // No orgId on the session — full org_members lookup needed.\n // getOrgContext is per-event memoized, so this is at most one DB read\n // even if other request code calls getOrgContext independently.\n try {\n const { getOrgContext } = await import(\"../org/context.js\");\n const ctx = await getOrgContext(event);\n return ctx?.orgId ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction getAppBasePath(): string {\n return getAppBasePathFromViteEnv();\n}\n\nfunction stripAppBasePath(pathname: string): string {\n return canonicalStripAppBasePath(pathname, getAppBasePath());\n}\n\nfunction stripBasePath(pathname: string, basePath: string): string {\n if (!basePath) return pathname;\n if (pathname === basePath) return \"/\";\n if (pathname.startsWith(`${basePath}/`)) {\n return pathname.slice(basePath.length) || \"/\";\n }\n return pathname;\n}\n\nfunction requestWithPathname(\n request: Request,\n pathname: string,\n basePath: string,\n): Request {\n const url = new URL(request.url);\n let changed = false;\n if (basePath && pathname === \"/__manifest\") {\n const paths = url.searchParams.get(\"paths\");\n if (paths) {\n const strippedPaths = paths\n .split(\",\")\n .map((path) => stripBasePath(path, basePath))\n .join(\",\");\n if (strippedPaths !== paths) {\n url.searchParams.set(\"paths\", strippedPaths);\n changed = true;\n }\n }\n }\n if (url.pathname !== pathname) {\n url.pathname = pathname;\n changed = true;\n }\n if (!changed) return request;\n const init: RequestInit & { duplex?: \"half\" } = {\n method: request.method,\n headers: request.headers,\n signal: request.signal,\n };\n if (request.body && ![\"GET\", \"HEAD\"].includes(request.method.toUpperCase())) {\n init.body = request.body;\n init.duplex = \"half\";\n }\n return new Request(url, init);\n}\n\nfunction prefixMountedPath(path: string, basePath: string): string {\n if (!basePath || !path.startsWith(\"/\") || path.startsWith(\"//\")) return path;\n if (path === basePath || path.startsWith(`${basePath}/`)) return path;\n return `${basePath}${path}`;\n}\n\nfunction prefixMountedHtml(html: string, basePath: string): string {\n if (!basePath) return html;\n return html\n .replace(\n /\\b(href|src|action|formaction|poster)=([\"'])(\\/(?!\\/)[^\"']*)\\2/g,\n (_match, attr: string, quote: string, path: string) =>\n `${attr}=${quote}${prefixMountedPath(path, basePath)}${quote}`,\n )\n .replace(/url\\(([\"']?)(\\/(?!\\/)[^)'\" ]+)\\1\\)/g, (_match, quote, path) => {\n const q = quote || \"\";\n return `url(${q}${prefixMountedPath(path, basePath)}${q})`;\n });\n}\n\nfunction injectHeadScript(html: string, script: string | null): string {\n if (!script) return html;\n const headCloseIdx = html.indexOf(\"</head>\");\n if (headCloseIdx === -1) return html;\n return html.slice(0, headCloseIdx) + script + html.slice(headCloseIdx);\n}\n\nconst OG_IMAGE_META_RE = /<meta\\b(?=[^>]*\\bproperty=([\"'])og:image\\1)[^>]*>/i;\nconst TWITTER_CARD_META_RE =\n /<meta\\b(?=[^>]*\\bname=([\"'])twitter:card\\1)[^>]*>/i;\nconst TWITTER_IMAGE_META_RE =\n /<meta\\b(?=[^>]*\\bname=([\"'])twitter:image\\1)[^>]*>/i;\n\nfunction defaultSocialImageUrl(requestUrl: string, basePath: string): string {\n return new URL(\n prefixMountedPath(AGENT_NATIVE_SOCIAL_IMAGE_PATH, basePath),\n requestUrl,\n ).toString();\n}\n\nfunction injectDefaultSocialImageMeta(html: string, imageUrl: string): string {\n const headCloseIdx = html.indexOf(\"</head>\");\n if (headCloseIdx === -1) return html;\n\n const hasAnySocialImage =\n OG_IMAGE_META_RE.test(html) || TWITTER_IMAGE_META_RE.test(html);\n const tags: string[] = [];\n\n if (!hasAnySocialImage) {\n tags.push(`<meta property=\"og:image\" content=\"${imageUrl}\">`);\n tags.push(`<meta property=\"og:image:secure_url\" content=\"${imageUrl}\">`);\n tags.push(\n `<meta property=\"og:image:type\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_TYPE}\">`,\n );\n tags.push(\n `<meta property=\"og:image:width\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_WIDTH}\">`,\n );\n tags.push(\n `<meta property=\"og:image:height\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT}\">`,\n );\n tags.push(\n `<meta property=\"og:image:alt\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_ALT}\">`,\n );\n }\n if (!TWITTER_CARD_META_RE.test(html)) {\n tags.push(`<meta name=\"twitter:card\" content=\"summary_large_image\">`);\n }\n if (!hasAnySocialImage) {\n tags.push(`<meta name=\"twitter:image\" content=\"${imageUrl}\">`);\n tags.push(\n `<meta name=\"twitter:image:alt\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_ALT}\">`,\n );\n }\n\n if (tags.length === 0) return html;\n return html.slice(0, headCloseIdx) + tags.join(\"\") + html.slice(headCloseIdx);\n}\n\nfunction requestHasAuthSignal(event: H3Event): boolean {\n const headers = event.req.headers;\n return Boolean(\n headers.get(\"authorization\") ||\n requestHasAuthenticatedCookie(headers.get(\"cookie\")) ||\n event.url.searchParams.has(EMBED_TOKEN_QUERY_PARAM) ||\n event.url.searchParams.has(\"_session\") ||\n requestHasEmbedAuthMarker(event),\n );\n}\n\nfunction requestHasAuthenticatedCookie(cookieHeader: string | null): boolean {\n if (!cookieHeader) return false;\n return cookieHeader\n .split(\";\")\n .map((cookie) => cookie.trim().split(\"=\", 1)[0]?.trim())\n .filter((name): name is string => Boolean(name))\n .some(isAuthenticatedCookieName);\n}\n\nfunction isAuthenticatedCookieName(name: string): boolean {\n if (ANONYMOUS_SESSION_COOKIE_NAMES.has(name)) return false;\n const bareName = name.replace(/^__(?:Secure|Host)-/, \"\");\n return (\n bareName === COOKIE_NAME ||\n bareName === EMBED_SESSION_COOKIE ||\n bareName === \"an_session\" ||\n bareName === \"an_session_workspace\" ||\n bareName.startsWith(\"an_session_\") ||\n bareName === `${BETTER_AUTH_COOKIE_PREFIX}.session_token` ||\n bareName === `${BETTER_AUTH_COOKIE_PREFIX}.session_data` ||\n BETTER_AUTH_SESSION_COOKIE_RE.test(bareName)\n );\n}\n\nconst PRIVATE_NO_STORE = \"private, no-store\";\n\nfunction isSsrHtmlOrDataResponse(\n headers: Headers,\n status: number,\n pathname: string,\n): boolean {\n if (status < 200 || status >= 400) return false;\n const contentType = headers.get(\"content-type\")?.toLowerCase() ?? \"\";\n if (contentType.includes(\"text/html\")) return true;\n return pathname.endsWith(\".data\") && contentType.includes(\"text/x-script\");\n}\n\n/**\n * Apply the correct SSR cache policy to the response headers.\n *\n * Anonymous requests (no auth signal on the incoming request) get the public\n * stale-while-revalidate default so the CDN can serve shared app-shell HTML\n * and React Router loader data to every unauthenticated visitor without\n * hammering origin.\n *\n * Authenticated requests must never be publicly CDN-cached: the loader may\n * have embedded session-personalized data. If the route already returned a\n * Cache-Control header we respect it; otherwise we fall back to\n * `private, no-store` so the browser re-fetches but no shared cache stores\n * the response.\n *\n * The distinction is on the *incoming* auth signal, not on whether the loader\n * actually used the session — that would require inspecting the response body.\n * Erring toward private for any credentialed request is the safe default.\n */\nfunction applyDefaultSsrCacheHeader(\n headers: Headers,\n status: number,\n pathname: string,\n hasAuthSignal: boolean,\n) {\n if (!isSsrHtmlOrDataResponse(headers, status, pathname)) return;\n\n if (hasAuthSignal) {\n // A route that explicitly opts into public caching (e.g. a share page that\n // accepts an optional auth cookie) can signal intent via a `public` directive.\n // Any other route-level or framework-default value (no-cache, private, unset)\n // is overridden with private/no-store so no shared CDN cache stores a\n // potentially personalized response.\n const existingCc = headers.get(\"cache-control\") ?? \"\";\n if (!existingCc.includes(\"public\")) {\n headers.set(\"cache-control\", PRIVATE_NO_STORE);\n }\n // Never propagate CDN-specific cache headers on authenticated responses,\n // regardless of what the route set.\n headers.delete(\"cdn-cache-control\");\n headers.delete(\"netlify-cdn-cache-control\");\n return;\n }\n\n // Netlify Functions/proxies are not cached by default, and production docs\n // requests often carry stale auth/doc cookies. Keep all three cache headers:\n // Cache-Control for browsers, CDN-Cache-Control for generic CDNs, and\n // Netlify-CDN-Cache-Control (with durable) so Netlify's shared cache actually\n // serves SSR HTML/.data instead of forwarding every request to origin.\n for (const [name, value] of Object.entries(DEFAULT_SSR_CACHE_HEADERS)) {\n headers.set(name, value);\n }\n}\n\nfunction applyDefaultSpeculationRulesHeader(\n headers: Headers,\n status: number,\n basePath: string,\n) {\n if (status < 200 || status >= 400) return;\n if (headers.has(\"speculation-rules\")) return;\n\n const contentType = headers.get(\"content-type\")?.toLowerCase() ?? \"\";\n if (!contentType.includes(\"text/html\")) return;\n\n // Cloudflare Speed Brain injects its own Speculation-Rules header when the\n // origin omits one. Those browser prefetches carry `Sec-Purpose: prefetch`,\n // and Cloudflare refuses cache-ineligible dynamic pages with a 503 before\n // the request can reach Netlify/origin. We publish an explicit no-op ruleset\n // by default so Cloudflare does not inject its edge prefetch rules. Preserve\n // an app-provided Speculation-Rules header above if a template deliberately\n // owns this behavior.\n const rulesPath = prefixMountedPath(DEFAULT_SPECULATION_RULES_PATH, basePath);\n headers.set(\"speculation-rules\", `\"${rulesPath}\"`);\n}\n\n/**\n * Extract the plain JS body from a `<script ...>body</script>` string.\n * Returns `null` if the input is falsy or has no recognisable `</script>` end.\n * Used to compute the sha256 hash of framework-injected inline scripts so the\n * hash can be listed in the `script-src` CSP directive without relying on\n * `'unsafe-inline'`.\n */\nfunction extractScriptBody(scriptTag: string | null): string | null {\n if (!scriptTag) return null;\n const start = scriptTag.indexOf(\">\") + 1;\n const end = scriptTag.lastIndexOf(\"</script>\");\n if (start <= 0 || end < start) return null;\n return scriptTag.slice(start, end);\n}\n\n/**\n * Apply a Content-Security-Policy header to HTML document responses.\n *\n * Two directives are always enforced in production:\n *\n * - `object-src 'none'` — disables Flash / Java / PDF plugin execution,\n * which are a reliable code-execution vector even in modern browsers.\n * - `base-uri 'self'` — prevents a `<base href=\"...\">` injection from\n * hijacking all relative URLs in the document (a common attack target when\n * user-controlled content reaches the HTML).\n *\n * A third directive, `script-src`, is emitted via `Content-Security-Policy-\n * Report-Only` rather than enforced. The framework injects one deterministic\n * inline script per process (the Sentry config block — its hash is computed\n * once at process startup from the resolved env vars). Templates additionally\n * render a theme-init inline script whose exact content varies by template\n * (default theme param, custom docs variant, etc.) and which is rendered by\n * React Router, not this handler, so its hash is not available here. Shipping\n * script-src as Report-Only surfaces violations without breaking template\n * customisations; teams can graduate to enforcement once their hashes are\n * enumerated.\n *\n * Skipped in development (`NODE_ENV !== 'production'`) so HMR eval and Vite\n * dev-server injects are never blocked. Set `AGENT_NATIVE_DISABLE_DOC_CSP=1`\n * to opt out in production for a template with exotic needs.\n */\nfunction applyDocumentCsp(headers: Headers, sentryScript: string | null): void {\n if (process.env.NODE_ENV !== \"production\") return;\n if (process.env.AGENT_NATIVE_DISABLE_DOC_CSP === \"1\") return;\n\n // object-src / base-uri: enforced; neither directive mentions scripts, so\n // they are safe even when a template's inline script hashes are unknown.\n const existing = headers.get(\"content-security-policy\") ?? \"\";\n if (!existing) {\n headers.set(\n \"content-security-policy\",\n \"object-src 'none'; base-uri 'self'\",\n );\n }\n\n // script-src as Report-Only: list 'self' plus the hash for the Sentry config\n // script the SSR handler injects into every HTML response (the hash is\n // computed once from the resolved env vars at process startup). Template\n // theme-init hashes are NOT included here — see function comment above.\n const sentryBody = extractScriptBody(sentryScript);\n const sentryHash = sentryBody ? computeInlineScriptHash(sentryBody) : null;\n const scriptSrcTokens = [\"'self'\", ...(sentryHash ? [sentryHash] : [])];\n const scriptSrc = `script-src ${scriptSrcTokens.join(\" \")}`;\n\n const existingRo = headers.get(\"content-security-policy-report-only\") ?? \"\";\n if (!existingRo) {\n headers.set(\"content-security-policy-report-only\", scriptSrc);\n }\n}\n\nfunction isFrameworkOrAssetPath(pathname: string): boolean {\n return (\n pathname.startsWith(\"/.well-known/\") ||\n pathname.startsWith(\"/_agent_native/\") ||\n pathname.startsWith(\"/_agent-native/\") ||\n pathname.startsWith(\"/api/\") ||\n pathname.startsWith(\"/@vite/\") ||\n pathname.startsWith(\"/@id/\") ||\n pathname.startsWith(\"/@fs/\") ||\n pathname === \"/@react-refresh\" ||\n pathname === \"/__vite_ping\" ||\n pathname === \"/__open-in-editor\" ||\n pathname === \"/favicon.ico\" ||\n pathname === \"/favicon.png\" ||\n (/\\.\\w+$/.test(pathname) && !pathname.endsWith(\".data\"))\n );\n}\n\nasync function rewriteMountedResponse(\n response: Response,\n basePath: string,\n pathname: string,\n requestUrl: string,\n hasAuthSignal: boolean,\n): Promise<Response> {\n const sentryClientConfigScript = getSentryClientConfigScript();\n const headers = new Headers(response.headers);\n applyDefaultSsrCacheHeader(headers, response.status, pathname, hasAuthSignal);\n applyDefaultSpeculationRulesHeader(headers, response.status, basePath);\n\n const location = headers.get(\"location\");\n if (location?.startsWith(\"/\") && !location.startsWith(\"//\")) {\n headers.set(\"location\", prefixMountedPath(location, basePath));\n }\n\n const contentType = headers.get(\"content-type\") ?? \"\";\n if (!contentType.toLowerCase().includes(\"text/html\") || !response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n const html = await response.text();\n headers.delete(\"content-length\");\n applyDocumentCsp(headers, sentryClientConfigScript);\n return new Response(\n injectHeadScript(\n injectDefaultSocialImageMeta(\n prefixMountedHtml(html, basePath),\n defaultSocialImageUrl(requestUrl, basePath),\n ),\n sentryClientConfigScript,\n ),\n {\n status: response.status,\n statusText: response.statusText,\n headers,\n },\n );\n}\n\n/**\n * Create an h3 catch-all that hands page routes to React Router and\n * returns 404 for framework / asset paths that React Router doesn't own.\n */\nexport function createH3SSRHandler(getBuild: () => Promise<unknown> | unknown) {\n const handler = createRequestHandler(getBuild as any);\n return defineEventHandler(async (event) => {\n const basePath = getAppBasePath();\n const p = stripAppBasePath(event.url.pathname);\n if (isFrameworkOrAssetPath(p)) {\n return new Response(null, { status: 404 });\n }\n try {\n const request = requestWithPathname(event.req as Request, p, basePath);\n // Pin the active session onto the async request context so React Router\n // loaders that call `getRequestUserEmail()` / `accessFilter()` see the\n // signed-in user. Without this, SSR loaders fall through to the\n // unauthenticated branch even when the user is logged in — which broke\n // shared-deck \"Presentation link\" access for non-public decks.\n let session: Awaited<ReturnType<typeof getSession>> | null = null;\n const hasAuthSignal = requestHasAuthSignal(event);\n if (hasAuthSignal) {\n try {\n session = await getSession(event);\n } catch {\n // Auth lookup failures must not break SSR; treat as unauthenticated.\n }\n }\n // readOrgIdForEvent fast-paths when session.orgId is already backfilled\n // (the common case), avoiding a duplicate org_members query. A second\n // query only fires for authenticated users whose session has no orgId.\n const orgId = session?.email\n ? await readOrgIdForEvent(event, session)\n : undefined;\n const ctx = {\n userEmail: session?.email ?? undefined,\n orgId,\n };\n if (request.method === \"HEAD\") {\n const getRequest = new Request(request.url, {\n method: \"GET\",\n headers: request.headers,\n signal: request.signal,\n });\n const response = await runWithRequestContext(ctx, () =>\n handler(getRequest),\n );\n return await rewriteMountedResponse(\n new Response(null, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n }),\n basePath,\n p,\n request.url,\n hasAuthSignal,\n );\n }\n return await rewriteMountedResponse(\n await runWithRequestContext(ctx, () => handler(request)),\n basePath,\n p,\n request.url,\n hasAuthSignal,\n );\n } catch (err) {\n // Log the full stack server-side, but never leak it to the client.\n // Stack traces expose file paths, library versions, and code structure\n // that aid reconnaissance attacks. In dev we surface the message text\n // so devtools shows something useful; in prod we return a bare 500.\n console.error(\"[ssr-handler] SSR error:\", err);\n const isProd = process.env.NODE_ENV === \"production\";\n const body = isProd\n ? \"Internal Server Error\"\n : `Internal Server Error: ${(err as Error)?.message ?? err}`;\n return new Response(body, {\n status: 500,\n headers: { \"content-type\": \"text/plain\" },\n });\n }\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ssr-handler.js","sourceRoot":"","sources":["../../src/server/ssr-handler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared SSR catch-all handler for React Router framework mode.\n *\n * Templates wire this up via:\n *\n * // server/routes/[...page].get.ts\n * import { createH3SSRHandler } from \"@agent-native/core/server/ssr-handler\";\n * export default createH3SSRHandler(\n * () => import(\"virtual:react-router/server-build\"),\n * );\n *\n * The `getBuild` callback MUST live in the template's own source so Vite's\n * @react-router/dev plugin can resolve the `virtual:` module. Pulling the\n * import into core (e.g. via a re-export) puts it in node_modules where\n * Vite's SSR externalizer leaves it untouched and Node's ESM loader rejects\n * the unknown scheme — silently 302'ing every request to \"/\".\n */\nimport { createRequestHandler } from \"react-router\";\nimport { defineEventHandler } from \"h3\";\nimport { getSentryClientConfigScript } from \"./sentry-config.js\";\nimport { computeInlineScriptHash } from \"./security-headers.js\";\nimport {\n getAppBasePathFromViteEnv,\n stripAppBasePath as canonicalStripAppBasePath,\n} from \"./app-base-path.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport {\n AGENT_NATIVE_SOCIAL_IMAGE_ALT,\n AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT,\n AGENT_NATIVE_SOCIAL_IMAGE_PATH,\n AGENT_NATIVE_SOCIAL_IMAGE_TYPE,\n AGENT_NATIVE_SOCIAL_IMAGE_WIDTH,\n} from \"../shared/social-meta.js\";\nimport {\n DEFAULT_SSR_CACHE_HEADERS,\n DEFAULT_SPECULATION_RULES_PATH,\n} from \"../shared/cache-control.js\";\n\nexport {\n DEFAULT_SSR_CACHE_HEADERS,\n DEFAULT_SPECULATION_RULES_HEADER,\n DEFAULT_SSR_CACHE_CONTROL,\n} from \"../shared/cache-control.js\";\n\nfunction getAppBasePath(): string {\n return getAppBasePathFromViteEnv();\n}\n\nfunction stripAppBasePath(pathname: string): string {\n return canonicalStripAppBasePath(pathname, getAppBasePath());\n}\n\nfunction stripBasePath(pathname: string, basePath: string): string {\n if (!basePath) return pathname;\n if (pathname === basePath) return \"/\";\n if (pathname.startsWith(`${basePath}/`)) {\n return pathname.slice(basePath.length) || \"/\";\n }\n return pathname;\n}\n\nfunction requestWithPathname(\n request: Request,\n pathname: string,\n basePath: string,\n): Request {\n const url = new URL(request.url);\n let changed = false;\n if (basePath && pathname === \"/__manifest\") {\n const paths = url.searchParams.get(\"paths\");\n if (paths) {\n const strippedPaths = paths\n .split(\",\")\n .map((path) => stripBasePath(path, basePath))\n .join(\",\");\n if (strippedPaths !== paths) {\n url.searchParams.set(\"paths\", strippedPaths);\n changed = true;\n }\n }\n }\n if (url.pathname !== pathname) {\n url.pathname = pathname;\n changed = true;\n }\n if (!changed) return request;\n const init: RequestInit & { duplex?: \"half\" } = {\n method: request.method,\n headers: request.headers,\n signal: request.signal,\n };\n if (request.body && ![\"GET\", \"HEAD\"].includes(request.method.toUpperCase())) {\n init.body = request.body;\n init.duplex = \"half\";\n }\n return new Request(url, init);\n}\n\nfunction prefixMountedPath(path: string, basePath: string): string {\n if (!basePath || !path.startsWith(\"/\") || path.startsWith(\"//\")) return path;\n if (path === basePath || path.startsWith(`${basePath}/`)) return path;\n return `${basePath}${path}`;\n}\n\nfunction prefixMountedHtml(html: string, basePath: string): string {\n if (!basePath) return html;\n return html\n .replace(\n /\\b(href|src|action|formaction|poster)=([\"'])(\\/(?!\\/)[^\"']*)\\2/g,\n (_match, attr: string, quote: string, path: string) =>\n `${attr}=${quote}${prefixMountedPath(path, basePath)}${quote}`,\n )\n .replace(/url\\(([\"']?)(\\/(?!\\/)[^)'\" ]+)\\1\\)/g, (_match, quote, path) => {\n const q = quote || \"\";\n return `url(${q}${prefixMountedPath(path, basePath)}${q})`;\n });\n}\n\nfunction injectHeadScript(html: string, script: string | null): string {\n if (!script) return html;\n const headCloseIdx = html.indexOf(\"</head>\");\n if (headCloseIdx === -1) return html;\n return html.slice(0, headCloseIdx) + script + html.slice(headCloseIdx);\n}\n\nconst OG_IMAGE_META_RE = /<meta\\b(?=[^>]*\\bproperty=([\"'])og:image\\1)[^>]*>/i;\nconst TWITTER_CARD_META_RE =\n /<meta\\b(?=[^>]*\\bname=([\"'])twitter:card\\1)[^>]*>/i;\nconst TWITTER_IMAGE_META_RE =\n /<meta\\b(?=[^>]*\\bname=([\"'])twitter:image\\1)[^>]*>/i;\n\nfunction defaultSocialImageUrl(requestUrl: string, basePath: string): string {\n return new URL(\n prefixMountedPath(AGENT_NATIVE_SOCIAL_IMAGE_PATH, basePath),\n requestUrl,\n ).toString();\n}\n\nfunction injectDefaultSocialImageMeta(html: string, imageUrl: string): string {\n const headCloseIdx = html.indexOf(\"</head>\");\n if (headCloseIdx === -1) return html;\n\n const hasAnySocialImage =\n OG_IMAGE_META_RE.test(html) || TWITTER_IMAGE_META_RE.test(html);\n const tags: string[] = [];\n\n if (!hasAnySocialImage) {\n tags.push(`<meta property=\"og:image\" content=\"${imageUrl}\">`);\n tags.push(`<meta property=\"og:image:secure_url\" content=\"${imageUrl}\">`);\n tags.push(\n `<meta property=\"og:image:type\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_TYPE}\">`,\n );\n tags.push(\n `<meta property=\"og:image:width\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_WIDTH}\">`,\n );\n tags.push(\n `<meta property=\"og:image:height\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT}\">`,\n );\n tags.push(\n `<meta property=\"og:image:alt\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_ALT}\">`,\n );\n }\n if (!TWITTER_CARD_META_RE.test(html)) {\n tags.push(`<meta name=\"twitter:card\" content=\"summary_large_image\">`);\n }\n if (!hasAnySocialImage) {\n tags.push(`<meta name=\"twitter:image\" content=\"${imageUrl}\">`);\n tags.push(\n `<meta name=\"twitter:image:alt\" content=\"${AGENT_NATIVE_SOCIAL_IMAGE_ALT}\">`,\n );\n }\n\n if (tags.length === 0) return html;\n return html.slice(0, headCloseIdx) + tags.join(\"\") + html.slice(headCloseIdx);\n}\n\nfunction isSsrHtmlOrDataResponse(\n headers: Headers,\n status: number,\n pathname: string,\n): boolean {\n if (status < 200 || status >= 400) return false;\n const contentType = headers.get(\"content-type\")?.toLowerCase() ?? \"\";\n if (contentType.includes(\"text/html\")) return true;\n return pathname.endsWith(\".data\") && contentType.includes(\"text/x-script\");\n}\n\n/**\n * Apply the SSR cache policy to the response headers.\n *\n * ┌──────────────────────────────────────────────────────────────────────────┐\n * │ SSR IS A PUBLIC, HARD-CDN-CACHED SHELL — SERVED IDENTICALLY TO EVERYONE. │\n * │ │\n * │ Every SSR HTML / React Router `.data` response gets the same public │\n * │ stale-while-revalidate policy for ALL visitors, authenticated or not, so │\n * │ the edge serves one shared copy and never stampedes origin. │\n * │ │\n * │ DO NOT reintroduce per-user / cookie-based cache variation here (no │\n * │ `private`, no `no-store`, no `Vary: Cookie`, no \"authenticated → don't │\n * │ cache\" branch). That makes pages uncacheable for every logged-in visitor, │\n * │ which is slow and expensive — exactly the regression this guardrail │\n * │ prevents. The reason it is SAFE to hard-cache is that the SSR response is │\n * │ impersonal: `createH3SSRHandler` renders without reading the request's │\n * │ session/cookies, so there is no per-user data baked into the HTML. ALL │\n * │ per-user state (who's logged in, private records, access checks) is │\n * │ resolved CLIENT-SIDE after load. Keep it that way: if you need the SSR │\n * │ output to differ per user, the fix is to move that work client-side, not │\n * │ to disable caching here. │\n * └──────────────────────────────────────────────────────────────────────────┘\n */\nfunction applyDefaultSsrCacheHeader(\n headers: Headers,\n status: number,\n pathname: string,\n) {\n if (!isSsrHtmlOrDataResponse(headers, status, pathname)) return;\n\n // Netlify Functions/proxies are not cached by default. Set all three cache\n // headers: Cache-Control for browsers, CDN-Cache-Control for generic CDNs,\n // and Netlify-CDN-Cache-Control (with durable) so Netlify's shared cache\n // actually serves SSR HTML/.data from the edge instead of forwarding every\n // request to origin — for every visitor, authenticated or not.\n for (const [name, value] of Object.entries(DEFAULT_SSR_CACHE_HEADERS)) {\n headers.set(name, value);\n }\n}\n\nfunction applyDefaultSpeculationRulesHeader(\n headers: Headers,\n status: number,\n basePath: string,\n) {\n if (status < 200 || status >= 400) return;\n if (headers.has(\"speculation-rules\")) return;\n\n const contentType = headers.get(\"content-type\")?.toLowerCase() ?? \"\";\n if (!contentType.includes(\"text/html\")) return;\n\n // Cloudflare Speed Brain injects its own Speculation-Rules header when the\n // origin omits one. Those browser prefetches carry `Sec-Purpose: prefetch`,\n // and Cloudflare refuses cache-ineligible dynamic pages with a 503 before\n // the request can reach Netlify/origin. We publish an explicit no-op ruleset\n // by default so Cloudflare does not inject its edge prefetch rules. Preserve\n // an app-provided Speculation-Rules header above if a template deliberately\n // owns this behavior.\n const rulesPath = prefixMountedPath(DEFAULT_SPECULATION_RULES_PATH, basePath);\n headers.set(\"speculation-rules\", `\"${rulesPath}\"`);\n}\n\n/**\n * Extract the plain JS body from a `<script ...>body</script>` string.\n * Returns `null` if the input is falsy or has no recognisable `</script>` end.\n * Used to compute the sha256 hash of framework-injected inline scripts so the\n * hash can be listed in the `script-src` CSP directive without relying on\n * `'unsafe-inline'`.\n */\nfunction extractScriptBody(scriptTag: string | null): string | null {\n if (!scriptTag) return null;\n const start = scriptTag.indexOf(\">\") + 1;\n const end = scriptTag.lastIndexOf(\"</script>\");\n if (start <= 0 || end < start) return null;\n return scriptTag.slice(start, end);\n}\n\n/**\n * Apply a Content-Security-Policy header to HTML document responses.\n *\n * Two directives are always enforced in production:\n *\n * - `object-src 'none'` — disables Flash / Java / PDF plugin execution,\n * which are a reliable code-execution vector even in modern browsers.\n * - `base-uri 'self'` — prevents a `<base href=\"...\">` injection from\n * hijacking all relative URLs in the document (a common attack target when\n * user-controlled content reaches the HTML).\n *\n * A third directive, `script-src`, is emitted via `Content-Security-Policy-\n * Report-Only` rather than enforced. The framework injects one deterministic\n * inline script per process (the Sentry config block — its hash is computed\n * once at process startup from the resolved env vars). Templates additionally\n * render a theme-init inline script whose exact content varies by template\n * (default theme param, custom docs variant, etc.) and which is rendered by\n * React Router, not this handler, so its hash is not available here. Shipping\n * script-src as Report-Only surfaces violations without breaking template\n * customisations; teams can graduate to enforcement once their hashes are\n * enumerated.\n *\n * Skipped in development (`NODE_ENV !== 'production'`) so HMR eval and Vite\n * dev-server injects are never blocked. Set `AGENT_NATIVE_DISABLE_DOC_CSP=1`\n * to opt out in production for a template with exotic needs.\n */\nfunction applyDocumentCsp(headers: Headers, sentryScript: string | null): void {\n if (process.env.NODE_ENV !== \"production\") return;\n if (process.env.AGENT_NATIVE_DISABLE_DOC_CSP === \"1\") return;\n\n // object-src / base-uri: enforced; neither directive mentions scripts, so\n // they are safe even when a template's inline script hashes are unknown.\n const existing = headers.get(\"content-security-policy\") ?? \"\";\n if (!existing) {\n headers.set(\n \"content-security-policy\",\n \"object-src 'none'; base-uri 'self'\",\n );\n }\n\n // script-src as Report-Only: list 'self' plus the hash for the Sentry config\n // script the SSR handler injects into every HTML response (the hash is\n // computed once from the resolved env vars at process startup). Template\n // theme-init hashes are NOT included here — see function comment above.\n const sentryBody = extractScriptBody(sentryScript);\n const sentryHash = sentryBody ? computeInlineScriptHash(sentryBody) : null;\n const scriptSrcTokens = [\"'self'\", ...(sentryHash ? [sentryHash] : [])];\n const scriptSrc = `script-src ${scriptSrcTokens.join(\" \")}`;\n\n const existingRo = headers.get(\"content-security-policy-report-only\") ?? \"\";\n if (!existingRo) {\n headers.set(\"content-security-policy-report-only\", scriptSrc);\n }\n}\n\nfunction isFrameworkOrAssetPath(pathname: string): boolean {\n return (\n pathname.startsWith(\"/.well-known/\") ||\n pathname.startsWith(\"/_agent_native/\") ||\n pathname.startsWith(\"/_agent-native/\") ||\n pathname.startsWith(\"/api/\") ||\n pathname.startsWith(\"/@vite/\") ||\n pathname.startsWith(\"/@id/\") ||\n pathname.startsWith(\"/@fs/\") ||\n pathname === \"/@react-refresh\" ||\n pathname === \"/__vite_ping\" ||\n pathname === \"/__open-in-editor\" ||\n pathname === \"/favicon.ico\" ||\n pathname === \"/favicon.png\" ||\n (/\\.\\w+$/.test(pathname) && !pathname.endsWith(\".data\"))\n );\n}\n\nasync function rewriteMountedResponse(\n response: Response,\n basePath: string,\n pathname: string,\n requestUrl: string,\n): Promise<Response> {\n const sentryClientConfigScript = getSentryClientConfigScript();\n const headers = new Headers(response.headers);\n applyDefaultSsrCacheHeader(headers, response.status, pathname);\n applyDefaultSpeculationRulesHeader(headers, response.status, basePath);\n\n const location = headers.get(\"location\");\n if (location?.startsWith(\"/\") && !location.startsWith(\"//\")) {\n headers.set(\"location\", prefixMountedPath(location, basePath));\n }\n\n const contentType = headers.get(\"content-type\") ?? \"\";\n if (!contentType.toLowerCase().includes(\"text/html\") || !response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n const html = await response.text();\n headers.delete(\"content-length\");\n applyDocumentCsp(headers, sentryClientConfigScript);\n return new Response(\n injectHeadScript(\n injectDefaultSocialImageMeta(\n prefixMountedHtml(html, basePath),\n defaultSocialImageUrl(requestUrl, basePath),\n ),\n sentryClientConfigScript,\n ),\n {\n status: response.status,\n statusText: response.statusText,\n headers,\n },\n );\n}\n\n/**\n * Create an h3 catch-all that hands page routes to React Router and\n * returns 404 for framework / asset paths that React Router doesn't own.\n */\nexport function createH3SSRHandler(getBuild: () => Promise<unknown> | unknown) {\n const handler = createRequestHandler(getBuild as any);\n return defineEventHandler(async (event) => {\n const basePath = getAppBasePath();\n const p = stripAppBasePath(event.url.pathname);\n if (isFrameworkOrAssetPath(p)) {\n return new Response(null, { status: 404 });\n }\n try {\n const request = requestWithPathname(event.req as Request, p, basePath);\n // SSR renders an IMPERSONAL public shell — we deliberately do NOT read the\n // request's session/cookies here, and pin an explicitly anonymous request\n // context. That keeps the SSR HTML/.data identical for every visitor so it\n // can be hard-cached at the CDN for everyone (see applyDefaultSsrCacheHeader).\n //\n // Consequence: SSR loaders that call `getRequestUserEmail()` / `accessFilter()`\n // always see the unauthenticated branch and render public content only. Any\n // per-user view (private records, share-grant access, who's logged in) MUST\n // be resolved CLIENT-SIDE after load, never baked into SSR. Do not re-pin the\n // session here to \"fix\" a per-user page — that silently makes the page\n // uncacheable and/or leaks one user's data into another's cached copy.\n const ctx = { userEmail: undefined, orgId: undefined };\n if (request.method === \"HEAD\") {\n const getRequest = new Request(request.url, {\n method: \"GET\",\n headers: request.headers,\n signal: request.signal,\n });\n const response = await runWithRequestContext(ctx, () =>\n handler(getRequest),\n );\n return await rewriteMountedResponse(\n new Response(null, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n }),\n basePath,\n p,\n request.url,\n );\n }\n return await rewriteMountedResponse(\n await runWithRequestContext(ctx, () => handler(request)),\n basePath,\n p,\n request.url,\n );\n } catch (err) {\n // Log the full stack server-side, but never leak it to the client.\n // Stack traces expose file paths, library versions, and code structure\n // that aid reconnaissance attacks. In dev we surface the message text\n // so devtools shows something useful; in prod we return a bare 500.\n console.error(\"[ssr-handler] SSR error:\", err);\n const isProd = process.env.NODE_ENV === \"production\";\n const body = isProd\n ? \"Internal Server Error\"\n : `Internal Server Error: ${(err as Error)?.message ?? err}`;\n return new Response(body, {\n status: 500,\n headers: { \"content-type\": \"text/plain\" },\n });\n }\n });\n}\n"]}
|
|
@@ -2,9 +2,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
2
2
|
resourceType: string;
|
|
3
3
|
resourceId: string;
|
|
4
4
|
}, {
|
|
5
|
-
ownerEmail:
|
|
6
|
-
visibility:
|
|
7
|
-
shares:
|
|
5
|
+
ownerEmail: any;
|
|
6
|
+
visibility: any;
|
|
7
|
+
shares: any[];
|
|
8
8
|
policy: {
|
|
9
9
|
allowPublic: boolean;
|
|
10
10
|
requireOrgMemberForUserShares: boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
declare const _default: import("../../action.js").ActionDefinition<{
|
|
2
2
|
resourceType: string;
|
|
3
3
|
resourceId: string;
|
|
4
|
-
visibility: "
|
|
4
|
+
visibility: "public" | "private" | "org";
|
|
5
5
|
}, {
|
|
6
6
|
ok: boolean;
|
|
7
|
-
visibility: "
|
|
7
|
+
visibility: "public" | "private" | "org";
|
|
8
8
|
}>;
|
|
9
9
|
export default _default;
|
|
10
10
|
//# sourceMappingURL=set-resource-visibility.d.ts.map
|
|
@@ -3,11 +3,11 @@ export declare function resolveShareNotificationUrl(explicitUrl: string | undefi
|
|
|
3
3
|
declare const _default: import("../../action.js").ActionDefinition<{
|
|
4
4
|
resourceType: string;
|
|
5
5
|
resourceId: string;
|
|
6
|
-
principalType: "
|
|
6
|
+
principalType: "org" | "user";
|
|
7
7
|
principalId: string;
|
|
8
|
-
role?: "
|
|
9
|
-
notify?: boolean
|
|
10
|
-
resourceUrl?: string
|
|
8
|
+
role?: "admin" | "viewer" | "editor";
|
|
9
|
+
notify?: boolean;
|
|
10
|
+
resourceUrl?: string;
|
|
11
11
|
}, {
|
|
12
12
|
id: any;
|
|
13
13
|
updated: boolean;
|
package/dist/sharing/schema.d.ts
CHANGED
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
* - `visibility`— coarse default: `'private' | 'org' | 'public'`. Default `'private'`.
|
|
32
32
|
*/
|
|
33
33
|
export declare function ownableColumns(): {
|
|
34
|
-
ownerEmail: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"owner_email", [string, ...string[]], number
|
|
35
|
-
orgId: import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"org_id", [string, ...string[]], number
|
|
36
|
-
visibility: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"visibility", ["private", "org", "public"], number
|
|
34
|
+
ownerEmail: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"owner_email", [string, ...string[]], number>>>;
|
|
35
|
+
orgId: import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"org_id", [string, ...string[]], number>;
|
|
36
|
+
visibility: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/sqlite-core").SQLiteTextBuilderInitial<"visibility", ["private", "org", "public"], number>>>;
|
|
37
37
|
};
|
|
38
38
|
/**
|
|
39
39
|
* Create a companion shares table for an ownable resource. Call this right
|
|
@@ -74,7 +74,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
|
|
|
74
74
|
identity: undefined;
|
|
75
75
|
generated: undefined;
|
|
76
76
|
}, {}, {
|
|
77
|
-
length: number
|
|
77
|
+
length: number;
|
|
78
78
|
}>;
|
|
79
79
|
resourceId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
80
80
|
name: "resource_id";
|
|
@@ -93,14 +93,14 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
|
|
|
93
93
|
identity: undefined;
|
|
94
94
|
generated: undefined;
|
|
95
95
|
}, {}, {
|
|
96
|
-
length: number
|
|
96
|
+
length: number;
|
|
97
97
|
}>;
|
|
98
98
|
principalType: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
99
99
|
name: "principal_type";
|
|
100
100
|
tableName: string;
|
|
101
101
|
dataType: "string";
|
|
102
102
|
columnType: "SQLiteText";
|
|
103
|
-
data: "
|
|
103
|
+
data: "org" | "user";
|
|
104
104
|
driverParam: string;
|
|
105
105
|
notNull: true;
|
|
106
106
|
hasDefault: false;
|
|
@@ -112,7 +112,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
|
|
|
112
112
|
identity: undefined;
|
|
113
113
|
generated: undefined;
|
|
114
114
|
}, {}, {
|
|
115
|
-
length: number
|
|
115
|
+
length: number;
|
|
116
116
|
}>;
|
|
117
117
|
principalId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
118
118
|
name: "principal_id";
|
|
@@ -131,14 +131,14 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
|
|
|
131
131
|
identity: undefined;
|
|
132
132
|
generated: undefined;
|
|
133
133
|
}, {}, {
|
|
134
|
-
length: number
|
|
134
|
+
length: number;
|
|
135
135
|
}>;
|
|
136
136
|
role: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
137
137
|
name: "role";
|
|
138
138
|
tableName: string;
|
|
139
139
|
dataType: "string";
|
|
140
140
|
columnType: "SQLiteText";
|
|
141
|
-
data: "
|
|
141
|
+
data: "admin" | "viewer" | "editor";
|
|
142
142
|
driverParam: string;
|
|
143
143
|
notNull: true;
|
|
144
144
|
hasDefault: true;
|
|
@@ -150,7 +150,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
|
|
|
150
150
|
identity: undefined;
|
|
151
151
|
generated: undefined;
|
|
152
152
|
}, {}, {
|
|
153
|
-
length: number
|
|
153
|
+
length: number;
|
|
154
154
|
}>;
|
|
155
155
|
createdBy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
156
156
|
name: "created_by";
|
|
@@ -169,7 +169,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
|
|
|
169
169
|
identity: undefined;
|
|
170
170
|
generated: undefined;
|
|
171
171
|
}, {}, {
|
|
172
|
-
length: number
|
|
172
|
+
length: number;
|
|
173
173
|
}>;
|
|
174
174
|
createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
175
175
|
name: "created_at";
|
|
@@ -188,7 +188,7 @@ export declare function createSharesTable(tableName: string): import("drizzle-or
|
|
|
188
188
|
identity: undefined;
|
|
189
189
|
generated: undefined;
|
|
190
190
|
}, {}, {
|
|
191
|
-
length: number
|
|
191
|
+
length: number;
|
|
192
192
|
}>;
|
|
193
193
|
};
|
|
194
194
|
dialect: "sqlite";
|
|
@@ -43,10 +43,10 @@ client, and complete authorization-code + PKCE at
|
|
|
43
43
|
`/_agent-native/mcp/oauth/authorize` / `/_agent-native/mcp/oauth/token`.
|
|
44
44
|
Access tokens are audience-bound to the exact MCP URL and carry user/org
|
|
45
45
|
identity plus `mcp:read`, `mcp:write`, and/or `mcp:apps`; refresh tokens are
|
|
46
|
-
stored hashed and rotate. Keep `ACCESS_TOKEN` and `agent-native connect` for
|
|
46
|
+
stored hashed and rotate. Keep `ACCESS_TOKEN` and `pnpm exec agent-native connect` for
|
|
47
47
|
local stdio proxying and fallback clients. The CLI
|
|
48
48
|
uses the OAuth-native URL-only entry for Claude Code/Claude Code CLI by
|
|
49
|
-
default; use the Connect page or `agent-native connect --token <token>` when a
|
|
49
|
+
default; use the Connect page or `npx @agent-native/core@latest connect --token <token>` when a
|
|
50
50
|
client needs explicit bearer headers.
|
|
51
51
|
|
|
52
52
|
## Local → Real Account Migration
|
|
@@ -106,7 +106,7 @@ no-CLI equivalent is `https://<app>/_agent-native/mcp/connect`, which shows
|
|
|
106
106
|
the copyable MCP URL, Claude / ChatGPT / Cursor / Claude Code / Codex / Other
|
|
107
107
|
steps, and static-token fallback for clients that need it.
|
|
108
108
|
|
|
109
|
-
Re-running `agent-native connect <url> --client claude-code` over an older
|
|
109
|
+
Re-running `npx @agent-native/core@latest connect <url> --client claude-code` over an older
|
|
110
110
|
Claude bearer-token entry is the migration path: the CLI replaces
|
|
111
111
|
`Authorization` headers with URL-only OAuth config and tells the user to
|
|
112
112
|
authenticate from `/mcp`.
|
|
@@ -325,10 +325,10 @@ agent sees what the user actually has on screen.
|
|
|
325
325
|
### 5. Advanced: local development & manual setup
|
|
326
326
|
|
|
327
327
|
The hosted `connect` flow above is the recommended path. For local dev, run
|
|
328
|
-
the app (`pnpm dev` / `agent-native dev`) then point a local agent at it:
|
|
328
|
+
the app (`pnpm dev` / `pnpm exec agent-native dev`) then point a local agent at it:
|
|
329
329
|
|
|
330
330
|
```bash
|
|
331
|
-
agent-native mcp install --client claude-code|claude-code-cli|codex|cowork \
|
|
331
|
+
pnpm exec agent-native mcp install --client claude-code|claude-code-cli|codex|cowork \
|
|
332
332
|
[--app <id>] [--scope user|project]
|
|
333
333
|
```
|
|
334
334
|
|
|
@@ -336,7 +336,7 @@ It provisions a token (random `ACCESS_TOKEN` into the workspace `.env` for
|
|
|
336
336
|
local dev, or a `signA2AToken` JWT for a detected hosted origin) and writes an
|
|
337
337
|
idempotent stdio server entry — `.mcp.json` / `~/.claude.json` for Claude Code,
|
|
338
338
|
the `[mcp_servers.*]` block in `~/.codex/config.toml` for Codex, the
|
|
339
|
-
Claude-Code JSON shape for Cowork. The entry runs `agent-native mcp serve
|
|
339
|
+
Claude-Code JSON shape for Cowork. The entry runs `pnpm exec agent-native mcp serve
|
|
340
340
|
--app <id>`, by default a **thin stdio proxy** to the running local app's
|
|
341
341
|
`/_agent-native/mcp` (live registry + HMR + correct deep links stay the single
|
|
342
342
|
source of truth; `--standalone` builds the registry in-process). Companion
|
|
@@ -351,7 +351,7 @@ deliberately exposes only the generic builtins plus actions with
|
|
|
351
351
|
and mutating actions are filtered out (`filterPublicAgentActions`). The full
|
|
352
352
|
surface appears when authenticated as a real caller: a deployed /
|
|
353
353
|
`AGENT_MODE=production` app, or a local app reached through `connect` /
|
|
354
|
-
`agent-native mcp install` (which provisions an identity-bearing token). A
|
|
354
|
+
`pnpm exec agent-native mcp install` (which provisions an identity-bearing token). A
|
|
355
355
|
sparse or empty `tools/list` is diagnostic, not proof of auth failure: check
|
|
356
356
|
OAuth scopes, compact-catalog filtering, and the client/server auth status
|
|
357
357
|
before telling the user they are unauthenticated.
|
|
@@ -395,7 +395,7 @@ before telling the user they are unauthenticated.
|
|
|
395
395
|
- Don't hand-write product UI in `mcpApp.resource.html`; use a real React
|
|
396
396
|
route/component and embed it with `embedApp()`.
|
|
397
397
|
- Don't test Claude full-app embeds against raw Vite dev modules and conclude
|
|
398
|
-
production is broken; use `agent-native start`, a preview deploy, or prod.
|
|
398
|
+
production is broken; use `pnpm exec agent-native start`, a preview deploy, or prod.
|
|
399
399
|
- Don't scope the `navigate` write to the agent token, or pass privileged
|
|
400
400
|
state through the deep link — it's a pure pointer.
|
|
401
401
|
- Don't invent a new navigation mechanism; bridge to the existing
|
|
@@ -136,8 +136,8 @@ Claude/ChatGPT conversation. Hidden context stays in model context; do not put
|
|
|
136
136
|
internal app-state file instructions into the visible prompt. `submit: false`
|
|
137
137
|
stays local as a prefill/review path.
|
|
138
138
|
|
|
139
|
-
When testing Claude through ngrok, use a production build (`agent-native build`
|
|
140
|
-
then `agent-native start`) or a deployed preview/production URL. Claude's
|
|
139
|
+
When testing Claude through ngrok, use a production build (`pnpm exec agent-native build`
|
|
140
|
+
then `pnpm exec agent-native start`) or a deployed preview/production URL. Claude's
|
|
141
141
|
transplant path works with production asset chunks; raw Vite dev modules such
|
|
142
142
|
as `/app/root.tsx` can be app-auth protected and fail dynamic imports from the
|
|
143
143
|
Claude resource origin.
|