@atproto/lex-client 0.0.9 → 0.0.11
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 +30 -0
- package/LICENSE.txt +1 -1
- package/dist/agent.d.ts +5 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +15 -1
- package/dist/agent.js.map +1 -1
- package/dist/client.d.ts +59 -40
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -6
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +52 -51
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +90 -71
- package/dist/errors.js.map +1 -1
- package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts +20 -10
- package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/defs.defs.d.ts +1 -1
- package/dist/lexicons/com/atproto/repo/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts +14 -6
- package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts +12 -4
- package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts +11 -11
- package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/listRecords.defs.js +2 -1
- package/dist/lexicons/com/atproto/repo/listRecords.defs.js.map +1 -1
- package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts +18 -10
- package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts.map +1 -1
- package/dist/response.d.ts +14 -13
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +36 -35
- package/dist/response.js.map +1 -1
- package/dist/util.d.ts +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js.map +1 -1
- package/dist/www-authenticate.d.ts +12 -0
- package/dist/www-authenticate.d.ts.map +1 -0
- package/dist/www-authenticate.js +57 -0
- package/dist/www-authenticate.js.map +1 -0
- package/dist/xrpc.d.ts +14 -21
- package/dist/xrpc.d.ts.map +1 -1
- package/dist/xrpc.js +18 -35
- package/dist/xrpc.js.map +1 -1
- package/package.json +6 -6
- package/src/agent.ts +34 -1
- package/src/client.ts +34 -33
- package/src/errors.ts +161 -128
- package/src/lexicons/com/atproto/repo/listRecords.defs.ts +4 -1
- package/src/response.ts +71 -71
- package/src/util.ts +1 -1
- package/src/www-authenticate.test.ts +227 -0
- package/src/www-authenticate.ts +77 -0
- package/src/xrpc.ts +53 -95
package/dist/xrpc.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.asLexRpcFailure = asLexRpcFailure;
|
|
4
3
|
exports.xrpc = xrpc;
|
|
5
4
|
exports.xrpcSafe = xrpcSafe;
|
|
6
5
|
const lex_data_1 = require("@atproto/lex-data");
|
|
@@ -9,49 +8,33 @@ const lex_schema_1 = require("@atproto/lex-schema");
|
|
|
9
8
|
const errors_js_1 = require("./errors.js");
|
|
10
9
|
const response_js_1 = require("./response.js");
|
|
11
10
|
const util_js_1 = require("./util.js");
|
|
12
|
-
/**
|
|
13
|
-
* Utility method to type cast the error thrown by {@link xrpc} to an
|
|
14
|
-
* {@link LexRpcFailure} matching the provided method. Only use this function
|
|
15
|
-
* inside a catch block right after calling {@link xrpc}, and use the same
|
|
16
|
-
* method type parameter as used in the {@link xrpc} call.
|
|
17
|
-
*/
|
|
18
|
-
function asLexRpcFailure(err) {
|
|
19
|
-
if (err instanceof errors_js_1.LexRpcResponseError)
|
|
20
|
-
return err;
|
|
21
|
-
if (err instanceof errors_js_1.LexRpcUpstreamError)
|
|
22
|
-
return err;
|
|
23
|
-
return errors_js_1.LexRpcUnexpectedError.from(err);
|
|
24
|
-
}
|
|
25
11
|
async function xrpc(agent, ns, options = {}) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
throw
|
|
31
|
-
}
|
|
12
|
+
const response = await xrpcSafe(agent, ns, options);
|
|
13
|
+
if (response.success)
|
|
14
|
+
return response;
|
|
15
|
+
else
|
|
16
|
+
throw response;
|
|
32
17
|
}
|
|
33
18
|
async function xrpcSafe(agent, ns, options = {}) {
|
|
34
|
-
return lexRpcRequest(agent, ns, options).catch((asLexRpcFailure));
|
|
35
|
-
}
|
|
36
|
-
async function lexRpcRequest(agent, ns, options = {}) {
|
|
37
|
-
const method = (0, lex_schema_1.getMain)(ns);
|
|
38
19
|
options.signal?.throwIfAborted();
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
20
|
+
const method = (0, lex_schema_1.getMain)(ns);
|
|
21
|
+
try {
|
|
22
|
+
const url = xrpcRequestUrl(method, options);
|
|
23
|
+
const request = xrpcRequestInit(method, options);
|
|
24
|
+
const response = await agent.fetchHandler(url, request);
|
|
25
|
+
return await response_js_1.XrpcResponse.fromFetchResponse(method, response, options);
|
|
26
|
+
}
|
|
27
|
+
catch (cause) {
|
|
28
|
+
return (0, errors_js_1.asXrpcFailure)(method, cause);
|
|
29
|
+
}
|
|
43
30
|
}
|
|
44
31
|
function xrpcRequestUrl(method, options) {
|
|
45
32
|
const path = `/xrpc/${method.nsid}`;
|
|
46
|
-
const queryString =
|
|
47
|
-
|
|
48
|
-
|
|
33
|
+
const queryString = method.parameters
|
|
34
|
+
?.toURLSearchParams(options.params ?? {})
|
|
35
|
+
.toString();
|
|
49
36
|
return queryString ? `${path}?${queryString}` : path;
|
|
50
37
|
}
|
|
51
|
-
function xrpcRequestParams(schema, params, options) {
|
|
52
|
-
const urlSearchParams = schema?.toURLSearchParams(options.validateRequest ? schema.parse(params) : params);
|
|
53
|
-
return urlSearchParams?.size ? urlSearchParams.toString() : undefined;
|
|
54
|
-
}
|
|
55
38
|
function xrpcRequestInit(schema, options) {
|
|
56
39
|
const headers = (0, util_js_1.buildAtprotoHeaders)(options);
|
|
57
40
|
// Tell the server what type of response we're expecting
|
package/dist/xrpc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xrpc.js","sourceRoot":"","sources":["../src/xrpc.ts"],"names":[],"mappings":";;AAoEA,0CAMC;AAgBD,oBAUC;AAaD,4BAMC;AAvHD,gDAAwE;AACxE,gDAAgD;AAChD,oDAY4B;AAE5B,2CAIoB;AACpB,+CAA8C;AAE9C,uCAMkB;AAiClB;;;;;GAKG;AACH,SAAgB,eAAe,CAE7B,GAAY;IACZ,IAAI,GAAG,YAAY,+BAAmB;QAAE,OAAO,GAAG,CAAA;IAClD,IAAI,GAAG,YAAY,+BAAmB;QAAE,OAAO,GAAG,CAAA;IAClD,OAAO,iCAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACxC,CAAC;AAgBM,KAAK,UAAU,IAAI,CACxB,KAAY,EACZ,EAAW,EACX,UAA4B,EAAsB;IAElD,IAAI,CAAC;QACH,OAAO,MAAM,aAAa,CAAI,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,eAAe,CAAI,GAAG,CAAC,CAAA;IAC/B,CAAC;AACH,CAAC;AAaM,KAAK,UAAU,QAAQ,CAC5B,KAAY,EACZ,EAAW,EACX,UAA4B,EAAsB;IAElD,OAAO,aAAa,CAAI,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAA,eAAkB,CAAA,CAAC,CAAA;AACvE,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,KAAY,EACZ,EAAW,EACX,UAA4B,EAAsB;IAElD,MAAM,MAAM,GAAG,IAAA,oBAAO,EAAC,EAAE,CAAC,CAAA;IAC1B,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAA;IAChC,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACvD,OAAO,4BAAc,CAAC,iBAAiB,CAAI,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;AACvE,CAAC;AAED,SAAS,cAAc,CACrB,MAAS,EACT,OAA0C;IAE1C,MAAM,IAAI,GAAG,SAAS,MAAM,CAAC,IAAI,EAAE,CAAA;IAEnC,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM;QAChC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;QAC/D,CAAC,CAAC,SAAS,CAAA;IAEb,OAAO,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACtD,CAAC;AAED,SAAS,iBAAiB,CACxB,MAAgC,EAChC,MAA0B,EAC1B,OAAoB;IAEpB,MAAM,eAAe,GAAG,MAAM,EAAE,iBAAiB,CAC/C,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,MAAc,CACjE,CAAA;IACD,OAAO,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;AACvE,CAAC;AAED,SAAS,eAAe,CACtB,MAAS,EACT,OAGC;IAED,MAAM,OAAO,GAAG,IAAA,6BAAmB,EAAC,OAAO,CAAC,CAAA;IAE5C,wDAAwD;IACxD,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC/C,CAAC;IAED,4CAA4C;IAC5C,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;QAC/C,MAAM,IAAI,SAAS,CAAC,mCAAmC,WAAW,GAAG,CAAC,CAAA;IACxE,CAAC;IAED,qBAAqB;IACrB,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;QACtB,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAA;QACrC,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAA;QAE/D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC7C,CAAC;aAAM,IAAI,YAAY,IAAI,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,SAAS,CAAC,6BAA6B,YAAY,GAAG,CAAC,CAAA;QACnE,CAAC;QAED,OAAO;YACL,MAAM,EAAE,MAAM;YACd,QAAQ,EAAE,QAAQ;YAClB,cAAc,EAAE,iCAAiC,EAAE,YAAY;YAC/D,IAAI,EAAE,MAAM,EAAE,YAAY;YAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,KAAK,EAAE,IAAI;SAClB,CAAA;IACH,CAAC;IAED,wBAAwB;IACxB,OAAO;QACL,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,QAAQ;QAClB,cAAc,EAAE,iCAAiC,EAAE,YAAY;QAC/D,IAAI,EAAE,MAAM,EAAE,YAAY;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,KAAK;QACb,OAAO;KACR,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB,CACzB,MAAiB,EACjB,OAA2D,EAC3D,YAAqB;IAErB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAA;IACxB,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IAExB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;IAED,kEAAkE;IAClE,IAAI,KAAK,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;QAC1C,uEAAuE;QACvE,mDAAmD;QACnD,IAAI,CAAC,IAAA,sBAAW,EAAC,IAAI,CAAC,IAAI,CAAC,IAAA,wBAAa,EAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACvE,MAAM,IAAI,SAAS,CAAC,+BAA+B,OAAO,IAAI,EAAE,CAAC,CAAA;QACnE,CAAC;QAED,OAAO,YAAY,CAAC,KAAK,EAAE,IAAA,uBAAY,EAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAA;IAC9D,CAAC;IAED,8DAA8D;IAC9D,QAAQ,OAAO,IAAI,EAAE,CAAC;QACpB,KAAK,WAAW,CAAC;QACjB,KAAK,QAAQ;YACX,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;QAChD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,IAAI,KAAK,IAAI;gBAAE,MAAK;YACxB,IACE,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC;gBACxB,IAAI,YAAY,WAAW;gBAC3B,IAAI,YAAY,cAAc,EAC9B,CAAC;gBACD,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;YAChD,CAAC;iBAAM,IAAI,IAAA,yBAAe,EAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,OAAO,YAAY,CAAC,KAAK,EAAE,IAAA,0BAAgB,EAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAA;YAClE,CAAC;iBAAM,IAAI,IAAA,oBAAU,EAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,CAAA;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,SAAS,CACjB,WAAW,OAAO,IAAI,aAAa,KAAK,CAAC,QAAQ,WAAW,CAC7D,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CACnB,MAAkB,EAClB,IAA0B,EAC1B,YAAqB;IAErB,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,SAAS,CACjB,iBAAiB,OAAO,IAAI,+BAA+B,CAC5D,CAAA;QACH,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,0EAA0E;QAC1E,2EAA2E;QAC3E,oEAAoE;QACpE,MAAM,IAAI,SAAS,CAAC,kDAAkD,CAAC,CAAA;IACzE,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACpD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;AAC3B,CAAC;AAED,SAAS,aAAa,CAAC,MAAkB,EAAE,YAAqB;IAC9D,iDAAiD;IACjD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,SAAS,CAAC,oBAAoB,CAAC,CAAA;IAC3C,CAAC;IAED,IAAI,YAAY,EAAE,MAAM,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,SAAS,CACjB,yCAAyC,YAAY,UAAU,MAAM,CAAC,QAAQ,YAAY,CAC3F,CAAA;QACH,CAAC;QACD,OAAO,YAAY,CAAA;IACrB,CAAC;IAED,WAAW;IAEX,IAAI,MAAM,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAC9B,OAAO,0BAA0B,CAAA;IACnC,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;YAClC,CAAC,CAAC,2BAA2B;YAC7B,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,iBAAiB,CAAA;IACzC,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,MAAM,CAAC,QAAQ,CAAA;IACxB,CAAC;IAED,MAAM,IAAI,SAAS,CACjB,yFAAyF,MAAM,CAAC,QAAQ,GAAG,CAC5G,CAAA;AACH,CAAC","sourcesContent":["import { LexValue, isLexScalar, isPlainObject } from '@atproto/lex-data'\nimport { lexStringify } from '@atproto/lex-json'\nimport {\n InferMethodInput,\n InferMethodParams,\n Main,\n Params,\n ParamsSchema,\n Payload as LexPayload,\n Procedure,\n Query,\n Restricted,\n Subscription,\n getMain,\n} from '@atproto/lex-schema'\nimport { Agent } from './agent.js'\nimport {\n LexRpcResponseError,\n LexRpcUnexpectedError,\n LexRpcUpstreamError,\n} from './errors.js'\nimport { LexRpcResponse } from './response.js'\nimport { BinaryBodyInit, CallOptions } from './types.js'\nimport {\n Payload,\n buildAtprotoHeaders,\n isAsyncIterable,\n isBlobLike,\n toReadableStream,\n} from './util.js'\n\n// If all params are optional, allow omitting the params object\ntype LexRpcParamsOptions<P extends Params> =\n NonNullable<unknown> extends P ? { params?: P } : { params: P }\n\ntype LexRpcRequestPayload<M extends Procedure | Query> = InferMethodInput<\n M,\n BinaryBodyInit\n>\n\ntype LexRpcInputOptions<In> = In extends { body: infer B; encoding: infer E }\n ? // encoding will be inferred from the schema at runtime if not provided\n { body: B; encoding?: E }\n : { body?: undefined; encoding?: undefined }\n\nexport type LexRpcOptions<M extends Procedure | Query = Procedure | Query> =\n CallOptions &\n LexRpcInputOptions<LexRpcRequestPayload<M>> &\n LexRpcParamsOptions<InferMethodParams<M>>\n\nexport type LexRpcFailure<M extends Procedure | Query> =\n // The server returned a valid XRPC error response\n | LexRpcResponseError<M>\n // The response was not a valid XRPC response, or it does not match the schema\n | LexRpcUpstreamError\n // Something went wrong (network error, etc.)\n | LexRpcUnexpectedError\n\nexport type LexRpcResult<M extends Procedure | Query> =\n | LexRpcResponse<M>\n | LexRpcFailure<M>\n\n/**\n * Utility method to type cast the error thrown by {@link xrpc} to an\n * {@link LexRpcFailure} matching the provided method. Only use this function\n * inside a catch block right after calling {@link xrpc}, and use the same\n * method type parameter as used in the {@link xrpc} call.\n */\nexport function asLexRpcFailure<\n M extends Procedure | Query = Procedure | Query,\n>(err: unknown): LexRpcFailure<M> {\n if (err instanceof LexRpcResponseError) return err\n if (err instanceof LexRpcUpstreamError) return err\n return LexRpcUnexpectedError.from(err)\n}\n\n/**\n * @throws LexRpcFailure<M>\n */\nexport async function xrpc<const M extends Query | Procedure>(\n agent: Agent,\n ns: NonNullable<unknown> extends LexRpcOptions<M>\n ? Main<M>\n : Restricted<'This XRPC method requires an \"options\" argument'>,\n): Promise<LexRpcResponse<M>>\nexport async function xrpc<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: LexRpcOptions<M>,\n): Promise<LexRpcResponse<M>>\nexport async function xrpc<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: LexRpcOptions<M> = {} as LexRpcOptions<M>,\n): Promise<LexRpcResponse<M>> {\n try {\n return await lexRpcRequest<M>(agent, ns, options)\n } catch (err) {\n throw asLexRpcFailure<M>(err)\n }\n}\n\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agent: Agent,\n ns: NonNullable<unknown> extends LexRpcOptions<M>\n ? Main<M>\n : Restricted<'This XRPC method requires an \"options\" argument'>,\n): Promise<LexRpcResult<M>>\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: LexRpcOptions<M>,\n): Promise<LexRpcResult<M>>\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: LexRpcOptions<M> = {} as LexRpcOptions<M>,\n): Promise<LexRpcResult<M>> {\n return lexRpcRequest<M>(agent, ns, options).catch(asLexRpcFailure<M>)\n}\n\nasync function lexRpcRequest<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: LexRpcOptions<M> = {} as LexRpcOptions<M>,\n): Promise<LexRpcResponse<M>> {\n const method = getMain(ns)\n options.signal?.throwIfAborted()\n const url = xrpcRequestUrl(method, options)\n const request = xrpcRequestInit(method, options)\n const response = await agent.fetchHandler(url, request)\n return LexRpcResponse.fromFetchResponse<M>(method, response, options)\n}\n\nfunction xrpcRequestUrl<M extends Procedure | Query | Subscription>(\n method: M,\n options: CallOptions & { params?: Params },\n) {\n const path = `/xrpc/${method.nsid}`\n\n const queryString = options.params\n ? xrpcRequestParams(method.parameters, options.params, options)\n : undefined\n\n return queryString ? `${path}?${queryString}` : path\n}\n\nfunction xrpcRequestParams(\n schema: ParamsSchema | undefined,\n params: Params | undefined,\n options: CallOptions,\n): undefined | string {\n const urlSearchParams = schema?.toURLSearchParams(\n options.validateRequest ? schema.parse(params) : (params as any),\n )\n return urlSearchParams?.size ? urlSearchParams.toString() : undefined\n}\n\nfunction xrpcRequestInit<T extends Procedure | Query>(\n schema: T,\n options: CallOptions & {\n body?: LexValue | BinaryBodyInit\n encoding?: string\n },\n): RequestInit & { duplex?: 'half' } {\n const headers = buildAtprotoHeaders(options)\n\n // Tell the server what type of response we're expecting\n if (schema.output.encoding) {\n headers.set('accept', schema.output.encoding)\n }\n\n // Caller should not set content-type header\n if (headers.has('content-type')) {\n const contentType = headers.get('content-type')\n throw new TypeError(`Unexpected content-type header (${contentType})`)\n }\n\n // Requests with body\n if ('input' in schema) {\n const encodingHint = options.encoding\n const input = xrpcProcedureInput(schema, options, encodingHint)\n\n if (input) {\n headers.set('content-type', input.encoding)\n } else if (encodingHint != null) {\n throw new TypeError(`Unexpected encoding hint (${encodingHint})`)\n }\n\n return {\n duplex: 'half',\n redirect: 'follow',\n referrerPolicy: 'strict-origin-when-cross-origin', // (default)\n mode: 'cors', // (default)\n signal: options.signal,\n method: 'POST',\n headers,\n body: input?.body,\n }\n }\n\n // Requests without body\n return {\n duplex: 'half',\n redirect: 'follow',\n referrerPolicy: 'strict-origin-when-cross-origin', // (default)\n mode: 'cors', // (default)\n signal: options.signal,\n method: 'GET',\n headers,\n }\n}\n\nfunction xrpcProcedureInput(\n method: Procedure,\n options: CallOptions & { body?: LexValue | BinaryBodyInit },\n encodingHint?: string,\n): null | Payload<BodyInit> {\n const { input } = method\n const { body } = options\n\n if (options.validateRequest) {\n input.schema?.check(body)\n }\n\n // Special handling for endpoints expecting application/json input\n if (input.encoding === 'application/json') {\n // @NOTE **NOT** using isLexValue here to avoid deep checks in order to\n // distinguish between LexValue and BinaryBodyInit.\n if (!isLexScalar(body) && !isPlainObject(body) && !Array.isArray(body)) {\n throw new TypeError(`Expected LexValue body, got ${typeof body}`)\n }\n\n return buildPayload(input, lexStringify(body), encodingHint)\n }\n\n // Other encodings will be sent unaltered (ie. as binary data)\n switch (typeof body) {\n case 'undefined':\n case 'string':\n return buildPayload(input, body, encodingHint)\n case 'object': {\n if (body === null) break\n if (\n ArrayBuffer.isView(body) ||\n body instanceof ArrayBuffer ||\n body instanceof ReadableStream\n ) {\n return buildPayload(input, body, encodingHint)\n } else if (isAsyncIterable(body)) {\n return buildPayload(input, toReadableStream(body), encodingHint)\n } else if (isBlobLike(body)) {\n return buildPayload(input, body, encodingHint || body.type)\n }\n }\n }\n\n throw new TypeError(\n `Invalid ${typeof body} body for ${input.encoding} encoding`,\n )\n}\n\nfunction buildPayload(\n schema: LexPayload,\n body: undefined | BodyInit,\n encodingHint?: string,\n): null | Payload<BodyInit> {\n if (schema.encoding === undefined) {\n if (body !== undefined) {\n throw new TypeError(\n `Cannot send a ${typeof body} body with undefined encoding`,\n )\n }\n\n return null\n }\n\n if (body === undefined) {\n // This error would be returned by the server, but we can catch it earlier\n // to avoid un-necessary requests. Note that a content-length of 0 does not\n // necessary mean that the body is \"empty\" (e.g. an empty txt file).\n throw new TypeError(`A request body is expected but none was provided`)\n }\n\n const encoding = buildEncoding(schema, encodingHint)\n return { encoding, body }\n}\n\nfunction buildEncoding(schema: LexPayload, encodingHint?: string): string {\n // Should never happen (required for type safety)\n if (!schema.encoding) {\n throw new TypeError('Unexpected payload')\n }\n\n if (encodingHint?.length) {\n if (!schema.matchesEncoding(encodingHint)) {\n throw new TypeError(\n `Cannot send a body with content-type \"${encodingHint}\" for \"${schema.encoding}\" encoding`,\n )\n }\n return encodingHint\n }\n\n // Fallback\n\n if (schema.encoding === '*/*') {\n return 'application/octet-stream'\n }\n\n if (schema.encoding.startsWith('text/')) {\n return schema.encoding.includes('*')\n ? 'text/plain; charset=utf-8'\n : `${schema.encoding}; charset=utf-8`\n }\n\n if (!schema.encoding.includes('*')) {\n return schema.encoding\n }\n\n throw new TypeError(\n `Unable to determine payload encoding. Please provide a 'content-type' header matching ${schema.encoding}.`,\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"xrpc.js","sourceRoot":"","sources":["../src/xrpc.ts"],"names":[],"mappings":"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","sourcesContent":["import { LexValue, isLexScalar, isPlainObject } from '@atproto/lex-data'\nimport { lexStringify } from '@atproto/lex-json'\nimport {\n InferInput,\n InferPayload,\n Main,\n Params,\n Payload,\n Procedure,\n Query,\n Restricted,\n Subscription,\n getMain,\n} from '@atproto/lex-schema'\nimport { Agent } from './agent.js'\nimport { XrpcFailure, asXrpcFailure } from './errors.js'\nimport { XrpcResponse } from './response.js'\nimport { BinaryBodyInit, CallOptions } from './types.js'\nimport {\n XrpcPayload,\n buildAtprotoHeaders,\n isAsyncIterable,\n isBlobLike,\n toReadableStream,\n} from './util.js'\n\n// If all params are optional, allow omitting the params object\ntype XrpcParamsOptions<P extends Params> =\n NonNullable<unknown> extends P ? { params?: P } : { params: P }\n\nexport type XrpcRequestParams<M extends Procedure | Query | Subscription> =\n InferInput<M['parameters']>\n\ntype XrpcRequestPayload<M extends Procedure | Query> = M extends Procedure\n ? InferPayload<M['input'], BinaryBodyInit>\n : undefined\n\ntype XrpcInputOptions<In> = In extends { body: infer B; encoding: infer E }\n ? // encoding will be inferred from the schema at runtime if not provided\n { body: B; encoding?: E }\n : { body?: undefined; encoding?: undefined }\n\nexport type XrpcOptions<M extends Procedure | Query = Procedure | Query> =\n CallOptions &\n XrpcInputOptions<XrpcRequestPayload<M>> &\n XrpcParamsOptions<XrpcRequestParams<M>>\n\n/**\n * @throws XrpcFailure<M>\n */\nexport async function xrpc<const M extends Query | Procedure>(\n agent: Agent,\n ns: NonNullable<unknown> extends XrpcOptions<M>\n ? Main<M>\n : Restricted<'This XRPC method requires an \"options\" argument'>,\n): Promise<XrpcResponse<M>>\nexport async function xrpc<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: XrpcOptions<M>,\n): Promise<XrpcResponse<M>>\nexport async function xrpc<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: XrpcOptions<M> = {} as XrpcOptions<M>,\n): Promise<XrpcResponse<M>> {\n const response = await xrpcSafe<M>(agent, ns, options)\n if (response.success) return response\n else throw response\n}\n\nexport type XrpcResult<M extends Procedure | Query> =\n | XrpcResponse<M>\n | XrpcFailure<M>\n\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agent: Agent,\n ns: NonNullable<unknown> extends XrpcOptions<M>\n ? Main<M>\n : Restricted<'This XRPC method requires an \"options\" argument'>,\n): Promise<XrpcResult<M>>\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: XrpcOptions<M>,\n): Promise<XrpcResult<M>>\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agent: Agent,\n ns: Main<M>,\n options: XrpcOptions<M> = {} as XrpcOptions<M>,\n): Promise<XrpcResult<M>> {\n options.signal?.throwIfAborted()\n const method: M = getMain(ns)\n try {\n const url = xrpcRequestUrl(method, options)\n const request = xrpcRequestInit(method, options)\n const response = await agent.fetchHandler(url, request)\n return await XrpcResponse.fromFetchResponse<M>(method, response, options)\n } catch (cause) {\n return asXrpcFailure(method, cause)\n }\n}\n\nfunction xrpcRequestUrl<M extends Procedure | Query | Subscription>(\n method: M,\n options: CallOptions & { params?: Params },\n) {\n const path = `/xrpc/${method.nsid}`\n\n const queryString = method.parameters\n ?.toURLSearchParams(options.params ?? {})\n .toString()\n\n return queryString ? `${path}?${queryString}` : path\n}\n\nfunction xrpcRequestInit<T extends Procedure | Query>(\n schema: T,\n options: CallOptions & {\n body?: LexValue | BinaryBodyInit\n encoding?: string\n },\n): RequestInit & { duplex?: 'half' } {\n const headers = buildAtprotoHeaders(options)\n\n // Tell the server what type of response we're expecting\n if (schema.output.encoding) {\n headers.set('accept', schema.output.encoding)\n }\n\n // Caller should not set content-type header\n if (headers.has('content-type')) {\n const contentType = headers.get('content-type')\n throw new TypeError(`Unexpected content-type header (${contentType})`)\n }\n\n // Requests with body\n if ('input' in schema) {\n const encodingHint = options.encoding\n const input = xrpcProcedureInput(schema, options, encodingHint)\n\n if (input) {\n headers.set('content-type', input.encoding)\n } else if (encodingHint != null) {\n throw new TypeError(`Unexpected encoding hint (${encodingHint})`)\n }\n\n return {\n duplex: 'half',\n redirect: 'follow',\n referrerPolicy: 'strict-origin-when-cross-origin', // (default)\n mode: 'cors', // (default)\n signal: options.signal,\n method: 'POST',\n headers,\n body: input?.body,\n }\n }\n\n // Requests without body\n return {\n duplex: 'half',\n redirect: 'follow',\n referrerPolicy: 'strict-origin-when-cross-origin', // (default)\n mode: 'cors', // (default)\n signal: options.signal,\n method: 'GET',\n headers,\n }\n}\n\nfunction xrpcProcedureInput(\n method: Procedure,\n options: CallOptions & { body?: LexValue | BinaryBodyInit },\n encodingHint?: string,\n): null | XrpcPayload<BodyInit> {\n const { input } = method\n const { body } = options\n\n if (options.validateRequest) {\n input.schema?.check(body)\n }\n\n // Special handling for endpoints expecting application/json input\n if (input.encoding === 'application/json') {\n // @NOTE **NOT** using isLexValue here to avoid deep checks in order to\n // distinguish between LexValue and BinaryBodyInit.\n if (!isLexScalar(body) && !isPlainObject(body) && !Array.isArray(body)) {\n throw new TypeError(`Expected LexValue body, got ${typeof body}`)\n }\n\n return buildPayload(input, lexStringify(body), encodingHint)\n }\n\n // Other encodings will be sent unaltered (ie. as binary data)\n switch (typeof body) {\n case 'undefined':\n case 'string':\n return buildPayload(input, body, encodingHint)\n case 'object': {\n if (body === null) break\n if (\n ArrayBuffer.isView(body) ||\n body instanceof ArrayBuffer ||\n body instanceof ReadableStream\n ) {\n return buildPayload(input, body, encodingHint)\n } else if (isAsyncIterable(body)) {\n return buildPayload(input, toReadableStream(body), encodingHint)\n } else if (isBlobLike(body)) {\n return buildPayload(input, body, encodingHint || body.type)\n }\n }\n }\n\n throw new TypeError(\n `Invalid ${typeof body} body for ${input.encoding} encoding`,\n )\n}\n\nfunction buildPayload(\n schema: Payload,\n body: undefined | BodyInit,\n encodingHint?: string,\n): null | XrpcPayload<BodyInit> {\n if (schema.encoding === undefined) {\n if (body !== undefined) {\n throw new TypeError(\n `Cannot send a ${typeof body} body with undefined encoding`,\n )\n }\n\n return null\n }\n\n if (body === undefined) {\n // This error would be returned by the server, but we can catch it earlier\n // to avoid un-necessary requests. Note that a content-length of 0 does not\n // necessary mean that the body is \"empty\" (e.g. an empty txt file).\n throw new TypeError(`A request body is expected but none was provided`)\n }\n\n const encoding = buildEncoding(schema, encodingHint)\n return { encoding, body }\n}\n\nfunction buildEncoding(schema: Payload, encodingHint?: string): string {\n // Should never happen (required for type safety)\n if (!schema.encoding) {\n throw new TypeError('Unexpected payload')\n }\n\n if (encodingHint?.length) {\n if (!schema.matchesEncoding(encodingHint)) {\n throw new TypeError(\n `Cannot send a body with content-type \"${encodingHint}\" for \"${schema.encoding}\" encoding`,\n )\n }\n return encodingHint\n }\n\n // Fallback\n\n if (schema.encoding === '*/*') {\n return 'application/octet-stream'\n }\n\n if (schema.encoding.startsWith('text/')) {\n return schema.encoding.includes('*')\n ? 'text/plain; charset=utf-8'\n : `${schema.encoding}; charset=utf-8`\n }\n\n if (!schema.encoding.includes('*')) {\n return schema.encoding\n }\n\n throw new TypeError(\n `Unable to determine payload encoding. Please provide a 'content-type' header matching ${schema.encoding}.`,\n )\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/lex-client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "HTTP client for interacting with Lexicon based APIs",
|
|
6
6
|
"keywords": [
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"tslib": "^2.8.1",
|
|
40
|
-
"@atproto/lex-data": "0.0.
|
|
41
|
-
"@atproto/lex-json": "0.0.
|
|
42
|
-
"@atproto/lex-schema": "0.0.
|
|
40
|
+
"@atproto/lex-data": "^0.0.10",
|
|
41
|
+
"@atproto/lex-json": "^0.0.10",
|
|
42
|
+
"@atproto/lex-schema": "^0.0.11"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"vitest": "^4.0.16",
|
|
46
|
-
"@atproto/lex-cbor": "0.0.
|
|
47
|
-
"@atproto/lex-builder": "0.0.
|
|
46
|
+
"@atproto/lex-cbor": "^0.0.10",
|
|
47
|
+
"@atproto/lex-builder": "^0.0.13"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"prebuild": "node ./scripts/lex-build.mjs",
|
package/src/agent.ts
CHANGED
|
@@ -28,6 +28,12 @@ export type AgentConfig = {
|
|
|
28
28
|
*/
|
|
29
29
|
service: string | URL
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Optional headers to include with every request made by this agent, unless
|
|
33
|
+
* overridden by the request-specific headers provided to the fetch handler.
|
|
34
|
+
*/
|
|
35
|
+
headers?: HeadersInit
|
|
36
|
+
|
|
31
37
|
/**
|
|
32
38
|
* Bring your own fetch implementation. Typically useful for testing, logging,
|
|
33
39
|
* mocking, or adding retries, session management, signatures, proof of
|
|
@@ -61,7 +67,34 @@ export function buildAgent(options: Agent | AgentOptions): Agent {
|
|
|
61
67
|
},
|
|
62
68
|
|
|
63
69
|
async fetchHandler(path, init) {
|
|
64
|
-
|
|
70
|
+
const headers =
|
|
71
|
+
config.headers != null && init.headers != null
|
|
72
|
+
? mergeHeaders(config.headers, init.headers)
|
|
73
|
+
: config.headers || init.headers
|
|
74
|
+
|
|
75
|
+
return fetch(
|
|
76
|
+
new URL(path, service),
|
|
77
|
+
headers !== init.headers ? { ...init, headers } : init,
|
|
78
|
+
)
|
|
65
79
|
},
|
|
66
80
|
}
|
|
67
81
|
}
|
|
82
|
+
|
|
83
|
+
function mergeHeaders(
|
|
84
|
+
defaultHeaders: HeadersInit,
|
|
85
|
+
requestHeaders: HeadersInit,
|
|
86
|
+
): Headers {
|
|
87
|
+
// We don't want to alter the original Headers objects, so we create a new one
|
|
88
|
+
const result = new Headers(defaultHeaders)
|
|
89
|
+
|
|
90
|
+
const overrides =
|
|
91
|
+
requestHeaders instanceof Headers
|
|
92
|
+
? requestHeaders
|
|
93
|
+
: new Headers(requestHeaders)
|
|
94
|
+
|
|
95
|
+
for (const [key, value] of overrides.entries()) {
|
|
96
|
+
result.set(key, value)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return result
|
|
100
|
+
}
|
package/src/client.ts
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
Infer,
|
|
7
7
|
InferMethodInputBody,
|
|
8
8
|
InferMethodOutputBody,
|
|
9
|
-
InferMethodParams,
|
|
10
9
|
InferRecordKey,
|
|
11
10
|
LexiconRecordKey,
|
|
12
11
|
Main,
|
|
@@ -16,15 +15,16 @@ import {
|
|
|
16
15
|
Query,
|
|
17
16
|
RecordSchema,
|
|
18
17
|
Restricted,
|
|
19
|
-
|
|
18
|
+
UnknownObject,
|
|
20
19
|
getMain,
|
|
21
20
|
} from '@atproto/lex-schema'
|
|
22
21
|
import { Agent, AgentOptions, buildAgent } from './agent.js'
|
|
22
|
+
import { XrpcFailure } from './errors.js'
|
|
23
23
|
import { com } from './lexicons/index.js'
|
|
24
|
-
import {
|
|
24
|
+
import { XrpcResponse, XrpcResponseBody } from './response.js'
|
|
25
25
|
import { BinaryBodyInit, CallOptions, Service } from './types.js'
|
|
26
26
|
import { buildAtprotoHeaders } from './util.js'
|
|
27
|
-
import {
|
|
27
|
+
import { XrpcOptions, XrpcRequestParams, xrpc, xrpcSafe } from './xrpc.js'
|
|
28
28
|
|
|
29
29
|
export type {
|
|
30
30
|
AtIdentifierString,
|
|
@@ -32,7 +32,6 @@ export type {
|
|
|
32
32
|
DidString,
|
|
33
33
|
InferMethodInputBody,
|
|
34
34
|
InferMethodOutputBody,
|
|
35
|
-
InferMethodParams,
|
|
36
35
|
InferRecordKey,
|
|
37
36
|
LexMap,
|
|
38
37
|
LexValue,
|
|
@@ -43,7 +42,6 @@ export type {
|
|
|
43
42
|
Query,
|
|
44
43
|
RecordSchema,
|
|
45
44
|
Restricted,
|
|
46
|
-
Schema,
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
export type ClientOptions = {
|
|
@@ -100,7 +98,7 @@ export type RecordKeyOptions<
|
|
|
100
98
|
: { rkey: InferRecordKey<T> }
|
|
101
99
|
|
|
102
100
|
export type CreateOptions<T extends RecordSchema> = CreateRecordOptions &
|
|
103
|
-
RecordKeyOptions<T, 'tid'>
|
|
101
|
+
RecordKeyOptions<T, 'tid' | 'any'>
|
|
104
102
|
export type CreateOutput = InferMethodOutputBody<
|
|
105
103
|
typeof com.atproto.repo.createRecord.main,
|
|
106
104
|
Uint8Array
|
|
@@ -133,8 +131,8 @@ export type ListOutput<T extends RecordSchema> = InferMethodOutputBody<
|
|
|
133
131
|
> & {
|
|
134
132
|
records: ListRecord<Infer<T>>[]
|
|
135
133
|
// @NOTE Because the schema uses "type": "unknown" instead of an open union,
|
|
136
|
-
// we have to use
|
|
137
|
-
invalid:
|
|
134
|
+
// we have to use UnknownObject instead of Unknown$TypedObject here.
|
|
135
|
+
invalid: UnknownObject[]
|
|
138
136
|
}
|
|
139
137
|
export type ListRecord<Value extends LexMap> =
|
|
140
138
|
com.atproto.repo.listRecords.Record & {
|
|
@@ -211,37 +209,37 @@ export class Client implements Agent {
|
|
|
211
209
|
}
|
|
212
210
|
|
|
213
211
|
/**
|
|
214
|
-
* @throws {
|
|
212
|
+
* @throws {XrpcFailure<M>} when the request fails or the response is an error
|
|
215
213
|
*/
|
|
216
214
|
async xrpc<const M extends Query | Procedure>(
|
|
217
|
-
ns: NonNullable<unknown> extends
|
|
215
|
+
ns: NonNullable<unknown> extends XrpcOptions<M>
|
|
218
216
|
? Main<M>
|
|
219
217
|
: Restricted<'This XRPC method requires an "options" argument'>,
|
|
220
|
-
): Promise<
|
|
218
|
+
): Promise<XrpcResponse<M>>
|
|
221
219
|
async xrpc<const M extends Query | Procedure>(
|
|
222
220
|
ns: Main<M>,
|
|
223
|
-
options:
|
|
224
|
-
): Promise<
|
|
221
|
+
options: XrpcOptions<M>,
|
|
222
|
+
): Promise<XrpcResponse<M>>
|
|
225
223
|
async xrpc<const M extends Query | Procedure>(
|
|
226
224
|
ns: Main<M>,
|
|
227
|
-
options:
|
|
228
|
-
): Promise<
|
|
225
|
+
options: XrpcOptions<M> = {} as XrpcOptions<M>,
|
|
226
|
+
): Promise<XrpcResponse<M>> {
|
|
229
227
|
return xrpc(this, ns, options)
|
|
230
228
|
}
|
|
231
229
|
|
|
232
230
|
async xrpcSafe<const M extends Query | Procedure>(
|
|
233
|
-
ns: NonNullable<unknown> extends
|
|
231
|
+
ns: NonNullable<unknown> extends XrpcOptions<M>
|
|
234
232
|
? Main<M>
|
|
235
233
|
: Restricted<'This XRPC method requires an "options" argument'>,
|
|
236
|
-
): Promise<
|
|
234
|
+
): Promise<XrpcResponse<M> | XrpcFailure<M>>
|
|
237
235
|
async xrpcSafe<const M extends Query | Procedure>(
|
|
238
236
|
ns: Main<M>,
|
|
239
|
-
options:
|
|
240
|
-
): Promise<
|
|
237
|
+
options: XrpcOptions<M>,
|
|
238
|
+
): Promise<XrpcResponse<M> | XrpcFailure<M>>
|
|
241
239
|
async xrpcSafe<const M extends Query | Procedure>(
|
|
242
240
|
ns: Main<M>,
|
|
243
|
-
options:
|
|
244
|
-
): Promise<
|
|
241
|
+
options: XrpcOptions<M> = {} as XrpcOptions<M>,
|
|
242
|
+
): Promise<XrpcResponse<M> | XrpcFailure<M>> {
|
|
245
243
|
return xrpcSafe(this, ns, options)
|
|
246
244
|
}
|
|
247
245
|
|
|
@@ -348,10 +346,15 @@ export class Client implements Agent {
|
|
|
348
346
|
}
|
|
349
347
|
|
|
350
348
|
public async call<const T extends Query>(
|
|
351
|
-
ns: NonNullable<unknown> extends
|
|
349
|
+
ns: NonNullable<unknown> extends XrpcRequestParams<T>
|
|
352
350
|
? Main<T>
|
|
353
351
|
: Restricted<'This query type requires a "params" argument'>,
|
|
354
|
-
): Promise<
|
|
352
|
+
): Promise<XrpcResponseBody<T>>
|
|
353
|
+
public async call<const T extends Procedure>(
|
|
354
|
+
ns: undefined extends InferMethodInputBody<T, Uint8Array>
|
|
355
|
+
? Main<T>
|
|
356
|
+
: Restricted<'This procedure type requires an "input" argument'>,
|
|
357
|
+
): Promise<XrpcResponseBody<T>>
|
|
355
358
|
public async call<const T extends Action>(
|
|
356
359
|
ns: void extends InferActionInput<T>
|
|
357
360
|
? Main<T>
|
|
@@ -364,16 +367,16 @@ export class Client implements Agent {
|
|
|
364
367
|
: T extends Procedure
|
|
365
368
|
? InferMethodInputBody<T, Uint8Array>
|
|
366
369
|
: T extends Query
|
|
367
|
-
?
|
|
370
|
+
? XrpcRequestParams<T>
|
|
368
371
|
: never,
|
|
369
372
|
options?: CallOptions,
|
|
370
373
|
): Promise<
|
|
371
374
|
T extends Action
|
|
372
375
|
? InferActionOutput<T>
|
|
373
376
|
: T extends Procedure
|
|
374
|
-
?
|
|
377
|
+
? XrpcResponseBody<T>
|
|
375
378
|
: T extends Query
|
|
376
|
-
?
|
|
379
|
+
? XrpcResponseBody<T>
|
|
377
380
|
: never
|
|
378
381
|
>
|
|
379
382
|
public async call(
|
|
@@ -415,8 +418,7 @@ export class Client implements Agent {
|
|
|
415
418
|
options: CreateOptions<T> = {} as CreateOptions<T>,
|
|
416
419
|
): Promise<CreateOutput> {
|
|
417
420
|
const schema: T = getMain(ns)
|
|
418
|
-
const record = schema.build(input)
|
|
419
|
-
if (options.validateRequest) schema.assert(record)
|
|
421
|
+
const record = schema.build(input) as { $type: NsidString } & LexMap
|
|
420
422
|
const rkey = options.rkey ?? getDefaultRecordKey(schema)
|
|
421
423
|
if (rkey !== undefined) schema.keySchema.assert(rkey)
|
|
422
424
|
const response = await this.createRecord(record, rkey, options)
|
|
@@ -462,7 +464,7 @@ export class Client implements Agent {
|
|
|
462
464
|
options.rkey ?? getLiteralRecordKey(schema),
|
|
463
465
|
)
|
|
464
466
|
const response = await this.getRecord(schema.$type, rkey, options)
|
|
465
|
-
const value = schema.
|
|
467
|
+
const value = schema.validate(response.body.value)
|
|
466
468
|
return { ...response.body, value }
|
|
467
469
|
}
|
|
468
470
|
|
|
@@ -483,8 +485,7 @@ export class Client implements Agent {
|
|
|
483
485
|
options: PutOptions<T> = {} as PutOptions<T>,
|
|
484
486
|
): Promise<PutOutput> {
|
|
485
487
|
const schema: T = getMain(ns)
|
|
486
|
-
const record = schema.build(input)
|
|
487
|
-
if (options.validateRequest) schema.assert(record)
|
|
488
|
+
const record = schema.build(input) as { $type: NsidString } & LexMap
|
|
488
489
|
const rkey = options.rkey ?? getLiteralRecordKey(schema)
|
|
489
490
|
const response = await this.putRecord(record, rkey, options)
|
|
490
491
|
return response.body
|
|
@@ -501,7 +502,7 @@ export class Client implements Agent {
|
|
|
501
502
|
const invalid: LexMap[] = []
|
|
502
503
|
|
|
503
504
|
for (const record of body.records) {
|
|
504
|
-
const parsed =
|
|
505
|
+
const parsed = schema.safeValidate(record.value)
|
|
505
506
|
if (parsed.success) {
|
|
506
507
|
records.push({ ...record, value: parsed.value })
|
|
507
508
|
} else {
|