@fedify/webfinger 2.0.0-dev.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/mod.cjs ADDED
@@ -0,0 +1,183 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ const __fedify_vocab_runtime = __toESM(require("@fedify/vocab-runtime"));
25
+ const __logtape_logtape = __toESM(require("@logtape/logtape"));
26
+ const __opentelemetry_api = __toESM(require("@opentelemetry/api"));
27
+
28
+ //#region deno.json
29
+ var name = "@fedify/webfinger";
30
+ var version = "2.0.0";
31
+ var license = "MIT";
32
+ var exports$1 = { ".": "./src/mod.ts" };
33
+ var description = "WebFinger client library for Fedify";
34
+ var author = {
35
+ "name": "Hong Minhee",
36
+ "email": "hong@minhee.org",
37
+ "url": "https://hongminhee.org/"
38
+ };
39
+ var imports = {
40
+ "es-toolkit": "npm:es-toolkit@^1.42.0",
41
+ "fetch-mock": "npm:fetch-mock@^12.5.4"
42
+ };
43
+ var exclude = ["dist", "node_modules"];
44
+ var tasks = {
45
+ "check": "deno fmt --check && deno lint && deno check src/*.ts",
46
+ "test": "deno test"
47
+ };
48
+ var deno_default = {
49
+ name,
50
+ version,
51
+ license,
52
+ exports: exports$1,
53
+ description,
54
+ author,
55
+ imports,
56
+ exclude,
57
+ tasks
58
+ };
59
+
60
+ //#endregion
61
+ //#region src/lookup.ts
62
+ const logger = (0, __logtape_logtape.getLogger)([
63
+ "fedify",
64
+ "webfinger",
65
+ "lookup"
66
+ ]);
67
+ const DEFAULT_MAX_REDIRECTION = 5;
68
+ /**
69
+ * Looks up a WebFinger resource.
70
+ * @param resource The resource URL to look up.
71
+ * @param options Extra options for looking up the resource.
72
+ * @returns The resource descriptor, or `null` if not found.
73
+ * @since 0.2.0
74
+ */
75
+ async function lookupWebFinger(resource, options = {}) {
76
+ const tracerProvider = options.tracerProvider ?? __opentelemetry_api.trace.getTracerProvider();
77
+ const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
78
+ return await tracer.startActiveSpan("webfinger.lookup", {
79
+ kind: __opentelemetry_api.SpanKind.CLIENT,
80
+ attributes: {
81
+ "webfinger.resource": resource.toString(),
82
+ "webfinger.resource.scheme": typeof resource === "string" ? resource.replace(/:.*$/, "") : resource.protocol.replace(/:$/, "")
83
+ }
84
+ }, async (span) => {
85
+ try {
86
+ const result = await lookupWebFingerInternal(resource, options);
87
+ span.setStatus({ code: result === null ? __opentelemetry_api.SpanStatusCode.ERROR : __opentelemetry_api.SpanStatusCode.OK });
88
+ return result;
89
+ } catch (error) {
90
+ span.setStatus({
91
+ code: __opentelemetry_api.SpanStatusCode.ERROR,
92
+ message: String(error)
93
+ });
94
+ throw error;
95
+ } finally {
96
+ span.end();
97
+ }
98
+ });
99
+ }
100
+ async function lookupWebFingerInternal(resource, options = {}) {
101
+ if (typeof resource === "string") resource = new URL(resource);
102
+ let protocol = "https:";
103
+ let server;
104
+ if (resource.protocol === "acct:") {
105
+ const atPos = resource.pathname.lastIndexOf("@");
106
+ if (atPos < 0) return null;
107
+ server = resource.pathname.substring(atPos + 1);
108
+ if (server === "") return null;
109
+ } else {
110
+ protocol = resource.protocol;
111
+ server = resource.host;
112
+ }
113
+ let url = new URL(`${protocol}//${server}/.well-known/webfinger`);
114
+ url.searchParams.set("resource", resource.href);
115
+ let redirected = 0;
116
+ while (true) {
117
+ logger.debug("Fetching WebFinger resource descriptor from {url}...", { url: url.href });
118
+ let response;
119
+ if (options.allowPrivateAddress !== true) try {
120
+ await (0, __fedify_vocab_runtime.validatePublicUrl)(url.href);
121
+ } catch (e) {
122
+ if (e instanceof __fedify_vocab_runtime.UrlError) {
123
+ logger.error("Invalid URL for WebFinger resource descriptor: {error}", { error: e });
124
+ return null;
125
+ }
126
+ throw e;
127
+ }
128
+ try {
129
+ response = await fetch(url, {
130
+ headers: {
131
+ Accept: "application/jrd+json",
132
+ "User-Agent": typeof options.userAgent === "string" ? options.userAgent : (0, __fedify_vocab_runtime.getUserAgent)(options.userAgent)
133
+ },
134
+ redirect: "manual",
135
+ signal: options.signal
136
+ });
137
+ } catch (error) {
138
+ logger.debug("Failed to fetch WebFinger resource descriptor: {error}", {
139
+ url: url.href,
140
+ error
141
+ });
142
+ return null;
143
+ }
144
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
145
+ redirected++;
146
+ const maxRedirection = options.maxRedirection ?? DEFAULT_MAX_REDIRECTION;
147
+ if (redirected >= maxRedirection) {
148
+ logger.error("Too many redirections ({redirections}) while fetching WebFinger resource descriptor.", { redirections: redirected });
149
+ return null;
150
+ }
151
+ const redirectedUrl = new URL(response.headers.get("Location"), response.url == null || response.url === "" ? url : response.url);
152
+ if (redirectedUrl.protocol !== url.protocol) {
153
+ logger.error("Redirected to a different protocol ({protocol} to {redirectedProtocol}) while fetching WebFinger resource descriptor.", {
154
+ protocol: url.protocol,
155
+ redirectedProtocol: redirectedUrl.protocol
156
+ });
157
+ return null;
158
+ }
159
+ url = redirectedUrl;
160
+ continue;
161
+ }
162
+ if (!response.ok) {
163
+ logger.debug("Failed to fetch WebFinger resource descriptor: {status} {statusText}.", {
164
+ url: url.href,
165
+ status: response.status,
166
+ statusText: response.statusText
167
+ });
168
+ return null;
169
+ }
170
+ try {
171
+ return await response.json();
172
+ } catch (e) {
173
+ if (e instanceof SyntaxError) {
174
+ logger.debug("Failed to parse WebFinger resource descriptor as JSON: {error}", { error: e });
175
+ return null;
176
+ }
177
+ throw e;
178
+ }
179
+ }
180
+ }
181
+
182
+ //#endregion
183
+ exports.lookupWebFinger = lookupWebFinger;
package/dist/mod.d.cts ADDED
@@ -0,0 +1,113 @@
1
+ import { GetUserAgentOptions } from "@fedify/vocab-runtime";
2
+ import { TracerProvider } from "@opentelemetry/api";
3
+
4
+ //#region src/jrd.d.ts
5
+ /**
6
+ * Describes a resource. See also
7
+ * [RFC 7033 section 4.4](https://datatracker.ietf.org/doc/html/rfc7033#section-4.4).
8
+ */
9
+ interface ResourceDescriptor {
10
+ /**
11
+ * A URI that identifies the entity that this descriptor describes.
12
+ */
13
+ subject?: string;
14
+ /**
15
+ * URIs that identify the same entity as the `subject`.
16
+ */
17
+ aliases?: string[];
18
+ /**
19
+ * Conveys additional information about the `subject` of this descriptor.
20
+ */
21
+ properties?: Record<string, string>;
22
+ /**
23
+ * Links to other resources.
24
+ */
25
+ links?: Link[];
26
+ }
27
+ /**
28
+ * Represents a link. See also
29
+ * [RFC 7033 section 4.4.4](https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4).
30
+ */
31
+ interface Link {
32
+ /**
33
+ * The link's relation type, which is either a URI or a registered relation
34
+ * type (see [RFC 5988](https://datatracker.ietf.org/doc/html/rfc5988)).
35
+ */
36
+ rel: string;
37
+ /**
38
+ * The media type of the target resource (see
39
+ * [RFC 6838](https://datatracker.ietf.org/doc/html/rfc6838)).
40
+ */
41
+ type?: string;
42
+ /**
43
+ * A URI pointing to the target resource.
44
+ */
45
+ href?: string;
46
+ /**
47
+ * Human-readable titles describing the link relation. If the language is
48
+ * unknown or unspecified, the key is `"und"`.
49
+ */
50
+ titles?: Record<string, string>;
51
+ /**
52
+ * Conveys additional information about the link relation.
53
+ */
54
+ properties?: Record<string, string>;
55
+ /**
56
+ * A URI Template (RFC 6570) that can be used to construct URIs by
57
+ * substituting variables. Used primarily for subscription endpoints
58
+ * where parameters like account URIs need to be dynamically inserted.
59
+ * @since 1.9.0
60
+ */
61
+ template?: string;
62
+ }
63
+ //#endregion
64
+ //#region src/lookup.d.ts
65
+ /**
66
+ * Options for {@link lookupWebFinger}.
67
+ * @since 1.3.0
68
+ */
69
+ interface LookupWebFingerOptions {
70
+ /**
71
+ * The options for making `User-Agent` header.
72
+ * If a string is given, it is used as the `User-Agent` header value.
73
+ * If an object is given, it is passed to {@link getUserAgent} to generate
74
+ * the `User-Agent` header value.
75
+ */
76
+ userAgent?: GetUserAgentOptions | string;
77
+ /**
78
+ * Whether to allow private IP addresses in the URL.
79
+ *
80
+ * Mostly useful for testing purposes. *Do not use this in production.*
81
+ *
82
+ * Turned off by default.
83
+ * @since 1.4.0
84
+ */
85
+ allowPrivateAddress?: boolean;
86
+ /**
87
+ * The maximum number of redirections to follow.
88
+ * @default `5`
89
+ * @since 1.8.0
90
+ */
91
+ maxRedirection?: number;
92
+ /**
93
+ * The OpenTelemetry tracer provider. If omitted, the global tracer provider
94
+ * is used.
95
+ */
96
+ tracerProvider?: TracerProvider;
97
+ /**
98
+ * AbortSignal for cancelling the request.
99
+ * @since 1.8.0
100
+ * @
101
+ */
102
+ signal?: AbortSignal;
103
+ }
104
+ /**
105
+ * Looks up a WebFinger resource.
106
+ * @param resource The resource URL to look up.
107
+ * @param options Extra options for looking up the resource.
108
+ * @returns The resource descriptor, or `null` if not found.
109
+ * @since 0.2.0
110
+ */
111
+ declare function lookupWebFinger(resource: URL | string, options?: LookupWebFingerOptions): Promise<ResourceDescriptor | null>;
112
+ //#endregion
113
+ export { Link, LookupWebFingerOptions, ResourceDescriptor, lookupWebFinger };
package/dist/mod.d.ts ADDED
@@ -0,0 +1,113 @@
1
+ import { GetUserAgentOptions } from "@fedify/vocab-runtime";
2
+ import { TracerProvider } from "@opentelemetry/api";
3
+
4
+ //#region src/jrd.d.ts
5
+ /**
6
+ * Describes a resource. See also
7
+ * [RFC 7033 section 4.4](https://datatracker.ietf.org/doc/html/rfc7033#section-4.4).
8
+ */
9
+ interface ResourceDescriptor {
10
+ /**
11
+ * A URI that identifies the entity that this descriptor describes.
12
+ */
13
+ subject?: string;
14
+ /**
15
+ * URIs that identify the same entity as the `subject`.
16
+ */
17
+ aliases?: string[];
18
+ /**
19
+ * Conveys additional information about the `subject` of this descriptor.
20
+ */
21
+ properties?: Record<string, string>;
22
+ /**
23
+ * Links to other resources.
24
+ */
25
+ links?: Link[];
26
+ }
27
+ /**
28
+ * Represents a link. See also
29
+ * [RFC 7033 section 4.4.4](https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4).
30
+ */
31
+ interface Link {
32
+ /**
33
+ * The link's relation type, which is either a URI or a registered relation
34
+ * type (see [RFC 5988](https://datatracker.ietf.org/doc/html/rfc5988)).
35
+ */
36
+ rel: string;
37
+ /**
38
+ * The media type of the target resource (see
39
+ * [RFC 6838](https://datatracker.ietf.org/doc/html/rfc6838)).
40
+ */
41
+ type?: string;
42
+ /**
43
+ * A URI pointing to the target resource.
44
+ */
45
+ href?: string;
46
+ /**
47
+ * Human-readable titles describing the link relation. If the language is
48
+ * unknown or unspecified, the key is `"und"`.
49
+ */
50
+ titles?: Record<string, string>;
51
+ /**
52
+ * Conveys additional information about the link relation.
53
+ */
54
+ properties?: Record<string, string>;
55
+ /**
56
+ * A URI Template (RFC 6570) that can be used to construct URIs by
57
+ * substituting variables. Used primarily for subscription endpoints
58
+ * where parameters like account URIs need to be dynamically inserted.
59
+ * @since 1.9.0
60
+ */
61
+ template?: string;
62
+ }
63
+ //#endregion
64
+ //#region src/lookup.d.ts
65
+ /**
66
+ * Options for {@link lookupWebFinger}.
67
+ * @since 1.3.0
68
+ */
69
+ interface LookupWebFingerOptions {
70
+ /**
71
+ * The options for making `User-Agent` header.
72
+ * If a string is given, it is used as the `User-Agent` header value.
73
+ * If an object is given, it is passed to {@link getUserAgent} to generate
74
+ * the `User-Agent` header value.
75
+ */
76
+ userAgent?: GetUserAgentOptions | string;
77
+ /**
78
+ * Whether to allow private IP addresses in the URL.
79
+ *
80
+ * Mostly useful for testing purposes. *Do not use this in production.*
81
+ *
82
+ * Turned off by default.
83
+ * @since 1.4.0
84
+ */
85
+ allowPrivateAddress?: boolean;
86
+ /**
87
+ * The maximum number of redirections to follow.
88
+ * @default `5`
89
+ * @since 1.8.0
90
+ */
91
+ maxRedirection?: number;
92
+ /**
93
+ * The OpenTelemetry tracer provider. If omitted, the global tracer provider
94
+ * is used.
95
+ */
96
+ tracerProvider?: TracerProvider;
97
+ /**
98
+ * AbortSignal for cancelling the request.
99
+ * @since 1.8.0
100
+ * @
101
+ */
102
+ signal?: AbortSignal;
103
+ }
104
+ /**
105
+ * Looks up a WebFinger resource.
106
+ * @param resource The resource URL to look up.
107
+ * @param options Extra options for looking up the resource.
108
+ * @returns The resource descriptor, or `null` if not found.
109
+ * @since 0.2.0
110
+ */
111
+ declare function lookupWebFinger(resource: URL | string, options?: LookupWebFingerOptions): Promise<ResourceDescriptor | null>;
112
+ //#endregion
113
+ export { Link, LookupWebFingerOptions, ResourceDescriptor, lookupWebFinger };
package/dist/mod.js ADDED
@@ -0,0 +1,160 @@
1
+ import { UrlError, getUserAgent, validatePublicUrl } from "@fedify/vocab-runtime";
2
+ import { getLogger } from "@logtape/logtape";
3
+ import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
4
+
5
+ //#region deno.json
6
+ var name = "@fedify/webfinger";
7
+ var version = "2.0.0";
8
+ var license = "MIT";
9
+ var exports = { ".": "./src/mod.ts" };
10
+ var description = "WebFinger client library for Fedify";
11
+ var author = {
12
+ "name": "Hong Minhee",
13
+ "email": "hong@minhee.org",
14
+ "url": "https://hongminhee.org/"
15
+ };
16
+ var imports = {
17
+ "es-toolkit": "npm:es-toolkit@^1.42.0",
18
+ "fetch-mock": "npm:fetch-mock@^12.5.4"
19
+ };
20
+ var exclude = ["dist", "node_modules"];
21
+ var tasks = {
22
+ "check": "deno fmt --check && deno lint && deno check src/*.ts",
23
+ "test": "deno test"
24
+ };
25
+ var deno_default = {
26
+ name,
27
+ version,
28
+ license,
29
+ exports,
30
+ description,
31
+ author,
32
+ imports,
33
+ exclude,
34
+ tasks
35
+ };
36
+
37
+ //#endregion
38
+ //#region src/lookup.ts
39
+ const logger = getLogger([
40
+ "fedify",
41
+ "webfinger",
42
+ "lookup"
43
+ ]);
44
+ const DEFAULT_MAX_REDIRECTION = 5;
45
+ /**
46
+ * Looks up a WebFinger resource.
47
+ * @param resource The resource URL to look up.
48
+ * @param options Extra options for looking up the resource.
49
+ * @returns The resource descriptor, or `null` if not found.
50
+ * @since 0.2.0
51
+ */
52
+ async function lookupWebFinger(resource, options = {}) {
53
+ const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
54
+ const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
55
+ return await tracer.startActiveSpan("webfinger.lookup", {
56
+ kind: SpanKind.CLIENT,
57
+ attributes: {
58
+ "webfinger.resource": resource.toString(),
59
+ "webfinger.resource.scheme": typeof resource === "string" ? resource.replace(/:.*$/, "") : resource.protocol.replace(/:$/, "")
60
+ }
61
+ }, async (span) => {
62
+ try {
63
+ const result = await lookupWebFingerInternal(resource, options);
64
+ span.setStatus({ code: result === null ? SpanStatusCode.ERROR : SpanStatusCode.OK });
65
+ return result;
66
+ } catch (error) {
67
+ span.setStatus({
68
+ code: SpanStatusCode.ERROR,
69
+ message: String(error)
70
+ });
71
+ throw error;
72
+ } finally {
73
+ span.end();
74
+ }
75
+ });
76
+ }
77
+ async function lookupWebFingerInternal(resource, options = {}) {
78
+ if (typeof resource === "string") resource = new URL(resource);
79
+ let protocol = "https:";
80
+ let server;
81
+ if (resource.protocol === "acct:") {
82
+ const atPos = resource.pathname.lastIndexOf("@");
83
+ if (atPos < 0) return null;
84
+ server = resource.pathname.substring(atPos + 1);
85
+ if (server === "") return null;
86
+ } else {
87
+ protocol = resource.protocol;
88
+ server = resource.host;
89
+ }
90
+ let url = new URL(`${protocol}//${server}/.well-known/webfinger`);
91
+ url.searchParams.set("resource", resource.href);
92
+ let redirected = 0;
93
+ while (true) {
94
+ logger.debug("Fetching WebFinger resource descriptor from {url}...", { url: url.href });
95
+ let response;
96
+ if (options.allowPrivateAddress !== true) try {
97
+ await validatePublicUrl(url.href);
98
+ } catch (e) {
99
+ if (e instanceof UrlError) {
100
+ logger.error("Invalid URL for WebFinger resource descriptor: {error}", { error: e });
101
+ return null;
102
+ }
103
+ throw e;
104
+ }
105
+ try {
106
+ response = await fetch(url, {
107
+ headers: {
108
+ Accept: "application/jrd+json",
109
+ "User-Agent": typeof options.userAgent === "string" ? options.userAgent : getUserAgent(options.userAgent)
110
+ },
111
+ redirect: "manual",
112
+ signal: options.signal
113
+ });
114
+ } catch (error) {
115
+ logger.debug("Failed to fetch WebFinger resource descriptor: {error}", {
116
+ url: url.href,
117
+ error
118
+ });
119
+ return null;
120
+ }
121
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
122
+ redirected++;
123
+ const maxRedirection = options.maxRedirection ?? DEFAULT_MAX_REDIRECTION;
124
+ if (redirected >= maxRedirection) {
125
+ logger.error("Too many redirections ({redirections}) while fetching WebFinger resource descriptor.", { redirections: redirected });
126
+ return null;
127
+ }
128
+ const redirectedUrl = new URL(response.headers.get("Location"), response.url == null || response.url === "" ? url : response.url);
129
+ if (redirectedUrl.protocol !== url.protocol) {
130
+ logger.error("Redirected to a different protocol ({protocol} to {redirectedProtocol}) while fetching WebFinger resource descriptor.", {
131
+ protocol: url.protocol,
132
+ redirectedProtocol: redirectedUrl.protocol
133
+ });
134
+ return null;
135
+ }
136
+ url = redirectedUrl;
137
+ continue;
138
+ }
139
+ if (!response.ok) {
140
+ logger.debug("Failed to fetch WebFinger resource descriptor: {status} {statusText}.", {
141
+ url: url.href,
142
+ status: response.status,
143
+ statusText: response.statusText
144
+ });
145
+ return null;
146
+ }
147
+ try {
148
+ return await response.json();
149
+ } catch (e) {
150
+ if (e instanceof SyntaxError) {
151
+ logger.debug("Failed to parse WebFinger resource descriptor as JSON: {error}", { error: e });
152
+ return null;
153
+ }
154
+ throw e;
155
+ }
156
+ }
157
+ }
158
+
159
+ //#endregion
160
+ export { lookupWebFinger };
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@fedify/webfinger",
3
+ "version": "2.0.0-dev.0",
4
+ "homepage": "https://fedify.dev/",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/fedify-dev/fedify.git",
8
+ "directory": "packages/webfinger"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/fedify-dev/fedify/issues"
12
+ },
13
+ "funding": [
14
+ "https://opencollective.com/fedify",
15
+ "https://github.com/sponsors/dahlia"
16
+ ],
17
+ "engines": {
18
+ "deno": ">=2.0.0",
19
+ "node": ">=22.0.0",
20
+ "bun": ">=1.1.0"
21
+ },
22
+ "description": "WebFinger client library for ActivityPub",
23
+ "type": "module",
24
+ "main": "./dist/mod.cjs",
25
+ "module": "./dist/mod.js",
26
+ "types": "./dist/mod.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": {
30
+ "import": "./dist/mod.d.ts",
31
+ "require": "./dist/mod.d.cts",
32
+ "default": "./dist/mod.d.ts"
33
+ },
34
+ "import": "./dist/mod.js",
35
+ "require": "./dist/mod.cjs",
36
+ "default": "./dist/mod.js"
37
+ },
38
+ "./package.json": "./package.json"
39
+ },
40
+ "keywords": [
41
+ "Fedify",
42
+ "WebFinger",
43
+ "ActivityPub",
44
+ "Fediverse"
45
+ ],
46
+ "author": {
47
+ "name": "Hong Minhee",
48
+ "email": "hong@minhee.org",
49
+ "url": "https://hongminhee.org/"
50
+ },
51
+ "license": "MIT",
52
+ "devDependencies": {
53
+ "@types/node": "^24.2.1",
54
+ "fetch-mock": "^12.5.4",
55
+ "tsdown": "^0.12.9",
56
+ "typescript": "^5.9.3",
57
+ "@fedify/fixture": "2.0.0"
58
+ },
59
+ "dependencies": {
60
+ "@logtape/logtape": "^1.3.5",
61
+ "@opentelemetry/api": "^1.9.0",
62
+ "es-toolkit": "1.43.0",
63
+ "@fedify/vocab-runtime": "2.0.0"
64
+ },
65
+ "scripts": {
66
+ "build": "tsdown",
67
+ "prepublish": "tsdown",
68
+ "test": "tsdown && cd dist/ && node --test"
69
+ }
70
+ }
package/src/jrd.ts ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Describes a resource. See also
3
+ * [RFC 7033 section 4.4](https://datatracker.ietf.org/doc/html/rfc7033#section-4.4).
4
+ */
5
+ export interface ResourceDescriptor {
6
+ /**
7
+ * A URI that identifies the entity that this descriptor describes.
8
+ */
9
+ subject?: string;
10
+
11
+ /**
12
+ * URIs that identify the same entity as the `subject`.
13
+ */
14
+ aliases?: string[];
15
+
16
+ /**
17
+ * Conveys additional information about the `subject` of this descriptor.
18
+ */
19
+ properties?: Record<string, string>;
20
+
21
+ /**
22
+ * Links to other resources.
23
+ */
24
+ links?: Link[];
25
+ }
26
+
27
+ /**
28
+ * Represents a link. See also
29
+ * [RFC 7033 section 4.4.4](https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4).
30
+ */
31
+ export interface Link {
32
+ /**
33
+ * The link's relation type, which is either a URI or a registered relation
34
+ * type (see [RFC 5988](https://datatracker.ietf.org/doc/html/rfc5988)).
35
+ */
36
+ rel: string;
37
+
38
+ /**
39
+ * The media type of the target resource (see
40
+ * [RFC 6838](https://datatracker.ietf.org/doc/html/rfc6838)).
41
+ */
42
+ type?: string;
43
+
44
+ /**
45
+ * A URI pointing to the target resource.
46
+ */
47
+ href?: string;
48
+
49
+ /**
50
+ * Human-readable titles describing the link relation. If the language is
51
+ * unknown or unspecified, the key is `"und"`.
52
+ */
53
+ titles?: Record<string, string>;
54
+
55
+ /**
56
+ * Conveys additional information about the link relation.
57
+ */
58
+ properties?: Record<string, string>;
59
+
60
+ /**
61
+ * A URI Template (RFC 6570) that can be used to construct URIs by
62
+ * substituting variables. Used primarily for subscription endpoints
63
+ * where parameters like account URIs need to be dynamically inserted.
64
+ * @since 1.9.0
65
+ */
66
+ template?: string;
67
+ }