@temporary-name/server 1.9.3-alpha.e2d8d164da72fb570c2b14a4fa956c80f9e33cdc → 1.9.3-alpha.edd373b82156a10608d43b19a44b75ae72e72de7

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 (44) hide show
  1. package/dist/adapters/aws-lambda/index.d.mts +4 -6
  2. package/dist/adapters/aws-lambda/index.d.ts +4 -6
  3. package/dist/adapters/aws-lambda/index.mjs +4 -4
  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 -155
  7. package/dist/adapters/node/index.d.mts +8 -63
  8. package/dist/adapters/node/index.d.ts +8 -63
  9. package/dist/adapters/node/index.mjs +14 -120
  10. package/dist/adapters/standard/index.d.mts +10 -7
  11. package/dist/adapters/standard/index.d.ts +10 -7
  12. package/dist/adapters/standard/index.mjs +4 -4
  13. package/dist/helpers/index.mjs +3 -29
  14. package/dist/index.d.mts +376 -242
  15. package/dist/index.d.ts +376 -242
  16. package/dist/index.mjs +482 -359
  17. package/dist/openapi/index.d.mts +18 -53
  18. package/dist/openapi/index.d.ts +18 -53
  19. package/dist/openapi/index.mjs +337 -347
  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.CQIFwyhc.mjs +40 -0
  25. package/dist/shared/server.CjPiuQYH.d.mts +51 -0
  26. package/dist/shared/server.CjPiuQYH.d.ts +51 -0
  27. package/dist/shared/server.Cq7SBLD5.mjs +403 -0
  28. package/dist/shared/server.DGH2Bq4t.d.mts +41 -0
  29. package/dist/shared/server.nQoUObAJ.d.ts +41 -0
  30. package/dist/shared/server.zsKBRxsz.d.mts +388 -0
  31. package/dist/shared/server.zsKBRxsz.d.ts +388 -0
  32. package/package.json +10 -28
  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.B93y_8tj.d.mts +0 -23
  37. package/dist/shared/server.BYYf0Wn6.mjs +0 -202
  38. package/dist/shared/server.C3RuMHWl.d.mts +0 -192
  39. package/dist/shared/server.C3RuMHWl.d.ts +0 -192
  40. package/dist/shared/server.CT1xhSmE.d.mts +0 -56
  41. package/dist/shared/server.CqTex_jI.mjs +0 -265
  42. package/dist/shared/server.D_fags8X.d.ts +0 -23
  43. package/dist/shared/server.Kxw442A9.mjs +0 -247
  44. package/dist/shared/server.cjcgLdr1.d.ts +0 -56
package/dist/index.mjs CHANGED
@@ -1,50 +1,78 @@
1
- import { onError, resolveMaybeOptionalOptions } from '@temporary-name/shared';
2
- export { AsyncIteratorClass, EventPublisher, ORPCError, asyncIteratorToStream as eventIteratorToStream, isDefinedError, onError, onFinish, onStart, onSuccess, safe, streamToAsyncIteratorClass as streamToEventIterator } from '@temporary-name/shared';
3
- import { isContractProcedure, mergePrefix, mergeErrorMap, enhanceRoute, mergeTags, ContractProcedure, mergeMeta, mergeRoute, prefixRoute, getContractRouter } from '@temporary-name/contract';
4
- export { ValidationError, eventIterator, validateORPCError } from '@temporary-name/contract';
5
- import { SchemaClass, gatingContext } from '@temporary-name/zod';
6
- import { c as createProcedureClient, i as isLazy, g as getLazyMeta, l as lazy, u as unlazy } from './shared/server.BYYf0Wn6.mjs';
7
- export { L as LAZY_SYMBOL, a as createORPCErrorConstructorMap, m as mergeCurrentContext, b as middlewareOutputFn } from './shared/server.BYYf0Wn6.mjs';
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';
8
12
  export { getEventMeta, withEventMeta } from '@temporary-name/standard-server';
13
+ import 'cookie';
14
+ import '@temporary-name/server/openapi';
15
+ import 'zod/v4/core';
9
16
 
10
- function isStartWithMiddlewares(middlewares, compare) {
11
- if (compare.length > middlewares.length) {
12
- return false;
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}"` });
13
20
  }
14
- for (let i = 0; i < middlewares.length; i++) {
15
- if (compare[i] === void 0) {
16
- return true;
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;
17
44
  }
18
- if (middlewares[i] !== compare[i]) {
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": {
19
62
  return false;
20
63
  }
64
+ default: {
65
+ assertNever(config);
66
+ }
21
67
  }
22
- return true;
23
- }
24
- function mergeMiddlewares(first, second, options) {
25
- if (options.dedupeLeading && isStartWithMiddlewares(second, first)) {
26
- return second;
27
- }
28
- return [...first, ...second];
29
68
  }
30
- function addMiddleware(middlewares, addition) {
31
- return [...middlewares, addition];
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);
32
72
  }
33
73
 
34
- class Procedure {
35
- /**
36
- * This property holds the defined options.
37
- */
38
- "~orpc";
39
- constructor(def) {
40
- this["~orpc"] = def;
41
- }
42
- }
43
- function isProcedure(item) {
44
- if (item instanceof Procedure) {
45
- return true;
46
- }
47
- return isContractProcedure(item) && "middlewares" in item["~orpc"] && "handler" in item["~orpc"];
74
+ function mergeMeta(meta1, meta2) {
75
+ return { ...meta1, ...meta2 };
48
76
  }
49
77
 
50
78
  class DecoratedProcedure extends Procedure {
@@ -66,170 +94,19 @@ class DecoratedProcedure extends Procedure {
66
94
  }
67
95
  }
68
96
 
69
- const HIDDEN_ROUTER_CONTRACT_SYMBOL = Symbol("ORPC_HIDDEN_ROUTER_CONTRACT");
70
- function setHiddenRouterContract(router, contract) {
71
- return new Proxy(router, {
72
- get(target, key) {
73
- if (key === HIDDEN_ROUTER_CONTRACT_SYMBOL) {
74
- return contract;
75
- }
76
- return Reflect.get(target, key);
77
- }
78
- });
79
- }
80
- function getHiddenRouterContract(router) {
81
- return router[HIDDEN_ROUTER_CONTRACT_SYMBOL];
82
- }
83
-
84
- function getRouter(router, path) {
85
- let current = router;
86
- for (let i = 0; i < path.length; i++) {
87
- const segment = path[i];
88
- if (!current) {
89
- return void 0;
90
- }
91
- if (isProcedure(current)) {
92
- return void 0;
93
- }
94
- if (!isLazy(current)) {
95
- current = current[segment];
96
- continue;
97
- }
98
- const lazied = current;
99
- const rest = path.slice(i);
100
- return lazy(async () => {
101
- const unwrapped = await unlazy(lazied);
102
- const next = getRouter(unwrapped.default, rest);
103
- return unlazy(next);
104
- }, getLazyMeta(lazied));
105
- }
106
- return current;
107
- }
108
- function createAccessibleLazyRouter(lazied) {
109
- const recursive = new Proxy(lazied, {
110
- get(target, key) {
111
- if (typeof key !== "string") {
112
- return Reflect.get(target, key);
113
- }
114
- const next = getRouter(lazied, [key]);
115
- return createAccessibleLazyRouter(next);
116
- }
117
- });
118
- return recursive;
119
- }
120
- function enhanceRouter(router, options) {
121
- if (isLazy(router)) {
122
- const laziedMeta = getLazyMeta(router);
123
- const enhancedPrefix = laziedMeta?.prefix ? mergePrefix(options.prefix, laziedMeta?.prefix) : options.prefix;
124
- const enhanced2 = lazy(
125
- async () => {
126
- const { default: unlaziedRouter } = await unlazy(router);
127
- const enhanced3 = enhanceRouter(unlaziedRouter, options);
128
- return unlazy(enhanced3);
129
- },
130
- {
131
- ...laziedMeta,
132
- prefix: enhancedPrefix
133
- }
134
- );
135
- const accessible = createAccessibleLazyRouter(enhanced2);
136
- return accessible;
137
- }
138
- if (isProcedure(router)) {
139
- const newMiddlewares = mergeMiddlewares(options.middlewares, router["~orpc"].middlewares, {
140
- dedupeLeading: options.dedupeLeadingMiddlewares
141
- });
142
- const newMiddlewareAdded = newMiddlewares.length - router["~orpc"].middlewares.length;
143
- const enhanced2 = new Procedure({
144
- ...router["~orpc"],
145
- route: enhanceRoute(router["~orpc"].route, options),
146
- errorMap: mergeErrorMap(options.errorMap, router["~orpc"].errorMap),
147
- middlewares: newMiddlewares,
148
- inputValidationIndex: router["~orpc"].inputValidationIndex + newMiddlewareAdded,
149
- outputValidationIndex: router["~orpc"].outputValidationIndex + newMiddlewareAdded
150
- });
151
- return enhanced2;
152
- }
153
- const enhanced = {};
154
- for (const key in router) {
155
- enhanced[key] = enhanceRouter(router[key], options);
156
- }
157
- return enhanced;
158
- }
159
- function traverseContractProcedures(options, callback, lazyOptions = []) {
160
- let currentRouter = options.router;
161
- const hiddenContract = getHiddenRouterContract(options.router);
162
- if (hiddenContract !== void 0) {
163
- currentRouter = hiddenContract;
164
- }
165
- if (isLazy(currentRouter)) {
166
- lazyOptions.push({
167
- router: currentRouter,
168
- path: options.path
169
- });
170
- } else if (isContractProcedure(currentRouter)) {
171
- callback({
172
- contract: currentRouter,
173
- path: options.path
174
- });
175
- } else {
176
- for (const key in currentRouter) {
177
- traverseContractProcedures(
178
- {
179
- router: currentRouter[key],
180
- path: [...options.path, key]
181
- },
182
- callback,
183
- lazyOptions
184
- );
185
- }
186
- }
187
- return lazyOptions;
188
- }
189
- async function resolveContractProcedures(options, callback) {
190
- const pending = [options];
191
- for (const options2 of pending) {
192
- const lazyOptions = traverseContractProcedures(options2, callback);
193
- for (const options3 of lazyOptions) {
194
- const { default: router } = await unlazy(options3.router);
195
- pending.push({
196
- router,
197
- path: options3.path
198
- });
199
- }
200
- }
201
- }
202
- async function unlazyRouter(router) {
203
- if (isProcedure(router)) {
204
- return router;
205
- }
206
- const unlazied = {};
207
- for (const key in router) {
208
- const item = router[key];
209
- const { default: unlaziedRouter } = await unlazy(item);
210
- unlazied[key] = await unlazyRouter(unlaziedRouter);
211
- }
212
- return unlazied;
213
- }
97
+ const initialSchemas = {
98
+ pathSchema: z.strictObject({}),
99
+ querySchema: z.strictObject({}),
100
+ bodySchema: z.strictObject({}),
101
+ outputSchema: z.unknown()
102
+ };
214
103
 
215
- class ProcedureBuilder extends ContractProcedure {
104
+ class ProcedureBuilder extends Contract {
216
105
  z;
217
106
  constructor(def) {
218
107
  super(def);
219
108
  this.z = new SchemaClass();
220
109
  }
221
- /**
222
- * Adds type-safe custom errors to the contract.
223
- * The provided errors are spared-merged with any existing errors in the contract.
224
- *
225
- * @see {@link https://orpc.unnoq.com/docs/error-handling#type%E2%80%90safe-error-handling Type-Safe Error Handling Docs}
226
- */
227
- errors(errors) {
228
- return new ProcedureBuilder({
229
- ...this["~orpc"],
230
- errorMap: mergeErrorMap(this["~orpc"].errorMap, errors)
231
- });
232
- }
233
110
  /**
234
111
  * Sets or updates the metadata for the contract.
235
112
  * The provided metadata is spared-merged with any existing metadata in the contract.
@@ -242,6 +119,19 @@ class ProcedureBuilder extends ContractProcedure {
242
119
  meta: mergeMeta(this["~orpc"].meta, meta)
243
120
  });
244
121
  }
122
+ endpoint(stringsOrEndpoint, ...values) {
123
+ const { method, path, pathSchema } = parseEndpointDefinition(stringsOrEndpoint, values);
124
+ const { prefix } = this["~orpc"];
125
+ const route = { method, path };
126
+ return new ProcedureBuilder({
127
+ ...this["~orpc"],
128
+ route: mergeRoute(this["~orpc"].route, prefix ? prefixRoute(route, prefix) : route),
129
+ schemas: {
130
+ ...this["~orpc"].schemas,
131
+ pathSchema
132
+ }
133
+ });
134
+ }
245
135
  /**
246
136
  * Sets or updates the route definition for the contract.
247
137
  * The provided route is spared-merged with any existing route in the contract.
@@ -250,22 +140,30 @@ class ProcedureBuilder extends ContractProcedure {
250
140
  * @see {@link https://orpc.unnoq.com/docs/openapi/routing OpenAPI Routing Docs}
251
141
  * @see {@link https://orpc.unnoq.com/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
252
142
  */
253
- route(route) {
143
+ endpointOpts(route) {
254
144
  const { prefix } = this["~orpc"];
255
145
  return new ProcedureBuilder({
256
146
  ...this["~orpc"],
257
147
  route: mergeRoute(this["~orpc"].route, prefix ? prefixRoute(route, prefix) : route)
258
148
  });
259
149
  }
260
- /**
261
- * Defines the input validation schema.
262
- *
263
- * @see {@link https://orpc.unnoq.com/docs/procedure#input-output-validation Input Validation Docs}
264
- */
265
- input(schema) {
150
+ query(schema) {
266
151
  return new ProcedureBuilder({
267
152
  ...this["~orpc"],
268
- inputSchema: schema,
153
+ schemas: {
154
+ ...this["~orpc"].schemas,
155
+ querySchema: schema instanceof core.$ZodType ? schema : object(schema)
156
+ },
157
+ inputValidationIndex: this["~orpc"].middlewares.length
158
+ });
159
+ }
160
+ body(schema) {
161
+ return new ProcedureBuilder({
162
+ ...this["~orpc"],
163
+ schemas: {
164
+ ...this["~orpc"].schemas,
165
+ bodySchema: schema instanceof core.$ZodType ? schema : object(schema)
166
+ },
269
167
  inputValidationIndex: this["~orpc"].middlewares.length
270
168
  });
271
169
  }
@@ -277,23 +175,47 @@ class ProcedureBuilder extends ContractProcedure {
277
175
  output(schema) {
278
176
  return new ProcedureBuilder({
279
177
  ...this["~orpc"],
280
- outputSchema: schema,
178
+ schemas: {
179
+ ...this["~orpc"].schemas,
180
+ outputSchema: schema instanceof core.$ZodType ? schema : object(schema)
181
+ },
281
182
  outputValidationIndex: this["~orpc"].middlewares.length
282
183
  });
283
184
  }
284
- /**
285
- * Uses a middleware to modify the context or improve the pipeline.
286
- *
287
- * @info Supports both normal middleware and inline middleware implementations.
288
- * @note The current context must be satisfy middleware dependent-context
289
- * @see {@link https://orpc.unnoq.com/docs/middleware Middleware Docs}
290
- */
291
185
  use(middleware) {
292
186
  return new this.constructor({
293
187
  ...this["~orpc"],
294
188
  middlewares: addMiddleware(this["~orpc"].middlewares, middleware)
295
189
  });
296
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
+ }
297
219
  useGating(gates, isGateEnabled) {
298
220
  return this.use(({ next, context }) => {
299
221
  return gatingContext.run(
@@ -308,6 +230,9 @@ class ProcedureBuilder extends ContractProcedure {
308
230
  * @see {@link https://orpc.unnoq.com/docs/procedure Procedure Docs}
309
231
  */
310
232
  handler(handler) {
233
+ if (this["~orpc"].schemas.outputSchema === initialSchemas.outputSchema) {
234
+ throw new Error("You must call .output() before calling .handler()");
235
+ }
311
236
  return new DecoratedProcedure({
312
237
  ...this["~orpc"],
313
238
  handler
@@ -359,31 +284,6 @@ function decorateMiddleware(middleware) {
359
284
  );
360
285
  return mapped;
361
286
  };
362
- decorated.concat = (concatMiddleware, mapInput) => {
363
- const mapped = mapInput ? decorateMiddleware(concatMiddleware).mapInput(mapInput) : concatMiddleware;
364
- const concatted = decorateMiddleware((options, input, output, ...rest) => {
365
- const merged = middleware(
366
- {
367
- ...options,
368
- next: (...[nextOptions1]) => mapped(
369
- {
370
- ...options,
371
- context: { ...options.context, ...nextOptions1?.context },
372
- next: (...[nextOptions2]) => options.next({ context: { ...nextOptions1?.context, ...nextOptions2?.context } })
373
- },
374
- input,
375
- output,
376
- ...rest
377
- )
378
- },
379
- input,
380
- output,
381
- ...rest
382
- );
383
- return merged;
384
- });
385
- return concatted;
386
- };
387
287
  return decorated;
388
288
  }
389
289
 
@@ -405,112 +305,351 @@ class Builder extends BuilderWithMiddlewares {
405
305
  return decorateMiddleware(middleware);
406
306
  }
407
307
  }
408
- function createApiBuilder(opts = {}) {
409
- return new Builder({
410
- route: {},
411
- meta: opts.meta ?? {},
412
- errorMap: {},
413
- inputValidationIndex: 0,
414
- outputValidationIndex: 0,
415
- middlewares: [
416
- onError((error, _options) => {
417
- console.dir(error, { depth: null });
418
- })
419
- ],
420
- // NB: this is a relic from orpc -- I'm not convinced there's a need for this (or if there is, that it's
421
- // the best solution). For now I've removed the interface to configure it externally.
422
- dedupeLeadingMiddlewares: true
423
- });
424
- }
425
- 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
+ });
426
324
 
427
- function implementerInternal(contract, middlewares) {
428
- if (isContractProcedure(contract)) {
429
- const impl2 = new Builder({
430
- ...contract["~orpc"],
431
- middlewares,
432
- inputValidationIndex: middlewares.length,
433
- outputValidationIndex: middlewares.length,
434
- dedupeLeadingMiddlewares: true
435
- });
436
- 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;
437
330
  }
438
- const impl = new Proxy(contract, {
439
- get: (target, key) => {
440
- if (typeof key !== "string") {
441
- return Reflect.get(target, key);
442
- }
443
- let method;
444
- if (key === "middleware") {
445
- method = (mid) => decorateMiddleware(mid);
446
- } else if (key === "use") {
447
- method = (mid) => {
448
- return implementerInternal(contract, addMiddleware(middlewares, mid));
449
- };
450
- } else if (key === "router") {
451
- method = (router) => {
452
- const adapted = enhanceRouter(router, {
453
- middlewares,
454
- errorMap: {},
455
- prefix: void 0,
456
- tags: void 0,
457
- dedupeLeadingMiddlewares: true
458
- });
459
- return setHiddenRouterContract(adapted, contract);
460
- };
461
- } else if (key === "lazyRoute") {
462
- method = (loader) => {
463
- const adapted = enhanceRouter(lazy(loader), {
464
- middlewares,
465
- errorMap: {},
466
- prefix: void 0,
467
- tags: void 0,
468
- dedupeLeadingMiddlewares: true
469
- });
470
- return setHiddenRouterContract(adapted, contract);
471
- };
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;
472
352
  }
473
- const next = getContractRouter(target, [key]);
474
- if (!next) {
475
- 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;
476
370
  }
477
- const nextImpl = implementerInternal(next, middlewares);
478
- if (method) {
479
- return new Proxy(method, {
480
- get(_, key2) {
481
- 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;
383
+ }
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);
482
398
  }
483
- });
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
+ }
484
484
  }
485
- return nextImpl;
486
485
  }
487
- });
488
- return impl;
489
- }
490
- function implement(contract) {
491
- const implInternal = implementerInternal(contract, []);
492
- const impl = new Proxy(implInternal, {
493
- get: (target, key) => {
494
- let method;
495
- if (key === "$context") {
496
- 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
+ }
497
547
  }
498
- const next = Reflect.get(target, key);
499
- if (!method || !next || typeof next !== "function" && typeof next !== "object") {
500
- 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
+ }
501
556
  }
502
- return new Proxy(method, {
503
- get(_, key2) {
504
- 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
+ }
505
571
  }
506
- });
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;
618
+ }
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;
507
646
  }
508
- });
509
- return impl;
647
+ return result;
648
+ }
510
649
  }
511
650
 
512
651
  function createAssertedLazyProcedure(lazied) {
513
- const lazyProcedure = lazy(async () => {
652
+ const lazyProcedure = lazyInternal(async () => {
514
653
  const { default: maybeProcedure } = await unlazy(lazied);
515
654
  if (!isProcedure(maybeProcedure)) {
516
655
  throw new Error(`
@@ -523,42 +662,26 @@ function createAssertedLazyProcedure(lazied) {
523
662
  }, getLazyMeta(lazied));
524
663
  return lazyProcedure;
525
664
  }
526
- function createContractedProcedure(procedure, contract) {
527
- return new Procedure({
528
- ...procedure["~orpc"],
529
- errorMap: contract["~orpc"].errorMap,
530
- route: contract["~orpc"].route,
531
- meta: contract["~orpc"].meta
532
- });
533
- }
534
665
  function call(procedure, input, ...rest) {
535
666
  const options = resolveMaybeOptionalOptions(rest);
536
667
  return createProcedureClient(procedure, options)(input, options);
537
668
  }
538
669
 
539
- function createRouterClient(router, ...rest) {
540
- const options = resolveMaybeOptionalOptions(rest);
541
- if (isProcedure(router)) {
542
- const caller = createProcedureClient(router, options);
543
- return caller;
544
- }
545
- const procedureCaller = isLazy(router) ? createProcedureClient(createAssertedLazyProcedure(router), options) : {};
546
- const recursive = new Proxy(procedureCaller, {
547
- get(target, key) {
548
- if (typeof key !== "string") {
549
- return Reflect.get(target, key);
550
- }
551
- const next = getRouter(router, [key]);
552
- if (!next) {
553
- return Reflect.get(target, key);
554
- }
555
- return createRouterClient(next, {
556
- ...rest[0],
557
- path: [...rest[0]?.path ?? [], key]
558
- });
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;
677
+ }
678
+ if (!issue.path.every(
679
+ (segment) => isPropertyKey(segment) || isTypescriptObject(segment) && isPropertyKey(segment.key)
680
+ )) {
681
+ return false;
559
682
  }
560
- });
561
- return recursive;
683
+ }
684
+ return true;
562
685
  }
563
686
 
564
- export { Builder, BuilderWithMiddlewares, DecoratedProcedure, Procedure, ProcedureBuilder, addMiddleware, call, createAccessibleLazyRouter, createApiBuilder, createAssertedLazyProcedure, createContractedProcedure, createProcedureClient, createRouterClient, decorateMiddleware, enhanceRouter, getHiddenRouterContract, getLazyMeta, getRouter, implement, implementerInternal, isLazy, isProcedure, isStartWithMiddlewares, lazy, mergeMiddlewares, os, resolveContractProcedures, setHiddenRouterContract, traverseContractProcedures, unlazy, unlazyRouter };
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 };