@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-
|
|
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:
|
|
1804
|
+
isAdmin: requestIsAdmin,
|
|
1790
1805
|
queryCoordinator: options.queryCoordinator,
|
|
1791
|
-
resolveForwardContext:
|
|
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 (!
|
|
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:
|
|
1944
|
+
isAdmin: requestIsAdmin,
|
|
1930
1945
|
knownTables: () => collectKnownTables(),
|
|
1931
1946
|
queryCoordinator: options.queryCoordinator,
|
|
1932
|
-
resolveForwardContext:
|
|
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 (!
|
|
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) =>
|
|
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);
|