@lunora/server 1.0.0-alpha.172 → 1.0.0-alpha.173
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 +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/storageRules-1GWSFFnl.mjs +1 -0
- package/dist/types.d.mts +339 -211
- package/dist/types.d.ts +339 -211
- package/package.json +3 -3
- package/dist/packem_shared/storageRules-DSmSbQqS.mjs +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Validator, Infer, v, Id, ValidatorMap, InferValidatorMap, ColumnValidator } 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, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, GlobalBackend, RelationDefinition, OnDeleteAction, SearchLanguage, SearchStrategy, ExternalSourceDefinition, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, DurableObjectJurisdiction, AggregateIndexDefinition, RankIndexDefinition, Secrets, LifecycleEvent, ShardInitEvent, RegisteredLifecycleHook, WhisperEvent } 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 MutationStorage, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type RelatedDirection, type RelatedNode, type RelatedOptions, type RelatedPage, type RelatedStart, type RelatedStartReference, type RestCacheConfig, type RetryPolicy, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type SpanContextIds, type SpanEvaluation, type SpanHandle, type SpanIdentity, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type StorageObjectBody, type StorageObjectHead, type StorageRange, 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 WorkflowInstanceEvent, 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 MutationStorage, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type RelatedDirection, type RelatedNode, type RelatedOptions, type RelatedPage, type RelatedStart, type RelatedStartReference, type RestCacheConfig, type RetryPolicy, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type SpanContextIds, type SpanEvaluation, type SpanHandle, type SpanIdentity, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageListOptions, type StorageListResult, type StorageMetadata, type StorageMultipartUpload, type StorageMultipartUploadOptions, type StorageObjectBody, type StorageObjectHead, type StorageRange, type StorageUploadBody, type StorageUploadOptions, type StorageUploadResult, type StorageUploadedPart, 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 WorkflowInstanceEvent, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.mjs";
|
|
5
5
|
import { LunoraError } from '@lunora/errors';
|
|
6
6
|
export { LunoraError, type LunoraErrorCode } from '@lunora/errors';
|
|
7
7
|
import { Context, Hono } from 'hono';
|
|
@@ -3659,14 +3659,17 @@ interface RegisteredShape<Args extends ValidatorMap = ValidatorMap, Context = Qu
|
|
|
3659
3659
|
declare const defineShape: <Args extends ValidatorMap = ValidatorMap, Context = QueryCtx>(definition: ShapeDefinition<Args, Context>) => RegisteredShape<Args, Context>;
|
|
3660
3660
|
/**
|
|
3661
3661
|
* Operations a storage rule can gate. `read` covers `download` / `getMetadata` /
|
|
3662
|
-
* `head` / `getSignedUrl` / `getUrl`; `write` covers `store` /
|
|
3663
|
-
* `generateUploadUrl
|
|
3662
|
+
* `head` / `getSignedUrl` / `getUrl`; `write` covers `store` / `upload` /
|
|
3663
|
+
* `generateUploadUrl` / `createMultipartUpload` / `resumeMultipartUpload`;
|
|
3664
|
+
* `delete` covers `delete` and the `deleteAfterCommit`
|
|
3664
3665
|
* enqueue; `list` is a prefix listing.
|
|
3665
3666
|
*
|
|
3666
3667
|
* `list` governs `ctx.db.system.query("_storage")` — the object enumeration
|
|
3667
3668
|
* reachable from a handler — plus the file browser / admin path. It governs
|
|
3668
|
-
* nothing on `ctx.storage
|
|
3669
|
-
*
|
|
3669
|
+
* nothing on `ctx.storage`: the action-only `ctx.storage.list` is not a gated
|
|
3670
|
+
* method, so `storageRules` refuses it with `FORBIDDEN` rather than enforcing
|
|
3671
|
+
* it. Note the
|
|
3672
|
+
* enumeration is additionally narrowed by the bucket's `read`
|
|
3670
3673
|
* rules, so a `read` prefix rule scopes what a handler can enumerate even with
|
|
3671
3674
|
* no `list` rule declared.
|
|
3672
3675
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Validator, Infer, v, Id, ValidatorMap, InferValidatorMap, ColumnValidator } 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, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, GlobalBackend, RelationDefinition, OnDeleteAction, SearchLanguage, SearchStrategy, ExternalSourceDefinition, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, DurableObjectJurisdiction, AggregateIndexDefinition, RankIndexDefinition, Secrets, LifecycleEvent, ShardInitEvent, RegisteredLifecycleHook, WhisperEvent } 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 MutationStorage, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type RelatedDirection, type RelatedNode, type RelatedOptions, type RelatedPage, type RelatedStart, type RelatedStartReference, type RestCacheConfig, type RetryPolicy, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type SpanContextIds, type SpanEvaluation, type SpanHandle, type SpanIdentity, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type StorageObjectBody, type StorageObjectHead, type StorageRange, 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 WorkflowInstanceEvent, 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 MutationStorage, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type RelatedDirection, type RelatedNode, type RelatedOptions, type RelatedPage, type RelatedStart, type RelatedStartReference, type RestCacheConfig, type RetryPolicy, type RunQueryOptions, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type SpanContextIds, type SpanEvaluation, type SpanHandle, type SpanIdentity, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageListOptions, type StorageListResult, type StorageMetadata, type StorageMultipartUpload, type StorageMultipartUploadOptions, type StorageObjectBody, type StorageObjectHead, type StorageRange, type StorageUploadBody, type StorageUploadOptions, type StorageUploadResult, type StorageUploadedPart, 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 WorkflowInstanceEvent, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.js";
|
|
5
5
|
import { LunoraError } from '@lunora/errors';
|
|
6
6
|
export { LunoraError, type LunoraErrorCode } from '@lunora/errors';
|
|
7
7
|
import { Context, Hono } from 'hono';
|
|
@@ -3659,14 +3659,17 @@ interface RegisteredShape<Args extends ValidatorMap = ValidatorMap, Context = Qu
|
|
|
3659
3659
|
declare const defineShape: <Args extends ValidatorMap = ValidatorMap, Context = QueryCtx>(definition: ShapeDefinition<Args, Context>) => RegisteredShape<Args, Context>;
|
|
3660
3660
|
/**
|
|
3661
3661
|
* Operations a storage rule can gate. `read` covers `download` / `getMetadata` /
|
|
3662
|
-
* `head` / `getSignedUrl` / `getUrl`; `write` covers `store` /
|
|
3663
|
-
* `generateUploadUrl
|
|
3662
|
+
* `head` / `getSignedUrl` / `getUrl`; `write` covers `store` / `upload` /
|
|
3663
|
+
* `generateUploadUrl` / `createMultipartUpload` / `resumeMultipartUpload`;
|
|
3664
|
+
* `delete` covers `delete` and the `deleteAfterCommit`
|
|
3664
3665
|
* enqueue; `list` is a prefix listing.
|
|
3665
3666
|
*
|
|
3666
3667
|
* `list` governs `ctx.db.system.query("_storage")` — the object enumeration
|
|
3667
3668
|
* reachable from a handler — plus the file browser / admin path. It governs
|
|
3668
|
-
* nothing on `ctx.storage
|
|
3669
|
-
*
|
|
3669
|
+
* nothing on `ctx.storage`: the action-only `ctx.storage.list` is not a gated
|
|
3670
|
+
* method, so `storageRules` refuses it with `FORBIDDEN` rather than enforcing
|
|
3671
|
+
* it. Note the
|
|
3672
|
+
* enumeration is additionally narrowed by the bucket's `read`
|
|
3670
3673
|
* rules, so a `read` prefix rule scopes what a handler can enumerate even with
|
|
3671
3674
|
* no `list` rule declared.
|
|
3672
3675
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ACTION_CACHE_DEFAULT_TTL_MS as t,ACTION_CACHE_TABLE as i,actionCacheExtension as n,cacheKeyFor as a,defineActionCache as f}from"./packem_shared/ACTION_CACHE_DEFAULT_TTL_MS-DHpfdhmu.mjs";import{initLunora as d}from"./packem_shared/initLunora-DAbEYdSo.mjs";import{isPerDispatchMiddleware as m,tagPerDispatchMiddleware as x}from"./packem_shared/isPerDispatchMiddleware-DDQPatSm.mjs";import{createSecrets as l}from"./packem_shared/createSecrets-D6rLB42U.mjs";import{beginDeferredDeletes as h,flushDeferredDeletes as S,withDeferredDeletes as u}from"./packem_shared/beginDeferredDeletes-DhwFBbvs.mjs";import{beginDeferredSchedules as T,withDeferredSchedules as g}from"./packem_shared/beginDeferredSchedules-DJ6U4iq5.mjs";import{DOCUMENT_HISTORY_REDACTED_FIELDS as R,DOCUMENT_HISTORY_TABLE as _,defineDocumentHistory as L,documentHistoryExtension as C}from"./packem_shared/DOCUMENT_HISTORY_REDACTED_FIELDS-DAfomt5Q.mjs";import{LunoraEnvError as M,defineEnv as P,redactSecrets as b}from"./packem_shared/LunoraEnvError-A5I-PzMh.mjs";import{bindOrm as F,bindTableFacade as O}from"./packem_shared/bindOrm-D_hFUjmr.mjs";import{httpAction as N,httpRoute as w,httpRouter as U,isSafeHeaderValue as k}from"./packem_shared/httpAction-DFVhrm8u.mjs";import{serveStorageObject as B}from"./packem_shared/serveStorageObject-9mdw0nyU.mjs";import{defineIdentity as W}from"./packem_shared/defineIdentity-DwkNKwYa.mjs";import{onConnect as Y,onDisconnect as J,onShardInit as K}from"./packem_shared/onConnect-BLRoOpv2.mjs";import{DEFAULT_LIMIT as X,DEFAULT_MAX_LIMIT as q,clampLimit as z,defineListArgs as G}from"./packem_shared/DEFAULT_LIMIT-pT_tV8R0.mjs";import{defineMigration as $}from"./packem_shared/defineMigration-CXOS0Bvq.mjs";import{defineModule as re}from"./packem_shared/defineModule-OecXWM3U.mjs";import{defineMutator as te}from"./packem_shared/defineMutator-DKy8UtbB.mjs";import{c as ne,d as ae,a as fe,b as se,e as de,f as pe,g as me,h as xe,i as ce,j as le,k as Ee,m as he}from"./packem_shared/plugin-DRIqze14.mjs";import{PRESENCE_DEFAULT_TTL_MS as ue,PRESENCE_TABLE as De,definePresence as Te,presenceExtension as ge}from"./packem_shared/PRESENCE_DEFAULT_TTL_MS-DObDBz6_.mjs";import{protectPublic as Re}from"./packem_shared/protectPublic-BUYCMZZB.mjs";import{onQueryChange as Le}from"./packem_shared/onQueryChange-CatdYnH5.mjs";import{createServices as Ie}from"./packem_shared/createServices-IJvoqi0e.mjs";import{defineShape as Pe}from"./packem_shared/defineShape-CbHQpfYD.mjs";import{anyApi as ye}from"./types.mjs";import{onWhisper as Oe}from"./packem_shared/onWhisper-CfDbFLQh.mjs";import{LunoraError as Ne}from"@lunora/errors";import{cronJobs as Ue}from"@lunora/scheduler";import{ValidationError as ve,v as Be}from"@lunora/values";import{allowAll as We,deny as je,isDeny as Ye,toWhereInput as Je}from"./packem_shared/allowAll-DkRAgItV.mjs";import{asBucketStorage as Qe}from"./packem_shared/asBucketStorage-DoGYOjq3.mjs";import{assertShapesDeclareReadPolicies as qe,buildRlsReadRegistry as ze,composeShapeReadWhere as Ge}from"./packem_shared/assertShapesDeclareReadPolicies-d9t7YZ7U.mjs";import{buildMaskRegistry as $e}from"./packem_shared/buildMaskRegistry-DpWMtalG.mjs";import{createPolicyDsl as rr,definePermission as or,definePolicies as tr,definePolicy as ir,defineRole as nr}from"./packem_shared/createPolicyDsl-BZa6SqLJ.mjs";import{defineStorageRule as fr,defineStorageRules as sr}from"./packem_shared/defineStorageRule-Dv4nJE0H.mjs";import{mask as pr}from"./packem_shared/mask-DrapWB_J.mjs";import{r as xr}from"./packem_shared/middleware-ChNz4wOv.mjs";import{storageRules as lr}from"./packem_shared/storageRules-
|
|
1
|
+
import{ACTION_CACHE_DEFAULT_TTL_MS as t,ACTION_CACHE_TABLE as i,actionCacheExtension as n,cacheKeyFor as a,defineActionCache as f}from"./packem_shared/ACTION_CACHE_DEFAULT_TTL_MS-DHpfdhmu.mjs";import{initLunora as d}from"./packem_shared/initLunora-DAbEYdSo.mjs";import{isPerDispatchMiddleware as m,tagPerDispatchMiddleware as x}from"./packem_shared/isPerDispatchMiddleware-DDQPatSm.mjs";import{createSecrets as l}from"./packem_shared/createSecrets-D6rLB42U.mjs";import{beginDeferredDeletes as h,flushDeferredDeletes as S,withDeferredDeletes as u}from"./packem_shared/beginDeferredDeletes-DhwFBbvs.mjs";import{beginDeferredSchedules as T,withDeferredSchedules as g}from"./packem_shared/beginDeferredSchedules-DJ6U4iq5.mjs";import{DOCUMENT_HISTORY_REDACTED_FIELDS as R,DOCUMENT_HISTORY_TABLE as _,defineDocumentHistory as L,documentHistoryExtension as C}from"./packem_shared/DOCUMENT_HISTORY_REDACTED_FIELDS-DAfomt5Q.mjs";import{LunoraEnvError as M,defineEnv as P,redactSecrets as b}from"./packem_shared/LunoraEnvError-A5I-PzMh.mjs";import{bindOrm as F,bindTableFacade as O}from"./packem_shared/bindOrm-D_hFUjmr.mjs";import{httpAction as N,httpRoute as w,httpRouter as U,isSafeHeaderValue as k}from"./packem_shared/httpAction-DFVhrm8u.mjs";import{serveStorageObject as B}from"./packem_shared/serveStorageObject-9mdw0nyU.mjs";import{defineIdentity as W}from"./packem_shared/defineIdentity-DwkNKwYa.mjs";import{onConnect as Y,onDisconnect as J,onShardInit as K}from"./packem_shared/onConnect-BLRoOpv2.mjs";import{DEFAULT_LIMIT as X,DEFAULT_MAX_LIMIT as q,clampLimit as z,defineListArgs as G}from"./packem_shared/DEFAULT_LIMIT-pT_tV8R0.mjs";import{defineMigration as $}from"./packem_shared/defineMigration-CXOS0Bvq.mjs";import{defineModule as re}from"./packem_shared/defineModule-OecXWM3U.mjs";import{defineMutator as te}from"./packem_shared/defineMutator-DKy8UtbB.mjs";import{c as ne,d as ae,a as fe,b as se,e as de,f as pe,g as me,h as xe,i as ce,j as le,k as Ee,m as he}from"./packem_shared/plugin-DRIqze14.mjs";import{PRESENCE_DEFAULT_TTL_MS as ue,PRESENCE_TABLE as De,definePresence as Te,presenceExtension as ge}from"./packem_shared/PRESENCE_DEFAULT_TTL_MS-DObDBz6_.mjs";import{protectPublic as Re}from"./packem_shared/protectPublic-BUYCMZZB.mjs";import{onQueryChange as Le}from"./packem_shared/onQueryChange-CatdYnH5.mjs";import{createServices as Ie}from"./packem_shared/createServices-IJvoqi0e.mjs";import{defineShape as Pe}from"./packem_shared/defineShape-CbHQpfYD.mjs";import{anyApi as ye}from"./types.mjs";import{onWhisper as Oe}from"./packem_shared/onWhisper-CfDbFLQh.mjs";import{LunoraError as Ne}from"@lunora/errors";import{cronJobs as Ue}from"@lunora/scheduler";import{ValidationError as ve,v as Be}from"@lunora/values";import{allowAll as We,deny as je,isDeny as Ye,toWhereInput as Je}from"./packem_shared/allowAll-DkRAgItV.mjs";import{asBucketStorage as Qe}from"./packem_shared/asBucketStorage-DoGYOjq3.mjs";import{assertShapesDeclareReadPolicies as qe,buildRlsReadRegistry as ze,composeShapeReadWhere as Ge}from"./packem_shared/assertShapesDeclareReadPolicies-d9t7YZ7U.mjs";import{buildMaskRegistry as $e}from"./packem_shared/buildMaskRegistry-DpWMtalG.mjs";import{createPolicyDsl as rr,definePermission as or,definePolicies as tr,definePolicy as ir,defineRole as nr}from"./packem_shared/createPolicyDsl-BZa6SqLJ.mjs";import{defineStorageRule as fr,defineStorageRules as sr}from"./packem_shared/defineStorageRule-Dv4nJE0H.mjs";import{mask as pr}from"./packem_shared/mask-DrapWB_J.mjs";import{r as xr}from"./packem_shared/middleware-ChNz4wOv.mjs";import{storageRules as lr}from"./packem_shared/storageRules-1GWSFFnl.mjs";const e="0.0.0";export{t as ACTION_CACHE_DEFAULT_TTL_MS,i as ACTION_CACHE_TABLE,X as DEFAULT_LIMIT,q as DEFAULT_MAX_LIMIT,R as DOCUMENT_HISTORY_REDACTED_FIELDS,_ as DOCUMENT_HISTORY_TABLE,M as LunoraEnvError,Ne as LunoraError,ue as PRESENCE_DEFAULT_TTL_MS,De as PRESENCE_TABLE,e as VERSION,ve as ValidationError,n as actionCacheExtension,We as allowAll,ye as anyApi,Qe as asBucketStorage,qe as assertShapesDeclareReadPolicies,h as beginDeferredDeletes,T as beginDeferredSchedules,F as bindOrm,O as bindTableFacade,$e as buildMaskRegistry,ze as buildRlsReadRegistry,a as cacheKeyFor,z as clampLimit,ne as composePluginMiddleware,Ge as composeShapeReadWhere,rr as createPolicyDsl,l as createSecrets,Ie as createServices,Ue as cronJobs,f as defineActionCache,ae as defineAggregateIndex,fe as defineComponent,L as defineDocumentHistory,P as defineEnv,W as defineIdentity,G as defineListArgs,$ as defineMigration,re as defineModule,te as defineMutator,or as definePermission,se as definePlugin,tr as definePolicies,ir as definePolicy,Te as definePresence,de as defineRankIndex,nr as defineRole,pe as defineSchema,me as defineSchemaExtension,Pe as defineShape,fr as defineStorageRule,sr as defineStorageRules,xe as defineTable,ce as defineVectorIndex,je as deny,C as documentHistoryExtension,S as flushDeferredDeletes,N as httpAction,w as httpRoute,U as httpRouter,le as indexFieldsFromSchema,d as initLunora,Ee as installPlugins,Ye as isDeny,m as isPerDispatchMiddleware,k as isSafeHeaderValue,pr as mask,he as mergeSchemaExtension,Y as onConnect,J as onDisconnect,Le as onQueryChange,K as onShardInit,Oe as onWhisper,ge as presenceExtension,Re as protectPublic,b as redactSecrets,xr as rls,B as serveStorageObject,lr as storageRules,x as tagPerDispatchMiddleware,Je as toWhereInput,Be as v,u as withDeferredDeletes,g as withDeferredSchedules};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as k}from"@lunora/errors";import{i as A,a as D}from"./middleware-ChNz4wOv.mjs";const E=(e,t,o)=>{const i=n=>o.isAllowed("list",n,t)&&o.isAllowed("read",n,t),{get:c,query:g}=e,f={...e},b=n=>n.filter(r=>typeof r.key=="string"&&i(r.key));return typeof c=="function"&&(f.get=async(n,r)=>(n==="_storage"&&o.assertAllowed("read",r,t),c(n,r))),typeof g=="function"&&(f.query=n=>{const r=g(n),{collect:p}=r;return n!=="_storage"||typeof p!="function"?r:{...r,collect:async()=>b(await p())}}),f},N=(e,t)=>{if(e===void 0)return!0;const o=e.endsWith("/")?e.slice(0,-1):e;return o===""||t===o||t.startsWith(`${o}/`)},S=e=>{const t=e[1],o=typeof t=="object"&&t!==null?t.method:void 0;return typeof o=="string"&&o.toUpperCase()==="PUT"?"write":"read"},M=[["createMultipartUpload","write"],["delete","delete"],["deleteAfterCommit","delete"],["download","read"],["generateUploadUrl","write"],["getMetadata","read"],["getSignedUrl",S],["getUrl","read"],["head","read"],["resumeMultipartUpload","write"],["store","write"],["upload","write"]],$=[["getPresignedUrl","ctx.storage.getPresignedUrl is not available under storageRules(...): a presigned URL reaches R2 directly, past every rule. Use getSignedUrl or generateUploadUrl, which route back through the Worker."],["list",'ctx.storage.list is not available under storageRules(...); enumerate via ctx.db.system.query("_storage"), which the rules filter.']],P=(e,t)=>{try{return e(t).bucketName===t}catch{return!1}},B=(e,t)=>{const o=e.bucketName??"default",{bucket:i}=e;for(const c of new Set(t))if(!(c===o||typeof i=="function"&&P(i,c)))throw new k("INTERNAL",`storageRules: rule for bucket "${c}" governs nothing — this request's storage cannot address that bucket (the accessor is "${o}", and selecting "${c}" does not reach a bucket of that name). A rule on an unaddressable bucket leaves the operation it was written to gate wide open. Match the rule's \`bucket\` to the name the binding is registered under in \`.storage({ bucket, buckets })\`.`)},_=(e,t={})=>{const o=A(t.roles);return async({ctx:i,next:c})=>{const g=await D(i.auth??{},o),f=(s,d,u)=>{const h=e.filter(a=>a.on===s&&a.bucket===u);if(h.length===0)return!0;const l={auth:g,ctx:i,key:d};return h.some(a=>N(a.prefix,d)&&a.when(l)===!0)},b=(s,d,u)=>{if(!f(s,d,u))throw new k("FORBIDDEN",`storage ${s} on "${d}" in bucket "${u}" denied by access rule`)},n=s=>{const d=s.bucketName??"default",u={bucketName:d};for(const[l,a]of M){const U=s[l];typeof U=="function"&&(u[l]=(...w)=>{const R=typeof w[0]=="string"?w[0]:"",v=typeof a=="function"?a(w):a;return b(v,R,d),U(...w)})}for(const[l,a]of $)typeof s[l]=="function"&&(u[l]=async()=>{throw new k("FORBIDDEN",a)});const{bucket:h}=s;return typeof h=="function"&&(u.bucket=l=>n(h(l))),u},r=i.storage;if(r===void 0)return c();B(r,e.map(s=>s.bucket));const p={storage:n(r)},y=i.db,m=y?.system;return y!==void 0&&m!==void 0&&typeof m=="object"&&(p.db={...y,system:E(m,r.bucketName??"default",{assertAllowed:b,isAllowed:f})}),c({ctx:p})}};export{_ as storageRules};
|
package/dist/types.d.mts
CHANGED
|
@@ -63,6 +63,344 @@ interface RestCachePolicy {
|
|
|
63
63
|
readonly tag?: string;
|
|
64
64
|
readonly vary?: string;
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* The `ctx.storage` surface, per function tier: {@link ReadOnlyStorage} for a
|
|
68
|
+
* query, {@link MutationStorage} for a mutation, {@link Storage} for an action.
|
|
69
|
+
*
|
|
70
|
+
* A structural mirror of `@lunora/storage`'s `Storage` — `@lunora/server` takes
|
|
71
|
+
* no dependency on that package. Re-exported through `../types`, so the public
|
|
72
|
+
* names are unchanged.
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* Per-file metadata returned by {@link ReadOnlyStorage.getMetadata}. A clean
|
|
76
|
+
* public mirror of `@lunora/storage`'s `ObjectMetadata` — re-declared here so
|
|
77
|
+
* the ctx surface carries no dependency on the storage package's types. Matches
|
|
78
|
+
* the columns Convex surfaces for `ctx.storage.getMetadata` / `_storage`.
|
|
79
|
+
*/
|
|
80
|
+
interface StorageMetadata {
|
|
81
|
+
/** The object's `Content-Type`, when recorded. */
|
|
82
|
+
contentType?: string;
|
|
83
|
+
/** Custom metadata set at upload time, if any. */
|
|
84
|
+
customMetadata?: Record<string, string>;
|
|
85
|
+
/** The object's key. */
|
|
86
|
+
key: string;
|
|
87
|
+
/** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
|
|
88
|
+
sha256?: string;
|
|
89
|
+
/** Body length in bytes. */
|
|
90
|
+
size: number;
|
|
91
|
+
/** When the object was last written (epoch ms), when reported. */
|
|
92
|
+
uploaded?: number;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The body-free object shape returned by {@link ReadOnlyStorage.head} — a clean
|
|
96
|
+
* public mirror of `@lunora/storage`'s head projection, re-declared here for the
|
|
97
|
+
* same reason as {@link StorageMetadata}: the ctx surface carries no dependency
|
|
98
|
+
* on the storage package's types.
|
|
99
|
+
*
|
|
100
|
+
* Richer than {@link StorageMetadata} on purpose. `getMetadata` is the tidy
|
|
101
|
+
* Convex-shaped summary; `head` is what an HTTP layer needs, so it keeps the
|
|
102
|
+
* validator (`etag`) and the base64 digest RFC 9530 `Repr-Digest` requires, and
|
|
103
|
+
* leaves `uploaded` as the `Date` the binding reports rather than epoch ms.
|
|
104
|
+
*/
|
|
105
|
+
interface StorageObjectHead {
|
|
106
|
+
/** Custom metadata set at upload time, if any. */
|
|
107
|
+
customMetadata?: Record<string, string>;
|
|
108
|
+
/**
|
|
109
|
+
* R2's unquoted etag (the MD5 hex for a single-part upload). Required: R2
|
|
110
|
+
* reports one on every object, and an HTTP layer built on `head()` (the
|
|
111
|
+
* `serveStorageObject` helper) needs it to emit a validator.
|
|
112
|
+
*/
|
|
113
|
+
etag: string;
|
|
114
|
+
/** The already-quoted form of {@link StorageObjectHead.etag}, when the binding reports one. */
|
|
115
|
+
httpEtag?: string;
|
|
116
|
+
/** Recorded HTTP metadata, notably the `Content-Type`. */
|
|
117
|
+
httpMetadata?: {
|
|
118
|
+
contentType?: string;
|
|
119
|
+
};
|
|
120
|
+
/** The object's key. */
|
|
121
|
+
key: string;
|
|
122
|
+
/** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
|
|
123
|
+
sha256?: string;
|
|
124
|
+
/** Base64-encoded SHA-256 of the same checksum — the encoding RFC 9530 digest headers require. */
|
|
125
|
+
sha256Base64?: string;
|
|
126
|
+
/** 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. */
|
|
127
|
+
size: number;
|
|
128
|
+
/** When the object was last written. */
|
|
129
|
+
uploaded?: Date;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Byte window forwarded to {@link ReadOnlyStorage.download} so R2 resolves the
|
|
133
|
+
* slice server-side and streams only those bytes back. Mirrors R2's own `range`
|
|
134
|
+
* option (`@lunora/platform`'s `R2RangeLike`), restated structurally so
|
|
135
|
+
* `@lunora/server` takes no dependency on the bindings package.
|
|
136
|
+
*/
|
|
137
|
+
type StorageRange = {
|
|
138
|
+
length?: number;
|
|
139
|
+
offset: number;
|
|
140
|
+
} | {
|
|
141
|
+
length: number;
|
|
142
|
+
offset?: number;
|
|
143
|
+
} | {
|
|
144
|
+
suffix: number;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* A downloaded object: the same metadata {@link StorageObjectHead} carries, plus
|
|
148
|
+
* the body stream. This is what `download()` resolves to — R2's object, NOT a
|
|
149
|
+
* bare stream.
|
|
150
|
+
*/
|
|
151
|
+
interface StorageObjectBody extends StorageObjectHead {
|
|
152
|
+
/** The object body stream. `null` for a zero-byte object. */
|
|
153
|
+
body: ReadableStream | null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Read-only projection of `Storage` exposed on `QueryCtx` / `MutationCtx`.
|
|
157
|
+
*
|
|
158
|
+
* Queries are pure reads, and mutations run inside a transactional scope —
|
|
159
|
+
* neither is allowed to perform side-effectful R2 writes (`upload`) or
|
|
160
|
+
* deletes (`delete`). They can, however, **read** existing objects and
|
|
161
|
+
* resolve signed URLs (the URL signing itself is HMAC-only — no R2 round
|
|
162
|
+
* trip), so the read-only surface keeps `download` and `getSignedUrl`. The
|
|
163
|
+
* full {@link Storage} surface stays on `ActionCtx`.
|
|
164
|
+
*/
|
|
165
|
+
interface ReadOnlyStorage<Buckets extends string = string> {
|
|
166
|
+
/**
|
|
167
|
+
* Select a named bucket (declared via `v.storage("name")`). The returned
|
|
168
|
+
* accessor's operations target that bucket — `ctx.storage.bucket("avatars")
|
|
169
|
+
* .download(key)`. The bare `ctx.storage` targets the default bucket.
|
|
170
|
+
*/
|
|
171
|
+
bucket: (name: Buckets) => ReadOnlyStorage<Buckets>;
|
|
172
|
+
/** The bucket this accessor's operations target (the default for the bare `ctx.storage`). */
|
|
173
|
+
readonly bucketName: string;
|
|
174
|
+
/**
|
|
175
|
+
* Fetch an existing object. Returns the R2 object — metadata plus a `body`
|
|
176
|
+
* stream — or `null` when absent.
|
|
177
|
+
*
|
|
178
|
+
* NOT a bare stream: `new Response(await ctx.storage.download(key))` would
|
|
179
|
+
* stringify the object and serve the literal text `[object Object]`. Reach
|
|
180
|
+
* for the body explicitly:
|
|
181
|
+
*
|
|
182
|
+
* ```ts
|
|
183
|
+
* const object = await ctx.storage.download(key);
|
|
184
|
+
*
|
|
185
|
+
* return object ? new Response(object.body) : new Response("Not found", { status: 404 });
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* (`serveStorageObject` from `@lunora/server` does this, plus range/ETag
|
|
189
|
+
* handling, for the common "serve a stored file over HTTP" case.)
|
|
190
|
+
*
|
|
191
|
+
* Pass `range` to have R2 resolve the byte window server-side, so the
|
|
192
|
+
* unwanted bytes never reach the worker.
|
|
193
|
+
*/
|
|
194
|
+
download: (key: string, options?: {
|
|
195
|
+
range?: StorageRange;
|
|
196
|
+
}) => Promise<StorageObjectBody | null>;
|
|
197
|
+
/**
|
|
198
|
+
* Read a file's metadata (size, content-type, sha256, upload time, custom
|
|
199
|
+
* metadata) without fetching its body. Returns `null` when the object is
|
|
200
|
+
* absent. Mirrors Convex's `ctx.storage.getMetadata`.
|
|
201
|
+
*/
|
|
202
|
+
getMetadata: (key: string) => Promise<StorageMetadata | null>;
|
|
203
|
+
/** Resolve a short-lived signed URL for an existing object. */
|
|
204
|
+
getSignedUrl: (key: string, options?: {
|
|
205
|
+
expiresInSeconds?: number;
|
|
206
|
+
}) => Promise<string>;
|
|
207
|
+
/** Public URL pointing at the configured base for `key`. */
|
|
208
|
+
getUrl: (key: string) => string;
|
|
209
|
+
/**
|
|
210
|
+
* Read an object's metadata with NO body transfer, as the raw object shape —
|
|
211
|
+
* `etag` and the base64 digest included, which is what an HTTP layer needs to
|
|
212
|
+
* answer a `Range` request. Returns `null` when the object is absent.
|
|
213
|
+
*
|
|
214
|
+
* {@link ReadOnlyStorage.getMetadata} is the tidier summary over the same
|
|
215
|
+
* read; reach for this one when building a response.
|
|
216
|
+
*/
|
|
217
|
+
head: (key: string) => Promise<StorageObjectHead | null>;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* `ctx.storage` inside a **mutation**: the read surface, plus the one write a
|
|
221
|
+
* transactional context can safely express. See `@lunora/server`'s
|
|
222
|
+
* `deferred-deletes.ts` for why `delete` itself stays action-only.
|
|
223
|
+
*/
|
|
224
|
+
interface MutationStorage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
|
|
225
|
+
/** Select a named bucket; deletes queued on it are flushed against that bucket. */
|
|
226
|
+
bucket: (name: Buckets) => MutationStorage<Buckets>;
|
|
227
|
+
/**
|
|
228
|
+
* Queue `key` for deletion once this mutation commits.
|
|
229
|
+
*
|
|
230
|
+
* Returns `void`, not a promise: nothing has been attempted yet, so the object
|
|
231
|
+
* is still there on the next line. A rolled-back mutation never flushes, so
|
|
232
|
+
* the row deletion and the object cleanup cannot disagree. A failed delete
|
|
233
|
+
* leaks the object rather than failing a mutation that already succeeded, and
|
|
234
|
+
* is logged with its key.
|
|
235
|
+
*/
|
|
236
|
+
deleteAfterCommit: (key: string) => void;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* The body shapes `store` / `upload` accept — what R2's `put` stores bytes from.
|
|
240
|
+
* Mirrors `@lunora/storage`'s `Storage.upload` parameter.
|
|
241
|
+
*/
|
|
242
|
+
type StorageUploadBody = ArrayBuffer | ArrayBufferView | Blob | ReadableStream | string;
|
|
243
|
+
/**
|
|
244
|
+
* Options for `store` / `upload` — a structural mirror of `@lunora/storage`'s
|
|
245
|
+
* `UploadOptions`, so the `maxSize` / `allowedContentTypes` guards are reachable
|
|
246
|
+
* from `ctx.storage` without a type dependency on the storage package.
|
|
247
|
+
*/
|
|
248
|
+
interface StorageUploadOptions {
|
|
249
|
+
/** Content-type allowlist; the supplied `contentType` must match. */
|
|
250
|
+
allowedContentTypes?: ReadonlyArray<string>;
|
|
251
|
+
contentType?: string;
|
|
252
|
+
customMetadata?: Record<string, string>;
|
|
253
|
+
/**
|
|
254
|
+
* Maximum body size in bytes. A `ReadableStream` is buffered under the cap,
|
|
255
|
+
* so on the stream path `maxSize` is itself capped at 16 MiB — above that use
|
|
256
|
+
* {@link Storage.createMultipartUpload}.
|
|
257
|
+
*/
|
|
258
|
+
maxSize?: number;
|
|
259
|
+
/** SHA-256 of the body (hex or a 32-byte buffer); R2 records and verifies it. */
|
|
260
|
+
sha256?: ArrayBuffer | string;
|
|
261
|
+
}
|
|
262
|
+
/** What `store` / `upload` resolve to: the stored key plus its etag (unquoted and quoted). */
|
|
263
|
+
interface StorageUploadResult {
|
|
264
|
+
etag: string;
|
|
265
|
+
httpEtag: string;
|
|
266
|
+
key: string;
|
|
267
|
+
}
|
|
268
|
+
/** One uploaded multipart part — returned by `uploadPart`, required by `complete`. Mirrors R2's `R2UploadedPart`. */
|
|
269
|
+
interface StorageUploadedPart {
|
|
270
|
+
etag: string;
|
|
271
|
+
partNumber: number;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* An in-progress R2 multipart upload, as {@link Storage.createMultipartUpload} /
|
|
275
|
+
* {@link Storage.resumeMultipartUpload} return it. A structural mirror of
|
|
276
|
+
* R2's own multipart upload handle, as `@lunora/platform` declares it.
|
|
277
|
+
*
|
|
278
|
+
* Every part except the last must be the same size, and at least 5 MiB. The
|
|
279
|
+
* object does not guarantee the upload still exists — a parallel `complete` /
|
|
280
|
+
* `abort` invalidates it — so handle errors on each call.
|
|
281
|
+
*/
|
|
282
|
+
interface StorageMultipartUpload {
|
|
283
|
+
/** Abort the upload, discarding every uploaded part. */
|
|
284
|
+
abort: () => Promise<void>;
|
|
285
|
+
/** Finish the upload from the collected parts; resolves to the stored object's metadata. */
|
|
286
|
+
complete: (uploadedParts: StorageUploadedPart[]) => Promise<StorageObjectHead>;
|
|
287
|
+
/** The object key being assembled. */
|
|
288
|
+
readonly key: string;
|
|
289
|
+
/** The R2 upload id — persist it to resume the upload in a later request. */
|
|
290
|
+
readonly uploadId: string;
|
|
291
|
+
/** Upload one part (1-indexed); returns the `{ partNumber, etag }` to pass to `complete`. */
|
|
292
|
+
uploadPart: (partNumber: number, value: StorageUploadBody) => Promise<StorageUploadedPart>;
|
|
293
|
+
}
|
|
294
|
+
/** Options for {@link Storage.createMultipartUpload}: the metadata recorded on the assembled object. */
|
|
295
|
+
interface StorageMultipartUploadOptions {
|
|
296
|
+
contentType?: string;
|
|
297
|
+
customMetadata?: Record<string, string>;
|
|
298
|
+
}
|
|
299
|
+
/** Options for {@link Storage.list}. Mirrors `@lunora/storage`'s `ListOptions`. */
|
|
300
|
+
interface StorageListOptions {
|
|
301
|
+
/** The `cursor` of the previous page. */
|
|
302
|
+
cursor?: string;
|
|
303
|
+
/** R2 list delimiter — keys sharing a segment roll up into `delimitedPrefixes`. */
|
|
304
|
+
delimiter?: string;
|
|
305
|
+
/** Page-size ceiling: defaults to 100, capped at 1000. A positive integer; anything else throws. */
|
|
306
|
+
limit?: number;
|
|
307
|
+
}
|
|
308
|
+
/** One page of {@link Storage.list}. */
|
|
309
|
+
interface StorageListResult {
|
|
310
|
+
/** Pass back as `options.cursor` for the next page, while `truncated` is `true`. */
|
|
311
|
+
cursor?: string;
|
|
312
|
+
/** The rolled-up "folders" when `options.delimiter` is set — these are NOT in `objects`. */
|
|
313
|
+
delimitedPrefixes?: string[];
|
|
314
|
+
/** The objects on this page, body-free and JSON-serializable. */
|
|
315
|
+
objects: StorageObjectHead[];
|
|
316
|
+
/** `true` while more pages remain. Paginate on this, never on `objects.length`. */
|
|
317
|
+
truncated?: boolean;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* `ctx.storage` inside an **action**: the full `@lunora/storage` `Storage`
|
|
321
|
+
* surface, plus `bucket(name)`.
|
|
322
|
+
*
|
|
323
|
+
* Declared structurally rather than imported — `@lunora/server` takes no
|
|
324
|
+
* runtime or published-type dependency on `@lunora/storage` — so it tracks that
|
|
325
|
+
* surface by hand. A type test (`__tests__/storage-surface.test-d.ts`) fails
|
|
326
|
+
* `tsc` when the two drift —
|
|
327
|
+
* the member sets differ (a runtime member left untyped here, or a member typed
|
|
328
|
+
* here the runtime lacks — `bucket` aside, which the ctx wiring adds); the
|
|
329
|
+
* runtime object no longer satisfies a signature here (a return type widened,
|
|
330
|
+
* or a parameter narrowed, upstream); or a parameter list here differs from the
|
|
331
|
+
* runtime's (an option or body shape the runtime takes but this interface
|
|
332
|
+
* refuses). `getSignedUrl` is the one deliberate parameter exception: its PUT
|
|
333
|
+
* options would mint an upload URL from a query.
|
|
334
|
+
*
|
|
335
|
+
* Return types here may be NARROWER than the runtime's on purpose — `head`
|
|
336
|
+
* resolves to the {@link StorageObjectHead} mirror rather than R2's object.
|
|
337
|
+
*
|
|
338
|
+
* Every member here is action-only. Under a procedure guarded by
|
|
339
|
+
* `storageRules(...)`, the write paths (`store` / `upload` /
|
|
340
|
+
* `createMultipartUpload` / `resumeMultipartUpload`) are gated as `write`, and
|
|
341
|
+
* `getPresignedUrl` / `list`, which no rule can gate, reject with `FORBIDDEN`.
|
|
342
|
+
*/
|
|
343
|
+
interface Storage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
|
|
344
|
+
/** Select a named bucket; the returned accessor exposes the full read/write surface. */
|
|
345
|
+
bucket: (name: Buckets) => Storage<Buckets>;
|
|
346
|
+
/**
|
|
347
|
+
* Begin a native R2 **multipart upload** — for objects above `store()`'s
|
|
348
|
+
* 16 MiB stream cap, streamed through the Worker without buffering. Upload
|
|
349
|
+
* the parts (each at least 5 MiB and uniform in size, except the last), then
|
|
350
|
+
* `complete` with the returned parts, or `abort`. Persist `uploadId` to
|
|
351
|
+
* continue in a later request via {@link Storage.resumeMultipartUpload}.
|
|
352
|
+
*/
|
|
353
|
+
createMultipartUpload: (key: string, options?: StorageMultipartUploadOptions) => Promise<StorageMultipartUpload>;
|
|
354
|
+
delete: (key: string) => Promise<void>;
|
|
355
|
+
/**
|
|
356
|
+
* Mint a short-lived signed `PUT` URL a client can upload directly to,
|
|
357
|
+
* optionally pinning the `Content-Type` the uploader must send. Mirrors
|
|
358
|
+
* Convex's `storage.generateUploadUrl`.
|
|
359
|
+
*/
|
|
360
|
+
generateUploadUrl: (key: string, options?: {
|
|
361
|
+
contentType?: string;
|
|
362
|
+
expiresInSeconds?: number;
|
|
363
|
+
}) => Promise<string>;
|
|
364
|
+
/**
|
|
365
|
+
* Mint a native S3 SigV4 URL that hits R2 **directly**, so the bytes never
|
|
366
|
+
* pass through the Worker — unlike {@link Storage.generateUploadUrl}, whose
|
|
367
|
+
* signed URL points back at this app so its storage rules still apply.
|
|
368
|
+
*
|
|
369
|
+
* Requires `s3` credentials on the `.storage({ s3 })` declaration; without
|
|
370
|
+
* them the call throws. That is the trade-off: no Worker in the path also
|
|
371
|
+
* means no rule enforcement in the path.
|
|
372
|
+
*/
|
|
373
|
+
getPresignedUrl: (key: string, options?: {
|
|
374
|
+
expiresInSeconds?: number;
|
|
375
|
+
method?: "GET" | "PUT";
|
|
376
|
+
}) => Promise<string>;
|
|
377
|
+
/**
|
|
378
|
+
* List objects under `prefix` — e.g. to sweep abandoned staging uploads. With
|
|
379
|
+
* `options.delimiter` set, keys sharing a segment roll up into
|
|
380
|
+
* `delimitedPrefixes` and are NOT in `objects`, so an empty `objects` is not
|
|
381
|
+
* an empty directory. A page may hold fewer objects than `options.limit`:
|
|
382
|
+
* paginate on `truncated` / `cursor`.
|
|
383
|
+
*
|
|
384
|
+
* Not gated by storage access rules (and dropped under `storageRules(...)`);
|
|
385
|
+
* a rule-scoped enumeration goes through `ctx.db.system.query("_storage")`.
|
|
386
|
+
*/
|
|
387
|
+
list: (prefix?: string, options?: StorageListOptions) => Promise<StorageListResult>;
|
|
388
|
+
/**
|
|
389
|
+
* Resume an in-progress multipart upload by its `uploadId` (e.g. across
|
|
390
|
+
* requests). Synchronous: R2 does not validate the id, so a stale one
|
|
391
|
+
* surfaces as an error on the first `uploadPart` / `complete`.
|
|
392
|
+
*/
|
|
393
|
+
resumeMultipartUpload: (key: string, uploadId: string) => StorageMultipartUpload;
|
|
394
|
+
/**
|
|
395
|
+
* Upload `body` to `key` from the server, returning the stored object's key
|
|
396
|
+
* and etag. Mirrors Convex's `storage.store`; the same function as
|
|
397
|
+
* {@link Storage.upload}, so the `maxSize` / `allowedContentTypes` guards
|
|
398
|
+
* apply through the alias.
|
|
399
|
+
*/
|
|
400
|
+
store: (key: string, body: StorageUploadBody, options?: StorageUploadOptions) => Promise<StorageUploadResult>;
|
|
401
|
+
/** Upload `body` to `key` — {@link Storage.store} under `@lunora/storage`'s own name, with one shared signature. */
|
|
402
|
+
upload: Storage<Buckets>["store"];
|
|
403
|
+
}
|
|
66
404
|
/** Map of validators describing a function's args record. Alias of `@lunora/values`' shared {@link ValidatorMap}. */
|
|
67
405
|
type ArgsValidator = ValidatorMap;
|
|
68
406
|
/** Infer the args object type from an {@link ArgsValidator}. Alias of `@lunora/values`' shared {@link InferValidatorMap}. */
|
|
@@ -1774,216 +2112,6 @@ interface TriggerBuilder<Shape extends Record<string, Validator> = Record<string
|
|
|
1774
2112
|
beforeInsert: (handler: TriggerHandler<TriggerInsertEvent<Shape>>) => TriggerDefinition;
|
|
1775
2113
|
beforeUpdate: (handler: TriggerHandler<TriggerUpdateEvent<Shape>>) => TriggerDefinition;
|
|
1776
2114
|
}
|
|
1777
|
-
/**
|
|
1778
|
-
* Per-file metadata returned by {@link ReadOnlyStorage.getMetadata}. A clean
|
|
1779
|
-
* public mirror of `@lunora/storage`'s `ObjectMetadata` — re-declared here so
|
|
1780
|
-
* the ctx surface carries no dependency on the storage package's types. Matches
|
|
1781
|
-
* the columns Convex surfaces for `ctx.storage.getMetadata` / `_storage`.
|
|
1782
|
-
*/
|
|
1783
|
-
interface StorageMetadata {
|
|
1784
|
-
/** The object's `Content-Type`, when recorded. */
|
|
1785
|
-
contentType?: string;
|
|
1786
|
-
/** Custom metadata set at upload time, if any. */
|
|
1787
|
-
customMetadata?: Record<string, string>;
|
|
1788
|
-
/** The object's key. */
|
|
1789
|
-
key: string;
|
|
1790
|
-
/** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
|
|
1791
|
-
sha256?: string;
|
|
1792
|
-
/** Body length in bytes. */
|
|
1793
|
-
size: number;
|
|
1794
|
-
/** When the object was last written (epoch ms), when reported. */
|
|
1795
|
-
uploaded?: number;
|
|
1796
|
-
}
|
|
1797
|
-
/**
|
|
1798
|
-
* The body-free object shape returned by {@link ReadOnlyStorage.head} — a clean
|
|
1799
|
-
* public mirror of `@lunora/storage`'s head projection, re-declared here for the
|
|
1800
|
-
* same reason as {@link StorageMetadata}: the ctx surface carries no dependency
|
|
1801
|
-
* on the storage package's types.
|
|
1802
|
-
*
|
|
1803
|
-
* Richer than {@link StorageMetadata} on purpose. `getMetadata` is the tidy
|
|
1804
|
-
* Convex-shaped summary; `head` is what an HTTP layer needs, so it keeps the
|
|
1805
|
-
* validator (`etag`) and the base64 digest RFC 9530 `Repr-Digest` requires, and
|
|
1806
|
-
* leaves `uploaded` as the `Date` the binding reports rather than epoch ms.
|
|
1807
|
-
*/
|
|
1808
|
-
interface StorageObjectHead {
|
|
1809
|
-
/** Custom metadata set at upload time, if any. */
|
|
1810
|
-
customMetadata?: Record<string, string>;
|
|
1811
|
-
/**
|
|
1812
|
-
* R2's unquoted etag (the MD5 hex for a single-part upload). Required: R2
|
|
1813
|
-
* reports one on every object, and an HTTP layer built on `head()` (the
|
|
1814
|
-
* `serveStorageObject` helper) needs it to emit a validator.
|
|
1815
|
-
*/
|
|
1816
|
-
etag: string;
|
|
1817
|
-
/** The already-quoted form of {@link StorageObjectHead.etag}, when the binding reports one. */
|
|
1818
|
-
httpEtag?: string;
|
|
1819
|
-
/** Recorded HTTP metadata, notably the `Content-Type`. */
|
|
1820
|
-
httpMetadata?: {
|
|
1821
|
-
contentType?: string;
|
|
1822
|
-
};
|
|
1823
|
-
/** The object's key. */
|
|
1824
|
-
key: string;
|
|
1825
|
-
/** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
|
|
1826
|
-
sha256?: string;
|
|
1827
|
-
/** Base64-encoded SHA-256 of the same checksum — the encoding RFC 9530 digest headers require. */
|
|
1828
|
-
sha256Base64?: string;
|
|
1829
|
-
/** 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. */
|
|
1830
|
-
size: number;
|
|
1831
|
-
/** When the object was last written. */
|
|
1832
|
-
uploaded?: Date;
|
|
1833
|
-
}
|
|
1834
|
-
/**
|
|
1835
|
-
* Byte window forwarded to {@link ReadOnlyStorage.download} so R2 resolves the
|
|
1836
|
-
* slice server-side and streams only those bytes back. Mirrors R2's own `range`
|
|
1837
|
-
* option (`@lunora/platform`'s `R2RangeLike`), restated structurally so
|
|
1838
|
-
* `@lunora/server` takes no dependency on the bindings package.
|
|
1839
|
-
*/
|
|
1840
|
-
type StorageRange = {
|
|
1841
|
-
length?: number;
|
|
1842
|
-
offset: number;
|
|
1843
|
-
} | {
|
|
1844
|
-
length: number;
|
|
1845
|
-
offset?: number;
|
|
1846
|
-
} | {
|
|
1847
|
-
suffix: number;
|
|
1848
|
-
};
|
|
1849
|
-
/**
|
|
1850
|
-
* A downloaded object: the same metadata {@link StorageObjectHead} carries, plus
|
|
1851
|
-
* the body stream. This is what `download()` resolves to — R2's object, NOT a
|
|
1852
|
-
* bare stream.
|
|
1853
|
-
*/
|
|
1854
|
-
interface StorageObjectBody extends StorageObjectHead {
|
|
1855
|
-
/** The object body stream. `null` for a zero-byte object. */
|
|
1856
|
-
body: ReadableStream | null;
|
|
1857
|
-
}
|
|
1858
|
-
/**
|
|
1859
|
-
* Read-only projection of `Storage` exposed on `QueryCtx` / `MutationCtx`.
|
|
1860
|
-
*
|
|
1861
|
-
* Queries are pure reads, and mutations run inside a transactional scope —
|
|
1862
|
-
* neither is allowed to perform side-effectful R2 writes (`upload`) or
|
|
1863
|
-
* deletes (`delete`). They can, however, **read** existing objects and
|
|
1864
|
-
* resolve signed URLs (the URL signing itself is HMAC-only — no R2 round
|
|
1865
|
-
* trip), so the read-only surface keeps `download` and `getSignedUrl`. The
|
|
1866
|
-
* full {@link Storage} surface stays on `ActionCtx`.
|
|
1867
|
-
*/
|
|
1868
|
-
interface ReadOnlyStorage<Buckets extends string = string> {
|
|
1869
|
-
/**
|
|
1870
|
-
* Select a named bucket (declared via `v.storage("name")`). The returned
|
|
1871
|
-
* accessor's operations target that bucket — `ctx.storage.bucket("avatars")
|
|
1872
|
-
* .download(key)`. The bare `ctx.storage` targets the default bucket.
|
|
1873
|
-
*/
|
|
1874
|
-
bucket: (name: Buckets) => ReadOnlyStorage<Buckets>;
|
|
1875
|
-
/** The bucket this accessor's operations target (the default for the bare `ctx.storage`). */
|
|
1876
|
-
readonly bucketName: string;
|
|
1877
|
-
/**
|
|
1878
|
-
* Fetch an existing object. Returns the R2 object — metadata plus a `body`
|
|
1879
|
-
* stream — or `null` when absent.
|
|
1880
|
-
*
|
|
1881
|
-
* NOT a bare stream: `new Response(await ctx.storage.download(key))` would
|
|
1882
|
-
* stringify the object and serve the literal text `[object Object]`. Reach
|
|
1883
|
-
* for the body explicitly:
|
|
1884
|
-
*
|
|
1885
|
-
* ```ts
|
|
1886
|
-
* const object = await ctx.storage.download(key);
|
|
1887
|
-
*
|
|
1888
|
-
* return object ? new Response(object.body) : new Response("Not found", { status: 404 });
|
|
1889
|
-
* ```
|
|
1890
|
-
*
|
|
1891
|
-
* (`serveStorageObject` from `@lunora/server` does this, plus range/ETag
|
|
1892
|
-
* handling, for the common "serve a stored file over HTTP" case.)
|
|
1893
|
-
*
|
|
1894
|
-
* Pass `range` to have R2 resolve the byte window server-side, so the
|
|
1895
|
-
* unwanted bytes never reach the worker.
|
|
1896
|
-
*/
|
|
1897
|
-
download: (key: string, options?: {
|
|
1898
|
-
range?: StorageRange;
|
|
1899
|
-
}) => Promise<StorageObjectBody | null>;
|
|
1900
|
-
/**
|
|
1901
|
-
* Read a file's metadata (size, content-type, sha256, upload time, custom
|
|
1902
|
-
* metadata) without fetching its body. Returns `null` when the object is
|
|
1903
|
-
* absent. Mirrors Convex's `ctx.storage.getMetadata`.
|
|
1904
|
-
*/
|
|
1905
|
-
getMetadata: (key: string) => Promise<StorageMetadata | null>;
|
|
1906
|
-
/** Resolve a short-lived signed URL for an existing object. */
|
|
1907
|
-
getSignedUrl: (key: string, options?: {
|
|
1908
|
-
expiresInSeconds?: number;
|
|
1909
|
-
}) => Promise<string>;
|
|
1910
|
-
/** Public URL pointing at the configured base for `key`. */
|
|
1911
|
-
getUrl: (key: string) => string;
|
|
1912
|
-
/**
|
|
1913
|
-
* Read an object's metadata with NO body transfer, as the raw object shape —
|
|
1914
|
-
* `etag` and the base64 digest included, which is what an HTTP layer needs to
|
|
1915
|
-
* answer a `Range` request. Returns `null` when the object is absent.
|
|
1916
|
-
*
|
|
1917
|
-
* {@link ReadOnlyStorage.getMetadata} is the tidier summary over the same
|
|
1918
|
-
* read; reach for this one when building a response.
|
|
1919
|
-
*/
|
|
1920
|
-
head: (key: string) => Promise<StorageObjectHead | null>;
|
|
1921
|
-
}
|
|
1922
|
-
/**
|
|
1923
|
-
* `ctx.storage` inside a **mutation**: the read surface, plus the one write a
|
|
1924
|
-
* transactional context can safely express. See `@lunora/server`'s
|
|
1925
|
-
* `deferred-deletes.ts` for why `delete` itself stays action-only.
|
|
1926
|
-
*/
|
|
1927
|
-
interface MutationStorage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
|
|
1928
|
-
/** Select a named bucket; deletes queued on it are flushed against that bucket. */
|
|
1929
|
-
bucket: (name: Buckets) => MutationStorage<Buckets>;
|
|
1930
|
-
/**
|
|
1931
|
-
* Queue `key` for deletion once this mutation commits.
|
|
1932
|
-
*
|
|
1933
|
-
* Returns `void`, not a promise: nothing has been attempted yet, so the object
|
|
1934
|
-
* is still there on the next line. A rolled-back mutation never flushes, so
|
|
1935
|
-
* the row deletion and the object cleanup cannot disagree. A failed delete
|
|
1936
|
-
* leaks the object rather than failing a mutation that already succeeded, and
|
|
1937
|
-
* is logged with its key.
|
|
1938
|
-
*/
|
|
1939
|
-
deleteAfterCommit: (key: string) => void;
|
|
1940
|
-
}
|
|
1941
|
-
interface Storage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
|
|
1942
|
-
/** Select a named bucket; the returned accessor exposes the full read/write surface. */
|
|
1943
|
-
bucket: (name: Buckets) => Storage<Buckets>;
|
|
1944
|
-
delete: (key: string) => Promise<void>;
|
|
1945
|
-
/**
|
|
1946
|
-
* Mint a short-lived signed `PUT` URL a client can upload directly to,
|
|
1947
|
-
* optionally pinning the `Content-Type` the uploader must send. Mirrors
|
|
1948
|
-
* Convex's `storage.generateUploadUrl`.
|
|
1949
|
-
*/
|
|
1950
|
-
generateUploadUrl: (key: string, options?: {
|
|
1951
|
-
contentType?: string;
|
|
1952
|
-
expiresInSeconds?: number;
|
|
1953
|
-
}) => Promise<string>;
|
|
1954
|
-
/**
|
|
1955
|
-
* Mint a native S3 SigV4 URL that hits R2 **directly**, so the bytes never
|
|
1956
|
-
* pass through the Worker — unlike {@link Storage.generateUploadUrl}, whose
|
|
1957
|
-
* signed URL points back at this app so its storage rules still apply.
|
|
1958
|
-
*
|
|
1959
|
-
* Requires `s3` credentials on the `.storage({ s3 })` declaration; without
|
|
1960
|
-
* them the call throws. That is the trade-off: no Worker in the path also
|
|
1961
|
-
* means no rule enforcement in the path.
|
|
1962
|
-
*
|
|
1963
|
-
* Declared structurally rather than imported — `@lunora/server` does not
|
|
1964
|
-
* depend on `@lunora/storage`, and this file mirrors that surface the same
|
|
1965
|
-
* way `head` and `download` do.
|
|
1966
|
-
*/
|
|
1967
|
-
getPresignedUrl: (key: string, options?: {
|
|
1968
|
-
expiresInSeconds?: number;
|
|
1969
|
-
method?: "GET" | "PUT";
|
|
1970
|
-
}) => Promise<string>;
|
|
1971
|
-
/**
|
|
1972
|
-
* Upload `body` to `key` from the server, returning the stored object's key
|
|
1973
|
-
* and etag. Mirrors Convex's `storage.store`. Accepts the same guard fields
|
|
1974
|
-
* as `@lunora/storage`'s `UploadOptions` so `maxSize` /
|
|
1975
|
-
* `allowedContentTypes` enforcement isn't lost behind the Convex-style alias.
|
|
1976
|
-
*/
|
|
1977
|
-
store: (key: string, body: ReadableStream | ArrayBuffer | Blob, options?: {
|
|
1978
|
-
allowedContentTypes?: ReadonlyArray<string>;
|
|
1979
|
-
contentType?: string;
|
|
1980
|
-
customMetadata?: Record<string, string>;
|
|
1981
|
-
maxSize?: number;
|
|
1982
|
-
}) => Promise<{
|
|
1983
|
-
etag: string;
|
|
1984
|
-
key: string;
|
|
1985
|
-
}>;
|
|
1986
|
-
}
|
|
1987
2115
|
interface VectorMatch {
|
|
1988
2116
|
id: string;
|
|
1989
2117
|
metadata?: Record<string, unknown>;
|
|
@@ -2613,4 +2741,4 @@ interface ActionCtx {
|
|
|
2613
2741
|
*/
|
|
2614
2742
|
type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
|
|
2615
2743
|
declare const anyApi: AnyApi;
|
|
2616
|
-
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 MutationStorage, 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 RelatedDirection, type RelatedNode, type RelatedOptions, type RelatedPage, type RelatedStart, type RelatedStartReference, type RelationDefinition, type RestCacheConfig, type RetryPolicy, 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 SpanContextIds, type SpanEvaluation, type SpanHandle, type SpanIdentity, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type StorageObjectBody, type StorageObjectHead, type StorageRange, 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 WhisperEvent, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceEvent, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, type X402ProcedureConfig, anyApi };
|
|
2744
|
+
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 MutationStorage, 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 RelatedDirection, type RelatedNode, type RelatedOptions, type RelatedPage, type RelatedStart, type RelatedStartReference, type RelationDefinition, type RestCacheConfig, type RetryPolicy, 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 SpanContextIds, type SpanEvaluation, type SpanHandle, type SpanIdentity, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageListOptions, type StorageListResult, type StorageMetadata, type StorageMultipartUpload, type StorageMultipartUploadOptions, type StorageObjectBody, type StorageObjectHead, type StorageRange, type StorageUploadBody, type StorageUploadOptions, type StorageUploadResult, type StorageUploadedPart, 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 WhisperEvent, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceEvent, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, type X402ProcedureConfig, anyApi };
|
package/dist/types.d.ts
CHANGED
|
@@ -63,6 +63,344 @@ interface RestCachePolicy {
|
|
|
63
63
|
readonly tag?: string;
|
|
64
64
|
readonly vary?: string;
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* The `ctx.storage` surface, per function tier: {@link ReadOnlyStorage} for a
|
|
68
|
+
* query, {@link MutationStorage} for a mutation, {@link Storage} for an action.
|
|
69
|
+
*
|
|
70
|
+
* A structural mirror of `@lunora/storage`'s `Storage` — `@lunora/server` takes
|
|
71
|
+
* no dependency on that package. Re-exported through `../types`, so the public
|
|
72
|
+
* names are unchanged.
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* Per-file metadata returned by {@link ReadOnlyStorage.getMetadata}. A clean
|
|
76
|
+
* public mirror of `@lunora/storage`'s `ObjectMetadata` — re-declared here so
|
|
77
|
+
* the ctx surface carries no dependency on the storage package's types. Matches
|
|
78
|
+
* the columns Convex surfaces for `ctx.storage.getMetadata` / `_storage`.
|
|
79
|
+
*/
|
|
80
|
+
interface StorageMetadata {
|
|
81
|
+
/** The object's `Content-Type`, when recorded. */
|
|
82
|
+
contentType?: string;
|
|
83
|
+
/** Custom metadata set at upload time, if any. */
|
|
84
|
+
customMetadata?: Record<string, string>;
|
|
85
|
+
/** The object's key. */
|
|
86
|
+
key: string;
|
|
87
|
+
/** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
|
|
88
|
+
sha256?: string;
|
|
89
|
+
/** Body length in bytes. */
|
|
90
|
+
size: number;
|
|
91
|
+
/** When the object was last written (epoch ms), when reported. */
|
|
92
|
+
uploaded?: number;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The body-free object shape returned by {@link ReadOnlyStorage.head} — a clean
|
|
96
|
+
* public mirror of `@lunora/storage`'s head projection, re-declared here for the
|
|
97
|
+
* same reason as {@link StorageMetadata}: the ctx surface carries no dependency
|
|
98
|
+
* on the storage package's types.
|
|
99
|
+
*
|
|
100
|
+
* Richer than {@link StorageMetadata} on purpose. `getMetadata` is the tidy
|
|
101
|
+
* Convex-shaped summary; `head` is what an HTTP layer needs, so it keeps the
|
|
102
|
+
* validator (`etag`) and the base64 digest RFC 9530 `Repr-Digest` requires, and
|
|
103
|
+
* leaves `uploaded` as the `Date` the binding reports rather than epoch ms.
|
|
104
|
+
*/
|
|
105
|
+
interface StorageObjectHead {
|
|
106
|
+
/** Custom metadata set at upload time, if any. */
|
|
107
|
+
customMetadata?: Record<string, string>;
|
|
108
|
+
/**
|
|
109
|
+
* R2's unquoted etag (the MD5 hex for a single-part upload). Required: R2
|
|
110
|
+
* reports one on every object, and an HTTP layer built on `head()` (the
|
|
111
|
+
* `serveStorageObject` helper) needs it to emit a validator.
|
|
112
|
+
*/
|
|
113
|
+
etag: string;
|
|
114
|
+
/** The already-quoted form of {@link StorageObjectHead.etag}, when the binding reports one. */
|
|
115
|
+
httpEtag?: string;
|
|
116
|
+
/** Recorded HTTP metadata, notably the `Content-Type`. */
|
|
117
|
+
httpMetadata?: {
|
|
118
|
+
contentType?: string;
|
|
119
|
+
};
|
|
120
|
+
/** The object's key. */
|
|
121
|
+
key: string;
|
|
122
|
+
/** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
|
|
123
|
+
sha256?: string;
|
|
124
|
+
/** Base64-encoded SHA-256 of the same checksum — the encoding RFC 9530 digest headers require. */
|
|
125
|
+
sha256Base64?: string;
|
|
126
|
+
/** 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. */
|
|
127
|
+
size: number;
|
|
128
|
+
/** When the object was last written. */
|
|
129
|
+
uploaded?: Date;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Byte window forwarded to {@link ReadOnlyStorage.download} so R2 resolves the
|
|
133
|
+
* slice server-side and streams only those bytes back. Mirrors R2's own `range`
|
|
134
|
+
* option (`@lunora/platform`'s `R2RangeLike`), restated structurally so
|
|
135
|
+
* `@lunora/server` takes no dependency on the bindings package.
|
|
136
|
+
*/
|
|
137
|
+
type StorageRange = {
|
|
138
|
+
length?: number;
|
|
139
|
+
offset: number;
|
|
140
|
+
} | {
|
|
141
|
+
length: number;
|
|
142
|
+
offset?: number;
|
|
143
|
+
} | {
|
|
144
|
+
suffix: number;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* A downloaded object: the same metadata {@link StorageObjectHead} carries, plus
|
|
148
|
+
* the body stream. This is what `download()` resolves to — R2's object, NOT a
|
|
149
|
+
* bare stream.
|
|
150
|
+
*/
|
|
151
|
+
interface StorageObjectBody extends StorageObjectHead {
|
|
152
|
+
/** The object body stream. `null` for a zero-byte object. */
|
|
153
|
+
body: ReadableStream | null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Read-only projection of `Storage` exposed on `QueryCtx` / `MutationCtx`.
|
|
157
|
+
*
|
|
158
|
+
* Queries are pure reads, and mutations run inside a transactional scope —
|
|
159
|
+
* neither is allowed to perform side-effectful R2 writes (`upload`) or
|
|
160
|
+
* deletes (`delete`). They can, however, **read** existing objects and
|
|
161
|
+
* resolve signed URLs (the URL signing itself is HMAC-only — no R2 round
|
|
162
|
+
* trip), so the read-only surface keeps `download` and `getSignedUrl`. The
|
|
163
|
+
* full {@link Storage} surface stays on `ActionCtx`.
|
|
164
|
+
*/
|
|
165
|
+
interface ReadOnlyStorage<Buckets extends string = string> {
|
|
166
|
+
/**
|
|
167
|
+
* Select a named bucket (declared via `v.storage("name")`). The returned
|
|
168
|
+
* accessor's operations target that bucket — `ctx.storage.bucket("avatars")
|
|
169
|
+
* .download(key)`. The bare `ctx.storage` targets the default bucket.
|
|
170
|
+
*/
|
|
171
|
+
bucket: (name: Buckets) => ReadOnlyStorage<Buckets>;
|
|
172
|
+
/** The bucket this accessor's operations target (the default for the bare `ctx.storage`). */
|
|
173
|
+
readonly bucketName: string;
|
|
174
|
+
/**
|
|
175
|
+
* Fetch an existing object. Returns the R2 object — metadata plus a `body`
|
|
176
|
+
* stream — or `null` when absent.
|
|
177
|
+
*
|
|
178
|
+
* NOT a bare stream: `new Response(await ctx.storage.download(key))` would
|
|
179
|
+
* stringify the object and serve the literal text `[object Object]`. Reach
|
|
180
|
+
* for the body explicitly:
|
|
181
|
+
*
|
|
182
|
+
* ```ts
|
|
183
|
+
* const object = await ctx.storage.download(key);
|
|
184
|
+
*
|
|
185
|
+
* return object ? new Response(object.body) : new Response("Not found", { status: 404 });
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* (`serveStorageObject` from `@lunora/server` does this, plus range/ETag
|
|
189
|
+
* handling, for the common "serve a stored file over HTTP" case.)
|
|
190
|
+
*
|
|
191
|
+
* Pass `range` to have R2 resolve the byte window server-side, so the
|
|
192
|
+
* unwanted bytes never reach the worker.
|
|
193
|
+
*/
|
|
194
|
+
download: (key: string, options?: {
|
|
195
|
+
range?: StorageRange;
|
|
196
|
+
}) => Promise<StorageObjectBody | null>;
|
|
197
|
+
/**
|
|
198
|
+
* Read a file's metadata (size, content-type, sha256, upload time, custom
|
|
199
|
+
* metadata) without fetching its body. Returns `null` when the object is
|
|
200
|
+
* absent. Mirrors Convex's `ctx.storage.getMetadata`.
|
|
201
|
+
*/
|
|
202
|
+
getMetadata: (key: string) => Promise<StorageMetadata | null>;
|
|
203
|
+
/** Resolve a short-lived signed URL for an existing object. */
|
|
204
|
+
getSignedUrl: (key: string, options?: {
|
|
205
|
+
expiresInSeconds?: number;
|
|
206
|
+
}) => Promise<string>;
|
|
207
|
+
/** Public URL pointing at the configured base for `key`. */
|
|
208
|
+
getUrl: (key: string) => string;
|
|
209
|
+
/**
|
|
210
|
+
* Read an object's metadata with NO body transfer, as the raw object shape —
|
|
211
|
+
* `etag` and the base64 digest included, which is what an HTTP layer needs to
|
|
212
|
+
* answer a `Range` request. Returns `null` when the object is absent.
|
|
213
|
+
*
|
|
214
|
+
* {@link ReadOnlyStorage.getMetadata} is the tidier summary over the same
|
|
215
|
+
* read; reach for this one when building a response.
|
|
216
|
+
*/
|
|
217
|
+
head: (key: string) => Promise<StorageObjectHead | null>;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* `ctx.storage` inside a **mutation**: the read surface, plus the one write a
|
|
221
|
+
* transactional context can safely express. See `@lunora/server`'s
|
|
222
|
+
* `deferred-deletes.ts` for why `delete` itself stays action-only.
|
|
223
|
+
*/
|
|
224
|
+
interface MutationStorage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
|
|
225
|
+
/** Select a named bucket; deletes queued on it are flushed against that bucket. */
|
|
226
|
+
bucket: (name: Buckets) => MutationStorage<Buckets>;
|
|
227
|
+
/**
|
|
228
|
+
* Queue `key` for deletion once this mutation commits.
|
|
229
|
+
*
|
|
230
|
+
* Returns `void`, not a promise: nothing has been attempted yet, so the object
|
|
231
|
+
* is still there on the next line. A rolled-back mutation never flushes, so
|
|
232
|
+
* the row deletion and the object cleanup cannot disagree. A failed delete
|
|
233
|
+
* leaks the object rather than failing a mutation that already succeeded, and
|
|
234
|
+
* is logged with its key.
|
|
235
|
+
*/
|
|
236
|
+
deleteAfterCommit: (key: string) => void;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* The body shapes `store` / `upload` accept — what R2's `put` stores bytes from.
|
|
240
|
+
* Mirrors `@lunora/storage`'s `Storage.upload` parameter.
|
|
241
|
+
*/
|
|
242
|
+
type StorageUploadBody = ArrayBuffer | ArrayBufferView | Blob | ReadableStream | string;
|
|
243
|
+
/**
|
|
244
|
+
* Options for `store` / `upload` — a structural mirror of `@lunora/storage`'s
|
|
245
|
+
* `UploadOptions`, so the `maxSize` / `allowedContentTypes` guards are reachable
|
|
246
|
+
* from `ctx.storage` without a type dependency on the storage package.
|
|
247
|
+
*/
|
|
248
|
+
interface StorageUploadOptions {
|
|
249
|
+
/** Content-type allowlist; the supplied `contentType` must match. */
|
|
250
|
+
allowedContentTypes?: ReadonlyArray<string>;
|
|
251
|
+
contentType?: string;
|
|
252
|
+
customMetadata?: Record<string, string>;
|
|
253
|
+
/**
|
|
254
|
+
* Maximum body size in bytes. A `ReadableStream` is buffered under the cap,
|
|
255
|
+
* so on the stream path `maxSize` is itself capped at 16 MiB — above that use
|
|
256
|
+
* {@link Storage.createMultipartUpload}.
|
|
257
|
+
*/
|
|
258
|
+
maxSize?: number;
|
|
259
|
+
/** SHA-256 of the body (hex or a 32-byte buffer); R2 records and verifies it. */
|
|
260
|
+
sha256?: ArrayBuffer | string;
|
|
261
|
+
}
|
|
262
|
+
/** What `store` / `upload` resolve to: the stored key plus its etag (unquoted and quoted). */
|
|
263
|
+
interface StorageUploadResult {
|
|
264
|
+
etag: string;
|
|
265
|
+
httpEtag: string;
|
|
266
|
+
key: string;
|
|
267
|
+
}
|
|
268
|
+
/** One uploaded multipart part — returned by `uploadPart`, required by `complete`. Mirrors R2's `R2UploadedPart`. */
|
|
269
|
+
interface StorageUploadedPart {
|
|
270
|
+
etag: string;
|
|
271
|
+
partNumber: number;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* An in-progress R2 multipart upload, as {@link Storage.createMultipartUpload} /
|
|
275
|
+
* {@link Storage.resumeMultipartUpload} return it. A structural mirror of
|
|
276
|
+
* R2's own multipart upload handle, as `@lunora/platform` declares it.
|
|
277
|
+
*
|
|
278
|
+
* Every part except the last must be the same size, and at least 5 MiB. The
|
|
279
|
+
* object does not guarantee the upload still exists — a parallel `complete` /
|
|
280
|
+
* `abort` invalidates it — so handle errors on each call.
|
|
281
|
+
*/
|
|
282
|
+
interface StorageMultipartUpload {
|
|
283
|
+
/** Abort the upload, discarding every uploaded part. */
|
|
284
|
+
abort: () => Promise<void>;
|
|
285
|
+
/** Finish the upload from the collected parts; resolves to the stored object's metadata. */
|
|
286
|
+
complete: (uploadedParts: StorageUploadedPart[]) => Promise<StorageObjectHead>;
|
|
287
|
+
/** The object key being assembled. */
|
|
288
|
+
readonly key: string;
|
|
289
|
+
/** The R2 upload id — persist it to resume the upload in a later request. */
|
|
290
|
+
readonly uploadId: string;
|
|
291
|
+
/** Upload one part (1-indexed); returns the `{ partNumber, etag }` to pass to `complete`. */
|
|
292
|
+
uploadPart: (partNumber: number, value: StorageUploadBody) => Promise<StorageUploadedPart>;
|
|
293
|
+
}
|
|
294
|
+
/** Options for {@link Storage.createMultipartUpload}: the metadata recorded on the assembled object. */
|
|
295
|
+
interface StorageMultipartUploadOptions {
|
|
296
|
+
contentType?: string;
|
|
297
|
+
customMetadata?: Record<string, string>;
|
|
298
|
+
}
|
|
299
|
+
/** Options for {@link Storage.list}. Mirrors `@lunora/storage`'s `ListOptions`. */
|
|
300
|
+
interface StorageListOptions {
|
|
301
|
+
/** The `cursor` of the previous page. */
|
|
302
|
+
cursor?: string;
|
|
303
|
+
/** R2 list delimiter — keys sharing a segment roll up into `delimitedPrefixes`. */
|
|
304
|
+
delimiter?: string;
|
|
305
|
+
/** Page-size ceiling: defaults to 100, capped at 1000. A positive integer; anything else throws. */
|
|
306
|
+
limit?: number;
|
|
307
|
+
}
|
|
308
|
+
/** One page of {@link Storage.list}. */
|
|
309
|
+
interface StorageListResult {
|
|
310
|
+
/** Pass back as `options.cursor` for the next page, while `truncated` is `true`. */
|
|
311
|
+
cursor?: string;
|
|
312
|
+
/** The rolled-up "folders" when `options.delimiter` is set — these are NOT in `objects`. */
|
|
313
|
+
delimitedPrefixes?: string[];
|
|
314
|
+
/** The objects on this page, body-free and JSON-serializable. */
|
|
315
|
+
objects: StorageObjectHead[];
|
|
316
|
+
/** `true` while more pages remain. Paginate on this, never on `objects.length`. */
|
|
317
|
+
truncated?: boolean;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* `ctx.storage` inside an **action**: the full `@lunora/storage` `Storage`
|
|
321
|
+
* surface, plus `bucket(name)`.
|
|
322
|
+
*
|
|
323
|
+
* Declared structurally rather than imported — `@lunora/server` takes no
|
|
324
|
+
* runtime or published-type dependency on `@lunora/storage` — so it tracks that
|
|
325
|
+
* surface by hand. A type test (`__tests__/storage-surface.test-d.ts`) fails
|
|
326
|
+
* `tsc` when the two drift —
|
|
327
|
+
* the member sets differ (a runtime member left untyped here, or a member typed
|
|
328
|
+
* here the runtime lacks — `bucket` aside, which the ctx wiring adds); the
|
|
329
|
+
* runtime object no longer satisfies a signature here (a return type widened,
|
|
330
|
+
* or a parameter narrowed, upstream); or a parameter list here differs from the
|
|
331
|
+
* runtime's (an option or body shape the runtime takes but this interface
|
|
332
|
+
* refuses). `getSignedUrl` is the one deliberate parameter exception: its PUT
|
|
333
|
+
* options would mint an upload URL from a query.
|
|
334
|
+
*
|
|
335
|
+
* Return types here may be NARROWER than the runtime's on purpose — `head`
|
|
336
|
+
* resolves to the {@link StorageObjectHead} mirror rather than R2's object.
|
|
337
|
+
*
|
|
338
|
+
* Every member here is action-only. Under a procedure guarded by
|
|
339
|
+
* `storageRules(...)`, the write paths (`store` / `upload` /
|
|
340
|
+
* `createMultipartUpload` / `resumeMultipartUpload`) are gated as `write`, and
|
|
341
|
+
* `getPresignedUrl` / `list`, which no rule can gate, reject with `FORBIDDEN`.
|
|
342
|
+
*/
|
|
343
|
+
interface Storage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
|
|
344
|
+
/** Select a named bucket; the returned accessor exposes the full read/write surface. */
|
|
345
|
+
bucket: (name: Buckets) => Storage<Buckets>;
|
|
346
|
+
/**
|
|
347
|
+
* Begin a native R2 **multipart upload** — for objects above `store()`'s
|
|
348
|
+
* 16 MiB stream cap, streamed through the Worker without buffering. Upload
|
|
349
|
+
* the parts (each at least 5 MiB and uniform in size, except the last), then
|
|
350
|
+
* `complete` with the returned parts, or `abort`. Persist `uploadId` to
|
|
351
|
+
* continue in a later request via {@link Storage.resumeMultipartUpload}.
|
|
352
|
+
*/
|
|
353
|
+
createMultipartUpload: (key: string, options?: StorageMultipartUploadOptions) => Promise<StorageMultipartUpload>;
|
|
354
|
+
delete: (key: string) => Promise<void>;
|
|
355
|
+
/**
|
|
356
|
+
* Mint a short-lived signed `PUT` URL a client can upload directly to,
|
|
357
|
+
* optionally pinning the `Content-Type` the uploader must send. Mirrors
|
|
358
|
+
* Convex's `storage.generateUploadUrl`.
|
|
359
|
+
*/
|
|
360
|
+
generateUploadUrl: (key: string, options?: {
|
|
361
|
+
contentType?: string;
|
|
362
|
+
expiresInSeconds?: number;
|
|
363
|
+
}) => Promise<string>;
|
|
364
|
+
/**
|
|
365
|
+
* Mint a native S3 SigV4 URL that hits R2 **directly**, so the bytes never
|
|
366
|
+
* pass through the Worker — unlike {@link Storage.generateUploadUrl}, whose
|
|
367
|
+
* signed URL points back at this app so its storage rules still apply.
|
|
368
|
+
*
|
|
369
|
+
* Requires `s3` credentials on the `.storage({ s3 })` declaration; without
|
|
370
|
+
* them the call throws. That is the trade-off: no Worker in the path also
|
|
371
|
+
* means no rule enforcement in the path.
|
|
372
|
+
*/
|
|
373
|
+
getPresignedUrl: (key: string, options?: {
|
|
374
|
+
expiresInSeconds?: number;
|
|
375
|
+
method?: "GET" | "PUT";
|
|
376
|
+
}) => Promise<string>;
|
|
377
|
+
/**
|
|
378
|
+
* List objects under `prefix` — e.g. to sweep abandoned staging uploads. With
|
|
379
|
+
* `options.delimiter` set, keys sharing a segment roll up into
|
|
380
|
+
* `delimitedPrefixes` and are NOT in `objects`, so an empty `objects` is not
|
|
381
|
+
* an empty directory. A page may hold fewer objects than `options.limit`:
|
|
382
|
+
* paginate on `truncated` / `cursor`.
|
|
383
|
+
*
|
|
384
|
+
* Not gated by storage access rules (and dropped under `storageRules(...)`);
|
|
385
|
+
* a rule-scoped enumeration goes through `ctx.db.system.query("_storage")`.
|
|
386
|
+
*/
|
|
387
|
+
list: (prefix?: string, options?: StorageListOptions) => Promise<StorageListResult>;
|
|
388
|
+
/**
|
|
389
|
+
* Resume an in-progress multipart upload by its `uploadId` (e.g. across
|
|
390
|
+
* requests). Synchronous: R2 does not validate the id, so a stale one
|
|
391
|
+
* surfaces as an error on the first `uploadPart` / `complete`.
|
|
392
|
+
*/
|
|
393
|
+
resumeMultipartUpload: (key: string, uploadId: string) => StorageMultipartUpload;
|
|
394
|
+
/**
|
|
395
|
+
* Upload `body` to `key` from the server, returning the stored object's key
|
|
396
|
+
* and etag. Mirrors Convex's `storage.store`; the same function as
|
|
397
|
+
* {@link Storage.upload}, so the `maxSize` / `allowedContentTypes` guards
|
|
398
|
+
* apply through the alias.
|
|
399
|
+
*/
|
|
400
|
+
store: (key: string, body: StorageUploadBody, options?: StorageUploadOptions) => Promise<StorageUploadResult>;
|
|
401
|
+
/** Upload `body` to `key` — {@link Storage.store} under `@lunora/storage`'s own name, with one shared signature. */
|
|
402
|
+
upload: Storage<Buckets>["store"];
|
|
403
|
+
}
|
|
66
404
|
/** Map of validators describing a function's args record. Alias of `@lunora/values`' shared {@link ValidatorMap}. */
|
|
67
405
|
type ArgsValidator = ValidatorMap;
|
|
68
406
|
/** Infer the args object type from an {@link ArgsValidator}. Alias of `@lunora/values`' shared {@link InferValidatorMap}. */
|
|
@@ -1774,216 +2112,6 @@ interface TriggerBuilder<Shape extends Record<string, Validator> = Record<string
|
|
|
1774
2112
|
beforeInsert: (handler: TriggerHandler<TriggerInsertEvent<Shape>>) => TriggerDefinition;
|
|
1775
2113
|
beforeUpdate: (handler: TriggerHandler<TriggerUpdateEvent<Shape>>) => TriggerDefinition;
|
|
1776
2114
|
}
|
|
1777
|
-
/**
|
|
1778
|
-
* Per-file metadata returned by {@link ReadOnlyStorage.getMetadata}. A clean
|
|
1779
|
-
* public mirror of `@lunora/storage`'s `ObjectMetadata` — re-declared here so
|
|
1780
|
-
* the ctx surface carries no dependency on the storage package's types. Matches
|
|
1781
|
-
* the columns Convex surfaces for `ctx.storage.getMetadata` / `_storage`.
|
|
1782
|
-
*/
|
|
1783
|
-
interface StorageMetadata {
|
|
1784
|
-
/** The object's `Content-Type`, when recorded. */
|
|
1785
|
-
contentType?: string;
|
|
1786
|
-
/** Custom metadata set at upload time, if any. */
|
|
1787
|
-
customMetadata?: Record<string, string>;
|
|
1788
|
-
/** The object's key. */
|
|
1789
|
-
key: string;
|
|
1790
|
-
/** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
|
|
1791
|
-
sha256?: string;
|
|
1792
|
-
/** Body length in bytes. */
|
|
1793
|
-
size: number;
|
|
1794
|
-
/** When the object was last written (epoch ms), when reported. */
|
|
1795
|
-
uploaded?: number;
|
|
1796
|
-
}
|
|
1797
|
-
/**
|
|
1798
|
-
* The body-free object shape returned by {@link ReadOnlyStorage.head} — a clean
|
|
1799
|
-
* public mirror of `@lunora/storage`'s head projection, re-declared here for the
|
|
1800
|
-
* same reason as {@link StorageMetadata}: the ctx surface carries no dependency
|
|
1801
|
-
* on the storage package's types.
|
|
1802
|
-
*
|
|
1803
|
-
* Richer than {@link StorageMetadata} on purpose. `getMetadata` is the tidy
|
|
1804
|
-
* Convex-shaped summary; `head` is what an HTTP layer needs, so it keeps the
|
|
1805
|
-
* validator (`etag`) and the base64 digest RFC 9530 `Repr-Digest` requires, and
|
|
1806
|
-
* leaves `uploaded` as the `Date` the binding reports rather than epoch ms.
|
|
1807
|
-
*/
|
|
1808
|
-
interface StorageObjectHead {
|
|
1809
|
-
/** Custom metadata set at upload time, if any. */
|
|
1810
|
-
customMetadata?: Record<string, string>;
|
|
1811
|
-
/**
|
|
1812
|
-
* R2's unquoted etag (the MD5 hex for a single-part upload). Required: R2
|
|
1813
|
-
* reports one on every object, and an HTTP layer built on `head()` (the
|
|
1814
|
-
* `serveStorageObject` helper) needs it to emit a validator.
|
|
1815
|
-
*/
|
|
1816
|
-
etag: string;
|
|
1817
|
-
/** The already-quoted form of {@link StorageObjectHead.etag}, when the binding reports one. */
|
|
1818
|
-
httpEtag?: string;
|
|
1819
|
-
/** Recorded HTTP metadata, notably the `Content-Type`. */
|
|
1820
|
-
httpMetadata?: {
|
|
1821
|
-
contentType?: string;
|
|
1822
|
-
};
|
|
1823
|
-
/** The object's key. */
|
|
1824
|
-
key: string;
|
|
1825
|
-
/** Hex-encoded SHA-256 of the body, when R2 carries a checksum. */
|
|
1826
|
-
sha256?: string;
|
|
1827
|
-
/** Base64-encoded SHA-256 of the same checksum — the encoding RFC 9530 digest headers require. */
|
|
1828
|
-
sha256Base64?: string;
|
|
1829
|
-
/** 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. */
|
|
1830
|
-
size: number;
|
|
1831
|
-
/** When the object was last written. */
|
|
1832
|
-
uploaded?: Date;
|
|
1833
|
-
}
|
|
1834
|
-
/**
|
|
1835
|
-
* Byte window forwarded to {@link ReadOnlyStorage.download} so R2 resolves the
|
|
1836
|
-
* slice server-side and streams only those bytes back. Mirrors R2's own `range`
|
|
1837
|
-
* option (`@lunora/platform`'s `R2RangeLike`), restated structurally so
|
|
1838
|
-
* `@lunora/server` takes no dependency on the bindings package.
|
|
1839
|
-
*/
|
|
1840
|
-
type StorageRange = {
|
|
1841
|
-
length?: number;
|
|
1842
|
-
offset: number;
|
|
1843
|
-
} | {
|
|
1844
|
-
length: number;
|
|
1845
|
-
offset?: number;
|
|
1846
|
-
} | {
|
|
1847
|
-
suffix: number;
|
|
1848
|
-
};
|
|
1849
|
-
/**
|
|
1850
|
-
* A downloaded object: the same metadata {@link StorageObjectHead} carries, plus
|
|
1851
|
-
* the body stream. This is what `download()` resolves to — R2's object, NOT a
|
|
1852
|
-
* bare stream.
|
|
1853
|
-
*/
|
|
1854
|
-
interface StorageObjectBody extends StorageObjectHead {
|
|
1855
|
-
/** The object body stream. `null` for a zero-byte object. */
|
|
1856
|
-
body: ReadableStream | null;
|
|
1857
|
-
}
|
|
1858
|
-
/**
|
|
1859
|
-
* Read-only projection of `Storage` exposed on `QueryCtx` / `MutationCtx`.
|
|
1860
|
-
*
|
|
1861
|
-
* Queries are pure reads, and mutations run inside a transactional scope —
|
|
1862
|
-
* neither is allowed to perform side-effectful R2 writes (`upload`) or
|
|
1863
|
-
* deletes (`delete`). They can, however, **read** existing objects and
|
|
1864
|
-
* resolve signed URLs (the URL signing itself is HMAC-only — no R2 round
|
|
1865
|
-
* trip), so the read-only surface keeps `download` and `getSignedUrl`. The
|
|
1866
|
-
* full {@link Storage} surface stays on `ActionCtx`.
|
|
1867
|
-
*/
|
|
1868
|
-
interface ReadOnlyStorage<Buckets extends string = string> {
|
|
1869
|
-
/**
|
|
1870
|
-
* Select a named bucket (declared via `v.storage("name")`). The returned
|
|
1871
|
-
* accessor's operations target that bucket — `ctx.storage.bucket("avatars")
|
|
1872
|
-
* .download(key)`. The bare `ctx.storage` targets the default bucket.
|
|
1873
|
-
*/
|
|
1874
|
-
bucket: (name: Buckets) => ReadOnlyStorage<Buckets>;
|
|
1875
|
-
/** The bucket this accessor's operations target (the default for the bare `ctx.storage`). */
|
|
1876
|
-
readonly bucketName: string;
|
|
1877
|
-
/**
|
|
1878
|
-
* Fetch an existing object. Returns the R2 object — metadata plus a `body`
|
|
1879
|
-
* stream — or `null` when absent.
|
|
1880
|
-
*
|
|
1881
|
-
* NOT a bare stream: `new Response(await ctx.storage.download(key))` would
|
|
1882
|
-
* stringify the object and serve the literal text `[object Object]`. Reach
|
|
1883
|
-
* for the body explicitly:
|
|
1884
|
-
*
|
|
1885
|
-
* ```ts
|
|
1886
|
-
* const object = await ctx.storage.download(key);
|
|
1887
|
-
*
|
|
1888
|
-
* return object ? new Response(object.body) : new Response("Not found", { status: 404 });
|
|
1889
|
-
* ```
|
|
1890
|
-
*
|
|
1891
|
-
* (`serveStorageObject` from `@lunora/server` does this, plus range/ETag
|
|
1892
|
-
* handling, for the common "serve a stored file over HTTP" case.)
|
|
1893
|
-
*
|
|
1894
|
-
* Pass `range` to have R2 resolve the byte window server-side, so the
|
|
1895
|
-
* unwanted bytes never reach the worker.
|
|
1896
|
-
*/
|
|
1897
|
-
download: (key: string, options?: {
|
|
1898
|
-
range?: StorageRange;
|
|
1899
|
-
}) => Promise<StorageObjectBody | null>;
|
|
1900
|
-
/**
|
|
1901
|
-
* Read a file's metadata (size, content-type, sha256, upload time, custom
|
|
1902
|
-
* metadata) without fetching its body. Returns `null` when the object is
|
|
1903
|
-
* absent. Mirrors Convex's `ctx.storage.getMetadata`.
|
|
1904
|
-
*/
|
|
1905
|
-
getMetadata: (key: string) => Promise<StorageMetadata | null>;
|
|
1906
|
-
/** Resolve a short-lived signed URL for an existing object. */
|
|
1907
|
-
getSignedUrl: (key: string, options?: {
|
|
1908
|
-
expiresInSeconds?: number;
|
|
1909
|
-
}) => Promise<string>;
|
|
1910
|
-
/** Public URL pointing at the configured base for `key`. */
|
|
1911
|
-
getUrl: (key: string) => string;
|
|
1912
|
-
/**
|
|
1913
|
-
* Read an object's metadata with NO body transfer, as the raw object shape —
|
|
1914
|
-
* `etag` and the base64 digest included, which is what an HTTP layer needs to
|
|
1915
|
-
* answer a `Range` request. Returns `null` when the object is absent.
|
|
1916
|
-
*
|
|
1917
|
-
* {@link ReadOnlyStorage.getMetadata} is the tidier summary over the same
|
|
1918
|
-
* read; reach for this one when building a response.
|
|
1919
|
-
*/
|
|
1920
|
-
head: (key: string) => Promise<StorageObjectHead | null>;
|
|
1921
|
-
}
|
|
1922
|
-
/**
|
|
1923
|
-
* `ctx.storage` inside a **mutation**: the read surface, plus the one write a
|
|
1924
|
-
* transactional context can safely express. See `@lunora/server`'s
|
|
1925
|
-
* `deferred-deletes.ts` for why `delete` itself stays action-only.
|
|
1926
|
-
*/
|
|
1927
|
-
interface MutationStorage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
|
|
1928
|
-
/** Select a named bucket; deletes queued on it are flushed against that bucket. */
|
|
1929
|
-
bucket: (name: Buckets) => MutationStorage<Buckets>;
|
|
1930
|
-
/**
|
|
1931
|
-
* Queue `key` for deletion once this mutation commits.
|
|
1932
|
-
*
|
|
1933
|
-
* Returns `void`, not a promise: nothing has been attempted yet, so the object
|
|
1934
|
-
* is still there on the next line. A rolled-back mutation never flushes, so
|
|
1935
|
-
* the row deletion and the object cleanup cannot disagree. A failed delete
|
|
1936
|
-
* leaks the object rather than failing a mutation that already succeeded, and
|
|
1937
|
-
* is logged with its key.
|
|
1938
|
-
*/
|
|
1939
|
-
deleteAfterCommit: (key: string) => void;
|
|
1940
|
-
}
|
|
1941
|
-
interface Storage<Buckets extends string = string> extends ReadOnlyStorage<Buckets> {
|
|
1942
|
-
/** Select a named bucket; the returned accessor exposes the full read/write surface. */
|
|
1943
|
-
bucket: (name: Buckets) => Storage<Buckets>;
|
|
1944
|
-
delete: (key: string) => Promise<void>;
|
|
1945
|
-
/**
|
|
1946
|
-
* Mint a short-lived signed `PUT` URL a client can upload directly to,
|
|
1947
|
-
* optionally pinning the `Content-Type` the uploader must send. Mirrors
|
|
1948
|
-
* Convex's `storage.generateUploadUrl`.
|
|
1949
|
-
*/
|
|
1950
|
-
generateUploadUrl: (key: string, options?: {
|
|
1951
|
-
contentType?: string;
|
|
1952
|
-
expiresInSeconds?: number;
|
|
1953
|
-
}) => Promise<string>;
|
|
1954
|
-
/**
|
|
1955
|
-
* Mint a native S3 SigV4 URL that hits R2 **directly**, so the bytes never
|
|
1956
|
-
* pass through the Worker — unlike {@link Storage.generateUploadUrl}, whose
|
|
1957
|
-
* signed URL points back at this app so its storage rules still apply.
|
|
1958
|
-
*
|
|
1959
|
-
* Requires `s3` credentials on the `.storage({ s3 })` declaration; without
|
|
1960
|
-
* them the call throws. That is the trade-off: no Worker in the path also
|
|
1961
|
-
* means no rule enforcement in the path.
|
|
1962
|
-
*
|
|
1963
|
-
* Declared structurally rather than imported — `@lunora/server` does not
|
|
1964
|
-
* depend on `@lunora/storage`, and this file mirrors that surface the same
|
|
1965
|
-
* way `head` and `download` do.
|
|
1966
|
-
*/
|
|
1967
|
-
getPresignedUrl: (key: string, options?: {
|
|
1968
|
-
expiresInSeconds?: number;
|
|
1969
|
-
method?: "GET" | "PUT";
|
|
1970
|
-
}) => Promise<string>;
|
|
1971
|
-
/**
|
|
1972
|
-
* Upload `body` to `key` from the server, returning the stored object's key
|
|
1973
|
-
* and etag. Mirrors Convex's `storage.store`. Accepts the same guard fields
|
|
1974
|
-
* as `@lunora/storage`'s `UploadOptions` so `maxSize` /
|
|
1975
|
-
* `allowedContentTypes` enforcement isn't lost behind the Convex-style alias.
|
|
1976
|
-
*/
|
|
1977
|
-
store: (key: string, body: ReadableStream | ArrayBuffer | Blob, options?: {
|
|
1978
|
-
allowedContentTypes?: ReadonlyArray<string>;
|
|
1979
|
-
contentType?: string;
|
|
1980
|
-
customMetadata?: Record<string, string>;
|
|
1981
|
-
maxSize?: number;
|
|
1982
|
-
}) => Promise<{
|
|
1983
|
-
etag: string;
|
|
1984
|
-
key: string;
|
|
1985
|
-
}>;
|
|
1986
|
-
}
|
|
1987
2115
|
interface VectorMatch {
|
|
1988
2116
|
id: string;
|
|
1989
2117
|
metadata?: Record<string, unknown>;
|
|
@@ -2613,4 +2741,4 @@ interface ActionCtx {
|
|
|
2613
2741
|
*/
|
|
2614
2742
|
type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
|
|
2615
2743
|
declare const anyApi: AnyApi;
|
|
2616
|
-
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 MutationStorage, 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 RelatedDirection, type RelatedNode, type RelatedOptions, type RelatedPage, type RelatedStart, type RelatedStartReference, type RelationDefinition, type RestCacheConfig, type RetryPolicy, 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 SpanContextIds, type SpanEvaluation, type SpanHandle, type SpanIdentity, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageMetadata, type StorageObjectBody, type StorageObjectHead, type StorageRange, 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 WhisperEvent, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceEvent, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, type X402ProcedureConfig, anyApi };
|
|
2744
|
+
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 MutationStorage, 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 RelatedDirection, type RelatedNode, type RelatedOptions, type RelatedPage, type RelatedStart, type RelatedStartReference, type RelationDefinition, type RestCacheConfig, type RetryPolicy, 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 SpanContextIds, type SpanEvaluation, type SpanHandle, type SpanIdentity, type SpanKind, type SpanLink, type SpanOptions, type Storage, type StorageListOptions, type StorageListResult, type StorageMetadata, type StorageMultipartUpload, type StorageMultipartUploadOptions, type StorageObjectBody, type StorageObjectHead, type StorageRange, type StorageUploadBody, type StorageUploadOptions, type StorageUploadResult, type StorageUploadedPart, 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 WhisperEvent, type WorkflowCreateOptions, type WorkflowEventDefinition, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceEvent, 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.
|
|
3
|
+
"version": "1.0.0-alpha.173",
|
|
4
4
|
"description": "Server primitives for Lunora: defineSchema, defineTable, query, mutation, and action",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"backend",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@lunora/errors": "1.0.0-alpha.50",
|
|
70
|
-
"@lunora/scheduler": "1.0.0-alpha.
|
|
71
|
-
"@lunora/shard-engine": "1.0.0-alpha.
|
|
70
|
+
"@lunora/scheduler": "1.0.0-alpha.107",
|
|
71
|
+
"@lunora/shard-engine": "1.0.0-alpha.109",
|
|
72
72
|
"@lunora/values": "1.0.0-alpha.60",
|
|
73
73
|
"drizzle-orm": "^0.45.2",
|
|
74
74
|
"hono": "^4.13.7"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as A}from"@lunora/errors";import{i as U,a as $}from"./middleware-ChNz4wOv.mjs";const N=(e,t,o)=>{const a=s=>o.isAllowed("list",s,t)&&o.isAllowed("read",s,t),{get:r,query:b}=e,l={...e},w=s=>s.filter(n=>typeof n.key=="string"&&a(n.key));return typeof r=="function"&&(l.get=async(s,n)=>(s==="_storage"&&o.assertAllowed("read",n,t),r(s,n))),typeof b=="function"&&(l.query=s=>{const n=b(s),{collect:p}=n;return s!=="_storage"||typeof p!="function"?n:{...n,collect:async()=>w(await p())}}),l},S=(e,t)=>{if(e===void 0)return!0;const o=e.endsWith("/")?e.slice(0,-1):e;return o===""||t===o||t.startsWith(`${o}/`)},D=e=>{const t=e[1],o=typeof t=="object"&&t!==null?t.method:void 0;return typeof o=="string"&&o.toUpperCase()==="PUT"?"write":"read"},E=[["delete","delete"],["deleteAfterCommit","delete"],["download","read"],["generateUploadUrl","write"],["getMetadata","read"],["getSignedUrl",D],["getUrl","read"],["head","read"],["store","write"]],M=(e,t)=>{try{return e(t).bucketName===t}catch{return!1}},P=(e,t)=>{const o=e.bucketName??"default",{bucket:a}=e;for(const r of new Set(t))if(!(r===o||typeof a=="function"&&M(a,r)))throw new A("INTERNAL",`storageRules: rule for bucket "${r}" governs nothing — this request's storage cannot address that bucket (the accessor is "${o}", and selecting "${r}" does not reach a bucket of that name). A rule on an unaddressable bucket leaves the operation it was written to gate wide open. Match the rule's \`bucket\` to the name the binding is registered under in \`.storage({ bucket, buckets })\`.`)},C=(e,t={})=>{const o=U(t.roles);return async({ctx:a,next:r})=>{const b=await $(a.auth??{},o),l=(c,u,d)=>{const h=e.filter(i=>i.on===c&&i.bucket===d);if(h.length===0)return!0;const f={auth:b,ctx:a,key:u};return h.some(i=>S(i.prefix,u)&&i.when(f)===!0)},w=(c,u,d)=>{if(!l(c,u,d))throw new A("FORBIDDEN",`storage ${c} on "${u}" in bucket "${d}" denied by access rule`)},s=c=>{const u=c.bucketName??"default",d={bucketName:u};for(const[f,i]of E){const k=c[f];typeof k=="function"&&(d[f]=(...y)=>{const R=typeof y[0]=="string"?y[0]:"",v=typeof i=="function"?i(y):i;return w(v,R,u),k(...y)})}const{bucket:h}=c;return typeof h=="function"&&(d.bucket=f=>s(h(f))),d},n=a.storage;if(n===void 0)return r();P(n,e.map(c=>c.bucket));const p={storage:s(n)},g=a.db,m=g?.system;return g!==void 0&&m!==void 0&&typeof m=="object"&&(p.db={...g,system:N(m,n.bucketName??"default",{assertAllowed:w,isAllowed:l})}),r({ctx:p})}};export{C as storageRules};
|