@temporary-name/server 1.9.3-alpha.6a70825f6d8c3dc99b87e4e5b778aea0fa007417 → 1.9.3-alpha.6a735c9469d995338b7d51335ea70485e18a4dca

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.
Files changed (45) hide show
  1. package/dist/adapters/aws-lambda/index.d.mts +5 -7
  2. package/dist/adapters/aws-lambda/index.d.ts +5 -7
  3. package/dist/adapters/aws-lambda/index.mjs +4 -6
  4. package/dist/adapters/fetch/index.d.mts +8 -86
  5. package/dist/adapters/fetch/index.d.ts +8 -86
  6. package/dist/adapters/fetch/index.mjs +16 -157
  7. package/dist/adapters/node/index.d.mts +9 -64
  8. package/dist/adapters/node/index.d.ts +9 -64
  9. package/dist/adapters/node/index.mjs +14 -122
  10. package/dist/{adapters/standard → handler}/index.d.mts +5 -7
  11. package/dist/{adapters/standard → handler}/index.d.ts +5 -7
  12. package/dist/handler/index.mjs +8 -0
  13. package/dist/helpers/index.mjs +3 -29
  14. package/dist/index.d.mts +368 -202
  15. package/dist/index.d.ts +368 -202
  16. package/dist/index.mjs +462 -176
  17. package/dist/openapi/index.d.mts +18 -53
  18. package/dist/openapi/index.d.ts +18 -53
  19. package/dist/openapi/index.mjs +340 -369
  20. package/dist/shared/server.BCY45g2x.mjs +160 -0
  21. package/dist/shared/server.BETu17rq.mjs +319 -0
  22. package/dist/shared/server.B_oW_rPl.mjs +525 -0
  23. package/dist/shared/server.C1RJffw4.mjs +30 -0
  24. package/dist/shared/server.CjPiuQYH.d.mts +51 -0
  25. package/dist/shared/server.CjPiuQYH.d.ts +51 -0
  26. package/dist/shared/server.CunymBH3.d.mts +39 -0
  27. package/dist/shared/server.DGMnYd7G.d.ts +39 -0
  28. package/dist/shared/server.xNz5cP2B.mjs +321 -0
  29. package/dist/shared/server.zsKBRxsz.d.mts +388 -0
  30. package/dist/shared/server.zsKBRxsz.d.ts +388 -0
  31. package/package.json +13 -31
  32. package/dist/adapters/standard/index.mjs +0 -10
  33. package/dist/plugins/index.d.mts +0 -160
  34. package/dist/plugins/index.d.ts +0 -160
  35. package/dist/plugins/index.mjs +0 -288
  36. package/dist/shared/server.BCcLYvdF.d.mts +0 -56
  37. package/dist/shared/server.CHV9AQHl.mjs +0 -412
  38. package/dist/shared/server.CdeqmULw.d.ts +0 -56
  39. package/dist/shared/server.DHezmW6C.d.mts +0 -23
  40. package/dist/shared/server.DN9mVGfv.mjs +0 -11
  41. package/dist/shared/server.DWwaAM-a.mjs +0 -255
  42. package/dist/shared/server.Da-qLzdU.d.ts +0 -23
  43. package/dist/shared/server.DecvGKtb.d.mts +0 -242
  44. package/dist/shared/server.DecvGKtb.d.ts +0 -242
  45. package/dist/shared/server.JtIZ8YG7.mjs +0 -237
package/dist/index.mjs CHANGED
@@ -1,12 +1,79 @@
1
- import { mergePrefix, mergeTags, ContractProcedure, mergeErrorMap, mergeMeta, mergeRoute, prefixRoute, initialSchemas, isContractProcedure, getContractRouter } from '@temporary-name/contract';
2
- export { ValidationError, eventIterator, validateORPCError } from '@temporary-name/contract';
3
- import { onError, resolveMaybeOptionalOptions } from '@temporary-name/shared';
4
- export { AsyncIteratorClass, EventPublisher, ORPCError, asyncIteratorToStream as eventIteratorToStream, isDefinedError, onError, onFinish, onStart, onSuccess, safe, streamToAsyncIteratorClass as streamToEventIterator } from '@temporary-name/shared';
5
- import { SchemaClass, core, object, gatingContext } from '@temporary-name/zod';
1
+ import { assertNever, splitFirst, ORPCError, onError, isObject, toArray, guard, resolveMaybeOptionalOptions, isTypescriptObject, isPropertyKey } from '@temporary-name/shared';
2
+ export { AsyncIteratorClass, EventPublisher, ORPCError, asyncIteratorToStream as eventIteratorToStream, isDefinedError, onError, onFinish, onStart, onSuccess, streamToAsyncIteratorClass as streamToEventIterator } from '@temporary-name/shared';
3
+ import * as z from '@temporary-name/zod';
4
+ import { SchemaClass, object, core, gatingContext } from '@temporary-name/zod';
5
+ import { g as getCookie } from './shared/server.C1RJffw4.mjs';
6
+ import { P as Procedure, m as mergePrefix, a as mergeTags, e as enhanceRouter, C as Contract, p as parseEndpointDefinition, b as mergeRoute, c as prefixRoute, d as addMiddleware, l as lazyInternal, f as getLazyMeta, u as unlazy, i as isProcedure } from './shared/server.BETu17rq.mjs';
7
+ export { L as LAZY_SYMBOL, V as ValidationError, q as createAccessibleLazyRouter, w as endpointRegex, g as getDynamicParams, o as getRouter, j as isLazy, k as isStartWithMiddlewares, h as lazy, n as mergeMiddlewares, r as resolveContractProcedures, s as standardizeHTTPPath, t as traverseContractProcedures, v as unlazyRouter } from './shared/server.BETu17rq.mjs';
8
+ import { c as createProcedureClient } from './shared/server.BCY45g2x.mjs';
9
+ export { m as mergeCurrentContext, a as middlewareOutputFn } from './shared/server.BCY45g2x.mjs';
10
+ import { J as JsonSchemaXNativeType } from './shared/server.B_oW_rPl.mjs';
11
+ export { b as JSON_SCHEMA_INPUT_REGISTRY, c as JSON_SCHEMA_OUTPUT_REGISTRY, a as JSON_SCHEMA_REGISTRY, Z as ZodToJsonSchemaConverter, e as eventIterator, g as getEventIteratorSchemaDetails } from './shared/server.B_oW_rPl.mjs';
6
12
  export { getEventMeta, withEventMeta } from '@temporary-name/standard-server';
7
- import { g as getDynamicParams } from './shared/server.DN9mVGfv.mjs';
8
- import { P as Procedure, c as createProcedureClient, e as enhanceRouter, a as addMiddleware, s as setHiddenRouterContract, l as lazyInternal, g as getLazyMeta, u as unlazy, i as isProcedure, b as isLazy, d as getRouter } from './shared/server.CHV9AQHl.mjs';
9
- export { L as LAZY_SYMBOL, p as createAccessibleLazyRouter, f as createORPCErrorConstructorMap, o as getHiddenRouterContract, k as isStartWithMiddlewares, h as lazy, m as mergeCurrentContext, n as mergeMiddlewares, j as middlewareOutputFn, r as resolveContractProcedures, t as traverseContractProcedures, q as unlazyRouter } from './shared/server.CHV9AQHl.mjs';
13
+ import 'cookie';
14
+ import '@temporary-name/server/openapi';
15
+ import 'zod/v4/core';
16
+
17
+ function validateTokenPrefix(prefix, token) {
18
+ if (prefix && !token.startsWith(prefix)) {
19
+ throw new ORPCError("UNAUTHORIZED", { message: `Invalid auth token. It must start with "${prefix}"` });
20
+ }
21
+ }
22
+ function validateTokenAuth(config, token, options) {
23
+ const { tokenPrefix, validate } = config;
24
+ validateTokenPrefix(tokenPrefix, token);
25
+ return validate(token, options);
26
+ }
27
+ function runAuth(config, options) {
28
+ switch (config.type) {
29
+ case "header": {
30
+ const authHeader = options.request.headers.get(config.name);
31
+ return authHeader ? validateTokenAuth(config, authHeader, options) : void 0;
32
+ }
33
+ case "query": {
34
+ const { name, tokenPrefix, validate } = config;
35
+ const query = options.request.url.searchParams;
36
+ const token = query.get(name);
37
+ if (!token) return void 0;
38
+ validateTokenPrefix(tokenPrefix, token);
39
+ return validate(token, options);
40
+ }
41
+ case "cookie": {
42
+ const cookie = getCookie(options.request.headers, config.name);
43
+ return cookie ? validateTokenAuth(config, cookie, options) : void 0;
44
+ }
45
+ case "bearer": {
46
+ const authHeader = options.request.headers.get("Authorization");
47
+ if (!authHeader) return void 0;
48
+ const [authType, bearer] = splitFirst(authHeader, " ");
49
+ return authType === "Bearer" ? validateTokenAuth(config, bearer, options) : void 0;
50
+ }
51
+ case "basic": {
52
+ const authHeader = options.request.headers.get("Authorization");
53
+ if (!authHeader) return void 0;
54
+ const [authType, encoded] = splitFirst(authHeader, " ");
55
+ if (authType !== "Basic") return void 0;
56
+ const decoded = Buffer.from(encoded, "base64").toString("utf-8");
57
+ const [username, password] = splitFirst(decoded, ":");
58
+ validateTokenPrefix(config.tokenPrefix, password);
59
+ return config.validate(username, password, options);
60
+ }
61
+ case "none": {
62
+ return false;
63
+ }
64
+ default: {
65
+ assertNever(config);
66
+ }
67
+ }
68
+ }
69
+ function authDescription(config) {
70
+ const { type } = config;
71
+ return type === "basic" ? "a Basic Authentication header" : type === "bearer" ? "a Bearer Authentication header" : type === "header" ? `a header named "${config.name}"` : type === "query" ? `a query parameter named "${config.name}"` : type === "cookie" ? `a cookie named "${config.name}"` : type === "none" ? "no authentication" : assertNever(type);
72
+ }
73
+
74
+ function mergeMeta(meta1, meta2) {
75
+ return { ...meta1, ...meta2 };
76
+ }
10
77
 
11
78
  class DecoratedProcedure extends Procedure {
12
79
  /**
@@ -27,24 +94,19 @@ class DecoratedProcedure extends Procedure {
27
94
  }
28
95
  }
29
96
 
30
- class ProcedureBuilder extends ContractProcedure {
97
+ const initialSchemas = {
98
+ pathSchema: z.strictObject({}),
99
+ querySchema: z.strictObject({}),
100
+ bodySchema: z.strictObject({}),
101
+ outputSchema: z.unknown()
102
+ };
103
+
104
+ class ProcedureBuilder extends Contract {
31
105
  z;
32
106
  constructor(def) {
33
107
  super(def);
34
108
  this.z = new SchemaClass();
35
109
  }
36
- /**
37
- * Adds type-safe custom errors to the contract.
38
- * The provided errors are spared-merged with any existing errors in the contract.
39
- *
40
- * @see {@link https://orpc.unnoq.com/docs/error-handling#type%E2%80%90safe-error-handling Type-Safe Error Handling Docs}
41
- */
42
- errors(errors) {
43
- return new ProcedureBuilder({
44
- ...this["~orpc"],
45
- errorMap: mergeErrorMap(this["~orpc"].errorMap, errors)
46
- });
47
- }
48
110
  /**
49
111
  * Sets or updates the metadata for the contract.
50
112
  * The provided metadata is spared-merged with any existing metadata in the contract.
@@ -57,16 +119,8 @@ class ProcedureBuilder extends ContractProcedure {
57
119
  meta: mergeMeta(this["~orpc"].meta, meta)
58
120
  });
59
121
  }
60
- endpoint(endpoint, schema) {
61
- const [method, path] = endpoint.split(" ", 2);
62
- const pathParamNames = getDynamicParams(path)?.map((p) => p.name) ?? [];
63
- if (schema && !(schema instanceof core.$ZodObject)) {
64
- throw new Error(`Path schema for endpoint "${endpoint}" must be a ZodObject schema.`);
65
- }
66
- const schemaKeys = schema ? Object.keys(schema._zod.def.shape) : [];
67
- if (pathParamNames.length !== schemaKeys.length || !pathParamNames.every((name) => schemaKeys.includes(name))) {
68
- throw new Error(`Path schema keys do not match dynamic parameters in endpoint "${endpoint}".`);
69
- }
122
+ endpoint(stringsOrEndpoint, ...values) {
123
+ const { method, path, pathSchema } = parseEndpointDefinition(stringsOrEndpoint, values);
70
124
  const { prefix } = this["~orpc"];
71
125
  const route = { method, path };
72
126
  return new ProcedureBuilder({
@@ -74,7 +128,7 @@ class ProcedureBuilder extends ContractProcedure {
74
128
  route: mergeRoute(this["~orpc"].route, prefix ? prefixRoute(route, prefix) : route),
75
129
  schemas: {
76
130
  ...this["~orpc"].schemas,
77
- pathSchema: schema instanceof core.$ZodType ? schema : object(schema ?? {})
131
+ pathSchema
78
132
  }
79
133
  });
80
134
  }
@@ -128,19 +182,40 @@ class ProcedureBuilder extends ContractProcedure {
128
182
  outputValidationIndex: this["~orpc"].middlewares.length
129
183
  });
130
184
  }
131
- /**
132
- * Uses a middleware to modify the context or improve the pipeline.
133
- *
134
- * @info Supports both normal middleware and inline middleware implementations.
135
- * @note The current context must be satisfy middleware dependent-context
136
- * @see {@link https://orpc.unnoq.com/docs/middleware Middleware Docs}
137
- */
138
185
  use(middleware) {
139
186
  return new this.constructor({
140
187
  ...this["~orpc"],
141
188
  middlewares: addMiddleware(this["~orpc"].middlewares, middleware)
142
189
  });
143
190
  }
191
+ // The default of false for ValidatedAuthContext is used when you pass in the type 'none'. We use false
192
+ // because we can't use null or undefined (see ValidatedAuthContext) but we still want it to be falsy.
193
+ useAuth(config) {
194
+ const middleware = baseApi.$context().middleware(async (options) => {
195
+ const { next, context } = options;
196
+ if (context.auth) return next();
197
+ const auth = await runAuth(config, options);
198
+ if (auth === void 0) {
199
+ const { authConfigs } = options.procedure["~orpc"];
200
+ if (context.auth !== false && config === authConfigs.at(-1)) {
201
+ let authDescriptions = authConfigs.map(authDescription).join(", ");
202
+ if (authConfigs.length > 1) {
203
+ authDescriptions = `one of: ${authDescriptions}`;
204
+ }
205
+ throw new ORPCError("UNAUTHORIZED", {
206
+ message: `Authentication required. You must provide ${authDescriptions}`
207
+ });
208
+ }
209
+ return next();
210
+ }
211
+ return next({ context: { auth } });
212
+ });
213
+ return new this.constructor({
214
+ ...this["~orpc"],
215
+ authConfigs: [...this["~orpc"].authConfigs, config],
216
+ middlewares: addMiddleware(this["~orpc"].middlewares, middleware)
217
+ });
218
+ }
144
219
  useGating(gates, isGateEnabled) {
145
220
  return this.use(({ next, context }) => {
146
221
  return gatingContext.run(
@@ -155,6 +230,9 @@ class ProcedureBuilder extends ContractProcedure {
155
230
  * @see {@link https://orpc.unnoq.com/docs/procedure Procedure Docs}
156
231
  */
157
232
  handler(handler) {
233
+ if (this["~orpc"].schemas.outputSchema === initialSchemas.outputSchema) {
234
+ throw new Error("You must call .output() before calling .handler()");
235
+ }
158
236
  return new DecoratedProcedure({
159
237
  ...this["~orpc"],
160
238
  handler
@@ -206,31 +284,6 @@ function decorateMiddleware(middleware) {
206
284
  );
207
285
  return mapped;
208
286
  };
209
- decorated.concat = (concatMiddleware, mapInput) => {
210
- const mapped = mapInput ? decorateMiddleware(concatMiddleware).mapInput(mapInput) : concatMiddleware;
211
- const concatted = decorateMiddleware((options, input, output, ...rest) => {
212
- const merged = middleware(
213
- {
214
- ...options,
215
- next: (...[nextOptions1]) => mapped(
216
- {
217
- ...options,
218
- context: { ...options.context, ...nextOptions1?.context },
219
- next: (...[nextOptions2]) => options.next({ context: { ...nextOptions1?.context, ...nextOptions2?.context } })
220
- },
221
- input,
222
- output,
223
- ...rest
224
- )
225
- },
226
- input,
227
- output,
228
- ...rest
229
- );
230
- return merged;
231
- });
232
- return concatted;
233
- };
234
287
  return decorated;
235
288
  }
236
289
 
@@ -252,98 +305,347 @@ class Builder extends BuilderWithMiddlewares {
252
305
  return decorateMiddleware(middleware);
253
306
  }
254
307
  }
255
- function createApiBuilder(opts = {}) {
256
- return new Builder({
257
- route: {},
258
- meta: opts.meta ?? {},
259
- errorMap: {},
260
- inputValidationIndex: 0,
261
- outputValidationIndex: 0,
262
- middlewares: [
263
- onError((error, _options) => {
264
- console.dir(error, { depth: null });
265
- })
266
- ],
267
- schemas: initialSchemas,
268
- // NB: this is a relic from orpc -- I'm not convinced there's a need for this (or if there is, that it's
269
- // the best solution). For now I've removed the interface to configure it externally.
270
- dedupeLeadingMiddlewares: true
271
- });
272
- }
273
- const os = createApiBuilder();
308
+ const baseApi = new Builder({
309
+ route: {},
310
+ meta: {},
311
+ inputValidationIndex: 0,
312
+ outputValidationIndex: 0,
313
+ middlewares: [
314
+ onError((error, _options) => {
315
+ console.dir(error, { depth: null });
316
+ })
317
+ ],
318
+ schemas: initialSchemas,
319
+ // NB: this is a relic from orpc -- I'm not convinced there's a need for this (or if there is, that it's
320
+ // the best solution). For now I've removed the interface to configure it externally.
321
+ dedupeLeadingMiddlewares: true,
322
+ authConfigs: []
323
+ });
274
324
 
275
- function implementerInternal(contract, middlewares) {
276
- if (isContractProcedure(contract)) {
277
- const impl2 = new Builder({
278
- ...contract["~orpc"],
279
- middlewares,
280
- inputValidationIndex: middlewares.length,
281
- outputValidationIndex: middlewares.length,
282
- dedupeLeadingMiddlewares: true
283
- });
284
- return impl2;
325
+ const FLEXIBLE_DATE_FORMAT_REGEX = /^[^-]+-[^-]+-[^-]+$/;
326
+ class experimental_JsonSchemaCoercer {
327
+ coerce(schema, value, options = {}) {
328
+ const [, coerced] = this.#coerce(schema, value, options);
329
+ return coerced;
285
330
  }
286
- const impl = new Proxy(contract, {
287
- get: (target, key) => {
288
- if (typeof key !== "string") {
289
- return Reflect.get(target, key);
290
- }
291
- let method;
292
- if (key === "middleware") {
293
- method = (mid) => decorateMiddleware(mid);
294
- } else if (key === "use") {
295
- method = (mid) => {
296
- return implementerInternal(contract, addMiddleware(middlewares, mid));
297
- };
298
- } else if (key === "router") {
299
- method = (router) => {
300
- const adapted = enhanceRouter(router, {
301
- middlewares,
302
- errorMap: {},
303
- prefix: void 0,
304
- tags: void 0,
305
- dedupeLeadingMiddlewares: true
306
- });
307
- return setHiddenRouterContract(adapted, contract);
308
- };
331
+ #coerce(schema, originalValue, options) {
332
+ if (typeof schema === "boolean") {
333
+ return [schema, originalValue];
334
+ }
335
+ if (Array.isArray(schema.type)) {
336
+ return this.#coerce(
337
+ {
338
+ anyOf: schema.type.map((type) => ({ ...schema, type }))
339
+ },
340
+ originalValue,
341
+ options
342
+ );
343
+ }
344
+ let coerced = originalValue;
345
+ let satisfied = true;
346
+ if (typeof schema.$ref === "string") {
347
+ const refSchema = options?.components?.[schema.$ref];
348
+ if (refSchema !== void 0) {
349
+ const [subSatisfied, subCoerced] = this.#coerce(refSchema, coerced, options);
350
+ coerced = subCoerced;
351
+ satisfied = subSatisfied;
309
352
  }
310
- const next = getContractRouter(target, [key]);
311
- if (!next) {
312
- return method ?? next;
353
+ }
354
+ const enumValues = schema.const !== void 0 ? [schema.const] : schema.enum;
355
+ if (enumValues !== void 0 && !enumValues.includes(coerced)) {
356
+ if (typeof coerced === "string") {
357
+ const numberValue = this.#stringToNumber(coerced);
358
+ if (enumValues.includes(numberValue)) {
359
+ coerced = numberValue;
360
+ } else {
361
+ const booleanValue = this.#stringToBoolean(coerced);
362
+ if (enumValues.includes(booleanValue)) {
363
+ coerced = booleanValue;
364
+ } else {
365
+ satisfied = false;
366
+ }
367
+ }
368
+ } else {
369
+ satisfied = false;
313
370
  }
314
- const nextImpl = implementerInternal(next, middlewares);
315
- if (method) {
316
- return new Proxy(method, {
317
- get(_, key2) {
318
- return Reflect.get(nextImpl, key2);
371
+ }
372
+ if (typeof schema.type === "string") {
373
+ switch (schema.type) {
374
+ case "null": {
375
+ if (coerced !== null) {
376
+ satisfied = false;
377
+ }
378
+ break;
379
+ }
380
+ case "string": {
381
+ if (typeof coerced !== "string") {
382
+ satisfied = false;
319
383
  }
320
- });
384
+ break;
385
+ }
386
+ case "number": {
387
+ if (typeof coerced === "string") {
388
+ coerced = this.#stringToNumber(coerced);
389
+ }
390
+ if (typeof coerced !== "number") {
391
+ satisfied = false;
392
+ }
393
+ break;
394
+ }
395
+ case "integer": {
396
+ if (typeof coerced === "string") {
397
+ coerced = this.#stringToInteger(coerced);
398
+ }
399
+ if (typeof coerced !== "number" || !Number.isInteger(coerced)) {
400
+ satisfied = false;
401
+ }
402
+ break;
403
+ }
404
+ case "boolean": {
405
+ if (typeof coerced === "string") {
406
+ coerced = this.#stringToBoolean(coerced);
407
+ }
408
+ if (typeof coerced !== "boolean") {
409
+ satisfied = false;
410
+ }
411
+ break;
412
+ }
413
+ case "array": {
414
+ if (Array.isArray(coerced)) {
415
+ const prefixItemSchemas = "prefixItems" in schema ? toArray(schema.prefixItems) : Array.isArray(schema.items) ? schema.items : [];
416
+ const itemSchema = Array.isArray(schema.items) ? schema.additionalItems : schema.items;
417
+ let shouldUseCoercedItems = false;
418
+ const coercedItems = coerced.map((item, i) => {
419
+ const subSchema = prefixItemSchemas[i] ?? itemSchema;
420
+ if (subSchema === void 0) {
421
+ satisfied = false;
422
+ return item;
423
+ }
424
+ const [subSatisfied, subCoerced] = this.#coerce(subSchema, item, options);
425
+ if (!subSatisfied) {
426
+ satisfied = false;
427
+ }
428
+ if (subCoerced !== item) {
429
+ shouldUseCoercedItems = true;
430
+ }
431
+ return subCoerced;
432
+ });
433
+ if (coercedItems.length < prefixItemSchemas.length) {
434
+ satisfied = false;
435
+ }
436
+ if (shouldUseCoercedItems) {
437
+ coerced = coercedItems;
438
+ }
439
+ } else {
440
+ satisfied = false;
441
+ }
442
+ break;
443
+ }
444
+ case "object": {
445
+ if (Array.isArray(coerced)) {
446
+ coerced = { ...coerced };
447
+ }
448
+ if (isObject(coerced)) {
449
+ let shouldUseCoercedItems = false;
450
+ const coercedItems = {};
451
+ const patternProperties = Object.entries(schema.patternProperties ?? {}).map(
452
+ ([key, value]) => [new RegExp(key), value]
453
+ );
454
+ for (const key in coerced) {
455
+ const value = coerced[key];
456
+ const subSchema = schema.properties?.[key] ?? patternProperties.find(([pattern]) => pattern.test(key))?.[1] ?? schema.additionalProperties;
457
+ if (value === void 0 && !schema.required?.includes(key)) {
458
+ coercedItems[key] = value;
459
+ } else if (subSchema === void 0) {
460
+ coercedItems[key] = value;
461
+ satisfied = false;
462
+ } else {
463
+ const [subSatisfied, subCoerced] = this.#coerce(subSchema, value, options);
464
+ coercedItems[key] = subCoerced;
465
+ if (!subSatisfied) {
466
+ satisfied = false;
467
+ }
468
+ if (subCoerced !== value) {
469
+ shouldUseCoercedItems = true;
470
+ }
471
+ }
472
+ }
473
+ if (schema.required?.some((key) => !Object.hasOwn(coercedItems, key))) {
474
+ satisfied = false;
475
+ }
476
+ if (shouldUseCoercedItems) {
477
+ coerced = coercedItems;
478
+ }
479
+ } else {
480
+ satisfied = false;
481
+ }
482
+ break;
483
+ }
321
484
  }
322
- return nextImpl;
323
485
  }
324
- });
325
- return impl;
326
- }
327
- function implement(contract) {
328
- const implInternal = implementerInternal(contract, []);
329
- const impl = new Proxy(implInternal, {
330
- get: (target, key) => {
331
- let method;
332
- if (key === "$context") {
333
- method = () => impl;
486
+ if ("x-native-type" in schema && typeof schema["x-native-type"] === "string") {
487
+ switch (schema["x-native-type"]) {
488
+ case JsonSchemaXNativeType.Date: {
489
+ if (typeof coerced === "string") {
490
+ coerced = this.#stringToDate(coerced);
491
+ }
492
+ if (!(coerced instanceof Date)) {
493
+ satisfied = false;
494
+ }
495
+ break;
496
+ }
497
+ case JsonSchemaXNativeType.BigInt: {
498
+ switch (typeof coerced) {
499
+ case "string":
500
+ coerced = this.#stringToBigInt(coerced);
501
+ break;
502
+ case "number":
503
+ coerced = this.#numberToBigInt(coerced);
504
+ break;
505
+ }
506
+ if (typeof coerced !== "bigint") {
507
+ satisfied = false;
508
+ }
509
+ break;
510
+ }
511
+ case JsonSchemaXNativeType.RegExp: {
512
+ if (typeof coerced === "string") {
513
+ coerced = this.#stringToRegExp(coerced);
514
+ }
515
+ if (!(coerced instanceof RegExp)) {
516
+ satisfied = false;
517
+ }
518
+ break;
519
+ }
520
+ case JsonSchemaXNativeType.Url: {
521
+ if (typeof coerced === "string") {
522
+ coerced = this.#stringToURL(coerced);
523
+ }
524
+ if (!(coerced instanceof URL)) {
525
+ satisfied = false;
526
+ }
527
+ break;
528
+ }
529
+ case JsonSchemaXNativeType.Set: {
530
+ if (Array.isArray(coerced)) {
531
+ coerced = this.#arrayToSet(coerced);
532
+ }
533
+ if (!(coerced instanceof Set)) {
534
+ satisfied = false;
535
+ }
536
+ break;
537
+ }
538
+ case JsonSchemaXNativeType.Map: {
539
+ if (Array.isArray(coerced)) {
540
+ coerced = this.#arrayToMap(coerced);
541
+ }
542
+ if (!(coerced instanceof Map)) {
543
+ satisfied = false;
544
+ }
545
+ break;
546
+ }
334
547
  }
335
- const next = Reflect.get(target, key);
336
- if (!method || !next || typeof next !== "function" && typeof next !== "object") {
337
- return method || next;
548
+ }
549
+ if (schema.allOf) {
550
+ for (const subSchema of schema.allOf) {
551
+ const [subSatisfied, subCoerced] = this.#coerce(subSchema, coerced, options);
552
+ coerced = subCoerced;
553
+ if (!subSatisfied) {
554
+ satisfied = false;
555
+ }
338
556
  }
339
- return new Proxy(method, {
340
- get(_, key2) {
341
- return Reflect.get(next, key2);
557
+ }
558
+ for (const key of ["anyOf", "oneOf"]) {
559
+ if (schema[key]) {
560
+ let bestOptions;
561
+ for (const subSchema of schema[key]) {
562
+ const [subSatisfied, subCoerced] = this.#coerce(subSchema, coerced, options);
563
+ if (subSatisfied) {
564
+ if (!bestOptions || subCoerced === coerced) {
565
+ bestOptions = { coerced: subCoerced, satisfied: subSatisfied };
566
+ }
567
+ if (subCoerced === coerced) {
568
+ break;
569
+ }
570
+ }
342
571
  }
343
- });
572
+ coerced = bestOptions ? bestOptions.coerced : coerced;
573
+ satisfied = bestOptions ? bestOptions.satisfied : false;
574
+ }
575
+ }
576
+ if (typeof schema.not !== "undefined") {
577
+ const [notSatisfied] = this.#coerce(schema.not, coerced, options);
578
+ if (notSatisfied) {
579
+ satisfied = false;
580
+ }
581
+ }
582
+ return [satisfied, coerced];
583
+ }
584
+ #stringToNumber(value) {
585
+ const num = Number.parseFloat(value);
586
+ if (Number.isNaN(num) || num !== Number(value)) {
587
+ return value;
588
+ }
589
+ return num;
590
+ }
591
+ #stringToInteger(value) {
592
+ const num = Number.parseInt(value);
593
+ if (Number.isNaN(num) || num !== Number(value)) {
594
+ return value;
595
+ }
596
+ return num;
597
+ }
598
+ #stringToBoolean(value) {
599
+ const lower = value.toLowerCase();
600
+ if (lower === "false" || lower === "off") {
601
+ return false;
602
+ }
603
+ if (lower === "true" || lower === "on") {
604
+ return true;
605
+ }
606
+ return value;
607
+ }
608
+ #stringToBigInt(value) {
609
+ return guard(() => BigInt(value)) ?? value;
610
+ }
611
+ #numberToBigInt(value) {
612
+ return guard(() => BigInt(value)) ?? value;
613
+ }
614
+ #stringToDate(value) {
615
+ const date = new Date(value);
616
+ if (Number.isNaN(date.getTime()) || !FLEXIBLE_DATE_FORMAT_REGEX.test(value)) {
617
+ return value;
344
618
  }
345
- });
346
- return impl;
619
+ return date;
620
+ }
621
+ #stringToRegExp(value) {
622
+ const match = value.match(/^\/(.*)\/([a-z]*)$/);
623
+ if (match) {
624
+ const [, pattern, flags] = match;
625
+ return guard(() => new RegExp(pattern, flags)) ?? value;
626
+ }
627
+ return value;
628
+ }
629
+ #stringToURL(value) {
630
+ return guard(() => new URL(value)) ?? value;
631
+ }
632
+ #arrayToSet(value) {
633
+ const set = new Set(value);
634
+ if (set.size !== value.length) {
635
+ return value;
636
+ }
637
+ return set;
638
+ }
639
+ #arrayToMap(value) {
640
+ if (value.some((item) => !Array.isArray(item) || item.length !== 2)) {
641
+ return value;
642
+ }
643
+ const result = new Map(value);
644
+ if (result.size !== value.length) {
645
+ return value;
646
+ }
647
+ return result;
648
+ }
347
649
  }
348
650
 
349
651
  function createAssertedLazyProcedure(lazied) {
@@ -360,42 +662,26 @@ function createAssertedLazyProcedure(lazied) {
360
662
  }, getLazyMeta(lazied));
361
663
  return lazyProcedure;
362
664
  }
363
- function createContractedProcedure(procedure, contract) {
364
- return new Procedure({
365
- ...procedure["~orpc"],
366
- errorMap: contract["~orpc"].errorMap,
367
- route: contract["~orpc"].route,
368
- meta: contract["~orpc"].meta
369
- });
370
- }
371
665
  function call(procedure, input, ...rest) {
372
666
  const options = resolveMaybeOptionalOptions(rest);
373
667
  return createProcedureClient(procedure, options)(input, options);
374
668
  }
375
669
 
376
- function createRouterClient(router, ...rest) {
377
- const options = resolveMaybeOptionalOptions(rest);
378
- if (isProcedure(router)) {
379
- const caller = createProcedureClient(router, options);
380
- return caller;
381
- }
382
- const procedureCaller = isLazy(router) ? createProcedureClient(createAssertedLazyProcedure(router), options) : {};
383
- const recursive = new Proxy(procedureCaller, {
384
- get(target, key) {
385
- if (typeof key !== "string") {
386
- return Reflect.get(target, key);
387
- }
388
- const next = getRouter(router, [key]);
389
- if (!next) {
390
- return Reflect.get(target, key);
391
- }
392
- return createRouterClient(next, {
393
- ...rest[0],
394
- path: [...rest[0]?.path ?? [], key]
395
- });
670
+ function isSchemaIssue(issue) {
671
+ if (!isTypescriptObject(issue) || typeof issue.message !== "string") {
672
+ return false;
673
+ }
674
+ if (issue.path !== void 0) {
675
+ if (!Array.isArray(issue.path)) {
676
+ return false;
396
677
  }
397
- });
398
- return recursive;
678
+ if (!issue.path.every(
679
+ (segment) => isPropertyKey(segment) || isTypescriptObject(segment) && isPropertyKey(segment.key)
680
+ )) {
681
+ return false;
682
+ }
683
+ }
684
+ return true;
399
685
  }
400
686
 
401
- export { Builder, BuilderWithMiddlewares, DecoratedProcedure, Procedure, ProcedureBuilder, addMiddleware, call, createApiBuilder, createAssertedLazyProcedure, createContractedProcedure, createProcedureClient, createRouterClient, decorateMiddleware, enhanceRouter, getLazyMeta, getRouter, implement, implementerInternal, isLazy, isProcedure, lazyInternal, os, setHiddenRouterContract, unlazy };
687
+ export { Builder, BuilderWithMiddlewares, Contract, DecoratedProcedure, JsonSchemaXNativeType, Procedure, ProcedureBuilder, addMiddleware, baseApi, call, createAssertedLazyProcedure, createProcedureClient, decorateMiddleware, enhanceRouter, experimental_JsonSchemaCoercer, getLazyMeta, initialSchemas, isProcedure, isSchemaIssue, lazyInternal, mergeMeta, parseEndpointDefinition, unlazy };