@abyss-project/tools 2.2.0 → 2.4.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.
Files changed (70) hide show
  1. package/dist/api/index.d.ts +2 -0
  2. package/dist/api/index.js +2 -0
  3. package/dist/api/index.js.map +1 -1
  4. package/dist/api/probe-usage.api.d.ts +2 -0
  5. package/dist/api/probe-usage.api.js +24 -0
  6. package/dist/api/probe-usage.api.js.map +1 -0
  7. package/dist/api/probe-usage.application.api.d.ts +2 -0
  8. package/dist/api/probe-usage.application.api.js +12 -0
  9. package/dist/api/probe-usage.application.api.js.map +1 -0
  10. package/dist/api/probe-webhook.api.d.ts +3 -1
  11. package/dist/api/probe-webhook.api.js +8 -1
  12. package/dist/api/probe-webhook.api.js.map +1 -1
  13. package/dist/api/probe-webhook.application.api.d.ts +3 -1
  14. package/dist/api/probe-webhook.application.api.js +14 -1
  15. package/dist/api/probe-webhook.application.api.js.map +1 -1
  16. package/dist/index.d.ts +12 -0
  17. package/dist/index.js +12 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/types/enum/beam.enum.d.ts +8 -2
  20. package/dist/types/enum/beam.enum.js +9 -2
  21. package/dist/types/enum/beam.enum.js.map +1 -1
  22. package/dist/types/interface/api/requests/index.d.ts +1 -0
  23. package/dist/types/interface/api/requests/index.js +1 -0
  24. package/dist/types/interface/api/requests/index.js.map +1 -1
  25. package/dist/types/interface/api/requests/probe-usage.request.d.ts +3 -0
  26. package/dist/types/interface/api/requests/probe-usage.request.js +3 -0
  27. package/dist/types/interface/api/requests/probe-usage.request.js.map +1 -0
  28. package/dist/types/interface/api/requests/probe-webhook.request.d.ts +8 -0
  29. package/dist/types/interface/api/responses/beam.response.d.ts +2 -1
  30. package/dist/types/interface/api/responses/index.d.ts +1 -0
  31. package/dist/types/interface/api/responses/index.js +1 -0
  32. package/dist/types/interface/api/responses/index.js.map +1 -1
  33. package/dist/types/interface/api/responses/probe-scan.response.d.ts +1 -0
  34. package/dist/types/interface/api/responses/probe-usage.response.d.ts +7 -0
  35. package/dist/types/interface/api/responses/probe-usage.response.js +3 -0
  36. package/dist/types/interface/api/responses/probe-usage.response.js.map +1 -0
  37. package/dist/types/interface/api/responses/probe-webhook.response.d.ts +4 -1
  38. package/dist/types/interface/models/probe-scan.dto.d.ts +8 -0
  39. package/dist/types/interface/models/probe-webhook-delivery.dto.d.ts +12 -0
  40. package/dist/types/interface/models/probe-webhook.dto.d.ts +2 -3
  41. package/dist/types/tests/probe.dto.test.js +40 -1
  42. package/dist/types/tests/probe.dto.test.js.map +1 -1
  43. package/dist/utils/index.d.ts +1 -0
  44. package/dist/utils/index.js +1 -0
  45. package/dist/utils/index.js.map +1 -1
  46. package/dist/utils/probe-scan-cost.utils.d.ts +5 -0
  47. package/dist/utils/probe-scan-cost.utils.js +21 -0
  48. package/dist/utils/probe-scan-cost.utils.js.map +1 -0
  49. package/package.json +1 -1
  50. package/src/api/index.ts +2 -0
  51. package/src/api/probe-usage.api.ts +47 -0
  52. package/src/api/probe-usage.application.api.ts +25 -0
  53. package/src/api/probe-webhook.api.ts +43 -5
  54. package/src/api/probe-webhook.application.api.ts +58 -4
  55. package/src/index.ts +28 -0
  56. package/src/types/enum/beam.enum.ts +17 -1
  57. package/src/types/interface/api/requests/index.ts +1 -0
  58. package/src/types/interface/api/requests/probe-usage.request.ts +7 -0
  59. package/src/types/interface/api/requests/probe-webhook.request.ts +23 -2
  60. package/src/types/interface/api/responses/beam.response.ts +10 -1
  61. package/src/types/interface/api/responses/index.ts +1 -0
  62. package/src/types/interface/api/responses/probe-scan.response.ts +7 -0
  63. package/src/types/interface/api/responses/probe-usage.response.ts +25 -0
  64. package/src/types/interface/api/responses/probe-webhook.response.ts +10 -3
  65. package/src/types/interface/models/probe-scan.dto.ts +27 -8
  66. package/src/types/interface/models/probe-webhook-delivery.dto.ts +47 -0
  67. package/src/types/interface/models/probe-webhook.dto.ts +25 -11
  68. package/src/types/tests/probe.dto.test.ts +73 -11
  69. package/src/utils/index.ts +1 -0
  70. package/src/utils/probe-scan-cost.utils.ts +101 -0
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const __1 = require("..");
4
+ const utils_1 = require("../../utils");
4
5
  const _verdicts = { clean: true, infected: true };
5
6
  const _modes = { sync: true, async: true };
6
7
  const _statuses = {
@@ -15,6 +16,13 @@ const _scanDetail = {
15
16
  verdict: __1.ProbeScanVerdict.CLEAN,
16
17
  viruses: [],
17
18
  context: null,
19
+ fileName: 'invoice.pdf',
20
+ fileSize: 1024,
21
+ mimeType: 'application/pdf',
22
+ mode: __1.ProbeScanMode.SYNC,
23
+ startedAt: new Date(),
24
+ finishedAt: new Date(),
25
+ costUnits: 3,
18
26
  };
19
27
  const _historyItem = {
20
28
  scanId: 's1',
@@ -28,27 +36,52 @@ const _historyItem = {
28
36
  context: { applicationFileId: 'af1' },
29
37
  startedAt: new Date(),
30
38
  finishedAt: new Date(),
39
+ costUnits: 1,
31
40
  createdAt: new Date(),
32
41
  };
33
42
  const _scanSyncData = {
34
43
  scanId: 's1',
35
44
  verdict: __1.ProbeScanVerdict.CLEAN,
36
45
  viruses: [],
46
+ costUnits: 3,
37
47
  };
38
48
  const _scanAsyncData = { scanId: 's1', status: __1.ProbeScanStatus.QUEUED };
39
49
  const _webhook = {
40
50
  id: 'w1',
41
51
  callbackUrl: 'https://example.com/hook',
52
+ secret: 'shh',
42
53
  active: true,
43
54
  createdAt: new Date(),
44
55
  };
45
- const _webhookCreated = { ..._webhook, secret: 'shh' };
56
+ const _webhookCreated = _webhook;
57
+ const _updateBody = { active: false };
58
+ const _updateBody2 = { callbackUrl: 'https://example.com/hook2' };
46
59
  const _deliveryPayload = {
47
60
  scanId: 's1',
48
61
  context: null,
49
62
  verdict: __1.ProbeScanVerdict.INFECTED,
50
63
  viruses: ['Eicar-Test-Signature'],
64
+ costUnits: 5,
65
+ };
66
+ const _deliveryRecord = {
67
+ id: 'd1',
68
+ webhookId: 'w1',
69
+ scanId: 's1',
70
+ url: 'https://example.com/hook',
71
+ statusCode: 200,
72
+ success: true,
73
+ attemptedAt: new Date(),
74
+ error: null,
75
+ createdAt: new Date(),
51
76
  };
77
+ const _deliveryRecordAdHoc = { ..._deliveryRecord, webhookId: null };
78
+ const _usage = { used: 10, limit: 1000, remaining: 990 };
79
+ const _usageUnlimited = { used: 10, limit: -1, remaining: -1 };
80
+ const _asyncCost = (0, utils_1.estimateProbeScanCost)(5 * 1024 * 1024, __1.ProbeScanMode.ASYNC);
81
+ const _syncCost = (0, utils_1.estimateProbeScanCost)(5 * 1024 * 1024, __1.ProbeScanMode.SYNC);
82
+ if (_asyncCost >= _syncCost) {
83
+ throw new Error('estimateProbeScanCost: ASYNC must cost strictly less than SYNC');
84
+ }
52
85
  void _verdicts;
53
86
  void _modes;
54
87
  void _statuses;
@@ -58,5 +91,11 @@ void _scanSyncData;
58
91
  void _scanAsyncData;
59
92
  void _webhook;
60
93
  void _webhookCreated;
94
+ void _updateBody;
95
+ void _updateBody2;
61
96
  void _deliveryPayload;
97
+ void _deliveryRecord;
98
+ void _deliveryRecordAdHoc;
99
+ void _usage;
100
+ void _usageUnlimited;
62
101
  //# sourceMappingURL=probe.dto.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"probe.dto.test.js","sourceRoot":"","sources":["../../../src/types/tests/probe.dto.test.ts"],"names":[],"mappings":";;AAOA,0BAWY;AAMZ,MAAM,SAAS,GAAmC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAClF,MAAM,MAAM,GAAgC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACxE,MAAM,SAAS,GAAkC;IAC/C,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,IAAI;IACd,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;CACZ,CAAC;AAGF,MAAM,WAAW,GAAqB;IACpC,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,mBAAe,CAAC,IAAI;IAC5B,OAAO,EAAE,oBAAgB,CAAC,KAAK;IAC/B,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,IAAI;CACd,CAAC;AAIF,MAAM,YAAY,GAA0B;IAC1C,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,aAAa;IACvB,QAAQ,EAAE,IAAI;IACd,QAAQ,EAAE,iBAAiB;IAC3B,OAAO,EAAE,oBAAgB,CAAC,QAAQ;IAClC,OAAO,EAAE,CAAC,sBAAsB,CAAC;IACjC,IAAI,EAAE,iBAAa,CAAC,KAAK;IACzB,MAAM,EAAE,mBAAe,CAAC,IAAI;IAC5B,OAAO,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE;IACrC,SAAS,EAAE,IAAI,IAAI,EAAE;IACrB,UAAU,EAAE,IAAI,IAAI,EAAE;IACtB,SAAS,EAAE,IAAI,IAAI,EAAE;CACtB,CAAC;AAGF,MAAM,aAAa,GAAkB;IACnC,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,oBAAgB,CAAC,KAAK;IAC/B,OAAO,EAAE,EAAE;CACZ,CAAC;AACF,MAAM,cAAc,GAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAe,CAAC,MAAM,EAAE,CAAC;AAGxF,MAAM,QAAQ,GAAkB;IAC9B,EAAE,EAAE,IAAI;IACR,WAAW,EAAE,0BAA0B;IACvC,MAAM,EAAE,IAAI;IACZ,SAAS,EAAE,IAAI,IAAI,EAAE;CACtB,CAAC;AACF,MAAM,eAAe,GAAyB,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAI7E,MAAM,gBAAgB,GAAiC;IACrD,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,oBAAgB,CAAC,QAAQ;IAClC,OAAO,EAAE,CAAC,sBAAsB,CAAC;CAClC,CAAC;AAEF,KAAK,SAAS,CAAC;AACf,KAAK,MAAM,CAAC;AACZ,KAAK,SAAS,CAAC;AACf,KAAK,WAAW,CAAC;AACjB,KAAK,YAAY,CAAC;AAClB,KAAK,aAAa,CAAC;AACnB,KAAK,cAAc,CAAC;AACpB,KAAK,QAAQ,CAAC;AACd,KAAK,eAAe,CAAC;AACrB,KAAK,gBAAgB,CAAC"}
1
+ {"version":3,"file":"probe.dto.test.js","sourceRoot":"","sources":["../../../src/types/tests/probe.dto.test.ts"],"names":[],"mappings":"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"}
@@ -5,3 +5,4 @@ export * from './icons.utils';
5
5
  export * from './enum.utils';
6
6
  export * from './extraction-webhook.utils';
7
7
  export * from './probe-webhook-signature.utils';
8
+ export * from './probe-scan-cost.utils';
@@ -21,4 +21,5 @@ __exportStar(require("./icons.utils"), exports);
21
21
  __exportStar(require("./enum.utils"), exports);
22
22
  __exportStar(require("./extraction-webhook.utils"), exports);
23
23
  __exportStar(require("./probe-webhook-signature.utils"), exports);
24
+ __exportStar(require("./probe-scan-cost.utils"), exports);
24
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,gDAA8B;AAC9B,gDAA8B;AAC9B,gDAA8B;AAC9B,+CAA6B;AAC7B,6DAA2C;AAC3C,kEAAgD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,gDAA8B;AAC9B,gDAA8B;AAC9B,gDAA8B;AAC9B,+CAA6B;AAC7B,6DAA2C;AAC3C,kEAAgD;AAChD,0DAAwC"}
@@ -0,0 +1,5 @@
1
+ import { ProbeScanMode } from '../types';
2
+ export declare const PROBE_SCAN_COST_BASE = 1;
3
+ export declare const PROBE_SCAN_COST_K_MB = 1;
4
+ export declare const PROBE_SCAN_COST_MODE_WEIGHT: Record<ProbeScanMode, number>;
5
+ export declare const estimateProbeScanCost: (sizeOctet: number, mode: ProbeScanMode | 'sync' | 'async') => number;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.estimateProbeScanCost = exports.PROBE_SCAN_COST_MODE_WEIGHT = exports.PROBE_SCAN_COST_K_MB = exports.PROBE_SCAN_COST_BASE = void 0;
4
+ const types_1 = require("../types");
5
+ exports.PROBE_SCAN_COST_BASE = 1;
6
+ exports.PROBE_SCAN_COST_K_MB = 1;
7
+ exports.PROBE_SCAN_COST_MODE_WEIGHT = {
8
+ [types_1.ProbeScanMode.ASYNC]: 1,
9
+ [types_1.ProbeScanMode.SYNC]: 3,
10
+ };
11
+ const ONE_MB = 1024 * 1024;
12
+ const estimateProbeScanCost = (sizeOctet, mode) => {
13
+ if (!Number.isFinite(sizeOctet) || sizeOctet <= 0) {
14
+ return 0;
15
+ }
16
+ const megabytes = Math.ceil(sizeOctet / ONE_MB);
17
+ const weight = exports.PROBE_SCAN_COST_MODE_WEIGHT[mode] ?? exports.PROBE_SCAN_COST_MODE_WEIGHT[types_1.ProbeScanMode.ASYNC];
18
+ return Math.round((exports.PROBE_SCAN_COST_BASE + exports.PROBE_SCAN_COST_K_MB * megabytes) * weight);
19
+ };
20
+ exports.estimateProbeScanCost = estimateProbeScanCost;
21
+ //# sourceMappingURL=probe-scan-cost.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe-scan-cost.utils.js","sourceRoot":"","sources":["../../src/utils/probe-scan-cost.utils.ts"],"names":[],"mappings":";;;AAuCA,oCAAyC;AAG5B,QAAA,oBAAoB,GAAG,CAAC,CAAC;AAGzB,QAAA,oBAAoB,GAAG,CAAC,CAAC;AAUzB,QAAA,2BAA2B,GAAkC;IACxE,CAAC,qBAAa,CAAC,KAAK,CAAC,EAAE,CAAC;IACxB,CAAC,qBAAa,CAAC,IAAI,CAAC,EAAE,CAAC;CACxB,CAAC;AAGF,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AA4BpB,MAAM,qBAAqB,GAAG,CACnC,SAAiB,EACjB,IAAsC,EAC9B,EAAE;IACV,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAClD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC;IAChD,MAAM,MAAM,GACV,mCAA2B,CAAC,IAAI,CAAC,IAAI,mCAA2B,CAAC,qBAAa,CAAC,KAAK,CAAC,CAAC;IACxF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,4BAAoB,GAAG,4BAAoB,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC;AACxF,CAAC,CAAC;AAXW,QAAA,qBAAqB,yBAWhC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abyss-project/tools",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "Core package to interact with Abyss-Project Tools",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/api/index.ts CHANGED
@@ -60,3 +60,5 @@ export * from './probe-scan.api';
60
60
  export * from './probe-webhook.api';
61
61
  export * from './probe-scan.application.api';
62
62
  export * from './probe-webhook.application.api';
63
+ export * from './probe-usage.api';
64
+ export * from './probe-usage.application.api';
@@ -0,0 +1,47 @@
1
+ // ──────────────────────────────────────────────
2
+ // AbyssProbe usage API — WS5-3 (AbyssProbe UX rework). `GET /usage`: current
3
+ // ACCOUNT_AV_SCAN_UNITS ("tokens") used/limit/remaining for the caller's
4
+ // scope, via the same billing check the quota gate itself already uses (see
5
+ // apps/api/src/utils/probe-scan-billing.util.ts#getProbeScanUsage). Mirrors
6
+ // apps/api/src/api/controllers/probe-usage.controller.ts EXACTLY. No
7
+ // `probe/` path prefix — `@Controller({ prefixPath: '/usage' })` mounts
8
+ // directly at `usage`.
9
+ //
10
+ // See probe-usage.application.api.ts for the application/API-key-auth
11
+ // counterpart (`/application/:applicationId/usage`, Phase 3a).
12
+ // ──────────────────────────────────────────────
13
+
14
+ import { AbyssToolsCore } from '..';
15
+ import type { IProbeUsageScopeQuery, IProbeUsageResponse } from '../types';
16
+
17
+ const DEFAULT_API_KEY_HEADER = 'abyss-api-key';
18
+
19
+ function authHeader(apiKey?: string): Record<string, string> {
20
+ return apiKey ? { [DEFAULT_API_KEY_HEADER]: apiKey } : {};
21
+ }
22
+
23
+ /** Renames `organizationId` to the wire's `organization_id` (see probe-scan.api.ts). */
24
+ function serializeProbeQuery<T extends object>(query: T): Record<string, unknown> {
25
+ const out: Record<string, unknown> = {};
26
+ for (const [key, value] of Object.entries(query as Record<string, unknown>)) {
27
+ if (value === undefined || value === null) continue;
28
+ const wireKey = key === 'organizationId' ? 'organization_id' : key;
29
+ out[wireKey] = value;
30
+ }
31
+ return out;
32
+ }
33
+
34
+ /**
35
+ * `GET /usage` — current ACCOUNT_AV_SCAN_UNITS consumption for the caller's
36
+ * scope (personal by default, `organizationId` for an organization scope).
37
+ */
38
+ export const getProbeUsage = async (
39
+ scope: IProbeUsageScopeQuery = {},
40
+ apiKey?: string,
41
+ ): Promise<IProbeUsageResponse> =>
42
+ (
43
+ await AbyssToolsCore.axios.get<IProbeUsageResponse>('usage', {
44
+ params: serializeProbeQuery(scope),
45
+ headers: authHeader(apiKey),
46
+ })
47
+ ).data;
@@ -0,0 +1,25 @@
1
+ // ──────────────────────────────────────────────
2
+ // AbyssProbe APPLICATION usage API — WS5-3 (AbyssProbe UX rework). `GET
3
+ // /application/:applicationId/usage`: current ACCOUNT_AV_SCAN_UNITS
4
+ // consumption for the calling application's resolved billing organization.
5
+ // Mirrors apps/api/src/api/controllers/probe-usage-application.controller.ts
6
+ // EXACTLY — the application counterpart of probe-usage.api.ts.
7
+ // ──────────────────────────────────────────────
8
+
9
+ import { AbyssToolsCore, API_KEY_APPLICATION_HEADER } from '..';
10
+ import type { IProbeUsageResponse } from '../types';
11
+
12
+ function authHeaderApplication(applicationApiKey?: string): Record<string, string> {
13
+ return applicationApiKey ? { [API_KEY_APPLICATION_HEADER]: applicationApiKey } : {};
14
+ }
15
+
16
+ /** `GET /application/:applicationId/usage` — current ACCOUNT_AV_SCAN_UNITS consumption for the calling application. */
17
+ export const getProbeUsageApplication = async (
18
+ applicationId: string,
19
+ applicationApiKey?: string,
20
+ ): Promise<IProbeUsageResponse> =>
21
+ (
22
+ await AbyssToolsCore.axios.get<IProbeUsageResponse>(`application/${applicationId}/usage`, {
23
+ headers: authHeaderApplication(applicationApiKey),
24
+ })
25
+ ).data;
@@ -1,10 +1,9 @@
1
1
  // ──────────────────────────────────────────────
2
2
  // AbyssProbe webhook subscription API — CRUD over registered `probe_webhooks`
3
- // (create / list / delete only — no update, no reset-secret: mirrors
4
- // apps/api/src/api/controllers/probe-webhook.controller.ts's deliberately
5
- // small surface EXACTLY, see that file's header comment). No `probe/` path
6
- // prefix — `@Controller({ prefixPath: '/webhook' })` mounts directly at
7
- // `webhook`.
3
+ // (create / list / delete / update, + paginated delivery history — mirrors
4
+ // apps/api/src/api/controllers/probe-webhook.controller.ts EXACTLY, see that
5
+ // file's header comment). No `probe/` path prefix — `@Controller({
6
+ // prefixPath: '/webhook' })` mounts directly at `webhook`.
8
7
  //
9
8
  // See probe-webhook.application.api.ts for the application/API-key-auth
10
9
  // counterpart of this client (`/application/:applicationId/webhook...`,
@@ -15,10 +14,14 @@
15
14
  import { AbyssToolsCore } from '..';
16
15
  import type {
17
16
  ICreateProbeWebhookBody,
17
+ IUpdateProbeWebhookBody,
18
18
  IProbeWebhookScopeQuery,
19
+ IListProbeWebhookDeliveriesQuery,
19
20
  ICreateProbeWebhookResponse,
20
21
  IListProbeWebhookResponse,
21
22
  IDeleteProbeWebhookResponse,
23
+ IUpdateProbeWebhookResponse,
24
+ IListProbeWebhookDeliveriesResponse,
22
25
  } from '../types';
23
26
 
24
27
  const DEFAULT_API_KEY_HEADER = 'abyss-api-key';
@@ -79,3 +82,38 @@ export const deleteProbeWebhook = async (
79
82
  headers: authHeader(apiKey),
80
83
  })
81
84
  ).data;
85
+
86
+ /**
87
+ * `PATCH /webhook/:webhookId` (WS5-5) — edit `callbackUrl` and/or `active`.
88
+ * At least one field is required. Scoped like {@link deleteProbeWebhook}
89
+ * (404, never 403, for a webhookId outside the resolved scope). The response
90
+ * includes `secret` — re-displayable now, see {@link IProbeWebhook}.
91
+ */
92
+ export const updateProbeWebhook = async (
93
+ webhookId: string,
94
+ body: IUpdateProbeWebhookBody,
95
+ scope: IProbeWebhookScopeQuery = {},
96
+ apiKey?: string,
97
+ ): Promise<IUpdateProbeWebhookResponse> =>
98
+ (
99
+ await AbyssToolsCore.axios.patch<IUpdateProbeWebhookResponse>(`webhook/${webhookId}`, body, {
100
+ params: serializeProbeQuery(scope),
101
+ headers: authHeader(apiKey),
102
+ })
103
+ ).data;
104
+
105
+ /**
106
+ * `GET /webhook/:webhookId/deliveries` (WS5-6) — paginated delivery-attempt
107
+ * history for one registered webhook. Scoped like {@link deleteProbeWebhook}.
108
+ */
109
+ export const listProbeWebhookDeliveries = async (
110
+ webhookId: string,
111
+ query: IListProbeWebhookDeliveriesQuery = {},
112
+ apiKey?: string,
113
+ ): Promise<IListProbeWebhookDeliveriesResponse> =>
114
+ (
115
+ await AbyssToolsCore.axios.get<IListProbeWebhookDeliveriesResponse>(
116
+ `webhook/${webhookId}/deliveries`,
117
+ { params: serializeProbeQuery(query), headers: authHeader(apiKey) },
118
+ )
119
+ ).data;
@@ -1,8 +1,8 @@
1
1
  // ──────────────────────────────────────────────
2
2
  // AbyssProbe APPLICATION webhook subscription API — CRUD over registered
3
- // `probe_webhooks` owned by a calling application (create / list / delete
4
- // only — no update, no reset-secret: same deliberately small surface as the
5
- // personal/org client, see probe-webhook.api.ts's header comment). Mirrors
3
+ // `probe_webhooks` owned by a calling application (create / list / delete /
4
+ // update, + paginated delivery history — same surface as the personal/org
5
+ // client, see probe-webhook.api.ts's header comment). Mirrors
6
6
  // apps/api/src/api/controllers/probe-webhook-application.controller.ts
7
7
  // EXACTLY — the application counterpart of probe-webhook.api.ts, for
8
8
  // inter-service callers (abyss-storage, external integrations)
@@ -10,7 +10,9 @@
10
10
  //
11
11
  // Reuses every request/response TYPE verbatim (`ICreateProbeWebhookBody`,
12
12
  // `ICreateProbeWebhookResponse`, `IListProbeWebhookResponse`,
13
- // `IDeleteProbeWebhookResponse`) — never redefined here. No scope
13
+ // `IDeleteProbeWebhookResponse`, `IUpdateProbeWebhookBody`,
14
+ // `IUpdateProbeWebhookResponse`, `IListProbeWebhookDeliveriesQuery`,
15
+ // `IListProbeWebhookDeliveriesResponse`) — never redefined here. No scope
14
16
  // argument/query on any of these calls (unlike the personal/org client's
15
17
  // `IProbeWebhookScopeQuery`) — an application caller's scope is entirely its
16
18
  // `:applicationId` URL segment, resolved server-side by
@@ -25,15 +27,29 @@
25
27
  import { AbyssToolsCore, API_KEY_APPLICATION_HEADER } from '..';
26
28
  import type {
27
29
  ICreateProbeWebhookBody,
30
+ IUpdateProbeWebhookBody,
31
+ IListProbeWebhookDeliveriesQuery,
28
32
  ICreateProbeWebhookResponse,
29
33
  IListProbeWebhookResponse,
30
34
  IDeleteProbeWebhookResponse,
35
+ IUpdateProbeWebhookResponse,
36
+ IListProbeWebhookDeliveriesResponse,
31
37
  } from '../types';
32
38
 
33
39
  function authHeaderApplication(applicationApiKey?: string): Record<string, string> {
34
40
  return applicationApiKey ? { [API_KEY_APPLICATION_HEADER]: applicationApiKey } : {};
35
41
  }
36
42
 
43
+ /** Renames nothing (no `organizationId` ever travels on an application call) — drops undefined/null and ISO-stringifies `Date`s, mirroring probe-scan.application.api.ts's own local helper. */
44
+ function serializeProbeQuery<T extends object>(query: T): Record<string, unknown> {
45
+ const out: Record<string, unknown> = {};
46
+ for (const [key, value] of Object.entries(query as Record<string, unknown>)) {
47
+ if (value === undefined || value === null) continue;
48
+ out[key] = value instanceof Date ? value.toISOString() : value;
49
+ }
50
+ return out;
51
+ }
52
+
37
53
  /**
38
54
  * `POST /application/:applicationId/webhook` — register a callbackUrl owned
39
55
  * by the calling application. The response's `secret` field (HMAC signing
@@ -85,3 +101,41 @@ export const deleteProbeWebhookApplication = async (
85
101
  { headers: authHeaderApplication(applicationApiKey) },
86
102
  )
87
103
  ).data;
104
+
105
+ /**
106
+ * `PATCH /application/:applicationId/webhook/:webhookId` (WS5-5) — edit
107
+ * `callbackUrl` and/or `active` on a webhook owned by the calling
108
+ * application. Cross-tenant guarded server-side (404, never 403). The
109
+ * response includes `secret` — re-displayable now, see {@link IProbeWebhook}.
110
+ */
111
+ export const updateProbeWebhookApplication = async (
112
+ applicationId: string,
113
+ webhookId: string,
114
+ body: IUpdateProbeWebhookBody,
115
+ applicationApiKey?: string,
116
+ ): Promise<IUpdateProbeWebhookResponse> =>
117
+ (
118
+ await AbyssToolsCore.axios.patch<IUpdateProbeWebhookResponse>(
119
+ `application/${applicationId}/webhook/${webhookId}`,
120
+ body,
121
+ { headers: authHeaderApplication(applicationApiKey) },
122
+ )
123
+ ).data;
124
+
125
+ /**
126
+ * `GET /application/:applicationId/webhook/:webhookId/deliveries` (WS5-6) —
127
+ * paginated delivery-attempt history for one webhook owned by the calling
128
+ * application. Cross-tenant guarded server-side (404, never 403).
129
+ */
130
+ export const listProbeWebhookDeliveriesApplication = async (
131
+ applicationId: string,
132
+ webhookId: string,
133
+ query: Omit<IListProbeWebhookDeliveriesQuery, 'organizationId'> = {},
134
+ applicationApiKey?: string,
135
+ ): Promise<IListProbeWebhookDeliveriesResponse> =>
136
+ (
137
+ await AbyssToolsCore.axios.get<IListProbeWebhookDeliveriesResponse>(
138
+ `application/${applicationId}/webhook/${webhookId}/deliveries`,
139
+ { params: serializeProbeQuery(query), headers: authHeaderApplication(applicationApiKey) },
140
+ )
141
+ ).data;
package/src/index.ts CHANGED
@@ -36,6 +36,8 @@ import * as probeScanApi from './api/probe-scan.api';
36
36
  import * as probeWebhookApi from './api/probe-webhook.api';
37
37
  import * as probeScanApplicationApi from './api/probe-scan.application.api';
38
38
  import * as probeWebhookApplicationApi from './api/probe-webhook.application.api';
39
+ import * as probeUsageApi from './api/probe-usage.api';
40
+ import * as probeUsageApplicationApi from './api/probe-usage.application.api';
39
41
 
40
42
  export * from './api';
41
43
  export * from './types';
@@ -347,10 +349,18 @@ type AbyssToolsCoreSDK = {
347
349
  getScan: typeof probeScanApi.getScan;
348
350
  /** `GET /scan` — paginated history/search. */
349
351
  listScans: typeof probeScanApi.listScans;
352
+ /** `GET /usage` — current ACCOUNT_AV_SCAN_UNITS used/limit/remaining for the caller's scope. */
353
+ usage: {
354
+ get: typeof probeUsageApi.getProbeUsage;
355
+ };
350
356
  webhook: {
351
357
  create: typeof probeWebhookApi.createProbeWebhook;
352
358
  list: typeof probeWebhookApi.listProbeWebhook;
353
359
  delete: typeof probeWebhookApi.deleteProbeWebhook;
360
+ /** `PATCH /webhook/:webhookId` — edit callbackUrl and/or active. */
361
+ update: typeof probeWebhookApi.updateProbeWebhook;
362
+ /** `GET /webhook/:webhookId/deliveries` — paginated delivery-attempt history. */
363
+ listDeliveries: typeof probeWebhookApi.listProbeWebhookDeliveries;
354
364
  };
355
365
  /**
356
366
  * Application/API-key-auth counterpart (Phase 3a) — for inter-service
@@ -371,10 +381,18 @@ type AbyssToolsCoreSDK = {
371
381
  getScan: typeof probeScanApplicationApi.getScanApplication;
372
382
  /** `GET /application/:applicationId/scan` — paginated history/search. */
373
383
  listScans: typeof probeScanApplicationApi.listScansApplication;
384
+ /** `GET /application/:applicationId/usage` — current ACCOUNT_AV_SCAN_UNITS used/limit/remaining for the calling application. */
385
+ usage: {
386
+ get: typeof probeUsageApplicationApi.getProbeUsageApplication;
387
+ };
374
388
  webhook: {
375
389
  create: typeof probeWebhookApplicationApi.createProbeWebhookApplication;
376
390
  list: typeof probeWebhookApplicationApi.listProbeWebhookApplication;
377
391
  delete: typeof probeWebhookApplicationApi.deleteProbeWebhookApplication;
392
+ /** `PATCH /application/:applicationId/webhook/:webhookId` — edit callbackUrl and/or active. */
393
+ update: typeof probeWebhookApplicationApi.updateProbeWebhookApplication;
394
+ /** `GET /application/:applicationId/webhook/:webhookId/deliveries` — paginated delivery-attempt history. */
395
+ listDeliveries: typeof probeWebhookApplicationApi.listProbeWebhookDeliveriesApplication;
378
396
  };
379
397
  };
380
398
  };
@@ -775,10 +793,15 @@ export class AbyssToolsCore {
775
793
  scanAsync: probeScanApi.scanAsync,
776
794
  getScan: probeScanApi.getScan,
777
795
  listScans: probeScanApi.listScans,
796
+ usage: {
797
+ get: probeUsageApi.getProbeUsage,
798
+ },
778
799
  webhook: {
779
800
  create: probeWebhookApi.createProbeWebhook,
780
801
  list: probeWebhookApi.listProbeWebhook,
781
802
  delete: probeWebhookApi.deleteProbeWebhook,
803
+ update: probeWebhookApi.updateProbeWebhook,
804
+ listDeliveries: probeWebhookApi.listProbeWebhookDeliveries,
782
805
  },
783
806
  application: {
784
807
  scan: probeScanApplicationApi.scanApplication,
@@ -786,10 +809,15 @@ export class AbyssToolsCore {
786
809
  scanAsync: probeScanApplicationApi.scanAsyncApplication,
787
810
  getScan: probeScanApplicationApi.getScanApplication,
788
811
  listScans: probeScanApplicationApi.listScansApplication,
812
+ usage: {
813
+ get: probeUsageApplicationApi.getProbeUsageApplication,
814
+ },
789
815
  webhook: {
790
816
  create: probeWebhookApplicationApi.createProbeWebhookApplication,
791
817
  list: probeWebhookApplicationApi.listProbeWebhookApplication,
792
818
  delete: probeWebhookApplicationApi.deleteProbeWebhookApplication,
819
+ update: probeWebhookApplicationApi.updateProbeWebhookApplication,
820
+ listDeliveries: probeWebhookApplicationApi.listProbeWebhookDeliveriesApplication,
793
821
  },
794
822
  },
795
823
  },
@@ -20,7 +20,23 @@ export enum BeamServeDenyReasonCode {
20
20
  FORBIDDEN_VISIBILITY = 'forbidden_visibility',
21
21
  MAX_DOWNLOADS = 'max_downloads',
22
22
  SCAN_PENDING = 'scan_pending',
23
- SCAN_INFECTED = 'scan_infected',
23
+ }
24
+
25
+ // Per-file AV verdict surfaced on the public listing (GET /b/:slug) so the
26
+ // front can render a per-file badge — clean / "en analyse" (pending) /
27
+ // "infecté" — independently of the whole-transfer denial reason above.
28
+ // Storage-neutral: AbyssBeam serves an INFECTED file's bytes (spec decision —
29
+ // infected files stay downloadable, not blocked; the front is expected to
30
+ // warn before/at download). Mirrors the storage extension's `FileScanStatus`
31
+ // (`@abyss-project/storage`) byte-for-byte; duplicated locally because this
32
+ // package does not depend on `@abyss-project/storage` (same rationale as
33
+ // BeamServeDenyReasonCode above).
34
+ export enum BeamFileScanStatus {
35
+ PENDING_SCAN = 'pending_scan',
36
+ CLEAN = 'clean',
37
+ INFECTED = 'infected',
38
+ SKIPPED = 'skipped',
39
+ ERROR = 'error',
24
40
  }
25
41
 
26
42
  // What a beam_download_events row counted: a single-file download (/b/:slug/
@@ -29,3 +29,4 @@ export * from './transfer.request';
29
29
  export * from './extraction.request';
30
30
  export * from './probe-scan.request';
31
31
  export * from './probe-webhook.request';
32
+ export * from './probe-usage.request';
@@ -0,0 +1,7 @@
1
+ // WS5-3 (AbyssProbe UX rework) — `GET /usage` / `GET /application/:applicationId/usage`.
2
+ // Mirrors apps/api/src/api/validators/probe-usage.validator.ts's Joi schema.
3
+
4
+ /** `GET /usage` query — personal scope (default) or an organization. Not needed for the application variant (its scope is the `:applicationId` URL segment). */
5
+ export interface IProbeUsageScopeQuery {
6
+ organizationId?: string;
7
+ }
@@ -1,7 +1,8 @@
1
1
  // Mirrors apps/api/src/api/controllers/probe-webhook.controller.ts's
2
- // ScopeQuery/CreateBody and probe-webhook.validator.ts's Joi schemas.
2
+ // ScopeQuery/CreateBody/UpdateBody and probe-webhook.validator.ts's Joi
3
+ // schemas.
3
4
 
4
- /** Shared by create/list/delete — personal scope (default) or an organization. */
5
+ /** Shared by create/list/delete/update — personal scope (default) or an organization. */
5
6
  export interface IProbeWebhookScopeQuery {
6
7
  organizationId?: string;
7
8
  }
@@ -10,3 +11,23 @@ export interface ICreateProbeWebhookBody {
10
11
  /** HTTPS endpoint the verdict is POSTed to. Required, `https://` only. */
11
12
  callbackUrl: string;
12
13
  }
14
+
15
+ /**
16
+ * `PATCH /webhook/:webhookId` body (WS5-5) — at least one field required
17
+ * (mirrors probe-webhook.validator.ts#updateBody's `.min(1)`); omitted
18
+ * fields are left unchanged.
19
+ */
20
+ export interface IUpdateProbeWebhookBody {
21
+ /** HTTPS endpoint the verdict is POSTed to, `https://` only. */
22
+ callbackUrl?: string;
23
+ /** Disabled webhooks are skipped by dispatch (soft-off, not deleted). */
24
+ active?: boolean;
25
+ }
26
+
27
+ /** `GET /webhook/:webhookId/deliveries` query (WS5-6) — paginated. */
28
+ export interface IListProbeWebhookDeliveriesQuery extends IProbeWebhookScopeQuery {
29
+ /** @default 1 */
30
+ page?: number;
31
+ /** @default 20 */
32
+ limit?: number;
33
+ }
@@ -2,7 +2,12 @@ import { BasePaginate } from '../type-message/base-paginate';
2
2
  import { IResponse } from '../type-message/response';
3
3
  import { IBeamTransfer, IBeamFile, IBeamRecipient } from '../../models/beam.dto';
4
4
  import { IContentShare } from '../../models/content-share.dto';
5
- import { BeamVisibility, BeamServeDenyReasonCode, BeamDownloadKind } from '../../../enum/beam.enum';
5
+ import {
6
+ BeamVisibility,
7
+ BeamServeDenyReasonCode,
8
+ BeamDownloadKind,
9
+ BeamFileScanStatus,
10
+ } from '../../../enum/beam.enum';
6
11
 
7
12
  export interface IGetBeamData {
8
13
  beamTransfer: IBeamTransfer;
@@ -39,6 +44,9 @@ export type IFinalizeBeamResponse = IResponse<IFinalizeBeamData>;
39
44
  // Public serving (B3) — safe, purpose-built projection of a transfer for the
40
45
  // browser-facing view: no owner ids, no password/manage hashes; adds
41
46
  // hasPassword/isLocked/hasThumbnail so the front can render the locked state.
47
+ // `scanStatus` is the per-file AV verdict (storage-neutral — an INFECTED file
48
+ // is still listed and downloadable; the front renders the warning from this
49
+ // field, see BeamFileScanStatus).
42
50
  export interface IBeamPublicFile {
43
51
  id: string;
44
52
  name: string;
@@ -48,6 +56,7 @@ export interface IBeamPublicFile {
48
56
  hasThumbnail: boolean;
49
57
  width: number | null;
50
58
  height: number | null;
59
+ scanStatus: BeamFileScanStatus;
51
60
  }
52
61
 
53
62
  export interface IBeamPublicView {
@@ -33,3 +33,4 @@ export * from './extraction.response';
33
33
  export * from './monitor.response';
34
34
  export * from './probe-scan.response';
35
35
  export * from './probe-webhook.response';
36
+ export * from './probe-usage.response';
@@ -12,6 +12,13 @@ export interface IScanSyncData {
12
12
  scanId: string;
13
13
  verdict: ProbeScanVerdict;
14
14
  viruses: string[];
15
+ /**
16
+ * `ACCOUNT_AV_SCAN_UNITS` this scan consumed (WS5-1/2 — see
17
+ * `estimateProbeScanCost`). Always a number here (never null): a SYNC
18
+ * response is only ever sent once the scan has reached a verdict, at
19
+ * which point the cost is always known and already billed.
20
+ */
21
+ costUnits: number;
15
22
  }
16
23
  export type IScanSyncResponse = IResponse<IScanSyncData>;
17
24
 
@@ -0,0 +1,25 @@
1
+ import { IResponse } from '../type-message/response';
2
+
3
+ // WS5-3 (AbyssProbe UX rework) — mirrors
4
+ // apps/api/src/api/controllers/probe-usage.controller.ts's local response
5
+ // shape EXACTLY. Current ACCOUNT_AV_SCAN_UNITS ("tokens") consumption for the
6
+ // caller's scope, via the same billing check the quota gate itself uses.
7
+
8
+ export interface IProbeUsageData {
9
+ /** Units consumed so far in the current billing period. */
10
+ used: number;
11
+ /**
12
+ * Plan cap. `-1` is this codebase's established "unlimited" sentinel (see
13
+ * `utils/billing-emit.util.ts#UNLIMITED_EXPIRY_DAYS` server-side) — an
14
+ * unmetered plan tier reports `-1` here rather than `Infinity`/`null`, so
15
+ * treat a negative value as "no cap", never a literal negative quota.
16
+ */
17
+ limit: number;
18
+ /**
19
+ * `limit - used`, floored at 0 — except it mirrors `limit`'s own `-1`
20
+ * sentinel unchanged when `limit` is unlimited (never a finite number in
21
+ * that case).
22
+ */
23
+ remaining: number;
24
+ }
25
+ export type IProbeUsageResponse = IResponse<IProbeUsageData>;