@lunora/server 1.0.0-alpha.28 → 1.0.0-alpha.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Validator, Infer, ValidatorMap, InferValidatorMap, 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, X402ProcedureConfig, 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 CachePurge, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LogFields, type LunoraLogMethod, 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 LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, 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';
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, X402ProcedureConfig, 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 CachePurge, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LogFields, type LunoraLogMethod, 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 LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, 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';
package/dist/types.d.mts CHANGED
@@ -1164,7 +1164,7 @@ interface VectorSearch extends VectorSearchReader {
1164
1164
  }
1165
1165
  /**
1166
1166
  * Structured, filterable key/value fields attached to a log line — the second
1167
- * argument of a `ctx.log.<level>(message, fields)` call, or the fields bound by
1167
+ * argument of a `ctx.log.&lt;level>(message, fields)` call, or the fields bound by
1168
1168
  * `ctx.log.with(fields)`. They travel to an `ObservabilitySink`'s `onLog` and,
1169
1169
  * for a network sink, become OTLP log-record attributes a log pipeline (or the
1170
1170
  * Cloud log viewer) can filter and index on. Primitive values pass through;
@@ -1174,10 +1174,8 @@ type LogFields = Record<string, unknown>;
1174
1174
  /**
1175
1175
  * One `ctx.log` severity method. Two call forms:
1176
1176
  *
1177
- * - **Structured** — `ctx.log.info("order placed", { orderId, total })`: a
1178
- * message string plus a `fields` object. The fields are indexed as attributes.
1179
- * - **Console-style** — `ctx.log.info("state", value, other)`: any number of
1180
- * values, joined into the display message exactly like `console.log`.
1177
+ * - **Structured** — `ctx.log.info("order placed", { orderId, total })`: a message string plus a `fields` object. The fields are indexed as attributes.
1178
+ * - **Console-style** `ctx.log.info("state", value, other)`: any number of values, joined into the display message exactly like `console.log`.
1181
1179
  *
1182
1180
  * The structured form is matched when the second argument is a plain object;
1183
1181
  * otherwise the call is treated as console-style, so existing `console`-shaped
@@ -1225,6 +1223,91 @@ interface LunoraLogger {
1225
1223
  */
1226
1224
  readonly with: (fields: LogFields) => LunoraLogger;
1227
1225
  }
1226
+ /**
1227
+ * Span factory on every function `ctx`. Wraps a sub-operation so it becomes its
1228
+ * own **span** nested under the dispatch's RPC span, giving a trace real shape:
1229
+ * without it a slow request is one opaque bar, with it you see which part was
1230
+ * slow.
1231
+ *
1232
+ * ```ts
1233
+ * const charge = await ctx.trace("stripe.charge", () => stripe.charges.create(…), { orderId });
1234
+ * ```
1235
+ *
1236
+ * **Nesting is explicit.** The body receives a tracer bound to its own span;
1237
+ * calling *that* is what makes a child:
1238
+ *
1239
+ * ```ts
1240
+ * await ctx.trace("fulfil", async (trace) => {
1241
+ * // Children of "fulfil" — including under Promise.all, where an ambient
1242
+ * // "currently open span" would mis-record these as nested inside each other.
1243
+ * await Promise.all([trace("reserve.stock", …), trace("email.receipt", …)]);
1244
+ * });
1245
+ * ```
1246
+ *
1247
+ * Calling `ctx.trace` again inside a body (rather than the passed tracer) is not
1248
+ * an error — that span is simply parented to the dispatch instead of to the
1249
+ * enclosing span, which is flatter but never wrong.
1250
+ *
1251
+ * Spans share the dispatch's trace id with its `ctx.log` lines and any container
1252
+ * the handler calls (the same `traceparent` is propagated), so one trace spans
1253
+ * worker, shard, and container.
1254
+ *
1255
+ * The span is recorded when the body settles, and the body's value is returned
1256
+ * unchanged. A throw is recorded as an error span and then **re-thrown** — this
1257
+ * is instrumentation, never flow control. Recording is best-effort: a failing
1258
+ * sink can't turn a working handler into a broken one.
1259
+ * @param name Span name, e.g. `"stripe.charge"`. Prefer a low-cardinality name
1260
+ * and put the varying part in `attributes` — a name built from an id makes every
1261
+ * span its own group in a collector.
1262
+ * @param fn The body to time, receiving a tracer bound to this span for any
1263
+ * nested spans. May be sync or async; the result is awaited.
1264
+ * @param attributes Structured attributes to stamp on the span, normalized like
1265
+ * a log line's `fields`.
1266
+ */
1267
+ type LunoraTracer = <T>(name: string, function_: (trace: LunoraTracer) => Promise<T> | T, attributes?: LogFields) => Promise<T>;
1268
+ /**
1269
+ * Application metrics on every function `ctx` — the third signal alongside
1270
+ * `ctx.log` and `ctx.trace`. Each call records one measurement that flows to an
1271
+ * `ObservabilitySink`'s `onMetric`, and from `otlpSink` to a collector's
1272
+ * `/v1/metrics`.
1273
+ *
1274
+ * ```ts
1275
+ * ctx.metrics.count("orders.placed", 1, { plan: user.plan });
1276
+ * ctx.metrics.record("checkout.latency_ms", Date.now() - started);
1277
+ * ctx.metrics.gauge("cart.items", cart.items.length);
1278
+ * ```
1279
+ *
1280
+ * Pick the instrument by the question you want to answer: `count` for "how many"
1281
+ * (summed over time), `gauge` for "how many right now" (replaces the last
1282
+ * reading), `record` for "what's the distribution" (percentiles, not just a
1283
+ * mean).
1284
+ *
1285
+ * `attributes` are the metric's dimensions. Keep them **low-cardinality** — an
1286
+ * attribute valued by user id or order id creates a distinct time series per id,
1287
+ * which is how a metrics backend gets expensive. Put identifiers on a log line or
1288
+ * a span instead.
1289
+ *
1290
+ * No pre-aggregation happens: one call is one exported measurement, with counter
1291
+ * deltas for the collector to sum. In a hot loop, sum locally and record once
1292
+ * rather than calling per iteration.
1293
+ */
1294
+ interface LunoraMetrics {
1295
+ /**
1296
+ * Add to a monotonic counter (default `1`) — requests served, retries,
1297
+ * bytes sent. The collector sums successive deltas.
1298
+ */
1299
+ readonly count: (name: string, value?: number, attributes?: LogFields) => void;
1300
+ /**
1301
+ * Report a point-in-time reading that replaces the previous one — queue
1302
+ * depth, cache size, connections open.
1303
+ */
1304
+ readonly gauge: (name: string, value: number, attributes?: LogFields) => void;
1305
+ /**
1306
+ * Observe one sample of a distribution — latency, payload size. Use this,
1307
+ * not a counter, when percentiles matter.
1308
+ */
1309
+ readonly record: (name: string, value: number, attributes?: LogFields) => void;
1310
+ }
1228
1311
  interface QueryCtx {
1229
1312
  readonly auth: AuthState;
1230
1313
  readonly db: DatabaseReader;
@@ -1245,6 +1328,8 @@ interface QueryCtx {
1245
1328
  readonly ip?: string;
1246
1329
  /** Structured, function-attributed logger; see {@link LunoraLogger}. */
1247
1330
  readonly log: LunoraLogger;
1331
+ /** Application counters, gauges, and histograms; see {@link LunoraMetrics}. */
1332
+ readonly metrics: LunoraMetrics;
1248
1333
  /**
1249
1334
  * Wall-clock time (epoch ms) the function began, captured once so the whole
1250
1335
  * handler sees a single stable value. Query/mutation handlers must be
@@ -1265,6 +1350,8 @@ interface QueryCtx {
1265
1350
  /** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
1266
1351
  readonly secrets: Secrets;
1267
1352
  readonly storage: ReadOnlyStorage;
1353
+ /** Wrap a sub-operation in its own nested span; see {@link LunoraTracer}. */
1354
+ readonly trace: LunoraTracer;
1268
1355
  readonly vectors: VectorSearchReader;
1269
1356
  }
1270
1357
  interface MutationCtx {
@@ -1287,6 +1374,8 @@ interface MutationCtx {
1287
1374
  readonly ip?: string;
1288
1375
  /** Structured, function-attributed logger; see {@link LunoraLogger}. */
1289
1376
  readonly log: LunoraLogger;
1377
+ /** Application counters, gauges, and histograms; see {@link LunoraMetrics}. */
1378
+ readonly metrics: LunoraMetrics;
1290
1379
  /**
1291
1380
  * Wall-clock time (epoch ms) the function began, captured once so the whole
1292
1381
  * handler sees a single stable value. Mutation handlers must be deterministic
@@ -1315,6 +1404,8 @@ interface MutationCtx {
1315
1404
  /** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
1316
1405
  readonly secrets: Secrets;
1317
1406
  readonly storage: ReadOnlyStorage;
1407
+ /** Wrap a sub-operation in its own nested span; see {@link LunoraTracer}. */
1408
+ readonly trace: LunoraTracer;
1318
1409
  readonly vectors: VectorSearch;
1319
1410
  /** Start / resume / inspect durable workflows; see {@link Workflows}. */
1320
1411
  readonly workflows: Workflows;
@@ -1347,6 +1438,8 @@ interface ActionCtx {
1347
1438
  readonly ip?: string;
1348
1439
  /** Structured, function-attributed logger; see {@link LunoraLogger}. */
1349
1440
  readonly log: LunoraLogger;
1441
+ /** Application counters, gauges, and histograms; see {@link LunoraMetrics}. */
1442
+ readonly metrics: LunoraMetrics;
1350
1443
  /**
1351
1444
  * Wall-clock time (epoch ms) the action began, captured once for convenience
1352
1445
  * and parity with query/mutation `ctx.now`. Actions run exactly once, so they
@@ -1360,6 +1453,8 @@ interface ActionCtx {
1360
1453
  /** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
1361
1454
  readonly secrets: Secrets;
1362
1455
  readonly storage: Storage;
1456
+ /** Wrap a sub-operation in its own nested span; see {@link LunoraTracer}. */
1457
+ readonly trace: LunoraTracer;
1363
1458
  readonly vectors: VectorSearch;
1364
1459
  /** Start / resume / inspect durable workflows; see {@link Workflows}. */
1365
1460
  readonly workflows: Workflows;
@@ -1370,4 +1465,4 @@ interface ActionCtx {
1370
1465
  */
1371
1466
  type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
1372
1467
  declare const anyApi: AnyApi;
1373
- export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceCursor, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LogFields, type LunoraLogMethod, 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, type X402ProcedureConfig, anyApi };
1468
+ export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceCursor, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, 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, type X402ProcedureConfig, anyApi };
package/dist/types.d.ts CHANGED
@@ -1164,7 +1164,7 @@ interface VectorSearch extends VectorSearchReader {
1164
1164
  }
1165
1165
  /**
1166
1166
  * Structured, filterable key/value fields attached to a log line — the second
1167
- * argument of a `ctx.log.<level>(message, fields)` call, or the fields bound by
1167
+ * argument of a `ctx.log.&lt;level>(message, fields)` call, or the fields bound by
1168
1168
  * `ctx.log.with(fields)`. They travel to an `ObservabilitySink`'s `onLog` and,
1169
1169
  * for a network sink, become OTLP log-record attributes a log pipeline (or the
1170
1170
  * Cloud log viewer) can filter and index on. Primitive values pass through;
@@ -1174,10 +1174,8 @@ type LogFields = Record<string, unknown>;
1174
1174
  /**
1175
1175
  * One `ctx.log` severity method. Two call forms:
1176
1176
  *
1177
- * - **Structured** — `ctx.log.info("order placed", { orderId, total })`: a
1178
- * message string plus a `fields` object. The fields are indexed as attributes.
1179
- * - **Console-style** — `ctx.log.info("state", value, other)`: any number of
1180
- * values, joined into the display message exactly like `console.log`.
1177
+ * - **Structured** — `ctx.log.info("order placed", { orderId, total })`: a message string plus a `fields` object. The fields are indexed as attributes.
1178
+ * - **Console-style** `ctx.log.info("state", value, other)`: any number of values, joined into the display message exactly like `console.log`.
1181
1179
  *
1182
1180
  * The structured form is matched when the second argument is a plain object;
1183
1181
  * otherwise the call is treated as console-style, so existing `console`-shaped
@@ -1225,6 +1223,91 @@ interface LunoraLogger {
1225
1223
  */
1226
1224
  readonly with: (fields: LogFields) => LunoraLogger;
1227
1225
  }
1226
+ /**
1227
+ * Span factory on every function `ctx`. Wraps a sub-operation so it becomes its
1228
+ * own **span** nested under the dispatch's RPC span, giving a trace real shape:
1229
+ * without it a slow request is one opaque bar, with it you see which part was
1230
+ * slow.
1231
+ *
1232
+ * ```ts
1233
+ * const charge = await ctx.trace("stripe.charge", () => stripe.charges.create(…), { orderId });
1234
+ * ```
1235
+ *
1236
+ * **Nesting is explicit.** The body receives a tracer bound to its own span;
1237
+ * calling *that* is what makes a child:
1238
+ *
1239
+ * ```ts
1240
+ * await ctx.trace("fulfil", async (trace) => {
1241
+ * // Children of "fulfil" — including under Promise.all, where an ambient
1242
+ * // "currently open span" would mis-record these as nested inside each other.
1243
+ * await Promise.all([trace("reserve.stock", …), trace("email.receipt", …)]);
1244
+ * });
1245
+ * ```
1246
+ *
1247
+ * Calling `ctx.trace` again inside a body (rather than the passed tracer) is not
1248
+ * an error — that span is simply parented to the dispatch instead of to the
1249
+ * enclosing span, which is flatter but never wrong.
1250
+ *
1251
+ * Spans share the dispatch's trace id with its `ctx.log` lines and any container
1252
+ * the handler calls (the same `traceparent` is propagated), so one trace spans
1253
+ * worker, shard, and container.
1254
+ *
1255
+ * The span is recorded when the body settles, and the body's value is returned
1256
+ * unchanged. A throw is recorded as an error span and then **re-thrown** — this
1257
+ * is instrumentation, never flow control. Recording is best-effort: a failing
1258
+ * sink can't turn a working handler into a broken one.
1259
+ * @param name Span name, e.g. `"stripe.charge"`. Prefer a low-cardinality name
1260
+ * and put the varying part in `attributes` — a name built from an id makes every
1261
+ * span its own group in a collector.
1262
+ * @param fn The body to time, receiving a tracer bound to this span for any
1263
+ * nested spans. May be sync or async; the result is awaited.
1264
+ * @param attributes Structured attributes to stamp on the span, normalized like
1265
+ * a log line's `fields`.
1266
+ */
1267
+ type LunoraTracer = <T>(name: string, function_: (trace: LunoraTracer) => Promise<T> | T, attributes?: LogFields) => Promise<T>;
1268
+ /**
1269
+ * Application metrics on every function `ctx` — the third signal alongside
1270
+ * `ctx.log` and `ctx.trace`. Each call records one measurement that flows to an
1271
+ * `ObservabilitySink`'s `onMetric`, and from `otlpSink` to a collector's
1272
+ * `/v1/metrics`.
1273
+ *
1274
+ * ```ts
1275
+ * ctx.metrics.count("orders.placed", 1, { plan: user.plan });
1276
+ * ctx.metrics.record("checkout.latency_ms", Date.now() - started);
1277
+ * ctx.metrics.gauge("cart.items", cart.items.length);
1278
+ * ```
1279
+ *
1280
+ * Pick the instrument by the question you want to answer: `count` for "how many"
1281
+ * (summed over time), `gauge` for "how many right now" (replaces the last
1282
+ * reading), `record` for "what's the distribution" (percentiles, not just a
1283
+ * mean).
1284
+ *
1285
+ * `attributes` are the metric's dimensions. Keep them **low-cardinality** — an
1286
+ * attribute valued by user id or order id creates a distinct time series per id,
1287
+ * which is how a metrics backend gets expensive. Put identifiers on a log line or
1288
+ * a span instead.
1289
+ *
1290
+ * No pre-aggregation happens: one call is one exported measurement, with counter
1291
+ * deltas for the collector to sum. In a hot loop, sum locally and record once
1292
+ * rather than calling per iteration.
1293
+ */
1294
+ interface LunoraMetrics {
1295
+ /**
1296
+ * Add to a monotonic counter (default `1`) — requests served, retries,
1297
+ * bytes sent. The collector sums successive deltas.
1298
+ */
1299
+ readonly count: (name: string, value?: number, attributes?: LogFields) => void;
1300
+ /**
1301
+ * Report a point-in-time reading that replaces the previous one — queue
1302
+ * depth, cache size, connections open.
1303
+ */
1304
+ readonly gauge: (name: string, value: number, attributes?: LogFields) => void;
1305
+ /**
1306
+ * Observe one sample of a distribution — latency, payload size. Use this,
1307
+ * not a counter, when percentiles matter.
1308
+ */
1309
+ readonly record: (name: string, value: number, attributes?: LogFields) => void;
1310
+ }
1228
1311
  interface QueryCtx {
1229
1312
  readonly auth: AuthState;
1230
1313
  readonly db: DatabaseReader;
@@ -1245,6 +1328,8 @@ interface QueryCtx {
1245
1328
  readonly ip?: string;
1246
1329
  /** Structured, function-attributed logger; see {@link LunoraLogger}. */
1247
1330
  readonly log: LunoraLogger;
1331
+ /** Application counters, gauges, and histograms; see {@link LunoraMetrics}. */
1332
+ readonly metrics: LunoraMetrics;
1248
1333
  /**
1249
1334
  * Wall-clock time (epoch ms) the function began, captured once so the whole
1250
1335
  * handler sees a single stable value. Query/mutation handlers must be
@@ -1265,6 +1350,8 @@ interface QueryCtx {
1265
1350
  /** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
1266
1351
  readonly secrets: Secrets;
1267
1352
  readonly storage: ReadOnlyStorage;
1353
+ /** Wrap a sub-operation in its own nested span; see {@link LunoraTracer}. */
1354
+ readonly trace: LunoraTracer;
1268
1355
  readonly vectors: VectorSearchReader;
1269
1356
  }
1270
1357
  interface MutationCtx {
@@ -1287,6 +1374,8 @@ interface MutationCtx {
1287
1374
  readonly ip?: string;
1288
1375
  /** Structured, function-attributed logger; see {@link LunoraLogger}. */
1289
1376
  readonly log: LunoraLogger;
1377
+ /** Application counters, gauges, and histograms; see {@link LunoraMetrics}. */
1378
+ readonly metrics: LunoraMetrics;
1290
1379
  /**
1291
1380
  * Wall-clock time (epoch ms) the function began, captured once so the whole
1292
1381
  * handler sees a single stable value. Mutation handlers must be deterministic
@@ -1315,6 +1404,8 @@ interface MutationCtx {
1315
1404
  /** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
1316
1405
  readonly secrets: Secrets;
1317
1406
  readonly storage: ReadOnlyStorage;
1407
+ /** Wrap a sub-operation in its own nested span; see {@link LunoraTracer}. */
1408
+ readonly trace: LunoraTracer;
1318
1409
  readonly vectors: VectorSearch;
1319
1410
  /** Start / resume / inspect durable workflows; see {@link Workflows}. */
1320
1411
  readonly workflows: Workflows;
@@ -1347,6 +1438,8 @@ interface ActionCtx {
1347
1438
  readonly ip?: string;
1348
1439
  /** Structured, function-attributed logger; see {@link LunoraLogger}. */
1349
1440
  readonly log: LunoraLogger;
1441
+ /** Application counters, gauges, and histograms; see {@link LunoraMetrics}. */
1442
+ readonly metrics: LunoraMetrics;
1350
1443
  /**
1351
1444
  * Wall-clock time (epoch ms) the action began, captured once for convenience
1352
1445
  * and parity with query/mutation `ctx.now`. Actions run exactly once, so they
@@ -1360,6 +1453,8 @@ interface ActionCtx {
1360
1453
  /** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
1361
1454
  readonly secrets: Secrets;
1362
1455
  readonly storage: Storage;
1456
+ /** Wrap a sub-operation in its own nested span; see {@link LunoraTracer}. */
1457
+ readonly trace: LunoraTracer;
1363
1458
  readonly vectors: VectorSearch;
1364
1459
  /** Start / resume / inspect durable workflows; see {@link Workflows}. */
1365
1460
  readonly workflows: Workflows;
@@ -1370,4 +1465,4 @@ interface ActionCtx {
1370
1465
  */
1371
1466
  type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
1372
1467
  declare const anyApi: AnyApi;
1373
- export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceCursor, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LogFields, type LunoraLogMethod, 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, type X402ProcedureConfig, anyApi };
1468
+ export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type CachePurge, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceCursor, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LogFields, type LunoraLogMethod, type LunoraLogger, type LunoraMetrics, type LunoraTracer, 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, type X402ProcedureConfig, anyApi };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/server",
3
- "version": "1.0.0-alpha.28",
3
+ "version": "1.0.0-alpha.29",
4
4
  "description": "Server primitives for Lunora: defineSchema, defineTable, query, mutation, and action",
5
5
  "keywords": [
6
6
  "backend",