canopycms 0.0.60 → 0.0.61-int.75
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/api/__test__/mock-client.d.ts +29 -0
- package/dist/api/__test__/mock-client.d.ts.map +1 -1
- package/dist/api/__test__/mock-client.js +51 -0
- package/dist/api/__test__/mock-client.js.map +1 -1
- package/dist/api/admin-branch-health.d.ts +65 -0
- package/dist/api/admin-branch-health.d.ts.map +1 -0
- package/dist/api/admin-branch-health.js +448 -0
- package/dist/api/admin-branch-health.js.map +1 -0
- package/dist/api/admin.d.ts +136 -0
- package/dist/api/admin.d.ts.map +1 -0
- package/dist/api/admin.js +338 -0
- package/dist/api/admin.js.map +1 -0
- package/dist/api/assets.d.ts.map +1 -1
- package/dist/api/assets.js +4 -0
- package/dist/api/assets.js.map +1 -1
- package/dist/api/branch-merge.d.ts +6 -0
- package/dist/api/branch-merge.d.ts.map +1 -1
- package/dist/api/branch-merge.js +13 -3
- package/dist/api/branch-merge.js.map +1 -1
- package/dist/api/branch-status.d.ts.map +1 -1
- package/dist/api/branch-status.js +15 -5
- package/dist/api/branch-status.js.map +1 -1
- package/dist/api/branch-withdraw.d.ts +6 -0
- package/dist/api/branch-withdraw.d.ts.map +1 -1
- package/dist/api/branch-withdraw.js +15 -3
- package/dist/api/branch-withdraw.js.map +1 -1
- package/dist/api/branch.d.ts +11 -1
- package/dist/api/branch.d.ts.map +1 -1
- package/dist/api/branch.js +70 -4
- package/dist/api/branch.js.map +1 -1
- package/dist/api/client.d.ts +34 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +47 -0
- package/dist/api/client.js.map +1 -1
- package/dist/api/comments.d.ts.map +1 -1
- package/dist/api/comments.js +4 -0
- package/dist/api/comments.js.map +1 -1
- package/dist/api/content.d.ts.map +1 -1
- package/dist/api/content.js +4 -4
- package/dist/api/content.js.map +1 -1
- package/dist/api/entries.js +1 -1
- package/dist/api/entries.js.map +1 -1
- package/dist/api/github-sync.d.ts.map +1 -1
- package/dist/api/github-sync.js +14 -3
- package/dist/api/github-sync.js.map +1 -1
- package/dist/api/guards.d.ts +7 -1
- package/dist/api/guards.d.ts.map +1 -1
- package/dist/api/guards.js +54 -0
- package/dist/api/guards.js.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +0 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/schema.js +7 -7
- package/dist/api/schema.js.map +1 -1
- package/dist/authorization/branch.d.ts +14 -1
- package/dist/authorization/branch.d.ts.map +1 -1
- package/dist/authorization/branch.js +5 -3
- package/dist/authorization/branch.js.map +1 -1
- package/dist/authorization/index.d.ts +1 -0
- package/dist/authorization/index.d.ts.map +1 -1
- package/dist/authorization/index.js +2 -0
- package/dist/authorization/index.js.map +1 -1
- package/dist/authorization/protected-branch.d.ts +39 -0
- package/dist/authorization/protected-branch.d.ts.map +1 -0
- package/dist/authorization/protected-branch.js +43 -0
- package/dist/authorization/protected-branch.js.map +1 -0
- package/dist/branch-health.d.ts +78 -0
- package/dist/branch-health.d.ts.map +1 -0
- package/dist/branch-health.js +151 -0
- package/dist/branch-health.js.map +1 -0
- package/dist/branch-metadata.d.ts +20 -0
- package/dist/branch-metadata.d.ts.map +1 -1
- package/dist/branch-metadata.js +21 -1
- package/dist/branch-metadata.js.map +1 -1
- package/dist/branch-registry.d.ts.map +1 -1
- package/dist/branch-registry.js +13 -1
- package/dist/branch-registry.js.map +1 -1
- package/dist/cli/cli.js +154 -13
- package/dist/cli/generate-ai-content.js +54 -10
- package/dist/cli/init.js +72 -0
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +4 -1
- package/dist/cli/sync.js.map +1 -1
- package/dist/content-store.d.ts +16 -0
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +22 -6
- package/dist/content-store.js.map +1 -1
- package/dist/editor/BranchManager.d.ts +9 -1
- package/dist/editor/BranchManager.d.ts.map +1 -1
- package/dist/editor/BranchManager.js +20 -9
- package/dist/editor/BranchManager.js.map +1 -1
- package/dist/editor/CommentsPanel.d.ts.map +1 -1
- package/dist/editor/CommentsPanel.js +4 -12
- package/dist/editor/CommentsPanel.js.map +1 -1
- package/dist/editor/Editor.d.ts.map +1 -1
- package/dist/editor/Editor.js +46 -10
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/EntryNavigator.d.ts +7 -0
- package/dist/editor/EntryNavigator.d.ts.map +1 -1
- package/dist/editor/EntryNavigator.js +17 -5
- package/dist/editor/EntryNavigator.js.map +1 -1
- package/dist/editor/FormRenderer.d.ts.map +1 -1
- package/dist/editor/FormRenderer.js +4 -0
- package/dist/editor/FormRenderer.js.map +1 -1
- package/dist/editor/admin/SystemHealthPanel.d.ts +6 -0
- package/dist/editor/admin/SystemHealthPanel.d.ts.map +1 -0
- package/dist/editor/admin/SystemHealthPanel.js +234 -0
- package/dist/editor/admin/SystemHealthPanel.js.map +1 -0
- package/dist/editor/admin/useSystemHealth.d.ts +40 -0
- package/dist/editor/admin/useSystemHealth.d.ts.map +1 -0
- package/dist/editor/admin/useSystemHealth.js +205 -0
- package/dist/editor/admin/useSystemHealth.js.map +1 -0
- package/dist/editor/comments/FieldWrapper.d.ts.map +1 -1
- package/dist/editor/comments/FieldWrapper.js +1 -1
- package/dist/editor/comments/FieldWrapper.js.map +1 -1
- package/dist/editor/comments/InlineCommentThread.d.ts.map +1 -1
- package/dist/editor/comments/InlineCommentThread.js +2 -21
- package/dist/editor/comments/InlineCommentThread.js.map +1 -1
- package/dist/editor/comments/ThreadCarousel.d.ts +2 -0
- package/dist/editor/comments/ThreadCarousel.d.ts.map +1 -1
- package/dist/editor/comments/ThreadCarousel.js +5 -2
- package/dist/editor/comments/ThreadCarousel.js.map +1 -1
- package/dist/editor/components/EditorHeader.d.ts +11 -0
- package/dist/editor/components/EditorHeader.d.ts.map +1 -1
- package/dist/editor/components/EditorHeader.js +75 -41
- package/dist/editor/components/EditorHeader.js.map +1 -1
- package/dist/editor/components/EditorSidebar.d.ts +7 -1
- package/dist/editor/components/EditorSidebar.d.ts.map +1 -1
- package/dist/editor/components/EditorSidebar.js +3 -3
- package/dist/editor/components/EditorSidebar.js.map +1 -1
- package/dist/editor/fields/ImageField.d.ts.map +1 -1
- package/dist/editor/fields/ImageField.js +4 -1
- package/dist/editor/fields/ImageField.js.map +1 -1
- package/dist/editor/fields/StringListField.d.ts +20 -0
- package/dist/editor/fields/StringListField.d.ts.map +1 -0
- package/dist/editor/fields/StringListField.js +25 -0
- package/dist/editor/fields/StringListField.js.map +1 -0
- package/dist/editor/hooks/useBranchActions.d.ts.map +1 -1
- package/dist/editor/hooks/useBranchActions.js +8 -2
- package/dist/editor/hooks/useBranchActions.js.map +1 -1
- package/dist/editor/hooks/useBranchManager.d.ts +12 -3
- package/dist/editor/hooks/useBranchManager.d.ts.map +1 -1
- package/dist/editor/hooks/useBranchManager.js +16 -1
- package/dist/editor/hooks/useBranchManager.js.map +1 -1
- package/dist/editor/hooks/useDraftManager.d.ts +7 -0
- package/dist/editor/hooks/useDraftManager.d.ts.map +1 -1
- package/dist/editor/hooks/useDraftManager.js +57 -3
- package/dist/editor/hooks/useDraftManager.js.map +1 -1
- package/dist/editor/hooks/useEntryManager.d.ts.map +1 -1
- package/dist/editor/hooks/useEntryManager.js +25 -7
- package/dist/editor/hooks/useEntryManager.js.map +1 -1
- package/dist/editor/media/AssetCard.d.ts.map +1 -1
- package/dist/editor/media/AssetCard.js +23 -2
- package/dist/editor/media/AssetCard.js.map +1 -1
- package/dist/editor/relative-time.d.ts +8 -0
- package/dist/editor/relative-time.d.ts.map +1 -0
- package/dist/editor/relative-time.js +26 -0
- package/dist/editor/relative-time.js.map +1 -0
- package/dist/git-manager.d.ts.map +1 -1
- package/dist/git-manager.js +10 -2
- package/dist/git-manager.js.map +1 -1
- package/dist/http/handler.d.ts.map +1 -1
- package/dist/http/handler.js +20 -9
- package/dist/http/handler.js.map +1 -1
- package/dist/http/router.d.ts.map +1 -1
- package/dist/http/router.js +2 -0
- package/dist/http/router.js.map +1 -1
- package/dist/paths/branch-name.d.ts +20 -0
- package/dist/paths/branch-name.d.ts.map +1 -0
- package/dist/paths/branch-name.js +24 -0
- package/dist/paths/branch-name.js.map +1 -0
- package/dist/paths/branch.d.ts +2 -8
- package/dist/paths/branch.d.ts.map +1 -1
- package/dist/paths/branch.js +6 -12
- package/dist/paths/branch.js.map +1 -1
- package/dist/paths/index.d.ts +2 -1
- package/dist/paths/index.d.ts.map +1 -1
- package/dist/paths/index.js +4 -1
- package/dist/paths/index.js.map +1 -1
- package/dist/services.js +9 -1
- package/dist/services.js.map +1 -1
- package/dist/task-queue/index.d.ts +2 -2
- package/dist/task-queue/index.d.ts.map +1 -1
- package/dist/task-queue/index.js +1 -1
- package/dist/task-queue/index.js.map +1 -1
- package/dist/task-queue/task-queue.d.ts +37 -1
- package/dist/task-queue/task-queue.d.ts.map +1 -1
- package/dist/task-queue/task-queue.js +104 -0
- package/dist/task-queue/task-queue.js.map +1 -1
- package/dist/task-queue/types.d.ts +11 -0
- package/dist/task-queue/types.d.ts.map +1 -1
- package/dist/types.d.ts +41 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/occ-json-write.d.ts.map +1 -1
- package/dist/utils/occ-json-write.js +7 -0
- package/dist/utils/occ-json-write.js.map +1 -1
- package/dist/utils/provisioning-lock.d.ts +19 -0
- package/dist/utils/provisioning-lock.d.ts.map +1 -1
- package/dist/utils/provisioning-lock.js +26 -0
- package/dist/utils/provisioning-lock.js.map +1 -1
- package/dist/validation/reference-validator.d.ts +17 -1
- package/dist/validation/reference-validator.d.ts.map +1 -1
- package/dist/validation/reference-validator.js +33 -10
- package/dist/validation/reference-validator.js.map +1 -1
- package/dist/worker/cms-worker.d.ts +38 -0
- package/dist/worker/cms-worker.d.ts.map +1 -1
- package/dist/worker/cms-worker.js +328 -25
- package/dist/worker/cms-worker.js.map +1 -1
- package/dist/worker/task-queue.d.ts +3 -3
- package/dist/worker/task-queue.d.ts.map +1 -1
- package/dist/worker/task-queue.js +2 -2
- package/dist/worker/task-queue.js.map +1 -1
- package/dist/worker/worker-status.d.ts +48 -0
- package/dist/worker/worker-status.d.ts.map +1 -0
- package/dist/worker/worker-status.js +53 -0
- package/dist/worker/worker-status.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin branch-health observability + recovery (PR-A3): a scan listing every
|
|
3
|
+
* directory under the branches root (healthy/corrupt-metadata/orphan), plus
|
|
4
|
+
* two recovery actions -- purge (reversible trash-rename) and repair-metadata
|
|
5
|
+
* (recreate defaults for a corrupt branch.json). Split out of admin.ts to
|
|
6
|
+
* keep that file under its size budget; ADMIN_ROUTES in admin.ts re-exports
|
|
7
|
+
* these routes so the router and generate-client keep a single import.
|
|
8
|
+
*
|
|
9
|
+
* See docs/concurrency.md's "Who uses what" table for the locking rationale
|
|
10
|
+
* (double-hold on purge, release-then-save ordering on repair).
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs/promises';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { simpleGit } from 'simple-git';
|
|
16
|
+
import { BranchMetadataFileManager, getBranchMetadataFileManager } from '../branch-metadata.js';
|
|
17
|
+
import { scanBranchHealth } from '../branch-health.js';
|
|
18
|
+
import { getDefaultBranchBase, sanitizeBranchName } from '../paths/index.js';
|
|
19
|
+
import { withOccFileLock } from '../utils/occ-json-write.js';
|
|
20
|
+
import { tryAcquireProvisioningLock } from '../utils/provisioning-lock.js';
|
|
21
|
+
import { getErrorMessage, isNodeError, isNotFoundError } from '../utils/error.js';
|
|
22
|
+
import { defineEndpoint } from './route-builder.js';
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Constants
|
|
25
|
+
// ============================================================================
|
|
26
|
+
/** [H1] A fresh (< 5 min old) init lock blocks purge -- provisioning may be running. */
|
|
27
|
+
const PROVISIONING_LOCK_FRESH_MS = 5 * 60_000;
|
|
28
|
+
/** An orphan dir younger than this may still be a clone in progress; corrupt dirs are exempt. */
|
|
29
|
+
const ORPHAN_YOUTH_THRESHOLD_MS = 15 * 60_000;
|
|
30
|
+
const BRANCH_META_DIR = '.canopy-meta';
|
|
31
|
+
const BRANCH_META_FILE = 'branch.json';
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// Zod schemas
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Mirrors deleteTaskHandler's fileName pattern in admin.ts: conservative
|
|
36
|
+
// charset plus explicit traversal/dot-prefix refinements (the regex alone
|
|
37
|
+
// technically excludes '/' already, but the refinements keep intent explicit
|
|
38
|
+
// and self-documenting at the validation layer).
|
|
39
|
+
const dirNameSchema = z
|
|
40
|
+
.string()
|
|
41
|
+
.regex(/^[A-Za-z0-9._-]{1,100}$/)
|
|
42
|
+
.refine((v) => !v.includes('..'), { message: 'dirName must not contain ..' })
|
|
43
|
+
.refine((v) => !v.startsWith('.'), { message: 'dirName must not be dot-prefixed' });
|
|
44
|
+
const branchDirParamsSchema = z.object({ dirName: dirNameSchema });
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// Shared helpers
|
|
47
|
+
// ============================================================================
|
|
48
|
+
/** Compact UTC stamp for trash/archive names: `YYYYMMDDTHHMMSSZ` (no colons -- portability). */
|
|
49
|
+
function formatTrashStamp(date) {
|
|
50
|
+
return date
|
|
51
|
+
.toISOString()
|
|
52
|
+
.replace(/[-:]/g, '')
|
|
53
|
+
.replace(/\.\d{3}Z$/, 'Z');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Re-resolve dirName under baseRoot and enforce containment (belt-and-
|
|
57
|
+
* suspenders on top of the zod regex, matching deleteTaskHandler's pattern
|
|
58
|
+
* in admin.ts).
|
|
59
|
+
*/
|
|
60
|
+
function resolveDirWithinBase(baseRoot, dirName) {
|
|
61
|
+
const resolvedBase = path.resolve(baseRoot);
|
|
62
|
+
const baseWithSep = resolvedBase.endsWith(path.sep) ? resolvedBase : resolvedBase + path.sep;
|
|
63
|
+
const dirPath = path.resolve(resolvedBase, dirName);
|
|
64
|
+
if (dirPath !== resolvedBase && !dirPath.startsWith(baseWithSep))
|
|
65
|
+
return null;
|
|
66
|
+
return dirPath;
|
|
67
|
+
}
|
|
68
|
+
/** Control-flow error for repair's precondition checks made INSIDE the lock hold. */
|
|
69
|
+
class RepairPreconditionError extends Error {
|
|
70
|
+
constructor(message, status) {
|
|
71
|
+
super(message);
|
|
72
|
+
this.name = 'RepairPreconditionError';
|
|
73
|
+
this.status = status;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ============================================================================
|
|
77
|
+
// Handlers
|
|
78
|
+
// ============================================================================
|
|
79
|
+
const getBranchHealthHandler = async (_gc, ctx, _req) => {
|
|
80
|
+
// Same derivation services.ts uses to construct the BranchRegistry --
|
|
81
|
+
// admin handlers must agree with it or the scan silently looks at the
|
|
82
|
+
// wrong directory.
|
|
83
|
+
const baseRoot = getDefaultBranchBase(ctx.services.config.mode);
|
|
84
|
+
const baseBranchName = ctx.services.config.defaultBaseBranch ?? 'main';
|
|
85
|
+
try {
|
|
86
|
+
const entries = await scanBranchHealth(baseRoot, { baseBranchName });
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
status: 200,
|
|
90
|
+
data: { entries, generatedAt: new Date().toISOString() },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return { ok: false, status: 500, error: getErrorMessage(err) };
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Purge a corrupt-metadata or orphan branch directory by renaming it into a
|
|
99
|
+
* dot-prefixed trash name (reversible -- nothing is deleted here; the worker
|
|
100
|
+
* sweeps trash older than 30 days, see cleanupTrashedBranchDirs in
|
|
101
|
+
* worker/cms-worker.ts).
|
|
102
|
+
*
|
|
103
|
+
* Safety rails (see the PR's design review for the finding IDs):
|
|
104
|
+
* - [always] the base branch directory can never be purged.
|
|
105
|
+
* - Server re-derives live/corrupt/orphan state itself -- never trusts the
|
|
106
|
+
* client's view of the world.
|
|
107
|
+
* - [H1] a fresh provisioning init-lock blocks purge; a stale one does not.
|
|
108
|
+
* - an orphan (not corrupt) dir younger than 15 minutes is presumed to be a
|
|
109
|
+
* clone in progress and is not purgeable yet.
|
|
110
|
+
* - [H2] the purge itself runs under a zero-retry provisioning lock, so a
|
|
111
|
+
* real in-flight provisioner (whose lock is therefore fresh, and would
|
|
112
|
+
* already have 409'd above) can never race the rename; a same-instant
|
|
113
|
+
* contender simply 409s.
|
|
114
|
+
* - [M3] ALSO runs under the branch.json lockfile -- the same lock every
|
|
115
|
+
* metadata save() takes -- closing the window where a concurrent
|
|
116
|
+
* repair-metadata save() resurrects a ghost branch.json mid-purge.
|
|
117
|
+
*/
|
|
118
|
+
const purgeBranchDirHandler = async (_gc, ctx, _req, params) => {
|
|
119
|
+
const baseRoot = getDefaultBranchBase(ctx.services.config.mode);
|
|
120
|
+
const baseBranchName = ctx.services.config.defaultBaseBranch ?? 'main';
|
|
121
|
+
const sanitizedBaseBranchName = sanitizeBranchName(baseBranchName);
|
|
122
|
+
if (params.dirName === sanitizedBaseBranchName) {
|
|
123
|
+
return { ok: false, status: 400, error: 'The base branch directory can never be purged' };
|
|
124
|
+
}
|
|
125
|
+
const dirPath = resolveDirWithinBase(baseRoot, params.dirName);
|
|
126
|
+
if (!dirPath) {
|
|
127
|
+
return { ok: false, status: 400, error: 'Invalid directory name' };
|
|
128
|
+
}
|
|
129
|
+
// [MEDIUM-1 rider] The directory must actually exist -- otherwise
|
|
130
|
+
// withOccFileLock's `mkdir -p` below would CREATE it, and purge would
|
|
131
|
+
// "succeed" with a phantom `.trash-*` entry for a directory that was
|
|
132
|
+
// never there. Must run before anything below treats "no branch.json" as
|
|
133
|
+
// orphan classification.
|
|
134
|
+
const dirExists = await fs
|
|
135
|
+
.stat(dirPath)
|
|
136
|
+
.then(() => true)
|
|
137
|
+
.catch(() => false);
|
|
138
|
+
if (!dirExists) {
|
|
139
|
+
return { ok: false, status: 404, error: 'Directory not found' };
|
|
140
|
+
}
|
|
141
|
+
const branchJsonPath = path.join(dirPath, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
142
|
+
// Re-derive state server-side -- never trust the client's classification.
|
|
143
|
+
let meta = null;
|
|
144
|
+
let hadLoadError = false;
|
|
145
|
+
try {
|
|
146
|
+
meta = await BranchMetadataFileManager.loadOnly(dirPath);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
hadLoadError = true;
|
|
150
|
+
}
|
|
151
|
+
if (meta) {
|
|
152
|
+
return { ok: false, status: 409, error: 'Directory holds a live branch; use branch delete' };
|
|
153
|
+
}
|
|
154
|
+
// True orphan (no branch.json, no load error) vs. corrupt-metadata
|
|
155
|
+
// (loadOnly threw). Only true orphans are subject to the youth rail below.
|
|
156
|
+
const isTrueOrphan = !hadLoadError;
|
|
157
|
+
// [H1] freshness rail: a fresh init lock means provisioning may genuinely
|
|
158
|
+
// be in progress; a stale one is just crash debris and does not block.
|
|
159
|
+
const lockPath = path.join(baseRoot, `.${params.dirName}.init.lock`);
|
|
160
|
+
const lockStat = await fs.stat(lockPath).catch(() => null);
|
|
161
|
+
if (lockStat && Date.now() - lockStat.mtimeMs < PROVISIONING_LOCK_FRESH_MS) {
|
|
162
|
+
return { ok: false, status: 409, error: 'Provisioning may be in progress' };
|
|
163
|
+
}
|
|
164
|
+
// Youth rail: a brand-new orphan dir may be a clone that just hasn't
|
|
165
|
+
// written branch.json yet. Corrupt-metadata dirs are exempt -- a
|
|
166
|
+
// parseable-then-corrupted file is not a mid-clone signature.
|
|
167
|
+
if (isTrueOrphan) {
|
|
168
|
+
const dirStat = await fs.stat(dirPath).catch(() => null);
|
|
169
|
+
if (dirStat && Date.now() - dirStat.mtimeMs < ORPHAN_YOUTH_THRESHOLD_MS) {
|
|
170
|
+
return {
|
|
171
|
+
ok: false,
|
|
172
|
+
status: 409,
|
|
173
|
+
error: 'Directory too young -- may be a clone in progress',
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// [H2] Zero-retry provisioning lock: fails fast (409) on genuine live
|
|
178
|
+
// contention instead of hanging the request for ~5 minutes.
|
|
179
|
+
let releaseProvisioningLock;
|
|
180
|
+
try {
|
|
181
|
+
releaseProvisioningLock = await tryAcquireProvisioningLock(baseRoot, `.${params.dirName}.init.lock`);
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
if (isNodeError(err) && err.code === 'ELOCKED') {
|
|
185
|
+
return { ok: false, status: 409, error: 'Provisioning lock contention, try again' };
|
|
186
|
+
}
|
|
187
|
+
return { ok: false, status: 500, error: getErrorMessage(err) };
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
return await withOccFileLock(branchJsonPath, async () => {
|
|
191
|
+
// [M3] Re-verify classification inside the double hold: a concurrent
|
|
192
|
+
// repair-metadata save() could have resurrected branch.json between
|
|
193
|
+
// our pre-lock check and now.
|
|
194
|
+
let recheckMeta = null;
|
|
195
|
+
try {
|
|
196
|
+
recheckMeta = await BranchMetadataFileManager.loadOnly(dirPath);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// Still corrupt (or now corrupt) -- fine, proceed with the purge.
|
|
200
|
+
}
|
|
201
|
+
if (recheckMeta) {
|
|
202
|
+
return { ok: false, status: 409, error: 'Directory holds a live branch; use branch delete' };
|
|
203
|
+
}
|
|
204
|
+
// [C1] The timestamp lives in the NAME, not the dir's mtime: rename()
|
|
205
|
+
// preserves the original mtime, so mtime-based retention would delete
|
|
206
|
+
// a months-stale orphan's trash on the very first cleanup pass.
|
|
207
|
+
const trashName = `.trash-${params.dirName}-${formatTrashStamp(new Date())}`;
|
|
208
|
+
const trashPath = path.join(baseRoot, trashName);
|
|
209
|
+
try {
|
|
210
|
+
await fs.rename(dirPath, trashPath);
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
// Rename failure: the directory stays exactly where it was --
|
|
214
|
+
// nothing evaporates, and the next scan still lists it.
|
|
215
|
+
return { ok: false, status: 500, error: getErrorMessage(err) };
|
|
216
|
+
}
|
|
217
|
+
await ctx.services.registry?.invalidate();
|
|
218
|
+
return { ok: true, status: 200, data: { trashedAs: trashName } };
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
return {
|
|
223
|
+
ok: false,
|
|
224
|
+
status: 409,
|
|
225
|
+
error: `Could not lock branch metadata: ${getErrorMessage(err)}`,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
if (releaseProvisioningLock) {
|
|
230
|
+
await releaseProvisioningLock().catch(() => { });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Repair a corrupt branch.json by archiving it (forensics preserved as
|
|
236
|
+
* `branch.json.corrupt-{STAMP}`, ignored by future scans since it doesn't
|
|
237
|
+
* match the exact `branch.json` name) and recreating defaults via the
|
|
238
|
+
* normal save() path. Unlike purge, the base branch IS a valid target here
|
|
239
|
+
* -- a corrupt BASE branch.json is exactly the degraded-service scenario
|
|
240
|
+
* this handler exists to fix.
|
|
241
|
+
*
|
|
242
|
+
* [M4] Lock sequence: withOccFileLock is NOT reentrant, and save() takes it
|
|
243
|
+
* internally, so the rename must happen and the lock must be RELEASED
|
|
244
|
+
* (exiting the withOccFileLock callback) before save() runs -- calling
|
|
245
|
+
* save() while still holding the lock would deadlock against itself.
|
|
246
|
+
*
|
|
247
|
+
* [MEDIUM-1] The provisioning lock is held across the ENTIRE archive+save
|
|
248
|
+
* sequence (acquired before withOccFileLock, released only after save()
|
|
249
|
+
* completes), same lock order as purge (provisioning -> branch.json) so the
|
|
250
|
+
* two can never deadlock against each other. Without this, a concurrent
|
|
251
|
+
* purge could trash the directory in the window between this handler
|
|
252
|
+
* releasing withOccFileLock (required before save(), per [M4] above) and
|
|
253
|
+
* save() actually running -- save() would then resurrect a metadata-only
|
|
254
|
+
* ghost of a directory purge just moved to trash.
|
|
255
|
+
*/
|
|
256
|
+
const repairBranchDirHandler = async (_gc, ctx, req, params) => {
|
|
257
|
+
const baseRoot = getDefaultBranchBase(ctx.services.config.mode);
|
|
258
|
+
const dirPath = resolveDirWithinBase(baseRoot, params.dirName);
|
|
259
|
+
if (!dirPath) {
|
|
260
|
+
return { ok: false, status: 400, error: 'Invalid directory name' };
|
|
261
|
+
}
|
|
262
|
+
// [MEDIUM-1 rider] Same stat guard as purge: the directory must actually
|
|
263
|
+
// exist, otherwise withOccFileLock's `mkdir -p` below would CREATE it.
|
|
264
|
+
const dirExists = await fs
|
|
265
|
+
.stat(dirPath)
|
|
266
|
+
.then(() => true)
|
|
267
|
+
.catch(() => false);
|
|
268
|
+
if (!dirExists) {
|
|
269
|
+
return { ok: false, status: 404, error: 'Directory not found' };
|
|
270
|
+
}
|
|
271
|
+
const branchJsonPath = path.join(dirPath, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
272
|
+
// Pre-lock precondition check: fail fast on the common cases without
|
|
273
|
+
// paying for a lock acquisition on a doomed request.
|
|
274
|
+
const precheck = await checkStillCorrupt(dirPath);
|
|
275
|
+
if (precheck !== 'corrupt') {
|
|
276
|
+
return precheck === 'healthy'
|
|
277
|
+
? { ok: false, status: 409, error: 'Metadata is healthy' }
|
|
278
|
+
: { ok: false, status: 409, error: 'No metadata file -- use purge for orphans' };
|
|
279
|
+
}
|
|
280
|
+
// [MEDIUM-1] Zero-retry provisioning lock, mirroring purge's [H2]: fails
|
|
281
|
+
// fast (409) on genuine live contention instead of hanging the request.
|
|
282
|
+
// Held until the `finally` below, AFTER save() completes.
|
|
283
|
+
let releaseProvisioningLock;
|
|
284
|
+
try {
|
|
285
|
+
releaseProvisioningLock = await tryAcquireProvisioningLock(baseRoot, `.${params.dirName}.init.lock`);
|
|
286
|
+
}
|
|
287
|
+
catch (err) {
|
|
288
|
+
if (isNodeError(err) && err.code === 'ELOCKED') {
|
|
289
|
+
return { ok: false, status: 409, error: 'Provisioning lock contention, try again' };
|
|
290
|
+
}
|
|
291
|
+
return { ok: false, status: 500, error: getErrorMessage(err) };
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
let archivedAs;
|
|
295
|
+
try {
|
|
296
|
+
archivedAs = await withOccFileLock(branchJsonPath, async () => {
|
|
297
|
+
// Re-verify still-corrupt under the lock (a concurrent repair could
|
|
298
|
+
// have already fixed this, or the file could have been purged out
|
|
299
|
+
// from under us).
|
|
300
|
+
const recheck = await checkStillCorrupt(dirPath);
|
|
301
|
+
if (recheck === 'healthy') {
|
|
302
|
+
throw new RepairPreconditionError('Metadata is healthy', 409);
|
|
303
|
+
}
|
|
304
|
+
if (recheck === 'missing') {
|
|
305
|
+
throw new RepairPreconditionError('No metadata file -- use purge for orphans', 409);
|
|
306
|
+
}
|
|
307
|
+
const archivedName = `${BRANCH_META_FILE}.corrupt-${formatTrashStamp(new Date())}`;
|
|
308
|
+
await fs.rename(branchJsonPath, path.join(dirPath, BRANCH_META_DIR, archivedName));
|
|
309
|
+
return archivedName;
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
if (err instanceof RepairPreconditionError) {
|
|
314
|
+
return { ok: false, status: err.status, error: err.message };
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
ok: false,
|
|
318
|
+
status: 409,
|
|
319
|
+
error: `Could not lock branch metadata: ${getErrorMessage(err)}`,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
// [MEDIUM-3] Prefer the clone's actual checked-out branch over the
|
|
323
|
+
// (possibly sanitized) directory name -- see resolveRepairedBranchName.
|
|
324
|
+
const branchName = await resolveRepairedBranchName(dirPath, params.dirName);
|
|
325
|
+
// Lock released above (we're outside the withOccFileLock callback now) --
|
|
326
|
+
// save() takes its own hold on the same lock internally. Its defaults
|
|
327
|
+
// path fabricates the rest of BranchMetadata and invalidates the
|
|
328
|
+
// registry. Still under the provisioning lock acquired above -- see
|
|
329
|
+
// [MEDIUM-1] in the docstring.
|
|
330
|
+
const manager = getBranchMetadataFileManager(dirPath, baseRoot);
|
|
331
|
+
const saved = await manager.save({
|
|
332
|
+
branch: { name: branchName, status: 'editing', createdBy: req.user.userId },
|
|
333
|
+
});
|
|
334
|
+
return { ok: true, status: 200, data: { branch: saved.branch, archivedAs } };
|
|
335
|
+
}
|
|
336
|
+
finally {
|
|
337
|
+
if (releaseProvisioningLock) {
|
|
338
|
+
await releaseProvisioningLock().catch(() => { });
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* [MEDIUM-3] Best-effort read of the branch actually checked out in the
|
|
344
|
+
* clone at `dirPath`, falling back to `dirName` on any failure (no `.git`,
|
|
345
|
+
* detached HEAD, corrupt repo, etc.). Workspace directory names are
|
|
346
|
+
* sanitized (slashes stripped, see paths/branch.ts's `sanitizeBranchName`),
|
|
347
|
+
* so a branch named `feature/foo` lives in a directory named `feature-foo`
|
|
348
|
+
* -- writing `dirName` as `branch.name` would make later push/PR tasks
|
|
349
|
+
* target the wrong ref.
|
|
350
|
+
*/
|
|
351
|
+
async function resolveRepairedBranchName(dirPath, dirName) {
|
|
352
|
+
const hasGitDir = await fs
|
|
353
|
+
.stat(path.join(dirPath, '.git'))
|
|
354
|
+
.then(() => true)
|
|
355
|
+
.catch(() => false);
|
|
356
|
+
if (!hasGitDir)
|
|
357
|
+
return dirName;
|
|
358
|
+
try {
|
|
359
|
+
const current = await simpleGit({ baseDir: dirPath }).revparse(['--abbrev-ref', 'HEAD']);
|
|
360
|
+
const trimmed = current.trim();
|
|
361
|
+
return trimmed || dirName;
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
return dirName;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/** Classify branch.json's current state for repair's precondition checks. */
|
|
368
|
+
async function checkStillCorrupt(dirPath) {
|
|
369
|
+
try {
|
|
370
|
+
const meta = await BranchMetadataFileManager.loadOnly(dirPath);
|
|
371
|
+
return meta ? 'healthy' : 'missing';
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
if (isNotFoundError(err))
|
|
375
|
+
return 'missing';
|
|
376
|
+
return 'corrupt';
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// ============================================================================
|
|
380
|
+
// Route definitions
|
|
381
|
+
// ============================================================================
|
|
382
|
+
/**
|
|
383
|
+
* Branch directory health scan (healthy/corrupt-metadata/orphan)
|
|
384
|
+
* GET /admin/branch-health
|
|
385
|
+
*/
|
|
386
|
+
const getBranchHealth = defineEndpoint({
|
|
387
|
+
namespace: 'admin',
|
|
388
|
+
name: 'branchHealth',
|
|
389
|
+
method: 'GET',
|
|
390
|
+
path: '/admin/branch-health',
|
|
391
|
+
responseType: 'BranchHealthResponse',
|
|
392
|
+
response: {},
|
|
393
|
+
defaultMockData: { entries: [], generatedAt: '2024-01-01T00:00:00.000Z' },
|
|
394
|
+
guards: ['admin'],
|
|
395
|
+
handler: getBranchHealthHandler,
|
|
396
|
+
});
|
|
397
|
+
/**
|
|
398
|
+
* Purge a corrupt-metadata or orphan branch directory (reversible trash-rename)
|
|
399
|
+
* POST /admin/branch-dirs/:dirName/purge
|
|
400
|
+
*/
|
|
401
|
+
const purgeBranchDir = defineEndpoint({
|
|
402
|
+
namespace: 'admin',
|
|
403
|
+
name: 'purgeBranchDir',
|
|
404
|
+
method: 'POST',
|
|
405
|
+
path: '/admin/branch-dirs/:dirName/purge',
|
|
406
|
+
params: branchDirParamsSchema,
|
|
407
|
+
responseType: 'PurgeBranchDirResponse',
|
|
408
|
+
response: {},
|
|
409
|
+
defaultMockData: { trashedAs: '.trash-example-branch-20240101T000000Z' },
|
|
410
|
+
guards: ['admin'],
|
|
411
|
+
handler: purgeBranchDirHandler,
|
|
412
|
+
});
|
|
413
|
+
/**
|
|
414
|
+
* Repair a corrupt branch.json by archiving it and recreating defaults
|
|
415
|
+
* POST /admin/branch-dirs/:dirName/repair-metadata
|
|
416
|
+
*/
|
|
417
|
+
const repairBranchDir = defineEndpoint({
|
|
418
|
+
namespace: 'admin',
|
|
419
|
+
name: 'repairBranchDir',
|
|
420
|
+
method: 'POST',
|
|
421
|
+
path: '/admin/branch-dirs/:dirName/repair-metadata',
|
|
422
|
+
params: branchDirParamsSchema,
|
|
423
|
+
responseType: 'RepairBranchDirResponse',
|
|
424
|
+
response: {},
|
|
425
|
+
defaultMockData: {
|
|
426
|
+
branch: {
|
|
427
|
+
name: 'example-branch',
|
|
428
|
+
status: 'editing',
|
|
429
|
+
access: {},
|
|
430
|
+
createdBy: 'admin',
|
|
431
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
432
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
433
|
+
},
|
|
434
|
+
archivedAs: 'branch.json.corrupt-20240101T000000Z',
|
|
435
|
+
},
|
|
436
|
+
guards: ['admin'],
|
|
437
|
+
handler: repairBranchDirHandler,
|
|
438
|
+
});
|
|
439
|
+
/**
|
|
440
|
+
* Exported routes, merged into ADMIN_ROUTES in admin.ts for a single
|
|
441
|
+
* router/generate-client import.
|
|
442
|
+
*/
|
|
443
|
+
export const ADMIN_BRANCH_HEALTH_ROUTES = {
|
|
444
|
+
branchHealth: getBranchHealth,
|
|
445
|
+
purgeBranchDir,
|
|
446
|
+
repairBranchDir,
|
|
447
|
+
};
|
|
448
|
+
//# sourceMappingURL=admin-branch-health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-branch-health.js","sourceRoot":"","sources":["../../src/api/admin-branch-health.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin observability endpoints: task queue stats/listing and worker
|
|
3
|
+
* liveness (PR-A1), plus task recovery actions — retry a failed task or
|
|
4
|
+
* delete a stuck/corrupt task file (PR-A2) — for an admin-only dashboard.
|
|
5
|
+
* Branch-health scan + purge/repair actions (PR-A3) live in
|
|
6
|
+
* admin-branch-health.ts and are merged into ADMIN_ROUTES below.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import type { ApiResponse } from './types';
|
|
10
|
+
import type { Task, QueueStats, CorruptTaskFile } from '../worker/task-queue';
|
|
11
|
+
import type { WorkerStatusReport } from '../types';
|
|
12
|
+
import type { OperatingMode } from '../operating-mode';
|
|
13
|
+
export type { BranchHealthResponse, PurgeBranchDirResponse, RepairBranchDirResponse, } from './admin-branch-health';
|
|
14
|
+
export type WorkerLivenessState = 'alive' | 'stale' | 'absent';
|
|
15
|
+
export interface WorkerLiveness {
|
|
16
|
+
/**
|
|
17
|
+
* 'absent' — the lock dir is removed on clean release, so this also covers
|
|
18
|
+
* "never started". 'alive' — heartbeat fresher than the threshold. 'stale'
|
|
19
|
+
* — heartbeat older than the threshold (the holder likely crashed).
|
|
20
|
+
*/
|
|
21
|
+
state: WorkerLivenessState;
|
|
22
|
+
lockMtime?: string;
|
|
23
|
+
lockAgeMs?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface AdminStatusData {
|
|
26
|
+
generatedAt: string;
|
|
27
|
+
mode: OperatingMode;
|
|
28
|
+
queue: QueueStats & {
|
|
29
|
+
oldestPendingAgeMs?: number;
|
|
30
|
+
};
|
|
31
|
+
worker: WorkerLiveness;
|
|
32
|
+
workerStatus: WorkerStatusReport | null;
|
|
33
|
+
statusReadError?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Response type for GET /admin/status */
|
|
36
|
+
export type AdminStatusResponse = ApiResponse<AdminStatusData>;
|
|
37
|
+
export interface AdminTasksData {
|
|
38
|
+
tasks?: Task[];
|
|
39
|
+
corruptFiles?: CorruptTaskFile[];
|
|
40
|
+
}
|
|
41
|
+
/** Response type for GET /admin/tasks/:status */
|
|
42
|
+
export type AdminTasksResponse = ApiResponse<AdminTasksData>;
|
|
43
|
+
export interface AdminRetryTaskData {
|
|
44
|
+
newTaskId: string;
|
|
45
|
+
}
|
|
46
|
+
/** Response type for POST /admin/tasks/:taskId/retry */
|
|
47
|
+
export type AdminRetryTaskResponse = ApiResponse<AdminRetryTaskData>;
|
|
48
|
+
export interface AdminDeleteTaskData {
|
|
49
|
+
deleted: true;
|
|
50
|
+
}
|
|
51
|
+
/** Response type for DELETE /admin/tasks/:status/:fileName */
|
|
52
|
+
export type AdminDeleteTaskResponse = ApiResponse<AdminDeleteTaskData>;
|
|
53
|
+
declare const listAdminTasksParamsSchema: z.ZodObject<{
|
|
54
|
+
status: z.ZodEnum<["pending", "processing", "completed", "failed", "corrupt"]>;
|
|
55
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
56
|
+
}, "strip", z.ZodTypeAny, {
|
|
57
|
+
status: "pending" | "processing" | "completed" | "failed" | "corrupt";
|
|
58
|
+
limit?: number | undefined;
|
|
59
|
+
}, {
|
|
60
|
+
status: "pending" | "processing" | "completed" | "failed" | "corrupt";
|
|
61
|
+
limit?: number | undefined;
|
|
62
|
+
}>;
|
|
63
|
+
export type ListAdminTasksParams = z.infer<typeof listAdminTasksParamsSchema>;
|
|
64
|
+
declare const retryTaskParamsSchema: z.ZodObject<{
|
|
65
|
+
taskId: z.ZodString;
|
|
66
|
+
}, "strip", z.ZodTypeAny, {
|
|
67
|
+
taskId: string;
|
|
68
|
+
}, {
|
|
69
|
+
taskId: string;
|
|
70
|
+
}>;
|
|
71
|
+
export type RetryTaskParams = z.infer<typeof retryTaskParamsSchema>;
|
|
72
|
+
declare const deleteTaskParamsSchema: z.ZodObject<{
|
|
73
|
+
status: z.ZodEnum<["pending", "failed", "corrupt"]>;
|
|
74
|
+
fileName: z.ZodEffects<z.ZodString, string, string>;
|
|
75
|
+
}, "strip", z.ZodTypeAny, {
|
|
76
|
+
status: "pending" | "failed" | "corrupt";
|
|
77
|
+
fileName: string;
|
|
78
|
+
}, {
|
|
79
|
+
status: "pending" | "failed" | "corrupt";
|
|
80
|
+
fileName: string;
|
|
81
|
+
}>;
|
|
82
|
+
export type DeleteTaskParams = z.infer<typeof deleteTaskParamsSchema>;
|
|
83
|
+
/**
|
|
84
|
+
* Exported routes for router registration.
|
|
85
|
+
*
|
|
86
|
+
* Branch-health scan + purge/repair (PR-A3) live in admin-branch-health.ts
|
|
87
|
+
* (kept out of this file to stay under its size budget) and are merged in
|
|
88
|
+
* here so the router (http/router.ts) and generate-client.ts keep a single
|
|
89
|
+
* `ADMIN_ROUTES` import.
|
|
90
|
+
*/
|
|
91
|
+
export declare const ADMIN_ROUTES: {
|
|
92
|
+
readonly branchHealth: import("./route-builder").RouteDefinition<undefined, undefined, import("./admin-branch-health").BranchHealthResponse>;
|
|
93
|
+
readonly purgeBranchDir: import("./route-builder").RouteDefinition<z.ZodObject<{
|
|
94
|
+
dirName: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
|
|
95
|
+
}, "strip", z.ZodTypeAny, {
|
|
96
|
+
dirName: string;
|
|
97
|
+
}, {
|
|
98
|
+
dirName: string;
|
|
99
|
+
}>, undefined, import("./admin-branch-health").PurgeBranchDirResponse>;
|
|
100
|
+
readonly repairBranchDir: import("./route-builder").RouteDefinition<z.ZodObject<{
|
|
101
|
+
dirName: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
|
|
102
|
+
}, "strip", z.ZodTypeAny, {
|
|
103
|
+
dirName: string;
|
|
104
|
+
}, {
|
|
105
|
+
dirName: string;
|
|
106
|
+
}>, undefined, import("./admin-branch-health").RepairBranchDirResponse>;
|
|
107
|
+
readonly status: import("./route-builder").RouteDefinition<undefined, undefined, AdminStatusResponse>;
|
|
108
|
+
readonly listTasks: import("./route-builder").RouteDefinition<z.ZodObject<{
|
|
109
|
+
status: z.ZodEnum<["pending", "processing", "completed", "failed", "corrupt"]>;
|
|
110
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
111
|
+
}, "strip", z.ZodTypeAny, {
|
|
112
|
+
status: "pending" | "processing" | "completed" | "failed" | "corrupt";
|
|
113
|
+
limit?: number | undefined;
|
|
114
|
+
}, {
|
|
115
|
+
status: "pending" | "processing" | "completed" | "failed" | "corrupt";
|
|
116
|
+
limit?: number | undefined;
|
|
117
|
+
}>, undefined, AdminTasksResponse>;
|
|
118
|
+
readonly retryTask: import("./route-builder").RouteDefinition<z.ZodObject<{
|
|
119
|
+
taskId: z.ZodString;
|
|
120
|
+
}, "strip", z.ZodTypeAny, {
|
|
121
|
+
taskId: string;
|
|
122
|
+
}, {
|
|
123
|
+
taskId: string;
|
|
124
|
+
}>, undefined, AdminRetryTaskResponse>;
|
|
125
|
+
readonly deleteTask: import("./route-builder").RouteDefinition<z.ZodObject<{
|
|
126
|
+
status: z.ZodEnum<["pending", "failed", "corrupt"]>;
|
|
127
|
+
fileName: z.ZodEffects<z.ZodString, string, string>;
|
|
128
|
+
}, "strip", z.ZodTypeAny, {
|
|
129
|
+
status: "pending" | "failed" | "corrupt";
|
|
130
|
+
fileName: string;
|
|
131
|
+
}, {
|
|
132
|
+
status: "pending" | "failed" | "corrupt";
|
|
133
|
+
fileName: string;
|
|
134
|
+
}>, undefined, AdminDeleteTaskResponse>;
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=admin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/api/admin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAA0B,WAAW,EAAE,MAAM,SAAS,CAAA;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAS7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAUtD,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,uBAAuB,CAAA;AAoB9B,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE9D,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,KAAK,EAAE,mBAAmB,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAgFD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,aAAa,CAAA;IACnB,KAAK,EAAE,UAAU,GAAG;QAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACnD,MAAM,EAAE,cAAc,CAAA;IACtB,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAA;IACvC,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,0CAA0C;AAC1C,MAAM,MAAM,mBAAmB,GAAG,WAAW,CAAC,eAAe,CAAC,CAAA;AAE9D,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,YAAY,CAAC,EAAE,eAAe,EAAE,CAAA;CACjC;AAED,iDAAiD;AACjD,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,cAAc,CAAC,CAAA;AAE5D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wDAAwD;AACxD,MAAM,MAAM,sBAAsB,GAAG,WAAW,CAAC,kBAAkB,CAAC,CAAA;AAEpE,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,IAAI,CAAA;CACd;AAED,8DAA8D;AAC9D,MAAM,MAAM,uBAAuB,GAAG,WAAW,CAAC,mBAAmB,CAAC,CAAA;AAQtE,QAAA,MAAM,0BAA0B;;;;;;;;;EAK9B,CAAA;AACF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAA;AAI7E,QAAA,MAAM,qBAAqB;;;;;;EAEzB,CAAA;AACF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAOnE,QAAA,MAAM,sBAAsB;;;;;;;;;EAM1B,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAkOrE;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAMf,CAAA"}
|