@fedify/fedify 2.4.0-dev.2149 → 2.4.0-dev.2155

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 (85) hide show
  1. package/dist/{builder-W2fIPRjv.mjs → builder-CxHALSwA.mjs} +56 -3
  2. package/dist/compat/mod.d.cts +1 -1
  3. package/dist/compat/mod.d.ts +1 -1
  4. package/dist/compat/transformers.test.mjs +1 -1
  5. package/dist/{compound-proof-B1QH25S6.mjs → compound-proof-nhrXTRQO.mjs} +216 -4
  6. package/dist/{context-CrDDVrbF.d.cts → context-BMggDR-l.d.cts} +394 -5
  7. package/dist/{context-DfSVPcJ8.mjs → context-OrnjnuMq.mjs} +8 -1
  8. package/dist/{context-B2C8nuN3.d.ts → context-exYu7gDU.d.ts} +394 -5
  9. package/dist/{deno-yXpYZm4K.mjs → deno-YLLbRq06.mjs} +1 -1
  10. package/dist/{docloader-C4h6PL7m.mjs → docloader-vc-pSu9-.mjs} +2 -2
  11. package/dist/federation/builder.test.mjs +1 -1
  12. package/dist/federation/compound-fanout.test.mjs +3 -3
  13. package/dist/federation/handler-compound-proof.test.mjs +4 -4
  14. package/dist/federation/handler.test.mjs +6 -6
  15. package/dist/federation/hashlink-media.test.mjs +2 -2
  16. package/dist/federation/idempotency.test.mjs +2 -2
  17. package/dist/federation/metrics.test.mjs +1 -1
  18. package/dist/federation/middleware.test.mjs +8 -8
  19. package/dist/federation/mod.cjs +1 -1
  20. package/dist/federation/mod.d.cts +3 -3
  21. package/dist/federation/mod.d.ts +3 -3
  22. package/dist/federation/mod.js +1 -1
  23. package/dist/federation/outgoing-proof.test.mjs +5 -5
  24. package/dist/federation/portable-actor.test.mjs +3 -3
  25. package/dist/federation/portable-chain.test.mjs +3 -3
  26. package/dist/federation/portable-collection.test.d.mts +2 -0
  27. package/dist/federation/portable-collection.test.mjs +768 -0
  28. package/dist/federation/portable-gateway-keys.test.mjs +4 -4
  29. package/dist/federation/portable-inbox.test.mjs +4 -4
  30. package/dist/federation/portable.test.mjs +4 -4
  31. package/dist/federation/send.test.mjs +3 -3
  32. package/dist/federation/tasks/enqueue.test.mjs +2 -2
  33. package/dist/federation/tasks/tasks.test.mjs +3 -3
  34. package/dist/federation/temporal.test.mjs +1 -1
  35. package/dist/federation/webfinger.test.mjs +2 -2
  36. package/dist/{federation-D4j-ZXUN.cjs → federation-D9TufmIO.cjs} +684 -68
  37. package/dist/{http-BoH-e8sR.mjs → http-CXnNbRe_.mjs} +4 -4
  38. package/dist/{http-CBRurnlR.js → http-Dk4O3WM0.js} +7 -2
  39. package/dist/{http-C_jobbLz.cjs → http-eqYXHRkz.cjs} +12 -1
  40. package/dist/{key-BtO7WCfP.mjs → key-BZ-Z4uez.mjs} +2 -2
  41. package/dist/{kv-cache-E0es0w4R.js → kv-cache-3uKc0G76.js} +1 -1
  42. package/dist/{kv-cache-CMuTXrkC.mjs → kv-cache-DZr8HTel.mjs} +1 -1
  43. package/dist/{kv-cache-BxUqVENn.cjs → kv-cache-DzClEalR.cjs} +1 -1
  44. package/dist/{ld-YYBfDbe_.mjs → ld-Djxsq6JR.mjs} +3 -3
  45. package/dist/{metrics-DMqdDud_.mjs → metrics-CBHhbHgG.mjs} +1 -1
  46. package/dist/{middleware-D6uiL1Tw.js → middleware-BDUR99k3.js} +686 -70
  47. package/dist/{middleware-C97UJpkA.mjs → middleware-BahNnLfD.mjs} +1 -1
  48. package/dist/{middleware-CBGR92fz.mjs → middleware-DDa8pCUa.mjs} +431 -80
  49. package/dist/{mod-C06GoL5Z.d.ts → mod-CnGtADvO.d.ts} +1 -1
  50. package/dist/{mod-B7SfEqIP.d.cts → mod-Decmur1U.d.cts} +1 -1
  51. package/dist/mod.cjs +4 -4
  52. package/dist/mod.d.cts +4 -4
  53. package/dist/mod.d.ts +4 -4
  54. package/dist/mod.js +4 -4
  55. package/dist/nodeinfo/handler.test.mjs +2 -2
  56. package/dist/{owner-Cn6CFYBy.mjs → owner-OdWSE8am.mjs} +3 -3
  57. package/dist/{portable-collection-CyhFWEB-.js → portable-collection-BCy06GiS.js} +1 -1
  58. package/dist/{portable-collection-B3swTTja.mjs → portable-collection-DAV7Ho3m.mjs} +2 -2
  59. package/dist/{portable-collection-CWgXwOdR.cjs → portable-collection-wBWbuHOH.cjs} +1 -1
  60. package/dist/{portable-key-HM5Siym0.mjs → portable-key-BL6K88p2.mjs} +1 -1
  61. package/dist/{proof-DWkXfZIU.mjs → proof-vZ04IAjq.mjs} +10 -5
  62. package/dist/{send-BQDT_8bc.mjs → send-ylV8KCLx.mjs} +3 -3
  63. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  64. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  65. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  66. package/dist/sig/compound-proof.test.mjs +2 -2
  67. package/dist/sig/http.test.mjs +2 -2
  68. package/dist/sig/key.test.mjs +1 -1
  69. package/dist/sig/ld.test.mjs +2 -2
  70. package/dist/sig/mod.cjs +2 -2
  71. package/dist/sig/mod.js +2 -2
  72. package/dist/sig/owner.test.mjs +1 -1
  73. package/dist/sig/portable-collection.test.mjs +1 -1
  74. package/dist/sig/portable-key.test.mjs +5 -5
  75. package/dist/sig/proof.test.mjs +3 -3
  76. package/dist/{temporal-CFI__wjQ.mjs → temporal-BTD4f_mZ.mjs} +1 -1
  77. package/dist/testing/kv.test.mjs +1 -1
  78. package/dist/testing/mod.d.mts +393 -4
  79. package/dist/testing/mod.mjs +2 -2
  80. package/dist/{testing-otQhu4aD.mjs → testing-CKaJhcA0.mjs} +1 -1
  81. package/dist/utils/docloader.test.mjs +2 -2
  82. package/dist/utils/kv-cache.test.mjs +1 -1
  83. package/dist/utils/mod.cjs +1 -1
  84. package/dist/utils/mod.js +1 -1
  85. package/package.json +6 -6
@@ -694,6 +694,28 @@ type ObjectAuthorizePredicate<TContextData, TParam extends string> = (context: R
694
694
  * @since 1.8.0
695
695
  */
696
696
  type CustomCollectionDispatcher<TItem, TParam extends string, TContext extends Context<TContextData>, TContextData> = (context: TContext, values: Record<TParam, string>, cursor: string | null) => PageItems<TItem> | null | Promise<PageItems<TItem> | null>;
697
+ /**
698
+ * A callback that maps a custom collection to the identifier of the actor
699
+ * that owns it, so that the collection can be served as an [FEP-ef61]
700
+ * portable collection through the gateway endpoint, e.g.,
701
+ * `GET /.well-known/apgateway/did:key:z6Mk.../users/alice/bookmarks`.
702
+ *
703
+ * Fedify serves such a request only if the returned actor is a portable actor
704
+ * whose ID is under the requested DID. The owner has to come from
705
+ * the application's data, not from the request, since the DID in the request
706
+ * path is not evidence that this server hosts collections for it.
707
+ *
708
+ * [FEP-ef61]: https://w3id.org/fep/ef61
709
+ *
710
+ * @template TContextData The context data to pass to the {@link Context}.
711
+ * @template TParam The parameter names of the requested URL.
712
+ * @param context The context.
713
+ * @param values The parameters of the requested URL.
714
+ * @returns The internal identifier of the actor that owns the collection, or
715
+ * `null` if the collection is not a portable collection.
716
+ * @since 2.4.0
717
+ */
718
+ type PortableCollectionOwnerMapper<TContextData, TParam extends string> = (context: Context<TContextData>, values: Record<TParam, string>) => string | null | Promise<string | null>;
697
719
  /**
698
720
  * A callback that counts the number of items in a custom collection.
699
721
  *
@@ -2786,6 +2808,21 @@ interface CustomCollectionCallbackSetters<TParam extends string, TContext extend
2786
2808
  * @since 0.7.0
2787
2809
  */
2788
2810
  authorize(predicate: ObjectAuthorizePredicate<TContextData, string>): CustomCollectionCallbackSetters<TParam, TContext, TContextData>;
2811
+ /**
2812
+ * Maps the custom collection to the actor that owns it, so that it is also
2813
+ * served as an [FEP-ef61] portable collection through the gateway endpoint,
2814
+ * e.g., `GET /.well-known/apgateway/did:key:z6Mk.../users/alice/bookmarks`,
2815
+ * if the owner is a portable actor under the requested DID. Without it,
2816
+ * the custom collection is not served through the gateway endpoint.
2817
+ *
2818
+ * [FEP-ef61]: https://w3id.org/fep/ef61
2819
+ * @param mapper A callback that returns the identifier of the actor that
2820
+ * owns the collection, or `null` if the collection is not
2821
+ * portable.
2822
+ * @returns The setters object so that settings can be chained.
2823
+ * @since 2.4.0
2824
+ */
2825
+ mapPortableOwner(mapper: PortableCollectionOwnerMapper<TContextData, TParam>): CustomCollectionCallbackSetters<TParam, TContext, TContextData>;
2789
2826
  }
2790
2827
  /**
2791
2828
  * Represents an object with a type ID, which is either a constructor or an
@@ -3040,6 +3077,35 @@ interface Context<TContextData> {
3040
3077
  * @throws {RouterError} If no outbox dispatcher is available.
3041
3078
  */
3042
3079
  getOutboxUri(identifier: string): URL;
3080
+ /**
3081
+ * Builds the [FEP-ef61] portable ID of an actor's outbox with the given
3082
+ * identifier under the given DID authority.
3083
+ *
3084
+ * The path is the same as the one {@link Context.getOutboxUri} builds, but
3085
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3086
+ * `ap+ef61://did:key:z6Mk.../users/alice/outbox`. If a portable actor has
3087
+ * it as its `outbox` and its ID is under the same DID, the collection is
3088
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3089
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/outbox`, by the same
3090
+ * collection dispatcher.
3091
+ *
3092
+ * The returned `URL` keeps the DID authority percent-encoded, because
3093
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3094
+ * from `@fedify/vocab-runtime` to get the canonical string.
3095
+ *
3096
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3097
+ *
3098
+ * @param identifier The actor's identifier.
3099
+ * @param authority The DID that controls the actor, e.g.,
3100
+ * `did:key:z6Mk...`. It must be a bare DID, without
3101
+ * a path, query, or fragment.
3102
+ * @returns The outbox's portable ID.
3103
+ * @throws {RouterError} If no outbox dispatcher is available.
3104
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3105
+ * DID that is not encoded in base58-btc.
3106
+ * @since 2.4.0
3107
+ */
3108
+ getPortableOutboxUri(identifier: string, authority: string): URL;
3043
3109
  /**
3044
3110
  * Builds the URI of an actor's media upload endpoint with the given
3045
3111
  * identifier. This is the endpoint advertised under `endpoints.uploadMedia`
@@ -3071,6 +3137,35 @@ interface Context<TContextData> {
3071
3137
  * @throws {RouterError} If no following collection is available.
3072
3138
  */
3073
3139
  getFollowingUri(identifier: string): URL;
3140
+ /**
3141
+ * Builds the [FEP-ef61] portable ID of an actor's following collection with the given
3142
+ * identifier under the given DID authority.
3143
+ *
3144
+ * The path is the same as the one {@link Context.getFollowingUri} builds, but
3145
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3146
+ * `ap+ef61://did:key:z6Mk.../users/alice/following`. If a portable actor has
3147
+ * it as its `following` and its ID is under the same DID, the collection is
3148
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3149
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/following`, by the same
3150
+ * collection dispatcher.
3151
+ *
3152
+ * The returned `URL` keeps the DID authority percent-encoded, because
3153
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3154
+ * from `@fedify/vocab-runtime` to get the canonical string.
3155
+ *
3156
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3157
+ *
3158
+ * @param identifier The actor's identifier.
3159
+ * @param authority The DID that controls the actor, e.g.,
3160
+ * `did:key:z6Mk...`. It must be a bare DID, without
3161
+ * a path, query, or fragment.
3162
+ * @returns The following collection's portable ID.
3163
+ * @throws {RouterError} If no following collection is available.
3164
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3165
+ * DID that is not encoded in base58-btc.
3166
+ * @since 2.4.0
3167
+ */
3168
+ getPortableFollowingUri(identifier: string, authority: string): URL;
3074
3169
  /**
3075
3170
  * Builds the URI of an actor's followers collection with the given
3076
3171
  * identifier.
@@ -3079,6 +3174,35 @@ interface Context<TContextData> {
3079
3174
  * @throws {RouterError} If no followers collection is available.
3080
3175
  */
3081
3176
  getFollowersUri(identifier: string): URL;
3177
+ /**
3178
+ * Builds the [FEP-ef61] portable ID of an actor's followers collection with the given
3179
+ * identifier under the given DID authority.
3180
+ *
3181
+ * The path is the same as the one {@link Context.getFollowersUri} builds, but
3182
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3183
+ * `ap+ef61://did:key:z6Mk.../users/alice/followers`. If a portable actor has
3184
+ * it as its `followers` and its ID is under the same DID, the collection is
3185
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3186
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/followers`, by the same
3187
+ * collection dispatcher.
3188
+ *
3189
+ * The returned `URL` keeps the DID authority percent-encoded, because
3190
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3191
+ * from `@fedify/vocab-runtime` to get the canonical string.
3192
+ *
3193
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3194
+ *
3195
+ * @param identifier The actor's identifier.
3196
+ * @param authority The DID that controls the actor, e.g.,
3197
+ * `did:key:z6Mk...`. It must be a bare DID, without
3198
+ * a path, query, or fragment.
3199
+ * @returns The followers collection's portable ID.
3200
+ * @throws {RouterError} If no followers collection is available.
3201
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3202
+ * DID that is not encoded in base58-btc.
3203
+ * @since 2.4.0
3204
+ */
3205
+ getPortableFollowersUri(identifier: string, authority: string): URL;
3082
3206
  /**
3083
3207
  * Builds the URI of an actor's liked collection with the given identifier.
3084
3208
  * @param identifier The actor's identifier.
@@ -3087,6 +3211,35 @@ interface Context<TContextData> {
3087
3211
  * @since 0.11.0
3088
3212
  */
3089
3213
  getLikedUri(identifier: string): URL;
3214
+ /**
3215
+ * Builds the [FEP-ef61] portable ID of an actor's liked collection with the given
3216
+ * identifier under the given DID authority.
3217
+ *
3218
+ * The path is the same as the one {@link Context.getLikedUri} builds, but
3219
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3220
+ * `ap+ef61://did:key:z6Mk.../users/alice/liked`. If a portable actor has
3221
+ * it as its `liked` and its ID is under the same DID, the collection is
3222
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3223
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/liked`, by the same
3224
+ * collection dispatcher.
3225
+ *
3226
+ * The returned `URL` keeps the DID authority percent-encoded, because
3227
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3228
+ * from `@fedify/vocab-runtime` to get the canonical string.
3229
+ *
3230
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3231
+ *
3232
+ * @param identifier The actor's identifier.
3233
+ * @param authority The DID that controls the actor, e.g.,
3234
+ * `did:key:z6Mk...`. It must be a bare DID, without
3235
+ * a path, query, or fragment.
3236
+ * @returns The liked collection's portable ID.
3237
+ * @throws {RouterError} If no liked collection is available.
3238
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3239
+ * DID that is not encoded in base58-btc.
3240
+ * @since 2.4.0
3241
+ */
3242
+ getPortableLikedUri(identifier: string, authority: string): URL;
3090
3243
  /**
3091
3244
  * Builds the URI of an actor's featured collection with the given identifier.
3092
3245
  * @param identifier The actor's identifier.
@@ -3095,6 +3248,35 @@ interface Context<TContextData> {
3095
3248
  * @since 0.11.0
3096
3249
  */
3097
3250
  getFeaturedUri(identifier: string): URL;
3251
+ /**
3252
+ * Builds the [FEP-ef61] portable ID of an actor's featured collection with the given
3253
+ * identifier under the given DID authority.
3254
+ *
3255
+ * The path is the same as the one {@link Context.getFeaturedUri} builds, but
3256
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3257
+ * `ap+ef61://did:key:z6Mk.../users/alice/featured`. If a portable actor has
3258
+ * it as its `featured` and its ID is under the same DID, the collection is
3259
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3260
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/featured`, by the same
3261
+ * collection dispatcher.
3262
+ *
3263
+ * The returned `URL` keeps the DID authority percent-encoded, because
3264
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3265
+ * from `@fedify/vocab-runtime` to get the canonical string.
3266
+ *
3267
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3268
+ *
3269
+ * @param identifier The actor's identifier.
3270
+ * @param authority The DID that controls the actor, e.g.,
3271
+ * `did:key:z6Mk...`. It must be a bare DID, without
3272
+ * a path, query, or fragment.
3273
+ * @returns The featured collection's portable ID.
3274
+ * @throws {RouterError} If no featured collection is available.
3275
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3276
+ * DID that is not encoded in base58-btc.
3277
+ * @since 2.4.0
3278
+ */
3279
+ getPortableFeaturedUri(identifier: string, authority: string): URL;
3098
3280
  /**
3099
3281
  * Builds the URI of an actor's featured tags collection with the given
3100
3282
  * identifier.
@@ -3104,6 +3286,35 @@ interface Context<TContextData> {
3104
3286
  * @since 0.11.0
3105
3287
  */
3106
3288
  getFeaturedTagsUri(identifier: string): URL;
3289
+ /**
3290
+ * Builds the [FEP-ef61] portable ID of an actor's featured tags collection with the given
3291
+ * identifier under the given DID authority.
3292
+ *
3293
+ * The path is the same as the one {@link Context.getFeaturedTagsUri} builds, but
3294
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3295
+ * `ap+ef61://did:key:z6Mk.../users/alice/tags`. If a portable actor has
3296
+ * it as its `featuredTags` and its ID is under the same DID, the collection is
3297
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3298
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/tags`, by the same
3299
+ * collection dispatcher.
3300
+ *
3301
+ * The returned `URL` keeps the DID authority percent-encoded, because
3302
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3303
+ * from `@fedify/vocab-runtime` to get the canonical string.
3304
+ *
3305
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3306
+ *
3307
+ * @param identifier The actor's identifier.
3308
+ * @param authority The DID that controls the actor, e.g.,
3309
+ * `did:key:z6Mk...`. It must be a bare DID, without
3310
+ * a path, query, or fragment.
3311
+ * @returns The featured tags collection's portable ID.
3312
+ * @throws {RouterError} If no featured tags collection is available.
3313
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3314
+ * DID that is not encoded in base58-btc.
3315
+ * @since 2.4.0
3316
+ */
3317
+ getPortableFeaturedTagsUri(identifier: string, authority: string): URL;
3107
3318
  /**
3108
3319
  * Determines the type of the URI and extracts the associated data.
3109
3320
  * @param uri The URI to parse.
@@ -3363,6 +3574,38 @@ interface Context<TContextData> {
3363
3574
  * @since 1.8.0
3364
3575
  */
3365
3576
  getCollectionUri<TParam extends Record<string, string>>(name: string | symbol, values: TParam): URL;
3577
+ /**
3578
+ * Builds the [FEP-ef61] portable ID of a custom collection with the given
3579
+ * name and values under the given DID authority.
3580
+ *
3581
+ * The path is the same as the one {@link Context.getCollectionUri} builds,
3582
+ * but the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3583
+ * `ap+ef61://did:key:z6Mk.../users/alice/bookmarks`. If the collection
3584
+ * dispatcher maps the collection to a portable actor under the same DID
3585
+ * with `CustomCollectionCallbackSetters.mapPortableOwner()`, the
3586
+ * collection is served through the FEP-ef61 gateway endpoint, e.g.,
3587
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/bookmarks`.
3588
+ *
3589
+ * The returned `URL` keeps the DID authority percent-encoded, because
3590
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3591
+ * from `@fedify/vocab-runtime` to get the canonical string.
3592
+ *
3593
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3594
+ *
3595
+ * @param name The name of the collection, which can be a string or a symbol.
3596
+ * @param values The values of the URI parameters.
3597
+ * @param authority The DID that controls the collection, e.g.,
3598
+ * `did:key:z6Mk...`. It must be a bare DID, without
3599
+ * a path, query, or fragment.
3600
+ * @returns The collection's portable ID.
3601
+ * @throws {RouterError} If no collection dispatcher is available for
3602
+ * the name.
3603
+ * @throws {TypeError} If values are invalid, or the authority is not a DID
3604
+ * or is a `did:key` DID that is not encoded in
3605
+ * base58-btc.
3606
+ * @since 2.4.0
3607
+ */
3608
+ getPortableCollectionUri<TParam extends Record<string, string>>(name: string | symbol, values: TParam, authority: string): URL;
3366
3609
  }
3367
3610
  /**
3368
3611
  * Information about an [FEP-ef61] portable object requested through
@@ -3379,7 +3622,7 @@ interface PortableRequest {
3379
3622
  */
3380
3623
  readonly authority: string;
3381
3624
  /**
3382
- * The ID of the requested portable object, e.g.,
3625
+ * The ID of the requested portable object or collection, e.g.,
3383
3626
  * `ap+ef61://did:key:z6Mk.../notes/123`, without a query. Like other
3384
3627
  * portable IDs, the `URL` keeps the DID authority percent-encoded; use
3385
3628
  * `formatIri()` from `@fedify/vocab-runtime` to get the canonical string.
@@ -3433,12 +3676,14 @@ interface RequestContext<TContextData> extends Context<TContextData> {
3433
3676
  * Information about the [FEP-ef61] portable object requested through
3434
3677
  * the gateway endpoint, e.g.,
3435
3678
  * `GET /.well-known/apgateway/did:key:z6Mk.../notes/123`, which is served
3436
- * by an object dispatcher or the actor dispatcher. It is `undefined` for
3437
- * ordinary requests.
3679
+ * by an object dispatcher, the actor dispatcher, or a collection
3680
+ * dispatcher. It is `undefined` for ordinary requests.
3438
3681
  *
3439
3682
  * The authority comes from the request path, so it is not evidence that
3440
3683
  * this server hosts objects for the DID. An object dispatcher or the actor
3441
- * dispatcher has to check that by itself.
3684
+ * dispatcher has to check that by itself. A portable collection is served
3685
+ * only if its owner, which the actor dispatcher looks up without this
3686
+ * property, is a portable actor under the DID.
3442
3687
  *
3443
3688
  * It describes the incoming request, so it stays the same in contexts
3444
3689
  * derived from this one, e.g., by {@link RequestContext.getObject}.
@@ -3520,6 +3765,150 @@ interface RequestContext<TContextData> extends Context<TContextData> {
3520
3765
  * @since 2.4.0
3521
3766
  */
3522
3767
  getPortableInboxUri(identifier: string, authority?: string): URL;
3768
+ /**
3769
+ * Builds the [FEP-ef61] portable ID of an actor's outbox with the given
3770
+ * identifier. It works the same as {@link Context.getPortableOutboxUri}, except that
3771
+ * the authority can be omitted while handling a portable gateway request.
3772
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
3773
+ *
3774
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3775
+ *
3776
+ * @param identifier The actor's identifier.
3777
+ * @param authority The DID that controls the actor, e.g.,
3778
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
3779
+ * portable object or collection.
3780
+ * @returns The outbox's portable ID.
3781
+ * @throws {RouterError} If no outbox dispatcher is available.
3782
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
3783
+ * that is not encoded in base58-btc, or the authority
3784
+ * is omitted outside a portable gateway request.
3785
+ * @since 2.4.0
3786
+ */
3787
+ getPortableOutboxUri(identifier: string, authority?: string): URL;
3788
+ /**
3789
+ * Builds the [FEP-ef61] portable ID of an actor's following collection with the given
3790
+ * identifier. It works the same as {@link Context.getPortableFollowingUri}, except that
3791
+ * the authority can be omitted while handling a portable gateway request.
3792
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
3793
+ *
3794
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3795
+ *
3796
+ * @param identifier The actor's identifier.
3797
+ * @param authority The DID that controls the actor, e.g.,
3798
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
3799
+ * portable object or collection.
3800
+ * @returns The following collection's portable ID.
3801
+ * @throws {RouterError} If no following collection is available.
3802
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
3803
+ * that is not encoded in base58-btc, or the authority
3804
+ * is omitted outside a portable gateway request.
3805
+ * @since 2.4.0
3806
+ */
3807
+ getPortableFollowingUri(identifier: string, authority?: string): URL;
3808
+ /**
3809
+ * Builds the [FEP-ef61] portable ID of an actor's followers collection with the given
3810
+ * identifier. It works the same as {@link Context.getPortableFollowersUri}, except that
3811
+ * the authority can be omitted while handling a portable gateway request.
3812
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
3813
+ *
3814
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3815
+ *
3816
+ * @param identifier The actor's identifier.
3817
+ * @param authority The DID that controls the actor, e.g.,
3818
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
3819
+ * portable object or collection.
3820
+ * @returns The followers collection's portable ID.
3821
+ * @throws {RouterError} If no followers collection is available.
3822
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
3823
+ * that is not encoded in base58-btc, or the authority
3824
+ * is omitted outside a portable gateway request.
3825
+ * @since 2.4.0
3826
+ */
3827
+ getPortableFollowersUri(identifier: string, authority?: string): URL;
3828
+ /**
3829
+ * Builds the [FEP-ef61] portable ID of an actor's liked collection with the given
3830
+ * identifier. It works the same as {@link Context.getPortableLikedUri}, except that
3831
+ * the authority can be omitted while handling a portable gateway request.
3832
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
3833
+ *
3834
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3835
+ *
3836
+ * @param identifier The actor's identifier.
3837
+ * @param authority The DID that controls the actor, e.g.,
3838
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
3839
+ * portable object or collection.
3840
+ * @returns The liked collection's portable ID.
3841
+ * @throws {RouterError} If no liked collection is available.
3842
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
3843
+ * that is not encoded in base58-btc, or the authority
3844
+ * is omitted outside a portable gateway request.
3845
+ * @since 2.4.0
3846
+ */
3847
+ getPortableLikedUri(identifier: string, authority?: string): URL;
3848
+ /**
3849
+ * Builds the [FEP-ef61] portable ID of an actor's featured collection with the given
3850
+ * identifier. It works the same as {@link Context.getPortableFeaturedUri}, except that
3851
+ * the authority can be omitted while handling a portable gateway request.
3852
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
3853
+ *
3854
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3855
+ *
3856
+ * @param identifier The actor's identifier.
3857
+ * @param authority The DID that controls the actor, e.g.,
3858
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
3859
+ * portable object or collection.
3860
+ * @returns The featured collection's portable ID.
3861
+ * @throws {RouterError} If no featured collection is available.
3862
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
3863
+ * that is not encoded in base58-btc, or the authority
3864
+ * is omitted outside a portable gateway request.
3865
+ * @since 2.4.0
3866
+ */
3867
+ getPortableFeaturedUri(identifier: string, authority?: string): URL;
3868
+ /**
3869
+ * Builds the [FEP-ef61] portable ID of an actor's featured tags collection with the given
3870
+ * identifier. It works the same as {@link Context.getPortableFeaturedTagsUri}, except that
3871
+ * the authority can be omitted while handling a portable gateway request.
3872
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
3873
+ *
3874
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3875
+ *
3876
+ * @param identifier The actor's identifier.
3877
+ * @param authority The DID that controls the actor, e.g.,
3878
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
3879
+ * portable object or collection.
3880
+ * @returns The featured tags collection's portable ID.
3881
+ * @throws {RouterError} If no featured tags collection is available.
3882
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
3883
+ * that is not encoded in base58-btc, or the authority
3884
+ * is omitted outside a portable gateway request.
3885
+ * @since 2.4.0
3886
+ */
3887
+ getPortableFeaturedTagsUri(identifier: string, authority?: string): URL;
3888
+ /**
3889
+ * Builds the [FEP-ef61] portable ID of a custom collection with the given
3890
+ * name and values. It works the same as
3891
+ * {@link Context.getPortableCollectionUri}, except that the authority can
3892
+ * be omitted while handling a portable gateway request. In that case,
3893
+ * the DID in {@link RequestContext.portableRequest} is used.
3894
+ *
3895
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3896
+ *
3897
+ * @param name The name of the collection, which can be a string or a symbol.
3898
+ * @param values The values of the URI parameters.
3899
+ * @param authority The DID that controls the collection, e.g.,
3900
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
3901
+ * portable object or collection.
3902
+ * @returns The collection's portable ID.
3903
+ * @throws {RouterError} If no collection dispatcher is available for
3904
+ * the name.
3905
+ * @throws {TypeError} If values are invalid, the authority is not a DID,
3906
+ * it is a `did:key` DID that is not encoded in
3907
+ * base58-btc, or the authority is omitted outside
3908
+ * a portable gateway request.
3909
+ * @since 2.4.0
3910
+ */
3911
+ getPortableCollectionUri<TParam extends Record<string, string>>(name: string | symbol, values: TParam, authority?: string): URL;
3523
3912
  /**
3524
3913
  * Creates a new context with the same properties as this one,
3525
3914
  * but with the given data.
@@ -2,8 +2,8 @@ import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { r as testDefinitions } from "../dist-BQvArojP.mjs";
5
- import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-DfSVPcJ8.mjs";
5
+ import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-OrnjnuMq.mjs";
6
6
  import { t as ManualClockKvStore } from "../kv-DBRWVx3Q.mjs";
7
7
  import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, r as envelopeSchema, t as MockQueue } from "../tasks-dbCShlCb.mjs";
8
- import "../testing-otQhu4aD.mjs";
8
+ import "../testing-CKaJhcA0.mjs";
9
9
  export { ManualClockKvStore, MockQueue, baseOptions, createInboxContext, createOutboxContext, createRequestContext, envelopeSchema, makeSchema, numberSchema, stringSchema, testDefinitions };
@@ -2,7 +2,7 @@ import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import "./dist-BQvArojP.mjs";
5
- import "./context-DfSVPcJ8.mjs";
5
+ import "./context-OrnjnuMq.mjs";
6
6
  import "./kv-DBRWVx3Q.mjs";
7
7
  import "./tasks-dbCShlCb.mjs";
8
8
  export {};
@@ -5,9 +5,9 @@ import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
6
6
  import "../std__assert-DvMDRPes.mjs";
7
7
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
8
- import { d as verifyRequest } from "../http-BoH-e8sR.mjs";
8
+ import { d as verifyRequest } from "../http-CXnNbRe_.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-DIJNHW-Y.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-C4h6PL7m.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-vc-pSu9-.mjs";
11
11
  import { configure, reset } from "@logtape/logtape";
12
12
  import { mockDocumentLoader, test } from "@fedify/fixture";
13
13
  import { FetchError, UrlError } from "@fedify/vocab-runtime";
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as kvCache, t as MockKvStore } from "../kv-cache-CMuTXrkC.mjs";
4
+ import { n as kvCache, t as MockKvStore } from "../kv-cache-DZr8HTel.mjs";
5
5
  import { deepStrictEqual, throws } from "node:assert";
6
6
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
7
7
  import { preloadedContexts } from "@fedify/vocab-runtime";
@@ -1,5 +1,5 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_kv_cache = require("../kv-cache-BxUqVENn.cjs");
3
+ const require_kv_cache = require("../kv-cache-DzClEalR.cjs");
4
4
  exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
5
5
  exports.kvCache = require_kv_cache.kvCache;
package/dist/utils/mod.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-E0es0w4R.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-3uKc0G76.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.4.0-dev.2149+e2302034",
3
+ "version": "2.4.0-dev.2155+2ccc5085",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -151,10 +151,10 @@
151
151
  "structured-field-values": "^2.0.4",
152
152
  "temporal-polyfill": "^1.0.1",
153
153
  "urlpattern-polyfill": "^10.1.0",
154
- "@fedify/uri-template": "2.4.0-dev.2149+e2302034",
155
- "@fedify/vocab-runtime": "2.4.0-dev.2149+e2302034",
156
- "@fedify/webfinger": "2.4.0-dev.2149+e2302034",
157
- "@fedify/vocab": "2.4.0-dev.2149+e2302034"
154
+ "@fedify/uri-template": "2.4.0-dev.2155+2ccc5085",
155
+ "@fedify/vocab-runtime": "2.4.0-dev.2155+2ccc5085",
156
+ "@fedify/vocab": "2.4.0-dev.2155+2ccc5085",
157
+ "@fedify/webfinger": "2.4.0-dev.2155+2ccc5085"
158
158
  },
159
159
  "devDependencies": {
160
160
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -167,7 +167,7 @@
167
167
  "typescript": "^6.0.0",
168
168
  "wrangler": "^4.17.0",
169
169
  "@fedify/fixture": "2.0.0",
170
- "@fedify/vocab-tools": "^2.4.0-dev.2149+e2302034"
170
+ "@fedify/vocab-tools": "^2.4.0-dev.2155+2ccc5085"
171
171
  },
172
172
  "scripts": {
173
173
  "build:self": "tsdown",