@abyss-project/probe 2.0.0 → 2.0.1
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/.eslintrc.js +32 -32
- package/.prettierrc +5 -5
- package/README.md +22 -22
- package/package.json +10 -15
- package/src/api/index.ts +6 -6
- package/src/api/probe-scan.api.test.ts +47 -47
- package/src/api/probe-scan.api.ts +203 -203
- package/src/api/probe-scan.application.api.test.ts +35 -35
- package/src/api/probe-scan.application.api.ts +157 -157
- package/src/api/probe-usage.api.ts +47 -47
- package/src/api/probe-usage.application.api.ts +25 -25
- package/src/api/probe-webhook.api.test.ts +17 -17
- package/src/api/probe-webhook.api.ts +119 -119
- package/src/api/probe-webhook.application.api.test.ts +18 -18
- package/src/api/probe-webhook.application.api.ts +141 -141
- package/src/constants/index.ts +1 -1
- package/src/index.ts +205 -205
- package/src/types/enum/api-error.enum.ts +33 -33
- package/src/types/enum/index.ts +2 -2
- package/src/types/enum/probe-scan.enum.ts +44 -44
- package/src/types/index.ts +2 -2
- package/src/types/interface/api/index.ts +5 -5
- package/src/types/interface/api/requests/index.ts +3 -3
- package/src/types/interface/api/requests/probe-scan.request.ts +54 -54
- package/src/types/interface/api/requests/probe-usage.request.ts +7 -7
- package/src/types/interface/api/requests/probe-webhook.request.ts +33 -33
- package/src/types/interface/api/responses/index.ts +3 -3
- package/src/types/interface/api/responses/probe-scan.response.ts +45 -45
- package/src/types/interface/api/responses/probe-usage.response.ts +25 -25
- package/src/types/interface/api/responses/probe-webhook.response.ts +24 -24
- package/src/types/interface/api/type-message/api-error.ts +7 -7
- package/src/types/interface/api/type-message/base-paginate.ts +11 -11
- package/src/types/interface/api/type-message/response.ts +6 -6
- package/src/types/interface/index.ts +2 -2
- package/src/types/interface/models/index.ts +3 -3
- package/src/types/interface/models/probe-scan.dto.ts +67 -67
- package/src/types/interface/models/probe-webhook-delivery.dto.ts +73 -73
- package/src/types/interface/models/probe-webhook.dto.ts +29 -29
- package/src/types/tests/probe.dto.test.ts +156 -156
- package/src/utils/enum.utils.ts +1 -1
- package/src/utils/error.utils.ts +30 -30
- package/src/utils/index.ts +4 -4
- package/src/utils/probe-scan-cost.utils.ts +101 -101
- package/src/utils/probe-webhook-signature.utils.ts +56 -56
- package/tsconfig.check.json +15 -15
- package/tsconfig.json +36 -36
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
import { ProbeScanVerdict } from '../../enum';
|
|
2
|
-
|
|
3
|
-
// Mirrors apps/api/src/services/probe-webhook-delivery.service.ts's
|
|
4
|
-
// ProbeWebhookPayload EXACTLY (same field set, same JSON.stringify'd body a
|
|
5
|
-
// receiver's raw request body will deserialize into) — this is the payload
|
|
6
|
-
// AbyssProbe POSTs to every registered webhook's `callbackUrl` (and to a
|
|
7
|
-
// scan's own per-request `callbackUrl`, see probe-scan docs) once an ASYNC
|
|
8
|
-
// scan reaches a verdict (`status: DONE`).
|
|
9
|
-
//
|
|
10
|
-
// `verdict` is typed as the concrete enum here (not `string` like the
|
|
11
|
-
// server's internal type) because delivery only ever happens on a DONE scan,
|
|
12
|
-
// where the verdict is always set — see dispatchProbeScanWebhooks's guard.
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Body of a webhook delivery, signed via HMAC-SHA256 of
|
|
16
|
-
* `JSON.stringify(payload)` — see {@link PROBE_WEBHOOK_SIGNATURE_HEADER} and
|
|
17
|
-
* {@link verifyProbeWebhookSignature} (this package's root / utils).
|
|
18
|
-
*/
|
|
19
|
-
export interface IProbeWebhookDeliveryPayload {
|
|
20
|
-
scanId: string;
|
|
21
|
-
/** Free-form caller reference, echoed back verbatim (see IProbeScanHistoryItem#context). */
|
|
22
|
-
context: Record<string, unknown> | null;
|
|
23
|
-
verdict: ProbeScanVerdict;
|
|
24
|
-
/** [] when clean. */
|
|
25
|
-
viruses: string[];
|
|
26
|
-
/**
|
|
27
|
-
* `ACCOUNT_AV_SCAN_UNITS` this scan consumed (WS5-1). Delivery only ever
|
|
28
|
-
* happens on a DONE scan, where the cost is always already computed and
|
|
29
|
-
* billed — see {@link IProbeScanHistoryItem#costUnits}.
|
|
30
|
-
*/
|
|
31
|
-
costUnits: number | null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// ─── Delivery HISTORY (WS5-6) ────────────────
|
|
35
|
-
//
|
|
36
|
-
// The interface above is the PAYLOAD a webhook receiver gets POSTed. This
|
|
37
|
-
// section is a DIFFERENT concept: the persisted AUDIT ROW AbyssProbe keeps
|
|
38
|
-
// of its OWN delivery attempts (one row per attempt — mirrors
|
|
39
|
-
// apps/api/src/database/models/probe-webhook-delivery.model.ts EXACTLY,
|
|
40
|
-
// itself modelled after this package's own extraction-webhook
|
|
41
|
-
// delivery-history shape, trimmed to AbyssProbe's simpler
|
|
42
|
-
// one-attempt-per-row reality — see that model's header comment). Read via
|
|
43
|
-
// `GET /webhook/:webhookId/deliveries` (`sdk.probe.webhook.listDeliveries`).
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* One persisted delivery-attempt row, as returned (paginated) by
|
|
47
|
-
* `GET /webhook/:webhookId/deliveries`.
|
|
48
|
-
*/
|
|
49
|
-
export interface IProbeWebhookDelivery {
|
|
50
|
-
id: string;
|
|
51
|
-
/**
|
|
52
|
-
* The registered webhook this delivery targeted. null for a delivery to a
|
|
53
|
-
* scan's own ad-hoc per-request `callbackUrl` that matched no registered
|
|
54
|
-
* webhook (see the server model's own doc comment) — such a row is never
|
|
55
|
-
* reachable via this webhook-scoped endpoint in practice (there is no
|
|
56
|
-
* webhookId to query it under), but the field stays nullable to mirror the
|
|
57
|
-
* server column's real type.
|
|
58
|
-
*/
|
|
59
|
-
webhookId: string | null;
|
|
60
|
-
/** The scan whose verdict this delivery carried. */
|
|
61
|
-
scanId: string;
|
|
62
|
-
/** The exact URL this attempt POSTed to. */
|
|
63
|
-
url: string;
|
|
64
|
-
/** HTTP status code received. null when the request never got a response (network error / timeout / abort). */
|
|
65
|
-
statusCode: number | null;
|
|
66
|
-
/** true only for a 2xx response. */
|
|
67
|
-
success: boolean;
|
|
68
|
-
/** When this attempt was made. */
|
|
69
|
-
attemptedAt: Date;
|
|
70
|
-
/** Failure reason (HTTP non-2xx status, or the caught network/timeout error's message). null on success. */
|
|
71
|
-
error: string | null;
|
|
72
|
-
createdAt: Date;
|
|
73
|
-
}
|
|
1
|
+
import { ProbeScanVerdict } from '../../enum';
|
|
2
|
+
|
|
3
|
+
// Mirrors apps/api/src/services/probe-webhook-delivery.service.ts's
|
|
4
|
+
// ProbeWebhookPayload EXACTLY (same field set, same JSON.stringify'd body a
|
|
5
|
+
// receiver's raw request body will deserialize into) — this is the payload
|
|
6
|
+
// AbyssProbe POSTs to every registered webhook's `callbackUrl` (and to a
|
|
7
|
+
// scan's own per-request `callbackUrl`, see probe-scan docs) once an ASYNC
|
|
8
|
+
// scan reaches a verdict (`status: DONE`).
|
|
9
|
+
//
|
|
10
|
+
// `verdict` is typed as the concrete enum here (not `string` like the
|
|
11
|
+
// server's internal type) because delivery only ever happens on a DONE scan,
|
|
12
|
+
// where the verdict is always set — see dispatchProbeScanWebhooks's guard.
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Body of a webhook delivery, signed via HMAC-SHA256 of
|
|
16
|
+
* `JSON.stringify(payload)` — see {@link PROBE_WEBHOOK_SIGNATURE_HEADER} and
|
|
17
|
+
* {@link verifyProbeWebhookSignature} (this package's root / utils).
|
|
18
|
+
*/
|
|
19
|
+
export interface IProbeWebhookDeliveryPayload {
|
|
20
|
+
scanId: string;
|
|
21
|
+
/** Free-form caller reference, echoed back verbatim (see IProbeScanHistoryItem#context). */
|
|
22
|
+
context: Record<string, unknown> | null;
|
|
23
|
+
verdict: ProbeScanVerdict;
|
|
24
|
+
/** [] when clean. */
|
|
25
|
+
viruses: string[];
|
|
26
|
+
/**
|
|
27
|
+
* `ACCOUNT_AV_SCAN_UNITS` this scan consumed (WS5-1). Delivery only ever
|
|
28
|
+
* happens on a DONE scan, where the cost is always already computed and
|
|
29
|
+
* billed — see {@link IProbeScanHistoryItem#costUnits}.
|
|
30
|
+
*/
|
|
31
|
+
costUnits: number | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ─── Delivery HISTORY (WS5-6) ────────────────
|
|
35
|
+
//
|
|
36
|
+
// The interface above is the PAYLOAD a webhook receiver gets POSTed. This
|
|
37
|
+
// section is a DIFFERENT concept: the persisted AUDIT ROW AbyssProbe keeps
|
|
38
|
+
// of its OWN delivery attempts (one row per attempt — mirrors
|
|
39
|
+
// apps/api/src/database/models/probe-webhook-delivery.model.ts EXACTLY,
|
|
40
|
+
// itself modelled after this package's own extraction-webhook
|
|
41
|
+
// delivery-history shape, trimmed to AbyssProbe's simpler
|
|
42
|
+
// one-attempt-per-row reality — see that model's header comment). Read via
|
|
43
|
+
// `GET /webhook/:webhookId/deliveries` (`sdk.probe.webhook.listDeliveries`).
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* One persisted delivery-attempt row, as returned (paginated) by
|
|
47
|
+
* `GET /webhook/:webhookId/deliveries`.
|
|
48
|
+
*/
|
|
49
|
+
export interface IProbeWebhookDelivery {
|
|
50
|
+
id: string;
|
|
51
|
+
/**
|
|
52
|
+
* The registered webhook this delivery targeted. null for a delivery to a
|
|
53
|
+
* scan's own ad-hoc per-request `callbackUrl` that matched no registered
|
|
54
|
+
* webhook (see the server model's own doc comment) — such a row is never
|
|
55
|
+
* reachable via this webhook-scoped endpoint in practice (there is no
|
|
56
|
+
* webhookId to query it under), but the field stays nullable to mirror the
|
|
57
|
+
* server column's real type.
|
|
58
|
+
*/
|
|
59
|
+
webhookId: string | null;
|
|
60
|
+
/** The scan whose verdict this delivery carried. */
|
|
61
|
+
scanId: string;
|
|
62
|
+
/** The exact URL this attempt POSTed to. */
|
|
63
|
+
url: string;
|
|
64
|
+
/** HTTP status code received. null when the request never got a response (network error / timeout / abort). */
|
|
65
|
+
statusCode: number | null;
|
|
66
|
+
/** true only for a 2xx response. */
|
|
67
|
+
success: boolean;
|
|
68
|
+
/** When this attempt was made. */
|
|
69
|
+
attemptedAt: Date;
|
|
70
|
+
/** Failure reason (HTTP non-2xx status, or the caught network/timeout error's message). null on success. */
|
|
71
|
+
error: string | null;
|
|
72
|
+
createdAt: Date;
|
|
73
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
// Mirrors apps/api/src/api/controllers/probe-webhook.controller.ts's local
|
|
2
|
-
// WebhookResponseData. Public shape of a registered `probe_webhooks` row —
|
|
3
|
-
// never echoes the internal ownership columns
|
|
4
|
-
// (userId/organizationId/applicationId), same discipline as the scan models.
|
|
5
|
-
//
|
|
6
|
-
// WS5-7 (AbyssProbe UX rework): `secret` is ALWAYS re-displayable now —
|
|
7
|
-
// returned on every read (GET /webhook list, and PATCH /webhook/:id), not
|
|
8
|
-
// just once on create. Mirrors how AbyssExtract's own webhook model
|
|
9
|
-
// (`IExtractionWebhookDelivery`'s sibling `ExtractionWebhook` — see
|
|
10
|
-
// apps/api/src/database/models/extraction-webhook.model.ts /
|
|
11
|
-
// extraction-webhook.controller.ts) has always exposed its
|
|
12
|
-
// `webhookSecret` column on every response, never a once-only reveal. This
|
|
13
|
-
// lets a consumer (e.g. abyss-storage's own webhook registration) read its
|
|
14
|
-
// secret back at any time instead of relying on a log-once bootstrap.
|
|
15
|
-
|
|
16
|
-
export interface IProbeWebhook {
|
|
17
|
-
id: string;
|
|
18
|
-
/** HTTPS endpoint the verdict is POSTed to. */
|
|
19
|
-
callbackUrl: string;
|
|
20
|
-
/**
|
|
21
|
-
* Server-generated HMAC-SHA256 signing secret. Re-displayable: returned on
|
|
22
|
-
* every read (list/create/update), not once-only — see this interface's
|
|
23
|
-
* own header note (WS5-7).
|
|
24
|
-
*/
|
|
25
|
-
secret: string;
|
|
26
|
-
/** Disabled webhooks are skipped by dispatch (soft-off, not deleted). */
|
|
27
|
-
active: boolean;
|
|
28
|
-
createdAt: Date;
|
|
29
|
-
}
|
|
1
|
+
// Mirrors apps/api/src/api/controllers/probe-webhook.controller.ts's local
|
|
2
|
+
// WebhookResponseData. Public shape of a registered `probe_webhooks` row —
|
|
3
|
+
// never echoes the internal ownership columns
|
|
4
|
+
// (userId/organizationId/applicationId), same discipline as the scan models.
|
|
5
|
+
//
|
|
6
|
+
// WS5-7 (AbyssProbe UX rework): `secret` is ALWAYS re-displayable now —
|
|
7
|
+
// returned on every read (GET /webhook list, and PATCH /webhook/:id), not
|
|
8
|
+
// just once on create. Mirrors how AbyssExtract's own webhook model
|
|
9
|
+
// (`IExtractionWebhookDelivery`'s sibling `ExtractionWebhook` — see
|
|
10
|
+
// apps/api/src/database/models/extraction-webhook.model.ts /
|
|
11
|
+
// extraction-webhook.controller.ts) has always exposed its
|
|
12
|
+
// `webhookSecret` column on every response, never a once-only reveal. This
|
|
13
|
+
// lets a consumer (e.g. abyss-storage's own webhook registration) read its
|
|
14
|
+
// secret back at any time instead of relying on a log-once bootstrap.
|
|
15
|
+
|
|
16
|
+
export interface IProbeWebhook {
|
|
17
|
+
id: string;
|
|
18
|
+
/** HTTPS endpoint the verdict is POSTed to. */
|
|
19
|
+
callbackUrl: string;
|
|
20
|
+
/**
|
|
21
|
+
* Server-generated HMAC-SHA256 signing secret. Re-displayable: returned on
|
|
22
|
+
* every read (list/create/update), not once-only — see this interface's
|
|
23
|
+
* own header note (WS5-7).
|
|
24
|
+
*/
|
|
25
|
+
secret: string;
|
|
26
|
+
/** Disabled webhooks are skipped by dispatch (soft-off, not deleted). */
|
|
27
|
+
active: boolean;
|
|
28
|
+
createdAt: Date;
|
|
29
|
+
}
|
|
@@ -1,156 +1,156 @@
|
|
|
1
|
-
// Type-level compile test for AbyssProbe's DTO/response shapes — asserts
|
|
2
|
-
// they match the server contract (probe-scan.controller.ts /
|
|
3
|
-
// probe-webhook.controller.ts / probe-usage.controller.ts /
|
|
4
|
-
// probe-webhook-delivery.service.ts) at compile time: any incompatible
|
|
5
|
-
// rename/removal on either side fails `npm run build` here. No jest runner
|
|
6
|
-
// in this SDK package; compile guard only (mirrors
|
|
7
|
-
// ../api/extraction-plan-preset.api.test.ts). Run: npx tsc --noEmit.
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
ProbeScanVerdict,
|
|
11
|
-
ProbeScanMode,
|
|
12
|
-
ProbeScanStatus,
|
|
13
|
-
IProbeScanDetail,
|
|
14
|
-
IProbeScanHistoryItem,
|
|
15
|
-
IProbeWebhook,
|
|
16
|
-
IProbeWebhookDelivery,
|
|
17
|
-
IProbeWebhookDeliveryPayload,
|
|
18
|
-
IScanSyncData,
|
|
19
|
-
IScanAsyncData,
|
|
20
|
-
IUpdateProbeWebhookBody,
|
|
21
|
-
IProbeUsageData,
|
|
22
|
-
} from '..';
|
|
23
|
-
// estimateProbeScanCost lives in src/utils/ (a SIBLING of src/types/, not
|
|
24
|
-
// re-exported by the types barrel this file otherwise imports from) — see
|
|
25
|
-
// probe-scan-cost.utils.ts's own header comment for why it is a plain
|
|
26
|
-
// top-level export rather than a `sdk.probe.*` method.
|
|
27
|
-
import { estimateProbeScanCost } from '../../utils';
|
|
28
|
-
|
|
29
|
-
// Enum exhaustiveness: fails to compile if a member is added/removed/renamed
|
|
30
|
-
// here without updating this file — a cheap drift guard for values
|
|
31
|
-
// transported verbatim over the wire (this SDK does not control the
|
|
32
|
-
// server's enum, so a silent value drift is exactly what this must catch).
|
|
33
|
-
const _verdicts: Record<ProbeScanVerdict, true> = { clean: true, infected: true };
|
|
34
|
-
const _modes: Record<ProbeScanMode, true> = { sync: true, async: true };
|
|
35
|
-
const _statuses: Record<ProbeScanStatus, true> = {
|
|
36
|
-
queued: true,
|
|
37
|
-
scanning: true,
|
|
38
|
-
done: true,
|
|
39
|
-
error: true,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// GET /scan/:scanId — WS5-4: full metadata parity with IProbeScanHistoryItem
|
|
43
|
-
// (fileName/fileSize/mimeType/mode/startedAt/finishedAt/costUnits).
|
|
44
|
-
const _scanDetail: IProbeScanDetail = {
|
|
45
|
-
scanId: 's1',
|
|
46
|
-
status: ProbeScanStatus.DONE,
|
|
47
|
-
verdict: ProbeScanVerdict.CLEAN,
|
|
48
|
-
viruses: [],
|
|
49
|
-
context: null,
|
|
50
|
-
fileName: 'invoice.pdf',
|
|
51
|
-
fileSize: 1024,
|
|
52
|
-
mimeType: 'application/pdf',
|
|
53
|
-
mode: ProbeScanMode.SYNC,
|
|
54
|
-
startedAt: new Date(),
|
|
55
|
-
finishedAt: new Date(),
|
|
56
|
-
costUnits: 3,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// GET /scan history row — WS5-1: costUnits added.
|
|
60
|
-
const _historyItem: IProbeScanHistoryItem = {
|
|
61
|
-
scanId: 's1',
|
|
62
|
-
fileName: 'invoice.pdf',
|
|
63
|
-
fileSize: 1024,
|
|
64
|
-
mimeType: 'application/pdf',
|
|
65
|
-
verdict: ProbeScanVerdict.INFECTED,
|
|
66
|
-
viruses: ['Eicar-Test-Signature'],
|
|
67
|
-
mode: ProbeScanMode.ASYNC,
|
|
68
|
-
status: ProbeScanStatus.DONE,
|
|
69
|
-
context: { applicationFileId: 'af1' },
|
|
70
|
-
startedAt: new Date(),
|
|
71
|
-
finishedAt: new Date(),
|
|
72
|
-
costUnits: 1,
|
|
73
|
-
createdAt: new Date(),
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// POST /scan — sync (200) / async (202) data shapes. WS5-1: costUnits added to the sync shape (always known/billed by the time a 200 is returned).
|
|
77
|
-
const _scanSyncData: IScanSyncData = {
|
|
78
|
-
scanId: 's1',
|
|
79
|
-
verdict: ProbeScanVerdict.CLEAN,
|
|
80
|
-
viruses: [],
|
|
81
|
-
costUnits: 3,
|
|
82
|
-
};
|
|
83
|
-
const _scanAsyncData: IScanAsyncData = { scanId: 's1', status: ProbeScanStatus.QUEUED };
|
|
84
|
-
|
|
85
|
-
// Webhook subscription — WS5-7: secret is now ALWAYS present (list/create/
|
|
86
|
-
// update) and the create response returns IProbeWebhook.
|
|
87
|
-
const _webhook: IProbeWebhook = {
|
|
88
|
-
id: 'w1',
|
|
89
|
-
callbackUrl: 'https://example.com/hook',
|
|
90
|
-
secret: 'shh',
|
|
91
|
-
active: true,
|
|
92
|
-
createdAt: new Date(),
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
// PATCH /webhook/:webhookId body (WS5-5) — every field optional (at least one required server-side).
|
|
96
|
-
const _updateBody: IUpdateProbeWebhookBody = { active: false };
|
|
97
|
-
const _updateBody2: IUpdateProbeWebhookBody = { callbackUrl: 'https://example.com/hook2' };
|
|
98
|
-
|
|
99
|
-
// Webhook delivery payload — the exact body signed by x-probe-signature
|
|
100
|
-
// (see verifyProbeWebhookSignature). WS5-1: costUnits added.
|
|
101
|
-
const _deliveryPayload: IProbeWebhookDeliveryPayload = {
|
|
102
|
-
scanId: 's1',
|
|
103
|
-
context: null,
|
|
104
|
-
verdict: ProbeScanVerdict.INFECTED,
|
|
105
|
-
viruses: ['Eicar-Test-Signature'],
|
|
106
|
-
costUnits: 5,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// GET /webhook/:webhookId/deliveries row (WS5-6) — a persisted delivery-attempt.
|
|
110
|
-
const _deliveryRecord: IProbeWebhookDelivery = {
|
|
111
|
-
id: 'd1',
|
|
112
|
-
webhookId: 'w1',
|
|
113
|
-
scanId: 's1',
|
|
114
|
-
url: 'https://example.com/hook',
|
|
115
|
-
statusCode: 200,
|
|
116
|
-
success: true,
|
|
117
|
-
attemptedAt: new Date(),
|
|
118
|
-
error: null,
|
|
119
|
-
createdAt: new Date(),
|
|
120
|
-
};
|
|
121
|
-
// webhookId is nullable (ad-hoc per-request callbackUrl with no matching registration).
|
|
122
|
-
const _deliveryRecordAdHoc: IProbeWebhookDelivery = { ..._deliveryRecord, webhookId: null };
|
|
123
|
-
|
|
124
|
-
// GET /usage data shape (WS5-3).
|
|
125
|
-
const _usage: IProbeUsageData = { used: 10, limit: 1000, remaining: 990 };
|
|
126
|
-
// -1 is the established "unlimited" sentinel (see estimateProbeScanCost's
|
|
127
|
-
// server-side counterpart, utils/billing-emit.util.ts#UNLIMITED_EXPIRY_DAYS).
|
|
128
|
-
const _usageUnlimited: IProbeUsageData = { used: 10, limit: -1, remaining: -1 };
|
|
129
|
-
|
|
130
|
-
// estimateProbeScanCost (WS5-2) — pure shared cost model, ASYNC must cost
|
|
131
|
-
// strictly less than SYNC for the same size (the scanner UI's "background
|
|
132
|
-
// analysis saves tokens" tooltip depends on this). A one-byte compile-time
|
|
133
|
-
// smoke check; the full behavioural suite lives in probe-scan-cost.utils.test.ts.
|
|
134
|
-
const _asyncCost: number = estimateProbeScanCost(5 * 1024 * 1024, ProbeScanMode.ASYNC);
|
|
135
|
-
const _syncCost: number = estimateProbeScanCost(5 * 1024 * 1024, ProbeScanMode.SYNC);
|
|
136
|
-
if (_asyncCost >= _syncCost) {
|
|
137
|
-
throw new Error('estimateProbeScanCost: ASYNC must cost strictly less than SYNC');
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
void _verdicts;
|
|
141
|
-
void _modes;
|
|
142
|
-
void _statuses;
|
|
143
|
-
void _scanDetail;
|
|
144
|
-
void _historyItem;
|
|
145
|
-
void _scanSyncData;
|
|
146
|
-
void _scanAsyncData;
|
|
147
|
-
void _webhook;
|
|
148
|
-
void _updateBody;
|
|
149
|
-
void _updateBody2;
|
|
150
|
-
void _deliveryPayload;
|
|
151
|
-
void _deliveryRecord;
|
|
152
|
-
void _deliveryRecordAdHoc;
|
|
153
|
-
void _usage;
|
|
154
|
-
void _usageUnlimited;
|
|
155
|
-
|
|
156
|
-
export {};
|
|
1
|
+
// Type-level compile test for AbyssProbe's DTO/response shapes — asserts
|
|
2
|
+
// they match the server contract (probe-scan.controller.ts /
|
|
3
|
+
// probe-webhook.controller.ts / probe-usage.controller.ts /
|
|
4
|
+
// probe-webhook-delivery.service.ts) at compile time: any incompatible
|
|
5
|
+
// rename/removal on either side fails `npm run build` here. No jest runner
|
|
6
|
+
// in this SDK package; compile guard only (mirrors
|
|
7
|
+
// ../api/extraction-plan-preset.api.test.ts). Run: npx tsc --noEmit.
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
ProbeScanVerdict,
|
|
11
|
+
ProbeScanMode,
|
|
12
|
+
ProbeScanStatus,
|
|
13
|
+
IProbeScanDetail,
|
|
14
|
+
IProbeScanHistoryItem,
|
|
15
|
+
IProbeWebhook,
|
|
16
|
+
IProbeWebhookDelivery,
|
|
17
|
+
IProbeWebhookDeliveryPayload,
|
|
18
|
+
IScanSyncData,
|
|
19
|
+
IScanAsyncData,
|
|
20
|
+
IUpdateProbeWebhookBody,
|
|
21
|
+
IProbeUsageData,
|
|
22
|
+
} from '..';
|
|
23
|
+
// estimateProbeScanCost lives in src/utils/ (a SIBLING of src/types/, not
|
|
24
|
+
// re-exported by the types barrel this file otherwise imports from) — see
|
|
25
|
+
// probe-scan-cost.utils.ts's own header comment for why it is a plain
|
|
26
|
+
// top-level export rather than a `sdk.probe.*` method.
|
|
27
|
+
import { estimateProbeScanCost } from '../../utils';
|
|
28
|
+
|
|
29
|
+
// Enum exhaustiveness: fails to compile if a member is added/removed/renamed
|
|
30
|
+
// here without updating this file — a cheap drift guard for values
|
|
31
|
+
// transported verbatim over the wire (this SDK does not control the
|
|
32
|
+
// server's enum, so a silent value drift is exactly what this must catch).
|
|
33
|
+
const _verdicts: Record<ProbeScanVerdict, true> = { clean: true, infected: true };
|
|
34
|
+
const _modes: Record<ProbeScanMode, true> = { sync: true, async: true };
|
|
35
|
+
const _statuses: Record<ProbeScanStatus, true> = {
|
|
36
|
+
queued: true,
|
|
37
|
+
scanning: true,
|
|
38
|
+
done: true,
|
|
39
|
+
error: true,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// GET /scan/:scanId — WS5-4: full metadata parity with IProbeScanHistoryItem
|
|
43
|
+
// (fileName/fileSize/mimeType/mode/startedAt/finishedAt/costUnits).
|
|
44
|
+
const _scanDetail: IProbeScanDetail = {
|
|
45
|
+
scanId: 's1',
|
|
46
|
+
status: ProbeScanStatus.DONE,
|
|
47
|
+
verdict: ProbeScanVerdict.CLEAN,
|
|
48
|
+
viruses: [],
|
|
49
|
+
context: null,
|
|
50
|
+
fileName: 'invoice.pdf',
|
|
51
|
+
fileSize: 1024,
|
|
52
|
+
mimeType: 'application/pdf',
|
|
53
|
+
mode: ProbeScanMode.SYNC,
|
|
54
|
+
startedAt: new Date(),
|
|
55
|
+
finishedAt: new Date(),
|
|
56
|
+
costUnits: 3,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// GET /scan history row — WS5-1: costUnits added.
|
|
60
|
+
const _historyItem: IProbeScanHistoryItem = {
|
|
61
|
+
scanId: 's1',
|
|
62
|
+
fileName: 'invoice.pdf',
|
|
63
|
+
fileSize: 1024,
|
|
64
|
+
mimeType: 'application/pdf',
|
|
65
|
+
verdict: ProbeScanVerdict.INFECTED,
|
|
66
|
+
viruses: ['Eicar-Test-Signature'],
|
|
67
|
+
mode: ProbeScanMode.ASYNC,
|
|
68
|
+
status: ProbeScanStatus.DONE,
|
|
69
|
+
context: { applicationFileId: 'af1' },
|
|
70
|
+
startedAt: new Date(),
|
|
71
|
+
finishedAt: new Date(),
|
|
72
|
+
costUnits: 1,
|
|
73
|
+
createdAt: new Date(),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// POST /scan — sync (200) / async (202) data shapes. WS5-1: costUnits added to the sync shape (always known/billed by the time a 200 is returned).
|
|
77
|
+
const _scanSyncData: IScanSyncData = {
|
|
78
|
+
scanId: 's1',
|
|
79
|
+
verdict: ProbeScanVerdict.CLEAN,
|
|
80
|
+
viruses: [],
|
|
81
|
+
costUnits: 3,
|
|
82
|
+
};
|
|
83
|
+
const _scanAsyncData: IScanAsyncData = { scanId: 's1', status: ProbeScanStatus.QUEUED };
|
|
84
|
+
|
|
85
|
+
// Webhook subscription — WS5-7: secret is now ALWAYS present (list/create/
|
|
86
|
+
// update) and the create response returns IProbeWebhook.
|
|
87
|
+
const _webhook: IProbeWebhook = {
|
|
88
|
+
id: 'w1',
|
|
89
|
+
callbackUrl: 'https://example.com/hook',
|
|
90
|
+
secret: 'shh',
|
|
91
|
+
active: true,
|
|
92
|
+
createdAt: new Date(),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// PATCH /webhook/:webhookId body (WS5-5) — every field optional (at least one required server-side).
|
|
96
|
+
const _updateBody: IUpdateProbeWebhookBody = { active: false };
|
|
97
|
+
const _updateBody2: IUpdateProbeWebhookBody = { callbackUrl: 'https://example.com/hook2' };
|
|
98
|
+
|
|
99
|
+
// Webhook delivery payload — the exact body signed by x-probe-signature
|
|
100
|
+
// (see verifyProbeWebhookSignature). WS5-1: costUnits added.
|
|
101
|
+
const _deliveryPayload: IProbeWebhookDeliveryPayload = {
|
|
102
|
+
scanId: 's1',
|
|
103
|
+
context: null,
|
|
104
|
+
verdict: ProbeScanVerdict.INFECTED,
|
|
105
|
+
viruses: ['Eicar-Test-Signature'],
|
|
106
|
+
costUnits: 5,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// GET /webhook/:webhookId/deliveries row (WS5-6) — a persisted delivery-attempt.
|
|
110
|
+
const _deliveryRecord: IProbeWebhookDelivery = {
|
|
111
|
+
id: 'd1',
|
|
112
|
+
webhookId: 'w1',
|
|
113
|
+
scanId: 's1',
|
|
114
|
+
url: 'https://example.com/hook',
|
|
115
|
+
statusCode: 200,
|
|
116
|
+
success: true,
|
|
117
|
+
attemptedAt: new Date(),
|
|
118
|
+
error: null,
|
|
119
|
+
createdAt: new Date(),
|
|
120
|
+
};
|
|
121
|
+
// webhookId is nullable (ad-hoc per-request callbackUrl with no matching registration).
|
|
122
|
+
const _deliveryRecordAdHoc: IProbeWebhookDelivery = { ..._deliveryRecord, webhookId: null };
|
|
123
|
+
|
|
124
|
+
// GET /usage data shape (WS5-3).
|
|
125
|
+
const _usage: IProbeUsageData = { used: 10, limit: 1000, remaining: 990 };
|
|
126
|
+
// -1 is the established "unlimited" sentinel (see estimateProbeScanCost's
|
|
127
|
+
// server-side counterpart, utils/billing-emit.util.ts#UNLIMITED_EXPIRY_DAYS).
|
|
128
|
+
const _usageUnlimited: IProbeUsageData = { used: 10, limit: -1, remaining: -1 };
|
|
129
|
+
|
|
130
|
+
// estimateProbeScanCost (WS5-2) — pure shared cost model, ASYNC must cost
|
|
131
|
+
// strictly less than SYNC for the same size (the scanner UI's "background
|
|
132
|
+
// analysis saves tokens" tooltip depends on this). A one-byte compile-time
|
|
133
|
+
// smoke check; the full behavioural suite lives in probe-scan-cost.utils.test.ts.
|
|
134
|
+
const _asyncCost: number = estimateProbeScanCost(5 * 1024 * 1024, ProbeScanMode.ASYNC);
|
|
135
|
+
const _syncCost: number = estimateProbeScanCost(5 * 1024 * 1024, ProbeScanMode.SYNC);
|
|
136
|
+
if (_asyncCost >= _syncCost) {
|
|
137
|
+
throw new Error('estimateProbeScanCost: ASYNC must cost strictly less than SYNC');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void _verdicts;
|
|
141
|
+
void _modes;
|
|
142
|
+
void _statuses;
|
|
143
|
+
void _scanDetail;
|
|
144
|
+
void _historyItem;
|
|
145
|
+
void _scanSyncData;
|
|
146
|
+
void _scanAsyncData;
|
|
147
|
+
void _webhook;
|
|
148
|
+
void _updateBody;
|
|
149
|
+
void _updateBody2;
|
|
150
|
+
void _deliveryPayload;
|
|
151
|
+
void _deliveryRecord;
|
|
152
|
+
void _deliveryRecordAdHoc;
|
|
153
|
+
void _usage;
|
|
154
|
+
void _usageUnlimited;
|
|
155
|
+
|
|
156
|
+
export {};
|
package/src/utils/enum.utils.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export type ValueOf<T> = T[keyof T];
|
|
1
|
+
export type ValueOf<T> = T[keyof T];
|
package/src/utils/error.utils.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { Code, ErrorType } from '../types';
|
|
2
|
-
|
|
3
|
-
type ErrorParams = { code: Code; type: ErrorType; message?: string };
|
|
4
|
-
|
|
5
|
-
export class ServiceException extends Error {
|
|
6
|
-
private readonly code: Code;
|
|
7
|
-
|
|
8
|
-
private readonly type: ErrorType;
|
|
9
|
-
|
|
10
|
-
getCode(): Code {
|
|
11
|
-
return this.code;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
getType(): ErrorType {
|
|
15
|
-
return this.type;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
constructor(params: ErrorParams) {
|
|
19
|
-
super(params.message);
|
|
20
|
-
this.code = params.code;
|
|
21
|
-
this.type = params.type;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const handleError = (error: Error | ErrorParams, _params?: ErrorParams): Error => {
|
|
26
|
-
if (error instanceof Error) {
|
|
27
|
-
return error;
|
|
28
|
-
}
|
|
29
|
-
return new ServiceException(error);
|
|
30
|
-
};
|
|
1
|
+
import { Code, ErrorType } from '../types';
|
|
2
|
+
|
|
3
|
+
type ErrorParams = { code: Code; type: ErrorType; message?: string };
|
|
4
|
+
|
|
5
|
+
export class ServiceException extends Error {
|
|
6
|
+
private readonly code: Code;
|
|
7
|
+
|
|
8
|
+
private readonly type: ErrorType;
|
|
9
|
+
|
|
10
|
+
getCode(): Code {
|
|
11
|
+
return this.code;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getType(): ErrorType {
|
|
15
|
+
return this.type;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
constructor(params: ErrorParams) {
|
|
19
|
+
super(params.message);
|
|
20
|
+
this.code = params.code;
|
|
21
|
+
this.type = params.type;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const handleError = (error: Error | ErrorParams, _params?: ErrorParams): Error => {
|
|
26
|
+
if (error instanceof Error) {
|
|
27
|
+
return error;
|
|
28
|
+
}
|
|
29
|
+
return new ServiceException(error);
|
|
30
|
+
};
|
package/src/utils/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from './error.utils';
|
|
2
|
-
export * from './enum.utils';
|
|
3
|
-
export * from './probe-webhook-signature.utils';
|
|
4
|
-
export * from './probe-scan-cost.utils';
|
|
1
|
+
export * from './error.utils';
|
|
2
|
+
export * from './enum.utils';
|
|
3
|
+
export * from './probe-webhook-signature.utils';
|
|
4
|
+
export * from './probe-scan-cost.utils';
|