@arkyc/types 1.2.11 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/errors.d.mts CHANGED
@@ -10,7 +10,7 @@
10
10
  * The typed clients surface this as `ArkycApiError.error` (`@arkyc/sdk`) and
11
11
  * `WidgetApiError.error` (`@arkyc/widget`).
12
12
  */
13
- type ApiErrorKey = 'missing_client_token' | 'invalid_client_token' | 'session_expired' | 'missing_api_key' | 'invalid_api_key' | 'invalid_workflow' | 'invalid_webhook';
13
+ type ApiErrorKey = 'missing_client_token' | 'invalid_client_token' | 'session_expired' | 'origin_not_allowed' | 'client_token_used' | 'handoff_disabled' | 'missing_api_key' | 'invalid_api_key' | 'invalid_workflow' | 'invalid_webhook';
14
14
  //#endregion
15
15
  export { ApiErrorKey };
16
16
  //# sourceMappingURL=errors.d.mts.map
package/dist/index.d.mts CHANGED
@@ -1,12 +1,14 @@
1
1
  import { Entity, Id, IsoDate, IsoDateTime, Metadata, OrganizationScoped, ProjectScoped, Timestamps } from "./common.mjs";
2
2
  import { PublicUser, User } from "./user.mjs";
3
+ import { DecisionReason, LivenessChallenge, LivenessMode, VerificationDecision, VerificationSession, VerificationStatus } from "./verification.mjs";
4
+ import { DEFAULT_FACE_EMBEDDING_SETTINGS, DEFAULT_RISK_SIGNAL_POLICY, DEFAULT_SCREENING_CONFIG, DEFAULT_VELOCITY_SETTINGS, FaceEmbeddingSettings, REVIEW_ONLY_RISK_SIGNALS, RISK_SIGNAL_KEYS, RISK_SIGNAL_REASONS, RiskPolicyConfig, RiskSeverity, RiskSignal, RiskSignalKey, RiskSignalPolicy, ScreeningHit, ScreeningHitCategory, ScreeningOnHit, ScreeningStepConfig, SessionRiskSignal, VelocitySettings, WebhookRiskCheck } from "./risk.mjs";
3
5
  import { InvitationStatus, MembershipStatus, Organization, OrganizationInvitation, OrganizationMember, OrganizationSettings } from "./organization.mjs";
4
6
  import { AdminPermission, AdminPermissionGroup, AdminPermissionKey, AdminRoleSlug, AnyPermissionGroup, AnyPermissionKey, Permission, PermissionGroup, PermissionKey, Role, RolePermission, SystemRoleSlug, UserPermission } from "./rbac.mjs";
5
- import { CaptureModel, DEFAULT_GLOBAL_SETTINGS, GlobalSetting, GlobalSettings, RealtimeTransport } from "./settings.mjs";
6
- import { DecisionReason, LivenessChallenge, LivenessMode, VerificationDecision, VerificationSession, VerificationStatus } from "./verification.mjs";
7
- import { REALTIME_EVENT, RealtimeEventName, ReviewActionEvent, SessionTransitionEvent, parseRealtimeChannel, realtimeChannels } from "./realtime.mjs";
8
- import { ApiKey, ApiKeyWithSecret, Project, ProjectBranding, ProjectContext, ProjectEnvironment, ProjectHandoffSettings, ProjectMember, ProjectSettings, ProjectStatus, VerificationThresholds } from "./project.mjs";
9
- import { ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, AddressMethod, AddressOnFail, AddressStepConfig, DEFAULT_ADDRESS_CONFIG, DEFAULT_WORKFLOW_CONFIG, WORKFLOW_STEP_KEYS, Workflow, WorkflowConfig, WorkflowOptions, WorkflowStep, WorkflowStepKey, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr } from "./workflow.mjs";
7
+ import { CaptureModel, DEFAULT_GLOBAL_SETTINGS, GlobalSetting, GlobalSettings } from "./settings.mjs";
8
+ import { REALTIME_EVENT, RealtimeEventName, ReviewActionEvent, SessionTransitionEvent, realtimeChannels } from "./realtime.mjs";
9
+ import { DEFAULT_NOTIFICATION_PREFERENCES, NOTIFICATION_TYPE, NotificationPreferences, NotificationType, PushPlatform, UserNotification } from "./notifications.mjs";
10
+ import { ApiKey, ApiKeyWithSecret, DEFAULT_VERIFICATION_THRESHOLDS, Project, ProjectBranding, ProjectContext, ProjectEnvironment, ProjectHandoffSettings, ProjectMember, ProjectSettings, ProjectStatus, VerificationThresholds } from "./project.mjs";
11
+ import { ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, AddressMethod, AddressOnFail, AddressStepConfig, DEFAULT_ADDRESS_CONFIG, DEFAULT_WORKFLOW_CONFIG, WORKFLOW_STEP_KEYS, Workflow, WorkflowConfig, WorkflowOptions, WorkflowStep, WorkflowStepKey, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr, workflowScreeningConfig } from "./workflow.mjs";
10
12
  import { AddressMethodResult, AddressResultData, AddressVerification, DocumentCapture, DocumentPortrait, DocumentType, FaceMatchCheck, FaceMatchResultData, LivenessCheck, LivenessResultData, OcrAuthenticity, OcrFields, OcrResult, OcrResultData, PostalAddress, SpoofSignals } from "./providers.mjs";
11
13
  import { Review, ReviewAction, ReviewNote } from "./review.mjs";
12
14
  import { WebhookChecks, WebhookDelivery, WebhookDeliveryStatus, WebhookEndpoint, WebhookEndpointStatus, WebhookEvent, WebhookEventName } from "./webhook.mjs";
@@ -15,4 +17,4 @@ import { ACCESS_CAPABILITIES, ACCESS_CAPABILITY_KEYS, AccessCapability, AccessCa
15
17
  import { CreateSessionParams, SdkOptions, SessionResource } from "./sdk.mjs";
16
18
  import { WidgetMode, WidgetOptions, WidgetResult, WidgetStep } from "./widget.mjs";
17
19
  import { ApiErrorKey } from "./errors.mjs";
18
- export { ACCESS_CAPABILITIES, ACCESS_CAPABILITY_KEYS, ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, AccessCapability, AccessCapabilityMeta, AccessGrant, AccessGrantDetails, AccessGrantStatus, ActorType, AddressMethod, AddressMethodResult, AddressOnFail, AddressResultData, AddressStepConfig, AddressVerification, AdminPermission, AdminPermissionGroup, AdminPermissionKey, AdminRoleSlug, AnyPermissionGroup, AnyPermissionKey, ApiErrorKey, ApiKey, ApiKeyWithSecret, AuditLog, CaptureModel, CreateSessionParams, DEFAULT_ADDRESS_CONFIG, DEFAULT_GLOBAL_SETTINGS, DEFAULT_WORKFLOW_CONFIG, DecisionReason, DocumentCapture, DocumentPortrait, DocumentType, Entity, ExtractedAddress, ExtractedData, ExtractedIdentity, FaceMatchCheck, FaceMatchResultData, GlobalSetting, GlobalSettings, Id, InvitationStatus, IsoDate, IsoDateTime, LivenessChallenge, LivenessCheck, LivenessMode, LivenessResultData, MembershipStatus, Metadata, OcrAuthenticity, OcrFields, OcrResult, OcrResultData, Organization, OrganizationInvitation, OrganizationMember, OrganizationScoped, OrganizationSettings, Permission, PermissionGroup, PermissionKey, PiiCategory, PiiTiming, PostalAddress, Project, ProjectBranding, ProjectContext, ProjectEnvironment, ProjectHandoffSettings, ProjectMember, ProjectScoped, ProjectSettings, ProjectStatus, PublicUser, REALTIME_EVENT, RealtimeEventName, RealtimeTransport, Review, ReviewAction, ReviewActionEvent, ReviewNote, Role, RolePermission, SdkOptions, SessionResource, SessionTransitionEvent, SpoofSignals, SystemRoleSlug, Timestamps, User, UserPermission, VerificationDecision, VerificationSession, VerificationStatus, VerificationThresholds, WORKFLOW_STEP_KEYS, WebhookChecks, WebhookDelivery, WebhookDeliveryStatus, WebhookEndpoint, WebhookEndpointStatus, WebhookEvent, WebhookEventName, WidgetMode, WidgetOptions, WidgetResult, WidgetStep, Workflow, WorkflowConfig, WorkflowOptions, WorkflowStep, WorkflowStepKey, parseRealtimeChannel, realtimeChannels, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr };
20
+ export { ACCESS_CAPABILITIES, ACCESS_CAPABILITY_KEYS, ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, AccessCapability, AccessCapabilityMeta, AccessGrant, AccessGrantDetails, AccessGrantStatus, ActorType, AddressMethod, AddressMethodResult, AddressOnFail, AddressResultData, AddressStepConfig, AddressVerification, AdminPermission, AdminPermissionGroup, AdminPermissionKey, AdminRoleSlug, AnyPermissionGroup, AnyPermissionKey, ApiErrorKey, ApiKey, ApiKeyWithSecret, AuditLog, CaptureModel, CreateSessionParams, DEFAULT_ADDRESS_CONFIG, DEFAULT_FACE_EMBEDDING_SETTINGS, DEFAULT_GLOBAL_SETTINGS, DEFAULT_NOTIFICATION_PREFERENCES, DEFAULT_RISK_SIGNAL_POLICY, DEFAULT_SCREENING_CONFIG, DEFAULT_VELOCITY_SETTINGS, DEFAULT_VERIFICATION_THRESHOLDS, DEFAULT_WORKFLOW_CONFIG, DecisionReason, DocumentCapture, DocumentPortrait, DocumentType, Entity, ExtractedAddress, ExtractedData, ExtractedIdentity, FaceEmbeddingSettings, FaceMatchCheck, FaceMatchResultData, GlobalSetting, GlobalSettings, Id, InvitationStatus, IsoDate, IsoDateTime, LivenessChallenge, LivenessCheck, LivenessMode, LivenessResultData, MembershipStatus, Metadata, NOTIFICATION_TYPE, NotificationPreferences, NotificationType, OcrAuthenticity, OcrFields, OcrResult, OcrResultData, Organization, OrganizationInvitation, OrganizationMember, OrganizationScoped, OrganizationSettings, Permission, PermissionGroup, PermissionKey, PiiCategory, PiiTiming, PostalAddress, Project, ProjectBranding, ProjectContext, ProjectEnvironment, ProjectHandoffSettings, ProjectMember, ProjectScoped, ProjectSettings, ProjectStatus, PublicUser, PushPlatform, REALTIME_EVENT, REVIEW_ONLY_RISK_SIGNALS, RISK_SIGNAL_KEYS, RISK_SIGNAL_REASONS, RealtimeEventName, Review, ReviewAction, ReviewActionEvent, ReviewNote, RiskPolicyConfig, RiskSeverity, RiskSignal, RiskSignalKey, RiskSignalPolicy, Role, RolePermission, ScreeningHit, ScreeningHitCategory, ScreeningOnHit, ScreeningStepConfig, SdkOptions, SessionResource, SessionRiskSignal, SessionTransitionEvent, SpoofSignals, SystemRoleSlug, Timestamps, User, UserNotification, UserPermission, VelocitySettings, VerificationDecision, VerificationSession, VerificationStatus, VerificationThresholds, WORKFLOW_STEP_KEYS, WebhookChecks, WebhookDelivery, WebhookDeliveryStatus, WebhookEndpoint, WebhookEndpointStatus, WebhookEvent, WebhookEventName, WebhookRiskCheck, WidgetMode, WidgetOptions, WidgetResult, WidgetStep, Workflow, WorkflowConfig, WorkflowOptions, WorkflowStep, WorkflowStepKey, realtimeChannels, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr, workflowScreeningConfig };
package/dist/index.mjs CHANGED
@@ -1,5 +1,8 @@
1
1
  import { DEFAULT_GLOBAL_SETTINGS } from "./settings.mjs";
2
- import { REALTIME_EVENT, parseRealtimeChannel, realtimeChannels } from "./realtime.mjs";
3
- import { ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, DEFAULT_ADDRESS_CONFIG, DEFAULT_WORKFLOW_CONFIG, WORKFLOW_STEP_KEYS, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr } from "./workflow.mjs";
2
+ import { REALTIME_EVENT, realtimeChannels } from "./realtime.mjs";
3
+ import { DEFAULT_NOTIFICATION_PREFERENCES, NOTIFICATION_TYPE } from "./notifications.mjs";
4
+ import { DEFAULT_VERIFICATION_THRESHOLDS } from "./project.mjs";
5
+ import { DEFAULT_FACE_EMBEDDING_SETTINGS, DEFAULT_RISK_SIGNAL_POLICY, DEFAULT_SCREENING_CONFIG, DEFAULT_VELOCITY_SETTINGS, REVIEW_ONLY_RISK_SIGNALS, RISK_SIGNAL_KEYS, RISK_SIGNAL_REASONS } from "./risk.mjs";
6
+ import { ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, DEFAULT_ADDRESS_CONFIG, DEFAULT_WORKFLOW_CONFIG, WORKFLOW_STEP_KEYS, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr, workflowScreeningConfig } from "./workflow.mjs";
4
7
  import { ACCESS_CAPABILITIES, ACCESS_CAPABILITY_KEYS } from "./access.mjs";
5
- export { ACCESS_CAPABILITIES, ACCESS_CAPABILITY_KEYS, ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, DEFAULT_ADDRESS_CONFIG, DEFAULT_GLOBAL_SETTINGS, DEFAULT_WORKFLOW_CONFIG, REALTIME_EVENT, WORKFLOW_STEP_KEYS, parseRealtimeChannel, realtimeChannels, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr };
8
+ export { ACCESS_CAPABILITIES, ACCESS_CAPABILITY_KEYS, ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, DEFAULT_ADDRESS_CONFIG, DEFAULT_FACE_EMBEDDING_SETTINGS, DEFAULT_GLOBAL_SETTINGS, DEFAULT_NOTIFICATION_PREFERENCES, DEFAULT_RISK_SIGNAL_POLICY, DEFAULT_SCREENING_CONFIG, DEFAULT_VELOCITY_SETTINGS, DEFAULT_VERIFICATION_THRESHOLDS, DEFAULT_WORKFLOW_CONFIG, NOTIFICATION_TYPE, REALTIME_EVENT, REVIEW_ONLY_RISK_SIGNALS, RISK_SIGNAL_KEYS, RISK_SIGNAL_REASONS, WORKFLOW_STEP_KEYS, realtimeChannels, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr, workflowScreeningConfig };
@@ -0,0 +1,37 @@
1
+ import { Id } from "./common.mjs";
2
+
3
+ //#region src/notifications.d.ts
4
+ /** Kinds of in-app notification a user can receive. */
5
+ declare const NOTIFICATION_TYPE: {
6
+ /** A verification session was assigned to you for review. */readonly reviewAssigned: "review.assigned"; /** A verification session in a project you review needs a manual decision. */
7
+ readonly sessionNeedsReview: "session.requires_review"; /** Someone else approved or rejected a session assigned to you. */
8
+ readonly reviewDecided: "review.decided"; /** A webhook endpoint you maintain exhausted its delivery retries. */
9
+ readonly webhookFailing: "webhook.failing"; /** You were invited to join an organization. */
10
+ readonly invitationReceived: "invitation.received"; /** Watchlist screening matched a session in a project you review. */
11
+ readonly screeningHit: "screening.hit";
12
+ };
13
+ type NotificationType = (typeof NOTIFICATION_TYPE)[keyof typeof NOTIFICATION_TYPE];
14
+ /** A user's notification delivery preferences. */
15
+ interface NotificationPreferences {
16
+ /** Also push notifications to the user's registered devices. */
17
+ push: boolean;
18
+ }
19
+ declare const DEFAULT_NOTIFICATION_PREFERENCES: NotificationPreferences;
20
+ /** Platforms a device push token can be registered for. */
21
+ type PushPlatform = 'ios' | 'android' | 'web';
22
+ /** A stored in-app notification, as the API returns it. */
23
+ interface UserNotification {
24
+ id: Id;
25
+ type: NotificationType | string | null;
26
+ title: string;
27
+ description: string;
28
+ action_text: string | null;
29
+ /** A dashboard path, e.g. `/o/acme/sessions/<id>`. */
30
+ action_link: string | null;
31
+ meta: Record<string, unknown> | null;
32
+ read_at: string | null;
33
+ created_at: string;
34
+ }
35
+ //#endregion
36
+ export { DEFAULT_NOTIFICATION_PREFERENCES, NOTIFICATION_TYPE, NotificationPreferences, NotificationType, PushPlatform, UserNotification };
37
+ //# sourceMappingURL=notifications.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.d.mts","names":[],"sources":["../src/notifications.ts"],"mappings":";;;;cAGa,iBAAA;EAAA;;;;;;;KAeD,gBAAA,WAA2B,iBAAA,eAAgC,iBAAiB;;UAGvE,uBAAA;EAHuE;EAKtF,IAAI;AAAA;AAAA,cAGO,gCAAA,EAAkC,uBAE9C;;KAGW,YAAA;AALZ;AAAA,UAQiB,gBAAA;EACf,EAAA,EAAI,EAAA;EACJ,IAAA,EAAM,gBAAA;EACN,KAAA;EACA,WAAA;EACA,WAAA;;EAEA,WAAA;EACA,IAAA,EAAM,MAAA;EACN,OAAA;EACA,UAAA;AAAA"}
@@ -0,0 +1,21 @@
1
+ //#region src/notifications.ts
2
+ /** Kinds of in-app notification a user can receive. */
3
+ const NOTIFICATION_TYPE = {
4
+ /** A verification session was assigned to you for review. */
5
+ reviewAssigned: "review.assigned",
6
+ /** A verification session in a project you review needs a manual decision. */
7
+ sessionNeedsReview: "session.requires_review",
8
+ /** Someone else approved or rejected a session assigned to you. */
9
+ reviewDecided: "review.decided",
10
+ /** A webhook endpoint you maintain exhausted its delivery retries. */
11
+ webhookFailing: "webhook.failing",
12
+ /** You were invited to join an organization. */
13
+ invitationReceived: "invitation.received",
14
+ /** Watchlist screening matched a session in a project you review. */
15
+ screeningHit: "screening.hit"
16
+ };
17
+ const DEFAULT_NOTIFICATION_PREFERENCES = { push: true };
18
+ //#endregion
19
+ export { DEFAULT_NOTIFICATION_PREFERENCES, NOTIFICATION_TYPE };
20
+
21
+ //# sourceMappingURL=notifications.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.mjs","names":[],"sources":["../src/notifications.ts"],"sourcesContent":["import type { Id } from './common'\n\n/** Kinds of in-app notification a user can receive. */\nexport const NOTIFICATION_TYPE = {\n /** A verification session was assigned to you for review. */\n reviewAssigned: 'review.assigned',\n /** A verification session in a project you review needs a manual decision. */\n sessionNeedsReview: 'session.requires_review',\n /** Someone else approved or rejected a session assigned to you. */\n reviewDecided: 'review.decided',\n /** A webhook endpoint you maintain exhausted its delivery retries. */\n webhookFailing: 'webhook.failing',\n /** You were invited to join an organization. */\n invitationReceived: 'invitation.received',\n /** Watchlist screening matched a session in a project you review. */\n screeningHit: 'screening.hit',\n} as const\n\nexport type NotificationType = (typeof NOTIFICATION_TYPE)[keyof typeof NOTIFICATION_TYPE]\n\n/** A user's notification delivery preferences. */\nexport interface NotificationPreferences {\n /** Also push notifications to the user's registered devices. */\n push: boolean\n}\n\nexport const DEFAULT_NOTIFICATION_PREFERENCES: NotificationPreferences = {\n push: true,\n}\n\n/** Platforms a device push token can be registered for. */\nexport type PushPlatform = 'ios' | 'android' | 'web'\n\n/** A stored in-app notification, as the API returns it. */\nexport interface UserNotification {\n id: Id\n type: NotificationType | string | null\n title: string\n description: string\n action_text: string | null\n /** A dashboard path, e.g. `/o/acme/sessions/<id>`. */\n action_link: string | null\n meta: Record<string, unknown> | null\n read_at: string | null\n created_at: string\n}\n"],"mappings":";;AAGA,MAAa,oBAAoB;;CAE/B,gBAAgB;;CAEhB,oBAAoB;;CAEpB,eAAe;;CAEf,gBAAgB;;CAEhB,oBAAoB;;CAEpB,cAAc;AAChB;AAUA,MAAa,mCAA4D,EACvE,MAAM,KACR"}
@@ -1,4 +1,5 @@
1
1
  import { Entity, Id, IsoDateTime, Metadata, OrganizationScoped } from "./common.mjs";
2
+ import { FaceEmbeddingSettings } from "./risk.mjs";
2
3
 
3
4
  //#region src/organization.d.ts
4
5
  /** Membership lifecycle states for organization/project members. */
@@ -19,6 +20,8 @@ interface Organization extends Entity {
19
20
  interface OrganizationSettings extends Metadata {
20
21
  /** Days to retain verification media before cleanup (Phase 15). */
21
22
  retention_days?: number;
23
+ /** Store face embeddings to catch one face behind several identities. Off by default. */
24
+ face_embeddings?: Partial<FaceEmbeddingSettings>;
22
25
  }
23
26
  /** Links a {@link User} to a {@link Organization} with a role. */
24
27
  interface OrganizationMember extends Entity, OrganizationScoped {
@@ -1 +1 @@
1
- {"version":3,"file":"organization.d.mts","names":[],"sources":["../src/organization.ts"],"mappings":";;;;KAGY,gBAAA;AAAZ;AAAA,KAGY,gBAAA;;;AAHgB;AAG5B;UAMiB,YAAA,SAAqB,MAAM;EAC1C,IAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA,EAAU,oBAAA;AAAA;;UAIK,oBAAA,SAA6B,QAAQ;EARhB;EAUpC,cAAc;AAAA;;UAIC,kBAAA,SAA2B,MAAA,EAAQ,kBAAA;EAClD,OAAA,EAAS,EAAA;EACT,OAAA,EAAS,EAAA;EACT,MAAA,EAAQ,gBAAA;EACR,SAAA,EAAW,WAAA;AAAA;;UAII,sBAAA,SAA+B,MAAA,EAAQ,kBAAA;EACtD,KAAA;EACA,OAAA,EAAS,EAAA;EAVyB;EAYlC,UAAA;EACA,UAAA,EAAY,WAAA;EACZ,WAAA,EAAa,WAAA;AAAA"}
1
+ {"version":3,"file":"organization.d.mts","names":[],"sources":["../src/organization.ts"],"mappings":";;;;;KAIY,gBAAA;AAAZ;AAAA,KAGY,gBAAA;;;AAHgB;AAG5B;UAMiB,YAAA,SAAqB,MAAM;EAC1C,IAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA,EAAU,oBAAA;AAAA;;UAIK,oBAAA,SAA6B,QAAA;EARR;EAUpC,cAAA;EARA;EAUA,eAAA,GAAkB,OAAA,CAAQ,qBAAA;AAAA;;UAIX,kBAAA,SAA2B,MAAA,EAAQ,kBAAA;EAClD,OAAA,EAAS,EAAA;EACT,OAAA,EAAS,EAAA;EACT,MAAA,EAAQ,gBAAA;EACR,SAAA,EAAW,WAAA;AAAA;;UAII,sBAAA,SAA+B,MAAA,EAAQ,kBAAA;EACtD,KAAA;EACA,OAAA,EAAS,EAAA;EAlBmC;EAoB5C,UAAA;EACA,UAAA,EAAY,WAAA;EACZ,WAAA,EAAa,WAAA;AAAA"}
@@ -1,4 +1,5 @@
1
1
  import { Entity, Id, IsoDateTime, Metadata, OrganizationScoped, ProjectScoped } from "./common.mjs";
2
+ import { VelocitySettings } from "./risk.mjs";
2
3
  import { MembershipStatus } from "./organization.mjs";
3
4
  import { CaptureModel } from "./settings.mjs";
4
5
 
@@ -9,7 +10,7 @@ type ProjectEnvironment = 'production' | 'staging' | 'development';
9
10
  type ProjectStatus = 'active' | 'paused' | 'archived';
10
11
  /**
11
12
  * Per-project, configurable thresholds the decision engine compares scores
12
- * against. Defaults live in `@arkyc/core`; projects may override any subset.
13
+ * against. Projects may override any subset of {@link DEFAULT_VERIFICATION_THRESHOLDS}.
13
14
  */
14
15
  interface VerificationThresholds {
15
16
  documentQualityThreshold: number;
@@ -19,9 +20,16 @@ interface VerificationThresholds {
19
20
  /** Minimum address-verification confidence before flagging for review. */
20
21
  addressThreshold: number;
21
22
  }
23
+ /** Platform default verification thresholds. */
24
+ declare const DEFAULT_VERIFICATION_THRESHOLDS: VerificationThresholds;
22
25
  /** Visual branding applied to the widget for a project. */
23
26
  interface ProjectBranding {
24
27
  logo_url?: string | null;
28
+ /**
29
+ * Storage object key of an uploaded logo. Server-side only: the API resolves
30
+ * it to a (signed, when the disk is private) `logo_url` in every response.
31
+ */
32
+ logo_key?: string | null;
25
33
  primary_color?: string;
26
34
  border_radius?: number;
27
35
  theme?: 'light' | 'dark';
@@ -57,6 +65,8 @@ interface ProjectSettings extends Metadata {
57
65
  capture_model?: CaptureModel;
58
66
  /** Cross-device session handoff (QR). Off unless the project opts in. */
59
67
  handoff?: ProjectHandoffSettings;
68
+ /** Repeat-session limits per network address (`VELOCITY_EXCEEDED`). */
69
+ velocity?: Partial<VelocitySettings>;
60
70
  }
61
71
  /**
62
72
  * A specific application, environment, or product integration owned by a
@@ -102,5 +112,5 @@ interface ProjectContext {
102
112
  api_key_id?: Id;
103
113
  }
104
114
  //#endregion
105
- export { ApiKey, ApiKeyWithSecret, Project, ProjectBranding, ProjectContext, ProjectEnvironment, ProjectHandoffSettings, ProjectMember, ProjectSettings, ProjectStatus, VerificationThresholds };
115
+ export { ApiKey, ApiKeyWithSecret, DEFAULT_VERIFICATION_THRESHOLDS, Project, ProjectBranding, ProjectContext, ProjectEnvironment, ProjectHandoffSettings, ProjectMember, ProjectSettings, ProjectStatus, VerificationThresholds };
106
116
  //# sourceMappingURL=project.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project.d.mts","names":[],"sources":["../src/project.ts"],"mappings":";;;;;;KAMY,kBAAA;AAAZ;AAAA,KAGY,aAAA;;;AAHkB;AAG9B;UAMiB,sBAAA;EACf,wBAAA;EACA,sBAAA;EACA,iBAAA;EACA,kBAAA;EAJqC;EAMrC,gBAAA;AAAA;;UAIe,eAAA;EACf,QAAA;EACA,aAAA;EACA,aAAA;EACA,KAAA;EARgB;EAUhB,IAAA;EAN8B;;;;EAW9B,aAAA;AAAA;;;;;AAAa;UAQE,sBAAA;EAAsB;EAErC,OAAA;EAAA;AAKa;AAIf;;EAJE,aAAa;AAAA;;UAIE,eAAA,SAAwB,QAAA;EACvC,UAAA,GAAa,OAAA,CAAQ,sBAAA;EACrB,eAAA;EAF+C;EAI/C,WAAA;EAJuC;EAMvC,aAAA,GAAgB,YAAA;EALH;EAOb,OAAA,GAAU,sBAAA;AAAA;;;;;UAOK,OAAA,SAAgB,MAAA,EAAQ,kBAAA;EACvC,IAAA;EACA,IAAA;EACA,WAAA,EAAa,kBAAA;EACb,QAAA,EAAU,eAAA;EACV,QAAA,EAAU,eAAA;EACV,MAAA,EAAQ,aAAA;EACR,YAAA;AAAA;;UAIe,aAAA,SAAsB,MAAA,EAAQ,aAAA;EAC7C,OAAA,EAAS,EAAA;EACT,OAAA,EAAS,EAAA;EACT,MAAA,EAAQ,gBAAA;AAAA;;;;;UAOO,MAAA,SAAe,MAAA,EAAQ,aAAA;EACtC,IAAA;EACA,UAAA;EACA,QAAA;EACA,YAAA,EAAc,WAAA;EACd,UAAA,EAAY,WAAA;EACZ,UAAA,EAAY,WAAA;AAAA;;UAIG,gBAAA;EACf,OAAA,EAAS,MAAM;EArBc;EAuB7B,MAAA;AAAA;;UAIe,cAAA;EACf,eAAA,EAAiB,EAAA;EACjB,UAAA,EAAY,EAAA;EACZ,UAAA,GAAa,EAAA;AAAA"}
1
+ {"version":3,"file":"project.d.mts","names":[],"sources":["../src/project.ts"],"mappings":";;;;;;;KAOY,kBAAA;AAAZ;AAAA,KAGY,aAAA;;;AAHkB;AAG9B;UAMiB,sBAAA;EACf,wBAAA;EACA,sBAAA;EACA,iBAAA;EACA,kBAAA;EAJqC;EAMrC,gBAAA;AAAA;;cAIW,+BAAA,EAAiC,sBAM7C;;UAGgB,eAAA;EACf,QAAA;EAdgB;AAAA;AAIlB;;EAeE,QAAA;EACA,aAAA;EACA,aAAA;EACA,KAAA;EAT8B;EAW9B,IAAA;EAX8B;;;;EAgB9B,aAAA;AAAA;;;;AAAa;AAQf;UAAiB,sBAAA;;EAEf,OAAA;EAKa;AAIf;;;EAJE,aAAa;AAAA;;UAIE,eAAA,SAAwB,QAAA;EACvC,UAAA,GAAa,OAAA,CAAQ,sBAAA;EACrB,eAAA;EAFuC;EAIvC,WAAA;EAJ+C;EAM/C,aAAA,GAAgB,YAAA;EALhB;EAOA,OAAA,GAAU,sBAAA;EAPW;EASrB,QAAA,GAAW,OAAA,CAAQ,gBAAA;AAAA;;;;;UAOJ,OAAA,SAAgB,MAAA,EAAQ,kBAAA;EACvC,IAAA;EACA,IAAA;EACA,WAAA,EAAa,kBAAA;EACb,QAAA,EAAU,eAAA;EACV,QAAA,EAAU,eAAA;EACV,MAAA,EAAQ,aAAA;EACR,YAAA;AAAA;;UAIe,aAAA,SAAsB,MAAA,EAAQ,aAAA;EAC7C,OAAA,EAAS,EAAA;EACT,OAAA,EAAS,EAAA;EACT,MAAA,EAAQ,gBAAA;AAAA;;;;;UAOO,MAAA,SAAe,MAAA,EAAQ,aAAA;EACtC,IAAA;EACA,UAAA;EACA,QAAA;EACA,YAAA,EAAc,WAAA;EACd,UAAA,EAAY,WAAA;EACZ,UAAA,EAAY,WAAA;AAAA;;UAIG,gBAAA;EACf,OAAA,EAAS,MAAM;EAzBH;EA2BZ,MAAA;AAAA;;UAIe,cAAA;EACf,eAAA,EAAiB,EAAA;EACjB,UAAA,EAAY,EAAA;EACZ,UAAA,GAAa,EAAA;AAAA"}
@@ -0,0 +1,13 @@
1
+ //#region src/project.ts
2
+ /** Platform default verification thresholds. */
3
+ const DEFAULT_VERIFICATION_THRESHOLDS = {
4
+ documentQualityThreshold: .75,
5
+ ocrConfidenceThreshold: .8,
6
+ livenessThreshold: .85,
7
+ faceMatchThreshold: .75,
8
+ addressThreshold: .6
9
+ };
10
+ //#endregion
11
+ export { DEFAULT_VERIFICATION_THRESHOLDS };
12
+
13
+ //# sourceMappingURL=project.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.mjs","names":[],"sources":["../src/project.ts"],"sourcesContent":["import type { Entity, Id, IsoDateTime, Metadata, OrganizationScoped, ProjectScoped } from './common'\n\nimport type { VelocitySettings } from './risk'\nimport type { CaptureModel } from './settings'\nimport type { MembershipStatus } from './organization'\n\n/** Deployment environment for a project. */\nexport type ProjectEnvironment = 'production' | 'staging' | 'development'\n\n/** Project lifecycle status. */\nexport type ProjectStatus = 'active' | 'paused' | 'archived'\n\n/**\n * Per-project, configurable thresholds the decision engine compares scores\n * against. Projects may override any subset of {@link DEFAULT_VERIFICATION_THRESHOLDS}.\n */\nexport interface VerificationThresholds {\n documentQualityThreshold: number\n ocrConfidenceThreshold: number\n livenessThreshold: number\n faceMatchThreshold: number\n /** Minimum address-verification confidence before flagging for review. */\n addressThreshold: number\n}\n\n/** Platform default verification thresholds. */\nexport const DEFAULT_VERIFICATION_THRESHOLDS: VerificationThresholds = {\n documentQualityThreshold: 0.75,\n ocrConfidenceThreshold: 0.8,\n livenessThreshold: 0.85,\n faceMatchThreshold: 0.75,\n addressThreshold: 0.6,\n}\n\n/** Visual branding applied to the widget for a project. */\nexport interface ProjectBranding {\n logo_url?: string | null\n /**\n * Storage object key of an uploaded logo. Server-side only: the API resolves\n * it to a (signed, when the disk is private) `logo_url` in every response.\n */\n logo_key?: string | null\n primary_color?: string\n border_radius?: number\n theme?: 'light' | 'dark'\n /** Display name (company/product) shown in the widget header. */\n name?: string | null\n /**\n * Whether to show the project's name/logo in the widget header. Defaults to\n * shown; set `false` for an unbranded (white-label) header.\n */\n show_branding?: boolean\n}\n\n/**\n * Cross-device handoff: a desktop user continues an in-progress verification on\n * their phone by scanning a QR code.\n * The QR is shown first on desktop.\n */\nexport interface ProjectHandoffSettings {\n /** Whether desktop users are offered the QR handoff to their phone. */\n enabled?: boolean\n /**\n * Whether a desktop user may instead continue on the desktop device. When\n * `false`, a desktop user must scan to a phone (no \"continue here\"). Defaults true.\n */\n allow_desktop?: boolean\n}\n\n/** Project-level configuration. */\nexport interface ProjectSettings extends Metadata {\n thresholds?: Partial<VerificationThresholds>\n allowed_origins?: string[]\n /** Maximum verification attempts before a session is hard-failed. */\n max_retries?: number\n /** Overrides the global capture model for this project (Phase 17). */\n capture_model?: CaptureModel\n /** Cross-device session handoff (QR). Off unless the project opts in. */\n handoff?: ProjectHandoffSettings\n /** Repeat-session limits per network address (`VELOCITY_EXCEEDED`). */\n velocity?: Partial<VelocitySettings>\n}\n\n/**\n * A specific application, environment, or product integration owned by a\n * organization. Sessions, API keys, and webhooks are scoped to a project.\n */\nexport interface Project extends Entity, OrganizationScoped {\n name: string\n slug: string\n environment: ProjectEnvironment\n settings: ProjectSettings\n branding: ProjectBranding\n status: ProjectStatus\n has_ai_grant?: boolean\n}\n\n/** Links a user to a project with a role (narrower tha organization membership). */\nexport interface ProjectMember extends Entity, ProjectScoped {\n user_id: Id\n role_id: Id\n status: MembershipStatus\n}\n\n/**\n * A project API key. Only `key_prefix` is stored in clear; the secret is hashed\n * (`key_hash`) and shown to the integrator exactly once at creation.\n */\nexport interface ApiKey extends Entity, ProjectScoped {\n name: string\n key_prefix: string\n key_hash: string\n last_used_at: IsoDateTime | null\n expires_at: IsoDateTime | null\n revoked_at: IsoDateTime | null\n}\n\n/** An API key plus its one-time-visible secret, returned only at creation. */\nexport interface ApiKeyWithSecret {\n api_key: ApiKey\n /** The full secret key, e.g. `sk_live_…`. Never persisted in clear. */\n secret: string\n}\n\n/** Resolves the organization + project + (optionally) acting user for a request. */\nexport interface ProjectContext {\n organization_id: Id\n project_id: Id\n api_key_id?: Id\n}\n"],"mappings":";;AA0BA,MAAa,kCAA0D;CACrE,0BAA0B;CAC1B,wBAAwB;CACxB,mBAAmB;CACnB,oBAAoB;CACpB,kBAAkB;AACpB"}
@@ -12,6 +12,7 @@ interface OcrFields {
12
12
  dateOfBirth?: IsoDate;
13
13
  documentNumber?: string;
14
14
  expiryDate?: IsoDate;
15
+ issueDate?: IsoDate;
15
16
  nationality?: string;
16
17
  }
17
18
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.mts","names":[],"sources":["../src/providers.ts"],"mappings":";;;;;KAIY,YAAA;AAAZ;AAAA,UAGiB,SAAA;EACf,SAAA;EACA,QAAA;EACA,QAAA;EACA,WAAA,GAAc,OAAA;EACd,cAAA;EACA,UAAA,GAAa,OAAO;EACpB,WAAA;AAAA;;;;;;UAQe,eAAA;EATF;EAWb,OAAA;EAVW;EAYX,UAAA;EAJe;EAMf,YAAA;;EAEA,SAAA;EANA;EAQA,gBAAA;EAJA;EAMA,iBAAA;EAFA;EAIA,YAAA;AAAA;;UAIe,aAAA;EACf,MAAA,EAAQ,SAAA;EADoB;EAG5B,UAAA;EAE8B;EAA9B,YAAA,GAAe,eAAe;EAJtB;EAMR,GAAA;AAAA;;UAIe,YAAA;EACf,YAAA;EACA,YAAA;EACA,YAAA;EACA,aAAA;EACA,eAAA;EACA,YAAA;AAAA;;UAIe,kBAAA;EACf,MAAA;EANA;EAQA,KAAA;EACA,YAAA,EAAc,YAAY;EAC1B,GAAA;AAAA;;UAIe,mBAAA;EACf,MAAA;EATA;EAWA,eAAA;EARA;EAUA,UAAA;EACA,GAAA;AAAA;AAVG;AAAA,UAcY,aAAA;EACf,KAAA;EACA,KAAA;EACA,IAAA;EAZA;EAcA,MAAA;EACA,UAAA;EAVA;EAYA,OAAA;EAZG;EAcH,QAAA;EACA,SAAA;AAAA;;UAIe,mBAAA;EACf,MAAA,EAAQ,aAAA;EAbR;EAeA,MAAA;EAZA;EAcA,UAAA;EAVA;EAYA,QAAA,GAAW,aAAa;EAXf;AAAA;AAIX;;;EAaE,aAAA;EAZA;EAcA,IAAA;EACA,GAAA;AAAA;;UAIe,iBAAA;EACf,MAAA;EANA;EAQA,KAAA;EAPG;EASH,OAAA,EAAS,mBAAmB;EALb;EAOf,UAAA;EACA,GAAA;AAAA;;UAIe,eAAA,SAAwB,MAAA,EAAQ,aAAA;EAC/C,UAAA,EAAY,EAAA;EACZ,OAAA;EACA,aAAA,EAAe,YAAA;EACf,gBAAA;EACA,eAAA;EACA,aAAA;AAAA;;UAIe,SAAA,SAAkB,MAAA,EAAQ,aAAA;EACzC,UAAA,EAAY,EAAA;EACZ,mBAAA,EAAqB,EAAA;EACrB,MAAA,EAAQ,SAAA;EACR,UAAA;EACA,YAAA;AAAA;;UAIe,gBAAA,SAAyB,MAAA,EAAQ,aAAA;EAChD,UAAA,EAAY,EAAA;EACZ,mBAAA,EAAqB,EAAA;EACrB,mBAAA;EACA,oBAAA;AAAA;;UAIe,aAAA,SAAsB,MAAA,EAAQ,aAAA;EAC7C,UAAA,EAAY,EAAA;EACZ,iBAAA;EACA,UAAA;EACA,KAAA;EACA,MAAA;EACA,aAAA,EAAe,YAAA;EACf,QAAA;EACA,YAAA;AAAA;;UAIe,cAAA,SAAuB,MAAA,EAAQ,aAAA;EAC9C,UAAA,EAAY,EAAA;EACZ,sBAAA;EACA,iBAAA;EACA,gBAAA;EACA,UAAA;EACA,MAAA;EACA,QAAA;EACA,YAAA;AAAA;;UAIe,mBAAA,SAA4B,MAAA,EAAQ,aAAA;EACnD,UAAA,EAAY,EAAA;EArCA;EAuCZ,eAAA,EAAiB,aAAA;EAnCF;EAqCf,mBAAA;;EAEA,QAAA;EACA,SAAA;EACA,MAAA;EAzCgD;EA2ChD,KAAA;EA3C6D;EA6C7D,OAAA,EAAS,mBAAA;EACT,QAAA;EACA,YAAA;AAAA"}
1
+ {"version":3,"file":"providers.d.mts","names":[],"sources":["../src/providers.ts"],"mappings":";;;;;KAIY,YAAA;AAAZ;AAAA,UAGiB,SAAA;EACf,SAAA;EACA,QAAA;EACA,QAAA;EACA,WAAA,GAAc,OAAA;EACd,cAAA;EACA,UAAA,GAAa,OAAA;EACb,SAAA,GAAY,OAAA;EACZ,WAAA;AAAA;;;;;;UAQe,eAAA;EAZD;EAcd,OAAA;EAZA;EAcA,UAAA;EAbA;EAeA,YAAA;EAdA;EAgBA,SAAA;EAhBW;EAkBX,gBAAA;EAV8B;EAY9B,iBAAA;EAZ8B;EAc9B,YAAA;AAAA;;UAIe,aAAA;EACf,MAAA,EAAQ,SAAA;EAPR;EASA,UAAA;EAPY;EASZ,YAAA,GAAe,eAAe;EALf;EAOf,GAAA;AAAA;;UAIe,YAAA;EACf,YAAA;EACA,YAAA;EACA,YAAA;EACA,aAAA;EACA,eAAA;EACA,YAAA;AAAA;AANF;AAAA,UAUiB,kBAAA;EACf,MAAA;EAX2B;EAa3B,KAAA;EACA,YAAA,EAAc,YAAY;EAC1B,GAAA;AAAA;;UAIe,mBAAA;EACf,MAAA;EAdY;EAgBZ,eAAA;EAZiC;EAcjC,UAAA;EACA,GAAA;AAAA;;UAIe,aAAA;EACf,KAAA;EACA,KAAA;EACA,IAAA;EAjBG;EAmBH,MAAA;EACA,UAAA;;EAEA,OAAA;EAjBA;EAmBA,QAAA;EACA,SAAA;AAAA;;UAIe,mBAAA;EACf,MAAA,EAAQ,aAAA;EAhBoB;EAkB5B,MAAA;EAlB4B;EAoB5B,UAAA;EAlBA;EAoBA,QAAA,GAAW,aAAa;EAjBxB;;;;;EAuBA,aAAA;EAjBS;EAmBT,IAAA;EACA,GAAA;AAAA;;UAIe,iBAAA;EACf,MAAA;EAlBA;EAoBA,KAAA;EAhBA;EAkBA,OAAA,EAAS,mBAAmB;EAZ5B;EAcA,UAAA;EACA,GAAA;AAAA;AAZG;AAAA,UAgBY,eAAA,SAAwB,MAAA,EAAQ,aAAA;EAC/C,UAAA,EAAY,EAAA;EACZ,OAAA;EACA,aAAA,EAAe,YAAA;EACf,gBAAA;EACA,eAAA;EACA,aAAA;AAAA;;UAIe,SAAA,SAAkB,MAAA,EAAQ,aAAA;EACzC,UAAA,EAAY,EAAA;EACZ,mBAAA,EAAqB,EAAA;EACrB,MAAA,EAAQ,SAAA;EACR,UAAA;EACA,YAAA;AAAA;;UAIe,gBAAA,SAAyB,MAAA,EAAQ,aAAA;EAChD,UAAA,EAAY,EAAA;EACZ,mBAAA,EAAqB,EAAA;EACrB,mBAAA;EACA,oBAAA;AAAA;;UAIe,aAAA,SAAsB,MAAA,EAAQ,aAAA;EAC7C,UAAA,EAAY,EAAA;EACZ,iBAAA;EACA,UAAA;EACA,KAAA;EACA,MAAA;EACA,aAAA,EAAe,YAAA;EACf,QAAA;EACA,YAAA;AAAA;;UAIe,cAAA,SAAuB,MAAA,EAAQ,aAAA;EAC9C,UAAA,EAAY,EAAA;EACZ,sBAAA;EACA,iBAAA;EACA,gBAAA;EACA,UAAA;EACA,MAAA;EACA,QAAA;EACA,YAAA;AAAA;;UAIe,mBAAA,SAA4B,MAAA,EAAQ,aAAA;EACnD,UAAA,EAAY,EAAA;EAxCS;EA0CrB,eAAA,EAAiB,aAAA;EAzCT;EA2CR,mBAAA;EAzCA;EA2CA,QAAA;EACA,SAAA;EACA,MAAA;EAzCgC;EA2ChC,KAAA;EA1CY;EA4CZ,OAAA,EAAS,mBAAA;EACT,QAAA;EACA,YAAA;AAAA"}
@@ -3,9 +3,8 @@ import { VerificationStatus } from "./verification.mjs";
3
3
 
4
4
  //#region src/realtime.d.ts
5
5
  /**
6
- * Realtime transport contracts (Phase 16). Pure, dependency-free helpers shared
7
- * by the API (server publish) and the dashboard/widget (client subscribe), so
8
- * channel and event names never drift between them.
6
+ * Realtime contracts shared by the API (server publish) and the dashboard and
7
+ * widget (client subscribe), so channel and event names never drift between them.
9
8
  */
10
9
  /** Events the API broadcasts. Clients react by invalidating their caches. */
11
10
  declare const REALTIME_EVENT: {
@@ -14,26 +13,16 @@ declare const REALTIME_EVENT: {
14
13
  };
15
14
  type RealtimeEventName = (typeof REALTIME_EVENT)[keyof typeof REALTIME_EVENT];
16
15
  /**
17
- * Private channel name builders. All channels are `private-` (Pusher protocol),
18
- * so a subscription must be authorized server-side against the caller's scope.
16
+ * Private channel name builders. Every channel is `private-`, so a subscription
17
+ * must be authorized by the API. Segments are dot-separated so the API's channel
18
+ * rules can capture each id.
19
19
  */
20
20
  declare const realtimeChannels: {
21
- /** Everything in an organization. */organization: (organizationId: Id) => string; /** Everything in a project. */
21
+ /** A user's own notifications. */user: (userId: Id) => string; /** Everything in an organization. */
22
+ organization: (organizationId: Id) => string; /** Everything in a project. */
22
23
  project: (organizationId: Id, projectId: Id) => string; /** A single verification session (used by the widget via client token). */
23
24
  session: (sessionId: Id) => string;
24
25
  };
25
- /** Parse a private channel name back into its scope, or null if unrecognized. */
26
- declare function parseRealtimeChannel(channel: string): {
27
- kind: 'organization';
28
- organizationId: string;
29
- } | {
30
- kind: 'project';
31
- organizationId: string;
32
- projectId: string;
33
- } | {
34
- kind: 'session';
35
- sessionId: string;
36
- } | null;
37
26
  /** Payload for {@link REALTIME_EVENT.sessionTransition}. */
38
27
  interface SessionTransitionEvent {
39
28
  session_id: Id;
@@ -52,5 +41,5 @@ interface ReviewActionEvent {
52
41
  actor_id: Id | null;
53
42
  }
54
43
  //#endregion
55
- export { REALTIME_EVENT, RealtimeEventName, ReviewActionEvent, SessionTransitionEvent, parseRealtimeChannel, realtimeChannels };
44
+ export { REALTIME_EVENT, RealtimeEventName, ReviewActionEvent, SessionTransitionEvent, realtimeChannels };
56
45
  //# sourceMappingURL=realtime.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.d.mts","names":[],"sources":["../src/realtime.ts"],"mappings":";;;;;;AAUA;;;;cAAa,cAAA;EAOD,uFAFF,iBAAA;WAAA,YAAA;AAAA;AAAA,KAEE,iBAAA,WAA4B,cAAA,eAA6B,cAAc;;;;;cAMtE,gBAAA;EAMU,oEAJU,EAAA,aAIR;4BAFG,EAAA,EAAE,SAAA,EAAa,EAAA,aAFV;uBAIV,EAAA;AAAA;;iBAIP,oBAAA,CACd,OAAA;EAEI,IAAA;EAAsB,cAAA;AAAA;EACtB,IAAA;EAAiB,cAAA;EAAwB,SAAA;AAAA;EACzC,IAAA;EAAiB,SAAA;AAAA;;UAYN,sBAAA;EACf,UAAA,EAAY,EAAA;EACZ,eAAA,EAAiB,EAAA;EACjB,UAAA,EAAY,EAAA;EACZ,MAAA,EAAQ,kBAAA;EACR,eAAA,EAAiB,kBAAA;AAAA;;UAIF,iBAAA;EACf,UAAA,EAAY,EAAA;EACZ,eAAA,EAAiB,EAAA;EACjB,UAAA,EAAY,EAAA;;EAEZ,MAAA;EACA,QAAA,EAAU,EAAA;AAAA"}
1
+ {"version":3,"file":"realtime.d.mts","names":[],"sources":["../src/realtime.ts"],"mappings":";;;;;;AASA;;;cAAa,cAAA;yFAKH,iBAAA,wBAEmB;EAAA,SAFnB,YAAA;AAAA;AAAA,KAEE,iBAAA,WAA4B,cAAA,eAA6B,cAAc;AAOnF;;;;;AAAA,cAAa,gBAAA;EAM8B,iDAJ1B,EAAA,aAMQ;iCAJQ,EAAA;4BAEL,EAAA,EAAE,SAAA,EAAa,EAAA;uBAEpB,EAAA;AAAA;;UAIN,sBAAA;EACf,UAAA,EAAY,EAAA;EACZ,eAAA,EAAiB,EAAA;EACjB,UAAA,EAAY,EAAA;EACZ,MAAA,EAAQ,kBAAA;EACR,eAAA,EAAiB,kBAAA;AAAA;;UAIF,iBAAA;EACf,UAAA,EAAY,EAAA;EACZ,eAAA,EAAiB,EAAA;EACjB,UAAA,EAAY,EAAA;;EAEZ,MAAA;EACA,QAAA,EAAU,EAAA;AAAA"}
package/dist/realtime.mjs CHANGED
@@ -1,8 +1,7 @@
1
1
  //#region src/realtime.ts
2
2
  /**
3
- * Realtime transport contracts (Phase 16). Pure, dependency-free helpers shared
4
- * by the API (server publish) and the dashboard/widget (client subscribe), so
5
- * channel and event names never drift between them.
3
+ * Realtime contracts shared by the API (server publish) and the dashboard and
4
+ * widget (client subscribe), so channel and event names never drift between them.
6
5
  */
7
6
  /** Events the API broadcasts. Clients react by invalidating their caches. */
8
7
  const REALTIME_EVENT = {
@@ -12,38 +11,21 @@ const REALTIME_EVENT = {
12
11
  reviewAction: "review.action"
13
12
  };
14
13
  /**
15
- * Private channel name builders. All channels are `private-` (Pusher protocol),
16
- * so a subscription must be authorized server-side against the caller's scope.
14
+ * Private channel name builders. Every channel is `private-`, so a subscription
15
+ * must be authorized by the API. Segments are dot-separated so the API's channel
16
+ * rules can capture each id.
17
17
  */
18
18
  const realtimeChannels = {
19
+ /** A user's own notifications. */
20
+ user: (userId) => `private-user.${userId}`,
19
21
  /** Everything in an organization. */
20
- organization: (organizationId) => `private-organization-${organizationId}`,
22
+ organization: (organizationId) => `private-organization.${organizationId}`,
21
23
  /** Everything in a project. */
22
- project: (organizationId, projectId) => `private-organization-${organizationId}-project-${projectId}`,
24
+ project: (organizationId, projectId) => `private-organization.${organizationId}.project.${projectId}`,
23
25
  /** A single verification session (used by the widget via client token). */
24
- session: (sessionId) => `private-session-${sessionId}`
26
+ session: (sessionId) => `private-session.${sessionId}`
25
27
  };
26
- /** Parse a private channel name back into its scope, or null if unrecognized. */
27
- function parseRealtimeChannel(channel) {
28
- const project = /^private-organization-(.+)-project-(.+)$/.exec(channel);
29
- if (project) return {
30
- kind: "project",
31
- organizationId: project[1],
32
- projectId: project[2]
33
- };
34
- const organization = /^private-organization-(.+)$/.exec(channel);
35
- if (organization) return {
36
- kind: "organization",
37
- organizationId: organization[1]
38
- };
39
- const session = /^private-session-(.+)$/.exec(channel);
40
- if (session) return {
41
- kind: "session",
42
- sessionId: session[1]
43
- };
44
- return null;
45
- }
46
28
  //#endregion
47
- export { REALTIME_EVENT, parseRealtimeChannel, realtimeChannels };
29
+ export { REALTIME_EVENT, realtimeChannels };
48
30
 
49
31
  //# sourceMappingURL=realtime.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.mjs","names":[],"sources":["../src/realtime.ts"],"sourcesContent":["import type { Id } from './common'\nimport type { VerificationStatus } from './verification'\n\n/**\n * Realtime transport contracts (Phase 16). Pure, dependency-free helpers shared\n * by the API (server publish) and the dashboard/widget (client subscribe), so\n * channel and event names never drift between them.\n */\n\n/** Events the API broadcasts. Clients react by invalidating their caches. */\nexport const REALTIME_EVENT = {\n /** A verification session changed status (the `transitionTo` choke point). */\n sessionTransition: 'session.transition',\n /** A reviewer acted on a session (assign/note/suspicious/decision/retry). */\n reviewAction: 'review.action',\n} as const\n\nexport type RealtimeEventName = (typeof REALTIME_EVENT)[keyof typeof REALTIME_EVENT]\n\n/**\n * Private channel name builders. All channels are `private-` (Pusher protocol),\n * so a subscription must be authorized server-side against the caller's scope.\n */\nexport const realtimeChannels = {\n /** Everything in an organization. */\n organization: (organizationId: Id): string => `private-organization-${organizationId}`,\n /** Everything in a project. */\n project: (organizationId: Id, projectId: Id): string => `private-organization-${organizationId}-project-${projectId}`,\n /** A single verification session (used by the widget via client token). */\n session: (sessionId: Id): string => `private-session-${sessionId}`,\n}\n\n/** Parse a private channel name back into its scope, or null if unrecognized. */\nexport function parseRealtimeChannel(\n channel: string,\n):\n | { kind: 'organization'; organizationId: string }\n | { kind: 'project'; organizationId: string; projectId: string }\n | { kind: 'session'; sessionId: string }\n | null {\n const project = /^private-organization-(.+)-project-(.+)$/.exec(channel)\n if (project) return { kind: 'project', organizationId: project[1]!, projectId: project[2]! }\n const organization = /^private-organization-(.+)$/.exec(channel)\n if (organization) return { kind: 'organization', organizationId: organization[1]! }\n const session = /^private-session-(.+)$/.exec(channel)\n if (session) return { kind: 'session', sessionId: session[1]! }\n return null\n}\n\n/** Payload for {@link REALTIME_EVENT.sessionTransition}. */\nexport interface SessionTransitionEvent {\n session_id: Id\n organization_id: Id\n project_id: Id | null\n status: VerificationStatus\n previous_status: VerificationStatus | null\n}\n\n/** Payload for {@link REALTIME_EVENT.reviewAction}. */\nexport interface ReviewActionEvent {\n session_id: Id\n organization_id: Id\n project_id: Id | null\n /** The audit action, e.g. `review.assigned`, `review.note`, `review.approved`. */\n action: string\n actor_id: Id | null\n}\n"],"mappings":";;;;;;;AAUA,MAAa,iBAAiB;;CAE5B,mBAAmB;;CAEnB,cAAc;AAChB;;;;;AAQA,MAAa,mBAAmB;;CAE9B,eAAe,mBAA+B,wBAAwB;;CAEtE,UAAU,gBAAoB,cAA0B,wBAAwB,eAAe,WAAW;;CAE1G,UAAU,cAA0B,mBAAmB;AACzD;;AAGA,SAAgB,qBACd,SAKO;CACP,MAAM,UAAU,2CAA2C,KAAK,OAAO;CACvE,IAAI,SAAS,OAAO;EAAE,MAAM;EAAW,gBAAgB,QAAQ;EAAK,WAAW,QAAQ;CAAI;CAC3F,MAAM,eAAe,8BAA8B,KAAK,OAAO;CAC/D,IAAI,cAAc,OAAO;EAAE,MAAM;EAAgB,gBAAgB,aAAa;CAAI;CAClF,MAAM,UAAU,yBAAyB,KAAK,OAAO;CACrD,IAAI,SAAS,OAAO;EAAE,MAAM;EAAW,WAAW,QAAQ;CAAI;CAC9D,OAAO;AACT"}
1
+ {"version":3,"file":"realtime.mjs","names":[],"sources":["../src/realtime.ts"],"sourcesContent":["import type { Id } from './common'\nimport type { VerificationStatus } from './verification'\n\n/**\n * Realtime contracts shared by the API (server publish) and the dashboard and\n * widget (client subscribe), so channel and event names never drift between them.\n */\n\n/** Events the API broadcasts. Clients react by invalidating their caches. */\nexport const REALTIME_EVENT = {\n /** A verification session changed status (the `transitionTo` choke point). */\n sessionTransition: 'session.transition',\n /** A reviewer acted on a session (assign/note/suspicious/decision/retry). */\n reviewAction: 'review.action',\n} as const\n\nexport type RealtimeEventName = (typeof REALTIME_EVENT)[keyof typeof REALTIME_EVENT]\n\n/**\n * Private channel name builders. Every channel is `private-`, so a subscription\n * must be authorized by the API. Segments are dot-separated so the API's channel\n * rules can capture each id.\n */\nexport const realtimeChannels = {\n /** A user's own notifications. */\n user: (userId: Id): string => `private-user.${userId}`,\n /** Everything in an organization. */\n organization: (organizationId: Id): string => `private-organization.${organizationId}`,\n /** Everything in a project. */\n project: (organizationId: Id, projectId: Id): string => `private-organization.${organizationId}.project.${projectId}`,\n /** A single verification session (used by the widget via client token). */\n session: (sessionId: Id): string => `private-session.${sessionId}`,\n}\n\n/** Payload for {@link REALTIME_EVENT.sessionTransition}. */\nexport interface SessionTransitionEvent {\n session_id: Id\n organization_id: Id\n project_id: Id | null\n status: VerificationStatus\n previous_status: VerificationStatus | null\n}\n\n/** Payload for {@link REALTIME_EVENT.reviewAction}. */\nexport interface ReviewActionEvent {\n session_id: Id\n organization_id: Id\n project_id: Id | null\n /** The audit action, e.g. `review.assigned`, `review.note`, `review.approved`. */\n action: string\n actor_id: Id | null\n}\n"],"mappings":";;;;;;AASA,MAAa,iBAAiB;;CAE5B,mBAAmB;;CAEnB,cAAc;AAChB;;;;;;AASA,MAAa,mBAAmB;;CAE9B,OAAO,WAAuB,gBAAgB;;CAE9C,eAAe,mBAA+B,wBAAwB;;CAEtE,UAAU,gBAAoB,cAA0B,wBAAwB,eAAe,WAAW;;CAE1G,UAAU,cAA0B,mBAAmB;AACzD"}
@@ -0,0 +1,101 @@
1
+ import { Id, IsoDateTime } from "./common.mjs";
2
+ import { DecisionReason } from "./verification.mjs";
3
+
4
+ //#region src/risk.d.ts
5
+ /** A fraud or compliance signal a detector can raise against a session. */
6
+ type RiskSignalKey = 'duplicate_document' | 'duplicate_identity' | 'duplicate_face' | 'document_tampering' | 'document_inconsistent' | 'sanctions_match' | 'pep_match' | 'adverse_media' | 'high_risk_network' | 'ip_country_mismatch' | 'velocity_exceeded' | 'underage';
7
+ /** Every signal key, in decision precedence order (most severe first). */
8
+ declare const RISK_SIGNAL_KEYS: readonly RiskSignalKey[];
9
+ /** What a signal does to the decision: nothing (`info`), manual review, or rejection. */
10
+ type RiskSeverity = 'info' | 'review' | 'reject';
11
+ /** How a workflow treats a signal key. */
12
+ type RiskSignalPolicy = 'ignore' | 'review' | 'reject';
13
+ /** Per-key policy overrides. Keys left out use {@link DEFAULT_RISK_SIGNAL_POLICY}. */
14
+ type RiskPolicyConfig = Partial<Record<RiskSignalKey, RiskSignalPolicy>>;
15
+ /** Signals route to review unless an organization opts a key into `ignore` or `reject`. */
16
+ declare const DEFAULT_RISK_SIGNAL_POLICY: RiskSignalPolicy;
17
+ /** Signals that never reject, whatever the policy says: their evidence is too soft. */
18
+ declare const REVIEW_ONLY_RISK_SIGNALS: readonly RiskSignalKey[];
19
+ /** The decision reason each signal key reports when it decides a session. */
20
+ declare const RISK_SIGNAL_REASONS: Record<RiskSignalKey, DecisionReason>;
21
+ /** A signal raised by a detector, before it is stored. */
22
+ interface RiskSignal {
23
+ key: RiskSignalKey;
24
+ severity: RiskSeverity;
25
+ /** How much the signal adds to the session's risk score, in [0, 1]. */
26
+ score: number;
27
+ /** Advisory signals (model opinions) are capped at review. */
28
+ advisory?: boolean;
29
+ /** Detector-specific facts that justify the signal. */
30
+ evidence: Record<string, unknown>;
31
+ }
32
+ /** A stored risk signal, as the dashboard API returns it. */
33
+ interface SessionRiskSignal extends RiskSignal {
34
+ id: Id;
35
+ session_id: Id;
36
+ /** Which detector raised it. */
37
+ source: string;
38
+ cleared_at: IsoDateTime | null;
39
+ cleared_by: Id | null;
40
+ clear_reason: string | null;
41
+ created_at: IsoDateTime;
42
+ }
43
+ /** The risk block of a webhook payload. */
44
+ interface WebhookRiskCheck {
45
+ score: number | null;
46
+ signals: Array<{
47
+ key: RiskSignalKey;
48
+ severity: RiskSeverity;
49
+ cleared: boolean;
50
+ }>;
51
+ }
52
+ /** A category of screening hit. */
53
+ type ScreeningHitCategory = 'sanction' | 'pep' | 'adverse_media' | 'other';
54
+ /** One watchlist entity a screened identity matched. */
55
+ interface ScreeningHit {
56
+ /** Provider entity id, stable across re-screens. */
57
+ entity_id: string;
58
+ name: string;
59
+ /** Match score in [0, 1]. */
60
+ score: number;
61
+ category: ScreeningHitCategory;
62
+ /** Provider topic tags, e.g. `sanction`, `role.pep`. */
63
+ topics: string[];
64
+ /** Source lists the entity appears on. */
65
+ datasets: string[];
66
+ birth_dates: string[];
67
+ countries: string[];
68
+ /** A page describing the entity, when the provider has one. */
69
+ url?: string;
70
+ }
71
+ /** What a screening hit does to the session. */
72
+ type ScreeningOnHit = 'review' | 'reject';
73
+ /** Configuration for the `screening` workflow stage. */
74
+ interface ScreeningStepConfig {
75
+ /** Minimum match score in [0, 1] that counts as a hit. */
76
+ threshold: number;
77
+ /** What a sanctions hit does. PEP and adverse media hits follow the workflow's risk policy. */
78
+ on_hit: ScreeningOnHit;
79
+ /** Re-screen the identity on a schedule after the session completes. */
80
+ monitor: boolean;
81
+ }
82
+ /** The default screening config applied when the stage is enabled without one. */
83
+ declare const DEFAULT_SCREENING_CONFIG: ScreeningStepConfig;
84
+ /** Project limits for repeat sessions from one network address. */
85
+ interface VelocitySettings {
86
+ /** Sessions from one IP, under different user references, before the signal fires. */
87
+ max_sessions: number;
88
+ /** The look-back window in minutes. */
89
+ window_minutes: number;
90
+ }
91
+ declare const DEFAULT_VELOCITY_SETTINGS: VelocitySettings;
92
+ /** Organization-level opt-in for storing face embeddings. Off by default. */
93
+ interface FaceEmbeddingSettings {
94
+ enabled: boolean;
95
+ /** Days to keep an embedding before it is deleted. */
96
+ retention_days: number;
97
+ }
98
+ declare const DEFAULT_FACE_EMBEDDING_SETTINGS: FaceEmbeddingSettings;
99
+ //#endregion
100
+ export { DEFAULT_FACE_EMBEDDING_SETTINGS, DEFAULT_RISK_SIGNAL_POLICY, DEFAULT_SCREENING_CONFIG, DEFAULT_VELOCITY_SETTINGS, FaceEmbeddingSettings, REVIEW_ONLY_RISK_SIGNALS, RISK_SIGNAL_KEYS, RISK_SIGNAL_REASONS, RiskPolicyConfig, RiskSeverity, RiskSignal, RiskSignalKey, RiskSignalPolicy, ScreeningHit, ScreeningHitCategory, ScreeningOnHit, ScreeningStepConfig, SessionRiskSignal, VelocitySettings, WebhookRiskCheck };
101
+ //# sourceMappingURL=risk.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk.d.mts","names":[],"sources":["../src/risk.ts"],"mappings":";;;;;KAIY,aAAA;AAAZ;AAAA,cAea,gBAAA,WAA2B,aAAa;;KAgBzC,YAAA;AA/Ba;AAAA,KAkCb,gBAAA;;KAGA,gBAAA,GAAmB,OAAA,CAAQ,MAAA,CAAO,aAAA,EAAe,gBAAA;;cAGhD,0BAAA,EAA4B,gBAA2B;AATpE;AAAA,cAYa,wBAAA,WAAmC,aAAa;;cAGhD,mBAAA,EAAqB,MAAA,CAAO,aAAA,EAAe,cAAA;AAfhC;AAAA,UA+BP,UAAA;EACf,GAAA,EAAK,aAAA;EACL,QAAA,EAAU,YAAA;EA9BgB;EAgC1B,KAAA;EA7BU;EA+BV,QAAA;;EAEA,QAAA,EAAU,MAAA;AAAA;;UAIK,iBAAA,SAA0B,UAAA;EACzC,EAAA,EAAI,EAAA;EACJ,UAAA,EAAY,EAAA;EAvCiB;EAyC7B,MAAA;EACA,UAAA,EAAY,WAAA;EACZ,UAAA,EAAY,EAAA;EACZ,YAAA;EACA,UAAA,EAAY,WAAA;AAAA;;UAIG,gBAAA;EACf,KAAA;EACA,OAAA,EAAS,KAAA;IACP,GAAA,EAAK,aAAA;IACL,QAAA,EAAU,YAAA;IACV,OAAA;EAAA;AAAA;AA7CJ;AAAA,KAkDY,oBAAA;;UAGK,YAAA;EArDuC;EAuDtD,SAAA;EACA,IAAA;EAxDsC;EA0DtC,KAAA;EACA,QAAA,EAAU,oBAAoB;EA3DwB;EA6DtD,MAAA;EA7DoE;EA+DpE,QAAA;EACA,WAAA;EACA,SAAA;EAhDK;EAkDL,GAAA;AAAA;;KAIU,cAAA;;UAGK,mBAAA;EAxDf;EA0DA,SAAA;EAxDA;EA0DA,MAAA,EAAQ,cAAc;EAtDtB;EAwDA,OAAA;AAAA;AAxDgB;AAAA,cA4DL,wBAAA,EAA0B,mBAItC;;UAGgB,gBAAA;EA9DX;EAgEJ,YAAA;EA5DY;EA8DZ,cAAc;AAAA;AAAA,cAGH,yBAAA,EAA2B,gBAGvC;;UAGgB,qBAAA;EACf,OAAA;EA5EA;EA8EA,cAAc;AAAA;AAAA,cAGH,+BAAA,EAAiC,qBAG7C"}
package/dist/risk.mjs ADDED
@@ -0,0 +1,53 @@
1
+ //#region src/risk.ts
2
+ /** Every signal key, in decision precedence order (most severe first). */
3
+ const RISK_SIGNAL_KEYS = [
4
+ "sanctions_match",
5
+ "underage",
6
+ "duplicate_document",
7
+ "duplicate_face",
8
+ "document_tampering",
9
+ "document_inconsistent",
10
+ "pep_match",
11
+ "adverse_media",
12
+ "duplicate_identity",
13
+ "high_risk_network",
14
+ "ip_country_mismatch",
15
+ "velocity_exceeded"
16
+ ];
17
+ /** Signals route to review unless an organization opts a key into `ignore` or `reject`. */
18
+ const DEFAULT_RISK_SIGNAL_POLICY = "review";
19
+ /** Signals that never reject, whatever the policy says: their evidence is too soft. */
20
+ const REVIEW_ONLY_RISK_SIGNALS = ["duplicate_identity", "ip_country_mismatch"];
21
+ /** The decision reason each signal key reports when it decides a session. */
22
+ const RISK_SIGNAL_REASONS = {
23
+ duplicate_document: "DUPLICATE_DOCUMENT",
24
+ duplicate_identity: "DUPLICATE_IDENTITY",
25
+ duplicate_face: "DUPLICATE_FACE",
26
+ document_tampering: "DOCUMENT_TAMPERING",
27
+ document_inconsistent: "DOCUMENT_TAMPERING",
28
+ sanctions_match: "SANCTIONS_MATCH",
29
+ pep_match: "PEP_MATCH",
30
+ adverse_media: "ADVERSE_MEDIA_MATCH",
31
+ high_risk_network: "HIGH_RISK_DEVICE",
32
+ ip_country_mismatch: "HIGH_RISK_DEVICE",
33
+ velocity_exceeded: "VELOCITY_EXCEEDED",
34
+ underage: "UNDERAGE"
35
+ };
36
+ /** The default screening config applied when the stage is enabled without one. */
37
+ const DEFAULT_SCREENING_CONFIG = {
38
+ threshold: .7,
39
+ on_hit: "review",
40
+ monitor: false
41
+ };
42
+ const DEFAULT_VELOCITY_SETTINGS = {
43
+ max_sessions: 5,
44
+ window_minutes: 60
45
+ };
46
+ const DEFAULT_FACE_EMBEDDING_SETTINGS = {
47
+ enabled: false,
48
+ retention_days: 365
49
+ };
50
+ //#endregion
51
+ export { DEFAULT_FACE_EMBEDDING_SETTINGS, DEFAULT_RISK_SIGNAL_POLICY, DEFAULT_SCREENING_CONFIG, DEFAULT_VELOCITY_SETTINGS, REVIEW_ONLY_RISK_SIGNALS, RISK_SIGNAL_KEYS, RISK_SIGNAL_REASONS };
52
+
53
+ //# sourceMappingURL=risk.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk.mjs","names":[],"sources":["../src/risk.ts"],"sourcesContent":["import type { Id, IsoDateTime } from './common'\nimport type { DecisionReason } from './verification'\n\n/** A fraud or compliance signal a detector can raise against a session. */\nexport type RiskSignalKey =\n | 'duplicate_document'\n | 'duplicate_identity'\n | 'duplicate_face'\n | 'document_tampering'\n | 'document_inconsistent'\n | 'sanctions_match'\n | 'pep_match'\n | 'adverse_media'\n | 'high_risk_network'\n | 'ip_country_mismatch'\n | 'velocity_exceeded'\n | 'underage'\n\n/** Every signal key, in decision precedence order (most severe first). */\nexport const RISK_SIGNAL_KEYS: readonly RiskSignalKey[] = [\n 'sanctions_match',\n 'underage',\n 'duplicate_document',\n 'duplicate_face',\n 'document_tampering',\n 'document_inconsistent',\n 'pep_match',\n 'adverse_media',\n 'duplicate_identity',\n 'high_risk_network',\n 'ip_country_mismatch',\n 'velocity_exceeded',\n]\n\n/** What a signal does to the decision: nothing (`info`), manual review, or rejection. */\nexport type RiskSeverity = 'info' | 'review' | 'reject'\n\n/** How a workflow treats a signal key. */\nexport type RiskSignalPolicy = 'ignore' | 'review' | 'reject'\n\n/** Per-key policy overrides. Keys left out use {@link DEFAULT_RISK_SIGNAL_POLICY}. */\nexport type RiskPolicyConfig = Partial<Record<RiskSignalKey, RiskSignalPolicy>>\n\n/** Signals route to review unless an organization opts a key into `ignore` or `reject`. */\nexport const DEFAULT_RISK_SIGNAL_POLICY: RiskSignalPolicy = 'review'\n\n/** Signals that never reject, whatever the policy says: their evidence is too soft. */\nexport const REVIEW_ONLY_RISK_SIGNALS: readonly RiskSignalKey[] = ['duplicate_identity', 'ip_country_mismatch']\n\n/** The decision reason each signal key reports when it decides a session. */\nexport const RISK_SIGNAL_REASONS: Record<RiskSignalKey, DecisionReason> = {\n duplicate_document: 'DUPLICATE_DOCUMENT',\n duplicate_identity: 'DUPLICATE_IDENTITY',\n duplicate_face: 'DUPLICATE_FACE',\n document_tampering: 'DOCUMENT_TAMPERING',\n document_inconsistent: 'DOCUMENT_TAMPERING',\n sanctions_match: 'SANCTIONS_MATCH',\n pep_match: 'PEP_MATCH',\n adverse_media: 'ADVERSE_MEDIA_MATCH',\n high_risk_network: 'HIGH_RISK_DEVICE',\n ip_country_mismatch: 'HIGH_RISK_DEVICE',\n velocity_exceeded: 'VELOCITY_EXCEEDED',\n underage: 'UNDERAGE',\n}\n\n/** A signal raised by a detector, before it is stored. */\nexport interface RiskSignal {\n key: RiskSignalKey\n severity: RiskSeverity\n /** How much the signal adds to the session's risk score, in [0, 1]. */\n score: number\n /** Advisory signals (model opinions) are capped at review. */\n advisory?: boolean\n /** Detector-specific facts that justify the signal. */\n evidence: Record<string, unknown>\n}\n\n/** A stored risk signal, as the dashboard API returns it. */\nexport interface SessionRiskSignal extends RiskSignal {\n id: Id\n session_id: Id\n /** Which detector raised it. */\n source: string\n cleared_at: IsoDateTime | null\n cleared_by: Id | null\n clear_reason: string | null\n created_at: IsoDateTime\n}\n\n/** The risk block of a webhook payload. */\nexport interface WebhookRiskCheck {\n score: number | null\n signals: Array<{\n key: RiskSignalKey\n severity: RiskSeverity\n cleared: boolean\n }>\n}\n\n/** A category of screening hit. */\nexport type ScreeningHitCategory = 'sanction' | 'pep' | 'adverse_media' | 'other'\n\n/** One watchlist entity a screened identity matched. */\nexport interface ScreeningHit {\n /** Provider entity id, stable across re-screens. */\n entity_id: string\n name: string\n /** Match score in [0, 1]. */\n score: number\n category: ScreeningHitCategory\n /** Provider topic tags, e.g. `sanction`, `role.pep`. */\n topics: string[]\n /** Source lists the entity appears on. */\n datasets: string[]\n birth_dates: string[]\n countries: string[]\n /** A page describing the entity, when the provider has one. */\n url?: string\n}\n\n/** What a screening hit does to the session. */\nexport type ScreeningOnHit = 'review' | 'reject'\n\n/** Configuration for the `screening` workflow stage. */\nexport interface ScreeningStepConfig {\n /** Minimum match score in [0, 1] that counts as a hit. */\n threshold: number\n /** What a sanctions hit does. PEP and adverse media hits follow the workflow's risk policy. */\n on_hit: ScreeningOnHit\n /** Re-screen the identity on a schedule after the session completes. */\n monitor: boolean\n}\n\n/** The default screening config applied when the stage is enabled without one. */\nexport const DEFAULT_SCREENING_CONFIG: ScreeningStepConfig = {\n threshold: 0.7,\n on_hit: 'review',\n monitor: false,\n}\n\n/** Project limits for repeat sessions from one network address. */\nexport interface VelocitySettings {\n /** Sessions from one IP, under different user references, before the signal fires. */\n max_sessions: number\n /** The look-back window in minutes. */\n window_minutes: number\n}\n\nexport const DEFAULT_VELOCITY_SETTINGS: VelocitySettings = {\n max_sessions: 5,\n window_minutes: 60,\n}\n\n/** Organization-level opt-in for storing face embeddings. Off by default. */\nexport interface FaceEmbeddingSettings {\n enabled: boolean\n /** Days to keep an embedding before it is deleted. */\n retention_days: number\n}\n\nexport const DEFAULT_FACE_EMBEDDING_SETTINGS: FaceEmbeddingSettings = {\n enabled: false,\n retention_days: 365,\n}\n"],"mappings":";;AAmBA,MAAa,mBAA6C;CACxD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAYA,MAAa,6BAA+C;;AAG5D,MAAa,2BAAqD,CAAC,sBAAsB,qBAAqB;;AAG9G,MAAa,sBAA6D;CACxE,oBAAoB;CACpB,oBAAoB;CACpB,gBAAgB;CAChB,oBAAoB;CACpB,uBAAuB;CACvB,iBAAiB;CACjB,WAAW;CACX,eAAe;CACf,mBAAmB;CACnB,qBAAqB;CACrB,mBAAmB;CACnB,UAAU;AACZ;;AAuEA,MAAa,2BAAgD;CAC3D,WAAW;CACX,QAAQ;CACR,SAAS;AACX;AAUA,MAAa,4BAA8C;CACzD,cAAc;CACd,gBAAgB;AAClB;AASA,MAAa,kCAAyD;CACpE,SAAS;CACT,gBAAgB;AAClB"}
@@ -1,14 +1,6 @@
1
1
  import { Entity } from "./common.mjs";
2
2
 
3
3
  //#region src/settings.d.ts
4
- /**
5
- * Realtime transport for verification events (Phase 16). `pusher` covers both
6
- * hosted Pusher Channels (default, via a cluster) and self-hosted soketi (opt-in,
7
- * via a host) — they share the Pusher protocol. `polling` carries no push
8
- * transport: clients poll the session endpoint instead (a universal fallback that
9
- * needs no infrastructure). `off` disables live updates entirely.
10
- */
11
- type RealtimeTransport = 'pusher' | 'firebase' | 'polling' | 'off';
12
4
  /**
13
5
  * Which capture/liveness flow the widget offers (Phase 17). `passive` = the
14
6
  * current selfie flow; `active` = guided active-liveness challenges; `both` =
@@ -27,10 +19,6 @@ interface GlobalSettings {
27
19
  support_email: string | null; /** Whether new organization sign-ups are accepted. */
28
20
  signups_enabled: boolean;
29
21
  };
30
- /** Realtime delivery configuration (consumed in Phase 16). */
31
- realtime: {
32
- transport: RealtimeTransport;
33
- };
34
22
  /** Default capture/liveness flow offered to widgets (Phase 17). */
35
23
  capture: {
36
24
  model: CaptureModel;
@@ -52,5 +40,5 @@ interface GlobalSetting extends Entity {
52
40
  /** Defaults applied when a settings key is unset. */
53
41
  declare const DEFAULT_GLOBAL_SETTINGS: GlobalSettings;
54
42
  //#endregion
55
- export { CaptureModel, DEFAULT_GLOBAL_SETTINGS, GlobalSetting, GlobalSettings, RealtimeTransport };
43
+ export { CaptureModel, DEFAULT_GLOBAL_SETTINGS, GlobalSetting, GlobalSettings };
56
44
  //# sourceMappingURL=settings.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.mts","names":[],"sources":["../src/settings.ts"],"mappings":";;;;;AASA;;;;AAA6B;KAAjB,iBAAA;;;;AAOY;AAOxB;KAPY,YAAA;;;;;;UAOK,cAAA;EASf;EAPA,QAAA;IACE,IAAA;IACA,aAAA,iBAUA;IARA,eAAA;EAAA;EAiBA;EAdF,QAAA;IACE,SAAA,EAAW,iBAAA;EAAA;EAkBgB;EAf7B,OAAA;IACE,KAAA,EAAO,YAAY;EAAA;EAerB;EAZA,MAAA;IAYwB;AAAA;AAI1B;;;IAVI,eAAA;EAAA;AAAA;;UAKa,aAAA,SAAsB,MAAM;EAC3C,QAAA,EAAU,cAAA;AAAA;;cAIC,uBAAA,EAAyB,cAerC"}
1
+ {"version":3,"file":"settings.d.mts","names":[],"sources":["../src/settings.ts"],"mappings":";;;;;AAOA;;;KAAY,YAAA;AAAY;AAOxB;;;;AAPwB,UAOP,cAAA;EAGb;EADF,QAAA;IACE,IAAA;IACA,aAAA,iBAMA;IAJA,eAAA;EAAA;EAaA;EAVF,OAAA;IACE,KAAA,EAAO,YAAY;EAAA;EAcQ;EAX7B,MAAA;IAW2C;;;;;IALzC,eAAA;EAAA;AAAA;;UAKa,aAAA,SAAsB,MAAM;EAC3C,QAAA,EAAU,cAAA;AAAA;;cAIC,uBAAA,EAAyB,cAYrC"}
package/dist/settings.mjs CHANGED
@@ -6,7 +6,6 @@ const DEFAULT_GLOBAL_SETTINGS = {
6
6
  support_email: null,
7
7
  signups_enabled: true
8
8
  },
9
- realtime: { transport: "off" },
10
9
  capture: { model: "passive" },
11
10
  assets: { url_ttl_seconds: 1800 }
12
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"settings.mjs","names":[],"sources":["../src/settings.ts"],"sourcesContent":["import type { Entity } from './common'\n\n/**\n * Realtime transport for verification events (Phase 16). `pusher` covers both\n * hosted Pusher Channels (default, via a cluster) and self-hosted soketi (opt-in,\n * via a host) — they share the Pusher protocol. `polling` carries no push\n * transport: clients poll the session endpoint instead (a universal fallback that\n * needs no infrastructure). `off` disables live updates entirely.\n */\nexport type RealtimeTransport = 'pusher' | 'firebase' | 'polling' | 'off'\n\n/**\n * Which capture/liveness flow the widget offers (Phase 17). `passive` = the\n * current selfie flow; `active` = guided active-liveness challenges; `both` =\n * offer active, falling back to passive on failure/unsupported devices.\n */\nexport type CaptureModel = 'passive' | 'active' | 'both'\n\n/**\n * Platform-wide settings, managed by platform admins on the `/admin` surface and\n * read by the app at runtime. A single typed record (see {@link GlobalSetting}),\n * always merged over {@link DEFAULT_GLOBAL_SETTINGS} so every key is present.\n */\nexport interface GlobalSettings {\n /** Branding/basics for the whole platform. */\n platform: {\n name: string\n support_email: string | null\n /** Whether new organization sign-ups are accepted. */\n signups_enabled: boolean\n }\n /** Realtime delivery configuration (consumed in Phase 16). */\n realtime: {\n transport: RealtimeTransport\n }\n /** Default capture/liveness flow offered to widgets (Phase 17). */\n capture: {\n model: CaptureModel\n }\n /** Signed session-asset links (captured document/selfie images). */\n assets: {\n /**\n * How long a signed asset URL stays valid, in seconds. The link embeds its\n * own expiry, so a change only affects newly minted URLs; existing links\n * keep their original window. Bounded to [60, 86400] (1 minute to 24 hours).\n */\n url_ttl_seconds: number\n }\n}\n\n/** The persisted singleton row backing {@link GlobalSettings}. */\nexport interface GlobalSetting extends Entity {\n settings: GlobalSettings\n}\n\n/** Defaults applied when a settings key is unset. */\nexport const DEFAULT_GLOBAL_SETTINGS: GlobalSettings = {\n platform: {\n name: 'Arkyc',\n support_email: null,\n signups_enabled: true,\n },\n realtime: {\n transport: 'off',\n },\n capture: {\n model: 'passive',\n },\n assets: {\n url_ttl_seconds: 1800,\n },\n}\n"],"mappings":";;AAwDA,MAAa,0BAA0C;CACrD,UAAU;EACR,MAAM;EACN,eAAe;EACf,iBAAiB;CACnB;CACA,UAAU,EACR,WAAW,MACb;CACA,SAAS,EACP,OAAO,UACT;CACA,QAAQ,EACN,iBAAiB,KACnB;AACF"}
1
+ {"version":3,"file":"settings.mjs","names":[],"sources":["../src/settings.ts"],"sourcesContent":["import type { Entity } from './common'\n\n/**\n * Which capture/liveness flow the widget offers (Phase 17). `passive` = the\n * current selfie flow; `active` = guided active-liveness challenges; `both` =\n * offer active, falling back to passive on failure/unsupported devices.\n */\nexport type CaptureModel = 'passive' | 'active' | 'both'\n\n/**\n * Platform-wide settings, managed by platform admins on the `/admin` surface and\n * read by the app at runtime. A single typed record (see {@link GlobalSetting}),\n * always merged over {@link DEFAULT_GLOBAL_SETTINGS} so every key is present.\n */\nexport interface GlobalSettings {\n /** Branding/basics for the whole platform. */\n platform: {\n name: string\n support_email: string | null\n /** Whether new organization sign-ups are accepted. */\n signups_enabled: boolean\n }\n /** Default capture/liveness flow offered to widgets (Phase 17). */\n capture: {\n model: CaptureModel\n }\n /** Signed session-asset links (captured document/selfie images). */\n assets: {\n /**\n * How long a signed asset URL stays valid, in seconds. The link embeds its\n * own expiry, so a change only affects newly minted URLs; existing links\n * keep their original window. Bounded to [60, 86400] (1 minute to 24 hours).\n */\n url_ttl_seconds: number\n }\n}\n\n/** The persisted singleton row backing {@link GlobalSettings}. */\nexport interface GlobalSetting extends Entity {\n settings: GlobalSettings\n}\n\n/** Defaults applied when a settings key is unset. */\nexport const DEFAULT_GLOBAL_SETTINGS: GlobalSettings = {\n platform: {\n name: 'Arkyc',\n support_email: null,\n signups_enabled: true,\n },\n capture: {\n model: 'passive',\n },\n assets: {\n url_ttl_seconds: 1800,\n },\n}\n"],"mappings":";;AA2CA,MAAa,0BAA0C;CACrD,UAAU;EACR,MAAM;EACN,eAAe;EACf,iBAAiB;CACnB;CACA,SAAS,EACP,OAAO,UACT;CACA,QAAQ,EACN,iBAAiB,KACnB;AACF"}
@@ -14,7 +14,7 @@ type LivenessMode = 'passive' | 'active';
14
14
  */
15
15
  type LivenessChallenge = 'turn_left' | 'turn_right' | 'blink' | 'smile' | 'nod' | 'move_closer';
16
16
  /** Why a session reached its decision. */
17
- type DecisionReason = 'AUTO_APPROVED' | 'LOW_DOCUMENT_QUALITY' | 'OCR_LOW_CONFIDENCE' | 'DOCUMENT_EXPIRED' | 'LIVENESS_FAILED' | 'LIVENESS_LOW_CONFIDENCE' | 'FACE_MATCH_FAILED' | 'FACE_MATCH_LOW_CONFIDENCE' | 'MULTIPLE_FACES_DETECTED' | 'ADDRESS_VERIFICATION_FAILED' | 'ADDRESS_LOW_CONFIDENCE' | 'MANUAL_APPROVAL' | 'MANUAL_REJECTION' | 'RETRY_REQUESTED';
17
+ type DecisionReason = 'AUTO_APPROVED' | 'LOW_DOCUMENT_QUALITY' | 'OCR_LOW_CONFIDENCE' | 'DOCUMENT_EXPIRED' | 'LIVENESS_FAILED' | 'LIVENESS_LOW_CONFIDENCE' | 'FACE_MATCH_FAILED' | 'FACE_MATCH_LOW_CONFIDENCE' | 'MULTIPLE_FACES_DETECTED' | 'ADDRESS_VERIFICATION_FAILED' | 'ADDRESS_LOW_CONFIDENCE' | 'MANUAL_APPROVAL' | 'MANUAL_REJECTION' | 'RETRY_REQUESTED' | 'DUPLICATE_DOCUMENT' | 'DUPLICATE_IDENTITY' | 'DUPLICATE_FACE' | 'DOCUMENT_TAMPERING' | 'SANCTIONS_MATCH' | 'PEP_MATCH' | 'ADVERSE_MEDIA_MATCH' | 'HIGH_RISK_DEVICE' | 'VELOCITY_EXCEEDED' | 'UNDERAGE';
18
18
  /**
19
19
  * A verification session: the full lifecycle of one verification flow, owned by
20
20
  * a project (and organization). Created from an integrator's backend, driven by the
@@ -1 +1 @@
1
- {"version":3,"file":"verification.d.mts","names":[],"sources":["../src/verification.ts"],"mappings":";;;;KAGY,kBAAA;AAAZ;AAAA,KAcY,oBAAA;;KAGA,YAAA;AAjBkB;AAc9B;;;;AAd8B,KAwBlB,iBAAA;AAPZ;AAAA,KAUY,cAAA;;;AAVY;AAOxB;;UAwBiB,mBAAA,SAA4B,MAAA,EAAQ,aAAA;EAxBxB;EA0B3B,cAAA;EAvBU;EAyBV,IAAA;EACA,MAAA,EAAQ,kBAAA;EACR,aAAA,EAAe,oBAAA;EACf,cAAA,EAAgB,oBAAA;EAChB,eAAA,EAAiB,cAAA;EARkB;EAUnC,UAAA;EALQ;EAOR,iBAAA;EACA,UAAA,EAAY,WAAA;EACZ,YAAA,EAAc,WAAA;EACd,WAAA,EAAa,WAAA;EACb,WAAA,EAAa,EAAA;EACb,QAAA,EAAU,QAAA;AAAA"}
1
+ {"version":3,"file":"verification.d.mts","names":[],"sources":["../src/verification.ts"],"mappings":";;;;KAGY,kBAAA;AAAZ;AAAA,KAcY,oBAAA;;KAGA,YAAA;AAjBkB;AAc9B;;;;AAd8B,KAwBlB,iBAAA;AAPZ;AAAA,KAUY,cAAA;;;AAVY;AAOxB;;UAkCiB,mBAAA,SAA4B,MAAA,EAAQ,aAAA;EAlCxB;EAoC3B,cAAA;EAjCU;EAmCV,IAAA;EACA,MAAA,EAAQ,kBAAA;EACR,aAAA,EAAe,oBAAA;EACf,cAAA,EAAgB,oBAAA;EAChB,eAAA,EAAiB,cAAA;EARkB;EAUnC,UAAA;EALQ;EAOR,iBAAA;EACA,UAAA,EAAY,WAAA;EACZ,YAAA,EAAc,WAAA;EACd,WAAA,EAAa,WAAA;EACb,WAAA,EAAa,EAAA;EACb,QAAA,EAAU,QAAA;AAAA"}
@@ -1,9 +1,10 @@
1
1
  import { Entity, Id, IsoDateTime, ProjectScoped } from "./common.mjs";
2
2
  import { DecisionReason, VerificationStatus } from "./verification.mjs";
3
+ import { ScreeningHit, WebhookRiskCheck } from "./risk.mjs";
3
4
 
4
5
  //#region src/webhook.d.ts
5
6
  /** The set of webhook event names Arkyc can deliver. */
6
- type WebhookEventName = 'verification.started' | 'verification.document_submitted' | 'verification.address_submitted' | 'verification.processing' | 'verification.requires_review' | 'verification.approved' | 'verification.rejected' | 'verification.completed' | 'verification.expired' | 'verification.cancelled';
7
+ type WebhookEventName = 'verification.started' | 'verification.document_submitted' | 'verification.address_submitted' | 'verification.processing' | 'verification.requires_review' | 'verification.approved' | 'verification.rejected' | 'verification.completed' | 'verification.expired' | 'verification.cancelled' | 'verification.screening_alert';
7
8
  /** Per-check summary included in a webhook payload. */
8
9
  interface WebhookChecks {
9
10
  document?: {
@@ -25,6 +26,12 @@ interface WebhookChecks {
25
26
  score: number; /** Which corroboration methods ran. */
26
27
  methods: string[];
27
28
  };
29
+ /** Risk signals raised against the session and the aggregate score. */
30
+ risk?: WebhookRiskCheck;
31
+ /** Watchlist screening, when the workflow runs it. */
32
+ screening?: {
33
+ hits: ScreeningHit[];
34
+ };
28
35
  }
29
36
  /** The JSON body delivered to a webhook endpoint. */
30
37
  interface WebhookEvent {
@@ -1 +1 @@
1
- {"version":3,"file":"webhook.d.mts","names":[],"sources":["../src/webhook.ts"],"mappings":";;;;;KAIY,gBAAA;AAAZ;AAAA,UAaiB,aAAA;EACf,QAAA;IACE,aAAA;IACA,cAAA;IACA,OAAA,WAJ0B;IAM1B,eAAA;EAAA;EAEF,QAAA;IACE,MAAA;IACA,KAAA;EAAA;EAEF,UAAA;IACE,MAAA;IACA,gBAAA;EAAA;EAEF,OAAA;IACE,MAAA;IACA,KAAA,UAFF;IAIE,OAAA;EAAA;AAAA;;UAKa,YAAA;EACf,KAAA,EAAO,gBAAA;EACP,UAAA,EAAY,EAAA;EACZ,eAAA,EAAiB,EAAA;EACjB,UAAA,EAAY,EAAA;EACZ,cAAA;EACA,MAAA,EAAQ,kBAAA;EACR,MAAA,EAAQ,aAAA;EACR,eAAA,EAAiB,cAAA;EADT;EAGR,MAAA,EAAQ,MAAA;EACR,UAAA,EAAY,WAAA;AAAA;;KAIF,qBAAA;;UAGK,eAAA,SAAwB,MAAA,EAAQ,aAAA;EAC/C,GAAA;EAjBY;EAmBZ,WAAA;EACA,MAAA,EAAQ,gBAAA;EACR,MAAA,EAAQ,qBAAA;AAAA;;KAIE,qBAAA;;UAGK,eAAA,SAAwB,MAAA,EAAQ,aAAA;EAC/C,mBAAA,EAAqB,EAAA;EACrB,KAAA,EAAO,gBAAA;EACP,OAAA,EAAS,YAAA;EACT,MAAA,EAAQ,qBAAA;EACR,eAAA;EACA,aAAA;EACA,QAAA;EACA,aAAA,EAAe,WAAA;AAAA"}
1
+ {"version":3,"file":"webhook.d.mts","names":[],"sources":["../src/webhook.ts"],"mappings":";;;;;;KAKY,gBAAA;AAAZ;AAAA,UAciB,aAAA;EACf,QAAA;IACE,aAAA;IACA,cAAA;IACA,OAAA,WAJ0B;IAM1B,eAAA;EAAA;EAEF,QAAA;IACE,MAAA;IACA,KAAA;EAAA;EAEF,UAAA;IACE,MAAA;IACA,gBAAA;EAAA;EAEF,OAAA;IACE,MAAA;IACA,KAAA,UAFF;IAIE,OAAA;EAAA;EAAA;EAGF,IAAA,GAAO,gBAAA;EAAA;EAEP,SAAA;IACE,IAAA,EAAM,YAAY;EAAA;AAAA;AAAA;AAAA,UAKL,YAAA;EACf,KAAA,EAAO,gBAAA;EACP,UAAA,EAAY,EAAA;EACZ,eAAA,EAAiB,EAAA;EACjB,UAAA,EAAY,EAAA;EACZ,cAAA;EACA,MAAA,EAAQ,kBAAA;EACR,MAAA,EAAQ,aAAA;EACR,eAAA,EAAiB,cAAA;EAAA;EAEjB,MAAA,EAAQ,MAAA;EACR,UAAA,EAAY,WAAA;AAAA;;KAIF,qBAAA;;UAGK,eAAA,SAAwB,MAAA,EAAQ,aAAA;EAC/C,GAAA;EAhBA;EAkBA,WAAA;EACA,MAAA,EAAQ,gBAAA;EACR,MAAA,EAAQ,qBAAA;AAAA;;KAIE,qBAAA;;UAGK,eAAA,SAAwB,MAAA,EAAQ,aAAA;EAC/C,mBAAA,EAAqB,EAAA;EACrB,KAAA,EAAO,gBAAA;EACP,OAAA,EAAS,YAAA;EACT,MAAA,EAAQ,qBAAA;EACR,eAAA;EACA,aAAA;EACA,QAAA;EACA,aAAA,EAAe,WAAA;AAAA"}
@@ -1,4 +1,5 @@
1
1
  import { Id, IsoDateTime } from "./common.mjs";
2
+ import { RiskPolicyConfig, ScreeningStepConfig } from "./risk.mjs";
2
3
 
3
4
  //#region src/workflow.d.ts
4
5
  /**
@@ -12,7 +13,7 @@ import { Id, IsoDateTime } from "./common.mjs";
12
13
  * disturbs sessions already in flight.
13
14
  */
14
15
  /** A coarse verification stage a workflow can order and toggle. */
15
- type WorkflowStepKey = 'document' | 'address' | 'liveness' | 'face_match';
16
+ type WorkflowStepKey = 'document' | 'screening' | 'address' | 'liveness' | 'face_match';
16
17
  /**
17
18
  * The default pipeline's stages, in canonical order — what runs when a session
18
19
  * has no workflow. `address` is deliberately NOT here: it's an opt-in stage,
@@ -22,7 +23,7 @@ declare const WORKFLOW_STEP_KEYS: readonly WorkflowStepKey[];
22
23
  /**
23
24
  * Every stage a custom workflow may include, in canonical order. Used by the
24
25
  * workflow editor and to validate/normalise stored steps — a superset of
25
- * {@link WORKFLOW_STEP_KEYS} that adds the opt-in `address` stage.
26
+ * {@link WORKFLOW_STEP_KEYS} that adds the opt-in `screening` and `address` stages.
26
27
  */
27
28
  declare const AVAILABLE_WORKFLOW_STEP_KEYS: readonly WorkflowStepKey[];
28
29
  /** A method the address stage uses to corroborate the user's address. */
@@ -53,8 +54,8 @@ declare const DEFAULT_ADDRESS_CONFIG: AddressStepConfig;
53
54
  interface WorkflowStep {
54
55
  key: WorkflowStepKey;
55
56
  enabled: boolean;
56
- /** Stage-specific configuration. Only the `address` stage uses this today. */
57
- config?: AddressStepConfig;
57
+ /** Stage-specific configuration, used by the `address` and `screening` stages. */
58
+ config?: AddressStepConfig | ScreeningStepConfig;
58
59
  }
59
60
  /** Workflow-wide toggles. */
60
61
  interface WorkflowOptions {
@@ -64,6 +65,10 @@ interface WorkflowOptions {
64
65
  * to a third party. Disables the document portrait too, so face match can't run.
65
66
  */
66
67
  skip_ocr: boolean;
68
+ /** Minimum age in years, from the extracted date of birth (`UNDERAGE`). */
69
+ min_age?: number;
70
+ /** How each risk signal affects the decision. Unlisted signals route to review. */
71
+ risk_policy?: RiskPolicyConfig;
67
72
  }
68
73
  /** The portable config of a workflow: ordered stages + options. */
69
74
  interface WorkflowConfig {
@@ -91,10 +96,15 @@ declare function workflowEnables(config: WorkflowConfig | null | undefined, key:
91
96
  * address stage isn't enabled. Missing fields fall back to {@link DEFAULT_ADDRESS_CONFIG}.
92
97
  */
93
98
  declare function workflowAddressConfig(config: WorkflowConfig | null | undefined): AddressStepConfig | null;
99
+ /**
100
+ * The resolved screening config for a session's workflow, or `null` when the
101
+ * screening stage isn't enabled. Screening needs OCR fields to screen.
102
+ */
103
+ declare function workflowScreeningConfig(config: WorkflowConfig | null | undefined): ScreeningStepConfig | null;
94
104
  /** Whether OCR parsing should run: the document stage is on and `skip_ocr` is off. */
95
105
  declare function workflowRunsOcr(config: WorkflowConfig | null | undefined): boolean;
96
106
  /** The enabled stages in pipeline order (used by the widget to sequence its steps). */
97
107
  declare function workflowEnabledSteps(config: WorkflowConfig | null | undefined): WorkflowStepKey[];
98
108
  //#endregion
99
- export { ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, AddressMethod, AddressOnFail, AddressStepConfig, DEFAULT_ADDRESS_CONFIG, DEFAULT_WORKFLOW_CONFIG, WORKFLOW_STEP_KEYS, Workflow, WorkflowConfig, WorkflowOptions, WorkflowStep, WorkflowStepKey, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr };
109
+ export { ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, AddressMethod, AddressOnFail, AddressStepConfig, DEFAULT_ADDRESS_CONFIG, DEFAULT_WORKFLOW_CONFIG, WORKFLOW_STEP_KEYS, Workflow, WorkflowConfig, WorkflowOptions, WorkflowStep, WorkflowStepKey, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr, workflowScreeningConfig };
100
110
  //# sourceMappingURL=workflow.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow.d.mts","names":[],"sources":["../src/workflow.ts"],"mappings":";;;;;AAcA;;;;AAA2B;AAO3B;;;;KAPY,eAAA;AAcZ;;;;AAAmE;AAAnE,cAPa,kBAAA,WAA6B,eAAe;;;;AAehC;AAGzB;cAXa,4BAAA,WAAuC,eAAe;;KAQvD,aAAA;AAGwC;AAAA,cAAvC,eAAA,WAA0B,aAAa;;KAGxC,aAAA;;UAGK,iBAAA;EAAA;EAEf,OAAA,EAAS,aAAA;;;;;EAKT,OAAA,EAAS,aAAa;EAAb;;;AAMa;AAIxB;EAJE,sBAAA;AAAA;;cAIW,sBAAA,EAAwB,iBAGpC;AAGD;AAAA,UAAiB,YAAA;EACf,GAAA,EAAK,eAAA;EACL,OAAA;EADA;EAGA,MAAA,GAAS,iBAAiB;AAAA;;UAIX,eAAA;EAJW;AAAA;AAI5B;;;EAME,QAAQ;AAAA;AAIV;AAAA,UAAiB,cAAA;EACf,KAAA,EAAO,YAAA;EACP,OAAA,EAAS,eAAe;AAAA;;UAIT,QAAA,SAAiB,cAAA;EAChC,EAAA,EAAI,EAAA;EACJ,eAAA,EAAiB,EAAA;EACjB,IAAA;EACA,UAAA,EAAY,WAAA;EACZ,UAAA,EAAY,WAAA;AAAA;;cAID,uBAAA,EAAyB,cAOrC;;;;;;iBAOe,eAAA,CAAgB,MAAA,EAAQ,cAAA,qBAAmC,GAAA,EAAK,eAAe;;;;;iBAY/E,qBAAA,CAAsB,MAAA,EAAQ,cAAA,sBAAoC,iBAAiB;;iBASnF,eAAA,CAAgB,MAAyC,EAAjC,cAAc;;iBAOtC,oBAAA,CAAqB,MAAA,EAAQ,cAAA,sBAAoC,eAAe"}
1
+ {"version":3,"file":"workflow.d.mts","names":[],"sources":["../src/workflow.ts"],"mappings":";;;;;;AAeA;;;;AAA2B;AAO3B;;;;KAPY,eAAA;AAcZ;;;;AAAmE;AAAnE,cAPa,kBAAA,WAA6B,eAAe;;;;AAgBhC;AAGzB;cAZa,4BAAA,WAAuC,eAAe;;KASvD,aAAA;AAGwC;AAAA,cAAvC,eAAA,WAA0B,aAAa;;KAGxC,aAAA;;UAGK,iBAAA;EAAA;EAEf,OAAA,EAAS,aAAA;;;;;EAKT,OAAA,EAAS,aAAa;EAAb;;;AAMa;AAIxB;EAJE,sBAAA;AAAA;;cAIW,sBAAA,EAAwB,iBAGpC;AAGD;AAAA,UAAiB,YAAA;EACf,GAAA,EAAK,eAAA;EACL,OAAA;EAES;EAAT,MAAA,GAAS,iBAAA,GAAoB,mBAAA;AAAA;;UAId,eAAA;EAPV;;;;;EAaL,QAAA;EAVgD;EAYhD,OAAA;EAR8B;EAU9B,WAAA,GAAc,gBAAgB;AAAA;;UAIf,cAAA;EACf,KAAA,EAAO,YAAA;EACP,OAAA,EAAS,eAAe;AAAA;AANM;AAAA,UAUf,QAAA,SAAiB,cAAA;EAChC,EAAA,EAAI,EAAA;EACJ,eAAA,EAAiB,EAAA;EACjB,IAAA;EACA,UAAA,EAAY,WAAA;EACZ,UAAA,EAAY,WAAA;AAAA;;cAID,uBAAA,EAAyB,cAOrC;AApByB;AAI1B;;;;AAJ0B,iBA2BV,eAAA,CAAgB,MAAA,EAAQ,cAAA,qBAAmC,GAAA,EAAK,eAAe;;;;;iBAY/E,qBAAA,CAAsB,MAAA,EAAQ,cAAA,sBAAoC,iBAAiB;;;;;iBAYnF,uBAAA,CAAwB,MAAA,EAAQ,cAAA,sBAAoC,mBAAmB;;iBASvF,eAAA,CAAgB,MAAyC,EAAjC,cAAc;;iBAOtC,oBAAA,CAAqB,MAAA,EAAQ,cAAA,sBAAoC,eAAe"}
package/dist/workflow.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_SCREENING_CONFIG } from "./risk.mjs";
1
2
  //#region src/workflow.ts
2
3
  /**
3
4
  * The default pipeline's stages, in canonical order — what runs when a session
@@ -12,10 +13,11 @@ const WORKFLOW_STEP_KEYS = [
12
13
  /**
13
14
  * Every stage a custom workflow may include, in canonical order. Used by the
14
15
  * workflow editor and to validate/normalise stored steps — a superset of
15
- * {@link WORKFLOW_STEP_KEYS} that adds the opt-in `address` stage.
16
+ * {@link WORKFLOW_STEP_KEYS} that adds the opt-in `screening` and `address` stages.
16
17
  */
17
18
  const AVAILABLE_WORKFLOW_STEP_KEYS = [
18
19
  "document",
20
+ "screening",
19
21
  "address",
20
22
  "liveness",
21
23
  "face_match"
@@ -71,6 +73,19 @@ function workflowAddressConfig(config) {
71
73
  ...step.config ?? {}
72
74
  };
73
75
  }
76
+ /**
77
+ * The resolved screening config for a session's workflow, or `null` when the
78
+ * screening stage isn't enabled. Screening needs OCR fields to screen.
79
+ */
80
+ function workflowScreeningConfig(config) {
81
+ if (!config || !workflowRunsOcr(config)) return null;
82
+ const step = config.steps.find((s) => s.key === "screening" && s.enabled);
83
+ if (!step) return null;
84
+ return {
85
+ ...DEFAULT_SCREENING_CONFIG,
86
+ ...step.config ?? {}
87
+ };
88
+ }
74
89
  /** Whether OCR parsing should run: the document stage is on and `skip_ocr` is off. */
75
90
  function workflowRunsOcr(config) {
76
91
  if (!config) return true;
@@ -82,6 +97,6 @@ function workflowEnabledSteps(config) {
82
97
  return config.steps.filter((step) => step.enabled).map((step) => step.key);
83
98
  }
84
99
  //#endregion
85
- export { ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, DEFAULT_ADDRESS_CONFIG, DEFAULT_WORKFLOW_CONFIG, WORKFLOW_STEP_KEYS, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr };
100
+ export { ADDRESS_METHODS, AVAILABLE_WORKFLOW_STEP_KEYS, DEFAULT_ADDRESS_CONFIG, DEFAULT_WORKFLOW_CONFIG, WORKFLOW_STEP_KEYS, workflowAddressConfig, workflowEnabledSteps, workflowEnables, workflowRunsOcr, workflowScreeningConfig };
86
101
 
87
102
  //# sourceMappingURL=workflow.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow.mjs","names":[],"sources":["../src/workflow.ts"],"sourcesContent":["import type { Id, IsoDateTime } from './common'\n\n/**\n * Workflows (Phase 19).\n *\n * An organization-scoped, reusable recipe that determines the order of the\n * coarse verification stages, lets each be turned off, and can skip OCR parsing\n * (capture-only). Workflows are optional: a session created without one runs the\n * default pipeline (document → liveness → face match, OCR on). A workflow's\n * config is snapshotted onto each session at creation, so editing it never\n * disturbs sessions already in flight.\n */\n\n/** A coarse verification stage a workflow can order and toggle. */\nexport type WorkflowStepKey = 'document' | 'address' | 'liveness' | 'face_match'\n\n/**\n * The default pipeline's stages, in canonical order — what runs when a session\n * has no workflow. `address` is deliberately NOT here: it's an opt-in stage,\n * available only on custom workflows.\n */\nexport const WORKFLOW_STEP_KEYS: readonly WorkflowStepKey[] = ['document', 'liveness', 'face_match']\n\n/**\n * Every stage a custom workflow may include, in canonical order. Used by the\n * workflow editor and to validate/normalise stored steps — a superset of\n * {@link WORKFLOW_STEP_KEYS} that adds the opt-in `address` stage.\n */\nexport const AVAILABLE_WORKFLOW_STEP_KEYS: readonly WorkflowStepKey[] = [\n 'document',\n 'address',\n 'liveness',\n 'face_match',\n]\n\n/** A method the address stage uses to corroborate the user's address. */\nexport type AddressMethod = 'poa_document' | 'device_location' | 'geocode_lookup'\n\n/** Every selectable address-verification method, in display order. */\nexport const ADDRESS_METHODS: readonly AddressMethod[] = ['poa_document', 'device_location', 'geocode_lookup']\n\n/** What a failed/low-confidence address result does to the session. */\nexport type AddressOnFail = 'review' | 'reject'\n\n/** Configuration for the `address` stage, carried on its {@link WorkflowStep}. */\nexport interface AddressStepConfig {\n /** Methods to run; at least one when the stage is enabled. */\n methods: AddressMethod[]\n /**\n * What a failed or low-confidence result does. `review` (default) flags the\n * session for a human; `reject` fails it outright.\n */\n on_fail: AddressOnFail\n /**\n * Minimum address-verification confidence in [0, 1] to auto-verify the address.\n * A passed address scoring below this is routed to manual review (the gate is\n * never a rejection). Omitted falls back to the project `addressThreshold`.\n */\n auto_approve_threshold?: number\n}\n\n/** The default address config applied when the stage is enabled without one. */\nexport const DEFAULT_ADDRESS_CONFIG: AddressStepConfig = {\n methods: ['geocode_lookup'],\n on_fail: 'review',\n}\n\n/** One stage within a workflow, in pipeline order, on or off. */\nexport interface WorkflowStep {\n key: WorkflowStepKey\n enabled: boolean\n /** Stage-specific configuration. Only the `address` stage uses this today. */\n config?: AddressStepConfig\n}\n\n/** Workflow-wide toggles. */\nexport interface WorkflowOptions {\n /**\n * Skip OCR parsing — capture the document image but don't extract fields.\n * Useful when Arkyc is only used for data capture and the assets are handed\n * to a third party. Disables the document portrait too, so face match can't run.\n */\n skip_ocr: boolean\n}\n\n/** The portable config of a workflow: ordered stages + options. */\nexport interface WorkflowConfig {\n steps: WorkflowStep[]\n options: WorkflowOptions\n}\n\n/** A saved, organization-scoped workflow. */\nexport interface Workflow extends WorkflowConfig {\n id: Id\n organization_id: Id\n name: string\n created_at: IsoDateTime\n updated_at: IsoDateTime\n}\n\n/** The default pipeline applied when a session has no workflow. */\nexport const DEFAULT_WORKFLOW_CONFIG: WorkflowConfig = {\n steps: [\n { key: 'document', enabled: true },\n { key: 'liveness', enabled: true },\n { key: 'face_match', enabled: true },\n ],\n options: { skip_ocr: false },\n}\n\n/**\n * Whether a stage runs under a config. A `null` config means \"no workflow\" — the\n * default pipeline, where every stage runs. Within a real config, a stage that is\n * absent or `enabled: false` does not run.\n */\nexport function workflowEnables(config: WorkflowConfig | null | undefined, key: WorkflowStepKey): boolean {\n // No workflow runs the default pipeline only — opt-in stages (`address`) are\n // off unless a custom workflow turns them on.\n if (!config) return WORKFLOW_STEP_KEYS.includes(key)\n\n return config.steps.some((step) => step.key === key && step.enabled)\n}\n\n/**\n * The resolved address config for a session's workflow, or `null` when the\n * address stage isn't enabled. Missing fields fall back to {@link DEFAULT_ADDRESS_CONFIG}.\n */\nexport function workflowAddressConfig(config: WorkflowConfig | null | undefined): AddressStepConfig | null {\n if (!config) return null\n const step = config.steps.find((s) => s.key === 'address' && s.enabled)\n if (!step) return null\n\n return { ...DEFAULT_ADDRESS_CONFIG, ...(step.config ?? {}) }\n}\n\n/** Whether OCR parsing should run: the document stage is on and `skip_ocr` is off. */\nexport function workflowRunsOcr(config: WorkflowConfig | null | undefined): boolean {\n if (!config) return true\n\n return workflowEnables(config, 'document') && !config.options.skip_ocr\n}\n\n/** The enabled stages in pipeline order (used by the widget to sequence its steps). */\nexport function workflowEnabledSteps(config: WorkflowConfig | null | undefined): WorkflowStepKey[] {\n if (!config) return [...WORKFLOW_STEP_KEYS]\n\n return config.steps.filter((step) => step.enabled).map((step) => step.key)\n}\n"],"mappings":";;;;;;AAqBA,MAAa,qBAAiD;CAAC;CAAY;CAAY;AAAY;;;;;;AAOnG,MAAa,+BAA2D;CACtE;CACA;CACA;CACA;AACF;;AAMA,MAAa,kBAA4C;CAAC;CAAgB;CAAmB;AAAgB;;AAuB7G,MAAa,yBAA4C;CACvD,SAAS,CAAC,gBAAgB;CAC1B,SAAS;AACX;;AAoCA,MAAa,0BAA0C;CACrD,OAAO;EACL;GAAE,KAAK;GAAY,SAAS;EAAK;EACjC;GAAE,KAAK;GAAY,SAAS;EAAK;EACjC;GAAE,KAAK;GAAc,SAAS;EAAK;CACrC;CACA,SAAS,EAAE,UAAU,MAAM;AAC7B;;;;;;AAOA,SAAgB,gBAAgB,QAA2C,KAA+B;CAGxG,IAAI,CAAC,QAAQ,OAAO,mBAAmB,SAAS,GAAG;CAEnD,OAAO,OAAO,MAAM,MAAM,SAAS,KAAK,QAAQ,OAAO,KAAK,OAAO;AACrE;;;;;AAMA,SAAgB,sBAAsB,QAAqE;CACzG,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,EAAE,QAAQ,aAAa,EAAE,OAAO;CACtE,IAAI,CAAC,MAAM,OAAO;CAElB,OAAO;EAAE,GAAG;EAAwB,GAAI,KAAK,UAAU,CAAC;CAAG;AAC7D;;AAGA,SAAgB,gBAAgB,QAAoD;CAClF,IAAI,CAAC,QAAQ,OAAO;CAEpB,OAAO,gBAAgB,QAAQ,UAAU,KAAK,CAAC,OAAO,QAAQ;AAChE;;AAGA,SAAgB,qBAAqB,QAA8D;CACjG,IAAI,CAAC,QAAQ,OAAO,CAAC,GAAG,kBAAkB;CAE1C,OAAO,OAAO,MAAM,QAAQ,SAAS,KAAK,OAAO,CAAC,CAAC,KAAK,SAAS,KAAK,GAAG;AAC3E"}
1
+ {"version":3,"file":"workflow.mjs","names":[],"sources":["../src/workflow.ts"],"sourcesContent":["import type { Id, IsoDateTime } from './common'\nimport { DEFAULT_SCREENING_CONFIG, type RiskPolicyConfig, type ScreeningStepConfig } from './risk'\n\n/**\n * Workflows (Phase 19).\n *\n * An organization-scoped, reusable recipe that determines the order of the\n * coarse verification stages, lets each be turned off, and can skip OCR parsing\n * (capture-only). Workflows are optional: a session created without one runs the\n * default pipeline (document → liveness → face match, OCR on). A workflow's\n * config is snapshotted onto each session at creation, so editing it never\n * disturbs sessions already in flight.\n */\n\n/** A coarse verification stage a workflow can order and toggle. */\nexport type WorkflowStepKey = 'document' | 'screening' | 'address' | 'liveness' | 'face_match'\n\n/**\n * The default pipeline's stages, in canonical order — what runs when a session\n * has no workflow. `address` is deliberately NOT here: it's an opt-in stage,\n * available only on custom workflows.\n */\nexport const WORKFLOW_STEP_KEYS: readonly WorkflowStepKey[] = ['document', 'liveness', 'face_match']\n\n/**\n * Every stage a custom workflow may include, in canonical order. Used by the\n * workflow editor and to validate/normalise stored steps — a superset of\n * {@link WORKFLOW_STEP_KEYS} that adds the opt-in `screening` and `address` stages.\n */\nexport const AVAILABLE_WORKFLOW_STEP_KEYS: readonly WorkflowStepKey[] = [\n 'document',\n 'screening',\n 'address',\n 'liveness',\n 'face_match',\n]\n\n/** A method the address stage uses to corroborate the user's address. */\nexport type AddressMethod = 'poa_document' | 'device_location' | 'geocode_lookup'\n\n/** Every selectable address-verification method, in display order. */\nexport const ADDRESS_METHODS: readonly AddressMethod[] = ['poa_document', 'device_location', 'geocode_lookup']\n\n/** What a failed/low-confidence address result does to the session. */\nexport type AddressOnFail = 'review' | 'reject'\n\n/** Configuration for the `address` stage, carried on its {@link WorkflowStep}. */\nexport interface AddressStepConfig {\n /** Methods to run; at least one when the stage is enabled. */\n methods: AddressMethod[]\n /**\n * What a failed or low-confidence result does. `review` (default) flags the\n * session for a human; `reject` fails it outright.\n */\n on_fail: AddressOnFail\n /**\n * Minimum address-verification confidence in [0, 1] to auto-verify the address.\n * A passed address scoring below this is routed to manual review (the gate is\n * never a rejection). Omitted falls back to the project `addressThreshold`.\n */\n auto_approve_threshold?: number\n}\n\n/** The default address config applied when the stage is enabled without one. */\nexport const DEFAULT_ADDRESS_CONFIG: AddressStepConfig = {\n methods: ['geocode_lookup'],\n on_fail: 'review',\n}\n\n/** One stage within a workflow, in pipeline order, on or off. */\nexport interface WorkflowStep {\n key: WorkflowStepKey\n enabled: boolean\n /** Stage-specific configuration, used by the `address` and `screening` stages. */\n config?: AddressStepConfig | ScreeningStepConfig\n}\n\n/** Workflow-wide toggles. */\nexport interface WorkflowOptions {\n /**\n * Skip OCR parsing — capture the document image but don't extract fields.\n * Useful when Arkyc is only used for data capture and the assets are handed\n * to a third party. Disables the document portrait too, so face match can't run.\n */\n skip_ocr: boolean\n /** Minimum age in years, from the extracted date of birth (`UNDERAGE`). */\n min_age?: number\n /** How each risk signal affects the decision. Unlisted signals route to review. */\n risk_policy?: RiskPolicyConfig\n}\n\n/** The portable config of a workflow: ordered stages + options. */\nexport interface WorkflowConfig {\n steps: WorkflowStep[]\n options: WorkflowOptions\n}\n\n/** A saved, organization-scoped workflow. */\nexport interface Workflow extends WorkflowConfig {\n id: Id\n organization_id: Id\n name: string\n created_at: IsoDateTime\n updated_at: IsoDateTime\n}\n\n/** The default pipeline applied when a session has no workflow. */\nexport const DEFAULT_WORKFLOW_CONFIG: WorkflowConfig = {\n steps: [\n { key: 'document', enabled: true },\n { key: 'liveness', enabled: true },\n { key: 'face_match', enabled: true },\n ],\n options: { skip_ocr: false },\n}\n\n/**\n * Whether a stage runs under a config. A `null` config means \"no workflow\" — the\n * default pipeline, where every stage runs. Within a real config, a stage that is\n * absent or `enabled: false` does not run.\n */\nexport function workflowEnables(config: WorkflowConfig | null | undefined, key: WorkflowStepKey): boolean {\n // No workflow runs the default pipeline only — opt-in stages (`screening`, `address`) are\n // off unless a custom workflow turns them on.\n if (!config) return WORKFLOW_STEP_KEYS.includes(key)\n\n return config.steps.some((step) => step.key === key && step.enabled)\n}\n\n/**\n * The resolved address config for a session's workflow, or `null` when the\n * address stage isn't enabled. Missing fields fall back to {@link DEFAULT_ADDRESS_CONFIG}.\n */\nexport function workflowAddressConfig(config: WorkflowConfig | null | undefined): AddressStepConfig | null {\n if (!config) return null\n const step = config.steps.find((s) => s.key === 'address' && s.enabled)\n if (!step) return null\n\n return { ...DEFAULT_ADDRESS_CONFIG, ...((step.config as AddressStepConfig | undefined) ?? {}) }\n}\n\n/**\n * The resolved screening config for a session's workflow, or `null` when the\n * screening stage isn't enabled. Screening needs OCR fields to screen.\n */\nexport function workflowScreeningConfig(config: WorkflowConfig | null | undefined): ScreeningStepConfig | null {\n if (!config || !workflowRunsOcr(config)) return null\n const step = config.steps.find((s) => s.key === 'screening' && s.enabled)\n if (!step) return null\n\n return { ...DEFAULT_SCREENING_CONFIG, ...((step.config as ScreeningStepConfig | undefined) ?? {}) }\n}\n\n/** Whether OCR parsing should run: the document stage is on and `skip_ocr` is off. */\nexport function workflowRunsOcr(config: WorkflowConfig | null | undefined): boolean {\n if (!config) return true\n\n return workflowEnables(config, 'document') && !config.options.skip_ocr\n}\n\n/** The enabled stages in pipeline order (used by the widget to sequence its steps). */\nexport function workflowEnabledSteps(config: WorkflowConfig | null | undefined): WorkflowStepKey[] {\n if (!config) return [...WORKFLOW_STEP_KEYS]\n\n return config.steps.filter((step) => step.enabled).map((step) => step.key)\n}\n"],"mappings":";;;;;;;AAsBA,MAAa,qBAAiD;CAAC;CAAY;CAAY;AAAY;;;;;;AAOnG,MAAa,+BAA2D;CACtE;CACA;CACA;CACA;CACA;AACF;;AAMA,MAAa,kBAA4C;CAAC;CAAgB;CAAmB;AAAgB;;AAuB7G,MAAa,yBAA4C;CACvD,SAAS,CAAC,gBAAgB;CAC1B,SAAS;AACX;;AAwCA,MAAa,0BAA0C;CACrD,OAAO;EACL;GAAE,KAAK;GAAY,SAAS;EAAK;EACjC;GAAE,KAAK;GAAY,SAAS;EAAK;EACjC;GAAE,KAAK;GAAc,SAAS;EAAK;CACrC;CACA,SAAS,EAAE,UAAU,MAAM;AAC7B;;;;;;AAOA,SAAgB,gBAAgB,QAA2C,KAA+B;CAGxG,IAAI,CAAC,QAAQ,OAAO,mBAAmB,SAAS,GAAG;CAEnD,OAAO,OAAO,MAAM,MAAM,SAAS,KAAK,QAAQ,OAAO,KAAK,OAAO;AACrE;;;;;AAMA,SAAgB,sBAAsB,QAAqE;CACzG,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,EAAE,QAAQ,aAAa,EAAE,OAAO;CACtE,IAAI,CAAC,MAAM,OAAO;CAElB,OAAO;EAAE,GAAG;EAAwB,GAAK,KAAK,UAA4C,CAAC;CAAG;AAChG;;;;;AAMA,SAAgB,wBAAwB,QAAuE;CAC7G,IAAI,CAAC,UAAU,CAAC,gBAAgB,MAAM,GAAG,OAAO;CAChD,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,EAAE,QAAQ,eAAe,EAAE,OAAO;CACxE,IAAI,CAAC,MAAM,OAAO;CAElB,OAAO;EAAE,GAAG;EAA0B,GAAK,KAAK,UAA8C,CAAC;CAAG;AACpG;;AAGA,SAAgB,gBAAgB,QAAoD;CAClF,IAAI,CAAC,QAAQ,OAAO;CAEpB,OAAO,gBAAgB,QAAQ,UAAU,KAAK,CAAC,OAAO,QAAQ;AAChE;;AAGA,SAAgB,qBAAqB,QAA8D;CACjG,IAAI,CAAC,QAAQ,OAAO,CAAC,GAAG,kBAAkB;CAE1C,OAAO,OAAO,MAAM,QAAQ,SAAS,KAAK,OAAO,CAAC,CAAC,KAAK,SAAS,KAAK,GAAG;AAC3E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkyc/types",
3
- "version": "1.2.11",
3
+ "version": "2.0.0",
4
4
  "description": "Shared domain types and contracts for Arkyc",
5
5
  "license": "MIT",
6
6
  "keywords": [