@morphemecms/cms 0.3.0 → 0.4.0-next-20261104164754
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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/bin/morpheme.mjs +1 -1
- package/defaults/editor.ts +3 -1
- package/lib/changelog.d.mts +24 -0
- package/lib/changelog.mjs +65 -0
- package/lib/changelog.test.d.mts +1 -0
- package/lib/changelog.test.mjs +67 -0
- package/lib/cms-version.d.mts +56 -0
- package/lib/cms-version.mjs +85 -0
- package/lib/cms-version.test.d.mts +1 -0
- package/lib/cms-version.test.mjs +68 -0
- package/lib/lockfile.d.mts +19 -0
- package/lib/lockfile.mjs +135 -0
- package/lib/lockfile.test.d.mts +1 -0
- package/lib/lockfile.test.mjs +88 -0
- package/lib/range.d.mts +4 -0
- package/lib/range.mjs +104 -0
- package/lib/range.test.d.mts +1 -0
- package/lib/range.test.mjs +46 -0
- package/package.json +2 -1
- package/scripts/built-site.mjs +14 -0
- package/scripts/check-cms-update.mjs +405 -0
- package/site/theme.d.mts +1 -1
- package/site/theme.mjs +2 -2
- package/src/App.tsx +3 -0
- package/src/CmsPage.tsx +139 -0
- package/src/Library.tsx +2 -0
- package/src/appFiles.ts +2 -2
- package/src/apps.ts +2 -2
- package/src/blocks.ts +1 -1
- package/src/cmsView.d.mts +15 -0
- package/src/cmsView.mjs +78 -0
- package/src/cmsView.test.d.mts +1 -0
- package/src/cmsView.test.mjs +146 -0
- package/src/frontmatter.mjs +4 -1
- package/src/frontmatter.test.mjs +6 -0
- package/src/i18n/da-DK/cms.ts +30 -0
- package/src/i18n/da-DK/common.ts +1 -0
- package/src/i18n/da-DK/index.ts +2 -0
- package/src/i18n/en-US/cms.ts +34 -0
- package/src/i18n/en-US/common.ts +2 -0
- package/src/i18n/en-US/index.ts +2 -0
- package/src/registry.tsx +3 -3
- package/src/schema.ts +1 -1
- package/starter/.prettierignore +1 -0
- package/starter/README.md +1 -0
- package/starter/package.json +1 -1
- package/starter/wrangler.jsonc +1 -1
- package/worker/cms-update.js +245 -0
- package/worker/github.js +8 -6
- package/worker/index.js +6 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// The Worker takes the CMS's new versions by itself: each hour it asks npm for the newest @morphemecms/cms, commits the new exact
|
|
2
|
+
// version in package.json and package-lock.json, and each minute watches the commit's check run, undoing a version that did not build.
|
|
3
|
+
// Exposes RUNNING, checkForUpdate, startUpdate, watchUpdate, cmsStatus and handleCms (/api/cms). Needs GITHUB_PUBLISH_TOKEN and the
|
|
4
|
+
// KV binding PUSH. Depends on github.js, session.js, push.js and lib/{lockfile,cms-version,changelog}.mjs; I/O is injected (`deps`).
|
|
5
|
+
import { config } from '@site/config';
|
|
6
|
+
import { cms as cmsEn } from '../src/i18n/en-US/cms';
|
|
7
|
+
import { cms as cmsDa } from '../src/i18n/da-DK/cms';
|
|
8
|
+
import { addToLock, NeedsNpm } from '../lib/lockfile.mjs';
|
|
9
|
+
import { compareVersions, managedVersion, nextVersion, PACKAGE, watchStep } from '../lib/cms-version.mjs';
|
|
10
|
+
import { fileFromTar, gunzip, sectionsBetween } from '../lib/changelog.mjs';
|
|
11
|
+
import pkg from '../package.json';
|
|
12
|
+
import { GitHubError } from './files.js';
|
|
13
|
+
import { commitFiles, readFiles } from './github.js';
|
|
14
|
+
import { json } from './not-found.js';
|
|
15
|
+
import { notifyAll } from './push.js';
|
|
16
|
+
import { mayEdit } from './session.js';
|
|
17
|
+
|
|
18
|
+
/** The version this Worker itself runs. */
|
|
19
|
+
export const RUNNING = pkg.version;
|
|
20
|
+
|
|
21
|
+
const PACKAGE_JSON = 'package.json';
|
|
22
|
+
const LOCK = 'package-lock.json';
|
|
23
|
+
const NPM = 'https://registry.npmjs.org';
|
|
24
|
+
const NPM_NAME = '@morphemecms%2fcms';
|
|
25
|
+
const BUILD_APP = 'cloudflare-workers-and-pages';
|
|
26
|
+
|
|
27
|
+
const defaultDeps = { readFiles, commitFiles, fetch: (...args) => fetch(...args), notify: notifyAll, mayEdit };
|
|
28
|
+
|
|
29
|
+
/** The site's language for the commits: its own, else the same language, else Danish. */
|
|
30
|
+
const siteTexts = () => {
|
|
31
|
+
const code = String(config.locale ?? '');
|
|
32
|
+
return code === 'en-US' || (code !== 'da-DK' && code.startsWith('en')) ? cmsEn : cmsDa;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const iso = (now) => new Date(now).toISOString();
|
|
36
|
+
|
|
37
|
+
/** Whether GitHub says the token may not write (GraphQL answers a read-only token with HTTP 200 and an error). */
|
|
38
|
+
const forbidden = (e) => e instanceof GitHubError && (e.status === 403 || /not accessible|forbidden/i.test(e.message));
|
|
39
|
+
|
|
40
|
+
async function getJson(deps, url, init) {
|
|
41
|
+
const res = await deps.fetch(url, init);
|
|
42
|
+
if (!res.ok) throw new Error(`${res.status} ${url}`);
|
|
43
|
+
return res.json();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** `JSON.stringify(x, null, 2)` with the file's own line ending at its end, as npm writes. */
|
|
47
|
+
const written = (value, original) => JSON.stringify(value, null, 2) + (original?.includes('\r\n') ? '\r\n' : '\n');
|
|
48
|
+
|
|
49
|
+
/** The files' texts parsed, and the branch's head. */
|
|
50
|
+
async function readSite(env, deps) {
|
|
51
|
+
const { head, texts } = await deps.readFiles(env, [PACKAGE_JSON, LOCK]);
|
|
52
|
+
return {
|
|
53
|
+
head,
|
|
54
|
+
texts,
|
|
55
|
+
packageJson: texts[0] ? JSON.parse(texts[0]) : null,
|
|
56
|
+
lock: typeof texts[1] === 'string' ? JSON.parse(texts[1]) : null,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The files with `version` of the package in them, as changes for one commit. */
|
|
61
|
+
async function filesFor(env, deps, site, version) {
|
|
62
|
+
const manifest = await getJson(deps, `${NPM}/${NPM_NAME}/${version}`);
|
|
63
|
+
if (!site.lock) throw new NeedsNpm('package-lock.json mangler.');
|
|
64
|
+
const out = addToLock(site.packageJson, site.lock, manifest);
|
|
65
|
+
return [
|
|
66
|
+
{ path: PACKAGE_JSON, text: written(out.packageJson, site.texts[0]) },
|
|
67
|
+
{ path: LOCK, text: written(out.lock, site.texts[1]) },
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Sends the notification in both languages; its text is the English sentence. */
|
|
72
|
+
async function tell(env, deps, key, version, error) {
|
|
73
|
+
const text = cmsEn[key](version);
|
|
74
|
+
await deps.notify(
|
|
75
|
+
env,
|
|
76
|
+
{ type: 'updates', id: 'cms', text, error },
|
|
77
|
+
{ 'en-US': { [text]: text }, 'da-DK': { [text]: cmsDa[key](version) } },
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const putJson = (kv, key, value) => kv.put(key, JSON.stringify(value));
|
|
82
|
+
|
|
83
|
+
/** Writes package.json and the lock for `version`, commits it and keeps `cms:update`. Throws NeedsNpm or a GitHubError. */
|
|
84
|
+
export async function startUpdate(env, version, deps = defaultDeps, now = Date.now()) {
|
|
85
|
+
const site = await readSite(env, deps);
|
|
86
|
+
const managed = managedVersion(site.packageJson, site.lock);
|
|
87
|
+
if (!('version' in managed)) throw new Error('not-managed');
|
|
88
|
+
const changes = await filesFor(env, deps, site, version);
|
|
89
|
+
const commit = await deps.commitFiles(env, site.head, siteTexts().commitUpdate(version), changes);
|
|
90
|
+
const update = { commit, from: managed.version, to: version, at: iso(now), state: 'waiting' };
|
|
91
|
+
await putJson(env.PUSH, 'cms:update', update);
|
|
92
|
+
return update;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The sections of the changelog from `current` to `latest`, each kept as cms:notes:<version>. */
|
|
96
|
+
async function keepNotes(env, deps, current, latest) {
|
|
97
|
+
const manifest = await getJson(deps, `${NPM}/${NPM_NAME}/${latest}`);
|
|
98
|
+
const res = await deps.fetch(manifest.dist.tarball);
|
|
99
|
+
if (!res.ok) return;
|
|
100
|
+
const changelog = fileFromTar(await gunzip(new Uint8Array(await res.arrayBuffer())), 'package/CHANGELOG.md');
|
|
101
|
+
if (!changelog) return;
|
|
102
|
+
for (const { version, text } of sectionsBetween(changelog, current, latest))
|
|
103
|
+
await putJson(env.PUSH, `cms:notes:${version}`, { version, text });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const versionsUnder = async (kv, prefix) => (await kv.list({ prefix })).keys.map((k) => k.name.slice(prefix.length));
|
|
107
|
+
|
|
108
|
+
/** Each hour: asks npm for the newest version and takes it when it may. */
|
|
109
|
+
export async function checkForUpdate(env, deps = defaultDeps, now = Date.now()) {
|
|
110
|
+
if (!env.GITHUB_PUBLISH_TOKEN || !env.PUSH) return;
|
|
111
|
+
const kv = env.PUSH;
|
|
112
|
+
const update = await kv.get('cms:update', 'json');
|
|
113
|
+
if (update?.state === 'waiting' || update?.state === 'undoing') return;
|
|
114
|
+
const before = await kv.get('cms:checked', 'json');
|
|
115
|
+
let latest = before?.latest ?? null;
|
|
116
|
+
const record = (problem) =>
|
|
117
|
+
putJson(kv, 'cms:checked', { at: iso(now), latest, ...(problem ? { problem } : {}), ...(before?.noChecks ? { noChecks: true } : {}) });
|
|
118
|
+
|
|
119
|
+
let site;
|
|
120
|
+
try {
|
|
121
|
+
site = await readSite(env, deps);
|
|
122
|
+
} catch {
|
|
123
|
+
return record({ kind: 'unreachable' });
|
|
124
|
+
}
|
|
125
|
+
const managed = managedVersion(site.packageJson, site.lock);
|
|
126
|
+
if (!('version' in managed)) return record({ kind: 'not-managed', detail: managed.reason });
|
|
127
|
+
try {
|
|
128
|
+
latest = (await getJson(deps, `${NPM}/-/package/${NPM_NAME}/dist-tags`)).latest;
|
|
129
|
+
} catch {
|
|
130
|
+
return record({ kind: 'unreachable' });
|
|
131
|
+
}
|
|
132
|
+
const next = nextVersion(managed.version, latest, await versionsUnder(kv, 'cms:skip:'));
|
|
133
|
+
if (!next) return record();
|
|
134
|
+
if (!(await kv.get(`cms:notes:${latest}`, 'json'))) await keepNotes(env, deps, managed.version, latest).catch(() => {});
|
|
135
|
+
if (!next.auto) return record({ kind: next.why });
|
|
136
|
+
try {
|
|
137
|
+
await startUpdate(env, next.version, deps, now);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
if (e instanceof NeedsNpm) return record({ kind: 'needs-npm', detail: e.message });
|
|
140
|
+
return record(forbidden(e) ? { kind: 'cannot-write' } : { kind: 'unreachable' });
|
|
141
|
+
}
|
|
142
|
+
return record();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** The conclusion of the newest check run of Cloudflare's build on a commit; null when none, or when GitHub will not say. */
|
|
146
|
+
async function checkOf(env, deps, sha, now) {
|
|
147
|
+
const { owner, name } = config.repo;
|
|
148
|
+
const res = await deps.fetch(`https://api.github.com/repos/${owner}/${name}/commits/${sha}/check-runs`, {
|
|
149
|
+
headers: { authorization: `Bearer ${env.GITHUB_PUBLISH_TOKEN}`, accept: 'application/vnd.github+json', 'user-agent': `${name}-worker` },
|
|
150
|
+
});
|
|
151
|
+
if (res.status === 403) {
|
|
152
|
+
const checked = await env.PUSH.get('cms:checked', 'json');
|
|
153
|
+
if (!checked?.noChecks) await putJson(env.PUSH, 'cms:checked', { at: iso(now), latest: null, ...checked, noChecks: true });
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
if (!res.ok) return null;
|
|
157
|
+
const { check_runs: runs = [] } = await res.json().catch(() => ({}));
|
|
158
|
+
const run = runs
|
|
159
|
+
.filter((r) => r.app?.slug === BUILD_APP)
|
|
160
|
+
.sort((a, b) => Date.parse(b.started_at ?? '') - Date.parse(a.started_at ?? ''))[0];
|
|
161
|
+
return run?.conclusion === 'success' || run?.conclusion === 'failure' ? run.conclusion : null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** The update written back to the version it came from, committed. Returns the commit's id. */
|
|
165
|
+
async function undoCommit(env, deps, update) {
|
|
166
|
+
const site = await readSite(env, deps);
|
|
167
|
+
const changes = await filesFor(env, deps, site, update.from);
|
|
168
|
+
return deps.commitFiles(env, site.head, siteTexts().commitUndo(update.to), changes);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Each minute: watches the update's (or its undo's) check run. One KV read when nothing is waiting. */
|
|
172
|
+
export async function watchUpdate(env, deps = defaultDeps, now = Date.now()) {
|
|
173
|
+
if (!env.PUSH) return;
|
|
174
|
+
const kv = env.PUSH;
|
|
175
|
+
const update = await kv.get('cms:update', 'json');
|
|
176
|
+
if (update?.state !== 'waiting' && update?.state !== 'undoing') return;
|
|
177
|
+
if (!env.GITHUB_PUBLISH_TOKEN) return;
|
|
178
|
+
const sha = update.state === 'waiting' ? update.commit : update.undoCommit;
|
|
179
|
+
const check = update.state === 'waiting' && update.to === RUNNING ? null : await checkOf(env, deps, sha, now).catch(() => null);
|
|
180
|
+
const step = watchStep(update, RUNNING, check, now);
|
|
181
|
+
if (step === 'wait') return;
|
|
182
|
+
if (step === 'done') {
|
|
183
|
+
await putJson(kv, 'cms:update', { ...update, state: 'done' });
|
|
184
|
+
return tell(env, deps, 'notifyDone', update.to);
|
|
185
|
+
}
|
|
186
|
+
if (step === 'undone') {
|
|
187
|
+
await putJson(kv, 'cms:update', { ...update, state: 'undone' });
|
|
188
|
+
return tell(env, deps, 'notifyUndone', update.to, true);
|
|
189
|
+
}
|
|
190
|
+
if (step === 'undo') {
|
|
191
|
+
try {
|
|
192
|
+
const commit = await undoCommit(env, deps, update);
|
|
193
|
+
await putJson(kv, `cms:skip:${update.to}`, { version: update.to, commit: update.commit, at: iso(now) });
|
|
194
|
+
return await putJson(kv, 'cms:update', { ...update, state: 'undoing', undoCommit: commit, undoAt: iso(now) });
|
|
195
|
+
} catch {
|
|
196
|
+
// The undo could not be committed either.
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
await putJson(kv, 'cms:update', { ...update, state: 'stuck' });
|
|
200
|
+
return tell(env, deps, 'notifyStuck', update.to, true);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** What the page shows: the running version, the token, what npm said, the update, the skipped versions and the notes. */
|
|
204
|
+
export async function cmsStatus(env) {
|
|
205
|
+
const kv = env.PUSH;
|
|
206
|
+
const status = { running: RUNNING, token: !!env.GITHUB_PUBLISH_TOKEN, kv: !!kv, checked: null, update: null, skipped: [], notes: [] };
|
|
207
|
+
if (!kv) return status;
|
|
208
|
+
status.checked = await kv.get('cms:checked', 'json');
|
|
209
|
+
status.update = await kv.get('cms:update', 'json');
|
|
210
|
+
status.skipped = await versionsUnder(kv, 'cms:skip:');
|
|
211
|
+
const plain = /^\d+\.\d+\.\d+$/;
|
|
212
|
+
const wanted = (await versionsUnder(kv, 'cms:notes:')).filter(
|
|
213
|
+
(v) =>
|
|
214
|
+
plain.test(v) && compareVersions(v, RUNNING) === 1 && (!status.checked?.latest || compareVersions(v, status.checked.latest) <= 0),
|
|
215
|
+
);
|
|
216
|
+
wanted.sort((a, b) => compareVersions(b, a));
|
|
217
|
+
const notes = await Promise.all(wanted.map((v) => kv.get(`cms:notes:${v}`, 'json')));
|
|
218
|
+
status.notes = notes.filter(Boolean).map(({ version, text }) => ({ version, text }));
|
|
219
|
+
return status;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** `GET /api/cms` (the status) and `POST /api/cms/update { version }`; null for other addresses. */
|
|
223
|
+
export async function handleCms(request, env, ctx, deps = defaultDeps) {
|
|
224
|
+
const match = /^\/api\/cms(\/update)?\/?$/.exec(new URL(request.url).pathname);
|
|
225
|
+
if (!match) return null;
|
|
226
|
+
const posting = !!match[1];
|
|
227
|
+
if (request.method !== (posting ? 'POST' : 'GET')) return json({ error: 'method' }, 405);
|
|
228
|
+
if (!(await deps.mayEdit(request))) return json({ error: 'forbidden' }, 403);
|
|
229
|
+
if (!posting) return json(await cmsStatus(env));
|
|
230
|
+
if (!env.GITHUB_PUBLISH_TOKEN || !env.PUSH) return json({ error: 'not-set-up' }, 503);
|
|
231
|
+
const { version } = await request.json().catch(() => ({}));
|
|
232
|
+
const checked = await env.PUSH.get('cms:checked', 'json');
|
|
233
|
+
if (typeof version !== 'string' || version !== checked?.latest) return json({ error: 'version' }, 400);
|
|
234
|
+
const current = await env.PUSH.get('cms:update', 'json');
|
|
235
|
+
if (current?.state === 'waiting' || current?.state === 'undoing') return json({ error: 'waiting' }, 409);
|
|
236
|
+
await env.PUSH.delete(`cms:skip:${version}`);
|
|
237
|
+
try {
|
|
238
|
+
return json({ update: await startUpdate(env, version, deps) });
|
|
239
|
+
} catch (e) {
|
|
240
|
+
if (e instanceof NeedsNpm) return json({ error: 'needs-npm', detail: e.message }, 422);
|
|
241
|
+
if (forbidden(e)) return json({ error: 'cannot-write' }, 502);
|
|
242
|
+
if (e?.message === 'not-managed') return json({ error: 'not-managed' }, 409);
|
|
243
|
+
return json({ error: 'unreachable' }, 502);
|
|
244
|
+
}
|
|
245
|
+
}
|
package/worker/github.js
CHANGED
|
@@ -20,16 +20,18 @@ export async function readFiles(env, paths, ctx, token = env.GITHUB_PUBLISH_TOKE
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/** Saves the files (`{ path, text }`) in one commit on the branch, if its head is still `head
|
|
23
|
+
/** Saves the files (`{ path, text }`) in one commit on the branch, if its head is still `head`; returns the new commit's id. */
|
|
24
24
|
export async function commitFiles(env, head, headline, changes, ctx, token = env.GITHUB_PUBLISH_TOKEN) {
|
|
25
25
|
const files = filesOf(env, token, ctx);
|
|
26
26
|
try {
|
|
27
27
|
const at = { commit: head, tree: await files.rootOf(head) };
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
return (
|
|
29
|
+
await files.save(
|
|
30
|
+
at,
|
|
31
|
+
headline,
|
|
32
|
+
changes.map((f) => ({ path: f.path, contents: toBase64(new TextEncoder().encode(f.text)) })),
|
|
33
|
+
)
|
|
34
|
+
).commit;
|
|
33
35
|
} finally {
|
|
34
36
|
await files.finish('Workeren gemmer');
|
|
35
37
|
}
|
package/worker/index.js
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
// - each hour, the pages and posts that are Planlagt published once their time has come (scheduled, packages/editor/worker/publish.js).
|
|
24
24
|
// - the editor's notifications on the phone, also when the editor is closed (/api/push, packages/editor/worker/push.js): each minute,
|
|
25
25
|
// whether the site has been built with a save, and an app's notifications (`notify` in its tools).
|
|
26
|
+
// - the CMS's own updates (/api/cms, packages/editor/worker/cms-update.js): each hour, whether npm has a newer @morphemecms/cms to commit, and
|
|
27
|
+
// each minute, whether the update built, else it is undone.
|
|
26
28
|
// - the apps' own parts (src/apps/<app>/worker.js, worker/apps.js), while they are installed: their addresses under
|
|
27
29
|
// /api/<app>/ and what they do each hour (scheduled), e.g. Cookiescanner's scan of the site's cookies, and their texts
|
|
28
30
|
// for their notifications. What the apps
|
|
@@ -39,6 +41,7 @@ import { handleR2 } from './r2-status.js';
|
|
|
39
41
|
import { publishScheduled, SCHEDULED_LIST } from './publish.js';
|
|
40
42
|
import { commitFiles, readFiles } from './github.js';
|
|
41
43
|
import { handlePush, notifyAll, waitForBuilds } from './push.js';
|
|
44
|
+
import { checkForUpdate, handleCms, watchUpdate } from './cms-update.js';
|
|
42
45
|
|
|
43
46
|
const STAGING = /\.workers\.dev$/i;
|
|
44
47
|
// The cron in wrangler.jsonc that runs each minute.
|
|
@@ -148,6 +151,7 @@ export default {
|
|
|
148
151
|
if (url.pathname.startsWith('/api/github/')) return handleGitHub(request, env, ctx);
|
|
149
152
|
if (url.pathname.startsWith('/api/store/')) return handleStore(request, env, ctx);
|
|
150
153
|
if (/^\/api\/push(\/wait)?\/?$/.test(url.pathname)) return handlePush(request, env);
|
|
154
|
+
if (/^\/api\/cms(\/update)?\/?$/.test(url.pathname)) return handleCms(request, env, ctx);
|
|
151
155
|
const answer = appAnswer(request, url, env, ctx);
|
|
152
156
|
if (answer) return answer;
|
|
153
157
|
// The build's lists (what is Planlagt) and the apps' files (what the cookie scan visits) are the Worker's own.
|
|
@@ -176,10 +180,11 @@ export default {
|
|
|
176
180
|
// The crons in wrangler.jsonc: each minute, whether the site has been built with a save (packages/editor/worker/push.js); each hour,
|
|
177
181
|
// the rest (also the answers in the consent log older than two years deleted).
|
|
178
182
|
async scheduled(controller, env, ctx) {
|
|
179
|
-
if (controller.cron === EACH_MINUTE) return ctx.waitUntil(waitForBuilds(env));
|
|
183
|
+
if (controller.cron === EACH_MINUTE) return ctx.waitUntil(Promise.allSettled([waitForBuilds(env), watchUpdate(env)]));
|
|
180
184
|
ctx.waitUntil(
|
|
181
185
|
Promise.all([
|
|
182
186
|
publishScheduled(env),
|
|
187
|
+
checkForUpdate(env),
|
|
183
188
|
forgetOldConsents(env),
|
|
184
189
|
...Object.entries(installed).map(([id, app]) => app.scheduled?.(env, ctx, tools(id, ctx))),
|
|
185
190
|
]),
|