@supacloud/elysia 0.19.0 → 0.20.1

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/README.md CHANGED
@@ -8,13 +8,19 @@ is a separately authorized business command, never an assumed rollback.
8
8
 
9
9
  ## Compatibility and Acceptance Boundary
10
10
 
11
- The dependency range is not a claim that every allowed version has been tested.
12
- The focused conformance suite was verified with Bun 1.4.2 and Elysia 1.4.30.
13
- The package declares Elysia `^1.4.30` as a peer and TypeScript `^7.0.2` as a
14
- development dependency. `compatibility.json` records the exact exercised tuple,
15
- including the compiler's separate TypeScript 6 semantic API. The contract-upgrade
16
- gate checks both that semantic API and the TypeScript 7 CLI. These tests do not
17
- establish a wider version matrix or Node.js runtime compatibility.
11
+ The Elysia peer and development dependency are pinned to `2.0.0-beta.19`.
12
+ `compatibility.json` records the acceptance target: Bun 1.4.2, Elysia
13
+ 2.0.0-beta.19, `typebox` 1.3.34, `exact-mirror` 1.2.6, TypeScript CLI 7.0.2
14
+ and the compiler's separate TypeScript 6 semantic API 6.0.2. The matrix is a
15
+ required target, not proof of an execution. See the dated, commit-specific
16
+ [framework acceptance record](../../docs/framework-acceptance.md) for actual
17
+ results. The contract-upgrade gate checks both TypeScript engines. These tests
18
+ do not establish a wider beta version matrix or Node.js runtime compatibility.
19
+
20
+ Keep the exact Elysia peer until additional versions have their own acceptance
21
+ evidence. A server using this adapter still installs Elysia; application metadata
22
+ and business modules need not import native Elysia types. See the
23
+ [dependency boundary and upgrade policy](../../docs/elysia-compatibility.md).
18
24
 
19
25
  Run `bun run test:conformance` in this package after building the local
20
26
  `@supacloud/contracts` and `@supacloud/app` dependencies and installing this
@@ -99,9 +105,11 @@ for the evidence boundaries and upgrade policy.
99
105
 
100
106
  Pass a native Elysia plugin as `http` to `createApplication`, `createTestApp`,
101
107
  or the options argument of `createModulePlugin`. `decorate` shares existing
102
- instances; `derive` runs before validation; `resolve` runs after validation.
103
- Use scoped/global hooks, or finish a context plugin with `.as("scoped")`.
104
- Local hooks retain native encapsulation and do not extend the consuming routes.
108
+ instances. In Elysia 2, `derive` runs after validation; do not assume the Elysia 1
109
+ pre-validation derive/resolve split. Use `.derive("plugin", callback)` for a
110
+ shared derived context, or finish a guarded context plugin with `.as("plugin")`.
111
+ Global hooks use `.as("global")`. Local hooks retain native encapsulation and
112
+ do not extend the consuming routes.
105
113
 
106
114
  ```ts
107
115
  import { Elysia, t } from "elysia";
@@ -109,10 +117,12 @@ import { createApplication } from "@supacloud/elysia";
109
117
 
110
118
  const http = new Elysia({ name: "application-context" })
111
119
  .decorate("clock", { now: () => Date.now() })
112
- .derive(({ clock }) => ({ startedAt: clock.now() }))
113
120
  .guard({ query: t.Object({ locale: t.Optional(t.String()) }) })
114
- .resolve(({ query }) => ({ locale: query.locale ?? "en" }))
115
- .as("scoped");
121
+ .derive(({ clock, query }) => ({
122
+ startedAt: clock.now(),
123
+ locale: query.locale ?? "en",
124
+ }))
125
+ .as("plugin");
116
126
 
117
127
  const app = createApplication({
118
128
  http,
@@ -132,13 +142,13 @@ The second `requestContext` argument contains the validated HTTP inputs and
132
142
  the inferred native plugin extensions. Existing one-argument factories remain
133
143
  valid. Its result is passed to generated request-scoped constructors and the
134
144
  controller's `context`/`requestContext` input. It is built once per request;
135
- early resolver responses and validation failures do not construct DI scopes.
145
+ early derived-context responses and validation failures do not construct DI scopes.
136
146
  Request scopes are created inside the existing governed handler and released
137
147
  after the response, including handler failures. They are not application
138
- singletons or native `resolve` hooks.
148
+ singletons or native context hooks.
139
149
 
140
- Native routes added to the returned app retain the HTTP plugin's decorator,
141
- derive and resolve types. `createModulePlugin` also preserves the concrete
150
+ Native routes added to the returned app retain the HTTP plugin's decorator
151
+ and derived context types. `createModulePlugin` also preserves the concrete
142
152
  `services` type supplied by its caller. Module service bags are attached by
143
153
  the module-local resolver, not merged into a root `decorator.services` bag;
144
154
  the service instances themselves remain shared. This prevents same-named
@@ -153,13 +163,13 @@ Compiled route schemas are runtime
153
163
  descriptors: their body/params/query/header/cookie fields in the application-wide
154
164
  context factory remain `unknown`-based instead of pretending to infer one
155
165
  route's schema for every route. Use shared guards for schema-typed native
156
- resolvers and the existing generated contracts for individual compiled routes.
166
+ context derivation and the existing generated contracts for individual compiled routes.
157
167
  Do not store per-request identity or transaction handles in decorated singletons.
158
168
 
159
169
  The `http` plugin is composed into each compiled module and subsequently into
160
170
  the root for native routes. Keep it focused on reusable context extensions;
161
171
  register unrelated endpoints on the returned app. Hook execution is tested
162
- for named/anonymous plugins and scoped/global hooks without duplicate work.
172
+ for named/anonymous plugins and plugin/global hooks without duplicate work.
163
173
  Anonymous extensions receive a stable internal plugin identity for native
164
174
  hook deduplication; the caller's plugin configuration is not mutated.
165
175
  This is native HTTP composition, not a replacement runtime DI container or
@@ -298,7 +308,7 @@ Runtime adapter that turns `@supacloud/compiler` output into a production-ready
298
308
  ## Installation
299
309
 
300
310
  ```bash
301
- bun add @supacloud/elysia elysia
311
+ bun add --exact @supacloud/elysia elysia@2.0.0-beta.19
302
312
  ```
303
313
 
304
314
  ## Usage
@@ -383,7 +393,7 @@ read-back protocol. A custom `errorMapper` can override this public envelope.
383
393
 
384
394
  Native `Response` objects are passed through by Elysia, including JSON responses.
385
395
  Use `validatedJsonResponse` to opt into validation when constructing a native
386
- JSON response. Otherwise handlers must validate their JSON payload themselves.
396
+ JSON response. Otherwise handlers must validate their JSON payloads themselves.
387
397
  The adapter does not consume or parse binary/streaming responses.
388
398
 
389
399
  Jobs are executed explicitly with `executeJob(compiledModule, services, job,
@@ -657,9 +667,8 @@ does not add Eden-style client inference to an existing Elysia instance; the
657
667
  compiler-generated client remains the source of transport types.
658
668
 
659
669
  Response maps may use concrete statuses, `1XX`-`5XX` families, and `default`.
660
- Because Elysia 1.4 only compiles numeric response keys, the adapter expands
661
- family/default entries to concrete validators before registration. Exact
662
- statuses take precedence over families, which take precedence over `default`.
670
+ The adapter expands family/default entries to concrete validators before
671
+ registration. Exact statuses take precedence over families, which take precedence over `default`.
663
672
  An actual status absent from a structured response map fails the route contract
664
673
  before Elysia can silently accept a default `200`; binary/stream routes may
665
674
  intentionally leave successful transport statuses unschematized when only their
@@ -700,12 +709,12 @@ const app = createApplication({
700
709
  });
701
710
  ```
702
711
 
703
- `identityPlugin` is an application-owned scoped/global Elysia plugin that verifies
712
+ `identityPlugin` is an application-owned plugin/global Elysia context plugin that verifies
704
713
  credentials and resolves `identity`; the adapter does not trust a raw user/tenant
705
714
  header as identity. Policy callbacks preserve its native context types.
706
715
 
707
716
  Policies become native route-local `beforeHandle` hooks. They execute sequentially
708
- after schema validation, native resolvers and the application request-context
717
+ after schema validation, native context derivation and the application request-context
709
718
  factory, but before compiled request-scope construction and command execution.
710
719
  Return `undefined` to continue or a `Response` to stop; thrown errors use the
711
720
  application error mapper. Native earlier hooks can still short-circuit the request.
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "bun": "1.4.2",
3
3
  "packages": {
4
- "elysia": "1.4.30",
4
+ "elysia": "2.0.0-beta.19",
5
5
  "typescript": "7.0.2",
6
- "@sinclair/typebox": "0.34.52",
6
+ "typebox": "1.3.34",
7
+ "exact-mirror": "1.2.6",
7
8
  "@typescript/typescript6": "6.0.2"
8
9
  }
9
10
  }
@@ -1,42 +1,42 @@
1
- export declare const WebhookInputSchema: import("@sinclair/typebox").TObject<{
2
- id: import("@sinclair/typebox").TString;
3
- enabled: import("@sinclair/typebox").TBoolean;
1
+ export declare const WebhookInputSchema: import("typebox").TObject<{
2
+ id: import("typebox").TString;
3
+ enabled: import("typebox").TBoolean;
4
4
  }>;
5
- export declare const WebhookHeadersSchema: import("@sinclair/typebox").TObject<{
6
- "idempotency-key": import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
5
+ export declare const WebhookHeadersSchema: import("typebox").TObject<{
6
+ "idempotency-key": import("typebox").TOptional<import("typebox").TString>;
7
7
  }>;
8
8
  export declare const decodeWebhookInput: (value: unknown) => {
9
9
  id: string;
10
10
  enabled: boolean;
11
11
  };
12
- export declare const WebhookReceiptSchema: import("@sinclair/typebox").TObject<{
13
- tenantId: import("@sinclair/typebox").TString;
14
- actorId: import("@sinclair/typebox").TString;
15
- command: import("@sinclair/typebox").TLiteral<"webhook.update.v1">;
16
- operationId: import("@sinclair/typebox").TString;
17
- dispatchKey: import("@sinclair/typebox").TString;
18
- status: import("@sinclair/typebox").TLiteral<"confirmed">;
19
- audit: import("@sinclair/typebox").TLiteral<"complete">;
20
- result: import("@sinclair/typebox").TObject<{
21
- id: import("@sinclair/typebox").TString;
22
- enabled: import("@sinclair/typebox").TBoolean;
12
+ export declare const WebhookReceiptSchema: import("typebox").TObject<{
13
+ tenantId: import("typebox").TString;
14
+ actorId: import("typebox").TString;
15
+ command: import("typebox").TLiteral<"webhook.update.v1">;
16
+ operationId: import("typebox").TString;
17
+ dispatchKey: import("typebox").TString;
18
+ status: import("typebox").TLiteral<"confirmed">;
19
+ audit: import("typebox").TLiteral<"complete">;
20
+ result: import("typebox").TObject<{
21
+ id: import("typebox").TString;
22
+ enabled: import("typebox").TBoolean;
23
23
  }>;
24
24
  }>;
25
- export declare const WebhookKeySchema: import("@sinclair/typebox").TObject<{
26
- key: import("@sinclair/typebox").TString;
25
+ export declare const WebhookKeySchema: import("typebox").TObject<{
26
+ key: import("typebox").TString;
27
27
  }>;
28
- export declare const WebhookLookupSchema: import("@sinclair/typebox").TObject<{
29
- receipt: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
30
- tenantId: import("@sinclair/typebox").TString;
31
- actorId: import("@sinclair/typebox").TString;
32
- command: import("@sinclair/typebox").TLiteral<"webhook.update.v1">;
33
- operationId: import("@sinclair/typebox").TString;
34
- dispatchKey: import("@sinclair/typebox").TString;
35
- status: import("@sinclair/typebox").TLiteral<"confirmed">;
36
- audit: import("@sinclair/typebox").TLiteral<"complete">;
37
- result: import("@sinclair/typebox").TObject<{
38
- id: import("@sinclair/typebox").TString;
39
- enabled: import("@sinclair/typebox").TBoolean;
28
+ export declare const WebhookLookupSchema: import("typebox").TObject<{
29
+ receipt: import("typebox").TUnion<[import("typebox").TObject<{
30
+ tenantId: import("typebox").TString;
31
+ actorId: import("typebox").TString;
32
+ command: import("typebox").TLiteral<"webhook.update.v1">;
33
+ operationId: import("typebox").TString;
34
+ dispatchKey: import("typebox").TString;
35
+ status: import("typebox").TLiteral<"confirmed">;
36
+ audit: import("typebox").TLiteral<"complete">;
37
+ result: import("typebox").TObject<{
38
+ id: import("typebox").TString;
39
+ enabled: import("typebox").TBoolean;
40
40
  }>;
41
- }>, import("@sinclair/typebox").TNull]>;
41
+ }>, import("typebox").TNull]>;
42
42
  }>;
@@ -44,32 +44,8 @@ export declare function principalKey(context: SupAuthRequestContext): unknown[];
44
44
  /** Pair the returned factory and registry; only this verifier can populate policy identity. */
45
45
  export declare function createHttpPolicySuite(options: HttpPolicySuiteOptions): {
46
46
  requestContext: (request: Request) => Promise<SupaCloudRequestContext | SupAuthRequestContext>;
47
- httpPolicies: Readonly<Record<string, (options: unknown, route: Readonly<Pick<import("./index").CompiledRoute, "method" | "path" | "command">>) => HttpPolicy<import("elysia").default<"", {
48
- decorator: {};
49
- store: {};
50
- derive: {};
51
- resolve: {};
52
- }, {
47
+ httpPolicies: Readonly<Record<string, (options: unknown, route: Readonly<Pick<import("./index").CompiledRoute, "method" | "path" | "command">>) => HttpPolicy<import("elysia").Elysia<"", "local", import("elysia").DefaultSingleton, {
53
48
  typebox: {};
54
- error: {};
55
- }, {
56
- schema: {};
57
- standaloneSchema: {};
58
- macro: {};
59
- macroFn: {};
60
- parser: {};
61
- response: {};
62
- }, {}, {
63
- derive: {};
64
- resolve: {};
65
- schema: {};
66
- standaloneSchema: {};
67
- response: {};
68
- }, {
69
- derive: {};
70
- resolve: {};
71
- schema: {};
72
- standaloneSchema: {};
73
- response: {};
74
- }>>>>;
49
+ error: [];
50
+ }, import("elysia").DefaultMetadata, {}, import("elysia").DefaultEphemeral, import("elysia").DefaultEphemeral>>>>;
75
51
  };
@@ -10,6 +10,8 @@ export interface HttpPolicyContext<Http extends AnyElysia = Elysia> {
10
10
  }
11
11
  export interface HttpPolicyResponseContext<Http extends AnyElysia = Elysia> extends HttpPolicyContext<Http> {
12
12
  response: unknown;
13
+ /** Validate and encode before replacing a handler value with a native Response. */
14
+ encodeResponse?: (value: unknown) => unknown | Promise<unknown>;
13
15
  }
14
16
  export type HttpPolicy<Http extends AnyElysia = Elysia> = ((context: HttpPolicyContext<Http>) => void | Response | Promise<void | Response>) & {
15
17
  /** Terminal policies (cache hits) must not skip later security checks. */
@@ -10,31 +10,18 @@ export interface HttpTelemetryEvent {
10
10
  }
11
11
  export type HttpTelemetryObserver = (event: Readonly<HttpTelemetryEvent>) => void | Promise<void>;
12
12
  /** Request tracing is best effort, not a durable business audit. */
13
- export declare function createHttpTelemetry(observe: HttpTelemetryObserver): Elysia<"", {
13
+ export declare function createHttpTelemetry(observe: HttpTelemetryObserver): Elysia<"", "local", {
14
14
  decorator: {};
15
15
  store: {};
16
16
  derive: {};
17
- resolve: {};
18
17
  }, {
19
18
  typebox: {};
20
- error: {};
19
+ error: [];
21
20
  }, {
22
21
  schema: {};
23
- standaloneSchema: {};
22
+ schemas: {};
24
23
  macro: {};
25
24
  macroFn: {};
26
25
  parser: {};
27
26
  response: {};
28
- }, {}, {
29
- derive: {};
30
- resolve: {};
31
- schema: {};
32
- standaloneSchema: {};
33
- response: {};
34
- }, {
35
- derive: {};
36
- resolve: {};
37
- schema: {};
38
- standaloneSchema: {};
39
- response: {};
40
- }>;
27
+ }, {}, import("elysia").DefaultEphemeral, import("elysia").DefaultEphemeral>;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Elysia, type AnyElysia, type InferContext, type StatusMap } from "elysia";
1
+ import { Elysia, type AnyElysia, type Context, type StatusMap } from "elysia";
2
2
  import type { CommandRuntimeAudit, CommandRuntimeAuthorizer, CommandRuntimeGovernance, CommandRuntimeInvocation, CommandRuntimeMiddleware } from "@supacloud/app";
3
3
  import { type CommandPreview } from "@supacloud/contracts";
4
4
  import { type HttpPolicyRegistry } from "./http-policy";
@@ -236,71 +236,11 @@ export interface ErrorContext {
236
236
  frameworkCode: string | number | undefined;
237
237
  }
238
238
  export type ErrorMapper = (error: unknown, context: ErrorContext) => Response | undefined | Promise<Response | undefined>;
239
- declare function mountHttp<const Http extends AnyElysia = Elysia>(http?: Http, name?: string, normalize?: boolean): Elysia<"", {
240
- decorator: {} & Http["~Singleton"]["decorator"];
241
- store: ({} & Http["~Singleton"]["store"] extends infer T_1 ? { [K_1 in keyof T_1]: T_1[K_1]; } : never) extends infer T ? { [K in keyof T]: T[K]; } : never;
242
- derive: {} & Http["~Singleton"]["derive"];
243
- resolve: {} & Http["~Singleton"]["resolve"];
244
- }, {
245
- typebox: {};
246
- error: {};
247
- } & Http["~Definitions"], {
248
- schema: {};
249
- standaloneSchema: {};
250
- macro: {};
251
- macroFn: {};
252
- parser: {};
253
- response: {};
254
- } & Http["~Metadata"], {} & Http["~Routes"], {
255
- derive: {};
256
- resolve: {};
257
- schema: {};
258
- standaloneSchema: {};
259
- response: {};
260
- }, {
261
- derive: {};
262
- resolve: {};
263
- schema: {};
264
- standaloneSchema: {};
265
- response: {};
266
- } & {
267
- derive: {} & ({
268
- derive: {};
269
- resolve: {};
270
- schema: {};
271
- standaloneSchema: {};
272
- response: {};
273
- } & Http["~Ephemeral"])["derive"];
274
- resolve: {} & ({
275
- derive: {};
276
- resolve: {};
277
- schema: {};
278
- standaloneSchema: {};
279
- response: {};
280
- } & Http["~Ephemeral"])["resolve"];
281
- schema: import("elysia").MergeSchema<({
282
- derive: {};
283
- resolve: {};
284
- schema: {};
285
- standaloneSchema: {};
286
- response: {};
287
- } & Http["~Ephemeral"])["schema"], {}, "">;
288
- standaloneSchema: ({
289
- derive: {};
290
- resolve: {};
291
- schema: {};
292
- standaloneSchema: {};
293
- response: {};
294
- } & Http["~Ephemeral"])["standaloneSchema"] & {};
295
- response: ({
296
- derive: {};
297
- resolve: {};
298
- schema: {};
299
- standaloneSchema: {};
300
- response: {};
301
- } & Http["~Ephemeral"])["response"] & {};
302
- }>;
303
- export type ApplicationHttpContext<Http extends AnyElysia = Elysia> = Omit<InferContext<ReturnType<typeof mountHttp<Http>>>, "body" | "params" | "query" | "headers" | "cookie"> & Pick<HttpContext, "body" | "params" | "query" | "headers" | "cookie">;
239
+ export type ApplicationHttpContext<Http extends AnyElysia = Elysia> = Omit<Context<{}, {
240
+ decorator: Http["~Singleton"]["decorator"];
241
+ store: Http["~Singleton"]["store"];
242
+ derive: Http["~Singleton"]["derive"] & Http["~Ephemeral"]["derive"];
243
+ }>, "body" | "params" | "query" | "headers" | "cookie"> & Pick<HttpContext, "body" | "params" | "query" | "headers" | "cookie">;
304
244
  export type HttpRequestContextFactory<Http extends AnyElysia = Elysia, Value = unknown> = (request: Request, context: ApplicationHttpContext<Http>) => Value | Promise<Value>;
305
245
  export interface ApplicationOptions<Http extends AnyElysia = Elysia, RequestContext = unknown> {
306
246
  name?: string;
@@ -396,69 +336,25 @@ interface HttpContext {
396
336
  * and passed to the controller input as `scope`. Request-scoped controllers
397
337
  * are looked up on that scope, everything else on `services`.
398
338
  */
399
- export declare function createModulePlugin<const Services extends Record<string, unknown>, const Http extends AnyElysia = Elysia>(compiled: CompiledModule, services: Services, ctxFactory?: HttpRequestContextFactory<Http>, options?: Pick<ApplicationOptions<Http>, "http" | "httpPolicies" | "commandGovernance" | "commandExecutor" | "errorMapper" | "onExecution" | "normalize">, imported?: Record<string, Record<string, unknown>>): Elysia<"", {
339
+ export declare function createModulePlugin<const Services extends Record<string, unknown>, const Http extends AnyElysia = Elysia>(compiled: CompiledModule, services: Services, ctxFactory?: HttpRequestContextFactory<Http>, options?: Pick<ApplicationOptions<Http>, "http" | "httpPolicies" | "commandGovernance" | "commandExecutor" | "errorMapper" | "onExecution" | "normalize">, imported?: Record<string, Record<string, unknown>>): import("elysia/types").LocalHookReturn<"", "local", {
400
340
  decorator: {} & Http["~Singleton"]["decorator"];
401
341
  store: ({} & Http["~Singleton"]["store"] extends infer T_1 ? { [K_1 in keyof T_1]: T_1[K_1]; } : never) extends infer T ? { [K in keyof T]: T[K]; } : never;
402
342
  derive: {} & Http["~Singleton"]["derive"];
403
- resolve: {} & Http["~Singleton"]["resolve"];
404
343
  }, {
405
- typebox: {};
406
- error: {};
407
- } & Http["~Definitions"], {
408
- schema: {};
409
- standaloneSchema: {};
410
- macro: {};
411
- macroFn: {};
412
- parser: {};
413
- response: {};
414
- } & Http["~Metadata"], {} & Http["~Routes"], {
415
- derive: {};
416
- resolve: {};
417
- schema: {};
418
- standaloneSchema: {};
419
- response: {};
420
- }, {
421
- derive: {} & ({
422
- derive: {};
423
- resolve: {};
424
- schema: {};
425
- standaloneSchema: {};
426
- response: {};
427
- } & Http["~Ephemeral"])["derive"];
428
- resolve: ({
429
- derive: {};
430
- resolve: {};
431
- schema: {};
432
- standaloneSchema: {};
433
- response: {};
434
- } & Http["~Ephemeral"])["resolve"] & {
435
- readonly services: Services;
436
- readonly requestContext: unknown;
437
- };
438
- schema: {} & import("elysia").MergeSchema<({
439
- derive: {};
440
- resolve: {};
441
- schema: {};
442
- standaloneSchema: {};
443
- response: {};
444
- } & Http["~Ephemeral"])["schema"], {}, "">;
445
- standaloneSchema: {} & ({
446
- derive: {};
447
- resolve: {};
448
- schema: {};
449
- standaloneSchema: {};
450
- response: {};
451
- } & Http["~Ephemeral"])["standaloneSchema"];
452
- response: import("elysia/types").UnionResponseStatus<{} & ({
453
- derive: {};
454
- resolve: {};
455
- schema: {};
456
- standaloneSchema: {};
457
- response: {};
458
- } & Http["~Ephemeral"])["response"], import("elysia").ExtractErrorFromHandle<{
459
- readonly services: Services;
460
- readonly requestContext: unknown;
461
- }>>;
344
+ typebox: {} & Http["~Definitions"]["typebox"];
345
+ error: [...Http["~Definitions"]["error"]];
346
+ }, import("elysia").DefaultMetadata & Http["~Metadata"], import("elysia/types").ResolveRouteErrors<{}, [...Http["~Definitions"]["error"], ...Http["~Ephemeral"]["error"]]> & Http["~Routes"], import("elysia").DefaultEphemeral, {
347
+ derive: {} & Http["~Ephemeral"]["derive"];
348
+ schema: {} & import("elysia/types").MergeSchema<{} & Http["~Ephemeral"]["schema"], {}, "", false>;
349
+ schemas: {} & Http["~Ephemeral"]["schemas"];
350
+ response: {} & Http["~Ephemeral"]["response"];
351
+ error: [...Http["~Ephemeral"]["error"]];
352
+ }, import("elysia/types").ExtractErrorFromHandle<{
353
+ readonly services: Services;
354
+ readonly requestContext: unknown;
355
+ }>, {
356
+ readonly services: Services;
357
+ readonly requestContext: unknown;
462
358
  }>;
463
359
  /**
464
360
  * Execute one compiler-emitted Job descriptor.
@@ -476,134 +372,48 @@ export declare function defaultErrorResponse(error: unknown, frameworkCode?: str
476
372
  * `createServices` receives `deps` plus the services of all previously
477
373
  * created modules, keyed by module name.
478
374
  */
479
- export declare function createApplication<const Http extends AnyElysia = Elysia>(options: ApplicationOptions<Http>): Elysia<"", {
375
+ export declare function createApplication<const Http extends AnyElysia = Elysia>(options: ApplicationOptions<Http>): Elysia<"", "local", {
480
376
  decorator: {} & Http["~Singleton"]["decorator"];
481
377
  store: ({} & Http["~Singleton"]["store"] extends infer T_1 ? { [K_1 in keyof T_1]: T_1[K_1]; } : never) extends infer T ? { [K in keyof T]: T[K]; } : never;
482
- derive: {} & Http["~Singleton"]["derive"];
483
- resolve: {} & Http["~Singleton"]["resolve"];
378
+ derive: {} & Http["~Singleton"]["derive"] & Http["~Ephemeral"]["derive"];
484
379
  }, {
485
- typebox: {};
486
- error: {};
487
- } & Http["~Definitions"], {
488
- schema: {};
489
- standaloneSchema: {};
490
- macro: {};
491
- macroFn: {};
492
- parser: {};
493
- response: {};
494
- } & Http["~Metadata"], {} & Http["~Routes"], {
380
+ typebox: {} & Http["~Definitions"]["typebox"];
381
+ error: [...Http["~Definitions"]["error"], ...Http["~Ephemeral"]["error"]];
382
+ }, import("elysia").DefaultMetadata & {
383
+ schema: import("elysia/types").MergeSchema<import("elysia/types").MergeSchema<{} & Http["~Ephemeral"]["schema"], {}, "", false>, (import("elysia").DefaultMetadata & Http["~Metadata"])["schema"], "", false>;
384
+ schemas: (import("elysia").DefaultMetadata & Http["~Metadata"])["schemas"] & {} & Http["~Ephemeral"]["schemas"];
385
+ macro: (import("elysia").DefaultMetadata & Http["~Metadata"])["macro"];
386
+ macroFn: (import("elysia").DefaultMetadata & Http["~Metadata"])["macroFn"];
387
+ parser: (import("elysia").DefaultMetadata & Http["~Metadata"])["parser"];
388
+ response: import("elysia/types").UnionResponseStatus<(import("elysia").DefaultMetadata & Http["~Metadata"])["response"], import("elysia/types").UnionResponseStatus<{} & Http["~Ephemeral"]["response"], {}>>;
389
+ }, import("elysia/types").ResolveRouteErrors<{}, [...Http["~Definitions"]["error"], ...Http["~Ephemeral"]["error"]]> & Http["~Routes"], import("elysia").DefaultEphemeral, {
495
390
  derive: {};
496
- resolve: {};
497
391
  schema: {};
498
- standaloneSchema: {};
392
+ schemas: {};
499
393
  response: {};
500
- }, {
501
- derive: {};
502
- resolve: {};
503
- schema: {};
504
- standaloneSchema: {};
505
- response: {};
506
- } & {
507
- derive: {} & ({
508
- derive: {};
509
- resolve: {};
510
- schema: {};
511
- standaloneSchema: {};
512
- response: {};
513
- } & Http["~Ephemeral"])["derive"];
514
- resolve: {} & ({
515
- derive: {};
516
- resolve: {};
517
- schema: {};
518
- standaloneSchema: {};
519
- response: {};
520
- } & Http["~Ephemeral"])["resolve"];
521
- schema: import("elysia").MergeSchema<({
522
- derive: {};
523
- resolve: {};
524
- schema: {};
525
- standaloneSchema: {};
526
- response: {};
527
- } & Http["~Ephemeral"])["schema"], {}, "">;
528
- standaloneSchema: ({
529
- derive: {};
530
- resolve: {};
531
- schema: {};
532
- standaloneSchema: {};
533
- response: {};
534
- } & Http["~Ephemeral"])["standaloneSchema"] & {};
535
- response: ({
536
- derive: {};
537
- resolve: {};
538
- schema: {};
539
- standaloneSchema: {};
540
- response: {};
541
- } & Http["~Ephemeral"])["response"] & {};
394
+ error: [];
542
395
  }>;
543
396
  /** Semantic alias of createApplication for readable tests. */
544
- export declare function createTestApp<const Http extends AnyElysia = Elysia>(options: ApplicationOptions<Http>): Elysia<"", {
397
+ export declare function createTestApp<const Http extends AnyElysia = Elysia>(options: ApplicationOptions<Http>): Elysia<"", "local", {
545
398
  decorator: {} & Http["~Singleton"]["decorator"];
546
399
  store: ({} & Http["~Singleton"]["store"] extends infer T_1 ? { [K_1 in keyof T_1]: T_1[K_1]; } : never) extends infer T ? { [K in keyof T]: T[K]; } : never;
547
- derive: {} & Http["~Singleton"]["derive"];
548
- resolve: {} & Http["~Singleton"]["resolve"];
549
- }, {
550
- typebox: {};
551
- error: {};
552
- } & Http["~Definitions"], {
553
- schema: {};
554
- standaloneSchema: {};
555
- macro: {};
556
- macroFn: {};
557
- parser: {};
558
- response: {};
559
- } & Http["~Metadata"], {} & Http["~Routes"], {
560
- derive: {};
561
- resolve: {};
562
- schema: {};
563
- standaloneSchema: {};
564
- response: {};
400
+ derive: {} & Http["~Singleton"]["derive"] & Http["~Ephemeral"]["derive"];
565
401
  }, {
402
+ typebox: {} & Http["~Definitions"]["typebox"];
403
+ error: [...Http["~Definitions"]["error"], ...Http["~Ephemeral"]["error"]];
404
+ }, import("elysia").DefaultMetadata & {
405
+ schema: import("elysia/types").MergeSchema<import("elysia/types").MergeSchema<{} & Http["~Ephemeral"]["schema"], {}, "", false>, (import("elysia").DefaultMetadata & Http["~Metadata"])["schema"], "", false>;
406
+ schemas: (import("elysia").DefaultMetadata & Http["~Metadata"])["schemas"] & {} & Http["~Ephemeral"]["schemas"];
407
+ macro: (import("elysia").DefaultMetadata & Http["~Metadata"])["macro"];
408
+ macroFn: (import("elysia").DefaultMetadata & Http["~Metadata"])["macroFn"];
409
+ parser: (import("elysia").DefaultMetadata & Http["~Metadata"])["parser"];
410
+ response: import("elysia/types").UnionResponseStatus<(import("elysia").DefaultMetadata & Http["~Metadata"])["response"], import("elysia/types").UnionResponseStatus<{} & Http["~Ephemeral"]["response"], {}>>;
411
+ }, import("elysia/types").ResolveRouteErrors<{}, [...Http["~Definitions"]["error"], ...Http["~Ephemeral"]["error"]]> & Http["~Routes"], import("elysia").DefaultEphemeral, {
566
412
  derive: {};
567
- resolve: {};
568
413
  schema: {};
569
- standaloneSchema: {};
414
+ schemas: {};
570
415
  response: {};
571
- } & {
572
- derive: {} & ({
573
- derive: {};
574
- resolve: {};
575
- schema: {};
576
- standaloneSchema: {};
577
- response: {};
578
- } & Http["~Ephemeral"])["derive"];
579
- resolve: {} & ({
580
- derive: {};
581
- resolve: {};
582
- schema: {};
583
- standaloneSchema: {};
584
- response: {};
585
- } & Http["~Ephemeral"])["resolve"];
586
- schema: import("elysia").MergeSchema<({
587
- derive: {};
588
- resolve: {};
589
- schema: {};
590
- standaloneSchema: {};
591
- response: {};
592
- } & Http["~Ephemeral"])["schema"], {}, "">;
593
- standaloneSchema: ({
594
- derive: {};
595
- resolve: {};
596
- schema: {};
597
- standaloneSchema: {};
598
- response: {};
599
- } & Http["~Ephemeral"])["standaloneSchema"] & {};
600
- response: ({
601
- derive: {};
602
- resolve: {};
603
- schema: {};
604
- standaloneSchema: {};
605
- response: {};
606
- } & Http["~Ephemeral"])["response"] & {};
416
+ error: [];
607
417
  }>;
608
418
  export { createMemorySandbox, } from "./memory";
609
419
  export type { HandleLike as MemoryHandleLike, MemoryDatabase, MemorySandbox, MemorySandboxOptions, MemoryStorage, MemoryStorageObject, } from "./memory";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { Elysia as Elysia3 } from "elysia";
2
+ import { Elysia as Elysia3, setupTypebox, Validator as Validator2 } from "elysia";
3
3
  import { decodeCommandPreview } from "@supacloud/contracts";
4
4
 
5
5
  // src/command-errors.ts
@@ -83,15 +83,15 @@ function httpRequestId(request) {
83
83
  }
84
84
  function createHttpTelemetry(observe) {
85
85
  const starts = new WeakMap;
86
- return new Elysia().onRequest(({ request, set }) => {
86
+ return new Elysia().request(({ request, set }) => {
87
87
  const supplied = request.headers.get("x-request-id");
88
88
  const requestId = supplied && /^[A-Za-z0-9._:-]{1,128}$/.test(supplied) ? supplied : crypto.randomUUID();
89
89
  starts.set(request, { time: performance.now(), requestId });
90
90
  requestIds.set(request, requestId);
91
91
  set.headers["x-request-id"] = requestId;
92
- }).onError(() => {
92
+ }).error(() => {
93
93
  return;
94
- }).onAfterResponse(async ({ request, response, set, route }) => {
94
+ }).afterResponse(async ({ request, responseValue: response, set, route }) => {
95
95
  const start = starts.get(request);
96
96
  if (!start)
97
97
  return;
@@ -193,7 +193,7 @@ function unauthenticated() {
193
193
  }
194
194
 
195
195
  // src/http-response-cache.ts
196
- import { mapResponse } from "elysia/adapter/web-standard/handler";
196
+ import { WebStandardAdapter } from "elysia/adapter/web-standard";
197
197
  function mayStore({ http, response }) {
198
198
  if (response === null || typeof response !== "object" || response instanceof Response || !Array.isArray(response) && Object.getPrototypeOf(response) !== Object.prototype)
199
199
  return false;
@@ -277,7 +277,10 @@ function createCachePolicy(options) {
277
277
  policy.mapResponse = async (context) => {
278
278
  if (!misses.has(context.http.request) || !mayStore(context))
279
279
  return;
280
- const response = await mapResponse(context.response, context.http.set, context.http.request);
280
+ const value = context.encodeResponse ? await context.encodeResponse(context.response) : context.response;
281
+ const response = await WebStandardAdapter.response.map(value, context.http.set, context.http.request);
282
+ if (!(response instanceof Response))
283
+ throw new Error("HTTP response mapping did not return a Response");
281
284
  const body = boundedBody(response.clone(), options.maxBodyBytes).catch(() => {
282
285
  try {
283
286
  options.onWriteError();
@@ -695,9 +698,10 @@ function executionTrace(context) {
695
698
 
696
699
  // src/schema_contract.ts
697
700
  import {
698
- getSchemaValidator,
701
+ Validator,
702
+ t,
699
703
  StatusMap as StatusMap2,
700
- ElysiaCustomStatusResponse
704
+ ElysiaStatus
701
705
  } from "elysia";
702
706
  function defineRouteContract(schemas) {
703
707
  return Object.freeze({ ...schemas });
@@ -708,7 +712,7 @@ var RESPONSE_STATUS_MAX = 599;
708
712
  var RESPONSE_FAMILY_PATTERN = /^([1-5])(?:xx|XX)$/;
709
713
  var RESPONSE_STATUS_PATTERN = /^[1-5]\d{2}$/;
710
714
  function isSchema(value) {
711
- return value !== null && typeof value === "object" && ((TYPEBOX_KIND in value) || ("~standard" in value));
715
+ return value !== null && typeof value === "object" && ((TYPEBOX_KIND in value) || ("~kind" in value) || ("~standard" in value));
712
716
  }
713
717
  function isJsonSchemaObject(value) {
714
718
  if (value === null || typeof value !== "object" || Array.isArray(value))
@@ -769,8 +773,8 @@ function responseStatusDeclared(responses, status) {
769
773
  function responseStatusOf(value, configuredStatus) {
770
774
  if (value instanceof Response)
771
775
  return value.status;
772
- if (value instanceof ElysiaCustomStatusResponse) {
773
- const code = value.code;
776
+ if (value instanceof ElysiaStatus) {
777
+ const code = value.status;
774
778
  if (typeof code === "number" && Number.isInteger(code) && code >= RESPONSE_STATUS_MIN && code <= RESPONSE_STATUS_MAX) {
775
779
  return code;
776
780
  }
@@ -884,7 +888,7 @@ function registerElysiaRoute(app, route) {
884
888
  }
885
889
  return value;
886
890
  };
887
- app.route(route.method, route.path, handler, toElysiaRouteSchema(route.contract));
891
+ app.method(route.method, route.path, toElysiaRouteSchema(route.contract), handler);
888
892
  return app;
889
893
  }
890
894
 
@@ -896,13 +900,19 @@ class SchemaContractError extends Error {
896
900
  }
897
901
  }
898
902
  function createSchemaDecoder(schema, options = {}) {
899
- const validator = getSchemaValidator(schema, {
900
- coerce: options.coerce ?? false,
903
+ const validator = Validator.create(schema, {
904
+ ...options.coerce ? { coerces: [[[
905
+ ["number", (value) => t.Numeric(value)],
906
+ ["integer", (value) => t.IntegerString(value)],
907
+ ["boolean", (value) => t.BooleanString(value)]
908
+ ]]] } : {},
901
909
  normalize: options.normalize ?? true
902
910
  });
903
911
  return (value) => {
904
912
  try {
905
- return validator.parse(value);
913
+ if (validator.isAsync)
914
+ throw new SchemaContractError;
915
+ return validator.FromSync(value);
906
916
  } catch {
907
917
  throw new SchemaContractError;
908
918
  }
@@ -1008,12 +1018,12 @@ function createDocumentationPlugin(options = {}) {
1008
1018
  reserve(specPath);
1009
1019
  reserve(uiPath);
1010
1020
  const title = options.openApi.title ?? "OpenAPI Documentation";
1011
- app.get(specPath, async () => jsonResponse(await resolveSource(options.openApi.document)), {
1021
+ app.get(specPath, {
1012
1022
  detail: { hide: true }
1013
- });
1014
- app.get(uiPath, () => new Response(renderViewerPage(title, specPath, "json"), {
1023
+ }, async () => jsonResponse(await resolveSource(options.openApi.document)));
1024
+ app.get(uiPath, { detail: { hide: true } }, () => new Response(renderViewerPage(title, specPath, "json"), {
1015
1025
  headers: { "content-type": "text/html; charset=utf-8" }
1016
- }), { detail: { hide: true } });
1026
+ }));
1017
1027
  }
1018
1028
  if (options.graphql) {
1019
1029
  const schemaPath = normalizePath(options.graphql.schemaPath, "/graphql/schema.graphql");
@@ -1021,12 +1031,12 @@ function createDocumentationPlugin(options = {}) {
1021
1031
  reserve(schemaPath);
1022
1032
  reserve(uiPath);
1023
1033
  const title = options.graphql.title ?? "GraphQL Schema";
1024
- app.get(schemaPath, async () => textResponse(await resolveSource(options.graphql.schema)), {
1034
+ app.get(schemaPath, {
1025
1035
  detail: { hide: true }
1026
- });
1027
- app.get(uiPath, () => new Response(renderViewerPage(title, schemaPath, "text"), {
1036
+ }, async () => textResponse(await resolveSource(options.graphql.schema)));
1037
+ app.get(uiPath, { detail: { hide: true } }, () => new Response(renderViewerPage(title, schemaPath, "text"), {
1028
1038
  headers: { "content-type": "text/html; charset=utf-8" }
1029
- }), { detail: { hide: true } });
1039
+ }));
1030
1040
  }
1031
1041
  return app;
1032
1042
  }
@@ -1832,6 +1842,7 @@ function createWorker(options) {
1832
1842
  }
1833
1843
 
1834
1844
  // src/index.ts
1845
+ setupTypebox();
1835
1846
  var VERIFIED_JWT_SUBJECT_HEADER = "x-supacloud-jwt-sub";
1836
1847
  var EXECUTION_ID_HEADER = "x-sb-execution-id";
1837
1848
  var IDEMPOTENCY_KEY_HEADER = "idempotency-key";
@@ -1974,7 +1985,7 @@ function contextPlugin(http) {
1974
1985
  seed = ++nextHttpPluginId;
1975
1986
  httpPluginIds.set(http, seed);
1976
1987
  }
1977
- return new Elysia3({ name: "supacloud:http-context", seed }).use(http ?? new Elysia3).as("scoped");
1988
+ return new Elysia3({ name: "supacloud:http-context", seed }).use(http ?? new Elysia3).as("plugin");
1978
1989
  }
1979
1990
  function mountHttp(http, name, normalize = true) {
1980
1991
  return new Elysia3({ name, normalize }).use(contextPlugin(http));
@@ -2363,7 +2374,7 @@ function createModulePlugin(compiled, services, ctxFactory = defaultRequestConte
2363
2374
  const requestContexts = new WeakMap;
2364
2375
  const governanceExecutor = options.commandGovernance ? createCommandExecutor(options.commandGovernance, options.onExecution) : undefined;
2365
2376
  const commandExecutor = options.commandExecutor && governanceExecutor ? composeCommandExecutors(options.commandExecutor, governanceExecutor) : options.commandExecutor ?? governanceExecutor;
2366
- const plugin = mountHttp(options.http, `supacloud:${compiled.name}`, options.normalize ?? true).resolve(async (context) => {
2377
+ const plugin = mountHttp(options.http, `supacloud:${compiled.name}`, options.normalize ?? true).derive(async (context) => {
2367
2378
  const requestContext = await ctxFactory(context.request, context);
2368
2379
  requestContexts.set(context.request, requestContext);
2369
2380
  return { services, requestContext };
@@ -2372,7 +2383,7 @@ function createModulePlugin(compiled, services, ctxFactory = defaultRequestConte
2372
2383
  const requestScopes = new WeakMap;
2373
2384
  if (compiled.destroyRequestScope) {
2374
2385
  const destroyRequestScope = compiled.destroyRequestScope;
2375
- plugin.onAfterResponse(async ({ request }) => {
2386
+ plugin.afterResponse(async ({ request }) => {
2376
2387
  const scope = requestScopes.get(request);
2377
2388
  if (!scope)
2378
2389
  return;
@@ -2384,7 +2395,8 @@ function createModulePlugin(compiled, services, ctxFactory = defaultRequestConte
2384
2395
  }
2385
2396
  });
2386
2397
  }
2387
- plugin.onError(async ({ code, error, request }) => {
2398
+ plugin.error(async ({ error, request }) => {
2399
+ const code = error instanceof Error && "code" in error && typeof error.code === "string" ? error.code.toUpperCase().replaceAll("-", "_") : "UNKNOWN";
2388
2400
  const context = {
2389
2401
  request,
2390
2402
  requestContext: requestContexts.get(request),
@@ -2399,12 +2411,14 @@ function createModulePlugin(compiled, services, ctxFactory = defaultRequestConte
2399
2411
  const path = joinPaths(controller.path, route.path);
2400
2412
  const documentation = route.data?.openapi;
2401
2413
  const hidden = documentation !== null && typeof documentation === "object" && "hide" in documentation && documentation.hide === true;
2414
+ const tags = documentation !== null && typeof documentation === "object" && "tags" in documentation && Array.isArray(documentation.tags) ? documentation.tags.filter((tag) => typeof tag === "string") : undefined;
2402
2415
  const schema = {
2403
2416
  ...toElysiaRouteSchema(route),
2404
2417
  ...route.parse === "none" ? { parse: "none" } : {},
2405
- ...route.title || hidden ? { detail: {
2418
+ ...route.title || hidden || tags ? { detail: {
2406
2419
  ...route.title ? { summary: route.title } : {},
2407
- ...hidden ? { hide: true } : {}
2420
+ ...hidden ? { hide: true } : {},
2421
+ ...tags ? { tags } : {}
2408
2422
  } } : {}
2409
2423
  };
2410
2424
  const policies = compileHttpPolicies(route, path, options.httpPolicies);
@@ -2428,15 +2442,28 @@ function createModulePlugin(compiled, services, ctxFactory = defaultRequestConte
2428
2442
  const responsePolicies = policies.filter((policy) => policy.afterResponse);
2429
2443
  const mappingPolicies = policies.filter((policy) => policy.mapResponse);
2430
2444
  if (mappingPolicies.length > 0) {
2445
+ const responseValidators = Validator2.response(schema.response, { normalize: options.normalize ?? true });
2431
2446
  Object.assign(schema, {
2432
2447
  mapResponse: async (context) => {
2433
- let response = context.response;
2448
+ let response = context.responseValue;
2434
2449
  let mapped;
2435
2450
  for (const policy of mappingPolicies) {
2436
2451
  const result = await policy.mapResponse({
2437
2452
  http: context,
2438
2453
  requestContext: requestContexts.get(context.request),
2439
- response
2454
+ response,
2455
+ encodeResponse: async (value) => {
2456
+ const validator = responseValidators?.[responseStatusOf(value, context.set.status)];
2457
+ if (!validator)
2458
+ return value;
2459
+ if (!("EncodeFrom" in validator) || typeof validator.EncodeFrom !== "function") {
2460
+ throw new ApplicationError("Response validation failed", { code: "RESPONSE_VALIDATION_FAILED" });
2461
+ }
2462
+ if ("mayReturnPromise" in validator && validator.mayReturnPromise && "From" in validator && typeof validator.From === "function") {
2463
+ return await Reflect.apply(validator.From, validator, [value, "response", true]);
2464
+ }
2465
+ return await Reflect.apply(validator.EncodeFrom, validator, [value, "response"]);
2466
+ }
2440
2467
  });
2441
2468
  if (result !== undefined) {
2442
2469
  if (!(result instanceof Response))
@@ -2456,7 +2483,7 @@ function createModulePlugin(compiled, services, ctxFactory = defaultRequestConte
2456
2483
  await policy.afterResponse({
2457
2484
  http: context,
2458
2485
  requestContext: requestContexts.get(context.request),
2459
- response: context.response
2486
+ response: context.responseValue
2460
2487
  });
2461
2488
  }
2462
2489
  }
@@ -2555,25 +2582,25 @@ function createModulePlugin(compiled, services, ctxFactory = defaultRequestConte
2555
2582
  };
2556
2583
  switch (route.method) {
2557
2584
  case "GET":
2558
- routeRegistrar.get(path, handler, schema);
2585
+ routeRegistrar.get(path, schema, handler);
2559
2586
  break;
2560
2587
  case "POST":
2561
- routeRegistrar.post(path, handler, schema);
2588
+ routeRegistrar.post(path, schema, handler);
2562
2589
  break;
2563
2590
  case "PUT":
2564
- routeRegistrar.put(path, handler, schema);
2591
+ routeRegistrar.put(path, schema, handler);
2565
2592
  break;
2566
2593
  case "PATCH":
2567
- routeRegistrar.patch(path, handler, schema);
2594
+ routeRegistrar.patch(path, schema, handler);
2568
2595
  break;
2569
2596
  case "DELETE":
2570
- routeRegistrar.delete(path, handler, schema);
2597
+ routeRegistrar.delete(path, schema, handler);
2571
2598
  break;
2572
2599
  case "HEAD":
2573
- routeRegistrar.head(path, handler, schema);
2600
+ routeRegistrar.head(path, schema, handler);
2574
2601
  break;
2575
2602
  case "OPTIONS":
2576
- routeRegistrar.options(path, handler, schema);
2603
+ routeRegistrar.options(path, schema, handler);
2577
2604
  break;
2578
2605
  }
2579
2606
  }
@@ -2675,7 +2702,7 @@ function isPublicApplicationError(error) {
2675
2702
  return error.expose === true && typeof error.status === "number" && Number.isInteger(error.status) && error.status >= 400 && error.status <= 599 && typeof error.code === "string" && error.code.length > 0;
2676
2703
  }
2677
2704
  function createApplication(options) {
2678
- const app = new Elysia3({ name: options.name ?? "supacloud:app", normalize: options.normalize ?? true });
2705
+ const app = new Elysia3({ name: options.name ?? "supacloud:app", normalize: options.normalize ?? true }).use(contextPlugin(options.http).as("global"));
2679
2706
  if (options.documentation)
2680
2707
  app.use(createDocumentationPlugin(options.documentation));
2681
2708
  const configuredContextFactory = options.requestContext ?? defaultRequestContext;
@@ -2692,9 +2719,9 @@ function createApplication(options) {
2692
2719
  for (const module of options.modules ?? []) {
2693
2720
  const services = module.createServices(options.deps ?? {}, imported);
2694
2721
  imported[module.name] = services;
2695
- app.use(createModulePlugin(module, services, ctxFactory, options, imported));
2722
+ app.use(createModulePlugin(module, services, ctxFactory, { ...options, http: undefined }, imported));
2696
2723
  }
2697
- return app.use(contextPlugin(options.http));
2724
+ return app;
2698
2725
  }
2699
2726
  function createTestApp(options) {
2700
2727
  return createApplication(options);
@@ -1,4 +1,6 @@
1
- import { StatusMap, ElysiaCustomStatusResponse, type Cookie, type AnyElysia, type HTTPMethod, type InputSchema, type MaybePromise, type TSchema, type UnwrapSchema } from "elysia";
1
+ import { StatusMap, ElysiaStatus, type Cookie, type AnyElysia, type InputSchema } from "elysia";
2
+ import type { HTTPMethod, MaybePromise } from "elysia/types";
3
+ import type { TSchema, StaticDecode as UnwrapSchema } from "typebox";
2
4
  import type { ResponseMapSelector as AppResponseMapSelector, RouteContractSchemas as AppRouteContractSchemas } from "@supacloud/app";
3
5
  /** Response selectors are owned by @supacloud/app and re-exported by the adapter. */
4
6
  export type ResponseMapSelector = AppResponseMapSelector;
@@ -40,17 +42,20 @@ type FamilyResponseCodes<Value> = Value extends Readonly<Record<string | number,
40
42
  }[keyof Value & string] : never;
41
43
  type ResponseStatusCodes<Value> = NumericResponseCodes<Value> | FamilyResponseCodes<Value> | ([DefaultResponseKey<Value>] extends [never] ? never : AllHttpStatusCodes);
42
44
  type DecodedSchema<Value> = Value extends TSchema ? UnwrapSchema<Value> : unknown;
43
- type DecodedResponse<Schemas extends RouteContractSchemas> = ResponseField<Schemas> extends infer Response ? Response extends TSchema ? DecodedSchema<Response> : Response extends Readonly<Record<string | number, unknown>> ? DecodedSchema<Response[keyof Response]> : DecodedSchema<Response> : unknown;
44
- type StatusResponse<Schemas extends RouteContractSchemas> = ResponseField<Schemas> extends infer Response ? Response extends TSchema ? never : Response extends Readonly<Record<string | number, unknown>> ? {
45
- [Code in ResponseStatusCodes<Response>]: ElysiaCustomStatusResponse<Code, DecodedSchema<ResponseSchemaForCode<Response, Code>>>;
46
- }[ResponseStatusCodes<Response>] : never : never;
45
+ type StatusResponse<Schemas extends RouteContractSchemas> = [
46
+ DeclaredResponses<Schemas>
47
+ ] extends [never] ? never : {
48
+ [Code in ResponseStatusCodes<DeclaredResponses<Schemas>>]: ElysiaStatus<Code, DecodedSchema<ResponseSchemaForCode<DeclaredResponses<Schemas>, Code>>>;
49
+ }[ResponseStatusCodes<DeclaredResponses<Schemas>>];
47
50
  /**
48
51
  * A plain handler return is sent as the default HTTP 200 response. When a
49
52
  * status map declares several payloads, only the schema selected for 200 is
50
53
  * valid here; every other payload must use `status(code, value)` so its
51
54
  * status and schema stay coupled at runtime.
52
55
  */
53
- type PlainResponse<Schemas extends RouteContractSchemas> = ResponseField<Schemas> extends infer Response ? Response extends Readonly<Record<string | number, unknown>> ? AllowsPlainSuccessResponse<Response> extends true ? DecodedSchema<ResponseSchemaForCode<Response, 200>> : never : DecodedResponse<Schemas> : never;
56
+ type PlainResponse<Schemas extends RouteContractSchemas> = [
57
+ DeclaredResponses<Schemas>
58
+ ] extends [never] ? DecodedSchema<LegacyResponse<Schemas>> : AllowsPlainSuccessResponse<DeclaredResponses<Schemas>> extends true ? DecodedSchema<ResponseSchemaForCode<DeclaredResponses<Schemas>, 200>> : never;
54
59
  type ElysiaRouteOutput<Schemas extends RouteContractSchemas> = PlainResponse<Schemas> | StatusResponse<Schemas> | Response | void;
55
60
  /** Raw schema shape consumed by Elysia's route registration API. */
56
61
  export interface ElysiaRouteSchema<Schemas extends RouteContractSchemas> {
@@ -71,9 +76,11 @@ type DecodedField<Schemas extends RouteContractSchemas, Key extends keyof RouteC
71
76
  type DecodedCookie<Schemas extends RouteContractSchemas> = DecodedField<Schemas, "cookie"> extends infer Value ? Value extends Record<string, unknown> ? Record<string, Cookie<unknown>> & {
72
77
  [Key in keyof Value]-?: Cookie<Value[Key]>;
73
78
  } : Record<string, Cookie<unknown>> : Record<string, Cookie<unknown>>;
74
- type StatusCode<Schemas extends RouteContractSchemas> = ResponseField<Schemas> extends infer Response ? Response extends TSchema ? never : Response extends Readonly<Record<string | number, unknown>> ? ResponseStatusCodes<Response> : never : never;
75
- type StatusResponseValue<Schemas extends RouteContractSchemas, Code extends number> = ResponseField<Schemas> extends infer Response ? Response extends TSchema ? DecodedSchema<Response> : Response extends Readonly<Record<string | number, unknown>> ? DecodedSchema<ResponseSchemaForCode<Response, Code>> : DecodedSchema<Response> : unknown;
76
- type RouteStatus<Schemas extends RouteContractSchemas> = [StatusCode<Schemas>] extends [never] ? <const Code extends number, const Value>(code: Code, response: Value) => ElysiaCustomStatusResponse<Code, Value> : <const Code extends StatusCode<Schemas>, const Value extends StatusResponseValue<Schemas, Code>>(code: Code, response: Value) => ElysiaCustomStatusResponse<Code, Value>;
79
+ type StatusCode<Schemas extends RouteContractSchemas> = [
80
+ DeclaredResponses<Schemas>
81
+ ] extends [never] ? never : ResponseStatusCodes<DeclaredResponses<Schemas>>;
82
+ type StatusResponseValue<Schemas extends RouteContractSchemas, Code extends number> = DecodedSchema<ResponseSchemaForCode<DeclaredResponses<Schemas>, Code>>;
83
+ type RouteStatus<Schemas extends RouteContractSchemas> = [StatusCode<Schemas>] extends [never] ? <const Code extends number, const Value>(code: Code, response: Value) => ElysiaStatus<Code, Value> : <const Code extends StatusCode<Schemas>, const Value extends StatusResponseValue<Schemas, Code>>(code: Code, response: Value) => ElysiaStatus<Code, Value>;
77
84
  /** Elysia-compatible decoded context inferred from one route contract and path. */
78
85
  export type ElysiaRouteContext<Schemas extends RouteContractSchemas, Path extends string = ""> = {
79
86
  body: DecodedField<Schemas, "body">;
@@ -147,8 +154,8 @@ export declare function defineJsonContract<const Input extends TSchema, const Re
147
154
  url: string;
148
155
  body?: unknown;
149
156
  }, options?: SchemaDecoderOptions): Readonly<{
150
- input: (value: unknown) => UnwrapSchema<Input, {}>;
151
- result: (value: unknown) => UnwrapSchema<Result, {}>;
157
+ input: (value: unknown) => import("typebox").StaticType<[], "Decode", {}, {}, Input>;
158
+ result: (value: unknown) => import("typebox").StaticType<[], "Decode", {}, {}, Result>;
152
159
  request: (input: NoInfer<UnwrapSchema<Input>>) => {
153
160
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
154
161
  url: string;
@@ -18,39 +18,26 @@ export declare function createWebhookMigrationExample(options: {
18
18
  authorize(identity: CommandIdentity, transaction: CommandTransaction): Promise<CommandAuthorization>;
19
19
  writeAudit?(transaction: CommandTransaction): Promise<void>;
20
20
  }): {
21
- app: import("elysia").default<"", {
21
+ app: import("elysia").Elysia<"", "local", {
22
22
  decorator: {};
23
23
  store: {};
24
24
  derive: {};
25
- resolve: {};
26
25
  }, {
27
26
  typebox: {};
28
- error: {};
29
- }, {
27
+ error: [];
28
+ }, import("elysia").DefaultMetadata & {
30
29
  schema: {};
31
- standaloneSchema: {};
30
+ schemas: {};
32
31
  macro: {};
33
32
  macroFn: {};
34
33
  parser: {};
35
34
  response: {};
36
- }, {}, {
37
- derive: {};
38
- resolve: {};
39
- schema: {};
40
- standaloneSchema: {};
41
- response: {};
42
- }, {
43
- derive: {};
44
- resolve: {};
45
- schema: {};
46
- standaloneSchema: {};
47
- response: {};
48
- } & {
35
+ }, {}, import("elysia").DefaultEphemeral, {
49
36
  derive: {};
50
- resolve: {};
51
37
  schema: {};
52
- standaloneSchema: {};
38
+ schemas: {};
53
39
  response: {};
40
+ error: [];
54
41
  }>;
55
42
  modules: import("./fixtures/webhook-generated/application").CompiledApplicationModule[];
56
43
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/elysia",
3
- "version": "0.19.0",
3
+ "version": "0.20.1",
4
4
  "description": "Elysia runtime adapter for SupaCloud compiled modules: application/request scopes, route registration and validation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -47,23 +47,27 @@
47
47
  "directory": "packages/elysia"
48
48
  },
49
49
  "dependencies": {
50
- "@supacloud/app": "0.17.0",
50
+ "@supacloud/app": "0.18.0",
51
51
  "@supacloud/contracts": "0.5.0",
52
- "jose": "^6.2.11"
52
+ "exact-mirror": "1.2.6",
53
+ "jose": "^6.2.11",
54
+ "typebox": "1.3.34"
53
55
  },
54
56
  "overrides": {
57
+ "@supacloud/delivery": "0.2.0",
55
58
  "@supacloud/contracts": "0.5.0",
56
59
  "@supacloud/commands": "0.7.0"
57
60
  },
58
61
  "peerDependencies": {
59
- "elysia": "^1.4.30"
62
+ "elysia": "2.0.0-beta.19"
60
63
  },
61
64
  "devDependencies": {
62
- "@supacloud/compiler": "0.26.0",
65
+ "@supacloud/compiler": "0.27.2",
66
+ "@supacloud/delivery": "0.2.0",
63
67
  "@supacloud/commands": "0.7.0",
64
- "@supacloud/db": "0.8.0",
68
+ "@supacloud/db": "0.9.0",
65
69
  "@types/bun": "^1.4.2",
66
- "elysia": "^1.4.30",
70
+ "elysia": "2.0.0-beta.19",
67
71
  "typescript": "^7.0.2"
68
72
  }
69
73
  }