@lunora/runtime 1.0.0-alpha.16 → 1.0.0-alpha.17
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 +22 -31
- package/dist/index.d.ts +22 -31
- package/dist/index.mjs +7 -7
- package/dist/packem_shared/{DEFAULT_REGISTRY_CACHE_TTL_MS-ocax8v0n.mjs → DEFAULT_REGISTRY_CACHE_TTL_MS-B3pA7aXp.mjs} +5 -4
- package/dist/packem_shared/LunoraError-Bpb9EFJ3.mjs +22 -0
- package/dist/packem_shared/{composeIdentityResolvers-YjvUKisc.mjs → composeIdentityResolvers-XGjO7V1J.mjs} +1 -1
- package/dist/packem_shared/{composeWorker-BnZf6iRH.mjs → composeWorker-DU8vDrgA.mjs} +7 -6
- package/dist/packem_shared/{createCrossShardRelationCapabilities-C0KOf7er.mjs → createCrossShardRelationCapabilities-CbcWjkAn.mjs} +4 -2
- package/dist/packem_shared/{createQueryCoordinator-ZeZYUPNu.mjs → createQueryCoordinator-DNCJzOZE.mjs} +1 -1
- package/dist/packem_shared/{decorateResponse-igd8FJqk.mjs → decorateResponse-CsZc49QC.mjs} +3 -1
- package/package.json +4 -1
- package/dist/packem_shared/LunoraError-CL0aOtpo.mjs +0 -46
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RankDirection, RankPageRow, DatabaseWriterLike } from '@lunora/do';
|
|
2
2
|
export type { RankDirection as RankPageDirection, RankPageRowKey as RankPageKey, RankPageRow, ShardRankPageResult } from '@lunora/do';
|
|
3
3
|
import { WorkflowsRestClient } from '@lunora/workflow';
|
|
4
|
+
import { LunoraError as LunoraError$1, ErrorBody } from '@lunora/errors';
|
|
4
5
|
/**
|
|
5
6
|
* Turn-key incremental-sync source helpers for warehouse connectors
|
|
6
7
|
* (Fivetran custom functions, Airbyte incremental sources).
|
|
@@ -1194,24 +1195,6 @@ interface ShardTrafficFanOutResult {
|
|
|
1194
1195
|
shards: ReadonlyArray<ShardTrafficEntry>;
|
|
1195
1196
|
}
|
|
1196
1197
|
declare const createQueryCoordinator: (options: QueryCoordinatorOptions) => QueryCoordinator;
|
|
1197
|
-
/**
|
|
1198
|
-
* Secure-by-default HTTP edge for the Lunora worker.
|
|
1199
|
-
*
|
|
1200
|
-
* The worker's top-level `fetch` (see `./create-worker`) is the single choke
|
|
1201
|
-
* point every response passes through — RPC, auth, admin, `httpRoute` handlers,
|
|
1202
|
-
* and the SSR fallback alike. This module supplies what is applied there:
|
|
1203
|
-
* `decorateResponse` adds baseline security headers plus, for allowed
|
|
1204
|
-
* cross-origin requests, the matching `Access-Control-Allow-*` headers (never
|
|
1205
|
-
* overwriting a header the inner handler set); `handleCorsPreflight` answers
|
|
1206
|
-
* `OPTIONS` preflights for allowlisted origins; `enforceOrigin` is a CSRF guard
|
|
1207
|
-
* that rejects state-changing, cookie-authenticated requests from untrusted
|
|
1208
|
-
* origins.
|
|
1209
|
-
*
|
|
1210
|
-
* Every layer is on by default and individually disable-able through the
|
|
1211
|
-
* `SecurityOptions` passed to `createWorker`. Resolution (`resolveSecurity`) is
|
|
1212
|
-
* pure and platform-agnostic — it touches only the global `Request`/`Response`/
|
|
1213
|
-
* `Headers`/`URL`, so it unit-tests under plain Node without workerd.
|
|
1214
|
-
*/
|
|
1215
1198
|
/** Per-header overrides for {@link SecurityHeadersOptions}. `false` omits the header. */
|
|
1216
1199
|
interface SecurityHeadersOptions {
|
|
1217
1200
|
/**
|
|
@@ -2467,18 +2450,30 @@ interface DynamicShardRegistry extends ShardRegistry {
|
|
|
2467
2450
|
}
|
|
2468
2451
|
declare const createDynamicShardRegistry: (options: DynamicShardRegistryOptions) => DynamicShardRegistry;
|
|
2469
2452
|
interface LunoraErrorBody {
|
|
2470
|
-
error:
|
|
2471
|
-
code: string;
|
|
2472
|
-
message: string;
|
|
2473
|
-
};
|
|
2453
|
+
error: ErrorBody;
|
|
2474
2454
|
}
|
|
2475
2455
|
/**
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
2456
|
+
* Convert any thrown value into a JSON error response.
|
|
2457
|
+
*
|
|
2458
|
+
* Delegates the envelope + redaction to `@lunora/errors`' {@link toErrorBody} —
|
|
2459
|
+
* a non-internal `LunoraError` (from `@lunora/server`, this runtime, or the
|
|
2460
|
+
* `@lunora/do` data layer) is echoed with its `code`/`message`/`hint`/`docsUrl`;
|
|
2461
|
+
* an internal-coded error keeps its status but its message is redacted; anything
|
|
2462
|
+
* else becomes a generic `INTERNAL` 500. All of these share the unified shape
|
|
2463
|
+
* recognized by `isLunoraError`.
|
|
2464
|
+
*/
|
|
2465
|
+
declare const toErrorResponse: (error: unknown) => Response;
|
|
2466
|
+
/**
|
|
2467
|
+
* Transport-level error for the worker entry. A thin ergonomic wrapper over the
|
|
2468
|
+
* shared `@lunora/errors` `LunoraError` that keeps the runtime's historical
|
|
2469
|
+
* `(message, { code, status })` signature — the runtime mints these with
|
|
2470
|
+
* dispatch-specific codes (`METHOD_NOT_ALLOWED`, `*_NOT_CONFIGURED`, …) and an
|
|
2471
|
+
* explicit status, so they don't need a central catalog entry. Because it is a
|
|
2472
|
+
* real `LunoraError`, it carries the unified wire shape and is recognized by
|
|
2473
|
+
* `isLunoraError` everywhere. Anything thrown that isn't a `LunoraError`
|
|
2474
|
+
* is mapped to a generic 500 with code `INTERNAL`.
|
|
2478
2475
|
*/
|
|
2479
|
-
declare class LunoraError extends
|
|
2480
|
-
readonly code: string;
|
|
2481
|
-
readonly status: number;
|
|
2476
|
+
declare class LunoraError extends LunoraError$1 {
|
|
2482
2477
|
constructor(message: string, options?: {
|
|
2483
2478
|
cause?: unknown;
|
|
2484
2479
|
code?: string;
|
|
@@ -2486,10 +2481,6 @@ declare class LunoraError extends Error {
|
|
|
2486
2481
|
});
|
|
2487
2482
|
toResponse(): Response;
|
|
2488
2483
|
}
|
|
2489
|
-
/** Shape recognised by the runtime's structural error checks. */
|
|
2490
|
-
|
|
2491
|
-
/** Convert any thrown value into a JSON error response. */
|
|
2492
|
-
declare const toErrorResponse: (error: unknown) => Response;
|
|
2493
2484
|
/** Shared shape for sinks that can be limited to error events only. */
|
|
2494
2485
|
interface OnlyErrorsOption {
|
|
2495
2486
|
/** When true, only events with `ok === false` are forwarded. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RankDirection, RankPageRow, DatabaseWriterLike } from '@lunora/do';
|
|
2
2
|
export type { RankDirection as RankPageDirection, RankPageRowKey as RankPageKey, RankPageRow, ShardRankPageResult } from '@lunora/do';
|
|
3
3
|
import { WorkflowsRestClient } from '@lunora/workflow';
|
|
4
|
+
import { LunoraError as LunoraError$1, ErrorBody } from '@lunora/errors';
|
|
4
5
|
/**
|
|
5
6
|
* Turn-key incremental-sync source helpers for warehouse connectors
|
|
6
7
|
* (Fivetran custom functions, Airbyte incremental sources).
|
|
@@ -1194,24 +1195,6 @@ interface ShardTrafficFanOutResult {
|
|
|
1194
1195
|
shards: ReadonlyArray<ShardTrafficEntry>;
|
|
1195
1196
|
}
|
|
1196
1197
|
declare const createQueryCoordinator: (options: QueryCoordinatorOptions) => QueryCoordinator;
|
|
1197
|
-
/**
|
|
1198
|
-
* Secure-by-default HTTP edge for the Lunora worker.
|
|
1199
|
-
*
|
|
1200
|
-
* The worker's top-level `fetch` (see `./create-worker`) is the single choke
|
|
1201
|
-
* point every response passes through — RPC, auth, admin, `httpRoute` handlers,
|
|
1202
|
-
* and the SSR fallback alike. This module supplies what is applied there:
|
|
1203
|
-
* `decorateResponse` adds baseline security headers plus, for allowed
|
|
1204
|
-
* cross-origin requests, the matching `Access-Control-Allow-*` headers (never
|
|
1205
|
-
* overwriting a header the inner handler set); `handleCorsPreflight` answers
|
|
1206
|
-
* `OPTIONS` preflights for allowlisted origins; `enforceOrigin` is a CSRF guard
|
|
1207
|
-
* that rejects state-changing, cookie-authenticated requests from untrusted
|
|
1208
|
-
* origins.
|
|
1209
|
-
*
|
|
1210
|
-
* Every layer is on by default and individually disable-able through the
|
|
1211
|
-
* `SecurityOptions` passed to `createWorker`. Resolution (`resolveSecurity`) is
|
|
1212
|
-
* pure and platform-agnostic — it touches only the global `Request`/`Response`/
|
|
1213
|
-
* `Headers`/`URL`, so it unit-tests under plain Node without workerd.
|
|
1214
|
-
*/
|
|
1215
1198
|
/** Per-header overrides for {@link SecurityHeadersOptions}. `false` omits the header. */
|
|
1216
1199
|
interface SecurityHeadersOptions {
|
|
1217
1200
|
/**
|
|
@@ -2467,18 +2450,30 @@ interface DynamicShardRegistry extends ShardRegistry {
|
|
|
2467
2450
|
}
|
|
2468
2451
|
declare const createDynamicShardRegistry: (options: DynamicShardRegistryOptions) => DynamicShardRegistry;
|
|
2469
2452
|
interface LunoraErrorBody {
|
|
2470
|
-
error:
|
|
2471
|
-
code: string;
|
|
2472
|
-
message: string;
|
|
2473
|
-
};
|
|
2453
|
+
error: ErrorBody;
|
|
2474
2454
|
}
|
|
2475
2455
|
/**
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
2456
|
+
* Convert any thrown value into a JSON error response.
|
|
2457
|
+
*
|
|
2458
|
+
* Delegates the envelope + redaction to `@lunora/errors`' {@link toErrorBody} —
|
|
2459
|
+
* a non-internal `LunoraError` (from `@lunora/server`, this runtime, or the
|
|
2460
|
+
* `@lunora/do` data layer) is echoed with its `code`/`message`/`hint`/`docsUrl`;
|
|
2461
|
+
* an internal-coded error keeps its status but its message is redacted; anything
|
|
2462
|
+
* else becomes a generic `INTERNAL` 500. All of these share the unified shape
|
|
2463
|
+
* recognized by `isLunoraError`.
|
|
2464
|
+
*/
|
|
2465
|
+
declare const toErrorResponse: (error: unknown) => Response;
|
|
2466
|
+
/**
|
|
2467
|
+
* Transport-level error for the worker entry. A thin ergonomic wrapper over the
|
|
2468
|
+
* shared `@lunora/errors` `LunoraError` that keeps the runtime's historical
|
|
2469
|
+
* `(message, { code, status })` signature — the runtime mints these with
|
|
2470
|
+
* dispatch-specific codes (`METHOD_NOT_ALLOWED`, `*_NOT_CONFIGURED`, …) and an
|
|
2471
|
+
* explicit status, so they don't need a central catalog entry. Because it is a
|
|
2472
|
+
* real `LunoraError`, it carries the unified wire shape and is recognized by
|
|
2473
|
+
* `isLunoraError` everywhere. Anything thrown that isn't a `LunoraError`
|
|
2474
|
+
* is mapped to a generic 500 with code `INTERNAL`.
|
|
2478
2475
|
*/
|
|
2479
|
-
declare class LunoraError extends
|
|
2480
|
-
readonly code: string;
|
|
2481
|
-
readonly status: number;
|
|
2476
|
+
declare class LunoraError extends LunoraError$1 {
|
|
2482
2477
|
constructor(message: string, options?: {
|
|
2483
2478
|
cause?: unknown;
|
|
2484
2479
|
code?: string;
|
|
@@ -2486,10 +2481,6 @@ declare class LunoraError extends Error {
|
|
|
2486
2481
|
});
|
|
2487
2482
|
toResponse(): Response;
|
|
2488
2483
|
}
|
|
2489
|
-
/** Shape recognised by the runtime's structural error checks. */
|
|
2490
|
-
|
|
2491
|
-
/** Convert any thrown value into a JSON error response. */
|
|
2492
|
-
declare const toErrorResponse: (error: unknown) => Response;
|
|
2493
2484
|
/** Shared shape for sinks that can be limited to error events only. */
|
|
2494
2485
|
interface OnlyErrorsOption {
|
|
2495
2486
|
/** When true, only events with `ok === false` are forwarded. */
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export { toAirbyteMessages, toFivetranResponse } from './packem_shared/toAirbyteMessages-DrHdplb4.mjs';
|
|
2
|
-
export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-
|
|
3
|
-
export { createCrossShardRelationCapabilities } from './packem_shared/createCrossShardRelationCapabilities-
|
|
4
|
-
export { DEFAULT_REGISTRY_CACHE_TTL_MS, SHARD_REGISTRY_DO_NAME, createDynamicShardRegistry } from './packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-
|
|
5
|
-
export { LunoraError, toErrorResponse } from './packem_shared/LunoraError-
|
|
2
|
+
export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-DU8vDrgA.mjs';
|
|
3
|
+
export { createCrossShardRelationCapabilities } from './packem_shared/createCrossShardRelationCapabilities-CbcWjkAn.mjs';
|
|
4
|
+
export { DEFAULT_REGISTRY_CACHE_TTL_MS, SHARD_REGISTRY_DO_NAME, createDynamicShardRegistry } from './packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-B3pA7aXp.mjs';
|
|
5
|
+
export { LunoraError, toErrorResponse } from './packem_shared/LunoraError-Bpb9EFJ3.mjs';
|
|
6
6
|
export { emitLogEvent, emitRpcEvent } from './packem_shared/emitLogEvent-pEdtqAK8.mjs';
|
|
7
7
|
export { analyticsEngineSink, combineSinks, consoleSink, sentrySink, webhookSink } from './packem_shared/analyticsEngineSink-DqEvrQs0.mjs';
|
|
8
|
-
export { createQueryCoordinator, createStaticShardRegistry, mergeStrategyForAggregate } from './packem_shared/createQueryCoordinator-
|
|
8
|
+
export { createQueryCoordinator, createStaticShardRegistry, mergeStrategyForAggregate } from './packem_shared/createQueryCoordinator-DNCJzOZE.mjs';
|
|
9
9
|
export { applyJurisdiction, resolveShard } from './packem_shared/applyJurisdiction-BkZtTkct.mjs';
|
|
10
|
-
export { decorateResponse, enforceOrigin, handleCorsPreflight, resolveSecurity } from './packem_shared/decorateResponse-
|
|
10
|
+
export { decorateResponse, enforceOrigin, handleCorsPreflight, resolveSecurity } from './packem_shared/decorateResponse-CsZc49QC.mjs';
|
|
11
11
|
export { NOOP_EXECUTION_CONTEXT } from './packem_shared/NOOP_EXECUTION_CONTEXT-CCTu0Bf1.mjs';
|
|
12
|
-
export { composeIdentityResolvers, routeIdentityResolvers } from './packem_shared/composeIdentityResolvers-
|
|
12
|
+
export { composeIdentityResolvers, routeIdentityResolvers } from './packem_shared/composeIdentityResolvers-XGjO7V1J.mjs';
|
|
13
13
|
|
|
14
14
|
const VERSION = "0.0.0";
|
|
15
15
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LunoraError } from './LunoraError-Bpb9EFJ3.mjs';
|
|
1
2
|
import { applyJurisdiction } from './applyJurisdiction-BkZtTkct.mjs';
|
|
2
3
|
|
|
3
4
|
const SHARD_REGISTRY_DO_NAME = "__lunora_shard_registry__";
|
|
@@ -42,7 +43,7 @@ const createDynamicShardRegistry = (options) => {
|
|
|
42
43
|
}
|
|
43
44
|
const response = await get(`/list?table=${encodeURIComponent(table)}`);
|
|
44
45
|
if (!response.ok) {
|
|
45
|
-
throw new
|
|
46
|
+
throw new LunoraError(`shard registry /list returned ${String(response.status)}`);
|
|
46
47
|
}
|
|
47
48
|
const { shardKeys } = await decodeJson(response);
|
|
48
49
|
if (cacheTtlMs > 0) {
|
|
@@ -53,14 +54,14 @@ const createDynamicShardRegistry = (options) => {
|
|
|
53
54
|
async register(table, shardKey) {
|
|
54
55
|
const response = await post("/register", { shardKey, table });
|
|
55
56
|
if (!response.ok) {
|
|
56
|
-
throw new
|
|
57
|
+
throw new LunoraError(`shard registry /register returned ${String(response.status)}`);
|
|
57
58
|
}
|
|
58
59
|
cache.delete(table);
|
|
59
60
|
},
|
|
60
61
|
async snapshot() {
|
|
61
62
|
const response = await get("/snapshot");
|
|
62
63
|
if (!response.ok) {
|
|
63
|
-
throw new
|
|
64
|
+
throw new LunoraError(`shard registry /snapshot returned ${String(response.status)}`);
|
|
64
65
|
}
|
|
65
66
|
const { tables } = await decodeJson(response);
|
|
66
67
|
return tables;
|
|
@@ -68,7 +69,7 @@ const createDynamicShardRegistry = (options) => {
|
|
|
68
69
|
async unregister(table, shardKey) {
|
|
69
70
|
const response = await post("/unregister", { shardKey, table });
|
|
70
71
|
if (!response.ok) {
|
|
71
|
-
throw new
|
|
72
|
+
throw new LunoraError(`shard registry /unregister returned ${String(response.status)}`);
|
|
72
73
|
}
|
|
73
74
|
cache.delete(table);
|
|
74
75
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LunoraError as LunoraError$1, toErrorBody } from '@lunora/errors';
|
|
2
|
+
|
|
3
|
+
const toErrorResponse = (error) => {
|
|
4
|
+
const { body, redacted, status } = toErrorBody(error, { fallbackCode: "INTERNAL", redactedMessage: "Internal error" });
|
|
5
|
+
if (redacted) {
|
|
6
|
+
console.error("[lunora] internal error:", error);
|
|
7
|
+
}
|
|
8
|
+
return Response.json({ error: body }, {
|
|
9
|
+
headers: { "content-type": "application/json" },
|
|
10
|
+
status
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
class LunoraError extends LunoraError$1 {
|
|
14
|
+
constructor(message, options) {
|
|
15
|
+
super(options?.code ?? "INTERNAL", message, { cause: options?.cause, status: options?.status });
|
|
16
|
+
}
|
|
17
|
+
toResponse() {
|
|
18
|
+
return toErrorResponse(this);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { LunoraError, toErrorResponse };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { isLunoraError } from '@lunora/errors';
|
|
1
2
|
import { NOOP_EXECUTION_CONTEXT } from './NOOP_EXECUTION_CONTEXT-CCTu0Bf1.mjs';
|
|
2
|
-
import { LunoraError, toErrorResponse
|
|
3
|
-
import { wrapResolverWithContract } from './composeIdentityResolvers-
|
|
4
|
-
export { composeIdentityResolvers, routeIdentityResolvers } from './composeIdentityResolvers-
|
|
3
|
+
import { LunoraError, toErrorResponse } from './LunoraError-Bpb9EFJ3.mjs';
|
|
4
|
+
import { wrapResolverWithContract } from './composeIdentityResolvers-XGjO7V1J.mjs';
|
|
5
|
+
export { composeIdentityResolvers, routeIdentityResolvers } from './composeIdentityResolvers-XGjO7V1J.mjs';
|
|
5
6
|
import { emitRpcEvent } from './emitLogEvent-pEdtqAK8.mjs';
|
|
6
7
|
import { resolveShard, applyJurisdiction } from './applyJurisdiction-BkZtTkct.mjs';
|
|
7
|
-
import { resolveSecurity, handleCorsPreflight, enforceOrigin, decorateResponse, enforceWebSocketOrigin } from './decorateResponse-
|
|
8
|
+
import { resolveSecurity, handleCorsPreflight, enforceOrigin, decorateResponse, enforceWebSocketOrigin } from './decorateResponse-CsZc49QC.mjs';
|
|
8
9
|
|
|
9
10
|
const RELAY_NAME_INFIX = "::relay::";
|
|
10
11
|
const relayName = (ownerKey, index) => `${ownerKey}${RELAY_NAME_INFIX}${String(index)}`;
|
|
@@ -1740,7 +1741,7 @@ const isAuthAttemptPath = (pathname, basePath) => {
|
|
|
1740
1741
|
return AUTH_ATTEMPT_SEGMENTS.some((segment) => suffix === segment || suffix.startsWith(`${segment}/`));
|
|
1741
1742
|
};
|
|
1742
1743
|
const buildErrorEvent = (functionPath, durationMs, error, extra) => {
|
|
1743
|
-
const mappable =
|
|
1744
|
+
const mappable = isLunoraError(error);
|
|
1744
1745
|
const code = mappable ? error.code : "INTERNAL_SERVER_ERROR";
|
|
1745
1746
|
const status = mappable ? error.status : 500;
|
|
1746
1747
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -2911,7 +2912,7 @@ const resolveLunoraOptions = (options, env) => {
|
|
|
2911
2912
|
}
|
|
2912
2913
|
const shardDO = options.shardDO ?? env?.SHARD;
|
|
2913
2914
|
if (!shardDO) {
|
|
2914
|
-
throw new
|
|
2915
|
+
throw new LunoraError(
|
|
2915
2916
|
"@lunora/runtime: no shard Durable Object namespace found. Bind `SHARD` in wrangler.jsonc, or pass `createLunoraHandler({ shardDO: env.MY_SHARD })`."
|
|
2916
2917
|
);
|
|
2917
2918
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from './LunoraError-Bpb9EFJ3.mjs';
|
|
2
|
+
|
|
1
3
|
const RPC_ENDPOINT = "/_lunora/rpc";
|
|
2
4
|
const buildIdentityHeaders = (options) => {
|
|
3
5
|
const headers = { "content-type": "application/json" };
|
|
@@ -19,12 +21,12 @@ const fanOutRelation = async (options, body, label) => {
|
|
|
19
21
|
})
|
|
20
22
|
);
|
|
21
23
|
if (!response.ok) {
|
|
22
|
-
throw new
|
|
24
|
+
throw new LunoraError(`cross-shard relation ${label} failed: worker returned ${String(response.status)}`);
|
|
23
25
|
}
|
|
24
26
|
const result = await response.json();
|
|
25
27
|
if (typeof result.failed === "number" && result.failed > 0) {
|
|
26
28
|
const reached = (typeof result.ok === "number" ? result.ok : 0) + result.failed;
|
|
27
|
-
throw new
|
|
29
|
+
throw new LunoraError(
|
|
28
30
|
`cross-shard relation ${label} failed on ${String(result.failed)} of ${String(reached)} shard(s) — refusing to return a partial result`
|
|
29
31
|
);
|
|
30
32
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from './LunoraError-Bpb9EFJ3.mjs';
|
|
2
|
+
|
|
1
3
|
const DEFAULT_CSP = "default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'";
|
|
2
4
|
const htmlCspFor = (frameOptions) => {
|
|
3
5
|
const parts = ["base-uri 'none'", "object-src 'none'"];
|
|
@@ -82,7 +84,7 @@ const resolveCors = (input) => {
|
|
|
82
84
|
} else {
|
|
83
85
|
const originsList = origins;
|
|
84
86
|
if (originsList.includes("*") && allowCredentials) {
|
|
85
|
-
throw new
|
|
87
|
+
throw new LunoraError(
|
|
86
88
|
'@lunora/runtime: security.cors cannot combine a wildcard origin ("*") with allowCredentials: true — browsers reject it and it defeats the allowlist.'
|
|
87
89
|
);
|
|
88
90
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/runtime",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.17",
|
|
4
4
|
"description": "Lunora Worker runtime: the RPC router, shard resolver, and query coordinator",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -45,6 +45,9 @@
|
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@lunora/errors": "1.0.0-alpha.1"
|
|
50
|
+
},
|
|
48
51
|
"engines": {
|
|
49
52
|
"node": "^22.15.0 || >=24.11.0"
|
|
50
53
|
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
class LunoraError extends Error {
|
|
2
|
-
code;
|
|
3
|
-
status;
|
|
4
|
-
constructor(message, options) {
|
|
5
|
-
super(message, { cause: options?.cause });
|
|
6
|
-
this.name = "LunoraError";
|
|
7
|
-
this.code = options?.code ?? "INTERNAL";
|
|
8
|
-
this.status = options?.status ?? 500;
|
|
9
|
-
}
|
|
10
|
-
toResponse() {
|
|
11
|
-
const body = { error: { code: this.code, message: this.message } };
|
|
12
|
-
return Response.json(body, {
|
|
13
|
-
headers: { "content-type": "application/json" },
|
|
14
|
-
status: this.status
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
const hasErrorShape = (error, name) => {
|
|
19
|
-
if (!error || typeof error !== "object") {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
const candidate = error;
|
|
23
|
-
return candidate.name === name && typeof candidate.code === "string" && typeof candidate.status === "number" && typeof candidate.message === "string";
|
|
24
|
-
};
|
|
25
|
-
const isStructuralConflictError = (error) => hasErrorShape(error, "ConflictError");
|
|
26
|
-
const isStructuralLunoraError = (error) => hasErrorShape(error, "LunoraError");
|
|
27
|
-
const toErrorResponse = (error) => {
|
|
28
|
-
if (error instanceof LunoraError) {
|
|
29
|
-
return error.toResponse();
|
|
30
|
-
}
|
|
31
|
-
if (isStructuralLunoraError(error) || isStructuralConflictError(error)) {
|
|
32
|
-
const body2 = { error: { code: error.code, message: error.message } };
|
|
33
|
-
return Response.json(body2, {
|
|
34
|
-
headers: { "content-type": "application/json" },
|
|
35
|
-
status: error.status
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
console.error("[lunora] unhandled error:", error);
|
|
39
|
-
const body = { error: { code: "INTERNAL", message: "Internal error" } };
|
|
40
|
-
return Response.json(body, {
|
|
41
|
-
headers: { "content-type": "application/json" },
|
|
42
|
-
status: 500
|
|
43
|
-
});
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export { LunoraError, isStructuralConflictError, isStructuralLunoraError, toErrorResponse };
|