@abyss-project/tools 2.1.0 → 2.2.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 (132) hide show
  1. package/dist/api/index.d.ts +4 -0
  2. package/dist/api/index.js +4 -0
  3. package/dist/api/index.js.map +1 -1
  4. package/dist/api/probe-scan.api.d.ts +15 -0
  5. package/dist/api/probe-scan.api.js +74 -0
  6. package/dist/api/probe-scan.api.js.map +1 -0
  7. package/dist/api/probe-scan.api.test.d.ts +1 -0
  8. package/dist/api/probe-scan.api.test.js +37 -0
  9. package/dist/api/probe-scan.api.test.js.map +1 -0
  10. package/dist/api/probe-scan.application.api.d.ts +7 -0
  11. package/dist/api/probe-scan.application.api.js +40 -0
  12. package/dist/api/probe-scan.application.api.js.map +1 -0
  13. package/dist/api/probe-scan.application.api.test.d.ts +1 -0
  14. package/dist/api/probe-scan.application.api.test.js +37 -0
  15. package/dist/api/probe-scan.application.api.test.js.map +1 -0
  16. package/dist/api/probe-webhook.api.d.ts +4 -0
  17. package/dist/api/probe-webhook.api.js +34 -0
  18. package/dist/api/probe-webhook.api.js.map +1 -0
  19. package/dist/api/probe-webhook.api.test.d.ts +1 -0
  20. package/dist/api/probe-webhook.api.test.js +33 -0
  21. package/dist/api/probe-webhook.api.test.js.map +1 -0
  22. package/dist/api/probe-webhook.application.api.d.ts +4 -0
  23. package/dist/api/probe-webhook.application.api.js +14 -0
  24. package/dist/api/probe-webhook.application.api.js.map +1 -0
  25. package/dist/api/probe-webhook.application.api.test.d.ts +1 -0
  26. package/dist/api/probe-webhook.application.api.test.js +33 -0
  27. package/dist/api/probe-webhook.application.api.test.js.map +1 -0
  28. package/dist/index.d.ts +31 -0
  29. package/dist/index.js +32 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/types/enum/api-error.enum.d.ts +1 -5
  32. package/dist/types/enum/api-error.enum.js +0 -4
  33. package/dist/types/enum/api-error.enum.js.map +1 -1
  34. package/dist/types/enum/index.d.ts +1 -1
  35. package/dist/types/enum/index.js +1 -1
  36. package/dist/types/enum/index.js.map +1 -1
  37. package/dist/types/enum/probe-scan.enum.d.ts +14 -0
  38. package/dist/types/enum/probe-scan.enum.js +21 -0
  39. package/dist/types/enum/probe-scan.enum.js.map +1 -0
  40. package/dist/types/interface/api/requests/index.d.ts +2 -0
  41. package/dist/types/interface/api/requests/index.js +2 -0
  42. package/dist/types/interface/api/requests/index.js.map +1 -1
  43. package/dist/types/interface/api/requests/probe-scan.request.d.ts +22 -0
  44. package/dist/types/interface/api/{responses/file-scan.response.js → requests/probe-scan.request.js} +1 -1
  45. package/dist/types/interface/api/requests/probe-scan.request.js.map +1 -0
  46. package/dist/types/interface/api/requests/probe-webhook.request.d.ts +6 -0
  47. package/dist/types/{enum/file-scan-status.enum.js → interface/api/requests/probe-webhook.request.js} +1 -1
  48. package/dist/types/interface/api/requests/probe-webhook.request.js.map +1 -0
  49. package/dist/types/interface/api/responses/beam.response.d.ts +1 -3
  50. package/dist/types/interface/api/responses/index.d.ts +2 -0
  51. package/dist/types/interface/api/responses/index.js +2 -0
  52. package/dist/types/interface/api/responses/index.js.map +1 -1
  53. package/dist/types/interface/api/responses/probe-scan.response.d.ts +18 -0
  54. package/dist/types/interface/api/responses/probe-scan.response.js +3 -0
  55. package/dist/types/interface/api/responses/probe-scan.response.js.map +1 -0
  56. package/dist/types/interface/api/responses/probe-webhook.response.d.ts +10 -0
  57. package/dist/types/interface/api/responses/probe-webhook.response.js +3 -0
  58. package/dist/types/interface/api/responses/probe-webhook.response.js.map +1 -0
  59. package/dist/types/interface/models/atlas-document.dto.d.ts +0 -3
  60. package/dist/types/interface/models/beam.dto.d.ts +0 -3
  61. package/dist/types/interface/models/board-card-document.dto.d.ts +0 -3
  62. package/dist/types/interface/models/extraction.dto.d.ts +0 -2
  63. package/dist/types/interface/models/extraction.dto.js.map +1 -1
  64. package/dist/types/interface/models/index.d.ts +3 -0
  65. package/dist/types/interface/models/index.js +3 -0
  66. package/dist/types/interface/models/index.js.map +1 -1
  67. package/dist/types/interface/models/probe-scan.dto.d.ts +22 -0
  68. package/dist/types/interface/models/{file-scan.dto.js → probe-scan.dto.js} +1 -1
  69. package/dist/types/interface/models/probe-scan.dto.js.map +1 -0
  70. package/dist/types/interface/models/probe-webhook-delivery.dto.d.ts +7 -0
  71. package/dist/types/interface/models/probe-webhook-delivery.dto.js +3 -0
  72. package/dist/types/interface/models/probe-webhook-delivery.dto.js.map +1 -0
  73. package/dist/types/interface/models/probe-webhook.dto.d.ts +9 -0
  74. package/dist/types/interface/{api/requests/file-scan.request.js → models/probe-webhook.dto.js} +1 -1
  75. package/dist/types/interface/models/probe-webhook.dto.js.map +1 -0
  76. package/dist/types/tests/probe.dto.test.d.ts +1 -0
  77. package/dist/types/tests/probe.dto.test.js +62 -0
  78. package/dist/types/tests/probe.dto.test.js.map +1 -0
  79. package/dist/utils/index.d.ts +1 -0
  80. package/dist/utils/index.js +1 -0
  81. package/dist/utils/index.js.map +1 -1
  82. package/dist/utils/probe-webhook-signature.utils.d.ts +8 -0
  83. package/dist/utils/probe-webhook-signature.utils.js +22 -0
  84. package/dist/utils/probe-webhook-signature.utils.js.map +1 -0
  85. package/package.json +1 -1
  86. package/src/api/index.ts +6 -0
  87. package/src/api/probe-scan.api.test.ts +21 -0
  88. package/src/api/probe-scan.api.ts +191 -0
  89. package/src/api/probe-scan.application.api.test.ts +21 -0
  90. package/src/api/probe-scan.application.api.ts +157 -0
  91. package/src/api/probe-webhook.api.test.ts +17 -0
  92. package/src/api/probe-webhook.api.ts +81 -0
  93. package/src/api/probe-webhook.application.api.test.ts +18 -0
  94. package/src/api/probe-webhook.application.api.ts +87 -0
  95. package/src/index.ts +86 -0
  96. package/src/types/enum/api-error.enum.ts +0 -25
  97. package/src/types/enum/index.ts +1 -1
  98. package/src/types/enum/probe-scan.enum.ts +44 -0
  99. package/src/types/interface/api/requests/index.ts +2 -0
  100. package/src/types/interface/api/requests/probe-scan.request.ts +50 -0
  101. package/src/types/interface/api/requests/probe-webhook.request.ts +12 -0
  102. package/src/types/interface/api/responses/beam.response.ts +1 -15
  103. package/src/types/interface/api/responses/index.ts +2 -0
  104. package/src/types/interface/api/responses/probe-scan.response.ts +38 -0
  105. package/src/types/interface/api/responses/probe-webhook.response.ts +17 -0
  106. package/src/types/interface/models/atlas-document.dto.ts +0 -18
  107. package/src/types/interface/models/beam.dto.ts +0 -22
  108. package/src/types/interface/models/board-card-document.dto.ts +0 -18
  109. package/src/types/interface/models/extraction.dto.ts +0 -17
  110. package/src/types/interface/models/index.ts +3 -0
  111. package/src/types/interface/models/probe-scan.dto.ts +48 -0
  112. package/src/types/interface/models/probe-webhook-delivery.dto.ts +26 -0
  113. package/src/types/interface/models/probe-webhook.dto.ts +25 -0
  114. package/src/types/tests/beam.dto.spec.ts +0 -2
  115. package/src/types/tests/probe.dto.test.ts +97 -0
  116. package/src/utils/index.ts +1 -0
  117. package/src/utils/probe-webhook-signature.utils.ts +56 -0
  118. package/dist/api/file-scan.api.d.ts +0 -5
  119. package/dist/api/file-scan.api.js +0 -49
  120. package/dist/api/file-scan.api.js.map +0 -1
  121. package/dist/types/enum/analysis-status.enum.d.ts +0 -7
  122. package/dist/types/enum/analysis-status.enum.js +0 -12
  123. package/dist/types/enum/analysis-status.enum.js.map +0 -1
  124. package/dist/types/enum/file-scan-status.enum.d.ts +0 -1
  125. package/dist/types/enum/file-scan-status.enum.js.map +0 -1
  126. package/dist/types/interface/api/requests/file-scan.request.d.ts +0 -3
  127. package/dist/types/interface/api/requests/file-scan.request.js.map +0 -1
  128. package/dist/types/interface/api/responses/file-scan.response.d.ts +0 -7
  129. package/dist/types/interface/api/responses/file-scan.response.js.map +0 -1
  130. package/dist/types/interface/models/file-scan.dto.d.ts +0 -11
  131. package/dist/types/interface/models/file-scan.dto.js.map +0 -1
  132. package/src/types/enum/file-scan-status.enum.ts +0 -23
package/src/index.ts CHANGED
@@ -32,6 +32,10 @@ import * as extractionApi from './api/extraction.api';
32
32
  import * as extractionSettingsApi from './api/extraction-settings.api';
33
33
  import * as extractionPlanPresetApi from './api/extraction-plan-preset.api';
34
34
  import * as monitorApi from './api/monitor.api';
35
+ import * as probeScanApi from './api/probe-scan.api';
36
+ import * as probeWebhookApi from './api/probe-webhook.api';
37
+ import * as probeScanApplicationApi from './api/probe-scan.application.api';
38
+ import * as probeWebhookApplicationApi from './api/probe-webhook.application.api';
35
39
 
36
40
  export * from './api';
37
41
  export * from './types';
@@ -42,8 +46,24 @@ export * from './server-sent-events';
42
46
  const DEFAULT_BASE_URL = 'https://tools-api.abyss-project.fr/api/';
43
47
 
44
48
  export const API_KEY_HEADER = 'abyss-api-key';
49
+ /**
50
+ * Application-level API key header (Phase 3a — AbyssProbe application/API-key
51
+ * authentication). Same literal value every other Abyss service's own core
52
+ * package independently declares for its `ApplicationMiddleware` (abyss-
53
+ * storage, abyss-monitor, abyss-console — see
54
+ * probe-application.middleware.ts for the mirrored resolution logic).
55
+ */
56
+ export const API_KEY_APPLICATION_HEADER = 'abyss-api-key-application';
45
57
  export const ADMIN_TOKEN_HEADER = 'abyss-admin-token';
46
58
 
59
+ /**
60
+ * Header carrying the HMAC-SHA256 signature of a probe webhook delivery's
61
+ * raw JSON body (see apps/api/src/services/probe-webhook-delivery.service.ts).
62
+ * Verify it with {@link verifyProbeWebhookSignature} (re-exported from './utils').
63
+ */
64
+ export const PROBE_WEBHOOK_SIGNATURE_HEADER = 'x-probe-signature';
65
+ export const PROBE_WEBHOOK_SIGNATURE_ALGORITHM = 'sha256';
66
+
47
67
  const NUMBER_RETRY_API = 10;
48
68
  const BASE_DELAY_BETWEEN_RETRY = 5000;
49
69
  const RETRY_CODES = [
@@ -316,6 +336,48 @@ type AbyssToolsCoreSDK = {
316
336
  monitor: {
317
337
  up: typeof monitorApi.upMonitor;
318
338
  };
339
+ probe: {
340
+ /** `POST /scan` — sync (default) or async depending on `options.mode`. */
341
+ scan: typeof probeScanApi.scan;
342
+ /** `POST /scan` forced to `mode: sync` — precisely-typed 200 response. */
343
+ scanSync: typeof probeScanApi.scanSync;
344
+ /** `POST /scan?mode=async` — precisely-typed 202 response. */
345
+ scanAsync: typeof probeScanApi.scanAsync;
346
+ /** `GET /scan/:scanId` — poll a scan's status/verdict. */
347
+ getScan: typeof probeScanApi.getScan;
348
+ /** `GET /scan` — paginated history/search. */
349
+ listScans: typeof probeScanApi.listScans;
350
+ webhook: {
351
+ create: typeof probeWebhookApi.createProbeWebhook;
352
+ list: typeof probeWebhookApi.listProbeWebhook;
353
+ delete: typeof probeWebhookApi.deleteProbeWebhook;
354
+ };
355
+ /**
356
+ * Application/API-key-auth counterpart (Phase 3a) — for inter-service
357
+ * callers (abyss-storage, external integrations) instead of a
358
+ * personal/org session. Same request/response contracts as the methods
359
+ * above, hitting `/application/:applicationId/...` and authenticated
360
+ * with the `abyss-api-key-application` header ({@link
361
+ * API_KEY_APPLICATION_HEADER}) instead of the personal `abyss-api-key`.
362
+ */
363
+ application: {
364
+ /** `POST /application/:applicationId/scan` — sync (default) or async depending on `options.mode`. */
365
+ scan: typeof probeScanApplicationApi.scanApplication;
366
+ /** `POST /application/:applicationId/scan` forced to `mode: sync` — precisely-typed 200 response. */
367
+ scanSync: typeof probeScanApplicationApi.scanSyncApplication;
368
+ /** `POST /application/:applicationId/scan?mode=async` — precisely-typed 202 response. */
369
+ scanAsync: typeof probeScanApplicationApi.scanAsyncApplication;
370
+ /** `GET /application/:applicationId/scan/:scanId` — poll a scan's status/verdict. */
371
+ getScan: typeof probeScanApplicationApi.getScanApplication;
372
+ /** `GET /application/:applicationId/scan` — paginated history/search. */
373
+ listScans: typeof probeScanApplicationApi.listScansApplication;
374
+ webhook: {
375
+ create: typeof probeWebhookApplicationApi.createProbeWebhookApplication;
376
+ list: typeof probeWebhookApplicationApi.listProbeWebhookApplication;
377
+ delete: typeof probeWebhookApplicationApi.deleteProbeWebhookApplication;
378
+ };
379
+ };
380
+ };
319
381
  tag: {
320
382
  list: typeof tagApi.listTag;
321
383
  create: typeof tagApi.createTag;
@@ -707,6 +769,30 @@ export class AbyssToolsCore {
707
769
  monitor: {
708
770
  up: monitorApi.upMonitor,
709
771
  },
772
+ probe: {
773
+ scan: probeScanApi.scan,
774
+ scanSync: probeScanApi.scanSync,
775
+ scanAsync: probeScanApi.scanAsync,
776
+ getScan: probeScanApi.getScan,
777
+ listScans: probeScanApi.listScans,
778
+ webhook: {
779
+ create: probeWebhookApi.createProbeWebhook,
780
+ list: probeWebhookApi.listProbeWebhook,
781
+ delete: probeWebhookApi.deleteProbeWebhook,
782
+ },
783
+ application: {
784
+ scan: probeScanApplicationApi.scanApplication,
785
+ scanSync: probeScanApplicationApi.scanSyncApplication,
786
+ scanAsync: probeScanApplicationApi.scanAsyncApplication,
787
+ getScan: probeScanApplicationApi.getScanApplication,
788
+ listScans: probeScanApplicationApi.listScansApplication,
789
+ webhook: {
790
+ create: probeWebhookApplicationApi.createProbeWebhookApplication,
791
+ list: probeWebhookApplicationApi.listProbeWebhookApplication,
792
+ delete: probeWebhookApplicationApi.deleteProbeWebhookApplication,
793
+ },
794
+ },
795
+ },
710
796
  tag: {
711
797
  list: tagApi.listTag,
712
798
  create: tagApi.createTag,
@@ -20,29 +20,4 @@ export enum Code {
20
20
  atlasDocumentLimitReached = 'atlas_document_limit_reached',
21
21
  boardCardDocumentLimitReached = 'board_card_document_limit_reached',
22
22
  boardCardMoveInvalidDestination = 'board_card_move_invalid_destination',
23
- // AV v3 P2 async-enforce: thrown by assertNotPendingScan while a document's
24
- // antivirus scan is still running (scanStatus === 'pending_scan'). Mapped
25
- // to HTTP 423 in http-response-error.module.ts.
26
- boardCardDocumentAnalysing = 'board_card_document_analysing',
27
- atlasDocumentAnalysing = 'atlas_document_analysing',
28
- // AV v3 P3 async-enforce: thrown by extractionFileService.assertNotPendingScan
29
- // while an ARCHIVE-OWNED extraction_files row's antivirus scan is still
30
- // running (scanStatus === 'pending_scan'). Gates only derived OUTPUTS
31
- // (bundle/records/diff/export/share) — never the extraction metadata
32
- // itself, which already ran synchronously before any verdict was known.
33
- // Mapped to HTTP 423 in http-response-error.module.ts.
34
- extractionFileAnalysing = 'extraction_file_analysing',
35
- // AV v3 P3 async-enforce server backstop: thrown by
36
- // beamUploadService.attachFiles when a resolved storage file's scanStatus
37
- // is not PENDING_SCAN at attach time. AbyssBeam's presign is front-driven
38
- // (resumable-upload.ts calls AbyssStorage directly, never through this
39
- // backend), so a client could omit `antivirus: { scan: true }` on its own
40
- // presign request; a properly-enrolled fresh upload is always
41
- // PENDING_SCAN the moment attach is called (the async worker has not run
42
- // yet), so anything else — most tellingly a null/absent scanStatus,
43
- // meaning no scan was ever requested — means enrollment was bypassed and
44
- // the attach is rejected outright. Not mapped in http-response-error
45
- // .module.ts's statusByCode table, so it falls through to the default 400
46
- // (a rejected request, not a "still analysing" 423 state).
47
- beamFileNotEnrolled = 'beam_file_not_enrolled',
48
23
  }
@@ -11,4 +11,4 @@ export * from './extraction-feedback-issue-type.enum';
11
11
  export * from './provider-kind.enum';
12
12
  export * from './interpreter-kind.enum';
13
13
  export * from './combine-strategy.enum';
14
- export * from './file-scan-status.enum';
14
+ export * from './probe-scan.enum';
@@ -0,0 +1,44 @@
1
+ // Mirrors apps/api/src/database/probe-scan.enum.ts EXACTLY (same string
2
+ // values — this SDK talks to that API over the wire, so the values must
3
+ // match byte-for-byte). Kept as a single file here too, on purpose: the
4
+ // server groups all three enums in one file for the same reason (they are
5
+ // one cohesive scan vocabulary), see that file's header comment.
6
+
7
+ /**
8
+ * Antivirus scan verdict. `null` on the wire while the scan has not reached
9
+ * `DONE` yet (see {@link ProbeScanStatus}) — a scan that never completes
10
+ * (e.g. the engine throws) is left at its last real status with no
11
+ * fabricated verdict.
12
+ */
13
+ export enum ProbeScanVerdict {
14
+ CLEAN = 'clean',
15
+ INFECTED = 'infected',
16
+ }
17
+
18
+ /**
19
+ * How the scan was (or will be) run: `SYNC` blocks the request until the
20
+ * engine returns the verdict inline; `ASYNC` queues the job and delivers the
21
+ * verdict later via a registered webhook and/or the per-request
22
+ * `callbackUrl`, and/or by polling `GET /scan/:scanId`.
23
+ */
24
+ export enum ProbeScanMode {
25
+ SYNC = 'sync',
26
+ ASYNC = 'async',
27
+ }
28
+
29
+ /**
30
+ * Scan lifecycle. A SYNC scan skips `QUEUED` entirely (created directly at
31
+ * `SCANNING`). An ASYNC scan is created at `QUEUED`, flipped to `SCANNING`
32
+ * once a worker picks the job off the queue, then to `DONE` or `ERROR`.
33
+ *
34
+ * `ERROR` (async-only) is a TERMINAL, no-verdict state — there is no
35
+ * automatic requeue/retry (the uploaded bytes are deleted the moment the job
36
+ * ends, success or failure). A caller that wants to retry submits a brand
37
+ * new `POST /scan?mode=async`.
38
+ */
39
+ export enum ProbeScanStatus {
40
+ QUEUED = 'queued',
41
+ SCANNING = 'scanning',
42
+ DONE = 'done',
43
+ ERROR = 'error',
44
+ }
@@ -27,3 +27,5 @@ export * from './metrics.request';
27
27
  export * from './tag.request';
28
28
  export * from './transfer.request';
29
29
  export * from './extraction.request';
30
+ export * from './probe-scan.request';
31
+ export * from './probe-webhook.request';
@@ -0,0 +1,50 @@
1
+ import { ProbeScanMode, ProbeScanStatus, ProbeScanVerdict } from '../../../enum';
2
+
3
+ // Mirrors apps/api/src/api/controllers/probe-scan.controller.ts's ScanBody +
4
+ // HistoryQuery, and apps/api/src/api/validators/probe-scan.validator.ts's
5
+ // historyQuery() Joi schema (field names/optionality).
6
+
7
+ /**
8
+ * Options accepted by `sdk.probe.scan(file, options)` — `POST /scan`. `mode`
9
+ * and `organizationId` travel as query params (`?mode=async&organization_id=`);
10
+ * `context` and `callbackUrl` travel as multipart text fields alongside the
11
+ * file — the sdk client handles that split, callers just pass one object.
12
+ */
13
+ export interface IScanOptions {
14
+ /** sync (default — verdict returned inline) or async (queued, 202 + webhook/poll). */
15
+ mode?: ProbeScanMode;
16
+ /** Personal scope (default) or an organization the caller belongs to. */
17
+ organizationId?: string;
18
+ /** Free-form caller reference (e.g. `{ applicationFileId }`), stored verbatim. */
19
+ context?: Record<string, unknown>;
20
+ /** ASYNC-only per-request delivery override (https only). Ignored for a SYNC scan. */
21
+ callbackUrl?: string;
22
+ /** Filename reported to the server (defaults to `'file'`). Cosmetic only. */
23
+ filename?: string;
24
+ /** Content-Type hint used when constructing a Blob from a raw buffer/Uint8Array in a browser context. */
25
+ mimeType?: string;
26
+ }
27
+
28
+ /**
29
+ * `GET /scan` query — all filters optional, combined with AND.
30
+ * `contextKey`/`contextValue` must be supplied together (business-reference
31
+ * search inside the free-form `context` JSONB column) — supplying one
32
+ * without the other is rejected by the API (400).
33
+ */
34
+ export interface IListScansQuery {
35
+ organizationId?: string;
36
+ verdict?: ProbeScanVerdict;
37
+ mode?: ProbeScanMode;
38
+ status?: ProbeScanStatus;
39
+ /** Date range on `createdAt`, inclusive at both ends. */
40
+ from?: Date;
41
+ to?: Date;
42
+ /** Case-insensitive partial match on the original file name. */
43
+ fileName?: string;
44
+ contextKey?: string;
45
+ contextValue?: string;
46
+ /** @default 1 */
47
+ page?: number;
48
+ /** @default 20, server max 200. */
49
+ limit?: number;
50
+ }
@@ -0,0 +1,12 @@
1
+ // Mirrors apps/api/src/api/controllers/probe-webhook.controller.ts's
2
+ // ScopeQuery/CreateBody and probe-webhook.validator.ts's Joi schemas.
3
+
4
+ /** Shared by create/list/delete — personal scope (default) or an organization. */
5
+ export interface IProbeWebhookScopeQuery {
6
+ organizationId?: string;
7
+ }
8
+
9
+ export interface ICreateProbeWebhookBody {
10
+ /** HTTPS endpoint the verdict is POSTed to. Required, `https://` only. */
11
+ callbackUrl: string;
12
+ }
@@ -3,7 +3,6 @@ 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
5
  import { BeamVisibility, BeamServeDenyReasonCode, BeamDownloadKind } from '../../../enum/beam.enum';
6
- import { FileScanStatus } from '../../../enum/file-scan-status.enum';
7
6
 
8
7
  export interface IGetBeamData {
9
8
  beamTransfer: IBeamTransfer;
@@ -41,16 +40,7 @@ export type IFinalizeBeamResponse = IResponse<IFinalizeBeamData>;
41
40
  // browser-facing view: no owner ids, no password/manage hashes; adds
42
41
  // hasPassword/isLocked/hasThumbnail so the front can render the locked state.
43
42
  export interface IBeamPublicFile {
44
- // AV v3 P3 async-enforce — the listing endpoint (GET /b/:slug) is the ONE
45
- // beam serve path that is not gated by beamServingService.gateFile (it is
46
- // a metadata list, not a byte stream). Per the link-live-gate-per-file
47
- // decision the share link itself always works, but a file whose own
48
- // scanStatus is not (yet) CLEAN must not hand out a servable identifier:
49
- // id is null and hasThumbnail is forced false so the front cannot build a
50
- // download/thumb URL for a pending or quarantined file. A legacy NULL
51
- // scanStatus (row written before this column existed) is treated as
52
- // servable, matching gateFile.
53
- id: string | null;
43
+ id: string;
54
44
  name: string;
55
45
  sizeOctet: number;
56
46
  mimeType: string | null;
@@ -58,10 +48,6 @@ export interface IBeamPublicFile {
58
48
  hasThumbnail: boolean;
59
49
  width: number | null;
60
50
  height: number | null;
61
- // Exposed as-is (never redacted) regardless of servability, so the front
62
- // can render an "analysing" placeholder for a withheld file instead of it
63
- // just silently vanishing from the list.
64
- scanStatus: FileScanStatus | null;
65
51
  }
66
52
 
67
53
  export interface IBeamPublicView {
@@ -31,3 +31,5 @@ export * from './recent.response';
31
31
  export * from './transfer.response';
32
32
  export * from './extraction.response';
33
33
  export * from './monitor.response';
34
+ export * from './probe-scan.response';
35
+ export * from './probe-webhook.response';
@@ -0,0 +1,38 @@
1
+ import { IResponse } from '../type-message/response';
2
+ import { BasePaginate } from '../type-message/base-paginate';
3
+ import { ProbeScanStatus, ProbeScanVerdict } from '../../../enum';
4
+ import { IProbeScanDetail, IProbeScanHistoryItem } from '../../models';
5
+
6
+ // Mirrors apps/api/src/api/controllers/probe-scan.controller.ts's local
7
+ // ScanSyncResponseData / ScanAsyncResponseData / GetScanResponseData /
8
+ // PaginateScanResponseData EXACTLY.
9
+
10
+ /** `POST /scan` (default, or explicit `?mode=sync`) — HTTP 200. */
11
+ export interface IScanSyncData {
12
+ scanId: string;
13
+ verdict: ProbeScanVerdict;
14
+ viruses: string[];
15
+ }
16
+ export type IScanSyncResponse = IResponse<IScanSyncData>;
17
+
18
+ /** `POST /scan?mode=async` — HTTP 202, job queued. */
19
+ export interface IScanAsyncData {
20
+ scanId: string;
21
+ status: ProbeScanStatus.QUEUED;
22
+ }
23
+ export type IScanAsyncResponse = IResponse<IScanAsyncData>;
24
+
25
+ /**
26
+ * `POST /scan`'s actual response body is one or the other of the two data
27
+ * shapes above, discriminated by the request's own `mode` (sync -> 200 +
28
+ * {@link IScanSyncData}, async -> 202 + {@link IScanAsyncData}). A caller
29
+ * that only ever uses one mode should prefer the sdk's `scanSync`/`scanAsync`
30
+ * wrappers, which return the precise, non-union type.
31
+ */
32
+ export type IScanResponse = IScanSyncResponse | IScanAsyncResponse;
33
+
34
+ /** `GET /scan/:scanId` — HTTP 200. */
35
+ export type IGetScanResponse = IResponse<IProbeScanDetail>;
36
+
37
+ /** `GET /scan` — HTTP 200, paginated history/search. */
38
+ export type IPaginateScanResponse = IResponse<BasePaginate<IProbeScanHistoryItem>>;
@@ -0,0 +1,17 @@
1
+ import { IResponse } from '../type-message/response';
2
+ import { IProbeWebhook, IProbeWebhookCreated } from '../../models';
3
+
4
+ // Mirrors apps/api/src/api/controllers/probe-webhook.controller.ts's local
5
+ // response shapes EXACTLY.
6
+
7
+ /** `POST /webhook` — HTTP 201. The only response that ever carries `secret`. */
8
+ export type ICreateProbeWebhookResponse = IResponse<IProbeWebhookCreated>;
9
+
10
+ /** `GET /webhook` — HTTP 200. A flat scope-filtered list, NOT paginated. */
11
+ export interface IListProbeWebhookData {
12
+ webhooks: IProbeWebhook[];
13
+ }
14
+ export type IListProbeWebhookResponse = IResponse<IListProbeWebhookData>;
15
+
16
+ /** `DELETE /webhook/:webhookId` — HTTP 200. */
17
+ export type IDeleteProbeWebhookResponse = IResponse<{ ok: true }>;
@@ -1,19 +1,11 @@
1
1
  import { IAtlasPage } from './atlas-page.dto';
2
2
  import { IAtlas } from './atlas.dto';
3
- import { FileScanStatus } from '../../enum/file-scan-status.enum';
4
3
 
5
4
  export interface IAtlasDocument {
6
5
  id: string;
7
6
  atlasPageId: string;
8
7
  atlasId: string;
9
8
  name: string;
10
- // AV v3 P2 async-enforce — WIRE CAVEAT: these 4 fields type as always-present
11
- // here (the true, always-populated stored/model shape), but the HTTP JSON
12
- // response actually redacts all four to `null` while scanStatus is
13
- // 'pending_scan' (see the AtlasDocument model's toJSON() override) —
14
- // pending_scan grants no servable identifier to any caller, owner included.
15
- // A future front consumer of this DTO must treat them as possibly-null at
16
- // runtime whenever scanStatus === 'pending_scan', despite the `string` type.
17
9
  externalId: string;
18
10
  publicAccessId: string;
19
11
  thumbnailId: string | null;
@@ -21,16 +13,6 @@ export interface IAtlasDocument {
21
13
  sizeOctet: number;
22
14
  mimeType: string;
23
15
  checksum: string;
24
- // AV v3 P2 async-enforce: antivirus verdict mirrored from AbyssStorage,
25
- // seeded pending_scan at the UPLOAD webhook, updated by applyScanResult /
26
- // purgeInfected on the SCAN_RESULT webhook. Null for rows created before
27
- // this column existed. See assertNotPendingScan for the 423 gate.
28
- scanStatus: FileScanStatus | null;
29
- // Id of the user who requested this upload (currentUser at presign time),
30
- // resolved server-side — never client-supplied. Null for an API-key/
31
- // anonymous upload. Used ONLY to notify the uploader if the file is later
32
- // found infected (purgeInfected) — not a permission/ownership field.
33
- uploadedByUserId: string | null;
34
16
  createdAt?: Date;
35
17
  updatedAt?: Date;
36
18
 
@@ -2,7 +2,6 @@ import { IOrganization } from './organization.dto';
2
2
  import { IUser } from './user.dto';
3
3
  import { IProject } from './project.dto';
4
4
  import { BeamVisibility, BeamDownloadKind } from '../../enum/beam.enum';
5
- import { FileScanStatus } from '../../enum/file-scan-status.enum';
6
5
 
7
6
  export interface IBeamTransfer {
8
7
  id: string;
@@ -39,13 +38,6 @@ export interface IBeamTransfer {
39
38
  export interface IBeamFile {
40
39
  id: string;
41
40
  transferId: string;
42
- // AV v3 P3 async-enforce — WIRE CAVEAT: typed as always-present here (the
43
- // true, always-populated stored/model shape), but the HTTP JSON response
44
- // actually redacts this (and thumbnailStorageFileId) to null while
45
- // scanStatus is 'pending_scan' (see the BeamFile model's get() override) —
46
- // pending_scan grants no servable identifier to any caller. A future front
47
- // consumer of this DTO must treat it as possibly-null at runtime whenever
48
- // scanStatus === 'pending_scan', despite the `string` type.
49
41
  // abyss-storage applicationFileId (PRIVATE bucket); resolved at serve time (B4).
50
42
  storageFileId: string;
51
43
  thumbnailStorageFileId: string | null;
@@ -59,20 +51,6 @@ export interface IBeamFile {
59
51
  position: number;
60
52
  createdAt?: Date;
61
53
 
62
- // AV v3 P3 async-enforce: antivirus verdict mirrored from AbyssStorage,
63
- // seeded at attach time (beamUploadService#attachFiles — REQUIRES
64
- // pending_scan, a server-side backstop against a client presign that
65
- // omitted antivirus enrollment; see resumable-upload.ts) and updated by
66
- // applyScanResult / purgeInfected on the SCAN_RESULT webhook. Null for
67
- // rows created before this column existed. See
68
- // beamServingService#gateFile for the per-file serve gate.
69
- scanStatus: FileScanStatus | null;
70
- // Id of the user who requested this attach (currentUser at attach time,
71
- // resolved server-side — never client-supplied). Null for an anonymous
72
- // transfer's attach. Used ONLY to notify the uploader if the file is later
73
- // found infected (purgeInfected) — not a permission/ownership field.
74
- uploadedByUserId: string | null;
75
-
76
54
  transfer?: IBeamTransfer;
77
55
  }
78
56
 
@@ -1,19 +1,11 @@
1
1
  import { IBoardCard } from './board-card.dto';
2
2
  import { IBoard } from './board.dto';
3
- import { FileScanStatus } from '../../enum/file-scan-status.enum';
4
3
 
5
4
  export interface IBoardCardDocument {
6
5
  id: string;
7
6
  boardCardId: string;
8
7
  boardId: string;
9
8
  name: string;
10
- // AV v3 P2 async-enforce — WIRE CAVEAT: these 4 fields type as always-present
11
- // here (the true, always-populated stored/model shape), but the HTTP JSON
12
- // response actually redacts all four to `null` while scanStatus is
13
- // 'pending_scan' (see the BoardCardDocument model's toJSON() override) —
14
- // pending_scan grants no servable identifier to any caller, owner included.
15
- // A future front consumer of this DTO must treat them as possibly-null at
16
- // runtime whenever scanStatus === 'pending_scan', despite the `string` type.
17
9
  externalId: string;
18
10
  publicAccessId: string;
19
11
  thumbnailId: string | null;
@@ -21,16 +13,6 @@ export interface IBoardCardDocument {
21
13
  checksum: string;
22
14
  mimeType: string;
23
15
  sizeOctet: number;
24
- // AV v3 P2 async-enforce: antivirus verdict mirrored from AbyssStorage,
25
- // seeded pending_scan at the UPLOAD webhook, updated by applyScanResult /
26
- // purgeInfected on the SCAN_RESULT webhook. Null for rows created before
27
- // this column existed. See assertNotPendingScan for the 423 gate.
28
- scanStatus: FileScanStatus | null;
29
- // Id of the user who requested this upload (currentUser at presign time),
30
- // resolved server-side — never client-supplied. Null for an API-key/
31
- // anonymous upload. Used ONLY to notify the uploader if the file is later
32
- // found infected (purgeInfected) — not a permission/ownership field.
33
- uploadedByUserId: string | null;
34
16
  updatedAt?: Date;
35
17
  createdAt?: Date;
36
18
 
@@ -6,7 +6,6 @@
6
6
  import { ExtractionWarningCode } from '../../../types/enum/extraction-warning.enum';
7
7
  import { ExtractionFeedbackIssueType } from '../../../types/enum/extraction-feedback-issue-type.enum';
8
8
  import { DocumentType } from '../../../types/enum/document-type.enum';
9
- import { FileScanStatus } from '../../enum/file-scan-status.enum';
10
9
  import type { IFieldValue, IExecutionManifest, IGlobalConfidence } from './extraction-plan.dto';
11
10
 
12
11
  // Re-export so consumers can import ExtractionFeedbackIssueType from the DTO barrel.
@@ -67,13 +66,6 @@ export interface IExtractionFile {
67
66
  pdfMimeType: string;
68
67
  pdfPageCount: number | null;
69
68
  pdfFilename: string | null;
70
- // AV v3 P3 async-enforce — WIRE CAVEAT: typed always-present here (the
71
- // stored/model shape), but the HTTP JSON response redacts this to `null`
72
- // while scanStatus is 'pending_scan' (see the ExtractionFile model's
73
- // get() override) — pending_scan grants no servable identifier to any
74
- // caller, owner included. Never gated for a by-reference (caller-owned)
75
- // file: AbyssExtract never mirrors a scan verdict locally for those (see
76
- // scanStatus below), gating on the caller's live verdict instead.
77
69
  applicationFileId: string | null;
78
70
  userExternalId: string | null;
79
71
  userMetadata: Record<string, unknown> | null;
@@ -82,15 +74,6 @@ export interface IExtractionFile {
82
74
  detectedIban: string | null;
83
75
  detectedBic: string | null;
84
76
  detectedCurrency: string | null;
85
- // AV v3 P3 async-enforce: antivirus verdict mirrored from AbyssStorage for
86
- // an ARCHIVE-OWNED file only (seeded at extractionFileService.upsert from
87
- // the archive-upload response — see extraction-extract.service.ts#archivePdf).
88
- // Null for by-reference files (gated live on the caller's own verdict
89
- // instead — no local mirror, since AbyssExtract never receives a
90
- // SCAN_RESULT webhook for a file it did not request the scan for) and for
91
- // rows created before this column existed. See assertNotPendingScan for
92
- // the 423 gate this enables on derived-output endpoints.
93
- scanStatus: FileScanStatus | null;
94
77
  createdAt: string;
95
78
  updatedAt: string;
96
79
  }
@@ -32,3 +32,6 @@ export * from './content-share.dto';
32
32
  export * from './extraction.dto';
33
33
  export * from './extraction-plan.dto';
34
34
  export * from './extraction-spatial-template.dto';
35
+ export * from './probe-scan.dto';
36
+ export * from './probe-webhook.dto';
37
+ export * from './probe-webhook-delivery.dto';
@@ -0,0 +1,48 @@
1
+ import { ProbeScanMode, ProbeScanStatus, ProbeScanVerdict } from '../../enum';
2
+
3
+ // Mirrors apps/api/src/api/controllers/probe-scan.controller.ts's local
4
+ // response interfaces. AbyssProbe deliberately returns TWO different scan
5
+ // shapes depending on the endpoint — never the raw `probe_scans` row, and
6
+ // never a single one-size-fits-all model — so this file mirrors that with
7
+ // two distinct interfaces rather than forcing one canonical "IProbeScan".
8
+
9
+ /**
10
+ * `GET /scan/:scanId` shape (poll the queued -> scanning -> done/error
11
+ * progression). Deliberately minimal: no fileName/fileSize/mimeType/mode/
12
+ * timestamps, no internal ownership columns (userId/organizationId/
13
+ * callbackUrl) — a caller polling by id already knows what it submitted.
14
+ */
15
+ export interface IProbeScanDetail {
16
+ scanId: string;
17
+ status: ProbeScanStatus;
18
+ /** null until `status` is DONE. */
19
+ verdict: ProbeScanVerdict | null;
20
+ /** null until `status` is DONE; [] when DONE and clean. */
21
+ viruses: string[] | null;
22
+ /** Free-form caller reference echoed back verbatim (see IProbeScanHistoryItem#context). */
23
+ context: Record<string, unknown> | null;
24
+ }
25
+
26
+ /**
27
+ * One row of `GET /scan`'s paginated history/search list. Richer than
28
+ * {@link IProbeScanDetail} (adds fileName/fileSize/mimeType/mode/timestamps)
29
+ * but still never echoes internal ownership columns (userId, organizationId,
30
+ * callbackUrl) — a caller already knows their own scope from the request
31
+ * they made.
32
+ */
33
+ export interface IProbeScanHistoryItem {
34
+ scanId: string;
35
+ fileName: string;
36
+ fileSize: number;
37
+ mimeType: string;
38
+ verdict: ProbeScanVerdict | null;
39
+ viruses: string[] | null;
40
+ mode: ProbeScanMode;
41
+ status: ProbeScanStatus;
42
+ context: Record<string, unknown> | null;
43
+ /** Set the moment the engine call starts (SYNC: row-creation time; ASYNC: when a worker picks the job off the queue). */
44
+ startedAt: Date;
45
+ /** Set once the engine call returns. null while status is not DONE. */
46
+ finishedAt: Date | null;
47
+ createdAt: Date;
48
+ }
@@ -0,0 +1,26 @@
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
+ }
@@ -0,0 +1,25 @@
1
+ // Mirrors apps/api/src/api/controllers/probe-webhook.controller.ts's local
2
+ // WebhookResponseData / CreateWebhookResponseData. Public shape of a
3
+ // registered `probe_webhooks` row — never carries `secret` except right
4
+ // after creation (see IProbeWebhookCreated below); never echoes the
5
+ // internal ownership columns (userId/organizationId/applicationId) either,
6
+ // same discipline as the scan models.
7
+
8
+ export interface IProbeWebhook {
9
+ id: string;
10
+ /** HTTPS endpoint the verdict is POSTed to. */
11
+ callbackUrl: string;
12
+ /** Disabled webhooks are skipped by dispatch (soft-off, not deleted). */
13
+ active: boolean;
14
+ createdAt: Date;
15
+ }
16
+
17
+ /**
18
+ * Create-only response shape: the ONE time `secret` is ever returned by the
19
+ * API ("Secret generated server-side, returned once on create"). Store it
20
+ * immediately — there is no reset-secret / re-reveal endpoint (see this
21
+ * package's header note on the deliberately small CRUD surface).
22
+ */
23
+ export interface IProbeWebhookCreated extends IProbeWebhook {
24
+ secret: string;
25
+ }
@@ -46,8 +46,6 @@ describe('beam DTOs', () => {
46
46
  height: 600,
47
47
  downloadCount: 0,
48
48
  position: 0,
49
- scanStatus: null,
50
- uploadedByUserId: null,
51
49
  };
52
50
  const recipient: IBeamRecipient = {
53
51
  id: 'r1',