@fedify/testing 2.4.0-dev.2157 → 2.4.0-dev.2159

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.
Files changed (3) hide show
  1. package/dist/mod.cjs +58 -10
  2. package/dist/mod.js +59 -11
  3. package/package.json +4 -4
package/dist/mod.cjs CHANGED
@@ -248,9 +248,56 @@ function expandUriTemplate(template, values) {
248
248
  function buildPortableUri(authority, path) {
249
249
  if (typeof authority !== "string" || !/^did:[a-z0-9]+:[^/?#]+$/i.test(authority)) throw new TypeError("The authority of a portable ID must be a DID without a path, query, or fragment.");
250
250
  const did = (0, _fedify_vocab_runtime.getFe34Origin)(authority);
251
- if (did.startsWith("did:key:") && !/^z[1-9A-HJ-NP-Za-km-z]+$/.test(did.slice(8))) throw new TypeError("The did:key authority of a portable ID must be encoded in base58-btc, i.e., start with z.");
251
+ if (!isBase58BtcDidKey(did)) throw new TypeError("The did:key authority of a portable ID must be encoded in base58-btc, i.e., start with z.");
252
252
  return (0, _fedify_vocab_runtime.parseIri)(`ap+ef61://${did}${path}`);
253
253
  }
254
+ /**
255
+ * Checks that a normalized DID, if it is a `did:key` DID, is encoded in
256
+ * base58-btc, as `@fedify/fedify` requires of portable IDs.
257
+ */
258
+ function isBase58BtcDidKey(did) {
259
+ return !did.startsWith("did:key:") || /^z[1-9A-HJ-NP-Za-km-z]+$/.test(did.slice(8));
260
+ }
261
+ /**
262
+ * Recognizes an FEP-ef61 portable ID, i.e., an `ap:` or `ap+ef61:` URI, or
263
+ * a compatible identifier on any gateway, validating it the same way as
264
+ * `Context.parseUri()` of `@fedify/fedify` does.
265
+ * @returns The DID and the path of the portable ID, `null` if it is
266
+ * malformed, or `undefined` if the URI is not a portable ID.
267
+ */
268
+ function parseMockPortableId(uri) {
269
+ const portable = uri.protocol === "ap:" || uri.protocol === "ap+ef61:";
270
+ if (!portable && !((uri.protocol === "http:" || uri.protocol === "https:") && /^\/\.well-known\/apgateway\/did(?::|%3A)/i.test(uri.pathname))) return;
271
+ if (uri.username !== "" || uri.password !== "") return null;
272
+ try {
273
+ const id = portable ? (0, _fedify_vocab_runtime.parseIri)(uri) : (0, _fedify_vocab_runtime.fromCompatibleEf61Id)(uri.origin + uri.pathname);
274
+ if (id == null) return null;
275
+ (0, _fedify_vocab_runtime.canonicalizePortableUri)((0, _fedify_vocab_runtime.formatIri)(id));
276
+ const authority = (0, _fedify_vocab_runtime.getFe34Origin)(id);
277
+ if (!isBase58BtcDidKey(authority)) return null;
278
+ return {
279
+ authority,
280
+ path: id.pathname
281
+ };
282
+ } catch (error) {
283
+ if (error instanceof TypeError) return null;
284
+ throw error;
285
+ }
286
+ }
287
+ /**
288
+ * Parses a path in the way {@link MockContext.parseUri} does, i.e., only
289
+ * `/users/{identifier}` and its subpaths are recognized, as actors.
290
+ */
291
+ function parseMockPath(path) {
292
+ if (path.startsWith("/users/")) {
293
+ const parts = path.split("/");
294
+ if (parts.length >= 3) return {
295
+ type: "actor",
296
+ identifier: parts[2]
297
+ };
298
+ }
299
+ return null;
300
+ }
254
301
  function validateOutboxListenerPath(path, dispatcherPath) {
255
302
  if (!path.startsWith("/")) throw new TypeError("Path must start with a slash.");
256
303
  if (dispatcherPath != null && dispatcherPath !== path) throw new TypeError("Outbox listener path and outbox dispatcher path must match.");
@@ -978,15 +1025,16 @@ var MockContext = class MockContext {
978
1025
  const path = globalThis.Object.entries(values).map(([key, value]) => `${key}/${value}`).join("/");
979
1026
  return new URL(`/collections/${String(_name)}/${path}`, this.origin);
980
1027
  }
981
- parseUri(uri) {
982
- if (uri.pathname.startsWith("/users/")) {
983
- const parts = uri.pathname.split("/");
984
- if (parts.length >= 3) return {
985
- type: "actor",
986
- identifier: parts[2]
987
- };
988
- }
989
- return null;
1028
+ parseUri(uri, options = {}) {
1029
+ if (uri == null) return null;
1030
+ const portable = parseMockPortableId(uri);
1031
+ if (portable === void 0) return parseMockPath(uri.pathname);
1032
+ if (portable === null || !options.portable) return null;
1033
+ const result = parseMockPath(portable.path);
1034
+ return result == null ? null : {
1035
+ ...result,
1036
+ authority: portable.authority
1037
+ };
990
1038
  }
991
1039
  async getActorKeyPairs(identifier) {
992
1040
  if (this.federation instanceof MockFederation && this.federation.actorKeyPairsDispatcher) {
package/dist/mod.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { hasProofLike, hasSignatureLike } from "@fedify/fedify/sig";
3
3
  import { Activity, CryptographicKey, Multikey, Tombstone, lookupObject, traverseCollection } from "@fedify/vocab";
4
- import { getFe34Origin, parseIri } from "@fedify/vocab-runtime";
4
+ import { canonicalizePortableUri, formatIri, fromCompatibleEf61Id, getFe34Origin, parseIri } from "@fedify/vocab-runtime";
5
5
  import { RouterError } from "@fedify/fedify/federation";
6
6
  import { delay } from "es-toolkit";
7
7
  import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
@@ -247,9 +247,56 @@ function expandUriTemplate(template, values) {
247
247
  function buildPortableUri(authority, path) {
248
248
  if (typeof authority !== "string" || !/^did:[a-z0-9]+:[^/?#]+$/i.test(authority)) throw new TypeError("The authority of a portable ID must be a DID without a path, query, or fragment.");
249
249
  const did = getFe34Origin(authority);
250
- if (did.startsWith("did:key:") && !/^z[1-9A-HJ-NP-Za-km-z]+$/.test(did.slice(8))) throw new TypeError("The did:key authority of a portable ID must be encoded in base58-btc, i.e., start with z.");
250
+ if (!isBase58BtcDidKey(did)) throw new TypeError("The did:key authority of a portable ID must be encoded in base58-btc, i.e., start with z.");
251
251
  return parseIri(`ap+ef61://${did}${path}`);
252
252
  }
253
+ /**
254
+ * Checks that a normalized DID, if it is a `did:key` DID, is encoded in
255
+ * base58-btc, as `@fedify/fedify` requires of portable IDs.
256
+ */
257
+ function isBase58BtcDidKey(did) {
258
+ return !did.startsWith("did:key:") || /^z[1-9A-HJ-NP-Za-km-z]+$/.test(did.slice(8));
259
+ }
260
+ /**
261
+ * Recognizes an FEP-ef61 portable ID, i.e., an `ap:` or `ap+ef61:` URI, or
262
+ * a compatible identifier on any gateway, validating it the same way as
263
+ * `Context.parseUri()` of `@fedify/fedify` does.
264
+ * @returns The DID and the path of the portable ID, `null` if it is
265
+ * malformed, or `undefined` if the URI is not a portable ID.
266
+ */
267
+ function parseMockPortableId(uri) {
268
+ const portable = uri.protocol === "ap:" || uri.protocol === "ap+ef61:";
269
+ if (!portable && !((uri.protocol === "http:" || uri.protocol === "https:") && /^\/\.well-known\/apgateway\/did(?::|%3A)/i.test(uri.pathname))) return;
270
+ if (uri.username !== "" || uri.password !== "") return null;
271
+ try {
272
+ const id = portable ? parseIri(uri) : fromCompatibleEf61Id(uri.origin + uri.pathname);
273
+ if (id == null) return null;
274
+ canonicalizePortableUri(formatIri(id));
275
+ const authority = getFe34Origin(id);
276
+ if (!isBase58BtcDidKey(authority)) return null;
277
+ return {
278
+ authority,
279
+ path: id.pathname
280
+ };
281
+ } catch (error) {
282
+ if (error instanceof TypeError) return null;
283
+ throw error;
284
+ }
285
+ }
286
+ /**
287
+ * Parses a path in the way {@link MockContext.parseUri} does, i.e., only
288
+ * `/users/{identifier}` and its subpaths are recognized, as actors.
289
+ */
290
+ function parseMockPath(path) {
291
+ if (path.startsWith("/users/")) {
292
+ const parts = path.split("/");
293
+ if (parts.length >= 3) return {
294
+ type: "actor",
295
+ identifier: parts[2]
296
+ };
297
+ }
298
+ return null;
299
+ }
253
300
  function validateOutboxListenerPath(path, dispatcherPath) {
254
301
  if (!path.startsWith("/")) throw new TypeError("Path must start with a slash.");
255
302
  if (dispatcherPath != null && dispatcherPath !== path) throw new TypeError("Outbox listener path and outbox dispatcher path must match.");
@@ -977,15 +1024,16 @@ var MockContext = class MockContext {
977
1024
  const path = globalThis.Object.entries(values).map(([key, value]) => `${key}/${value}`).join("/");
978
1025
  return new URL(`/collections/${String(_name)}/${path}`, this.origin);
979
1026
  }
980
- parseUri(uri) {
981
- if (uri.pathname.startsWith("/users/")) {
982
- const parts = uri.pathname.split("/");
983
- if (parts.length >= 3) return {
984
- type: "actor",
985
- identifier: parts[2]
986
- };
987
- }
988
- return null;
1027
+ parseUri(uri, options = {}) {
1028
+ if (uri == null) return null;
1029
+ const portable = parseMockPortableId(uri);
1030
+ if (portable === void 0) return parseMockPath(uri.pathname);
1031
+ if (portable === null || !options.portable) return null;
1032
+ const result = parseMockPath(portable.path);
1033
+ return result == null ? null : {
1034
+ ...result,
1035
+ authority: portable.authority
1036
+ };
989
1037
  }
990
1038
  async getActorKeyPairs(identifier) {
991
1039
  if (this.federation instanceof MockFederation && this.federation.actorKeyPairsDispatcher) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/testing",
3
- "version": "2.4.0-dev.2157+b76e5888",
3
+ "version": "2.4.0-dev.2159+bb072eda",
4
4
  "description": "Testing utilities for Fedify applications",
5
5
  "keywords": [
6
6
  "fedify",
@@ -47,13 +47,13 @@
47
47
  "package.json"
48
48
  ],
49
49
  "peerDependencies": {
50
- "@fedify/fedify": "^2.4.0-dev.2157+b76e5888"
50
+ "@fedify/fedify": "^2.4.0-dev.2159+bb072eda"
51
51
  },
52
52
  "dependencies": {
53
53
  "es-toolkit": "1.46.1",
54
54
  "temporal-polyfill": "^1.0.1",
55
- "@fedify/vocab-runtime": "^2.4.0-dev.2157+b76e5888",
56
- "@fedify/vocab": "2.4.0-dev.2157+b76e5888"
55
+ "@fedify/vocab": "2.4.0-dev.2159+bb072eda",
56
+ "@fedify/vocab-runtime": "^2.4.0-dev.2159+bb072eda"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@standard-schema/spec": "^1.1.0",