@lunora/server 1.0.0-alpha.16 → 1.0.0-alpha.18

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/LICENSE.md CHANGED
@@ -103,3 +103,9 @@ Unless required by applicable law or agreed to in writing, software distributed
103
103
  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
104
  CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
105
  specific language governing permissions and limitations under the License.
106
+
107
+ <!-- DEPENDENCIES -->
108
+ <!-- /DEPENDENCIES -->
109
+
110
+ <!-- TYPE_DEPENDENCIES -->
111
+ <!-- /TYPE_DEPENDENCIES -->
package/README.md CHANGED
@@ -99,6 +99,52 @@ The builder chain is `<builder>.input(validators).<kind>(handler)`, plus `.use(m
99
99
 
100
100
  > This README covers the basics. For the full API, options, and guides, see the **[documentation](https://lunora.sh/docs/packages/server)**.
101
101
 
102
+ ### Caching with Workers Cache
103
+
104
+ Lunora supports Cloudflare Workers Cache for HTTP actions (`httpRoute`). RPC queries and mutations are `POST /_lunora/rpc` and are not cacheable at the edge by design.
105
+
106
+ **Enable Workers Cache** in `wrangler.jsonc`:
107
+
108
+ ```jsonc
109
+ {
110
+ "cache": { "enabled": true },
111
+ }
112
+ ```
113
+
114
+ The dev server and CLI automatically bump `compatibility_date` to the minimum required when cache is enabled — you do not need to set it manually.
115
+
116
+ **Set cache headers declaratively** on an `httpRoute`:
117
+
118
+ ```ts
119
+ import { httpRoute } from "./_generated/server";
120
+
121
+ export const getProduct = httpRoute
122
+ .get("/api/products/:id")
123
+ .params({ id: v.string() })
124
+ .cacheControl("public, max-age=300, stale-while-revalidate=3600")
125
+ .cacheTag("products")
126
+ .handler(async ({ ctx, params }) => {
127
+ return { id: params.id, name: "Widget" };
128
+ });
129
+ ```
130
+
131
+ **Purge cache by tag** from an action handler:
132
+
133
+ ```ts
134
+ import { action } from "./_generated/server";
135
+
136
+ export const refreshProducts = action.action(async ({ ctx }) => {
137
+ if (!ctx.cache) {
138
+ throw new Error("Workers Cache is not enabled in wrangler.jsonc");
139
+ }
140
+
141
+ await ctx.cache.purge({ tags: ["products"] });
142
+ return { ok: true };
143
+ });
144
+ ```
145
+
146
+ The `ctx.cache.purge` API accepts `{ tags?: string[]; purgeEverything?: boolean }`. Only action handlers expose `ctx.cache`; queries and mutations run inside the Durable Object and do not have access to the Worker-level cache binding.
147
+
102
148
  ## Related
103
149
 
104
150
  - [`@lunora/values`](https://www.npmjs.com/package/@lunora/values) — the `v.*` validators re-exported here.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Validator, Infer, ValidatorMap, InferValidatorMap, v } from '@lunora/values';
2
2
  export { type ColumnValidator, type Id, type Infer, ValidationError, type Validator, type ValidatorKind, v } from '@lunora/values';
3
3
  import { ArgsValidator, InferArgs, RegisteredAction, ActionCtx, MutationCtx, RegisteredMutation, QueryCtx, RegisteredQuery, RegisteredStream, FunctionKind, Secrets, LifecycleEvent, RegisteredLifecycleHook, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, DurableObjectJurisdiction, RelationDefinition, GlobalBackend, OnDeleteAction, ExternalSourceDefinition, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, AggregateIndexDefinition, RankIndexDefinition } from "./types.mjs";
4
- export { type AnyApi, type AuthState, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LunoraLogger, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.mjs";
4
+ export { type AnyApi, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LunoraLogger, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.mjs";
5
5
  import { LunoraError as LunoraError$1, LunoraErrorCode } from '@lunora/errors';
6
6
  export type { LunoraErrorCode } from '@lunora/errors';
7
7
  import { Context, Hono } from 'hono';
@@ -435,7 +435,7 @@ type HttpMethod = "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PU
435
435
  * `storage` surface — reach the data layer through `runQuery` / `runMutation` /
436
436
  * `runAction`, which forward to the owning shard.
437
437
  */
438
- type HttpActionCtx = Pick<ActionCtx, "auth" | "fetch" | "runAction" | "runMutation" | "runQuery">;
438
+ type HttpActionCtx = Pick<ActionCtx, "auth" | "cache" | "fetch" | "runAction" | "runMutation" | "runQuery">;
439
439
  /** A raw handler wrapped by {@link httpAction}. Receives the raw request, returns the raw response. */
440
440
  type HttpActionHandler = (context: HttpActionCtx, request: Request) => Promise<Response> | Response;
441
441
  /**
@@ -519,6 +519,16 @@ interface HttpStreamHandlerOptions<SearchParams extends ArgsValidator, Params ex
519
519
  */
520
520
  interface HttpRouteBuilder<SearchParams extends ArgsValidator, Body extends ArgsValidator, Params extends ArgsValidator, Output = undefined> {
521
521
  body: <B extends ArgsValidator>(validators: B) => HttpRouteBuilder<SearchParams, B & Body, Params, Output>;
522
+ /**
523
+ * Attach a `Cache-Control` header to the response. Only meaningful when
524
+ * Workers Cache is enabled in `wrangler.jsonc` (`"cache": { "enabled": true }`).
525
+ */
526
+ cacheControl: (value: string) => HttpRouteBuilder<SearchParams, Body, Params, Output>;
527
+ /**
528
+ * Attach a `Cache-Tag` header to the response for tag-based purging via
529
+ * `ctx.cache.purge({ tags: [...] })`.
530
+ */
531
+ cacheTag: (value: string) => HttpRouteBuilder<SearchParams, Body, Params, Output>;
522
532
  handler: [Output] extends [undefined] ? <R>(handler: (options: HttpRouteHandlerOptions<SearchParams, Body, Params>) => Promise<R> | R) => LunoraRouteHandler : (handler: (options: HttpRouteHandlerOptions<SearchParams, Body, Params>) => Output | Promise<Output>) => LunoraRouteHandler;
523
533
  output: <V extends Validator>(validator: V) => HttpRouteBuilder<SearchParams, Body, Params, Infer<V>>;
524
534
  params: <P extends ArgsValidator>(validators: P) => HttpRouteBuilder<SearchParams, Body, P & Params, Output>;
@@ -533,6 +543,11 @@ interface HttpRouteBuilder<SearchParams extends ArgsValidator, Body extends Args
533
543
  * handler's yielded type.
534
544
  */
535
545
  stream: <R>(handler: (options: HttpStreamHandlerOptions<SearchParams, Params>) => AsyncGenerator<R, void, void> | AsyncIterable<R>) => LunoraRouteHandler;
546
+ /**
547
+ * Attach a `Vary` header to the response so Cloudflare stores separate
548
+ * cached variants per distinct value of the listed request headers.
549
+ */
550
+ vary: (value: string) => HttpRouteBuilder<SearchParams, Body, Params, Output>;
536
551
  }
537
552
  /** Opens a fresh {@link HttpRouteBuilder}. The `path` documents intent; hono owns the actual routing at mount. */
538
553
  type HttpRouteFactory = (path: string) => HttpRouteBuilder<EmptyArgs, EmptyArgs, EmptyArgs>;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Validator, Infer, ValidatorMap, InferValidatorMap, v } from '@lunora/values';
2
2
  export { type ColumnValidator, type Id, type Infer, ValidationError, type Validator, type ValidatorKind, v } from '@lunora/values';
3
3
  import { ArgsValidator, InferArgs, RegisteredAction, ActionCtx, MutationCtx, RegisteredMutation, QueryCtx, RegisteredQuery, RegisteredStream, FunctionKind, Secrets, LifecycleEvent, RegisteredLifecycleHook, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, DurableObjectJurisdiction, RelationDefinition, GlobalBackend, OnDeleteAction, ExternalSourceDefinition, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, AggregateIndexDefinition, RankIndexDefinition } from "./types.js";
4
- export { type AnyApi, type AuthState, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LunoraLogger, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.js";
4
+ export { type AnyApi, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LunoraLogger, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.js";
5
5
  import { LunoraError as LunoraError$1, LunoraErrorCode } from '@lunora/errors';
6
6
  export type { LunoraErrorCode } from '@lunora/errors';
7
7
  import { Context, Hono } from 'hono';
@@ -435,7 +435,7 @@ type HttpMethod = "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PU
435
435
  * `storage` surface — reach the data layer through `runQuery` / `runMutation` /
436
436
  * `runAction`, which forward to the owning shard.
437
437
  */
438
- type HttpActionCtx = Pick<ActionCtx, "auth" | "fetch" | "runAction" | "runMutation" | "runQuery">;
438
+ type HttpActionCtx = Pick<ActionCtx, "auth" | "cache" | "fetch" | "runAction" | "runMutation" | "runQuery">;
439
439
  /** A raw handler wrapped by {@link httpAction}. Receives the raw request, returns the raw response. */
440
440
  type HttpActionHandler = (context: HttpActionCtx, request: Request) => Promise<Response> | Response;
441
441
  /**
@@ -519,6 +519,16 @@ interface HttpStreamHandlerOptions<SearchParams extends ArgsValidator, Params ex
519
519
  */
520
520
  interface HttpRouteBuilder<SearchParams extends ArgsValidator, Body extends ArgsValidator, Params extends ArgsValidator, Output = undefined> {
521
521
  body: <B extends ArgsValidator>(validators: B) => HttpRouteBuilder<SearchParams, B & Body, Params, Output>;
522
+ /**
523
+ * Attach a `Cache-Control` header to the response. Only meaningful when
524
+ * Workers Cache is enabled in `wrangler.jsonc` (`"cache": { "enabled": true }`).
525
+ */
526
+ cacheControl: (value: string) => HttpRouteBuilder<SearchParams, Body, Params, Output>;
527
+ /**
528
+ * Attach a `Cache-Tag` header to the response for tag-based purging via
529
+ * `ctx.cache.purge({ tags: [...] })`.
530
+ */
531
+ cacheTag: (value: string) => HttpRouteBuilder<SearchParams, Body, Params, Output>;
522
532
  handler: [Output] extends [undefined] ? <R>(handler: (options: HttpRouteHandlerOptions<SearchParams, Body, Params>) => Promise<R> | R) => LunoraRouteHandler : (handler: (options: HttpRouteHandlerOptions<SearchParams, Body, Params>) => Output | Promise<Output>) => LunoraRouteHandler;
523
533
  output: <V extends Validator>(validator: V) => HttpRouteBuilder<SearchParams, Body, Params, Infer<V>>;
524
534
  params: <P extends ArgsValidator>(validators: P) => HttpRouteBuilder<SearchParams, Body, P & Params, Output>;
@@ -533,6 +543,11 @@ interface HttpRouteBuilder<SearchParams extends ArgsValidator, Body extends Args
533
543
  * handler's yielded type.
534
544
  */
535
545
  stream: <R>(handler: (options: HttpStreamHandlerOptions<SearchParams, Params>) => AsyncGenerator<R, void, void> | AsyncIterable<R>) => LunoraRouteHandler;
546
+ /**
547
+ * Attach a `Vary` header to the response so Cloudflare stores separate
548
+ * cached variants per distinct value of the listed request headers.
549
+ */
550
+ vary: (value: string) => HttpRouteBuilder<SearchParams, Body, Params, Output>;
536
551
  }
537
552
  /** Opens a fresh {@link HttpRouteBuilder}. The `path` documents intent; hono owns the actual routing at mount. */
538
553
  type HttpRouteFactory = (path: string) => HttpRouteBuilder<EmptyArgs, EmptyArgs, EmptyArgs>;
package/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ export { createSecrets } from './packem_shared/createSecrets-DwaR2rNG.mjs';
4
4
  export { LunoraEnvError, defineEnv, redactSecrets } from './packem_shared/LunoraEnvError-BGmd1Qs0.mjs';
5
5
  export { LunoraError } from './packem_shared/LunoraError-WbxmrpxR.mjs';
6
6
  export { bindOrm, bindTableFacade } from './packem_shared/bindOrm-CNXKgfUa.mjs';
7
- export { httpAction, httpRoute, httpRouter, isSafeHeaderValue, serveStorageObject } from './packem_shared/httpAction-B_16WzMO.mjs';
7
+ export { httpAction, httpRoute, httpRouter, isSafeHeaderValue, serveStorageObject } from './packem_shared/httpAction-DCXoYPIk.mjs';
8
8
  export { defineIdentity } from './packem_shared/defineIdentity-DiX4zM9x.mjs';
9
9
  export { onConnect, onDisconnect } from './packem_shared/onConnect-CIPXKPyw.mjs';
10
10
  export { defineMigration } from './packem_shared/defineMigration-Hx01yIht.mjs';
@@ -110,7 +110,11 @@ const errorResponse = (error) => {
110
110
  return Response.json({ code: "BAD_REQUEST", error: error.message }, { status: 400 });
111
111
  }
112
112
  if (error instanceof LunoraError) {
113
- return Response.json({ code: error.code, error: error.message }, { status: error.status });
113
+ const { body, redacted, status } = toErrorBody(error, { fallbackCode: "INTERNAL_SERVER_ERROR", redactedMessage: "Internal error" });
114
+ if (redacted) {
115
+ console.error("[lunora] http action error (redacted on the wire):", error);
116
+ }
117
+ return Response.json({ code: body.code, error: body.message }, { status });
114
118
  }
115
119
  throw error;
116
120
  };
@@ -122,7 +126,21 @@ const buildRouteHandler = (state, userHandler) => async (c) => {
122
126
  const body = Object.keys(state.body).length > 0 ? await parseBody(state.body, c) : {};
123
127
  const result = await userHandler({ body, ctx: context, params, searchParams });
124
128
  const payload = state.output ? applyOutput(state.output, result) : result;
125
- return payload === void 0 ? new Response(null, { status: 204 }) : Response.json(payload);
129
+ const headers = {};
130
+ if (state.cacheControl) {
131
+ headers["cache-control"] = state.cacheControl;
132
+ }
133
+ if (state.cacheTag) {
134
+ headers["cache-tag"] = state.cacheTag;
135
+ }
136
+ if (state.vary) {
137
+ headers.vary = state.vary;
138
+ }
139
+ const hasCacheHeaders = Object.keys(headers).length > 0;
140
+ if (payload === void 0) {
141
+ return new Response(null, { headers: hasCacheHeaders ? headers : void 0, status: 204 });
142
+ }
143
+ return Response.json(payload, { headers: hasCacheHeaders ? headers : void 0 });
126
144
  } catch (error) {
127
145
  return errorResponse(error);
128
146
  }
@@ -198,25 +216,31 @@ const buildStreamHandler = (state, userHandler) => (
198
216
  }
199
217
  }
200
218
  });
201
- return new Response(stream, {
202
- headers: {
203
- "cache-control": "no-cache, no-transform",
204
- "content-type": "text/event-stream; charset=utf-8",
205
- // Hint to proxies (including Cloudflare's own buffering layer)
206
- // that this response must not be coalesced.
207
- "x-accel-buffering": "no"
208
- }
209
- });
219
+ const headers = {
220
+ // SSE responses must stay uncacheable so proxies don't buffer or
221
+ // coalesce live frames. `cacheControl()` is intentionally ignored
222
+ // for stream() routes; `cacheTag`/`vary` are also omitted because
223
+ // they only make sense alongside a cacheable response.
224
+ "cache-control": "no-cache, no-transform",
225
+ "content-type": "text/event-stream; charset=utf-8",
226
+ // Hint to proxies (including Cloudflare's own buffering layer)
227
+ // that this response must not be coalesced.
228
+ "x-accel-buffering": "no"
229
+ };
230
+ return new Response(stream, { headers });
210
231
  }
211
232
  );
212
233
  const makeRouteBuilder = (state) => {
213
234
  return {
214
235
  body: (validators) => makeRouteBuilder({ ...state, body: { ...state.body, ...validators } }),
236
+ cacheControl: (value) => makeRouteBuilder({ ...state, cacheControl: value }),
237
+ cacheTag: (value) => makeRouteBuilder({ ...state, cacheTag: value }),
215
238
  handler: (userHandler) => buildRouteHandler(state, userHandler),
216
239
  output: (validator) => makeRouteBuilder({ ...state, output: validator }),
217
240
  params: (validators) => makeRouteBuilder({ ...state, params: { ...state.params, ...validators } }),
218
241
  searchParams: (validators) => makeRouteBuilder({ ...state, searchParams: { ...state.searchParams, ...validators } }),
219
- stream: (userHandler) => buildStreamHandler(state, userHandler)
242
+ stream: (userHandler) => buildStreamHandler(state, userHandler),
243
+ vary: (value) => makeRouteBuilder({ ...state, vary: value })
220
244
  };
221
245
  };
222
246
  const makeRouteFactory = (method) => (path) => makeRouteBuilder({ body: {}, method, params: {}, path, searchParams: {} });
package/dist/types.d.mts CHANGED
@@ -690,6 +690,21 @@ interface Workflows {
690
690
  get: <Params = Record<string, unknown>>(name: string) => WorkflowHandle<Params>;
691
691
  }
692
692
  /**
693
+ * Programmatic cache purge surface exposed on {@link ActionCtx}. Actions run
694
+ * in the Worker (not the DO), so they can reach the Worker's `ctx.cache.purge`.
695
+ * Queries and mutations do not expose this — they run inside the Durable Object.
696
+ */
697
+ interface CachePurge {
698
+ /**
699
+ * Purge cached responses matching the given tags, or everything when
700
+ * `purgeEverything` is true. Only available in action handlers.
701
+ */
702
+ purge: (options: {
703
+ purgeEverything?: boolean;
704
+ tags?: string[];
705
+ }) => Promise<unknown>;
706
+ }
707
+ /**
693
708
  * Structural projection of workers-types' `SecretsStoreSecret` binding — the
694
709
  * per-secret `secrets_store_secrets[]` binding whose `.get()` resolves the
695
710
  * secret value (or throws if it does not exist). Mirrored structurally so the
@@ -1136,6 +1151,13 @@ interface MutationCtx {
1136
1151
  }
1137
1152
  interface ActionCtx {
1138
1153
  readonly auth: AuthState;
1154
+ /**
1155
+ * Programmatic Workers Cache purge; see {@link CachePurge}.
1156
+ * **Action-only** — actions run in the Worker, which has a `cache` binding.
1157
+ * Queries and mutations run inside the Durable Object and do not expose this.
1158
+ * Optional at runtime because Workers Cache is only present when enabled.
1159
+ */
1160
+ readonly cache?: CachePurge;
1139
1161
  readonly db: DatabaseWriter;
1140
1162
  /**
1141
1163
  * The validated, typed environment. Populated only when the project declares
@@ -1178,4 +1200,4 @@ interface ActionCtx {
1178
1200
  */
1179
1201
  type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
1180
1202
  declare const anyApi: AnyApi;
1181
- export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LunoraLogger, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type Secrets, type SecretsStoreSecretLike, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi };
1203
+ export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LunoraLogger, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type Secrets, type SecretsStoreSecretLike, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi };
package/dist/types.d.ts CHANGED
@@ -690,6 +690,21 @@ interface Workflows {
690
690
  get: <Params = Record<string, unknown>>(name: string) => WorkflowHandle<Params>;
691
691
  }
692
692
  /**
693
+ * Programmatic cache purge surface exposed on {@link ActionCtx}. Actions run
694
+ * in the Worker (not the DO), so they can reach the Worker's `ctx.cache.purge`.
695
+ * Queries and mutations do not expose this — they run inside the Durable Object.
696
+ */
697
+ interface CachePurge {
698
+ /**
699
+ * Purge cached responses matching the given tags, or everything when
700
+ * `purgeEverything` is true. Only available in action handlers.
701
+ */
702
+ purge: (options: {
703
+ purgeEverything?: boolean;
704
+ tags?: string[];
705
+ }) => Promise<unknown>;
706
+ }
707
+ /**
693
708
  * Structural projection of workers-types' `SecretsStoreSecret` binding — the
694
709
  * per-secret `secrets_store_secrets[]` binding whose `.get()` resolves the
695
710
  * secret value (or throws if it does not exist). Mirrored structurally so the
@@ -1136,6 +1151,13 @@ interface MutationCtx {
1136
1151
  }
1137
1152
  interface ActionCtx {
1138
1153
  readonly auth: AuthState;
1154
+ /**
1155
+ * Programmatic Workers Cache purge; see {@link CachePurge}.
1156
+ * **Action-only** — actions run in the Worker, which has a `cache` binding.
1157
+ * Queries and mutations run inside the Durable Object and do not expose this.
1158
+ * Optional at runtime because Workers Cache is only present when enabled.
1159
+ */
1160
+ readonly cache?: CachePurge;
1139
1161
  readonly db: DatabaseWriter;
1140
1162
  /**
1141
1163
  * The validated, typed environment. Populated only when the project declares
@@ -1178,4 +1200,4 @@ interface ActionCtx {
1178
1200
  */
1179
1201
  type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
1180
1202
  declare const anyApi: AnyApi;
1181
- export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LunoraLogger, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type Secrets, type SecretsStoreSecretLike, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi };
1203
+ export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LunoraLogger, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type Secrets, type SecretsStoreSecretLike, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/server",
3
- "version": "1.0.0-alpha.16",
3
+ "version": "1.0.0-alpha.18",
4
4
  "description": "Server primitives for Lunora: defineSchema, defineTable, query, mutation, and action",
5
5
  "keywords": [
6
6
  "backend",
@@ -62,9 +62,9 @@
62
62
  "access": "public"
63
63
  },
64
64
  "dependencies": {
65
- "@lunora/errors": "1.0.0-alpha.1",
66
- "@lunora/scheduler": "1.0.0-alpha.5",
67
- "@lunora/values": "1.0.0-alpha.4",
65
+ "@lunora/errors": "1.0.0-alpha.2",
66
+ "@lunora/scheduler": "1.0.0-alpha.6",
67
+ "@lunora/values": "1.0.0-alpha.5",
68
68
  "drizzle-orm": "^0.45.2",
69
69
  "hono": "^4.12.27"
70
70
  },