@danypops/tickets 0.8.5 → 0.8.6
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danypops/tickets",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "Unified CLI, daemon, and TypeScript library for issue tracking across GitHub, GitLab, and Jira.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"typecheck": "tsc --noEmit"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@danypops/vehicle-core": "^0.
|
|
28
|
-
"@danypops/vehicle-server": "^0.
|
|
27
|
+
"@danypops/vehicle-core": "^0.12.1",
|
|
28
|
+
"@danypops/vehicle-server": "^0.17.0",
|
|
29
29
|
"@danypops/vehicle-client": "^0.5.0",
|
|
30
30
|
"@danypops/enigma-client": "^0.3.0",
|
|
31
31
|
"@gitbeaker/rest": "^43.8.0",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import {
|
|
18
18
|
bindVehicleOperation,
|
|
19
|
+
defineErrorMapping,
|
|
19
20
|
defineLooseObjectSchema,
|
|
20
21
|
defineVehicleOperation,
|
|
21
22
|
type LooseObjectProperty,
|
|
@@ -24,11 +25,21 @@ import {
|
|
|
24
25
|
} from "@danypops/vehicle-core";
|
|
25
26
|
import { VehicleRegistry } from "@danypops/vehicle-server";
|
|
26
27
|
import type { BackendCapabilities, TicketService } from "../issue/service.js";
|
|
28
|
+
import { statusForKnownTicketError } from "../rpc/error-status.js";
|
|
27
29
|
import type { TicketOperation } from "../rpc/ops.js";
|
|
28
30
|
import { TICKET_OP_HANDLERS, type TicketsAppDeps } from "../rpc/server.js";
|
|
29
31
|
|
|
30
32
|
const OWNER = "tickets";
|
|
31
33
|
|
|
34
|
+
const withTicketsErrorParity = defineErrorMapping(
|
|
35
|
+
[
|
|
36
|
+
{ matches: (error) => statusForKnownTicketError(error) === 404, category: "not_found" },
|
|
37
|
+
{ matches: (error) => statusForKnownTicketError(error) === 400, category: "validation" },
|
|
38
|
+
{ matches: (error) => statusForKnownTicketError(error) === 422, category: "authorization" },
|
|
39
|
+
],
|
|
40
|
+
{ fallbackCategory: "internal", fallbackCode: "handler-failed", fallbackMessage: "Tickets operation failed" },
|
|
41
|
+
);
|
|
42
|
+
|
|
32
43
|
const LIMITS = { defaultTimeoutMs: 10_000, maxTimeoutMs: 30_000, maxRequestBytes: 65_536, maxResponseBytes: 262_144 };
|
|
33
44
|
|
|
34
45
|
const stringProp: LooseObjectProperty = { type: "string" };
|
|
@@ -288,10 +299,8 @@ export function createTicketsVehicleRegistry(deps: Omit<TicketsAppDeps, "vehicle
|
|
|
288
299
|
version: deps.version,
|
|
289
300
|
description: "Unified issue tracking across GitHub, GitLab, and Jira.",
|
|
290
301
|
});
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
// here either -- TICKET_OP_HANDLERS' real errors reach the registry's own catch-all as-is.
|
|
294
|
-
|
|
302
|
+
// Every handler passes through the reviewed mapper above; unmatched failures stay redacted.
|
|
303
|
+
registry.setExposeHandlerFailureDetails(true);
|
|
295
304
|
for (const spec of OPERATIONS) {
|
|
296
305
|
const operation = defineVehicleOperation({
|
|
297
306
|
name: spec.action,
|
|
@@ -308,7 +317,11 @@ export function createTicketsVehicleRegistry(deps: Omit<TicketsAppDeps, "vehicle
|
|
|
308
317
|
const mapInput = spec.mapInput ?? ((input: Record<string, unknown>) => input);
|
|
309
318
|
registry.register(
|
|
310
319
|
OWNER,
|
|
311
|
-
bindVehicleOperation(
|
|
320
|
+
bindVehicleOperation(
|
|
321
|
+
operation,
|
|
322
|
+
() => async (context) =>
|
|
323
|
+
withTicketsErrorParity<unknown>(() => handler(deps, mapInput(context.input as Record<string, unknown>) as never)),
|
|
324
|
+
),
|
|
312
325
|
);
|
|
313
326
|
}
|
|
314
327
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AuthRequiredError, IssueNotFoundError } from "../issue/errors.js";
|
|
2
|
+
import { NotSupportedError, UnknownBackendError } from "../issue/service.js";
|
|
3
|
+
import { FocusError } from "../sqlite/focus.js";
|
|
4
|
+
import { SavedQueryNotFoundError } from "../sqlite/saved-queries.js";
|
|
5
|
+
|
|
6
|
+
/** Returns the legacy HTTP status only for reviewed business errors; unknown failures stay unclassified. */
|
|
7
|
+
export function statusForKnownTicketError(error: unknown): number | undefined {
|
|
8
|
+
if (error instanceof IssueNotFoundError || error instanceof SavedQueryNotFoundError) return 404;
|
|
9
|
+
if (error instanceof UnknownBackendError || error instanceof NotSupportedError || error instanceof FocusError) return 400;
|
|
10
|
+
if (error instanceof AuthRequiredError) return 422;
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
package/src/rpc/server.ts
CHANGED
|
@@ -11,12 +11,12 @@ import type { VehicleRegistry } from "@danypops/vehicle-server";
|
|
|
11
11
|
import { createVehicleHttpApp } from "@danypops/vehicle-server/http";
|
|
12
12
|
import type { Logger } from "@danypops/vehicle-server/logging";
|
|
13
13
|
import { errorResponse, healthResponse, jsonResponse, readyResponse, requireBearerToken } from "@danypops/vehicle-server/rpc-http";
|
|
14
|
-
import { AuthRequiredError, IssueNotFoundError } from "../issue/errors.js";
|
|
15
14
|
import { parseRef } from "../issue/issue.js";
|
|
16
|
-
import {
|
|
15
|
+
import type { TicketService } from "../issue/service.js";
|
|
17
16
|
import { FocusError, type FocusStore } from "../sqlite/focus.js";
|
|
18
17
|
import type { Ledger } from "../sqlite/ledger.js";
|
|
19
18
|
import { SavedQueryNotFoundError, type SavedQueryStore } from "../sqlite/saved-queries.js";
|
|
19
|
+
import { statusForKnownTicketError } from "./error-status.js";
|
|
20
20
|
import { TICKET_OPERATIONS, type TicketOperation, type TicketOpInputs, type TicketOpOutputs } from "./ops.js";
|
|
21
21
|
|
|
22
22
|
export interface TicketsAppDeps {
|
|
@@ -117,10 +117,7 @@ function isTicketOperation(value: unknown): value is TicketOperation {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function statusFor(error: unknown): number {
|
|
120
|
-
|
|
121
|
-
if (error instanceof UnknownBackendError || error instanceof NotSupportedError || error instanceof FocusError) return 400;
|
|
122
|
-
if (error instanceof AuthRequiredError) return 422;
|
|
123
|
-
return 500;
|
|
120
|
+
return statusForKnownTicketError(error) ?? 500;
|
|
124
121
|
}
|
|
125
122
|
|
|
126
123
|
export function buildApp(deps: TicketsAppDeps): { fetch(request: Request): Promise<Response> } {
|