@cat-factory/server 0.30.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +2 -0
- package/dist/app.js.map +1 -1
- package/dist/config/types.d.ts +1 -15
- package/dist/config/types.d.ts.map +1 -1
- package/dist/github/FetchGitHubClient.d.ts +15 -1
- package/dist/github/FetchGitHubClient.d.ts.map +1 -1
- package/dist/github/FetchGitHubClient.js +128 -7
- package/dist/github/FetchGitHubClient.js.map +1 -1
- package/dist/github/GitHubPullRequestReviewProvider.d.ts +25 -0
- package/dist/github/GitHubPullRequestReviewProvider.d.ts.map +1 -0
- package/dist/github/GitHubPullRequestReviewProvider.js +170 -0
- package/dist/github/GitHubPullRequestReviewProvider.js.map +1 -0
- package/dist/http/errorHandler.d.ts.map +1 -1
- package/dist/http/errorHandler.js +20 -0
- package/dist/http/errorHandler.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/accounts/AccountController.d.ts +4 -0
- package/dist/modules/accounts/AccountController.d.ts.map +1 -1
- package/dist/modules/accounts/AccountController.js +78 -58
- package/dist/modules/accounts/AccountController.js.map +1 -1
- package/dist/modules/agentRuns/AgentRunController.d.ts.map +1 -1
- package/dist/modules/agentRuns/AgentRunController.js +8 -6
- package/dist/modules/agentRuns/AgentRunController.js.map +1 -1
- package/dist/modules/auth/AuthController.d.ts.map +1 -1
- package/dist/modules/auth/AuthController.js +23 -23
- package/dist/modules/auth/AuthController.js.map +1 -1
- package/dist/modules/board/BoardController.d.ts.map +1 -1
- package/dist/modules/board/BoardController.js +26 -26
- package/dist/modules/board/BoardController.js.map +1 -1
- package/dist/modules/bootstrap/BootstrapController.d.ts.map +1 -1
- package/dist/modules/bootstrap/BootstrapController.js +15 -15
- package/dist/modules/bootstrap/BootstrapController.js.map +1 -1
- package/dist/modules/brainstorm/BrainstormController.d.ts +3 -2
- package/dist/modules/brainstorm/BrainstormController.d.ts.map +1 -1
- package/dist/modules/brainstorm/BrainstormController.js +36 -52
- package/dist/modules/brainstorm/BrainstormController.js.map +1 -1
- package/dist/modules/clarity/ClarityReviewController.d.ts.map +1 -1
- package/dist/modules/clarity/ClarityReviewController.js +27 -25
- package/dist/modules/clarity/ClarityReviewController.js.map +1 -1
- package/dist/modules/consensus/ConsensusController.d.ts.map +1 -1
- package/dist/modules/consensus/ConsensusController.js +6 -4
- package/dist/modules/consensus/ConsensusController.js.map +1 -1
- package/dist/modules/documents/DocumentSourceController.d.ts.map +1 -1
- package/dist/modules/documents/DocumentSourceController.js +17 -17
- package/dist/modules/documents/DocumentSourceController.js.map +1 -1
- package/dist/modules/environments/EnvironmentController.d.ts.map +1 -1
- package/dist/modules/environments/EnvironmentController.js +24 -24
- package/dist/modules/environments/EnvironmentController.js.map +1 -1
- package/dist/modules/execution/ExecutionController.d.ts.map +1 -1
- package/dist/modules/execution/ExecutionController.js +57 -45
- package/dist/modules/execution/ExecutionController.js.map +1 -1
- package/dist/modules/followUp/FollowUpController.d.ts.map +1 -1
- package/dist/modules/followUp/FollowUpController.js +21 -17
- package/dist/modules/followUp/FollowUpController.js.map +1 -1
- package/dist/modules/fragmentLibrary/FragmentLibraryController.d.ts.map +1 -1
- package/dist/modules/fragmentLibrary/FragmentLibraryController.js +26 -26
- package/dist/modules/fragmentLibrary/FragmentLibraryController.js.map +1 -1
- package/dist/modules/github/GitHubController.d.ts.map +1 -1
- package/dist/modules/github/GitHubController.js +44 -44
- package/dist/modules/github/GitHubController.js.map +1 -1
- package/dist/modules/humanReview/HumanReviewController.d.ts +11 -0
- package/dist/modules/humanReview/HumanReviewController.d.ts.map +1 -0
- package/dist/modules/humanReview/HumanReviewController.js +22 -0
- package/dist/modules/humanReview/HumanReviewController.js.map +1 -0
- package/dist/modules/humanTest/HumanTestController.d.ts.map +1 -1
- package/dist/modules/humanTest/HumanTestController.js +17 -17
- package/dist/modules/humanTest/HumanTestController.js.map +1 -1
- package/dist/modules/incidentEnrichment/IncidentEnrichmentController.d.ts.map +1 -1
- package/dist/modules/incidentEnrichment/IncidentEnrichmentController.js +7 -7
- package/dist/modules/incidentEnrichment/IncidentEnrichmentController.js.map +1 -1
- package/dist/modules/kaizen/KaizenController.d.ts.map +1 -1
- package/dist/modules/kaizen/KaizenController.js +7 -5
- package/dist/modules/kaizen/KaizenController.js.map +1 -1
- package/dist/modules/localModels/LocalModelEndpointController.d.ts.map +1 -1
- package/dist/modules/localModels/LocalModelEndpointController.js +10 -11
- package/dist/modules/localModels/LocalModelEndpointController.js.map +1 -1
- package/dist/modules/localSettings/LocalSettingsController.d.ts.map +1 -1
- package/dist/modules/localSettings/LocalSettingsController.js +6 -6
- package/dist/modules/localSettings/LocalSettingsController.js.map +1 -1
- package/dist/modules/merge/MergePresetController.d.ts.map +1 -1
- package/dist/modules/merge/MergePresetController.js +10 -10
- package/dist/modules/merge/MergePresetController.js.map +1 -1
- package/dist/modules/modelPresets/ModelPresetController.d.ts.map +1 -1
- package/dist/modules/modelPresets/ModelPresetController.js +10 -10
- package/dist/modules/modelPresets/ModelPresetController.js.map +1 -1
- package/dist/modules/models/ModelController.d.ts.map +1 -1
- package/dist/modules/models/ModelController.js +6 -4
- package/dist/modules/models/ModelController.js.map +1 -1
- package/dist/modules/notifications/NotificationController.d.ts.map +1 -1
- package/dist/modules/notifications/NotificationController.js +11 -9
- package/dist/modules/notifications/NotificationController.js.map +1 -1
- package/dist/modules/openrouter/OpenRouterCatalogController.d.ts.map +1 -1
- package/dist/modules/openrouter/OpenRouterCatalogController.js +9 -10
- package/dist/modules/openrouter/OpenRouterCatalogController.js.map +1 -1
- package/dist/modules/pipelines/PipelineController.d.ts.map +1 -1
- package/dist/modules/pipelines/PipelineController.js +17 -15
- package/dist/modules/pipelines/PipelineController.js.map +1 -1
- package/dist/modules/promptFragments/PromptFragmentController.d.ts.map +1 -1
- package/dist/modules/promptFragments/PromptFragmentController.js +4 -2
- package/dist/modules/promptFragments/PromptFragmentController.js.map +1 -1
- package/dist/modules/providers/ApiKeyController.d.ts.map +1 -1
- package/dist/modules/providers/ApiKeyController.js +12 -12
- package/dist/modules/providers/ApiKeyController.js.map +1 -1
- package/dist/modules/providers/PersonalSubscriptionController.d.ts.map +1 -1
- package/dist/modules/providers/PersonalSubscriptionController.js +7 -8
- package/dist/modules/providers/PersonalSubscriptionController.js.map +1 -1
- package/dist/modules/providers/UserSecretController.d.ts.map +1 -1
- package/dist/modules/providers/UserSecretController.js +14 -15
- package/dist/modules/providers/UserSecretController.js.map +1 -1
- package/dist/modules/providers/VendorCredentialController.d.ts.map +1 -1
- package/dist/modules/providers/VendorCredentialController.js +7 -7
- package/dist/modules/providers/VendorCredentialController.js.map +1 -1
- package/dist/modules/providers/personalCredentialGate.d.ts +2 -2
- package/dist/modules/providers/personalCredentialGate.d.ts.map +1 -1
- package/dist/modules/providers/personalCredentialGate.js.map +1 -1
- package/dist/modules/provisioningLogs/ProvisioningLogController.d.ts.map +1 -1
- package/dist/modules/provisioningLogs/ProvisioningLogController.js +4 -3
- package/dist/modules/provisioningLogs/ProvisioningLogController.js.map +1 -1
- package/dist/modules/recurring/RecurringPipelineController.d.ts.map +1 -1
- package/dist/modules/recurring/RecurringPipelineController.js +15 -15
- package/dist/modules/recurring/RecurringPipelineController.js.map +1 -1
- package/dist/modules/recurring/TrackerSettingsController.d.ts.map +1 -1
- package/dist/modules/recurring/TrackerSettingsController.js +6 -6
- package/dist/modules/recurring/TrackerSettingsController.js.map +1 -1
- package/dist/modules/releaseHealth/ReleaseHealthController.d.ts.map +1 -1
- package/dist/modules/releaseHealth/ReleaseHealthController.js +14 -14
- package/dist/modules/releaseHealth/ReleaseHealthController.js.map +1 -1
- package/dist/modules/requirements/RequirementReviewController.d.ts.map +1 -1
- package/dist/modules/requirements/RequirementReviewController.js +43 -38
- package/dist/modules/requirements/RequirementReviewController.js.map +1 -1
- package/dist/modules/runners/RunnerPoolController.d.ts.map +1 -1
- package/dist/modules/runners/RunnerPoolController.js +12 -12
- package/dist/modules/runners/RunnerPoolController.js.map +1 -1
- package/dist/modules/sandbox/SandboxController.d.ts.map +1 -1
- package/dist/modules/sandbox/SandboxController.js +35 -26
- package/dist/modules/sandbox/SandboxController.js.map +1 -1
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsController.d.ts.map +1 -1
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsController.js +6 -6
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsController.js.map +1 -1
- package/dist/modules/serviceSpec/ServiceSpecController.d.ts.map +1 -1
- package/dist/modules/serviceSpec/ServiceSpecController.js +9 -8
- package/dist/modules/serviceSpec/ServiceSpecController.js.map +1 -1
- package/dist/modules/services/ServiceMountController.d.ts.map +1 -1
- package/dist/modules/services/ServiceMountController.js +14 -14
- package/dist/modules/services/ServiceMountController.js.map +1 -1
- package/dist/modules/settings/WorkspaceSettingsController.d.ts.map +1 -1
- package/dist/modules/settings/WorkspaceSettingsController.js +6 -6
- package/dist/modules/settings/WorkspaceSettingsController.js.map +1 -1
- package/dist/modules/slack/SlackController.d.ts.map +1 -1
- package/dist/modules/slack/SlackController.js +18 -18
- package/dist/modules/slack/SlackController.js.map +1 -1
- package/dist/modules/tasks/TaskSourceController.d.ts.map +1 -1
- package/dist/modules/tasks/TaskSourceController.js +19 -19
- package/dist/modules/tasks/TaskSourceController.js.map +1 -1
- package/dist/modules/workspaces/WorkspaceController.d.ts.map +1 -1
- package/dist/modules/workspaces/WorkspaceController.js +11 -11
- package/dist/modules/workspaces/WorkspaceController.js.map +1 -1
- package/package.json +11 -9
- package/dist/http/validation.d.ts +0 -21
- package/dist/http/validation.d.ts.map +0 -1
- package/dist/http/validation.js +0 -21
- package/dist/http/validation.js.map +0 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
const EMPTY = {
|
|
2
|
+
headSha: null,
|
|
3
|
+
requiredApprovingReviewCount: 1,
|
|
4
|
+
assignedReviewers: [],
|
|
5
|
+
approvals: 0,
|
|
6
|
+
unresolvedThreads: [],
|
|
7
|
+
comments: [],
|
|
8
|
+
};
|
|
9
|
+
/** A GitHub App's own comments/reviews show as `<app-slug>[bot]`; treat those as the bot. */
|
|
10
|
+
function isBotLogin(login) {
|
|
11
|
+
return login.endsWith('[bot]');
|
|
12
|
+
}
|
|
13
|
+
/** The standing review states that determine approval (a later COMMENTED/PENDING doesn't change it). */
|
|
14
|
+
const STANDING = new Set(['APPROVED', 'CHANGES_REQUESTED', 'DISMISSED']);
|
|
15
|
+
/**
|
|
16
|
+
* Reduce a PR's review event log to the count of distinct reviewers whose LATEST standing review
|
|
17
|
+
* is APPROVED. Mirrors GitHub's own rule: a `COMMENTED`/`PENDING` review after an approval does
|
|
18
|
+
* not dismiss it (only an explicit CHANGES_REQUESTED / DISMISSED does). Approvers are NOT filtered
|
|
19
|
+
* to the current requested-reviewer list — GitHub removes a reviewer from "requested" once they
|
|
20
|
+
* approve, so filtering there would never count an approval.
|
|
21
|
+
*/
|
|
22
|
+
function countApprovals(reviews) {
|
|
23
|
+
const latestByAuthor = new Map();
|
|
24
|
+
for (const r of reviews) {
|
|
25
|
+
if (!r.author || isBotLogin(r.author))
|
|
26
|
+
continue;
|
|
27
|
+
if (!STANDING.has(r.state))
|
|
28
|
+
continue;
|
|
29
|
+
latestByAuthor.set(r.author, r.state);
|
|
30
|
+
}
|
|
31
|
+
let approvals = 0;
|
|
32
|
+
for (const state of latestByAuthor.values())
|
|
33
|
+
if (state === 'APPROVED')
|
|
34
|
+
approvals++;
|
|
35
|
+
return approvals;
|
|
36
|
+
}
|
|
37
|
+
function toReviewThread(t) {
|
|
38
|
+
const first = t.comments[0];
|
|
39
|
+
const last = t.comments[t.comments.length - 1];
|
|
40
|
+
const body = (last?.body ?? '').trim();
|
|
41
|
+
return {
|
|
42
|
+
threadId: t.id,
|
|
43
|
+
author: first?.author ?? '',
|
|
44
|
+
bodyExcerpt: body.length > 280 ? `${body.slice(0, 277)}…` : body,
|
|
45
|
+
path: t.path,
|
|
46
|
+
line: t.line,
|
|
47
|
+
isBot: isBotLogin(last?.author ?? ''),
|
|
48
|
+
latestCommentAt: t.comments.reduce((m, c) => Math.max(m, c.createdAt), 0),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Reads a block's PR human-review state from GitHub for the `human-review` gate: assigned
|
|
53
|
+
* reviewers, the approval count (vs branch-protection's required count), the unresolved review
|
|
54
|
+
* threads and the plain PR comments. Reads LIVE each poll (no projection table), mirroring
|
|
55
|
+
* {@link GitHubCiStatusProvider}. Returns the empty snapshot (`headSha: null`) when there is no
|
|
56
|
+
* resolvable PR branch + number yet (the engine treats that as "nothing to gate").
|
|
57
|
+
*/
|
|
58
|
+
export class GitHubPullRequestReviewProvider {
|
|
59
|
+
deps;
|
|
60
|
+
constructor(deps) {
|
|
61
|
+
this.deps = deps;
|
|
62
|
+
}
|
|
63
|
+
async getReview(workspaceId, blockId, cachedRequiredApprovingReviewCount) {
|
|
64
|
+
const block = await this.deps.blockRepository.get(workspaceId, blockId);
|
|
65
|
+
const branch = block?.pullRequest?.branch;
|
|
66
|
+
const number = block?.pullRequest?.number;
|
|
67
|
+
if (!branch || number == null)
|
|
68
|
+
return EMPTY;
|
|
69
|
+
const target = await this.deps.resolveRepoTarget(workspaceId, blockId);
|
|
70
|
+
if (!target)
|
|
71
|
+
return EMPTY;
|
|
72
|
+
const ref = { owner: target.owner, repo: target.name };
|
|
73
|
+
const gh = this.deps.githubClient;
|
|
74
|
+
// Head commit of the PR branch (the latest commit on the ref), for the GateProbe. This gate
|
|
75
|
+
// polls indefinitely, so use the exact single-ref lookup (one API call, correctly 404→null on
|
|
76
|
+
// a deleted branch) rather than paginating the whole branch history just to read its tip.
|
|
77
|
+
const headSha = await gh.branchHeadSha(target.installationId, ref, branch);
|
|
78
|
+
if (!headSha)
|
|
79
|
+
return EMPTY;
|
|
80
|
+
// The required-approval count is static repo config (branch protection), so the gate caches
|
|
81
|
+
// it after the first probe and passes it back here — skip BOTH the base-branch lookup and the
|
|
82
|
+
// protection read on every subsequent poll. On the first probe (no cache) read protection
|
|
83
|
+
// against the PR's ACTUAL base branch (`pulls/{n}.base.ref`), not the repo default: a PR into
|
|
84
|
+
// a stricter protected branch (e.g. a release branch requiring 2 approvals) must be gated
|
|
85
|
+
// against its own rule. Fall back to the resolved repo default when the base ref is unreadable.
|
|
86
|
+
const requiredCount = cachedRequiredApprovingReviewCount != null
|
|
87
|
+
? cachedRequiredApprovingReviewCount
|
|
88
|
+
: await this.resolveRequiredApprovingReviewCount(target, ref, number);
|
|
89
|
+
// The reviews (approval) + unresolved threads are needed on EVERY poll. The plain issue
|
|
90
|
+
// comments and the assigned-reviewer list are consulted by the gate ONLY while the PR is
|
|
91
|
+
// not yet approved — `classifyHumanReview` discards comments once approved, and the
|
|
92
|
+
// assigned-reviewer list only feeds the "assign a reviewer" awaiting-approval card — so
|
|
93
|
+
// skip those two reads once the PR is approved. Over an indefinite review wait that trims
|
|
94
|
+
// the per-poll GitHub reads in the approved-with-open-threads window. (The dominant
|
|
95
|
+
// not-yet-approved wait still needs all four; the GraphQL thread read has no etag, so it
|
|
96
|
+
// can't be made conditional.) `approved` MUST mirror the gate's `isApproved` floor
|
|
97
|
+
// (`max(1, requiredApprovingReviewCount)` — see review.logic.ts) so the provider never
|
|
98
|
+
// skips a read the gate would have consulted.
|
|
99
|
+
const [reviews, threads] = await Promise.all([
|
|
100
|
+
gh.listPullRequestReviews?.(target.installationId, ref, number) ?? Promise.resolve([]),
|
|
101
|
+
gh.listReviewThreads?.(target.installationId, ref, number) ?? Promise.resolve([]),
|
|
102
|
+
]);
|
|
103
|
+
const approvals = countApprovals(reviews);
|
|
104
|
+
const approved = approvals >= Math.max(1, requiredCount);
|
|
105
|
+
const [assignedReviewers, comments] = approved
|
|
106
|
+
? [[], []]
|
|
107
|
+
: await Promise.all([
|
|
108
|
+
gh.listRequestedReviewers?.(target.installationId, ref, number) ?? Promise.resolve([]),
|
|
109
|
+
gh.listIssueComments?.(target.installationId, ref, number) ?? Promise.resolve([]),
|
|
110
|
+
]);
|
|
111
|
+
return {
|
|
112
|
+
headSha,
|
|
113
|
+
requiredApprovingReviewCount: requiredCount,
|
|
114
|
+
assignedReviewers,
|
|
115
|
+
approvals,
|
|
116
|
+
unresolvedThreads: threads.filter((t) => !t.isResolved).map(toReviewThread),
|
|
117
|
+
comments: comments.map((c) => ({
|
|
118
|
+
id: c.id,
|
|
119
|
+
author: c.author,
|
|
120
|
+
body: c.body,
|
|
121
|
+
createdAt: c.createdAt,
|
|
122
|
+
isBot: isBotLogin(c.author),
|
|
123
|
+
})),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Read branch-protection's required-approval count against the PR's actual base branch. */
|
|
127
|
+
async resolveRequiredApprovingReviewCount(target, ref, number) {
|
|
128
|
+
const gh = this.deps.githubClient;
|
|
129
|
+
if (!gh.getRequiredApprovingReviewCount)
|
|
130
|
+
return 1;
|
|
131
|
+
const baseRef = (await gh.getPullRequestBaseRef?.(target.installationId, ref, number)) ?? target.baseBranch;
|
|
132
|
+
return gh.getRequiredApprovingReviewCount(target.installationId, ref, baseRef);
|
|
133
|
+
}
|
|
134
|
+
async resolveThreads(workspaceId, blockId, threadIds, reply) {
|
|
135
|
+
if (threadIds.length === 0)
|
|
136
|
+
return;
|
|
137
|
+
const target = await this.deps.resolveRepoTarget(workspaceId, blockId);
|
|
138
|
+
if (!target)
|
|
139
|
+
return;
|
|
140
|
+
const ref = { owner: target.owner, repo: target.name };
|
|
141
|
+
const gh = this.deps.githubClient;
|
|
142
|
+
const wantsReply = reply.trim().length > 0;
|
|
143
|
+
const failed = [];
|
|
144
|
+
for (const threadId of threadIds) {
|
|
145
|
+
try {
|
|
146
|
+
// RESOLVE first, then (only if a reply was requested) post the courtesy reply. Doing the
|
|
147
|
+
// state-changing resolve before the cosmetic reply guarantees we never leave a bot reply
|
|
148
|
+
// as a thread's latest comment while it is still unresolved — that combination would hide
|
|
149
|
+
// the thread from the gate's outstanding set (bot-latest is treated as "addressed") yet
|
|
150
|
+
// leave it open forever. An empty `reply` means "resolve only" (the probe's reconcile
|
|
151
|
+
// retry passes ''), so a retry never double-posts the reply.
|
|
152
|
+
await gh.resolveReviewThread?.(target.installationId, ref, threadId);
|
|
153
|
+
if (wantsReply)
|
|
154
|
+
await gh.replyToReviewThread?.(target.installationId, ref, threadId, reply);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Best-effort per thread: keep going so a single bad thread doesn't strand the rest.
|
|
158
|
+
failed.push(threadId);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Surface a partial failure to the caller. The gate's onHelperComplete RETAINS the handed
|
|
162
|
+
// thread ids when this throws so the next probe's reconcile retries exactly those (a
|
|
163
|
+
// swallowed failure here would let the gate clear its stash and re-dispatch a whole fixer
|
|
164
|
+
// round for an already-fixed thread instead of the cheap resolve-only reconcile).
|
|
165
|
+
if (failed.length > 0) {
|
|
166
|
+
throw new Error(`Failed to resolve ${failed.length} review thread(s): ${failed.join(', ')}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=GitHubPullRequestReviewProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GitHubPullRequestReviewProvider.js","sourceRoot":"","sources":["../../src/github/GitHubPullRequestReviewProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../src/http/errorHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../src/http/errorHandler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAanC,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,QAAQ,CAmDhE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DomainError } from '@cat-factory/kernel';
|
|
2
|
+
import { SchemaValidationError } from '@toad-contracts/core';
|
|
2
3
|
import { logger } from '../observability/logger.js';
|
|
3
4
|
const STATUS_BY_CODE = {
|
|
4
5
|
not_found: 404,
|
|
@@ -10,6 +11,25 @@ const STATUS_BY_CODE = {
|
|
|
10
11
|
};
|
|
11
12
|
/** Maps domain errors to HTTP responses; anything else is a 500. */
|
|
12
13
|
export function handleError(error, c) {
|
|
14
|
+
// A contract request schema (path/query/header/body) rejected the input. Surface the
|
|
15
|
+
// same `{ error: { code: 'validation', ... } }` envelope the old @hono/valibot-validator
|
|
16
|
+
// `jsonBody` middleware produced, so the wire shape is unchanged after the contract migration.
|
|
17
|
+
if (error instanceof SchemaValidationError) {
|
|
18
|
+
return c.json({
|
|
19
|
+
error: {
|
|
20
|
+
code: 'validation',
|
|
21
|
+
message: 'Request failed validation',
|
|
22
|
+
issues: error.issues.map((issue) => ({
|
|
23
|
+
path: issue.path
|
|
24
|
+
?.map((segment) => typeof segment === 'object' && segment !== null && 'key' in segment
|
|
25
|
+
? String(segment.key)
|
|
26
|
+
: String(segment))
|
|
27
|
+
.join('.'),
|
|
28
|
+
message: issue.message,
|
|
29
|
+
})),
|
|
30
|
+
},
|
|
31
|
+
}, 400);
|
|
32
|
+
}
|
|
13
33
|
if (error instanceof DomainError) {
|
|
14
34
|
return c.json({
|
|
15
35
|
error: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/http/errorHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/http/errorHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAG5D,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAEnD,MAAM,cAAc,GAAsD;IACxE,SAAS,EAAE,GAAG;IACd,UAAU,EAAE,GAAG;IACf,QAAQ,EAAE,GAAG;IACb,mFAAmF;IACnF,qFAAqF;IACrF,mBAAmB,EAAE,GAAG;CACzB,CAAA;AAED,oEAAoE;AACpE,MAAM,UAAU,WAAW,CAAC,KAAc,EAAE,CAAU;IACpD,qFAAqF;IACrF,yFAAyF;IACzF,+FAA+F;IAC/F,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;QAC3C,OAAO,CAAC,CAAC,IAAI,CACX;YACE,KAAK,EAAE;gBACL,IAAI,EAAE,YAAY;gBAClB,OAAO,EAAE,2BAA2B;gBACpC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBACnC,IAAI,EAAE,KAAK,CAAC,IAAI;wBACd,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAChB,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI,OAAO;wBACjE,CAAC,CAAC,MAAM,CAAE,OAAgC,CAAC,GAAG,CAAC;wBAC/C,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CACpB;yBACA,IAAI,CAAC,GAAG,CAAC;oBACZ,OAAO,EAAE,KAAK,CAAC,OAAO;iBACvB,CAAC,CAAC;aACJ;SACF,EACD,GAAG,CACJ,CAAA;IACH,CAAC;IACD,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO,CAAC,CAAC,IAAI,CACX;YACE,KAAK,EAAE;gBACL,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrD;SACF,EACD,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAC3B,CAAA;IACH,CAAC;IACD,6EAA6E;IAC7E,gCAAgC;IAChC,MAAM,CAAC,KAAK,CACV;QACE,GAAG,EACD,KAAK,YAAY,KAAK;YACpB,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE;YAChD,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE;QAChC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM;QACpB,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ;KAClC,EACD,yBAAyB,CAC1B,CAAA;IACD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,uBAAuB,EAAE,EAAE,EAAE,GAAG,CAAC,CAAA;AACvF,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,6 @@ export { FanOutEventPublisher, type FanOutEventPublisherDependencies, } from './
|
|
|
25
25
|
export { InAppNotificationChannel } from './events/InAppNotificationChannel.js';
|
|
26
26
|
export { mountAuthGate } from './http/authGate.js';
|
|
27
27
|
export { param } from './http/params.js';
|
|
28
|
-
export { jsonBody } from './http/validation.js';
|
|
29
28
|
export { handleError } from './http/errorHandler.js';
|
|
30
29
|
export { parseAllowedOrigins, resolveCorsOrigin } from './http/cors.js';
|
|
31
30
|
export { base64url, base64urlToBytes, pkcs8PemToDer, timingSafeEqual } from './crypto/encoding.js';
|
|
@@ -39,6 +38,7 @@ export { FetchGitHubClient, GitHubApiError, type FetchGitHubClientDependencies,
|
|
|
39
38
|
export { FetchGitHubProvisioningClient, type FetchGitHubProvisioningClientDependencies, } from './github/FetchGitHubProvisioningClient.js';
|
|
40
39
|
export { WebCryptoWebhookVerifier } from './github/WebCryptoWebhookVerifier.js';
|
|
41
40
|
export { GitHubCiStatusProvider, type GitHubCiStatusProviderDependencies, } from './github/GitHubCiStatusProvider.js';
|
|
41
|
+
export { GitHubPullRequestReviewProvider, type GitHubPullRequestReviewProviderDependencies, } from './github/GitHubPullRequestReviewProvider.js';
|
|
42
42
|
export { GitHubMergeabilityProvider, classifyMergeability, type GitHubMergeabilityProviderDependencies, } from './github/GitHubMergeabilityProvider.js';
|
|
43
43
|
export { GitHubBranchUpdater, type GitHubBranchUpdaterDependencies, } from './github/GitHubBranchUpdater.js';
|
|
44
44
|
export { GitHubPullRequestMerger, type GitHubPullRequestMergerDependencies, } from './github/GitHubPullRequestMerger.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AACjE,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EACL,WAAW,EACX,KAAK,uBAAuB,EAC5B,KAAK,cAAc,GACpB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,WAAW,EACX,KAAK,uBAAuB,EAC5B,KAAK,cAAc,GACpB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAA;AAC7E,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,yCAAyC,CAAA;AAIhD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAA;AAC3E,OAAO,EACL,sBAAsB,EACtB,KAAK,kCAAkC,EACvC,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,GACtB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,uBAAuB,EAAE,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAClG,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAC1F,OAAO,EACL,iCAAiC,EACjC,KAAK,0BAA0B,GAChC,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,4BAA4B,EAC5B,KAAK,kBAAkB,GACxB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EACL,yBAAyB,EACzB,KAAK,qCAAqC,GAC3C,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,sBAAsB,EACtB,KAAK,6BAA6B,GACnC,MAAM,+BAA+B,CAAA;AAGtC,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,UAAU,GACX,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EACL,oBAAoB,EACpB,KAAK,gCAAgC,GACtC,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,6 @@ export { FanOutEventPublisher, } from './events/FanOutEventPublisher.js';
|
|
|
34
34
|
export { InAppNotificationChannel } from './events/InAppNotificationChannel.js';
|
|
35
35
|
export { mountAuthGate } from './http/authGate.js';
|
|
36
36
|
export { param } from './http/params.js';
|
|
37
|
-
export { jsonBody } from './http/validation.js';
|
|
38
37
|
export { handleError } from './http/errorHandler.js';
|
|
39
38
|
export { parseAllowedOrigins, resolveCorsOrigin } from './http/cors.js';
|
|
40
39
|
export { base64url, base64urlToBytes, pkcs8PemToDer, timingSafeEqual } from './crypto/encoding.js';
|
|
@@ -57,6 +56,7 @@ export { FetchGitHubClient, GitHubApiError, } from './github/FetchGitHubClient.j
|
|
|
57
56
|
export { FetchGitHubProvisioningClient, } from './github/FetchGitHubProvisioningClient.js';
|
|
58
57
|
export { WebCryptoWebhookVerifier } from './github/WebCryptoWebhookVerifier.js';
|
|
59
58
|
export { GitHubCiStatusProvider, } from './github/GitHubCiStatusProvider.js';
|
|
59
|
+
export { GitHubPullRequestReviewProvider, } from './github/GitHubPullRequestReviewProvider.js';
|
|
60
60
|
export { GitHubMergeabilityProvider, classifyMergeability, } from './github/GitHubMergeabilityProvider.js';
|
|
61
61
|
export { GitHubBranchUpdater, } from './github/GitHubBranchUpdater.js';
|
|
62
62
|
export { GitHubPullRequestMerger, } from './github/GitHubPullRequestMerger.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,gFAAgF;AAChF,8EAA8E;AAC9E,qEAAqE;AACrE,OAAO,EAAE,MAAM,EAAe,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAqC,MAAM,eAAe,CAAA;AACjE,OAAO,EAYN,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAqB,MAAM,mBAAmB,CAAA;AAClE,OAAO,EACL,WAAW,GAGZ,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,WAAW,GAGZ,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAA;AAC7E,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GAGvB,MAAM,yCAAyC,CAAA;AAChD,mFAAmF;AACnF,kFAAkF;AAClF,oFAAoF;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAA;AAC3E,OAAO,EACL,sBAAsB,GAMvB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,uBAAuB,EAA8B,MAAM,8BAA8B,CAAA;AAClG,OAAO,EAAE,eAAe,EAA+B,MAAM,6BAA6B,CAAA;AAC1F,OAAO,EACL,iCAAiC,GAElC,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,4BAA4B,GAE7B,MAAM,kCAAkC,CAAA;AACzC,OAAO,EACL,yBAAyB,GAE1B,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,sBAAsB,GAEvB,MAAM,+BAA+B,CAAA;AACtC,qFAAqF;AACrF,4FAA4F;AAC5F,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,UAAU,GACX,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EACL,oBAAoB,GAErB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,gFAAgF;AAChF,8EAA8E;AAC9E,qEAAqE;AACrE,OAAO,EAAE,MAAM,EAAe,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAqC,MAAM,eAAe,CAAA;AACjE,OAAO,EAYN,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAqB,MAAM,mBAAmB,CAAA;AAClE,OAAO,EACL,WAAW,GAGZ,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,WAAW,GAGZ,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAA;AAC7E,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GAGvB,MAAM,yCAAyC,CAAA;AAChD,mFAAmF;AACnF,kFAAkF;AAClF,oFAAoF;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAA;AAC3E,OAAO,EACL,sBAAsB,GAMvB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,uBAAuB,EAA8B,MAAM,8BAA8B,CAAA;AAClG,OAAO,EAAE,eAAe,EAA+B,MAAM,6BAA6B,CAAA;AAC1F,OAAO,EACL,iCAAiC,GAElC,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,4BAA4B,GAE7B,MAAM,kCAAkC,CAAA;AACzC,OAAO,EACL,yBAAyB,GAE1B,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,sBAAsB,GAEvB,MAAM,+BAA+B,CAAA;AACtC,qFAAqF;AACrF,4FAA4F;AAC5F,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,UAAU,GACX,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EACL,oBAAoB,GAErB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACvE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAClG,kFAAkF;AAClF,8EAA8E;AAC9E,kEAAkE;AAClE,OAAO,EACL,qBAAqB,GAEtB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EAAE,6BAA6B,EAAE,MAAM,2CAA2C,CAAA;AACzF,OAAO,EAAE,aAAa,EAAkC,MAAM,2BAA2B,CAAA;AACzF,OAAO,EACL,iBAAiB,GAIlB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AACpF,gFAAgF;AAChF,kFAAkF;AAClF,qFAAqF;AACrF,6BAA6B;AAC7B,OAAO,EACL,iBAAiB,EACjB,cAAc,GAEf,MAAM,+BAA+B,CAAA;AACtC,oFAAoF;AACpF,qEAAqE;AACrE,OAAO,EACL,6BAA6B,GAE9B,MAAM,2CAA2C,CAAA;AAClD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EACL,sBAAsB,GAEvB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EACL,+BAA+B,GAEhC,MAAM,6CAA6C,CAAA;AACpD,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GAErB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EACL,mBAAmB,GAEpB,MAAM,iCAAiC,CAAA;AACxC,OAAO,EACL,uBAAuB,GAExB,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EACL,UAAU,EACV,cAAc,GAIf,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,GAGb,MAAM,oBAAoB,CAAA;AAqB3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,mFAAmF;AACnF,iEAAiE;AACjE,cAAc,0BAA0B,CAAA;AACxC,cAAc,kCAAkC,CAAA"}
|
|
@@ -5,6 +5,10 @@ import type { AppEnv } from '../../http/env.js';
|
|
|
5
5
|
* plus any orgs they belong to), org creation, and membership management. Accounts
|
|
6
6
|
* are an authenticated concept; with auth disabled (no signed-in user) there is a
|
|
7
7
|
* single implicit dev context, so the list is empty and mutations are refused.
|
|
8
|
+
*
|
|
9
|
+
* Every route is mounted from its `@cat-factory/contracts` contract via
|
|
10
|
+
* `buildHonoRoute`: the method/path and request validation come from the contract,
|
|
11
|
+
* and `c.req.valid(...)` + the `c.json(body, status)` return are typed from it.
|
|
8
12
|
*/
|
|
9
13
|
export declare function accountController(): Hono<AppEnv>;
|
|
10
14
|
//# sourceMappingURL=AccountController.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountController.d.ts","sourceRoot":"","sources":["../../../src/modules/accounts/AccountController.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AccountController.d.ts","sourceRoot":"","sources":["../../../src/modules/accounts/AccountController.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAgB/C;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAAC,MAAM,CAAC,CAwOhD"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { addAccountApiKeyContract, addAccountMemberContract, connectEmailContract, createAccountContract, createInvitationContract, disconnectEmailContract, getAccountSettingsContract, getEmailConnectionContract, listAccountApiKeysContract, listAccountMembersContract, listAccountsContract, listInvitationsContract, removeAccountApiKeyContract, revokeInvitationContract, setMemberRolesContract, testEmailContract, updateAccountContract, updateAccountSettingsContract, } from '@cat-factory/contracts';
|
|
2
|
+
import { buildHonoRoute } from '@toad-contracts/hono';
|
|
2
3
|
import { Hono } from 'hono';
|
|
3
|
-
import { param } from '../../http/params.js';
|
|
4
|
-
import { jsonBody } from '../../http/validation.js';
|
|
5
4
|
import { apiKeyToWire } from '../providers/ApiKeyController.js';
|
|
6
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* The signed-in user, narrowed to what the tenancy layer needs. Generic over the
|
|
7
|
+
* env so it accepts a contract-typed handler context (`ContractEnv<T> & AppEnv`),
|
|
8
|
+
* which Hono treats as a distinct, non-assignable env from the bare `AppEnv`.
|
|
9
|
+
*/
|
|
7
10
|
function accountUser(c) {
|
|
8
11
|
const user = c.get('user');
|
|
9
12
|
return user ? { id: user.id, login: user.login, name: user.name } : null;
|
|
@@ -14,74 +17,81 @@ const signInRequired = (c) => c.json({ error: { code: 'unauthorized', message: '
|
|
|
14
17
|
* plus any orgs they belong to), org creation, and membership management. Accounts
|
|
15
18
|
* are an authenticated concept; with auth disabled (no signed-in user) there is a
|
|
16
19
|
* single implicit dev context, so the list is empty and mutations are refused.
|
|
20
|
+
*
|
|
21
|
+
* Every route is mounted from its `@cat-factory/contracts` contract via
|
|
22
|
+
* `buildHonoRoute`: the method/path and request validation come from the contract,
|
|
23
|
+
* and `c.req.valid(...)` + the `c.json(body, status)` return are typed from it.
|
|
17
24
|
*/
|
|
18
25
|
export function accountController() {
|
|
19
26
|
const app = new Hono();
|
|
20
|
-
app
|
|
27
|
+
buildHonoRoute(app, listAccountsContract, async (c) => {
|
|
21
28
|
const user = accountUser(c);
|
|
22
29
|
if (!user)
|
|
23
|
-
return c.json([]);
|
|
24
|
-
return c.json(await c.get('container').accountService.listForUser(user));
|
|
30
|
+
return c.json([], 200);
|
|
31
|
+
return c.json(await c.get('container').accountService.listForUser(user), 200);
|
|
25
32
|
});
|
|
26
|
-
app
|
|
33
|
+
buildHonoRoute(app, createAccountContract, async (c) => {
|
|
27
34
|
const user = accountUser(c);
|
|
28
35
|
if (!user)
|
|
29
36
|
return signInRequired(c);
|
|
30
37
|
const account = await c.get('container').accountService.createOrg(user, c.req.valid('json'));
|
|
31
38
|
return c.json(account, 201);
|
|
32
39
|
});
|
|
33
|
-
app
|
|
40
|
+
buildHonoRoute(app, updateAccountContract, async (c) => {
|
|
34
41
|
const user = accountUser(c);
|
|
35
42
|
if (!user)
|
|
36
43
|
return signInRequired(c);
|
|
37
44
|
const account = await c
|
|
38
45
|
.get('container')
|
|
39
|
-
.accountService.updateSettings(
|
|
40
|
-
return c.json(account);
|
|
46
|
+
.accountService.updateSettings(c.req.valid('param').accountId, user.id, c.req.valid('json'));
|
|
47
|
+
return c.json(account, 200);
|
|
41
48
|
});
|
|
42
|
-
app
|
|
49
|
+
buildHonoRoute(app, listAccountMembersContract, async (c) => {
|
|
43
50
|
const user = accountUser(c);
|
|
44
51
|
if (!user)
|
|
45
52
|
return signInRequired(c);
|
|
46
53
|
const accounts = c.get('container').accountService;
|
|
54
|
+
const { accountId } = c.req.valid('param');
|
|
47
55
|
// Membership in the account is required to see its roster (404 otherwise).
|
|
48
|
-
await accounts.requireMember(
|
|
49
|
-
return c.json(await accounts.members(
|
|
56
|
+
await accounts.requireMember(accountId, user.id);
|
|
57
|
+
return c.json(await accounts.members(accountId), 200);
|
|
50
58
|
});
|
|
51
|
-
app
|
|
59
|
+
buildHonoRoute(app, addAccountMemberContract, async (c) => {
|
|
52
60
|
const user = accountUser(c);
|
|
53
61
|
if (!user)
|
|
54
62
|
return signInRequired(c);
|
|
55
63
|
const body = c.req.valid('json');
|
|
56
64
|
const member = await c
|
|
57
65
|
.get('container')
|
|
58
|
-
.accountService.addMember(
|
|
66
|
+
.accountService.addMember(c.req.valid('param').accountId, user.id, body.userId, body.roles);
|
|
59
67
|
return c.json(member, 201);
|
|
60
68
|
});
|
|
61
69
|
// Set a member's role set (admin-only). The acting admin can't drop their own admin.
|
|
62
|
-
app
|
|
70
|
+
buildHonoRoute(app, setMemberRolesContract, async (c) => {
|
|
63
71
|
const user = accountUser(c);
|
|
64
72
|
if (!user)
|
|
65
73
|
return signInRequired(c);
|
|
74
|
+
const { accountId, userId } = c.req.valid('param');
|
|
66
75
|
const member = await c
|
|
67
76
|
.get('container')
|
|
68
|
-
.accountService.setMemberRoles(
|
|
69
|
-
return c.json(member);
|
|
77
|
+
.accountService.setMemberRoles(accountId, user.id, userId, c.req.valid('json').roles);
|
|
78
|
+
return c.json(member, 200);
|
|
70
79
|
});
|
|
71
80
|
// ---- Invitations (email-based org onboarding) ---------------------------
|
|
72
81
|
// Available only when the invitation repository is wired (opt-in feature).
|
|
73
|
-
app
|
|
82
|
+
buildHonoRoute(app, listInvitationsContract, async (c) => {
|
|
74
83
|
const user = accountUser(c);
|
|
75
84
|
if (!user)
|
|
76
85
|
return signInRequired(c);
|
|
77
86
|
const container = c.get('container');
|
|
78
87
|
if (!container.invitations)
|
|
79
|
-
return c.json([]);
|
|
88
|
+
return c.json([], 200);
|
|
89
|
+
const { accountId } = c.req.valid('param');
|
|
80
90
|
// Membership is required to view the account's pending invitations.
|
|
81
|
-
await container.accountService.requireMember(
|
|
82
|
-
return c.json(await container.invitations.list(
|
|
91
|
+
await container.accountService.requireMember(accountId, user.id);
|
|
92
|
+
return c.json(await container.invitations.list(accountId), 200);
|
|
83
93
|
});
|
|
84
|
-
app
|
|
94
|
+
buildHonoRoute(app, createInvitationContract, async (c) => {
|
|
85
95
|
const user = accountUser(c);
|
|
86
96
|
if (!user)
|
|
87
97
|
return signInRequired(c);
|
|
@@ -90,19 +100,20 @@ export function accountController() {
|
|
|
90
100
|
return c.json({ error: { code: 'unavailable', message: 'Invitations are not configured' } }, 503);
|
|
91
101
|
}
|
|
92
102
|
const body = c.req.valid('json');
|
|
93
|
-
const created = await container.invitations.invite(
|
|
103
|
+
const created = await container.invitations.invite(c.req.valid('param').accountId, user.id, body.email, body.roles);
|
|
94
104
|
// The raw accept link is returned so an operator can share it manually when no
|
|
95
105
|
// email transport is configured; never re-derivable afterwards.
|
|
96
106
|
return c.json({ invitation: created.invitation, acceptUrl: created.acceptUrl }, 201);
|
|
97
107
|
});
|
|
98
|
-
app
|
|
108
|
+
buildHonoRoute(app, revokeInvitationContract, async (c) => {
|
|
99
109
|
const user = accountUser(c);
|
|
100
110
|
if (!user)
|
|
101
111
|
return signInRequired(c);
|
|
102
112
|
const container = c.get('container');
|
|
103
113
|
if (!container.invitations)
|
|
104
114
|
return c.body(null, 204);
|
|
105
|
-
|
|
115
|
+
const { accountId, invitationId } = c.req.valid('param');
|
|
116
|
+
await container.invitations.revoke(accountId, user.id, invitationId);
|
|
106
117
|
return c.body(null, 204);
|
|
107
118
|
});
|
|
108
119
|
// ---- Account-scoped provider API keys (admin-onboarded, shared org pool) ----
|
|
@@ -111,53 +122,57 @@ export function accountController() {
|
|
|
111
122
|
// the raw key is write-only — only secret-free metadata is ever returned. Available
|
|
112
123
|
// only when the API-key store is wired (ENCRYPTION_KEY).
|
|
113
124
|
const apiKeysUnavailable = (c) => c.json({ error: { code: 'unavailable', message: 'API key storage is not configured' } }, 503);
|
|
114
|
-
app
|
|
125
|
+
buildHonoRoute(app, listAccountApiKeysContract, async (c) => {
|
|
115
126
|
const user = accountUser(c);
|
|
116
127
|
if (!user)
|
|
117
128
|
return signInRequired(c);
|
|
118
129
|
const container = c.get('container');
|
|
119
130
|
if (!container.apiKeys)
|
|
120
131
|
return apiKeysUnavailable(c);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
const { accountId } = c.req.valid('param');
|
|
133
|
+
await container.accountService.requireAdmin(accountId, user.id);
|
|
134
|
+
const keys = await container.apiKeys.listKeys('account', accountId);
|
|
135
|
+
return c.json({ keys: keys.map(apiKeyToWire) }, 200);
|
|
124
136
|
});
|
|
125
|
-
app
|
|
137
|
+
buildHonoRoute(app, addAccountApiKeyContract, async (c) => {
|
|
126
138
|
const user = accountUser(c);
|
|
127
139
|
if (!user)
|
|
128
140
|
return signInRequired(c);
|
|
129
141
|
const container = c.get('container');
|
|
130
142
|
if (!container.apiKeys)
|
|
131
143
|
return apiKeysUnavailable(c);
|
|
132
|
-
|
|
133
|
-
|
|
144
|
+
const { accountId } = c.req.valid('param');
|
|
145
|
+
await container.accountService.requireAdmin(accountId, user.id);
|
|
146
|
+
const summary = await container.apiKeys.addKey('account', accountId, c.req.valid('json'));
|
|
134
147
|
return c.json(apiKeyToWire(summary), 201);
|
|
135
148
|
});
|
|
136
|
-
app
|
|
149
|
+
buildHonoRoute(app, removeAccountApiKeyContract, async (c) => {
|
|
137
150
|
const user = accountUser(c);
|
|
138
151
|
if (!user)
|
|
139
152
|
return signInRequired(c);
|
|
140
153
|
const container = c.get('container');
|
|
141
154
|
if (!container.apiKeys)
|
|
142
155
|
return apiKeysUnavailable(c);
|
|
143
|
-
|
|
144
|
-
await container.
|
|
156
|
+
const { accountId, id } = c.req.valid('param');
|
|
157
|
+
await container.accountService.requireAdmin(accountId, user.id);
|
|
158
|
+
await container.apiKeys.removeKey('account', accountId, id);
|
|
145
159
|
return c.body(null, 204);
|
|
146
160
|
});
|
|
147
161
|
// ---- Email sender connection (per-account, UI-onboarded) ----------------
|
|
148
162
|
// Owner-only mutations; available only when the email module is wired.
|
|
149
|
-
app
|
|
163
|
+
buildHonoRoute(app, getEmailConnectionContract, async (c) => {
|
|
150
164
|
const user = accountUser(c);
|
|
151
165
|
if (!user)
|
|
152
166
|
return signInRequired(c);
|
|
153
167
|
const container = c.get('container');
|
|
154
168
|
if (!container.email)
|
|
155
|
-
return c.json({ connection: null, configured: false });
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
169
|
+
return c.json({ connection: null, configured: false }, 200);
|
|
170
|
+
const { accountId } = c.req.valid('param');
|
|
171
|
+
await container.accountService.requireMember(accountId, user.id);
|
|
172
|
+
const connection = await container.email.getConnection(accountId);
|
|
173
|
+
return c.json({ connection, configured: true }, 200);
|
|
159
174
|
});
|
|
160
|
-
app
|
|
175
|
+
buildHonoRoute(app, connectEmailContract, async (c) => {
|
|
161
176
|
const user = accountUser(c);
|
|
162
177
|
if (!user)
|
|
163
178
|
return signInRequired(c);
|
|
@@ -165,22 +180,24 @@ export function accountController() {
|
|
|
165
180
|
if (!container.email) {
|
|
166
181
|
return c.json({ error: { code: 'unavailable', message: 'Email is not configured' } }, 503);
|
|
167
182
|
}
|
|
168
|
-
|
|
169
|
-
|
|
183
|
+
const { accountId } = c.req.valid('param');
|
|
184
|
+
await container.accountService.requireAdmin(accountId, user.id);
|
|
185
|
+
const connection = await container.email.connect(accountId, c.req.valid('json'));
|
|
170
186
|
return c.json(connection, 201);
|
|
171
187
|
});
|
|
172
|
-
app
|
|
188
|
+
buildHonoRoute(app, disconnectEmailContract, async (c) => {
|
|
173
189
|
const user = accountUser(c);
|
|
174
190
|
if (!user)
|
|
175
191
|
return signInRequired(c);
|
|
176
192
|
const container = c.get('container');
|
|
177
193
|
if (!container.email)
|
|
178
194
|
return c.body(null, 204);
|
|
179
|
-
|
|
180
|
-
await container.
|
|
195
|
+
const { accountId } = c.req.valid('param');
|
|
196
|
+
await container.accountService.requireAdmin(accountId, user.id);
|
|
197
|
+
await container.email.disconnect(accountId);
|
|
181
198
|
return c.body(null, 204);
|
|
182
199
|
});
|
|
183
|
-
app
|
|
200
|
+
buildHonoRoute(app, testEmailContract, async (c) => {
|
|
184
201
|
const user = accountUser(c);
|
|
185
202
|
if (!user)
|
|
186
203
|
return signInRequired(c);
|
|
@@ -188,9 +205,10 @@ export function accountController() {
|
|
|
188
205
|
if (!container.email) {
|
|
189
206
|
return c.json({ error: { code: 'unavailable', message: 'Email is not configured' } }, 503);
|
|
190
207
|
}
|
|
191
|
-
|
|
192
|
-
await container.
|
|
193
|
-
|
|
208
|
+
const { accountId } = c.req.valid('param');
|
|
209
|
+
await container.accountService.requireAdmin(accountId, user.id);
|
|
210
|
+
await container.email.sendTest(accountId, c.req.valid('json').to);
|
|
211
|
+
return c.json({ ok: true }, 200);
|
|
194
212
|
});
|
|
195
213
|
// ---- Deployment settings (per-account, admin-only) ----------------------
|
|
196
214
|
// The integration secrets (Slack OAuth / web-search / Langfuse) + tuning (retention,
|
|
@@ -199,25 +217,27 @@ export function accountController() {
|
|
|
199
217
|
// settings store is wired (ENCRYPTION_KEY). Admin-gated for BOTH read and write —
|
|
200
218
|
// these are sensitive deployment knobs.
|
|
201
219
|
const settingsUnavailable = (c) => c.json({ error: { code: 'unavailable', message: 'Account settings storage is not configured' } }, 503);
|
|
202
|
-
app
|
|
220
|
+
buildHonoRoute(app, getAccountSettingsContract, async (c) => {
|
|
203
221
|
const user = accountUser(c);
|
|
204
222
|
if (!user)
|
|
205
223
|
return signInRequired(c);
|
|
206
224
|
const container = c.get('container');
|
|
207
225
|
if (!container.accountSettings)
|
|
208
226
|
return settingsUnavailable(c);
|
|
209
|
-
|
|
210
|
-
|
|
227
|
+
const { accountId } = c.req.valid('param');
|
|
228
|
+
await container.accountService.requireAdmin(accountId, user.id);
|
|
229
|
+
return c.json(await container.accountSettings.service.read(accountId), 200);
|
|
211
230
|
});
|
|
212
|
-
app
|
|
231
|
+
buildHonoRoute(app, updateAccountSettingsContract, async (c) => {
|
|
213
232
|
const user = accountUser(c);
|
|
214
233
|
if (!user)
|
|
215
234
|
return signInRequired(c);
|
|
216
235
|
const container = c.get('container');
|
|
217
236
|
if (!container.accountSettings)
|
|
218
237
|
return settingsUnavailable(c);
|
|
219
|
-
|
|
220
|
-
|
|
238
|
+
const { accountId } = c.req.valid('param');
|
|
239
|
+
await container.accountService.requireAdmin(accountId, user.id);
|
|
240
|
+
return c.json(await container.accountSettings.service.write(accountId, c.req.valid('json')), 200);
|
|
221
241
|
});
|
|
222
242
|
return app;
|
|
223
243
|
}
|