@lunora/runtime 1.0.0-alpha.63 → 1.0.0-alpha.65

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
@@ -208,6 +208,13 @@ declare const toAirbyteMessages: (page: ConnectorSyncPage, emittedAt?: number) =
208
208
  * fall back to {@link NOOP_EXECUTION_CONTEXT}.
209
209
  */
210
210
  interface ExecutionContextLike {
211
+ /**
212
+ * Present only when Cloudflare Access authenticated the request against a
213
+ * policy attached to the **Worker** (rather than to a hostname). `undefined`
214
+ * on every unauthenticated request, so its presence is itself the "Access
215
+ * authorized this caller" signal — see {@link AccessContextLike}.
216
+ */
217
+ access?: AccessContextLike;
211
218
  cache?: {
212
219
  purge: (options: {
213
220
  purgeEverything?: boolean;
@@ -217,6 +224,48 @@ interface ExecutionContextLike {
217
224
  passThroughOnException?: () => void;
218
225
  waitUntil?: (promise: Promise<unknown>) => void;
219
226
  }
227
+ /**
228
+ * The identity Cloudflare Access attaches to a Worker-protected request.
229
+ *
230
+ * Shape follows the Access application-token payload: `sub` is the stable per-user
231
+ * id, `email` the verified address, `common_name` the service-token name (machine
232
+ * callers, whose `sub` is empty), and `exp` the credential expiry in epoch
233
+ * **seconds**. Group membership is whatever the Access policy emits — a list of
234
+ * names, or of `{ id, name }` objects — hence `unknown`; normalize before use.
235
+ *
236
+ * Cloudflare may add further fields, so the index signature keeps them rather
237
+ * than dropping them: this is a view of a payload we do not own.
238
+ */
239
+ interface AccessIdentityLike {
240
+ [claim: string]: unknown;
241
+ /** Service-token name. Present for non-interactive (machine) callers instead of `email`. */
242
+ common_name?: string;
243
+ /** Verified user email. Present for interactive (SSO) callers. */
244
+ email?: string;
245
+ /** Credential expiry, epoch **seconds**. */
246
+ exp?: number;
247
+ /** IdP group membership — names or `{ id, name }` objects, depending on the policy. */
248
+ groups?: unknown;
249
+ /** Display name from the identity provider, when it emits one. */
250
+ name?: string;
251
+ /** Stable per-user id, and what consumers key a user on. Empty for service tokens. */
252
+ sub?: string;
253
+ /** Cloudflare's per-user UUID. Carried through, but deliberately not used as an id — only this path emits it, so keying on it would not match the JWT path. */
254
+ user_uuid?: string;
255
+ }
256
+ /**
257
+ * The `ctx.access` facade Cloudflare exposes on a Worker protected by Access.
258
+ *
259
+ * Reading the identity from here is preferable to verifying the
260
+ * `Cf-Access-Jwt-Assertion` header: the platform has already authenticated the
261
+ * caller, so there is no JWKS fetch, no audience check to get wrong, and nothing
262
+ * a request can forge — the field simply does not exist unless Access authorized
263
+ * the call. The header path remains the fallback for hostname-scoped Access
264
+ * applications, which do not populate this.
265
+ */
266
+ interface AccessContextLike {
267
+ getIdentity: () => AccessIdentityLike | null | undefined | Promise<AccessIdentityLike | null | undefined>;
268
+ }
220
269
  /**
221
270
  * No-op `ExecutionContext` used when the host runtime didn't supply one (a
222
271
  * non-Cloudflare preview, or a unit test), so the worker's `fetch` always
@@ -1597,8 +1646,13 @@ interface ResolvedIdentity {
1597
1646
  * so `.auth()`'s better-auth session resolver, a signed-preview-link verifier, a
1598
1647
  * per-tenant bearer check, an upstream-JWT reader, … are all just `IdentityResolver`s
1599
1648
  * — the identity layer is generic over every scheme, not coupled to any one.
1649
+ *
1650
+ * The optional third argument is the request's `ExecutionContext`, for a scheme
1651
+ * whose credential the platform supplies out-of-band rather than on the request
1652
+ * (`context.access` under Worker-scoped Cloudflare Access). It is `undefined`
1653
+ * wherever the host gave the worker no context.
1600
1654
  */
1601
- type IdentityResolver = (request: Request, env: unknown) => Promise<ResolvedIdentity | null> | ResolvedIdentity | null;
1655
+ type IdentityResolver = (request: Request, env: unknown, context?: ExecutionContextLike) => Promise<ResolvedIdentity | null> | ResolvedIdentity | null;
1602
1656
  /** Error policy for {@link composeIdentityResolvers} when a participant resolver throws. */
1603
1657
  type ComposeIdentityResolversErrorMode = "fail-closed" | "skip";
1604
1658
  /** Options for {@link composeIdentityResolvers}. */
@@ -2439,12 +2493,12 @@ type RestRateLimit = (request: Request, functionPath: string) => Promise<Respons
2439
2493
  /**
2440
2494
  * A built REST route. Takes the same `(request, env, url, context)` shape as the
2441
2495
  * runtime's internal route table so it can be spread straight into it; `url` is
2442
- * unused here (the route re-parses it) and `context` is read only for its
2443
- * `waitUntil`, which keeps dispatch telemetry alive past the response.
2496
+ * unused here (the route re-parses it). The context is the real
2497
+ * {@link ExecutionContextLike} rather than a `waitUntil`-only projection, because
2498
+ * the cache decision reads `context.access` too — see the `applyRestCache` call
2499
+ * below.
2444
2500
  */
2445
- type RestRoute = (request: Request, env: unknown, url?: URL, context?: {
2446
- waitUntil?: (promise: Promise<unknown>) => void;
2447
- }) => Promise<Response>;
2501
+ type RestRoute = (request: Request, env: unknown, url?: URL, context?: ExecutionContextLike) => Promise<Response>;
2448
2502
  interface RestRouteDeps {
2449
2503
  /** The generated function registry — the source of which procedures are exposed. */
2450
2504
  functions: RestRegistryLike;
@@ -3393,11 +3447,15 @@ interface WorkerOptions {
3393
3447
  * The intended producer is `@lunora/cloudflare-access`'s `accessAdminGate(...)`,
3394
3448
  * which verifies the request's `Cf-Access-Jwt-Assertion` JWT and applies an
3395
3449
  * `isAdmin(claims)` predicate — so the Studio can sit behind Cloudflare Access
3396
- * instead of (or alongside) a shared admin token. It takes only the request
3397
- * (verification needs static team-domain/aud config + the remote JWKS, no env
3398
- * binding), so it composes without threading async through every admin route.
3450
+ * instead of (or alongside) a shared admin token. It needs no `env` binding
3451
+ * (verification is static team-domain/aud config + the remote JWKS), so it
3452
+ * composes without threading async through every admin route.
3453
+ *
3454
+ * The second argument is the request's `ExecutionContext`, carrying
3455
+ * `context.access` when the Access policy is attached to the Worker rather
3456
+ * than to a hostname. It is `undefined` when the host supplied no context.
3399
3457
  */
3400
- adminGate?: (request: Request) => boolean | Promise<boolean>;
3458
+ adminGate?: (request: Request, context?: ExecutionContextLike) => boolean | Promise<boolean>;
3401
3459
  /**
3402
3460
  * Admin bearer token expected by the export/import endpoints. When unset,
3403
3461
  * the endpoints respond with `ADMIN_FORBIDDEN` — the same posture the
@@ -3804,8 +3862,16 @@ interface WorkerOptions {
3804
3862
  * forwarded as `x-lunora-identity` so `ctx.auth.getIdentity()` can
3805
3863
  * return them. Returning `null` (or omitting this option) means
3806
3864
  * anonymous — no identity headers are injected.
3865
+ *
3866
+ * The third argument is the request's `ExecutionContext`, forwarded so a
3867
+ * resolver can read identity the platform supplies out-of-band rather than
3868
+ * off the request — `context.access` on a Worker protected by Cloudflare
3869
+ * Access is the one that exists today. It is `undefined` on the paths that
3870
+ * have no context to give (a direct {@link LunoraWorker.serverQuery} call, a
3871
+ * host that mounts the worker without one), so a resolver that uses it must
3872
+ * still handle its absence.
3807
3873
  */
3808
- resolveIdentity?: (request: Request, env: unknown) => Promise<ResolvedIdentity | null> | ResolvedIdentity | null;
3874
+ resolveIdentity?: (request: Request, env: unknown, context?: ExecutionContextLike) => Promise<ResolvedIdentity | null> | ResolvedIdentity | null;
3809
3875
  /**
3810
3876
  * Resolve a table's sharding metadata. Required by the import endpoint to
3811
3877
  * bucket rows; when omitted, every row routes to the default shard.
@@ -4074,12 +4140,18 @@ interface LunoraWorker {
4074
4140
  * `__lunoraRef` is the `"namespace:fn"` dispatched.
4075
4141
  * @param args The function arguments.
4076
4142
  * @param options Call options mirroring the RPC envelope.
4143
+ * @param options.context The host's `ExecutionContext`. Required to reach an
4144
+ * identity the platform supplies out-of-band rather than on the
4145
+ * request — `context.access` under a Worker-scoped Cloudflare
4146
+ * Access policy. Omit it there and the call resolves anonymous
4147
+ * while the same user's `/_lunora/rpc` traffic is authenticated.
4077
4148
  * @param options.shardKey Routes to a specific shard (omitted → the worker's
4078
4149
  * `defaultShardKey`).
4079
4150
  * @param options.waitUntil The host's `waitUntil`, so dispatch telemetry
4080
4151
  * whose export is deferred (a gzipped OTLP body) survives isolate teardown.
4081
4152
  */
4082
4153
  serverQuery: (request: Request, env: unknown, reference: unknown, args?: Record<string, unknown>, options?: {
4154
+ context?: ExecutionContextLike;
4083
4155
  shardKey?: string;
4084
4156
  waitUntil?: (promise: Promise<unknown>) => void;
4085
4157
  }) => Promise<Response>;
@@ -4799,8 +4871,16 @@ declare const combineSinks: (...sinks: ObservabilitySink[]) => ObservabilitySink
4799
4871
  * as caller-specific. Checks the built-in identity headers plus anything the
4800
4872
  * policy declares via `credentialHeaders` — an app whose `resolveIdentity` reads
4801
4873
  * a bespoke header must say so, or its callers read as anonymous here.
4874
+ *
4875
+ * A credential does not have to be on the request at all: under a Cloudflare
4876
+ * Access policy attached to the Worker, the caller is authenticated by the edge
4877
+ * and their identity arrives on the `ExecutionContext` as `access`, with no
4878
+ * header this function could see. Its mere presence means Access authorized this
4879
+ * specific caller, so it counts as a credential — otherwise a per-user response
4880
+ * would be labelled `public` and a shared cache could hand it to the next
4881
+ * visitor.
4802
4882
  */
4803
- declare const requestCarriesCredentials: (request: Request, policy: RestCachePolicy) => boolean;
4883
+ declare const requestCarriesCredentials: (request: Request, policy: RestCachePolicy, context?: ExecutionContextLike) => boolean;
4804
4884
  /**
4805
4885
  * Build the cache headers for one exchange, or `undefined` when the exchange
4806
4886
  * isn't cacheable at all (non-`GET`, or a non-2xx result — an error body must
@@ -4809,14 +4889,14 @@ declare const requestCarriesCredentials: (request: Request, policy: RestCachePol
4809
4889
  * The effective scope is `policy.scope` narrowed by {@link requestCarriesCredentials};
4810
4890
  * `"public"` survives only for a genuinely anonymous request.
4811
4891
  */
4812
- declare const restCacheHeaders: (policy: RestCachePolicy, request: Request, status: number) => Record<string, string> | undefined;
4892
+ declare const restCacheHeaders: (policy: RestCachePolicy, request: Request, status: number, context?: ExecutionContextLike) => Record<string, string> | undefined;
4813
4893
  /**
4814
4894
  * Return `response` with the declared cache headers applied. A shard `Response`
4815
4895
  * has immutable headers, so this rebuilds it (status/statusText/existing headers
4816
4896
  * are carried over, the body is streamed through untouched). When the exchange
4817
4897
  * isn't cacheable the original response is returned as-is — no copy.
4818
4898
  */
4819
- declare const applyRestCache: (response: Response, policy: RestCachePolicy | undefined, request: Request) => Response;
4899
+ declare const applyRestCache: (response: Response, policy: RestCachePolicy | undefined, request: Request, context?: ExecutionContextLike) => Response;
4820
4900
  /**
4821
4901
  * Structural mirror of `@lunora/client`'s `FunctionReference`, re-declared so this
4822
4902
  * module carries no `runtime → client` (browser SDK) dependency. The phantom
@@ -4910,7 +4990,7 @@ declare const createShardClient: (namespace: ShardNamespaceLike, options?: Shard
4910
4990
  */
4911
4991
  declare const STORAGE_UPLOAD_MAX_BODY_BYTES: number;
4912
4992
  declare const VERSION: string;
4913
- export { type AdminTableResolver, type AirbyteMessage, type AnalyticsEngineDataPointLike, type AnalyticsEngineDatasetLike, type AnalyticsEngineSinkOptions, type AuthAdmin, type AuthCapabilities, type AuthConfigInfo, type AuthImpersonation, type AuthPage, type AuthSession, type AuthUser, type AuthUserFieldSpec, BACKUP_KEY_PREFIX, type BackupManifest, type BackupManifestEntry, type BackupRetentionPreview, type BackupStore, type ComposeIdentityResolversErrorMode, type ComposeIdentityResolversOptions, type ConnectorChange, type ConnectorSyncPage, type CorsOptions, type CronHandler, type CronJobDispatch, type CronJobInfo, type CrossShardCounter, type CrossShardReader, type CrossShardRelationCapabilities, type CrossShardRelationOptions, type CsrfOptions, DEFAULT_LOG_COLUMNS, DEFAULT_LOG_LIMIT, DEFAULT_REGISTRY_CACHE_TTL_MS, type DurableObjectJurisdiction, type DynamicShardRegistry, type DynamicShardRegistryOptions, type ExecutionContextLike, type ExportBatch, type ExportChange, type ExportCursorStore, type ExportFanOutRequest, type ExportFanOutResult, type ExportSink, type ExportTapFailure, type ExportTapResult, type FanOutRequest, type FanOutResult, type FanOutSpec, type FivetranResponse, type FrameworkHostHandler, type FrameworkWorkerOptions, type FrameworkWorkerOptionsInput, type FunctionDescriptor, type FunctionRegistryEntry, type FunctionRegistryLike, type GlobalExportFunction as GlobalExportFn, type GlobalImportFunction as GlobalImportFn, type GlobalIntrospector, type GlobalTableInfo as GlobalTableInfoMeta, type GlobalTablePage as GlobalTablePageMeta, HEALTH_PATH, HEALTH_READY_PATH, type HealthAuthPosture, type HealthBody, type HealthCheckReport, type HealthProbe, type HealthProbeKind, type HealthProbeResult, type HealthRouteDeps, type HttpActionContext, type HttpActionLike, type HttpRouterLike, type IdentityContractLike, type IdentityResolver, type IdentityValidation, type ImportFanOutRequest, type ImportFanOutResult, type KvIntrospector, type KvKeyEntry, type KvKeyListResult, type KvNamespaceSummary, type KvValueResult, LOG_ARCHIVE_NOT_CONFIGURED, LOG_ARCHIVE_PATH, type ListAuthUsersOptions, type LogArchiveConfig, type LogEvent, type LogFields, type LogLevel, LunoraError, type LunoraErrorBody, type LunoraHandlerOptions, type LunoraWorker, type MemoizeIdentityOptions, type MergeStrategy, type MetricEvent, type MetricKind, type MigrationFanOutRequest, type MigrationFanOutResult, NOOP_EXECUTION_CONTEXT, type NotifySubscriptionDevice, type NotifySubscriptionStoreLike, type ObservabilityEvent, type ObservabilitySink, type ObservabilitySinkContext,
4993
+ export { type AccessContextLike, type AccessIdentityLike, type AdminTableResolver, type AirbyteMessage, type AnalyticsEngineDataPointLike, type AnalyticsEngineDatasetLike, type AnalyticsEngineSinkOptions, type AuthAdmin, type AuthCapabilities, type AuthConfigInfo, type AuthImpersonation, type AuthPage, type AuthSession, type AuthUser, type AuthUserFieldSpec, BACKUP_KEY_PREFIX, type BackupManifest, type BackupManifestEntry, type BackupRetentionPreview, type BackupStore, type ComposeIdentityResolversErrorMode, type ComposeIdentityResolversOptions, type ConnectorChange, type ConnectorSyncPage, type CorsOptions, type CronHandler, type CronJobDispatch, type CronJobInfo, type CrossShardCounter, type CrossShardReader, type CrossShardRelationCapabilities, type CrossShardRelationOptions, type CsrfOptions, DEFAULT_LOG_COLUMNS, DEFAULT_LOG_LIMIT, DEFAULT_REGISTRY_CACHE_TTL_MS, type DurableObjectJurisdiction, type DynamicShardRegistry, type DynamicShardRegistryOptions, type ExecutionContextLike, type ExportBatch, type ExportChange, type ExportCursorStore, type ExportFanOutRequest, type ExportFanOutResult, type ExportSink, type ExportTapFailure, type ExportTapResult, type FanOutRequest, type FanOutResult, type FanOutSpec, type FivetranResponse, type FrameworkHostHandler, type FrameworkWorkerOptions, type FrameworkWorkerOptionsInput, type FunctionDescriptor, type FunctionRegistryEntry, type FunctionRegistryLike, type GlobalExportFunction as GlobalExportFn, type GlobalImportFunction as GlobalImportFn, type GlobalIntrospector, type GlobalTableInfo as GlobalTableInfoMeta, type GlobalTablePage as GlobalTablePageMeta, HEALTH_PATH, HEALTH_READY_PATH, type HealthAuthPosture, type HealthBody, type HealthCheckReport, type HealthProbe, type HealthProbeKind, type HealthProbeResult, type HealthRouteDeps, type HttpActionContext, type HttpActionLike, type HttpRouterLike, type IdentityContractLike, type IdentityResolver, type IdentityValidation, type ImportFanOutRequest, type ImportFanOutResult, type KvIntrospector, type KvKeyEntry, type KvKeyListResult, type KvNamespaceSummary, type KvValueResult, LOG_ARCHIVE_NOT_CONFIGURED, LOG_ARCHIVE_PATH, type ListAuthUsersOptions, type LogArchiveConfig, type LogEvent, type LogFields, type LogLevel, LunoraError, type LunoraErrorBody, type LunoraHandlerOptions, type LunoraWorker, type MemoizeIdentityOptions, type MergeStrategy, type MetricEvent, type MetricKind, type MigrationFanOutRequest, type MigrationFanOutResult, NOOP_EXECUTION_CONTEXT, type NotifySubscriptionDevice, type NotifySubscriptionStoreLike, type ObservabilityEvent, type ObservabilitySink, type ObservabilitySinkContext,
4914
4994
  /**
4915
4995
  * Resource attribute bag used by OTLP exporters. Re-exported from `shared/otlp`
4916
4996
  * because {@link OtlpSinkOptions.resourceAttributes} is part of the public
package/dist/index.d.ts CHANGED
@@ -208,6 +208,13 @@ declare const toAirbyteMessages: (page: ConnectorSyncPage, emittedAt?: number) =
208
208
  * fall back to {@link NOOP_EXECUTION_CONTEXT}.
209
209
  */
210
210
  interface ExecutionContextLike {
211
+ /**
212
+ * Present only when Cloudflare Access authenticated the request against a
213
+ * policy attached to the **Worker** (rather than to a hostname). `undefined`
214
+ * on every unauthenticated request, so its presence is itself the "Access
215
+ * authorized this caller" signal — see {@link AccessContextLike}.
216
+ */
217
+ access?: AccessContextLike;
211
218
  cache?: {
212
219
  purge: (options: {
213
220
  purgeEverything?: boolean;
@@ -217,6 +224,48 @@ interface ExecutionContextLike {
217
224
  passThroughOnException?: () => void;
218
225
  waitUntil?: (promise: Promise<unknown>) => void;
219
226
  }
227
+ /**
228
+ * The identity Cloudflare Access attaches to a Worker-protected request.
229
+ *
230
+ * Shape follows the Access application-token payload: `sub` is the stable per-user
231
+ * id, `email` the verified address, `common_name` the service-token name (machine
232
+ * callers, whose `sub` is empty), and `exp` the credential expiry in epoch
233
+ * **seconds**. Group membership is whatever the Access policy emits — a list of
234
+ * names, or of `{ id, name }` objects — hence `unknown`; normalize before use.
235
+ *
236
+ * Cloudflare may add further fields, so the index signature keeps them rather
237
+ * than dropping them: this is a view of a payload we do not own.
238
+ */
239
+ interface AccessIdentityLike {
240
+ [claim: string]: unknown;
241
+ /** Service-token name. Present for non-interactive (machine) callers instead of `email`. */
242
+ common_name?: string;
243
+ /** Verified user email. Present for interactive (SSO) callers. */
244
+ email?: string;
245
+ /** Credential expiry, epoch **seconds**. */
246
+ exp?: number;
247
+ /** IdP group membership — names or `{ id, name }` objects, depending on the policy. */
248
+ groups?: unknown;
249
+ /** Display name from the identity provider, when it emits one. */
250
+ name?: string;
251
+ /** Stable per-user id, and what consumers key a user on. Empty for service tokens. */
252
+ sub?: string;
253
+ /** Cloudflare's per-user UUID. Carried through, but deliberately not used as an id — only this path emits it, so keying on it would not match the JWT path. */
254
+ user_uuid?: string;
255
+ }
256
+ /**
257
+ * The `ctx.access` facade Cloudflare exposes on a Worker protected by Access.
258
+ *
259
+ * Reading the identity from here is preferable to verifying the
260
+ * `Cf-Access-Jwt-Assertion` header: the platform has already authenticated the
261
+ * caller, so there is no JWKS fetch, no audience check to get wrong, and nothing
262
+ * a request can forge — the field simply does not exist unless Access authorized
263
+ * the call. The header path remains the fallback for hostname-scoped Access
264
+ * applications, which do not populate this.
265
+ */
266
+ interface AccessContextLike {
267
+ getIdentity: () => AccessIdentityLike | null | undefined | Promise<AccessIdentityLike | null | undefined>;
268
+ }
220
269
  /**
221
270
  * No-op `ExecutionContext` used when the host runtime didn't supply one (a
222
271
  * non-Cloudflare preview, or a unit test), so the worker's `fetch` always
@@ -1597,8 +1646,13 @@ interface ResolvedIdentity {
1597
1646
  * so `.auth()`'s better-auth session resolver, a signed-preview-link verifier, a
1598
1647
  * per-tenant bearer check, an upstream-JWT reader, … are all just `IdentityResolver`s
1599
1648
  * — the identity layer is generic over every scheme, not coupled to any one.
1649
+ *
1650
+ * The optional third argument is the request's `ExecutionContext`, for a scheme
1651
+ * whose credential the platform supplies out-of-band rather than on the request
1652
+ * (`context.access` under Worker-scoped Cloudflare Access). It is `undefined`
1653
+ * wherever the host gave the worker no context.
1600
1654
  */
1601
- type IdentityResolver = (request: Request, env: unknown) => Promise<ResolvedIdentity | null> | ResolvedIdentity | null;
1655
+ type IdentityResolver = (request: Request, env: unknown, context?: ExecutionContextLike) => Promise<ResolvedIdentity | null> | ResolvedIdentity | null;
1602
1656
  /** Error policy for {@link composeIdentityResolvers} when a participant resolver throws. */
1603
1657
  type ComposeIdentityResolversErrorMode = "fail-closed" | "skip";
1604
1658
  /** Options for {@link composeIdentityResolvers}. */
@@ -2439,12 +2493,12 @@ type RestRateLimit = (request: Request, functionPath: string) => Promise<Respons
2439
2493
  /**
2440
2494
  * A built REST route. Takes the same `(request, env, url, context)` shape as the
2441
2495
  * runtime's internal route table so it can be spread straight into it; `url` is
2442
- * unused here (the route re-parses it) and `context` is read only for its
2443
- * `waitUntil`, which keeps dispatch telemetry alive past the response.
2496
+ * unused here (the route re-parses it). The context is the real
2497
+ * {@link ExecutionContextLike} rather than a `waitUntil`-only projection, because
2498
+ * the cache decision reads `context.access` too — see the `applyRestCache` call
2499
+ * below.
2444
2500
  */
2445
- type RestRoute = (request: Request, env: unknown, url?: URL, context?: {
2446
- waitUntil?: (promise: Promise<unknown>) => void;
2447
- }) => Promise<Response>;
2501
+ type RestRoute = (request: Request, env: unknown, url?: URL, context?: ExecutionContextLike) => Promise<Response>;
2448
2502
  interface RestRouteDeps {
2449
2503
  /** The generated function registry — the source of which procedures are exposed. */
2450
2504
  functions: RestRegistryLike;
@@ -3393,11 +3447,15 @@ interface WorkerOptions {
3393
3447
  * The intended producer is `@lunora/cloudflare-access`'s `accessAdminGate(...)`,
3394
3448
  * which verifies the request's `Cf-Access-Jwt-Assertion` JWT and applies an
3395
3449
  * `isAdmin(claims)` predicate — so the Studio can sit behind Cloudflare Access
3396
- * instead of (or alongside) a shared admin token. It takes only the request
3397
- * (verification needs static team-domain/aud config + the remote JWKS, no env
3398
- * binding), so it composes without threading async through every admin route.
3450
+ * instead of (or alongside) a shared admin token. It needs no `env` binding
3451
+ * (verification is static team-domain/aud config + the remote JWKS), so it
3452
+ * composes without threading async through every admin route.
3453
+ *
3454
+ * The second argument is the request's `ExecutionContext`, carrying
3455
+ * `context.access` when the Access policy is attached to the Worker rather
3456
+ * than to a hostname. It is `undefined` when the host supplied no context.
3399
3457
  */
3400
- adminGate?: (request: Request) => boolean | Promise<boolean>;
3458
+ adminGate?: (request: Request, context?: ExecutionContextLike) => boolean | Promise<boolean>;
3401
3459
  /**
3402
3460
  * Admin bearer token expected by the export/import endpoints. When unset,
3403
3461
  * the endpoints respond with `ADMIN_FORBIDDEN` — the same posture the
@@ -3804,8 +3862,16 @@ interface WorkerOptions {
3804
3862
  * forwarded as `x-lunora-identity` so `ctx.auth.getIdentity()` can
3805
3863
  * return them. Returning `null` (or omitting this option) means
3806
3864
  * anonymous — no identity headers are injected.
3865
+ *
3866
+ * The third argument is the request's `ExecutionContext`, forwarded so a
3867
+ * resolver can read identity the platform supplies out-of-band rather than
3868
+ * off the request — `context.access` on a Worker protected by Cloudflare
3869
+ * Access is the one that exists today. It is `undefined` on the paths that
3870
+ * have no context to give (a direct {@link LunoraWorker.serverQuery} call, a
3871
+ * host that mounts the worker without one), so a resolver that uses it must
3872
+ * still handle its absence.
3807
3873
  */
3808
- resolveIdentity?: (request: Request, env: unknown) => Promise<ResolvedIdentity | null> | ResolvedIdentity | null;
3874
+ resolveIdentity?: (request: Request, env: unknown, context?: ExecutionContextLike) => Promise<ResolvedIdentity | null> | ResolvedIdentity | null;
3809
3875
  /**
3810
3876
  * Resolve a table's sharding metadata. Required by the import endpoint to
3811
3877
  * bucket rows; when omitted, every row routes to the default shard.
@@ -4074,12 +4140,18 @@ interface LunoraWorker {
4074
4140
  * `__lunoraRef` is the `"namespace:fn"` dispatched.
4075
4141
  * @param args The function arguments.
4076
4142
  * @param options Call options mirroring the RPC envelope.
4143
+ * @param options.context The host's `ExecutionContext`. Required to reach an
4144
+ * identity the platform supplies out-of-band rather than on the
4145
+ * request — `context.access` under a Worker-scoped Cloudflare
4146
+ * Access policy. Omit it there and the call resolves anonymous
4147
+ * while the same user's `/_lunora/rpc` traffic is authenticated.
4077
4148
  * @param options.shardKey Routes to a specific shard (omitted → the worker's
4078
4149
  * `defaultShardKey`).
4079
4150
  * @param options.waitUntil The host's `waitUntil`, so dispatch telemetry
4080
4151
  * whose export is deferred (a gzipped OTLP body) survives isolate teardown.
4081
4152
  */
4082
4153
  serverQuery: (request: Request, env: unknown, reference: unknown, args?: Record<string, unknown>, options?: {
4154
+ context?: ExecutionContextLike;
4083
4155
  shardKey?: string;
4084
4156
  waitUntil?: (promise: Promise<unknown>) => void;
4085
4157
  }) => Promise<Response>;
@@ -4799,8 +4871,16 @@ declare const combineSinks: (...sinks: ObservabilitySink[]) => ObservabilitySink
4799
4871
  * as caller-specific. Checks the built-in identity headers plus anything the
4800
4872
  * policy declares via `credentialHeaders` — an app whose `resolveIdentity` reads
4801
4873
  * a bespoke header must say so, or its callers read as anonymous here.
4874
+ *
4875
+ * A credential does not have to be on the request at all: under a Cloudflare
4876
+ * Access policy attached to the Worker, the caller is authenticated by the edge
4877
+ * and their identity arrives on the `ExecutionContext` as `access`, with no
4878
+ * header this function could see. Its mere presence means Access authorized this
4879
+ * specific caller, so it counts as a credential — otherwise a per-user response
4880
+ * would be labelled `public` and a shared cache could hand it to the next
4881
+ * visitor.
4802
4882
  */
4803
- declare const requestCarriesCredentials: (request: Request, policy: RestCachePolicy) => boolean;
4883
+ declare const requestCarriesCredentials: (request: Request, policy: RestCachePolicy, context?: ExecutionContextLike) => boolean;
4804
4884
  /**
4805
4885
  * Build the cache headers for one exchange, or `undefined` when the exchange
4806
4886
  * isn't cacheable at all (non-`GET`, or a non-2xx result — an error body must
@@ -4809,14 +4889,14 @@ declare const requestCarriesCredentials: (request: Request, policy: RestCachePol
4809
4889
  * The effective scope is `policy.scope` narrowed by {@link requestCarriesCredentials};
4810
4890
  * `"public"` survives only for a genuinely anonymous request.
4811
4891
  */
4812
- declare const restCacheHeaders: (policy: RestCachePolicy, request: Request, status: number) => Record<string, string> | undefined;
4892
+ declare const restCacheHeaders: (policy: RestCachePolicy, request: Request, status: number, context?: ExecutionContextLike) => Record<string, string> | undefined;
4813
4893
  /**
4814
4894
  * Return `response` with the declared cache headers applied. A shard `Response`
4815
4895
  * has immutable headers, so this rebuilds it (status/statusText/existing headers
4816
4896
  * are carried over, the body is streamed through untouched). When the exchange
4817
4897
  * isn't cacheable the original response is returned as-is — no copy.
4818
4898
  */
4819
- declare const applyRestCache: (response: Response, policy: RestCachePolicy | undefined, request: Request) => Response;
4899
+ declare const applyRestCache: (response: Response, policy: RestCachePolicy | undefined, request: Request, context?: ExecutionContextLike) => Response;
4820
4900
  /**
4821
4901
  * Structural mirror of `@lunora/client`'s `FunctionReference`, re-declared so this
4822
4902
  * module carries no `runtime → client` (browser SDK) dependency. The phantom
@@ -4910,7 +4990,7 @@ declare const createShardClient: (namespace: ShardNamespaceLike, options?: Shard
4910
4990
  */
4911
4991
  declare const STORAGE_UPLOAD_MAX_BODY_BYTES: number;
4912
4992
  declare const VERSION: string;
4913
- export { type AdminTableResolver, type AirbyteMessage, type AnalyticsEngineDataPointLike, type AnalyticsEngineDatasetLike, type AnalyticsEngineSinkOptions, type AuthAdmin, type AuthCapabilities, type AuthConfigInfo, type AuthImpersonation, type AuthPage, type AuthSession, type AuthUser, type AuthUserFieldSpec, BACKUP_KEY_PREFIX, type BackupManifest, type BackupManifestEntry, type BackupRetentionPreview, type BackupStore, type ComposeIdentityResolversErrorMode, type ComposeIdentityResolversOptions, type ConnectorChange, type ConnectorSyncPage, type CorsOptions, type CronHandler, type CronJobDispatch, type CronJobInfo, type CrossShardCounter, type CrossShardReader, type CrossShardRelationCapabilities, type CrossShardRelationOptions, type CsrfOptions, DEFAULT_LOG_COLUMNS, DEFAULT_LOG_LIMIT, DEFAULT_REGISTRY_CACHE_TTL_MS, type DurableObjectJurisdiction, type DynamicShardRegistry, type DynamicShardRegistryOptions, type ExecutionContextLike, type ExportBatch, type ExportChange, type ExportCursorStore, type ExportFanOutRequest, type ExportFanOutResult, type ExportSink, type ExportTapFailure, type ExportTapResult, type FanOutRequest, type FanOutResult, type FanOutSpec, type FivetranResponse, type FrameworkHostHandler, type FrameworkWorkerOptions, type FrameworkWorkerOptionsInput, type FunctionDescriptor, type FunctionRegistryEntry, type FunctionRegistryLike, type GlobalExportFunction as GlobalExportFn, type GlobalImportFunction as GlobalImportFn, type GlobalIntrospector, type GlobalTableInfo as GlobalTableInfoMeta, type GlobalTablePage as GlobalTablePageMeta, HEALTH_PATH, HEALTH_READY_PATH, type HealthAuthPosture, type HealthBody, type HealthCheckReport, type HealthProbe, type HealthProbeKind, type HealthProbeResult, type HealthRouteDeps, type HttpActionContext, type HttpActionLike, type HttpRouterLike, type IdentityContractLike, type IdentityResolver, type IdentityValidation, type ImportFanOutRequest, type ImportFanOutResult, type KvIntrospector, type KvKeyEntry, type KvKeyListResult, type KvNamespaceSummary, type KvValueResult, LOG_ARCHIVE_NOT_CONFIGURED, LOG_ARCHIVE_PATH, type ListAuthUsersOptions, type LogArchiveConfig, type LogEvent, type LogFields, type LogLevel, LunoraError, type LunoraErrorBody, type LunoraHandlerOptions, type LunoraWorker, type MemoizeIdentityOptions, type MergeStrategy, type MetricEvent, type MetricKind, type MigrationFanOutRequest, type MigrationFanOutResult, NOOP_EXECUTION_CONTEXT, type NotifySubscriptionDevice, type NotifySubscriptionStoreLike, type ObservabilityEvent, type ObservabilitySink, type ObservabilitySinkContext,
4993
+ export { type AccessContextLike, type AccessIdentityLike, type AdminTableResolver, type AirbyteMessage, type AnalyticsEngineDataPointLike, type AnalyticsEngineDatasetLike, type AnalyticsEngineSinkOptions, type AuthAdmin, type AuthCapabilities, type AuthConfigInfo, type AuthImpersonation, type AuthPage, type AuthSession, type AuthUser, type AuthUserFieldSpec, BACKUP_KEY_PREFIX, type BackupManifest, type BackupManifestEntry, type BackupRetentionPreview, type BackupStore, type ComposeIdentityResolversErrorMode, type ComposeIdentityResolversOptions, type ConnectorChange, type ConnectorSyncPage, type CorsOptions, type CronHandler, type CronJobDispatch, type CronJobInfo, type CrossShardCounter, type CrossShardReader, type CrossShardRelationCapabilities, type CrossShardRelationOptions, type CsrfOptions, DEFAULT_LOG_COLUMNS, DEFAULT_LOG_LIMIT, DEFAULT_REGISTRY_CACHE_TTL_MS, type DurableObjectJurisdiction, type DynamicShardRegistry, type DynamicShardRegistryOptions, type ExecutionContextLike, type ExportBatch, type ExportChange, type ExportCursorStore, type ExportFanOutRequest, type ExportFanOutResult, type ExportSink, type ExportTapFailure, type ExportTapResult, type FanOutRequest, type FanOutResult, type FanOutSpec, type FivetranResponse, type FrameworkHostHandler, type FrameworkWorkerOptions, type FrameworkWorkerOptionsInput, type FunctionDescriptor, type FunctionRegistryEntry, type FunctionRegistryLike, type GlobalExportFunction as GlobalExportFn, type GlobalImportFunction as GlobalImportFn, type GlobalIntrospector, type GlobalTableInfo as GlobalTableInfoMeta, type GlobalTablePage as GlobalTablePageMeta, HEALTH_PATH, HEALTH_READY_PATH, type HealthAuthPosture, type HealthBody, type HealthCheckReport, type HealthProbe, type HealthProbeKind, type HealthProbeResult, type HealthRouteDeps, type HttpActionContext, type HttpActionLike, type HttpRouterLike, type IdentityContractLike, type IdentityResolver, type IdentityValidation, type ImportFanOutRequest, type ImportFanOutResult, type KvIntrospector, type KvKeyEntry, type KvKeyListResult, type KvNamespaceSummary, type KvValueResult, LOG_ARCHIVE_NOT_CONFIGURED, LOG_ARCHIVE_PATH, type ListAuthUsersOptions, type LogArchiveConfig, type LogEvent, type LogFields, type LogLevel, LunoraError, type LunoraErrorBody, type LunoraHandlerOptions, type LunoraWorker, type MemoizeIdentityOptions, type MergeStrategy, type MetricEvent, type MetricKind, type MigrationFanOutRequest, type MigrationFanOutResult, NOOP_EXECUTION_CONTEXT, type NotifySubscriptionDevice, type NotifySubscriptionStoreLike, type ObservabilityEvent, type ObservabilitySink, type ObservabilitySinkContext,
4914
4994
  /**
4915
4995
  * Resource attribute bag used by OTLP exporters. Re-exported from `shared/otlp`
4916
4996
  * because {@link OtlpSinkOptions.resourceAttributes} is part of the public
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{BACKUP_KEY_PREFIX as t,backupManifestKey as a,backupObjectKey as s,backupObjectKeyOfManifest as i,isBackupManifestEntry as n,isBackupManifestKey as p,normalizeBackupPrefix as c}from"./packem_shared/BACKUP_KEY_PREFIX-BOtSu-_3.mjs";import{toAirbyteMessages as f,toFivetranResponse as E}from"./packem_shared/toAirbyteMessages-Cy3uaySU.mjs";import{composeWorker as S,createLunoraHandler as x,createWorker as _,defineRpcEnvelope as d,resolveLunoraOptions as l,withFrameworkWorker as u}from"./packem_shared/composeWorker-BtABY25U.mjs";import{createCrossShardRelationCapabilities as k}from"./packem_shared/createCrossShardRelationCapabilities-DgQYQzd1.mjs";import{DEFAULT_REGISTRY_CACHE_TTL_MS as A,SHARD_REGISTRY_DO_NAME as C,createDynamicShardRegistry as L}from"./packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-D5O7elXI.mjs";import{LunoraError as b,toErrorResponse as g}from"./packem_shared/LunoraError-DksAgIpa.mjs";import{createKvCursorStore as H,createMemoryCursorStore as I,defineExportSink as P,r2Sink as v,runExportTap as D,sanitizeChange as F,webhookExportSink as M}from"./packem_shared/createKvCursorStore-VOd1DFsf.mjs";import{HEALTH_PATH as K,HEALTH_READY_PATH as N,buildHealthRoutes as U,d1Probe as B,durableObjectProbe as Y,presenceProbe as w}from"./packem_shared/HEALTH_PATH-jZsuCmSs.mjs";import{LOG_ARCHIVE_PATH as X,resolveLogArchiveFromEnv as j}from"./packem_shared/LOG_ARCHIVE_PATH-jgHjdsz2.mjs";import{memoizeIdentity as W,memoizeIdentityPerRequest as q}from"./packem_shared/memoizeIdentity-DVd9yDW1.mjs";import{e as J,a as Z}from"./packem_shared/observability-vDK-rMbs.mjs";import{analyticsEngineSink as ee,combineSinks as re,consoleSink as oe,otlpSink as te,pipelineLogSink as ae,sentrySink as se,webhookSink as ie}from"./packem_shared/analyticsEngineSink-D7qu89f2.mjs";import{D as pe,a as ce,c as me}from"./packem_shared/pipeline-log-reader-BGrl66P5.mjs";import{createQueryCoordinator as Ee,createStaticShardRegistry as Re,mergeStrategyForAggregate as Se}from"./packem_shared/createQueryCoordinator-CnNyazLX.mjs";import{applyJurisdiction as _e,resolveShard as de}from"./packem_shared/applyJurisdiction-C0ddU7Tg.mjs";import{a as ue,r as ye,b as ke}from"./packem_shared/rest-cache-D6nWkevc.mjs";import{a as Ae,b as Ce,c as Le,r as Te,d as be}from"./packem_shared/rest-routes-3l718ENH.mjs";import{decorateResponse as he,enforceOrigin as He,handleCorsPreflight as Ie,resolveSecurity as Pe}from"./packem_shared/decorateResponse-D3NzOIvB.mjs";import{createShardClient as De}from"./packem_shared/createShardClient-Yb6_Mzd6.mjs";import{STORAGE_UPLOAD_MAX_BODY_BYTES as Me}from"./packem_shared/STORAGE_UPLOAD_MAX_BODY_BYTES-BqyO-1l6.mjs";import{LOG_ARCHIVE_NOT_CONFIGURED as Ke}from"./packem_shared/LOG_ARCHIVE_NOT_CONFIGURED-CDpi4yFD.mjs";import{NOOP_EXECUTION_CONTEXT as Ue}from"./packem_shared/NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs";import{composeIdentityResolvers as Ye,routeIdentityResolvers as we}from"./packem_shared/composeIdentityResolvers-DdDFfuTV.mjs";const e="0.0.0";export{t as BACKUP_KEY_PREFIX,pe as DEFAULT_LOG_COLUMNS,ce as DEFAULT_LOG_LIMIT,A as DEFAULT_REGISTRY_CACHE_TTL_MS,K as HEALTH_PATH,N as HEALTH_READY_PATH,Ke as LOG_ARCHIVE_NOT_CONFIGURED,X as LOG_ARCHIVE_PATH,b as LunoraError,Ue as NOOP_EXECUTION_CONTEXT,C as SHARD_REGISTRY_DO_NAME,Me as STORAGE_UPLOAD_MAX_BODY_BYTES,e as VERSION,ee as analyticsEngineSink,_e as applyJurisdiction,ue as applyRestCache,Ae as argsFromQuery,a as backupManifestKey,s as backupObjectKey,i as backupObjectKeyOfManifest,U as buildHealthRoutes,Ce as buildRestRoutes,re as combineSinks,Ye as composeIdentityResolvers,S as composeWorker,oe as consoleSink,k as createCrossShardRelationCapabilities,L as createDynamicShardRegistry,H as createKvCursorStore,x as createLunoraHandler,I as createMemoryCursorStore,me as createPipelineLogReader,Ee as createQueryCoordinator,Le as createRestRateLimit,De as createShardClient,Re as createStaticShardRegistry,_ as createWorker,B as d1Probe,he as decorateResponse,P as defineExportSink,d as defineRpcEnvelope,Y as durableObjectProbe,J as emitLogEvent,Z as emitRpcEvent,He as enforceOrigin,Ie as handleCorsPreflight,n as isBackupManifestEntry,p as isBackupManifestKey,W as memoizeIdentity,q as memoizeIdentityPerRequest,Se as mergeStrategyForAggregate,c as normalizeBackupPrefix,te as otlpSink,ae as pipelineLogSink,w as presenceProbe,v as r2Sink,Te as readShardKey,ye as requestCarriesCredentials,j as resolveLogArchiveFromEnv,l as resolveLunoraOptions,Pe as resolveSecurity,de as resolveShard,ke as restCacheHeaders,be as restSurfaceFromRegistry,we as routeIdentityResolvers,D as runExportTap,F as sanitizeChange,se as sentrySink,f as toAirbyteMessages,g as toErrorResponse,E as toFivetranResponse,M as webhookExportSink,ie as webhookSink,u as withFrameworkWorker};
1
+ import{BACKUP_KEY_PREFIX as t,backupManifestKey as a,backupObjectKey as s,backupObjectKeyOfManifest as i,isBackupManifestEntry as n,isBackupManifestKey as p,normalizeBackupPrefix as c}from"./packem_shared/BACKUP_KEY_PREFIX-BOtSu-_3.mjs";import{toAirbyteMessages as f,toFivetranResponse as E}from"./packem_shared/toAirbyteMessages-Cy3uaySU.mjs";import{composeWorker as S,createLunoraHandler as x,createWorker as _,defineRpcEnvelope as d,resolveLunoraOptions as l,withFrameworkWorker as u}from"./packem_shared/composeWorker-CTKu1qZV.mjs";import{createCrossShardRelationCapabilities as k}from"./packem_shared/createCrossShardRelationCapabilities-DgQYQzd1.mjs";import{DEFAULT_REGISTRY_CACHE_TTL_MS as A,SHARD_REGISTRY_DO_NAME as C,createDynamicShardRegistry as L}from"./packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-D5O7elXI.mjs";import{LunoraError as b,toErrorResponse as g}from"./packem_shared/LunoraError-DksAgIpa.mjs";import{createKvCursorStore as H,createMemoryCursorStore as I,defineExportSink as P,r2Sink as v,runExportTap as D,sanitizeChange as F,webhookExportSink as M}from"./packem_shared/createKvCursorStore-VOd1DFsf.mjs";import{HEALTH_PATH as K,HEALTH_READY_PATH as N,buildHealthRoutes as U,d1Probe as B,durableObjectProbe as Y,presenceProbe as w}from"./packem_shared/HEALTH_PATH-jZsuCmSs.mjs";import{LOG_ARCHIVE_PATH as X,resolveLogArchiveFromEnv as j}from"./packem_shared/LOG_ARCHIVE_PATH-jgHjdsz2.mjs";import{memoizeIdentity as W,memoizeIdentityPerRequest as q}from"./packem_shared/memoizeIdentity-DnOj3QRi.mjs";import{e as J,a as Z}from"./packem_shared/observability-vDK-rMbs.mjs";import{analyticsEngineSink as ee,combineSinks as re,consoleSink as oe,otlpSink as te,pipelineLogSink as ae,sentrySink as se,webhookSink as ie}from"./packem_shared/analyticsEngineSink-D7qu89f2.mjs";import{D as pe,a as ce,c as me}from"./packem_shared/pipeline-log-reader-BGrl66P5.mjs";import{createQueryCoordinator as Ee,createStaticShardRegistry as Re,mergeStrategyForAggregate as Se}from"./packem_shared/createQueryCoordinator-CnNyazLX.mjs";import{applyJurisdiction as _e,resolveShard as de}from"./packem_shared/applyJurisdiction-C0ddU7Tg.mjs";import{a as ue,r as ye,b as ke}from"./packem_shared/rest-cache-BnMq2hbO.mjs";import{a as Ae,b as Ce,c as Le,r as Te,d as be}from"./packem_shared/rest-routes-D2b3HXA9.mjs";import{decorateResponse as he,enforceOrigin as He,handleCorsPreflight as Ie,resolveSecurity as Pe}from"./packem_shared/decorateResponse-D3NzOIvB.mjs";import{createShardClient as De}from"./packem_shared/createShardClient-Yb6_Mzd6.mjs";import{STORAGE_UPLOAD_MAX_BODY_BYTES as Me}from"./packem_shared/STORAGE_UPLOAD_MAX_BODY_BYTES-BqyO-1l6.mjs";import{LOG_ARCHIVE_NOT_CONFIGURED as Ke}from"./packem_shared/LOG_ARCHIVE_NOT_CONFIGURED-CDpi4yFD.mjs";import{NOOP_EXECUTION_CONTEXT as Ue}from"./packem_shared/NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs";import{composeIdentityResolvers as Ye,routeIdentityResolvers as we}from"./packem_shared/composeIdentityResolvers-BHZ4jH8o.mjs";const e="0.0.0";export{t as BACKUP_KEY_PREFIX,pe as DEFAULT_LOG_COLUMNS,ce as DEFAULT_LOG_LIMIT,A as DEFAULT_REGISTRY_CACHE_TTL_MS,K as HEALTH_PATH,N as HEALTH_READY_PATH,Ke as LOG_ARCHIVE_NOT_CONFIGURED,X as LOG_ARCHIVE_PATH,b as LunoraError,Ue as NOOP_EXECUTION_CONTEXT,C as SHARD_REGISTRY_DO_NAME,Me as STORAGE_UPLOAD_MAX_BODY_BYTES,e as VERSION,ee as analyticsEngineSink,_e as applyJurisdiction,ue as applyRestCache,Ae as argsFromQuery,a as backupManifestKey,s as backupObjectKey,i as backupObjectKeyOfManifest,U as buildHealthRoutes,Ce as buildRestRoutes,re as combineSinks,Ye as composeIdentityResolvers,S as composeWorker,oe as consoleSink,k as createCrossShardRelationCapabilities,L as createDynamicShardRegistry,H as createKvCursorStore,x as createLunoraHandler,I as createMemoryCursorStore,me as createPipelineLogReader,Ee as createQueryCoordinator,Le as createRestRateLimit,De as createShardClient,Re as createStaticShardRegistry,_ as createWorker,B as d1Probe,he as decorateResponse,P as defineExportSink,d as defineRpcEnvelope,Y as durableObjectProbe,J as emitLogEvent,Z as emitRpcEvent,He as enforceOrigin,Ie as handleCorsPreflight,n as isBackupManifestEntry,p as isBackupManifestKey,W as memoizeIdentity,q as memoizeIdentityPerRequest,Se as mergeStrategyForAggregate,c as normalizeBackupPrefix,te as otlpSink,ae as pipelineLogSink,w as presenceProbe,v as r2Sink,Te as readShardKey,ye as requestCarriesCredentials,j as resolveLogArchiveFromEnv,l as resolveLunoraOptions,Pe as resolveSecurity,de as resolveShard,ke as restCacheHeaders,be as restSurfaceFromRegistry,we as routeIdentityResolvers,D as runExportTap,F as sanitizeChange,se as sentrySink,f as toAirbyteMessages,g as toErrorResponse,E as toFivetranResponse,M as webhookExportSink,ie as webhookSink,u as withFrameworkWorker};
@@ -1 +1 @@
1
- import{a as r,r as s,b as t}from"./rest-cache-D6nWkevc.mjs";export{r as applyRestCache,s as requestCarriesCredentials,t as restCacheHeaders};
1
+ import{a as r,r as s,b as t}from"./rest-cache-BnMq2hbO.mjs";export{r as applyRestCache,s as requestCarriesCredentials,t as restCacheHeaders};
@@ -1 +1 @@
1
- import"./rest-cache-D6nWkevc.mjs";import{a as t,b as o,c as i,r as m,d as R}from"./rest-routes-3l718ENH.mjs";import"./method-guard-BG_vJNTl.mjs";export{t as argsFromQuery,o as buildRestRoutes,i as createRestRateLimit,m as readShardKey,R as restSurfaceFromRegistry};
1
+ import"./rest-cache-BnMq2hbO.mjs";import{a as t,b as o,c as i,r as m,d as R}from"./rest-routes-D2b3HXA9.mjs";import"./method-guard-BG_vJNTl.mjs";export{t as argsFromQuery,o as buildRestRoutes,i as createRestRateLimit,m as readShardKey,R as restSurfaceFromRegistry};
@@ -0,0 +1 @@
1
+ import{LunoraError as a}from"./LunoraError-DksAgIpa.mjs";const u=(t,o={})=>{const r=o.onError??"fail-closed";return async(n,c,e)=>{for(const s of t){let i;try{i=await s(n,c,e)}catch(l){if(r==="skip")continue;throw l}if(i)return i}return null}},f=t=>{const o=Object.keys(t).filter(r=>r!=="*").toSorted((r,n)=>n.length-r.length);return(r,n,c)=>{const{pathname:e}=new URL(r.url),s=o.find(l=>e===l||e.startsWith(l.endsWith("/")?l:`${l}/`)),i=s===void 0?t["*"]:t[s];return i===void 0?null:i(r,n,c)}},h=(t,o)=>o===void 0||t===void 0?t:async(r,n,c)=>{const e=await t(r,n,c);if(!e)return e;const s=o.validate(e);if(s.ok)return e;if(o.onInvalid==="reject")throw new a(`identity claims failed the declared contract: ${s.error}`,{code:"UNAUTHENTICATED",status:401});return null};export{u as composeIdentityResolvers,f as routeIdentityResolvers,h as wrapResolverWithContract};
@@ -0,0 +1,6 @@
1
+ import{isLunoraError as Dn,toErrorBody as Nn}from"@lunora/errors";import{e as Dt}from"./evict-oldest-BNXsKx4s.mjs";import{NOOP_EXECUTION_CONTEXT as Un}from"./NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs";import{e as Cn,a as Bn}from"./identity-header-JF5q3H5w.mjs";import{o as Se,b as xn,p as Hn,m as Ln,d as Mn,a as jn,r as $n}from"./otlp-resource-B4Yylr0V.mjs";import{e as Z,f as be,M as Nt,b as Kn,g as Fn,h as Ut,i as Ct}from"./rest-routes-D2b3HXA9.mjs";import{LunoraError as d,toErrorResponse as tt}from"./LunoraError-DksAgIpa.mjs";import{a as j,m as me}from"./method-guard-BG_vJNTl.mjs";import{normalizeBackupPrefix as Ge,BACKUP_KEY_PREFIX as Qe,isBackupManifestKey as Gn,backupObjectKeyOfManifest as Bt,backupObjectKey as Qn,backupManifestKey as zn}from"./BACKUP_KEY_PREFIX-BOtSu-_3.mjs";import{toHex as Wn,buildStorageAdminRoutes as Vn,STORAGE_UPLOAD_MAX_BODY_BYTES as Jn,STORAGE_PATH as qn}from"./STORAGE_UPLOAD_MAX_BODY_BYTES-BqyO-1l6.mjs";import{runExportTap as Yn}from"./createKvCursorStore-VOd1DFsf.mjs";import{buildHealthRoutes as Xn,durableObjectProbe as Zn,d1Probe as er,presenceProbe as Ce}from"./HEALTH_PATH-jZsuCmSs.mjs";import{wrapResolverWithContract as tr}from"./composeIdentityResolvers-BHZ4jH8o.mjs";import{composeIdentityResolvers as _s,routeIdentityResolvers as Rs}from"./composeIdentityResolvers-BHZ4jH8o.mjs";import{buildLogArchiveAdminRoutes as nr}from"./LOG_ARCHIVE_PATH-jgHjdsz2.mjs";import{r as rr,f as nt,a as ce}from"./observability-vDK-rMbs.mjs";import{resolveShard as we,applyJurisdiction as rt}from"./applyJurisdiction-C0ddU7Tg.mjs";import{resolveSecurity as ot,handleCorsPreflight as or,enforceOrigin as ar,decorateResponse as Be,enforceWebSocketOrigin as at}from"./decorateResponse-D3NzOIvB.mjs";const sr=e=>{const n=e??{};if(typeof n.bucket=="function")return n;const t={...n,bucketName:"default"};return t.bucket=()=>t,t},xt="__lunoraBranch",ir=e=>typeof e=="object"&&e!==null&&Object.hasOwn(e,xt),cr=`may not contain the reserved workflow branch-marker key ("${xt}")`,ze=(e,n)=>{const t=Math.max(e.length,n.length);let r=e.length^n.length;for(let a=0;a<t;a+=1){const s=a<e.length?e.charCodeAt(a):0,l=a<n.length?n.charCodeAt(a):0;r|=s^l}return r===0},We=new TextEncoder,dr=Array.from({length:32},(e,n)=>n);new RegExp(`[${dr.map(e=>String.fromCodePoint(e)).join("")}]`,"u");const ur=e=>{const n=String.fromCodePoint(...e);return btoa(n).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},lr=e=>{const n=e.replaceAll("-","+").replaceAll("_","/")+"===".slice((e.length+3)%4),t=atob(n),r=new Uint8Array(t.length);for(let a=0;a<t.length;a+=1)r[a]=t.codePointAt(a)??0;return r},hr=64,xe=new Map,Ht=async e=>{const n=xe.get(e);if(n)return n;Dt(xe,hr);const t=crypto.subtle.importKey("raw",We.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]);return xe.set(e,t),t},Lt=async(e,n)=>{const t=await Ht(e),r=await crypto.subtle.sign("HMAC",t,We.encode(n));return ur(new Uint8Array(r))},fr=async(e,n,t)=>{const r=await Ht(e);return crypto.subtle.verify("HMAC",r,t,We.encode(n))},pr=["wnam","enam","sam","weur","eeur","apac","apac-ne","apac-se","oc","afr","me"];new Set(pr);const mr=new Set(["AE","BH","IL","IQ","IR","JO","KW","LB","OM","PS","QA","SA","SY","TR","YE"]),wr=-100,gr=15,yr=e=>{const n=Number(e.longitude??Number.NaN);switch(e.continent){case"AF":return"afr";case"AS":return e.country!==void 0&&mr.has(e.country)?"me":"apac";case"EU":return Number.isFinite(n)&&n>gr?"eeur":"weur";case"NA":return Number.isFinite(n)&&n<wr?"wnam":"enam";case"OC":return"oc";case"SA":return"sam";default:return}},st=e=>{const n=e.cf;return n===void 0?void 0:yr(n)},Mt="::relay::",br=(e,n)=>`${e}${Mt}${String(n)}`,jt="::replica::",_r=(e,n)=>`${e}${jt}${n}`,Rr=e=>{if(e==null||!/^\d+$/.test(e))return;const n=Number.parseInt(e,10);return Number.isSafeInteger(n)&&n>0?n:void 0},Er=new Set(["1","enabled","on","true","yes"]),Ar=new Set(["0","disabled","false","no","off"]),Sr=(e,n)=>{const t=(e??"").trim().toLowerCase();return Er.has(t)?!0:Ar.has(t)?!1:n},$t="v1",Tr=6e4,Or=async(e,n={})=>{const t=(n.now??Date.now())+(n.ttlMs??Tr),r=`${$t}.${String(t)}`,a=await Lt(e,r);return{expiresAtMs:t,token:`${r}.${a}`}},vr=async(e,n,t=Date.now())=>{if(e.length===0||n.length===0)return!1;const r=n.split(".");if(r.length!==3)return!1;const[a,s,l]=r;if(a!==$t||l.length===0)return!1;const u=Number(s);if(!Number.isFinite(u)||u<=t)return!1;let f;try{f=lr(l)}catch{return!1}return fr(e,`${a}.${s}`,f)},P="/_lunora/admin/auth",kr={INVITER_REQUIRED:400,ORG_SLUG_INVALID:400,ORG_SLUG_TAKEN:409,PASSWORD_TOO_LONG:400,PASSWORD_TOO_SHORT:400,USER_ALREADY_EXISTS:409,USER_NOT_FOUND:404},N=(e,n)=>{const t=e[n];if(typeof t!="string"||t==="")throw new d(`\`${n}\` is required`,{code:"BAD_REQUEST",status:400});return t},le=(e,n)=>{const t=e(n);if(t===void 0)throw new d(`\`${n}\` query parameter is required`,{code:"BAD_REQUEST",status:400});return t},Kt=e=>{if(typeof e=="string"||Array.isArray(e)&&e.every(n=>typeof n=="string"))return e},re=(e,n)=>typeof e[n]=="string"?e[n]:void 0,He=(e,n)=>{const t=e[n];return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:void 0},it=e=>{const n=Kt(e.role);if(n===void 0||typeof n=="string"&&n.trim()==="")throw new d("`role` is required",{code:"BAD_REQUEST",status:400});return n},ct=e=>{const n=e.permission;if(typeof n!="object"||n===null||Array.isArray(n))throw new d("`permission` object is required",{code:"BAD_REQUEST",status:400});const t={};for(const[r,a]of Object.entries(n))Array.isArray(a)&&a.every(s=>typeof s=="string")&&(t[r]=a);return t},Ir={[`${P}/capabilities`]:{build:()=>({}),http:"GET",method:"capabilities"},[`${P}/users`]:{build:({paging:e,query:n})=>{const t=n("sortDirection");return{...e,filterField:n("filterField"),filterValue:n("filterValue"),search:n("search"),searchField:n("searchField"),sortBy:n("sortBy"),sortDirection:t==="asc"||t==="desc"?t:void 0}},http:"GET",method:"listUsers"},[`${P}/sessions`]:{build:({paging:e,query:n})=>({...e,userId:n("userId")}),http:"GET",method:"listSessions"},[`${P}/accounts`]:{build:({query:e})=>({userId:le(e,"userId")}),http:"GET",method:"listAccounts"},[`${P}/passkeys`]:{build:({query:e})=>({userId:le(e,"userId")}),http:"GET",method:"listPasskeys"},[`${P}/organizations`]:{build:({paging:e})=>({...e}),http:"GET",method:"listOrganizations"},[`${P}/organizations/members`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listMembers"},[`${P}/organizations/invitations`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listInvitations"},[`${P}/config`]:{build:()=>({}),http:"GET",method:"config"},[`${P}/organizations/teams`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listTeams"},[`${P}/organizations/teams/members`]:{build:({paging:e,query:n})=>({...e,teamId:le(n,"teamId")}),http:"GET",method:"listTeamMembers"},[`${P}/organizations/roles`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listOrgRoles"},[`${P}/users/create`]:{build:({body:e})=>({data:He(e,"data"),email:N(e,"email"),name:N(e,"name"),password:re(e,"password"),role:Kt(e.role)}),http:"POST",method:"createUser"},[`${P}/users/update`]:{build:({body:e})=>{const{data:n}=e;if(typeof n!="object"||n===null||Array.isArray(n))throw new d("`data` object is required",{code:"BAD_REQUEST",status:400});return{data:n,userId:N(e,"userId")}},http:"POST",method:"updateUser"},[`${P}/users/role`]:{build:({body:e})=>({role:it(e),userId:N(e,"userId")}),http:"POST",method:"setRole"},[`${P}/users/ban`]:{build:({body:e})=>({expiresInSeconds:typeof e.expiresInSeconds=="number"?e.expiresInSeconds:void 0,reason:re(e,"reason"),userId:N(e,"userId")}),http:"POST",method:"banUser"},[`${P}/users/unban`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"unbanUser"},[`${P}/users/password`]:{build:({body:e})=>({newPassword:N(e,"newPassword"),userId:N(e,"userId")}),http:"POST",method:"setUserPassword",returns:"void"},[`${P}/users/remove`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"removeUser",returns:"void"},[`${P}/users/impersonate`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"impersonateUser"},[`${P}/sessions/revoke`]:{build:({body:e})=>({sessionId:N(e,"sessionId")}),http:"POST",method:"revokeUserSession",returns:"void"},[`${P}/sessions/revoke-all`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"revokeUserSessions",returns:"void"},[`${P}/accounts/unlink`]:{build:({body:e})=>({accountId:N(e,"accountId"),userId:N(e,"userId")}),http:"POST",method:"unlinkAccount",returns:"void"},[`${P}/two-factor/disable`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"disableTwoFactor",returns:"void"},[`${P}/passkeys/delete`]:{build:({body:e})=>({passkeyId:N(e,"passkeyId")}),http:"POST",method:"deletePasskey",returns:"void"},[`${P}/organizations/members/remove`]:{build:({body:e})=>({memberId:N(e,"memberId")}),http:"POST",method:"removeMember",returns:"void"},[`${P}/organizations/invitations/cancel`]:{build:({body:e})=>({invitationId:N(e,"invitationId")}),http:"POST",method:"cancelInvitation",returns:"void"},[`${P}/organizations/create`]:{build:({body:e})=>({logo:re(e,"logo"),metadata:He(e,"metadata"),name:N(e,"name"),ownerId:re(e,"ownerId"),slug:re(e,"slug")}),http:"POST",method:"createOrganization"},[`${P}/organizations/update`]:{build:({body:e})=>({logo:re(e,"logo"),metadata:He(e,"metadata"),name:re(e,"name"),organizationId:N(e,"organizationId"),slug:re(e,"slug")}),http:"POST",method:"updateOrganization"},[`${P}/organizations/remove`]:{build:({body:e})=>({organizationId:N(e,"organizationId")}),http:"POST",method:"deleteOrganization",returns:"void"},[`${P}/organizations/members/add`]:{build:({body:e})=>({organizationId:N(e,"organizationId"),role:re(e,"role"),userId:N(e,"userId")}),http:"POST",method:"addMember"},[`${P}/organizations/members/invite`]:{build:({body:e})=>({email:N(e,"email"),inviterId:re(e,"inviterId"),organizationId:N(e,"organizationId"),role:re(e,"role")}),http:"POST",method:"inviteMember"},[`${P}/organizations/members/role`]:{build:({body:e})=>({memberId:N(e,"memberId"),role:it(e)}),http:"POST",method:"updateMemberRole"},[`${P}/organizations/teams/create`]:{build:({body:e})=>({name:N(e,"name"),organizationId:N(e,"organizationId")}),http:"POST",method:"createTeam"},[`${P}/organizations/teams/update`]:{build:({body:e})=>({name:N(e,"name"),teamId:N(e,"teamId")}),http:"POST",method:"updateTeam"},[`${P}/organizations/teams/remove`]:{build:({body:e})=>({teamId:N(e,"teamId")}),http:"POST",method:"removeTeam",returns:"void"},[`${P}/organizations/teams/members/add`]:{build:({body:e})=>({teamId:N(e,"teamId"),userId:N(e,"userId")}),http:"POST",method:"addTeamMember"},[`${P}/organizations/teams/members/remove`]:{build:({body:e})=>({teamMemberId:N(e,"teamMemberId")}),http:"POST",method:"removeTeamMember",returns:"void"},[`${P}/organizations/roles/create`]:{build:({body:e})=>({organizationId:N(e,"organizationId"),permission:ct(e),role:N(e,"role")}),http:"POST",method:"createOrgRole"},[`${P}/organizations/roles/update`]:{build:({body:e})=>({permission:ct(e),roleId:N(e,"roleId")}),http:"POST",method:"updateOrgRole"},[`${P}/organizations/roles/remove`]:{build:({body:e})=>({roleId:N(e,"roleId")}),http:"POST",method:"deleteOrgRole",returns:"void"}},Pr=e=>{const n=async a=>{try{return await a()}catch(s){if(s instanceof d)throw s;const l=s,u=typeof l.code=="string"?l.code:"AUTH_ADMIN_ERROR";throw console.error("[lunora] auth admin operation failed:",s),new d("auth admin operation failed",{code:u,status:kr[u]??500})}},t=async(a,s)=>{if(e.assertAdmin(a),a.method!==s.http)throw new d(`Auth admin endpoint requires ${s.http}`,{code:"METHOD_NOT_ALLOWED",status:405});const l=e.getAuthAdmin();if(l===void 0)throw new d("auth endpoints require an `authAdmin` on the worker",{code:"AUTH_NOT_CONFIGURED",status:400});const u=l[s.method];if(u===void 0)throw new d(`auth admin does not support \`${s.method}\``,{code:"AUTH_OP_NOT_SUPPORTED",status:400});const f=new URL(a.url),g={body:s.http==="POST"?await e.readJsonBody(a):{},paging:e.parsePaging(a),query:v=>e.queryParameter(f,v)},E=s.build(g),k=await n(()=>u(E));return Response.json(s.returns==="void"?{ok:!0}:k,{headers:{"content-type":"application/json"},status:200})},r={};for(const[a,s]of Object.entries(Ir))r[a]=l=>t(l,s);return r},Dr="__lunora_admin__:getAuthAuditLog",dt=e=>typeof e=="string"&&e!==""?e:void 0,ut=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0,Nr=e=>async(t,r)=>{e.assertAdmin(t);const a=e.getReader();if(a===void 0)throw new d("the auth/security audit endpoint requires an `authAuditReader` on the worker",{code:"AUTH_AUDIT_NOT_CONFIGURED",status:400});const s=dt(r.actorId),l=dt(r.event),u=ut(r.sinceSeq),f=ut(r.limit),g={...s===void 0?{}:{actorId:s},...l===void 0?{}:{event:l},...u===void 0?{}:{sinceSeq:u},...f===void 0?{}:{limit:f}};let E;try{E=await a.read(g)}catch(v){throw v instanceof d?v:(console.error("[lunora] auth audit read failed:",v),new d("auth audit read failed",{code:"AUTH_AUDIT_READ_FAILED",status:500}))}const k={entries:E};return Response.json(k,{headers:{"content-type":"application/json"},status:200})},Ur=(e,n)=>{const t=[],r=[];if(n&&n.length>0)for(const a of n)e.resolveTableSharding?.(a)?.mode.kind==="global"?r.push(a):t.push(a);return{globalTables:r,shardLocalTables:t}},Cr=async(e,n,t,r,a,s)=>{if(t!==void 0&&r.length===0)return;const l=await e.orchestrateExport(s,{args:{tables:r},headers:n,tables:r});for(const u of l.shards)if(!u.error)for(const f of u.rows??[])a(f)},Ft=async(e,n,t,r,a,s)=>{const{globalTables:l,shardLocalTables:u}=Ur(e,r);await Cr(n,t,r,u,a,s);const f=e.exportGlobals;if((r===void 0||l.length>0)&&f)for await(const E of f({tables:l}))a(E)},Br=new TextEncoder,xr=1e3,Gt=10,Hr=200,lt=8,Qt="lunoraBackupCron",ht=24*1048576,ft=e=>{const n=e.slice(0,Gt).map(r=>Bt(r)),t=e.length-n.length;return`${n.join(", ")}${t>0?` (+${String(t)} more)`:""}`},Lr=(e,n)=>{const t=new Uint8Array(new ArrayBuffer(n));let r=0;for(const a of e)t.set(a,r),r+=a.byteLength;return t},Ve=async(e,n,t,r)=>{if(t===void 0||!Number.isInteger(t)||t<=0)return{eligible:0,stale:[]};const a=[];let s;for(let l=0;l<xr;l+=1){const u=await e.list({cursor:s,include:["customMetadata"],prefix:n});for(const f of u.objects)Gn(f.key)&&f.customMetadata?.[Qt]===r&&a.push(f.key);if(!u.truncated||u.cursor===void 0)break;s=u.cursor}return{eligible:a.length,stale:a.toSorted((l,u)=>u.localeCompare(l)).slice(t)}},Mr=async(e,n,t,r,a)=>{const{stale:s}=await Ve(e,n,t,r),l=new Set(a),u=s.filter(w=>l.has(w)),f=u.slice(0,Hr),g=s.length-f.length,E=a.length-u.length;if(f.length===0)return{deleted:[],failed:[],ignored:E,remaining:g};const k=[],v=[];for(let w=0;w<f.length;w+=lt){const b=await Promise.allSettled(f.slice(w,w+lt).map(async _=>(await e.delete(Bt(_)),await e.delete(_),_)));for(const[_,p]of b.entries())p.status==="fulfilled"?k.push(p.value):v.push(f[w+_])}return k.length>0&&console.info(`[lunora] backup prune kept the newest ${String(t)} and deleted ${String(k.length)}: ${ft(k)}`),v.length>0&&console.warn(`[lunora] backup prune failed to remove ${String(v.length)}: ${ft(v)}`),{deleted:k,failed:v,ignored:E,remaining:g}},jr=async e=>{const n=e.backupStore;if(!n)throw new d("backup retention preview requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});const t=Ge(e.backupPrefix??Qe),r=e.backupCron,{eligible:a,stale:s}=r===void 0?{eligible:0,stale:[]}:await Ve(n,t,e.backupRetain,r);return{cron:r,eligible:a,keep:e.backupRetain??0,prefix:t,wouldDelete:s}},$r=async(e,n,t,r)=>{const a=e.backupStore,s=e.queryCoordinator;if(!a)throw new d("scheduled backup requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});if(!s)throw new d("scheduled backup requires a `queryCoordinator` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});if(!t||t.length===0)throw new d("scheduled backup requires an `adminToken` (or `env.LUNORA_ADMIN_TOKEN`) to authenticate the per-shard export gate",{code:"BACKUP_NOT_CONFIGURED",status:500});const l={authorization:`Bearer ${t}`,"content-type":"application/json"},u=e.backupTables;let f=0,g=0,E=[];await Ft(e,s,l,u,D=>{const T=Br.encode(`${JSON.stringify(D)}
2
+ `);if(f+=1,g+=T.byteLength,g>ht)throw new d(`scheduled backup reached ${String(g)} bytes of NDJSON, past the ${String(ht)}-byte limit for a snapshot assembled inside a Worker — nothing was written. Narrow it with \`backupTables\`, or take this snapshot off-platform with \`lunora backup create --bucket\`.`,{code:"BACKUP_TOO_LARGE",status:507});E.push(T)},n);const v=Ge(e.backupPrefix??Qe),w=new Date(r.scheduledTime).toISOString(),b=Qn(v,w),_=Lr(E,g);E=[];const p=Wn(await crypto.subtle.digest("SHA-256",_));await a.put(b,_,{httpMetadata:{contentType:"application/x-ndjson"},sha256:p});const S={bytes:g,createdAt:w,cron:r.cron,file:b,id:w,rows:f,scheduledTime:r.scheduledTime,sha256:p,...u?{tables:u.join(",")}:{}};await a.put(zn(b),`${JSON.stringify(S,void 0,2)}
3
+ `,{customMetadata:{[Qt]:r.cron},httpMetadata:{contentType:"application/json"}});try{const{stale:D}=await Ve(a,v,e.backupRetain,r.cron);if(D.length>0){const T=D.slice(0,Gt),x=D.length-T.length;console.info(`[lunora] backup retention: ${String(D.length)} snapshot(s) past the newest ${String(e.backupRetain)} — run \`lunora backup prune\` to remove them: ${T.join(", ")}${x>0?` (+${String(x)} more)`:""}`)}}catch(D){console.warn(`[lunora] backup ${b} was written, but the retention report failed:`,D)}},Kr=async(e,n)=>{const t=e.backupStore;if(!t)throw new d("backup prune requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});const r=e.backupCron,a=e.backupRetain;if(r===void 0||a===void 0||!Number.isInteger(a)||a<=0)throw new d("backup prune needs a retention window: set `backupRetain` (and `backupCron`, which decides whose snapshots retention owns) on the worker. Without one there is nothing past the window to remove.",{code:"BACKUP_RETENTION_NOT_CONFIGURED",status:400});return Mr(t,Ge(e.backupPrefix??Qe),a,r,n)},Fr="/_lunora/admin/backup/retention",Gr="/_lunora/admin/backup/prune",Qr=e=>{const{options:n,readJsonBody:t,requireAdminOption:r}=e,a=(u,f)=>{r(u,n.backupStore,{code:"BACKUP_NOT_CONFIGURED",message:`backup ${f} requires a \`backupStore\` on the worker`})},s=async u=>(j(u,"GET","Backup-retention"),a(u,"retention preview"),Response.json(await jr(n),{headers:{"cache-control":"no-store"}})),l=async u=>{j(u,"POST","Backup-prune"),a(u,"prune");const{confirm:f}=await t(u);if(!Array.isArray(f)||f.some(g=>typeof g!="string"))throw new d("backup prune requires a `confirm` array of the sidecar keys to remove — read them from `GET /_lunora/admin/backup/retention` and pass back the ones you mean to delete",{code:"BAD_REQUEST",status:400});return Response.json(await Kr(n,f),{headers:{"cache-control":"no-store"}})};return{[Gr]:l,[Fr]:s}},pt=500,zr=(e,n,t)=>{if(typeof e!="object"||e===null||Array.isArray(e))throw new d("each batch call must be an object",{code:"BAD_REQUEST",status:400});const r=e;if(typeof r.functionPath!="string")throw new d("each batch call needs a string `functionPath`",{code:"BAD_REQUEST",status:400});if(r.functionPath.startsWith("__lunora_relation__:")||r.functionPath.startsWith("__lunora_admin__"))throw new d("reserved function path cannot be batched",{code:"FORBIDDEN",status:403});if(r.args!==void 0&&(typeof r.args!="object"||r.args===null||Array.isArray(r.args)))throw new d("each batch call `args` must be an object",{code:"BAD_REQUEST",status:400});return{entry:{args:r.args===void 0?{}:r.args,clientId:typeof r.clientId=="string"?r.clientId:void 0,clientSeq:typeof r.clientSeq=="number"?r.clientSeq:void 0,functionPath:r.functionPath,id:typeof r.id=="number"?r.id:n,mutationId:typeof r.mutationId=="string"?r.mutationId:void 0},shardKey:typeof r.shardKey=="string"?r.shardKey:t}},Wr=(e,n)=>{if(e.length>pt)throw new d(`RPC batch exceeds the ${String(pt)}-call limit`,{code:"BAD_REQUEST",status:400});const t=new Map;for(const[r,a]of e.entries()){const{entry:s,shardKey:l}=zr(a,r,n),u=t.get(l)??[];u.push(s),t.set(l,u)}return t},Vr=new TextEncoder,Jr=e=>{const n=JSON.stringify(e),t=Vr.encode(n);let r="";for(const a of t)r+=String.fromCodePoint(a);return btoa(r).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},qr=e=>{const n={g:0,s:{},v:1};if(typeof e!="string"||e.length===0)return n;try{const t=atob(e.replaceAll("-","+").replaceAll("_","/")),r=new Uint8Array(t.length);for(let u=0;u<t.length;u+=1)r[u]=t.codePointAt(u)??0;const a=JSON.parse(new TextDecoder().decode(r)),s=a.s&&typeof a.s=="object"?a.s:{},l={};for(const[u,f]of Object.entries(s))typeof f=="number"&&Number.isFinite(f)&&(l[u]=f);return{g:typeof a.g=="number"&&Number.isFinite(a.g)?a.g:0,s:l,v:1}}catch{return n}},Yr=e=>{const n=typeof e.table=="string"?e.table:"",t=typeof e.op=="string"?e.op:"",r=t==="delete"||t==="insert"||t==="update"?t:"upsert",a=typeof e.id=="string"?e.id:void 0;return{doc:(e.doc&&typeof e.doc=="object"?e.doc:void 0)??(a===void 0?{}:{_id:a}),op:r,table:n}},mt=(e,n,t)=>{for(const r of n)e.push(Yr(r));return t!==void 0&&n.length>=t},Xr="/_lunora/admin/export",Zr="/_lunora/admin/import",eo="/_lunora/admin/sync",to="/_lunora/admin/connector/sync",no="/_lunora/admin/apply",ro="/_lunora/admin/export-tap/run",oo=new TextEncoder,ao=async e=>{const t=await be(e,"Export")??{};if(t.tables===void 0)return{tables:void 0};if(!Array.isArray(t.tables))throw new d("Export `tables` must be a string array",{code:"BAD_REQUEST",status:400});const r=[];for(const a of t.tables){if(typeof a!="string"||a.length===0)throw new d("Export `tables` entries must be non-empty strings",{code:"BAD_REQUEST",status:400});r.push(a)}return{tables:r}},Le=e=>Array.isArray(e)?e.filter(n=>typeof n=="string"):void 0,so=e=>{const{applyGlobals:n,exportCursorStore:t,exportSinks:r,knownTables:a,queryCoordinator:s,assertAdmin:l,requireAdminOption:u,resolveForwardContext:f,shardDO:g,streamExportRows:E,streamingImport:k,syncGlobals:v}=e,w=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Export endpoint requires a `queryCoordinator` on the worker"}),U=await ao(T),{headers:W}=await f(T,x),K=new ReadableStream({async pull(V){const X=J=>{V.enqueue(oo.encode(`${JSON.stringify(J)}
4
+ `))};try{await E($,W,U.tables,X),V.close()}catch(J){V.error(J)}}});return new Response(K,{headers:{"content-type":"application/x-ndjson"},status:200})},b=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Sync endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),W=typeof U.cursors=="object"&&U.cursors!==null?U.cursors:{},K=typeof U.limit=="number"?U.limit:void 0,V=typeof U.globalCursor=="number"?U.globalCursor:0,X=Le(U.tables),{headers:J}=await f(T,x),ae=X??a(),F=await $.orchestrateCdcSync(g,{cursors:W,headers:J,limit:K,tables:ae}),he=v?await v({limit:K,sinceSeq:V}):void 0;return Response.json({global:he,shards:F.shards},{status:200})},_=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Connector sync endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),W=qr(U.cursor),K=typeof U.limit=="number"&&U.limit>0?U.limit:void 0,V=Le(U.tables),{headers:X}=await f(T,x),J=V??a(),ae=await $.orchestrateCdcSync(g,{cursors:W.s,headers:X,limit:K,tables:J}),F=[],he={...W.s};let G=!1;for(const se of ae.shards)G=mt(F,se.changes??[],K)||G,he[se.shardKey]=se.cursor;let oe=W.g;if(v){const se=await v({limit:K,sinceSeq:W.g});G=mt(F,se.changes,K)||G,oe=se.cursor}const Te=Jr({g:oe,s:he,v:1}),Oe={changes:F,hasMore:G,nextCursor:Te};return Response.json(Oe,{status:200})},p=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Apply endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),K=(Array.isArray(U.batches)?U.batches:[]).map(F=>F).filter(F=>F!==null&&typeof F=="object"&&typeof F.shardKey=="string"&&Array.isArray(F.changes)),V=Array.isArray(U.globalChanges)?U.globalChanges:[],{headers:X}=await f(T,x),J=await $.orchestrateApplyCdc(g,{batches:K,headers:X}),ae=V.length>0&&n?await n({changes:V}):0;return Response.json({applied:J.applied+ae,failed:J.failed,ok:J.ok},{status:200})},S=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;l(T);const{headers:$}=await f(T,x),U=await k(T,$);return Response.json(U,{headers:{"content-type":"application/json"},status:200})},D=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Export-tap endpoint requires a `queryCoordinator` on the worker"});if(r===void 0||Object.keys(r).length===0||t===void 0)throw new d("Export-tap endpoint requires `exportSinks` + `exportCursorStore` on the worker",{code:"EXPORT_TAP_NOT_CONFIGURED",status:400});const U=await Z(T),W=typeof U.sink=="string"?U.sink:void 0,K=typeof U.limit=="number"&&U.limit>0?U.limit:void 0,V=Le(U.tables);if(W===void 0)throw new d("Export-tap `sink` must name a configured sink",{code:"BAD_REQUEST",status:400});const X=r[W];if(X===void 0)throw new d(`Export-tap sink "${W}" is not configured`,{code:"NOT_FOUND",status:404});const{headers:J}=await f(T,x),ae=V??a(),F=await Yn({coordinator:$,cursorStore:t,headers:J,limit:K,shardDO:g,sink:X,tables:ae});return Response.json(F,{headers:{"content-type":"application/json"},status:200})};return{[no]:p,[to]:_,[Xr]:w,[ro]:D,[Zr]:S,[eo]:b}},io=(e,n)=>{let t;try{t=JSON.parse(e)}catch{return{error:{code:"BAD_ROW",line:n,message:"line is not valid JSON",table:""},ok:!1}}if(!t||typeof t!="object"||Array.isArray(t))return{error:{code:"BAD_ROW",line:n,message:"row must be a JSON object",table:""},ok:!1};const r=t;return typeof r.table!="string"||r.table.length===0?{error:{code:"BAD_ROW",line:n,message:"row is missing `table`",table:""},ok:!1}:!r.doc||typeof r.doc!="object"||Array.isArray(r.doc)?{error:{code:"BAD_ROW",line:n,message:"row is missing or malformed `doc`",table:r.table},ok:!1}:{doc:r.doc,ok:!0,table:r.table}},co=(e,n,t,r,a)=>{if(t?.mode.kind==="shardBy"&&typeof t.mode.field=="string"){const s=e[t.mode.field];return s==null?{error:{code:"BAD_ROW",line:a,message:`row missing shard field "${t.mode.field}" for table "${n}"`,table:n},ok:!1}:{ok:!0,shardKey:typeof s=="string"?s:JSON.stringify(s)}}return{ok:!0,shardKey:r}},uo=async(e,n,t)=>{if(!e.body)throw new d("Import endpoint requires a request body",{code:"BAD_REQUEST",status:400});const r=[],a=[],s=new Map;let l=0,u=0;const f=e.body.getReader(),g=new TextDecoder;let E="",k=0;const v=w=>{u+=1;const b=w.trim();if(b.length===0)return;l+=1;const _=io(b,u);if(!_.ok){r.push(_.error);return}const{doc:p,table:S}=_,D=n.resolveTableSharding?.(S);if(D?.mode.kind==="global"){a.push({doc:p,line:u,table:S});return}const T=co(p,S,D,t,u);if(!T.ok){r.push(T.error);return}const x=s.get(T.shardKey);x?x.rows.push({doc:p,table:S}):s.set(T.shardKey,{rows:[{doc:p,table:S}],shardKey:T.shardKey,startLine:u})};for(;;){const{done:w,value:b}=await f.read();if(w)break;if(b&&(k+=b.byteLength,k>Nt))throw await f.cancel().catch(()=>{}),new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});E+=g.decode(b,{stream:!0});let _=E.indexOf(`
5
+ `);for(;_!==-1;){const p=E.slice(0,_);E=E.slice(_+1),v(p),_=E.indexOf(`
6
+ `)}}return E.length>0&&v(E),{errors:r,globalRows:a,perShard:s,received:l}},wt=(e,n)=>{for(const[t,r]of Object.entries(n.inserted))e.inserted[t]=(e.inserted[t]??0)+r;for(const t of n.errors)e.errors.push({...t});e.conflicts+=n.conflicts},lo=async(e,n,t,r)=>{const a=n.defaultShardKey??"__root__",{errors:s,globalRows:l,perShard:u,received:f}=await uo(e,n,a),g={conflicts:0,errors:s,inserted:{}},E=[];if(n.resolveTableSharding===void 0&&u.size>0&&E.push("no `resolveTableSharding` is configured, so every row was routed to the default shard and no row could be recognised as `.global()` — correct for a single-shard app, silent misplacement for a sharded one"),u.size>0){const k=n.queryCoordinator;if(!k)throw new d("Import endpoint requires a `queryCoordinator` on the worker",{code:"BAD_REQUEST",status:400});const v=await k.orchestrateImport(r,{batches:[...u.values()],headers:t});wt(g,v)}if(l.length>0)if(n.importGlobals){const k=l[0]?.line??1,v=await n.importGlobals({rows:l,startLine:k});wt(g,v)}else for(const k of l)g.errors.push({code:"GLOBAL_NOT_CONFIGURED",line:k.line,message:`row targets global table "${k.table}" but no \`importGlobals\` is configured`,table:k.table});return{conflicts:g.conflicts,errors:g.errors,inserted:g.inserted,received:f,...E.length>0?{warnings:E}:{}}},Me=e=>typeof e=="object"&&e!==null?e:{},je=e=>typeof e.kind=="string"?e.kind:"unknown",ho=(e,n)=>{let t=Me(n),r=!1;je(t)==="optional"&&(r=!0,t=Me(t._meta?.inner));const a=je(t),s=t._meta??{},l={kind:a,name:e,optional:r};if(a==="id"&&typeof s.tableName=="string"&&(l.table=s.tableName),a==="array"){const u=je(Me(s.inner));u!=="unknown"&&(l.element=u)}return l},fo=e=>typeof e!="object"||e===null?[]:Object.entries(e).map(([n,t])=>ho(n,t)).toSorted((n,t)=>n.name.localeCompare(t.name)),po="/_lunora/admin/functions",mo="/_lunora/admin/cron-jobs",wo="/_lunora/admin/openapi",go="/_lunora/admin/openrpc",yo="/_lunora/admin/global/tables",bo="/_lunora/admin/global/table",_o="/_lunora/admin/global/facet",gt=e=>{if(e===void 0||e==="")return;let n;try{n=JSON.parse(e)}catch{return}if(!Array.isArray(n))return;const t=n.flatMap(r=>{if(typeof r!="object"||r===null||typeof r.column!="string")return[];const{column:a,value:s}=r;return[{column:a,value:s}]});return t.length===0?void 0:t},Ro=Object.freeze({info:{description:'No OpenAPI spec is configured on this worker. Run `lunora codegen`, then wire the generated module to `createWorker`: `import { openApiSpec } from "./lunora/_generated/openapi"`.',title:"Lunora API",version:"0.0.0"},openapi:"3.1.0",paths:{}}),Eo=Object.freeze({info:{description:'No OpenRPC spec is configured on this worker. Run `lunora codegen --api-spec openrpc` (or `both`), then wire the generated module to `createWorker`: `import { openRpcSpec } from "./lunora/_generated/openrpc"`.',title:"Lunora RPC",version:"0.0.0"},methods:[],openrpc:"1.3.2"}),Ao=e=>{const{assertAdmin:n,options:t,parsePaging:r,queryParameter:a,requireAdminOption:s}=e,l=w=>{j(w,"GET","Functions");const b=s(w,t.functions,{code:"FUNCTIONS_NOT_CONFIGURED",message:"functions endpoint requires a `functions` registry on the worker"}),_=Object.entries(b).flatMap(([p,S])=>S.visibility==="internal"||S.kind==="stream"?[]:[{args:fo(S.args),kind:S.kind,path:p}]).toSorted((p,S)=>p.path.localeCompare(S.path));return Response.json({functions:_},{headers:{"content-type":"application/json"},status:200})},u=w=>{j(w,"GET","Cron-jobs");const b=s(w,t.cronJobs,{code:"CRON_JOBS_NOT_CONFIGURED",message:"cron-jobs endpoint requires a `cronJobs` map on the worker"}),_=Object.entries(b).flatMap(([p,S])=>S.map(D=>({args:D.args,cron:p,functionPath:D.functionPath,name:D.name,shardKey:D.shardKey,workflow:D.workflow}))).toSorted((p,S)=>p.name.localeCompare(S.name));return Response.json({jobs:_},{headers:{"content-type":"application/json"},status:200})},f=w=>(j(w,"GET","OpenAPI"),n(w),Response.json(t.openApiSpec??Ro,{headers:{"content-type":"application/json"},status:200})),g=w=>(j(w,"GET","OpenRPC"),n(w),Response.json(t.openRpcSpec??Eo,{headers:{"content-type":"application/json"},status:200})),E=async w=>{j(w,"GET","Global-tables");const b=s(w,t.globalIntrospector,{code:"GLOBALS_NOT_CONFIGURED",message:"global endpoints require a `globalIntrospector` on the worker"});return Response.json(await b.listTables(),{headers:{"content-type":"application/json"},status:200})},k=async w=>{j(w,"GET","Global-table");const b=s(w,t.globalIntrospector,{code:"GLOBALS_NOT_CONFIGURED",message:"global endpoints require a `globalIntrospector` on the worker"}),_=new URL(w.url),p=a(_,"table");if(p===void 0)throw new d("Global-table endpoint requires a `table` query param",{code:"BAD_REQUEST",status:400});const S=await b.readTablePage({...r(w),filters:gt(a(_,"filters")),table:p});return Response.json(S,{headers:{"content-type":"application/json"},status:200})},v=async w=>{j(w,"GET","Global-facet");const b=s(w,t.globalIntrospector,{code:"GLOBALS_NOT_CONFIGURED",message:"global endpoints require a `globalIntrospector` on the worker"}),_=new URL(w.url),p=a(_,"table"),S=a(_,"column");if(p===void 0||S===void 0)throw new d("Global-facet endpoint requires `table` and `column` query params",{code:"BAD_REQUEST",status:400});const D=a(_,"limit"),T=D===void 0?void 0:Number(D),x=await b.facetColumn({column:S,filters:gt(a(_,"filters")),limit:T!==void 0&&Number.isFinite(T)?T:void 0,table:p});return Response.json(x,{headers:{"content-type":"application/json"},status:200})};return{[mo]:u,[po]:l,[_o]:v,[bo]:k,[yo]:E,[wo]:f,[go]:g}},So="/_lunora/admin/kv/namespaces",To="/_lunora/admin/kv/keys",zt="/_lunora/admin/kv/value",Wt=32*1048576,yt=60,Oo=e=>{const{readJsonBody:n,requireAdminOption:t}=e,r=b=>t(b,e.kvIntrospector,{code:"KV_NOT_CONFIGURED",message:"KV endpoints require a `kvIntrospector` on the worker"}),a=b=>Response.json(b,{headers:{"content-type":"application/json"},status:200}),s=(b,_)=>{const p=new URL(b.url),S=p.searchParams.get("namespace")??"",D=p.searchParams.get("key")??"";if(S==="")throw new d(`KV-value ${_} request requires a \`namespace\` query parameter`,{code:"BAD_REQUEST",status:400});if(D==="")throw new d(`KV-value ${_} request requires a \`key\` query parameter`,{code:"BAD_REQUEST",status:400});return{key:D,namespace:S}},l=async(b,_)=>{if(!(await b.listNamespaces()).some(S=>S.binding===_))throw new d(`Unknown KV namespace binding \`${_}\``,{code:"NOT_FOUND",status:404})},u=async b=>(j(b,"GET","KV-namespaces"),a({namespaces:await r(b).listNamespaces()})),f=async b=>{j(b,"GET","KV-keys");const _=r(b),p=new URL(b.url),S=p.searchParams.get("namespace")??"";if(S==="")throw new d("KV-keys request requires a `namespace` query parameter",{code:"BAD_REQUEST",status:400});const D=p.searchParams.get("prefix")??void 0,T=p.searchParams.get("cursor")??void 0,x=p.searchParams.get("limit"),H=x===null?void 0:Number.parseInt(x,10);if(H!==void 0&&(!Number.isInteger(H)||H<1))throw new d("KV-keys `limit` must be a positive integer",{code:"BAD_REQUEST",status:400});const $=H===void 0?void 0:Math.min(H,1e3);return await l(_,S),a(await _.listKeys({cursor:T,limit:$,namespace:S,prefix:D}))},v={DELETE:async b=>{const _=r(b),p=s(b,"DELETE");return await l(_,p.namespace),await _.deleteKey(p),a({deleted:!0})},GET:async b=>{const _=r(b),p=s(b,"GET");return await l(_,p.namespace),a(await _.getValue(p))},PUT:async b=>{const _=r(b),p=await n(b,Wt);if(typeof p.namespace!="string"||p.namespace==="")throw new d("KV-value PUT request requires a `namespace` string",{code:"BAD_REQUEST",status:400});if(typeof p.key!="string"||p.key==="")throw new d("KV-value PUT request requires a `key` string",{code:"BAD_REQUEST",status:400});if(typeof p.value!="string")throw new d("KV-value PUT request requires a `value` string",{code:"BAD_REQUEST",status:400});if(p.expirationTtl!==void 0&&(typeof p.expirationTtl!="number"||!Number.isInteger(p.expirationTtl)||p.expirationTtl<yt))throw new d("KV-value PUT `expirationTtl` must be an integer ≥ 60",{code:"BAD_REQUEST",status:400});const S=Math.floor(Date.now()/1e3)+yt;if(p.expiration!==void 0&&(typeof p.expiration!="number"||!Number.isInteger(p.expiration)||p.expiration<S))throw new d("KV-value PUT `expiration` must be a Unix-seconds timestamp at least 60 seconds in the future",{code:"BAD_REQUEST",status:400});return await l(_,p.namespace),await _.putValue({expiration:p.expiration,expirationTtl:p.expirationTtl,key:p.key,metadata:p.metadata,namespace:p.namespace,value:p.value}),a({ok:!0})}},w=b=>{const _=v[b.method];if(!_)throw new d("KV-value endpoint requires GET, PUT, or DELETE",{code:"METHOD_NOT_ALLOWED",status:405});return _(b)};return{[So]:u,[To]:f,[zt]:w}},vo="/_lunora/migrate",ko="/_lunora/admin/pitr",Io="/_lunora/admin/rank",Po="/_lunora/admin/rankpage",Do="/_lunora/admin/shard-traffic",No=new Set(["__lunora_admin__:migrationStatus","__lunora_admin__:runMigration"]),Uo=new Set(["__lunora_admin__:getPitrBookmark","__lunora_admin__:pitrRestore"]),Co=async e=>{const t=await be(e,"Migration")??{};if(typeof t.table!="string"||t.table.length===0)throw new d("Migration request is missing `table`",{code:"BAD_REQUEST",status:400});if(typeof t.functionPath!="string"||!No.has(t.functionPath))throw new d("Migration request `functionPath` must be a migration admin op",{code:"BAD_REQUEST",status:400});return{args:t.args??{},functionPath:t.functionPath,table:t.table}},Bo=async e=>{const t=await be(e,"Rank")??{};if(typeof t.table!="string"||t.table.length===0)throw new d("Rank request is missing `table`",{code:"BAD_REQUEST",status:400});if(typeof t.index!="string"||t.index.length===0)throw new d("Rank request is missing `index`",{code:"BAD_REQUEST",status:400});if(typeof t.partitionKey!="string")throw new d("Rank request `partitionKey` must be a string",{code:"BAD_REQUEST",status:400});if(typeof t.rowId!="string"||t.rowId.length===0)throw new d("Rank request is missing `rowId`",{code:"BAD_REQUEST",status:400});if(!Array.isArray(t.sortValues))throw new d("Rank request `sortValues` must be an array",{code:"BAD_REQUEST",status:400});return{index:t.index,partitionKey:t.partitionKey,rowId:t.rowId,sortValues:t.sortValues,table:t.table}},xo=e=>{if(e!==void 0){if(!Array.isArray(e)||e.some(n=>n!=="asc"&&n!=="desc"))throw new d('Rank page request `directions` must be an array of "asc"|"desc"',{code:"BAD_REQUEST",status:400});return e}},Ho=e=>{if(typeof e.table!="string"||e.table.length===0)throw new d("Rank page request is missing `table`",{code:"BAD_REQUEST",status:400});if(typeof e.index!="string"||e.index.length===0)throw new d("Rank page request is missing `index`",{code:"BAD_REQUEST",status:400});if(e.partitionKey!==void 0&&typeof e.partitionKey!="string")throw new d("Rank page request `partitionKey` must be a string",{code:"BAD_REQUEST",status:400});if(e.take!==void 0&&(typeof e.take!="number"||!Number.isFinite(e.take)))throw new d("Rank page request `take` must be a number",{code:"BAD_REQUEST",status:400});if(e.cursor!==void 0&&e.cursor!==null&&typeof e.cursor!="string")throw new d("Rank page request `cursor` must be a string or null",{code:"BAD_REQUEST",status:400})},Lo=async e=>{const t=await be(e,"Rank page")??{};Ho(t);const r=xo(t.directions);return{cursor:typeof t.cursor=="string"?t.cursor:null,directions:r,index:t.index,partitionKey:typeof t.partitionKey=="string"?t.partitionKey:void 0,table:t.table,take:typeof t.take=="number"?t.take:void 0}},Mo=async e=>{const t=await be(e,"Shard-traffic")??{};if(typeof t.table!="string"||t.table.length===0)throw new d("Shard-traffic request is missing `table`",{code:"BAD_REQUEST",status:400});return{table:t.table}},jo=async e=>{const t=await Z(e);if(typeof t.functionPath!="string"||!Uo.has(t.functionPath))throw new d("PITR request `functionPath` must be a PITR admin op",{code:"BAD_REQUEST",status:400});if(t.shardKey!==void 0&&typeof t.shardKey!="string")throw new d("PITR `shardKey` must be a string",{code:"BAD_REQUEST",status:400});return{args:t.args??{},functionPath:t.functionPath,shardKey:t.shardKey}},$o=e=>{const{defaultShard:n,forwardToShard:t,isAdmin:r,queryCoordinator:a,resolveForwardContext:s,shardDO:l}=e,u=(w,b)=>{if(w.method!=="POST")throw new d(`${b} endpoint requires POST`,{code:"METHOD_NOT_ALLOWED",status:405});if(!r(w))throw new d("Admin auth required",{code:"FORBIDDEN",status:403});if(!a)throw new d(`${b} endpoint requires a \`queryCoordinator\` on the worker`,{code:"BAD_REQUEST",status:400});return a},f=async(w,b)=>{const _=u(w,"Migration"),p=await Co(w),{headers:S}=await s(w,b),D=await _.orchestrateMigration(l,{args:p.args,functionPath:p.functionPath,headers:S,table:p.table});return Response.json(D,{headers:{"content-type":"application/json"},status:200})},g=async(w,b)=>{const _=u(w,"Rank"),p=await Bo(w),{headers:S}=await s(w,b),D=await _.orchestrateRank(l,{headers:S,index:p.index,partitionKey:p.partitionKey,rowId:p.rowId,sortValues:p.sortValues,table:p.table});return Response.json(D,{headers:{"content-type":"application/json"},status:200})},E=async(w,b)=>{const _=u(w,"Rank page"),p=await Lo(w),{headers:S}=await s(w,b),D=await _.orchestrateRankPage(l,{...p,headers:S});return Response.json(D,{headers:{"content-type":"application/json"},status:200})},k=async(w,b)=>{const _=u(w,"Shard-traffic"),p=await Mo(w),{headers:S}=await s(w,b),D=await _.orchestrateShardTraffic(l,{headers:S,table:p.table});return Response.json(D,{headers:{"content-type":"application/json"},status:200})},v=async(w,b)=>{if(j(w,"POST","PITR"),!r(w))throw new d("admin PITR endpoint requires a valid admin bearer",{code:"ADMIN_FORBIDDEN",status:403});const _=await jo(w),{headers:p}=await s(w,b),S=new Request("https://shard.internal/rpc",{body:JSON.stringify({args:_.args,functionPath:_.functionPath}),headers:p,method:"POST"});return t(l,_.shardKey??n,S)};return{[vo]:f,[ko]:v,[Io]:g,[Po]:E,[Do]:k}},Ko=1,Fo=0,Go=32,Qo=512,zo=/^[a-z][\d_a-z*/-]{0,255}(?:@[a-z][\d_a-z*/-]{0,13})?=[\u0020-\u002B\u002D-\u003C\u003E-\u007E]{1,256}$/,Wo=e=>{if(e==null)return;const n=e.trim();if(n.length===0||n.length>Qo)return;const t=n.split(",");if(!(t.length>Go)){for(const r of t)if(!zo.test(r.trim()))return;return n}},Vo=e=>{const n=Hn(e.headers.get("traceparent"));if(n===void 0)return;const t=Wo(e.headers.get("tracestate"));return{parentSpanId:n.parentSpanId,sampled:n.sampled,traceId:n.traceId,...t===void 0?{}:{traceState:t}}},Jo=(e,n={})=>{const t=Vo(e),r=n.trustInbound===!0?t:void 0,a=Se(8),s=r?.traceId??Se(16),l=rr(n.sampling,r===void 0?a:s),u=l.isTraced&&(r===void 0||r.sampled);return{decision:l,ignoredUpstream:t!==void 0&&r===void 0,trace:{sampled:u,spanId:a,traceFlags:u?Ko:Fo,traceId:s,...r?.parentSpanId===void 0?{}:{parentSpanId:r.parentSpanId},...r?.traceState===void 0?{}:{traceState:r.traceState}}}},qo=(e,n)=>{n.traceparent=xn(e.traceId,e.spanId,e.sampled),e.traceState!==void 0&&(n.tracestate=e.traceState)},Yo=(e,n)=>{let t;return()=>{if(t===void 0){const r=$n(e),a=n===void 0?void 0:n.cf;t=Ln(jn(r),Mn(r,a))}return t}},Xo="/_lunora/admin/scheduled",Zo="/_lunora/admin/scheduled/status",ea="/_lunora/admin/scheduled/ws",ta="/_lunora/admin/scheduled/cancel",na="/_lunora/admin/scheduled/dead",ra="/_lunora/admin/scheduled/dead/retry",oa="/_lunora/admin/scheduled/dead/cancel",aa=e=>{const{checkWsAdmin:n,requireSchedulerNamespace:t,resolveSchedulerStub:r,schedulerInstanceName:a}=e,s=(f,g)=>E=>{if(E.method!=="GET")throw new d(`${g} endpoint requires GET`,{code:"METHOD_NOT_ALLOWED",status:405});return r(E).fetch(new Request(`https://scheduler.internal${f}`,{method:"GET"}))},l=(f,g,E=g)=>async k=>{if(k.method!=="POST")throw new d(`${E} requires POST`,{code:"METHOD_NOT_ALLOWED",status:405});const v=r(k),w=await k.json().catch(()=>{});if(typeof w?.id!="string"||w.id==="")throw new d(`${g} requires a string \`id\``,{code:"BAD_REQUEST",status:400});return v.fetch(new Request(`https://scheduler.internal${f}`,{body:JSON.stringify({id:w.id}),headers:{"content-type":"application/json"},method:"POST"}))},u=async f=>{if(f.headers.get("Upgrade")!=="websocket")throw new d("WebSocket upgrade header missing",{code:"BAD_REQUEST",status:426});if(!await n(f))throw new d("admin authorization required",{code:"ADMIN_FORBIDDEN",status:403});const g=t();return we(g,a).fetch(new Request("https://scheduler.internal/ws",{headers:{Upgrade:"websocket"}}))};return{[ta]:l("/cancel","Scheduled-cancel","Scheduled-cancel endpoint"),[oa]:l("/dead/cancel","Scheduled dead-letter action"),[na]:s("/dead","Scheduled dead-letter"),[ra]:l("/dead/retry","Scheduled dead-letter action"),[Xo]:s("/list","Scheduled-list"),[Zo]:s("/status","Scheduler-status"),[ea]:u}},sa=(e,...n)=>{let t=e.cf;for(const r of n){if(typeof t!="object"||t===null)return;t=t[r]}return typeof t=="string"?t:void 0},bt={mtls:e=>sa(e,"tlsClientAuth","certVerified")==="SUCCESS"},ia=e=>e===void 0||e===!1?()=>!1:e===!0?()=>!0:typeof e=="function"?e:(Object.hasOwn(bt,e)?bt[e]:void 0)??(()=>!1),ca=e=>{if(e!==void 0)return()=>{};let n=!1;return()=>{n||(n=!0,console.warn('[lunora] Ignored an inbound `traceparent`, so this request starts a new trace instead of joining the caller\'s. That is the safe default: the header is caller-supplied, and trusting it lets any client choose which trace its spans and logs join. If this worker sits behind a gateway, service mesh, or Cloudflare Access that sets `traceparent` itself, set `trustInboundTraceContext: true` on createWorker() (or `"mtls"` to trust only edge-verified client certificates). Set it to `false` to keep this behaviour and silence this message.'))}},da="/_lunora/admin/vector/indexes",ua="/_lunora/admin/vector/query",la=e=>{const{readJsonBody:n,requireAdminOption:t}=e,r=async s=>{j(s,"GET","Vector-indexes");const l=t(s,e.vectorIntrospector,{code:"VECTORS_NOT_CONFIGURED",message:"vector endpoints require a `vectorIntrospector` on the worker"});return Response.json({indexes:await l.listIndexes()},{headers:{"content-type":"application/json"},status:200})},a=async s=>{j(s,"POST","Vector-query");const l=t(s,e.vectorIntrospector,{code:"VECTORS_NOT_CONFIGURED",message:"vector endpoints require a `vectorIntrospector` on the worker"});if(l.queryIndex===void 0)throw new d("vector index querying is not enabled on this worker",{code:"VECTOR_QUERY_UNSUPPORTED",status:400});const f=await n(s);if(typeof f.name!="string"||f.name==="")throw new d("Vector-query request requires a `name` string",{code:"BAD_REQUEST",status:400});if(typeof f.text!="string"||f.text==="")throw new d("Vector-query request requires a `text` string",{code:"BAD_REQUEST",status:400});if(f.topK!==void 0&&(typeof f.topK!="number"||!Number.isInteger(f.topK)||f.topK<1))throw new d("Vector-query `topK` must be a positive integer",{code:"BAD_REQUEST",status:400});const g=await l.queryIndex({name:f.name,text:f.text,topK:f.topK});return Response.json(g,{headers:{"content-type":"application/json"},status:200})};return{[da]:r,[ua]:a}},ha="/_lunora/admin/workflows/instances",fa="/_lunora/admin/workflows/instance",pa="/_lunora/admin/workflows/status",ma={complete:!0,errored:!0,paused:!0,queued:!0,running:!0,terminated:!0,unknown:!0,waiting:!0,waitingForPause:!0},wa=e=>e!==null&&Object.hasOwn(ma,e)?e:void 0,_t=(e,n)=>{const t=e.searchParams.get(n);if(t===null)return;const r=Number(t);return Number.isInteger(r)&&r>0?r:void 0},$e=(e,n)=>{const t=e.searchParams.get(n);if(t===null||t==="")throw new d(`Workflows admin endpoint requires a \`${n}\` query parameter`,{code:"BAD_REQUEST",status:400});return t},Rt=()=>{throw new d("Workflow inspection is unconfigured. Set CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN in your .dev.vars to enable it.",{code:"WORKFLOWS_NOT_CONFIGURED",status:501})},ga=e=>{const{assertAdmin:n,resolveWorkflowsClient:t}=e,r=async(l,u,f)=>{j(l,"GET","Workflows instances"),n(l);const g=t(u);if(!g)return Response.json({configured:!1,instances:[],page:1,perPage:0,totalCount:0});const E=$e(f,"name"),k=wa(f.searchParams.get("status"));return Response.json(await g.listInstances({page:_t(f,"page"),perPage:_t(f,"perPage"),status:k,workflowName:E}))},a=async(l,u,f)=>{j(l,"GET","Workflows instance"),n(l);const g=t(u);return g?Response.json(await g.getInstance({instanceId:$e(f,"id"),workflowName:$e(f,"name")})):Rt()},s=async(l,u)=>{j(l,"POST","Workflows status"),n(l);const f=t(u);if(!f)return Rt();const g=await l.json().catch(()=>{});if(typeof g?.name!="string"||g.name===""||typeof g.id!="string"||g.id==="")throw new d("Workflows status action requires string `name` and `id`",{code:"BAD_REQUEST",status:400});const{action:E}=g;if(E!=="pause"&&E!=="resume"&&E!=="terminate")throw new d("Workflows status action must be one of: pause, resume, terminate",{code:"BAD_REQUEST",status:400});return Response.json(await f.setInstanceStatus({action:E,instanceId:g.id,workflowName:g.name}))};return{[fa]:a,[ha]:r,[pa]:s}},ya={[zt]:Wt,[qn]:Jn},Et="/_lunora/rpc",ba="/_lunora/rpc-batch",_a="/_lunora/ws",Re=(e,n,t)=>({resourceAttributes:Yo(e,n),...t===void 0?{}:{waitUntil:t}}),At=e=>e?.waitUntil?{waitUntil:n=>e.waitUntil?.(n)}:{},St=e=>({spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId,...e.parentSpanId===void 0?{}:{parentSpanId:e.parentSpanId}}),Ke=e=>{const{method:n}=e,t=e.headers.get("user-agent")??void 0;let r;try{r=new URL(e.url)}catch{return{method:n,userAgent:t}}const a=r.port===""?void 0:Number(r.port);return{host:r.hostname,method:n,path:r.pathname,port:Number.isNaN(a)?void 0:a,scheme:r.protocol.replace(":",""),userAgent:t}},Tt="/_lunora/voice/",Ra="/_lunora/scheduler/dispatch",Ea="/_lunora/admin/cron-jobs/run",Aa="/_lunora/admin/ws-token",Sa="/_lunora/admin/",Ta="/_lunora/migrate",Oa="/_lunora/status",va=e=>e.startsWith(Sa)||e===Ta,ka=e=>{const n=e.headers.get("x-lunora-userid"),t=e.headers.get("x-lunora-identity");if(!(n===null&&t===null))return{...t===null?{}:{identity:t},...n===null?{}:{userId:n}}},Ia="/api/auth",Pa="__lunora_admin__:recordAuthEvent",Da="__lunora_admin__:listPushSubscriptions",Na=["/sign-in","/sign-up","/callback"],Ua=(e,n)=>{const t=n.endsWith("/")?n.slice(0,-1):n;if(!e.startsWith(`${t}/`))return!1;const r=e.slice(t.length);return Na.some(a=>r===a||r.startsWith(`${a}/`))},Ee=(e,n,t,r)=>{const a=Dn(t),s=a?t.code:"INTERNAL_SERVER_ERROR",l=a?t.status:500,u=t instanceof Error?t.message:String(t);return{durationMs:n,error:{code:s,message:u,status:l},functionPath:e,ok:!1,...r.fanOut?{fanOut:{failed:0,shards:0,table:r.fanOut.table}}:{},...r.shardKey?{shardKey:r.shardKey}:{}}},Ca=e=>{const{exp:n,expiresAtMs:t}=e;if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof n=="number"&&Number.isFinite(n))return n*1e3},Ot=e=>e.waitUntil?{waitUntil:n=>{e.waitUntil?.(n)}}:void 0,Ba=e=>{const n=e?.queue;return typeof n=="string"&&n.length>0?n:"unknown"},Fe=new WeakMap,de=async(e,n,t,r=Fe.get(e))=>{const a={"content-type":"application/json"},s=e.headers.get("authorization"),l=e.headers.get("cookie"),u=e.headers.get("x-d1-bookmark"),f=e.headers.get("x-lunora-mutation-id"),g=e.headers.get("x-lunora-client-id"),E=e.headers.get("x-lunora-client-seq");s&&(a.authorization=s),l&&(a.cookie=l),u&&(a["x-d1-bookmark"]=u),f&&(a["x-lunora-mutation-id"]=f),g&&(a["x-lunora-client-id"]=g),E&&(a["x-lunora-client-seq"]=E);const k=e.headers.get("cf-connecting-ip");if(k&&(a["x-lunora-client-ip"]=k),!t)return{claims:null,headers:a,identity:null,userId:null};const v=await t(e,n,r);if(!v||typeof v.userId!="string"||v.userId.length===0)return{claims:null,headers:a,identity:null,userId:null};a["x-lunora-userid"]=Cn(v.userId);const w=Ca(v);w!==void 0&&(a["x-lunora-identity-exp"]=String(w));const{userId:b,..._}=v,p=Object.keys(_).length>0?_:null;return p&&(a["x-lunora-identity"]=Bn(p)),{claims:p,headers:a,identity:v,userId:b}},xa=new Set(["concat","first","groupBy","max","min","rank","sum","topK"]),Ha=e=>{if(e===void 0)return;if(!e||typeof e!="object")throw new d("RPC `fanOut` must be an object",{code:"BAD_REQUEST",status:400});const n=e;if(typeof n.table!="string"||n.table.length===0)throw new d("RPC `fanOut.table` must be a non-empty string",{code:"BAD_REQUEST",status:400});if(!n.merge||typeof n.merge!="object")throw new d("RPC `fanOut.merge` must be an object",{code:"BAD_REQUEST",status:400});const t=n.merge;if(typeof t.kind!="string"||!xa.has(t.kind))throw new d("RPC `fanOut.merge.kind` is not a recognized merge strategy",{code:"BAD_REQUEST",status:400});if(t.kind==="topK"){if(typeof t.k!="number"||!Number.isInteger(t.k)||t.k<0)throw new d("RPC `fanOut.merge.k` must be a non-negative integer",{code:"BAD_REQUEST",status:400});if(typeof t.by!="string"||t.by.length===0)throw new d("RPC `fanOut.merge.by` must be a non-empty string",{code:"BAD_REQUEST",status:400})}return n},La=(e,n)=>{e?.LUNORA_DEBUG_RPC&&console.warn(`[lunora:rpc] ${n.fanOut?"fan-out":`shard=${n.shardKey??"(root)"}`} ${n.functionPath}`)},vt=(e,n)=>{const t=n.functions?.[e.functionPath]?.x402;if(t){if(e.fanOut)throw new d("a paid (`.x402`) function cannot be fanned out",{code:"BAD_REQUEST",status:400});if(!n.x402Charge)throw new d(`function "${e.functionPath}" is marked paid (.x402) but no x402Charge gate is configured on the worker`,{code:"MISCONFIGURED",status:500});return t}},Ma=async e=>{const n=await Ct(e);let t;try{t=JSON.parse(n)}catch{throw new d("RPC body must be valid JSON",{code:"BAD_REQUEST",status:400})}if(!t||typeof t!="object"||typeof t.functionPath!="string")throw new d("RPC envelope is missing `functionPath`",{code:"BAD_REQUEST",status:400});const r=t;if(r.args!==void 0&&Ut(r.args,"RPC"),r.shardKey!==void 0&&typeof r.shardKey!="string")throw new d("RPC `shardKey` must be a string",{code:"BAD_REQUEST",status:400});const a=t,s=Ha(a.fanOut),l=a.args??{};if(s&&a.functionPath.startsWith("__lunora_relation__:")){const u=l.table;if(typeof u=="string"&&u!==s.table)throw new d("RPC `args.table` must match the authorized `fanOut.table` for a relation fan-out",{code:"BAD_REQUEST",status:400});l.table=s.table}return{args:l,fanOut:s,functionPath:a.functionPath,shardKey:a.shardKey}},Ae=new Map,ja=5e3,$a=4096,Ka=async(e,n)=>{const t=Date.now(),r=Ae.get(n);if(r!==void 0&&r.expiresMs>t)return r.relayCount;r!==void 0&&Ae.delete(n);let a=0;try{const s=await we(e,n).fetch(new Request("https://shard.internal/_lunora/route"));if(s.ok){const u=(await s.json()).relayCount;typeof u=="number"&&u>0&&(a=Math.floor(u))}}catch{a=0}return Dt(Ae,$a),Ae.set(n,{expiresMs:t+ja,relayCount:a}),a},kt=(e,n)=>{if(!(e===null||typeof e!="object"))return Object.entries(e).find(([,t])=>t===n)?.[0]},ye=(e,n,t)=>new Request("https://shard.internal/rpc",{body:JSON.stringify({args:n,functionPath:e}),headers:t,method:"POST"}),Fa=["x-lunora-userid","x-lunora-identity","x-lunora-identity-exp"],It=(e,n)=>{for(const t of Fa){e.delete(t);const r=n[t];r!==void 0&&e.set(t,r)}},Ga=async(e,n,t)=>e.length===0||t.length===0?!1:ze(await Lt(e,n),t),Pt=(e,n)=>{if(!n||n.length===0)return!1;const t=e.headers.get("authorization");if(!t)return!1;const[r,...a]=t.split(" ");return r?.toLowerCase()!=="bearer"?!1:ze(n,a.join(" ").trim())},Qa=async(e,n,t)=>{if(!n||n.length===0)return!1;const r=new URL(e.url).searchParams.get("token");return r===null?!1:await vr(n,r)?!0:t?!1:ze(n,r)},za=(e,n)=>{if(n===null||typeof n!="object"&&typeof n!="function")return;const t=n;if(typeof t.prepare=="function"&&typeof t.batch=="function"&&typeof t.dump=="function")return er(`d1:${e}`,n);if(typeof t.list=="function"&&typeof t.head=="function"&&typeof t.createMultipartUpload=="function")return Ce(`r2:${e}`,!0);if(typeof t.send=="function"&&typeof t.sendBatch=="function"&&typeof t.get!="function")return Ce(`queue:${e}`,!0);if(typeof t.connectionString=="string")return Ce(`hyperdrive:${e}`,!0)},Vt=e=>{const n=ia(e.trustInboundTraceContext),t=ca(e.trustInboundTraceContext),r=e.defaultShardKey??"__root__",a=tr(e.resolveIdentity,e.identity),s=rt(e.shardDO,e.jurisdiction),l=e.schedulerDO===void 0?void 0:rt(e.schedulerDO,e.jurisdiction);let u=!1;const f=o=>{if(o===void 0||e.jurisdiction===void 0)return o;u||(u=!0,console.warn(`[lunora] jurisdiction "${e.jurisdiction}" pins placement, so region hints (\`shardRegion\`, replica and relay placement) are not sent. Residency wins.`))},g=async(o,i,h,c=e.shardRegion?.(i))=>we(o,i,f(c)).fetch(h);let E;const k=()=>e.adminToken??E;let v;const w=()=>e.requireEphemeralWsToken??v??!0;let b;const _=o=>{const i=o??{};if(b??=kt(o,e.shardDO),v===void 0&&e.requireEphemeralWsToken===void 0){const c=i.LUNORA_REQUIRE_EPHEMERAL_WS_TOKEN;typeof c=="string"&&c.length>0&&(v=Sr(c,!0))}if(E!==void 0||e.adminToken!==void 0)return;const h=i.LUNORA_ADMIN_TOKEN;typeof h=="string"&&h.length>0&&(E=h)},p=new WeakSet,S=o=>Pt(o,k())||p.has(o),D=async(o,i)=>{const h=await de(o,i,e.resolveIdentity);if(p.has(o)&&h.headers.authorization===void 0){const c=k();c!==void 0&&(h.headers.authorization=`Bearer ${c}`)}return h};let T=!1,x=!1;const H=()=>{x||(x=!0,console.warn("[lunora] `replicaReads: true` has no effect without `functions` — read eligibility is decided from the function registry."))},$=o=>{if(!e.allowUnauthenticatedShardAccess){const i=o==="fan-out"?"authorizeFanOut":"authorizeShard";throw new d(`${o} access is default-denied: configure \`${i}\` on the worker, or set \`allowUnauthenticatedShardAccess: true\` to explicitly allow unauthenticated ${o} access (relying solely on per-row RLS).`,{code:o==="fan-out"?"FORBIDDEN_FANOUT":"FORBIDDEN_SHARD",status:403})}T||(T=!0,console.warn([`[lunora] SECURITY: serving ${o} access with \`allowUnauthenticatedShardAccess: true\` and no \`authorizeShard\`/\`authorizeFanOut\` — `,"any caller (including unauthenticated ones) can target any shard / fan out across the table. ","This is safe only if every table is protected by per-row RLS. Configure `authorizeShard`/`authorizeFanOut` to gate it."].join("")))},U=async(o,i,h=!0)=>{if(e.authorizeShard){if(!await e.authorizeShard(o,i))throw new d("Forbidden shard",{code:"FORBIDDEN_SHARD",status:403})}else h&&i!==r&&$("shard")},W=$o({defaultShard:r,forwardToShard:g,isAdmin:S,queryCoordinator:e.queryCoordinator,resolveForwardContext:D,shardDO:s}),K=async(o,i,h,c,m)=>{await U(null,h,!1);const R={"content-type":"application/json","x-lunora-system":"1"};return m?.userId!==void 0&&m.userId.length>0&&(R["x-lunora-userid"]=m.userId),m?.identity!==void 0&&m.identity.length>0&&(R["x-lunora-identity"]=m.identity),c!==void 0&&c.length>0&&(R["x-lunora-mutation-id"]=c),g(s,h,ye(o,i,R))},V=async(o,i,h,c)=>{const m=h?.[o];if(!m||typeof m.create!="function")throw new d(`${c} targets workflow binding "${o}", which is not bound on env`,{code:"CRON_JOB_FAILED",status:500});if(ir(i))throw new d(`${c} params ${cr}`,{code:"BAD_REQUEST",status:400});await m.create({params:i})},X=async(o,i)=>{if(o.workflow){await V(o.workflow,o.args??{},i,`cron job "${o.name}"`);return}if(o.functionPath===void 0)throw new d(`cron job "${o.name}" has neither a function target nor a workflow target`,{code:"CRON_JOB_FAILED",status:500});const h=await K(o.functionPath,o.args??{},o.shardKey??r);if(!h.ok)throw new d(`cron job "${o.name}" (${o.functionPath}) failed with shard status ${String(h.status)}`,{code:"CRON_JOB_FAILED",status:500})},J=async(o,i,h,c)=>{const m=e.cronJobs?.[o];if(m)for(const R of m)try{await X(R,i)}catch(I){h.push(c(I))}},ae=async(o,i)=>{if(!S(o))throw new d("admin endpoint requires a valid admin bearer",{code:"ADMIN_FORBIDDEN",status:403});if(j(o,"POST","cron-jobs run"),!e.cronJobs)throw new d("cron-jobs run endpoint requires a `cronJobs` map on the worker",{code:"CRON_JOBS_NOT_CONFIGURED",status:400});const h=await Z(o),c=typeof h.name=="string"?h.name:"";if(c==="")throw new d("cron-jobs run endpoint requires a job `name`",{code:"BAD_REQUEST",status:400});const m=Object.values(e.cronJobs).flat().find(R=>R.name===c);if(!m)throw new d(`no cron job named "${c}" is registered`,{code:"CRON_JOB_NOT_FOUND",status:404});return await X(m,i),Response.json({name:c,ran:!0},{status:200})},F=async o=>{const i=typeof o.pool=="string"&&o.pool.length>0?o.pool:void 0;if(!i||!l||typeof o.id!="string")return;const h=typeof o.instanceName=="string"&&o.instanceName.length>0?o.instanceName:"default";try{await we(l,h).fetch(new Request("https://scheduler.internal/complete",{body:JSON.stringify({id:o.id,pool:i}),headers:{"content-type":"application/json"},method:"POST"}))}catch{}},he=async(o,i)=>{j(o,"POST","Scheduler dispatch");const h=await Ct(o),c=i??{},m=typeof c.LUNORA_SCHEDULER_SECRET=="string"?c.LUNORA_SCHEDULER_SECRET:void 0,R=e.adminToken??(typeof c.LUNORA_ADMIN_TOKEN=="string"?c.LUNORA_ADMIN_TOKEN:void 0),I=o.headers.get("x-lunora-scheduler-signature");let y=!1;if(I&&m?y=await Ga(m,h,I):R&&(y=Pt(o,R)),!y)throw new d("Scheduler dispatch requires a valid signature or admin bearer",{code:"FORBIDDEN",status:403});let A;try{A=JSON.parse(h)}catch{throw new d("Scheduler dispatch body must be valid JSON",{code:"BAD_REQUEST",status:400})}const O=A??{},C=O.args??{};if(typeof O.workflow=="string"&&O.workflow.length>0)return await V(O.workflow,C,i,"scheduled workflow"),Response.json({ok:!0},{status:200});if(typeof O.functionPath!="string"||O.functionPath.length===0)throw new d("Scheduler dispatch is missing `functionPath`",{code:"BAD_REQUEST",status:400});const B=typeof O.shardKey=="string"&&O.shardKey.length>0?O.shardKey:r,L=typeof O.id=="string"&&O.id.length>0?O.id:void 0,te=ka(o),M=await K(O.functionPath,C,B,L,te);return await F(O),M},G=o=>{if(!S(o))throw new d("admin endpoint requires a valid admin bearer",{code:"ADMIN_FORBIDDEN",status:403})},oe=(o,i,h)=>{if(G(o),i===void 0)throw new d(h.message,{code:h.code,status:400});return i},Te=Nr({assertAdmin:G,getReader:()=>e.authAuditReader}),Oe=async(o,i)=>{G(o);const h=e.notifySubscriptionStore;if(h===void 0)return Response.json({subscriptions:[]},{headers:{"content-type":"application/json"},status:200});const c=i?.kind,m=i?.userId,R=i?.limit,I=c==="fcm"||c==="web-push"?c:void 0,y=typeof m=="string"&&m!==""?m:void 0,A=typeof R=="number"&&Number.isFinite(R)?Math.trunc(R):0,O=A>0?Math.min(A,1e3):1e3,B=(await h.list({kind:I,limit:O,userId:y})).filter(L=>I!==void 0&&L.kind!==I?!1:y===void 0||(L.userId??null)===y).map(({keys:L,token:te,...M})=>M);return Response.json({subscriptions:B},{headers:{"content-type":"application/json"},status:200})},se=async(o,i)=>{if(!i.fanOut){if(i.functionPath===Dr)return Te(o,i.args??{});if(i.functionPath===Da)return Oe(o,i.args)}},Jt=so({applyGlobals:e.applyGlobals,assertAdmin:G,exportCursorStore:e.exportCursorStore,exportSinks:e.exportSinks,knownTables:()=>[],queryCoordinator:e.queryCoordinator,requireAdminOption:oe,resolveForwardContext:D,shardDO:s,streamExportRows:(o,i,h,c)=>Ft(e,o,i,h,c,s),streamingImport:(o,i)=>lo(o,e,i,s),syncGlobals:e.syncGlobals}),ve=(o,i)=>{const h=o.searchParams.get(i);return h===null||h===""?void 0:h},ke=o=>{const i=new URL(o.url),h=i.searchParams.get("limit"),c=i.searchParams.get("offset"),m=h===null?void 0:Number.parseInt(h,10),R=c===null?void 0:Number.parseInt(c,10);return{limit:m!==void 0&&Number.isFinite(m)&&m>=0?m:void 0,offset:R!==void 0&&Number.isFinite(R)&&R>=0?R:void 0}},Je=()=>{if(l===void 0)throw new d("scheduled endpoints require a `schedulerDO` namespace on the worker",{code:"SCHEDULER_NOT_CONFIGURED",status:400});return l},qt=aa({checkWsAdmin:async o=>S(o)||Qa(o,k(),w()),requireSchedulerNamespace:Je,resolveSchedulerStub:o=>(G(o),we(Je(),e.schedulerInstanceName??"default")),schedulerInstanceName:e.schedulerInstanceName??"default"}),Yt=ga({assertAdmin:G,resolveWorkflowsClient:e.workflowsClient??(()=>{})}),Xt=Vn({assertAdmin:G,parsePaging:ke,queryParameter:ve,readBodyBytes:Fn,requireAdminOption:oe,storage:{storageBuckets:e.storageBuckets,storageDelete:e.storageDelete,storageDownload:e.storageDownload,storageList:e.storageList,storageSignedUrl:e.storageSignedUrl,storageUpload:e.storageUpload}}),Zt=Qr({options:e,readJsonBody:Z,requireAdminOption:oe}),en=la({readJsonBody:Z,requireAdminOption:oe,vectorIntrospector:e.vectorIntrospector}),tn=Oo({kvIntrospector:e.kvIntrospector,readJsonBody:Z,requireAdminOption:oe}),nn=nr({logArchive:e.logArchive,readJsonBody:Z,requireAdminOption:oe}),rn=Ao({assertAdmin:G,options:{cronJobs:e.cronJobs,functions:e.functions,globalIntrospector:e.globalIntrospector,openApiSpec:e.openApiSpec,openRpcSpec:e.openRpcSpec},parsePaging:ke,queryParameter:ve,requireAdminOption:oe}),on=o=>{const i=[],h=s??o?.SHARD;if(h!==void 0&&i.push(Zn("durable-object:default",h,r)),e.health?.disableBindingProbes!==!0)for(const[c,m]of Object.entries(o??{})){const R=za(c,m);R!==void 0&&i.push(R)}for(const c of e.health?.probes??[])i.push(c);return i},an=Xn({appName:e.health?.appName,appVersion:e.health?.appVersion,auth:e.health?.auth??"public",cacheTtlMs:e.health?.cacheTtlMs,isAdmin:S,resolveProbes:on}),sn=o=>{const i=e.schedulerInstanceName??"default",h=()=>we(o,i),c=async(y,A)=>{const O=await h().fetch(new Request(`https://scheduler.internal${y}`,A));if(!O.ok)throw new d(`ctx.scheduler: SchedulerDO ${y} failed (${String(O.status)}): ${await O.text()}`,{code:"INTERNAL",status:500});return await O.json()},m=async(y,A)=>await c(y,{body:JSON.stringify(A),headers:{"content-type":"application/json"},method:"POST"}),R=y=>{const A=y;if(A==null)throw new d("ctx.scheduler: target is required — pass a reference from the generated `internal` / `workflows` / `agents`",{code:"BAD_REQUEST",status:400});if(typeof A.binding=="string"&&A.binding.length>0)return{workflow:A.binding};if(typeof A.__lunoraRef=="string")return{functionPath:A.__lunoraRef};throw new d("ctx.scheduler: expected a reference from the generated `internal` / `workflows` / `agents` — a bare function-path string is refused here, because an HTTP action can be reached unauthenticated",{code:"BAD_REQUEST",status:400})},I=async(y,A,O={})=>{const{id:C}=await m("/schedule",{args:O,scheduledFor:y,...R(A)});return C};return{cancel:async y=>await m("/cancel",{id:y}),get:async y=>await c(`/get?id=${encodeURIComponent(y)}`,{method:"GET"}),list:async()=>await c("/list",{method:"GET"}),runAfter:async(y,A,O)=>{if(!Number.isFinite(y)||y<0)throw new d("ctx.scheduler.runAfter: `delayMs` must be a non-negative finite number",{code:"BAD_REQUEST",status:400});return await I(Date.now()+y,A,O)},runAt:async(y,A,O)=>{if(!Number.isFinite(y))throw new d("ctx.scheduler.runAt: `timestampMs` must be a finite epoch-millisecond number",{code:"BAD_REQUEST",status:400});return await I(y,A,O)}}},cn=async(o,i,h)=>{const{claims:c,headers:m,userId:R}=await de(o,i,a),I=async(y,A={})=>{const O=y.__lunoraRef;if(typeof O!="string")throw new d("ctx.run*: expected a function reference from the generated `api`",{code:"BAD_REQUEST",status:400});const C=ye(O,A,{...m,"x-lunora-system":"1"}),B=await g(s,r,C),L=await B.json();if(L.error)throw new d(L.error.message??"shard RPC failed",{code:L.error.code??"INTERNAL",status:B.status});return L.result};return{auth:{getIdentity:()=>Promise.resolve(c),userId:R},cache:h.cache,fetch:globalThis.fetch.bind(globalThis),runAction:I,runMutation:I,runQuery:I,...l===void 0?{}:{scheduler:sn(l)},...e.storage===void 0?{}:{storage:sr(e.storage(i))}}},dn=async(o,i,h)=>{if(!e.httpRouter)return;const c=await cn(o,i,h);try{return await e.httpRouter.fetch(o,{...i,__lunoraCtx:c},h)}catch(m){return console.error("[lunora] httpRouter (SSR) handler threw:",m),new Response("Internal Server Error",{status:500})}},un=async(o,i,h)=>{if(o.headers.get("Upgrade")!=="websocket")throw new d("WebSocket upgrade header missing",{code:"BAD_REQUEST",status:426});const c=at(o,ie);if(c)return c;const m=h.searchParams.get("shard")??r,{headers:R,identity:I}=await de(o,i,a);await U(I,m);const y=new Headers(o.headers),A=[...y.keys()];for(const C of A)C.startsWith("x-lunora-")&&y.delete(C);It(y,R);const O=kt(i,e.shardDO);if(O!==void 0){y.set("x-lunora-shard-binding",O);const C=await Ka(s,m);if(C>0){const B=br(m,Math.floor(Math.random()*C));return g(s,B,new Request(o,{headers:y}),st(o))}}return g(s,m,new Request(o,{headers:y}))},ln=async(o,i,h)=>{const{voiceAgents:c}=e;if(c===void 0)return new Response("Not found",{status:404});if(o.headers.get("Upgrade")!=="websocket")return new Response("Expected a WebSocket upgrade",{headers:{allow:"GET"},status:426});const m=at(o,ie);if(m)return m;let R;try{R=decodeURIComponent(h.pathname.slice(Tt.length))}catch{return new Response("Unknown voice agent",{status:404})}const I=Object.hasOwn(c,R)?c[R]:void 0;if(I===void 0)return new Response("Unknown voice agent",{status:404});const y=h.searchParams.get("threadKey");if(y===null||y.length===0)return new Response("Missing threadKey",{status:400});const{headers:A,identity:O}=await de(o,i,a);if(e.authorizeShard){if(!await e.authorizeShard(O,y))return new Response("Forbidden",{status:403})}else $("shard");const C=new Headers(o.headers);for(const B of C.keys())B.startsWith("x-lunora-")&&C.delete(B);return It(C,A),g(I,y,new Request(o,{headers:C}))},hn=async(o,i,h)=>{if(e.authorizeFanOut){if(!await e.authorizeFanOut(h,o.table,i))throw new d("Forbidden fan-out",{code:"FORBIDDEN_FANOUT",status:403});return}if(i.startsWith("__lunora_relation__:"))throw new d("reverse cross-backend relation reads (`__lunora_relation__:*`) require `authorizeFanOut` to be configured on the worker",{code:"FORBIDDEN_FANOUT",status:403});if(e.authorizeShard)throw new d("Fan-out requires `authorizeFanOut` to be configured on the worker when `authorizeShard` is set",{code:"FORBIDDEN_FANOUT",status:403});$("fan-out")},_e=async(o,i)=>{if(!(!o.fanOut&&o.functionPath.startsWith("__lunora_admin__:"))){if(o.fanOut){await hn(o.fanOut,o.functionPath,i);return}await U(i,o.shardKey??r)}},fn=(o,i,h)=>{if(e.replicaReads!==!0)return;if(e.functions===void 0){H();return}if(e.functions[i]?.kind!=="query"||h.includes(jt)||h.includes(Mt))return;const c=st(o);return c===void 0?void 0:{name:_r(h,c),region:c}},pn=async(o,i,h,c,m)=>{const R=fn(o,i,c);if(R!==void 0){const I={...m,"x-lunora-replica-read":"1",...b===void 0?{}:{"x-lunora-shard-binding":b}},y=Rr(o.headers.get("x-lunora-min-seq"));y!==void 0&&(I["x-lunora-min-seq"]=String(y));const A=await g(s,R.name,ye(i,h,I),R.region);if(A.status!==421)return A}return g(s,c,ye(i,h,m))},Ie=async(o,i,h,c,m,R)=>{const I=Date.now(),{observability:y,sampling:A}=e,O=Ke(o),{decision:C,ignoredUpstream:B,trace:L}=Jo(o,{...A===void 0?{}:{sampling:A},trustInbound:n(o)});B&&t();const te={...m,"x-lunora-sample-errors":C.keepErrors?"1":"0"};qo(L,te);try{const M=await pn(o,i,h,c,te);ce(y,{...O,...St(L),durationMs:Date.now()-I,functionPath:i,ok:M.ok,shardKey:c,...M.ok?{}:{error:{code:"SHARD_ERROR",message:`shard returned ${String(M.status)}`,status:M.status}}},R,void 0,{isTraced:L.sampled,keepErrors:C.keepErrors});const ee=new Response(M.body,{headers:M.headers,status:M.status,statusText:M.statusText});return ee.headers.set("x-lunora-shard-key",c),ee}catch(M){throw ce(y,{...O,...St(L),...Ee(i,Date.now()-I,M,{shardKey:c})},R,void 0,{isTraced:L.sampled,keepErrors:C.keepErrors}),M}},mn=o=>{if(o.fanOut&&o.shardKey)throw new d("RPC envelope cannot set both `shardKey` and `fanOut`",{code:"BAD_REQUEST",status:400});if(!o.fanOut&&o.functionPath.startsWith("__lunora_relation__:"))throw new d("`__lunora_relation__:*` is a fan-out-only reserved RPC and cannot be dispatched to a single shard",{code:"FORBIDDEN",status:403});if(o.fanOut&&!e.queryCoordinator)throw new d("RPC envelope set `fanOut` but no `queryCoordinator` is configured on the worker",{code:"BAD_REQUEST",status:400})},wn=async(o,i,h)=>{j(o,"POST","RPC");const c=await Ma(o);La(i,c),mn(c);const m=await se(o,c);if(m!==void 0)return m;const{headers:R,identity:I}=await de(o,i,a);await _e(c,I);const y=vt(c,e);{const A=Date.now(),{observability:O}=e,C=Ke(o),B=Re(i,o,h&&(M=>h.waitUntil?.(M)));if(c.fanOut){const M=e.queryCoordinator;if(!M)throw new d("RPC envelope set `fanOut` but no `queryCoordinator` is configured on the worker",{code:"BAD_REQUEST",status:400});try{const ee=await M.fanOut(s,{args:c.args??{},fanOut:c.fanOut,functionPath:c.functionPath,headers:R});return ce(O,{durationMs:Date.now()-A,fanOut:{failed:ee.failed,shards:ee.ok+ee.failed,table:c.fanOut.table},functionPath:c.functionPath,...C,ok:!0},B),Response.json(ee,{headers:{"content-type":"application/json"},status:200})}catch(ee){throw ce(O,{...Ee(c.functionPath,Date.now()-A,ee,{fanOut:{table:c.fanOut.table}}),...C},B),ee}}const L=c.shardKey??r,te=()=>Ie(o,c.functionPath,c.args??{},L,R,B);return y&&e.x402Charge?e.x402Charge(o,{functionPath:c.functionPath,price:y.price},te,At(h)):te()}},gn=async(o,i,h)=>{j(o,"POST","RPC batch");const c=await Z(o),{calls:m}=c;if(!Array.isArray(m))throw new d("RPC batch `calls` must be an array",{code:"BAD_REQUEST",status:400});const{headers:R,identity:I}=await de(o,i,a),y=Wr(m,r);for(const Q of y.values())for(const z of Q)if(e.functions?.[z.functionPath]?.x402)throw new d(`paid (\`.x402\`) function "${z.functionPath}" cannot be called in a batch; dispatch it individually over ${Et}`,{code:"BAD_REQUEST",status:400});await Promise.all([...y.entries()].flatMap(([Q,z])=>z.map(ne=>_e({args:ne.args,functionPath:ne.functionPath,shardKey:Q},I))));const{observability:A}=e,O=Re(i,o,h&&(Q=>h.waitUntil?.(Q))),C=Ke(o),B=[],L=[],te=(Q,z,ne,ue)=>({body:{error:{code:ne,message:ue}},id:Q.id,status:z}),M=(Q,z,ne,ue,fe)=>{for(const q of Q)ce(A,fe(q),O),B.push(te(q,z,ne,ue))},ee=(Q,z,ne,ue,fe)=>{for(const q of Q){const pe=ue.get(q.id)??fe,ge=pe<400;ce(A,{durationMs:ne,functionPath:q.functionPath,...C,ok:ge,shardKey:z,...ge?{}:{error:{code:"SHARD_ERROR",message:`batched call returned ${String(pe)}`,status:pe}}},O)}};await Promise.all([...y.entries()].map(async([Q,z])=>{const ne=new Headers(R);ne.set("content-type","application/json");const ue=new Request("https://shard.internal/rpc-batch",{body:JSON.stringify({calls:z}),headers:ne,method:"POST"}),fe=Date.now();let q;try{q=await g(s,Q,ue)}catch(Y){const Ue=Date.now()-fe,{body:et}=Nn(Y,{fallbackCode:"SHARD_UNAVAILABLE",redactedMessage:"shard unavailable"});M(z,502,et.code,et.message,Pn=>({...Ee(Pn.functionPath,Ue,Y,{shardKey:Q}),...C}));return}const pe=Date.now()-fe,ge=q.headers.get("x-d1-bookmark");ge&&L.push(ge);let De;try{De=await q.json()}catch{const Y=`shard batch returned a non-JSON response (${String(q.status)})`;M(z,q.status,"SHARD_ERROR",Y,Ue=>({durationMs:pe,error:{code:"SHARD_ERROR",message:Y,status:q.status},functionPath:Ue.functionPath,...C,ok:!1,shardKey:Q}));return}const Ne=Array.isArray(De.results)?De.results:[],kn=new Map(Ne.map(Y=>[Y.id,Y.status??q.status])),In=new Set(Ne.map(Y=>Y.id));ee(z,Q,pe,kn,q.status),B.push(...Ne);for(const Y of z)In.has(Y.id)||B.push(te(Y,q.status,"SHARD_ERROR",`shard batch omitted result for call ${String(Y.id)}`))}));const Xe={"content-type":"application/json"},[Ze]=L;return L.length===1&&Ze!==void 0&&(Xe["x-d1-bookmark"]=Ze),Response.json({results:B},{headers:Xe,status:200})},yn=async(o,i,h,c={},m={})=>{try{const R=h.__lunoraRef;if(typeof R!="string")throw new d("serverQuery: expected a function reference from the generated `api`",{code:"BAD_REQUEST",status:400});const{headers:I,identity:y}=await de(o,i,a,m.context);await _e({args:c,functionPath:R,shardKey:m.shardKey},y);const A=m.shardKey??r,O=Re(i,o,m.waitUntil);return await Ie(o,R,c,A,I,O)}catch(R){return tt(R)}},qe=async(o,i,h)=>{const{observability:c}=e,m=Date.now(),R=Se(16),I=Se(8),y=Ot(i);try{const A=await h();return ce(c,{durationMs:Date.now()-m,functionPath:o,ok:!0,spanId:I,traceId:R},y),A}catch(A){throw ce(c,{...Ee(o,Date.now()-m,A,{}),spanId:I,traceId:R},y),A}finally{nt(c,y)}},bn=async(o,i,h)=>{_(i);const c=[],m=y=>y instanceof Error?y:new Error(String(y)),R=e.crons?.[o.cron];if(R)try{await R(o,i,h)}catch(y){c.push(m(y))}if(await J(o.cron,i,c,m),e.backupStore&&e.backupCron!==void 0&&e.backupCron===o.cron)try{await $r(e,s,k(),o)}catch(y){c.push(m(y))}const[I]=c;if(c.length===1&&I)throw I;if(c.length>1)throw new AggregateError(c,`scheduled("${o.cron}") had ${String(c.length)} failure(s)`)},_n=async(o,i)=>{try{const h=o??{},c=e.adminToken??(typeof h.LUNORA_ADMIN_TOKEN=="string"?h.LUNORA_ADMIN_TOKEN:void 0);if(!c||c.length===0)return;await g(s,r,ye(Pa,{outcome:i},{authorization:`Bearer ${c}`,"content-type":"application/json"}))}catch{}},Rn=async(o,i,h,c)=>{if(!e.authHandler)return;const m=await e.authHandler(o);if(!m)return;const R=e.authBasePath??Ia;return Ua(h.pathname,R)&&c.waitUntil?.(_n(i,m.status>=400?"fail":"ok")),m},En=async({args:o,env:i,functionPath:h,request:c,shardKey:m,waitUntil:R})=>{Ut(o,"REST");const I={functionPath:h,...m===void 0?{}:{shardKey:m}},{headers:y,identity:A}=await de(c,i,a);await _e(I,A);const O=m??r,C=Re(i,c,R),B=()=>Ie(c,h,o,O,y,C),L=vt(I,e);return L&&e.x402Charge?e.x402Charge(c,{functionPath:h,price:L.price},B,At({waitUntil:R})):B()},An=Kn({functions:e.functions??{},invoke:En,readJsonBody:Z,...e.restRateLimit?{rateLimit:e.restRateLimit}:{}}),Pe=e.routes!==void 0&&Object.keys(e.routes).length>0?e.routes:void 0,Sn={[Oa]:o=>o.method!=="GET"&&o.method!=="HEAD"?new Response(void 0,{headers:{allow:"GET, HEAD"},status:405}):Response.json({ok:!0},{headers:{"cache-control":"no-store"}}),[_a]:(o,i,h)=>un(o,i,h),[Et]:(o,i,h,c)=>wn(o,i,c),[ba]:(o,i,h,c)=>gn(o,i,c),[Ra]:(o,i)=>he(o,i),[Ea]:(o,i)=>ae(o,i),[Aa]:async o=>{j(o,"POST","ws-token"),G(o);const i=k();if(i===void 0)throw new d("ws-token minting requires a configured admin token",{code:"ADMIN_TOKEN_NOT_CONFIGURED",status:400});const h=await Or(i);return Response.json(h,{headers:{"cache-control":"no-store"}})},...W,...Jt,...qt,...Yt,...Xt,...Zt,...en,...tn,...nn,...rn,...an,...An,...Pr({assertAdmin:G,getAuthAdmin:()=>e.authAdmin,parsePaging:ke,queryParameter:ve,readJsonBody:Z})};let ie=ot(e.security),Ye=!1;const Tn=o=>{Ye||(Ye=!0,ie=ot(e.security,o??{}))},On=async(o,i)=>{if(!(e.adminGate===void 0||!va(i)))try{await e.adminGate(o,Fe.get(o))&&p.add(o)}catch{}},vn=async(o,i,h)=>{Fe.set(o,h);const c=new URL(o.url);if(o.method==="POST"||o.method==="PUT"){const y=Number(o.headers.get("content-length")??""),A=ya[c.pathname]??Nt;if(Number.isFinite(y)&&y>A)throw new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413})}const m=await Rn(o,i,c,h);if(m)return m;if(Pe){const y=`${o.method} ${c.pathname}`,A=Pe[y]??Pe[c.pathname];if(A)return A(o,i,h)}const R=Sn[c.pathname];if(R)return await On(o,c.pathname),R(o,i,c,h);if(e.voiceAgents!==void 0&&c.pathname.startsWith(Tt))return ln(o,i,c);const I=await dn(o,i,h);return I||new Response("Not found",{status:404})};return{async fetch(o,i,h){e.passThroughOnException&&h.passThroughOnException?.(),Tn(i),_(i);const c=or(o,ie);if(c)return c;const m=ar(o,ie);if(m)return Be(m,o,ie);try{const R=await vn(o,i,h);return Be(R,o,ie)}catch(R){return Be(tt(R),o,ie)}finally{nt(e.observability,Ot(h))}},async queue(o,i,h){await qe(`queue:${Ba(o)}`,h,async()=>{await e.queue?.(o,i,h)})},async scheduled(o,i,h){await qe(`cron:${o.cron}`,h,async()=>{await bn(o,i,h)})},serverQuery:yn}},Wa=e=>Vt(e),Va=e=>typeof e=="function"?{fetch:e}:e,Ja=e=>!!(e.crons??e.cronJobs??e.backupCron),ms=(e,n)=>{const t=Va(e),r=typeof e=="object"&&typeof e.scheduled=="function"?e.scheduled:void 0,a=l=>{const u=Wa({...l,httpRouter:t});return r!==void 0&&!Ja(l)?{...u,scheduled:async(f,g,E)=>{await r(f,g,E)}}:u};if(typeof n!="function")return a(n);const s=n;return{fetch:(l,u,f)=>a(s(u)).fetch(l,u,f),queue:(l,u,f)=>a(s(u)).queue?.(l,u,f)??Promise.resolve(),scheduled:(l,u,f)=>a(s(u)).scheduled(l,u,f),serverQuery:(l,u,f,g,E)=>a(s(u)).serverQuery(l,u,f,g,E)}},qa=(e,n)=>{if(typeof e=="function")return e(n);const t=e.shardDO??n?.SHARD;if(!t)throw new d("@lunora/runtime: no shard Durable Object namespace found. Bind `SHARD` in wrangler.jsonc, or pass `createLunoraHandler({ shardDO: env.MY_SHARD })`.");return{...e,shardDO:t}},ws=(e={})=>(n,t,r)=>Vt(qa(e,t)).fetch(n,t,r??Un),gs=e=>e;export{Dr as GET_AUTH_AUDIT_LOG_OP,Un as NOOP_EXECUTION_CONTEXT,_s as composeIdentityResolvers,Wa as composeWorker,ws as createLunoraHandler,Vt as createWorker,gs as defineRpcEnvelope,Ka as probeRelayCount,qa as resolveLunoraOptions,Rs as routeIdentityResolvers,ms as withFrameworkWorker};
@@ -0,0 +1 @@
1
+ import{e as v}from"./evict-oldest-BNXsKx4s.mjs";const g=o=>{const e=new WeakMap;return(n,i,a)=>{const s=e.get(n);if(s)return s;const t=Promise.resolve(o(n,i,a));return e.set(n,t),t}},f=5e3,p=500,y=o=>{const e=o.headers.get("cookie")??"",n=o.headers.get("authorization")??"";if(!(e===""&&n===""))return`${n}\0${e}`},M=(o,e={})=>{const n=e.ttlMs??f,i=Math.max(1,e.maxEntries??p),a=e.cacheKey??y,s=g(o),t=new Map;return(d,h,l)=>{const r=a(d);if(r===void 0||l?.access!==void 0)return s(d,h,l);const m=Date.now(),u=t.get(r);if(u&&u.expiresAt>m)return u.value;const c=Promise.resolve(s(d,h,l));return c.catch(()=>{t.get(r)?.value===c&&t.delete(r)}),t.delete(r),v(t,i),t.set(r,{expiresAt:m+n,value:c}),c}};export{M as memoizeIdentity,g as memoizeIdentityPerRequest};
@@ -0,0 +1 @@
1
+ const v="/_lunora/rest",m=["authorization","cf-access-jwt-assertion","cookie"],d=["x-d1-bookmark","x-lunora-shard-key"],h=e=>[...m,...(e.credentialHeaders??[]).map(t=>t.toLowerCase())],u=e=>Number.isFinite(e)?Math.max(0,Math.floor(e)):0,i=(...e)=>{const t=[];for(const a of e)for(const r of a?.split(",")??[]){const n=r.trim().toLowerCase();n!==""&&!t.includes(n)&&t.push(n)}return t.length===0?void 0:t.join(", ")},l=(e,t)=>{const a=[t,`max-age=${String(u(e.maxAge))}`];return e.staleWhileRevalidate!==void 0&&a.push(`stale-while-revalidate=${String(u(e.staleWhileRevalidate))}`),a.join(", ")},p=e=>e.scope==="public"?i(e.vary,...h(e),...d):i(e.vary,...d),f=e=>{const t=e.indexOf(":");if(!(t<=0||t>=e.length-1||e.indexOf(":",t+1)!==-1))return{name:e.slice(t+1),namespace:e.slice(0,t)}},g=e=>{const t=f(e);if(t!==void 0)return`${v}/${t.namespace}/${t.name}`},E=e=>e==="query"?"GET":"POST",S=e=>{const t=[];for(const a of e){if(a.exposure?.rest!==!0||a.kind==="stream")continue;const r=f(a.functionPath),n=g(a.functionPath);r===void 0||n===void 0||t.push({functionPath:a.functionPath,kind:a.kind,method:E(a.kind),name:r.name,namespace:r.namespace,path:n})}return t.sort((a,r)=>a.path.localeCompare(r.path)),t},C=(e,t,a)=>a?.access!==void 0||h(t).some(r=>e.headers.has(r)),R=(e,t,a,r)=>{if(t.method!=="GET"||a<200||a>299)return;const n=e.scope==="public"&&!C(t,e,r)?"public":"private",s={"cache-control":l(e,n)};e.tag!==void 0&&e.tag!==""&&(s["cache-tag"]=e.tag);const o=p(e);return o!==void 0&&(s.vary=o),s},b=(e,t,a,r)=>{if(t===void 0)return e;const n=R(t,a,e.status,r);if(n===void 0)return e;const s=new Response(e.body,e);for(const[o,c]of Object.entries(n))s.headers.set(o,o==="vary"?i(s.headers.get("vary")??void 0,c)??c:c);return s};export{b as a,R as b,S as d,C as r};
@@ -1 +1 @@
1
- import{a as A,d as L}from"./rest-cache-D6nWkevc.mjs";import{LunoraError as d}from"./LunoraError-DksAgIpa.mjs";import{m as O}from"./method-guard-BG_vJNTl.mjs";const h=1048576,g=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),E=async(e,r=h)=>{if(!e.body)return"";const t=e.body.getReader(),a=new TextDecoder;let s=0,o="";for(;;){const{done:n,value:c}=await t.read();if(n)break;if(c){if(s+=c.byteLength,s>r)throw await t.cancel().catch(()=>{}),new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});o+=a.decode(c,{stream:!0})}}return o+=a.decode(),o},D=async(e,r=h)=>{if(!e.body)return new ArrayBuffer(0);const t=e.body.getReader(),a=[];let s=0;for(;;){const{done:c,value:u}=await t.read();if(c)break;if(u){if(s+=u.byteLength,s>r)throw await t.cancel().catch(()=>{}),new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});a.push(u)}}const o=new Uint8Array(s);let n=0;for(const c of a)o.set(c,n),n+=c.byteLength;return o.buffer},S=async(e,r,t=h)=>{try{const a=await E(e,t);return a===""?{}:JSON.parse(a)}catch(a){throw a instanceof d?a:new d(`${r} body must be valid JSON`,{code:"BAD_REQUEST",status:400})}},U=async(e,r=h)=>{const t=await S(e,"Request",r);if(!g(t))throw new d("Request body must be an object",{code:"BAD_REQUEST",status:400});return t},T=(e,r)=>{if(!g(e))throw new d(`${r} \`args\` must be an object`,{code:"BAD_REQUEST",status:400})},k=e=>L(Object.entries(e).map(([r,t])=>({exposure:t.expose,functionPath:r,kind:t.kind}))),B=(e,r)=>{const t=e.searchParams.get("shardKey");if(t!==null&&t!=="")return t;const a=r.headers.get("x-lunora-shard-key");return a===null||a===""?void 0:a},v=e=>{const r=Object.create(null);for(const[t,a]of e.searchParams.entries())if(t!=="shardKey")try{r[t]=JSON.parse(a)}catch{r[t]=a}return r},J=e=>{const{functions:r,invoke:t,rateLimit:a,readJsonBody:s}=e,o={};for(const n of k(r)){const c=n.kind==="query"?["GET","POST"]:["POST"],u=r[n.functionPath].expose?.cache;o[n.path]=async(i,R,P,l)=>{const w=O(i,c);if(w)return w;const m=new URL(i.url);if(a){const f=await a(i,n.functionPath);if(f)return f}let y;i.method==="GET"?y=v(m):y=i.body===null?{}:await s(i),T(y,"REST");const b=B(m,i),p=await t({args:y,env:R,functionPath:n.functionPath,request:i,...b===void 0?{}:{shardKey:b},...l?.waitUntil===void 0?{}:{waitUntil:f=>l.waitUntil?.(f)}});return A(p,u,i)}}return o},M=(e,r)=>async(t,a)=>{const s=r.key?r.key(t,a):t.headers.get("cf-connecting-ip")??void 0,o=await e.limit(r.name,s===void 0?{}:{key:s});if(o.ok)return;const n=Math.max(1,Math.ceil(o.retryAfter/1e3));return Response.json({error:{code:"RATE_LIMITED",message:"Rate limit exceeded"}},{headers:{"content-type":"application/json","retry-after":String(n)},status:429})};export{h as M,v as a,J as b,M as c,k as d,U as e,S as f,D as g,T as h,E as i,B as r};
1
+ import{a as A,d as L}from"./rest-cache-BnMq2hbO.mjs";import{LunoraError as d}from"./LunoraError-DksAgIpa.mjs";import{m as O}from"./method-guard-BG_vJNTl.mjs";const h=1048576,g=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),E=async(e,r=h)=>{if(!e.body)return"";const t=e.body.getReader(),a=new TextDecoder;let s=0,o="";for(;;){const{done:n,value:c}=await t.read();if(n)break;if(c){if(s+=c.byteLength,s>r)throw await t.cancel().catch(()=>{}),new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});o+=a.decode(c,{stream:!0})}}return o+=a.decode(),o},U=async(e,r=h)=>{if(!e.body)return new ArrayBuffer(0);const t=e.body.getReader(),a=[];let s=0;for(;;){const{done:c,value:u}=await t.read();if(c)break;if(u){if(s+=u.byteLength,s>r)throw await t.cancel().catch(()=>{}),new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});a.push(u)}}const o=new Uint8Array(s);let n=0;for(const c of a)o.set(c,n),n+=c.byteLength;return o.buffer},S=async(e,r,t=h)=>{try{const a=await E(e,t);return a===""?{}:JSON.parse(a)}catch(a){throw a instanceof d?a:new d(`${r} body must be valid JSON`,{code:"BAD_REQUEST",status:400})}},x=async(e,r=h)=>{const t=await S(e,"Request",r);if(!g(t))throw new d("Request body must be an object",{code:"BAD_REQUEST",status:400});return t},T=(e,r)=>{if(!g(e))throw new d(`${r} \`args\` must be an object`,{code:"BAD_REQUEST",status:400})},k=e=>L(Object.entries(e).map(([r,t])=>({exposure:t.expose,functionPath:r,kind:t.kind}))),B=(e,r)=>{const t=e.searchParams.get("shardKey");if(t!==null&&t!=="")return t;const a=r.headers.get("x-lunora-shard-key");return a===null||a===""?void 0:a},v=e=>{const r=Object.create(null);for(const[t,a]of e.searchParams.entries())if(t!=="shardKey")try{r[t]=JSON.parse(a)}catch{r[t]=a}return r},J=e=>{const{functions:r,invoke:t,rateLimit:a,readJsonBody:s}=e,o={};for(const n of k(r)){const c=n.kind==="query"?["GET","POST"]:["POST"],u=r[n.functionPath].expose?.cache;o[n.path]=async(i,R,P,l)=>{const w=O(i,c);if(w)return w;const m=new URL(i.url);if(a){const f=await a(i,n.functionPath);if(f)return f}let y;i.method==="GET"?y=v(m):y=i.body===null?{}:await s(i),T(y,"REST");const b=B(m,i),p=await t({args:y,env:R,functionPath:n.functionPath,request:i,...b===void 0?{}:{shardKey:b},...l?.waitUntil===void 0?{}:{waitUntil:f=>l.waitUntil?.(f)}});return A(p,u,i,l)}}return o},M=(e,r)=>async(t,a)=>{const s=r.key?r.key(t,a):t.headers.get("cf-connecting-ip")??void 0,o=await e.limit(r.name,s===void 0?{}:{key:s});if(o.ok)return;const n=Math.max(1,Math.ceil(o.retryAfter/1e3));return Response.json({error:{code:"RATE_LIMITED",message:"Rate limit exceeded"}},{headers:{"content-type":"application/json","retry-after":String(n)},status:429})};export{h as M,v as a,J as b,M as c,k as d,x as e,S as f,U as g,T as h,E as i,B as r};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/runtime",
3
- "version": "1.0.0-alpha.63",
3
+ "version": "1.0.0-alpha.65",
4
4
  "description": "Lunora Worker runtime: the RPC router, shard resolver, and query coordinator",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -46,9 +46,9 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@lunora/bindings": "1.0.0-alpha.29",
49
+ "@lunora/bindings": "1.0.0-alpha.30",
50
50
  "@lunora/errors": "1.0.0-alpha.22",
51
- "@lunora/platform": "1.0.0-alpha.11"
51
+ "@lunora/platform": "1.0.0-alpha.12"
52
52
  },
53
53
  "engines": {
54
54
  "node": "^22.15.0 || >=24.11.0"
@@ -1 +0,0 @@
1
- import{LunoraError as c}from"./LunoraError-DksAgIpa.mjs";const d=(t,o={})=>{const r=o.onError??"fail-closed";return async(n,e)=>{for(const s of t){let i;try{i=await s(n,e)}catch(l){if(r==="skip")continue;throw l}if(i)return i}return null}},u=t=>{const o=Object.keys(t).filter(r=>r!=="*").toSorted((r,n)=>n.length-r.length);return(r,n)=>{const{pathname:e}=new URL(r.url),s=o.find(l=>e===l||e.startsWith(l.endsWith("/")?l:`${l}/`)),i=s===void 0?t["*"]:t[s];return i===void 0?null:i(r,n)}},f=(t,o)=>o===void 0||t===void 0?t:async(r,n)=>{const e=await t(r,n);if(!e)return e;const s=o.validate(e);if(s.ok)return e;if(o.onInvalid==="reject")throw new c(`identity claims failed the declared contract: ${s.error}`,{code:"UNAUTHENTICATED",status:401});return null};export{d as composeIdentityResolvers,u as routeIdentityResolvers,f as wrapResolverWithContract};
@@ -1,6 +0,0 @@
1
- import{isLunoraError as Pn,toErrorBody as Dn}from"@lunora/errors";import{e as Pt}from"./evict-oldest-BNXsKx4s.mjs";import{NOOP_EXECUTION_CONTEXT as Nn}from"./NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs";import{e as Un,a as Cn}from"./identity-header-JF5q3H5w.mjs";import{o as Se,b as Bn,p as xn,m as Hn,d as Ln,a as jn,r as Mn}from"./otlp-resource-B4Yylr0V.mjs";import{e as Z,f as be,M as Dt,b as $n,g as Kn,h as Nt,i as Ut}from"./rest-routes-3l718ENH.mjs";import{LunoraError as d,toErrorResponse as et}from"./LunoraError-DksAgIpa.mjs";import{a as M,m as me}from"./method-guard-BG_vJNTl.mjs";import{normalizeBackupPrefix as Fe,BACKUP_KEY_PREFIX as Ge,isBackupManifestKey as Fn,backupObjectKeyOfManifest as Ct,backupObjectKey as Gn,backupManifestKey as Qn}from"./BACKUP_KEY_PREFIX-BOtSu-_3.mjs";import{toHex as zn,buildStorageAdminRoutes as Wn,STORAGE_UPLOAD_MAX_BODY_BYTES as Vn,STORAGE_PATH as qn}from"./STORAGE_UPLOAD_MAX_BODY_BYTES-BqyO-1l6.mjs";import{runExportTap as Jn}from"./createKvCursorStore-VOd1DFsf.mjs";import{buildHealthRoutes as Yn,durableObjectProbe as Xn,d1Probe as Zn,presenceProbe as Ce}from"./HEALTH_PATH-jZsuCmSs.mjs";import{wrapResolverWithContract as er}from"./composeIdentityResolvers-DdDFfuTV.mjs";import{composeIdentityResolvers as bs,routeIdentityResolvers as _s}from"./composeIdentityResolvers-DdDFfuTV.mjs";import{buildLogArchiveAdminRoutes as tr}from"./LOG_ARCHIVE_PATH-jgHjdsz2.mjs";import{r as nr,f as tt,a as ce}from"./observability-vDK-rMbs.mjs";import{resolveShard as we,applyJurisdiction as nt}from"./applyJurisdiction-C0ddU7Tg.mjs";import{resolveSecurity as rt,handleCorsPreflight as rr,enforceOrigin as or,decorateResponse as Be,enforceWebSocketOrigin as ot}from"./decorateResponse-D3NzOIvB.mjs";const ar=e=>{const n=e??{};if(typeof n.bucket=="function")return n;const t={...n,bucketName:"default"};return t.bucket=()=>t,t},Bt="__lunoraBranch",sr=e=>typeof e=="object"&&e!==null&&Object.hasOwn(e,Bt),ir=`may not contain the reserved workflow branch-marker key ("${Bt}")`,Qe=(e,n)=>{const t=Math.max(e.length,n.length);let r=e.length^n.length;for(let a=0;a<t;a+=1){const s=a<e.length?e.charCodeAt(a):0,l=a<n.length?n.charCodeAt(a):0;r|=s^l}return r===0},ze=new TextEncoder,cr=Array.from({length:32},(e,n)=>n);new RegExp(`[${cr.map(e=>String.fromCodePoint(e)).join("")}]`,"u");const dr=e=>{const n=String.fromCodePoint(...e);return btoa(n).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},ur=e=>{const n=e.replaceAll("-","+").replaceAll("_","/")+"===".slice((e.length+3)%4),t=atob(n),r=new Uint8Array(t.length);for(let a=0;a<t.length;a+=1)r[a]=t.codePointAt(a)??0;return r},lr=64,xe=new Map,xt=async e=>{const n=xe.get(e);if(n)return n;Pt(xe,lr);const t=crypto.subtle.importKey("raw",ze.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]);return xe.set(e,t),t},Ht=async(e,n)=>{const t=await xt(e),r=await crypto.subtle.sign("HMAC",t,ze.encode(n));return dr(new Uint8Array(r))},hr=async(e,n,t)=>{const r=await xt(e);return crypto.subtle.verify("HMAC",r,t,ze.encode(n))},fr=["wnam","enam","sam","weur","eeur","apac","apac-ne","apac-se","oc","afr","me"];new Set(fr);const pr=new Set(["AE","BH","IL","IQ","IR","JO","KW","LB","OM","PS","QA","SA","SY","TR","YE"]),mr=-100,wr=15,gr=e=>{const n=Number(e.longitude??Number.NaN);switch(e.continent){case"AF":return"afr";case"AS":return e.country!==void 0&&pr.has(e.country)?"me":"apac";case"EU":return Number.isFinite(n)&&n>wr?"eeur":"weur";case"NA":return Number.isFinite(n)&&n<mr?"wnam":"enam";case"OC":return"oc";case"SA":return"sam";default:return}},at=e=>{const n=e.cf;return n===void 0?void 0:gr(n)},Lt="::relay::",yr=(e,n)=>`${e}${Lt}${String(n)}`,jt="::replica::",br=(e,n)=>`${e}${jt}${n}`,_r=e=>{if(e==null||!/^\d+$/.test(e))return;const n=Number.parseInt(e,10);return Number.isSafeInteger(n)&&n>0?n:void 0},Rr=new Set(["1","enabled","on","true","yes"]),Er=new Set(["0","disabled","false","no","off"]),Ar=(e,n)=>{const t=(e??"").trim().toLowerCase();return Rr.has(t)?!0:Er.has(t)?!1:n},Mt="v1",Sr=6e4,Tr=async(e,n={})=>{const t=(n.now??Date.now())+(n.ttlMs??Sr),r=`${Mt}.${String(t)}`,a=await Ht(e,r);return{expiresAtMs:t,token:`${r}.${a}`}},Or=async(e,n,t=Date.now())=>{if(e.length===0||n.length===0)return!1;const r=n.split(".");if(r.length!==3)return!1;const[a,s,l]=r;if(a!==Mt||l.length===0)return!1;const u=Number(s);if(!Number.isFinite(u)||u<=t)return!1;let f;try{f=ur(l)}catch{return!1}return hr(e,`${a}.${s}`,f)},P="/_lunora/admin/auth",vr={INVITER_REQUIRED:400,ORG_SLUG_INVALID:400,ORG_SLUG_TAKEN:409,PASSWORD_TOO_LONG:400,PASSWORD_TOO_SHORT:400,USER_ALREADY_EXISTS:409,USER_NOT_FOUND:404},N=(e,n)=>{const t=e[n];if(typeof t!="string"||t==="")throw new d(`\`${n}\` is required`,{code:"BAD_REQUEST",status:400});return t},le=(e,n)=>{const t=e(n);if(t===void 0)throw new d(`\`${n}\` query parameter is required`,{code:"BAD_REQUEST",status:400});return t},$t=e=>{if(typeof e=="string"||Array.isArray(e)&&e.every(n=>typeof n=="string"))return e},re=(e,n)=>typeof e[n]=="string"?e[n]:void 0,He=(e,n)=>{const t=e[n];return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:void 0},st=e=>{const n=$t(e.role);if(n===void 0||typeof n=="string"&&n.trim()==="")throw new d("`role` is required",{code:"BAD_REQUEST",status:400});return n},it=e=>{const n=e.permission;if(typeof n!="object"||n===null||Array.isArray(n))throw new d("`permission` object is required",{code:"BAD_REQUEST",status:400});const t={};for(const[r,a]of Object.entries(n))Array.isArray(a)&&a.every(s=>typeof s=="string")&&(t[r]=a);return t},kr={[`${P}/capabilities`]:{build:()=>({}),http:"GET",method:"capabilities"},[`${P}/users`]:{build:({paging:e,query:n})=>{const t=n("sortDirection");return{...e,filterField:n("filterField"),filterValue:n("filterValue"),search:n("search"),searchField:n("searchField"),sortBy:n("sortBy"),sortDirection:t==="asc"||t==="desc"?t:void 0}},http:"GET",method:"listUsers"},[`${P}/sessions`]:{build:({paging:e,query:n})=>({...e,userId:n("userId")}),http:"GET",method:"listSessions"},[`${P}/accounts`]:{build:({query:e})=>({userId:le(e,"userId")}),http:"GET",method:"listAccounts"},[`${P}/passkeys`]:{build:({query:e})=>({userId:le(e,"userId")}),http:"GET",method:"listPasskeys"},[`${P}/organizations`]:{build:({paging:e})=>({...e}),http:"GET",method:"listOrganizations"},[`${P}/organizations/members`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listMembers"},[`${P}/organizations/invitations`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listInvitations"},[`${P}/config`]:{build:()=>({}),http:"GET",method:"config"},[`${P}/organizations/teams`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listTeams"},[`${P}/organizations/teams/members`]:{build:({paging:e,query:n})=>({...e,teamId:le(n,"teamId")}),http:"GET",method:"listTeamMembers"},[`${P}/organizations/roles`]:{build:({paging:e,query:n})=>({...e,organizationId:le(n,"organizationId")}),http:"GET",method:"listOrgRoles"},[`${P}/users/create`]:{build:({body:e})=>({data:He(e,"data"),email:N(e,"email"),name:N(e,"name"),password:re(e,"password"),role:$t(e.role)}),http:"POST",method:"createUser"},[`${P}/users/update`]:{build:({body:e})=>{const{data:n}=e;if(typeof n!="object"||n===null||Array.isArray(n))throw new d("`data` object is required",{code:"BAD_REQUEST",status:400});return{data:n,userId:N(e,"userId")}},http:"POST",method:"updateUser"},[`${P}/users/role`]:{build:({body:e})=>({role:st(e),userId:N(e,"userId")}),http:"POST",method:"setRole"},[`${P}/users/ban`]:{build:({body:e})=>({expiresInSeconds:typeof e.expiresInSeconds=="number"?e.expiresInSeconds:void 0,reason:re(e,"reason"),userId:N(e,"userId")}),http:"POST",method:"banUser"},[`${P}/users/unban`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"unbanUser"},[`${P}/users/password`]:{build:({body:e})=>({newPassword:N(e,"newPassword"),userId:N(e,"userId")}),http:"POST",method:"setUserPassword",returns:"void"},[`${P}/users/remove`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"removeUser",returns:"void"},[`${P}/users/impersonate`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"impersonateUser"},[`${P}/sessions/revoke`]:{build:({body:e})=>({sessionId:N(e,"sessionId")}),http:"POST",method:"revokeUserSession",returns:"void"},[`${P}/sessions/revoke-all`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"revokeUserSessions",returns:"void"},[`${P}/accounts/unlink`]:{build:({body:e})=>({accountId:N(e,"accountId"),userId:N(e,"userId")}),http:"POST",method:"unlinkAccount",returns:"void"},[`${P}/two-factor/disable`]:{build:({body:e})=>({userId:N(e,"userId")}),http:"POST",method:"disableTwoFactor",returns:"void"},[`${P}/passkeys/delete`]:{build:({body:e})=>({passkeyId:N(e,"passkeyId")}),http:"POST",method:"deletePasskey",returns:"void"},[`${P}/organizations/members/remove`]:{build:({body:e})=>({memberId:N(e,"memberId")}),http:"POST",method:"removeMember",returns:"void"},[`${P}/organizations/invitations/cancel`]:{build:({body:e})=>({invitationId:N(e,"invitationId")}),http:"POST",method:"cancelInvitation",returns:"void"},[`${P}/organizations/create`]:{build:({body:e})=>({logo:re(e,"logo"),metadata:He(e,"metadata"),name:N(e,"name"),ownerId:re(e,"ownerId"),slug:re(e,"slug")}),http:"POST",method:"createOrganization"},[`${P}/organizations/update`]:{build:({body:e})=>({logo:re(e,"logo"),metadata:He(e,"metadata"),name:re(e,"name"),organizationId:N(e,"organizationId"),slug:re(e,"slug")}),http:"POST",method:"updateOrganization"},[`${P}/organizations/remove`]:{build:({body:e})=>({organizationId:N(e,"organizationId")}),http:"POST",method:"deleteOrganization",returns:"void"},[`${P}/organizations/members/add`]:{build:({body:e})=>({organizationId:N(e,"organizationId"),role:re(e,"role"),userId:N(e,"userId")}),http:"POST",method:"addMember"},[`${P}/organizations/members/invite`]:{build:({body:e})=>({email:N(e,"email"),inviterId:re(e,"inviterId"),organizationId:N(e,"organizationId"),role:re(e,"role")}),http:"POST",method:"inviteMember"},[`${P}/organizations/members/role`]:{build:({body:e})=>({memberId:N(e,"memberId"),role:st(e)}),http:"POST",method:"updateMemberRole"},[`${P}/organizations/teams/create`]:{build:({body:e})=>({name:N(e,"name"),organizationId:N(e,"organizationId")}),http:"POST",method:"createTeam"},[`${P}/organizations/teams/update`]:{build:({body:e})=>({name:N(e,"name"),teamId:N(e,"teamId")}),http:"POST",method:"updateTeam"},[`${P}/organizations/teams/remove`]:{build:({body:e})=>({teamId:N(e,"teamId")}),http:"POST",method:"removeTeam",returns:"void"},[`${P}/organizations/teams/members/add`]:{build:({body:e})=>({teamId:N(e,"teamId"),userId:N(e,"userId")}),http:"POST",method:"addTeamMember"},[`${P}/organizations/teams/members/remove`]:{build:({body:e})=>({teamMemberId:N(e,"teamMemberId")}),http:"POST",method:"removeTeamMember",returns:"void"},[`${P}/organizations/roles/create`]:{build:({body:e})=>({organizationId:N(e,"organizationId"),permission:it(e),role:N(e,"role")}),http:"POST",method:"createOrgRole"},[`${P}/organizations/roles/update`]:{build:({body:e})=>({permission:it(e),roleId:N(e,"roleId")}),http:"POST",method:"updateOrgRole"},[`${P}/organizations/roles/remove`]:{build:({body:e})=>({roleId:N(e,"roleId")}),http:"POST",method:"deleteOrgRole",returns:"void"}},Ir=e=>{const n=async a=>{try{return await a()}catch(s){if(s instanceof d)throw s;const l=s,u=typeof l.code=="string"?l.code:"AUTH_ADMIN_ERROR";throw console.error("[lunora] auth admin operation failed:",s),new d("auth admin operation failed",{code:u,status:vr[u]??500})}},t=async(a,s)=>{if(e.assertAdmin(a),a.method!==s.http)throw new d(`Auth admin endpoint requires ${s.http}`,{code:"METHOD_NOT_ALLOWED",status:405});const l=e.getAuthAdmin();if(l===void 0)throw new d("auth endpoints require an `authAdmin` on the worker",{code:"AUTH_NOT_CONFIGURED",status:400});const u=l[s.method];if(u===void 0)throw new d(`auth admin does not support \`${s.method}\``,{code:"AUTH_OP_NOT_SUPPORTED",status:400});const f=new URL(a.url),w={body:s.http==="POST"?await e.readJsonBody(a):{},paging:e.parsePaging(a),query:I=>e.queryParameter(f,I)},E=s.build(w),O=await n(()=>u(E));return Response.json(s.returns==="void"?{ok:!0}:O,{headers:{"content-type":"application/json"},status:200})},r={};for(const[a,s]of Object.entries(kr))r[a]=l=>t(l,s);return r},Pr="__lunora_admin__:getAuthAuditLog",ct=e=>typeof e=="string"&&e!==""?e:void 0,dt=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0,Dr=e=>async(t,r)=>{e.assertAdmin(t);const a=e.getReader();if(a===void 0)throw new d("the auth/security audit endpoint requires an `authAuditReader` on the worker",{code:"AUTH_AUDIT_NOT_CONFIGURED",status:400});const s=ct(r.actorId),l=ct(r.event),u=dt(r.sinceSeq),f=dt(r.limit),w={...s===void 0?{}:{actorId:s},...l===void 0?{}:{event:l},...u===void 0?{}:{sinceSeq:u},...f===void 0?{}:{limit:f}};let E;try{E=await a.read(w)}catch(I){throw I instanceof d?I:(console.error("[lunora] auth audit read failed:",I),new d("auth audit read failed",{code:"AUTH_AUDIT_READ_FAILED",status:500}))}const O={entries:E};return Response.json(O,{headers:{"content-type":"application/json"},status:200})},Nr=(e,n)=>{const t=[],r=[];if(n&&n.length>0)for(const a of n)e.resolveTableSharding?.(a)?.mode.kind==="global"?r.push(a):t.push(a);return{globalTables:r,shardLocalTables:t}},Ur=async(e,n,t,r,a,s)=>{if(t!==void 0&&r.length===0)return;const l=await e.orchestrateExport(s,{args:{tables:r},headers:n,tables:r});for(const u of l.shards)if(!u.error)for(const f of u.rows??[])a(f)},Kt=async(e,n,t,r,a,s)=>{const{globalTables:l,shardLocalTables:u}=Nr(e,r);await Ur(n,t,r,u,a,s);const f=e.exportGlobals;if((r===void 0||l.length>0)&&f)for await(const E of f({tables:l}))a(E)},Cr=new TextEncoder,Br=1e3,Ft=10,xr=200,ut=8,Gt="lunoraBackupCron",lt=24*1048576,ht=e=>{const n=e.slice(0,Ft).map(r=>Ct(r)),t=e.length-n.length;return`${n.join(", ")}${t>0?` (+${String(t)} more)`:""}`},Hr=(e,n)=>{const t=new Uint8Array(new ArrayBuffer(n));let r=0;for(const a of e)t.set(a,r),r+=a.byteLength;return t},We=async(e,n,t,r)=>{if(t===void 0||!Number.isInteger(t)||t<=0)return{eligible:0,stale:[]};const a=[];let s;for(let l=0;l<Br;l+=1){const u=await e.list({cursor:s,include:["customMetadata"],prefix:n});for(const f of u.objects)Fn(f.key)&&f.customMetadata?.[Gt]===r&&a.push(f.key);if(!u.truncated||u.cursor===void 0)break;s=u.cursor}return{eligible:a.length,stale:a.toSorted((l,u)=>u.localeCompare(l)).slice(t)}},Lr=async(e,n,t,r,a)=>{const{stale:s}=await We(e,n,t,r),l=new Set(a),u=s.filter(g=>l.has(g)),f=u.slice(0,xr),w=s.length-f.length,E=a.length-u.length;if(f.length===0)return{deleted:[],failed:[],ignored:E,remaining:w};const O=[],I=[];for(let g=0;g<f.length;g+=ut){const b=await Promise.allSettled(f.slice(g,g+ut).map(async _=>(await e.delete(Ct(_)),await e.delete(_),_)));for(const[_,p]of b.entries())p.status==="fulfilled"?O.push(p.value):I.push(f[g+_])}return O.length>0&&console.info(`[lunora] backup prune kept the newest ${String(t)} and deleted ${String(O.length)}: ${ht(O)}`),I.length>0&&console.warn(`[lunora] backup prune failed to remove ${String(I.length)}: ${ht(I)}`),{deleted:O,failed:I,ignored:E,remaining:w}},jr=async e=>{const n=e.backupStore;if(!n)throw new d("backup retention preview requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});const t=Fe(e.backupPrefix??Ge),r=e.backupCron,{eligible:a,stale:s}=r===void 0?{eligible:0,stale:[]}:await We(n,t,e.backupRetain,r);return{cron:r,eligible:a,keep:e.backupRetain??0,prefix:t,wouldDelete:s}},Mr=async(e,n,t,r)=>{const a=e.backupStore,s=e.queryCoordinator;if(!a)throw new d("scheduled backup requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});if(!s)throw new d("scheduled backup requires a `queryCoordinator` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});if(!t||t.length===0)throw new d("scheduled backup requires an `adminToken` (or `env.LUNORA_ADMIN_TOKEN`) to authenticate the per-shard export gate",{code:"BACKUP_NOT_CONFIGURED",status:500});const l={authorization:`Bearer ${t}`,"content-type":"application/json"},u=e.backupTables;let f=0,w=0,E=[];await Kt(e,s,l,u,D=>{const T=Cr.encode(`${JSON.stringify(D)}
2
- `);if(f+=1,w+=T.byteLength,w>lt)throw new d(`scheduled backup reached ${String(w)} bytes of NDJSON, past the ${String(lt)}-byte limit for a snapshot assembled inside a Worker — nothing was written. Narrow it with \`backupTables\`, or take this snapshot off-platform with \`lunora backup create --bucket\`.`,{code:"BACKUP_TOO_LARGE",status:507});E.push(T)},n);const I=Fe(e.backupPrefix??Ge),g=new Date(r.scheduledTime).toISOString(),b=Gn(I,g),_=Hr(E,w);E=[];const p=zn(await crypto.subtle.digest("SHA-256",_));await a.put(b,_,{httpMetadata:{contentType:"application/x-ndjson"},sha256:p});const S={bytes:w,createdAt:g,cron:r.cron,file:b,id:g,rows:f,scheduledTime:r.scheduledTime,sha256:p,...u?{tables:u.join(",")}:{}};await a.put(Qn(b),`${JSON.stringify(S,void 0,2)}
3
- `,{customMetadata:{[Gt]:r.cron},httpMetadata:{contentType:"application/json"}});try{const{stale:D}=await We(a,I,e.backupRetain,r.cron);if(D.length>0){const T=D.slice(0,Ft),x=D.length-T.length;console.info(`[lunora] backup retention: ${String(D.length)} snapshot(s) past the newest ${String(e.backupRetain)} — run \`lunora backup prune\` to remove them: ${T.join(", ")}${x>0?` (+${String(x)} more)`:""}`)}}catch(D){console.warn(`[lunora] backup ${b} was written, but the retention report failed:`,D)}},$r=async(e,n)=>{const t=e.backupStore;if(!t)throw new d("backup prune requires a `backupStore` on the worker",{code:"BACKUP_NOT_CONFIGURED",status:500});const r=e.backupCron,a=e.backupRetain;if(r===void 0||a===void 0||!Number.isInteger(a)||a<=0)throw new d("backup prune needs a retention window: set `backupRetain` (and `backupCron`, which decides whose snapshots retention owns) on the worker. Without one there is nothing past the window to remove.",{code:"BACKUP_RETENTION_NOT_CONFIGURED",status:400});return Lr(t,Fe(e.backupPrefix??Ge),a,r,n)},Kr="/_lunora/admin/backup/retention",Fr="/_lunora/admin/backup/prune",Gr=e=>{const{options:n,readJsonBody:t,requireAdminOption:r}=e,a=(u,f)=>{r(u,n.backupStore,{code:"BACKUP_NOT_CONFIGURED",message:`backup ${f} requires a \`backupStore\` on the worker`})},s=async u=>(M(u,"GET","Backup-retention"),a(u,"retention preview"),Response.json(await jr(n),{headers:{"cache-control":"no-store"}})),l=async u=>{M(u,"POST","Backup-prune"),a(u,"prune");const{confirm:f}=await t(u);if(!Array.isArray(f)||f.some(w=>typeof w!="string"))throw new d("backup prune requires a `confirm` array of the sidecar keys to remove — read them from `GET /_lunora/admin/backup/retention` and pass back the ones you mean to delete",{code:"BAD_REQUEST",status:400});return Response.json(await $r(n,f),{headers:{"cache-control":"no-store"}})};return{[Fr]:l,[Kr]:s}},ft=500,Qr=(e,n,t)=>{if(typeof e!="object"||e===null||Array.isArray(e))throw new d("each batch call must be an object",{code:"BAD_REQUEST",status:400});const r=e;if(typeof r.functionPath!="string")throw new d("each batch call needs a string `functionPath`",{code:"BAD_REQUEST",status:400});if(r.functionPath.startsWith("__lunora_relation__:")||r.functionPath.startsWith("__lunora_admin__"))throw new d("reserved function path cannot be batched",{code:"FORBIDDEN",status:403});if(r.args!==void 0&&(typeof r.args!="object"||r.args===null||Array.isArray(r.args)))throw new d("each batch call `args` must be an object",{code:"BAD_REQUEST",status:400});return{entry:{args:r.args===void 0?{}:r.args,clientId:typeof r.clientId=="string"?r.clientId:void 0,clientSeq:typeof r.clientSeq=="number"?r.clientSeq:void 0,functionPath:r.functionPath,id:typeof r.id=="number"?r.id:n,mutationId:typeof r.mutationId=="string"?r.mutationId:void 0},shardKey:typeof r.shardKey=="string"?r.shardKey:t}},zr=(e,n)=>{if(e.length>ft)throw new d(`RPC batch exceeds the ${String(ft)}-call limit`,{code:"BAD_REQUEST",status:400});const t=new Map;for(const[r,a]of e.entries()){const{entry:s,shardKey:l}=Qr(a,r,n),u=t.get(l)??[];u.push(s),t.set(l,u)}return t},Wr=new TextEncoder,Vr=e=>{const n=JSON.stringify(e),t=Wr.encode(n);let r="";for(const a of t)r+=String.fromCodePoint(a);return btoa(r).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")},qr=e=>{const n={g:0,s:{},v:1};if(typeof e!="string"||e.length===0)return n;try{const t=atob(e.replaceAll("-","+").replaceAll("_","/")),r=new Uint8Array(t.length);for(let u=0;u<t.length;u+=1)r[u]=t.codePointAt(u)??0;const a=JSON.parse(new TextDecoder().decode(r)),s=a.s&&typeof a.s=="object"?a.s:{},l={};for(const[u,f]of Object.entries(s))typeof f=="number"&&Number.isFinite(f)&&(l[u]=f);return{g:typeof a.g=="number"&&Number.isFinite(a.g)?a.g:0,s:l,v:1}}catch{return n}},Jr=e=>{const n=typeof e.table=="string"?e.table:"",t=typeof e.op=="string"?e.op:"",r=t==="delete"||t==="insert"||t==="update"?t:"upsert",a=typeof e.id=="string"?e.id:void 0;return{doc:(e.doc&&typeof e.doc=="object"?e.doc:void 0)??(a===void 0?{}:{_id:a}),op:r,table:n}},pt=(e,n,t)=>{for(const r of n)e.push(Jr(r));return t!==void 0&&n.length>=t},Yr="/_lunora/admin/export",Xr="/_lunora/admin/import",Zr="/_lunora/admin/sync",eo="/_lunora/admin/connector/sync",to="/_lunora/admin/apply",no="/_lunora/admin/export-tap/run",ro=new TextEncoder,oo=async e=>{const t=await be(e,"Export")??{};if(t.tables===void 0)return{tables:void 0};if(!Array.isArray(t.tables))throw new d("Export `tables` must be a string array",{code:"BAD_REQUEST",status:400});const r=[];for(const a of t.tables){if(typeof a!="string"||a.length===0)throw new d("Export `tables` entries must be non-empty strings",{code:"BAD_REQUEST",status:400});r.push(a)}return{tables:r}},Le=e=>Array.isArray(e)?e.filter(n=>typeof n=="string"):void 0,ao=e=>{const{applyGlobals:n,exportCursorStore:t,exportSinks:r,knownTables:a,queryCoordinator:s,assertAdmin:l,requireAdminOption:u,resolveForwardContext:f,shardDO:w,streamExportRows:E,streamingImport:O,syncGlobals:I}=e,g=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Export endpoint requires a `queryCoordinator` on the worker"}),U=await oo(T),{headers:W}=await f(T,x),K=new ReadableStream({async pull(V){const X=q=>{V.enqueue(ro.encode(`${JSON.stringify(q)}
4
- `))};try{await E($,W,U.tables,X),V.close()}catch(q){V.error(q)}}});return new Response(K,{headers:{"content-type":"application/x-ndjson"},status:200})},b=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Sync endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),W=typeof U.cursors=="object"&&U.cursors!==null?U.cursors:{},K=typeof U.limit=="number"?U.limit:void 0,V=typeof U.globalCursor=="number"?U.globalCursor:0,X=Le(U.tables),{headers:q}=await f(T,x),ae=X??a(),F=await $.orchestrateCdcSync(w,{cursors:W,headers:q,limit:K,tables:ae}),he=I?await I({limit:K,sinceSeq:V}):void 0;return Response.json({global:he,shards:F.shards},{status:200})},_=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Connector sync endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),W=qr(U.cursor),K=typeof U.limit=="number"&&U.limit>0?U.limit:void 0,V=Le(U.tables),{headers:X}=await f(T,x),q=V??a(),ae=await $.orchestrateCdcSync(w,{cursors:W.s,headers:X,limit:K,tables:q}),F=[],he={...W.s};let G=!1;for(const se of ae.shards)G=pt(F,se.changes??[],K)||G,he[se.shardKey]=se.cursor;let oe=W.g;if(I){const se=await I({limit:K,sinceSeq:W.g});G=pt(F,se.changes,K)||G,oe=se.cursor}const Te=Vr({g:oe,s:he,v:1}),Oe={changes:F,hasMore:G,nextCursor:Te};return Response.json(Oe,{status:200})},p=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Apply endpoint requires a `queryCoordinator` on the worker"}),U=await Z(T),K=(Array.isArray(U.batches)?U.batches:[]).map(F=>F).filter(F=>F!==null&&typeof F=="object"&&typeof F.shardKey=="string"&&Array.isArray(F.changes)),V=Array.isArray(U.globalChanges)?U.globalChanges:[],{headers:X}=await f(T,x),q=await $.orchestrateApplyCdc(w,{batches:K,headers:X}),ae=V.length>0&&n?await n({changes:V}):0;return Response.json({applied:q.applied+ae,failed:q.failed,ok:q.ok},{status:200})},S=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;l(T);const{headers:$}=await f(T,x),U=await O(T,$);return Response.json(U,{headers:{"content-type":"application/json"},status:200})},D=async(T,x)=>{const H=me(T,["POST"]);if(H)return H;const $=u(T,s,{code:"BAD_REQUEST",message:"Export-tap endpoint requires a `queryCoordinator` on the worker"});if(r===void 0||Object.keys(r).length===0||t===void 0)throw new d("Export-tap endpoint requires `exportSinks` + `exportCursorStore` on the worker",{code:"EXPORT_TAP_NOT_CONFIGURED",status:400});const U=await Z(T),W=typeof U.sink=="string"?U.sink:void 0,K=typeof U.limit=="number"&&U.limit>0?U.limit:void 0,V=Le(U.tables);if(W===void 0)throw new d("Export-tap `sink` must name a configured sink",{code:"BAD_REQUEST",status:400});const X=r[W];if(X===void 0)throw new d(`Export-tap sink "${W}" is not configured`,{code:"NOT_FOUND",status:404});const{headers:q}=await f(T,x),ae=V??a(),F=await Jn({coordinator:$,cursorStore:t,headers:q,limit:K,shardDO:w,sink:X,tables:ae});return Response.json(F,{headers:{"content-type":"application/json"},status:200})};return{[to]:p,[eo]:_,[Yr]:g,[no]:D,[Xr]:S,[Zr]:b}},so=(e,n)=>{let t;try{t=JSON.parse(e)}catch{return{error:{code:"BAD_ROW",line:n,message:"line is not valid JSON",table:""},ok:!1}}if(!t||typeof t!="object"||Array.isArray(t))return{error:{code:"BAD_ROW",line:n,message:"row must be a JSON object",table:""},ok:!1};const r=t;return typeof r.table!="string"||r.table.length===0?{error:{code:"BAD_ROW",line:n,message:"row is missing `table`",table:""},ok:!1}:!r.doc||typeof r.doc!="object"||Array.isArray(r.doc)?{error:{code:"BAD_ROW",line:n,message:"row is missing or malformed `doc`",table:r.table},ok:!1}:{doc:r.doc,ok:!0,table:r.table}},io=(e,n,t,r,a)=>{if(t?.mode.kind==="shardBy"&&typeof t.mode.field=="string"){const s=e[t.mode.field];return s==null?{error:{code:"BAD_ROW",line:a,message:`row missing shard field "${t.mode.field}" for table "${n}"`,table:n},ok:!1}:{ok:!0,shardKey:typeof s=="string"?s:JSON.stringify(s)}}return{ok:!0,shardKey:r}},co=async(e,n,t)=>{if(!e.body)throw new d("Import endpoint requires a request body",{code:"BAD_REQUEST",status:400});const r=[],a=[],s=new Map;let l=0,u=0;const f=e.body.getReader(),w=new TextDecoder;let E="",O=0;const I=g=>{u+=1;const b=g.trim();if(b.length===0)return;l+=1;const _=so(b,u);if(!_.ok){r.push(_.error);return}const{doc:p,table:S}=_,D=n.resolveTableSharding?.(S);if(D?.mode.kind==="global"){a.push({doc:p,line:u,table:S});return}const T=io(p,S,D,t,u);if(!T.ok){r.push(T.error);return}const x=s.get(T.shardKey);x?x.rows.push({doc:p,table:S}):s.set(T.shardKey,{rows:[{doc:p,table:S}],shardKey:T.shardKey,startLine:u})};for(;;){const{done:g,value:b}=await f.read();if(g)break;if(b&&(O+=b.byteLength,O>Dt))throw await f.cancel().catch(()=>{}),new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413});E+=w.decode(b,{stream:!0});let _=E.indexOf(`
5
- `);for(;_!==-1;){const p=E.slice(0,_);E=E.slice(_+1),I(p),_=E.indexOf(`
6
- `)}}return E.length>0&&I(E),{errors:r,globalRows:a,perShard:s,received:l}},mt=(e,n)=>{for(const[t,r]of Object.entries(n.inserted))e.inserted[t]=(e.inserted[t]??0)+r;for(const t of n.errors)e.errors.push({...t});e.conflicts+=n.conflicts},uo=async(e,n,t,r)=>{const a=n.defaultShardKey??"__root__",{errors:s,globalRows:l,perShard:u,received:f}=await co(e,n,a),w={conflicts:0,errors:s,inserted:{}},E=[];if(n.resolveTableSharding===void 0&&u.size>0&&E.push("no `resolveTableSharding` is configured, so every row was routed to the default shard and no row could be recognised as `.global()` — correct for a single-shard app, silent misplacement for a sharded one"),u.size>0){const O=n.queryCoordinator;if(!O)throw new d("Import endpoint requires a `queryCoordinator` on the worker",{code:"BAD_REQUEST",status:400});const I=await O.orchestrateImport(r,{batches:[...u.values()],headers:t});mt(w,I)}if(l.length>0)if(n.importGlobals){const O=l[0]?.line??1,I=await n.importGlobals({rows:l,startLine:O});mt(w,I)}else for(const O of l)w.errors.push({code:"GLOBAL_NOT_CONFIGURED",line:O.line,message:`row targets global table "${O.table}" but no \`importGlobals\` is configured`,table:O.table});return{conflicts:w.conflicts,errors:w.errors,inserted:w.inserted,received:f,...E.length>0?{warnings:E}:{}}},je=e=>typeof e=="object"&&e!==null?e:{},Me=e=>typeof e.kind=="string"?e.kind:"unknown",lo=(e,n)=>{let t=je(n),r=!1;Me(t)==="optional"&&(r=!0,t=je(t._meta?.inner));const a=Me(t),s=t._meta??{},l={kind:a,name:e,optional:r};if(a==="id"&&typeof s.tableName=="string"&&(l.table=s.tableName),a==="array"){const u=Me(je(s.inner));u!=="unknown"&&(l.element=u)}return l},ho=e=>typeof e!="object"||e===null?[]:Object.entries(e).map(([n,t])=>lo(n,t)).toSorted((n,t)=>n.name.localeCompare(t.name)),fo="/_lunora/admin/functions",po="/_lunora/admin/cron-jobs",mo="/_lunora/admin/openapi",wo="/_lunora/admin/openrpc",go="/_lunora/admin/global/tables",yo="/_lunora/admin/global/table",bo="/_lunora/admin/global/facet",wt=e=>{if(e===void 0||e==="")return;let n;try{n=JSON.parse(e)}catch{return}if(!Array.isArray(n))return;const t=n.flatMap(r=>{if(typeof r!="object"||r===null||typeof r.column!="string")return[];const{column:a,value:s}=r;return[{column:a,value:s}]});return t.length===0?void 0:t},_o=Object.freeze({info:{description:'No OpenAPI spec is configured on this worker. Run `lunora codegen`, then wire the generated module to `createWorker`: `import { openApiSpec } from "./lunora/_generated/openapi"`.',title:"Lunora API",version:"0.0.0"},openapi:"3.1.0",paths:{}}),Ro=Object.freeze({info:{description:'No OpenRPC spec is configured on this worker. Run `lunora codegen --api-spec openrpc` (or `both`), then wire the generated module to `createWorker`: `import { openRpcSpec } from "./lunora/_generated/openrpc"`.',title:"Lunora RPC",version:"0.0.0"},methods:[],openrpc:"1.3.2"}),Eo=e=>{const{assertAdmin:n,options:t,parsePaging:r,queryParameter:a,requireAdminOption:s}=e,l=g=>{M(g,"GET","Functions");const b=s(g,t.functions,{code:"FUNCTIONS_NOT_CONFIGURED",message:"functions endpoint requires a `functions` registry on the worker"}),_=Object.entries(b).flatMap(([p,S])=>S.visibility==="internal"||S.kind==="stream"?[]:[{args:ho(S.args),kind:S.kind,path:p}]).toSorted((p,S)=>p.path.localeCompare(S.path));return Response.json({functions:_},{headers:{"content-type":"application/json"},status:200})},u=g=>{M(g,"GET","Cron-jobs");const b=s(g,t.cronJobs,{code:"CRON_JOBS_NOT_CONFIGURED",message:"cron-jobs endpoint requires a `cronJobs` map on the worker"}),_=Object.entries(b).flatMap(([p,S])=>S.map(D=>({args:D.args,cron:p,functionPath:D.functionPath,name:D.name,shardKey:D.shardKey,workflow:D.workflow}))).toSorted((p,S)=>p.name.localeCompare(S.name));return Response.json({jobs:_},{headers:{"content-type":"application/json"},status:200})},f=g=>(M(g,"GET","OpenAPI"),n(g),Response.json(t.openApiSpec??_o,{headers:{"content-type":"application/json"},status:200})),w=g=>(M(g,"GET","OpenRPC"),n(g),Response.json(t.openRpcSpec??Ro,{headers:{"content-type":"application/json"},status:200})),E=async g=>{M(g,"GET","Global-tables");const b=s(g,t.globalIntrospector,{code:"GLOBALS_NOT_CONFIGURED",message:"global endpoints require a `globalIntrospector` on the worker"});return Response.json(await b.listTables(),{headers:{"content-type":"application/json"},status:200})},O=async g=>{M(g,"GET","Global-table");const b=s(g,t.globalIntrospector,{code:"GLOBALS_NOT_CONFIGURED",message:"global endpoints require a `globalIntrospector` on the worker"}),_=new URL(g.url),p=a(_,"table");if(p===void 0)throw new d("Global-table endpoint requires a `table` query param",{code:"BAD_REQUEST",status:400});const S=await b.readTablePage({...r(g),filters:wt(a(_,"filters")),table:p});return Response.json(S,{headers:{"content-type":"application/json"},status:200})},I=async g=>{M(g,"GET","Global-facet");const b=s(g,t.globalIntrospector,{code:"GLOBALS_NOT_CONFIGURED",message:"global endpoints require a `globalIntrospector` on the worker"}),_=new URL(g.url),p=a(_,"table"),S=a(_,"column");if(p===void 0||S===void 0)throw new d("Global-facet endpoint requires `table` and `column` query params",{code:"BAD_REQUEST",status:400});const D=a(_,"limit"),T=D===void 0?void 0:Number(D),x=await b.facetColumn({column:S,filters:wt(a(_,"filters")),limit:T!==void 0&&Number.isFinite(T)?T:void 0,table:p});return Response.json(x,{headers:{"content-type":"application/json"},status:200})};return{[po]:u,[fo]:l,[bo]:I,[yo]:O,[go]:E,[mo]:f,[wo]:w}},Ao="/_lunora/admin/kv/namespaces",So="/_lunora/admin/kv/keys",Qt="/_lunora/admin/kv/value",zt=32*1048576,gt=60,To=e=>{const{readJsonBody:n,requireAdminOption:t}=e,r=b=>t(b,e.kvIntrospector,{code:"KV_NOT_CONFIGURED",message:"KV endpoints require a `kvIntrospector` on the worker"}),a=b=>Response.json(b,{headers:{"content-type":"application/json"},status:200}),s=(b,_)=>{const p=new URL(b.url),S=p.searchParams.get("namespace")??"",D=p.searchParams.get("key")??"";if(S==="")throw new d(`KV-value ${_} request requires a \`namespace\` query parameter`,{code:"BAD_REQUEST",status:400});if(D==="")throw new d(`KV-value ${_} request requires a \`key\` query parameter`,{code:"BAD_REQUEST",status:400});return{key:D,namespace:S}},l=async(b,_)=>{if(!(await b.listNamespaces()).some(S=>S.binding===_))throw new d(`Unknown KV namespace binding \`${_}\``,{code:"NOT_FOUND",status:404})},u=async b=>(M(b,"GET","KV-namespaces"),a({namespaces:await r(b).listNamespaces()})),f=async b=>{M(b,"GET","KV-keys");const _=r(b),p=new URL(b.url),S=p.searchParams.get("namespace")??"";if(S==="")throw new d("KV-keys request requires a `namespace` query parameter",{code:"BAD_REQUEST",status:400});const D=p.searchParams.get("prefix")??void 0,T=p.searchParams.get("cursor")??void 0,x=p.searchParams.get("limit"),H=x===null?void 0:Number.parseInt(x,10);if(H!==void 0&&(!Number.isInteger(H)||H<1))throw new d("KV-keys `limit` must be a positive integer",{code:"BAD_REQUEST",status:400});const $=H===void 0?void 0:Math.min(H,1e3);return await l(_,S),a(await _.listKeys({cursor:T,limit:$,namespace:S,prefix:D}))},I={DELETE:async b=>{const _=r(b),p=s(b,"DELETE");return await l(_,p.namespace),await _.deleteKey(p),a({deleted:!0})},GET:async b=>{const _=r(b),p=s(b,"GET");return await l(_,p.namespace),a(await _.getValue(p))},PUT:async b=>{const _=r(b),p=await n(b,zt);if(typeof p.namespace!="string"||p.namespace==="")throw new d("KV-value PUT request requires a `namespace` string",{code:"BAD_REQUEST",status:400});if(typeof p.key!="string"||p.key==="")throw new d("KV-value PUT request requires a `key` string",{code:"BAD_REQUEST",status:400});if(typeof p.value!="string")throw new d("KV-value PUT request requires a `value` string",{code:"BAD_REQUEST",status:400});if(p.expirationTtl!==void 0&&(typeof p.expirationTtl!="number"||!Number.isInteger(p.expirationTtl)||p.expirationTtl<gt))throw new d("KV-value PUT `expirationTtl` must be an integer ≥ 60",{code:"BAD_REQUEST",status:400});const S=Math.floor(Date.now()/1e3)+gt;if(p.expiration!==void 0&&(typeof p.expiration!="number"||!Number.isInteger(p.expiration)||p.expiration<S))throw new d("KV-value PUT `expiration` must be a Unix-seconds timestamp at least 60 seconds in the future",{code:"BAD_REQUEST",status:400});return await l(_,p.namespace),await _.putValue({expiration:p.expiration,expirationTtl:p.expirationTtl,key:p.key,metadata:p.metadata,namespace:p.namespace,value:p.value}),a({ok:!0})}},g=b=>{const _=I[b.method];if(!_)throw new d("KV-value endpoint requires GET, PUT, or DELETE",{code:"METHOD_NOT_ALLOWED",status:405});return _(b)};return{[Ao]:u,[So]:f,[Qt]:g}},Oo="/_lunora/migrate",vo="/_lunora/admin/pitr",ko="/_lunora/admin/rank",Io="/_lunora/admin/rankpage",Po="/_lunora/admin/shard-traffic",Do=new Set(["__lunora_admin__:migrationStatus","__lunora_admin__:runMigration"]),No=new Set(["__lunora_admin__:getPitrBookmark","__lunora_admin__:pitrRestore"]),Uo=async e=>{const t=await be(e,"Migration")??{};if(typeof t.table!="string"||t.table.length===0)throw new d("Migration request is missing `table`",{code:"BAD_REQUEST",status:400});if(typeof t.functionPath!="string"||!Do.has(t.functionPath))throw new d("Migration request `functionPath` must be a migration admin op",{code:"BAD_REQUEST",status:400});return{args:t.args??{},functionPath:t.functionPath,table:t.table}},Co=async e=>{const t=await be(e,"Rank")??{};if(typeof t.table!="string"||t.table.length===0)throw new d("Rank request is missing `table`",{code:"BAD_REQUEST",status:400});if(typeof t.index!="string"||t.index.length===0)throw new d("Rank request is missing `index`",{code:"BAD_REQUEST",status:400});if(typeof t.partitionKey!="string")throw new d("Rank request `partitionKey` must be a string",{code:"BAD_REQUEST",status:400});if(typeof t.rowId!="string"||t.rowId.length===0)throw new d("Rank request is missing `rowId`",{code:"BAD_REQUEST",status:400});if(!Array.isArray(t.sortValues))throw new d("Rank request `sortValues` must be an array",{code:"BAD_REQUEST",status:400});return{index:t.index,partitionKey:t.partitionKey,rowId:t.rowId,sortValues:t.sortValues,table:t.table}},Bo=e=>{if(e!==void 0){if(!Array.isArray(e)||e.some(n=>n!=="asc"&&n!=="desc"))throw new d('Rank page request `directions` must be an array of "asc"|"desc"',{code:"BAD_REQUEST",status:400});return e}},xo=e=>{if(typeof e.table!="string"||e.table.length===0)throw new d("Rank page request is missing `table`",{code:"BAD_REQUEST",status:400});if(typeof e.index!="string"||e.index.length===0)throw new d("Rank page request is missing `index`",{code:"BAD_REQUEST",status:400});if(e.partitionKey!==void 0&&typeof e.partitionKey!="string")throw new d("Rank page request `partitionKey` must be a string",{code:"BAD_REQUEST",status:400});if(e.take!==void 0&&(typeof e.take!="number"||!Number.isFinite(e.take)))throw new d("Rank page request `take` must be a number",{code:"BAD_REQUEST",status:400});if(e.cursor!==void 0&&e.cursor!==null&&typeof e.cursor!="string")throw new d("Rank page request `cursor` must be a string or null",{code:"BAD_REQUEST",status:400})},Ho=async e=>{const t=await be(e,"Rank page")??{};xo(t);const r=Bo(t.directions);return{cursor:typeof t.cursor=="string"?t.cursor:null,directions:r,index:t.index,partitionKey:typeof t.partitionKey=="string"?t.partitionKey:void 0,table:t.table,take:typeof t.take=="number"?t.take:void 0}},Lo=async e=>{const t=await be(e,"Shard-traffic")??{};if(typeof t.table!="string"||t.table.length===0)throw new d("Shard-traffic request is missing `table`",{code:"BAD_REQUEST",status:400});return{table:t.table}},jo=async e=>{const t=await Z(e);if(typeof t.functionPath!="string"||!No.has(t.functionPath))throw new d("PITR request `functionPath` must be a PITR admin op",{code:"BAD_REQUEST",status:400});if(t.shardKey!==void 0&&typeof t.shardKey!="string")throw new d("PITR `shardKey` must be a string",{code:"BAD_REQUEST",status:400});return{args:t.args??{},functionPath:t.functionPath,shardKey:t.shardKey}},Mo=e=>{const{defaultShard:n,forwardToShard:t,isAdmin:r,queryCoordinator:a,resolveForwardContext:s,shardDO:l}=e,u=(g,b)=>{if(g.method!=="POST")throw new d(`${b} endpoint requires POST`,{code:"METHOD_NOT_ALLOWED",status:405});if(!r(g))throw new d("Admin auth required",{code:"FORBIDDEN",status:403});if(!a)throw new d(`${b} endpoint requires a \`queryCoordinator\` on the worker`,{code:"BAD_REQUEST",status:400});return a},f=async(g,b)=>{const _=u(g,"Migration"),p=await Uo(g),{headers:S}=await s(g,b),D=await _.orchestrateMigration(l,{args:p.args,functionPath:p.functionPath,headers:S,table:p.table});return Response.json(D,{headers:{"content-type":"application/json"},status:200})},w=async(g,b)=>{const _=u(g,"Rank"),p=await Co(g),{headers:S}=await s(g,b),D=await _.orchestrateRank(l,{headers:S,index:p.index,partitionKey:p.partitionKey,rowId:p.rowId,sortValues:p.sortValues,table:p.table});return Response.json(D,{headers:{"content-type":"application/json"},status:200})},E=async(g,b)=>{const _=u(g,"Rank page"),p=await Ho(g),{headers:S}=await s(g,b),D=await _.orchestrateRankPage(l,{...p,headers:S});return Response.json(D,{headers:{"content-type":"application/json"},status:200})},O=async(g,b)=>{const _=u(g,"Shard-traffic"),p=await Lo(g),{headers:S}=await s(g,b),D=await _.orchestrateShardTraffic(l,{headers:S,table:p.table});return Response.json(D,{headers:{"content-type":"application/json"},status:200})},I=async(g,b)=>{if(M(g,"POST","PITR"),!r(g))throw new d("admin PITR endpoint requires a valid admin bearer",{code:"ADMIN_FORBIDDEN",status:403});const _=await jo(g),{headers:p}=await s(g,b),S=new Request("https://shard.internal/rpc",{body:JSON.stringify({args:_.args,functionPath:_.functionPath}),headers:p,method:"POST"});return t(l,_.shardKey??n,S)};return{[Oo]:f,[vo]:I,[ko]:w,[Io]:E,[Po]:O}},$o=1,Ko=0,Fo=32,Go=512,Qo=/^[a-z][\d_a-z*/-]{0,255}(?:@[a-z][\d_a-z*/-]{0,13})?=[\u0020-\u002B\u002D-\u003C\u003E-\u007E]{1,256}$/,zo=e=>{if(e==null)return;const n=e.trim();if(n.length===0||n.length>Go)return;const t=n.split(",");if(!(t.length>Fo)){for(const r of t)if(!Qo.test(r.trim()))return;return n}},Wo=e=>{const n=xn(e.headers.get("traceparent"));if(n===void 0)return;const t=zo(e.headers.get("tracestate"));return{parentSpanId:n.parentSpanId,sampled:n.sampled,traceId:n.traceId,...t===void 0?{}:{traceState:t}}},Vo=(e,n={})=>{const t=Wo(e),r=n.trustInbound===!0?t:void 0,a=Se(8),s=r?.traceId??Se(16),l=nr(n.sampling,r===void 0?a:s),u=l.isTraced&&(r===void 0||r.sampled);return{decision:l,ignoredUpstream:t!==void 0&&r===void 0,trace:{sampled:u,spanId:a,traceFlags:u?$o:Ko,traceId:s,...r?.parentSpanId===void 0?{}:{parentSpanId:r.parentSpanId},...r?.traceState===void 0?{}:{traceState:r.traceState}}}},qo=(e,n)=>{n.traceparent=Bn(e.traceId,e.spanId,e.sampled),e.traceState!==void 0&&(n.tracestate=e.traceState)},Jo=(e,n)=>{let t;return()=>{if(t===void 0){const r=Mn(e),a=n===void 0?void 0:n.cf;t=Hn(jn(r),Ln(r,a))}return t}},Yo="/_lunora/admin/scheduled",Xo="/_lunora/admin/scheduled/status",Zo="/_lunora/admin/scheduled/ws",ea="/_lunora/admin/scheduled/cancel",ta="/_lunora/admin/scheduled/dead",na="/_lunora/admin/scheduled/dead/retry",ra="/_lunora/admin/scheduled/dead/cancel",oa=e=>{const{checkWsAdmin:n,requireSchedulerNamespace:t,resolveSchedulerStub:r,schedulerInstanceName:a}=e,s=(f,w)=>E=>{if(E.method!=="GET")throw new d(`${w} endpoint requires GET`,{code:"METHOD_NOT_ALLOWED",status:405});return r(E).fetch(new Request(`https://scheduler.internal${f}`,{method:"GET"}))},l=(f,w,E=w)=>async O=>{if(O.method!=="POST")throw new d(`${E} requires POST`,{code:"METHOD_NOT_ALLOWED",status:405});const I=r(O),g=await O.json().catch(()=>{});if(typeof g?.id!="string"||g.id==="")throw new d(`${w} requires a string \`id\``,{code:"BAD_REQUEST",status:400});return I.fetch(new Request(`https://scheduler.internal${f}`,{body:JSON.stringify({id:g.id}),headers:{"content-type":"application/json"},method:"POST"}))},u=async f=>{if(f.headers.get("Upgrade")!=="websocket")throw new d("WebSocket upgrade header missing",{code:"BAD_REQUEST",status:426});if(!await n(f))throw new d("admin authorization required",{code:"ADMIN_FORBIDDEN",status:403});const w=t();return we(w,a).fetch(new Request("https://scheduler.internal/ws",{headers:{Upgrade:"websocket"}}))};return{[ea]:l("/cancel","Scheduled-cancel","Scheduled-cancel endpoint"),[ra]:l("/dead/cancel","Scheduled dead-letter action"),[ta]:s("/dead","Scheduled dead-letter"),[na]:l("/dead/retry","Scheduled dead-letter action"),[Yo]:s("/list","Scheduled-list"),[Xo]:s("/status","Scheduler-status"),[Zo]:u}},aa=(e,...n)=>{let t=e.cf;for(const r of n){if(typeof t!="object"||t===null)return;t=t[r]}return typeof t=="string"?t:void 0},yt={mtls:e=>aa(e,"tlsClientAuth","certVerified")==="SUCCESS"},sa=e=>e===void 0||e===!1?()=>!1:e===!0?()=>!0:typeof e=="function"?e:(Object.hasOwn(yt,e)?yt[e]:void 0)??(()=>!1),ia=e=>{if(e!==void 0)return()=>{};let n=!1;return()=>{n||(n=!0,console.warn('[lunora] Ignored an inbound `traceparent`, so this request starts a new trace instead of joining the caller\'s. That is the safe default: the header is caller-supplied, and trusting it lets any client choose which trace its spans and logs join. If this worker sits behind a gateway, service mesh, or Cloudflare Access that sets `traceparent` itself, set `trustInboundTraceContext: true` on createWorker() (or `"mtls"` to trust only edge-verified client certificates). Set it to `false` to keep this behaviour and silence this message.'))}},ca="/_lunora/admin/vector/indexes",da="/_lunora/admin/vector/query",ua=e=>{const{readJsonBody:n,requireAdminOption:t}=e,r=async s=>{M(s,"GET","Vector-indexes");const l=t(s,e.vectorIntrospector,{code:"VECTORS_NOT_CONFIGURED",message:"vector endpoints require a `vectorIntrospector` on the worker"});return Response.json({indexes:await l.listIndexes()},{headers:{"content-type":"application/json"},status:200})},a=async s=>{M(s,"POST","Vector-query");const l=t(s,e.vectorIntrospector,{code:"VECTORS_NOT_CONFIGURED",message:"vector endpoints require a `vectorIntrospector` on the worker"});if(l.queryIndex===void 0)throw new d("vector index querying is not enabled on this worker",{code:"VECTOR_QUERY_UNSUPPORTED",status:400});const f=await n(s);if(typeof f.name!="string"||f.name==="")throw new d("Vector-query request requires a `name` string",{code:"BAD_REQUEST",status:400});if(typeof f.text!="string"||f.text==="")throw new d("Vector-query request requires a `text` string",{code:"BAD_REQUEST",status:400});if(f.topK!==void 0&&(typeof f.topK!="number"||!Number.isInteger(f.topK)||f.topK<1))throw new d("Vector-query `topK` must be a positive integer",{code:"BAD_REQUEST",status:400});const w=await l.queryIndex({name:f.name,text:f.text,topK:f.topK});return Response.json(w,{headers:{"content-type":"application/json"},status:200})};return{[ca]:r,[da]:a}},la="/_lunora/admin/workflows/instances",ha="/_lunora/admin/workflows/instance",fa="/_lunora/admin/workflows/status",pa={complete:!0,errored:!0,paused:!0,queued:!0,running:!0,terminated:!0,unknown:!0,waiting:!0,waitingForPause:!0},ma=e=>e!==null&&Object.hasOwn(pa,e)?e:void 0,bt=(e,n)=>{const t=e.searchParams.get(n);if(t===null)return;const r=Number(t);return Number.isInteger(r)&&r>0?r:void 0},$e=(e,n)=>{const t=e.searchParams.get(n);if(t===null||t==="")throw new d(`Workflows admin endpoint requires a \`${n}\` query parameter`,{code:"BAD_REQUEST",status:400});return t},_t=()=>{throw new d("Workflow inspection is unconfigured. Set CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN in your .dev.vars to enable it.",{code:"WORKFLOWS_NOT_CONFIGURED",status:501})},wa=e=>{const{assertAdmin:n,resolveWorkflowsClient:t}=e,r=async(l,u,f)=>{M(l,"GET","Workflows instances"),n(l);const w=t(u);if(!w)return Response.json({configured:!1,instances:[],page:1,perPage:0,totalCount:0});const E=$e(f,"name"),O=ma(f.searchParams.get("status"));return Response.json(await w.listInstances({page:bt(f,"page"),perPage:bt(f,"perPage"),status:O,workflowName:E}))},a=async(l,u,f)=>{M(l,"GET","Workflows instance"),n(l);const w=t(u);return w?Response.json(await w.getInstance({instanceId:$e(f,"id"),workflowName:$e(f,"name")})):_t()},s=async(l,u)=>{M(l,"POST","Workflows status"),n(l);const f=t(u);if(!f)return _t();const w=await l.json().catch(()=>{});if(typeof w?.name!="string"||w.name===""||typeof w.id!="string"||w.id==="")throw new d("Workflows status action requires string `name` and `id`",{code:"BAD_REQUEST",status:400});const{action:E}=w;if(E!=="pause"&&E!=="resume"&&E!=="terminate")throw new d("Workflows status action must be one of: pause, resume, terminate",{code:"BAD_REQUEST",status:400});return Response.json(await f.setInstanceStatus({action:E,instanceId:w.id,workflowName:w.name}))};return{[ha]:a,[la]:r,[fa]:s}},ga={[Qt]:zt,[qn]:Vn},Rt="/_lunora/rpc",ya="/_lunora/rpc-batch",ba="/_lunora/ws",Re=(e,n,t)=>({resourceAttributes:Jo(e,n),...t===void 0?{}:{waitUntil:t}}),Et=e=>e?.waitUntil?{waitUntil:n=>e.waitUntil?.(n)}:{},At=e=>({spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId,...e.parentSpanId===void 0?{}:{parentSpanId:e.parentSpanId}}),Ke=e=>{const{method:n}=e,t=e.headers.get("user-agent")??void 0;let r;try{r=new URL(e.url)}catch{return{method:n,userAgent:t}}const a=r.port===""?void 0:Number(r.port);return{host:r.hostname,method:n,path:r.pathname,port:Number.isNaN(a)?void 0:a,scheme:r.protocol.replace(":",""),userAgent:t}},St="/_lunora/voice/",_a="/_lunora/scheduler/dispatch",Ra="/_lunora/admin/cron-jobs/run",Ea="/_lunora/admin/ws-token",Aa="/_lunora/admin/",Sa="/_lunora/migrate",Ta="/_lunora/status",Oa=e=>e.startsWith(Aa)||e===Sa,va=e=>{const n=e.headers.get("x-lunora-userid"),t=e.headers.get("x-lunora-identity");if(!(n===null&&t===null))return{...t===null?{}:{identity:t},...n===null?{}:{userId:n}}},ka="/api/auth",Ia="__lunora_admin__:recordAuthEvent",Pa="__lunora_admin__:listPushSubscriptions",Da=["/sign-in","/sign-up","/callback"],Na=(e,n)=>{const t=n.endsWith("/")?n.slice(0,-1):n;if(!e.startsWith(`${t}/`))return!1;const r=e.slice(t.length);return Da.some(a=>r===a||r.startsWith(`${a}/`))},Ee=(e,n,t,r)=>{const a=Pn(t),s=a?t.code:"INTERNAL_SERVER_ERROR",l=a?t.status:500,u=t instanceof Error?t.message:String(t);return{durationMs:n,error:{code:s,message:u,status:l},functionPath:e,ok:!1,...r.fanOut?{fanOut:{failed:0,shards:0,table:r.fanOut.table}}:{},...r.shardKey?{shardKey:r.shardKey}:{}}},Ua=e=>{const{exp:n,expiresAtMs:t}=e;if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof n=="number"&&Number.isFinite(n))return n*1e3},Tt=e=>e.waitUntil?{waitUntil:n=>{e.waitUntil?.(n)}}:void 0,Ca=e=>{const n=e?.queue;return typeof n=="string"&&n.length>0?n:"unknown"},de=async(e,n,t)=>{const r={"content-type":"application/json"},a=e.headers.get("authorization"),s=e.headers.get("cookie"),l=e.headers.get("x-d1-bookmark"),u=e.headers.get("x-lunora-mutation-id"),f=e.headers.get("x-lunora-client-id"),w=e.headers.get("x-lunora-client-seq");a&&(r.authorization=a),s&&(r.cookie=s),l&&(r["x-d1-bookmark"]=l),u&&(r["x-lunora-mutation-id"]=u),f&&(r["x-lunora-client-id"]=f),w&&(r["x-lunora-client-seq"]=w);const E=e.headers.get("cf-connecting-ip");if(E&&(r["x-lunora-client-ip"]=E),!t)return{claims:null,headers:r,identity:null,userId:null};const O=await t(e,n);if(!O||typeof O.userId!="string"||O.userId.length===0)return{claims:null,headers:r,identity:null,userId:null};r["x-lunora-userid"]=Un(O.userId);const I=Ua(O);I!==void 0&&(r["x-lunora-identity-exp"]=String(I));const{userId:g,...b}=O,_=Object.keys(b).length>0?b:null;return _&&(r["x-lunora-identity"]=Cn(_)),{claims:_,headers:r,identity:O,userId:g}},Ba=new Set(["concat","first","groupBy","max","min","rank","sum","topK"]),xa=e=>{if(e===void 0)return;if(!e||typeof e!="object")throw new d("RPC `fanOut` must be an object",{code:"BAD_REQUEST",status:400});const n=e;if(typeof n.table!="string"||n.table.length===0)throw new d("RPC `fanOut.table` must be a non-empty string",{code:"BAD_REQUEST",status:400});if(!n.merge||typeof n.merge!="object")throw new d("RPC `fanOut.merge` must be an object",{code:"BAD_REQUEST",status:400});const t=n.merge;if(typeof t.kind!="string"||!Ba.has(t.kind))throw new d("RPC `fanOut.merge.kind` is not a recognized merge strategy",{code:"BAD_REQUEST",status:400});if(t.kind==="topK"){if(typeof t.k!="number"||!Number.isInteger(t.k)||t.k<0)throw new d("RPC `fanOut.merge.k` must be a non-negative integer",{code:"BAD_REQUEST",status:400});if(typeof t.by!="string"||t.by.length===0)throw new d("RPC `fanOut.merge.by` must be a non-empty string",{code:"BAD_REQUEST",status:400})}return n},Ha=(e,n)=>{e?.LUNORA_DEBUG_RPC&&console.warn(`[lunora:rpc] ${n.fanOut?"fan-out":`shard=${n.shardKey??"(root)"}`} ${n.functionPath}`)},Ot=(e,n)=>{const t=n.functions?.[e.functionPath]?.x402;if(t){if(e.fanOut)throw new d("a paid (`.x402`) function cannot be fanned out",{code:"BAD_REQUEST",status:400});if(!n.x402Charge)throw new d(`function "${e.functionPath}" is marked paid (.x402) but no x402Charge gate is configured on the worker`,{code:"MISCONFIGURED",status:500});return t}},La=async e=>{const n=await Ut(e);let t;try{t=JSON.parse(n)}catch{throw new d("RPC body must be valid JSON",{code:"BAD_REQUEST",status:400})}if(!t||typeof t!="object"||typeof t.functionPath!="string")throw new d("RPC envelope is missing `functionPath`",{code:"BAD_REQUEST",status:400});const r=t;if(r.args!==void 0&&Nt(r.args,"RPC"),r.shardKey!==void 0&&typeof r.shardKey!="string")throw new d("RPC `shardKey` must be a string",{code:"BAD_REQUEST",status:400});const a=t,s=xa(a.fanOut),l=a.args??{};if(s&&a.functionPath.startsWith("__lunora_relation__:")){const u=l.table;if(typeof u=="string"&&u!==s.table)throw new d("RPC `args.table` must match the authorized `fanOut.table` for a relation fan-out",{code:"BAD_REQUEST",status:400});l.table=s.table}return{args:l,fanOut:s,functionPath:a.functionPath,shardKey:a.shardKey}},Ae=new Map,ja=5e3,Ma=4096,$a=async(e,n)=>{const t=Date.now(),r=Ae.get(n);if(r!==void 0&&r.expiresMs>t)return r.relayCount;r!==void 0&&Ae.delete(n);let a=0;try{const s=await we(e,n).fetch(new Request("https://shard.internal/_lunora/route"));if(s.ok){const u=(await s.json()).relayCount;typeof u=="number"&&u>0&&(a=Math.floor(u))}}catch{a=0}return Pt(Ae,Ma),Ae.set(n,{expiresMs:t+ja,relayCount:a}),a},vt=(e,n)=>{if(!(e===null||typeof e!="object"))return Object.entries(e).find(([,t])=>t===n)?.[0]},ye=(e,n,t)=>new Request("https://shard.internal/rpc",{body:JSON.stringify({args:n,functionPath:e}),headers:t,method:"POST"}),Ka=["x-lunora-userid","x-lunora-identity","x-lunora-identity-exp"],kt=(e,n)=>{for(const t of Ka){e.delete(t);const r=n[t];r!==void 0&&e.set(t,r)}},Fa=async(e,n,t)=>e.length===0||t.length===0?!1:Qe(await Ht(e,n),t),It=(e,n)=>{if(!n||n.length===0)return!1;const t=e.headers.get("authorization");if(!t)return!1;const[r,...a]=t.split(" ");return r?.toLowerCase()!=="bearer"?!1:Qe(n,a.join(" ").trim())},Ga=async(e,n,t)=>{if(!n||n.length===0)return!1;const r=new URL(e.url).searchParams.get("token");return r===null?!1:await Or(n,r)?!0:t?!1:Qe(n,r)},Qa=(e,n)=>{if(n===null||typeof n!="object"&&typeof n!="function")return;const t=n;if(typeof t.prepare=="function"&&typeof t.batch=="function"&&typeof t.dump=="function")return Zn(`d1:${e}`,n);if(typeof t.list=="function"&&typeof t.head=="function"&&typeof t.createMultipartUpload=="function")return Ce(`r2:${e}`,!0);if(typeof t.send=="function"&&typeof t.sendBatch=="function"&&typeof t.get!="function")return Ce(`queue:${e}`,!0);if(typeof t.connectionString=="string")return Ce(`hyperdrive:${e}`,!0)},Wt=e=>{const n=sa(e.trustInboundTraceContext),t=ia(e.trustInboundTraceContext),r=e.defaultShardKey??"__root__",a=er(e.resolveIdentity,e.identity),s=nt(e.shardDO,e.jurisdiction),l=e.schedulerDO===void 0?void 0:nt(e.schedulerDO,e.jurisdiction);let u=!1;const f=o=>{if(o===void 0||e.jurisdiction===void 0)return o;u||(u=!0,console.warn(`[lunora] jurisdiction "${e.jurisdiction}" pins placement, so region hints (\`shardRegion\`, replica and relay placement) are not sent. Residency wins.`))},w=async(o,i,h,c=e.shardRegion?.(i))=>we(o,i,f(c)).fetch(h);let E;const O=()=>e.adminToken??E;let I;const g=()=>e.requireEphemeralWsToken??I??!0;let b;const _=o=>{const i=o??{};if(b??=vt(o,e.shardDO),I===void 0&&e.requireEphemeralWsToken===void 0){const c=i.LUNORA_REQUIRE_EPHEMERAL_WS_TOKEN;typeof c=="string"&&c.length>0&&(I=Ar(c,!0))}if(E!==void 0||e.adminToken!==void 0)return;const h=i.LUNORA_ADMIN_TOKEN;typeof h=="string"&&h.length>0&&(E=h)},p=new WeakSet,S=o=>It(o,O())||p.has(o),D=async(o,i)=>{const h=await de(o,i,e.resolveIdentity);if(p.has(o)&&h.headers.authorization===void 0){const c=O();c!==void 0&&(h.headers.authorization=`Bearer ${c}`)}return h};let T=!1,x=!1;const H=()=>{x||(x=!0,console.warn("[lunora] `replicaReads: true` has no effect without `functions` — read eligibility is decided from the function registry."))},$=o=>{if(!e.allowUnauthenticatedShardAccess){const i=o==="fan-out"?"authorizeFanOut":"authorizeShard";throw new d(`${o} access is default-denied: configure \`${i}\` on the worker, or set \`allowUnauthenticatedShardAccess: true\` to explicitly allow unauthenticated ${o} access (relying solely on per-row RLS).`,{code:o==="fan-out"?"FORBIDDEN_FANOUT":"FORBIDDEN_SHARD",status:403})}T||(T=!0,console.warn([`[lunora] SECURITY: serving ${o} access with \`allowUnauthenticatedShardAccess: true\` and no \`authorizeShard\`/\`authorizeFanOut\` — `,"any caller (including unauthenticated ones) can target any shard / fan out across the table. ","This is safe only if every table is protected by per-row RLS. Configure `authorizeShard`/`authorizeFanOut` to gate it."].join("")))},U=async(o,i,h=!0)=>{if(e.authorizeShard){if(!await e.authorizeShard(o,i))throw new d("Forbidden shard",{code:"FORBIDDEN_SHARD",status:403})}else h&&i!==r&&$("shard")},W=Mo({defaultShard:r,forwardToShard:w,isAdmin:S,queryCoordinator:e.queryCoordinator,resolveForwardContext:D,shardDO:s}),K=async(o,i,h,c,m)=>{await U(null,h,!1);const R={"content-type":"application/json","x-lunora-system":"1"};return m?.userId!==void 0&&m.userId.length>0&&(R["x-lunora-userid"]=m.userId),m?.identity!==void 0&&m.identity.length>0&&(R["x-lunora-identity"]=m.identity),c!==void 0&&c.length>0&&(R["x-lunora-mutation-id"]=c),w(s,h,ye(o,i,R))},V=async(o,i,h,c)=>{const m=h?.[o];if(!m||typeof m.create!="function")throw new d(`${c} targets workflow binding "${o}", which is not bound on env`,{code:"CRON_JOB_FAILED",status:500});if(sr(i))throw new d(`${c} params ${ir}`,{code:"BAD_REQUEST",status:400});await m.create({params:i})},X=async(o,i)=>{if(o.workflow){await V(o.workflow,o.args??{},i,`cron job "${o.name}"`);return}if(o.functionPath===void 0)throw new d(`cron job "${o.name}" has neither a function target nor a workflow target`,{code:"CRON_JOB_FAILED",status:500});const h=await K(o.functionPath,o.args??{},o.shardKey??r);if(!h.ok)throw new d(`cron job "${o.name}" (${o.functionPath}) failed with shard status ${String(h.status)}`,{code:"CRON_JOB_FAILED",status:500})},q=async(o,i,h,c)=>{const m=e.cronJobs?.[o];if(m)for(const R of m)try{await X(R,i)}catch(k){h.push(c(k))}},ae=async(o,i)=>{if(!S(o))throw new d("admin endpoint requires a valid admin bearer",{code:"ADMIN_FORBIDDEN",status:403});if(M(o,"POST","cron-jobs run"),!e.cronJobs)throw new d("cron-jobs run endpoint requires a `cronJobs` map on the worker",{code:"CRON_JOBS_NOT_CONFIGURED",status:400});const h=await Z(o),c=typeof h.name=="string"?h.name:"";if(c==="")throw new d("cron-jobs run endpoint requires a job `name`",{code:"BAD_REQUEST",status:400});const m=Object.values(e.cronJobs).flat().find(R=>R.name===c);if(!m)throw new d(`no cron job named "${c}" is registered`,{code:"CRON_JOB_NOT_FOUND",status:404});return await X(m,i),Response.json({name:c,ran:!0},{status:200})},F=async o=>{const i=typeof o.pool=="string"&&o.pool.length>0?o.pool:void 0;if(!i||!l||typeof o.id!="string")return;const h=typeof o.instanceName=="string"&&o.instanceName.length>0?o.instanceName:"default";try{await we(l,h).fetch(new Request("https://scheduler.internal/complete",{body:JSON.stringify({id:o.id,pool:i}),headers:{"content-type":"application/json"},method:"POST"}))}catch{}},he=async(o,i)=>{M(o,"POST","Scheduler dispatch");const h=await Ut(o),c=i??{},m=typeof c.LUNORA_SCHEDULER_SECRET=="string"?c.LUNORA_SCHEDULER_SECRET:void 0,R=e.adminToken??(typeof c.LUNORA_ADMIN_TOKEN=="string"?c.LUNORA_ADMIN_TOKEN:void 0),k=o.headers.get("x-lunora-scheduler-signature");let y=!1;if(k&&m?y=await Fa(m,h,k):R&&(y=It(o,R)),!y)throw new d("Scheduler dispatch requires a valid signature or admin bearer",{code:"FORBIDDEN",status:403});let A;try{A=JSON.parse(h)}catch{throw new d("Scheduler dispatch body must be valid JSON",{code:"BAD_REQUEST",status:400})}const v=A??{},C=v.args??{};if(typeof v.workflow=="string"&&v.workflow.length>0)return await V(v.workflow,C,i,"scheduled workflow"),Response.json({ok:!0},{status:200});if(typeof v.functionPath!="string"||v.functionPath.length===0)throw new d("Scheduler dispatch is missing `functionPath`",{code:"BAD_REQUEST",status:400});const B=typeof v.shardKey=="string"&&v.shardKey.length>0?v.shardKey:r,L=typeof v.id=="string"&&v.id.length>0?v.id:void 0,te=va(o),j=await K(v.functionPath,C,B,L,te);return await F(v),j},G=o=>{if(!S(o))throw new d("admin endpoint requires a valid admin bearer",{code:"ADMIN_FORBIDDEN",status:403})},oe=(o,i,h)=>{if(G(o),i===void 0)throw new d(h.message,{code:h.code,status:400});return i},Te=Dr({assertAdmin:G,getReader:()=>e.authAuditReader}),Oe=async(o,i)=>{G(o);const h=e.notifySubscriptionStore;if(h===void 0)return Response.json({subscriptions:[]},{headers:{"content-type":"application/json"},status:200});const c=i?.kind,m=i?.userId,R=i?.limit,k=c==="fcm"||c==="web-push"?c:void 0,y=typeof m=="string"&&m!==""?m:void 0,A=typeof R=="number"&&Number.isFinite(R)?Math.trunc(R):0,v=A>0?Math.min(A,1e3):1e3,B=(await h.list({kind:k,limit:v,userId:y})).filter(L=>k!==void 0&&L.kind!==k?!1:y===void 0||(L.userId??null)===y).map(({keys:L,token:te,...j})=>j);return Response.json({subscriptions:B},{headers:{"content-type":"application/json"},status:200})},se=async(o,i)=>{if(!i.fanOut){if(i.functionPath===Pr)return Te(o,i.args??{});if(i.functionPath===Pa)return Oe(o,i.args)}},Vt=ao({applyGlobals:e.applyGlobals,assertAdmin:G,exportCursorStore:e.exportCursorStore,exportSinks:e.exportSinks,knownTables:()=>[],queryCoordinator:e.queryCoordinator,requireAdminOption:oe,resolveForwardContext:D,shardDO:s,streamExportRows:(o,i,h,c)=>Kt(e,o,i,h,c,s),streamingImport:(o,i)=>uo(o,e,i,s),syncGlobals:e.syncGlobals}),ve=(o,i)=>{const h=o.searchParams.get(i);return h===null||h===""?void 0:h},ke=o=>{const i=new URL(o.url),h=i.searchParams.get("limit"),c=i.searchParams.get("offset"),m=h===null?void 0:Number.parseInt(h,10),R=c===null?void 0:Number.parseInt(c,10);return{limit:m!==void 0&&Number.isFinite(m)&&m>=0?m:void 0,offset:R!==void 0&&Number.isFinite(R)&&R>=0?R:void 0}},Ve=()=>{if(l===void 0)throw new d("scheduled endpoints require a `schedulerDO` namespace on the worker",{code:"SCHEDULER_NOT_CONFIGURED",status:400});return l},qt=oa({checkWsAdmin:async o=>S(o)||Ga(o,O(),g()),requireSchedulerNamespace:Ve,resolveSchedulerStub:o=>(G(o),we(Ve(),e.schedulerInstanceName??"default")),schedulerInstanceName:e.schedulerInstanceName??"default"}),Jt=wa({assertAdmin:G,resolveWorkflowsClient:e.workflowsClient??(()=>{})}),Yt=Wn({assertAdmin:G,parsePaging:ke,queryParameter:ve,readBodyBytes:Kn,requireAdminOption:oe,storage:{storageBuckets:e.storageBuckets,storageDelete:e.storageDelete,storageDownload:e.storageDownload,storageList:e.storageList,storageSignedUrl:e.storageSignedUrl,storageUpload:e.storageUpload}}),Xt=Gr({options:e,readJsonBody:Z,requireAdminOption:oe}),Zt=ua({readJsonBody:Z,requireAdminOption:oe,vectorIntrospector:e.vectorIntrospector}),en=To({kvIntrospector:e.kvIntrospector,readJsonBody:Z,requireAdminOption:oe}),tn=tr({logArchive:e.logArchive,readJsonBody:Z,requireAdminOption:oe}),nn=Eo({assertAdmin:G,options:{cronJobs:e.cronJobs,functions:e.functions,globalIntrospector:e.globalIntrospector,openApiSpec:e.openApiSpec,openRpcSpec:e.openRpcSpec},parsePaging:ke,queryParameter:ve,requireAdminOption:oe}),rn=o=>{const i=[],h=s??o?.SHARD;if(h!==void 0&&i.push(Xn("durable-object:default",h,r)),e.health?.disableBindingProbes!==!0)for(const[c,m]of Object.entries(o??{})){const R=Qa(c,m);R!==void 0&&i.push(R)}for(const c of e.health?.probes??[])i.push(c);return i},on=Yn({appName:e.health?.appName,appVersion:e.health?.appVersion,auth:e.health?.auth??"public",cacheTtlMs:e.health?.cacheTtlMs,isAdmin:S,resolveProbes:rn}),an=o=>{const i=e.schedulerInstanceName??"default",h=()=>we(o,i),c=async(y,A)=>{const v=await h().fetch(new Request(`https://scheduler.internal${y}`,A));if(!v.ok)throw new d(`ctx.scheduler: SchedulerDO ${y} failed (${String(v.status)}): ${await v.text()}`,{code:"INTERNAL",status:500});return await v.json()},m=async(y,A)=>await c(y,{body:JSON.stringify(A),headers:{"content-type":"application/json"},method:"POST"}),R=y=>{const A=y;if(A==null)throw new d("ctx.scheduler: target is required — pass a reference from the generated `internal` / `workflows` / `agents`",{code:"BAD_REQUEST",status:400});if(typeof A.binding=="string"&&A.binding.length>0)return{workflow:A.binding};if(typeof A.__lunoraRef=="string")return{functionPath:A.__lunoraRef};throw new d("ctx.scheduler: expected a reference from the generated `internal` / `workflows` / `agents` — a bare function-path string is refused here, because an HTTP action can be reached unauthenticated",{code:"BAD_REQUEST",status:400})},k=async(y,A,v={})=>{const{id:C}=await m("/schedule",{args:v,scheduledFor:y,...R(A)});return C};return{cancel:async y=>await m("/cancel",{id:y}),get:async y=>await c(`/get?id=${encodeURIComponent(y)}`,{method:"GET"}),list:async()=>await c("/list",{method:"GET"}),runAfter:async(y,A,v)=>{if(!Number.isFinite(y)||y<0)throw new d("ctx.scheduler.runAfter: `delayMs` must be a non-negative finite number",{code:"BAD_REQUEST",status:400});return await k(Date.now()+y,A,v)},runAt:async(y,A,v)=>{if(!Number.isFinite(y))throw new d("ctx.scheduler.runAt: `timestampMs` must be a finite epoch-millisecond number",{code:"BAD_REQUEST",status:400});return await k(y,A,v)}}},sn=async(o,i,h)=>{const{claims:c,headers:m,userId:R}=await de(o,i,a),k=async(y,A={})=>{const v=y.__lunoraRef;if(typeof v!="string")throw new d("ctx.run*: expected a function reference from the generated `api`",{code:"BAD_REQUEST",status:400});const C=ye(v,A,{...m,"x-lunora-system":"1"}),B=await w(s,r,C),L=await B.json();if(L.error)throw new d(L.error.message??"shard RPC failed",{code:L.error.code??"INTERNAL",status:B.status});return L.result};return{auth:{getIdentity:()=>Promise.resolve(c),userId:R},cache:h.cache,fetch:globalThis.fetch.bind(globalThis),runAction:k,runMutation:k,runQuery:k,...l===void 0?{}:{scheduler:an(l)},...e.storage===void 0?{}:{storage:ar(e.storage(i))}}},cn=async(o,i,h)=>{if(!e.httpRouter)return;const c=await sn(o,i,h);try{return await e.httpRouter.fetch(o,{...i,__lunoraCtx:c},h)}catch(m){return console.error("[lunora] httpRouter (SSR) handler threw:",m),new Response("Internal Server Error",{status:500})}},dn=async(o,i,h)=>{if(o.headers.get("Upgrade")!=="websocket")throw new d("WebSocket upgrade header missing",{code:"BAD_REQUEST",status:426});const c=ot(o,ie);if(c)return c;const m=h.searchParams.get("shard")??r,{headers:R,identity:k}=await de(o,i,a);await U(k,m);const y=new Headers(o.headers),A=[...y.keys()];for(const C of A)C.startsWith("x-lunora-")&&y.delete(C);kt(y,R);const v=vt(i,e.shardDO);if(v!==void 0){y.set("x-lunora-shard-binding",v);const C=await $a(s,m);if(C>0){const B=yr(m,Math.floor(Math.random()*C));return w(s,B,new Request(o,{headers:y}),at(o))}}return w(s,m,new Request(o,{headers:y}))},un=async(o,i,h)=>{const{voiceAgents:c}=e;if(c===void 0)return new Response("Not found",{status:404});if(o.headers.get("Upgrade")!=="websocket")return new Response("Expected a WebSocket upgrade",{headers:{allow:"GET"},status:426});const m=ot(o,ie);if(m)return m;let R;try{R=decodeURIComponent(h.pathname.slice(St.length))}catch{return new Response("Unknown voice agent",{status:404})}const k=Object.hasOwn(c,R)?c[R]:void 0;if(k===void 0)return new Response("Unknown voice agent",{status:404});const y=h.searchParams.get("threadKey");if(y===null||y.length===0)return new Response("Missing threadKey",{status:400});const{headers:A,identity:v}=await de(o,i,a);if(e.authorizeShard){if(!await e.authorizeShard(v,y))return new Response("Forbidden",{status:403})}else $("shard");const C=new Headers(o.headers);for(const B of C.keys())B.startsWith("x-lunora-")&&C.delete(B);return kt(C,A),w(k,y,new Request(o,{headers:C}))},ln=async(o,i,h)=>{if(e.authorizeFanOut){if(!await e.authorizeFanOut(h,o.table,i))throw new d("Forbidden fan-out",{code:"FORBIDDEN_FANOUT",status:403});return}if(i.startsWith("__lunora_relation__:"))throw new d("reverse cross-backend relation reads (`__lunora_relation__:*`) require `authorizeFanOut` to be configured on the worker",{code:"FORBIDDEN_FANOUT",status:403});if(e.authorizeShard)throw new d("Fan-out requires `authorizeFanOut` to be configured on the worker when `authorizeShard` is set",{code:"FORBIDDEN_FANOUT",status:403});$("fan-out")},_e=async(o,i)=>{if(!(!o.fanOut&&o.functionPath.startsWith("__lunora_admin__:"))){if(o.fanOut){await ln(o.fanOut,o.functionPath,i);return}await U(i,o.shardKey??r)}},hn=(o,i,h)=>{if(e.replicaReads!==!0)return;if(e.functions===void 0){H();return}if(e.functions[i]?.kind!=="query"||h.includes(jt)||h.includes(Lt))return;const c=at(o);return c===void 0?void 0:{name:br(h,c),region:c}},fn=async(o,i,h,c,m)=>{const R=hn(o,i,c);if(R!==void 0){const k={...m,"x-lunora-replica-read":"1",...b===void 0?{}:{"x-lunora-shard-binding":b}},y=_r(o.headers.get("x-lunora-min-seq"));y!==void 0&&(k["x-lunora-min-seq"]=String(y));const A=await w(s,R.name,ye(i,h,k),R.region);if(A.status!==421)return A}return w(s,c,ye(i,h,m))},Ie=async(o,i,h,c,m,R)=>{const k=Date.now(),{observability:y,sampling:A}=e,v=Ke(o),{decision:C,ignoredUpstream:B,trace:L}=Vo(o,{...A===void 0?{}:{sampling:A},trustInbound:n(o)});B&&t();const te={...m,"x-lunora-sample-errors":C.keepErrors?"1":"0"};qo(L,te);try{const j=await fn(o,i,h,c,te);ce(y,{...v,...At(L),durationMs:Date.now()-k,functionPath:i,ok:j.ok,shardKey:c,...j.ok?{}:{error:{code:"SHARD_ERROR",message:`shard returned ${String(j.status)}`,status:j.status}}},R,void 0,{isTraced:L.sampled,keepErrors:C.keepErrors});const ee=new Response(j.body,{headers:j.headers,status:j.status,statusText:j.statusText});return ee.headers.set("x-lunora-shard-key",c),ee}catch(j){throw ce(y,{...v,...At(L),...Ee(i,Date.now()-k,j,{shardKey:c})},R,void 0,{isTraced:L.sampled,keepErrors:C.keepErrors}),j}},pn=o=>{if(o.fanOut&&o.shardKey)throw new d("RPC envelope cannot set both `shardKey` and `fanOut`",{code:"BAD_REQUEST",status:400});if(!o.fanOut&&o.functionPath.startsWith("__lunora_relation__:"))throw new d("`__lunora_relation__:*` is a fan-out-only reserved RPC and cannot be dispatched to a single shard",{code:"FORBIDDEN",status:403});if(o.fanOut&&!e.queryCoordinator)throw new d("RPC envelope set `fanOut` but no `queryCoordinator` is configured on the worker",{code:"BAD_REQUEST",status:400})},mn=async(o,i,h)=>{M(o,"POST","RPC");const c=await La(o);Ha(i,c),pn(c);const m=await se(o,c);if(m!==void 0)return m;const{headers:R,identity:k}=await de(o,i,a);await _e(c,k);const y=Ot(c,e);{const A=Date.now(),{observability:v}=e,C=Ke(o),B=Re(i,o,h&&(j=>h.waitUntil?.(j)));if(c.fanOut){const j=e.queryCoordinator;if(!j)throw new d("RPC envelope set `fanOut` but no `queryCoordinator` is configured on the worker",{code:"BAD_REQUEST",status:400});try{const ee=await j.fanOut(s,{args:c.args??{},fanOut:c.fanOut,functionPath:c.functionPath,headers:R});return ce(v,{durationMs:Date.now()-A,fanOut:{failed:ee.failed,shards:ee.ok+ee.failed,table:c.fanOut.table},functionPath:c.functionPath,...C,ok:!0},B),Response.json(ee,{headers:{"content-type":"application/json"},status:200})}catch(ee){throw ce(v,{...Ee(c.functionPath,Date.now()-A,ee,{fanOut:{table:c.fanOut.table}}),...C},B),ee}}const L=c.shardKey??r,te=()=>Ie(o,c.functionPath,c.args??{},L,R,B);return y&&e.x402Charge?e.x402Charge(o,{functionPath:c.functionPath,price:y.price},te,Et(h)):te()}},wn=async(o,i,h)=>{M(o,"POST","RPC batch");const c=await Z(o),{calls:m}=c;if(!Array.isArray(m))throw new d("RPC batch `calls` must be an array",{code:"BAD_REQUEST",status:400});const{headers:R,identity:k}=await de(o,i,a),y=zr(m,r);for(const Q of y.values())for(const z of Q)if(e.functions?.[z.functionPath]?.x402)throw new d(`paid (\`.x402\`) function "${z.functionPath}" cannot be called in a batch; dispatch it individually over ${Rt}`,{code:"BAD_REQUEST",status:400});await Promise.all([...y.entries()].flatMap(([Q,z])=>z.map(ne=>_e({args:ne.args,functionPath:ne.functionPath,shardKey:Q},k))));const{observability:A}=e,v=Re(i,o,h&&(Q=>h.waitUntil?.(Q))),C=Ke(o),B=[],L=[],te=(Q,z,ne,ue)=>({body:{error:{code:ne,message:ue}},id:Q.id,status:z}),j=(Q,z,ne,ue,fe)=>{for(const J of Q)ce(A,fe(J),v),B.push(te(J,z,ne,ue))},ee=(Q,z,ne,ue,fe)=>{for(const J of Q){const pe=ue.get(J.id)??fe,ge=pe<400;ce(A,{durationMs:ne,functionPath:J.functionPath,...C,ok:ge,shardKey:z,...ge?{}:{error:{code:"SHARD_ERROR",message:`batched call returned ${String(pe)}`,status:pe}}},v)}};await Promise.all([...y.entries()].map(async([Q,z])=>{const ne=new Headers(R);ne.set("content-type","application/json");const ue=new Request("https://shard.internal/rpc-batch",{body:JSON.stringify({calls:z}),headers:ne,method:"POST"}),fe=Date.now();let J;try{J=await w(s,Q,ue)}catch(Y){const Ue=Date.now()-fe,{body:Ze}=Dn(Y,{fallbackCode:"SHARD_UNAVAILABLE",redactedMessage:"shard unavailable"});j(z,502,Ze.code,Ze.message,In=>({...Ee(In.functionPath,Ue,Y,{shardKey:Q}),...C}));return}const pe=Date.now()-fe,ge=J.headers.get("x-d1-bookmark");ge&&L.push(ge);let De;try{De=await J.json()}catch{const Y=`shard batch returned a non-JSON response (${String(J.status)})`;j(z,J.status,"SHARD_ERROR",Y,Ue=>({durationMs:pe,error:{code:"SHARD_ERROR",message:Y,status:J.status},functionPath:Ue.functionPath,...C,ok:!1,shardKey:Q}));return}const Ne=Array.isArray(De.results)?De.results:[],vn=new Map(Ne.map(Y=>[Y.id,Y.status??J.status])),kn=new Set(Ne.map(Y=>Y.id));ee(z,Q,pe,vn,J.status),B.push(...Ne);for(const Y of z)kn.has(Y.id)||B.push(te(Y,J.status,"SHARD_ERROR",`shard batch omitted result for call ${String(Y.id)}`))}));const Ye={"content-type":"application/json"},[Xe]=L;return L.length===1&&Xe!==void 0&&(Ye["x-d1-bookmark"]=Xe),Response.json({results:B},{headers:Ye,status:200})},gn=async(o,i,h,c={},m={})=>{try{const R=h.__lunoraRef;if(typeof R!="string")throw new d("serverQuery: expected a function reference from the generated `api`",{code:"BAD_REQUEST",status:400});const{headers:k,identity:y}=await de(o,i,a);await _e({args:c,functionPath:R,shardKey:m.shardKey},y);const A=m.shardKey??r,v=Re(i,o,m.waitUntil);return await Ie(o,R,c,A,k,v)}catch(R){return et(R)}},qe=async(o,i,h)=>{const{observability:c}=e,m=Date.now(),R=Se(16),k=Se(8),y=Tt(i);try{const A=await h();return ce(c,{durationMs:Date.now()-m,functionPath:o,ok:!0,spanId:k,traceId:R},y),A}catch(A){throw ce(c,{...Ee(o,Date.now()-m,A,{}),spanId:k,traceId:R},y),A}finally{tt(c,y)}},yn=async(o,i,h)=>{_(i);const c=[],m=y=>y instanceof Error?y:new Error(String(y)),R=e.crons?.[o.cron];if(R)try{await R(o,i,h)}catch(y){c.push(m(y))}if(await q(o.cron,i,c,m),e.backupStore&&e.backupCron!==void 0&&e.backupCron===o.cron)try{await Mr(e,s,O(),o)}catch(y){c.push(m(y))}const[k]=c;if(c.length===1&&k)throw k;if(c.length>1)throw new AggregateError(c,`scheduled("${o.cron}") had ${String(c.length)} failure(s)`)},bn=async(o,i)=>{try{const h=o??{},c=e.adminToken??(typeof h.LUNORA_ADMIN_TOKEN=="string"?h.LUNORA_ADMIN_TOKEN:void 0);if(!c||c.length===0)return;await w(s,r,ye(Ia,{outcome:i},{authorization:`Bearer ${c}`,"content-type":"application/json"}))}catch{}},_n=async(o,i,h,c)=>{if(!e.authHandler)return;const m=await e.authHandler(o);if(!m)return;const R=e.authBasePath??ka;return Na(h.pathname,R)&&c.waitUntil?.(bn(i,m.status>=400?"fail":"ok")),m},Rn=async({args:o,env:i,functionPath:h,request:c,shardKey:m,waitUntil:R})=>{Nt(o,"REST");const k={functionPath:h,...m===void 0?{}:{shardKey:m}},{headers:y,identity:A}=await de(c,i,a);await _e(k,A);const v=m??r,C=Re(i,c,R),B=()=>Ie(c,h,o,v,y,C),L=Ot(k,e);return L&&e.x402Charge?e.x402Charge(c,{functionPath:h,price:L.price},B,Et({waitUntil:R})):B()},En=$n({functions:e.functions??{},invoke:Rn,readJsonBody:Z,...e.restRateLimit?{rateLimit:e.restRateLimit}:{}}),Pe=e.routes!==void 0&&Object.keys(e.routes).length>0?e.routes:void 0,An={[Ta]:o=>o.method!=="GET"&&o.method!=="HEAD"?new Response(void 0,{headers:{allow:"GET, HEAD"},status:405}):Response.json({ok:!0},{headers:{"cache-control":"no-store"}}),[ba]:(o,i,h)=>dn(o,i,h),[Rt]:(o,i,h,c)=>mn(o,i,c),[ya]:(o,i,h,c)=>wn(o,i,c),[_a]:(o,i)=>he(o,i),[Ra]:(o,i)=>ae(o,i),[Ea]:async o=>{M(o,"POST","ws-token"),G(o);const i=O();if(i===void 0)throw new d("ws-token minting requires a configured admin token",{code:"ADMIN_TOKEN_NOT_CONFIGURED",status:400});const h=await Tr(i);return Response.json(h,{headers:{"cache-control":"no-store"}})},...W,...Vt,...qt,...Jt,...Yt,...Xt,...Zt,...en,...tn,...nn,...on,...En,...Ir({assertAdmin:G,getAuthAdmin:()=>e.authAdmin,parsePaging:ke,queryParameter:ve,readJsonBody:Z})};let ie=rt(e.security),Je=!1;const Sn=o=>{Je||(Je=!0,ie=rt(e.security,o??{}))},Tn=async(o,i)=>{if(!(e.adminGate===void 0||!Oa(i)))try{await e.adminGate(o)&&p.add(o)}catch{}},On=async(o,i,h)=>{const c=new URL(o.url);if(o.method==="POST"||o.method==="PUT"){const y=Number(o.headers.get("content-length")??""),A=ga[c.pathname]??Dt;if(Number.isFinite(y)&&y>A)throw new d("Body too large",{code:"PAYLOAD_TOO_LARGE",status:413})}const m=await _n(o,i,c,h);if(m)return m;if(Pe){const y=`${o.method} ${c.pathname}`,A=Pe[y]??Pe[c.pathname];if(A)return A(o,i,h)}const R=An[c.pathname];if(R)return await Tn(o,c.pathname),R(o,i,c,h);if(e.voiceAgents!==void 0&&c.pathname.startsWith(St))return un(o,i,c);const k=await cn(o,i,h);return k||new Response("Not found",{status:404})};return{async fetch(o,i,h){e.passThroughOnException&&h.passThroughOnException?.(),Sn(i),_(i);const c=rr(o,ie);if(c)return c;const m=or(o,ie);if(m)return Be(m,o,ie);try{const R=await On(o,i,h);return Be(R,o,ie)}catch(R){return Be(et(R),o,ie)}finally{tt(e.observability,Tt(h))}},async queue(o,i,h){await qe(`queue:${Ca(o)}`,h,async()=>{await e.queue?.(o,i,h)})},async scheduled(o,i,h){await qe(`cron:${o.cron}`,h,async()=>{await yn(o,i,h)})},serverQuery:gn}},za=e=>Wt(e),Wa=e=>typeof e=="function"?{fetch:e}:e,Va=e=>!!(e.crons??e.cronJobs??e.backupCron),ps=(e,n)=>{const t=Wa(e),r=typeof e=="object"&&typeof e.scheduled=="function"?e.scheduled:void 0,a=l=>{const u=za({...l,httpRouter:t});return r!==void 0&&!Va(l)?{...u,scheduled:async(f,w,E)=>{await r(f,w,E)}}:u};if(typeof n!="function")return a(n);const s=n;return{fetch:(l,u,f)=>a(s(u)).fetch(l,u,f),queue:(l,u,f)=>a(s(u)).queue?.(l,u,f)??Promise.resolve(),scheduled:(l,u,f)=>a(s(u)).scheduled(l,u,f),serverQuery:(l,u,f,w,E)=>a(s(u)).serverQuery(l,u,f,w,E)}},qa=(e,n)=>{if(typeof e=="function")return e(n);const t=e.shardDO??n?.SHARD;if(!t)throw new d("@lunora/runtime: no shard Durable Object namespace found. Bind `SHARD` in wrangler.jsonc, or pass `createLunoraHandler({ shardDO: env.MY_SHARD })`.");return{...e,shardDO:t}},ms=(e={})=>(n,t,r)=>Wt(qa(e,t)).fetch(n,t,r??Nn),ws=e=>e;export{Pr as GET_AUTH_AUDIT_LOG_OP,Nn as NOOP_EXECUTION_CONTEXT,bs as composeIdentityResolvers,za as composeWorker,ms as createLunoraHandler,Wt as createWorker,ws as defineRpcEnvelope,$a as probeRelayCount,qa as resolveLunoraOptions,_s as routeIdentityResolvers,ps as withFrameworkWorker};
@@ -1 +0,0 @@
1
- import{e as m}from"./evict-oldest-BNXsKx4s.mjs";const g=n=>{const e=new WeakMap;return(t,a)=>{const i=e.get(t);if(i)return i;const c=Promise.resolve(n(t,a));return e.set(t,c),c}},v=5e3,f=500,p=n=>{const e=n.headers.get("cookie")??"",t=n.headers.get("authorization")??"";if(!(e===""&&t===""))return`${t}\0${e}`},E=(n,e={})=>{const t=e.ttlMs??v,a=Math.max(1,e.maxEntries??f),i=e.cacheKey??p,c=g(n),o=new Map;return(d,u)=>{const r=i(d);if(r===void 0)return c(d,u);const h=Date.now(),l=o.get(r);if(l&&l.expiresAt>h)return l.value;const s=Promise.resolve(c(d,u));return s.catch(()=>{o.get(r)?.value===s&&o.delete(r)}),o.delete(r),m(o,a),o.set(r,{expiresAt:h+t,value:s}),s}};export{E as memoizeIdentity,g as memoizeIdentityPerRequest};
@@ -1 +0,0 @@
1
- const f="/_lunora/rest",v=["authorization","cf-access-jwt-assertion","cookie"],i=["x-d1-bookmark","x-lunora-shard-key"],u=e=>[...v,...(e.credentialHeaders??[]).map(t=>t.toLowerCase())],d=e=>Number.isFinite(e)?Math.max(0,Math.floor(e)):0,c=(...e)=>{const t=[];for(const a of e)for(const n of a?.split(",")??[]){const r=n.trim().toLowerCase();r!==""&&!t.includes(r)&&t.push(r)}return t.length===0?void 0:t.join(", ")},m=(e,t)=>{const a=[t,`max-age=${String(d(e.maxAge))}`];return e.staleWhileRevalidate!==void 0&&a.push(`stale-while-revalidate=${String(d(e.staleWhileRevalidate))}`),a.join(", ")},l=e=>e.scope==="public"?c(e.vary,...u(e),...i):c(e.vary,...i),h=e=>{const t=e.indexOf(":");if(!(t<=0||t>=e.length-1||e.indexOf(":",t+1)!==-1))return{name:e.slice(t+1),namespace:e.slice(0,t)}},p=e=>{const t=h(e);if(t!==void 0)return`${f}/${t.namespace}/${t.name}`},g=e=>e==="query"?"GET":"POST",R=e=>{const t=[];for(const a of e){if(a.exposure?.rest!==!0||a.kind==="stream")continue;const n=h(a.functionPath),r=p(a.functionPath);n===void 0||r===void 0||t.push({functionPath:a.functionPath,kind:a.kind,method:g(a.kind),name:n.name,namespace:n.namespace,path:r})}return t.sort((a,n)=>a.path.localeCompare(n.path)),t},E=(e,t)=>u(t).some(a=>e.headers.has(a)),C=(e,t,a)=>{if(t.method!=="GET"||a<200||a>299)return;const n=e.scope==="public"&&!E(t,e)?"public":"private",r={"cache-control":m(e,n)};e.tag!==void 0&&e.tag!==""&&(r["cache-tag"]=e.tag);const s=l(e);return s!==void 0&&(r.vary=s),r},S=(e,t,a)=>{if(t===void 0)return e;const n=C(t,a,e.status);if(n===void 0)return e;const r=new Response(e.body,e);for(const[s,o]of Object.entries(n))r.headers.set(s,s==="vary"?c(r.headers.get("vary")??void 0,o)??o:o);return r};export{S as a,C as b,R as d,E as r};