@fedify/vocab 2.4.0-dev.2030 → 2.4.0-dev.2047

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.
@@ -1,13 +1,14 @@
1
1
  import "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import { H as Service, N as Organization, P as Person, a as Application, y as Group } from "./vocab-Dw_Vm0NE.mjs";
3
+ import { H as Service, N as Organization, P as Person, a as Application, y as Group } from "./vocab-BJGPw--L.mjs";
4
4
  import { t as getTypeId } from "./type-BMdjm4Eg.mjs";
5
+ import { canonicalizePortableUri, formatIri, fromCompatibleEf61Id, isGatewayUrl } from "@fedify/vocab-runtime";
5
6
  import { lookupWebFinger } from "@fedify/webfinger";
6
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
7
8
  import { domainToASCII, domainToUnicode } from "node:url";
8
9
  //#region deno.json
9
10
  var name = "@fedify/vocab";
10
- var version = "2.4.0-dev.2030+e6b3de3d";
11
+ var version = "2.4.0-dev.2047+140b94db";
11
12
  //#endregion
12
13
  //#region src/actor.ts
13
14
  const ACTOR_DISCOVERY_HISTOGRAM_BUCKETS = [
@@ -49,6 +50,7 @@ function getActorDiscoveryInstruments(meterProvider) {
49
50
  function getActorDiscoveryRemoteHost(actor) {
50
51
  const id = actor instanceof URL ? actor : actor.id;
51
52
  if (id == null) return void 0;
53
+ if (isPortableActorId(id)) return actor instanceof URL ? void 0 : actor.gateway?.host;
52
54
  return id.host === "" ? void 0 : id.host;
53
55
  }
54
56
  var ActorHandleNotFoundError = class extends TypeError {
@@ -108,6 +110,17 @@ function getActorClassByTypeName(typeName) {
108
110
  * await getActorHandle(new URL("https://fosstodon.org/users/hongminhee"));
109
111
  * ```
110
112
  *
113
+ * For an [FEP-ef61] portable actor, whose ID is an `ap:` or `ap+ef61:` URI,
114
+ * the domain is taken from the first gateway in the actor's `gateways` rather
115
+ * than from its ID. The handle is returned only if its WebFinger response
116
+ * links back to the actor, since the actor's `gateways` are claimed by the
117
+ * actor itself; a failed WebFinger lookup is not enough information to get
118
+ * the handle. A portable actor without `gateways` or
119
+ * `preferredUsername`, or a portable actor URI (which does not tell its
120
+ * gateways), is not supported.
121
+ *
122
+ * [FEP-ef61]: https://w3id.org/fep/ef61
123
+ *
111
124
  * @param actor The actor or actor URI to get the handle from.
112
125
  * @param options The extra options for getting the actor handle.
113
126
  * @returns The actor handle. It starts with `@` and is followed by the
@@ -152,6 +165,10 @@ async function getActorHandle(actor, options = {}) {
152
165
  }
153
166
  async function getActorHandleInternal(actor, options = {}) {
154
167
  const actorId = actor instanceof URL ? actor : actor.id;
168
+ if (actorId != null && isPortableActorId(actorId)) {
169
+ if (actor instanceof URL) throw new ActorHandleNotFoundError();
170
+ return await getPortableActorHandle(actor, actorId, options);
171
+ }
155
172
  if (actorId != null) {
156
173
  const result = await lookupWebFinger(actorId, {
157
174
  userAgent: options.userAgent,
@@ -173,6 +190,58 @@ async function getActorHandleInternal(actor, options = {}) {
173
190
  if (!(actor instanceof URL) && actor.preferredUsername != null && actor.id != null) return normalizeActorHandle(`@${actor.preferredUsername}@${actor.id.host}`, options);
174
191
  throw new ActorHandleNotFoundError();
175
192
  }
193
+ function isPortableActorId(id) {
194
+ return id.protocol === "ap:" || id.protocol === "ap+ef61:";
195
+ }
196
+ /**
197
+ * The reverse discovery of an FEP-ef61 portable actor's WebFinger address,
198
+ * which takes the domain from the first gateway in its `gateways`.
199
+ */
200
+ async function getPortableActorHandle(actor, actorId, options) {
201
+ const gateway = actor.gateway;
202
+ const username = actor.preferredUsername?.toString();
203
+ if (gateway == null || !isGatewayUrl(gateway) || username == null) throw new ActorHandleNotFoundError();
204
+ const canonicalId = canonicalizePortableUri(formatIri(actorId));
205
+ const handle = `acct:${username}@${gateway.host}`;
206
+ const result = await lookupWebFinger(handle, {
207
+ userAgent: options.userAgent,
208
+ tracerProvider: options.tracerProvider,
209
+ meterProvider: options.meterProvider
210
+ });
211
+ if (result == null || !linksToPortableActor(result, canonicalId)) throw new ActorHandleNotFoundError();
212
+ const subject = result.subject?.match(/^acct:([^@]+)@([^@]+)$/);
213
+ if (subject != null && result.subject !== handle) {
214
+ const subjectResult = await lookupWebFinger(result.subject, {
215
+ userAgent: options.userAgent,
216
+ tracerProvider: options.tracerProvider,
217
+ meterProvider: options.meterProvider
218
+ });
219
+ if (subjectResult != null && linksToPortableActor(subjectResult, canonicalId)) return normalizeActorHandle(`@${subject[1]}@${subject[2]}`, options);
220
+ }
221
+ return normalizeActorHandle(`@${username}@${gateway.host}`, options);
222
+ }
223
+ /**
224
+ * Checks if the first ActivityStreams `self` link of a WebFinger response
225
+ * identifies the portable actor, either by its portable ID or by
226
+ * a compatible identifier.
227
+ */
228
+ function linksToPortableActor(jrd, canonicalId) {
229
+ const link = jrd.links?.find((l) => l.rel === "self" && l.href != null && (l.type === "application/activity+json" || l.type?.match(/application\/ld\+json;\s*profile="https:\/\/www.w3.org\/ns\/activitystreams"/) != null));
230
+ if (link?.href == null) return false;
231
+ try {
232
+ let id;
233
+ if (/^ap(?:\+ef61)?:/i.test(link.href)) id = link.href;
234
+ else {
235
+ const portable = URL.canParse(link.href) ? fromCompatibleEf61Id(link.href) : null;
236
+ if (portable == null) return false;
237
+ id = formatIri(portable);
238
+ }
239
+ return canonicalizePortableUri(id) === canonicalId;
240
+ } catch (error) {
241
+ if (error instanceof TypeError) return false;
242
+ throw error;
243
+ }
244
+ }
176
245
  async function verifyCrossOriginActorHandle(actorId, alias, userAgent, tracerProvider, meterProvider) {
177
246
  const response = await lookupWebFinger(alias, {
178
247
  userAgent,
@@ -1,8 +1,8 @@
1
1
  import "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import { H as Service, N as Organization, P as Person, Z as __exportAll, a as Application, y as Group } from "./vocab-Dw_Vm0NE.mjs";
4
- import { t as esm_default } from "./esm-C_FjLvhG.mjs";
5
- import { a as normalizeActorHandle, i as isActor, n as getActorHandle, r as getActorTypeName, t as getActorClassByTypeName } from "./actor-DMXlfUoB.mjs";
3
+ import { H as Service, N as Organization, P as Person, Z as __exportAll, a as Application, y as Group } from "./vocab-BJGPw--L.mjs";
4
+ import { t as esm_default } from "./esm-Df0Yo-Tp.mjs";
5
+ import { a as normalizeActorHandle, i as isActor, n as getActorHandle, r as getActorTypeName, t as getActorClassByTypeName } from "./actor-chbmxipX.mjs";
6
6
  import { createTestMeterProvider, test } from "@fedify/fixture";
7
7
  import { deepStrictEqual, ok, rejects, strictEqual, throws } from "node:assert/strict";
8
8
  //#region ../../node_modules/.pnpm/fast-check@3.23.2/node_modules/fast-check/lib/esm/check/precondition/PreconditionFailure.js
@@ -1,6 +1,6 @@
1
1
  import "temporal-polyfill";
2
2
  globalThis.addEventListener = () => {};
3
- import { Q as __toESM, X as __commonJSMin } from "./vocab-Dw_Vm0NE.mjs";
3
+ import { Q as __toESM, X as __commonJSMin } from "./vocab-BJGPw--L.mjs";
4
4
  //#endregion
5
5
  //#region ../../node_modules/.pnpm/regexparam@3.0.0/node_modules/regexparam/dist/index.mjs
6
6
  var import_glob_to_regexp = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {