effortless-aws 0.34.0 → 0.36.0

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.
@@ -765,9 +765,18 @@ var createHandlerRuntime = (handler, handlerType, logLevel = "info", extraSetupA
765
765
  resolvedCfSigningConfig = { privateKey, keyPairId: cfKeyPairId, domain: cfDomain };
766
766
  return resolvedCfSigningConfig;
767
767
  };
768
- const getAuthRuntime = async (setupCtx) => {
768
+ const getAuthRuntime = async () => {
769
769
  if (resolvedAuthRuntime !== null) return resolvedAuthRuntime;
770
- const authOpts = setupCtx && typeof setupCtx === "object" && "auth" in setupCtx ? setupCtx.auth : void 0;
770
+ if (!handler.authFn) {
771
+ resolvedAuthRuntime = void 0;
772
+ return void 0;
773
+ }
774
+ const params = await getParams();
775
+ const deps = getDeps();
776
+ const authArgs = {};
777
+ if (params) authArgs.config = params;
778
+ if (deps) authArgs.deps = deps;
779
+ const authOpts = await handler.authFn(authArgs);
771
780
  if (!authOpts?.secret) {
772
781
  resolvedAuthRuntime = void 0;
773
782
  return void 0;
@@ -795,7 +804,7 @@ var createHandlerRuntime = (handler, handlerType, logLevel = "info", extraSetupA
795
804
  if (handler.setup) {
796
805
  const params = await getParams();
797
806
  const deps = getDeps();
798
- const args = { enableAuth: (opts) => opts };
807
+ const args = {};
799
808
  if (params) args.config = params;
800
809
  if (deps) args.deps = deps;
801
810
  if (handler.static) args.files = staticFiles;
@@ -813,7 +822,7 @@ var createHandlerRuntime = (handler, handlerType, logLevel = "info", extraSetupA
813
822
  const params = await getParams();
814
823
  if (params) args.config = params;
815
824
  if (handler.static) args.files = staticFiles;
816
- const authRuntime = await getAuthRuntime(args.ctx);
825
+ const authRuntime = await getAuthRuntime();
817
826
  if (authRuntime) {
818
827
  let finalAuthHeader = authHeader;
819
828
  if (finalAuthHeader === void 0 && headers && resolvedAuthHeaderName) {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { StandardSchemaV1, StandardJSONSchemaV1 } from '@standard-schema/spec';
2
+
1
3
  /**
2
4
  * Configuration for an Effortless project.
3
5
  *
@@ -421,7 +423,7 @@ type BucketObjectRemovedFn<C = undefined> = (args: {
421
423
  * Internal handler object created by defineBucket
422
424
  * @internal
423
425
  */
424
- type BucketHandler$1<C = any, Entities extends Record<string, any> = {}> = {
426
+ type BucketHandler$1<C = any, _Entities extends Record<string, any> = {}> = {
425
427
  readonly __brand: "effortless-bucket";
426
428
  readonly __spec: BucketConfig;
427
429
  readonly onError?: (...args: any[]) => any;
@@ -728,7 +730,7 @@ type WorkerMessageFn<T, C = undefined> = (msg: T, ctx: SpreadCtx$4<C>) => Promis
728
730
  * Handler object created by defineWorker.
729
731
  * @internal
730
732
  */
731
- type WorkerHandler$1<T = any, C = any> = {
733
+ type WorkerHandler$1<_T = any, C = any> = {
732
734
  readonly __brand: "effortless-worker";
733
735
  readonly __spec: WorkerConfig;
734
736
  readonly onError?: (...args: any[]) => any;
@@ -1206,22 +1208,10 @@ type AppHandler = {
1206
1208
  */
1207
1209
  declare const defineApp: () => (options: AppConfig) => AppHandler;
1208
1210
 
1209
- /** Any branded handler that deploys to API Gateway (HttpHandler, ApiHandler, etc.) */
1211
+ /** Any branded handler that deploys to API Gateway or S3 */
1210
1212
  type AnyRoutableHandler = {
1211
1213
  readonly __brand: string;
1212
1214
  };
1213
- /** Route configuration for serving bucket content through CloudFront */
1214
- type BucketRouteConfig = {
1215
- bucket: {
1216
- readonly __brand: "effortless-bucket";
1217
- };
1218
- /** Access control: "private" requires CloudFront signed cookies, "public" serves openly. Default: "public" */
1219
- access?: "private" | "public";
1220
- };
1221
- /** A route value: either an API handler or a bucket route config */
1222
- type RouteValue = AnyRoutableHandler | BucketRouteConfig;
1223
- /** Type guard for bucket route entries */
1224
- declare const isBucketRoute: (v: unknown) => v is BucketRouteConfig;
1225
1215
  /** Simplified request object passed to middleware */
1226
1216
  type MiddlewareRequest = {
1227
1217
  uri: string;
@@ -1253,33 +1243,32 @@ type StaticSiteSeo = {
1253
1243
  googleIndexing?: string;
1254
1244
  };
1255
1245
  /**
1256
- * Configuration for a static site handler (S3 + CloudFront)
1246
+ * Configuration for a static site (S3 + CloudFront)
1257
1247
  */
1258
1248
  type StaticSiteConfig = {
1259
- /** Handler name. Defaults to export name if not specified */
1260
- name?: string;
1261
1249
  /** Directory containing the static site files, relative to project root */
1262
1250
  dir: string;
1263
1251
  /** Default file for directory requests (default: "index.html") */
1264
1252
  index?: string;
1265
- /** SPA mode: serve index.html for all paths that don't match a file (default: false) */
1266
- spa?: boolean;
1267
1253
  /** Shell command to run before deploy to generate site content (e.g., "npx astro build") */
1268
1254
  build?: string;
1255
+ /** Path to a custom error page relative to `dir`.
1256
+ * - If set to the same value as `index` (e.g. "index.html"), enables SPA mode:
1257
+ * all paths that don't match a file are served with `index.html` (HTTP 200), letting the client-side router handle them.
1258
+ * - If set to a different file (e.g. "404.html"), that file is served with HTTP 404 for missing paths.
1259
+ * - If omitted, a default 404 page is auto-generated. */
1260
+ errorPage?: string;
1269
1261
  /** Custom domain name. Accepts a string (same domain for all stages) or a Record mapping stage names to domains (e.g., `{ prod: "example.com", dev: "dev.example.com" }`). Requires an ACM certificate in us-east-1. If the cert also covers www, a 301 redirect from www to non-www is set up automatically. */
1270
1262
  domain?: string | Record<string, string>;
1271
- /** CloudFront route overrides: path patterns forwarded to API Gateway or S3 bucket origins.
1272
- * Keys are CloudFront path patterns (e.g., "/api/*"), values are HTTP handlers or bucket route configs.
1273
- * Example: `routes: { "/api/*": api, "/files/*": { bucket: storage, access: "private" } }` */
1274
- routes?: Record<string, RouteValue>;
1275
- /** Custom 404 error page path relative to `dir` (e.g. "404.html").
1276
- * For non-SPA sites only. If not set, a default page is generated automatically. */
1277
- errorPage?: string;
1278
- /** Lambda@Edge middleware that runs before serving pages. Use for auth checks, redirects, etc. */
1279
- middleware?: MiddlewareHandler;
1280
1263
  /** SEO: auto-generate sitemap.xml and robots.txt at deploy time, optionally submit URLs to Google Indexing API */
1281
1264
  seo?: StaticSiteSeo;
1282
1265
  };
1266
+ /** Route entry stored on the static site handler */
1267
+ type StaticSiteRouteEntry = {
1268
+ pattern: string;
1269
+ origin: AnyRoutableHandler;
1270
+ access?: "private" | "public";
1271
+ };
1283
1272
  /**
1284
1273
  * Internal handler object created by defineStaticSite
1285
1274
  * @internal
@@ -1287,16 +1276,24 @@ type StaticSiteConfig = {
1287
1276
  type StaticSiteHandler = {
1288
1277
  readonly __brand: "effortless-static-site";
1289
1278
  readonly __spec: StaticSiteConfig;
1279
+ readonly routes: StaticSiteRouteEntry[];
1280
+ readonly middleware?: MiddlewareHandler;
1290
1281
  };
1291
1282
  /**
1292
- * Deploy a static site via S3 + CloudFront CDN.
1283
+ * Deploy a static site via S3 + CloudFront CDN, with optional API and bucket route overrides.
1293
1284
  *
1294
1285
  * @see {@link https://effortless-aws.website/use-cases/web-app | Web app guide}
1295
1286
  *
1296
- * @param options - Static site configuration: directory, optional SPA mode, build command
1297
- * @returns Handler object used by the deployment system
1287
+ * @param options - Static site configuration: directory, optional SPA mode, build command, domain
1288
+ * @returns Builder with `.route()`, `.middleware()`, and `.build()` methods
1298
1289
  */
1299
- declare const defineStaticSite: () => (options: StaticSiteConfig) => StaticSiteHandler;
1290
+ declare function defineStaticSite(options: StaticSiteConfig): {
1291
+ route(pattern: string, origin: AnyRoutableHandler, opts?: {
1292
+ access?: "private" | "public";
1293
+ }): /*elided*/ any;
1294
+ middleware(fn: MiddlewareHandler): /*elided*/ any;
1295
+ build(): StaticSiteHandler;
1296
+ };
1300
1297
 
1301
1298
  /** Options for CloudFront signed cookie policy */
1302
1299
  type CdnPolicyOptions = {
@@ -1355,16 +1352,6 @@ type AuthOptions<A = unknown> = {
1355
1352
  cacheTtl?: Duration;
1356
1353
  };
1357
1354
  };
1358
- /** Branded auth config — created by `enableAuth<A>()` helper, carries session type A */
1359
- type ApiAuthConfig<A = unknown> = AuthOptions<A> & {
1360
- readonly __sessionType: A;
1361
- };
1362
- /** Type of the `enableAuth` helper injected into setup args */
1363
- type EnableAuth = <A = unknown>(options: AuthOptions<A>) => ApiAuthConfig<A>;
1364
- /** Extract session type A from ctx.auth if present */
1365
- type ExtractAuth<C> = C extends {
1366
- auth: ApiAuthConfig<infer A>;
1367
- } ? A : undefined;
1368
1355
  /** Property names reserved by the framework — cannot be used in setup return */
1369
1356
  type ReservedKeys = 'req' | 'input' | 'stream' | 'ok' | 'fail';
1370
1357
  /** Success response helper: `ok({ data })` → `{ status: 200, body: { data } }` */
@@ -1392,35 +1379,36 @@ type RouteEntry = {
1392
1379
  method: HttpMethod;
1393
1380
  path: string;
1394
1381
  onRequest: (...args: any[]) => any;
1382
+ schema?: unknown;
1395
1383
  public?: boolean;
1396
1384
  cache?: ResolvedCache;
1397
1385
  };
1398
- /** Spread ctx into route args: Omit auth config, add AuthHelpers if present */
1399
- type SpreadCtx$2<C> = ([C] extends [undefined] ? {} : Omit<C & {}, 'auth'>) & ([ExtractAuth<C>] extends [undefined] ? {} : {
1400
- auth: AuthHelpers<ExtractAuth<C>>;
1386
+ /** Spread ctx into route args, add AuthHelpers if A is set */
1387
+ type SpreadCtx$2<C, A = undefined> = ([C] extends [undefined] ? {} : C & {}) & ([A] extends [undefined] ? {} : {
1388
+ auth: AuthHelpers<A>;
1401
1389
  });
1390
+ /** Infer validated output type from a Standard Schema, or fall back to unknown */
1391
+ type InferInput<S> = S extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<S> : unknown;
1402
1392
  /** Callback args available inside each route — ctx is spread into args */
1403
- type RouteArgs<C, ST> = SpreadCtx$2<C> & {
1393
+ type RouteArgs<C, ST, A = undefined, S = undefined> = SpreadCtx$2<C, A> & {
1404
1394
  req: HttpRequest;
1405
- input: unknown;
1395
+ input: InferInput<S>;
1406
1396
  ok: OkHelper;
1407
1397
  fail: FailHelper;
1408
1398
  } & ([ST] extends [true] ? {
1409
1399
  stream: ResponseStream;
1410
1400
  } : {});
1411
1401
  /** Route handler function */
1412
- type RouteHandler<C, ST> = (args: RouteArgs<C, ST>) => Promise<HttpResponse | void> | HttpResponse | void;
1413
- /** Route options for all methods */
1414
- type RouteOptions = {
1402
+ type RouteHandler<C, ST, A = undefined, S = undefined> = (args: RouteArgs<C, ST, A, S>) => Promise<HttpResponse | void> | HttpResponse | void;
1403
+ /** Route definition — pass `input` for typed schema validation */
1404
+ type RouteDef<S extends StandardSchemaV1 | undefined = undefined> = {
1405
+ path: `/${string}`;
1406
+ input?: S;
1415
1407
  public?: boolean;
1416
- };
1417
- /** Route options for GET — supports caching */
1418
- type GetRouteOptions = RouteOptions & {
1419
1408
  cache?: CacheOptions;
1420
1409
  };
1421
- /** Setup factory — receives deps/config/files/enableAuth based on what was declared */
1410
+ /** Setup factory — receives deps/config/files based on what was declared */
1422
1411
  type SetupArgs$2<D, P, HasFiles extends boolean> = {
1423
- enableAuth: EnableAuth;
1424
1412
  ok: OkHelper;
1425
1413
  fail: FailHelper;
1426
1414
  } & ([D] extends [undefined] ? {} : {
@@ -1430,6 +1418,12 @@ type SetupArgs$2<D, P, HasFiles extends boolean> = {
1430
1418
  }) & (HasFiles extends true ? {
1431
1419
  files: StaticFiles;
1432
1420
  } : {});
1421
+ /** Auth factory args — receives config/deps based on what was declared */
1422
+ type AuthArgs$1<D, P> = ([D] extends [undefined] ? {} : {
1423
+ deps: ResolveDeps<D>;
1424
+ }) & ([P] extends [undefined] ? {} : {
1425
+ config: ResolveConfig<P & {}>;
1426
+ });
1433
1427
  /** Validate that setup return type does not use reserved property names */
1434
1428
  type ValidateSetupReturn<C> = C & {
1435
1429
  [K in ReservedKeys]?: never;
@@ -1466,12 +1460,12 @@ type ApiOptions = {
1466
1460
  * Finalized API handler with route-adding methods.
1467
1461
  * Has `__brand` so CLI discovers it. Each `.get()/.post()` adds a route and returns self.
1468
1462
  */
1469
- interface ApiRoutes<C = undefined, ST extends boolean = false> extends ApiHandler<C> {
1470
- get(path: `/${string}`, handler: RouteHandler<C, ST>, options?: GetRouteOptions): ApiRoutes<C, ST>;
1471
- post(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
1472
- put(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
1473
- patch(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
1474
- delete(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
1463
+ interface ApiRoutes<C = undefined, ST extends boolean = false, A = undefined> extends ApiHandler<C> {
1464
+ get<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1465
+ post<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1466
+ put<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1467
+ patch<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1468
+ delete<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1475
1469
  }
1476
1470
  /**
1477
1471
  * Builder interface for defining API handlers.
@@ -1479,38 +1473,35 @@ interface ApiRoutes<C = undefined, ST extends boolean = false> extends ApiHandle
1479
1473
  * Each method sets exactly one generic, so inference happens one step at a time.
1480
1474
  * This prevents cascading type errors when one property has a mistake.
1481
1475
  */
1482
- interface ApiBuilder<D = undefined, P = undefined, C = undefined, ST extends boolean = false, HasFiles extends boolean = false> {
1476
+ interface ApiBuilder<D = undefined, P = undefined, C = undefined, ST extends boolean = false, HasFiles extends boolean = false, A = undefined> {
1483
1477
  /** Declare handler dependencies (tables, queues, buckets, mailers) */
1484
- deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): ApiBuilder<D2, P, C, ST, HasFiles>;
1478
+ deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): ApiBuilder<D2, P, C, ST, HasFiles, A>;
1485
1479
  /** Declare SSM secrets */
1486
- config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): ApiBuilder<D, P2, C, ST, HasFiles>;
1480
+ config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): ApiBuilder<D, P2, C, ST, HasFiles, A>;
1487
1481
  /** Include static files by glob pattern */
1488
- include(glob: string): ApiBuilder<D, P, C, ST, true>;
1482
+ include(glob: string): ApiBuilder<D, P, C, ST, true, A>;
1483
+ /** Configure session-based authentication. Receives resolved config/deps. */
1484
+ auth<A2>(fn: (args: AuthArgs$1<D, P>) => AuthOptions<A2> | Promise<AuthOptions<A2>>): ApiBuilder<D, P, C, ST, HasFiles, A2>;
1489
1485
  /** Configure Lambda settings only (no init function) */
1490
- setup(lambda: LambdaOptions): ApiBuilder<D, P, C, ST, HasFiles>;
1486
+ setup(lambda: LambdaOptions): ApiBuilder<D, P, C, ST, HasFiles, A>;
1491
1487
  /** Initialize shared state on cold start. Receives deps/config/files based on what was declared. */
1492
- setup<C2>(fn: (args: SetupArgs$2<D, P, HasFiles>) => ValidateSetupReturn<C2> | Promise<ValidateSetupReturn<C2>>): ApiBuilder<D, P, C2, ST, HasFiles>;
1488
+ setup<C2>(fn: (args: SetupArgs$2<D, P, HasFiles>) => ValidateSetupReturn<C2> | Promise<ValidateSetupReturn<C2>>): ApiBuilder<D, P, C2, ST, HasFiles, A>;
1493
1489
  /** Initialize shared state on cold start with Lambda config. */
1494
- setup<C2>(fn: (args: SetupArgs$2<D, P, HasFiles>) => ValidateSetupReturn<C2> | Promise<ValidateSetupReturn<C2>>, lambda: LambdaOptions): ApiBuilder<D, P, C2, ST, HasFiles>;
1490
+ setup<C2>(fn: (args: SetupArgs$2<D, P, HasFiles>) => ValidateSetupReturn<C2> | Promise<ValidateSetupReturn<C2>>, lambda: LambdaOptions): ApiBuilder<D, P, C2, ST, HasFiles, A>;
1495
1491
  /** Handle errors thrown by routes */
1496
1492
  onError(fn: (args: {
1497
1493
  error: unknown;
1498
1494
  req: HttpRequest;
1499
1495
  ok: OkHelper;
1500
1496
  fail: FailHelper;
1501
- } & SpreadCtx$2<C>) => HttpResponse | Promise<HttpResponse>): ApiBuilder<D, P, C, ST, HasFiles>;
1497
+ } & SpreadCtx$2<C, A>) => HttpResponse | Promise<HttpResponse>): ApiBuilder<D, P, C, ST, HasFiles, A>;
1502
1498
  /** Cleanup callback — runs after each invocation, before Lambda freezes */
1503
- onCleanup(fn: (args: SpreadCtx$2<C>) => void | Promise<void>): ApiBuilder<D, P, C, ST, HasFiles>;
1504
- /** Add a GET route (terminal returns finalized handler with route methods) */
1505
- get(path: `/${string}`, handler: RouteHandler<C, ST>, options?: GetRouteOptions): ApiRoutes<C, ST>;
1506
- /** Add a POST route (terminal) */
1507
- post(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
1508
- /** Add a PUT route (terminal) */
1509
- put(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
1510
- /** Add a PATCH route (terminal) */
1511
- patch(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
1512
- /** Add a DELETE route (terminal) */
1513
- delete(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
1499
+ onCleanup(fn: (args: SpreadCtx$2<C, A>) => void | Promise<void>): ApiBuilder<D, P, C, ST, HasFiles, A>;
1500
+ get<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1501
+ post<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1502
+ put<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1503
+ patch<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1504
+ delete<S extends StandardSchemaV1 | undefined = undefined>(def: RouteDef<S>, handler: RouteHandler<C, ST, A, S>): ApiRoutes<C, ST, A>;
1514
1505
  }
1515
1506
  /**
1516
1507
  * Define an API with typed routes using a builder pattern.
@@ -1519,16 +1510,12 @@ interface ApiBuilder<D = undefined, P = undefined, C = undefined, ST extends boo
1519
1510
  *
1520
1511
  * @example
1521
1512
  * ```typescript
1522
- * export const api = defineApi({ basePath: "/api", timeout: "30s" })
1513
+ * export const api = defineApi({ basePath: "/api" })
1523
1514
  * .deps(() => ({ users }))
1524
- * .config(({ defineSecret }) => ({ dbUrl: defineSecret() }))
1525
- * .setup(async ({ deps, config, enableAuth }) => ({
1526
- * users: deps.users,
1527
- * auth: enableAuth<Session>({ secret: config.dbUrl }),
1528
- * }))
1529
- * .onError(({ error, fail }) => fail(String(error), 500))
1530
- * .get("/me", async ({ users, auth, ok }) => ok(auth.session))
1531
- * .post("/login", async ({ auth, ok }) => ok(await auth.createSession()), { public: true })
1515
+ * .config(({ defineSecret }) => ({ authSecret: defineSecret() }))
1516
+ * .auth<Session>(({ config }) => ({ secret: config.authSecret, expiresIn: "1h" }))
1517
+ * .get({ path: "/me" }, async ({ users, auth, ok }) => ok(auth.session))
1518
+ * .post({ path: "/login", public: true }, async ({ auth, ok }) => ok(await auth.createSession()))
1532
1519
  * ```
1533
1520
  */
1534
1521
  declare function defineApi<const O extends ApiOptions>(options: O): ApiBuilder<undefined, undefined, undefined, O["stream"] extends true ? true : false, false>;
@@ -1699,29 +1686,42 @@ type McpResourceContent = {
1699
1686
  mimeType?: string;
1700
1687
  blob: string;
1701
1688
  };
1702
- /** A static resource definition */
1703
- type McpResourceDef$1<C = undefined> = {
1689
+ /** Legacy resource content result type used by runtime internals */
1690
+ type McpResourceResult = McpResourceContent | McpResourceContent[] | Promise<McpResourceContent | McpResourceContent[]>;
1691
+ /** Infer resource params type from schema, or fall back to Record<string, string> */
1692
+ type InferResourceParams<S> = S extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<S> : Record<string, string>;
1693
+ /** Resource definition — pass `params` for typed schema validation on URI template params */
1694
+ type McpResourceDefInput<S extends StandardSchemaV1 | undefined = undefined> = {
1695
+ /** Resource URI or URI template (e.g. "resource://contacts/{id}") */
1696
+ uri: string;
1704
1697
  /** Human-readable name */
1705
1698
  name: string;
1699
+ /** Schema for URI template params — provides type inference + validation */
1700
+ params?: S;
1706
1701
  /** Optional description */
1707
1702
  description?: string;
1708
1703
  /** Optional MIME type */
1709
1704
  mimeType?: string;
1710
- /** Handler called on resources/read */
1711
- handler: (ctx: SpreadCtx<C>) => McpResourceContent | McpResourceContent[] | Promise<McpResourceContent | McpResourceContent[]>;
1712
1705
  };
1713
- /** A parameterized resource template (URI template RFC 6570) */
1706
+ /** What resource handlers can return plain data is auto-wrapped by the runtime */
1707
+ type McpResourceReturn = unknown | Promise<unknown>;
1708
+ /** Resource handler — receives params (typed or Record<string, string>) and ctx */
1709
+ type McpResourceHandler<C, S = undefined> = (params: InferResourceParams<S>, ctx: SpreadCtx<C>) => McpResourceReturn;
1710
+ /** @internal */
1711
+ type McpResourceDef$1<C = undefined> = {
1712
+ name: string;
1713
+ description?: string;
1714
+ mimeType?: string;
1715
+ handler: (ctx: SpreadCtx<C>) => McpResourceResult;
1716
+ };
1717
+ /** @internal */
1714
1718
  type McpResourceTemplateDef$1<C = undefined> = {
1715
- /** Human-readable name */
1716
1719
  name: string;
1717
- /** Optional description */
1718
1720
  description?: string;
1719
- /** Optional MIME type */
1720
1721
  mimeType?: string;
1721
- /** Handler called on resources/read receives matched URI params */
1722
- handler: (params: Record<string, string>, ctx: SpreadCtx<C>) => McpResourceContent | McpResourceContent[] | Promise<McpResourceContent | McpResourceContent[]>;
1722
+ handler: (params: Record<string, string>, ctx: SpreadCtx<C>) => McpResourceResult;
1723
1723
  };
1724
- /** Map of uri → resource definition, or uriTemplate → template definition */
1724
+ /** @internal */
1725
1725
  type McpResourceMap$1<C = undefined> = {
1726
1726
  [uriOrTemplate: string]: McpResourceDef$1<C> | McpResourceTemplateDef$1<C>;
1727
1727
  };
@@ -1765,34 +1765,54 @@ type McpPromptResult = {
1765
1765
  description?: string;
1766
1766
  messages: McpPromptMessage[];
1767
1767
  };
1768
- /** A single prompt definition */
1768
+ /** @internal Legacy prompt definition used by runtime */
1769
1769
  type McpPromptDef$1<C = undefined> = {
1770
- /** Human-readable description */
1771
1770
  description?: string;
1772
- /** Arguments this prompt accepts */
1773
1771
  arguments?: McpPromptArgument[];
1774
- /** Handler called on prompts/get — receives argument values */
1775
1772
  handler: (args: Record<string, string>, ctx: SpreadCtx<C>) => McpPromptResult | Promise<McpPromptResult>;
1776
1773
  };
1777
- /** A single MCP tool definition */
1778
- type McpToolDef$1<C = undefined> = {
1774
+ /** Infer prompt args type from schema, or fall back to Record<string, string> */
1775
+ type InferPromptArgs<S> = S extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<S> : Record<string, string>;
1776
+ /** Prompt definition — pass a Standard Schema for `args` for typed validation, or McpPromptArgument[] for untyped */
1777
+ type McpPromptDefInput<S extends StandardSchemaV1 | McpPromptArgument[] | undefined = undefined> = {
1778
+ /** Prompt name */
1779
+ name: string;
1780
+ /** Human-readable description */
1781
+ description?: string;
1782
+ /** Args: Standard Schema for typed validation, or McpPromptArgument[] for untyped */
1783
+ args?: S;
1784
+ };
1785
+ /** Handler return: string auto-wraps as user message, or return full McpPromptResult */
1786
+ type McpPromptReturn = string | McpPromptResult | Promise<string | McpPromptResult>;
1787
+ /** Prompt handler — receives args (typed or Record<string, string>) and ctx */
1788
+ type McpPromptHandler<C, S = undefined> = (args: InferPromptArgs<S>, ctx: SpreadCtx<C>) => McpPromptReturn;
1789
+ /** Infer tool input type from schema, or fall back to any */
1790
+ type InferToolInput<S> = S extends StandardJSONSchemaV1 ? StandardJSONSchemaV1.InferOutput<S> : any;
1791
+ /** Tool definition — pass a StandardJSONSchemaV1 for `input` for typed validation, or McpInputSchema for raw JSON Schema */
1792
+ type McpToolDefInput<S extends StandardJSONSchemaV1 | McpInputSchema = McpInputSchema> = {
1793
+ /** Tool name */
1794
+ name: string;
1779
1795
  /** Human-readable description of the tool */
1780
1796
  description: string;
1781
- /** JSON Schema describing the tool's input parameters */
1782
- input: McpInputSchema;
1783
- /** Handler function called when the tool is invoked */
1784
- handler: (input: any, ctx: SpreadCtx<C>) => McpToolResult | Promise<McpToolResult>;
1785
- };
1786
- /** Setup factory — receives deps/config/files/enableAuth based on what was declared */
1787
- type SetupArgs<D, P, HasFiles extends boolean> = {
1788
- enableAuth: EnableAuth;
1789
- } & ([D] extends [undefined] ? {} : {
1797
+ /** Schema for tool input: StandardJSONSchemaV1 (e.g. z.object({...})) or raw McpInputSchema */
1798
+ input: S;
1799
+ };
1800
+ /** Tool handler — receives input (typed or any) and ctx */
1801
+ type McpToolHandler<C, S = McpInputSchema> = (input: InferToolInput<S>, ctx: SpreadCtx<C>) => unknown | Promise<unknown>;
1802
+ /** Setup factory — receives deps/config/files based on what was declared */
1803
+ type SetupArgs<D, P, HasFiles extends boolean> = ([D] extends [undefined] ? {} : {
1790
1804
  deps: ResolveDeps<D>;
1791
1805
  }) & ([P] extends [undefined] ? {} : {
1792
1806
  config: ResolveConfig<P & {}>;
1793
1807
  }) & (HasFiles extends true ? {
1794
1808
  files: StaticFiles;
1795
1809
  } : {});
1810
+ /** Auth factory args — receives config/deps based on what was declared */
1811
+ type AuthArgs<D, P> = ([D] extends [undefined] ? {} : {
1812
+ deps: ResolveDeps<D>;
1813
+ }) & ([P] extends [undefined] ? {} : {
1814
+ config: ResolveConfig<P & {}>;
1815
+ });
1796
1816
  /** Spread ctx into callback args (empty when no setup) */
1797
1817
  type SpreadCtx<C> = [C] extends [undefined] ? {} : C & {};
1798
1818
  /**
@@ -1812,6 +1832,18 @@ type McpHandler$1<C = any> = {
1812
1832
  readonly prompts?: (...args: any[]) => any;
1813
1833
  readonly tools?: (...args: any[]) => any;
1814
1834
  };
1835
+ /**
1836
+ * Finalized MCP handler with chainable registration methods.
1837
+ * Has `__brand` so CLI discovers it. Each `.tool()/.resource()/.prompt()` adds an entry and returns self.
1838
+ */
1839
+ interface McpEntries<C = undefined> extends McpHandler$1<C> {
1840
+ /** Register a tool */
1841
+ tool<S extends StandardJSONSchemaV1 | McpInputSchema = McpInputSchema>(def: McpToolDefInput<S>, handler: McpToolHandler<C, S>): McpEntries<C>;
1842
+ /** Register a resource */
1843
+ resource<S extends StandardSchemaV1 | undefined = undefined>(def: McpResourceDefInput<S>, handler: McpResourceHandler<C, S>): McpEntries<C>;
1844
+ /** Register a prompt */
1845
+ prompt<S extends StandardSchemaV1 | McpPromptArgument[] | undefined = undefined>(def: McpPromptDefInput<S>, handler: McpPromptHandler<C, S>): McpEntries<C>;
1846
+ }
1815
1847
  /** Options passed to `defineMcp()` */
1816
1848
  type McpOptions = {
1817
1849
  /** MCP server name (used in server info) */
@@ -1828,6 +1860,8 @@ interface McpBuilder<D = undefined, P = undefined, C = undefined, HasFiles exten
1828
1860
  config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): McpBuilder<D, P2, C, HasFiles>;
1829
1861
  /** Include static files in the bundle. Chainable — call multiple times. */
1830
1862
  include(glob: string): McpBuilder<D, P, C, true>;
1863
+ /** Configure session-based authentication. Receives resolved config/deps. All requests require a valid session. */
1864
+ auth<A2>(fn: (args: AuthArgs<D, P>) => AuthOptions<A2> | Promise<AuthOptions<A2>>): McpBuilder<D, P, C, HasFiles>;
1831
1865
  /** Configure Lambda settings only (memory, timeout, permissions, logLevel) */
1832
1866
  setup(lambda: LambdaOptions): McpBuilder<D, P, C, HasFiles>;
1833
1867
  /** Initialize shared state on cold start. Receives deps, config, files. */
@@ -1841,12 +1875,14 @@ interface McpBuilder<D = undefined, P = undefined, C = undefined, HasFiles exten
1841
1875
  } & SpreadCtx<C>) => void | Promise<void>): McpBuilder<D, P, C, HasFiles>;
1842
1876
  /** Cleanup callback — runs on shutdown */
1843
1877
  onCleanup(fn: (args: SpreadCtx<C>) => void | Promise<void>): McpBuilder<D, P, C, HasFiles>;
1844
- /** Define MCP resources (chainable) */
1845
- resources(fn: (ctx: SpreadCtx<C>) => McpResourceMap$1<C>): McpBuilder<D, P, C, HasFiles>;
1846
- /** Define MCP prompts (chainable) */
1847
- prompts(fn: (ctx: SpreadCtx<C>) => Record<string, McpPromptDef$1<C>>): McpBuilder<D, P, C, HasFiles>;
1848
- /** Define MCP tools (terminal) */
1849
- tools(fn: (ctx: SpreadCtx<C>) => Record<string, McpToolDef$1<C>>): McpHandler$1<C>;
1878
+ /** Register a tool */
1879
+ tool<S extends StandardJSONSchemaV1 | McpInputSchema = McpInputSchema>(def: McpToolDefInput<S>, handler: McpToolHandler<C, S>): McpEntries<C>;
1880
+ /** Register a resource */
1881
+ resource<S extends StandardSchemaV1 | undefined = undefined>(def: McpResourceDefInput<S>, handler: McpResourceHandler<C, S>): McpEntries<C>;
1882
+ /** Register a prompt */
1883
+ prompt<S extends StandardSchemaV1 | McpPromptArgument[] | undefined = undefined>(def: McpPromptDefInput<S>, handler: McpPromptHandler<C, S>): McpEntries<C>;
1884
+ /** Finalize the handler without adding more entries */
1885
+ build(): McpHandler$1<C>;
1850
1886
  }
1851
1887
  /**
1852
1888
  * Define an MCP (Model Context Protocol) server endpoint.
@@ -1859,7 +1895,7 @@ interface McpBuilder<D = undefined, P = undefined, C = undefined, HasFiles exten
1859
1895
  */
1860
1896
  declare function defineMcp(options: McpOptions): McpBuilder;
1861
1897
 
1862
- type McpToolDef = McpToolDef$1;
1898
+ type McpToolDef = McpToolDefInput;
1863
1899
  type McpResourceDef = McpResourceDef$1;
1864
1900
  type McpResourceTemplateDef = McpResourceTemplateDef$1;
1865
1901
  type McpResourceMap = McpResourceMap$1;
@@ -1872,4 +1908,4 @@ type CronHandler = CronHandler$1<any>;
1872
1908
  type WorkerHandler<T = any> = WorkerHandler$1<T, any>;
1873
1909
  type McpHandler = McpHandler$1<any>;
1874
1910
 
1875
- export { type ApiAuthConfig, type ApiConfig, type ApiHandler, type ApiRoutes, type AppConfig, type AppHandler, type AuthHelpers, type BucketClient, type BucketClientWithEntities, type BucketConfig, type BucketEntityConfig, type BucketEvent, type BucketHandler, type BucketRouteConfig, type CacheOptions, type CdnPolicyOptions, type ConfigHelpers, type ContentType, type CronConfig, type CronHandler, type DefineSecretFn, type Duration, type EffortlessConfig, type EmailClient, type FifoQueueConfig, type FifoQueueHandler, type FifoQueueMessage, type HttpMethod$1 as HttpMethod, type HttpRequest, type HttpResponse, type LogLevel, type MailerConfig, type MailerHandler, type McpConfig, type McpHandler, type McpInputSchema, type McpPromptArgument, type McpPromptContent, type McpPromptDef, type McpPromptMessage, type McpPromptResult, type McpResourceContent, type McpResourceDef, type McpResourceMap, type McpResourceTemplateDef, type McpToolContent, type McpToolDef, type McpToolResult, type MiddlewareDeny, type MiddlewareHandler, type MiddlewareRedirect, type MiddlewareRequest, type MiddlewareResult, type ParamRef, type Permission, type PutInput, type PutOptions, type QueryByTagParams, type QueryParams, type QueueClient, type ResponseStream, type SecretRef, type SendEmailOptions, type SendMessageInput, type SkCondition, type StaticFiles, type StaticSiteConfig, type StaticSiteHandler, type StaticSiteSeo, type StoreEntityClient, type StreamView, type TableClient, type TableConfig, type TableHandler, type TableItem, type TableKey, type TableRecord, type Timezone, type UpdateActions, type WorkerClient, type WorkerConfig, type WorkerHandler, type WorkerSendOptions, defineApi, defineApp, defineBucket, defineConfig, defineCron, defineFifoQueue, defineMailer, defineMcp, defineSecret, defineStaticSite, defineTable, defineWorker, generateBase64, generateHex, generateUuid, isBucketRoute, param, secret, toSeconds };
1911
+ export { type ApiConfig, type ApiHandler, type ApiRoutes, type AppConfig, type AppHandler, type AuthHelpers, type AuthOptions, type BucketClient, type BucketClientWithEntities, type BucketConfig, type BucketEntityConfig, type BucketEvent, type BucketHandler, type CacheOptions, type CdnPolicyOptions, type ConfigHelpers, type ContentType, type CronConfig, type CronHandler, type DefineSecretFn, type Duration, type EffortlessConfig, type EmailClient, type FifoQueueConfig, type FifoQueueHandler, type FifoQueueMessage, type HttpMethod$1 as HttpMethod, type HttpRequest, type HttpResponse, type LogLevel, type MailerConfig, type MailerHandler, type McpConfig, type McpEntries, type McpHandler, type McpInputSchema, type McpPromptArgument, type McpPromptContent, type McpPromptDef, type McpPromptMessage, type McpPromptResult, type McpResourceContent, type McpResourceDef, type McpResourceMap, type McpResourceTemplateDef, type McpToolContent, type McpToolDef, type McpToolResult, type MiddlewareDeny, type MiddlewareHandler, type MiddlewareRedirect, type MiddlewareRequest, type MiddlewareResult, type ParamRef, type Permission, type PutInput, type PutOptions, type QueryByTagParams, type QueryParams, type QueueClient, type ResponseStream, type SecretRef, type SendEmailOptions, type SendMessageInput, type SkCondition, type StaticFiles, type StaticSiteConfig, type StaticSiteHandler, type StaticSiteSeo, type StoreEntityClient, type StreamView, type TableClient, type TableConfig, type TableHandler, type TableItem, type TableKey, type TableRecord, type Timezone, type UpdateActions, type WorkerClient, type WorkerConfig, type WorkerHandler, type WorkerSendOptions, defineApi, defineApp, defineBucket, defineConfig, defineCron, defineFifoQueue, defineMailer, defineMcp, defineSecret, defineStaticSite, defineTable, defineWorker, generateBase64, generateHex, generateUuid, param, secret, toSeconds };