@geekity/cms 0.35.0 → 0.37.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/admin/components/blocks.njk +250 -0
- package/admin/components/card.njk +4 -2
- package/admin/components/job-status.njk +15 -10
- package/admin/components/upload.njk +26 -0
- package/admin/pages/comments/all.njk +1 -1
- package/admin/pages/dashboard/home.njk +33 -32
- package/admin/pages/documents/editor.njk +34 -19
- package/admin/pages/federation/followers.njk +3 -2
- package/admin/pages/media/file.njk +5 -4
- package/admin/pages/media/library.njk +7 -3
- package/admin/pages/plugins/screen.njk +5 -35
- package/admin/pages/settings/general.njk +4 -1
- package/admin/pages/tools/export.njk +54 -51
- package/admin/pages/tools/maintenance.njk +2 -1
- package/admin/pages/users/edit.njk +3 -0
- package/admin/src/admin.css +1 -0
- package/admin/static/admin.css +374 -0
- package/admin/static/job-status.js +158 -0
- package/admin/static/upload-drop.js +225 -0
- package/dist/admin/blocks.d.ts +133 -0
- package/dist/admin/blocks.d.ts.map +1 -0
- package/dist/admin/blocks.js +454 -0
- package/dist/admin/blocks.js.map +1 -0
- package/dist/admin/core-widgets.d.ts +3 -0
- package/dist/admin/core-widgets.d.ts.map +1 -0
- package/dist/admin/core-widgets.js +17 -0
- package/dist/admin/core-widgets.js.map +1 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +0 -2
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/engagement.d.ts +16 -0
- package/dist/admin/engagement.d.ts.map +1 -0
- package/dist/admin/engagement.js +38 -0
- package/dist/admin/engagement.js.map +1 -0
- package/dist/admin/federation.d.ts +2 -0
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +2 -1
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/formatting.d.ts +1 -0
- package/dist/admin/formatting.d.ts.map +1 -1
- package/dist/admin/formatting.js +18 -0
- package/dist/admin/formatting.js.map +1 -1
- package/dist/admin/index.d.ts +2 -2
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +2 -2
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/job-status.d.ts +1 -0
- package/dist/admin/job-status.d.ts.map +1 -1
- package/dist/admin/job-status.js +1 -0
- package/dist/admin/job-status.js.map +1 -1
- package/dist/admin/media.d.ts +6 -9
- package/dist/admin/media.d.ts.map +1 -1
- package/dist/admin/media.js +85 -27
- package/dist/admin/media.js.map +1 -1
- package/dist/admin/posts-by-path.d.ts +11 -0
- package/dist/admin/posts-by-path.d.ts.map +1 -0
- package/dist/admin/posts-by-path.js +59 -0
- package/dist/admin/posts-by-path.js.map +1 -0
- package/dist/admin/routes.d.ts +0 -2
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +24 -12
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +2 -0
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/tools.js +1 -1
- package/dist/admin/tools.js.map +1 -1
- package/dist/admin/uploads.d.ts +2 -1
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +5 -2
- package/dist/admin/uploads.js.map +1 -1
- package/dist/admin/widget-fediverse.d.ts +3 -0
- package/dist/admin/widget-fediverse.d.ts.map +1 -0
- package/dist/admin/widget-fediverse.js +49 -0
- package/dist/admin/widget-fediverse.js.map +1 -0
- package/dist/admin/widget-followers.d.ts +3 -0
- package/dist/admin/widget-followers.d.ts.map +1 -0
- package/dist/admin/widget-followers.js +37 -0
- package/dist/admin/widget-followers.js.map +1 -0
- package/dist/admin/widget-health.d.ts +3 -0
- package/dist/admin/widget-health.d.ts.map +1 -0
- package/dist/admin/widget-health.js +103 -0
- package/dist/admin/widget-health.js.map +1 -0
- package/dist/admin/widget-interactions.d.ts +4 -0
- package/dist/admin/widget-interactions.d.ts.map +1 -0
- package/dist/admin/widget-interactions.js +99 -0
- package/dist/admin/widget-interactions.js.map +1 -0
- package/dist/admin/widget-posting.d.ts +3 -0
- package/dist/admin/widget-posting.d.ts.map +1 -0
- package/dist/admin/widget-posting.js +111 -0
- package/dist/admin/widget-posting.js.map +1 -0
- package/dist/admin/widget-scheduled.d.ts +4 -0
- package/dist/admin/widget-scheduled.d.ts.map +1 -0
- package/dist/admin/widget-scheduled.js +30 -0
- package/dist/admin/widget-scheduled.js.map +1 -0
- package/dist/admin/widget-top-posts.d.ts +4 -0
- package/dist/admin/widget-top-posts.d.ts.map +1 -0
- package/dist/admin/widget-top-posts.js +55 -0
- package/dist/admin/widget-top-posts.js.map +1 -0
- package/dist/admin/widgets.d.ts +35 -0
- package/dist/admin/widgets.d.ts.map +1 -0
- package/dist/admin/widgets.js +103 -0
- package/dist/admin/widgets.js.map +1 -0
- package/dist/cms/app.d.ts.map +1 -1
- package/dist/cms/app.js +2 -1
- package/dist/cms/app.js.map +1 -1
- package/dist/cms/boot.d.ts.map +1 -1
- package/dist/cms/boot.js +3 -2
- package/dist/cms/boot.js.map +1 -1
- package/dist/cms/services.d.ts.map +1 -1
- package/dist/cms/services.js +19 -0
- package/dist/cms/services.js.map +1 -1
- package/dist/content/alt-text.d.ts +1 -0
- package/dist/content/alt-text.d.ts.map +1 -1
- package/dist/content/alt-text.js +26 -1
- package/dist/content/alt-text.js.map +1 -1
- package/dist/content/sqlite/catalog.d.ts.map +1 -1
- package/dist/content/sqlite/catalog.js +15 -2
- package/dist/content/sqlite/catalog.js.map +1 -1
- package/dist/content/store.d.ts +10 -0
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js.map +1 -1
- package/dist/content/write.d.ts.map +1 -1
- package/dist/content/write.js +3 -1
- package/dist/content/write.js.map +1 -1
- package/dist/federation/backfill.d.ts +1 -1
- package/dist/federation/backfill.d.ts.map +1 -1
- package/dist/federation/backfill.js +5 -1
- package/dist/federation/backfill.js.map +1 -1
- package/dist/federation/follower-history.d.ts +16 -0
- package/dist/federation/follower-history.d.ts.map +1 -0
- package/dist/federation/follower-history.js +61 -0
- package/dist/federation/follower-history.js.map +1 -0
- package/dist/federation/inbox.d.ts.map +1 -1
- package/dist/federation/inbox.js +2 -1
- package/dist/federation/inbox.js.map +1 -1
- package/dist/federation/records.d.ts +1 -0
- package/dist/federation/records.d.ts.map +1 -1
- package/dist/federation/records.js +24 -6
- package/dist/federation/records.js.map +1 -1
- package/dist/files/data-files.d.ts +1 -0
- package/dist/files/data-files.d.ts.map +1 -1
- package/dist/files/data-files.js +6 -0
- package/dist/files/data-files.js.map +1 -1
- package/dist/jobs/queue.d.ts.map +1 -1
- package/dist/jobs/queue.js +5 -0
- package/dist/jobs/queue.js.map +1 -1
- package/dist/jobs/types.d.ts +7 -0
- package/dist/jobs/types.d.ts.map +1 -1
- package/dist/jobs/types.js.map +1 -1
- package/dist/media/library.d.ts +9 -0
- package/dist/media/library.d.ts.map +1 -1
- package/dist/media/library.js +25 -1
- package/dist/media/library.js.map +1 -1
- package/dist/plugin.d.ts +275 -21
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +9 -8
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/fetch.d.ts +0 -5
- package/dist/plugins/fetch.d.ts.map +1 -1
- package/dist/plugins/fetch.js +31 -7
- package/dist/plugins/fetch.js.map +1 -1
- package/dist/plugins/host-api.d.ts +3 -0
- package/dist/plugins/host-api.d.ts.map +1 -0
- package/dist/plugins/host-api.js +8 -0
- package/dist/plugins/host-api.js.map +1 -0
- package/dist/plugins/install.d.ts.map +1 -1
- package/dist/plugins/install.js +4 -2
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/page-tags.d.ts +8 -0
- package/dist/plugins/page-tags.d.ts.map +1 -0
- package/dist/plugins/page-tags.js +73 -0
- package/dist/plugins/page-tags.js.map +1 -0
- package/dist/plugins/registry.d.ts +4 -1
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +50 -9
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/site.js +1 -1
- package/dist/plugins/site.js.map +1 -1
- package/dist/store/admin-store.d.ts +2 -2
- package/dist/store/admin-store.d.ts.map +1 -1
- package/dist/store/admin-store.js.map +1 -1
- package/dist/store/comments.d.ts +7 -0
- package/dist/store/comments.d.ts.map +1 -1
- package/dist/store/comments.js +21 -0
- package/dist/store/comments.js.map +1 -1
- package/dist/store/deliveries.d.ts +1 -0
- package/dist/store/deliveries.d.ts.map +1 -1
- package/dist/store/deliveries.js +6 -0
- package/dist/store/deliveries.js.map +1 -1
- package/dist/store/inbox.d.ts +16 -0
- package/dist/store/inbox.d.ts.map +1 -1
- package/dist/store/inbox.js +62 -0
- package/dist/store/inbox.js.map +1 -1
- package/dist/store/queue-database.d.ts +6 -0
- package/dist/store/queue-database.d.ts.map +1 -1
- package/dist/store/queue-database.js +16 -1
- package/dist/store/queue-database.js.map +1 -1
- package/dist/store/webmentions.d.ts +1 -0
- package/dist/store/webmentions.d.ts.map +1 -1
- package/dist/store/webmentions.js +6 -0
- package/dist/store/webmentions.js.map +1 -1
- package/dist/web/env.d.ts +3 -0
- package/dist/web/env.d.ts.map +1 -1
- package/dist/web/feed-item.d.ts +4 -3
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +8 -2
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/listing-pages.d.ts.map +1 -1
- package/dist/web/listing-pages.js +7 -2
- package/dist/web/listing-pages.js.map +1 -1
- package/dist/web/page-tags.d.ts +4 -0
- package/dist/web/page-tags.d.ts.map +1 -0
- package/dist/web/page-tags.js +39 -0
- package/dist/web/page-tags.js.map +1 -0
- package/dist/web/render.d.ts +2 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +14 -0
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts +2 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +3 -1
- package/dist/web/routes.js.map +1 -1
- package/package.json +6 -1
- package/themes/default/layouts/base.njk +6 -4
- package/dist/comments/routes.d.ts +0 -65
- package/dist/comments/routes.d.ts.map +0 -1
- package/dist/comments/routes.js +0 -235
- package/dist/comments/routes.js.map +0 -1
- package/dist/content/media.d.ts +0 -85
- package/dist/content/media.d.ts.map +0 -1
- package/dist/content/media.js +0 -237
- package/dist/content/media.js.map +0 -1
- package/dist/content/read-form.d.ts +0 -31
- package/dist/content/read-form.d.ts.map +0 -1
- package/dist/content/read-form.js +0 -157
- package/dist/content/read-form.js.map +0 -1
- package/dist/content/read.d.ts +0 -29
- package/dist/content/read.d.ts.map +0 -1
- package/dist/content/read.js +0 -82
- package/dist/content/read.js.map +0 -1
- package/dist/export/export-archives.d.ts +0 -29
- package/dist/export/export-archives.d.ts.map +0 -1
- package/dist/export/export-archives.js +0 -88
- package/dist/export/export-archives.js.map +0 -1
- package/dist/federation/mount.d.ts +0 -53
- package/dist/federation/mount.d.ts.map +0 -1
- package/dist/federation/mount.js +0 -344
- package/dist/federation/mount.js.map +0 -1
- package/dist/mail/credentials.d.ts +0 -62
- package/dist/mail/credentials.d.ts.map +0 -1
- package/dist/mail/credentials.js +0 -86
- package/dist/mail/credentials.js.map +0 -1
- package/dist/site/setting-rows.d.ts +0 -45
- package/dist/site/setting-rows.d.ts.map +0 -1
- package/dist/site/setting-rows.js +0 -361
- package/dist/site/setting-rows.js.map +0 -1
- package/dist/site/settings-form.d.ts +0 -30
- package/dist/site/settings-form.d.ts.map +0 -1
- package/dist/site/settings-form.js +0 -54
- package/dist/site/settings-form.js.map +0 -1
- package/dist/site/site-json.d.ts +0 -38
- package/dist/site/site-json.d.ts.map +0 -1
- package/dist/site/site-json.js +0 -69
- package/dist/site/site-json.js.map +0 -1
- package/dist/webmention/routes.d.ts +0 -37
- package/dist/webmention/routes.d.ts.map +0 -1
- package/dist/webmention/routes.js +0 -75
- package/dist/webmention/routes.js.map +0 -1
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { readdir, rm, stat } from 'node:fs/promises';
|
|
2
|
-
import { EXPORTS, dataPath } from '../files/data-files.js';
|
|
3
|
-
/**
|
|
4
|
-
* The archives the admin's export job leaves in `data/exports/` for a
|
|
5
|
-
* download (decision-55, section 4). Each holds actor keys, password hashes
|
|
6
|
-
* and personal data, so only the newest is kept and it goes 24 hours after it
|
|
7
|
-
* was written. Its age comes from the time in its name, which the site's
|
|
8
|
-
* clock wrote.
|
|
9
|
-
*/
|
|
10
|
-
export const EXPORT_LIFETIME_MS = 24 * 60 * 60 * 1000;
|
|
11
|
-
const ARCHIVE = /^geekity-.+-(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z\.tar\.gz$/;
|
|
12
|
-
function archiveOf(dataDir, name) {
|
|
13
|
-
const match = ARCHIVE.exec(name);
|
|
14
|
-
if (match === null)
|
|
15
|
-
return undefined;
|
|
16
|
-
const [, year, month, day, hour, minute, second] = match;
|
|
17
|
-
const writtenAt = new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}Z`);
|
|
18
|
-
return {
|
|
19
|
-
name,
|
|
20
|
-
path: dataPath(dataDir, EXPORTS, name),
|
|
21
|
-
writtenAt,
|
|
22
|
-
expiresAt: new Date(writtenAt.getTime() + EXPORT_LIFETIME_MS),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
async function namesIn(dataDir) {
|
|
26
|
-
try {
|
|
27
|
-
return await readdir(dataPath(dataDir, EXPORTS));
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
if (error.code === 'ENOENT')
|
|
31
|
-
return [];
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/** Every archive in the folder, newest first. */
|
|
36
|
-
async function archives(dataDir) {
|
|
37
|
-
return (await namesIn(dataDir))
|
|
38
|
-
.flatMap((name) => archiveOf(dataDir, name) ?? [])
|
|
39
|
-
.sort((a, b) => b.writtenAt.getTime() - a.writtenAt.getTime());
|
|
40
|
-
}
|
|
41
|
-
function expired(archive, now) {
|
|
42
|
-
return archive.expiresAt.getTime() <= now.getTime();
|
|
43
|
-
}
|
|
44
|
-
/** Delete the archives 24 hours old or older, and say how many went. */
|
|
45
|
-
export async function expireExports(dataDir, now) {
|
|
46
|
-
let deleted = 0;
|
|
47
|
-
for (const archive of await archives(dataDir)) {
|
|
48
|
-
if (expired(archive, now)) {
|
|
49
|
-
await rm(archive.path, { force: true });
|
|
50
|
-
deleted += 1;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return deleted;
|
|
54
|
-
}
|
|
55
|
-
/** The archive a download serves: the newest, unless it has expired. Expired ones are deleted. */
|
|
56
|
-
export async function currentExport(dataDir, now) {
|
|
57
|
-
await expireExports(dataDir, now);
|
|
58
|
-
const [newest] = await archives(dataDir);
|
|
59
|
-
if (newest === undefined)
|
|
60
|
-
return undefined;
|
|
61
|
-
try {
|
|
62
|
-
return { ...newest, size: (await stat(newest.path)).size };
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
if (error.code === 'ENOENT')
|
|
66
|
-
return undefined;
|
|
67
|
-
throw error;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Delete what an export a crash cut off left: everything that is not an
|
|
72
|
-
* archive. Only one export job runs at a time, so no other writer's temporary
|
|
73
|
-
* file is here.
|
|
74
|
-
*/
|
|
75
|
-
export async function clearUnfinishedExports(dataDir) {
|
|
76
|
-
for (const name of await namesIn(dataDir)) {
|
|
77
|
-
if (!ARCHIVE.test(name))
|
|
78
|
-
await rm(dataPath(dataDir, EXPORTS, name), { recursive: true, force: true });
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
/** Empty the folder but for the archive just written. */
|
|
82
|
-
export async function keepOnlyExport(dataDir, keep) {
|
|
83
|
-
for (const name of await namesIn(dataDir)) {
|
|
84
|
-
if (name !== keep)
|
|
85
|
-
await rm(dataPath(dataDir, EXPORTS, name), { recursive: true, force: true });
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
//# sourceMappingURL=export-archives.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"export-archives.js","sourceRoot":"","sources":["../../src/export/export-archives.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import type { Context, Hono, MiddlewareHandler } from 'hono';
|
|
2
|
-
import type { GeekityEnv } from '../web/env.ts';
|
|
3
|
-
import type { User } from '../site/users.ts';
|
|
4
|
-
import type { FederationContextData, SiteFederation } from './federation.ts';
|
|
5
|
-
/**
|
|
6
|
-
* Put Fedify in front of the rest of the app.
|
|
7
|
-
*
|
|
8
|
-
* The middleware only answers the paths Fedify registered — the actor, its
|
|
9
|
-
* collections, WebFinger and NodeInfo; everything else falls through to
|
|
10
|
-
* `next()` and reaches the admin and the public site as before. That is why it
|
|
11
|
-
* is mounted first: the public site claims every unmatched path in its
|
|
12
|
-
* not-found handler, so anything registered after it never sees a request.
|
|
13
|
-
*
|
|
14
|
-
* A post's object is not one of Fedify's paths at all. decision-13 makes a
|
|
15
|
-
* post's ActivityStreams id its permalink, so {@link activityStreamsDocument}
|
|
16
|
-
* is what serves the `Article`: one URL, answering a browser with the page and
|
|
17
|
-
* a peer with the object. The same handler answers at the `activitypub.id` a
|
|
18
|
-
* migrated post's file names, and sends a browser from there to the permalink.
|
|
19
|
-
*
|
|
20
|
-
* The dispatchers are handed the stores off the Hono context rather than
|
|
21
|
-
* closing over them, so one federation object could serve more than one CMS
|
|
22
|
-
* and so a dispatcher is never reading a store the request did not come with.
|
|
23
|
-
*/
|
|
24
|
-
export declare function mountFederation(app: Hono<GeekityEnv>, federation: SiteFederation, options?: MountFederationOptions): void;
|
|
25
|
-
/** What {@link mountFederation} takes beyond the site's own federation. */
|
|
26
|
-
export interface MountFederationOptions {
|
|
27
|
-
/** The phase plugins answer federation requests in. */
|
|
28
|
-
plugins?: MiddlewareHandler<GeekityEnv> | undefined;
|
|
29
|
-
}
|
|
30
|
-
/** Where WebFinger lives, which is defined on the host rather than under a site. */
|
|
31
|
-
export declare const WEBFINGER_PATH = "/.well-known/webfinger";
|
|
32
|
-
/** `acct:{username}@{host}`, the handle a person types into a search box. */
|
|
33
|
-
export declare function acctOf(username: string, baseUrl: string): string;
|
|
34
|
-
/**
|
|
35
|
-
* The user a WebFinger `resource` asks about, or `undefined` for one this site
|
|
36
|
-
* answers for nobody.
|
|
37
|
-
*
|
|
38
|
-
* Every spelling of a person resolves, and they are the ones decision-14 lists
|
|
39
|
-
* as their aliases: the `acct:` handle, the author archive, `/@{username}` and
|
|
40
|
-
* — for somebody who was published elsewhere first — the id they were
|
|
41
|
-
* published under. Matching every one of them is what lets a peer that holds
|
|
42
|
-
* any one URL for this person find the others, which is the whole job of
|
|
43
|
-
* WebFinger, and it is how a server holding only `?author=2` discovers that
|
|
44
|
-
* the account it follows is still here.
|
|
45
|
-
*
|
|
46
|
-
* Both sides of the comparison go through {@link canonicalResource} first, so
|
|
47
|
-
* the spellings that differ only in how they were typed are one spelling by
|
|
48
|
-
* the time they are matched, and no spelling needs a branch of its own.
|
|
49
|
-
*/
|
|
50
|
-
export declare function webFingerSubject(c: Context<GeekityEnv>, resource: string): User | undefined;
|
|
51
|
-
/** What the dispatchers are handed, off the Hono context. */
|
|
52
|
-
export declare function contextData(c: Context<GeekityEnv>): FederationContextData;
|
|
53
|
-
//# sourceMappingURL=mount.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/federation/mount.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAK7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAQ7C,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG7E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,EACrB,UAAU,EAAE,cAAc,EAC1B,OAAO,GAAE,sBAA2B,GACnC,IAAI,CAuGN;AAED,2EAA2E;AAC3E,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,OAAO,CAAC,EAAE,iBAAiB,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;CACrD;AA+JD,oFAAoF;AACpF,eAAO,MAAM,cAAc,2BAA2B,CAAC;AAEvD,6EAA6E;AAC7E,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAa3F;AAoCD,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,qBAAqB,CAQzE"}
|
package/dist/federation/mount.js
DELETED
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
import { respondWithObject } from '@fedify/fedify';
|
|
2
|
-
import { federation as federationMiddleware } from '@fedify/hono';
|
|
3
|
-
import { isGone, isFederatedDocument } from '../content/served.js';
|
|
4
|
-
import { isTrashedPath } from '../content/store.js';
|
|
5
|
-
import { listUsers } from '../site/users.js';
|
|
6
|
-
import { absoluteUrl } from '../util/url.js';
|
|
7
|
-
import { authorHref, parseAuthorPath, accountOf } from '../content/authors.js';
|
|
8
|
-
import { goneDocumentAt, publicDocumentAt } from '../content/permalinks.js';
|
|
9
|
-
import { prefersActivityStreams } from '../web/negotiate.js';
|
|
10
|
-
import { notFound, requestPath } from '../web/request.js';
|
|
11
|
-
import { actorAliases, actorId, userActor } from './actor.js';
|
|
12
|
-
import { postObject, postTombstone } from './article.js';
|
|
13
|
-
import { handleHref } from './paths.js';
|
|
14
|
-
/**
|
|
15
|
-
* Put Fedify in front of the rest of the app.
|
|
16
|
-
*
|
|
17
|
-
* The middleware only answers the paths Fedify registered — the actor, its
|
|
18
|
-
* collections, WebFinger and NodeInfo; everything else falls through to
|
|
19
|
-
* `next()` and reaches the admin and the public site as before. That is why it
|
|
20
|
-
* is mounted first: the public site claims every unmatched path in its
|
|
21
|
-
* not-found handler, so anything registered after it never sees a request.
|
|
22
|
-
*
|
|
23
|
-
* A post's object is not one of Fedify's paths at all. decision-13 makes a
|
|
24
|
-
* post's ActivityStreams id its permalink, so {@link activityStreamsDocument}
|
|
25
|
-
* is what serves the `Article`: one URL, answering a browser with the page and
|
|
26
|
-
* a peer with the object. The same handler answers at the `activitypub.id` a
|
|
27
|
-
* migrated post's file names, and sends a browser from there to the permalink.
|
|
28
|
-
*
|
|
29
|
-
* The dispatchers are handed the stores off the Hono context rather than
|
|
30
|
-
* closing over them, so one federation object could serve more than one CMS
|
|
31
|
-
* and so a dispatcher is never reading a store the request did not come with.
|
|
32
|
-
*/
|
|
33
|
-
export function mountFederation(app, federation, options = {}) {
|
|
34
|
-
// WebFinger is ours rather than Fedify's, and so has to be registered before
|
|
35
|
-
// the middleware that would otherwise answer it. Fedify hard-codes the
|
|
36
|
-
// `self` link to the dispatcher path and computes `aliases` from the
|
|
37
|
-
// resource, neither of which can be added to, so an actor served under the
|
|
38
|
-
// id it had elsewhere could never be discovered by it (doc-8). Owning the
|
|
39
|
-
// route is a dozen lines and gives complete control of `subject`, `aliases`
|
|
40
|
-
// and `links`.
|
|
41
|
-
app.get(WEBFINGER_PATH, (c) => {
|
|
42
|
-
const resource = c.req.query('resource') ?? '';
|
|
43
|
-
const user = webFingerSubject(c, resource);
|
|
44
|
-
if (user === undefined)
|
|
45
|
-
return c.notFound();
|
|
46
|
-
const context = federation.createContext(c.req.raw, contextData(c));
|
|
47
|
-
const { baseUrl } = c.var.config;
|
|
48
|
-
const aliases = actorAliases(context, user, baseUrl);
|
|
49
|
-
return c.json({
|
|
50
|
-
subject: acctOf(user.username, c.var.config.baseUrl),
|
|
51
|
-
aliases: aliases.map((alias) => alias.href),
|
|
52
|
-
links: [
|
|
53
|
-
{
|
|
54
|
-
rel: 'self',
|
|
55
|
-
type: 'application/activity+json',
|
|
56
|
-
href: actorId(context, user).href,
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
rel: 'http://webfinger.net/rel/profile-page',
|
|
60
|
-
type: 'text/html',
|
|
61
|
-
href: absoluteUrl(authorHref(user.username), baseUrl),
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
}, 200, {
|
|
65
|
-
// The media type RFC 7033 defines, and the header that lets a browser
|
|
66
|
-
// application read the answer, which is what every other WebFinger
|
|
67
|
-
// server sends.
|
|
68
|
-
'content-type': 'application/jrd+json; charset=utf-8',
|
|
69
|
-
'access-control-allow-origin': '*',
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
// `/@ada`, the short URL WordPress publishes beside the author archive and
|
|
73
|
-
// the one a person is most likely to type. It is an alias rather than a
|
|
74
|
-
// second identity, so it goes where the identity is.
|
|
75
|
-
app.get('/:handle{@.+}', async (c, next) => {
|
|
76
|
-
// The pattern is a regex rather than `/@:username`, because Hono's path
|
|
77
|
-
// parameters are whole segments: the `@` has to be matched inside one.
|
|
78
|
-
const handle = (c.req.param('handle') ?? '').slice(1);
|
|
79
|
-
// An alias is only an alias of somebody. The route used to send every
|
|
80
|
-
// handle to `/author/<whatever was typed>/`, so a profile link with a
|
|
81
|
-
// menu item's flag on the end of it — `https://shll.me/@a | me` — landed a
|
|
82
|
-
// reader on `/author/a%20%7C%20me/` instead of saying there is no such
|
|
83
|
-
// person (TASK-112). Spelled exactly, the way WebFinger matches: `Ada` and
|
|
84
|
-
// `ada` are two accounts on a screen that can tell them apart, and only
|
|
85
|
-
// one of them exists.
|
|
86
|
-
const user = listUsers(c.var.config.dataDir).find((account) => account.username === handle);
|
|
87
|
-
// The site's own not-found handler answers rather than a bare 404 here, so
|
|
88
|
-
// a handle nobody has gets the theme's 404 page like any other URL that is
|
|
89
|
-
// not there.
|
|
90
|
-
if (user === undefined)
|
|
91
|
-
return await next();
|
|
92
|
-
return c.redirect(authorHref(user.username), 301);
|
|
93
|
-
});
|
|
94
|
-
// `@fedify/hono` types its context as the two properties it actually reads,
|
|
95
|
-
// which is looser than Hono's own; the cast is what puts `c.var` back.
|
|
96
|
-
const fedify = federationMiddleware(federation, (context) => {
|
|
97
|
-
const c = context;
|
|
98
|
-
return contextData(c);
|
|
99
|
-
});
|
|
100
|
-
// The one path where Fedify and the public site both have a claim: a user's
|
|
101
|
-
// author archive is their actor id (decision-14), and Fedify answers a bare
|
|
102
|
-
// `Accept: application/json` as an ActivityStreams request while doc-3 gives
|
|
103
|
-
// that spelling the listing's own JSON. The CMS's rule decides, so a peer
|
|
104
|
-
// asking for `activity+json` or `ld+json` gets the actor and everything else
|
|
105
|
-
// — a browser, a reader, a feed tool — reaches the archive it asked for.
|
|
106
|
-
// Every other Fedify path is left exactly as it was.
|
|
107
|
-
const federationGate = async (c, next) => {
|
|
108
|
-
const isArchive = parseAuthorPath(requestPath(c)) !== undefined;
|
|
109
|
-
if (isArchive && !prefersActivityStreams(c.req.header('accept')))
|
|
110
|
-
return await next();
|
|
111
|
-
return await fedify(c, next);
|
|
112
|
-
};
|
|
113
|
-
app.use('*', federationGate);
|
|
114
|
-
if (options.plugins !== undefined)
|
|
115
|
-
app.use('*', options.plugins);
|
|
116
|
-
// Named, and typed as a middleware, so the Hono context arrives with its
|
|
117
|
-
// path parameters resolved rather than as `any`.
|
|
118
|
-
const activityStreams = async (c, next) => {
|
|
119
|
-
const response = (await activityStreamsActor(c, federation)) ?? (await activityStreamsDocument(c, federation));
|
|
120
|
-
if (response !== undefined)
|
|
121
|
-
return response;
|
|
122
|
-
await next();
|
|
123
|
-
};
|
|
124
|
-
app.use('*', activityStreams);
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* The person this request is about, when it asks at the id they were published
|
|
128
|
-
* under somewhere else: the `Person` for a peer, a redirect to the author
|
|
129
|
-
* archive for a browser, and `undefined` for everything else.
|
|
130
|
-
*
|
|
131
|
-
* The twin of {@link activityStreamsDocument}, and for the same reason
|
|
132
|
-
* (decision-14): a stored actor id is identity. A follower's server keys the
|
|
133
|
-
* account by the URL it first saw, so that URL has to keep answering with this
|
|
134
|
-
* person's actor for as long as the account exists, or every follow out there
|
|
135
|
-
* points at nothing.
|
|
136
|
-
*
|
|
137
|
-
* Fedify cannot serve it — its router matches paths, and a stored id is
|
|
138
|
-
* commonly a query string on the site root (doc-8) — so it is served here,
|
|
139
|
-
* ahead of the public site, exactly as a post's stored `activitypub.id` is.
|
|
140
|
-
*/
|
|
141
|
-
async function activityStreamsActor(c, federation) {
|
|
142
|
-
const user = storedActorAt(c);
|
|
143
|
-
if (user === undefined)
|
|
144
|
-
return undefined;
|
|
145
|
-
if (!prefersActivityStreams(c.req.header('accept'))) {
|
|
146
|
-
return c.redirect(authorHref(user.username), 301);
|
|
147
|
-
}
|
|
148
|
-
const context = federation.createContext(c.req.raw, contextData(c));
|
|
149
|
-
const actor = await userActor(context, user, { baseUrl: c.var.config.baseUrl });
|
|
150
|
-
return await respondWithObject(actor, { contextLoader: context.contextLoader });
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* The user whose stored actor id is the URL this request asks for, or
|
|
154
|
-
* `undefined`.
|
|
155
|
-
*
|
|
156
|
-
* Built the way {@link storedObjectAt} builds a post's candidate — the
|
|
157
|
-
* request's path and query on the site's base URL, rather than `request.url`,
|
|
158
|
-
* which behind a proxy is the internal address — and matched on the whole URL,
|
|
159
|
-
* query string and all, which is what decision-14 asks for.
|
|
160
|
-
*
|
|
161
|
-
* A user whose stored id happens to be their author URL is not one of these:
|
|
162
|
-
* the actor dispatcher has already answered for that URL, and answering again
|
|
163
|
-
* here would only redirect a browser to where it already is.
|
|
164
|
-
*/
|
|
165
|
-
function storedActorAt(c) {
|
|
166
|
-
const { search } = new URL(c.req.url);
|
|
167
|
-
const candidate = `${absoluteUrl(requestPath(c), c.var.config.baseUrl)}${search}`;
|
|
168
|
-
const user = listUsers(c.var.config.dataDir).find((entry) => entry.actorId === candidate);
|
|
169
|
-
if (user === undefined)
|
|
170
|
-
return undefined;
|
|
171
|
-
if (absoluteUrl(authorHref(user.username), c.var.config.baseUrl) === candidate)
|
|
172
|
-
return undefined;
|
|
173
|
-
return user;
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* The post this request is about, when it is about one: the `Article` for a
|
|
177
|
-
* peer, a redirect to the permalink for a browser at a stored id, and
|
|
178
|
-
* `undefined` for everything else.
|
|
179
|
-
*
|
|
180
|
-
* Two URLs can name a post. Its permalink always does — that is the whole of
|
|
181
|
-
* decision-13, and a peer that dereferences a link somebody shared lands on
|
|
182
|
-
* the object rather than on a page it cannot read. The other is the
|
|
183
|
-
* `activitypub.id` a migrated post's file carries: the name its followers,
|
|
184
|
-
* its replies and, unless it sets a `guid`, its RSS subscribers already hold,
|
|
185
|
-
* which has to keep answering or every copy out there points at nothing. A
|
|
186
|
-
* browser that follows one of those old links is sent on to the permalink,
|
|
187
|
-
* because that is the URL a person should end up at.
|
|
188
|
-
*
|
|
189
|
-
* Anything else — a browser at a permalink, a `.md` or `.json` request, a
|
|
190
|
-
* page, a listing — gets `undefined` and falls through to the public site
|
|
191
|
-
* untouched.
|
|
192
|
-
*/
|
|
193
|
-
async function activityStreamsDocument(c, federation) {
|
|
194
|
-
const wantsObject = prefersActivityStreams(c.req.header('accept'));
|
|
195
|
-
if (wantsObject) {
|
|
196
|
-
const atPermalink = publicDocumentAt(c.var.store, requestPath(c));
|
|
197
|
-
if (atPermalink !== undefined && isFederatedDocument(atPermalink, c.var.store.now())) {
|
|
198
|
-
return await article(c, federation, atPermalink);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const stored = storedObjectAt(c);
|
|
202
|
-
if (wantsObject) {
|
|
203
|
-
const trashed = stored ?? goneDocumentAt(c.var.store, requestPath(c));
|
|
204
|
-
if (trashed?.type === 'post' && isTrashedPath(trashed.path)) {
|
|
205
|
-
return isGone(trashed, c.var.store.now())
|
|
206
|
-
? await tombstone(c, federation, trashed)
|
|
207
|
-
: undefined;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (stored === undefined)
|
|
211
|
-
return undefined;
|
|
212
|
-
const now = c.var.store.now();
|
|
213
|
-
if (!isFederatedDocument(stored, now) && !isGone(stored, now)) {
|
|
214
|
-
return wantsObject ? notFound(c) : undefined;
|
|
215
|
-
}
|
|
216
|
-
if (wantsObject)
|
|
217
|
-
return await article(c, federation, stored);
|
|
218
|
-
// A renamed post's old URL is its stored id (decision-20). Once a new
|
|
219
|
-
// document takes that URL over, a browser there is reading the new one; the
|
|
220
|
-
// id keeps answering peers, who hold it as a name rather than a page.
|
|
221
|
-
if (publicDocumentAt(c.var.store, requestPath(c)) !== undefined)
|
|
222
|
-
return undefined;
|
|
223
|
-
return c.redirect(stored.permalink, 301);
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* The post whose `activitypub.id` is the URL this request asks for, or
|
|
227
|
-
* `undefined`.
|
|
228
|
-
*
|
|
229
|
-
* The candidate is built the way the ids themselves are — the request's path
|
|
230
|
-
* and query on the site's base URL — rather than taken from `request.url`,
|
|
231
|
-
* which behind a proxy is the internal address. A post whose stored id is its
|
|
232
|
-
* permalink is not one of these: the permalink lookup has already answered for
|
|
233
|
-
* it, and answering again here would only invite a redirect to itself.
|
|
234
|
-
*/
|
|
235
|
-
function storedObjectAt(c) {
|
|
236
|
-
const { search } = new URL(c.req.url);
|
|
237
|
-
const candidate = `${absoluteUrl(requestPath(c), c.var.config.baseUrl)}${search}`;
|
|
238
|
-
const document = c.var.store.getByStoredObjectId(candidate);
|
|
239
|
-
if (document === undefined || document.type !== 'post')
|
|
240
|
-
return undefined;
|
|
241
|
-
if (absoluteUrl(document.permalink, c.var.config.baseUrl) === candidate)
|
|
242
|
-
return undefined;
|
|
243
|
-
return document;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* One post as the ActivityStreams response a peer asked for.
|
|
247
|
-
*
|
|
248
|
-
* The object is built through the same {@link postObject} the outbox uses,
|
|
249
|
-
* off a context Fedify makes for this request, so the object a peer fetches
|
|
250
|
-
* and the one it is delivered cannot drift apart.
|
|
251
|
-
*/
|
|
252
|
-
async function article(c, federation, document) {
|
|
253
|
-
const context = federation.createContext(c.req.raw, contextData(c));
|
|
254
|
-
if (listUsers(c.var.config.dataDir).length === 0)
|
|
255
|
-
return notFound(c);
|
|
256
|
-
return await respondWithObject(postObject(context, document), {
|
|
257
|
-
contextLoader: context.contextLoader,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
async function tombstone(c, federation, document) {
|
|
261
|
-
const context = federation.createContext(c.req.raw, contextData(c));
|
|
262
|
-
const response = await respondWithObject(postTombstone(context, document), {
|
|
263
|
-
contextLoader: context.contextLoader,
|
|
264
|
-
});
|
|
265
|
-
return new Response(response.body, { status: 410, headers: response.headers });
|
|
266
|
-
}
|
|
267
|
-
/** Where WebFinger lives, which is defined on the host rather than under a site. */
|
|
268
|
-
export const WEBFINGER_PATH = '/.well-known/webfinger';
|
|
269
|
-
/** `acct:{username}@{host}`, the handle a person types into a search box. */
|
|
270
|
-
export function acctOf(username, baseUrl) {
|
|
271
|
-
return `acct:${accountOf(username, baseUrl)}`;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* The user a WebFinger `resource` asks about, or `undefined` for one this site
|
|
275
|
-
* answers for nobody.
|
|
276
|
-
*
|
|
277
|
-
* Every spelling of a person resolves, and they are the ones decision-14 lists
|
|
278
|
-
* as their aliases: the `acct:` handle, the author archive, `/@{username}` and
|
|
279
|
-
* — for somebody who was published elsewhere first — the id they were
|
|
280
|
-
* published under. Matching every one of them is what lets a peer that holds
|
|
281
|
-
* any one URL for this person find the others, which is the whole job of
|
|
282
|
-
* WebFinger, and it is how a server holding only `?author=2` discovers that
|
|
283
|
-
* the account it follows is still here.
|
|
284
|
-
*
|
|
285
|
-
* Both sides of the comparison go through {@link canonicalResource} first, so
|
|
286
|
-
* the spellings that differ only in how they were typed are one spelling by
|
|
287
|
-
* the time they are matched, and no spelling needs a branch of its own.
|
|
288
|
-
*/
|
|
289
|
-
export function webFingerSubject(c, resource) {
|
|
290
|
-
const wanted = canonicalResource(resource);
|
|
291
|
-
if (wanted === '')
|
|
292
|
-
return undefined;
|
|
293
|
-
const { baseUrl } = c.var.config;
|
|
294
|
-
return listUsers(c.var.config.dataDir).find((user) => [
|
|
295
|
-
acctOf(user.username, baseUrl),
|
|
296
|
-
absoluteUrl(authorHref(user.username), baseUrl),
|
|
297
|
-
absoluteUrl(handleHref(user.username), baseUrl),
|
|
298
|
-
...(user.actorId === undefined ? [] : [user.actorId]),
|
|
299
|
-
].some((spelling) => canonicalResource(spelling) === wanted));
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* One resource in the spelling every equivalent one reduces to.
|
|
303
|
-
*
|
|
304
|
-
* A host is case-insensitive — in DNS, in RFC 3986 and in RFC 7033 — so
|
|
305
|
-
* `acct:ada@EXAMPLE.COM` names the same person as `acct:ada@example.com` and
|
|
306
|
-
* has to find them. A username is not: Geekity compares one case sensitively
|
|
307
|
-
* (see {@link User.username}), so the case is left exactly as it was asked
|
|
308
|
-
* for and `acct:Ada@example.com` stays somebody this site does not have.
|
|
309
|
-
*
|
|
310
|
-
* A bare `user@host` is not what RFC 7033 asks for, but it is what enough
|
|
311
|
-
* clients send that refusing it would only look like a missing account, and
|
|
312
|
-
* the same goes for the leading `@` of `@ada@example.com`, which is how the
|
|
313
|
-
* handle is written everywhere a person reads it. Both are spelled back out
|
|
314
|
-
* as the `acct:` URI they meant.
|
|
315
|
-
*/
|
|
316
|
-
function canonicalResource(resource) {
|
|
317
|
-
const trimmed = resource.trim();
|
|
318
|
-
// A URL carries its own rules, and `URL` applies them: the scheme and the
|
|
319
|
-
// host come back lower-cased, the path untouched.
|
|
320
|
-
if (/^[a-z][a-z\d+.-]*:\/\//i.test(trimmed)) {
|
|
321
|
-
try {
|
|
322
|
-
return new URL(trimmed).href;
|
|
323
|
-
}
|
|
324
|
-
catch {
|
|
325
|
-
return trimmed;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
const handle = trimmed.replace(/^acct:/i, '').replace(/^@/, '');
|
|
329
|
-
const at = handle.lastIndexOf('@');
|
|
330
|
-
if (at <= 0)
|
|
331
|
-
return handle;
|
|
332
|
-
return `acct:${handle.slice(0, at)}@${handle.slice(at + 1).toLowerCase()}`;
|
|
333
|
-
}
|
|
334
|
-
/** What the dispatchers are handed, off the Hono context. */
|
|
335
|
-
export function contextData(c) {
|
|
336
|
-
return {
|
|
337
|
-
admin: c.var.admin,
|
|
338
|
-
store: c.var.store,
|
|
339
|
-
config: c.var.config,
|
|
340
|
-
actorProfiles: c.var.actorProfiles,
|
|
341
|
-
cited: (url) => c.var.replyContexts.read(url),
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
//# sourceMappingURL=mount.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mount.js","sourceRoot":"","sources":["../../src/federation/mount.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a site needs to prove it may send: `data/mail.json`.
|
|
3
|
-
*
|
|
4
|
-
* A credential, not a setting, so it lives where the Akismet key and the
|
|
5
|
-
* password hashes live — under `data/` at mode `0600` — and never in
|
|
6
|
-
* `content/_data/site.json`, which is public, in git and published with the
|
|
7
|
-
* site. Which provider is in use, who mail is from and where a reply goes are
|
|
8
|
-
* settings and are in `site.json`; the key and the SMTP password are here.
|
|
9
|
-
*
|
|
10
|
-
* Read on every send, like the Akismet key, so a credential pasted into the
|
|
11
|
-
* settings screen sends the next message and one removed stops sending at
|
|
12
|
-
* once, neither of them needing a restart.
|
|
13
|
-
*/
|
|
14
|
-
/** Where the credentials live, under `dataDir`. */
|
|
15
|
-
export declare const MAIL_CREDENTIALS_FILE = "mail.json";
|
|
16
|
-
/** Brevo's half: one API key. */
|
|
17
|
-
export interface BrevoCredential {
|
|
18
|
-
/** The account's API key, `xkeysib-…`. */
|
|
19
|
-
readonly apiKey: string;
|
|
20
|
-
}
|
|
21
|
-
/** SMTP's half: the whole connection, because all of it is a credential. */
|
|
22
|
-
export interface SmtpCredential {
|
|
23
|
-
/** The server's hostname. */
|
|
24
|
-
readonly host: string;
|
|
25
|
-
/** The port: 587 for submission with STARTTLS, 465 for implicit TLS. */
|
|
26
|
-
readonly port: number;
|
|
27
|
-
/** Whether the connection is TLS from the first byte, which is port 465. */
|
|
28
|
-
readonly secure: boolean;
|
|
29
|
-
/** The username. Empty for a server that wants no credentials. */
|
|
30
|
-
readonly user: string;
|
|
31
|
-
/** The password. */
|
|
32
|
-
readonly password: string;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* The file's whole contents: at most one entry per provider.
|
|
36
|
-
*
|
|
37
|
-
* Both may be present at once, and that is deliberate — a site trying SMTP
|
|
38
|
-
* after Brevo should be able to switch the `mailProvider` setting back without
|
|
39
|
-
* having to paste a key in again.
|
|
40
|
-
*/
|
|
41
|
-
export interface MailCredentials {
|
|
42
|
-
/** Brevo's key, when the site has one. */
|
|
43
|
-
readonly brevo?: BrevoCredential | undefined;
|
|
44
|
-
/** The SMTP connection, when the site has one. */
|
|
45
|
-
readonly smtp?: SmtpCredential | undefined;
|
|
46
|
-
}
|
|
47
|
-
/** Where one site's credential file is. */
|
|
48
|
-
export declare function mailCredentialsPath(dataDir: string): string;
|
|
49
|
-
/**
|
|
50
|
-
* The stored credentials, or an empty object when the site has none.
|
|
51
|
-
*
|
|
52
|
-
* Read tolerantly and synchronously, like every other file this CMS treats as
|
|
53
|
-
* truth: a file that will not parse, or an entry missing the one field that
|
|
54
|
-
* makes it usable, is a site with no mail rather than a site that will not
|
|
55
|
-
* boot.
|
|
56
|
-
*/
|
|
57
|
-
export declare function readMailCredentials(dataDir: string): MailCredentials;
|
|
58
|
-
/** Write the credentials, private to the account the site runs as. */
|
|
59
|
-
export declare function writeMailCredentials(dataDir: string, credentials: MailCredentials): Promise<void>;
|
|
60
|
-
/** Forget them, which is how a site stops sending mail entirely. */
|
|
61
|
-
export declare function removeMailCredentials(dataDir: string): Promise<void>;
|
|
62
|
-
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/mail/credentials.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AAEH,mDAAmD;AACnD,eAAO,MAAM,qBAAqB,cAAc,CAAC;AAEjD,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IAC7C,kDAAkD;IAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CAC5C;AAED,2CAA2C;AAC3C,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAkBpE;AAED,sEAAsE;AACtE,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,eAAe,GAC3B,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,oEAAoE;AACpE,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1E"}
|