@kernhq/module-quire 0.11.1 → 0.12.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/dist/contract/models.d.ts +46 -0
- package/dist/contract/models.d.ts.map +1 -1
- package/dist/contract/models.js +73 -0
- package/dist/contract/models.js.map +1 -1
- package/dist/contract/permissions.d.ts +17 -1
- package/dist/contract/permissions.d.ts.map +1 -1
- package/dist/contract/permissions.js +34 -0
- package/dist/contract/permissions.js.map +1 -1
- package/dist/contract/router.d.ts +670 -0
- package/dist/contract/router.d.ts.map +1 -1
- package/dist/contract/router.js +273 -2
- package/dist/contract/router.js.map +1 -1
- package/dist/server/_impl.d.ts +770 -0
- package/dist/server/_impl.d.ts.map +1 -1
- package/dist/server/_impl.js +264 -2
- package/dist/server/_impl.js.map +1 -1
- package/dist/server/schema.d.ts +318 -1
- package/dist/server/schema.d.ts.map +1 -1
- package/dist/server/schema.js +86 -0
- package/dist/server/schema.js.map +1 -1
- package/dist/server/services/access.d.ts +1 -0
- package/dist/server/services/access.d.ts.map +1 -1
- package/dist/server/services/index.d.ts +3 -0
- package/dist/server/services/index.d.ts.map +1 -1
- package/dist/server/services/index.js +5 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/pages.d.ts.map +1 -1
- package/dist/server/services/pages.js +6 -0
- package/dist/server/services/pages.js.map +1 -1
- package/dist/server/services/publications.d.ts +177 -0
- package/dist/server/services/publications.d.ts.map +1 -0
- package/dist/server/services/publications.js +553 -0
- package/dist/server/services/publications.js.map +1 -0
- package/dist/server/services/versions.d.ts +4 -0
- package/dist/server/services/versions.d.ts.map +1 -1
- package/migrations/0008_publications.sql +140 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/src/client/components/PublishDialog.svelte +857 -0
- package/src/client/i18n.ts +434 -0
- package/src/client/index.ts +21 -0
- package/src/client/mock.ts +426 -2
- package/src/client/pages/PageView.svelte +139 -0
- package/src/client/public-url.ts +64 -0
- package/src/client/query.ts +16 -0
- package/src/contract/models.ts +77 -0
- package/src/contract/permissions.ts +53 -1
- package/src/contract/router.ts +302 -1
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publishing a page, and everything under it, to a URL a signed-out stranger can open.
|
|
3
|
+
*
|
|
4
|
+
* This file holds both halves: the authenticated CRUD an author uses, and the read path an
|
|
5
|
+
* anonymous request takes. They are together because the second one is only safe if it agrees with
|
|
6
|
+
* the first about what "public" means, and the definition lives here once:
|
|
7
|
+
*
|
|
8
|
+
* **A page is public iff it is the publication's root or a descendant of it reached without
|
|
9
|
+
* passing through a page that is opted out, archived, trashed, unpublished or not a `page`; and
|
|
10
|
+
* it has a published version that has been rendered to HTML.**
|
|
11
|
+
*
|
|
12
|
+
* Note that the walk *prunes* rather than filters. A page whose parent is private is private, even
|
|
13
|
+
* though it is inside the subtree — otherwise excluding a section would leave every page under it
|
|
14
|
+
* reachable by anyone who guessed its address, and the nav would simply not mention them. The cost
|
|
15
|
+
* is that forgetting to publish a middle page hides its children, which is the safe direction to be
|
|
16
|
+
* wrong in and is worth saying in the interface.
|
|
17
|
+
*
|
|
18
|
+
* Three things about the anonymous path that the type system cannot hold:
|
|
19
|
+
*
|
|
20
|
+
* - it runs in a **read-only transaction** (`read`, below). Once the workspace is set, row-level
|
|
21
|
+
* security has stopped being a fence around an anonymous request — the whole workspace is inside
|
|
22
|
+
* it, which is right for reading a publication and wrong for everything else. Postgres refuses
|
|
23
|
+
* the write with 25006 instead of a code review catching it;
|
|
24
|
+
* - **every query carries the publication in its own `WHERE`**. Workspace scope is not publication
|
|
25
|
+
* scope, and RLS will happily return a page in another space that nobody published;
|
|
26
|
+
* - **nothing it returns carries an id.** Pages are addressed by path, the cache validator is a
|
|
27
|
+
* hash rather than the version id, and the rendered HTML is scrubbed of `id` and `data-id`
|
|
28
|
+
* before it leaves. An id in a public response is a string somebody can try somewhere else.
|
|
29
|
+
*/
|
|
30
|
+
import { createHash, randomBytes, scrypt as scryptCb, timingSafeEqual } from 'node:crypto';
|
|
31
|
+
import { promisify } from 'node:util';
|
|
32
|
+
import { KernError } from '@kernhq/kernel';
|
|
33
|
+
import { and, desc, eq, inArray, sql } from 'drizzle-orm';
|
|
34
|
+
import { escapeHtml } from '../render.js';
|
|
35
|
+
import { pages, pageVersions, publications } from '../schema.js';
|
|
36
|
+
const scrypt = promisify(scryptCb);
|
|
37
|
+
/** How deep a published site may nest before the walk stops descending. */
|
|
38
|
+
const MAX_DEPTH = 32;
|
|
39
|
+
/** How many pages one `create`/`update` will render HTML for before giving up and logging. */
|
|
40
|
+
const MAX_BACKFILL = 200;
|
|
41
|
+
/** How long an unlock token is good for. Short, because there is nothing to revoke it with. */
|
|
42
|
+
const TOKEN_TTL_MS = 12 * 60 * 60_000;
|
|
43
|
+
/** How much of a page's prose a search hit shows around the match. */
|
|
44
|
+
const SNIPPET = 180;
|
|
45
|
+
/**
|
|
46
|
+
* A publication as a client sees it — with `hasPassword` in place of the hash.
|
|
47
|
+
*
|
|
48
|
+
* The hash never leaves this file. It is a hash, a salt and a cost, so shipping it to a browser
|
|
49
|
+
* turns an online guess, which the server can rate-limit, into an offline one, which it cannot.
|
|
50
|
+
* Row-level security is row-level: the column is inside every row the workspace can read, including
|
|
51
|
+
* on the public path once the handler has set the workspace, so "do not select it" is not a
|
|
52
|
+
* protection — mapping through this function is.
|
|
53
|
+
*/
|
|
54
|
+
export function toPublication(row) {
|
|
55
|
+
return {
|
|
56
|
+
id: row.id,
|
|
57
|
+
workspaceId: row.workspaceId,
|
|
58
|
+
rootPageId: row.rootPageId,
|
|
59
|
+
includeDescendants: row.includeDescendants,
|
|
60
|
+
slug: row.slug,
|
|
61
|
+
hasPassword: row.passwordHash !== null,
|
|
62
|
+
expiresAt: row.expiresAt?.toISOString() ?? null,
|
|
63
|
+
seoTitle: row.seoTitle,
|
|
64
|
+
seoDescription: row.seoDescription,
|
|
65
|
+
ogImageUrl: row.ogImageUrl,
|
|
66
|
+
indexable: row.indexable,
|
|
67
|
+
theme: row.theme,
|
|
68
|
+
createdBy: row.createdBy,
|
|
69
|
+
createdAt: row.createdAt.toISOString(),
|
|
70
|
+
updatedAt: row.updatedAt.toISOString(),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A title reduced to a URL segment, keeping Unicode letters and digits.
|
|
75
|
+
*
|
|
76
|
+
* `[^\p{L}\p{N}]` rather than `[^a-z0-9]`: a Persian or Arabic title would otherwise slugify to
|
|
77
|
+
* nothing at all, and a handbook in Persian would be a tree of `untitled`, `untitled-2`,
|
|
78
|
+
* `untitled-3`. Percent-encoding makes the result URL-safe; readability in the address bar is the
|
|
79
|
+
* browser's job, and every browser shows it decoded.
|
|
80
|
+
*/
|
|
81
|
+
export function slugifyTitle(title) {
|
|
82
|
+
const cleaned = title
|
|
83
|
+
.normalize('NFC')
|
|
84
|
+
.toLowerCase()
|
|
85
|
+
.replace(/[^\p{L}\p{N}]+/gu, '-')
|
|
86
|
+
.replace(/^-+|-+$/g, '')
|
|
87
|
+
.slice(0, 60)
|
|
88
|
+
.replace(/-+$/g, '');
|
|
89
|
+
return cleaned || 'untitled';
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Give every page in the walk its path, and nothing else its path.
|
|
93
|
+
*
|
|
94
|
+
* Siblings that slugify the same get `-2`, `-3` in `position` order, which is deterministic from the
|
|
95
|
+
* tree: two people looking at the same site get the same URLs, and nothing has to be stored. The
|
|
96
|
+
* rows arrive ordered by depth and then position, so a parent's path is always known before its
|
|
97
|
+
* children are reached.
|
|
98
|
+
*/
|
|
99
|
+
export function withPaths(rows) {
|
|
100
|
+
const pathOf = new Map();
|
|
101
|
+
const takenUnder = new Map();
|
|
102
|
+
const out = [];
|
|
103
|
+
for (const row of rows) {
|
|
104
|
+
const parentPath = row.parent_id === null ? null : (pathOf.get(row.parent_id) ?? null);
|
|
105
|
+
// A child whose parent did not survive the walk cannot be addressed, so it is not public
|
|
106
|
+
// either. Unreachable while the walk prunes, and it stays correct if it ever stops.
|
|
107
|
+
if (row.parent_id !== null && parentPath === null)
|
|
108
|
+
continue;
|
|
109
|
+
if (row.depth === 0) {
|
|
110
|
+
pathOf.set(row.id, '');
|
|
111
|
+
out.push({ ...row, path: '', parentPath: null });
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const taken = takenUnder.get(row.parent_id) ?? new Set();
|
|
115
|
+
takenUnder.set(row.parent_id, taken);
|
|
116
|
+
const base = slugifyTitle(row.title);
|
|
117
|
+
let slug = base;
|
|
118
|
+
for (let n = 2; taken.has(slug); n++)
|
|
119
|
+
slug = `${base}-${n}`;
|
|
120
|
+
taken.add(slug);
|
|
121
|
+
const path = parentPath === '' ? slug : `${parentPath}/${slug}`;
|
|
122
|
+
pathOf.set(row.id, path);
|
|
123
|
+
out.push({ ...row, path, parentPath });
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
/** Compare two public paths the way a URL bar does: trimmed of slashes, case-folded, NFC. */
|
|
128
|
+
const normalisePath = (path) => path
|
|
129
|
+
.normalize('NFC')
|
|
130
|
+
.replace(/^\/+|\/+$/g, '')
|
|
131
|
+
.toLowerCase();
|
|
132
|
+
/**
|
|
133
|
+
* The public rendering of a stored version.
|
|
134
|
+
*
|
|
135
|
+
* Two passes, in this order because the first needs what the second removes:
|
|
136
|
+
*
|
|
137
|
+
* 1. **Re-point page mentions.** `versions.html` writes `/quire/<space-key>/<page-id>`, which is
|
|
138
|
+
* an address inside the application: a stranger following it gets a sign-in screen, and the id
|
|
139
|
+
* in it belongs to a page that may not be public at all. A mention of a page in this
|
|
140
|
+
* publication becomes a link to its public path; anything else loses its `href` and stays as
|
|
141
|
+
* readable text.
|
|
142
|
+
* 2. **Strip every identifier.** `id` is the block anchor the editor wrote and `data-id` is the
|
|
143
|
+
* mentioned page's or person's id — a user id on a public page is a person's identifier handed
|
|
144
|
+
* to the internet for no reader's benefit.
|
|
145
|
+
*
|
|
146
|
+
* A regular expression over HTML is usually a mistake and is safe here for one specific reason: this
|
|
147
|
+
* HTML was produced by `render.ts`, which escapes every attribute value, so a `"` never appears
|
|
148
|
+
* inside one and `[^"]*` cannot run past the attribute it is in. Prose that happens to contain the
|
|
149
|
+
* text `id="x"` arrives as `id="x"` and is left alone. `publications.int.test.ts` holds
|
|
150
|
+
* that with a code block written to look like markup.
|
|
151
|
+
*/
|
|
152
|
+
export function publicHtml(html, publicPathOf, basePath) {
|
|
153
|
+
const linked = html.replace(/href="\/quire\/[^"/]*\/([0-9a-fA-F-]{36})"/g, (_match, pageId) => {
|
|
154
|
+
const path = publicPathOf(pageId);
|
|
155
|
+
return path === null ? '' : `href="${escapeHtml(basePath + encodeURI(path))}"`;
|
|
156
|
+
});
|
|
157
|
+
return linked.replace(/ (?:data-)?id="[^"]*"/g, '');
|
|
158
|
+
}
|
|
159
|
+
/** A plain-text window around the first match, for a search result. */
|
|
160
|
+
export function snippetAround(text, query) {
|
|
161
|
+
const flat = text.replace(/\s+/g, ' ').trim();
|
|
162
|
+
const at = flat.toLowerCase().indexOf(query.toLowerCase());
|
|
163
|
+
if (at < 0)
|
|
164
|
+
return flat.slice(0, SNIPPET);
|
|
165
|
+
const from = Math.max(0, at - Math.floor(SNIPPET / 3));
|
|
166
|
+
const to = Math.min(flat.length, from + SNIPPET);
|
|
167
|
+
return `${from > 0 ? '…' : ''}${flat.slice(from, to)}${to < flat.length ? '…' : ''}`;
|
|
168
|
+
}
|
|
169
|
+
/** `%`, `_` and `\` mean something to `ILIKE`, so a reader searching for `50%` gets `50%`. */
|
|
170
|
+
const escapeLike = (value) => value.replace(/[\\%_]/g, (c) => `\\${c}`);
|
|
171
|
+
export function quirePublications(kernel, access, versions) {
|
|
172
|
+
/**
|
|
173
|
+
* The associated data an unlock token is sealed with.
|
|
174
|
+
*
|
|
175
|
+
* AES-GCM authenticates it, so a token minted for one publication cannot be presented to another
|
|
176
|
+
* — and a token from another instance cannot be presented at all, because the key is derived from
|
|
177
|
+
* that instance's own secret. This is what makes the token a capability rather than a session:
|
|
178
|
+
* there is nothing on the server to look up, nothing to expire on a schedule, and nothing that
|
|
179
|
+
* says who is holding it.
|
|
180
|
+
*/
|
|
181
|
+
const aad = (workspaceId, publicationId) => `quire.publication.unlock:${workspaceId}:${publicationId}`;
|
|
182
|
+
async function hashPassword(plain) {
|
|
183
|
+
const salt = randomBytes(16);
|
|
184
|
+
const key = await scrypt(plain.normalize('NFC'), salt, 32, { N: 16384, r: 8, p: 1 });
|
|
185
|
+
return `$scrypt$N=16384,r=8,p=1$${salt.toString('base64url')}$${key.toString('base64url')}`;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Constant-time in the comparison, and deliberately not in the parse: a malformed stored hash is
|
|
189
|
+
* a bug in this file rather than something an attacker can produce, and answering `false` for one
|
|
190
|
+
* is the safe direction.
|
|
191
|
+
*/
|
|
192
|
+
async function verifyPassword(plain, phc) {
|
|
193
|
+
const parts = phc.split('$');
|
|
194
|
+
if (parts.length !== 5 || parts[1] !== 'scrypt')
|
|
195
|
+
return false;
|
|
196
|
+
const params = Object.fromEntries((parts[2] ?? '').split(',').map((pair) => {
|
|
197
|
+
const [k, v] = pair.split('=');
|
|
198
|
+
return [k ?? '', Number(v)];
|
|
199
|
+
}));
|
|
200
|
+
const salt = Buffer.from(parts[3] ?? '', 'base64url');
|
|
201
|
+
const expected = Buffer.from(parts[4] ?? '', 'base64url');
|
|
202
|
+
if (!Number.isInteger(params.N) || !Number.isInteger(params.r) || !Number.isInteger(params.p))
|
|
203
|
+
return false;
|
|
204
|
+
if (salt.length === 0 || expected.length === 0)
|
|
205
|
+
return false;
|
|
206
|
+
const actual = await scrypt(plain.normalize('NFC'), salt, expected.length, {
|
|
207
|
+
N: params.N,
|
|
208
|
+
r: params.r,
|
|
209
|
+
p: params.p,
|
|
210
|
+
});
|
|
211
|
+
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* The walk, as one recursive query.
|
|
215
|
+
*
|
|
216
|
+
* `cycle` is not paranoia: a page that had somehow become its own ancestor would otherwise hang
|
|
217
|
+
* the connection rather than fail, and this is the one endpoint where a hung connection is
|
|
218
|
+
* something a stranger can ask for. `depth < MAX_DEPTH` bounds the other direction.
|
|
219
|
+
*/
|
|
220
|
+
async function walk(tx, workspaceId, pub, opts) {
|
|
221
|
+
const rendered = opts.requireHtml;
|
|
222
|
+
const res = await tx.execute(sql `
|
|
223
|
+
with recursive tree as (
|
|
224
|
+
select p.id, p.parent_id, p.title, p.icon, p.cover_url, p.position,
|
|
225
|
+
v.id as version_id, v.created_at as published_at,
|
|
226
|
+
(v.html is not null) as has_html, 0 as depth
|
|
227
|
+
from mod_quire.pages p
|
|
228
|
+
join mod_quire.page_versions v
|
|
229
|
+
on v.workspace_id = p.workspace_id and v.id = p.published_version_id
|
|
230
|
+
where p.workspace_id = ${workspaceId}::uuid
|
|
231
|
+
and p.id = ${pub.rootPageId}::uuid
|
|
232
|
+
and p.kind = 'page'
|
|
233
|
+
and p.database_id is null
|
|
234
|
+
and p.deleted_at is null
|
|
235
|
+
and p.archived_at is null
|
|
236
|
+
and p.excluded_from_public = false
|
|
237
|
+
and (${rendered}::boolean = false or v.html is not null)
|
|
238
|
+
union all
|
|
239
|
+
select c.id, c.parent_id, c.title, c.icon, c.cover_url, c.position,
|
|
240
|
+
cv.id, cv.created_at, (cv.html is not null), tree.depth + 1
|
|
241
|
+
from mod_quire.pages c
|
|
242
|
+
join tree on c.parent_id = tree.id
|
|
243
|
+
join mod_quire.page_versions cv
|
|
244
|
+
on cv.workspace_id = ${workspaceId}::uuid and cv.id = c.published_version_id
|
|
245
|
+
where c.workspace_id = ${workspaceId}::uuid
|
|
246
|
+
and ${pub.includeDescendants}::boolean
|
|
247
|
+
and c.kind = 'page'
|
|
248
|
+
and c.database_id is null
|
|
249
|
+
and c.deleted_at is null
|
|
250
|
+
and c.archived_at is null
|
|
251
|
+
and c.excluded_from_public = false
|
|
252
|
+
and tree.depth < ${MAX_DEPTH}
|
|
253
|
+
and (${rendered}::boolean = false or cv.html is not null)
|
|
254
|
+
) cycle id set looped using cyclepath
|
|
255
|
+
select id, parent_id, title, icon, cover_url, position,
|
|
256
|
+
version_id, published_at, has_html, depth
|
|
257
|
+
from tree
|
|
258
|
+
order by depth asc, position asc
|
|
259
|
+
`);
|
|
260
|
+
return res.rows.map((row) => ({
|
|
261
|
+
id: row.id,
|
|
262
|
+
parent_id: row.parent_id,
|
|
263
|
+
title: row.title,
|
|
264
|
+
icon: row.icon,
|
|
265
|
+
cover_url: row.cover_url,
|
|
266
|
+
position: row.position,
|
|
267
|
+
version_id: row.version_id,
|
|
268
|
+
published_at: row.published_at instanceof Date ? row.published_at : new Date(row.published_at),
|
|
269
|
+
has_html: row.has_html === true,
|
|
270
|
+
depth: Number(row.depth),
|
|
271
|
+
}));
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
/**
|
|
275
|
+
* The anonymous path's transaction: the workspace set, and nothing writable.
|
|
276
|
+
*
|
|
277
|
+
* `set transaction read only` is issued after `withWorkspace`'s own `set_config`, which
|
|
278
|
+
* Postgres allows — the access mode is fixed by the first *write*, not by the first statement —
|
|
279
|
+
* and covers `pages` and `page_versions` as well as `publications`. It is the second fence, not
|
|
280
|
+
* the first: the first is that every query below carries the publication.
|
|
281
|
+
*/
|
|
282
|
+
read(workspaceId, fn) {
|
|
283
|
+
return kernel.database.withWorkspace(workspaceId, async (tx) => {
|
|
284
|
+
await tx.execute(sql `set transaction read only`);
|
|
285
|
+
return fn(tx);
|
|
286
|
+
}, { userId: null });
|
|
287
|
+
},
|
|
288
|
+
/**
|
|
289
|
+
* The publication behind a slug, or `notFound`.
|
|
290
|
+
*
|
|
291
|
+
* Expiry is checked here rather than by a sweep, so the URL stops working at the moment its
|
|
292
|
+
* author said it would even if nothing has run since. Everything that cannot be served answers
|
|
293
|
+
* the same 404: a slug nobody has taken, one that has expired, and one whose root page has
|
|
294
|
+
* since been trashed are indistinguishable from outside, which is the point.
|
|
295
|
+
*/
|
|
296
|
+
async bySlug(tx, workspaceId, slug) {
|
|
297
|
+
const [row] = await tx
|
|
298
|
+
.select()
|
|
299
|
+
.from(publications)
|
|
300
|
+
.where(and(eq(publications.workspaceId, workspaceId), eq(publications.slug, slug)))
|
|
301
|
+
.limit(1);
|
|
302
|
+
if (!row)
|
|
303
|
+
throw new KernError('NOT_FOUND', 'There is no published site at this address');
|
|
304
|
+
if (row.expiresAt && row.expiresAt.getTime() <= Date.now())
|
|
305
|
+
throw new KernError('NOT_FOUND', 'There is no published site at this address');
|
|
306
|
+
return row;
|
|
307
|
+
},
|
|
308
|
+
/** Whether this request may see anything but the door. */
|
|
309
|
+
async unlocked(pub, token) {
|
|
310
|
+
if (!pub.passwordHash)
|
|
311
|
+
return true;
|
|
312
|
+
if (!token)
|
|
313
|
+
return false;
|
|
314
|
+
try {
|
|
315
|
+
const claims = JSON.parse(kernel.secrets.decrypt(token, aad(pub.workspaceId, pub.id)));
|
|
316
|
+
return typeof claims.exp === 'number' && claims.exp > Date.now();
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
// A forged, truncated, re-used-from-another-publication or simply stale token is not an
|
|
320
|
+
// error worth reporting to whoever sent it — it is a locked door.
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
async mintToken(pub) {
|
|
325
|
+
const exp = Date.now() + TOKEN_TTL_MS;
|
|
326
|
+
return {
|
|
327
|
+
token: kernel.secrets.encrypt(JSON.stringify({ exp }), aad(pub.workspaceId, pub.id)),
|
|
328
|
+
expiresAt: new Date(exp).toISOString(),
|
|
329
|
+
};
|
|
330
|
+
},
|
|
331
|
+
async checkPassword(pub, password) {
|
|
332
|
+
if (!pub.passwordHash)
|
|
333
|
+
return false;
|
|
334
|
+
return verifyPassword(password, pub.passwordHash);
|
|
335
|
+
},
|
|
336
|
+
/** Every publicly reachable page of this publication, addressed, root first. */
|
|
337
|
+
async tree(tx, workspaceId, pub) {
|
|
338
|
+
return withPaths(await walk(tx, workspaceId, pub, { requireHtml: true }));
|
|
339
|
+
},
|
|
340
|
+
/** The node at a public path, or `notFound`. Never an id — `path` names a place or nothing. */
|
|
341
|
+
find(nodes, path) {
|
|
342
|
+
const wanted = normalisePath(path);
|
|
343
|
+
const node = nodes.find((n) => normalisePath(n.path) === wanted);
|
|
344
|
+
if (!node)
|
|
345
|
+
throw new KernError('NOT_FOUND', 'There is no published page at this address');
|
|
346
|
+
return node;
|
|
347
|
+
},
|
|
348
|
+
/** The pinned version's stored HTML, scrubbed for the internet. */
|
|
349
|
+
async html(tx, workspaceId, node, nodes, basePath) {
|
|
350
|
+
const [row] = await tx
|
|
351
|
+
.select({ html: pageVersions.html })
|
|
352
|
+
.from(pageVersions)
|
|
353
|
+
.where(and(eq(pageVersions.workspaceId, workspaceId), eq(pageVersions.id, node.version_id)))
|
|
354
|
+
.limit(1);
|
|
355
|
+
/*
|
|
356
|
+
* `=== null`, not falsy. `''` and NULL mean different things in this column and the
|
|
357
|
+
* difference is the whole reason it is nullable: NULL is "nobody has drawn this version",
|
|
358
|
+
* which is not servable, and `''` is "this version draws to nothing", which is a page
|
|
359
|
+
* somebody published while it was empty and is perfectly servable. Treating them the same
|
|
360
|
+
* way 404s a real page — it did, on every page in the fixture whose prose the renderer could
|
|
361
|
+
* not decode.
|
|
362
|
+
*/
|
|
363
|
+
if (!row || row.html === null)
|
|
364
|
+
throw new KernError('NOT_FOUND', 'There is no published page at this address');
|
|
365
|
+
const pathById = new Map(nodes.map((n) => [n.id, n.path]));
|
|
366
|
+
return publicHtml(row.html, (id) => pathById.get(id) ?? null, basePath);
|
|
367
|
+
},
|
|
368
|
+
/**
|
|
369
|
+
* Search the published text of this publication's pages.
|
|
370
|
+
*
|
|
371
|
+
* The ids come from the walk, so the search cannot reach outside the publication however the
|
|
372
|
+
* query is written — and it reads `page_versions.text`, which is the published copy, rather than
|
|
373
|
+
* `pages.text`, which mirrors the live document.
|
|
374
|
+
*/
|
|
375
|
+
async search(tx, workspaceId, nodes, query, limit) {
|
|
376
|
+
const versionIds = nodes.map((n) => n.version_id);
|
|
377
|
+
if (versionIds.length === 0)
|
|
378
|
+
return [];
|
|
379
|
+
const pattern = `%${escapeLike(query.trim())}%`;
|
|
380
|
+
const rows = await tx
|
|
381
|
+
.select({ id: pageVersions.id, text: pageVersions.text })
|
|
382
|
+
.from(pageVersions)
|
|
383
|
+
.where(and(eq(pageVersions.workspaceId, workspaceId), inArray(pageVersions.id, versionIds), sql `${pageVersions.text} ilike ${pattern}`))
|
|
384
|
+
.limit(limit);
|
|
385
|
+
const byVersion = new Map(nodes.map((n) => [n.version_id, n]));
|
|
386
|
+
const hits = [];
|
|
387
|
+
for (const row of rows) {
|
|
388
|
+
const node = byVersion.get(row.id);
|
|
389
|
+
if (node)
|
|
390
|
+
hits.push({ node, snippet: snippetAround(row.text, query) });
|
|
391
|
+
}
|
|
392
|
+
// Titles are worth matching too, and they are already in hand rather than in the database.
|
|
393
|
+
for (const node of nodes) {
|
|
394
|
+
if (hits.length >= limit)
|
|
395
|
+
break;
|
|
396
|
+
if (hits.some((h) => h.node.id === node.id))
|
|
397
|
+
continue;
|
|
398
|
+
if (node.title.toLowerCase().includes(query.trim().toLowerCase()))
|
|
399
|
+
hits.push({ node, snippet: '' });
|
|
400
|
+
}
|
|
401
|
+
return hits.slice(0, limit);
|
|
402
|
+
},
|
|
403
|
+
/**
|
|
404
|
+
* A cache validator for a pinned version that is not the version's id.
|
|
405
|
+
*
|
|
406
|
+
* The id addresses `versions.get`, which asks a permission; a hash of it changes exactly when
|
|
407
|
+
* the pinned version does and can be tried nowhere.
|
|
408
|
+
*/
|
|
409
|
+
etagFor(versionId) {
|
|
410
|
+
return createHash('sha256').update(`quire.public.v1:${versionId}`).digest('base64url').slice(0, 32);
|
|
411
|
+
},
|
|
412
|
+
// ---------------------------------------------------------------- authenticated side
|
|
413
|
+
/** Every publication rooted at a page of this space, newest first. */
|
|
414
|
+
async list(tx, workspaceId, spaceId) {
|
|
415
|
+
return tx
|
|
416
|
+
.select({ pub: publications })
|
|
417
|
+
.from(publications)
|
|
418
|
+
.innerJoin(pages, and(eq(pages.workspaceId, publications.workspaceId), eq(pages.id, publications.rootPageId)))
|
|
419
|
+
.where(and(eq(publications.workspaceId, workspaceId), eq(pages.spaceId, spaceId)))
|
|
420
|
+
.orderBy(desc(publications.createdAt))
|
|
421
|
+
.then((rows) => rows.map((r) => r.pub));
|
|
422
|
+
},
|
|
423
|
+
async row(tx, workspaceId, publicationId) {
|
|
424
|
+
const [row] = await tx
|
|
425
|
+
.select()
|
|
426
|
+
.from(publications)
|
|
427
|
+
.where(and(eq(publications.workspaceId, workspaceId), eq(publications.id, publicationId)))
|
|
428
|
+
.limit(1);
|
|
429
|
+
if (!row)
|
|
430
|
+
throw KernError.notFound('Publication');
|
|
431
|
+
return row;
|
|
432
|
+
},
|
|
433
|
+
async create(tx, principal, workspaceId, input) {
|
|
434
|
+
const root = await access.pageRow(tx, workspaceId, input.rootPageId);
|
|
435
|
+
if (root.kind !== 'page')
|
|
436
|
+
throw KernError.badRequest('Only a page can be published; a live doc and a database cannot');
|
|
437
|
+
const [row] = await tx
|
|
438
|
+
.insert(publications)
|
|
439
|
+
.values({
|
|
440
|
+
workspaceId,
|
|
441
|
+
rootPageId: input.rootPageId,
|
|
442
|
+
includeDescendants: input.includeDescendants,
|
|
443
|
+
slug: input.slug,
|
|
444
|
+
passwordHash: input.password ? await hashPassword(input.password) : null,
|
|
445
|
+
expiresAt: input.expiresAt ? new Date(input.expiresAt) : null,
|
|
446
|
+
seoTitle: input.seoTitle,
|
|
447
|
+
seoDescription: input.seoDescription,
|
|
448
|
+
ogImageUrl: input.ogImageUrl,
|
|
449
|
+
indexable: input.indexable,
|
|
450
|
+
theme: input.theme,
|
|
451
|
+
createdBy: principal.userId,
|
|
452
|
+
})
|
|
453
|
+
.returning()
|
|
454
|
+
.catch((err) => {
|
|
455
|
+
if (err.code === '23505')
|
|
456
|
+
throw KernError.conflict('That address is already taken in this workspace', 'quire.slug.taken');
|
|
457
|
+
throw err;
|
|
458
|
+
});
|
|
459
|
+
return row;
|
|
460
|
+
},
|
|
461
|
+
async update(tx, workspaceId, publicationId, patch) {
|
|
462
|
+
await this.row(tx, workspaceId, publicationId);
|
|
463
|
+
const values = { updatedAt: new Date() };
|
|
464
|
+
if (patch.slug !== undefined)
|
|
465
|
+
values.slug = patch.slug;
|
|
466
|
+
if (patch.includeDescendants !== undefined)
|
|
467
|
+
values.includeDescendants = patch.includeDescendants;
|
|
468
|
+
// Three-valued: a string sets, `null` removes, absent leaves alone. See the contract.
|
|
469
|
+
if (patch.password !== undefined)
|
|
470
|
+
values.passwordHash = patch.password === null ? null : await hashPassword(patch.password);
|
|
471
|
+
if (patch.expiresAt !== undefined)
|
|
472
|
+
values.expiresAt = patch.expiresAt === null ? null : new Date(patch.expiresAt);
|
|
473
|
+
if (patch.seoTitle !== undefined)
|
|
474
|
+
values.seoTitle = patch.seoTitle;
|
|
475
|
+
if (patch.seoDescription !== undefined)
|
|
476
|
+
values.seoDescription = patch.seoDescription;
|
|
477
|
+
if (patch.ogImageUrl !== undefined)
|
|
478
|
+
values.ogImageUrl = patch.ogImageUrl;
|
|
479
|
+
if (patch.indexable !== undefined)
|
|
480
|
+
values.indexable = patch.indexable;
|
|
481
|
+
if (patch.theme !== undefined)
|
|
482
|
+
values.theme = patch.theme;
|
|
483
|
+
const [row] = await tx
|
|
484
|
+
.update(publications)
|
|
485
|
+
.set(values)
|
|
486
|
+
.where(and(eq(publications.workspaceId, workspaceId), eq(publications.id, publicationId)))
|
|
487
|
+
.returning()
|
|
488
|
+
.catch((err) => {
|
|
489
|
+
if (err.code === '23505')
|
|
490
|
+
throw KernError.conflict('That address is already taken in this workspace', 'quire.slug.taken');
|
|
491
|
+
throw err;
|
|
492
|
+
});
|
|
493
|
+
return row;
|
|
494
|
+
},
|
|
495
|
+
async remove(tx, workspaceId, publicationId) {
|
|
496
|
+
await this.row(tx, workspaceId, publicationId);
|
|
497
|
+
await tx
|
|
498
|
+
.delete(publications)
|
|
499
|
+
.where(and(eq(publications.workspaceId, workspaceId), eq(publications.id, publicationId)));
|
|
500
|
+
},
|
|
501
|
+
/** "Never public", on the page rather than on any one publication. */
|
|
502
|
+
async setExcluded(tx, workspaceId, pageId, excluded) {
|
|
503
|
+
await access.pageRow(tx, workspaceId, pageId);
|
|
504
|
+
const [row] = await tx
|
|
505
|
+
.update(pages)
|
|
506
|
+
.set({ excludedFromPublic: excluded, updatedAt: new Date() })
|
|
507
|
+
.where(and(eq(pages.workspaceId, workspaceId), eq(pages.id, pageId)))
|
|
508
|
+
.returning({ excluded: pages.excludedFromPublic });
|
|
509
|
+
return row?.excluded ?? excluded;
|
|
510
|
+
},
|
|
511
|
+
/**
|
|
512
|
+
* Draw one version and keep the drawing.
|
|
513
|
+
*
|
|
514
|
+
* Called when a page is published, so the work happens once per publish rather than once per
|
|
515
|
+
* anonymous read — the version is immutable, so every render of it would be identical. Already
|
|
516
|
+
* rendered is a no-op, which is what makes it safe to call from both `publish` and the backfill.
|
|
517
|
+
*/
|
|
518
|
+
async renderVersion(tx, workspaceId, versionId) {
|
|
519
|
+
const [row] = await tx
|
|
520
|
+
.select({ id: pageVersions.id, state: pageVersions.state, html: pageVersions.html })
|
|
521
|
+
.from(pageVersions)
|
|
522
|
+
.where(and(eq(pageVersions.workspaceId, workspaceId), eq(pageVersions.id, versionId)))
|
|
523
|
+
.limit(1);
|
|
524
|
+
if (!row || row.html !== null)
|
|
525
|
+
return;
|
|
526
|
+
const html = await versions.html(tx, workspaceId, row.state);
|
|
527
|
+
await tx
|
|
528
|
+
.update(pageVersions)
|
|
529
|
+
.set({ html })
|
|
530
|
+
.where(and(eq(pageVersions.workspaceId, workspaceId), eq(pageVersions.id, versionId)));
|
|
531
|
+
},
|
|
532
|
+
/**
|
|
533
|
+
* Render whatever in this publication's subtree has never been rendered.
|
|
534
|
+
*
|
|
535
|
+
* Only ever needed for a page published before this feature existed — a publish since then
|
|
536
|
+
* writes the HTML as it goes. It runs on `create` and `update` because that is the moment an
|
|
537
|
+
* author is asking for the site to work, and it is bounded: past `MAX_BACKFILL` the rest are
|
|
538
|
+
* left to be rendered when they are next published, and the gap is a warning rather than a
|
|
539
|
+
* failed request. A page whose HTML is missing is simply not part of the site yet, which is the
|
|
540
|
+
* same rule as a page with no published version.
|
|
541
|
+
*/
|
|
542
|
+
async backfill(tx, workspaceId, pub) {
|
|
543
|
+
const all = await walk(tx, workspaceId, pub, { requireHtml: false });
|
|
544
|
+
const missing = all.filter((r) => !r.has_html);
|
|
545
|
+
if (missing.length > MAX_BACKFILL)
|
|
546
|
+
kernel.log.warn({ publicationId: pub.id, pending: missing.length, cap: MAX_BACKFILL }, 'too many unrendered versions to publish in one request');
|
|
547
|
+
for (const row of missing.slice(0, MAX_BACKFILL))
|
|
548
|
+
await this.renderVersion(tx, workspaceId, row.version_id);
|
|
549
|
+
return Math.min(missing.length, MAX_BACKFILL);
|
|
550
|
+
},
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
//# sourceMappingURL=publications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publications.js","sourceRoot":"","sources":["../../../src/server/services/publications.ts"],"names":[],"mappings":"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"}
|
|
@@ -42,6 +42,7 @@ export declare function quireVersions(kernel: Kernel, access: QuireAccess): {
|
|
|
42
42
|
state: Buffer<ArrayBufferLike>;
|
|
43
43
|
snapshot: Buffer<ArrayBufferLike> | null;
|
|
44
44
|
text: string;
|
|
45
|
+
html: string | null;
|
|
45
46
|
size: number;
|
|
46
47
|
authorId: string | null;
|
|
47
48
|
createdAt: Date;
|
|
@@ -64,6 +65,7 @@ export declare function quireVersions(kernel: Kernel, access: QuireAccess): {
|
|
|
64
65
|
size: number;
|
|
65
66
|
authorId: string | null;
|
|
66
67
|
text: string;
|
|
68
|
+
html: string | null;
|
|
67
69
|
state: Buffer<ArrayBufferLike>;
|
|
68
70
|
snapshot: Buffer<ArrayBufferLike> | null;
|
|
69
71
|
}>;
|
|
@@ -84,6 +86,7 @@ export declare function quireVersions(kernel: Kernel, access: QuireAccess): {
|
|
|
84
86
|
databaseId: string | null;
|
|
85
87
|
props: unknown;
|
|
86
88
|
computed: unknown;
|
|
89
|
+
excludedFromPublic: boolean;
|
|
87
90
|
createdBy: string | null;
|
|
88
91
|
updatedBy: string | null;
|
|
89
92
|
createdAt: Date;
|
|
@@ -108,6 +111,7 @@ export declare function quireVersions(kernel: Kernel, access: QuireAccess): {
|
|
|
108
111
|
databaseId: string | null;
|
|
109
112
|
props: unknown;
|
|
110
113
|
computed: unknown;
|
|
114
|
+
excludedFromPublic: boolean;
|
|
111
115
|
createdBy: string | null;
|
|
112
116
|
updatedBy: string | null;
|
|
113
117
|
createdAt: Date;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,EAAE,EAAU,MAAM,gBAAgB,CAAA;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAG1D,OAAO,EAAS,YAAY,EAAU,MAAM,cAAc,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,KAAK,UAAU,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAKlD,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CAalF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS7D;;;;;;OAMG;gBAEG,EAAE,eACO,MAAM,UACX,MAAM,QACR;QAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GACnF,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;aA0Cd,EAAE,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,UAAU,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;YAkB9E,EAAE,eAAe,MAAM,aAAa,MAAM
|
|
1
|
+
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,EAAE,EAAU,MAAM,gBAAgB,CAAA;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAG1D,OAAO,EAAS,YAAY,EAAU,MAAM,cAAc,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,KAAK,UAAU,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAKlD,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CAalF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS7D;;;;;;OAMG;gBAEG,EAAE,eACO,MAAM,UACX,MAAM,QACR;QAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GACnF,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;aA0Cd,EAAE,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,UAAU,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;YAkB9E,EAAE,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;;IAUxD;;;;;;;OAOG;gBACe,EAAE,aAAa,SAAS,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;;IAsBlF,kEAAkE;gBAChD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;;IAyBrG,wEAAwE;eACvD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;;;;;IAyB9E,2FAA2F;uBAClE,EAAE,eAAe,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAUvF,wFAAwF;+BAC7D,MAAM,UAAU,MAAM;;;;;;IAMjD;;;;;;;;;;;;;;;;;;OAkBG;aACY,EAAE,eAAe,MAAM,SAAS,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;EAwC9F;AACD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA"}
|