@cogenta/cli 0.3.0 → 0.6.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/CHANGELOG.md +3856 -0
- package/dist/admin-assets/assets/index-CxZHGwVA.css +1 -0
- package/dist/admin-assets/assets/index-fYXyHpn8.js +1090 -0
- package/dist/admin-assets/assets/vips-_dmTUXFO.wasm +0 -0
- package/dist/admin-assets/assets/vips-es6-DrQTTS8Q.js +7 -0
- package/dist/admin-assets/branding/logo-cogenta-dark.png +0 -0
- package/dist/admin-assets/branding/logo-cogenta-icon.png +0 -0
- package/dist/admin-assets/branding/logo-cogenta-light.png +0 -0
- package/dist/admin-assets/branding/logo-cogenta-small.png +0 -0
- package/dist/admin-assets/branding/logo-cogenta-transparent.png +0 -0
- package/dist/admin-assets/branding/logo-cogenta.png +0 -0
- package/dist/admin-assets/favicon.png +0 -0
- package/dist/admin-assets/fonts/ibm-plex-mono-400.woff2 +0 -0
- package/dist/admin-assets/fonts/ibm-plex-mono-500.woff2 +0 -0
- package/dist/admin-assets/fonts/ibm-plex-mono-600.woff2 +0 -0
- package/dist/admin-assets/fonts/ibm-plex-mono-700.woff2 +0 -0
- package/dist/admin-assets/fonts/ibm-plex-sans-var.woff2 +0 -0
- package/dist/admin-assets/fonts/jetbrains-mono-var.woff2 +0 -0
- package/dist/admin-assets/fonts/space-grotesk-var.woff2 +0 -0
- package/dist/admin-assets/index.html +3 -2
- package/dist/bin.js +6 -0
- package/dist/bin.js.map +1 -1
- package/dist/commands/admin-assets.d.ts +1 -0
- package/dist/commands/admin-assets.d.ts.map +1 -1
- package/dist/commands/admin-assets.js +19 -1
- package/dist/commands/admin-assets.js.map +1 -1
- package/dist/commands/agent-runtime.d.ts +151 -0
- package/dist/commands/agent-runtime.d.ts.map +1 -0
- package/dist/commands/agent-runtime.js +519 -0
- package/dist/commands/agent-runtime.js.map +1 -0
- package/dist/commands/assistant.d.ts +89 -3
- package/dist/commands/assistant.d.ts.map +1 -1
- package/dist/commands/assistant.js +206 -39
- package/dist/commands/assistant.js.map +1 -1
- package/dist/commands/audit-integrity-alert.d.ts +23 -0
- package/dist/commands/audit-integrity-alert.d.ts.map +1 -0
- package/dist/commands/audit-integrity-alert.js +33 -0
- package/dist/commands/audit-integrity-alert.js.map +1 -0
- package/dist/commands/backup.d.ts +78 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +238 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/channels.d.ts +47 -0
- package/dist/commands/channels.d.ts.map +1 -0
- package/dist/commands/channels.js +277 -0
- package/dist/commands/channels.js.map +1 -0
- package/dist/commands/default-logo.d.ts +27 -0
- package/dist/commands/default-logo.d.ts.map +1 -0
- package/dist/commands/default-logo.js +30 -0
- package/dist/commands/default-logo.js.map +1 -0
- package/dist/commands/doctor.d.ts +5 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +74 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/export.d.ts +22 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +182 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/forms-page.d.ts +75 -0
- package/dist/commands/forms-page.d.ts.map +1 -0
- package/dist/commands/forms-page.js +191 -0
- package/dist/commands/forms-page.js.map +1 -0
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +13 -1
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/mcp.d.ts +35 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +277 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/roles.d.ts +22 -0
- package/dist/commands/roles.d.ts.map +1 -0
- package/dist/commands/roles.js +79 -0
- package/dist/commands/roles.js.map +1 -0
- package/dist/commands/search-page.d.ts +15 -0
- package/dist/commands/search-page.d.ts.map +1 -1
- package/dist/commands/search-page.js +22 -16
- package/dist/commands/search-page.js.map +1 -1
- package/dist/commands/seo.d.ts +92 -4
- package/dist/commands/seo.d.ts.map +1 -1
- package/dist/commands/seo.js +168 -4
- package/dist/commands/seo.js.map +1 -1
- package/dist/commands/serve.d.ts +489 -6
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +3883 -164
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/site-plan.d.ts +27 -1
- package/dist/commands/site-plan.d.ts.map +1 -1
- package/dist/commands/site-plan.js +71 -4
- package/dist/commands/site-plan.js.map +1 -1
- package/dist/commands/term-archive-page.d.ts +94 -0
- package/dist/commands/term-archive-page.d.ts.map +1 -0
- package/dist/commands/term-archive-page.js +195 -0
- package/dist/commands/term-archive-page.js.map +1 -0
- package/dist/commands/theme-css.d.ts +22 -7
- package/dist/commands/theme-css.d.ts.map +1 -1
- package/dist/commands/theme-css.js +33 -8
- package/dist/commands/theme-css.js.map +1 -1
- package/dist/commands/theme-registry.d.ts +94 -0
- package/dist/commands/theme-registry.d.ts.map +1 -0
- package/dist/commands/theme-registry.js +130 -0
- package/dist/commands/theme-registry.js.map +1 -0
- package/dist/commands/theme-render.d.ts +360 -2
- package/dist/commands/theme-render.d.ts.map +1 -1
- package/dist/commands/theme-render.js +984 -29
- package/dist/commands/theme-render.js.map +1 -1
- package/dist/commands/theme-wiring.d.ts +107 -0
- package/dist/commands/theme-wiring.d.ts.map +1 -0
- package/dist/commands/theme-wiring.js +295 -0
- package/dist/commands/theme-wiring.js.map +1 -0
- package/dist/commands/tools.d.ts +71 -0
- package/dist/commands/tools.d.ts.map +1 -0
- package/dist/commands/tools.js +330 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commands/update.d.ts +25 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +193 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/users.d.ts.map +1 -1
- package/dist/commands/users.js +6 -36
- package/dist/commands/users.js.map +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +146 -4
- package/dist/index.js.map +1 -1
- package/dist/invite-mail.d.ts +39 -0
- package/dist/invite-mail.d.ts.map +1 -0
- package/dist/invite-mail.js +39 -0
- package/dist/invite-mail.js.map +1 -0
- package/dist/reset-mail.d.ts +39 -0
- package/dist/reset-mail.d.ts.map +1 -0
- package/dist/reset-mail.js +45 -0
- package/dist/reset-mail.js.map +1 -0
- package/dist/update/apply.d.ts +54 -0
- package/dist/update/apply.d.ts.map +1 -0
- package/dist/update/apply.js +77 -0
- package/dist/update/apply.js.map +1 -0
- package/dist/update/changelog-risk.d.ts +20 -0
- package/dist/update/changelog-risk.d.ts.map +1 -0
- package/dist/update/changelog-risk.js +55 -0
- package/dist/update/changelog-risk.js.map +1 -0
- package/dist/update/check.d.ts +60 -0
- package/dist/update/check.d.ts.map +1 -0
- package/dist/update/check.js +56 -0
- package/dist/update/check.js.map +1 -0
- package/dist/update/contract-risk.d.ts +55 -0
- package/dist/update/contract-risk.d.ts.map +1 -0
- package/dist/update/contract-risk.js +75 -0
- package/dist/update/contract-risk.js.map +1 -0
- package/dist/update/history.d.ts +30 -0
- package/dist/update/history.d.ts.map +1 -0
- package/dist/update/history.js +38 -0
- package/dist/update/history.js.map +1 -0
- package/dist/update/index.d.ts +28 -0
- package/dist/update/index.d.ts.map +1 -0
- package/dist/update/index.js +11 -0
- package/dist/update/index.js.map +1 -0
- package/dist/update/list-restore-points.d.ts +20 -0
- package/dist/update/list-restore-points.d.ts.map +1 -0
- package/dist/update/list-restore-points.js +35 -0
- package/dist/update/list-restore-points.js.map +1 -0
- package/dist/update/npm-registry.d.ts +11 -0
- package/dist/update/npm-registry.d.ts.map +1 -0
- package/dist/update/npm-registry.js +74 -0
- package/dist/update/npm-registry.js.map +1 -0
- package/dist/update/restore-point.d.ts +26 -0
- package/dist/update/restore-point.d.ts.map +1 -0
- package/dist/update/restore-point.js +23 -0
- package/dist/update/restore-point.js.map +1 -0
- package/dist/update/tar.d.ts +27 -0
- package/dist/update/tar.d.ts.map +1 -0
- package/dist/update/tar.js +56 -0
- package/dist/update/tar.js.map +1 -0
- package/dist/update/version-compare.d.ts +17 -0
- package/dist/update/version-compare.d.ts.map +1 -0
- package/dist/update/version-compare.js +42 -0
- package/dist/update/version-compare.js.map +1 -0
- package/dist/version.d.ts +13 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +18 -0
- package/dist/version.js.map +1 -0
- package/package.json +33 -13
- package/dist/admin-assets/assets/index-Buwdj1V2.js +0 -71
- package/dist/admin-assets/assets/index-Csef0SiA.css +0 -1
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { variantKeyFor } from '@cogenta/api';
|
|
3
|
+
import { createEmailAdapter } from '@cogenta/channels';
|
|
4
|
+
import { CogentaError, } from '@cogenta/core';
|
|
5
|
+
import { checkLinks, createContentStore, reindexAll, } from '@cogenta/schema';
|
|
6
|
+
import { reindexAllVectors } from './assistant.js';
|
|
7
|
+
/**
|
|
8
|
+
* The seven maintenance tools (fiche 24 task 3): what they do, and the run
|
|
9
|
+
* bookkeeping the admin polls while they run.
|
|
10
|
+
*
|
|
11
|
+
* Every tool goes through the queue, never inline in the request that
|
|
12
|
+
* triggers it — "un traitement long ne doit pas être une requête HTTP qui
|
|
13
|
+
* expire" is a literal acceptance criterion of the lot, and the queue
|
|
14
|
+
* already exists with a degraded (database) tier that needs no Redis (R1).
|
|
15
|
+
* A run's bookkeeping is a bounded, in-process ring — durability across a
|
|
16
|
+
* restart is not the point, seeing progress while the process is up is.
|
|
17
|
+
*/
|
|
18
|
+
export const TOOL_DEFINITIONS = [
|
|
19
|
+
{
|
|
20
|
+
id: 'purge-cache',
|
|
21
|
+
labelKey: 'tools.purgeCache',
|
|
22
|
+
reversible: true,
|
|
23
|
+
estimatedDurationKey: 'tools.durationSeconds',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 'reindex-search',
|
|
27
|
+
labelKey: 'tools.reindexSearch',
|
|
28
|
+
reversible: true,
|
|
29
|
+
estimatedDurationKey: 'tools.durationMinutes',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'reindex-vectors',
|
|
33
|
+
labelKey: 'tools.reindexVectors',
|
|
34
|
+
reversible: true,
|
|
35
|
+
estimatedDurationKey: 'tools.durationMinutes',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'regenerate-images',
|
|
39
|
+
labelKey: 'tools.regenerateImages',
|
|
40
|
+
reversible: true,
|
|
41
|
+
estimatedDurationKey: 'tools.durationMinutes',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
// Internal checking never leaves the site; external does, and the
|
|
45
|
+
// per-run `{ external: true }` request flag (default off) is what keeps
|
|
46
|
+
// that opt-in (R1) — this definition itself carries no such switch.
|
|
47
|
+
id: 'check-links',
|
|
48
|
+
labelKey: 'tools.checkLinks',
|
|
49
|
+
reversible: true,
|
|
50
|
+
estimatedDurationKey: 'tools.durationMinutes',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'test-email',
|
|
54
|
+
labelKey: 'tools.testEmail',
|
|
55
|
+
reversible: true,
|
|
56
|
+
estimatedDurationKey: 'tools.durationSeconds',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'purge-trash',
|
|
60
|
+
labelKey: 'tools.purgeTrash',
|
|
61
|
+
reversible: false,
|
|
62
|
+
estimatedDurationKey: 'tools.durationSeconds',
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
function toLike(run) {
|
|
66
|
+
return {
|
|
67
|
+
id: run.id,
|
|
68
|
+
tool: run.tool,
|
|
69
|
+
status: run.status,
|
|
70
|
+
startedAt: run.startedAt,
|
|
71
|
+
finishedAt: run.finishedAt,
|
|
72
|
+
log: [...run.log],
|
|
73
|
+
error: run.error,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Wires the seven tool bodies to the queue and keeps an in-process run log.
|
|
78
|
+
*
|
|
79
|
+
* One queue job name per tool, registered once; `run()` enqueues a job
|
|
80
|
+
* carrying only the run id, and the handler looks the run up to append to
|
|
81
|
+
* its log as it goes. Nothing here assumes the queue's optimal (Redis) tier
|
|
82
|
+
* — the database tier's own test (fiche 24 § 6, "driver dégradé testé")
|
|
83
|
+
* exercises this exact path.
|
|
84
|
+
*/
|
|
85
|
+
export function createToolRunner(options) {
|
|
86
|
+
const capacity = options.capacity ?? 50;
|
|
87
|
+
const now = options.now ?? (() => new Date());
|
|
88
|
+
const newId = options.newId ?? randomUUID;
|
|
89
|
+
const runs = new Map();
|
|
90
|
+
const order = [];
|
|
91
|
+
for (const definition of TOOL_DEFINITIONS) {
|
|
92
|
+
const body = options.bodies[definition.id];
|
|
93
|
+
if (body === undefined)
|
|
94
|
+
continue;
|
|
95
|
+
options.queue.process(definition.id, async (job) => {
|
|
96
|
+
const run = runs.get(job.payload.runId);
|
|
97
|
+
if (run === undefined)
|
|
98
|
+
return;
|
|
99
|
+
run.status = 'running';
|
|
100
|
+
try {
|
|
101
|
+
await body({
|
|
102
|
+
log: (line) => run.log.push(line),
|
|
103
|
+
external: job.payload.external === true,
|
|
104
|
+
email: job.payload.email,
|
|
105
|
+
});
|
|
106
|
+
run.status = 'completed';
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
run.status = 'failed';
|
|
110
|
+
run.error = error instanceof Error ? error.message : String(error);
|
|
111
|
+
options.logger.error('maintenance tool run failed', {
|
|
112
|
+
tool: definition.id,
|
|
113
|
+
runId: run.id,
|
|
114
|
+
error: run.error,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
run.finishedAt = now().toISOString();
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
run: async (toolId, runOptions) => {
|
|
124
|
+
const id = newId();
|
|
125
|
+
const run = {
|
|
126
|
+
id,
|
|
127
|
+
tool: toolId,
|
|
128
|
+
status: 'queued',
|
|
129
|
+
startedAt: now().toISOString(),
|
|
130
|
+
finishedAt: undefined,
|
|
131
|
+
log: [],
|
|
132
|
+
error: undefined,
|
|
133
|
+
};
|
|
134
|
+
runs.set(id, run);
|
|
135
|
+
order.push(id);
|
|
136
|
+
while (order.length > capacity) {
|
|
137
|
+
const evicted = order.shift();
|
|
138
|
+
if (evicted !== undefined)
|
|
139
|
+
runs.delete(evicted);
|
|
140
|
+
}
|
|
141
|
+
await options.queue.enqueue({
|
|
142
|
+
name: toolId,
|
|
143
|
+
payload: {
|
|
144
|
+
runId: id,
|
|
145
|
+
...(runOptions.external === undefined ? {} : { external: runOptions.external }),
|
|
146
|
+
...(runOptions.email === undefined ? {} : { email: runOptions.email }),
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
// Nudge the degraded (database) queue right away instead of leaving this
|
|
150
|
+
// run to wait for the next scheduled drain — on `cogenta serve` that is
|
|
151
|
+
// `SCHEDULED_PUBLISH_TICK_MS` (60s) away, which reads as "stuck forever"
|
|
152
|
+
// for a tool the admin screen itself labels as taking mere seconds. This
|
|
153
|
+
// is fire-and-forget on purpose: the response to the caller must still
|
|
154
|
+
// return the run id immediately, never wait on the tool body itself
|
|
155
|
+
// (that would turn a long tool into the very "requête HTTP qui expire"
|
|
156
|
+
// this whole queue exists to avoid). The periodic tick remains the real
|
|
157
|
+
// drain — for jobs left behind by a crash, and for every backend that
|
|
158
|
+
// isn't the single in-process caller of `run()`.
|
|
159
|
+
options.queue.tick().catch((error) => {
|
|
160
|
+
options.logger.error('immediate tool queue tick failed', {
|
|
161
|
+
tool: toolId,
|
|
162
|
+
runId: id,
|
|
163
|
+
error: error instanceof Error ? error.message : String(error),
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
return id;
|
|
167
|
+
},
|
|
168
|
+
getRun: (id) => {
|
|
169
|
+
const run = runs.get(id);
|
|
170
|
+
return run === undefined ? null : toLike(run);
|
|
171
|
+
},
|
|
172
|
+
listRuns: () => [...order].reverse().map((id) => toLike(runs.get(id))),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/** A fresh, undecorated store per collection — reindexing and link-checking only ever read, so none of the write-path wrapping (`withSearchIndexing`, the read-only guard, …) matters here. */
|
|
176
|
+
function storeForFactory(db, collections) {
|
|
177
|
+
const cache = new Map();
|
|
178
|
+
return (collection) => {
|
|
179
|
+
const existing = cache.get(collection.name);
|
|
180
|
+
if (existing !== undefined)
|
|
181
|
+
return existing;
|
|
182
|
+
const created = createContentStore({ db, collection, siblings: collections });
|
|
183
|
+
cache.set(collection.name, created);
|
|
184
|
+
return created;
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* The seven real tool implementations (fiche 24 task 3), each honest about
|
|
189
|
+
* what it needs and what it does when that is absent — no tool ever throws
|
|
190
|
+
* because a driver is missing; it logs why and finishes.
|
|
191
|
+
*/
|
|
192
|
+
export function buildToolBodies(options) {
|
|
193
|
+
const storeFor = storeForFactory(options.db, options.collections);
|
|
194
|
+
return {
|
|
195
|
+
'purge-cache': async (ctx) => {
|
|
196
|
+
if (options.cache === null) {
|
|
197
|
+
ctx.log('No cache driver is configured on this site — nothing to purge.');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
await options.cache.clear();
|
|
201
|
+
ctx.log('Cache cleared.');
|
|
202
|
+
},
|
|
203
|
+
'reindex-search': async (ctx) => {
|
|
204
|
+
let total = 0;
|
|
205
|
+
for (const collection of options.collections) {
|
|
206
|
+
const store = storeFor(collection);
|
|
207
|
+
const count = await reindexAll(store, { collection, index: options.searchIndex });
|
|
208
|
+
total += count;
|
|
209
|
+
ctx.log(`${collection.name}: ${count} entr(y/ies) reindexed.`);
|
|
210
|
+
}
|
|
211
|
+
ctx.log(`Done. ${total} entr(y/ies) reindexed across ${options.collections.length} collection(s).`);
|
|
212
|
+
},
|
|
213
|
+
'reindex-vectors': async (ctx) => {
|
|
214
|
+
if (options.vectors === null) {
|
|
215
|
+
ctx.log('No embeddings provider is configured on this site — nothing to reindex.');
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
let total = 0;
|
|
219
|
+
for (const collection of options.collections) {
|
|
220
|
+
const store = storeFor(collection);
|
|
221
|
+
const count = await reindexAllVectors(store, { ...options.vectors, collection });
|
|
222
|
+
total += count;
|
|
223
|
+
ctx.log(`${collection.name}: ${count} entr(y/ies) reindexed.`);
|
|
224
|
+
}
|
|
225
|
+
ctx.log(`Done. ${total} entr(y/ies) reindexed.`);
|
|
226
|
+
},
|
|
227
|
+
'regenerate-images': async (ctx) => {
|
|
228
|
+
if (options.images === null) {
|
|
229
|
+
ctx.log('No image driver is available on this host — nothing to regenerate.');
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const images = options.images;
|
|
233
|
+
let processed = 0;
|
|
234
|
+
let cursor;
|
|
235
|
+
for (;;) {
|
|
236
|
+
const page = await options.mediaStore.list({
|
|
237
|
+
kind: 'image',
|
|
238
|
+
limit: 50,
|
|
239
|
+
...(cursor ? { cursor } : {}),
|
|
240
|
+
});
|
|
241
|
+
for (const asset of page.items) {
|
|
242
|
+
if (asset.width === null || asset.height === null)
|
|
243
|
+
continue;
|
|
244
|
+
try {
|
|
245
|
+
const stream = await options.storage.get(asset.storageKey);
|
|
246
|
+
const chunks = [];
|
|
247
|
+
for await (const chunk of stream)
|
|
248
|
+
chunks.push(chunk);
|
|
249
|
+
const bytes = Buffer.concat(chunks);
|
|
250
|
+
const variants = await images.variants(bytes, {
|
|
251
|
+
width: asset.width,
|
|
252
|
+
height: asset.height,
|
|
253
|
+
});
|
|
254
|
+
for (const variant of variants) {
|
|
255
|
+
await options.storage.put(variantKeyFor(asset.id, variant.name), Buffer.from(variant.bytes), {
|
|
256
|
+
contentType: variant.contentType,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
processed += 1;
|
|
260
|
+
ctx.log(`${asset.filename}: ${variants.length} variant(s) regenerated.`);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
ctx.log(`${asset.filename}: failed — ${error instanceof Error ? error.message : String(error)}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (!page.hasMore || page.nextCursor === null)
|
|
267
|
+
break;
|
|
268
|
+
cursor = page.nextCursor;
|
|
269
|
+
}
|
|
270
|
+
ctx.log(`Done. ${processed} image(s) processed.`);
|
|
271
|
+
},
|
|
272
|
+
'check-links': async (ctx) => {
|
|
273
|
+
const report = await checkLinks({
|
|
274
|
+
collections: options.collections,
|
|
275
|
+
storeFor,
|
|
276
|
+
locales: options.locales,
|
|
277
|
+
defaultLocale: options.defaultLocale,
|
|
278
|
+
...(ctx.external ? { checkExternal: true } : {}),
|
|
279
|
+
});
|
|
280
|
+
ctx.log(`Checked ${report.checkedLinks} link(s) across ${report.checkedEntries} published entries.`);
|
|
281
|
+
if (report.skippedExternal > 0) {
|
|
282
|
+
ctx.log(`${report.skippedExternal} external link(s) were not followed (external checking is off).`);
|
|
283
|
+
}
|
|
284
|
+
if (report.broken.length === 0) {
|
|
285
|
+
ctx.log('Nothing broken.');
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
for (const broken of report.broken) {
|
|
289
|
+
const target = broken.link.kind === 'url'
|
|
290
|
+
? broken.link.href
|
|
291
|
+
: `${broken.link.collection}/${broken.link.id}`;
|
|
292
|
+
ctx.log(`${broken.collection}/${broken.entryId} [${broken.locale}] ${broken.at} → ${target}: ${broken.reason}`);
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
'test-email': async (ctx) => {
|
|
296
|
+
if (ctx.email === undefined) {
|
|
297
|
+
ctx.log('No destination address was given.');
|
|
298
|
+
throw new CogentaError({
|
|
299
|
+
code: 'MAINT_TOOL_INPUT_INVALID',
|
|
300
|
+
message: 'The "test email" tool needs a destination address.',
|
|
301
|
+
hint: 'Send { "email": "you@example.com" } in the run request body.',
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
const adapter = createEmailAdapter({ transport: options.emailTransport });
|
|
305
|
+
try {
|
|
306
|
+
await adapter.send({ id: ctx.email }, {
|
|
307
|
+
level: 'notification',
|
|
308
|
+
text: `${options.siteName} — this is a test message from the admin's "Tools" screen. If it reached you, outgoing mail works.`,
|
|
309
|
+
});
|
|
310
|
+
ctx.log(`Sent to ${ctx.email}.`);
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
ctx.log(`Transport error: ${error instanceof Error ? error.message : String(error)}`);
|
|
314
|
+
throw error;
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
'purge-trash': async (ctx) => {
|
|
318
|
+
let total = 0;
|
|
319
|
+
for (const collection of options.collections) {
|
|
320
|
+
const store = storeFor(collection);
|
|
321
|
+
const report = await store.purgeExpired();
|
|
322
|
+
if (report.purged > 0)
|
|
323
|
+
ctx.log(`${collection.name}: ${report.purged} entr(y/ies) purged.`);
|
|
324
|
+
total += report.purged;
|
|
325
|
+
}
|
|
326
|
+
ctx.log(`Done. ${total} entr(y/ies) purged in total.`);
|
|
327
|
+
},
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/commands/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Logger } from '@cogenta/core';
|
|
2
|
+
import type { Output, Writer } from '../output.js';
|
|
3
|
+
import { type RunPackageInstall } from '../update/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* `cogenta update` (L22 task 9) — the CLI half of the same logic the admin
|
|
6
|
+
* screen's "Update now" button calls (`@cogenta/api`'s `createUpdateRouter`,
|
|
7
|
+
* wired in `serve.ts`). Both go through exactly `checkForUpdates`/
|
|
8
|
+
* `applyUpdate` from `../update/index.js`, never a second implementation.
|
|
9
|
+
*/
|
|
10
|
+
export type UpdateSubcommand = 'check' | 'apply' | 'history';
|
|
11
|
+
export interface UpdateOptions {
|
|
12
|
+
readonly subcommand: string | undefined;
|
|
13
|
+
readonly cwd?: string;
|
|
14
|
+
readonly env?: Record<string, string | undefined>;
|
|
15
|
+
readonly logger?: Logger;
|
|
16
|
+
readonly out: Output;
|
|
17
|
+
readonly stderr: Writer;
|
|
18
|
+
readonly confirmBreaking?: boolean;
|
|
19
|
+
readonly dir?: string;
|
|
20
|
+
readonly fetchImpl?: typeof fetch;
|
|
21
|
+
/** Test seam only — real `cogenta update apply` always uses the real `npm install`. */
|
|
22
|
+
readonly runInstall?: RunPackageInstall;
|
|
23
|
+
}
|
|
24
|
+
export declare function runUpdate(options: UpdateOptions): Promise<number>;
|
|
25
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgD,KAAK,MAAM,EAAE,MAAM,eAAe,CAAA;AACzF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAML,KAAK,iBAAiB,EAMvB,MAAM,oBAAoB,CAAA;AAI3B;;;;;GAKG;AAEH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;AAE5D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACjC,uFAAuF;IACvF,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAA;CACxC;AAmED,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA8IvE"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { classifyAuditActor, createAuditLog, ensureAuthTables } from '@cogenta/auth';
|
|
3
|
+
import { createLogger, getCoreVersion, isCogentaError } from '@cogenta/core';
|
|
4
|
+
import { applyUpdate, checkForUpdates, listRestorePoints, listUpdateHistory, recordUpdateHistory, UPDATE_APPLIED_ACTION, UPDATE_APPLY_FAILED_ACTION, UPDATE_CHECKED_ACTION, } from '../update/index.js';
|
|
5
|
+
import { getCliVersion } from '../version.js';
|
|
6
|
+
import { defaultBackupDir, openSite } from './backup.js';
|
|
7
|
+
const UPDATE_USAGE = `Usage
|
|
8
|
+
cogenta update check Compare the installed version against npm
|
|
9
|
+
cogenta update apply Apply an available update (creates a restore point first)
|
|
10
|
+
cogenta update history Show past checks, applies and the restore points they took
|
|
11
|
+
|
|
12
|
+
Options
|
|
13
|
+
--confirm-breaking apply: proceed even though a contract-risk warning was found
|
|
14
|
+
--dir <path> Where restore points are written/read (default .cogenta/backups)
|
|
15
|
+
`;
|
|
16
|
+
function installedPackages() {
|
|
17
|
+
return [
|
|
18
|
+
{ name: '@cogenta/core', installed: getCoreVersion() },
|
|
19
|
+
{ name: '@cogenta/cli', installed: getCliVersion() },
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
function printReport(report, out) {
|
|
23
|
+
out.heading('Update check');
|
|
24
|
+
out.line(`Checked at ${report.checkedAt}`);
|
|
25
|
+
for (const pkg of report.packages) {
|
|
26
|
+
if (pkg.checkError !== undefined) {
|
|
27
|
+
out.line(`${pkg.name}: installed ${pkg.installed} — could not check npm: ${pkg.checkError}`);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (!pkg.updateAvailable) {
|
|
31
|
+
out.line(`${pkg.name}: ${pkg.installed} — up to date`);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
out.line(`${pkg.name}: ${pkg.installed} -> ${pkg.latest} (${pkg.bump})`);
|
|
35
|
+
if (pkg.contractRisk === null)
|
|
36
|
+
continue;
|
|
37
|
+
if (!pkg.contractRisk.available) {
|
|
38
|
+
out.line(` contract risk: could not be determined — ${pkg.contractRisk.reason ?? 'unknown reason'}`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (pkg.contractRisk.warnings.length === 0) {
|
|
42
|
+
out.line(' contract risk: none of the scanned changelog entries mention a frozen contract');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
out.line(' contract risk: possible — a scan of the changelog found a mention of a frozen contract (review before applying):');
|
|
46
|
+
for (const warning of pkg.contractRisk.warnings) {
|
|
47
|
+
out.line(` ${warning.version}: ${warning.excerpt}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!report.updateAvailable)
|
|
52
|
+
out.line('Everything is up to date.');
|
|
53
|
+
}
|
|
54
|
+
async function withAuditLog(options, logger, run) {
|
|
55
|
+
const { db, dispose } = await openSite(options, logger);
|
|
56
|
+
try {
|
|
57
|
+
await ensureAuthTables(db);
|
|
58
|
+
return await run(createAuditLog(db));
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
await dispose();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export async function runUpdate(options) {
|
|
65
|
+
const { out, stderr } = options;
|
|
66
|
+
const logger = options.logger ?? createLogger({ level: 'silent' });
|
|
67
|
+
const cwd = options.cwd ?? process.cwd();
|
|
68
|
+
const dir = options.dir ?? defaultBackupDir(cwd);
|
|
69
|
+
if (options.subcommand === undefined) {
|
|
70
|
+
stderr(`cogenta update needs a subcommand.\n\n${UPDATE_USAGE}`);
|
|
71
|
+
return 2;
|
|
72
|
+
}
|
|
73
|
+
if (options.subcommand !== 'check' &&
|
|
74
|
+
options.subcommand !== 'apply' &&
|
|
75
|
+
options.subcommand !== 'history') {
|
|
76
|
+
stderr(`Unknown subcommand "${options.subcommand}".\n\n${UPDATE_USAGE}`);
|
|
77
|
+
return 2;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
if (options.subcommand === 'history') {
|
|
81
|
+
const [history, restorePoints] = await withAuditLog(options, logger, async (auditLog) => [
|
|
82
|
+
await listUpdateHistory(auditLog),
|
|
83
|
+
await listRestorePoints(dir),
|
|
84
|
+
]);
|
|
85
|
+
out.heading('Update history');
|
|
86
|
+
if (history.length === 0)
|
|
87
|
+
out.line('No update has been checked or applied yet.');
|
|
88
|
+
for (const entry of history) {
|
|
89
|
+
const actor = entry.actorId ?? `(${classifyAuditActor(entry)})`;
|
|
90
|
+
out.line(`${entry.at} ${entry.action} by ${actor}`);
|
|
91
|
+
}
|
|
92
|
+
out.heading('Restore points');
|
|
93
|
+
if (restorePoints.length === 0)
|
|
94
|
+
out.line('No restore point exists yet.');
|
|
95
|
+
for (const point of restorePoints) {
|
|
96
|
+
out.line(`${point.createdAt} ${point.path} ${point.tables} tables, ${point.rows} rows${point.triggeredByUpdate ? ' (taken automatically before an update)' : ''}`);
|
|
97
|
+
}
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
if (options.subcommand === 'check') {
|
|
101
|
+
const report = await checkForUpdates({
|
|
102
|
+
packages: installedPackages(),
|
|
103
|
+
...(options.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
104
|
+
});
|
|
105
|
+
printReport(report, out);
|
|
106
|
+
await withAuditLog(options, logger, (auditLog) => recordUpdateHistory(auditLog, {
|
|
107
|
+
actorId: null,
|
|
108
|
+
actorRoles: ['admin'],
|
|
109
|
+
action: UPDATE_CHECKED_ACTION,
|
|
110
|
+
diff: {
|
|
111
|
+
packages: report.packages.map((pkg) => ({
|
|
112
|
+
name: pkg.name,
|
|
113
|
+
installed: pkg.installed,
|
|
114
|
+
latest: pkg.latest,
|
|
115
|
+
bump: pkg.bump,
|
|
116
|
+
})),
|
|
117
|
+
},
|
|
118
|
+
})).catch((error) => {
|
|
119
|
+
logger.error('update history record failed', { error: String(error) });
|
|
120
|
+
});
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
// apply
|
|
124
|
+
let result;
|
|
125
|
+
try {
|
|
126
|
+
result = await applyUpdate({
|
|
127
|
+
cwd,
|
|
128
|
+
...(options.env === undefined ? {} : { env: options.env }),
|
|
129
|
+
logger,
|
|
130
|
+
packages: installedPackages(),
|
|
131
|
+
confirmBreakingChange: options.confirmBreaking === true,
|
|
132
|
+
backupDir: dir,
|
|
133
|
+
...(options.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
134
|
+
...(options.runInstall === undefined ? {} : { runInstall: options.runInstall }),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
await withAuditLog(options, logger, (auditLog) => recordUpdateHistory(auditLog, {
|
|
139
|
+
actorId: null,
|
|
140
|
+
actorRoles: ['admin'],
|
|
141
|
+
action: UPDATE_APPLY_FAILED_ACTION,
|
|
142
|
+
diff: { error: isCogentaError(error) ? error.message : String(error) },
|
|
143
|
+
})).catch(() => undefined);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
if (result.kind === 'up-to-date') {
|
|
147
|
+
out.heading('Nothing to update');
|
|
148
|
+
out.line('Every checked package is already at the latest version.');
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
if (result.kind === 'confirmation-required') {
|
|
152
|
+
out.heading('Update refused — contract risk found');
|
|
153
|
+
out.line('The following packages have an update available whose changelog mentions a frozen contract. Review before proceeding:');
|
|
154
|
+
for (const pkg of result.risky) {
|
|
155
|
+
out.line(`${pkg.name}: ${pkg.installed} -> ${pkg.latest}`);
|
|
156
|
+
for (const warning of pkg.contractRisk?.warnings ?? []) {
|
|
157
|
+
out.line(` ${warning.version}: ${warning.excerpt}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
out.line('Re-run with --confirm-breaking once you have reviewed this, to proceed anyway.');
|
|
161
|
+
return 1;
|
|
162
|
+
}
|
|
163
|
+
out.heading('Update applied');
|
|
164
|
+
out.line(`Restore point: ${result.restorePoint.path}`);
|
|
165
|
+
for (const pkg of result.installed)
|
|
166
|
+
out.line(`${pkg.name} -> ${pkg.version}`);
|
|
167
|
+
out.line('Restart cogenta for the new version to take effect.');
|
|
168
|
+
await withAuditLog(options, logger, (auditLog) => recordUpdateHistory(auditLog, {
|
|
169
|
+
actorId: null,
|
|
170
|
+
actorRoles: ['admin'],
|
|
171
|
+
action: UPDATE_APPLIED_ACTION,
|
|
172
|
+
diff: {
|
|
173
|
+
installed: result.installed,
|
|
174
|
+
restorePoint: result.restorePoint.path,
|
|
175
|
+
},
|
|
176
|
+
})).catch((error) => {
|
|
177
|
+
logger.error('update history record failed', { error: String(error) });
|
|
178
|
+
});
|
|
179
|
+
return 0;
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
if (isCogentaError(error)) {
|
|
183
|
+
stderr(`${error.code}: ${error.message}\n`);
|
|
184
|
+
if (error.hint !== undefined)
|
|
185
|
+
stderr(`${error.hint}\n`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
stderr(`${error instanceof Error ? error.stack : String(error)}\n`);
|
|
189
|
+
}
|
|
190
|
+
return 1;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACpF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAe,MAAM,eAAe,CAAA;AAEzF,OAAO,EAEL,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EAEjB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,GAEtB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAyBxD,MAAM,YAAY,GAAG;;;;;;;;CAQpB,CAAA;AAED,SAAS,iBAAiB;IACxB,OAAO;QACL,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE;QACtD,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE;KACrD,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAyB,EAAE,GAAW;IACzD,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IAC3B,GAAG,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;IAC1C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAClC,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACjC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,eAAe,GAAG,CAAC,SAAS,2BAA2B,GAAG,CAAC,UAAU,EAAE,CAAC,CAAA;YAC5F,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;YACzB,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,SAAS,eAAe,CAAC,CAAA;YACtD,SAAQ;QACV,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,SAAS,OAAO,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,CAAA;QACxE,IAAI,GAAG,CAAC,YAAY,KAAK,IAAI;YAAE,SAAQ;QACvC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC;YAChC,GAAG,CAAC,IAAI,CACN,8CAA8C,GAAG,CAAC,YAAY,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAC5F,CAAA;YACD,SAAQ;QACV,CAAC;QACD,IAAI,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,IAAI,CAAC,kFAAkF,CAAC,CAAA;QAC9F,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CACN,oHAAoH,CACrH,CAAA;YACD,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;gBAChD,GAAG,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;YACxD,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,eAAe;QAAE,GAAG,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;AACpE,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,OAAqF,EACrF,MAAc,EACd,GAAgE;IAEhE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACvD,IAAI,CAAC;QACH,MAAM,gBAAgB,CAAC,EAAE,CAAC,CAAA;QAC1B,OAAO,MAAM,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAA;IACtC,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAA;IACjB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAsB;IACpD,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;IAClE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACxC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAEhD,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,CAAC,yCAAyC,YAAY,EAAE,CAAC,CAAA;QAC/D,OAAO,CAAC,CAAA;IACV,CAAC;IACD,IACE,OAAO,CAAC,UAAU,KAAK,OAAO;QAC9B,OAAO,CAAC,UAAU,KAAK,OAAO;QAC9B,OAAO,CAAC,UAAU,KAAK,SAAS,EAChC,CAAC;QACD,MAAM,CAAC,uBAAuB,OAAO,CAAC,UAAU,SAAS,YAAY,EAAE,CAAC,CAAA;QACxE,OAAO,CAAC,CAAA;IACV,CAAC;IAED,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACrC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC;gBACvF,MAAM,iBAAiB,CAAC,QAAQ,CAAC;gBACjC,MAAM,iBAAiB,CAAC,GAAG,CAAC;aAC7B,CAAC,CAAA;YACF,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;YAC7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAA;YAChF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAA;gBAC/D,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,MAAM,QAAQ,KAAK,EAAE,CAAC,CAAA;YACvD,CAAC;YACD,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;YAC7B,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAA;YACxE,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;gBAClC,GAAG,CAAC,IAAI,CACN,GAAG,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,IAAI,QAAQ,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,0CAA0C,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5J,CAAA;YACH,CAAC;YACD,OAAO,CAAC,CAAA;QACV,CAAC;QAED,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,QAAQ,EAAE,iBAAiB,EAAE;gBAC7B,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;aAC7E,CAAC,CAAA;YACF,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;YACxB,MAAM,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC/C,mBAAmB,CAAC,QAAQ,EAAE;gBAC5B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,CAAC,OAAO,CAAC;gBACrB,MAAM,EAAE,qBAAqB;gBAC7B,IAAI,EAAE;oBACJ,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;wBACtC,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,SAAS,EAAE,GAAG,CAAC,SAAS;wBACxB,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;qBACf,CAAC,CAAC;iBACJ;aACF,CAAC,CACH,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBACzB,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YACxE,CAAC,CAAC,CAAA;YACF,OAAO,CAAC,CAAA;QACV,CAAC;QAED,QAAQ;QACR,IAAI,MAAyB,CAAA;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,WAAW,CAAC;gBACzB,GAAG;gBACH,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;gBAC1D,MAAM;gBACN,QAAQ,EAAE,iBAAiB,EAAE;gBAC7B,qBAAqB,EAAE,OAAO,CAAC,eAAe,KAAK,IAAI;gBACvD,SAAS,EAAE,GAAG;gBACd,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC5E,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;aAChF,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC/C,mBAAmB,CAAC,QAAQ,EAAE;gBAC5B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,CAAC,OAAO,CAAC;gBACrB,MAAM,EAAE,0BAA0B;gBAClC,IAAI,EAAE,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;aACvE,CAAC,CACH,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;YACxB,MAAM,KAAK,CAAA;QACb,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;YAChC,GAAG,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAA;YACnE,OAAO,CAAC,CAAA;QACV,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;YAC5C,GAAG,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAA;YACnD,GAAG,CAAC,IAAI,CACN,uHAAuH,CACxH,CAAA;YACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBAC/B,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,SAAS,OAAO,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;gBAC1D,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,YAAY,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;oBACvD,GAAG,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;gBACtD,CAAC;YACH,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAA;YAC1F,OAAO,CAAC,CAAA;QACV,CAAC;QAED,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;QAC7B,GAAG,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAA;QACtD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;QAC7E,GAAG,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAA;QAE/D,MAAM,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC/C,mBAAmB,CAAC,QAAQ,EAAE;YAC5B,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,CAAC,OAAO,CAAC;YACrB,MAAM,EAAE,qBAAqB;YAC7B,IAAI,EAAE;gBACJ,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI;aACvC;SACF,CAAC,CACH,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACzB,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACxE,CAAC,CAAC,CAAA;QAEF,OAAO,CAAC,CAAA;IACV,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,IAAI,CAAC,CAAA;YAC3C,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;gBAAE,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,CAAA;QACzD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACrE,CAAC;QACD,OAAO,CAAC,CAAA;IACV,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/commands/users.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/commands/users.ts"],"names":[],"mappings":"AAUA,OAAO,EAKL,KAAK,MAAM,EAEZ,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAGlD,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,gBAAgB,CAAA;AAEzD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;IACxB,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAyKD;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAwErE"}
|
package/dist/commands/users.js
CHANGED
|
@@ -2,8 +2,8 @@ import { randomBytes } from 'node:crypto';
|
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import process from 'node:process';
|
|
4
4
|
import { createCredentialStore, createPasswordResetStore, createSessionStore, createUserStore, ensureAuthTables, } from '@cogenta/auth';
|
|
5
|
-
import { createEmailAdapter, createFileEmailTransport } from '@cogenta/channels';
|
|
6
5
|
import { createDatabaseRegistry, createLogger, isCogentaError, loadConfig, } from '@cogenta/core';
|
|
6
|
+
import { sendResetMail as sendResetMailShared } from '../reset-mail.js';
|
|
7
7
|
const USAGE = `Usage
|
|
8
8
|
cogenta users create --email <email> [--roles <role,role>] [--admin]
|
|
9
9
|
cogenta users reset-password --email <email>
|
|
@@ -62,44 +62,14 @@ async function withDatabase(options, logger, use) {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* The transport is the file one, because it is the only one that exists: a
|
|
70
|
-
* real SMTP transport is a documented, deliberate gap in that package
|
|
71
|
-
* (`providers/email/transport.ts`). So this writes a real message to a real
|
|
72
|
-
* file and says exactly where, rather than pretending mail left the machine.
|
|
65
|
+
* The terminal's own wrapper around the shared `sendResetMail` (`../reset-mail.js`),
|
|
66
|
+
* which is also what `cogenta serve` calls for `POST /api/auth/forgot-password` —
|
|
67
|
+
* one function decides how the mail is worded, this only resolves *where* it
|
|
68
|
+
* is written from this command's own `--mail-dir`/`--cwd` options.
|
|
73
69
|
*/
|
|
74
70
|
async function sendResetMail(options, site, address, token, expiresAt) {
|
|
75
71
|
const directory = options.mailDir ?? resolve(options.cwd ?? process.cwd(), '.cogenta', 'mail');
|
|
76
|
-
|
|
77
|
-
transport: createFileEmailTransport({ directory }),
|
|
78
|
-
});
|
|
79
|
-
// `report` of the three fixed message levels: `notification` is one line
|
|
80
|
-
// with nowhere to put a token, and `alert` would stamp "[WARNING]" on the
|
|
81
|
-
// subject and demand an incident's `expectedAction`/`adminUrl`. None of the
|
|
82
|
-
// three was designed for transactional mail; a fourth level would change a
|
|
83
|
-
// closed union every one of the five adapters renders, for one caller.
|
|
84
|
-
await adapter.send({ id: address }, {
|
|
85
|
-
level: 'report',
|
|
86
|
-
title: `${site.name} — password reset`,
|
|
87
|
-
keyFigures: [
|
|
88
|
-
{ label: 'Valid until', value: expiresAt },
|
|
89
|
-
{ label: 'Uses left', value: '1' },
|
|
90
|
-
],
|
|
91
|
-
sections: [
|
|
92
|
-
{
|
|
93
|
-
heading: 'Your one-time token',
|
|
94
|
-
body: token,
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
heading: 'How to use it',
|
|
98
|
-
body: `Run: cogenta users reset-password --token ${token}\n\nThe token works once and expires at ${expiresAt}. If you did not ask for this, ignore this message — the token is useless without it, and asking again replaces it.`,
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
});
|
|
102
|
-
return directory;
|
|
72
|
+
return sendResetMailShared({ mailDir: directory }, site, address, token, expiresAt);
|
|
103
73
|
}
|
|
104
74
|
async function issueReset(options, logger) {
|
|
105
75
|
const { out, stderr } = options;
|