@procedures/client 0.35.0 → 0.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/http/server/handler.d.ts.map +1 -1
- package/dist/adapters/http/server/handler.js +17 -3
- package/dist/adapters/http/server/handler.js.map +1 -1
- package/dist/adapters/port/transport.d.ts.map +1 -1
- package/dist/adapters/port/transport.js +2 -0
- package/dist/adapters/port/transport.js.map +1 -1
- package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/server/transport.js +2 -0
- package/dist/adapters/websocket/server/transport.js.map +1 -1
- package/dist/adapters/websocket/shared/rpc.d.ts.map +1 -1
- package/dist/adapters/websocket/shared/rpc.js +14 -5
- package/dist/adapters/websocket/shared/rpc.js.map +1 -1
- package/dist/browser.d.ts +3 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -1
- package/dist/browser.js.map +1 -1
- package/dist/client/errors/index.d.ts +1 -1
- package/dist/client/errors/index.d.ts.map +1 -1
- package/dist/client/errors/index.js +1 -1
- package/dist/client/errors/index.js.map +1 -1
- package/dist/client/errors/registry.d.ts +10 -0
- package/dist/client/errors/registry.d.ts.map +1 -1
- package/dist/client/errors/registry.js +12 -0
- package/dist/client/errors/registry.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/procedures/collection/changes.d.ts +15 -0
- package/dist/procedures/collection/changes.d.ts.map +1 -1
- package/dist/procedures/collection/changes.js.map +1 -1
- package/dist/server/error-policy.d.ts +96 -0
- package/dist/server/error-policy.d.ts.map +1 -0
- package/dist/server/error-policy.js +196 -0
- package/dist/server/error-policy.js.map +1 -0
- package/dist/server/error-response.d.ts +30 -0
- package/dist/server/error-response.d.ts.map +1 -0
- package/dist/server/error-response.js +90 -0
- package/dist/server/error-response.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/last-resort.d.ts +17 -0
- package/dist/server/last-resort.d.ts.map +1 -0
- package/dist/server/last-resort.js +19 -0
- package/dist/server/last-resort.js.map +1 -0
- package/dist/server/procedure-server.d.ts +3 -11
- package/dist/server/procedure-server.d.ts.map +1 -1
- package/dist/server/procedure-server.js +7 -42
- package/dist/server/procedure-server.js.map +1 -1
- package/dist/server/server.d.ts +43 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +39 -2
- package/dist/server/server.js.map +1 -1
- package/dist/server/types.d.ts +12 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/http/server/handler.ts +18 -3
- package/src/adapters/port/transport.ts +2 -0
- package/src/adapters/websocket/server/transport.ts +2 -0
- package/src/adapters/websocket/shared/rpc.ts +14 -5
- package/src/browser.ts +4 -0
- package/src/client/errors/index.ts +1 -0
- package/src/client/errors/registry.ts +13 -0
- package/src/client/index.ts +1 -0
- package/src/procedures/collection/changes.ts +12 -0
- package/src/server/error-policy.ts +263 -0
- package/src/server/error-response.ts +91 -0
- package/src/server/index.ts +2 -0
- package/src/server/last-resort.ts +23 -0
- package/src/server/procedure-server.ts +8 -41
- package/src/server/server.ts +73 -3
- package/src/server/types.ts +13 -0
package/dist/server/server.js
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { HandlerNotFoundError, ServerError } from "./types.js";
|
|
8
8
|
import { compose } from "../middleware/index.js";
|
|
9
|
+
import { callOf, exposeError, exposedResponse, markLogged, policyActs } from "./error-policy.js";
|
|
10
|
+
import { withRealError } from "./error-response.js";
|
|
11
|
+
/** The request that `onError` gets for an error of a face that failed before it knew the call (CLI-80). */
|
|
12
|
+
const UNKNOWN_REQUEST = { id: "unknown", method: { service: "", operation: "" }, payload: undefined, metadata: {} };
|
|
9
13
|
/**
|
|
10
14
|
* Universal RPC server.
|
|
11
15
|
*
|
|
@@ -127,6 +131,33 @@ export class Server {
|
|
|
127
131
|
* @returns Response in unified format
|
|
128
132
|
*/
|
|
129
133
|
async handle(request) {
|
|
134
|
+
const policy = this.options.errors;
|
|
135
|
+
if (!policyActs(policy))
|
|
136
|
+
return this.handleRaw(request);
|
|
137
|
+
const response = await this.handleRaw(request);
|
|
138
|
+
return exposedResponse(policy, request, response, this.hiddenErrorLog);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The error that the last-resort catch of a face sends (roadmap CLI-80): when `handle()` throws,
|
|
142
|
+
* or the face fails after it. `raw` is the error that the face sends without a policy. Under the
|
|
143
|
+
* option `errors`, `map` runs first, and `"coded"` hides the message of `INTERNAL_ERROR`. The
|
|
144
|
+
* logger gets each hidden error one time. A face calls it through `lastResortError`.
|
|
145
|
+
*/
|
|
146
|
+
exposeError(error, request, raw) {
|
|
147
|
+
return exposeError(this.options.errors, error, callOf(request), (real) => this.hiddenErrorLog(real, request), raw);
|
|
148
|
+
}
|
|
149
|
+
/** The logger of the errors that the error policy hides: `onError`, or `console.error`. */
|
|
150
|
+
hiddenErrorLog = (error, request) => {
|
|
151
|
+
const real = error instanceof Error ? error : new Error(String(error));
|
|
152
|
+
// A face that failed before it knew the call gives no request: onError gets a request of no call
|
|
153
|
+
if (this.options.onError)
|
|
154
|
+
this.options.onError(real, request ?? UNKNOWN_REQUEST);
|
|
155
|
+
// A constant format: the request id comes from the caller (CodeQL js/tainted-format-string)
|
|
156
|
+
else
|
|
157
|
+
console.error("[Server] hidden error of %s: %o", request?.id ?? "a request", real);
|
|
158
|
+
};
|
|
159
|
+
/** The response of a request, before the error policy. */
|
|
160
|
+
async handleRaw(request) {
|
|
130
161
|
// Log request
|
|
131
162
|
if (this.options.onRequest) {
|
|
132
163
|
this.options.onRequest(request);
|
|
@@ -159,9 +190,11 @@ export class Server {
|
|
|
159
190
|
// Log error
|
|
160
191
|
if (this.options.onError) {
|
|
161
192
|
this.options.onError(error, request);
|
|
193
|
+
// The error policy does not log this error again (CLI-80)
|
|
194
|
+
markLogged(error);
|
|
162
195
|
}
|
|
163
196
|
// Convert error to response
|
|
164
|
-
return this.errorToResponse(request
|
|
197
|
+
return this.errorToResponse(request, error);
|
|
165
198
|
}
|
|
166
199
|
}
|
|
167
200
|
/**
|
|
@@ -236,7 +269,11 @@ export class Server {
|
|
|
236
269
|
/**
|
|
237
270
|
* Convert error to response.
|
|
238
271
|
*/
|
|
239
|
-
errorToResponse(
|
|
272
|
+
errorToResponse(request, error) {
|
|
273
|
+
return withRealError(this.errorToStatus(request.id, error), error, request);
|
|
274
|
+
}
|
|
275
|
+
/** The response of an error, without its record for the error policy. */
|
|
276
|
+
errorToStatus(id, error) {
|
|
240
277
|
if (error instanceof HandlerNotFoundError) {
|
|
241
278
|
return {
|
|
242
279
|
id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { Elicit } from "../procedures/elicit.js";
|
|
|
8
8
|
import type { ReportProgress } from "../procedures/progress.js";
|
|
9
9
|
import type { Metadata, Status, Method } from "../client/types.js";
|
|
10
10
|
import type { CapabilityRequest } from "../procedures/types.js";
|
|
11
|
+
import type { ExposedError } from "./error-policy.js";
|
|
11
12
|
export type { Method };
|
|
12
13
|
/**
|
|
13
14
|
* Server request in unified RPC format.
|
|
@@ -35,6 +36,11 @@ export interface ServerRequest<TReq = unknown> {
|
|
|
35
36
|
progress?: ReportProgress | undefined;
|
|
36
37
|
/** Abort signal for cancellation */
|
|
37
38
|
signal?: AbortSignal;
|
|
39
|
+
/**
|
|
40
|
+
* The face that took the request: `"http"`, `"websocket"`, `"port"` or `"mcp"` (roadmap CLI-80). The face
|
|
41
|
+
* sets it, not the caller. The `map` function of the error policy (`errors`) gets it.
|
|
42
|
+
*/
|
|
43
|
+
transport?: string | undefined;
|
|
38
44
|
/**
|
|
39
45
|
* The credentials of the request (roadmap R18). A network face reads them from the request: the
|
|
40
46
|
* bearer token of an `Authorization` header or of the `token` query of a WebSocket connection,
|
|
@@ -188,6 +194,12 @@ export interface ServerDebugReport {
|
|
|
188
194
|
*/
|
|
189
195
|
export interface RequestHandler {
|
|
190
196
|
handle(request: ServerRequest): Promise<ServerResponse>;
|
|
197
|
+
/**
|
|
198
|
+
* The error that the last-resort catch of a face sends, when `handle()` throws or the face fails
|
|
199
|
+
* after it (roadmap CLI-80): `raw` under the error policy of the handler. `Server` has it, and
|
|
200
|
+
* a face calls it through `lastResortError`. Absent: the face sends `raw`.
|
|
201
|
+
*/
|
|
202
|
+
exposeError?(error: unknown, request: ServerRequest | undefined, raw: ExposedError): ExposedError;
|
|
191
203
|
/**
|
|
192
204
|
* How the handler can authenticate a network request with ambient credentials: the cookies that
|
|
193
205
|
* a browser sends by itself, also for a request of another site (CSRF). A network face then
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IAEX,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IAEf,sBAAsB;IACtB,OAAO,EAAE,IAAI,CAAC;IAEd,qDAAqD;IACrD,QAAQ,EAAE,QAAQ,CAAC;IAEnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAEtC,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE/B;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAEtC,+GAA+G;IAC/G,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAElC;;;;OAIG;IACH,SAAS,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAC3C;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,OAAO,MAA2D,CAAC;AAE9F;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IAC3C,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,qGAAqG;IACrG,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IAChE,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IAChE,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IAC9D;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACrD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,iGAAiG;IACjG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,oGAAoG;IACpG,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,oEAAoE;IACpE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC3C;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACpD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,WAAW,GAAG,CACxB,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,KAC5B,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;AAExE,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACjE;AAED,kFAAkF;AAClF,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6BAA6B;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wHAAwH;IACxH,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACjE;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACxD;;;;OAIG;IACH,WAAW,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,SAAS,EAAE,GAAG,EAAE,YAAY,GAAG,YAAY,CAAC;IAClG;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC7D;;;;;OAKG;IACH,QAAQ,CAAC,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IACpE;;;;;;OAMG;IACH,SAAS,CAAC,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CAC1D;AAED;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE,GACpG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtD;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,IAAI,GAAG,OAAO;IAC5C,mCAAmC;IACnC,EAAE,EAAE,MAAM,CAAC;IAEX,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IAEf,iDAAiD;IACjD,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf;;;;OAIG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAE7B,wBAAwB;IACxB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CAC1D,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,2BAA2B;IAC3B,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAE7B,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CACzD,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;AAEnC;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CAC7D,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,KAC3B,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAE9B;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;OAEG;IACH,SAAS,IAAI,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAM,EAAE,MAAM,EAOzB;CACF;AAED;;;GAGG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAGlB,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,OAAO;IAHpC,YACE,OAAO,EAAE,MAAM,EACC,IAAI,GAAE,MAAyB,EAC/B,SAAS,GAAE,OAAe,EAI3C;CACF"}
|
package/dist/server/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAmEzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAkB,MAAM,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;AAiR9F;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAc;QACxB,KAAK,CACH,wBAAwB,UAAU,CAAC,MAAM,CAAC,GACxC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAC7C,EAAE,CACH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAGlB,IAAI;IACJ,SAAS;IAH3B,YACE,OAAe,EACC,IAAI,GAAW,gBAAgB,EAC/B,SAAS,GAAY,KAAK;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;oBAHC,IAAI;yBACJ,SAAS;QAGzB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/client",
|
|
4
|
-
"version": "0.35.
|
|
4
|
+
"version": "0.35.1",
|
|
5
5
|
"description": "Procedures as data for TypeScript: define typed procedures once and call them in process, over HTTP, WebSocket, the CLI or MCP. Streaming, middleware, retries, caching and a JSON program format.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"rpc",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import type { IncomingHttpHeaders, IncomingMessage, ServerResponse as NodeResponse } from "node:http";
|
|
20
20
|
import type { Metadata, Method } from "../../../client/types.js";
|
|
21
21
|
import type { RequestHandler, ServerRequest, ServerResponse } from "../../../server/types.js";
|
|
22
|
+
import { lastResortError } from "../../../server/last-resort.js";
|
|
22
23
|
import { decodeMetadataHeader, METADATA_HEADER_LIMIT } from "../shared/index.js";
|
|
23
24
|
import { ERROR_REGISTRY } from "../../../client/errors/index.js";
|
|
24
25
|
import { assertNamedOrigins, checkBrowserRequest, needsNamedOrigin, type BrowserGuardOptions } from "../../../server/browser-guard.js";
|
|
@@ -396,6 +397,8 @@ export function createProcedureHandler(server: RequestHandler, options: Procedur
|
|
|
396
397
|
method,
|
|
397
398
|
payload,
|
|
398
399
|
metadata,
|
|
400
|
+
// The face of the request, for the error policy of the server (CLI-80)
|
|
401
|
+
transport: "http",
|
|
399
402
|
// A network request: ProcedureServer examines the token and the request hook (R18, CLI-2a).
|
|
400
403
|
// The credentials have the connection of the socket of the request (CLI-71)
|
|
401
404
|
credentials: requestCredentials({ headers: req.headers as Record<string, unknown>, url: req.url, socket: req.socket }),
|
|
@@ -497,6 +500,18 @@ export function createProcedureHandler(server: RequestHandler, options: Procedur
|
|
|
497
500
|
await writeNdjsonStream(res, stream, { signal, keepAlive, errorOf, clock });
|
|
498
501
|
};
|
|
499
502
|
|
|
503
|
+
/**
|
|
504
|
+
* The last resort: an error of `handle()` or of this face after it. The error policy of the
|
|
505
|
+
* server applies here too (CLI-80), and the code of its result gives the HTTP status.
|
|
506
|
+
*/
|
|
507
|
+
const sendLastResort = (res: NodeResponse, error: unknown, request: ServerRequest | undefined, message: string): void => {
|
|
508
|
+
const exposed = lastResortError(server, error, request, { code: "INTERNAL_ERROR", message, retryable: false });
|
|
509
|
+
// The wait of a map result (retryAfterMs) goes out as on the usual error path (CLI-80)
|
|
510
|
+
const wait = exposed.retryAfterMs;
|
|
511
|
+
const metadata = typeof wait === "number" && Number.isFinite(wait) && wait >= 0 ? { "retry-after": wait } : {};
|
|
512
|
+
toHttp({ id: request?.id ?? "unknown", status: { type: "error", code: exposed.code, message: exposed.message, retryable: exposed.retryable === true }, metadata }, res);
|
|
513
|
+
};
|
|
514
|
+
|
|
500
515
|
/** This function serves a request that the handler took. */
|
|
501
516
|
const serve = async (req: IncomingMessage, res: NodeResponse): Promise<void> => {
|
|
502
517
|
if (cors && applyCors(req, res, cors)) return;
|
|
@@ -540,8 +555,8 @@ export function createProcedureHandler(server: RequestHandler, options: Procedur
|
|
|
540
555
|
if (!res.writableFinished) controller.abort();
|
|
541
556
|
requestEnded(controller);
|
|
542
557
|
});
|
|
558
|
+
let serverRequest: ServerRequest | null = null;
|
|
543
559
|
try {
|
|
544
|
-
let serverRequest: ServerRequest | null;
|
|
545
560
|
try {
|
|
546
561
|
serverRequest = toServerRequest(req, await readBody(req));
|
|
547
562
|
} catch (error) {
|
|
@@ -562,7 +577,7 @@ export function createProcedureHandler(server: RequestHandler, options: Procedur
|
|
|
562
577
|
}
|
|
563
578
|
toHttp(serverResponse, res);
|
|
564
579
|
} catch (error) {
|
|
565
|
-
if (!res.headersSent)
|
|
580
|
+
if (!res.headersSent) sendLastResort(res, error, serverRequest ?? undefined, (error as Error).message || "Internal server error");
|
|
566
581
|
} finally {
|
|
567
582
|
// An open response (an error before its end) stays in progress until its close event
|
|
568
583
|
if (res.writableEnded || res.destroyed) requestEnded(controller);
|
|
@@ -572,7 +587,7 @@ export function createProcedureHandler(server: RequestHandler, options: Procedur
|
|
|
572
587
|
/** This function serves a request, and does not reject: an error ends the response with 500. */
|
|
573
588
|
const settle = (req: IncomingMessage, res: NodeResponse): Promise<void> =>
|
|
574
589
|
serve(req, res).catch((error: unknown) => {
|
|
575
|
-
if (!res.headersSent)
|
|
590
|
+
if (!res.headersSent) sendLastResort(res, error, undefined, error instanceof Error ? error.message : String(error));
|
|
576
591
|
else if (!res.writableEnded) res.destroy();
|
|
577
592
|
});
|
|
578
593
|
|
|
@@ -105,6 +105,8 @@ export class PortTransport implements Transport {
|
|
|
105
105
|
payload: frame.payload === undefined ? {} : frame.payload,
|
|
106
106
|
metadata: withoutInternalKeys(frame.metadata),
|
|
107
107
|
signal,
|
|
108
|
+
// The face of the request, for the error policy of the server (CLI-80)
|
|
109
|
+
transport: "port",
|
|
108
110
|
credentials,
|
|
109
111
|
}),
|
|
110
112
|
});
|
|
@@ -496,6 +496,8 @@ export class WebSocketServerTransport implements ServerTransport {
|
|
|
496
496
|
headers: withoutSecretHeaders(req.headers as Record<string, unknown>, this.secretHeaders),
|
|
497
497
|
},
|
|
498
498
|
signal,
|
|
499
|
+
// The face of the request, for the error policy of the server (CLI-80)
|
|
500
|
+
transport: "websocket",
|
|
499
501
|
// The credentials of the connection: the bearer token of its upgrade (R18), its cookies,
|
|
500
502
|
// its headers and its query (CLI-2a)
|
|
501
503
|
credentials,
|
|
@@ -18,6 +18,7 @@ import { withoutInternalKeys } from "../../metadata.js";
|
|
|
18
18
|
import { StreamSequence, gapOf, itemMetadata } from "../../sequence.js";
|
|
19
19
|
import { DELIVERY_METADATA_KEY } from "../../../client/middleware/items.js";
|
|
20
20
|
import { errorCodeOf, foldedErrorCode, retryableOf } from "../../../protocol.js";
|
|
21
|
+
import { lastResortError } from "../../../server/last-resort.js";
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* A queue of response items that one reader takes in order: push, then end or fail. The reader
|
|
@@ -382,8 +383,10 @@ export class IncomingCalls {
|
|
|
382
383
|
const controller = new AbortController();
|
|
383
384
|
this.inflight.set(frame.id, controller);
|
|
384
385
|
let credit: StreamCredit | undefined;
|
|
386
|
+
let request: ServerRequest | undefined;
|
|
385
387
|
try {
|
|
386
|
-
|
|
388
|
+
request = this.options.requestOf(frame, controller.signal);
|
|
389
|
+
const response = await this.options.handler.handle(request);
|
|
387
390
|
if (response.stream) {
|
|
388
391
|
credit = typeof frame.credit === "number" && frame.credit > 0 ? new StreamCredit(frame.credit) : undefined;
|
|
389
392
|
if (credit) this.credits.set(frame.id, credit);
|
|
@@ -402,7 +405,12 @@ export class IncomingCalls {
|
|
|
402
405
|
this.send(out);
|
|
403
406
|
}
|
|
404
407
|
} catch (error) {
|
|
405
|
-
|
|
408
|
+
// The last resort: the error policy of the server applies here too (CLI-80)
|
|
409
|
+
const raw = { code: "INTERNAL_ERROR", message: error instanceof Error ? error.message : "Internal server error", retryable: false };
|
|
410
|
+
const exposed = lastResortError(this.options.handler, error, request, raw);
|
|
411
|
+
// The wait of a map result (retryAfterMs) goes out as on the usual error path (CLI-80)
|
|
412
|
+
const wait = exposed.retryAfterMs;
|
|
413
|
+
this.sendError(frame.id, exposed.message, exposed.code, exposed.retryable === true, typeof wait === "number" && Number.isFinite(wait) && wait >= 0 ? { "retry-after": wait } : undefined);
|
|
406
414
|
} finally {
|
|
407
415
|
// Delete only this request's entries (deep dive TRN-9)
|
|
408
416
|
if (this.inflight.get(frame.id) === controller) {
|
|
@@ -463,12 +471,13 @@ export class IncomingCalls {
|
|
|
463
471
|
if (this.options.isOpen()) this.options.send(frame);
|
|
464
472
|
}
|
|
465
473
|
|
|
466
|
-
private sendError(id: string, message: string, code: string): void {
|
|
474
|
+
private sendError(id: string, message: string, code: string, retryable = false, metadata?: Record<string, unknown>): void {
|
|
467
475
|
this.send({
|
|
468
476
|
id,
|
|
469
477
|
type: "error",
|
|
470
|
-
|
|
471
|
-
|
|
478
|
+
...(metadata ? { metadata } : {}),
|
|
479
|
+
status: { type: "error", code, message, retryable },
|
|
480
|
+
error: { code, message, retryable },
|
|
472
481
|
});
|
|
473
482
|
}
|
|
474
483
|
}
|
package/src/browser.ts
CHANGED
|
@@ -64,6 +64,7 @@ export {
|
|
|
64
64
|
ERROR_REGISTRY,
|
|
65
65
|
getErrorMetadata,
|
|
66
66
|
isKnownError,
|
|
67
|
+
isKnownErrorCode,
|
|
67
68
|
createError,
|
|
68
69
|
createErrorFromHTTPStatus,
|
|
69
70
|
createErrorFromException,
|
|
@@ -76,6 +77,9 @@ export {
|
|
|
76
77
|
// ============================================================================
|
|
77
78
|
export { Server } from "./server/server.js";
|
|
78
79
|
export type { ServerOptions } from "./server/server.js";
|
|
80
|
+
// The error policy of a server: what an error tells the caller (roadmap CLI-80)
|
|
81
|
+
export type { ServerErrorPolicy, ExposedError, ErrorCall } from "./server/error-policy.js";
|
|
82
|
+
export { exposeError, lastResortError, HIDDEN_ERROR_MESSAGE, DEFAULT_KEPT_METADATA } from "./server/error-policy.js";
|
|
79
83
|
export { ProcedureServer, createProcedureServer, STREAM_METADATA_KEY, isUnboundedStream, tokenMatches } from "./server/procedure-server.js";
|
|
80
84
|
// The credentials of a network request (roadmap R18), and the parts that a request hook reads (CLI-2a)
|
|
81
85
|
export { credentialsOf, bearerOf, withoutSecretHeaders, cookiesOf, requestCredentials, LOCAL_CREDENTIALS, isLocalCredentials } from "./server/request-auth.js";
|
|
@@ -643,6 +643,19 @@ export function isKnownError(code: string): boolean {
|
|
|
643
643
|
return code in ERROR_REGISTRY;
|
|
644
644
|
}
|
|
645
645
|
|
|
646
|
+
/**
|
|
647
|
+
* True when a value is a known error code of the client: a code of the wire protocol
|
|
648
|
+
* (`ERROR_CODES`) or another code of `ERROR_REGISTRY`, for example `CONFLICT` or `BAD_REQUEST`
|
|
649
|
+
* (roadmap CLI-80). Only a string can be a known code. A code of the platform (`ECONNREFUSED`,
|
|
650
|
+
* `ENOENT`) and a number (a code of MongoDB) are not known codes.
|
|
651
|
+
*
|
|
652
|
+
* The error policy `expose: "coded"` of a server uses this check: an error with a known code is a
|
|
653
|
+
* deliberate refusal, so its code and its message go to the caller.
|
|
654
|
+
*/
|
|
655
|
+
export function isKnownErrorCode(code: unknown): code is string {
|
|
656
|
+
return typeof code === "string" && Object.prototype.hasOwnProperty.call(ERROR_REGISTRY, code);
|
|
657
|
+
}
|
|
658
|
+
|
|
646
659
|
/**
|
|
647
660
|
* Get all error codes by category.
|
|
648
661
|
*/
|
package/src/client/index.ts
CHANGED
|
@@ -54,6 +54,18 @@ export interface CollectionChangeEvent {
|
|
|
54
54
|
readonly values?: ReadonlyArray<{ readonly id: string; readonly value: unknown }> | undefined;
|
|
55
55
|
/** With the option `values`: the changed ids whose values the filter refused. Read them with `changes`. */
|
|
56
56
|
readonly withheld?: readonly string[] | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* The version of each changed item, as `versionOf(id)` of the storage gives it (roadmap CLI-77).
|
|
59
|
+
* A publisher that knows the versions sets it, for example `watchStorageChanges()` of
|
|
60
|
+
* `@procedures/mongo`. Without it, read the versions with `changes`. A deleted id has no version.
|
|
61
|
+
*/
|
|
62
|
+
readonly versions?: ReadonlyArray<{ readonly id: string; readonly version: string }> | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* True: read the collection in full, with `changes` and no `since` (roadmap CLI-77). A publisher
|
|
65
|
+
* sets it when it cannot tell what changed, for example `watchStorageChanges()` of
|
|
66
|
+
* `@procedures/mongo` after it lost its resume token. A read since the cursor can miss changes.
|
|
67
|
+
*/
|
|
68
|
+
readonly reset?: boolean | undefined;
|
|
57
69
|
/** The origin of the writes, when one origin made all the changes of the event. */
|
|
58
70
|
readonly origin?: string | undefined;
|
|
59
71
|
}
|