forgeos 0.1.0-alpha.58 → 0.1.0-alpha.60

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/AGENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.58 input=195942726f1885a6c7556503abb9f76ac8ee4cfa1bc0725c319a77c97d08c195 content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
1
+ // @forge-generated generator=0.1.0-alpha.60 input=dd73ff0861775ded0c4b42b55e3261a44043d4c09aa3c9f5641d3c23b17e2e6c content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
2
2
  # AGENTS.md
3
3
 
4
4
  <!-- forge-generated:start -->
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # forgeos
2
2
 
3
+ ## 0.1.0-alpha.60
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix the real WorkOS/AuthKit session bridge for Forge runtime calls.
8
+
9
+ - Generated WorkOS React bridges now pass normalized `/session` claims into
10
+ `ForgeProvider` auth so commands, queries, and liveQueries receive user,
11
+ role, permissions, membership, and tenant headers.
12
+ - WorkOS browser env sync now includes optional tenant mapping variables for
13
+ apps that use internal UUID tenants while WorkOS emits hosted `org_...`
14
+ organization ids.
15
+ - WorkOS dev sessions now derive permissions from active Forge policies when
16
+ AuthKit returns a role without permission claims, and normalize WorkOS
17
+ organization ids before cookie-backed runtime calls touch tenant-scoped data.
18
+ - `forge workos doctor` now validates that generated browser bridges pass
19
+ WorkOS claims into Forge auth instead of only exposing a UI session.
20
+
3
21
  ## 0.1.0-alpha.58
4
22
 
5
23
  ### Patch Changes
package/docs/changelog.md CHANGED
@@ -6,6 +6,20 @@ The canonical source file in the repository is `CHANGELOG.md`.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.1.0-alpha.60
10
+
11
+ - Fixed the real WorkOS/AuthKit session bridge so generated React apps pass
12
+ normalized `/session` claims into `ForgeProvider` auth for commands, queries,
13
+ and liveQueries.
14
+ - Added optional WorkOS organization-to-Forge tenant mapping env support for
15
+ apps that use internal UUID tenant ids while WorkOS emits hosted `org_...`
16
+ organization ids.
17
+ - WorkOS dev sessions now derive permissions from active Forge policies when
18
+ AuthKit returns a role without permission claims, then normalize WorkOS
19
+ organization ids before cookie-backed runtime calls touch tenant-scoped data.
20
+ - `forge workos doctor` now validates that generated browser bridges pass
21
+ WorkOS claims into Forge auth instead of only exposing a UI session.
22
+
9
23
  ## 0.1.0-alpha.58
10
24
 
11
25
  - Fixed generated WorkOS AuthKit route helper TypeScript output by reading
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgeos",
3
- "version": "0.1.0-alpha.58",
3
+ "version": "0.1.0-alpha.60",
4
4
  "description": "Agent-native application framework and compiler for building Forge apps without a mandatory dashboard.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1 +1 @@
1
- {"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.58","releaseId":"forgeos@0.1.0-alpha.58+unknown","schemaVersion":"0.1.0"}
1
+ {"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.60","releaseId":"forgeos@0.1.0-alpha.60+unknown","schemaVersion":"0.1.0"}
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.58 input=195942726f1885a6c7556503abb9f76ac8ee4cfa1bc0725c319a77c97d08c195 content=8104f3f07c4474c0d9d56bf89444a70d0a709d06a30739a7153bdb9d054f3ed2
1
+ // @forge-generated generator=0.1.0-alpha.60 input=dd73ff0861775ded0c4b42b55e3261a44043d4c09aa3c9f5641d3c23b17e2e6c content=185c42e22dbf3b1cc6e329af86d71f513f19cde067ec0e4ea0a228df020c30f9
2
2
  export const releaseManifest = {
3
3
  "defaultProvider": "local",
4
4
  "diagnostics": [],
@@ -19,7 +19,7 @@ export const releaseManifest = {
19
19
  "custom"
20
20
  ],
21
21
  "packageName": "forgeos",
22
- "packageVersion": "0.1.0-alpha.58",
23
- "releaseId": "forgeos@0.1.0-alpha.58+unknown",
22
+ "packageVersion": "0.1.0-alpha.60",
23
+ "releaseId": "forgeos@0.1.0-alpha.60+unknown",
24
24
  "schemaVersion": "0.1.0"
25
25
  } as const;
@@ -1819,6 +1819,15 @@ function collectWorkOSChecks(workspaceRoot: string, preferredSeedPath = DEFAULT_
1819
1819
  ["/login", "/logout", "/session"].every((route) => generatedFrontendAuthBridge.includes(route));
1820
1820
  const authBridgeProvidesSessionClaims =
1821
1821
  includesAll(generatedFrontendAuthBridge, ["useForgeWorkOSSession", "/session", "claims"]);
1822
+ const authBridgePassesClaimsToForge =
1823
+ includesAll(generatedFrontendAuthBridge, [
1824
+ "workOSSessionToForgeAuth",
1825
+ "forgeTenantIdForWorkOSOrganization",
1826
+ "workOSAuthProvider",
1827
+ "auth={workOSAuthProvider}",
1828
+ "permissions: claims.permissions",
1829
+ "organizationId: forgeTenantId",
1830
+ ]);
1822
1831
  const authSessionProxyConfigured = webAuthSessionProxyConfigured(workspaceRoot);
1823
1832
 
1824
1833
  return [
@@ -1877,9 +1886,10 @@ function collectWorkOSChecks(workspaceRoot: string, preferredSeedPath = DEFAULT_
1877
1886
  name: "browser-authkit-bridge",
1878
1887
  ok: !hasWeb || generatedFrontendAuthBridge.includes("ForgeProvider") &&
1879
1888
  authBridgeUsesBackendRoutes &&
1880
- authBridgeProvidesSessionClaims,
1889
+ authBridgeProvidesSessionClaims &&
1890
+ authBridgePassesClaimsToForge,
1881
1891
  detail: hasWeb
1882
- ? "generated web/src/lib/workos-auth.tsx bridge uses backend-owned AuthKit routes, ForgeProvider, and normalized /session claims"
1892
+ ? "generated web/src/lib/workos-auth.tsx bridge uses backend-owned AuthKit routes and passes normalized WorkOS claims into ForgeProvider auth"
1883
1893
  : "no web workspace detected",
1884
1894
  },
1885
1895
  {
@@ -552,6 +552,8 @@ function syncWorkOSPublicWebEnv(workspaceRoot: string, frontendWorkspace: string
552
552
  VITE_FORGE_URL: source.VITE_FORGE_URL || "http://localhost:3765",
553
553
  VITE_WORKOS_CLIENT_ID: clientId,
554
554
  VITE_WORKOS_REDIRECT_URI: redirectUri,
555
+ VITE_FORGE_WORKOS_TENANT_MAP: source.VITE_FORGE_WORKOS_TENANT_MAP || "",
556
+ VITE_FORGE_WORKOS_TENANT_ID_FALLBACK: source.VITE_FORGE_WORKOS_TENANT_ID_FALLBACK || "",
555
557
  };
556
558
  const envRel = `${frontendWorkspace}/.env.local`;
557
559
  const envPath = join(workspaceRoot, envRel);
@@ -288,6 +288,9 @@ export function renderWorkosEnvExample(_input: IntegrationTemplateInput): string
288
288
  "VITE_FORGE_URL=http://localhost:3765",
289
289
  "VITE_WORKOS_CLIENT_ID=",
290
290
  "VITE_WORKOS_REDIRECT_URI=http://localhost:5173/callback",
291
+ "# Optional: map hosted WorkOS organization IDs to Forge tenant IDs when your app uses internal UUID tenants.",
292
+ "# VITE_FORGE_WORKOS_TENANT_MAP={\"org_...\":\"11111111-1111-4111-8111-111111111111\"}",
293
+ "# VITE_FORGE_WORKOS_TENANT_ID_FALLBACK=",
291
294
  "",
292
295
  "# WorkOS token claims expected by ForgeOS after forge add auth workos:",
293
296
  "# sub, email, organization_id, role, roles, permissions, organization_membership_id",
@@ -306,6 +309,8 @@ export function renderWorkosReactBridge(_input: IntegrationTemplateInput): strin
306
309
  "const clientId = import.meta.env.VITE_WORKOS_CLIENT_ID as string | undefined;",
307
310
  "const redirectUri = import.meta.env.VITE_WORKOS_REDIRECT_URI as string | undefined;",
308
311
  "const forgeApiUrl = import.meta.env.VITE_FORGE_URL as string | undefined;",
312
+ "const workosTenantMap = import.meta.env.VITE_FORGE_WORKOS_TENANT_MAP as string | undefined;",
313
+ "const workosTenantFallback = import.meta.env.VITE_FORGE_WORKOS_TENANT_ID_FALLBACK as string | undefined;",
309
314
  "",
310
315
  "function workOSApiUrl(path: string): URL {",
311
316
  " if (typeof window !== 'undefined' && forgeApiUrl) {",
@@ -321,12 +326,70 @@ export function renderWorkosReactBridge(_input: IntegrationTemplateInput): strin
321
326
  " return Boolean(clientId && redirectUri);",
322
327
  "}",
323
328
  "",
329
+ "function forgeTenantIdForWorkOSOrganization(claims: ForgeWorkOSBrowserSession['claims']) {",
330
+ " if (!claims) {",
331
+ " return undefined;",
332
+ " }",
333
+ " const explicitTenant = claims.tenant_id ?? claims.forge_tenant_id;",
334
+ " if (explicitTenant) {",
335
+ " return explicitTenant;",
336
+ " }",
337
+ " const organizationId = claims.organization_id;",
338
+ " if (!organizationId) {",
339
+ " return undefined;",
340
+ " }",
341
+ " if (workosTenantMap) {",
342
+ " try {",
343
+ " const parsed = JSON.parse(workosTenantMap) as Record<string, string>;",
344
+ " if (parsed[organizationId]) {",
345
+ " return parsed[organizationId];",
346
+ " }",
347
+ " } catch {",
348
+ " // Keep authentication usable; forge workos doctor validates mapping syntax separately.",
349
+ " }",
350
+ " }",
351
+ " if (organizationId.startsWith('org_') && workosTenantFallback) {",
352
+ " return workosTenantFallback;",
353
+ " }",
354
+ " return organizationId;",
355
+ "}",
356
+ "",
357
+ "function workOSSessionToForgeAuth(session: ForgeWorkOSBrowserSession | null | undefined) {",
358
+ " const claims = session?.claims;",
359
+ " if (!claims?.sub) {",
360
+ " return {};",
361
+ " }",
362
+ " const forgeTenantId = forgeTenantIdForWorkOSOrganization(claims);",
363
+ " return {",
364
+ " userId: claims.sub,",
365
+ " tenantId: forgeTenantId,",
366
+ " organizationId: forgeTenantId,",
367
+ " organizationMembershipId: claims.organization_membership_id,",
368
+ " role: claims.role ?? claims.roles?.[0],",
369
+ " roles: claims.roles,",
370
+ " permissions: claims.permissions,",
371
+ " claims,",
372
+ " };",
373
+ "}",
374
+ "",
375
+ "const workOSAuthProvider = async () => {",
376
+ " const response = await fetch(workOSApiUrl('/session'), { credentials: 'include' });",
377
+ " if (response.status === 401) {",
378
+ " return {};",
379
+ " }",
380
+ " if (!response.ok) {",
381
+ " throw new Error(`WorkOS session request failed with HTTP ${response.status}`);",
382
+ " }",
383
+ " const payload = await response.json() as { ok?: boolean; session?: ForgeWorkOSBrowserSession | null };",
384
+ " return workOSSessionToForgeAuth(payload.ok ? payload.session ?? null : null);",
385
+ "};",
386
+ "",
324
387
  "export function ForgeWorkOSAuthProvider({ children }: { children: ReactNode }) {",
325
388
  " if (!clientId || !redirectUri) {",
326
389
  " throw new Error(\"WorkOS AuthKit requires VITE_WORKOS_CLIENT_ID and VITE_WORKOS_REDIRECT_URI\");",
327
390
  " }",
328
391
  " return (",
329
- " <ForgeProvider url={forgeUrl}>",
392
+ " <ForgeProvider url={forgeUrl} auth={workOSAuthProvider}>",
330
393
  " {children}",
331
394
  " </ForgeProvider>",
332
395
  " );",
@@ -338,6 +401,8 @@ export function renderWorkosReactBridge(_input: IntegrationTemplateInput): strin
338
401
  " sub?: string;",
339
402
  " email?: string;",
340
403
  " organization_id?: string;",
404
+ " tenant_id?: string;",
405
+ " forge_tenant_id?: string;",
341
406
  " organization_membership_id?: string;",
342
407
  " role?: string;",
343
408
  " roles?: string[];",
@@ -836,7 +901,8 @@ export function renderWorkosSession(_input: IntegrationTemplateInput): string {
836
901
  ].join("\n");
837
902
  }
838
903
 
839
- export function renderWorkosAuthRoutes(_input: IntegrationTemplateInput): string {
904
+ export function renderWorkosAuthRoutes(input: IntegrationTemplateInput): string {
905
+ const fallbackRolePermissions = rolePermissions(permissionsFromApp(input));
840
906
  return [
841
907
  "/** Forge generated framework-agnostic WorkOS AuthKit routes. */",
842
908
  'import type { WorkOS } from "@workos-inc/node";',
@@ -878,6 +944,18 @@ export function renderWorkosAuthRoutes(_input: IntegrationTemplateInput): string
878
944
  " };",
879
945
  "}",
880
946
  "",
947
+ "const forgeWorkOSFallbackRolePermissions = {",
948
+ ...Object.entries(fallbackRolePermissions).map(([role, permissions]) =>
949
+ ` ${JSON.stringify(role)}: [${permissions.map((permission) => JSON.stringify(permission)).join(", ")}],`
950
+ ),
951
+ "} as const;",
952
+ "",
953
+ "function fallbackPermissionsForRole(role: string | undefined): string[] {",
954
+ " if (!role) return [];",
955
+ " const permissions = forgeWorkOSFallbackRolePermissions[role.toLowerCase() as keyof typeof forgeWorkOSFallbackRolePermissions];",
956
+ " return permissions ? [...permissions] : [];",
957
+ "}",
958
+ "",
881
959
  "export function getWorkOSAuthorizationUrl(input: { workos: WorkOS; config: ForgeWorkOSAuthKitConfig; state?: string }): string {",
882
960
  " if (!input.config.redirectUri) throw new Error(\"WORKOS_REDIRECT_URI is required\");",
883
961
  " const url = new URL(input.workos.userManagement.getAuthorizationUrl({",
@@ -915,7 +993,7 @@ export function renderWorkosAuthRoutes(_input: IntegrationTemplateInput): string
915
993
  " const organizationMembershipId = resolved?.organizationMembershipId ?? resultOrganizationMembershipId;",
916
994
  " const role = resolved?.role ?? (typeof rawResult.role === \"string\" ? rawResult.role : resultRoles[0]);",
917
995
  " const roles = resolved?.roles ?? resultRoles;",
918
- " const permissions = resolved?.permissions ?? resultPermissions;",
996
+ " const permissions = resolved?.permissions ?? (resultPermissions.length > 0 ? resultPermissions : fallbackPermissionsForRole(role));",
919
997
  " return {",
920
998
  " user: workOSSessionUser(user),",
921
999
  " accessToken: result.accessToken,",
@@ -508,8 +508,85 @@ function workOSDevSessionClaims(session: WorkOSDevSession): Record<string, unkno
508
508
  };
509
509
  }
510
510
 
511
+ function parseWorkOSTenantMap(value: string | undefined): Record<string, string> {
512
+ if (!value) {
513
+ return {};
514
+ }
515
+ try {
516
+ const parsed = JSON.parse(value) as unknown;
517
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
518
+ return {};
519
+ }
520
+ return Object.fromEntries(
521
+ Object.entries(parsed as Record<string, unknown>)
522
+ .filter((entry): entry is [string, string] =>
523
+ typeof entry[0] === "string" &&
524
+ typeof entry[1] === "string" &&
525
+ entry[0].length > 0 &&
526
+ entry[1].length > 0
527
+ ),
528
+ );
529
+ } catch {
530
+ return {};
531
+ }
532
+ }
533
+
534
+ function mapWorkOSTenantId(
535
+ envStore: ReturnType<typeof getRuntimeEnvStore>,
536
+ organizationId: unknown,
537
+ ): string | undefined {
538
+ if (typeof organizationId !== "string" || organizationId.length === 0) {
539
+ return undefined;
540
+ }
541
+ const tenantMap = {
542
+ ...parseWorkOSTenantMap(envStore.resolve("FORGE_WORKOS_TENANT_MAP")),
543
+ ...parseWorkOSTenantMap(envStore.resolve("VITE_FORGE_WORKOS_TENANT_MAP")),
544
+ };
545
+ if (tenantMap[organizationId]) {
546
+ return tenantMap[organizationId];
547
+ }
548
+ const fallback =
549
+ normalizeOptionalId(envStore.resolve("FORGE_WORKOS_TENANT_ID_FALLBACK")) ??
550
+ normalizeOptionalId(envStore.resolve("VITE_FORGE_WORKOS_TENANT_ID_FALLBACK"));
551
+ if (organizationId.startsWith("org_") && fallback) {
552
+ return fallback;
553
+ }
554
+ return organizationId;
555
+ }
556
+
557
+ function mapWorkOSClaimsTenant(
558
+ envStore: ReturnType<typeof getRuntimeEnvStore>,
559
+ claims: Record<string, unknown>,
560
+ ): Record<string, unknown> {
561
+ const rawOrganizationId = claims.organization_id;
562
+ const mappedTenantId = mapWorkOSTenantId(envStore, rawOrganizationId);
563
+ if (!mappedTenantId || mappedTenantId === rawOrganizationId) {
564
+ return claims;
565
+ }
566
+ return {
567
+ ...claims,
568
+ workos_organization_id: rawOrganizationId,
569
+ organization_id: mappedTenantId,
570
+ tenant_id: mappedTenantId,
571
+ };
572
+ }
573
+
574
+ function enrichWorkOSDevSession(workspaceRoot: string, session: WorkOSDevSession): WorkOSDevSession {
575
+ const role = session.role ?? session.roles?.[0];
576
+ const permissions = session.permissions && session.permissions.length > 0
577
+ ? session.permissions
578
+ : deriveDevPermissionsForRole(workspaceRoot, role);
579
+ return {
580
+ ...session,
581
+ ...(role && !session.role ? { role } : {}),
582
+ ...(role && (!session.roles || session.roles.length === 0) ? { roles: [role] } : {}),
583
+ ...(permissions.length > 0 ? { permissions } : {}),
584
+ };
585
+ }
586
+
511
587
  function authFromWorkOSDevSessionCookie(
512
588
  request: Request,
589
+ workspaceRoot: string,
513
590
  envStore: ReturnType<typeof getRuntimeEnvStore>,
514
591
  ): AuthContext | null {
515
592
  const cookiePassword = envStore.resolve("WORKOS_COOKIE_PASSWORD");
@@ -523,7 +600,10 @@ function authFromWorkOSDevSessionCookie(
523
600
  if (!session) {
524
601
  return null;
525
602
  }
526
- const claims = workOSDevSessionClaims(session);
603
+ const claims = mapWorkOSClaimsTenant(
604
+ envStore,
605
+ workOSDevSessionClaims(enrichWorkOSDevSession(workspaceRoot, session)),
606
+ );
527
607
  return resolveAuthFromHeaders({
528
608
  userId: typeof claims.sub === "string" ? claims.sub : undefined,
529
609
  tenantId: typeof claims.organization_id === "string" ? claims.organization_id : undefined,
@@ -541,6 +621,7 @@ function authFromWorkOSDevSessionCookie(
541
621
 
542
622
  async function authenticateDevRequest(
543
623
  request: Request,
624
+ workspaceRoot: string,
544
625
  authConfig: ReturnType<typeof loadAuthConfigFromEnv>,
545
626
  envStore: ReturnType<typeof getRuntimeEnvStore>,
546
627
  ): Promise<AuthContext> {
@@ -549,13 +630,13 @@ async function authenticateDevRequest(
549
630
  if (headerAuth.kind !== "anonymous") {
550
631
  return headerAuth;
551
632
  }
552
- return authFromWorkOSDevSessionCookie(request, envStore) ?? headerAuth;
633
+ return authFromWorkOSDevSessionCookie(request, workspaceRoot, envStore) ?? headerAuth;
553
634
  }
554
635
 
555
636
  try {
556
637
  return await authenticateHeaders(request.headers, authConfig);
557
638
  } catch (error) {
558
- const cookieAuth = authFromWorkOSDevSessionCookie(request, envStore);
639
+ const cookieAuth = authFromWorkOSDevSessionCookie(request, workspaceRoot, envStore);
559
640
  if (cookieAuth) {
560
641
  return cookieAuth;
561
642
  }
@@ -1585,6 +1666,20 @@ export async function startDevServer(
1585
1666
  const membership = (result.organizationMembership ?? {}) as Record<string, unknown>;
1586
1667
  const accessToken = typeof result.accessToken === "string" ? result.accessToken : "";
1587
1668
  const refreshToken = typeof result.refreshToken === "string" ? result.refreshToken : undefined;
1669
+ const roles = Array.isArray(result.roles)
1670
+ ? result.roles.filter((role): role is string => typeof role === "string")
1671
+ : [];
1672
+ const role =
1673
+ typeof result.role === "string"
1674
+ ? result.role
1675
+ : typeof (membership.role as Record<string, unknown> | undefined)?.slug === "string"
1676
+ ? String((membership.role as Record<string, unknown>).slug)
1677
+ : roles[0];
1678
+ const permissions = Array.isArray(result.permissions)
1679
+ ? result.permissions.filter((permission): permission is string => typeof permission === "string")
1680
+ : [];
1681
+ const effectivePermissions =
1682
+ permissions.length > 0 ? permissions : deriveDevPermissionsForRole(workspaceRoot, role);
1588
1683
  const session: WorkOSDevSession = {
1589
1684
  user,
1590
1685
  accessToken,
@@ -1599,17 +1694,9 @@ export async function startDevServer(
1599
1694
  : typeof membership.id === "string"
1600
1695
  ? { organizationMembershipId: membership.id }
1601
1696
  : {}),
1602
- ...(typeof result.role === "string" ? { role: result.role } : {}),
1603
- ...(Array.isArray(result.roles)
1604
- ? { roles: result.roles.filter((role): role is string => typeof role === "string") }
1605
- : {}),
1606
- ...(Array.isArray(result.permissions)
1607
- ? {
1608
- permissions: result.permissions.filter(
1609
- (permission): permission is string => typeof permission === "string",
1610
- ),
1611
- }
1612
- : {}),
1697
+ ...(role ? { role } : {}),
1698
+ ...(roles.length > 0 ? { roles } : role ? { roles: [role] } : {}),
1699
+ ...(effectivePermissions.length > 0 ? { permissions: effectivePermissions } : {}),
1613
1700
  issuedAt: Math.floor(Date.now() / 1000),
1614
1701
  };
1615
1702
  return redirectResponse(
@@ -1660,7 +1747,16 @@ export async function startDevServer(
1660
1747
  cookiePassword,
1661
1748
  );
1662
1749
  return session
1663
- ? jsonResponse({ ok: true, session: { user: session.user, claims: workOSDevSessionClaims(session) } })
1750
+ ? jsonResponse({
1751
+ ok: true,
1752
+ session: {
1753
+ user: session.user,
1754
+ claims: mapWorkOSClaimsTenant(
1755
+ envStore,
1756
+ workOSDevSessionClaims(enrichWorkOSDevSession(workspaceRoot, session)),
1757
+ ),
1758
+ },
1759
+ })
1664
1760
  : jsonResponse({ ok: false, session: null }, 401);
1665
1761
  }
1666
1762
  }
@@ -1885,7 +1981,7 @@ export async function startDevServer(
1885
1981
  }
1886
1982
  }
1887
1983
 
1888
- const auth = await authenticateDevRequest(request, authConfig, getRuntimeEnvStore(workspaceRoot));
1984
+ const auth = await authenticateDevRequest(request, workspaceRoot, authConfig, getRuntimeEnvStore(workspaceRoot));
1889
1985
  const lastRevision = Number(
1890
1986
  request.headers.get("last-event-id") ??
1891
1987
  url.searchParams.get("lastRevision") ??
@@ -2009,7 +2105,7 @@ export async function startDevServer(
2009
2105
  400,
2010
2106
  );
2011
2107
  }
2012
- const auth = await authenticateDevRequest(request, authConfig, getRuntimeEnvStore(workspaceRoot));
2108
+ const auth = await authenticateDevRequest(request, workspaceRoot, authConfig, getRuntimeEnvStore(workspaceRoot));
2013
2109
  const envStore = getRuntimeEnvStore(workspaceRoot);
2014
2110
  const secretRegistry = loadSecretRegistry(workspaceRoot);
2015
2111
  const bundle = createRuntimeSecretsBundle({
@@ -2129,7 +2225,7 @@ export async function startDevServer(
2129
2225
  }
2130
2226
 
2131
2227
  const purpose = body.purpose ?? "dev_agent_chat";
2132
- const auth = await authenticateDevRequest(request, authConfig, getRuntimeEnvStore(workspaceRoot));
2228
+ const auth = await authenticateDevRequest(request, workspaceRoot, authConfig, getRuntimeEnvStore(workspaceRoot));
2133
2229
  const envStore = getRuntimeEnvStore(workspaceRoot);
2134
2230
  const secretRegistry = loadSecretRegistry(workspaceRoot);
2135
2231
  const bundle = createRuntimeSecretsBundle({
@@ -2544,7 +2640,7 @@ export async function startDevServer(
2544
2640
  const externalInvoke = parseExternalInvoke(pathname);
2545
2641
  if (externalInvoke) {
2546
2642
  const args = await parseRequestArgs(request);
2547
- const auth = await authenticateDevRequest(request, authConfig, getRuntimeEnvStore(workspaceRoot));
2643
+ const auth = await authenticateDevRequest(request, workspaceRoot, authConfig, getRuntimeEnvStore(workspaceRoot));
2548
2644
  const result = await runExternalEntry(
2549
2645
  workspaceRoot,
2550
2646
  {
@@ -2612,7 +2708,7 @@ export async function startDevServer(
2612
2708
  }
2613
2709
 
2614
2710
  const args = await parseRequestArgs(request);
2615
- const auth = await authenticateDevRequest(request, authConfig, getRuntimeEnvStore(workspaceRoot));
2711
+ const auth = await authenticateDevRequest(request, workspaceRoot, authConfig, getRuntimeEnvStore(workspaceRoot));
2616
2712
 
2617
2713
  const result = await runQuery(
2618
2714
  workspaceRoot,
@@ -2685,7 +2781,7 @@ export async function startDevServer(
2685
2781
  }
2686
2782
 
2687
2783
  const args = await parseRequestArgs(request);
2688
- const auth = await authenticateDevRequest(request, authConfig, getRuntimeEnvStore(workspaceRoot));
2784
+ const auth = await authenticateDevRequest(request, workspaceRoot, authConfig, getRuntimeEnvStore(workspaceRoot));
2689
2785
 
2690
2786
  await prepareRuntimeEnvironment(workspaceRoot, {
2691
2787
  mock: options.mock,
@@ -1,3 +1,3 @@
1
- export const FORGEOS_VERSION = "0.1.0-alpha.58";
1
+ export const FORGEOS_VERSION = "0.1.0-alpha.60";
2
2
  export const GENERATOR_VERSION = FORGEOS_VERSION;
3
3
  export const CLI_VERSION = FORGEOS_VERSION;