@lunora/runtime 1.0.0-alpha.8 → 1.0.0-alpha.9

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/index.d.mts CHANGED
@@ -1614,6 +1614,22 @@ interface BackupManifest {
1614
1614
  tables?: string;
1615
1615
  }
1616
1616
  interface WorkerOptions {
1617
+ /**
1618
+ * An additional, async authorization gate for the `/_lunora/admin/*` plane
1619
+ * (the Studio's HTTP + WS endpoints), OR-ed with the static {@link WorkerOptions.adminToken}
1620
+ * bearer. When it resolves `true` for a request, that request is treated as
1621
+ * admin-authorized even without the bearer; when it resolves `false` (or is
1622
+ * unset) the bearer remains the only path. Evaluated once per admin request
1623
+ * and never on the RPC/WebSocket data hot path.
1624
+ *
1625
+ * The intended producer is `@lunora/cloudflare-access`'s `accessAdminGate(...)`,
1626
+ * which verifies the request's `Cf-Access-Jwt-Assertion` JWT and applies an
1627
+ * `isAdmin(claims)` predicate — so the Studio can sit behind Cloudflare Access
1628
+ * instead of (or alongside) a shared admin token. It takes only the request
1629
+ * (verification needs static team-domain/aud config + the remote JWKS, no env
1630
+ * binding), so it composes without threading async through every admin route.
1631
+ */
1632
+ adminGate?: (request: Request) => boolean | Promise<boolean>;
1617
1633
  /**
1618
1634
  * Admin bearer token expected by the export/import endpoints. When unset,
1619
1635
  * the endpoints respond with `ADMIN_FORBIDDEN` — the same posture the
package/dist/index.d.ts CHANGED
@@ -1614,6 +1614,22 @@ interface BackupManifest {
1614
1614
  tables?: string;
1615
1615
  }
1616
1616
  interface WorkerOptions {
1617
+ /**
1618
+ * An additional, async authorization gate for the `/_lunora/admin/*` plane
1619
+ * (the Studio's HTTP + WS endpoints), OR-ed with the static {@link WorkerOptions.adminToken}
1620
+ * bearer. When it resolves `true` for a request, that request is treated as
1621
+ * admin-authorized even without the bearer; when it resolves `false` (or is
1622
+ * unset) the bearer remains the only path. Evaluated once per admin request
1623
+ * and never on the RPC/WebSocket data hot path.
1624
+ *
1625
+ * The intended producer is `@lunora/cloudflare-access`'s `accessAdminGate(...)`,
1626
+ * which verifies the request's `Cf-Access-Jwt-Assertion` JWT and applies an
1627
+ * `isAdmin(claims)` predicate — so the Studio can sit behind Cloudflare Access
1628
+ * instead of (or alongside) a shared admin token. It takes only the request
1629
+ * (verification needs static team-domain/aud config + the remote JWKS, no env
1630
+ * binding), so it composes without threading async through every admin route.
1631
+ */
1632
+ adminGate?: (request: Request) => boolean | Promise<boolean>;
1617
1633
  /**
1618
1634
  * Admin bearer token expected by the export/import endpoints. When unset,
1619
1635
  * the endpoints respond with `ADMIN_FORBIDDEN` — the same posture the
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  export { toAirbyteMessages, toFivetranResponse } from './packem_shared/toAirbyteMessages-DrHdplb4.mjs';
2
- export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-Y3uASpzc.mjs';
2
+ export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-CxhwYzSP.mjs';
3
3
  export { createCrossShardRelationCapabilities } from './packem_shared/createCrossShardRelationCapabilities-C0KOf7er.mjs';
4
4
  export { DEFAULT_REGISTRY_CACHE_TTL_MS, SHARD_REGISTRY_DO_NAME, createDynamicShardRegistry } from './packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-ocax8v0n.mjs';
5
5
  export { LunoraError, toErrorResponse } from './packem_shared/LunoraError-CL0aOtpo.mjs';
@@ -967,7 +967,7 @@ const buildIntrospectionAdminRoutes = (deps) => {
967
967
  };
968
968
  };
969
969
 
970
- const MIGRATE_PATH = "/_lunora/migrate";
970
+ const MIGRATE_PATH$1 = "/_lunora/migrate";
971
971
  const PITR_PATH = "/_lunora/admin/pitr";
972
972
  const RANK_PATH = "/_lunora/admin/rank";
973
973
  const RANKPAGE_PATH = "/_lunora/admin/rankpage";
@@ -1224,7 +1224,7 @@ const buildOrchestrationAdminRoutes = (deps) => {
1224
1224
  return forwardToShard(shardDO, pitr.shardKey ?? defaultShard, forwarded);
1225
1225
  };
1226
1226
  return {
1227
- [MIGRATE_PATH]: handleMigrate,
1227
+ [MIGRATE_PATH$1]: handleMigrate,
1228
1228
  [PITR_PATH]: handlePitr,
1229
1229
  [RANK_PATH]: handleRank,
1230
1230
  [RANKPAGE_PATH]: handleRankPage,
@@ -1558,6 +1558,9 @@ const RPC_PATH = "/_lunora/rpc";
1558
1558
  const WS_PATH = "/_lunora/ws";
1559
1559
  const SCHEDULER_DISPATCH_PATH = "/_lunora/scheduler/dispatch";
1560
1560
  const CRON_JOBS_RUN_PATH = "/_lunora/admin/cron-jobs/run";
1561
+ const ADMIN_PATH_PREFIX = "/_lunora/admin/";
1562
+ const MIGRATE_PATH = "/_lunora/migrate";
1563
+ const isAdminPath = (pathname) => pathname.startsWith(ADMIN_PATH_PREFIX) || pathname === MIGRATE_PATH;
1561
1564
  const DEFAULT_AUTH_BASE_PATH = "/api/auth";
1562
1565
  const RECORD_AUTH_EVENT_OP = "__lunora_admin__:recordAuthEvent";
1563
1566
  const AUTH_ATTEMPT_SEGMENTS = ["/sign-in", "/sign-up", "/callback"];
@@ -1768,6 +1771,18 @@ const createWorker = (options) => {
1768
1771
  envAdminToken = value;
1769
1772
  }
1770
1773
  };
1774
+ const accessAdminGrants = /* @__PURE__ */ new WeakSet();
1775
+ const requestIsAdmin = (request) => checkAdminAuth(request, effectiveAdminToken()) || accessAdminGrants.has(request);
1776
+ const resolveAdminForwardContext = async (request, env) => {
1777
+ const context = await resolveForwardContext(request, env, options.resolveIdentity);
1778
+ if (accessAdminGrants.has(request) && context.headers["authorization"] === void 0) {
1779
+ const token = effectiveAdminToken();
1780
+ if (token !== void 0) {
1781
+ context.headers["authorization"] = `Bearer ${token}`;
1782
+ }
1783
+ }
1784
+ return context;
1785
+ };
1771
1786
  const hasAnyShardAuth = Boolean(options.authorizeShard) || Boolean(options.authorizeFanOut);
1772
1787
  let warnedUnauthenticatedShardAccess = false;
1773
1788
  const warnUnauthenticatedShardAccessOnce = (kind) => {
@@ -1786,9 +1801,9 @@ const createWorker = (options) => {
1786
1801
  const orchestrationAdminRoutes = buildOrchestrationAdminRoutes({
1787
1802
  defaultShard,
1788
1803
  forwardToShard,
1789
- isAdmin: (request) => checkAdminAuth(request, effectiveAdminToken()),
1804
+ isAdmin: requestIsAdmin,
1790
1805
  queryCoordinator: options.queryCoordinator,
1791
- resolveForwardContext: (request, env) => resolveForwardContext(request, env, options.resolveIdentity),
1806
+ resolveForwardContext: resolveAdminForwardContext,
1792
1807
  shardDO
1793
1808
  });
1794
1809
  const dispatchToShard = async (functionPath, args, shardKey) => {
@@ -1852,7 +1867,7 @@ const createWorker = (options) => {
1852
1867
  }
1853
1868
  };
1854
1869
  const handleRunCronJob = async (request, env) => {
1855
- if (!checkAdminAuth(request, effectiveAdminToken())) {
1870
+ if (!requestIsAdmin(request)) {
1856
1871
  throw new LunoraError("admin endpoint requires a valid admin bearer", { code: "ADMIN_FORBIDDEN", status: 403 });
1857
1872
  }
1858
1873
  if (request.method !== "POST") {
@@ -1926,17 +1941,17 @@ const createWorker = (options) => {
1926
1941
  };
1927
1942
  const dataMovementAdminRoutes = buildDataMovementAdminRoutes({
1928
1943
  applyGlobals: options.applyGlobals,
1929
- isAdmin: (request) => checkAdminAuth(request, effectiveAdminToken()),
1944
+ isAdmin: requestIsAdmin,
1930
1945
  knownTables: () => collectKnownTables(),
1931
1946
  queryCoordinator: options.queryCoordinator,
1932
- resolveForwardContext: (request, env) => resolveForwardContext(request, env, options.resolveIdentity),
1947
+ resolveForwardContext: resolveAdminForwardContext,
1933
1948
  shardDO,
1934
1949
  streamExportRows: (coordinator, headers, tables, writeRow) => streamExportRows(options, coordinator, headers, tables, writeRow, shardDO),
1935
1950
  streamingImport: (request, headers) => streamingImport(request, options, headers, shardDO),
1936
1951
  syncGlobals: options.syncGlobals
1937
1952
  });
1938
1953
  const assertAdminAuthorized = (request) => {
1939
- if (!checkAdminAuth(request, effectiveAdminToken())) {
1954
+ if (!requestIsAdmin(request)) {
1940
1955
  throw new LunoraError("admin endpoint requires a valid admin bearer", { code: "ADMIN_FORBIDDEN", status: 403 });
1941
1956
  }
1942
1957
  };
@@ -1973,7 +1988,7 @@ const createWorker = (options) => {
1973
1988
  return resolveShard(requireSchedulerNamespace(), options.schedulerInstanceName ?? "default");
1974
1989
  };
1975
1990
  const scheduledAdminRoutes = buildScheduledAdminRoutes({
1976
- checkWsAdmin: (request) => checkAdminAuth(request, effectiveAdminToken()) || checkAdminWsToken(request, effectiveAdminToken()),
1991
+ checkWsAdmin: (request) => requestIsAdmin(request) || checkAdminWsToken(request, effectiveAdminToken()),
1977
1992
  requireSchedulerNamespace,
1978
1993
  resolveSchedulerStub,
1979
1994
  schedulerInstanceName: options.schedulerInstanceName ?? "default"
@@ -2432,6 +2447,17 @@ const createWorker = (options) => {
2432
2447
  resolvedSecurity = resolveSecurity(options.security, env ?? {});
2433
2448
  }
2434
2449
  };
2450
+ const applyAdminGate = async (request, pathname) => {
2451
+ if (options.adminGate === void 0 || !isAdminPath(pathname)) {
2452
+ return;
2453
+ }
2454
+ try {
2455
+ if (await options.adminGate(request)) {
2456
+ accessAdminGrants.add(request);
2457
+ }
2458
+ } catch {
2459
+ }
2460
+ };
2435
2461
  const handle = async (request, env, context) => {
2436
2462
  const url = new URL(request.url);
2437
2463
  if (request.method === "POST" || request.method === "PUT") {
@@ -2453,6 +2479,7 @@ const createWorker = (options) => {
2453
2479
  }
2454
2480
  const internalRoute = internalRoutes[url.pathname];
2455
2481
  if (internalRoute) {
2482
+ await applyAdminGate(request, url.pathname);
2456
2483
  return internalRoute(request, env, url, context);
2457
2484
  }
2458
2485
  const httpRouteResponse = await dispatchHttpRoute(request, env, context);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/runtime",
3
- "version": "1.0.0-alpha.8",
3
+ "version": "1.0.0-alpha.9",
4
4
  "description": "Lunora Worker runtime: the RPC router, shard resolver, and query coordinator",
5
5
  "keywords": [
6
6
  "cloudflare",