@lunora/runtime 1.0.0-alpha.7 → 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-Bq1WvIOp.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"];
@@ -1599,6 +1602,8 @@ const resolveForwardContext = async (request, env, resolveIdentity) => {
1599
1602
  const cookie = request.headers.get("cookie");
1600
1603
  const bookmark = request.headers.get("x-d1-bookmark");
1601
1604
  const mutationId = request.headers.get("x-lunora-mutation-id");
1605
+ const clientId = request.headers.get("x-lunora-client-id");
1606
+ const clientSeq = request.headers.get("x-lunora-client-seq");
1602
1607
  if (authorization) {
1603
1608
  headers["authorization"] = authorization;
1604
1609
  }
@@ -1611,6 +1616,12 @@ const resolveForwardContext = async (request, env, resolveIdentity) => {
1611
1616
  if (mutationId) {
1612
1617
  headers["x-lunora-mutation-id"] = mutationId;
1613
1618
  }
1619
+ if (clientId) {
1620
+ headers["x-lunora-client-id"] = clientId;
1621
+ }
1622
+ if (clientSeq) {
1623
+ headers["x-lunora-client-seq"] = clientSeq;
1624
+ }
1614
1625
  const clientIp = request.headers.get("cf-connecting-ip");
1615
1626
  if (clientIp) {
1616
1627
  headers["x-lunora-client-ip"] = clientIp;
@@ -1760,6 +1771,18 @@ const createWorker = (options) => {
1760
1771
  envAdminToken = value;
1761
1772
  }
1762
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
+ };
1763
1786
  const hasAnyShardAuth = Boolean(options.authorizeShard) || Boolean(options.authorizeFanOut);
1764
1787
  let warnedUnauthenticatedShardAccess = false;
1765
1788
  const warnUnauthenticatedShardAccessOnce = (kind) => {
@@ -1778,9 +1801,9 @@ const createWorker = (options) => {
1778
1801
  const orchestrationAdminRoutes = buildOrchestrationAdminRoutes({
1779
1802
  defaultShard,
1780
1803
  forwardToShard,
1781
- isAdmin: (request) => checkAdminAuth(request, effectiveAdminToken()),
1804
+ isAdmin: requestIsAdmin,
1782
1805
  queryCoordinator: options.queryCoordinator,
1783
- resolveForwardContext: (request, env) => resolveForwardContext(request, env, options.resolveIdentity),
1806
+ resolveForwardContext: resolveAdminForwardContext,
1784
1807
  shardDO
1785
1808
  });
1786
1809
  const dispatchToShard = async (functionPath, args, shardKey) => {
@@ -1844,7 +1867,7 @@ const createWorker = (options) => {
1844
1867
  }
1845
1868
  };
1846
1869
  const handleRunCronJob = async (request, env) => {
1847
- if (!checkAdminAuth(request, effectiveAdminToken())) {
1870
+ if (!requestIsAdmin(request)) {
1848
1871
  throw new LunoraError("admin endpoint requires a valid admin bearer", { code: "ADMIN_FORBIDDEN", status: 403 });
1849
1872
  }
1850
1873
  if (request.method !== "POST") {
@@ -1918,17 +1941,17 @@ const createWorker = (options) => {
1918
1941
  };
1919
1942
  const dataMovementAdminRoutes = buildDataMovementAdminRoutes({
1920
1943
  applyGlobals: options.applyGlobals,
1921
- isAdmin: (request) => checkAdminAuth(request, effectiveAdminToken()),
1944
+ isAdmin: requestIsAdmin,
1922
1945
  knownTables: () => collectKnownTables(),
1923
1946
  queryCoordinator: options.queryCoordinator,
1924
- resolveForwardContext: (request, env) => resolveForwardContext(request, env, options.resolveIdentity),
1947
+ resolveForwardContext: resolveAdminForwardContext,
1925
1948
  shardDO,
1926
1949
  streamExportRows: (coordinator, headers, tables, writeRow) => streamExportRows(options, coordinator, headers, tables, writeRow, shardDO),
1927
1950
  streamingImport: (request, headers) => streamingImport(request, options, headers, shardDO),
1928
1951
  syncGlobals: options.syncGlobals
1929
1952
  });
1930
1953
  const assertAdminAuthorized = (request) => {
1931
- if (!checkAdminAuth(request, effectiveAdminToken())) {
1954
+ if (!requestIsAdmin(request)) {
1932
1955
  throw new LunoraError("admin endpoint requires a valid admin bearer", { code: "ADMIN_FORBIDDEN", status: 403 });
1933
1956
  }
1934
1957
  };
@@ -1965,7 +1988,7 @@ const createWorker = (options) => {
1965
1988
  return resolveShard(requireSchedulerNamespace(), options.schedulerInstanceName ?? "default");
1966
1989
  };
1967
1990
  const scheduledAdminRoutes = buildScheduledAdminRoutes({
1968
- checkWsAdmin: (request) => checkAdminAuth(request, effectiveAdminToken()) || checkAdminWsToken(request, effectiveAdminToken()),
1991
+ checkWsAdmin: (request) => requestIsAdmin(request) || checkAdminWsToken(request, effectiveAdminToken()),
1969
1992
  requireSchedulerNamespace,
1970
1993
  resolveSchedulerStub,
1971
1994
  schedulerInstanceName: options.schedulerInstanceName ?? "default"
@@ -2424,6 +2447,17 @@ const createWorker = (options) => {
2424
2447
  resolvedSecurity = resolveSecurity(options.security, env ?? {});
2425
2448
  }
2426
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
+ };
2427
2461
  const handle = async (request, env, context) => {
2428
2462
  const url = new URL(request.url);
2429
2463
  if (request.method === "POST" || request.method === "PUT") {
@@ -2445,6 +2479,7 @@ const createWorker = (options) => {
2445
2479
  }
2446
2480
  const internalRoute = internalRoutes[url.pathname];
2447
2481
  if (internalRoute) {
2482
+ await applyAdminGate(request, url.pathname);
2448
2483
  return internalRoute(request, env, url, context);
2449
2484
  }
2450
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.7",
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",