@atproto/lex-client 0.2.3 → 0.3.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.
package/dist/util.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import type { InferRecordKey, LexiconRecordKey, RecordSchema } from '@atproto/lex-schema';
2
2
  import type { DidString, Service } from './types.ts';
3
- export declare function applyDefaults<TDefaults extends Record<string, unknown>, TOptions extends {
4
- [K in keyof TDefaults]?: TDefaults[K];
5
- }>(options: TOptions, defaults: TDefaults): TOptions & TDefaults;
3
+ type NonReadonly<T> = {
4
+ -readonly [K in keyof T]: T[K];
5
+ };
6
+ export type WithDefaults<TOptions extends Record<string, unknown>, TDefaults extends Record<string, unknown>[]> = TDefaults extends [infer First, ...infer Rest extends any[]] ? TOptions & WithDefaults<NonReadonly<First>, Rest> : TOptions;
7
+ export declare function applyDefaults<TOptions extends Readonly<Record<string, unknown>>, TDefaults extends Readonly<Record<string, unknown>>[]>(options: TOptions, ...defaults: TDefaults): WithDefaults<TOptions, TDefaults>;
6
8
  /**
7
9
  * Type guard to check if a value is {@link Blob}-like.
8
10
  *
@@ -16,24 +18,55 @@ export declare function isBlobLike(value: unknown): value is Blob;
16
18
  export declare function isAsyncIterable<T>(value: T): value is unknown extends T ? T & AsyncIterable<unknown> : Extract<T, AsyncIterable<any>>;
17
19
  export declare function asUint8ArrayArrayBuffer(bytes: Uint8Array): Uint8Array<ArrayBuffer>;
18
20
  export type XrpcRequestHeadersOptions = {
19
- /** Additional HTTP headers to include in the request. */
21
+ /**
22
+ * Additional custom HTTP headers to include in the request.
23
+ *
24
+ * @note "atproto-proxy" and "atproto-accept-labelers" headers might change
25
+ * depending on the `service` and `labelers` options, respectively, if they
26
+ * are provided (which is always the case when using {@link Client.xrpc}).
27
+ */
20
28
  headers?: HeadersInit;
21
- /** Labeler DIDs to request labels from for content moderation. */
22
- labelers?: Iterable<DidString>;
23
- /** Service proxy identifier for routing requests through a specific service. */
24
- service?: Service;
29
+ /**
30
+ * Labeler DIDs to request labels from for content moderation.
31
+ *
32
+ * When `undefined`, will default to the client instance's default. When
33
+ * `null`, it will cause any existing `atproto-accept-labelers` header
34
+ * (including one provided through the
35
+ * {@link XrpcRequestHeadersOptions.headers} option) to be removed.
36
+ */
37
+ labelers?: null | Iterable<DidString>;
38
+ /**
39
+ * Labeler DIDs to request labels from for content moderation. Values here
40
+ * will always be applied with the ";redact" suffix, which indicates that the
41
+ * client is requesting that the labeler redact content that is deemed
42
+ * inappropriate.
43
+ */
44
+ appLabelers?: null | Iterable<DidString>;
45
+ /**
46
+ * Service proxy identifier for routing requests through a specific service.
47
+ *
48
+ * When `undefined`, will default to the client instance's default. When not
49
+ * used against a client instance (e.g., when using the {@link xrpc} helper
50
+ * function), the default is to not alter the `atproto-proxy` header (e.g. if
51
+ * one is provided in the {@link XrpcRequestHeadersOptions.headers}).
52
+ *
53
+ * When defined (as either `null` or a string), it will override any
54
+ * `atproto-proxy` header provided in the
55
+ * {@link XrpcRequestHeadersOptions.headers} option.
56
+ */
57
+ service?: null | Service;
25
58
  };
26
59
  /**
27
60
  * Builds HTTP headers for AT Protocol requests.
28
61
  *
29
- * Adds the following headers when applicable:
62
+ * Adds or removes the following headers based on the provided options:
30
63
  * - `atproto-proxy`: Service routing header (if service is specified)
31
64
  * - `atproto-accept-labelers`: Comma-separated list of labeler DIDs
32
65
  *
33
66
  * @see {@link XrpcRequestHeadersOptions}
34
67
  * @returns A new Headers object with AT Protocol headers added
35
68
  */
36
- export declare function buildXrpcRequestHeaders(options: XrpcRequestHeadersOptions): Headers;
69
+ export declare function buildXrpcRequestHeaders({ service, labelers, appLabelers, headers: headersInit, }: XrpcRequestHeadersOptions): Headers;
37
70
  export declare function toReadableStream(data: AsyncIterable<Uint8Array>): ReadableStream<Uint8Array>;
38
71
  export declare function toReadableStreamPonyfill(data: AsyncIterable<Uint8Array>): ReadableStream<Uint8Array>;
39
72
  export type RecordKeyOptions<T extends RecordSchema, AlsoOptionalWhenRecordKeyIs extends LexiconRecordKey = never> = T['key'] extends `literal:${string}` | AlsoOptionalWhenRecordKeyIs ? {
@@ -43,7 +76,10 @@ export type RecordKeyOptions<T extends RecordSchema, AlsoOptionalWhenRecordKeyIs
43
76
  };
44
77
  export declare function getDefaultRecordKey<const T extends RecordSchema>(schema: T): undefined | InferRecordKey<T>;
45
78
  export declare function getLiteralRecordKey<const T extends RecordSchema>(schema: T): InferRecordKey<T>;
79
+ export declare function mergeHeaders(defaultHeaders: HeadersInit, requestHeaders: HeadersInit): Headers;
46
80
  export declare function wait(ms: number, { signal }?: {
47
81
  signal?: AbortSignal;
48
82
  }): Promise<void>;
83
+ export declare function trim(value: string): string;
84
+ export {};
49
85
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,YAAY,EACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpD,wBAAgB,aAAa,CAC3B,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzC,QAAQ,SAAS;KACd,CAAC,IAAI,MAAM,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;CACtC,EACD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAY9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CAexD;AAED,wBAAgB,eAAe,CAAC,CAAC,EAC/B,KAAK,EAAE,CAAC,GACP,KAAK,IAAI,OAAO,SAAS,CAAC,GACzB,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,GAC1B,OAAO,CAAC,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAIjC;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,UAAU,GAChB,UAAU,CAAC,WAAW,CAAC,CASzB;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,yDAAyD;IACzD,OAAO,CAAC,EAAE,WAAW,CAAA;IAErB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAA;IAE9B,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAiBT;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,GAC9B,cAAc,CAAC,UAAU,CAAC,CAU5B;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,GAC9B,cAAc,CAAC,UAAU,CAAC,CAmB5B;AAED,MAAM,MAAM,gBAAgB,CAC1B,CAAC,SAAS,YAAY,EACtB,2BAA2B,SAAS,gBAAgB,GAAG,KAAK,IAC1D,CAAC,CAAC,KAAK,CAAC,SAAS,WAAW,MAAM,EAAE,GAAG,2BAA2B,GAClE;IAAE,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;CAAE,CAAA;AAE/B,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,CAAC,SAAS,YAAY,EAC9D,MAAM,EAAE,CAAC,GACR,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,CAM/B;AAED,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,CAAC,SAAS,YAAY,EAC9D,MAAM,EAAE,CAAC,GACR,cAAc,CAAC,CAAC,CAAC,CAQnB;AAED,wBAAgB,IAAI,CAClB,EAAE,EAAE,MAAM,EACV,EAAE,MAAM,EAAE,GAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GACxC,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
package/dist/util.js CHANGED
@@ -1,10 +1,13 @@
1
- export function applyDefaults(options, defaults) {
1
+ export function applyDefaults(options, ...defaults) {
2
2
  const combined = { ...options };
3
3
  // @NOTE We make sure that options with an explicit `undefined` value get the
4
- // default, since spreading doesn't override with `undefined`.
5
- for (const key of Object.keys(defaults)) {
6
- if (options[key] === undefined) {
7
- combined[key] = defaults[key];
4
+ // default, since spreading doesn't override with `undefined`. When multiple
5
+ // defaults define the same key, the first defined value wins.
6
+ for (const def of defaults) {
7
+ for (const key of Object.keys(def)) {
8
+ if (combined[key] === undefined) {
9
+ combined[key] = def[key];
10
+ }
8
11
  }
9
12
  }
10
13
  return combined;
@@ -49,22 +52,58 @@ export function asUint8ArrayArrayBuffer(bytes) {
49
52
  /**
50
53
  * Builds HTTP headers for AT Protocol requests.
51
54
  *
52
- * Adds the following headers when applicable:
55
+ * Adds or removes the following headers based on the provided options:
53
56
  * - `atproto-proxy`: Service routing header (if service is specified)
54
57
  * - `atproto-accept-labelers`: Comma-separated list of labeler DIDs
55
58
  *
56
59
  * @see {@link XrpcRequestHeadersOptions}
57
60
  * @returns A new Headers object with AT Protocol headers added
58
61
  */
59
- export function buildXrpcRequestHeaders(options) {
60
- const headers = new Headers(options?.headers);
61
- if (options.service && !headers.has('atproto-proxy')) {
62
- headers.set('atproto-proxy', options.service);
62
+ export function buildXrpcRequestHeaders({ service, labelers, appLabelers, headers: headersInit, }) {
63
+ const headers = new Headers(headersInit);
64
+ // If provided, the "service" option overrides any existing "atproto-proxy"
65
+ // header. If `null`, the header is removed entirely.
66
+ if (service !== undefined) {
67
+ if (service === null) {
68
+ headers.delete('atproto-proxy');
69
+ }
70
+ else {
71
+ headers.set('atproto-proxy', service);
72
+ }
73
+ }
74
+ // Labelers are combined from the "appLabelers" and "labelers" options, as
75
+ // well as any existing "atproto-accept-labelers" header. The "appLabelers"
76
+ // are always added with the ";redact" suffix, while the "labelers" are added
77
+ // as-is. Existing labelers headers are not preserved if the "labelers" option
78
+ // is explicitly set to null.
79
+ const combinedLabelers = new Set();
80
+ if (appLabelers) {
81
+ for (const labeler of appLabelers) {
82
+ combinedLabelers.add(`${labeler};redact`);
83
+ }
84
+ }
85
+ if (labelers) {
86
+ for (const labeler of labelers) {
87
+ combinedLabelers.add(labeler);
88
+ }
63
89
  }
64
- if (options.labelers) {
65
- headers.set('atproto-accept-labelers', [...options.labelers, headers.get('atproto-accept-labelers')?.trim()]
66
- .filter(Boolean)
67
- .join(', '));
90
+ if (labelers !== null) {
91
+ const headersLabelers = headers.get('atproto-accept-labelers');
92
+ if (headersLabelers) {
93
+ for (const labeler of headersLabelers
94
+ .split(',')
95
+ .map(trim)
96
+ .filter(Boolean)) {
97
+ if (labeler)
98
+ combinedLabelers.add(labeler);
99
+ }
100
+ }
101
+ }
102
+ if (combinedLabelers.size > 0) {
103
+ headers.set('atproto-accept-labelers', Array.from(combinedLabelers).join(', '));
104
+ }
105
+ else {
106
+ headers.delete('atproto-accept-labelers');
68
107
  }
69
108
  return headers;
70
109
  }
@@ -114,6 +153,17 @@ export function getLiteralRecordKey(schema) {
114
153
  }
115
154
  throw new TypeError(`An "rkey" must be provided for record key type "${schema.key}" (${schema.$type})`);
116
155
  }
156
+ export function mergeHeaders(defaultHeaders, requestHeaders) {
157
+ // We don't want to alter the original Headers objects, so we create a new one
158
+ const result = new Headers(defaultHeaders);
159
+ const overrides = requestHeaders instanceof Headers
160
+ ? requestHeaders
161
+ : new Headers(requestHeaders);
162
+ for (const [key, value] of overrides.entries()) {
163
+ result.set(key, value);
164
+ }
165
+ return result;
166
+ }
117
167
  export function wait(ms, { signal } = {}) {
118
168
  return new Promise((resolve, reject) => {
119
169
  signal?.throwIfAborted();
@@ -138,4 +188,7 @@ export function wait(ms, { signal } = {}) {
138
188
  signal?.addEventListener('abort', onAbort);
139
189
  });
140
190
  }
191
+ export function trim(value) {
192
+ return value.trim();
193
+ }
141
194
  //# sourceMappingURL=util.js.map
package/dist/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,aAAa,CAK3B,OAAiB,EAAE,QAAmB;IACtC,MAAM,QAAQ,GAAuB,EAAE,GAAG,OAAO,EAAE,CAAA;IAEnD,6EAA6E;IAC7E,8DAA8D;IAC9D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAA8B,EAAE,CAAC;QACrE,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;YAC/B,QAAQ,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,QAAgC,CAAA;AACzC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,KAAK,CAAA;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,OAAO,IAAI,KAAK,UAAU,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,IAAI,CAAA;IAEpE,yEAAyE;IACzE,qCAAqC;IACrC,4GAA4G;IAE5G,MAAM,GAAG,GAAI,KAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IAC9C,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACrC,OAAO,QAAQ,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,UAAU,CAAA;IAChE,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,KAAQ;IAIR,OAAO,CACL,KAAK,IAAI,IAAI,IAAI,OAAQ,KAAa,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,UAAU,CAC5E,CAAA;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,KAAiB;IAEjB,8EAA8E;IAC9E,eAAe;IACf,IAAI,KAAK,CAAC,MAAM,YAAY,WAAW,EAAE,CAAC;QACxC,OAAO,KAAgC,CAAA;IACzC,CAAC;IAED,oEAAoE;IACpE,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;AAC9B,CAAC;AAaD;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAkC;IAElC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAE7C,IAAI,OAAO,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/C,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CACT,yBAAyB,EACzB,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,EAAE,IAAI,EAAE,CAAC;aAClE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,IAAI,CAAC,CACd,CAAA;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAA+B;IAE/B,qDAAqD;IAErD,iCAAiC;IACjC,IAAI,MAAM,IAAI,cAAc,IAAI,OAAO,cAAc,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC1E,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC;IAED,iCAAiC;IACjC,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,IAA+B;IAE/B,IAAI,QAA+C,CAAA;IACnD,OAAO,IAAI,cAAc,CAAa;QACpC,KAAK,CAAC,IAAI,CAAC,UAAU;YACnB,IAAI,CAAC;gBACH,QAAQ,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAA;gBACzC,MAAM,MAAM,GAAG,MAAM,QAAS,CAAC,IAAI,EAAE,CAAA;gBACrC,IAAI,MAAM,CAAC,IAAI;oBAAE,UAAU,CAAC,KAAK,EAAE,CAAA;;oBAC9B,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACvC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBACrB,QAAQ,GAAG,SAAS,CAAA;YACtB,CAAC;QACH,CAAC;QACD,KAAK,CAAC,MAAM;YACV,MAAM,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAA;YAC1B,QAAQ,GAAG,SAAS,CAAA;QACtB,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AASD,MAAM,UAAU,mBAAmB,CACjC,MAAS;IAET,kCAAkC;IAClC,IAAI,MAAM,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,SAAS,CAAA;IAC1C,IAAI,MAAM,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,SAAS,CAAA;IAE1C,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAA;AACpC,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAS;IAET,IAAI,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAsB,CAAA;IACjD,CAAC;IAED,MAAM,IAAI,SAAS,CACjB,mDAAmD,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,KAAK,GAAG,CACnF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,IAAI,CAClB,EAAU,EACV,EAAE,MAAM,EAAE,GAA6B,EAAE;IAEzC,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,MAAM,EAAE,cAAc,EAAE,CAAA;QAExB,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,YAAY,CAAC,OAAO,CAAC,CAAA;YACrB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAC/C,CAAC,CAAA;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,OAAO,EAAE,CAAA;YACT,OAAO,EAAE,CAAA;QACX,CAAC,EAAE,EAAE,CAAC,CAAA;QAEN,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,OAAO,EAAE,CAAA;YACT,MAAM;YACJ,uEAAuE;YACvE,MAAM,EAAE,MAAM;gBACZ,0CAA0C;gBAC1C,CAAC,OAAO,YAAY,KAAK,WAAW;oBAClC,CAAC,CAAC,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC;oBAC3C,CAAC,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAC5B,CAAA;QACH,CAAC,CAAA;QAED,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAC5C,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import type {\n InferRecordKey,\n LexiconRecordKey,\n RecordSchema,\n} from '@atproto/lex-schema'\nimport type { DidString, Service } from './types.ts'\n\nexport function applyDefaults<\n TDefaults extends Record<string, unknown>,\n TOptions extends {\n [K in keyof TDefaults]?: TDefaults[K]\n },\n>(options: TOptions, defaults: TDefaults): TOptions & TDefaults {\n const combined: Partial<TDefaults> = { ...options }\n\n // @NOTE We make sure that options with an explicit `undefined` value get the\n // default, since spreading doesn't override with `undefined`.\n for (const key of Object.keys(defaults) as (keyof typeof defaults)[]) {\n if (options[key] === undefined) {\n combined[key] = defaults[key]\n }\n }\n\n return combined as TOptions & TDefaults\n}\n\n/**\n * Type guard to check if a value is {@link Blob}-like.\n *\n * Handles both native Blobs and polyfilled Blob implementations\n * (e.g., fetch-blob from node-fetch).\n *\n * @param value - The value to check\n * @returns `true` if the value is a Blob or Blob-like object\n */\nexport function isBlobLike(value: unknown): value is Blob {\n if (value == null) return false\n if (typeof value !== 'object') return false\n if (typeof Blob === 'function' && value instanceof Blob) return true\n\n // Support for Blobs provided by libraries that don't use the native Blob\n // (e.g. fetch-blob from node-fetch).\n // https://github.com/node-fetch/fetch-blob/blob/a1a182e5978811407bef4ea1632b517567dda01f/index.js#L233-L244\n\n const tag = (value as any)[Symbol.toStringTag]\n if (tag === 'Blob' || tag === 'File') {\n return 'stream' in value && typeof value.stream === 'function'\n }\n\n return false\n}\n\nexport function isAsyncIterable<T>(\n value: T,\n): value is unknown extends T\n ? T & AsyncIterable<unknown>\n : Extract<T, AsyncIterable<any>> {\n return (\n value != null && typeof (value as any)[Symbol.asyncIterator] === 'function'\n )\n}\n\nexport function asUint8ArrayArrayBuffer(\n bytes: Uint8Array,\n): Uint8Array<ArrayBuffer> {\n // If the Uint8Array is already backed by a non-shared ArrayBuffer, we can use\n // it directly.\n if (bytes.buffer instanceof ArrayBuffer) {\n return bytes as Uint8Array<ArrayBuffer>\n }\n\n // Otherwise, we need to create a new ArrayBuffer and copy the data.\n return new Uint8Array(bytes)\n}\n\nexport type XrpcRequestHeadersOptions = {\n /** Additional HTTP headers to include in the request. */\n headers?: HeadersInit\n\n /** Labeler DIDs to request labels from for content moderation. */\n labelers?: Iterable<DidString>\n\n /** Service proxy identifier for routing requests through a specific service. */\n service?: Service\n}\n\n/**\n * Builds HTTP headers for AT Protocol requests.\n *\n * Adds the following headers when applicable:\n * - `atproto-proxy`: Service routing header (if service is specified)\n * - `atproto-accept-labelers`: Comma-separated list of labeler DIDs\n *\n * @see {@link XrpcRequestHeadersOptions}\n * @returns A new Headers object with AT Protocol headers added\n */\nexport function buildXrpcRequestHeaders(\n options: XrpcRequestHeadersOptions,\n): Headers {\n const headers = new Headers(options?.headers)\n\n if (options.service && !headers.has('atproto-proxy')) {\n headers.set('atproto-proxy', options.service)\n }\n\n if (options.labelers) {\n headers.set(\n 'atproto-accept-labelers',\n [...options.labelers, headers.get('atproto-accept-labelers')?.trim()]\n .filter(Boolean)\n .join(', '),\n )\n }\n\n return headers\n}\n\nexport function toReadableStream(\n data: AsyncIterable<Uint8Array>,\n): ReadableStream<Uint8Array> {\n // Use the native ReadableStream.from() if available.\n\n /* v8 ignore next -- @preserve */\n if ('from' in ReadableStream && typeof ReadableStream.from === 'function') {\n return ReadableStream.from(data)\n }\n\n /* v8 ignore next -- @preserve */\n return toReadableStreamPonyfill(data)\n}\n\nexport function toReadableStreamPonyfill(\n data: AsyncIterable<Uint8Array>,\n): ReadableStream<Uint8Array> {\n let iterator: AsyncIterator<Uint8Array> | undefined\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n iterator ??= data[Symbol.asyncIterator]()\n const result = await iterator!.next()\n if (result.done) controller.close()\n else controller.enqueue(result.value)\n } catch (err) {\n controller.error(err)\n iterator = undefined\n }\n },\n async cancel() {\n await iterator?.return?.()\n iterator = undefined\n },\n })\n}\n\nexport type RecordKeyOptions<\n T extends RecordSchema,\n AlsoOptionalWhenRecordKeyIs extends LexiconRecordKey = never,\n> = T['key'] extends `literal:${string}` | AlsoOptionalWhenRecordKeyIs\n ? { rkey?: InferRecordKey<T> }\n : { rkey: InferRecordKey<T> }\n\nexport function getDefaultRecordKey<const T extends RecordSchema>(\n schema: T,\n): undefined | InferRecordKey<T> {\n // Let the server generate the TID\n if (schema.key === 'tid') return undefined\n if (schema.key === 'any') return undefined\n\n return getLiteralRecordKey(schema)\n}\n\nexport function getLiteralRecordKey<const T extends RecordSchema>(\n schema: T,\n): InferRecordKey<T> {\n if (schema.key.startsWith('literal:')) {\n return schema.key.slice(8) as InferRecordKey<T>\n }\n\n throw new TypeError(\n `An \"rkey\" must be provided for record key type \"${schema.key}\" (${schema.$type})`,\n )\n}\n\nexport function wait(\n ms: number,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n signal?.throwIfAborted()\n\n const cleanup = () => {\n clearTimeout(timeout)\n signal?.removeEventListener('abort', onAbort)\n }\n\n const timeout = setTimeout(() => {\n cleanup()\n resolve()\n }, ms)\n\n const onAbort = () => {\n cleanup()\n reject(\n // @NOTE the signal exists, and the reason should be set at this point.\n signal?.reason ??\n // React Native does not have DOMException\n (typeof DOMException !== 'undefined'\n ? new DOMException('Aborted', 'AbortError')\n : new Error('Aborted')),\n )\n }\n\n signal?.addEventListener('abort', onAbort)\n })\n}\n"]}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n InferRecordKey,\n LexiconRecordKey,\n RecordSchema,\n} from '@atproto/lex-schema'\nimport type { DidString, Service } from './types.ts'\n\ntype NonReadonly<T> = { -readonly [K in keyof T]: T[K] }\n\nexport type WithDefaults<\n TOptions extends Record<string, unknown>,\n TDefaults extends Record<string, unknown>[],\n> = TDefaults extends [infer First, ...infer Rest extends any[]]\n ? TOptions & WithDefaults<NonReadonly<First>, Rest>\n : TOptions\n\nexport function applyDefaults<\n TOptions extends Readonly<Record<string, unknown>>,\n TDefaults extends Readonly<Record<string, unknown>>[],\n>(\n options: TOptions,\n ...defaults: TDefaults\n): WithDefaults<TOptions, TDefaults> {\n const combined: Record<string, unknown> = { ...options }\n\n // @NOTE We make sure that options with an explicit `undefined` value get the\n // default, since spreading doesn't override with `undefined`. When multiple\n // defaults define the same key, the first defined value wins.\n for (const def of defaults) {\n for (const key of Object.keys(def) as (keyof typeof def)[]) {\n if (combined[key] === undefined) {\n combined[key] = def[key]\n }\n }\n }\n\n return combined as WithDefaults<TOptions, TDefaults>\n}\n\n/**\n * Type guard to check if a value is {@link Blob}-like.\n *\n * Handles both native Blobs and polyfilled Blob implementations\n * (e.g., fetch-blob from node-fetch).\n *\n * @param value - The value to check\n * @returns `true` if the value is a Blob or Blob-like object\n */\nexport function isBlobLike(value: unknown): value is Blob {\n if (value == null) return false\n if (typeof value !== 'object') return false\n if (typeof Blob === 'function' && value instanceof Blob) return true\n\n // Support for Blobs provided by libraries that don't use the native Blob\n // (e.g. fetch-blob from node-fetch).\n // https://github.com/node-fetch/fetch-blob/blob/a1a182e5978811407bef4ea1632b517567dda01f/index.js#L233-L244\n\n const tag = (value as any)[Symbol.toStringTag]\n if (tag === 'Blob' || tag === 'File') {\n return 'stream' in value && typeof value.stream === 'function'\n }\n\n return false\n}\n\nexport function isAsyncIterable<T>(\n value: T,\n): value is unknown extends T\n ? T & AsyncIterable<unknown>\n : Extract<T, AsyncIterable<any>> {\n return (\n value != null && typeof (value as any)[Symbol.asyncIterator] === 'function'\n )\n}\n\nexport function asUint8ArrayArrayBuffer(\n bytes: Uint8Array,\n): Uint8Array<ArrayBuffer> {\n // If the Uint8Array is already backed by a non-shared ArrayBuffer, we can use\n // it directly.\n if (bytes.buffer instanceof ArrayBuffer) {\n return bytes as Uint8Array<ArrayBuffer>\n }\n\n // Otherwise, we need to create a new ArrayBuffer and copy the data.\n return new Uint8Array(bytes)\n}\n\nexport type XrpcRequestHeadersOptions = {\n /**\n * Additional custom HTTP headers to include in the request.\n *\n * @note \"atproto-proxy\" and \"atproto-accept-labelers\" headers might change\n * depending on the `service` and `labelers` options, respectively, if they\n * are provided (which is always the case when using {@link Client.xrpc}).\n */\n headers?: HeadersInit\n\n /**\n * Labeler DIDs to request labels from for content moderation.\n *\n * When `undefined`, will default to the client instance's default. When\n * `null`, it will cause any existing `atproto-accept-labelers` header\n * (including one provided through the\n * {@link XrpcRequestHeadersOptions.headers} option) to be removed.\n */\n labelers?: null | Iterable<DidString>\n\n /**\n * Labeler DIDs to request labels from for content moderation. Values here\n * will always be applied with the \";redact\" suffix, which indicates that the\n * client is requesting that the labeler redact content that is deemed\n * inappropriate.\n */\n appLabelers?: null | Iterable<DidString>\n\n /**\n * Service proxy identifier for routing requests through a specific service.\n *\n * When `undefined`, will default to the client instance's default. When not\n * used against a client instance (e.g., when using the {@link xrpc} helper\n * function), the default is to not alter the `atproto-proxy` header (e.g. if\n * one is provided in the {@link XrpcRequestHeadersOptions.headers}).\n *\n * When defined (as either `null` or a string), it will override any\n * `atproto-proxy` header provided in the\n * {@link XrpcRequestHeadersOptions.headers} option.\n */\n service?: null | Service\n}\n\n/**\n * Builds HTTP headers for AT Protocol requests.\n *\n * Adds or removes the following headers based on the provided options:\n * - `atproto-proxy`: Service routing header (if service is specified)\n * - `atproto-accept-labelers`: Comma-separated list of labeler DIDs\n *\n * @see {@link XrpcRequestHeadersOptions}\n * @returns A new Headers object with AT Protocol headers added\n */\nexport function buildXrpcRequestHeaders({\n service,\n labelers,\n appLabelers,\n headers: headersInit,\n}: XrpcRequestHeadersOptions): Headers {\n const headers = new Headers(headersInit)\n\n // If provided, the \"service\" option overrides any existing \"atproto-proxy\"\n // header. If `null`, the header is removed entirely.\n if (service !== undefined) {\n if (service === null) {\n headers.delete('atproto-proxy')\n } else {\n headers.set('atproto-proxy', service)\n }\n }\n\n // Labelers are combined from the \"appLabelers\" and \"labelers\" options, as\n // well as any existing \"atproto-accept-labelers\" header. The \"appLabelers\"\n // are always added with the \";redact\" suffix, while the \"labelers\" are added\n // as-is. Existing labelers headers are not preserved if the \"labelers\" option\n // is explicitly set to null.\n const combinedLabelers = new Set<string>()\n\n if (appLabelers) {\n for (const labeler of appLabelers) {\n combinedLabelers.add(`${labeler};redact`)\n }\n }\n\n if (labelers) {\n for (const labeler of labelers) {\n combinedLabelers.add(labeler)\n }\n }\n\n if (labelers !== null) {\n const headersLabelers = headers.get('atproto-accept-labelers')\n if (headersLabelers) {\n for (const labeler of headersLabelers\n .split(',')\n .map(trim)\n .filter(Boolean)) {\n if (labeler) combinedLabelers.add(labeler)\n }\n }\n }\n\n if (combinedLabelers.size > 0) {\n headers.set(\n 'atproto-accept-labelers',\n Array.from(combinedLabelers).join(', '),\n )\n } else {\n headers.delete('atproto-accept-labelers')\n }\n\n return headers\n}\n\nexport function toReadableStream(\n data: AsyncIterable<Uint8Array>,\n): ReadableStream<Uint8Array> {\n // Use the native ReadableStream.from() if available.\n\n /* v8 ignore next -- @preserve */\n if ('from' in ReadableStream && typeof ReadableStream.from === 'function') {\n return ReadableStream.from(data)\n }\n\n /* v8 ignore next -- @preserve */\n return toReadableStreamPonyfill(data)\n}\n\nexport function toReadableStreamPonyfill(\n data: AsyncIterable<Uint8Array>,\n): ReadableStream<Uint8Array> {\n let iterator: AsyncIterator<Uint8Array> | undefined\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n iterator ??= data[Symbol.asyncIterator]()\n const result = await iterator!.next()\n if (result.done) controller.close()\n else controller.enqueue(result.value)\n } catch (err) {\n controller.error(err)\n iterator = undefined\n }\n },\n async cancel() {\n await iterator?.return?.()\n iterator = undefined\n },\n })\n}\n\nexport type RecordKeyOptions<\n T extends RecordSchema,\n AlsoOptionalWhenRecordKeyIs extends LexiconRecordKey = never,\n> = T['key'] extends `literal:${string}` | AlsoOptionalWhenRecordKeyIs\n ? { rkey?: InferRecordKey<T> }\n : { rkey: InferRecordKey<T> }\n\nexport function getDefaultRecordKey<const T extends RecordSchema>(\n schema: T,\n): undefined | InferRecordKey<T> {\n // Let the server generate the TID\n if (schema.key === 'tid') return undefined\n if (schema.key === 'any') return undefined\n\n return getLiteralRecordKey(schema)\n}\n\nexport function getLiteralRecordKey<const T extends RecordSchema>(\n schema: T,\n): InferRecordKey<T> {\n if (schema.key.startsWith('literal:')) {\n return schema.key.slice(8) as InferRecordKey<T>\n }\n\n throw new TypeError(\n `An \"rkey\" must be provided for record key type \"${schema.key}\" (${schema.$type})`,\n )\n}\n\nexport function mergeHeaders(\n defaultHeaders: HeadersInit,\n requestHeaders: HeadersInit,\n): Headers {\n // We don't want to alter the original Headers objects, so we create a new one\n const result = new Headers(defaultHeaders)\n\n const overrides =\n requestHeaders instanceof Headers\n ? requestHeaders\n : new Headers(requestHeaders)\n\n for (const [key, value] of overrides.entries()) {\n result.set(key, value)\n }\n\n return result\n}\n\nexport function wait(\n ms: number,\n { signal }: { signal?: AbortSignal } = {},\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n signal?.throwIfAborted()\n\n const cleanup = () => {\n clearTimeout(timeout)\n signal?.removeEventListener('abort', onAbort)\n }\n\n const timeout = setTimeout(() => {\n cleanup()\n resolve()\n }, ms)\n\n const onAbort = () => {\n cleanup()\n reject(\n // @NOTE the signal exists, and the reason should be set at this point.\n signal?.reason ??\n // React Native does not have DOMException\n (typeof DOMException !== 'undefined'\n ? new DOMException('Aborted', 'AbortError')\n : new Error('Aborted')),\n )\n }\n\n signal?.addEventListener('abort', onAbort)\n })\n}\n\nexport function trim(value: string): string {\n return value.trim()\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/lex-client",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "description": "HTTP client for interacting with Lexicon based APIs",
6
6
  "keywords": [
@@ -33,13 +33,13 @@
33
33
  "dependencies": {
34
34
  "tslib": "^2.8.1",
35
35
  "@atproto/lex-data": "^0.1.5",
36
- "@atproto/lex-json": "^0.1.4",
37
- "@atproto/lex-schema": "^0.2.1"
36
+ "@atproto/lex-schema": "^0.2.2",
37
+ "@atproto/lex-json": "^0.1.4"
38
38
  },
39
39
  "devDependencies": {
40
40
  "vitest": "^4.0.16",
41
- "@atproto/lex-cbor": "^0.1.4",
42
- "@atproto/lex-builder": "^0.1.7"
41
+ "@atproto/lex-builder": "^0.1.8",
42
+ "@atproto/lex-cbor": "^0.1.4"
43
43
  },
44
44
  "scripts": {
45
45
  "codegen:lex": "node ./scripts/lex-build.mjs",