@beignet/core 0.0.3 → 0.0.4
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/CHANGELOG.md +157 -0
- package/README.md +785 -43
- package/dist/application/index.d.ts +28 -2
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +140 -12
- package/dist/application/index.js.map +1 -1
- package/dist/client/client.d.ts +2 -2
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +136 -48
- package/dist/client/client.js.map +1 -1
- package/dist/client/error-messages.d.ts +14 -0
- package/dist/client/error-messages.d.ts.map +1 -0
- package/dist/client/error-messages.js +23 -0
- package/dist/client/error-messages.js.map +1 -0
- package/dist/client/index.d.ts +8 -4
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +35 -5
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client-only.d.ts +8 -0
- package/dist/client-only.d.ts.map +1 -0
- package/dist/client-only.js +8 -0
- package/dist/client-only.js.map +1 -0
- package/dist/config/index.d.ts +5 -5
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -2
- package/dist/config/index.js.map +1 -1
- package/dist/contracts/catalog-errors.d.ts +27 -0
- package/dist/contracts/catalog-errors.d.ts.map +1 -0
- package/dist/contracts/catalog-errors.js +69 -0
- package/dist/contracts/catalog-errors.js.map +1 -0
- package/dist/contracts/contract-builder.d.ts +15 -12
- package/dist/contracts/contract-builder.d.ts.map +1 -1
- package/dist/contracts/contract-builder.js +15 -41
- package/dist/contracts/contract-builder.js.map +1 -1
- package/dist/contracts/contract-group.d.ts +11 -8
- package/dist/contracts/contract-group.d.ts.map +1 -1
- package/dist/contracts/contract-group.js +13 -40
- package/dist/contracts/contract-group.js.map +1 -1
- package/dist/contracts/contract-like.d.ts +1 -1
- package/dist/contracts/contract-like.d.ts.map +1 -1
- package/dist/contracts/index.d.ts +13 -9
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +9 -5
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/openapi-meta.d.ts +48 -0
- package/dist/contracts/openapi-meta.d.ts.map +1 -1
- package/dist/contracts/openapi-meta.js +3 -0
- package/dist/contracts/openapi-meta.js.map +1 -1
- package/dist/contracts/path-template.d.ts +1 -1
- package/dist/contracts/path-template.js +2 -2
- package/dist/contracts/path-template.js.map +1 -1
- package/dist/contracts/schema-shape.d.ts +37 -0
- package/dist/contracts/schema-shape.d.ts.map +1 -0
- package/dist/contracts/schema-shape.js +61 -0
- package/dist/contracts/schema-shape.js.map +1 -0
- package/dist/contracts/success-status.d.ts +32 -0
- package/dist/contracts/success-status.d.ts.map +1 -0
- package/dist/contracts/success-status.js +18 -0
- package/dist/contracts/success-status.js.map +1 -0
- package/dist/contracts/types.d.ts +25 -5
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/contracts/types.js.map +1 -1
- package/dist/contracts/utils.d.ts +1 -1
- package/dist/contracts/utils.d.ts.map +1 -1
- package/dist/contracts/utils.js +1 -1
- package/dist/contracts/utils.js.map +1 -1
- package/dist/domain/events.d.ts +1 -1
- package/dist/domain/events.d.ts.map +1 -1
- package/dist/domain/events.js +1 -1
- package/dist/domain/events.js.map +1 -1
- package/dist/domain/index.d.ts +3 -3
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +3 -3
- package/dist/domain/index.js.map +1 -1
- package/dist/errors/catalog.d.ts +9 -1
- package/dist/errors/catalog.d.ts.map +1 -1
- package/dist/errors/catalog.js +7 -1
- package/dist/errors/catalog.js.map +1 -1
- package/dist/errors/http.d.ts +10 -0
- package/dist/errors/http.d.ts.map +1 -1
- package/dist/errors/http.js +11 -1
- package/dist/errors/http.js.map +1 -1
- package/dist/errors/index.d.ts +4 -4
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +4 -4
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/response.d.ts +4 -1
- package/dist/errors/response.d.ts.map +1 -1
- package/dist/errors/response.js.map +1 -1
- package/dist/events/index.d.ts +10 -12
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +10 -10
- package/dist/events/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +5 -3
- package/dist/idempotency/index.d.ts.map +1 -1
- package/dist/idempotency/index.js.map +1 -1
- package/dist/jobs/index.d.ts +12 -14
- package/dist/jobs/index.d.ts.map +1 -1
- package/dist/jobs/index.js +13 -13
- package/dist/jobs/index.js.map +1 -1
- package/dist/notifications/index.d.ts +14 -16
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +14 -14
- package/dist/notifications/index.js.map +1 -1
- package/dist/openapi/index.d.ts +8 -3
- package/dist/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +41 -29
- package/dist/openapi/index.js.map +1 -1
- package/dist/openapi/schema-introspector.d.ts +37 -0
- package/dist/openapi/schema-introspector.d.ts.map +1 -1
- package/dist/openapi/schema-introspector.js +23 -17
- package/dist/openapi/schema-introspector.js.map +1 -1
- package/dist/outbox/index.d.ts +15 -6
- package/dist/outbox/index.d.ts.map +1 -1
- package/dist/outbox/index.js +60 -16
- package/dist/outbox/index.js.map +1 -1
- package/dist/ports/audit.d.ts +56 -10
- package/dist/ports/audit.d.ts.map +1 -1
- package/dist/ports/audit.js +71 -3
- package/dist/ports/audit.js.map +1 -1
- package/dist/ports/auth.d.ts +92 -0
- package/dist/ports/auth.d.ts.map +1 -1
- package/dist/ports/auth.js +92 -0
- package/dist/ports/auth.js.map +1 -1
- package/dist/ports/events.d.ts +2 -2
- package/dist/ports/events.d.ts.map +1 -1
- package/dist/ports/index.d.ts +62 -33
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +28 -34
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/policy.d.ts +32 -3
- package/dist/ports/policy.d.ts.map +1 -1
- package/dist/ports/policy.js +13 -2
- package/dist/ports/policy.js.map +1 -1
- package/dist/ports/testing.d.ts +1030 -2
- package/dist/ports/testing.d.ts.map +1 -1
- package/dist/ports/testing.js +1031 -1
- package/dist/ports/testing.js.map +1 -1
- package/dist/ports/unbound.d.ts +21 -0
- package/dist/ports/unbound.d.ts.map +1 -0
- package/dist/ports/unbound.js +57 -0
- package/dist/ports/unbound.js.map +1 -0
- package/dist/ports/unit-of-work.d.ts +1 -1
- package/dist/ports/unit-of-work.d.ts.map +1 -1
- package/dist/ports/unit-of-work.js +1 -1
- package/dist/ports/unit-of-work.js.map +1 -1
- package/dist/providers/index.d.ts +3 -2
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +3 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/instrumentation.d.ts +45 -4
- package/dist/providers/instrumentation.d.ts.map +1 -1
- package/dist/providers/instrumentation.js +25 -6
- package/dist/providers/instrumentation.js.map +1 -1
- package/dist/providers/metadata.d.ts +39 -0
- package/dist/providers/metadata.d.ts.map +1 -0
- package/dist/providers/metadata.js +169 -0
- package/dist/providers/metadata.js.map +1 -0
- package/dist/providers/provider.d.ts +114 -9
- package/dist/providers/provider.d.ts.map +1 -1
- package/dist/providers/provider.js +3 -20
- package/dist/providers/provider.js.map +1 -1
- package/dist/schedules/index.d.ts +94 -13
- package/dist/schedules/index.d.ts.map +1 -1
- package/dist/schedules/index.js +66 -12
- package/dist/schedules/index.js.map +1 -1
- package/dist/server/audit-context.d.ts +29 -0
- package/dist/server/audit-context.d.ts.map +1 -0
- package/dist/server/audit-context.js +44 -0
- package/dist/server/audit-context.js.map +1 -0
- package/dist/server/context.d.ts +141 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +39 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/contract-like.d.ts +1 -1
- package/dist/server/contract-like.d.ts.map +1 -1
- package/dist/server/contract-like.js +1 -1
- package/dist/server/contract-like.js.map +1 -1
- package/dist/server/health.d.ts +2 -2
- package/dist/server/health.d.ts.map +1 -1
- package/dist/server/hooks/auth.d.ts +49 -10
- package/dist/server/hooks/auth.d.ts.map +1 -1
- package/dist/server/hooks/auth.js +77 -37
- package/dist/server/hooks/auth.js.map +1 -1
- package/dist/server/hooks/cors.d.ts +1 -1
- package/dist/server/hooks/cors.d.ts.map +1 -1
- package/dist/server/hooks/errors.d.ts +2 -2
- package/dist/server/hooks/errors.d.ts.map +1 -1
- package/dist/server/hooks/errors.js +2 -2
- package/dist/server/hooks/errors.js.map +1 -1
- package/dist/server/hooks/idempotency.d.ts +78 -0
- package/dist/server/hooks/idempotency.d.ts.map +1 -0
- package/dist/server/hooks/idempotency.js +154 -0
- package/dist/server/hooks/idempotency.js.map +1 -0
- package/dist/server/hooks/index.d.ts +8 -7
- package/dist/server/hooks/index.d.ts.map +1 -1
- package/dist/server/hooks/index.js +6 -5
- package/dist/server/hooks/index.js.map +1 -1
- package/dist/server/hooks/logging.d.ts +2 -2
- package/dist/server/hooks/logging.d.ts.map +1 -1
- package/dist/server/hooks/logging.js +1 -1
- package/dist/server/hooks/logging.js.map +1 -1
- package/dist/server/hooks/rate-limit.d.ts +25 -7
- package/dist/server/hooks/rate-limit.d.ts.map +1 -1
- package/dist/server/hooks/rate-limit.js +47 -12
- package/dist/server/hooks/rate-limit.js.map +1 -1
- package/dist/server/hooks.d.ts +1 -1
- package/dist/server/hooks.d.ts.map +1 -1
- package/dist/server/hooks.js +1 -1
- package/dist/server/hooks.js.map +1 -1
- package/dist/server/http.d.ts +61 -35
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +1 -20
- package/dist/server/http.js.map +1 -1
- package/dist/server/index.d.ts +36 -12
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +24 -8
- package/dist/server/index.js.map +1 -1
- package/dist/server/instrumentation.d.ts +108 -0
- package/dist/server/instrumentation.d.ts.map +1 -0
- package/dist/server/instrumentation.js +297 -0
- package/dist/server/instrumentation.js.map +1 -0
- package/dist/server/openapi.d.ts +3 -3
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/openapi.js +1 -1
- package/dist/server/openapi.js.map +1 -1
- package/dist/server/providers/index.d.ts +3 -3
- package/dist/server/providers/index.d.ts.map +1 -1
- package/dist/server/providers/index.js +3 -3
- package/dist/server/providers/index.js.map +1 -1
- package/dist/server/providers/loadProviderConfig.d.ts +2 -2
- package/dist/server/providers/loadProviderConfig.d.ts.map +1 -1
- package/dist/server/providers/loadProviderConfig.js +2 -2
- package/dist/server/providers/loadProviderConfig.js.map +1 -1
- package/dist/server/request-context.d.ts +67 -0
- package/dist/server/request-context.d.ts.map +1 -0
- package/dist/server/request-context.js +79 -0
- package/dist/server/request-context.js.map +1 -0
- package/dist/server/server-context.d.ts +38 -0
- package/dist/server/server-context.d.ts.map +1 -0
- package/dist/server/server-context.js +38 -0
- package/dist/server/server-context.js.map +1 -0
- package/dist/server/server.d.ts +105 -33
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +434 -118
- package/dist/server/server.js.map +1 -1
- package/dist/server/types.d.ts +2 -2
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +2 -2
- package/dist/server/types.js.map +1 -1
- package/dist/server/use-case-route.d.ts +263 -0
- package/dist/server/use-case-route.d.ts.map +1 -0
- package/dist/server/use-case-route.js +77 -0
- package/dist/server/use-case-route.js.map +1 -0
- package/dist/server-only.d.ts +8 -0
- package/dist/server-only.d.ts.map +1 -0
- package/dist/server-only.js +8 -0
- package/dist/server-only.js.map +1 -0
- package/dist/tasks/index.d.ts +139 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +98 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/testing/index.d.ts +607 -5
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +426 -4
- package/dist/testing/index.js.map +1 -1
- package/dist/tracing/index.d.ts +89 -0
- package/dist/tracing/index.d.ts.map +1 -0
- package/dist/tracing/index.js +101 -0
- package/dist/tracing/index.js.map +1 -0
- package/dist/uploads/client.d.ts +1 -1
- package/dist/uploads/client.d.ts.map +1 -1
- package/dist/uploads/index.d.ts +2 -2
- package/dist/uploads/index.d.ts.map +1 -1
- package/dist/uploads/index.js +1 -1
- package/dist/uploads/index.js.map +1 -1
- package/package.json +24 -2
- package/src/application/index.ts +193 -10
- package/src/client/client.ts +148 -150
- package/src/client/error-messages.ts +35 -0
- package/src/client/index.ts +12 -4
- package/src/client/types.ts +44 -5
- package/src/client-only.ts +7 -0
- package/src/config/index.ts +6 -6
- package/src/contracts/catalog-errors.ts +115 -0
- package/src/contracts/contract-builder.ts +39 -76
- package/src/contracts/contract-group.ts +33 -68
- package/src/contracts/contract-like.ts +1 -1
- package/src/contracts/index.ts +24 -11
- package/src/contracts/openapi-meta.ts +55 -0
- package/src/contracts/path-template.ts +2 -2
- package/src/contracts/schema-shape.ts +75 -0
- package/src/contracts/success-status.ts +68 -0
- package/src/contracts/types.ts +32 -5
- package/src/contracts/utils.ts +5 -2
- package/src/domain/events.ts +6 -2
- package/src/domain/index.ts +3 -3
- package/src/errors/catalog.ts +9 -1
- package/src/errors/http.ts +11 -1
- package/src/errors/index.ts +4 -4
- package/src/errors/response.ts +4 -1
- package/src/events/index.ts +12 -26
- package/src/idempotency/index.ts +5 -3
- package/src/jobs/index.ts +14 -24
- package/src/notifications/index.ts +17 -27
- package/src/openapi/index.ts +73 -38
- package/src/openapi/schema-introspector.ts +68 -17
- package/src/outbox/index.ts +84 -19
- package/src/ports/audit.ts +120 -11
- package/src/ports/auth.ts +132 -0
- package/src/ports/events.ts +2 -2
- package/src/ports/index.ts +104 -35
- package/src/ports/policy.ts +50 -3
- package/src/ports/testing.ts +2220 -33
- package/src/ports/unbound.ts +64 -0
- package/src/ports/unit-of-work.ts +6 -2
- package/src/providers/index.ts +16 -3
- package/src/providers/instrumentation.ts +86 -7
- package/src/providers/metadata.ts +234 -0
- package/src/providers/provider.ts +168 -9
- package/src/schedules/index.ts +173 -23
- package/src/server/audit-context.ts +45 -0
- package/src/server/context.ts +224 -0
- package/src/server/contract-like.ts +1 -1
- package/src/server/health.ts +2 -2
- package/src/server/hooks/auth.ts +141 -51
- package/src/server/hooks/cors.ts +1 -1
- package/src/server/hooks/errors.ts +7 -4
- package/src/server/hooks/idempotency.ts +263 -0
- package/src/server/hooks/index.ts +14 -7
- package/src/server/hooks/logging.ts +3 -3
- package/src/server/hooks/rate-limit.ts +85 -17
- package/src/server/hooks.ts +1 -1
- package/src/server/http.ts +78 -51
- package/src/server/index.ts +62 -12
- package/src/server/instrumentation.ts +470 -0
- package/src/server/openapi.ts +4 -4
- package/src/server/providers/index.ts +6 -3
- package/src/server/providers/loadProviderConfig.ts +4 -4
- package/src/server/request-context.ts +116 -0
- package/src/server/server-context.ts +44 -0
- package/src/server/server.ts +886 -238
- package/src/server/types.ts +2 -2
- package/src/server/use-case-route.ts +430 -0
- package/src/server-only.ts +7 -0
- package/src/tasks/index.ts +275 -0
- package/src/testing/index.ts +1142 -6
- package/src/tracing/index.ts +176 -0
- package/src/uploads/client.ts +1 -1
- package/src/uploads/index.ts +7 -3
- package/dist/ports/mailer.d.ts +0 -6
- package/dist/ports/mailer.d.ts.map +0 -1
- package/dist/ports/mailer.js +0 -2
- package/dist/ports/mailer.js.map +0 -1
- package/dist/ports/schedules.d.ts +0 -9
- package/dist/ports/schedules.d.ts.map +0 -1
- package/dist/ports/schedules.js +0 -2
- package/dist/ports/schedules.js.map +0 -1
package/src/client/client.ts
CHANGED
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
type StandardErrorResponseBody,
|
|
11
11
|
type StandardSchema,
|
|
12
12
|
type StandardSchemaV1,
|
|
13
|
-
} from "../contracts";
|
|
14
|
-
import { isErrorResponseBody, SchemaValidationError } from "../errors";
|
|
13
|
+
} from "../contracts/index.js";
|
|
14
|
+
import { isErrorResponseBody, SchemaValidationError } from "../errors/index.js";
|
|
15
15
|
import type {
|
|
16
16
|
CallArgs,
|
|
17
17
|
ClientConfig,
|
|
@@ -21,7 +21,7 @@ import type {
|
|
|
21
21
|
InferEndpointErrorResponseByStatus,
|
|
22
22
|
InferEndpointErrorStatus,
|
|
23
23
|
InferSuccessResponse,
|
|
24
|
-
} from "./types";
|
|
24
|
+
} from "./types.js";
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Source category for a `ContractError`.
|
|
@@ -583,11 +583,10 @@ export class Endpoint<
|
|
|
583
583
|
|
|
584
584
|
try {
|
|
585
585
|
if (args.body !== undefined && args.rawBody !== undefined) {
|
|
586
|
-
throw this.createError(
|
|
587
|
-
|
|
588
|
-
"
|
|
589
|
-
|
|
590
|
-
);
|
|
586
|
+
throw this.createError({
|
|
587
|
+
code: "INVALID_REQUEST_BODY",
|
|
588
|
+
message: "Pass either body or rawBody, not both.",
|
|
589
|
+
});
|
|
591
590
|
}
|
|
592
591
|
|
|
593
592
|
const methodSupportsBody = methodSupportsRequestBody(
|
|
@@ -597,11 +596,10 @@ export class Endpoint<
|
|
|
597
596
|
(args.body !== undefined || args.rawBody !== undefined) &&
|
|
598
597
|
!methodSupportsBody
|
|
599
598
|
) {
|
|
600
|
-
throw this.createError(
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
);
|
|
599
|
+
throw this.createError({
|
|
600
|
+
code: "INVALID_REQUEST_BODY",
|
|
601
|
+
message: `Request bodies are not supported for ${this.contract.method} contracts. Use POST, PUT, or PATCH for contract request bodies.`,
|
|
602
|
+
});
|
|
605
603
|
}
|
|
606
604
|
|
|
607
605
|
let requestBody: BodyInit | undefined;
|
|
@@ -613,7 +611,7 @@ export class Endpoint<
|
|
|
613
611
|
|
|
614
612
|
if (args.body !== undefined && methodSupportsBody) {
|
|
615
613
|
let bodyToSend = args.body;
|
|
616
|
-
if (this.config.
|
|
614
|
+
if (this.config.validateInput && this.contract.body) {
|
|
617
615
|
try {
|
|
618
616
|
bodyToSend = (await validateSchema(
|
|
619
617
|
this.contract.body,
|
|
@@ -621,12 +619,11 @@ export class Endpoint<
|
|
|
621
619
|
)) as typeof bodyToSend;
|
|
622
620
|
} catch (err) {
|
|
623
621
|
if (err instanceof SchemaValidationError) {
|
|
624
|
-
throw this.createError(
|
|
625
|
-
|
|
626
|
-
"
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
);
|
|
622
|
+
throw this.createError({
|
|
623
|
+
code: "INPUT_VALIDATION_ERROR",
|
|
624
|
+
message: "Body validation failed",
|
|
625
|
+
details: err.issues,
|
|
626
|
+
});
|
|
630
627
|
}
|
|
631
628
|
throw err;
|
|
632
629
|
}
|
|
@@ -643,19 +640,28 @@ export class Endpoint<
|
|
|
643
640
|
args.headers as Record<string, string> | undefined,
|
|
644
641
|
requestBodyType === "json",
|
|
645
642
|
);
|
|
646
|
-
|
|
643
|
+
const idempotencyMeta = this.contract.metadata?.idempotency;
|
|
644
|
+
if (idempotencyMeta) {
|
|
645
|
+
const idempotencyHeader = (
|
|
646
|
+
idempotencyMeta.header ?? "idempotency-key"
|
|
647
|
+
).toLowerCase();
|
|
648
|
+
if (!headers[idempotencyHeader]) {
|
|
649
|
+
headers[idempotencyHeader] =
|
|
650
|
+
args.idempotencyKey ?? crypto.randomUUID();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (this.config.validateInput) {
|
|
647
654
|
const headerSchemas = getContractHeaderSchemas(this.contract.headers);
|
|
648
655
|
if (headerSchemas.length > 0) {
|
|
649
656
|
try {
|
|
650
657
|
headers = await validateHeaderSchemas(headerSchemas, headers);
|
|
651
658
|
} catch (err) {
|
|
652
659
|
if (err instanceof SchemaValidationError) {
|
|
653
|
-
throw this.createError(
|
|
654
|
-
|
|
655
|
-
"
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
);
|
|
660
|
+
throw this.createError({
|
|
661
|
+
code: "INPUT_VALIDATION_ERROR",
|
|
662
|
+
message: "Headers validation failed",
|
|
663
|
+
details: err.issues,
|
|
664
|
+
});
|
|
659
665
|
}
|
|
660
666
|
throw err;
|
|
661
667
|
}
|
|
@@ -674,6 +680,7 @@ export class Endpoint<
|
|
|
674
680
|
}
|
|
675
681
|
|
|
676
682
|
const response = await fetchFn(url, options);
|
|
683
|
+
const shouldValidateResponses = this.config.validateResponses !== false;
|
|
677
684
|
|
|
678
685
|
// Handle non-2xx responses
|
|
679
686
|
if (!response.ok) {
|
|
@@ -682,35 +689,34 @@ export class Endpoint<
|
|
|
682
689
|
errorBody = await parseResponseBody(response);
|
|
683
690
|
} catch (parseErr) {
|
|
684
691
|
// JSON parse failed — still report the HTTP error
|
|
685
|
-
throw this.createError(
|
|
686
|
-
response.status,
|
|
687
|
-
"INVALID_JSON",
|
|
688
|
-
createInvalidJsonMessage("error", response.status),
|
|
689
|
-
|
|
690
|
-
parseErr,
|
|
691
|
-
undefined,
|
|
692
|
+
throw this.createError({
|
|
693
|
+
status: response.status,
|
|
694
|
+
code: "INVALID_JSON",
|
|
695
|
+
message: createInvalidJsonMessage("error", response.status),
|
|
696
|
+
cause: parseErr,
|
|
692
697
|
response,
|
|
693
|
-
"contract",
|
|
694
|
-
);
|
|
698
|
+
source: "contract",
|
|
699
|
+
});
|
|
695
700
|
}
|
|
696
701
|
|
|
697
|
-
const validatedError =
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
+
const validatedError = shouldValidateResponses
|
|
703
|
+
? await validateErrorBodyOrStandardEnvelope(
|
|
704
|
+
this.contract,
|
|
705
|
+
response,
|
|
706
|
+
errorBody,
|
|
707
|
+
)
|
|
708
|
+
: errorBody;
|
|
702
709
|
|
|
703
710
|
const errorPayload = getErrorPayload(validatedError);
|
|
704
|
-
throw this.createError(
|
|
705
|
-
response.status,
|
|
706
|
-
errorPayload.code || "HTTP_ERROR",
|
|
707
|
-
errorPayload.message || response.statusText,
|
|
708
|
-
errorPayload.details,
|
|
709
|
-
|
|
710
|
-
validatedError,
|
|
711
|
+
throw this.createError({
|
|
712
|
+
status: response.status,
|
|
713
|
+
code: errorPayload.code || "HTTP_ERROR",
|
|
714
|
+
message: errorPayload.message || response.statusText,
|
|
715
|
+
details: errorPayload.details,
|
|
716
|
+
body: validatedError,
|
|
711
717
|
response,
|
|
712
|
-
"http",
|
|
713
|
-
);
|
|
718
|
+
source: "http",
|
|
719
|
+
});
|
|
714
720
|
}
|
|
715
721
|
|
|
716
722
|
// Parse response
|
|
@@ -718,71 +724,68 @@ export class Endpoint<
|
|
|
718
724
|
try {
|
|
719
725
|
data = await parseResponseBody(response);
|
|
720
726
|
} catch (parseErr) {
|
|
721
|
-
throw this.createError(
|
|
722
|
-
response.status,
|
|
723
|
-
"INVALID_JSON",
|
|
724
|
-
createInvalidJsonMessage("success", response.status),
|
|
725
|
-
|
|
726
|
-
parseErr,
|
|
727
|
-
undefined,
|
|
727
|
+
throw this.createError({
|
|
728
|
+
status: response.status,
|
|
729
|
+
code: "INVALID_JSON",
|
|
730
|
+
message: createInvalidJsonMessage("success", response.status),
|
|
731
|
+
cause: parseErr,
|
|
728
732
|
response,
|
|
729
|
-
"contract",
|
|
730
|
-
);
|
|
733
|
+
source: "contract",
|
|
734
|
+
});
|
|
731
735
|
}
|
|
732
736
|
|
|
733
737
|
// Validate response if schema exists for this status
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
if (
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
response,
|
|
754
|
-
"contract",
|
|
755
|
-
);
|
|
756
|
-
}
|
|
757
|
-
} else if (hasSchema && responseSchema) {
|
|
758
|
-
try {
|
|
759
|
-
data = await validateSchema(responseSchema, data);
|
|
760
|
-
} catch (err) {
|
|
761
|
-
if (err instanceof SchemaValidationError) {
|
|
762
|
-
throw this.createError(
|
|
763
|
-
response.status,
|
|
764
|
-
"RESPONSE_VALIDATION_ERROR",
|
|
765
|
-
`Response validation failed for ${this.contract.method} ${this.contract.path} (status ${response.status}, contract: ${this.contract.name})`,
|
|
766
|
-
err.issues,
|
|
767
|
-
err,
|
|
768
|
-
data,
|
|
738
|
+
if (shouldValidateResponses) {
|
|
739
|
+
const statusKey = String(response.status);
|
|
740
|
+
const hasSchema = statusKey in this.contract.responses;
|
|
741
|
+
const hasDeclaredResponses =
|
|
742
|
+
Object.keys(this.contract.responses).length > 0;
|
|
743
|
+
const responseSchema = this.contract.responses[response.status];
|
|
744
|
+
if (hasSchema && responseSchema === null) {
|
|
745
|
+
if (data !== undefined && data !== null) {
|
|
746
|
+
throw this.createError({
|
|
747
|
+
status: response.status,
|
|
748
|
+
code: "RESPONSE_VALIDATION_ERROR",
|
|
749
|
+
message: `Response validation failed for ${this.contract.method} ${this.contract.path} (status ${response.status}, contract: ${this.contract.name})`,
|
|
750
|
+
details: [
|
|
751
|
+
{
|
|
752
|
+
message:
|
|
753
|
+
"Response body must be empty for a null response schema.",
|
|
754
|
+
},
|
|
755
|
+
],
|
|
756
|
+
body: data,
|
|
769
757
|
response,
|
|
770
|
-
"contract",
|
|
771
|
-
);
|
|
758
|
+
source: "contract",
|
|
759
|
+
});
|
|
772
760
|
}
|
|
773
|
-
|
|
761
|
+
} else if (hasSchema && responseSchema) {
|
|
762
|
+
try {
|
|
763
|
+
data = await validateSchema(responseSchema, data);
|
|
764
|
+
} catch (err) {
|
|
765
|
+
if (err instanceof SchemaValidationError) {
|
|
766
|
+
throw this.createError({
|
|
767
|
+
status: response.status,
|
|
768
|
+
code: "RESPONSE_VALIDATION_ERROR",
|
|
769
|
+
message: `Response validation failed for ${this.contract.method} ${this.contract.path} (status ${response.status}, contract: ${this.contract.name})`,
|
|
770
|
+
details: err.issues,
|
|
771
|
+
cause: err,
|
|
772
|
+
body: data,
|
|
773
|
+
response,
|
|
774
|
+
source: "contract",
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
throw err;
|
|
778
|
+
}
|
|
779
|
+
} else if (!hasSchema && hasDeclaredResponses) {
|
|
780
|
+
throw this.createError({
|
|
781
|
+
status: response.status,
|
|
782
|
+
code: "UNDECLARED_RESPONSE_STATUS",
|
|
783
|
+
message: `Server returned undeclared status ${response.status} for ${this.contract.method} ${this.contract.path} (contract: ${this.contract.name})`,
|
|
784
|
+
body: data,
|
|
785
|
+
response,
|
|
786
|
+
source: "contract",
|
|
787
|
+
});
|
|
774
788
|
}
|
|
775
|
-
} else if (!hasSchema && hasDeclaredResponses) {
|
|
776
|
-
throw this.createError(
|
|
777
|
-
response.status,
|
|
778
|
-
"UNDECLARED_RESPONSE_STATUS",
|
|
779
|
-
`Server returned undeclared status ${response.status} for ${this.contract.method} ${this.contract.path} (contract: ${this.contract.name})`,
|
|
780
|
-
undefined,
|
|
781
|
-
undefined,
|
|
782
|
-
data,
|
|
783
|
-
response,
|
|
784
|
-
"contract",
|
|
785
|
-
);
|
|
786
789
|
}
|
|
787
790
|
|
|
788
791
|
return {
|
|
@@ -801,16 +804,12 @@ export class Endpoint<
|
|
|
801
804
|
response: error.response,
|
|
802
805
|
};
|
|
803
806
|
}
|
|
804
|
-
const error = this.createError(
|
|
805
|
-
|
|
806
|
-
"
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
undefined,
|
|
811
|
-
undefined,
|
|
812
|
-
"network",
|
|
813
|
-
) as InferEndpointContractError<TContract>;
|
|
807
|
+
const error = this.createError({
|
|
808
|
+
code: "NETWORK_ERROR",
|
|
809
|
+
message: err instanceof Error ? err.message : "Network request failed",
|
|
810
|
+
cause: err,
|
|
811
|
+
source: "network",
|
|
812
|
+
}) as InferEndpointContractError<TContract>;
|
|
814
813
|
return {
|
|
815
814
|
ok: false,
|
|
816
815
|
status: error.status,
|
|
@@ -843,7 +842,7 @@ export class Endpoint<
|
|
|
843
842
|
// Replace path parameters
|
|
844
843
|
if (path && parsedPath.keys.length > 0) {
|
|
845
844
|
// Validate path params if schema exists and validation is enabled
|
|
846
|
-
if (this.config.
|
|
845
|
+
if (this.config.validateInput && this.contract.pathParams) {
|
|
847
846
|
try {
|
|
848
847
|
pathToSerialize = (await validateSchema(
|
|
849
848
|
this.contract.pathParams,
|
|
@@ -851,12 +850,11 @@ export class Endpoint<
|
|
|
851
850
|
)) as PathParams;
|
|
852
851
|
} catch (err) {
|
|
853
852
|
if (err instanceof SchemaValidationError) {
|
|
854
|
-
throw this.createError(
|
|
855
|
-
|
|
856
|
-
"
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
);
|
|
853
|
+
throw this.createError({
|
|
854
|
+
code: "INPUT_VALIDATION_ERROR",
|
|
855
|
+
message: "Path params validation failed",
|
|
856
|
+
details: err.issues,
|
|
857
|
+
});
|
|
860
858
|
}
|
|
861
859
|
throw err;
|
|
862
860
|
}
|
|
@@ -894,7 +892,7 @@ export class Endpoint<
|
|
|
894
892
|
let queryToSerialize = query;
|
|
895
893
|
if (query) {
|
|
896
894
|
// Validate query params if schema exists and validation is enabled
|
|
897
|
-
if (this.config.
|
|
895
|
+
if (this.config.validateInput && this.contract.query) {
|
|
898
896
|
try {
|
|
899
897
|
queryToSerialize = (await validateSchema(
|
|
900
898
|
this.contract.query,
|
|
@@ -902,12 +900,11 @@ export class Endpoint<
|
|
|
902
900
|
)) as QueryParams;
|
|
903
901
|
} catch (err) {
|
|
904
902
|
if (err instanceof SchemaValidationError) {
|
|
905
|
-
throw this.createError(
|
|
906
|
-
|
|
907
|
-
"
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
);
|
|
903
|
+
throw this.createError({
|
|
904
|
+
code: "INPUT_VALIDATION_ERROR",
|
|
905
|
+
message: "Query params validation failed",
|
|
906
|
+
details: err.issues,
|
|
907
|
+
});
|
|
911
908
|
}
|
|
912
909
|
throw err;
|
|
913
910
|
}
|
|
@@ -987,26 +984,27 @@ export class Endpoint<
|
|
|
987
984
|
/**
|
|
988
985
|
* Create a contract error
|
|
989
986
|
*/
|
|
990
|
-
private createError(
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
details?: unknown
|
|
995
|
-
cause?: unknown
|
|
996
|
-
body?: unknown
|
|
997
|
-
response?: Response
|
|
998
|
-
source
|
|
999
|
-
): AnyContractError {
|
|
987
|
+
private createError(options: {
|
|
988
|
+
code: string;
|
|
989
|
+
message: string;
|
|
990
|
+
status?: number;
|
|
991
|
+
details?: unknown;
|
|
992
|
+
cause?: unknown;
|
|
993
|
+
body?: unknown;
|
|
994
|
+
response?: Response;
|
|
995
|
+
source?: ContractErrorSource;
|
|
996
|
+
}): AnyContractError {
|
|
997
|
+
const source = options.source ?? "client";
|
|
998
|
+
const isLocalError = source === "client" || source === "network";
|
|
1000
999
|
return new ContractError({
|
|
1001
1000
|
source,
|
|
1002
|
-
status:
|
|
1003
|
-
code,
|
|
1004
|
-
message,
|
|
1005
|
-
body:
|
|
1006
|
-
details,
|
|
1007
|
-
response:
|
|
1008
|
-
|
|
1009
|
-
cause,
|
|
1001
|
+
status: isLocalError ? undefined : options.status,
|
|
1002
|
+
code: options.code,
|
|
1003
|
+
message: options.message,
|
|
1004
|
+
body: isLocalError ? undefined : options.body,
|
|
1005
|
+
details: options.details,
|
|
1006
|
+
response: isLocalError ? undefined : options.response,
|
|
1007
|
+
cause: options.cause,
|
|
1010
1008
|
}) as AnyContractError;
|
|
1011
1009
|
}
|
|
1012
1010
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { isContractError } from "./client.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* User-facing copy overrides keyed by error code.
|
|
5
|
+
*/
|
|
6
|
+
export type ErrorMessageOverrides = Partial<Record<string, string>>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Map an unknown error to user-facing copy.
|
|
10
|
+
*
|
|
11
|
+
* Non-`ContractError` values return the fallback. Override copy per catalog
|
|
12
|
+
* code with `overrides`. Client-side input validation failures return a
|
|
13
|
+
* generic "check the highlighted fields" message; other contract errors
|
|
14
|
+
* return the error message.
|
|
15
|
+
*/
|
|
16
|
+
export function contractErrorMessage(
|
|
17
|
+
error: unknown,
|
|
18
|
+
fallback: string,
|
|
19
|
+
overrides: ErrorMessageOverrides = {},
|
|
20
|
+
): string {
|
|
21
|
+
if (!isContractError(error)) {
|
|
22
|
+
return fallback;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const override = error.code ? overrides[error.code] : undefined;
|
|
26
|
+
if (override) {
|
|
27
|
+
return override;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (error.hasSource("client") && error.hasCode("INPUT_VALIDATION_ERROR")) {
|
|
31
|
+
return "Check the highlighted fields and try again.";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return error.message;
|
|
35
|
+
}
|
package/src/client/index.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* Schema validation error re-exported for client users.
|
|
9
9
|
*/
|
|
10
|
-
export { SchemaValidationError } from "../errors";
|
|
10
|
+
export { SchemaValidationError } from "../errors/index.js";
|
|
11
11
|
/**
|
|
12
12
|
* Contract client error types.
|
|
13
13
|
*/
|
|
@@ -23,7 +23,7 @@ export type {
|
|
|
23
23
|
InferEndpointErrorCode,
|
|
24
24
|
NetworkContractError,
|
|
25
25
|
ResponseContractError,
|
|
26
|
-
} from "./client";
|
|
26
|
+
} from "./client.js";
|
|
27
27
|
/**
|
|
28
28
|
* Contract client runtime helpers.
|
|
29
29
|
*/
|
|
@@ -33,11 +33,19 @@ export {
|
|
|
33
33
|
createClient,
|
|
34
34
|
Endpoint,
|
|
35
35
|
isContractError,
|
|
36
|
-
} from "./client";
|
|
36
|
+
} from "./client.js";
|
|
37
|
+
/**
|
|
38
|
+
* Client error message helpers.
|
|
39
|
+
*/
|
|
40
|
+
export {
|
|
41
|
+
contractErrorMessage,
|
|
42
|
+
type ErrorMessageOverrides,
|
|
43
|
+
} from "./error-messages.js";
|
|
37
44
|
/**
|
|
38
45
|
* Contract client inference and call types.
|
|
39
46
|
*/
|
|
40
47
|
export type {
|
|
48
|
+
AutoProvidedHeaders,
|
|
41
49
|
CallArgs,
|
|
42
50
|
ClientConfig,
|
|
43
51
|
EndpointCallArgs,
|
|
@@ -54,4 +62,4 @@ export type {
|
|
|
54
62
|
InferPathParams,
|
|
55
63
|
InferQuery,
|
|
56
64
|
InferSuccessResponse,
|
|
57
|
-
} from "./types";
|
|
65
|
+
} from "./types.js";
|
package/src/client/types.ts
CHANGED
|
@@ -6,8 +6,8 @@ import type {
|
|
|
6
6
|
InferOutput,
|
|
7
7
|
StandardSchema,
|
|
8
8
|
StandardSchemaV1,
|
|
9
|
-
} from "../contracts";
|
|
10
|
-
import type { ErrorResponseBody } from "../errors";
|
|
9
|
+
} from "../contracts/index.js";
|
|
10
|
+
import type { ErrorResponseBody } from "../errors/index.js";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Configuration for a Beignet contract client.
|
|
@@ -29,8 +29,20 @@ export type ClientConfig<TProvidedHeaders extends string = never> = {
|
|
|
29
29
|
* Fetch implementation. Defaults to global `fetch`.
|
|
30
30
|
*/
|
|
31
31
|
fetch?: typeof fetch;
|
|
32
|
-
/**
|
|
33
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Validate path params, query params, request bodies, and declared request
|
|
34
|
+
* headers against contract schemas before sending. Failures throw a
|
|
35
|
+
* client-source `ContractError` with code `INPUT_VALIDATION_ERROR`.
|
|
36
|
+
* Default: false.
|
|
37
|
+
*/
|
|
38
|
+
validateInput?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Validate response bodies (success and declared error responses) against
|
|
41
|
+
* contract schemas. Disabling this returns success bodies as-is and skips
|
|
42
|
+
* contract-drift checks such as undeclared response statuses.
|
|
43
|
+
* Default: true.
|
|
44
|
+
*/
|
|
45
|
+
validateResponses?: boolean;
|
|
34
46
|
};
|
|
35
47
|
|
|
36
48
|
type PathParamPrimitive = string | number | boolean;
|
|
@@ -300,6 +312,25 @@ type ProvidedHeaderKeys<THeaders, TProvidedHeaders extends string> = Extract<
|
|
|
300
312
|
TProvidedHeaders
|
|
301
313
|
>;
|
|
302
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Header names the client fills in automatically from contract metadata.
|
|
317
|
+
*
|
|
318
|
+
* Contracts with idempotency metadata get their idempotency key header
|
|
319
|
+
* generated per call, so typed calls may omit it. When the metadata header
|
|
320
|
+
* name is widened to `string`, only the default `idempotency-key` header is
|
|
321
|
+
* treated as auto-provided so other required headers stay required.
|
|
322
|
+
*/
|
|
323
|
+
export type AutoProvidedHeaders<TContract extends HttpContractConfig> =
|
|
324
|
+
TContract["metadata"] extends { idempotency: infer M }
|
|
325
|
+
? M extends { header: infer H extends string }
|
|
326
|
+
? string extends H
|
|
327
|
+
? "idempotency-key"
|
|
328
|
+
: Lowercase<H>
|
|
329
|
+
: M extends object
|
|
330
|
+
? "idempotency-key"
|
|
331
|
+
: never
|
|
332
|
+
: never;
|
|
333
|
+
|
|
303
334
|
type ApplyProvidedHeaders<THeaders, TProvidedHeaders extends string> = Omit<
|
|
304
335
|
THeaders,
|
|
305
336
|
ProvidedHeaderKeys<THeaders, TProvidedHeaders>
|
|
@@ -312,7 +343,10 @@ type HeaderInput<
|
|
|
312
343
|
> =
|
|
313
344
|
InferHeaders<TContract> extends undefined
|
|
314
345
|
? Record<string, string>
|
|
315
|
-
: ApplyProvidedHeaders<
|
|
346
|
+
: ApplyProvidedHeaders<
|
|
347
|
+
InferHeaders<TContract>,
|
|
348
|
+
TProvidedHeaders | AutoProvidedHeaders<TContract>
|
|
349
|
+
>;
|
|
316
350
|
|
|
317
351
|
type HeadersArgs<
|
|
318
352
|
TContract extends HttpContractConfig,
|
|
@@ -341,6 +375,11 @@ export type EndpointCallArgs<
|
|
|
341
375
|
* and is not validated or JSON-serialized.
|
|
342
376
|
*/
|
|
343
377
|
rawBody?: TContract["method"] extends BodyHttpMethod ? BodyInit : never;
|
|
378
|
+
/**
|
|
379
|
+
* Idempotency key to send instead of an auto-generated one. Use for
|
|
380
|
+
* retry-with-same-key flows on contracts with idempotency metadata.
|
|
381
|
+
*/
|
|
382
|
+
idempotencyKey?: string;
|
|
344
383
|
/**
|
|
345
384
|
* Abort signal passed to fetch.
|
|
346
385
|
*/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static Beignet lint marker for modules intended for client-side imports.
|
|
3
|
+
*
|
|
4
|
+
* Host frameworks may provide their own runtime-only enforcement. This marker
|
|
5
|
+
* is intentionally a no-op so Beignet can enforce intent through `beignet lint`.
|
|
6
|
+
*/
|
|
7
|
+
export const beignetClientOnly = true;
|
package/src/config/index.ts
CHANGED
|
@@ -96,9 +96,9 @@ export interface ReadEnvOptions {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
* Options for
|
|
99
|
+
* Options for creating a single validated env loader.
|
|
100
100
|
*/
|
|
101
|
-
export interface
|
|
101
|
+
export interface CreateEnvLoaderOptions<Schema extends StandardSchemaV1> {
|
|
102
102
|
/**
|
|
103
103
|
* Standard Schema for validating the full environment object.
|
|
104
104
|
*/
|
|
@@ -133,7 +133,7 @@ export interface DefineEnvOptions<Schema extends StandardSchemaV1> {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
|
-
* Validated env loader returned by `
|
|
136
|
+
* Validated env loader returned by `createEnvLoader(...)`.
|
|
137
137
|
*/
|
|
138
138
|
export interface EnvInstance<Out> {
|
|
139
139
|
/**
|
|
@@ -396,13 +396,13 @@ function wrapEnvError(err: unknown, prefix?: string): Error {
|
|
|
396
396
|
}
|
|
397
397
|
|
|
398
398
|
/**
|
|
399
|
-
*
|
|
399
|
+
* Create a reusable validated env loader.
|
|
400
400
|
*
|
|
401
401
|
* This is useful for provider config and app-level config objects that are
|
|
402
402
|
* loaded from a prefixed subset of the environment.
|
|
403
403
|
*/
|
|
404
|
-
export function
|
|
405
|
-
options:
|
|
404
|
+
export function createEnvLoader<Schema extends StandardSchemaV1>(
|
|
405
|
+
options: CreateEnvLoaderOptions<Schema>,
|
|
406
406
|
): EnvInstance<InferOutput<Schema>> {
|
|
407
407
|
const {
|
|
408
408
|
schema,
|