@fedify/fedify 1.2.0-dev.450 → 1.2.0-dev.456

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGES.md CHANGED
@@ -8,12 +8,33 @@ Version 1.2.0
8
8
 
9
9
  To be released.
10
10
 
11
+ - Added NodeInfo client functions.
12
+
13
+ - Added `getNodeInfo()` function.
14
+ - Added `GetNodeInfoOptions` interface.
15
+ - Added `parseNodeInfo()` function.
16
+ - Added `ParseNodeInfoOptions` interface.
17
+
11
18
  - Re-exported Semantic Versioning-related types and functions:
12
19
 
13
20
  - Added `SemVer` type.
14
21
  - Added `formatSemVer()` function.
15
22
  - Added `parseSemVer()` function.
16
23
 
24
+ - Added more log messages using the [LogTape] library. Currently the below
25
+ logger categories are used:
26
+
27
+ - `["fedify", "nodeinfo", "client"]`
28
+
29
+
30
+ Version 1.1.1
31
+ -------------
32
+
33
+ Released on October 23, 2024.
34
+
35
+ - The `fetchDocumentLoader()` function now preloads the following JSON-LD
36
+ context: <https://purl.archive.org/socialweb/webfinger>.
37
+
17
38
 
18
39
  Version 1.1.0
19
40
  -------------
@@ -115,6 +136,15 @@ Released on October 20, 2024.
115
136
  [#150]: https://github.com/dahlia/fedify/issues/150
116
137
 
117
138
 
139
+ Version 1.0.5
140
+ -------------
141
+
142
+ Released on October 23, 2024.
143
+
144
+ - The `fetchDocumentLoader()` function now preloads the following JSON-LD
145
+ context: <https://purl.archive.org/socialweb/webfinger>.
146
+
147
+
118
148
  Version 1.0.4
119
149
  -------------
120
150
 
@@ -334,6 +364,15 @@ Released on September 26, 2024.
334
364
  [#137]: https://github.com/dahlia/fedify/issues/137
335
365
 
336
366
 
367
+ Version 0.15.3
368
+ --------------
369
+
370
+ Released on October 23, 2024.
371
+
372
+ - The `fetchDocumentLoader()` function now preloads the following JSON-LD
373
+ context: <https://purl.archive.org/socialweb/webfinger>.
374
+
375
+
337
376
  Version 0.15.2
338
377
  --------------
339
378
 
package/FEDERATION.md CHANGED
@@ -58,6 +58,7 @@ lists the activity types that Fedify provides:
58
58
  - [`Create`](https://jsr.io/@fedify/fedify/doc/vocab/~/Create)
59
59
  - [`Delete`](https://jsr.io/@fedify/fedify/doc/vocab/~/Delete)
60
60
  - [`Dislike`](https://jsr.io/@fedify/fedify/doc/vocab/~/Dislike)
61
+ - [`EmojiReact`](https://jsr.io/@fedify/fedify/doc/vocab/~/EmojiReact)
61
62
  - [`Flag`](https://jsr.io/@fedify/fedify/doc/vocab/~/Flag)
62
63
  - [`Follow`](https://jsr.io/@fedify/fedify/doc/vocab/~/Follow)
63
64
  - [`Ignore`](https://jsr.io/@fedify/fedify/doc/vocab/~/Ignore)
@@ -0,0 +1,365 @@
1
+ import { getLogger } from "@logtape/logtape";
2
+ import { parse } from "../deps/jsr.io/@std/semver/1.0.3/mod.js";
3
+ const logger = getLogger(["fedify", "nodeinfo", "client"]);
4
+ /**
5
+ * Fetches a NodeInfo document from the given URL.
6
+ * @param url The base URL of the server. If `options.direct` is turned off
7
+ * (default), the NodeInfo document will be fetched from
8
+ * the `.well-known` location of this URL (hence the only origin
9
+ * of the URL is used). If `options.direct` is turned on,
10
+ * the NodeInfo document will be fetched from the given URL.
11
+ * @param options Options for fetching the NodeInfo document.
12
+ * @returns The NodeInfo document if it could be fetched successfully.
13
+ * Otherwise, `null` is returned.
14
+ * @since 1.2.0
15
+ */
16
+ export async function getNodeInfo(url, options = {}) {
17
+ try {
18
+ let nodeInfoUrl = url;
19
+ if (!options.direct) {
20
+ const wellKnownUrl = new URL("/.well-known/nodeinfo", url);
21
+ const wellKnownResponse = await fetch(wellKnownUrl);
22
+ if (!wellKnownResponse.ok) {
23
+ logger.error("Failed to fetch {url}: {status} {statusText}", {
24
+ url: wellKnownUrl.href,
25
+ status: wellKnownResponse.status,
26
+ statusText: wellKnownResponse.statusText,
27
+ });
28
+ return null;
29
+ }
30
+ const wellKnownRd = await wellKnownResponse.json();
31
+ const link = wellKnownRd?.links?.find((link) => link != null &&
32
+ "rel" in link &&
33
+ (link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.0" ||
34
+ link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.1") &&
35
+ "href" in link &&
36
+ link.href != null);
37
+ if (link == null) {
38
+ logger.error("Failed to find a NodeInfo document link from {url}: {resourceDescriptor}", { url: wellKnownUrl.href, resourceDescriptor: wellKnownRd });
39
+ return null;
40
+ }
41
+ nodeInfoUrl = link.href;
42
+ }
43
+ const response = await fetch(nodeInfoUrl);
44
+ if (!response.ok) {
45
+ logger.error("Failed to fetch NodeInfo document from {url}: {status} {statusText}", {
46
+ url: nodeInfoUrl.toString(),
47
+ status: response.status,
48
+ statusText: response.statusText,
49
+ });
50
+ return null;
51
+ }
52
+ const data = await response.json();
53
+ return parseNodeInfo(data, options);
54
+ }
55
+ catch (error) {
56
+ logger.error("Failed to fetch NodeInfo document from {url}: {error}", {
57
+ url: url.toString(),
58
+ error,
59
+ });
60
+ return null;
61
+ }
62
+ }
63
+ /**
64
+ * Parses a NodeInfo document.
65
+ * @param data A JSON value that complies with the NodeInfo schema.
66
+ * @param options Options for parsing the NodeInfo document.
67
+ * @returns The parsed NodeInfo document if it is valid. Otherwise, `null`
68
+ * is returned.
69
+ * @since 1.2.0
70
+ */
71
+ export function parseNodeInfo(data, options = {}) {
72
+ if (typeof data !== "object" || data == null || !("software" in data)) {
73
+ return null;
74
+ }
75
+ const software = parseSoftware(data.software, options);
76
+ if (software == null)
77
+ return null;
78
+ let protocols = [];
79
+ if ("protocols" in data && Array.isArray(data.protocols)) {
80
+ const ps = data.protocols.map(parseProtocol);
81
+ protocols = ps.filter((p) => p != null);
82
+ if (ps.length != protocols.length && !options.tryBestEffort)
83
+ return null;
84
+ }
85
+ else {
86
+ if (!options.tryBestEffort)
87
+ return null;
88
+ }
89
+ let services;
90
+ if ("services" in data) {
91
+ if (typeof data.services === "object" && data.services != null) {
92
+ const ss = parseServices(data.services, options);
93
+ if (ss == null) {
94
+ if (!options.tryBestEffort)
95
+ return null;
96
+ }
97
+ else {
98
+ services = ss;
99
+ }
100
+ }
101
+ else if (!options.tryBestEffort)
102
+ return null;
103
+ }
104
+ let openRegistrations;
105
+ if ("openRegistrations" in data) {
106
+ if (typeof data.openRegistrations === "boolean") {
107
+ openRegistrations = data.openRegistrations;
108
+ }
109
+ else {
110
+ if (!options.tryBestEffort)
111
+ return null;
112
+ }
113
+ }
114
+ let usage = {
115
+ users: {},
116
+ localPosts: 0,
117
+ localComments: 0,
118
+ };
119
+ if ("usage" in data) {
120
+ const u = parseUsage(data.usage, options);
121
+ if (u == null) {
122
+ if (!options.tryBestEffort)
123
+ return null;
124
+ }
125
+ else {
126
+ usage = u;
127
+ }
128
+ }
129
+ let metadata;
130
+ if ("metadata" in data) {
131
+ if (typeof data.metadata === "object" && data.metadata != null) {
132
+ metadata = Object.fromEntries(Object.entries(data.metadata));
133
+ }
134
+ else if (!options.tryBestEffort)
135
+ return null;
136
+ }
137
+ const result = { software, protocols, usage };
138
+ if (services != null)
139
+ result.services = services;
140
+ if (openRegistrations != null)
141
+ result.openRegistrations = openRegistrations;
142
+ if (metadata != null)
143
+ result.metadata = metadata;
144
+ return result;
145
+ }
146
+ export function parseSoftware(data, options = {}) {
147
+ if (typeof data !== "object" || data == null) {
148
+ if (!options.tryBestEffort)
149
+ data = {};
150
+ return null;
151
+ }
152
+ let name;
153
+ if ("name" in data && typeof data.name === "string" &&
154
+ data.name.match(/^\s*[A-Za-z0-9-]+\s*$/)) {
155
+ if (!data.name.match(/^[a-z0-9-]+$/) && !options.tryBestEffort)
156
+ return null;
157
+ name = data.name.trim().toLowerCase();
158
+ }
159
+ else {
160
+ return null;
161
+ }
162
+ let version;
163
+ if ("version" in data && typeof data.version === "string") {
164
+ try {
165
+ version = parse(data.version);
166
+ }
167
+ catch {
168
+ if (!options.tryBestEffort)
169
+ return null;
170
+ version = { major: 0, minor: 0, patch: 0, build: [], prerelease: [] };
171
+ }
172
+ }
173
+ else {
174
+ if (!options.tryBestEffort)
175
+ return null;
176
+ version = { major: 0, minor: 0, patch: 0, build: [], prerelease: [] };
177
+ }
178
+ let repository;
179
+ if ("repository" in data) {
180
+ if (typeof data.repository === "string") {
181
+ try {
182
+ repository = new URL(data.repository);
183
+ }
184
+ catch {
185
+ if (!options.tryBestEffort)
186
+ return null;
187
+ }
188
+ }
189
+ else {
190
+ if (!options.tryBestEffort)
191
+ return null;
192
+ }
193
+ }
194
+ let homepage;
195
+ if ("homepage" in data) {
196
+ if (typeof data.homepage === "string") {
197
+ try {
198
+ homepage = new URL(data.homepage);
199
+ }
200
+ catch {
201
+ if (!options.tryBestEffort)
202
+ return null;
203
+ }
204
+ }
205
+ else {
206
+ if (!options.tryBestEffort)
207
+ return null;
208
+ }
209
+ }
210
+ const result = { name, version };
211
+ if (repository != null)
212
+ result.repository = repository;
213
+ if (homepage != null)
214
+ result.homepage = homepage;
215
+ return result;
216
+ }
217
+ export function parseProtocol(data) {
218
+ // cSpell: disable
219
+ if (data === "activitypub" || data === "buddycloud" || data === "dfrn" ||
220
+ data === "diaspora" || data === "libertree" || data === "ostatus" ||
221
+ data === "pumpio" || data === "tent" || data === "xmpp" ||
222
+ data === "zot") {
223
+ // cSpell: enable
224
+ return data;
225
+ }
226
+ return null;
227
+ }
228
+ export function parseServices(data, options = {}) {
229
+ if (!(typeof data === "object") || data == null) {
230
+ if (options.tryBestEffort)
231
+ return {};
232
+ return null;
233
+ }
234
+ let inbound;
235
+ if ("inbound" in data && Array.isArray(data.inbound)) {
236
+ const is = data.inbound.map(parseInboundService);
237
+ inbound = is.filter((i) => i != null);
238
+ if (is.length > inbound.length && !options.tryBestEffort)
239
+ return null;
240
+ }
241
+ let outbound;
242
+ if ("outbound" in data && Array.isArray(data.outbound)) {
243
+ const os = data.outbound.map(parseOutboundService);
244
+ outbound = os.filter((o) => o != null);
245
+ if (os.length > outbound.length && !options.tryBestEffort)
246
+ return null;
247
+ }
248
+ const result = {};
249
+ if (inbound != null)
250
+ result.inbound = inbound;
251
+ if (outbound != null)
252
+ result.outbound = outbound;
253
+ return result;
254
+ }
255
+ export function parseInboundService(data) {
256
+ // cSpell: disable
257
+ if (data === "atom1.0" || data === "gnusocial" || data === "imap" ||
258
+ data === "pnut" || data === "pop3" || data === "pumpio" ||
259
+ data === "rss2.0" || data === "twitter") {
260
+ // cSpell: enable
261
+ return data;
262
+ }
263
+ return null;
264
+ }
265
+ export function parseOutboundService(data) {
266
+ // cSpell: disable
267
+ if (data === "atom1.0" || data === "blogger" || data === "buddycloud" ||
268
+ data === "diaspora" || data === "dreamwidth" || data === "drupal" ||
269
+ data === "facebook" || data === "friendica" || data === "gnusocial" ||
270
+ data === "google" || data === "insanejournal" || data === "libertree" ||
271
+ data === "linkedin" || data === "livejournal" || data === "mediagoblin" ||
272
+ data === "myspace" || data === "pinterest" || data === "pnut" ||
273
+ data === "posterous" || data === "pumpio" || data === "redmatrix" ||
274
+ data === "rss2.0" || data === "smtp" || data === "tent" ||
275
+ data === "tumblr" || data === "twitter" || data === "wordpress" ||
276
+ data === "xmpp") {
277
+ // cSpell: enable
278
+ return data;
279
+ }
280
+ return null;
281
+ }
282
+ export function parseUsage(data, options = {}) {
283
+ if (typeof data !== "object" || data == null)
284
+ return null;
285
+ const users = {};
286
+ if ("users" in data && typeof data.users === "object" && data.users != null) {
287
+ if ("total" in data.users) {
288
+ if (typeof data.users.total === "number") {
289
+ users.total = data.users.total;
290
+ }
291
+ else {
292
+ if (!options.tryBestEffort)
293
+ return null;
294
+ if (typeof data.users.total === "string") {
295
+ const n = parseInt(data.users.total);
296
+ if (!isNaN(n))
297
+ users.total = n;
298
+ }
299
+ }
300
+ }
301
+ if ("activeHalfyear" in data.users) {
302
+ if (typeof data.users.activeHalfyear === "number") {
303
+ users.activeHalfyear = data.users.activeHalfyear;
304
+ }
305
+ else {
306
+ if (!options.tryBestEffort)
307
+ return null;
308
+ if (typeof data.users.activeHalfyear === "string") {
309
+ const n = parseInt(data.users.activeHalfyear);
310
+ if (!isNaN(n))
311
+ users.activeHalfyear = n;
312
+ }
313
+ }
314
+ }
315
+ if ("activeMonth" in data.users) {
316
+ if (typeof data.users.activeMonth === "number") {
317
+ users.activeMonth = data.users.activeMonth;
318
+ }
319
+ else {
320
+ if (!options.tryBestEffort)
321
+ return null;
322
+ if (typeof data.users.activeMonth === "string") {
323
+ const n = parseInt(data.users.activeMonth);
324
+ if (!isNaN(n))
325
+ users.activeMonth = n;
326
+ }
327
+ }
328
+ }
329
+ }
330
+ else {
331
+ if (!options.tryBestEffort)
332
+ return null;
333
+ }
334
+ let localPosts = 0;
335
+ if ("localPosts" in data) {
336
+ if (typeof data.localPosts === "number") {
337
+ localPosts = data.localPosts;
338
+ }
339
+ else {
340
+ if (!options.tryBestEffort)
341
+ return null;
342
+ if (typeof data.localPosts === "string") {
343
+ const n = parseInt(data.localPosts);
344
+ if (!isNaN(n))
345
+ localPosts = n;
346
+ }
347
+ }
348
+ }
349
+ let localComments = 0;
350
+ if ("localComments" in data) {
351
+ if (typeof data.localComments === "number") {
352
+ localComments = data.localComments;
353
+ }
354
+ else {
355
+ if (!options.tryBestEffort)
356
+ return null;
357
+ if (typeof data.localComments === "string") {
358
+ const n = parseInt(data.localComments);
359
+ if (!isNaN(n))
360
+ localComments = n;
361
+ }
362
+ }
363
+ }
364
+ return { users, localPosts, localComments };
365
+ }
@@ -6,4 +6,5 @@
6
6
  * @since 0.2.0
7
7
  */
8
8
  export { format as formatSemVer, parse as parseSemVer, } from "../deps/jsr.io/@std/semver/1.0.3/mod.js";
9
+ export { getNodeInfo, parseNodeInfo, } from "./client.js";
9
10
  export * from "./types.js";
@@ -777,5 +777,15 @@ const preloadedContexts = {
777
777
  },
778
778
  },
779
779
  },
780
+ "https://purl.archive.org/socialweb/webfinger": {
781
+ "@context": {
782
+ "wf": "https://purl.archive.org/socialweb/webfinger#",
783
+ "xsd": "http://www.w3.org/2001/XMLSchema#",
784
+ "webfinger": {
785
+ "@id": "wf:webfinger",
786
+ "@type": "xsd:string",
787
+ },
788
+ },
789
+ },
780
790
  };
781
791
  export default preloadedContexts;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "1.2.0-dev.450+58427679",
3
+ "version": "1.2.0-dev.456+f3ae1273",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -0,0 +1,58 @@
1
+ /// <reference types="node" />
2
+ import type { InboundService, NodeInfo, OutboundService, Protocol, Services, Software, Usage } from "./types.js";
3
+ /**
4
+ * Options for {@link getNodeInfo} function.
5
+ * @since 1.2.0
6
+ */
7
+ export interface GetNodeInfoOptions extends ParseNodeInfoOptions {
8
+ /**
9
+ * Whether to directly fetch the NodeInfo document from the given URL.
10
+ * Otherwise, the NodeInfo document will be fetched from the `.well-known`
11
+ * location of the given URL.
12
+ *
13
+ * Turned off by default.
14
+ */
15
+ direct?: boolean;
16
+ }
17
+ /**
18
+ * Fetches a NodeInfo document from the given URL.
19
+ * @param url The base URL of the server. If `options.direct` is turned off
20
+ * (default), the NodeInfo document will be fetched from
21
+ * the `.well-known` location of this URL (hence the only origin
22
+ * of the URL is used). If `options.direct` is turned on,
23
+ * the NodeInfo document will be fetched from the given URL.
24
+ * @param options Options for fetching the NodeInfo document.
25
+ * @returns The NodeInfo document if it could be fetched successfully.
26
+ * Otherwise, `null` is returned.
27
+ * @since 1.2.0
28
+ */
29
+ export declare function getNodeInfo(url: URL | string, options?: GetNodeInfoOptions): Promise<NodeInfo | null>;
30
+ /**
31
+ * Options for {@link parseNodeInfo} function.
32
+ * @since 1.2.0
33
+ */
34
+ export interface ParseNodeInfoOptions {
35
+ /**
36
+ * Whether to try to parse the NodeInfo document even if it is invalid.
37
+ * If turned on, the function will return a best-effort result.
38
+ *
39
+ * Turned off by default.
40
+ */
41
+ tryBestEffort?: boolean;
42
+ }
43
+ /**
44
+ * Parses a NodeInfo document.
45
+ * @param data A JSON value that complies with the NodeInfo schema.
46
+ * @param options Options for parsing the NodeInfo document.
47
+ * @returns The parsed NodeInfo document if it is valid. Otherwise, `null`
48
+ * is returned.
49
+ * @since 1.2.0
50
+ */
51
+ export declare function parseNodeInfo(data: unknown, options?: ParseNodeInfoOptions): NodeInfo | null;
52
+ export declare function parseSoftware(data: unknown, options?: ParseNodeInfoOptions): Software | null;
53
+ export declare function parseProtocol(data: unknown): Protocol | null;
54
+ export declare function parseServices(data: unknown, options?: ParseNodeInfoOptions): Services | null;
55
+ export declare function parseInboundService(data: unknown): InboundService | null;
56
+ export declare function parseOutboundService(data: unknown): OutboundService | null;
57
+ export declare function parseUsage(data: unknown, options?: ParseNodeInfoOptions): Usage | null;
58
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/nodeinfo/client.ts"],"names":[],"mappings":";AAGA,OAAO,KAAK,EACV,cAAc,EAEd,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,KAAK,EACN,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,GAAG,GAAG,MAAM,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAqD1B;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,oBAAyB,GACjC,QAAQ,GAAG,IAAI,CAyDjB;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,oBAAyB,GACjC,QAAQ,GAAG,IAAI,CAuDjB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAY5D;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,oBAAyB,GACjC,QAAQ,GAAG,IAAI,CAqBjB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAWxE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAkB1E;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,oBAAyB,GACjC,KAAK,GAAG,IAAI,CAiEd"}
@@ -6,5 +6,6 @@
6
6
  * @since 0.2.0
7
7
  */
8
8
  export { format as formatSemVer, parse as parseSemVer, type SemVer, } from "../deps/jsr.io/@std/semver/1.0.3/mod.js";
9
+ export { getNodeInfo, type GetNodeInfoOptions, parseNodeInfo, type ParseNodeInfoOptions, } from "./client.js";
9
10
  export * from "./types.js";
10
11
  //# sourceMappingURL=mod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/nodeinfo/mod.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,MAAM,IAAI,YAAY,EACtB,KAAK,IAAI,WAAW,EACpB,KAAK,MAAM,GACZ,MAAM,yCAAyC,CAAC;AACjD,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/nodeinfo/mod.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,MAAM,IAAI,YAAY,EACtB,KAAK,IAAI,WAAW,EACpB,KAAK,MAAM,GACZ,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,WAAW,EACX,KAAK,kBAAkB,EACvB,aAAa,EACb,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,cAAc,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"contexts.d.ts","sourceRoot":"","sources":["../../src/runtime/contexts.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CA6wB9C,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"contexts.d.ts","sourceRoot":"","sources":["../../src/runtime/contexts.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAwxB9C,CAAC;AAEF,eAAe,iBAAiB,CAAC"}