@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-
|
|
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:
|
|
1804
|
+
isAdmin: requestIsAdmin,
|
|
1782
1805
|
queryCoordinator: options.queryCoordinator,
|
|
1783
|
-
resolveForwardContext:
|
|
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 (!
|
|
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:
|
|
1944
|
+
isAdmin: requestIsAdmin,
|
|
1922
1945
|
knownTables: () => collectKnownTables(),
|
|
1923
1946
|
queryCoordinator: options.queryCoordinator,
|
|
1924
|
-
resolveForwardContext:
|
|
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 (!
|
|
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) =>
|
|
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);
|