@fedify/adonisjs 2.4.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/LICENSE +20 -0
- package/README.md +420 -0
- package/dist/configure.cjs +108 -0
- package/dist/configure.cjs.map +1 -0
- package/dist/configure.d.cts +14 -0
- package/dist/configure.d.ts +14 -0
- package/dist/configure.js +107 -0
- package/dist/configure.js.map +1 -0
- package/dist/index.cjs +19 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/package.cjs +121 -0
- package/dist/package.cjs.map +1 -0
- package/dist/package.js +115 -0
- package/dist/package.js.map +1 -0
- package/dist/providers/fedify_provider.cjs +270 -0
- package/dist/providers/fedify_provider.cjs.map +1 -0
- package/dist/providers/fedify_provider.d.cts +54 -0
- package/dist/providers/fedify_provider.d.ts +55 -0
- package/dist/providers/fedify_provider.js +269 -0
- package/dist/providers/fedify_provider.js.map +1 -0
- package/dist/services/builder.cjs +9 -0
- package/dist/services/builder.cjs.map +1 -0
- package/dist/services/builder.d.cts +7 -0
- package/dist/services/builder.d.ts +8 -0
- package/dist/services/builder.js +8 -0
- package/dist/services/builder.js.map +1 -0
- package/dist/src/builder.cjs +55 -0
- package/dist/src/builder.cjs.map +1 -0
- package/dist/src/builder.d.cts +14 -0
- package/dist/src/builder.d.ts +14 -0
- package/dist/src/builder.js +54 -0
- package/dist/src/builder.js.map +1 -0
- package/dist/src/define_config.cjs +114 -0
- package/dist/src/define_config.cjs.map +1 -0
- package/dist/src/define_config.d.cts +30 -0
- package/dist/src/define_config.d.ts +30 -0
- package/dist/src/define_config.js +113 -0
- package/dist/src/define_config.js.map +1 -0
- package/dist/src/errors.cjs +77 -0
- package/dist/src/errors.cjs.map +1 -0
- package/dist/src/errors.d.cts +56 -0
- package/dist/src/errors.d.ts +56 -0
- package/dist/src/errors.js +73 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/fedify_middleware.cjs +507 -0
- package/dist/src/fedify_middleware.cjs.map +1 -0
- package/dist/src/fedify_middleware.d.cts +85 -0
- package/dist/src/fedify_middleware.d.ts +85 -0
- package/dist/src/fedify_middleware.js +505 -0
- package/dist/src/fedify_middleware.js.map +1 -0
- package/dist/src/http_context.cjs +79 -0
- package/dist/src/http_context.cjs.map +1 -0
- package/dist/src/http_context.d.cts +31 -0
- package/dist/src/http_context.d.ts +31 -0
- package/dist/src/http_context.js +76 -0
- package/dist/src/http_context.js.map +1 -0
- package/dist/src/logging.cjs +106 -0
- package/dist/src/logging.cjs.map +1 -0
- package/dist/src/logging.d.cts +45 -0
- package/dist/src/logging.d.ts +45 -0
- package/dist/src/logging.js +106 -0
- package/dist/src/logging.js.map +1 -0
- package/dist/src/types.cjs +1 -0
- package/dist/src/types.d.cts +269 -0
- package/dist/src/types.d.ts +269 -0
- package/dist/src/types.js +1 -0
- package/dist/src/unusable_authority.cjs +79 -0
- package/dist/src/unusable_authority.cjs.map +1 -0
- package/dist/src/unusable_authority.js +76 -0
- package/dist/src/unusable_authority.js.map +1 -0
- package/dist/stubs/config/fedify.stub +105 -0
- package/dist/stubs/federation/main.stub +64 -0
- package/dist/stubs/main.cjs +16 -0
- package/dist/stubs/main.cjs.map +1 -0
- package/dist/stubs/main.d.cts +11 -0
- package/dist/stubs/main.d.ts +11 -0
- package/dist/stubs/main.js +15 -0
- package/dist/stubs/main.js.map +1 -0
- package/dist/stubs/start/federation.stub +20 -0
- package/package.json +124 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2024–2026 Hong Minhee
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
<!-- deno-fmt-ignore-file -->
|
|
2
|
+
|
|
3
|
+
@fedify/adonisjs: Integrate Fedify with AdonisJS
|
|
4
|
+
================================================
|
|
5
|
+
|
|
6
|
+
[![npm][npm badge]][npm]
|
|
7
|
+
[![Matrix][Matrix badge]][Matrix]
|
|
8
|
+
[![@fedify@hackers.pub][@fedify@hackers.pub badge]][@fedify@hackers.pub]
|
|
9
|
+
|
|
10
|
+
*This package is available since Fedify 2.4.0.*
|
|
11
|
+
|
|
12
|
+
[Fedify] is a TypeScript library for building federated server applications
|
|
13
|
+
powered by [ActivityPub] and other standards, so-called [fediverse]. This
|
|
14
|
+
package integrates Fedify with [AdonisJS], a fully featured Node.js web
|
|
15
|
+
framework.
|
|
16
|
+
|
|
17
|
+
It gives an AdonisJS application everything Fedify needs and nothing it does
|
|
18
|
+
not: a server middleware that mounts the federation, a service provider that
|
|
19
|
+
owns the `Federation` object's lifecycle and constructs that middleware, a
|
|
20
|
+
*config/fedify.ts* file, and a `ctx.federation` context on every request. The
|
|
21
|
+
package follows the layout and conventions of the official AdonisJS packages
|
|
22
|
+
(`@adonisjs/cors`, `@adonisjs/session`), so it should feel familiar.
|
|
23
|
+
|
|
24
|
+
[npm badge]: https://img.shields.io/npm/v/@fedify/adonisjs?logo=npm
|
|
25
|
+
[npm]: https://www.npmjs.com/package/@fedify/adonisjs
|
|
26
|
+
[Matrix badge]: https://img.shields.io/matrix/fedify%3Amatrix.org
|
|
27
|
+
[Matrix]: https://matrix.to/#/#fedify:matrix.org
|
|
28
|
+
[@fedify@hackers.pub badge]: https://fedi-badge.minhee.org/@fedify@hackers.pub/followers.svg
|
|
29
|
+
[@fedify@hackers.pub]: https://hackers.pub/@fedify
|
|
30
|
+
[Fedify]: https://fedify.dev/
|
|
31
|
+
[ActivityPub]: https://www.w3.org/TR/activitypub/
|
|
32
|
+
[fediverse]: https://en.wikipedia.org/wiki/Fediverse
|
|
33
|
+
[AdonisJS]: https://adonisjs.com/
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
Requirements
|
|
37
|
+
------------
|
|
38
|
+
|
|
39
|
+
- AdonisJS 7.4.0 or later
|
|
40
|
+
- Fedify 2.4.0 or later
|
|
41
|
+
- Node.js 24 or later — and Node.js only; see below
|
|
42
|
+
|
|
43
|
+
The package ships both ESM and CommonJS builds. The CommonJS one works because
|
|
44
|
+
the Node.js versions AdonisJS supports can `require()` ESM dependencies.
|
|
45
|
+
|
|
46
|
+
### Runtime support: Node.js only
|
|
47
|
+
|
|
48
|
+
> [!IMPORTANT]
|
|
49
|
+
> This package targets Node.js exclusively. It is published to npm only, never
|
|
50
|
+
> to JSR, and it is neither tested nor supported on Deno or Bun.
|
|
51
|
+
|
|
52
|
+
That is a deliberate scope decision inherited from the framework rather than an
|
|
53
|
+
oversight, for three reasons.
|
|
54
|
+
|
|
55
|
+
- AdonisJS documents Node.js as its only runtime. Its installation guide
|
|
56
|
+
lists Node.js ≥ 24 and npm ≥ 11 as the sole prerequisites and never
|
|
57
|
+
mentions Deno or Bun, and its maintainers have
|
|
58
|
+
[declined to support multiple runtimes][adonisjs-runtimes]. An integration
|
|
59
|
+
package cannot credibly promise a runtime that the framework it integrates
|
|
60
|
+
does not.
|
|
61
|
+
- The Node.js 24 floor is AdonisJS's own. `@adonisjs/core` declares
|
|
62
|
+
`engines.node >= 24.0.0`; this package matches that floor rather than
|
|
63
|
+
inventing one.
|
|
64
|
+
- JSR cannot represent this package. The AdonisJS-native layer works by
|
|
65
|
+
augmenting AdonisJS's own module types — `ctx.federation` on `HttpContext`,
|
|
66
|
+
and the `fedify`, `fedify.builder` and `fedify.config` container bindings.
|
|
67
|
+
JSR's [“slow types”][jsr-slow-types] rules reject ambient `declare module`
|
|
68
|
+
augmentation anywhere in a published module graph, and the augmentation
|
|
69
|
+
cannot be hidden from that graph without also hiding it from the
|
|
70
|
+
applications that need it. So the feature and JSR publication are mutually
|
|
71
|
+
exclusive, and the feature is the entire point of the package.
|
|
72
|
+
|
|
73
|
+
Consequently this package ships no *deno.json* and stays out of the Fedify
|
|
74
|
+
monorepo's Deno workspace — the same position as `@fedify/nestjs` and
|
|
75
|
+
`@fedify/next`.
|
|
76
|
+
|
|
77
|
+
[adonisjs-runtimes]: https://github.com/orgs/adonisjs/discussions/4191
|
|
78
|
+
[jsr-slow-types]: https://jsr.io/docs/about-slow-types#global-augmentation
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
Installation
|
|
82
|
+
------------
|
|
83
|
+
|
|
84
|
+
~~~~ sh
|
|
85
|
+
node ace add @fedify/adonisjs
|
|
86
|
+
~~~~
|
|
87
|
+
|
|
88
|
+
That installs the package and runs its `configure` hook, which does the whole
|
|
89
|
+
wiring:
|
|
90
|
+
|
|
91
|
+
- installs `@fedify/fedify` and `@fedify/vocab`, in the version range this
|
|
92
|
+
package's peer dependency accepts,
|
|
93
|
+
- declares `PUBLIC_URL` and an optional `FEDERATION_HANDLE_HOST` in
|
|
94
|
+
*start/env.ts*, and adds `PUBLIC_URL` to *.env*,
|
|
95
|
+
- writes *config/fedify.ts*, *start/federation.ts* and
|
|
96
|
+
*app/federation/main.ts*,
|
|
97
|
+
- registers the service provider (`@fedify/adonisjs/fedify_provider`) and the
|
|
98
|
+
*start/federation.ts* preload file in *adonisrc.ts*, and
|
|
99
|
+
- adds the middleware (`@fedify/adonisjs/fedify_middleware`) to the front of
|
|
100
|
+
the `server` middleware stack in *start/kernel.ts*.
|
|
101
|
+
|
|
102
|
+
To install it without running the hook, use `npm install @fedify/adonisjs`
|
|
103
|
+
followed by `node ace configure @fedify/adonisjs`.
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
Usage
|
|
107
|
+
-----
|
|
108
|
+
|
|
109
|
+
### Registering dispatchers
|
|
110
|
+
|
|
111
|
+
Actor dispatchers, collection dispatchers and inbox listeners are registered on
|
|
112
|
+
the `FederationBuilder` exported by `@fedify/adonisjs/services/builder`:
|
|
113
|
+
|
|
114
|
+
~~~~ typescript
|
|
115
|
+
// app/federation/main.ts
|
|
116
|
+
import federation from '@fedify/adonisjs/services/builder'
|
|
117
|
+
import { Endpoints, Person } from '@fedify/vocab'
|
|
118
|
+
import Actor from '#models/actor'
|
|
119
|
+
|
|
120
|
+
federation
|
|
121
|
+
.setActorDispatcher('/actors/{identifier}', async (ctx, identifier) => {
|
|
122
|
+
const actor = await Actor.findBy('identifier', identifier)
|
|
123
|
+
if (actor === null) return null
|
|
124
|
+
|
|
125
|
+
const keys = await ctx.getActorKeyPairs(identifier)
|
|
126
|
+
|
|
127
|
+
return new Person({
|
|
128
|
+
id: ctx.getActorUri(identifier),
|
|
129
|
+
preferredUsername: identifier,
|
|
130
|
+
name: actor.name,
|
|
131
|
+
inbox: ctx.getInboxUri(identifier),
|
|
132
|
+
endpoints: new Endpoints({ sharedInbox: ctx.getInboxUri() }),
|
|
133
|
+
publicKeys: keys.map((keyPair) => keyPair.cryptographicKey),
|
|
134
|
+
assertionMethods: keys.map((keyPair) => keyPair.multikey),
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
.setKeyPairsDispatcher(async (_ctx, _identifier) => {
|
|
138
|
+
// Load or generate the actor's key pairs.
|
|
139
|
+
return []
|
|
140
|
+
})
|
|
141
|
+
~~~~
|
|
142
|
+
|
|
143
|
+
The module is loaded by the *start/federation.ts* preload file, which AdonisJS
|
|
144
|
+
imports after every service provider has booted — so dispatchers may use Lucid
|
|
145
|
+
models, the container, and anything else the application provides. Import
|
|
146
|
+
further modules from that file as the federation grows.
|
|
147
|
+
|
|
148
|
+
Registration happens once per process. Do not add *app/federation* to
|
|
149
|
+
`hotHook.boundaries`: re-importing a module on a hot reload would register the
|
|
150
|
+
same dispatcher twice, and Fedify rejects that. Restart the dev server after
|
|
151
|
+
changing a dispatcher.
|
|
152
|
+
|
|
153
|
+
### Using the federation from controllers
|
|
154
|
+
|
|
155
|
+
The middleware attaches a Fedify `RequestContext` to every request:
|
|
156
|
+
|
|
157
|
+
~~~~ typescript
|
|
158
|
+
import type { HttpContext } from '@adonisjs/core/http'
|
|
159
|
+
|
|
160
|
+
export default class ActorsController {
|
|
161
|
+
// GET /actors/:identifier — the same URL template the actor dispatcher
|
|
162
|
+
// serves, so the route parameter is the local identifier.
|
|
163
|
+
async show({ params, view, federation }: HttpContext) {
|
|
164
|
+
return view.render('pages/actors/show', {
|
|
165
|
+
actorUri: federation.getActorUri(params.identifier).href,
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// GET /lookup/:handle — dereference a remote object by its fediverse handle
|
|
170
|
+
// or URI, for example `@fedify@hackers.pub`.
|
|
171
|
+
async lookup({ params, view, federation }: HttpContext) {
|
|
172
|
+
const object = await federation.lookupObject(params.handle)
|
|
173
|
+
|
|
174
|
+
return view.render('pages/actors/lookup', { object })
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
~~~~
|
|
178
|
+
|
|
179
|
+
`federation` is a getter on `HttpContext` — installed once by the service
|
|
180
|
+
provider through AdonisJS's `Macroable`, the same mechanism behind `ctx.view` —
|
|
181
|
+
and the context is created lazily on first access and memoised for the rest of
|
|
182
|
+
the request, so requests that never touch it pay nothing for it.
|
|
183
|
+
|
|
184
|
+
Outside an HTTP request — in an Ace command, a scheduled job or a queue worker —
|
|
185
|
+
resolve the `Federation` object from the container and create a context from
|
|
186
|
+
the canonical origin:
|
|
187
|
+
|
|
188
|
+
~~~~ typescript
|
|
189
|
+
import app from '@adonisjs/core/services/app'
|
|
190
|
+
import env from '#start/env'
|
|
191
|
+
|
|
192
|
+
const federation = await app.container.make('fedify')
|
|
193
|
+
const ctx = federation.createContext(new URL(env.get('PUBLIC_URL')), null)
|
|
194
|
+
await ctx.sendActivity({ identifier: 'me' }, recipient, activity)
|
|
195
|
+
~~~~
|
|
196
|
+
|
|
197
|
+
The binding resolves only once the application is ready; resolving it earlier —
|
|
198
|
+
from a preload file or a service provider — throws `E_FEDERATION_NOT_READY`
|
|
199
|
+
rather than handing back a federation with no routes. Preload files should
|
|
200
|
+
register dispatchers on `@fedify/adonisjs/services/builder` instead.
|
|
201
|
+
|
|
202
|
+
### Without the container
|
|
203
|
+
|
|
204
|
+
`fedifyMiddleware` is the package's main integration function and its default
|
|
205
|
+
export. It takes a `Federation` and a context-data factory, and has nothing to
|
|
206
|
+
do with the IoC container, so an application that would rather build its own
|
|
207
|
+
`Federation` can skip the provider entirely:
|
|
208
|
+
|
|
209
|
+
~~~~ typescript
|
|
210
|
+
// start/kernel.ts
|
|
211
|
+
import fedifyMiddleware from '@fedify/adonisjs'
|
|
212
|
+
import federation from '../app/federation.js'
|
|
213
|
+
|
|
214
|
+
server.use([
|
|
215
|
+
async () => ({ default: fedifyMiddleware(federation, (ctx) => ctx) }),
|
|
216
|
+
])
|
|
217
|
+
~~~~
|
|
218
|
+
|
|
219
|
+
Here *app/federation.ts* is a module of the application's own that
|
|
220
|
+
default-exports the `Federation` it built — not the scaffolded
|
|
221
|
+
*app/federation/main.ts*, which registers dispatchers on the builder service
|
|
222
|
+
and exports nothing.
|
|
223
|
+
|
|
224
|
+
The factory may be left out only when the federation's context data type admits
|
|
225
|
+
`undefined`, since that is what the default factory produces; with the package's
|
|
226
|
+
default context data of `HttpContext | null`, `(ctx) => ctx` gives the same
|
|
227
|
+
behaviour as the provider.
|
|
228
|
+
|
|
229
|
+
It returns a subclass of `FedifyMiddleware`, the class the service provider
|
|
230
|
+
constructs, with the arguments closed over so that `server.use()` can
|
|
231
|
+
instantiate it without the container. The class itself is exported too, for
|
|
232
|
+
applications that bind it in the container from a provider of their own —
|
|
233
|
+
*start/kernel.ts* then registers `@fedify/adonisjs/fedify_middleware` as usual,
|
|
234
|
+
and the binding is what constructs it:
|
|
235
|
+
|
|
236
|
+
~~~~ typescript
|
|
237
|
+
import { FedifyMiddleware } from '@fedify/adonisjs'
|
|
238
|
+
|
|
239
|
+
this.app.container.bind(
|
|
240
|
+
FedifyMiddleware,
|
|
241
|
+
() => new FedifyMiddleware(federation, (ctx) => ctx),
|
|
242
|
+
)
|
|
243
|
+
~~~~
|
|
244
|
+
|
|
245
|
+
`ctx.federation` works either way: the middleware installs the getter itself
|
|
246
|
+
when no provider has.
|
|
247
|
+
|
|
248
|
+
### Configuration
|
|
249
|
+
|
|
250
|
+
*config/fedify.ts* takes every [`FederationOptions`] Fedify accepts, plus a few
|
|
251
|
+
AdonisJS-specific keys:
|
|
252
|
+
|
|
253
|
+
~~~~ typescript
|
|
254
|
+
import { defineConfig } from '@fedify/adonisjs'
|
|
255
|
+
import { SqliteKvStore, SqliteMessageQueue } from '@fedify/sqlite'
|
|
256
|
+
import env from '#start/env'
|
|
257
|
+
|
|
258
|
+
export default defineConfig({
|
|
259
|
+
origin: env.get('PUBLIC_URL'),
|
|
260
|
+
kv: new SqliteKvStore(database),
|
|
261
|
+
queue: new SqliteMessageQueue(database),
|
|
262
|
+
queueContextData: () => null,
|
|
263
|
+
ignoreRoutePrefixes: ['/@vite/'],
|
|
264
|
+
})
|
|
265
|
+
~~~~
|
|
266
|
+
|
|
267
|
+
| Option | Purpose |
|
|
268
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
269
|
+
| `origin` | Required. The canonical public origin. Actor URIs and activity IDs are minted from it. |
|
|
270
|
+
| `kv` | Fedify's key–value store. Defaults to an in-memory store, with a warning in production. |
|
|
271
|
+
| `contextDataFactory` | Builds the per-request context data. Defaults to the `HttpContext` itself, and is required once `FedifyTypes` is augmented. |
|
|
272
|
+
| `ignoreRoutePrefixes` | URL path prefixes that skip Fedify entirely. Defaults to none. |
|
|
273
|
+
| `logging` | Whether to pipe Fedify's LogTape output into the AdonisJS logger. Defaults to `true`. |
|
|
274
|
+
| `queueContextData` | Who drains the queue: a callback (this process) or `false` (a separate worker). Required with `queue`; a callback without one warns. |
|
|
275
|
+
|
|
276
|
+
[`FederationOptions`]: https://jsr.io/@fedify/fedify/doc/~/FederationOptions
|
|
277
|
+
|
|
278
|
+
### Module exports
|
|
279
|
+
|
|
280
|
+
| Specifier | What it is |
|
|
281
|
+
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
282
|
+
| `@fedify/adonisjs` | `fedifyMiddleware` (default), `FedifyMiddleware`, `defineConfig`, `configure`, `configureFedifyLogging`, `stubsRoot`, the error classes and the types |
|
|
283
|
+
| `@fedify/adonisjs/types` | The augmentation target for `FedifyTypes` |
|
|
284
|
+
| `@fedify/adonisjs/fedify_provider` | The service provider, referenced by specifier from *adonisrc.ts* |
|
|
285
|
+
| `@fedify/adonisjs/fedify_middleware` | The `FedifyMiddleware` class, referenced by specifier from *start/kernel.ts* |
|
|
286
|
+
| `@fedify/adonisjs/services/builder` | The `FederationBuilder`, as an AdonisJS service module |
|
|
287
|
+
|
|
288
|
+
Each subpath exists because AdonisJS reaches for it by module specifier or by
|
|
289
|
+
service-module convention, and the names follow the official packages
|
|
290
|
+
(`@adonisjs/cors/cors_middleware`, `@adonisjs/cors/cors_provider`); everything
|
|
291
|
+
else lives on the root export. The built `Federation` deliberately has no
|
|
292
|
+
service module of its own — resolve it with `app.container.make('fedify')`,
|
|
293
|
+
which can also tell you *why* when it is not available yet. A service module
|
|
294
|
+
in the style of `@adonisjs/core/services/router` would have to capture the
|
|
295
|
+
instance from an `app.booted()` hook, but dispatchers are registered from
|
|
296
|
+
preload files, which AdonisJS imports after `booted`, so the `Federation` is
|
|
297
|
+
only sealed in the provider's `ready` phase — later than such a module could
|
|
298
|
+
observe.
|
|
299
|
+
|
|
300
|
+
### Context data
|
|
301
|
+
|
|
302
|
+
Fedify threads an application-defined value through every dispatcher and inbox
|
|
303
|
+
listener. By default that value is `HttpContext | null` — `null` when Fedify is
|
|
304
|
+
working outside a request, such as inside a queue worker. To carry something
|
|
305
|
+
else, augment the register interface and supply a factory. The augmentation
|
|
306
|
+
makes `contextDataFactory` a required option, so forgetting it is a type error
|
|
307
|
+
in *config/fedify.ts* rather than an `HttpContext` turning up where a dispatcher
|
|
308
|
+
expected the augmented value:
|
|
309
|
+
|
|
310
|
+
~~~~ typescript
|
|
311
|
+
declare module '@fedify/adonisjs/types' {
|
|
312
|
+
interface FedifyTypes {
|
|
313
|
+
contextData: { requestId: string | undefined }
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export default defineConfig({
|
|
318
|
+
origin: env.get('PUBLIC_URL'),
|
|
319
|
+
contextDataFactory: (ctx) => ({ requestId: ctx.request.id() }),
|
|
320
|
+
})
|
|
321
|
+
~~~~
|
|
322
|
+
|
|
323
|
+
The factory runs in the server middleware stack, before route matching, so only
|
|
324
|
+
`ctx.request`, `ctx.response`, `ctx.logger` and `ctx.containerResolver` are set;
|
|
325
|
+
`ctx.auth`, `ctx.session`, `ctx.bouncer`, `ctx.params` and `ctx.route` are still
|
|
326
|
+
`undefined` (`ctx.params` is `{}`) because the middleware that fills them has
|
|
327
|
+
not run yet. Look anything session-bound up inside the dispatcher that needs
|
|
328
|
+
it—a federation request comes from a remote server and has no session anyway.
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
How requests are routed
|
|
332
|
+
-----------------------
|
|
333
|
+
|
|
334
|
+
The middleware runs in the `server` stack, before route matching and before
|
|
335
|
+
the body parser. Both matter: Fedify serves paths the AdonisJS router knows
|
|
336
|
+
nothing about, and HTTP Signature verification needs the raw request body. It
|
|
337
|
+
also runs before `@adonisjs/shield`, so inbox `POST`s are not rejected by CSRF
|
|
338
|
+
protection.
|
|
339
|
+
|
|
340
|
+
The configure hook puts it *first* in that stack, and it belongs there:
|
|
341
|
+
content negotiation decides what Fedify answers, so nothing that rewrites
|
|
342
|
+
`Accept` may run ahead of it. The API starter kit's
|
|
343
|
+
`force_json_response_middleware` turns every `Accept` into
|
|
344
|
+
`application/json`, which Fedify reads as a request for the ActivityPub
|
|
345
|
+
document—a browser asking an actor URL for HTML would get the actor document
|
|
346
|
+
instead, and the HTML fall-through below could never run. Requests Fedify
|
|
347
|
+
answers itself therefore skip the rest of the stack, including the starter
|
|
348
|
+
kits' `container_bindings_middleware`; a dispatcher that needs an
|
|
349
|
+
`HttpContext` reads it from `ctx.data`, which is what the default context data
|
|
350
|
+
carries.
|
|
351
|
+
|
|
352
|
+
Every request the middleware does not bypass (see `ignoreRoutePrefixes`)
|
|
353
|
+
reaches Fedify first, and one of three things happens.
|
|
354
|
+
|
|
355
|
+
- Fedify serves it. Actor documents, collections, inboxes,
|
|
356
|
+
*/.well-known/webfinger* and */.well-known/nodeinfo* never reach the
|
|
357
|
+
AdonisJS router.
|
|
358
|
+
- Fedify has no route for the path. The request is handed to the AdonisJS
|
|
359
|
+
router, and the application answers exactly as it would without this
|
|
360
|
+
package.
|
|
361
|
+
- Fedify has a route but cannot satisfy the `Accept` header. This is the
|
|
362
|
+
interesting one. Rather than answering `406` immediately, the middleware
|
|
363
|
+
gives the AdonisJS router a chance first, and only answers
|
|
364
|
+
`406 Not Acceptable` if the router had nothing either.
|
|
365
|
+
|
|
366
|
+
That last rule is what lets a single URL serve an HTML profile page to browsers
|
|
367
|
+
and an ActivityPub actor document to servers. Register an ordinary route on the
|
|
368
|
+
same path as the actor dispatcher and it will handle the HTML half:
|
|
369
|
+
|
|
370
|
+
~~~~ typescript
|
|
371
|
+
// start/routes.ts — same path as setActorDispatcher('/actors/{identifier}', …)
|
|
372
|
+
router.get('/actors/:identifier', [controllers.Actors, 'show'])
|
|
373
|
+
~~~~
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
Deployment notes
|
|
377
|
+
----------------
|
|
378
|
+
|
|
379
|
+
- Set `origin` to the public URL. Fedify mints actor URIs from it, so behind
|
|
380
|
+
a reverse proxy, a load balancer or a tunnel it must be the address remote
|
|
381
|
+
servers can reach, not the address Node listens on. When developing with
|
|
382
|
+
`fedify tunnel`, point `PUBLIC_URL` at the tunnel and restart.
|
|
383
|
+
- Configure a persistent `kv` and a `queue`. Without a queue, delivery is
|
|
384
|
+
synchronous and failed deliveries are never retried. `@fedify/sqlite`,
|
|
385
|
+
`@fedify/postgres`, `@fedify/redis` and `@fedify/mysql` all provide both.
|
|
386
|
+
`queueContextData` says who drains the queue: a callback has the web
|
|
387
|
+
process do it (started in the `ready` hook, stopped on shutdown, and never
|
|
388
|
+
started in an Ace command or a test run), while `false` leaves the queue to
|
|
389
|
+
a separate worker. A `queue` without it is refused at boot. A callback
|
|
390
|
+
without a `queue` only warns, since a task registered through
|
|
391
|
+
`defineTask()` may bring its own queue. `false` without a `queue` is
|
|
392
|
+
accepted silently, so a deployment that enables the queue in production
|
|
393
|
+
only can write `queue: app.inProduction ? … : undefined` together with
|
|
394
|
+
`queueContextData: app.inProduction ? () => … : false`.
|
|
395
|
+
- Configure `trustProxy` in *config/app.ts* when a proxy sits in front of the
|
|
396
|
+
application. AdonisJS honours `X-Forwarded-Proto` and `X-Forwarded-Host`
|
|
397
|
+
only from peers it trusts, and its default trusts loopback — which is
|
|
398
|
+
where `fedify tunnel` connects from. Name the proxy's address rather than
|
|
399
|
+
trusting every client, since a trusted client chooses the host and protocol
|
|
400
|
+
the application sees.
|
|
401
|
+
- Make the proxy preserve `Host`. HTTP Signatures cover the bytes the peer
|
|
402
|
+
sent, so a proxy that rewrites `Host` to the upstream's own name—the
|
|
403
|
+
`proxy_pass` default in nginx—breaks signature verification. Keep it, port
|
|
404
|
+
included: `proxy_set_header Host $http_host;` in nginx. Over HTTP/2 the
|
|
405
|
+
`:authority` pseudo-header wins over `X-Forwarded-Host`, so a proxy
|
|
406
|
+
speaking HTTP/2 to the application has to preserve that too.
|
|
407
|
+
- Watch for the “unusable request authority” warning. A host carrying a
|
|
408
|
+
path, query, fragment or userinfo cannot be a real authority. The request
|
|
409
|
+
is still answered, but Fedify sees a placeholder host, and while `origin`
|
|
410
|
+
keeps the URLs it mints correct, a request signed over RFC 9421's
|
|
411
|
+
`@authority` fails to verify. The warning is logged once per distinct
|
|
412
|
+
value, for at most sixteen values an hour, so junk hosts from clients can
|
|
413
|
+
neither fill the log nor hide a real misconfiguration for long. Behind a
|
|
414
|
+
proxy, treat it as a misconfiguration to fix; without one, it only records
|
|
415
|
+
that a client sent an unusable `Host`.
|
|
416
|
+
|
|
417
|
+
A complete, runnable application using all of this lives in the
|
|
418
|
+
[*examples/adonisjs*] directory.
|
|
419
|
+
|
|
420
|
+
[*examples/adonisjs*]: https://github.com/fedify-dev/fedify/tree/main/examples/adonisjs
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_package = require('./package.cjs');
|
|
3
|
+
const require_stubs_main = require('./stubs/main.cjs');
|
|
4
|
+
|
|
5
|
+
//#region configure.ts
|
|
6
|
+
/**
|
|
7
|
+
* The range the Fedify runtime packages are installed with.
|
|
8
|
+
*
|
|
9
|
+
* Derived from this package's own version so a release cannot leave it behind:
|
|
10
|
+
* every package in this monorepo shares one version, and the `@fedify/fedify`
|
|
11
|
+
* peer dependency is declared as `workspace:^`, which publishes as this range.
|
|
12
|
+
*
|
|
13
|
+
* Installing unpinned would pull the next major once it is out, which the peer
|
|
14
|
+
* range rejects: a peer warning, and two copies of the vocabulary, which the
|
|
15
|
+
* `instanceof` comparisons noted below cannot survive.
|
|
16
|
+
*/
|
|
17
|
+
const FEDIFY_RANGE = `^${require_package.version}`;
|
|
18
|
+
/**
|
|
19
|
+
* Wires `@fedify/adonisjs` into an application.
|
|
20
|
+
*
|
|
21
|
+
* Run by `node ace configure @fedify/adonisjs` (and therefore by
|
|
22
|
+
* `node ace add @fedify/adonisjs`); see the module documentation for the
|
|
23
|
+
* steps it performs.
|
|
24
|
+
*/
|
|
25
|
+
async function configure(command) {
|
|
26
|
+
const codemods = await command.createCodemods();
|
|
27
|
+
/**
|
|
28
|
+
* Fedify itself is a peer dependency: the application, not this package,
|
|
29
|
+
* decides which version it runs, and having exactly one copy in the tree
|
|
30
|
+
* matters because Fedify's vocabulary classes are compared with `instanceof`.
|
|
31
|
+
*
|
|
32
|
+
* `@fedify/vocab` carries the ActivityStreams classes (`Person`, `Follow`,
|
|
33
|
+
* `Note`, …) that dispatchers and inbox listeners are written against.
|
|
34
|
+
*/
|
|
35
|
+
await codemods.installPackages([{
|
|
36
|
+
name: `@fedify/fedify@${FEDIFY_RANGE}`,
|
|
37
|
+
isDevDependency: false
|
|
38
|
+
}, {
|
|
39
|
+
name: `@fedify/vocab@${FEDIFY_RANGE}`,
|
|
40
|
+
isDevDependency: false
|
|
41
|
+
}]);
|
|
42
|
+
/**
|
|
43
|
+
* `PUBLIC_URL` is the canonical origin remote servers use to reach this
|
|
44
|
+
* application. Fedify mints actor URIs and activity IDs from it, so it has to
|
|
45
|
+
* be the public address rather than the listen address — behind a proxy or a
|
|
46
|
+
* `fedify tunnel` those differ.
|
|
47
|
+
*
|
|
48
|
+
* `FEDERATION_HANDLE_HOST` is optional and only needed when fediverse handles
|
|
49
|
+
* live on a different domain than the web origin, for example `@me@example.com`
|
|
50
|
+
* served from `https://social.example.com`.
|
|
51
|
+
*/
|
|
52
|
+
await codemods.defineEnvValidations({
|
|
53
|
+
leadingComment: "Variables for configuring Fedify",
|
|
54
|
+
variables: {
|
|
55
|
+
PUBLIC_URL: `Env.schema.string({ format: 'url', tld: false })`,
|
|
56
|
+
FEDERATION_HANDLE_HOST: `Env.schema.string.optional({ format: 'host' })`
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
await codemods.defineEnvVariables({ PUBLIC_URL: "http://localhost:3333" });
|
|
60
|
+
/**
|
|
61
|
+
* `config/fedify.ts` — the federation options.
|
|
62
|
+
*/
|
|
63
|
+
await codemods.makeUsingStub(require_stubs_main.stubsRoot, "config/fedify.stub", {});
|
|
64
|
+
/**
|
|
65
|
+
* `start/federation.ts` — a preload file that imports the application's
|
|
66
|
+
* dispatcher modules.
|
|
67
|
+
*
|
|
68
|
+
* A preload file rather than directory globbing: preload files are ordinary
|
|
69
|
+
* application source, so `node ace build` compiles them and their relative
|
|
70
|
+
* imports along with everything else, and AdonisJS imports them after every
|
|
71
|
+
* provider has booted, which is what lets dispatchers use Lucid models.
|
|
72
|
+
*/
|
|
73
|
+
await codemods.makeUsingStub(require_stubs_main.stubsRoot, "start/federation.stub", {});
|
|
74
|
+
/**
|
|
75
|
+
* `app/federation/main.ts` — a starting point for dispatchers.
|
|
76
|
+
*/
|
|
77
|
+
await codemods.makeUsingStub(require_stubs_main.stubsRoot, "federation/main.stub", {});
|
|
78
|
+
await codemods.updateRcFile((rcFile) => {
|
|
79
|
+
rcFile.addProvider("@fedify/adonisjs/fedify_provider");
|
|
80
|
+
rcFile.addPreloadFile("#start/federation");
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* The middleware must live in the **server** stack.
|
|
84
|
+
*
|
|
85
|
+
* Fedify answers paths the AdonisJS router does not know about
|
|
86
|
+
* (`/.well-known/webfinger`, `/.well-known/nodeinfo`, actor and inbox
|
|
87
|
+
* endpoints), so it has to run before route matching. The server stack also
|
|
88
|
+
* runs before `bodyparser_middleware` and before `@adonisjs/shield`, which
|
|
89
|
+
* matters twice over: HTTP Signature verification needs the raw, unparsed
|
|
90
|
+
* request body, and inbox `POST`s must not be rejected by CSRF protection.
|
|
91
|
+
*
|
|
92
|
+
* It also goes *first* in that stack, so that Fedify negotiates on the
|
|
93
|
+
* client's real `Accept` header. The API starter kit's
|
|
94
|
+
* `force_json_response_middleware`, for example, rewrites every `Accept` to
|
|
95
|
+
* `application/json`, which would make Fedify serve the ActivityPub document
|
|
96
|
+
* to a browser asking for HTML and skip the HTML fall-through.
|
|
97
|
+
*/
|
|
98
|
+
await codemods.registerMiddleware("server", [{
|
|
99
|
+
path: "@fedify/adonisjs/fedify_middleware",
|
|
100
|
+
position: "before"
|
|
101
|
+
}]);
|
|
102
|
+
command.logger.success("Configured @fedify/adonisjs");
|
|
103
|
+
command.logger.info("Register dispatchers in app/federation/main.ts, then run \"node ace serve\"");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
107
|
+
exports.configure = configure;
|
|
108
|
+
//# sourceMappingURL=configure.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.cjs","names":["stubsRoot"],"sources":["../configure.ts"],"sourcesContent":["/**\n * The configure hook, run by `node ace configure @fedify/adonisjs`.\n *\n * It performs every wiring step the package needs, so that a freshly configured\n * application already federates: install the Fedify runtime packages, declare\n * the environment variables, publish the config file and the federation preload\n * files, register the service provider, and add the middleware to the server\n * stack.\n *\n * @module\n */\nimport type ConfigureCommand from \"@adonisjs/core/commands/configure\";\n\nimport packageJson from \"./package.json\" with { type: \"json\" };\nimport { stubsRoot } from \"./stubs/main.ts\";\n\n/**\n * The slice of `@adonisjs/assembler`'s `RcFileTransformer` this hook touches.\n *\n * Spelled out rather than inferred because the assembler is an *optional* peer\n * dependency: wherever it is absent — a type-check of a tree that did not\n * install it, for instance — the inferred parameter type of `updateRcFile`'s\n * callback degrades to `any`, and this file stops compiling under\n * `noImplicitAny`.\n */\ninterface RcFileEditor {\n addProvider(providerPath: string): unknown;\n addPreloadFile(modulePath: string): unknown;\n}\n\n/**\n * The range the Fedify runtime packages are installed with.\n *\n * Derived from this package's own version so a release cannot leave it behind:\n * every package in this monorepo shares one version, and the `@fedify/fedify`\n * peer dependency is declared as `workspace:^`, which publishes as this range.\n *\n * Installing unpinned would pull the next major once it is out, which the peer\n * range rejects: a peer warning, and two copies of the vocabulary, which the\n * `instanceof` comparisons noted below cannot survive.\n */\nconst FEDIFY_RANGE = `^${packageJson.version}`;\n\n/**\n * Wires `@fedify/adonisjs` into an application.\n *\n * Run by `node ace configure @fedify/adonisjs` (and therefore by\n * `node ace add @fedify/adonisjs`); see the module documentation for the\n * steps it performs.\n */\nexport async function configure(command: ConfigureCommand): Promise<void> {\n const codemods = await command.createCodemods();\n\n /**\n * Fedify itself is a peer dependency: the application, not this package,\n * decides which version it runs, and having exactly one copy in the tree\n * matters because Fedify's vocabulary classes are compared with `instanceof`.\n *\n * `@fedify/vocab` carries the ActivityStreams classes (`Person`, `Follow`,\n * `Note`, …) that dispatchers and inbox listeners are written against.\n */\n await codemods.installPackages([\n { name: `@fedify/fedify@${FEDIFY_RANGE}`, isDevDependency: false },\n { name: `@fedify/vocab@${FEDIFY_RANGE}`, isDevDependency: false },\n ]);\n\n /**\n * `PUBLIC_URL` is the canonical origin remote servers use to reach this\n * application. Fedify mints actor URIs and activity IDs from it, so it has to\n * be the public address rather than the listen address — behind a proxy or a\n * `fedify tunnel` those differ.\n *\n * `FEDERATION_HANDLE_HOST` is optional and only needed when fediverse handles\n * live on a different domain than the web origin, for example `@me@example.com`\n * served from `https://social.example.com`.\n */\n await codemods.defineEnvValidations({\n leadingComment: \"Variables for configuring Fedify\",\n variables: {\n PUBLIC_URL: `Env.schema.string({ format: 'url', tld: false })`,\n FEDERATION_HANDLE_HOST: `Env.schema.string.optional({ format: 'host' })`,\n },\n });\n\n await codemods.defineEnvVariables({ PUBLIC_URL: \"http://localhost:3333\" });\n\n /**\n * `config/fedify.ts` — the federation options.\n */\n await codemods.makeUsingStub(stubsRoot, \"config/fedify.stub\", {});\n\n /**\n * `start/federation.ts` — a preload file that imports the application's\n * dispatcher modules.\n *\n * A preload file rather than directory globbing: preload files are ordinary\n * application source, so `node ace build` compiles them and their relative\n * imports along with everything else, and AdonisJS imports them after every\n * provider has booted, which is what lets dispatchers use Lucid models.\n */\n await codemods.makeUsingStub(stubsRoot, \"start/federation.stub\", {});\n\n /**\n * `app/federation/main.ts` — a starting point for dispatchers.\n */\n await codemods.makeUsingStub(stubsRoot, \"federation/main.stub\", {});\n\n await codemods.updateRcFile((rcFile: RcFileEditor) => {\n rcFile.addProvider(\"@fedify/adonisjs/fedify_provider\");\n rcFile.addPreloadFile(\"#start/federation\");\n });\n\n /**\n * The middleware must live in the **server** stack.\n *\n * Fedify answers paths the AdonisJS router does not know about\n * (`/.well-known/webfinger`, `/.well-known/nodeinfo`, actor and inbox\n * endpoints), so it has to run before route matching. The server stack also\n * runs before `bodyparser_middleware` and before `@adonisjs/shield`, which\n * matters twice over: HTTP Signature verification needs the raw, unparsed\n * request body, and inbox `POST`s must not be rejected by CSRF protection.\n *\n * It also goes *first* in that stack, so that Fedify negotiates on the\n * client's real `Accept` header. The API starter kit's\n * `force_json_response_middleware`, for example, rewrites every `Accept` to\n * `application/json`, which would make Fedify serve the ActivityPub document\n * to a browser asking for HTML and skip the HTML fall-through.\n */\n await codemods.registerMiddleware(\"server\", [{\n path: \"@fedify/adonisjs/fedify_middleware\",\n position: \"before\",\n }]);\n\n command.logger.success(\"Configured @fedify/adonisjs\");\n command.logger.info(\n 'Register dispatchers in app/federation/main.ts, then run \"node ace serve\"',\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyCA,MAAM,eAAe;;;;;;;;AASrB,eAAsB,UAAU,SAA0C;CACxE,MAAM,WAAW,MAAM,QAAQ,eAAe;;;;;;;;;CAU9C,MAAM,SAAS,gBAAgB,CAC7B;EAAE,MAAM,kBAAkB;EAAgB,iBAAiB;CAAM,GACjE;EAAE,MAAM,iBAAiB;EAAgB,iBAAiB;CAAM,CAClE,CAAC;;;;;;;;;;;CAYD,MAAM,SAAS,qBAAqB;EAClC,gBAAgB;EAChB,WAAW;GACT,YAAY;GACZ,wBAAwB;EAC1B;CACF,CAAC;CAED,MAAM,SAAS,mBAAmB,EAAE,YAAY,wBAAwB,CAAC;;;;CAKzE,MAAM,SAAS,cAAcA,8BAAW,sBAAsB,CAAC,CAAC;;;;;;;;;;CAWhE,MAAM,SAAS,cAAcA,8BAAW,yBAAyB,CAAC,CAAC;;;;CAKnE,MAAM,SAAS,cAAcA,8BAAW,wBAAwB,CAAC,CAAC;CAElE,MAAM,SAAS,cAAc,WAAyB;EACpD,OAAO,YAAY,kCAAkC;EACrD,OAAO,eAAe,mBAAmB;CAC3C,CAAC;;;;;;;;;;;;;;;;;CAkBD,MAAM,SAAS,mBAAmB,UAAU,CAAC;EAC3C,MAAM;EACN,UAAU;CACZ,CAAC,CAAC;CAEF,QAAQ,OAAO,QAAQ,6BAA6B;CACpD,QAAQ,OAAO,KACb,6EACF;AACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import ConfigureCommand from "@adonisjs/core/commands/configure";
|
|
2
|
+
|
|
3
|
+
//#region configure.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Wires `@fedify/adonisjs` into an application.
|
|
6
|
+
*
|
|
7
|
+
* Run by `node ace configure @fedify/adonisjs` (and therefore by
|
|
8
|
+
* `node ace add @fedify/adonisjs`); see the module documentation for the
|
|
9
|
+
* steps it performs.
|
|
10
|
+
*/
|
|
11
|
+
declare function configure(command: ConfigureCommand): Promise<void>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { configure };
|
|
14
|
+
//# sourceMappingURL=configure.d.cts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import ConfigureCommand from "@adonisjs/core/commands/configure";
|
|
2
|
+
|
|
3
|
+
//#region configure.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Wires `@fedify/adonisjs` into an application.
|
|
6
|
+
*
|
|
7
|
+
* Run by `node ace configure @fedify/adonisjs` (and therefore by
|
|
8
|
+
* `node ace add @fedify/adonisjs`); see the module documentation for the
|
|
9
|
+
* steps it performs.
|
|
10
|
+
*/
|
|
11
|
+
declare function configure(command: ConfigureCommand): Promise<void>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { configure };
|
|
14
|
+
//# sourceMappingURL=configure.d.ts.map
|