@lunora/server 1.0.0-alpha.80 → 1.0.0-alpha.82

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
@@ -1,7 +1,7 @@
1
1
  import { Validator, Infer, ValidatorMap, InferValidatorMap, ColumnValidator, v } from '@lunora/values';
2
2
  export { type ColumnValidator, type GeoPoint, type Id, type Infer, ValidationError, type Validator, type ValidatorKind, v } from '@lunora/values';
3
3
  import { ArgsValidator, InferArgs, RegisteredAction, ExposeConfig, X402ProcedureConfig, ActionCtx, MutationCtx, RegisteredMutation, QueryCtx, RegisteredQuery, DurableStreamOptions, RegisteredStream, FunctionKind, Secrets, LifecycleEvent, ShardInitEvent, RegisteredLifecycleHook, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, DurableObjectJurisdiction, RelationDefinition, GlobalBackend, OnDeleteAction, SearchLanguage, SearchStrategy, ExternalSourceDefinition, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, AggregateIndexDefinition, RankIndexDefinition } from "./types.mjs";
4
- export { type AnyApi, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type GeoBoundingBox, type GeoFilterBuilder, type GeoIndexDefinition, type GeoPointInput, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, type LunoraWideEvent, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type RestCacheConfig, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type SpanEvaluation, type SpanHandle, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type TtlDefinition, type VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.mjs";
4
+ export { type AnyApi, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type GeoBoundingBox, type GeoFilterBuilder, type GeoIndexDefinition, type GeoPointInput, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, type LunoraWideEvent, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type RestCacheConfig, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type SpanEvaluation, type SpanHandle, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type StorageObjectHead, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type TtlDefinition, type VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.mjs";
5
5
  import { LunoraError as LunoraError$1, LunoraErrorCode } from '@lunora/errors';
6
6
  export type { LunoraErrorCode } from '@lunora/errors';
7
7
  import { Context, Hono } from 'hono';
@@ -796,8 +796,22 @@ interface StorageRange {
796
796
  length: number;
797
797
  offset: number;
798
798
  }
799
- /** The minimal storage surface {@link serveStorageObject} needs: a metadata-rich `download`. */
800
- interface StorageDownloader {
799
+ /**
800
+ * The minimal storage surface {@link serveStorageObject} needs: a metadata-rich
801
+ * `download`, plus the body-free `head` a range request resolves against.
802
+ *
803
+ * `head` is required rather than optional-with-a-fallback because the fallback
804
+ * is the bug: without it a ranged request has to start a full-object `download`
805
+ * just to learn the size, then throw that body away. `@lunora/storage`'s `head`
806
+ * already degrades internally to a 0-length ranged `get()` on a binding with no
807
+ * HEAD, so there is nothing a caller here could usefully do that it does not.
808
+ */
809
+ interface StorageHead {
810
+ /** Object metadata with no body. `size` is the FULL object size (mirrors R2). */
811
+ head: (key: string) => Promise<Omit<StorageObjectBody, "body"> | null>;
812
+ }
813
+ /** The storage surface {@link serveStorageObject} reads through. */
814
+ interface StorageDownloader extends StorageHead {
801
815
  download: (key: string, options?: {
802
816
  range?: StorageRange;
803
817
  }) => Promise<StorageObjectBody | null>;
@@ -823,12 +837,14 @@ declare const isSafeHeaderValue: (value: string) => boolean;
823
837
  * **404**; an out-of-bounds range is a **416** with a `Content-Range` of
824
838
  * `bytes` star-slash-size.
825
839
  *
826
- * A range request re-issues the `download()` with the resolved `{ offset, length }`
827
- * window so R2 streams only those bytes back to the Worker the slice is never
828
- * buffered in the isolate. The first `download()` is used only for the object's
829
- * size + metadata (its body is left unread and cancelled). For very large
830
- * objects a signed URL (`ctx.storage.getSignedUrl`) is still cheaper since the
831
- * client then ranges against R2/CDN directly with no Worker hop.
840
+ * A range request resolves its window against a body-free `head()`, then issues
841
+ * ONE `download()` with the resolved `{ offset, length }` so R2 streams just
842
+ * those bytes the slice is never buffered in the isolate, and no full-object
843
+ * body transfer is started only to be cancelled. A request that cannot produce a
844
+ * 206 at all (no `Range`, multi-range, malformed) skips the `head()` entirely and
845
+ * streams straight from a single `download()`. For very
846
+ * large objects a signed URL (`ctx.storage.getSignedUrl`) is still cheaper since
847
+ * the client then ranges against R2/CDN directly with no Worker hop.
832
848
  */
833
849
  declare const serveStorageObject: (context: ContextWithStorage, key: string, request: Request) => Promise<Response>;
834
850
  /**
@@ -2363,6 +2379,20 @@ interface DefinePresenceOptions {
2363
2379
  * AnyCable `presence_ttl` behaviour). Clamped to `ttlMs`.
2364
2380
  */
2365
2381
  disconnectGraceMs?: number;
2382
+ /**
2383
+ * Upper bound on SESSION ROWS `listPresent` reads per call — one row per
2384
+ * `(roomId, sessionId)`, so one per open tab, NOT one per person. The read
2385
+ * is newest-first over the `(roomId, lastSeen)` index, so the rows kept are
2386
+ * always the freshest heartbeats and a room with more sessions than this
2387
+ * has its stalest ones truncated.
2388
+ *
2389
+ * Because the multi-tab dedup collapses rows only AFTER the read, a cap
2390
+ * below the room's live session count drops real, currently-heartbeating
2391
+ * members off the bottom of the list. Size it against expected tabs (a
2392
+ * 300-person room at two tabs each is 600 rows), not expected people.
2393
+ * Defaults to 1024. A non-finite value falls back to the default.
2394
+ */
2395
+ maxSessions?: number;
2366
2396
  /**
2367
2397
  * How long (ms) a heartbeat keeps a member present. `listPresent` excludes
2368
2398
  * rows whose `lastSeen` is older than `now - ttlMs`. Defaults to 30s.
@@ -2405,8 +2435,10 @@ interface PresenceFunctions {
2405
2435
  }, PresenceMember[]>;
2406
2436
  /**
2407
2437
  * Internal mutation that hard-deletes every expired row for `roomId`. Stale
2408
- * rows already vanish from `listPresent` via the read-time TTL filter; this
2409
- * only reclaims storage. Schedule it (cron / `runAfter`) if you care.
2438
+ * rows already vanish from `listPresent` via the read-time TTL filter, and
2439
+ * active rooms self-clean via the heartbeat's opportunistic reap; this is
2440
+ * optional hardening for bulk cleanup of rooms that went quiet with stale
2441
+ * rows left behind (schedule it on a cron / `runAfter` if you care).
2410
2442
  */
2411
2443
  sweep: RegisteredMutation<{
2412
2444
  roomId: ReturnType<typeof v.string>;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Validator, Infer, ValidatorMap, InferValidatorMap, ColumnValidator, v } from '@lunora/values';
2
2
  export { type ColumnValidator, type GeoPoint, type Id, type Infer, ValidationError, type Validator, type ValidatorKind, v } from '@lunora/values';
3
3
  import { ArgsValidator, InferArgs, RegisteredAction, ExposeConfig, X402ProcedureConfig, ActionCtx, MutationCtx, RegisteredMutation, QueryCtx, RegisteredQuery, DurableStreamOptions, RegisteredStream, FunctionKind, Secrets, LifecycleEvent, ShardInitEvent, RegisteredLifecycleHook, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, DurableObjectJurisdiction, RelationDefinition, GlobalBackend, OnDeleteAction, SearchLanguage, SearchStrategy, ExternalSourceDefinition, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, AggregateIndexDefinition, RankIndexDefinition } from "./types.js";
4
- export { type AnyApi, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type GeoBoundingBox, type GeoFilterBuilder, type GeoIndexDefinition, type GeoPointInput, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, type LunoraWideEvent, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type RestCacheConfig, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type SpanEvaluation, type SpanHandle, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type TtlDefinition, type VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.js";
4
+ export { type AnyApi, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type GeoBoundingBox, type GeoFilterBuilder, type GeoIndexDefinition, type GeoPointInput, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, type LunoraWideEvent, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type RestCacheConfig, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type SpanEvaluation, type SpanHandle, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type StorageObjectHead, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type TtlDefinition, type VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.js";
5
5
  import { LunoraError as LunoraError$1, LunoraErrorCode } from '@lunora/errors';
6
6
  export type { LunoraErrorCode } from '@lunora/errors';
7
7
  import { Context, Hono } from 'hono';
@@ -796,8 +796,22 @@ interface StorageRange {
796
796
  length: number;
797
797
  offset: number;
798
798
  }
799
- /** The minimal storage surface {@link serveStorageObject} needs: a metadata-rich `download`. */
800
- interface StorageDownloader {
799
+ /**
800
+ * The minimal storage surface {@link serveStorageObject} needs: a metadata-rich
801
+ * `download`, plus the body-free `head` a range request resolves against.
802
+ *
803
+ * `head` is required rather than optional-with-a-fallback because the fallback
804
+ * is the bug: without it a ranged request has to start a full-object `download`
805
+ * just to learn the size, then throw that body away. `@lunora/storage`'s `head`
806
+ * already degrades internally to a 0-length ranged `get()` on a binding with no
807
+ * HEAD, so there is nothing a caller here could usefully do that it does not.
808
+ */
809
+ interface StorageHead {
810
+ /** Object metadata with no body. `size` is the FULL object size (mirrors R2). */
811
+ head: (key: string) => Promise<Omit<StorageObjectBody, "body"> | null>;
812
+ }
813
+ /** The storage surface {@link serveStorageObject} reads through. */
814
+ interface StorageDownloader extends StorageHead {
801
815
  download: (key: string, options?: {
802
816
  range?: StorageRange;
803
817
  }) => Promise<StorageObjectBody | null>;
@@ -823,12 +837,14 @@ declare const isSafeHeaderValue: (value: string) => boolean;
823
837
  * **404**; an out-of-bounds range is a **416** with a `Content-Range` of
824
838
  * `bytes` star-slash-size.
825
839
  *
826
- * A range request re-issues the `download()` with the resolved `{ offset, length }`
827
- * window so R2 streams only those bytes back to the Worker the slice is never
828
- * buffered in the isolate. The first `download()` is used only for the object's
829
- * size + metadata (its body is left unread and cancelled). For very large
830
- * objects a signed URL (`ctx.storage.getSignedUrl`) is still cheaper since the
831
- * client then ranges against R2/CDN directly with no Worker hop.
840
+ * A range request resolves its window against a body-free `head()`, then issues
841
+ * ONE `download()` with the resolved `{ offset, length }` so R2 streams just
842
+ * those bytes the slice is never buffered in the isolate, and no full-object
843
+ * body transfer is started only to be cancelled. A request that cannot produce a
844
+ * 206 at all (no `Range`, multi-range, malformed) skips the `head()` entirely and
845
+ * streams straight from a single `download()`. For very
846
+ * large objects a signed URL (`ctx.storage.getSignedUrl`) is still cheaper since
847
+ * the client then ranges against R2/CDN directly with no Worker hop.
832
848
  */
833
849
  declare const serveStorageObject: (context: ContextWithStorage, key: string, request: Request) => Promise<Response>;
834
850
  /**
@@ -2363,6 +2379,20 @@ interface DefinePresenceOptions {
2363
2379
  * AnyCable `presence_ttl` behaviour). Clamped to `ttlMs`.
2364
2380
  */
2365
2381
  disconnectGraceMs?: number;
2382
+ /**
2383
+ * Upper bound on SESSION ROWS `listPresent` reads per call — one row per
2384
+ * `(roomId, sessionId)`, so one per open tab, NOT one per person. The read
2385
+ * is newest-first over the `(roomId, lastSeen)` index, so the rows kept are
2386
+ * always the freshest heartbeats and a room with more sessions than this
2387
+ * has its stalest ones truncated.
2388
+ *
2389
+ * Because the multi-tab dedup collapses rows only AFTER the read, a cap
2390
+ * below the room's live session count drops real, currently-heartbeating
2391
+ * members off the bottom of the list. Size it against expected tabs (a
2392
+ * 300-person room at two tabs each is 600 rows), not expected people.
2393
+ * Defaults to 1024. A non-finite value falls back to the default.
2394
+ */
2395
+ maxSessions?: number;
2366
2396
  /**
2367
2397
  * How long (ms) a heartbeat keeps a member present. `listPresent` excludes
2368
2398
  * rows whose `lastSeen` is older than `now - ttlMs`. Defaults to 30s.
@@ -2405,8 +2435,10 @@ interface PresenceFunctions {
2405
2435
  }, PresenceMember[]>;
2406
2436
  /**
2407
2437
  * Internal mutation that hard-deletes every expired row for `roomId`. Stale
2408
- * rows already vanish from `listPresent` via the read-time TTL filter; this
2409
- * only reclaims storage. Schedule it (cron / `runAfter`) if you care.
2438
+ * rows already vanish from `listPresent` via the read-time TTL filter, and
2439
+ * active rooms self-clean via the heartbeat's opportunistic reap; this is
2440
+ * optional hardening for bulk cleanup of rooms that went quiet with stale
2441
+ * rows left behind (schedule it on a cron / `runAfter` if you care).
2410
2442
  */
2411
2443
  sweep: RegisteredMutation<{
2412
2444
  roomId: ReturnType<typeof v.string>;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{initLunora as t}from"./packem_shared/initLunora-CRypyq1P.mjs";import{createSecrets as i}from"./packem_shared/createSecrets-CyrEddTF.mjs";import{LunoraEnvError as f,defineEnv as s,redactSecrets as m}from"./packem_shared/LunoraEnvError-CjFbbR9t.mjs";import{LunoraError as p}from"./packem_shared/LunoraError-DcKdk9Ti.mjs";import{bindOrm as c,bindTableFacade as l}from"./packem_shared/bindOrm-lWdeDi9P.mjs";import{httpAction as E,httpRoute as g,httpRouter as S,isSafeHeaderValue as R,serveStorageObject as h}from"./packem_shared/httpAction-Ddi7f0t6.mjs";import{defineIdentity as I}from"./packem_shared/defineIdentity-DwkNKwYa.mjs";import{onConnect as b,onDisconnect as A,onShardInit as T}from"./packem_shared/onConnect-BLRoOpv2.mjs";import{DEFAULT_LIMIT as M,DEFAULT_MAX_LIMIT as _,clampLimit as D,defineListArgs as F}from"./packem_shared/DEFAULT_LIMIT-B947Pbij.mjs";import{defineMigration as C}from"./packem_shared/defineMigration-7GI9Qbtd.mjs";import{defineMutator as V}from"./packem_shared/defineMutator-DKy8UtbB.mjs";import{c as O,d as U,a as j,b as w,e as B,f as W,g as H,h as J,i as Q,j as X,k as q,m as z}from"./packem_shared/plugin-DQcLxTx1.mjs";import{PRESENCE_DEFAULT_TTL_MS as K,PRESENCE_TABLE as Y,definePresence as Z,presenceExtension as $}from"./packem_shared/PRESENCE_DEFAULT_TTL_MS-C-McIltl.mjs";import{protectPublic as re}from"./packem_shared/protectPublic-Bo4G9xaV.mjs";import{onQueryChange as te}from"./packem_shared/onQueryChange-gepYD6KC.mjs";import{defineShape as ie}from"./packem_shared/defineShape-DYxbNl5W.mjs";import{anyApi as fe}from"./types.mjs";import{cronJobs as me}from"@lunora/scheduler";import{ValidationError as pe,v as xe}from"@lunora/values";import{allowAll as le,deny as ue,isDeny as Ee,toWhereInput as ge}from"./packem_shared/allowAll-DkRAgItV.mjs";import{asBucketStorage as Re}from"./packem_shared/asBucketStorage-BthCnWop.mjs";import{buildMaskRegistry as Le}from"./packem_shared/buildMaskRegistry-72SL8fJn.mjs";import{buildRlsReadRegistry as Pe,composeShapeReadWhere as be}from"./packem_shared/buildRlsReadRegistry-Deq8inqS.mjs";import{createPolicyDsl as Te,definePermission as ye,definePolicies as Me,definePolicy as _e,defineRole as De}from"./packem_shared/createPolicyDsl-DNfByAUX.mjs";import{defineStorageRule as ke,defineStorageRules as Ce}from"./packem_shared/defineStorageRule-BvxHVq3b.mjs";import{mask as Ve}from"./packem_shared/mask-CfHNITgg.mjs";import{r as Oe}from"./packem_shared/middleware-DEW0yLvU.mjs";import{storageRules as je}from"./packem_shared/storageRules-CTnby6M1.mjs";const e="0.0.0";export{M as DEFAULT_LIMIT,_ as DEFAULT_MAX_LIMIT,f as LunoraEnvError,p as LunoraError,K as PRESENCE_DEFAULT_TTL_MS,Y as PRESENCE_TABLE,e as VERSION,pe as ValidationError,le as allowAll,fe as anyApi,Re as asBucketStorage,c as bindOrm,l as bindTableFacade,Le as buildMaskRegistry,Pe as buildRlsReadRegistry,D as clampLimit,O as composePluginMiddleware,be as composeShapeReadWhere,Te as createPolicyDsl,i as createSecrets,me as cronJobs,U as defineAggregateIndex,j as defineComponent,s as defineEnv,I as defineIdentity,F as defineListArgs,C as defineMigration,V as defineMutator,ye as definePermission,w as definePlugin,Me as definePolicies,_e as definePolicy,Z as definePresence,B as defineRankIndex,De as defineRole,W as defineSchema,H as defineSchemaExtension,ie as defineShape,ke as defineStorageRule,Ce as defineStorageRules,J as defineTable,Q as defineVectorIndex,ue as deny,E as httpAction,g as httpRoute,S as httpRouter,X as indexFieldsFromSchema,t as initLunora,q as installPlugins,Ee as isDeny,R as isSafeHeaderValue,Ve as mask,z as mergeSchemaExtension,b as onConnect,A as onDisconnect,te as onQueryChange,T as onShardInit,$ as presenceExtension,re as protectPublic,m as redactSecrets,Oe as rls,h as serveStorageObject,je as storageRules,ge as toWhereInput,xe as v};
1
+ import{initLunora as t}from"./packem_shared/initLunora-B2sfmFJ6.mjs";import{createSecrets as i}from"./packem_shared/createSecrets-CyrEddTF.mjs";import{LunoraEnvError as f,defineEnv as s,redactSecrets as m}from"./packem_shared/LunoraEnvError-ByvihJFy.mjs";import{LunoraError as p}from"./packem_shared/LunoraError-DcKdk9Ti.mjs";import{bindOrm as c,bindTableFacade as l}from"./packem_shared/bindOrm-lWdeDi9P.mjs";import{httpAction as E,httpRoute as g,httpRouter as S,isSafeHeaderValue as R,serveStorageObject as h}from"./packem_shared/httpAction-D3b9-YiY.mjs";import{defineIdentity as I}from"./packem_shared/defineIdentity-DwkNKwYa.mjs";import{onConnect as b,onDisconnect as A,onShardInit as T}from"./packem_shared/onConnect-BLRoOpv2.mjs";import{DEFAULT_LIMIT as M,DEFAULT_MAX_LIMIT as _,clampLimit as D,defineListArgs as F}from"./packem_shared/DEFAULT_LIMIT-DC-M6faS.mjs";import{defineMigration as C}from"./packem_shared/defineMigration-7GI9Qbtd.mjs";import{defineMutator as V}from"./packem_shared/defineMutator-DKy8UtbB.mjs";import{c as O,d as U,a as j,b as w,e as B,f as W,g as H,h as J,i as Q,j as X,k as q,m as z}from"./packem_shared/plugin-DQcLxTx1.mjs";import{PRESENCE_DEFAULT_TTL_MS as K,PRESENCE_TABLE as Y,definePresence as Z,presenceExtension as $}from"./packem_shared/PRESENCE_DEFAULT_TTL_MS-BpSPSCwL.mjs";import{protectPublic as re}from"./packem_shared/protectPublic-Bo4G9xaV.mjs";import{onQueryChange as te}from"./packem_shared/onQueryChange-DDxYz2CF.mjs";import{defineShape as ie}from"./packem_shared/defineShape-DYxbNl5W.mjs";import{anyApi as fe}from"./types.mjs";import{cronJobs as me}from"@lunora/scheduler";import{ValidationError as pe,v as xe}from"@lunora/values";import{allowAll as le,deny as ue,isDeny as Ee,toWhereInput as ge}from"./packem_shared/allowAll-DkRAgItV.mjs";import{asBucketStorage as Re}from"./packem_shared/asBucketStorage-BthCnWop.mjs";import{buildMaskRegistry as Le}from"./packem_shared/buildMaskRegistry-72SL8fJn.mjs";import{buildRlsReadRegistry as Pe,composeShapeReadWhere as be}from"./packem_shared/buildRlsReadRegistry-Deq8inqS.mjs";import{createPolicyDsl as Te,definePermission as ye,definePolicies as Me,definePolicy as _e,defineRole as De}from"./packem_shared/createPolicyDsl-DNfByAUX.mjs";import{defineStorageRule as ke,defineStorageRules as Ce}from"./packem_shared/defineStorageRule-BvxHVq3b.mjs";import{mask as Ve}from"./packem_shared/mask-Da7q82ZC.mjs";import{r as Oe}from"./packem_shared/middleware-DEW0yLvU.mjs";import{storageRules as je}from"./packem_shared/storageRules-CyaiZ0av.mjs";const e="0.0.0";export{M as DEFAULT_LIMIT,_ as DEFAULT_MAX_LIMIT,f as LunoraEnvError,p as LunoraError,K as PRESENCE_DEFAULT_TTL_MS,Y as PRESENCE_TABLE,e as VERSION,pe as ValidationError,le as allowAll,fe as anyApi,Re as asBucketStorage,c as bindOrm,l as bindTableFacade,Le as buildMaskRegistry,Pe as buildRlsReadRegistry,D as clampLimit,O as composePluginMiddleware,be as composeShapeReadWhere,Te as createPolicyDsl,i as createSecrets,me as cronJobs,U as defineAggregateIndex,j as defineComponent,s as defineEnv,I as defineIdentity,F as defineListArgs,C as defineMigration,V as defineMutator,ye as definePermission,w as definePlugin,Me as definePolicies,_e as definePolicy,Z as definePresence,B as defineRankIndex,De as defineRole,W as defineSchema,H as defineSchemaExtension,ie as defineShape,ke as defineStorageRule,Ce as defineStorageRules,J as defineTable,Q as defineVectorIndex,ue as deny,E as httpAction,g as httpRoute,S as httpRouter,X as indexFieldsFromSchema,t as initLunora,q as installPlugins,Ee as isDeny,R as isSafeHeaderValue,Ve as mask,z as mergeSchemaExtension,b as onConnect,A as onDisconnect,te as onQueryChange,T as onShardInit,$ as presenceExtension,re as protectPublic,m as redactSecrets,Oe as rls,h as serveStorageObject,je as storageRules,ge as toWhereInput,xe as v};
@@ -0,0 +1 @@
1
+ import{v as o,optionalInner as b}from"@lunora/values";const g=25,A=100,O=100,S=8,w=new Set(["id","storage","string"]),p=t=>{const n=b(t)??t;if(w.has(n.kind))return!0;const r=n._meta;if(n.kind==="literal")return typeof r?.value=="string";if(n.kind!=="union"||r?.members===void 0)return!1;const{members:s}=r;return s.some(e=>p(e))&&s.every(e=>e.kind==="null"||p(e))},L=(t,n)=>{const r=s=>o.optional(o.array(s).check(e=>e.length<=n,{message:`at most ${String(n)} values`}));return o.object({...p(t)?{contains:o.optional(o.string())}:{},eq:o.optional(t),gt:o.optional(t),gte:o.optional(t),in:r(t),isNull:o.optional(o.boolean()),lt:o.optional(t),lte:o.optional(t),ne:o.optional(t),notIn:r(t)})},_=(t,n,r)=>t===void 0||!Number.isFinite(t)?Math.min(n,r):Math.min(Math.max(1,Math.floor(t)),r),u=(t,n)=>t===void 0||!Number.isFinite(t)?n:Math.max(1,Math.floor(t)),I=new Set(["contains","eq","gt","gte","in","isNull","lt","lte","ne","notIn"]),M=(t,n,r)=>{if(typeof t!="object"||t===null||Array.isArray(t))return;const s=t,e={};let l=0;for(const a of I){if(!Object.hasOwn(s,a)||(l+=1,a==="contains"&&!r))continue;const c=s[a];e[a]=Array.isArray(c)?c.slice(0,n):c}return l===0?void 0:e},B=(t,n,r,s)=>{const e={};for(const l of n){if(!Object.hasOwn(t,l))continue;const a=t[l],c=M(a,s,r.has(l));c!==void 0&&Object.keys(c).length===0||(e[l]=c??a)}return e},T=()=>t=>{const n=u(t.defaultLimit,g),r=u(t.maxLimit,A),s=u(t.maxInValues,O),e=u(t.maxOrderBy,S),l=new Set(Object.keys(t.filter)),a=new Set,c={};for(const[i,d]of Object.entries(t.filter))p(d)&&a.add(i),c[i]=o.optional(o.union(d,L(d,s)));const h=new Set(t.orderBy),y=t.orderBy.length===0?o.string().check(()=>!1,{message:"no sortable columns are declared for this endpoint"}):o.union(...t.orderBy.map(i=>o.literal(i)));return{args:{cursor:o.optional(o.union(o.string(),o.number(),o.null())),limit:o.optional(o.number()),orderBy:o.optional(o.array(o.object({direction:o.optional(o.union(o.literal("asc"),o.literal("desc"))),field:y}))),where:o.optional(o.object(c))},toQueryArgs:i=>{const d=i.orderBy?.filter(m=>h.has(m.field)).slice(0,e).map(m=>({[m.field]:m.direction??"asc"})),f=i.where===void 0?void 0:B(i.where,l,a,s);return{...i.cursor===void 0?{}:{cursor:typeof i.cursor=="number"?String(i.cursor):i.cursor},limit:_(i.limit,n,r),...d===void 0||d.length===0?{}:{orderBy:d},...f===void 0?{}:{where:f}}}}};export{g as DEFAULT_LIMIT,O as DEFAULT_MAX_IN_VALUES,A as DEFAULT_MAX_LIMIT,S as DEFAULT_MAX_ORDER_BY,_ as clampLimit,T as defineListArgs,u as normalizeBound,B as sanitizeWhere};
@@ -0,0 +1,3 @@
1
+ import{LunoraError as A}from"@lunora/errors";import{optionalInner as h}from"@lunora/values";const b=/(?:key|password|secret|token)$/iu,d=t=>b.test(t),w=[/^sk_/u,/^pk_/u,/^rk_/u,/^ghp_/u,/^gho_/u,/^ghs_/u,/^ghr_/u,/^github_pat_/u,/^xox[baprs]-/u,/^AKIA/u,/^AIza/u,/^Bearer\s/u],L=/[\w./+-]{24,}/gu,p=/^[\w./+-]+$/u,I=/\b(?:(?:sk|pk|rk|ghp|gho|ghs|ghr)_[\w./+-]*|github_pat_[\w./+-]*|xox[baprs]-[\w./+-]*)/gu,N=/\b(?:AKIA|AIza)[\w./+-]+|Bearer\s+[\w./+-]+/gu,v=/\b([a-z][\w.+-]*:\/\/[\w.%+-]+):[\w.%+-]+@/gu,a="[redacted]",D=t=>{if(w.some(n=>n.test(t)))return!0;const e=t.trim();return e.length>=24&&p.test(e)},S=/(["'])(?<inner>(?:\\.|(?!\1).)*)\1/gu,y=/\b(?<key>[A-Za-z_]\w*)\s*[=:]\s*\S+/gu,T=t=>{let e=t;return e=e.replaceAll(S,(n,...r)=>{const s=r.at(-1);return s?.inner!==void 0&&D(s.inner)?a:n}),e=e.replaceAll(v,(n,r)=>`${r}:${a}@`),e=e.replaceAll(I,a),e=e.replaceAll(N,a),e=e.replaceAll(y,(n,...r)=>{const s=r.at(-1);return s?.key!==void 0&&d(s.key)?`${s.key}=${a}`:n}),e=e.replaceAll(L,a),e},R=(t,e,n)=>{const r=T(t);return typeof n=="string"&&n!==""&&d(e)?r.replaceAll(n,a):r};class g extends A{failures;constructor(e){const n=e.map(r=>` - ${r.key}: ${r.message}`).join(`
2
+ `);super("ENV_INVALID",`Invalid environment (${String(e.length)} key(s)):
3
+ ${n}`,{name:"LunoraEnvError"}),this.failures=e}}const $=new Set(["1","on","true","yes"]),K=new Set(["0","false","no","off"]),O=/^-?\d+$/u,k=t=>{if(t.kind!=="optional")return t.kind;const e=h(t);return e?k(e):t.kind},U=(t,e)=>{if(typeof e!="string")return e;switch(k(t)){case"bigint":return O.test(e.trim())?BigInt(e.trim()):e;case"boolean":{const n=e.trim().toLowerCase();return $.has(n)?!0:K.has(n)?!1:e}case"number":{const n=e.trim();if(n==="")return e;const r=Number(n);return Number.isNaN(r)?e:r}default:return e}},_=(t,e,n,r)=>{const s=n[t];if(s===void 0&&e.kind==="optional")return{ok:!0,value:void 0};const c=e.safeParse(U(e,s));return c.ok?{ok:!0,value:c.value}:(r.push({key:t,message:R(c.error.message,t,s)}),{ok:!1})},m=t=>{if(typeof t!="object"||t===null)throw new g([{key:"<env>",message:`expected an object, received ${t===null?"null":typeof t}`}]);return t},F=t=>{const e=Object.keys(t),n=new WeakMap,r=(s=>{const c=m(s);let i=n.get(c);i===void 0&&(i=new Map,n.set(c,i));const l=i,E=u=>{if(l.has(u))return l.get(u);const o=[],f=_(u,t[u],c,o);if(!f.ok)throw new g(o);return l.set(u,f.value),f.value};return new Proxy({},{get(u,o){if(!(typeof o!="string"||!(o in t)))return E(o)},getOwnPropertyDescriptor(u,o){if(typeof o=="string"&&o in t)return{configurable:!0,enumerable:!0,value:E(o),writable:!1}},has(u,o){return typeof o=="string"&&o in t},ownKeys(){return e}})});return r.parse=s=>{const c=m(s),i=[],l={};for(const E of e){const u=_(E,t[E],c,i);u.ok&&u.value!==void 0&&(l[E]=u.value)}if(i.length>0)throw new g(i);return l},r};export{g as LunoraEnvError,F as defineEnv,T as redactSecrets};
@@ -0,0 +1 @@
1
+ import{v as t}from"@lunora/values";import{initLunora as M}from"./initLunora-B2sfmFJ6.mjs";import{LunoraError as b}from"./LunoraError-DcKdk9Ti.mjs";import{onDisconnect as T}from"./onConnect-BLRoOpv2.mjs";import{g as v,h as A,a as L}from"./plugin-DQcLxTx1.mjs";const D=3e4,g=1024,P=8,p=4096,w="presence",h="present",l=`${w}_${h}`,N=v(w,{tables:{[h]:A({data:t.optional(t.record(t.string(),t.any())),lastSeen:t.number(),roomId:t.string(),sessionId:t.string(),userId:t.optional(t.string())}).index("byRoomSession",["roomId","sessionId"]).index("byRoom",["roomId"]).index("byRoomLastSeen",["roomId","lastSeen"])}}),{mutation:E,query:B}=M.dataModel().create(),G=(u={})=>{const m=u.ttlMs??D,f=Math.max(0,Math.min(u.disconnectGraceMs??0,m)),S=u.maxSessions,y=S!==void 0&&Number.isFinite(S)?Math.max(1,Math.floor(S)):g,_=E.input({data:t.optional(t.record(t.string(),t.any())),roomId:t.string(),sessionId:t.string()}).mutation(async({args:o,ctx:s})=>{const r=Date.now(),d=s.auth.userId??void 0;if(o.data!==void 0&&new TextEncoder().encode(JSON.stringify(o.data)).length>p)throw new b("BAD_REQUEST",`presence data exceeds the ${String(p)}-byte limit`);const e=await s.db.query(l).withIndex("byRoomSession",i=>i.eq("roomId",o.roomId).eq("sessionId",o.sessionId)).first();if(e&&(e.userId??void 0)!==d)throw new b("FORBIDDEN","presence heartbeat denied: this (roomId, sessionId) is held by another identity");const a={lastSeen:r,roomId:o.roomId,sessionId:o.sessionId,...o.data===void 0?{}:{data:o.data},...d===void 0?{}:{userId:d}};await(e?s.db.patch(e._id,a):s.db.insert(l,a));const I=r-m-Math.max(f,m),c=(await s.db.query(l).withIndex("byRoomLastSeen",i=>i.eq("roomId",o.roomId)).order("asc").take(P)).filter(i=>i.lastSeen<=I);return await Promise.all(c.map(i=>s.db.delete(i._id))),{lastSeen:r}}),x=B.input({roomId:t.string()}).query(async({args:o,ctx:s})=>{const r=Date.now()-m,e=(await s.db.query(l).withIndex("byRoomLastSeen",n=>n.eq("roomId",o.roomId)).order("desc").take(y)).filter(n=>n.lastSeen>r),a=new Set,I=[];for(const n of e){const c=n.userId;if(c!==void 0){if(a.has(c))continue;a.add(c)}const i={lastSeen:n.lastSeen,roomId:n.roomId};c!==void 0&&(i.userId=c),n.data!==void 0&&(i.data=n.data),I.push(i)}return I}),R={...E.input({roomId:t.string()}).mutation(async({args:o,ctx:s})=>{const r=Date.now()-m,d=await s.db.query(l).withIndex("byRoom",e=>e.eq("roomId",o.roomId)).filter(e=>e.lastSeen<=r).collect();return await Promise.all(d.map(e=>s.db.delete(e._id))),{deleted:d.length}}),visibility:"internal"},q=T(async(o,s)=>{const r=s.context?.roomId,d=s.context?.sessionId;if(typeof r!="string"||typeof d!="string")return;const e=await o.db.query(l).withIndex("byRoomSession",n=>n.eq("roomId",r).eq("sessionId",d)).first();if(!e)return;const a=s.userId??void 0;if((e.userId??void 0)!==a)return;if(f===0){await o.db.delete(e._id);return}const I=Math.min(e.lastSeen,Date.now()+f-m);await o.db.patch(e._id,{lastSeen:I})});return L(w,{extension:N,functions:{disconnect:q,heartbeat:_,listPresent:x,sweep:R}})};export{D as PRESENCE_DEFAULT_TTL_MS,l as PRESENCE_TABLE,G as definePresence,N as presenceExtension};
@@ -0,0 +1 @@
1
+ import{ValidationError as e}from"@lunora/values";import{LunoraError as a}from"./LunoraError-DcKdk9Ti.mjs";const s=(t,o)=>{try{return t.parse(o)}catch(r){throw r instanceof e?new a("INTERNAL_SERVER_ERROR",`Response did not match the declared output schema: ${r.message}`):r}};export{s as a};
@@ -0,0 +1 @@
1
+ const n=2166136261,o=16777619,S=(F,e=2166136261)=>{let t=e;for(let a=0;a<F.length;a+=1)t^=F.codePointAt(a)??0,t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")};export{n as F,o as a,S as f};
@@ -0,0 +1,5 @@
1
+ import{toErrorBody as S}from"@lunora/errors";import{parseValidatorMap as R,ValidationError as A}from"@lunora/values";import{Hono as x}from"hono";import{a as q}from"./apply-output-BG8Bd0Ug.mjs";import{LunoraError as g}from"./LunoraError-DcKdk9Ti.mjs";const G=e=>async t=>e(t.get("lunora"),t.req.raw),J=()=>{const e=new x;return e.use("*",async(t,r)=>{const n=t.env.__lunoraCtx;if(!n)throw new g("INTERNAL_SERVER_ERROR","HttpActionCtx was not injected — mount httpRouter() on createWorker(), which supplies it per request.");t.set("lunora",n),await r()}),e},k=e=>e.kind==="optional"?e._meta?.inner??e:e,y=(e,t)=>{switch(e){case"bigint":try{return BigInt(t)}catch{return t}case"boolean":return t==="true"||t==="1"?!0:t==="false"||t==="0"?!1:t;case"number":return t===""?Number.NaN:Number(t);default:return t}},C=(e,t,r)=>{const n=k(e);if(n.kind==="array"){const o=t.req.queries(r);if(o===void 0)return;const s=n._meta?.inner;return o.map(c=>y(s?.kind??"string",c))}const a=t.req.query(r);return a===void 0?void 0:y(n.kind,a)},v=(e,t)=>{const r={};for(const n of Object.keys(e)){const a=e[n];a&&(r[n]=C(a,t,n))}return R(e,r,"searchParams")},N=(e,t)=>{const r=t.req.param(),n={};for(const a of Object.keys(e)){const o=e[a];if(!o)continue;const s=r[a];n[a]=s===void 0?void 0:y(k(o).kind,s)}return R(e,n,"params")},H=async(e,t)=>{let r;try{r=await t.req.json()}catch{throw new g("BAD_REQUEST","Invalid JSON body")}if(typeof r!="object"||r===null||Array.isArray(r))throw new g("BAD_REQUEST","Expected a JSON object body");return R(e,r,"body")},O=e=>{if(e instanceof A)return Response.json({code:"BAD_REQUEST",error:e.message},{status:400});if(e instanceof g){const{body:t,redacted:r,status:n}=S(e,{fallbackCode:"INTERNAL_SERVER_ERROR",redactedMessage:"Internal error"});return r&&console.error("[lunora] http action error (redacted on the wire):",e),Response.json({code:t.code,error:t.message},{status:n})}throw e},B=(e,t)=>async r=>{try{const n=r.get("lunora"),a=Object.keys(e.searchParams).length>0?v(e.searchParams,r):{},o=Object.keys(e.params).length>0?N(e.params,r):{},s=Object.keys(e.body).length>0?await H(e.body,r):{},c=await t({body:s,ctx:n,params:o,searchParams:a}),u=e.output?q(e.output,c):c,i={};e.cacheControl&&(i["cache-control"]=e.cacheControl),e.cacheTag&&(i["cache-tag"]=e.cacheTag),e.vary&&(i.vary=e.vary);const h=Object.keys(i).length>0;return u===void 0?new Response(null,{headers:h?i:void 0,status:204}):Response.json(u,{headers:h?i:void 0})}catch(n){return O(n)}},E={"cache-control":"no-cache, no-transform","content-type":"text/event-stream; charset=utf-8","x-accel-buffering":"no"},b=(e,t)=>{const r=JSON.stringify(e);return`${t?`event: ${t}
2
+ `:""}data: ${r}
3
+
4
+ `},$=(e,t)=>(async r=>{let n,a;try{n=Object.keys(e.searchParams).length>0?v(e.searchParams,r):{},a=Object.keys(e.params).length>0?N(e.params,r):{}}catch(p){return O(p)}const o=r.get("lunora"),s=r.req.raw,c=new TextEncoder,u=new AbortController;if(s.signal.aborted)return u.abort(),new Response("",{headers:E});const i=()=>{u.abort()};s.signal.addEventListener("abort",i,{once:!0});const h=new ReadableStream({cancel(){s.signal.removeEventListener("abort",i),u.abort()},async start(p){try{const f=t({ctx:o,params:a,request:s,searchParams:n,signal:u.signal});for await(const m of f){if(u.signal.aborted)break;p.enqueue(c.encode(b(m)))}p.enqueue(c.encode(b({},"complete")))}catch(f){const{body:m,redacted:_}=S(f,{fallbackCode:"INTERNAL_SERVER_ERROR",redactedMessage:"Internal error"});_&&console.error("[lunora] unhandled stream handler error:",f),p.enqueue(c.encode(b({code:m.code,message:m.message},"error")))}finally{s.signal.removeEventListener("abort",i),p.close()}}});return new Response(h,{headers:E})}),d=e=>({body:t=>d({...e,body:{...e.body,...t}}),cacheControl:t=>d({...e,cacheControl:t}),cacheTag:t=>d({...e,cacheTag:t}),handler:t=>B(e,t),output:t=>d({...e,output:t}),params:t=>d({...e,params:{...e.params,...t}}),searchParams:t=>d({...e,searchParams:{...e.searchParams,...t}}),stream:t=>$(e,t),vary:t=>d({...e,vary:t})}),l=e=>t=>d({body:{},method:e,params:{},path:t,searchParams:{}}),Q={delete:l("DELETE"),get:l("GET"),head:l("HEAD"),options:l("OPTIONS"),patch:l("PATCH"),post:l("POST"),put:l("PUT")},I=/^bytes=(\d*)-(\d*)$/,T=e=>e.startsWith('"')||e.startsWith('W/"')?e:`"${e}"`,L=e=>!(e.includes("\r")||e.includes(`
5
+ `)||e.includes("\0")),j=(e,t)=>{if(e===null)return{kind:"full"};const r=I.exec(e.trim());if(!r)return{kind:"full"};const n=r[1]??"",a=r[2]??"";if(n===""&&a==="")return{kind:"full"};let o,s;if(n===""){const c=Number(a);if(c===0)return{kind:"unsatisfiable"};o=Math.max(0,t-c),s=t-1}else o=Number(n),s=a===""?t-1:Math.min(Number(a),t-1);return o>s||o>=t?{kind:"unsatisfiable"}:{end:s,kind:"partial",start:o}},P=e=>{const t=e.httpMetadata?.contentType,r={"accept-ranges":"bytes","content-type":t!==void 0&&L(t)?t:"application/octet-stream",etag:T(e.etag)};return e.sha256Base64!==void 0&&(r["repr-digest"]=`sha-256=:${e.sha256Base64}:`),r},D=e=>j(e,0).kind==="full",w=async(e,t)=>{const r=await e.storage.download(t);return r?new Response(r.body,{headers:{...P(r),"content-length":String(r.size)},status:200}):new Response("Not Found",{status:404})},Y=async(e,t,r)=>{const n=r.headers.get("range");if(D(n))return w(e,t);const a=await e.storage.head(t);if(!a)return new Response("Not Found",{status:404});const o=j(n,a.size);if(o.kind==="unsatisfiable")return new Response("Range Not Satisfiable",{headers:{"accept-ranges":"bytes","content-range":`bytes */${String(a.size)}`,"content-type":"text/plain; charset=utf-8",etag:T(a.etag)},status:416});if(o.kind==="full")return w(e,t);const s=o.end-o.start+1,c=await e.storage.download(t,{range:{length:s,offset:o.start}});return c?new Response(c.body,{headers:{...P(a),"content-length":String(s),"content-range":`bytes ${String(o.start)}-${String(o.end)}/${String(a.size)}`},status:206}):new Response("Not Found",{status:404})};export{G as httpAction,Q as httpRoute,J as httpRouter,L as isSafeHeaderValue,Y as serveStorageObject};
@@ -0,0 +1 @@
1
+ import{a as M}from"./apply-output-BG8Bd0Ug.mjs";import{v as f}from"./functions-B2-H4PQT.mjs";import{readMaskTag as h}from"./buildMaskRegistry-72SL8fJn.mjs";import{r as j}from"./policy-tag-D4RzgQnw.mjs";import{r as O}from"./run-middleware-B-JeGGp9.mjs";const x=(e,r)=>r===void 0||typeof e!="object"||e===null?e:Object.assign(Object.create(Object.getPrototypeOf(e)),e,{meta:r}),i=(e,r)=>O(e,r,o=>o),_=(e,r,o,a,n)=>async(s,u)=>{const t=f(e,u),l=await i(r,x(s,n)),c=await o({args:t,ctx:l});return a?M(a,c):c},q=(e,r,o,a)=>(n,s,u)=>{const t=f(e,s);return(async function*(){const c=await i(r,x(n,a)),m=o({args:t,ctx:c,signal:u})[Symbol.asyncIterator]();try{for(;;){if(u.aborted)return;const p=await m.next();if(p.done||u.aborted)return;yield p.value}}finally{await m.return?.()}})()},w=e=>{const r=e.map(o=>j(o)).filter(o=>o!==void 0);return r.length>0?{tags:r}:void 0},g=e=>{const r=new Map;for(const o of e){const a=h(o);if(a)for(const[n,s]of a.columns){const u=r.get(n)??new Set;for(const t of s)u.add(t);r.set(n,u)}}return r.size>0?r:void 0},d=(e,r,o)=>({__lunoraProcedure:e,...o?{__lunoraVisibility:o}:{},input:a=>d(e,{...r,args:{...r.args,...a}},o),[e]:a=>{const n=w(r.middlewares),s=g(r.middlewares);return{args:r.args,...r.expose?{expose:r.expose}:{},handler:_(r.args,r.middlewares,a,r.output,r.meta),kind:e,...s?{maskedTables:s}:{},...r.meta?{meta:r.meta}:{},...n?{rls:n}:{},...o?{visibility:o}:{},...r.x402?{x402:r.x402}:{}}},meta:a=>d(e,{...r,meta:Object.freeze({...r.meta,...a})},o),output:a=>d(e,{...r,output:a},o),...e==="query"?{stream:(a,n)=>{const s=w(r.middlewares),u=g(r.middlewares),t=n?.durable===!0?{}:n?.durable;return{args:r.args,...t?{durable:t}:{},...r.expose?{expose:r.expose}:{},handler:q(r.args,r.middlewares,a,r.meta),kind:"stream",...u?{maskedTables:u}:{},...r.meta?{meta:r.meta}:{},...s?{rls:s}:{},...o?{visibility:o}:{},...r.x402?{x402:r.x402}:{}}}}:{},use:a=>d(e,{...r,middlewares:[...r.middlewares,a]},o),...o?{}:{expose:a=>d(e,{...r,expose:a},o)},...o?{}:{x402:a=>d(e,{...r,x402:a},o)}}),A={dataModel:()=>({create:e=>({action:d("action",{args:{},middlewares:[]}),internalAction:d("action",{args:{},middlewares:[]},"internal"),internalMutation:d("mutation",{args:{},middlewares:[]},"internal"),internalQuery:d("query",{args:{},middlewares:[]},"internal"),mutation:d("mutation",{args:{},middlewares:[]}),query:d("query",{args:{},middlewares:[]})})})};export{A as initLunora};
@@ -0,0 +1 @@
1
+ import{f as B}from"./fnv1a-D6VtE8WR.mjs";import{LunoraError as P}from"./LunoraError-DcKdk9Ti.mjs";import{bindTableFacade as E,bindOrm as _}from"./bindOrm-lWdeDi9P.mjs";import{i as D,a as K,o as v,b as q}from"./middleware-DEW0yLvU.mjs";import{tagMaskMiddleware as m}from"./buildMaskRegistry-72SL8fJn.mjs";const G=(i,e,c)=>{try{return i==="redact"?null:i==="hash"?e==null?e:typeof e=="bigint"?B(e.toString()):B(typeof e=="string"?e:JSON.stringify(e)):i(e,c)}catch{return null}},a=(i,e,c)=>{const y={...i};for(const[h,g]of Object.entries(e))h in y&&(y[h]=G(g,i[h],{...c,column:h,row:i}));return y},W=(i,e,c)=>({...i,page:i.page.map(y=>a(y,e,c))}),U=(i,e,c,y)=>{if(typeof i!="function")return;const h=new Set,g=()=>new Proxy({},{get:()=>f=>(typeof f=="string"&&h.add(f),g())});i(g());for(const f of h)if(f in e)throw new P("MASK_UNSUPPORTED",`${y}() filtering "${c}" by masked column "${f}" is not supported`)},L=(i,e,c,y)=>{const h=i.rankBefore,g=i.rankPageRows,f=(r,n)=>{const t=e.get(r);return t?n.map(o=>a(o,t,c)):n},p=r=>{const n=r?.relationMask;return{...r,relationMask:n===void 0?f:(t,o)=>n(t,f(t,o))}},k=(r,n,t,o)=>{const s=e.get(r);if(!s)return;const d=y?.[r]?.[o]?.[n];if(!d)return;const w=d.find($=>$ in s);if(w!==void 0)throw new P("MASK_UNSUPPORTED",`${t}() reading "${r}" via index "${n}" would order rows by masked column "${w}" — use an index whose declared fields are all unmasked, or unmask the column`)},l=(r,n,t)=>({async*[Symbol.asyncIterator](){for await(const o of{[Symbol.asyncIterator]:()=>r[Symbol.asyncIterator]()})yield a(o,n,c)},collect:async()=>(await r.collect()).map(s=>a(s,n,c)),collectWithScores:async()=>(await r.collectWithScores()).map(s=>{const d=a(s.document,n,c);return"distanceMeters"in s?{distanceMeters:null,document:d}:{document:d,score:s.score}}),filter:o=>l(r.filter(s=>o(a(s,n,c))),n,t),first:async()=>{const o=await r.first();return o?a(o,n,c):null},order:o=>l(r.order(o),n,t),paginate:async o=>W(await r.paginate(o),n,c),take:async o=>(await r.take(o)).map(d=>a(d,n,c)),unique:async()=>{const o=await r.unique();return o?a(o,n,c):null},withIndex:(o,s)=>(k(t,o,"withIndex","index"),U(s,n,t,"withIndex"),l(r.withIndex(o,s),n,t)),withSearchIndex:(o,s)=>(U(s,n,t,"withSearchIndex"),l(r.withSearchIndex(o,s),n,t)),withGeoIndex:(o,s)=>(k(t,o,"withGeoIndex","geo"),l(r.withGeoIndex(o,s),n,t))}),S=async(r,n)=>{if(i.lookupById){const w=await i.lookupById(r,n);return w?{row:w.row,tableName:e.has(w.tableName)?w.tableName:void 0}:{row:null,tableName:void 0}}const t=await i.get(r,n);if(!t)return{row:null,tableName:void 0};const o=n!==void 0&&e.has(n)?[n]:[],s=n===void 0?[...e.keys()]:o,d=await Promise.all(s.map(async w=>(await i.findFirst(w,{limit:1,where:{_id:r}}))?._id===r?w:void 0));return{row:t,tableName:d.find(w=>w!==void 0)}},M=(r,n,t)=>{const o=e.get(r);if(!o)return;const s=n.find(d=>typeof d=="string"&&d in o);if(s!==void 0)throw new P("MASK_UNSUPPORTED",`${t}() over masked column "${s}" on "${r}" is not supported`)},R=(r,n)=>{if(!(!r||typeof r!="object"||Array.isArray(r)))for(const[t,o]of Object.entries(r))if(t==="AND"||t==="OR"){if(Array.isArray(o))for(const s of o)R(s,n)}else t==="NOT"?R(o,n):t.startsWith("__")||n.add(t)},u=(r,n,t)=>{const o=e.get(r);if(!o||n===void 0)return;const s=new Set;R(n,s);for(const d of s)if(d in o)throw new P("MASK_UNSUPPORTED",`${t}() filtering "${r}" by masked column "${d}" is not supported`)},I=(r,n,t)=>{const o=e.get(r);if(!(!o||!Array.isArray(n))){for(const s of n)if(s&&typeof s=="object"&&!Array.isArray(s)){for(const d of Object.keys(s))if(d in o)throw new P("MASK_UNSUPPORTED",`${t}() ordering "${r}" by masked column "${d}" is not supported`)}}},F=r=>r&&typeof r=="object"&&!Array.isArray(r)?r:void 0,A=(r,n,t)=>{const o=F(n);u(r,o?.where,t),u(r,o?.baseWhere,t)},O={...i,async deleteWhere(r,n,t){if(u(r,n,"deleteMany({ where })"),i.deleteWhere===void 0)throw new P("INTERNAL",`ctx.db.${r}.deleteMany({ where }) is unavailable: this writer has no where-based delete`);return i.deleteWhere(r,n,t)},async patchWhere(r,n,t){if(u(r,n.where,"patchMany({ where })"),i.patchWhere===void 0)throw new P("INTERNAL",`ctx.db.${r}.patchMany({ where }) is unavailable: this writer has no where-based patch`);return i.patchWhere(r,n,t)},aggregate(r,n){return M(r,[n.field],"aggregate"),u(r,n.where,"aggregate"),i.aggregate(r,n)},count(r,n){const t=F(n),o=t&&("where"in t||"baseWhere"in t||"restrictsCounts"in t)?t.where:n;return u(r,o,"count"),t&&u(r,t.baseWhere,"count"),i.count(r,n)},async findFirst(r,n){u(r,n?.where,"findFirst"),u(r,n?.baseWhere,"findFirst"),I(r,n?.orderBy,"findFirst");const t=await i.findFirst(r,p(n)),o=e.get(r);return t&&o?a(t,o,c):t},async findFirstOrThrow(r,n){u(r,n?.where,"findFirstOrThrow"),u(r,n?.baseWhere,"findFirstOrThrow"),I(r,n?.orderBy,"findFirstOrThrow");const t=await i.findFirstOrThrow(r,p(n)),o=e.get(r);return o?a(t,o,c):t},async findMany(r,n){u(r,n?.where,"findMany"),u(r,n?.baseWhere,"findMany"),I(r,n?.orderBy,"findMany");const t=await i.findMany(r,p(n)),o=e.get(r);return o?W(t,o,c):t},async get(r,n){const{row:t,tableName:o}=await S(r,n),s=o===void 0?void 0:e.get(o);return!t||!s?t:a(t,s,c)},async lookupById(r,n){const t=await i.lookupById?.(r,n);if(!t)return null;const o=e.get(t.tableName);return{row:o?a(t.row,o,c):t.row,tableName:t.tableName}},groupBy(r,n){return M(r,[...n.by,n.agg?.field],"groupBy"),u(r,n.where,"groupBy"),i.groupBy(r,n)},query(r){const n=i.query(r),t=e.get(r);return t?l(n,t,r):n},async rank(r,n,t){return A(r,t,"rank"),k(r,n,"rank","rank"),i.rank(r,n,t)},async rankPage(r,n,t){A(r,t,"rankPage"),k(r,n,"rankPage","rank");const o=await i.rankPage(r,n,t),s=e.get(r);return s?W(o,s,c):o},...v("rankBefore",h,r=>(n,t,o)=>(A(n,o,"rankBefore"),k(n,t,"rankBefore","rank"),r(n,t,o))),...v("rankPageRows",g,r=>async(n,t,o)=>{A(n,o,"rankPageRows"),k(n,t,"rankPageRows","rank");const s=await r(n,t,o),d=e.get(n);return d?{...s,rows:s.rows.map(w=>({...w,doc:a(w.doc,d,c)}))}:s})},j=O;for(const r of e.keys())q(i[r])&&(j[r]=E(O,r));return O},V=(i,e={})=>{const c=new Map(Object.entries(i)),y=D(e.roles),h=async({ctx:f,next:p})=>{const k={auth:await K(f.auth??{},y),ctx:f};if(e.bypass?.(k))return p();const l=L(f.db,c,k,e.indexFields),S={db:l},{orm:M}=f;return M!==null&&typeof M=="object"&&(S.orm=_(l)),p({ctx:S})},g=new Map;for(const[f,p]of c)g.set(f,new Set(Object.keys(p)));return m(h,{columns:g})};export{V as mask};
@@ -0,0 +1 @@
1
+ import{f as c,F as f,a as y}from"./fnv1a-D6VtE8WR.mjs";const p=t=>`${c(t,f)}${c(t,y)}`,u=(t,n)=>t<n?-1:t>n?1:0,o=t=>{if(t===void 0)return"null";if(typeof t=="bigint")throw new TypeError("stableStringify: cannot use a bigint in a stable JSON cache key — pass it as a string, or use stableWireKey");if(typeof t=="number"){if(Number.isNaN(t))return"nan";if(t===1/0)return"inf";if(t===-1/0)return"-inf";if(Object.is(t,-0))return"-0"}if(t===null||typeof t!="object")return JSON.stringify(t);if(Array.isArray(t))return`[${t.map(r=>o(r)).join(",")}]`;const n=Object.getPrototypeOf(t);if(n!==null&&n!==Object.prototype){const r=t.constructor?.name??"value";throw new TypeError(`stableStringify: cannot use a ${r} in a stable JSON cache key — only plain objects, arrays, and JSON primitives are supported (wire-typed values key via stableWireKey)`)}const e=t,s=Object.keys(e).toSorted(u),i=[];for(const r of s){const a=e[r];a!==void 0&&i.push(`${JSON.stringify(r)}:${o(a)}`)}return`{${i.join(",")}}`},g=(t,n)=>({args:{},handler:async(e,s)=>{const i=await t(e),r=p(o(i));return r===s?.previousDigest?{digest:r,ran:!1}:(await n(e,i),{digest:r,ran:!0})},kind:"mutation",lifecycle:"reactor",visibility:"internal"});export{g as onQueryChange};
@@ -0,0 +1 @@
1
+ import{LunoraError as y}from"./LunoraError-DcKdk9Ti.mjs";import{i as U,a as v}from"./middleware-DEW0yLvU.mjs";const D=(o,e)=>o===void 0||e.startsWith(o),k=o=>{const e=o[1],c=typeof e=="object"&&e!==null?e.method:void 0;return typeof c=="string"&&c.toUpperCase()==="PUT"?"write":"read"},E=[["delete","delete"],["download","read"],["generateUploadUrl","write"],["getMetadata","read"],["getSignedUrl",k],["getUrl","read"],["head","read"],["store","write"]],S=(o,e={})=>{const c=U(e.roles);return async({ctx:u,next:f})=>{const w=await v(u.auth??{},c),g=(n,r,s)=>{const i=o.filter(t=>t.on===n&&t.bucket===s);if(i.length===0)return;const a={auth:w,ctx:u,key:r};if(!i.some(t=>D(t.prefix,r)&&t.when(a)===!0))throw new y("FORBIDDEN",`storage ${n} on "${r}" in bucket "${s}" denied by access rule`)},p=n=>{const r=n.bucketName??"default",s={bucketName:r};for(const[a,d]of E){const t=n[a];typeof t=="function"&&(s[a]=(...l)=>{const m=typeof l[0]=="string"?l[0]:"",b=typeof d=="function"?d(l):d;return g(b,m,r),t(...l)})}const{bucket:i}=n;return typeof i=="function"&&(s.bucket=a=>p(i(a))),s},h=u.storage;return h===void 0?f():f({ctx:{storage:p(h)}})}};export{S as storageRules};
package/dist/types.d.mts CHANGED
@@ -1583,6 +1583,39 @@ interface StorageMetadata {
1583
1583
  /** When the object was last written (epoch ms), when reported. */
1584
1584
  uploaded?: number;
1585
1585
  }
1586
+ /**
1587
+ * The body-free object shape returned by {@link ReadOnlyStorage.head} — a clean
1588
+ * public mirror of `@lunora/storage`'s head projection, re-declared here for the
1589
+ * same reason as {@link StorageMetadata}: the ctx surface carries no dependency
1590
+ * on the storage package's types.
1591
+ *
1592
+ * Richer than {@link StorageMetadata} on purpose. `getMetadata` is the tidy
1593
+ * Convex-shaped summary; `head` is what an HTTP layer needs, so it keeps the
1594
+ * validator (`etag`) and the base64 digest RFC 9530 `Repr-Digest` requires, and
1595
+ * leaves `uploaded` as the `Date` the binding reports rather than epoch ms.
1596
+ */
1597
+ interface StorageObjectHead {
1598
+ /** Custom metadata set at upload time, if any. */
1599
+ customMetadata?: Record<string, string>;
1600
+ /** R2's unquoted etag (the MD5 hex for a single-part upload). */
1601
+ etag?: string;
1602
+ /** The already-quoted form of {@link StorageObjectHead.etag}, when the binding reports one. */
1603
+ httpEtag?: string;
1604
+ /** Recorded HTTP metadata, notably the `Content-Type`. */
1605
+ httpMetadata?: {
1606
+ contentType?: string;
1607
+ };
1608
+ /** The object's key. */
1609
+ key: string;
1610
+ /** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
1611
+ sha256?: string;
1612
+ /** Base64-encoded SHA-256 of the same checksum — the encoding RFC 9530 digest headers require. */
1613
+ sha256Base64?: string;
1614
+ /** The FULL object size in bytes: R2 reports the object's size, not a returned window's, which is what makes a head enough to resolve a `Range` against. */
1615
+ size: number;
1616
+ /** When the object was last written. */
1617
+ uploaded?: Date;
1618
+ }
1586
1619
  /**
1587
1620
  * Read-only projection of `Storage` exposed on `QueryCtx` / `MutationCtx`.
1588
1621
  *
@@ -1616,6 +1649,15 @@ interface ReadOnlyStorage<Buckets extends string = string> {
1616
1649
  }) => Promise<string>;
1617
1650
  /** Public URL pointing at the configured base for `key`. */
1618
1651
  getUrl: (key: string) => string;
1652
+ /**
1653
+ * Read an object's metadata with NO body transfer, as the raw object shape —
1654
+ * `etag` and the base64 digest included, which is what an HTTP layer needs to
1655
+ * answer a `Range` request. Returns `null` when the object is absent.
1656
+ *
1657
+ * {@link ReadOnlyStorage.getMetadata} is the tidier summary over the same
1658
+ * read; reach for this one when building a response.
1659
+ */
1660
+ head: (key: string) => Promise<StorageObjectHead | null>;
1619
1661
  }
1620
1662
  interface Storage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
1621
1663
  /** Select a named bucket; the returned accessor exposes the full read/write surface. */
@@ -2200,4 +2242,4 @@ interface ActionCtx {
2200
2242
  */
2201
2243
  type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
2202
2244
  declare const anyApi: AnyApi;
2203
- export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type DurableStreamOptions, type ExposeConfig, type ExternalSourceCursor, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GeoBoundingBox, type GeoFilterBuilder, type GeoIndexDefinition, type GeoPointInput, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, type LunoraWideEvent, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type RestCacheConfig, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type SearchLanguage, type SearchStrategy, type Secrets, type SecretsStoreSecretLike, type ShardInitEvent, type ShardMode, type SpanEvaluation, type SpanHandle, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type TtlDefinition, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, type X402ProcedureConfig, anyApi };
2245
+ export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type DurableStreamOptions, type ExposeConfig, type ExternalSourceCursor, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GeoBoundingBox, type GeoFilterBuilder, type GeoIndexDefinition, type GeoPointInput, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, type LunoraWideEvent, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type RestCacheConfig, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type SearchLanguage, type SearchStrategy, type Secrets, type SecretsStoreSecretLike, type ShardInitEvent, type ShardMode, type SpanEvaluation, type SpanHandle, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type StorageObjectHead, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type TtlDefinition, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, type X402ProcedureConfig, anyApi };
package/dist/types.d.ts CHANGED
@@ -1583,6 +1583,39 @@ interface StorageMetadata {
1583
1583
  /** When the object was last written (epoch ms), when reported. */
1584
1584
  uploaded?: number;
1585
1585
  }
1586
+ /**
1587
+ * The body-free object shape returned by {@link ReadOnlyStorage.head} — a clean
1588
+ * public mirror of `@lunora/storage`'s head projection, re-declared here for the
1589
+ * same reason as {@link StorageMetadata}: the ctx surface carries no dependency
1590
+ * on the storage package's types.
1591
+ *
1592
+ * Richer than {@link StorageMetadata} on purpose. `getMetadata` is the tidy
1593
+ * Convex-shaped summary; `head` is what an HTTP layer needs, so it keeps the
1594
+ * validator (`etag`) and the base64 digest RFC 9530 `Repr-Digest` requires, and
1595
+ * leaves `uploaded` as the `Date` the binding reports rather than epoch ms.
1596
+ */
1597
+ interface StorageObjectHead {
1598
+ /** Custom metadata set at upload time, if any. */
1599
+ customMetadata?: Record<string, string>;
1600
+ /** R2's unquoted etag (the MD5 hex for a single-part upload). */
1601
+ etag?: string;
1602
+ /** The already-quoted form of {@link StorageObjectHead.etag}, when the binding reports one. */
1603
+ httpEtag?: string;
1604
+ /** Recorded HTTP metadata, notably the `Content-Type`. */
1605
+ httpMetadata?: {
1606
+ contentType?: string;
1607
+ };
1608
+ /** The object's key. */
1609
+ key: string;
1610
+ /** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
1611
+ sha256?: string;
1612
+ /** Base64-encoded SHA-256 of the same checksum — the encoding RFC 9530 digest headers require. */
1613
+ sha256Base64?: string;
1614
+ /** The FULL object size in bytes: R2 reports the object's size, not a returned window's, which is what makes a head enough to resolve a `Range` against. */
1615
+ size: number;
1616
+ /** When the object was last written. */
1617
+ uploaded?: Date;
1618
+ }
1586
1619
  /**
1587
1620
  * Read-only projection of `Storage` exposed on `QueryCtx` / `MutationCtx`.
1588
1621
  *
@@ -1616,6 +1649,15 @@ interface ReadOnlyStorage<Buckets extends string = string> {
1616
1649
  }) => Promise<string>;
1617
1650
  /** Public URL pointing at the configured base for `key`. */
1618
1651
  getUrl: (key: string) => string;
1652
+ /**
1653
+ * Read an object's metadata with NO body transfer, as the raw object shape —
1654
+ * `etag` and the base64 digest included, which is what an HTTP layer needs to
1655
+ * answer a `Range` request. Returns `null` when the object is absent.
1656
+ *
1657
+ * {@link ReadOnlyStorage.getMetadata} is the tidier summary over the same
1658
+ * read; reach for this one when building a response.
1659
+ */
1660
+ head: (key: string) => Promise<StorageObjectHead | null>;
1619
1661
  }
1620
1662
  interface Storage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
1621
1663
  /** Select a named bucket; the returned accessor exposes the full read/write surface. */
@@ -2200,4 +2242,4 @@ interface ActionCtx {
2200
2242
  */
2201
2243
  type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
2202
2244
  declare const anyApi: AnyApi;
2203
- export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type DurableStreamOptions, type ExposeConfig, type ExternalSourceCursor, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GeoBoundingBox, type GeoFilterBuilder, type GeoIndexDefinition, type GeoPointInput, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, type LunoraWideEvent, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type RestCacheConfig, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type SearchLanguage, type SearchStrategy, type Secrets, type SecretsStoreSecretLike, type ShardInitEvent, type ShardMode, type SpanEvaluation, type SpanHandle, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type TtlDefinition, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, type X402ProcedureConfig, anyApi };
2245
+ export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type DurableStreamOptions, type ExposeConfig, type ExternalSourceCursor, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GeoBoundingBox, type GeoFilterBuilder, type GeoIndexDefinition, type GeoPointInput, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, type LunoraWideEvent, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type RestCacheConfig, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type SearchLanguage, type SearchStrategy, type Secrets, type SecretsStoreSecretLike, type ShardInitEvent, type ShardMode, type SpanEvaluation, type SpanHandle, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type StorageObjectHead, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type TtlDefinition, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, type X402ProcedureConfig, anyApi };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/server",
3
- "version": "1.0.0-alpha.80",
3
+ "version": "1.0.0-alpha.82",
4
4
  "description": "Server primitives for Lunora: defineSchema, defineTable, query, mutation, and action",
5
5
  "keywords": [
6
6
  "backend",
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "dependencies": {
69
69
  "@lunora/errors": "1.0.0-alpha.22",
70
- "@lunora/scheduler": "1.0.0-alpha.36",
70
+ "@lunora/scheduler": "1.0.0-alpha.37",
71
71
  "@lunora/values": "1.0.0-alpha.27",
72
72
  "drizzle-orm": "^0.45.2",
73
73
  "hono": "^4.13.1"
@@ -1 +0,0 @@
1
- import{v as o}from"@lunora/values";const h=25,b=100,y=100,A=8,O=(t,r)=>{const n=i=>o.optional(o.array(i).check(s=>s.length<=r,{message:`at most ${String(r)} values`}));return o.object({contains:o.optional(o.string()),eq:o.optional(t),gt:o.optional(t),gte:o.optional(t),in:n(t),isNull:o.optional(o.boolean()),lt:o.optional(t),lte:o.optional(t),ne:o.optional(t),notIn:n(t)})},g=(t,r,n)=>t===void 0||!Number.isFinite(t)?Math.min(r,n):Math.min(Math.max(1,Math.floor(t)),n),p=(t,r)=>t===void 0||!Number.isFinite(t)?r:Math.max(1,Math.floor(t)),L=new Set(["contains","eq","gt","gte","in","isNull","lt","lte","ne","notIn"]),M=(t,r)=>{if(typeof t!="object"||t===null||Array.isArray(t))return;const n=t,i={};for(const s of L){if(!Object.hasOwn(n,s))continue;const a=n[s];i[s]=Array.isArray(a)?a.slice(0,r):a}return Object.keys(i).length===0?void 0:i},B=(t,r,n)=>{const i={};for(const s of r){if(!Object.hasOwn(t,s))continue;const a=t[s],l=M(a,n);i[s]=l??a}return i},E=()=>t=>{const r=p(t.defaultLimit,h),n=p(t.maxLimit,b),i=p(t.maxInValues,y),s=p(t.maxOrderBy,A),a=new Set(Object.keys(t.filter)),l={};for(const[e,c]of Object.entries(t.filter))l[e]=o.optional(o.union(c,O(c,i)));const u=new Set(t.orderBy),f=t.orderBy.length===0?o.string().check(()=>!1,{message:"no sortable columns are declared for this endpoint"}):o.union(...t.orderBy.map(e=>o.literal(e)));return{args:{cursor:o.optional(o.union(o.string(),o.number(),o.null())),limit:o.optional(o.number()),orderBy:o.optional(o.array(o.object({direction:o.optional(o.union(o.literal("asc"),o.literal("desc"))),field:f}))),where:o.optional(o.object(l))},toQueryArgs:e=>{const c=e.orderBy?.filter(d=>u.has(d.field)).slice(0,s).map(d=>({[d.field]:d.direction??"asc"})),m=e.where===void 0?void 0:B(e.where,a,i);return{...e.cursor===void 0?{}:{cursor:typeof e.cursor=="number"?String(e.cursor):e.cursor},limit:g(e.limit,r,n),...c===void 0||c.length===0?{}:{orderBy:c},...m===void 0?{}:{where:m}}}}};export{h as DEFAULT_LIMIT,y as DEFAULT_MAX_IN_VALUES,b as DEFAULT_MAX_LIMIT,A as DEFAULT_MAX_ORDER_BY,g as clampLimit,E as defineListArgs,p as normalizeBound,B as sanitizeWhere};
@@ -1,3 +0,0 @@
1
- import{LunoraError as A}from"@lunora/errors";import{optionalInner as h}from"@lunora/values";const b=[/^sk_/u,/^pk_/u,/^rk_/u,/^ghp_/u,/^gho_/u,/^ghs_/u,/^ghr_/u,/^github_pat_/u,/^xox[baprs]-/u,/^AKIA/u,/^AIza/u,/^Bearer\s/u],L=/[\w./+-]{24,}/gu,w=/^[\w./+-]+$/u,D=/\b(?:(?:sk|pk|rk|ghp|gho|ghs|ghr)_[\w./+-]*|github_pat_[\w./+-]*|xox[baprs]-[\w./+-]*)/gu,N=/\b(?:AKIA|AIza)[\w./+-]+|Bearer\s+[\w./+-]+/gu,S=/\b([a-z][\w.+-]*:\/\/[\w.%+-]+):[\w.%+-]+@/gu,a="[redacted]",d=/(?:KEY|PASSWORD|SECRET|TOKEN)$/u,T=t=>{if(b.some(n=>n.test(t)))return!0;const e=t.trim();return e.length>=24&&w.test(e)},p=/(["'])(?<inner>(?:\\.|(?!\1).)*)\1/gu,v=/\b(?<key>[A-Za-z_]\w*)\s*[=:]\s*\S+/gu,I=t=>{let e=t;return e=e.replaceAll(p,(n,...r)=>{const o=r.at(-1);return o?.inner!==void 0&&T(o.inner)?a:n}),e=e.replaceAll(S,(n,r)=>`${r}:${a}@`),e=e.replaceAll(D,a),e=e.replaceAll(N,a),e=e.replaceAll(v,(n,...r)=>{const o=r.at(-1);return o?.key!==void 0&&d.test(o.key)?`${o.key}=${a}`:n}),e=e.replaceAll(L,a),e},R=(t,e,n)=>{const r=I(t);return typeof n=="string"&&n!==""&&d.test(e)?r.replaceAll(n,a):r};class g extends A{failures;constructor(e){const n=e.map(r=>` - ${r.key}: ${r.message}`).join(`
2
- `);super("ENV_INVALID",`Invalid environment (${String(e.length)} key(s)):
3
- ${n}`,{name:"LunoraEnvError"}),this.failures=e}}const K=new Set(["1","on","true","yes"]),O=new Set(["0","false","no","off"]),y=/^-?\d+$/u,k=t=>{if(t.kind!=="optional")return t.kind;const e=h(t);return e?k(e):t.kind},$=(t,e)=>{if(typeof e!="string")return e;switch(k(t)){case"bigint":return y.test(e.trim())?BigInt(e.trim()):e;case"boolean":{const n=e.trim().toLowerCase();return K.has(n)?!0:O.has(n)?!1:e}case"number":{const n=e.trim();if(n==="")return e;const r=Number(n);return Number.isNaN(r)?e:r}default:return e}},_=(t,e,n,r)=>{const o=n[t];if(o===void 0&&e.kind==="optional")return{ok:!0,value:void 0};const c=e.safeParse($(e,o));return c.ok?{ok:!0,value:c.value}:(r.push({key:t,message:R(c.error.message,t,o)}),{ok:!1})},m=t=>{if(typeof t!="object"||t===null)throw new g([{key:"<env>",message:`expected an object, received ${t===null?"null":typeof t}`}]);return t},P=t=>{const e=Object.keys(t),n=new WeakMap,r=(o=>{const c=m(o);let i=n.get(c);i===void 0&&(i=new Map,n.set(c,i));const l=i,E=u=>{if(l.has(u))return l.get(u);const s=[],f=_(u,t[u],c,s);if(!f.ok)throw new g(s);return l.set(u,f.value),f.value};return new Proxy({},{get(u,s){if(!(typeof s!="string"||!(s in t)))return E(s)},getOwnPropertyDescriptor(u,s){if(typeof s=="string"&&s in t)return{configurable:!0,enumerable:!0,value:E(s),writable:!1}},has(u,s){return typeof s=="string"&&s in t},ownKeys(){return e}})});return r.parse=o=>{const c=m(o),i=[],l={};for(const E of e){const u=_(E,t[E],c,i);u.ok&&u.value!==void 0&&(l[E]=u.value)}if(i.length>0)throw new g(i);return l},r};export{g as LunoraEnvError,P as defineEnv,I as redactSecrets};
@@ -1 +0,0 @@
1
- import{v as t}from"@lunora/values";import{initLunora as R}from"./initLunora-CRypyq1P.mjs";import{LunoraError as S}from"./LunoraError-DcKdk9Ti.mjs";import{onDisconnect as T}from"./onConnect-BLRoOpv2.mjs";import{g,h as q,a as v}from"./plugin-DQcLxTx1.mjs";const D=3e4,p=4096,u="presence",b="present",m=`${u}_${b}`,M=g(u,{tables:{[b]:q({data:t.optional(t.record(t.string(),t.any())),lastSeen:t.number(),roomId:t.string(),sessionId:t.string(),userId:t.optional(t.string())}).index("byRoomSession",["roomId","sessionId"]).index("byRoom",["roomId"])}}),{mutation:E,query:A}=R.dataModel().create(),F=(f={})=>{const I=f.ttlMs??D,w=Math.max(0,Math.min(f.disconnectGraceMs??0,I)),y=E.input({data:t.optional(t.record(t.string(),t.any())),roomId:t.string(),sessionId:t.string()}).mutation(async({args:o,ctx:n})=>{const r=Date.now(),i=n.auth.userId??void 0;if(o.data!==void 0&&new TextEncoder().encode(JSON.stringify(o.data)).length>p)throw new S("BAD_REQUEST",`presence data exceeds the ${String(p)}-byte limit`);const e=await n.db.query(m).withIndex("byRoomSession",c=>c.eq("roomId",o.roomId).eq("sessionId",o.sessionId)).first();if(e&&(e.userId??void 0)!==i)throw new S("FORBIDDEN","presence heartbeat denied: this (roomId, sessionId) is held by another identity");const d={lastSeen:r,roomId:o.roomId,sessionId:o.sessionId,...o.data===void 0?{}:{data:o.data},...i===void 0?{}:{userId:i}};return await(e?n.db.patch(e._id,d):n.db.insert(m,d)),{lastSeen:r}}),h=A.input({roomId:t.string()}).query(async({args:o,ctx:n})=>{const r=Date.now()-I,e=(await n.db.query(m).withIndex("byRoom",s=>s.eq("roomId",o.roomId)).collect()).filter(s=>s.lastSeen>r).toSorted((s,a)=>a.lastSeen-s.lastSeen),d=new Set,c=[];for(const s of e){const a=s.userId;if(a!==void 0){if(d.has(a))continue;d.add(a)}const l={lastSeen:s.lastSeen,roomId:s.roomId};a!==void 0&&(l.userId=a),s.data!==void 0&&(l.data=s.data),c.push(l)}return c}),_={...E.input({roomId:t.string()}).mutation(async({args:o,ctx:n})=>{const r=Date.now()-I,i=await n.db.query(m).withIndex("byRoom",e=>e.eq("roomId",o.roomId)).filter(e=>e.lastSeen<=r).collect();return await Promise.all(i.map(e=>n.db.delete(e._id))),{deleted:i.length}}),visibility:"internal"},x=T(async(o,n)=>{const r=n.context?.roomId,i=n.context?.sessionId;if(typeof r!="string"||typeof i!="string")return;const e=await o.db.query(m).withIndex("byRoomSession",s=>s.eq("roomId",r).eq("sessionId",i)).first();if(!e)return;const d=n.userId??void 0;if((e.userId??void 0)!==d)return;if(w===0){await o.db.delete(e._id);return}const c=Math.min(e.lastSeen,Date.now()+w-I);await o.db.patch(e._id,{lastSeen:c})});return v(u,{extension:M,functions:{disconnect:x,heartbeat:y,listPresent:h,sweep:_}})};export{D as PRESENCE_DEFAULT_TTL_MS,m as PRESENCE_TABLE,F as definePresence,M as presenceExtension};
@@ -1,5 +0,0 @@
1
- import{toErrorBody as S}from"@lunora/errors";import{parseValidatorMap as R,ValidationError as k}from"@lunora/values";import{Hono as _}from"hono";import{LunoraError as p}from"./LunoraError-DcKdk9Ti.mjs";const M=e=>async t=>e(t.get("lunora"),t.req.raw),F=()=>{const e=new _;return e.use("*",async(t,r)=>{const n=t.env.__lunoraCtx;if(!n)throw new p("INTERNAL_SERVER_ERROR","HttpActionCtx was not injected — mount httpRouter() on createWorker(), which supplies it per request.");t.set("lunora",n),await r()}),e},N=e=>e.kind==="optional"?e._meta?.inner??e:e,g=(e,t)=>{switch(e){case"bigint":try{return BigInt(t)}catch{return t}case"boolean":return t==="true"||t==="1"?!0:t==="false"||t==="0"?!1:t;case"number":return t===""?Number.NaN:Number(t);default:return t}},P=(e,t,r)=>{const n=N(e);if(n.kind==="array"){const c=t.req.queries(r);if(c===void 0)return;const o=n._meta?.inner;return c.map(s=>g(o?.kind??"string",s))}const a=t.req.query(r);return a===void 0?void 0:g(n.kind,a)},T=(e,t)=>{const r={};for(const n of Object.keys(e)){const a=e[n];a&&(r[n]=P(a,t,n))}return R(e,r,"searchParams")},v=(e,t)=>{const r=t.req.param(),n={};for(const a of Object.keys(e)){const c=e[a];if(!c)continue;const o=r[a];n[a]=o===void 0?void 0:g(N(c).kind,o)}return R(e,n,"params")},A=async(e,t)=>{let r;try{r=await t.req.json()}catch{throw new p("BAD_REQUEST","Invalid JSON body")}if(typeof r!="object"||r===null||Array.isArray(r))throw new p("BAD_REQUEST","Expected a JSON object body");return R(e,r,"body")},x=(e,t)=>{try{return e.parse(t)}catch(r){throw r instanceof k?new p("INTERNAL_SERVER_ERROR",`Response did not match the declared output schema: ${r.message}`):r}},O=e=>{if(e instanceof k)return Response.json({code:"BAD_REQUEST",error:e.message},{status:400});if(e instanceof p){const{body:t,redacted:r,status:n}=S(e,{fallbackCode:"INTERNAL_SERVER_ERROR",redactedMessage:"Internal error"});return r&&console.error("[lunora] http action error (redacted on the wire):",e),Response.json({code:t.code,error:t.message},{status:n})}throw e},q=(e,t)=>async r=>{try{const n=r.get("lunora"),a=Object.keys(e.searchParams).length>0?T(e.searchParams,r):{},c=Object.keys(e.params).length>0?v(e.params,r):{},o=Object.keys(e.body).length>0?await A(e.body,r):{},s=await t({body:o,ctx:n,params:c,searchParams:a}),u=e.output?x(e.output,s):s,i={};e.cacheControl&&(i["cache-control"]=e.cacheControl),e.cacheTag&&(i["cache-tag"]=e.cacheTag),e.vary&&(i.vary=e.vary);const f=Object.keys(i).length>0;return u===void 0?new Response(null,{headers:f?i:void 0,status:204}):Response.json(u,{headers:f?i:void 0})}catch(n){return O(n)}},E={"cache-control":"no-cache, no-transform","content-type":"text/event-stream; charset=utf-8","x-accel-buffering":"no"},b=(e,t)=>{const r=JSON.stringify(e);return`${t?`event: ${t}
2
- `:""}data: ${r}
3
-
4
- `},C=(e,t)=>(async r=>{let n,a;try{n=Object.keys(e.searchParams).length>0?T(e.searchParams,r):{},a=Object.keys(e.params).length>0?v(e.params,r):{}}catch(h){return O(h)}const c=r.get("lunora"),o=r.req.raw,s=new TextEncoder,u=new AbortController;if(o.signal.aborted)return u.abort(),new Response("",{headers:E});const i=()=>{u.abort()};o.signal.addEventListener("abort",i,{once:!0});const f=new ReadableStream({cancel(){o.signal.removeEventListener("abort",i),u.abort()},async start(h){try{const m=t({ctx:c,params:a,request:o,searchParams:n,signal:u.signal});for await(const y of m){if(u.signal.aborted)break;h.enqueue(s.encode(b(y)))}h.enqueue(s.encode(b({},"complete")))}catch(m){const{body:y,redacted:j}=S(m,{fallbackCode:"INTERNAL_SERVER_ERROR",redactedMessage:"Internal error"});j&&console.error("[lunora] unhandled stream handler error:",m),h.enqueue(s.encode(b({code:y.code,message:y.message},"error")))}finally{o.signal.removeEventListener("abort",i),h.close()}}});return new Response(f,{headers:E})}),d=e=>({body:t=>d({...e,body:{...e.body,...t}}),cacheControl:t=>d({...e,cacheControl:t}),cacheTag:t=>d({...e,cacheTag:t}),handler:t=>q(e,t),output:t=>d({...e,output:t}),params:t=>d({...e,params:{...e.params,...t}}),searchParams:t=>d({...e,searchParams:{...e.searchParams,...t}}),stream:t=>C(e,t),vary:t=>d({...e,vary:t})}),l=e=>t=>d({body:{},method:e,params:{},path:t,searchParams:{}}),U={delete:l("DELETE"),get:l("GET"),head:l("HEAD"),options:l("OPTIONS"),patch:l("PATCH"),post:l("POST"),put:l("PUT")},H=/^bytes=(\d*)-(\d*)$/,w=e=>e.startsWith('"')||e.startsWith('W/"')?e:`"${e}"`,$=e=>!(e.includes("\r")||e.includes(`
5
- `)||e.includes("\0")),B=(e,t)=>{if(e===null)return{kind:"full"};const r=H.exec(e.trim());if(!r)return{kind:"full"};const n=r[1]??"",a=r[2]??"";if(n===""&&a==="")return{kind:"full"};let c,o;if(n===""){const s=Number(a);if(s===0)return{kind:"unsatisfiable"};c=Math.max(0,t-s),o=t-1}else c=Number(n),o=a===""?t-1:Math.min(Number(a),t-1);return c>o||c>=t?{kind:"unsatisfiable"}:{end:o,kind:"partial",start:c}},W=async(e,t,r)=>{const n=await e.storage.download(t);if(!n)return new Response("Not Found",{status:404});const a=n.httpMetadata?.contentType,o={"accept-ranges":"bytes","content-type":a!==void 0&&$(a)?a:"application/octet-stream",etag:w(n.etag)};n.sha256Base64!==void 0&&(o["repr-digest"]=`sha-256=:${n.sha256Base64}:`);const s=B(r.headers.get("range"),n.size);if(s.kind==="unsatisfiable")return n.body?.cancel().catch(()=>{}),new Response("Range Not Satisfiable",{headers:{"accept-ranges":"bytes","content-range":`bytes */${String(n.size)}`,"content-type":"text/plain; charset=utf-8",etag:w(n.etag)},status:416});if(s.kind==="full")return new Response(n.body,{headers:{...o,"content-length":String(n.size)},status:200});n.body?.cancel().catch(()=>{});const u=s.end-s.start+1,i=await e.storage.download(t,{range:{length:u,offset:s.start}});return i?new Response(i.body,{headers:{...o,"content-length":String(u),"content-range":`bytes ${String(s.start)}-${String(s.end)}/${String(n.size)}`},status:206}):new Response("Not Found",{status:404})};export{M as httpAction,U as httpRoute,F as httpRouter,$ as isSafeHeaderValue,W as serveStorageObject};
@@ -1 +0,0 @@
1
- import{v as f}from"./functions-B2-H4PQT.mjs";import{readMaskTag as M}from"./buildMaskRegistry-72SL8fJn.mjs";import{r as h}from"./policy-tag-D4RzgQnw.mjs";import{r as j}from"./run-middleware-B-JeGGp9.mjs";const x=(e,r)=>r===void 0||typeof e!="object"||e===null?e:Object.assign(Object.create(Object.getPrototypeOf(e)),e,{meta:r}),i=(e,r)=>j(e,r,o=>o),_=(e,r,o,a,n)=>async(s,u)=>{const c=f(e,u),t=await i(r,x(s,n)),l=await o({args:c,ctx:t});return a?a.parse(l):l},q=(e,r,o,a)=>(n,s,u)=>{const c=f(e,s);return(async function*(){const l=await i(r,x(n,a)),m=o({args:c,ctx:l,signal:u})[Symbol.asyncIterator]();try{for(;;){if(u.aborted)return;const w=await m.next();if(w.done||u.aborted)return;yield w.value}}finally{await m.return?.()}})()},g=e=>{const r=e.map(o=>h(o)).filter(o=>o!==void 0);return r.length>0?{tags:r}:void 0},p=e=>{const r=new Map;for(const o of e){const a=M(o);if(a)for(const[n,s]of a.columns){const u=r.get(n)??new Set;for(const c of s)u.add(c);r.set(n,u)}}return r.size>0?r:void 0},d=(e,r,o)=>({__lunoraProcedure:e,...o?{__lunoraVisibility:o}:{},input:a=>d(e,{...r,args:{...r.args,...a}},o),[e]:a=>{const n=g(r.middlewares),s=p(r.middlewares);return{args:r.args,...r.expose?{expose:r.expose}:{},handler:_(r.args,r.middlewares,a,r.output,r.meta),kind:e,...s?{maskedTables:s}:{},...r.meta?{meta:r.meta}:{},...n?{rls:n}:{},...o?{visibility:o}:{},...r.x402?{x402:r.x402}:{}}},meta:a=>d(e,{...r,meta:Object.freeze({...r.meta,...a})},o),output:a=>d(e,{...r,output:a},o),...e==="query"?{stream:(a,n)=>{const s=g(r.middlewares),u=p(r.middlewares),c=n?.durable===!0?{}:n?.durable;return{args:r.args,...c?{durable:c}:{},...r.expose?{expose:r.expose}:{},handler:q(r.args,r.middlewares,a,r.meta),kind:"stream",...u?{maskedTables:u}:{},...r.meta?{meta:r.meta}:{},...s?{rls:s}:{},...o?{visibility:o}:{},...r.x402?{x402:r.x402}:{}}}}:{},use:a=>d(e,{...r,middlewares:[...r.middlewares,a]},o),...o?{}:{expose:a=>d(e,{...r,expose:a},o)},...o?{}:{x402:a=>d(e,{...r,x402:a},o)}}),y={dataModel:()=>({create:e=>({action:d("action",{args:{},middlewares:[]}),internalAction:d("action",{args:{},middlewares:[]},"internal"),internalMutation:d("mutation",{args:{},middlewares:[]},"internal"),internalQuery:d("query",{args:{},middlewares:[]},"internal"),mutation:d("mutation",{args:{},middlewares:[]}),query:d("query",{args:{},middlewares:[]})})})};export{y as initLunora};
@@ -1 +0,0 @@
1
- import{LunoraError as P}from"./LunoraError-DcKdk9Ti.mjs";import{bindTableFacade as j,bindOrm as E}from"./bindOrm-lWdeDi9P.mjs";import{i as _,a as D,o as v,b as K}from"./middleware-DEW0yLvU.mjs";import{tagMaskMiddleware as q}from"./buildMaskRegistry-72SL8fJn.mjs";const G=e=>{let i=2166136261;for(let c=0;c<e.length;c+=1)i^=e.codePointAt(c)??0,i=Math.imul(i,16777619);return(i>>>0).toString(16).padStart(8,"0")},L=(e,i,c)=>{try{return e==="redact"?null:e==="hash"?i==null?i:G(typeof i=="string"?i:JSON.stringify(i)):e(i,c)}catch{return null}},a=(e,i,c)=>{const y={...e};for(const[h,g]of Object.entries(i))h in y&&(y[h]=L(g,e[h],{...c,column:h,row:e}));return y},W=(e,i,c)=>({...e,page:e.page.map(y=>a(y,i,c))}),B=(e,i,c,y)=>{if(typeof e!="function")return;const h=new Set,g=()=>new Proxy({},{get:()=>f=>(typeof f=="string"&&h.add(f),g())});e(g());for(const f of h)if(f in i)throw new P("MASK_UNSUPPORTED",`${y}() filtering "${c}" by masked column "${f}" is not supported`)},m=(e,i,c,y)=>{const h=e.rankBefore,g=e.rankPageRows,f=(r,n)=>{const t=i.get(r);return t?n.map(o=>a(o,t,c)):n},p=r=>{const n=r?.relationMask;return{...r,relationMask:n===void 0?f:(t,o)=>n(t,f(t,o))}},k=(r,n,t,o)=>{const s=i.get(r);if(!s)return;const d=y?.[r]?.[o]?.[n];if(!d)return;const w=d.find($=>$ in s);if(w!==void 0)throw new P("MASK_UNSUPPORTED",`${t}() reading "${r}" via index "${n}" would order rows by masked column "${w}" — use an index whose declared fields are all unmasked, or unmask the column`)},l=(r,n,t)=>({async*[Symbol.asyncIterator](){for await(const o of{[Symbol.asyncIterator]:()=>r[Symbol.asyncIterator]()})yield a(o,n,c)},collect:async()=>(await r.collect()).map(s=>a(s,n,c)),collectWithScores:async()=>(await r.collectWithScores()).map(s=>{const d=a(s.document,n,c);return"distanceMeters"in s?{distanceMeters:null,document:d}:{document:d,score:s.score}}),filter:o=>l(r.filter(s=>o(a(s,n,c))),n,t),first:async()=>{const o=await r.first();return o?a(o,n,c):null},order:o=>l(r.order(o),n,t),paginate:async o=>W(await r.paginate(o),n,c),take:async o=>(await r.take(o)).map(d=>a(d,n,c)),unique:async()=>{const o=await r.unique();return o?a(o,n,c):null},withIndex:(o,s)=>(k(t,o,"withIndex","index"),B(s,n,t,"withIndex"),l(r.withIndex(o,s),n,t)),withSearchIndex:(o,s)=>(B(s,n,t,"withSearchIndex"),l(r.withSearchIndex(o,s),n,t)),withGeoIndex:(o,s)=>(k(t,o,"withGeoIndex","geo"),l(r.withGeoIndex(o,s),n,t))}),S=async(r,n)=>{if(e.lookupById){const w=await e.lookupById(r,n);return w?{row:w.row,tableName:i.has(w.tableName)?w.tableName:void 0}:{row:null,tableName:void 0}}const t=await e.get(r,n);if(!t)return{row:null,tableName:void 0};const o=n!==void 0&&i.has(n)?[n]:[],s=n===void 0?[...i.keys()]:o,d=await Promise.all(s.map(async w=>(await e.findFirst(w,{limit:1,where:{_id:r}}))?._id===r?w:void 0));return{row:t,tableName:d.find(w=>w!==void 0)}},M=(r,n,t)=>{const o=i.get(r);if(!o)return;const s=n.find(d=>typeof d=="string"&&d in o);if(s!==void 0)throw new P("MASK_UNSUPPORTED",`${t}() over masked column "${s}" on "${r}" is not supported`)},R=(r,n)=>{if(!(!r||typeof r!="object"||Array.isArray(r)))for(const[t,o]of Object.entries(r))if(t==="AND"||t==="OR"){if(Array.isArray(o))for(const s of o)R(s,n)}else t==="NOT"?R(o,n):t.startsWith("__")||n.add(t)},u=(r,n,t)=>{const o=i.get(r);if(!o||n===void 0)return;const s=new Set;R(n,s);for(const d of s)if(d in o)throw new P("MASK_UNSUPPORTED",`${t}() filtering "${r}" by masked column "${d}" is not supported`)},I=(r,n,t)=>{const o=i.get(r);if(!(!o||!Array.isArray(n))){for(const s of n)if(s&&typeof s=="object"&&!Array.isArray(s)){for(const d of Object.keys(s))if(d in o)throw new P("MASK_UNSUPPORTED",`${t}() ordering "${r}" by masked column "${d}" is not supported`)}}},F=r=>r&&typeof r=="object"&&!Array.isArray(r)?r:void 0,A=(r,n,t)=>{const o=F(n);u(r,o?.where,t),u(r,o?.baseWhere,t)},O={...e,async deleteWhere(r,n,t){if(u(r,n,"deleteMany({ where })"),e.deleteWhere===void 0)throw new P("INTERNAL",`ctx.db.${r}.deleteMany({ where }) is unavailable: this writer has no where-based delete`);return e.deleteWhere(r,n,t)},async patchWhere(r,n,t){if(u(r,n.where,"patchMany({ where })"),e.patchWhere===void 0)throw new P("INTERNAL",`ctx.db.${r}.patchMany({ where }) is unavailable: this writer has no where-based patch`);return e.patchWhere(r,n,t)},aggregate(r,n){return M(r,[n.field],"aggregate"),u(r,n.where,"aggregate"),e.aggregate(r,n)},count(r,n){const t=F(n),o=t&&("where"in t||"baseWhere"in t||"restrictsCounts"in t)?t.where:n;return u(r,o,"count"),t&&u(r,t.baseWhere,"count"),e.count(r,n)},async findFirst(r,n){u(r,n?.where,"findFirst"),u(r,n?.baseWhere,"findFirst"),I(r,n?.orderBy,"findFirst");const t=await e.findFirst(r,p(n)),o=i.get(r);return t&&o?a(t,o,c):t},async findFirstOrThrow(r,n){u(r,n?.where,"findFirstOrThrow"),u(r,n?.baseWhere,"findFirstOrThrow"),I(r,n?.orderBy,"findFirstOrThrow");const t=await e.findFirstOrThrow(r,p(n)),o=i.get(r);return o?a(t,o,c):t},async findMany(r,n){u(r,n?.where,"findMany"),u(r,n?.baseWhere,"findMany"),I(r,n?.orderBy,"findMany");const t=await e.findMany(r,p(n)),o=i.get(r);return o?W(t,o,c):t},async get(r,n){const{row:t,tableName:o}=await S(r,n),s=o===void 0?void 0:i.get(o);return!t||!s?t:a(t,s,c)},async lookupById(r,n){const t=await e.lookupById?.(r,n);if(!t)return null;const o=i.get(t.tableName);return{row:o?a(t.row,o,c):t.row,tableName:t.tableName}},groupBy(r,n){return M(r,[...n.by,n.agg?.field],"groupBy"),u(r,n.where,"groupBy"),e.groupBy(r,n)},query(r){const n=e.query(r),t=i.get(r);return t?l(n,t,r):n},async rank(r,n,t){return A(r,t,"rank"),k(r,n,"rank","rank"),e.rank(r,n,t)},async rankPage(r,n,t){A(r,t,"rankPage"),k(r,n,"rankPage","rank");const o=await e.rankPage(r,n,t),s=i.get(r);return s?W(o,s,c):o},...v("rankBefore",h,r=>(n,t,o)=>(A(n,o,"rankBefore"),k(n,t,"rankBefore","rank"),r(n,t,o))),...v("rankPageRows",g,r=>async(n,t,o)=>{A(n,o,"rankPageRows"),k(n,t,"rankPageRows","rank");const s=await r(n,t,o),d=i.get(n);return d?{...s,rows:s.rows.map(w=>({...w,doc:a(w.doc,d,c)}))}:s})},U=O;for(const r of i.keys())K(e[r])&&(U[r]=j(O,r));return O},Q=(e,i={})=>{const c=new Map(Object.entries(e)),y=_(i.roles),h=async({ctx:f,next:p})=>{const k={auth:await D(f.auth??{},y),ctx:f};if(i.bypass?.(k))return p();const l=m(f.db,c,k,i.indexFields),S={db:l},{orm:M}=f;return M!==null&&typeof M=="object"&&(S.orm=E(l)),p({ctx:S})},g=new Map;for(const[f,p]of c)g.set(f,new Set(Object.keys(p)));return q(h,{columns:g})};export{Q as mask};
@@ -1 +0,0 @@
1
- const c=(t,e)=>{let r=e;for(let i=0;i<t.length;i+=1)r^=t.codePointAt(i)??0,r=Math.imul(r,16777619)>>>0;return r.toString(16).padStart(8,"0")},f=t=>`${c(t,2166136261)}${c(t,16777619)}`,y=(t,e)=>t<e?-1:t>e?1:0,s=t=>{if(t===void 0)return"null";if(typeof t=="bigint")throw new TypeError("stableStringify: cannot use a bigint in a stable JSON cache key — pass it as a string, or use stableWireKey");if(typeof t=="number"){if(Number.isNaN(t))return"nan";if(t===1/0)return"inf";if(t===-1/0)return"-inf";if(Object.is(t,-0))return"-0"}if(t===null||typeof t!="object")return JSON.stringify(t);if(Array.isArray(t))return`[${t.map(n=>s(n)).join(",")}]`;const e=Object.getPrototypeOf(t);if(e!==null&&e!==Object.prototype){const n=t.constructor?.name??"value";throw new TypeError(`stableStringify: cannot use a ${n} in a stable JSON cache key — only plain objects, arrays, and JSON primitives are supported (wire-typed values key via stableWireKey)`)}const r=t,i=Object.keys(r).toSorted(y),o=[];for(const n of i){const a=r[n];a!==void 0&&o.push(`${JSON.stringify(n)}:${s(a)}`)}return`{${o.join(",")}}`},p=(t,e)=>({args:{},handler:async(r,i)=>{const o=await t(r),n=f(s(o));return n===i?.previousDigest?{digest:n,ran:!1}:(await e(r,o),{digest:n,ran:!0})},kind:"mutation",lifecycle:"reactor",visibility:"internal"});export{p as onQueryChange};
@@ -1 +0,0 @@
1
- import{LunoraError as y}from"./LunoraError-DcKdk9Ti.mjs";import{i as U,a as v}from"./middleware-DEW0yLvU.mjs";const D=(o,e)=>o===void 0||e.startsWith(o),k=o=>{const e=o[1],c=typeof e=="object"&&e!==null?e.method:void 0;return typeof c=="string"&&c.toUpperCase()==="PUT"?"write":"read"},E=[["delete","delete"],["download","read"],["generateUploadUrl","write"],["getMetadata","read"],["getSignedUrl",k],["getUrl","read"],["store","write"]],S=(o,e={})=>{const c=U(e.roles);return async({ctx:u,next:f})=>{const h=await v(u.auth??{},c),g=(n,r,s)=>{const a=o.filter(t=>t.on===n&&t.bucket===s);if(a.length===0)return;const i={auth:h,ctx:u,key:r};if(!a.some(t=>D(t.prefix,r)&&t.when(i)===!0))throw new y("FORBIDDEN",`storage ${n} on "${r}" in bucket "${s}" denied by access rule`)},p=n=>{const r=n.bucketName??"default",s={bucketName:r};for(const[i,l]of E){const t=n[i];typeof t=="function"&&(s[i]=(...d)=>{const m=typeof d[0]=="string"?d[0]:"",b=typeof l=="function"?l(d):l;return g(b,m,r),t(...d)})}const{bucket:a}=n;return typeof a=="function"&&(s.bucket=i=>p(a(i))),s},w=u.storage;return w===void 0?f():f({ctx:{storage:p(w)}})}};export{S as storageRules};