@lunora/runtime 1.0.0-alpha.6 → 1.0.0-alpha.7

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
@@ -110,6 +110,38 @@ declare const toFivetranResponse: (page: ConnectorSyncPage, primaryKey?: Record<
110
110
  * @param emittedAt epoch-ms stamped on each `RECORD` (default `Date.now()`).
111
111
  */
112
112
  declare const toAirbyteMessages: (page: ConnectorSyncPage, emittedAt?: number) => AirbyteMessage[];
113
+ /**
114
+ * The subset of the Cloudflare `ExecutionContext` the Lunora worker entry and
115
+ * the framework mount seams rely on — `waitUntil` for fire-and-forget work that
116
+ * must outlive the response, and `passThroughOnException` for the top-level
117
+ * error posture.
118
+ *
119
+ * It is deliberately **not** a package. `@lunora/runtime` is the leaf server
120
+ * runtime and `@lunora/nuxt` is a framework integration that intentionally does
121
+ * not depend on `@lunora/runtime`'s worker types, yet both need this exact
122
+ * shape: the runtime to build/forward the worker `fetch`, Nuxt to forward an
123
+ * inbound request to the user's composed worker. Each imports this file by
124
+ * relative path and the bundler (packem/rollup) inlines it: no runtime
125
+ * dependency edge is created, the helper is duplicated only in emitted output,
126
+ * never in source. One source of truth, zero deps. See AGENTS.md → "Top-level
127
+ * `shared/` — bundler-inlined source".
128
+ *
129
+ * Both methods are **optional**: a real Cloudflare `ExecutionContext` always
130
+ * supplies them, but a host that mounts Lunora as a sub-handler (Nitro/H3, a
131
+ * non-Cloudflare preview, a unit test) may hand over a partial context or none
132
+ * at all. Callers therefore invoke them defensively (`ctx.waitUntil?.(…)`) or
133
+ * fall back to {@link NOOP_EXECUTION_CONTEXT}.
134
+ */
135
+ interface ExecutionContextLike {
136
+ passThroughOnException?: () => void;
137
+ waitUntil?: (promise: Promise<unknown>) => void;
138
+ }
139
+ /**
140
+ * No-op `ExecutionContext` used when the host runtime didn't supply one (a
141
+ * non-Cloudflare preview, or a unit test), so the worker's `fetch` always
142
+ * receives a valid third argument.
143
+ */
144
+ declare const NOOP_EXECUTION_CONTEXT: ExecutionContextLike;
113
145
  /** A timestamp as better-auth stores it: epoch-ms, an ISO string, or absent. */
114
146
  type AuthTimestamp = null | number | string;
115
147
  /**
@@ -1157,10 +1189,6 @@ interface RpcEnvelope {
1157
1189
  functionPath: string;
1158
1190
  shardKey?: string;
1159
1191
  }
1160
- interface ExecutionContextLike {
1161
- passThroughOnException: () => void;
1162
- waitUntil: (promise: Promise<unknown>) => void;
1163
- }
1164
1192
  type Route = (request: Request, env: unknown, context: ExecutionContextLike) => Promise<Response> | Response;
1165
1193
  /**
1166
1194
  * Context handed to HTTP-action handlers. Built per request by the worker; its
@@ -2095,12 +2123,6 @@ declare const withFrameworkWorker: (host: FrameworkHostHandler, optionsInput: Fr
2095
2123
  */
2096
2124
  type LunoraHandlerOptions = ((env: unknown) => FrameworkWorkerOptions) | Partial<FrameworkWorkerOptions>;
2097
2125
  /**
2098
- * No-op `ExecutionContext` used when the host runtime didn't supply one (a
2099
- * non-Cloudflare preview, or a unit test), so the worker's `fetch` always
2100
- * receives a valid third argument.
2101
- */
2102
- declare const NOOP_EXECUTION_CONTEXT: ExecutionContextLike;
2103
- /**
2104
2126
  * Resolve per-request Lunora worker options. A factory is called with the
2105
2127
  * request `env`; a partial object has its `shardDO` defaulted to `env.SHARD` so
2106
2128
  * the common case needs no configuration. Throws a clear error when no shard
package/dist/index.d.ts CHANGED
@@ -110,6 +110,38 @@ declare const toFivetranResponse: (page: ConnectorSyncPage, primaryKey?: Record<
110
110
  * @param emittedAt epoch-ms stamped on each `RECORD` (default `Date.now()`).
111
111
  */
112
112
  declare const toAirbyteMessages: (page: ConnectorSyncPage, emittedAt?: number) => AirbyteMessage[];
113
+ /**
114
+ * The subset of the Cloudflare `ExecutionContext` the Lunora worker entry and
115
+ * the framework mount seams rely on — `waitUntil` for fire-and-forget work that
116
+ * must outlive the response, and `passThroughOnException` for the top-level
117
+ * error posture.
118
+ *
119
+ * It is deliberately **not** a package. `@lunora/runtime` is the leaf server
120
+ * runtime and `@lunora/nuxt` is a framework integration that intentionally does
121
+ * not depend on `@lunora/runtime`'s worker types, yet both need this exact
122
+ * shape: the runtime to build/forward the worker `fetch`, Nuxt to forward an
123
+ * inbound request to the user's composed worker. Each imports this file by
124
+ * relative path and the bundler (packem/rollup) inlines it: no runtime
125
+ * dependency edge is created, the helper is duplicated only in emitted output,
126
+ * never in source. One source of truth, zero deps. See AGENTS.md → "Top-level
127
+ * `shared/` — bundler-inlined source".
128
+ *
129
+ * Both methods are **optional**: a real Cloudflare `ExecutionContext` always
130
+ * supplies them, but a host that mounts Lunora as a sub-handler (Nitro/H3, a
131
+ * non-Cloudflare preview, a unit test) may hand over a partial context or none
132
+ * at all. Callers therefore invoke them defensively (`ctx.waitUntil?.(…)`) or
133
+ * fall back to {@link NOOP_EXECUTION_CONTEXT}.
134
+ */
135
+ interface ExecutionContextLike {
136
+ passThroughOnException?: () => void;
137
+ waitUntil?: (promise: Promise<unknown>) => void;
138
+ }
139
+ /**
140
+ * No-op `ExecutionContext` used when the host runtime didn't supply one (a
141
+ * non-Cloudflare preview, or a unit test), so the worker's `fetch` always
142
+ * receives a valid third argument.
143
+ */
144
+ declare const NOOP_EXECUTION_CONTEXT: ExecutionContextLike;
113
145
  /** A timestamp as better-auth stores it: epoch-ms, an ISO string, or absent. */
114
146
  type AuthTimestamp = null | number | string;
115
147
  /**
@@ -1157,10 +1189,6 @@ interface RpcEnvelope {
1157
1189
  functionPath: string;
1158
1190
  shardKey?: string;
1159
1191
  }
1160
- interface ExecutionContextLike {
1161
- passThroughOnException: () => void;
1162
- waitUntil: (promise: Promise<unknown>) => void;
1163
- }
1164
1192
  type Route = (request: Request, env: unknown, context: ExecutionContextLike) => Promise<Response> | Response;
1165
1193
  /**
1166
1194
  * Context handed to HTTP-action handlers. Built per request by the worker; its
@@ -2095,12 +2123,6 @@ declare const withFrameworkWorker: (host: FrameworkHostHandler, optionsInput: Fr
2095
2123
  */
2096
2124
  type LunoraHandlerOptions = ((env: unknown) => FrameworkWorkerOptions) | Partial<FrameworkWorkerOptions>;
2097
2125
  /**
2098
- * No-op `ExecutionContext` used when the host runtime didn't supply one (a
2099
- * non-Cloudflare preview, or a unit test), so the worker's `fetch` always
2100
- * receives a valid third argument.
2101
- */
2102
- declare const NOOP_EXECUTION_CONTEXT: ExecutionContextLike;
2103
- /**
2104
2126
  * Resolve per-request Lunora worker options. A factory is called with the
2105
2127
  * request `env`; a partial object has its `shardDO` defaulted to `env.SHARD` so
2106
2128
  * the common case needs no configuration. Throws a clear error when no shard
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  export { toAirbyteMessages, toFivetranResponse } from './packem_shared/toAirbyteMessages-DrHdplb4.mjs';
2
- export { NOOP_EXECUTION_CONTEXT, composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/NOOP_EXECUTION_CONTEXT-Rns-X7RV.mjs';
2
+ export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-Bq1WvIOp.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';
@@ -8,6 +8,7 @@ export { analyticsEngineSink, combineSinks, consoleSink, sentrySink, webhookSink
8
8
  export { createQueryCoordinator, createStaticShardRegistry, mergeStrategyForAggregate } from './packem_shared/createQueryCoordinator-Cbds9cUI.mjs';
9
9
  export { applyJurisdiction, resolveShard } from './packem_shared/applyJurisdiction-BkZtTkct.mjs';
10
10
  export { decorateResponse, enforceOrigin, handleCorsPreflight, resolveSecurity } from './packem_shared/decorateResponse-DbISh_Wi.mjs';
11
+ export { NOOP_EXECUTION_CONTEXT } from './packem_shared/NOOP_EXECUTION_CONTEXT-CCTu0Bf1.mjs';
11
12
 
12
13
  const VERSION = "0.0.0";
13
14
 
@@ -0,0 +1,8 @@
1
+ const NOOP_EXECUTION_CONTEXT = {
2
+ passThroughOnException: () => {
3
+ },
4
+ waitUntil: () => {
5
+ }
6
+ };
7
+
8
+ export { NOOP_EXECUTION_CONTEXT };
@@ -1,3 +1,4 @@
1
+ import { NOOP_EXECUTION_CONTEXT } from './NOOP_EXECUTION_CONTEXT-CCTu0Bf1.mjs';
1
2
  import { LunoraError, toErrorResponse, isStructuralLunoraError, isStructuralConflictError } from './LunoraError-CL0aOtpo.mjs';
2
3
  import { emitRpcEvent } from './emitLogEvent-pEdtqAK8.mjs';
3
4
  import { resolveShard, applyJurisdiction } from './applyJurisdiction-BkZtTkct.mjs';
@@ -1502,7 +1503,7 @@ const buildWorkflowsAdminRoutes = (deps) => {
1502
1503
  assertAdmin(request);
1503
1504
  const client = resolveWorkflowsClient(env);
1504
1505
  if (!client) {
1505
- return throwNotConfigured();
1506
+ return Response.json({ configured: false, instances: [], page: 1, perPage: 0, totalCount: 0 });
1506
1507
  }
1507
1508
  const workflowName = requireQuery(url, "name");
1508
1509
  const status = toInstanceStatus(url.searchParams.get("status"));
@@ -1662,6 +1663,12 @@ const validateFanOut = (fanOut) => {
1662
1663
  }
1663
1664
  return spec;
1664
1665
  };
1666
+ const logRpcDebug = (env, envelope) => {
1667
+ if (!env?.LUNORA_DEBUG_RPC) {
1668
+ return;
1669
+ }
1670
+ console.warn(`[lunora:rpc] ${envelope.fanOut ? "fan-out" : `shard=${envelope.shardKey ?? "(root)"}`} ${envelope.functionPath}`);
1671
+ };
1665
1672
  const parseEnvelope = async (request) => {
1666
1673
  const text = await readBodyTextWithLimit(request);
1667
1674
  let body;
@@ -2149,6 +2156,7 @@ const createWorker = (options) => {
2149
2156
  throw new LunoraError("RPC endpoint requires POST", { code: "METHOD_NOT_ALLOWED", status: 405 });
2150
2157
  }
2151
2158
  const envelope = await parseEnvelope(request);
2159
+ logRpcDebug(env, envelope);
2152
2160
  if (envelope.fanOut && envelope.shardKey) {
2153
2161
  throw new LunoraError("RPC envelope cannot set both `shardKey` and `fanOut`", { code: "BAD_REQUEST", status: 400 });
2154
2162
  }
@@ -2171,7 +2179,7 @@ const createWorker = (options) => {
2171
2179
  const { observability } = options;
2172
2180
  const sinkContext = context ? {
2173
2181
  waitUntil: (promise) => {
2174
- context.waitUntil(promise);
2182
+ context.waitUntil?.(promise);
2175
2183
  }
2176
2184
  } : void 0;
2177
2185
  if (envelope.fanOut) {
@@ -2375,7 +2383,7 @@ const createWorker = (options) => {
2375
2383
  }
2376
2384
  const basePath = options.authBasePath ?? DEFAULT_AUTH_BASE_PATH;
2377
2385
  if (isAuthAttemptPath(url.pathname, basePath)) {
2378
- context.waitUntil(recordAuthAttempt(env, authResponse.status >= 400 ? "fail" : "ok"));
2386
+ context.waitUntil?.(recordAuthAttempt(env, authResponse.status >= 400 ? "fail" : "ok"));
2379
2387
  }
2380
2388
  return authResponse;
2381
2389
  };
@@ -2448,7 +2456,7 @@ const createWorker = (options) => {
2448
2456
  return {
2449
2457
  async fetch(request, env, context) {
2450
2458
  if (options.passThroughOnException) {
2451
- context.passThroughOnException();
2459
+ context.passThroughOnException?.();
2452
2460
  }
2453
2461
  ensureSecurityResolved(env);
2454
2462
  resolveAdminTokenFromEnv(env);
@@ -2505,12 +2513,6 @@ const withFrameworkWorker = (host, optionsInput) => {
2505
2513
  serverQuery: (request, env, reference, args, options) => build(optionsFactory(env)).serverQuery(request, env, reference, args, options)
2506
2514
  };
2507
2515
  };
2508
- const NOOP_EXECUTION_CONTEXT = {
2509
- passThroughOnException: () => {
2510
- },
2511
- waitUntil: () => {
2512
- }
2513
- };
2514
2516
  const resolveLunoraOptions = (options, env) => {
2515
2517
  if (typeof options === "function") {
2516
2518
  return options(env);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/runtime",
3
- "version": "1.0.0-alpha.6",
3
+ "version": "1.0.0-alpha.7",
4
4
  "description": "Lunora Worker runtime: the RPC router, shard resolver, and query coordinator",
5
5
  "keywords": [
6
6
  "cloudflare",