@cleverbrush/server 4.5.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,52 +1,31 @@
1
- /**
2
- * Server-side idempotency middleware.
3
- *
4
- * Ensures mutating requests with the same idempotency key produce the
5
- * same result exactly once — subsequent replays return the stored
6
- * response without re-executing the handler.
7
- *
8
- * @module
9
- */
10
1
  import type { RequestContext } from '../RequestContext.js';
11
2
  import type { Middleware } from '../types.js';
12
- /**
13
- * Configuration for {@link idempotency}.
14
- */
3
+ /** Configuration for bounded, process-local mutation response replay. */
15
4
  export interface ServerIdempotencyOptions {
16
5
  /**
17
- * TTL in milliseconds for stored responses.
18
- * Defaults to `86_400_000` (24 hours).
6
+ * Explicit authorization/tenant scope. Run after authentication and
7
+ * authorization. Return undefined to skip; use a fixed string only for
8
+ * deliberately public operations. Never use an unverified identity header.
19
9
  */
10
+ scope: (ctx: RequestContext) => string | undefined;
11
+ /** Stored response lifetime in milliseconds. Default: 86,400,000. */
20
12
  ttl?: number;
21
- /**
22
- * Header name to read the idempotency key from.
23
- * Defaults to `"x-idempotency-key"`.
24
- */
13
+ /** Case-insensitive request header. Default: x-idempotency-key. */
25
14
  headerName?: string;
26
- /**
27
- * Predicate that decides whether a request should be skipped.
28
- * Defaults to skipping non-mutating requests (GET, HEAD, OPTIONS).
29
- */
15
+ /** Default: skip GET, HEAD, OPTIONS and other non-mutating methods. */
30
16
  skip?: (ctx: RequestContext) => boolean;
17
+ /** Maximum retained keys, including pending requests. Default: 1000. */
18
+ maxEntries?: number;
19
+ /** Maximum response body retained per key. Default: 65,536 bytes. */
20
+ maxResponseBytes?: number;
31
21
  }
32
22
  /**
33
- * Server-side idempotency middleware.
34
- *
35
- * Reads the `x-idempotency-key` header from mutating requests. If a
36
- * response has already been stored for that key, it is returned
37
- * immediately — the handler is never called. Otherwise the handler
38
- * executes and its response is stored for future replays.
39
- *
40
- * GET, HEAD, and OPTIONS requests pass through without checking.
41
- *
42
- * @param options - Configuration.
43
- * @returns A server-side {@link Middleware}.
44
- *
45
- * @example
46
- * ```ts
47
- * server.handle(CreateTodo, createHandler, {
48
- * middlewares: [idempotency({ ttl: 86_400_000 })]
49
- * });
50
- * ```
23
+ * Replay completed mutations and coalesce concurrent requests within one
24
+ * middleware instance. Keys include explicit scope, method and full request URL.
25
+ * Reusing a key means retrying the same input; bodies are not fingerprinted.
26
+ * This is not durable exactly-once execution: restarts, expiry and thrown
27
+ * failures may permit another execution. Use database deduplication for that.
28
+ * Oversized/incomplete responses retain a non-replayable reservation (409).
29
+ * Capacity exhaustion returns 503 without executing the operation.
51
30
  */
52
- export declare function idempotency(options?: ServerIdempotencyOptions): Middleware;
31
+ export declare function idempotency(options: ServerIdempotencyOptions): Middleware;
@@ -22,6 +22,10 @@ export interface ServerCacheOptions {
22
22
  * Per-tag TTL overrides: `{ [tagName]: ttlMs }`.
23
23
  */
24
24
  ttlByTag?: Record<string, number>;
25
+ /** Maximum retained cache keys. Default: 1000 (oldest keys are evicted). */
26
+ maxEntries?: number;
27
+ /** Maximum retained response body size. Default: 65,536 bytes. */
28
+ maxResponseBytes?: number;
25
29
  }
26
30
  /**
27
31
  * Server-side cache response middleware.
@@ -36,6 +40,9 @@ export interface ServerCacheOptions {
36
40
  * - **Mutation (POST/PUT/PATCH/DELETE)**: Lets the handler run, then
37
41
  * invalidates all cache entries whose tag names start with any of the
38
42
  * endpoint's cache tag names. Older in-flight reads cannot refill them.
43
+ * - By default, retain at most 1000 keys and bodies up to 65,536 bytes. Private/no-store and
44
+ * Set-Cookie responses are not cached. Install after authorization and encode
45
+ * every identity/tenant/representation dimension in tag properties.
39
46
  *
40
47
  * @param options - Cache configuration.
41
48
  * @returns A server-side {@link Middleware}.
@@ -0,0 +1,9 @@
1
+ import type { OutgoingHttpHeaders, ServerResponse } from 'node:http';
2
+ /** @internal A complete, bounded response suitable for replay. */
3
+ export interface ResponseSnapshot {
4
+ status: number;
5
+ headers: OutgoingHttpHeaders;
6
+ body: Buffer;
7
+ }
8
+ /** @internal Capture all write/end overloads without changing their behavior. */
9
+ export declare function captureResponse(response: ServerResponse, next: () => Promise<void>, maxBytes: number): Promise<ResponseSnapshot | undefined>;
@@ -0,0 +1,9 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ import type { FilePart, RejectedFile } from './types.js';
3
+ import type { UploadConfiguration } from './upload.js';
4
+ /** @internal Buffered multipart parsing with a bound on the entire wire body. */
5
+ export declare function parseMultipart(req: IncomingMessage, options: UploadConfiguration, maxBodySize: number): Promise<{
6
+ fields: Record<string, string>;
7
+ files: Record<string, FilePart | FilePart[]>;
8
+ rejectedFiles: RejectedFile[];
9
+ }>;
package/dist/types.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import type { EndpointMetadata } from './Endpoint.js';
2
+ import type { RuntimeEndpointOptions } from './EndpointOptions.js';
2
3
  import type { RequestContext } from './RequestContext.js';
3
4
  import type { SubscriptionMetadata } from './Subscription.js';
4
5
  /**
5
6
  * A registered endpoint pairing its metadata (method, path, schemas) with
6
7
  * the handler function and any per-endpoint middleware.
7
8
  */
8
- export interface EndpointRegistration {
9
+ export interface EndpointRegistration extends RuntimeEndpointOptions {
9
10
  readonly endpoint: EndpointMetadata;
10
11
  readonly handler: (...args: any[]) => any;
11
12
  readonly middlewares?: readonly Middleware[];
@@ -100,6 +101,8 @@ export interface FilePart {
100
101
  * Describes a file that was rejected during multipart parsing.
101
102
  */
102
103
  export interface RejectedFile {
104
+ /** Multipart field name, when available. */
105
+ readonly fieldName?: string;
103
106
  /** Original filename as provided by the client. */
104
107
  readonly filename: string;
105
108
  /** MIME type of the file (e.g. `'application/xlsx'`). */
@@ -112,6 +115,14 @@ export interface RejectedFile {
112
115
  * `EndpointBuilder.upload()`.
113
116
  */
114
117
  export interface UploadOptions {
118
+ /** Maximum bytes per text field. Default: 1 MiB. */
119
+ maxFieldSize?: number;
120
+ /** Maximum text fields per request. Default: 100. */
121
+ maxFieldCount?: number;
122
+ /** Maximum UTF-8 bytes per field name. Default: 100. */
123
+ maxFieldNameSize?: number;
124
+ /** Maximum parts. Default: maxFileCount + maxFieldCount. */
125
+ maxPartCount?: number;
115
126
  /**
116
127
  * Maximum allowed file size per uploaded file in bytes.
117
128
  * @default 10_485_760 (10 MB)
@@ -0,0 +1,16 @@
1
+ import { type InferType, type ObjectSchemaBuilder, type SchemaBuilder } from '@cleverbrush/schema';
2
+ import type { FilePart, UploadOptions } from './types.js';
3
+ /** A buffered file in an upload contract. Safe to import in browser contracts. */
4
+ export declare function file(): import("@cleverbrush/schema").AnySchemaBuilder<true, false, FilePart, false, {}, FilePart>;
5
+ /** Flat object of file() and array(file()) fields. */
6
+ export type UploadSchema = ObjectSchemaBuilder<any, any, any, any, any, any, any>;
7
+ /** Upload metadata shared by the server, typed client, and OpenAPI generator. */
8
+ export interface UploadConfiguration extends UploadOptions {
9
+ readonly schema?: UploadSchema;
10
+ }
11
+ /** The upload state carried through immutable endpoint chaining. */
12
+ export type UploadContract = boolean | UploadSchema;
13
+ /** Files received by a handler, inferred from the upload schema. */
14
+ export type UploadFiles<T extends UploadContract> = T extends UploadSchema ? InferType<T> : Record<string, FilePart>;
15
+ /** @internal Validate the supported multipart shape in either chaining order. */
16
+ export declare function validateUploadConfiguration(upload: UploadConfiguration | null, body: SchemaBuilder<any, any, any, any, any> | null): void;
@@ -0,0 +1,29 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ /** HTTP lifecycle fields required to cancel request-owned work. */
3
+ export interface RequestSignalContext {
4
+ readonly request: Pick<IncomingMessage, 'aborted' | 'once' | 'off'>;
5
+ readonly response: Pick<ServerResponse, 'destroyed' | 'writableFinished' | 'once' | 'off'>;
6
+ }
7
+ /** Application-owned deadline and optional cancellation for request work. */
8
+ export interface RequestSignalOptions {
9
+ /** Positive integer deadline in milliseconds, at most 2,147,483,647. */
10
+ timeoutMs: number;
11
+ /** Additional cancellation, such as application shutdown. */
12
+ signal?: AbortSignal;
13
+ }
14
+ /**
15
+ * Run cooperative work with cancellation on disconnect, deadline or caller abort.
16
+ *
17
+ * The visitor must observe its signal; this helper does not forcibly interrupt
18
+ * arbitrary promises. A normal response finish does not cancel the work. The
19
+ * deadline timer and all listeners are removed when work settles, including on
20
+ * failure. Already-aborted inputs reject without invoking the visitor.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * await withRequestSignal(context, signal => loadReport(signal), {
25
+ * timeoutMs: 30_000
26
+ * });
27
+ * ```
28
+ */
29
+ export declare function withRequestSignal<T>(context: RequestSignalContext, work: (signal: AbortSignal) => T | PromiseLike<T>, options: RequestSignalOptions): Promise<T>;
package/package.json CHANGED
@@ -5,11 +5,11 @@
5
5
  "email": "andrew_zol@cleverbrush.com"
6
6
  },
7
7
  "dependencies": {
8
- "@cleverbrush/auth": "^4.5.0",
9
- "@cleverbrush/di": "^4.5.0",
10
- "@cleverbrush/schema": "^4.5.0",
11
- "@fastify/busboy": "^3.2.0",
12
- "ws": "^8.20.0"
8
+ "@cleverbrush/auth": "^5.1.0",
9
+ "@cleverbrush/di": "^5.1.0",
10
+ "@cleverbrush/schema": "^5.1.0",
11
+ "@fastify/busboy": "^3.2.2",
12
+ "ws": "^8.22.0"
13
13
  },
14
14
  "devDependencies": {
15
15
  "@types/busboy": "1.5.4",
@@ -29,7 +29,7 @@
29
29
  "typescript",
30
30
  "cleverbrush"
31
31
  ],
32
- "license": "BSD 3-Clause",
32
+ "license": "BSD-3-Clause",
33
33
  "main": "./dist/index.js",
34
34
  "exports": {
35
35
  ".": {
@@ -43,6 +43,9 @@
43
43
  },
44
44
  "sideEffects": false,
45
45
  "name": "@cleverbrush/server",
46
+ "engines": {
47
+ "node": ">=24"
48
+ },
46
49
  "readme": "https://github.com/cleverbrush/framework/tree/master/libs/server#readme",
47
50
  "repository": {
48
51
  "type": "git",
@@ -55,5 +58,5 @@
55
58
  },
56
59
  "type": "module",
57
60
  "types": "./dist/index.d.ts",
58
- "version": "4.5.0"
61
+ "version": "5.1.0"
59
62
  }
@@ -1,2 +0,0 @@
1
- function f(n,e){if(n===null)return["null"];switch(typeof n){case"undefined":return["undefined"];case"string":case"boolean":return[typeof n,n];case"number":return["number",Object.is(n,-0)?"-0":String(n)];case"bigint":return["bigint",String(n)];case"object":{if(e.has(n))throw new TypeError("Cache tag values must not contain cycles.");if(n instanceof Date){if(!Number.isFinite(n.getTime()))throw new TypeError("Cache tag dates must be valid.");return["date",n.toISOString()]}let t=Object.getPrototypeOf(n);if(!Array.isArray(n)&&t!==Object.prototype&&t!==null)throw new TypeError("Unsupported cache tag object.");if(Object.getOwnPropertySymbols(n).length>0)throw new TypeError("Cache tag values cannot have symbol keys.");e.add(n);try{if(Array.isArray(n)){if(Object.keys(n).some(a=>!/^(0|[1-9]\d*)$/.test(a)||Number(a)>=n.length))throw new TypeError("Cache tag arrays cannot have named properties.");return["array",Array.from({length:n.length},(a,s)=>{let i=Object.getOwnPropertyDescriptor(n,s);if(i&&!("value"in i))throw new TypeError("Cache tag values cannot contain getters.");return f(i?.value,e)})]}return["object",Object.keys(n).sort().map(a=>{let s=Object.getOwnPropertyDescriptor(n,a);if(!("value"in s))throw new TypeError("Cache tag values cannot contain getters.");return[a,f(s.value,e)]})]}finally{e.delete(n)}}default:throw new TypeError(`Unsupported cache tag value: ${typeof n}.`)}}function B(n,e){let t=[];for(let a of Object.keys(n.properties).sort()){let s=n.properties[a].getValue(e);s.success&&s.value!==void 0&&t.push([a,f(s.value,new Set)])}return`ct2:${JSON.stringify([n.name,t])}`}import{object as b,SYMBOL_HAS_PROPERTIES as x,SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR as R}from"@cleverbrush/schema";function E(n){let e={};if(n.paramsSchema){let a=n.paramsSchema;typeof a.introspect=="function"&&a.introspect().objectSchema?e.params=a.introspect().objectSchema:a[x]===!0&&(e.params=a)}if(n.bodySchema){let a=n.bodySchema;(a[x]===!0||typeof a.introspect=="function")&&(e.body=a)}n.querySchema&&(e.query=n.querySchema),n.headerSchema&&(e.headers=n.headerSchema);let t=b(e);return b.getPropertiesFor(t)}function z(n){return n==null||typeof n!="object"?!1:typeof n[R]=="object"&&n[R]!==null}function O(n,e){let t={};for(let[a,s]of Object.entries(e)){if(!z(s))throw new Error(`Cache tag "${n}": property "${a}" is not a valid PropertyDescriptor. Make sure you select a leaf property from the tree (e.g. p.query.id, not p.query).`);let i=s[R];t[a]={getValue:o=>i.getValue(o)}}return{name:n,properties:t}}var P=Symbol.for("cleverbrush.tracked");function G(n,e){return{[P]:!0,id:n,data:e}}function ee(n){return n!==null&&typeof n=="object"&&P in n&&n[P]===!0}var u=class n{#s;#a;#n;#i;#r;#o;#l;#t;#d;#h;#c;#u;#p;#y;constructor(e,t="/",a=null,s=null,i=null,o=null,y=null,d=null,l=null,h=null,c=[],m=null,g=!1,S=null){this.#s=e,this.#a=t,this.#n=a,this.#i=s,this.#r=i,this.#o=o,this.#l=y,this.#t=d,this.#d=l,this.#h=h,this.#c=c,this.#u=m,this.#p=g,this.#y=S}#e(e){return new n(e.basePath??this.#s,e.pathTemplate??this.#a,e.incomingSchema!==void 0?e.incomingSchema:this.#n,e.outgoingSchema!==void 0?e.outgoingSchema:this.#i,e.querySchema!==void 0?e.querySchema:this.#r,e.headerSchema!==void 0?e.headerSchema:this.#o,e.serviceSchemas!==void 0?e.serviceSchemas:this.#l,e.authRoles!==void 0?e.authRoles:this.#t,e.summary!==void 0?e.summary:this.#d,e.description!==void 0?e.description:this.#h,e.tags??this.#c,e.operationId!==void 0?e.operationId:this.#u,e.deprecated??this.#p,e.externalDocs!==void 0?e.externalDocs:this.#y)}incoming(e){return this.#e({incomingSchema:e})}outgoing(e){return this.#e({outgoingSchema:e})}query(e){return this.#e({querySchema:e})}headers(e){return this.#e({headerSchema:e})}inject(e){return this.#e({serviceSchemas:e})}authorize(...e){let t;e.length>0&&typeof e[0]=="object"&&e[0]!==null&&"introspect"in e[0]?t=e.slice(1):t=e;let a=this.#t?[...this.#t,...t]:t;return this.#e({authRoles:a})}public(){return this.#e({authRoles:null})}summary(e){return this.#e({summary:e})}description(e){return this.#e({description:e})}tags(...e){return this.#e({tags:e})}operationId(e){return this.#e({operationId:e})}deprecated(){return this.#e({deprecated:!0})}externalDocs(e,t){return this.#e({externalDocs:{url:e,description:t}})}introspect(){return{protocol:"subscription",basePath:this.#s,pathTemplate:this.#a,incomingSchema:this.#n,outgoingSchema:this.#i,querySchema:this.#r,headerSchema:this.#o,serviceSchemas:this.#l,authRoles:this.#t,summary:this.#d,description:this.#h,tags:this.#c,operationId:this.#u,deprecated:this.#p,externalDocs:this.#y}}};function k(n,e){return new u(n,e??"/")}function w(n){return n instanceof u}function se(n,e){let t=[],a=[];for(let s of Object.keys(n)){let i=n[s],o=e[s];for(let y of Object.keys(i)){let d=i[y],l=o[y],h=typeof l=="function"?l:l.handler,c=typeof l=="function"?void 0:l.middlewares;w(d)?a.push({endpoint:d,handler:h,middlewares:c}):t.push({endpoint:d,handler:h,middlewares:c})}}return{_entries:t,_subscriptions:a}}var T=class n{#s;#a;#n;#i;#r;#o;#l;#t;#d;#h;#c;#u;#p;#y;#e;#m;#g;#S;#f;#R;#P;#B;#b;#x;#T;constructor(e,t,a,s,i,o,y=null,d=null,l=null,h=null,c=[],m=null,g=!1,S=null,C=null,A=null,v=null,I=null,D=null,Q=null,K=null,M=null,U=null,F=null,q=[]){this.#s=e,this.#a=t,this.#n=a,this.#i=s,this.#r=i,this.#o=o,this.#l=y,this.#t=d,this.#d=l,this.#h=h,this.#c=c,this.#u=m,this.#p=g,this.#y=S,this.#e=C,this.#m=A,this.#g=v,this.#S=I,this.#f=D,this.#R=Q,this.#P=K,this.#B=M,this.#b=U,this.#x=F,this.#T=q}body(e){return new n(this.#s,this.#a,this.#n,e,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}query(e){return new n(this.#s,this.#a,this.#n,this.#i,e,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}headers(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,e,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}inject(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,e,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}authorize(...e){let t;e.length>0&&typeof e[0]=="object"&&e[0]!==null&&"introspect"in e[0]?t=e.slice(1):t=e;let a=this.#t?[...this.#t,...t]:t;return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,a,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}public(){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,null,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}returns(e){let t=e!=null&&typeof e=="object"&&"introspect"in e?e:null;return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,t??this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}responses(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}summary(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,e,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}description(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,e,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}tags(...e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,e,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}operationId(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,e,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}deprecated(){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,!0,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}example(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,e,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}examples(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,e,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}producesFile(e,t){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,{contentType:e,description:t},this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}upload(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,{maxFileSize:e?.maxFileSize??10*1024*1024,allowedMimeTypes:e?.allowedMimeTypes,maxFileCount:e?.maxFileCount??10},this.#T)}get path(){let e=this.#a,t=this.#n,a;if(typeof t=="string")a=t;else{let{literals:s,segments:i}=t.introspect().templateDefinition,o="";for(let y=0;y<i.length;y++)o+=s[y]+`:${i[y].path}`;o+=s[i.length]??"",a=o}return a==="/"?e||"/":e+a}introspect(){return{method:this.#s,basePath:this.#a,pathTemplate:this.#n,bodySchema:this.#i,querySchema:this.#r,headerSchema:this.#o,serviceSchemas:this.#l,authRoles:this.#t,summary:this.#d,description:this.#h,tags:this.#c,operationId:this.#u,deprecated:this.#p,responseSchema:this.#y,responsesSchemas:this.#e,example:this.#m,examples:this.#g,producesFile:this.#S,produces:this.#f,responseHeaderSchema:this.#R,externalDocs:this.#P,links:this.#B,callbacks:this.#b,fileUpload:this.#x,cacheTags:this.#T}}produces(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,e,this.#R,this.#P,this.#B,this.#b,this.#x,this.#T)}responseHeaders(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,e,this.#P,this.#B,this.#b,this.#x,this.#T)}externalDocs(e,t){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,{url:e,description:t},this.#B,this.#b,this.#x,this.#T)}links(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,e,this.#b,this.#x,this.#T)}callbacks(e){return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,e,this.#x,this.#T)}cacheTag(e,t){return this.clearsCacheTag(e,t)}clearsCacheTag(e,t){if(!t)return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,[...this.#T,{name:e,properties:{}}]);let a=Y(this.#n),s=E({paramsSchema:a,bodySchema:this.#i,querySchema:this.#r,headerSchema:this.#o}),i=t(s);if(typeof i!="object"||i===null)throw new Error(`Cache tag "${e}": selector must return an object with property descriptors (e.g. { id: p.query.id }).`);let o=O(e,i);return new n(this.#s,this.#a,this.#n,this.#i,this.#r,this.#o,this.#l,this.#t,this.#d,this.#h,this.#c,this.#u,this.#p,this.#y,this.#e,this.#m,this.#g,this.#S,this.#f,this.#R,this.#P,this.#B,this.#b,this.#x,[...this.#T,o])}};function r(n,e,t,a,s){return new T(n,e,t??"/",null,null,null,null,a??null,s?.summary??null,s?.description??null,s?.tags??[],s?.operationId??null,s?.deprecated??!1,null,null,null,null,null,null,null)}function p(n,e){return{get:t=>r("GET",n,t,e),post:t=>r("POST",n,t,e),put:t=>r("PUT",n,t,e),patch:t=>r("PATCH",n,t,e),delete:t=>r("DELETE",n,t,e),head:t=>r("HEAD",n,t,e),options:t=>r("OPTIONS",n,t,e),public:()=>p(n,null)}}function L(n){return{...p(n,null),authorize(...e){let t;return e.length>0&&typeof e[0]=="object"&&e[0]!==null&&"introspect"in e[0]?t=e.slice(1):t=e,p(n,t)},public(){return p(n,null)}}}function Y(n){if(n&&typeof n!="string"&&typeof n.introspect=="function"){let e=n.introspect();if(e.objectSchema)return e.objectSchema}return null}function N(n){return H}var H={get:(n,e)=>r("GET",n,e),post:(n,e)=>r("POST",n,e),put:(n,e)=>r("PUT",n,e),patch:(n,e)=>r("PATCH",n,e),delete:(n,e)=>r("DELETE",n,e),head:(n,e)=>r("HEAD",n,e),options:(n,e)=>r("OPTIONS",n,e),resource:L,subscription:(n,e)=>k(n,e)};import{object as $,parseString as V}from"@cleverbrush/schema";function j(n){let e=$(n);return((t,...a)=>V(e,s=>s(t,...a)))}function J(n,...e){return n!=null&&Array.isArray(n.raw)?j({})(n):j(n??{})}function ye(n){for(let e of Object.values(n))Object.freeze(e);return Object.freeze(n)}function le(n,e){let t={};for(let a of Object.keys(n))t[a]={...n[a]};for(let a of Object.keys(e))Object.hasOwn(t,a)?t[a]={...t[a],...e[a]}:t[a]={...e[a]};for(let a of Object.values(t))Object.freeze(a);return Object.freeze(t)}function de(n,...e){let t={};for(let a of e)t[a]=n[a],Object.freeze(t[a]);return Object.freeze(t)}function he(n,...e){let t=new Set(e),a={};for(let s of Object.keys(n))t.has(s)||(a[s]=n[s],Object.freeze(a[s]));return Object.freeze(a)}export{B as a,E as b,O as c,G as d,ee as e,u as f,se as g,T as h,N as i,H as j,J as k,ye as l,le as m,de as n,he as o};
2
- //# sourceMappingURL=chunk-L2OPVEOF.js.map