@stndrds/schema 0.1.0-alpha.54 → 0.1.0-alpha.56

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.
@@ -1,6 +1,262 @@
1
1
  import { ColorId, IconName, CountryIso3, CurrencyCode, MimeType } from '@stndrds/constants';
2
+ import { JWTPayload } from 'jose';
2
3
  import { z } from 'zod';
3
4
 
5
+ /**
6
+ * OCR Adapter Interface for extracting text from documents.
7
+ *
8
+ * Implementations:
9
+ * - GoogleVisionAdapter (schema-nestjs/adapters/ocr/)
10
+ * - TesseractAdapter (schema-nestjs/adapters/ocr/)
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * class GoogleVisionAdapter implements OcrAdapter {
15
+ * readonly name = "google-vision";
16
+ * readonly supportedMimeTypes = ["image/jpeg", "image/png", "application/pdf"];
17
+ *
18
+ * async extractText(input: OcrInput): Promise<OcrResult> {
19
+ * // Call Google Cloud Vision API
20
+ * }
21
+ * }
22
+ * ```
23
+ */
24
+ interface OcrAdapter {
25
+ /** Provider name for identification */
26
+ readonly name: string;
27
+ /** MIME types this adapter can process */
28
+ readonly supportedMimeTypes: readonly string[];
29
+ /** Extract text from a document */
30
+ extractText(input: OcrInput): Promise<OcrResult>;
31
+ }
32
+ interface OcrInput {
33
+ /** File content as Buffer */
34
+ buffer: Buffer;
35
+ /** MIME type of the file */
36
+ mimeType: string;
37
+ /** Original filename */
38
+ filename: string;
39
+ /** OCR options */
40
+ options?: OcrOptions;
41
+ }
42
+ interface OcrOptions {
43
+ /** Languages to detect (ISO 639-1 codes) */
44
+ languages?: string[];
45
+ /** Enable structured data extraction (forms, tables) */
46
+ extractStructured?: boolean;
47
+ }
48
+ interface OcrResult {
49
+ /** Extracted full text */
50
+ text: string;
51
+ /** Overall confidence score (0-1) */
52
+ confidence: number;
53
+ /** Per-page results */
54
+ pages?: OcrPage[];
55
+ /** Structured data if extracted (forms, tables) */
56
+ structuredData?: Record<string, unknown>;
57
+ }
58
+ interface OcrPage {
59
+ pageNumber: number;
60
+ text: string;
61
+ confidence: number;
62
+ /** Bounding boxes for detected text blocks */
63
+ blocks?: OcrTextBlock[];
64
+ }
65
+ interface OcrTextBlock {
66
+ text: string;
67
+ confidence: number;
68
+ boundingBox: BoundingBox;
69
+ }
70
+ interface BoundingBox {
71
+ x: number;
72
+ y: number;
73
+ width: number;
74
+ height: number;
75
+ }
76
+ /**
77
+ * Signature Adapter Interface for electronic signatures.
78
+ *
79
+ * Implementations:
80
+ * - YousignAdapter (schema-nestjs/adapters/signature/)
81
+ * - DocusignAdapter (schema-nestjs/adapters/signature/)
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * class YousignAdapter implements SignatureAdapter {
86
+ * readonly name = "yousign";
87
+ *
88
+ * async createSignatureRequest(input): Promise<SignatureRequestResult> {
89
+ * // Create signature request via Yousign API
90
+ * }
91
+ * }
92
+ * ```
93
+ */
94
+ interface SignatureAdapter {
95
+ /** Provider name for identification */
96
+ readonly name: string;
97
+ /** Create a new signature request */
98
+ createSignatureRequest(input: CreateSignatureInput): Promise<SignatureRequestResult>;
99
+ /** Get current status of a signature request */
100
+ getStatus(externalId: string): Promise<SignatureStatusResult>;
101
+ /** Cancel a pending signature request */
102
+ cancel(externalId: string): Promise<void>;
103
+ /** Download the signed document */
104
+ downloadSignedDocument(externalId: string): Promise<Buffer>;
105
+ }
106
+ interface CreateSignatureInput {
107
+ /** Document content as Buffer */
108
+ documentBuffer: Buffer;
109
+ /** Document filename */
110
+ documentName: string;
111
+ /** List of signers */
112
+ signers: SignerRequest[];
113
+ /** Expiration date for the signature request */
114
+ expiresAt?: Date;
115
+ /** Webhook URL for status updates */
116
+ webhookUrl?: string;
117
+ /** Custom metadata to attach */
118
+ metadata?: Record<string, string>;
119
+ }
120
+ interface SignerRequest {
121
+ /** Signer's email address */
122
+ email: string;
123
+ /** Signer's first name */
124
+ firstName: string;
125
+ /** Signer's last name */
126
+ lastName: string;
127
+ /** Phone number for SMS verification */
128
+ phone?: string;
129
+ /** Signature position on the document */
130
+ signaturePosition?: SignaturePosition;
131
+ /** Order in which to sign (1-based) */
132
+ order?: number;
133
+ }
134
+ interface SignaturePosition {
135
+ /** Page number (1-based) */
136
+ page: number;
137
+ /** X coordinate (from left) */
138
+ x: number;
139
+ /** Y coordinate (from top) */
140
+ y: number;
141
+ /** Signature box width */
142
+ width: number;
143
+ /** Signature box height */
144
+ height: number;
145
+ }
146
+ interface SignatureRequestResult {
147
+ /** External ID from the provider */
148
+ externalId: string;
149
+ /** URL for signers to access */
150
+ signatureUrl: string;
151
+ /** Per-signer URLs if different */
152
+ signerUrls?: Record<string, string>;
153
+ /** Current status */
154
+ status: SignatureStatus;
155
+ }
156
+ interface SignatureStatusResult {
157
+ /** External ID */
158
+ externalId: string;
159
+ /** Current status */
160
+ status: SignatureStatus;
161
+ /** Per-signer status */
162
+ signers?: SignerStatus[];
163
+ /** Signed document available for download */
164
+ signedDocumentAvailable?: boolean;
165
+ /** Completion timestamp */
166
+ completedAt?: Date;
167
+ /** Reason for decline (if status is "declined") */
168
+ declineReason?: string;
169
+ }
170
+ interface SignerStatus {
171
+ email: string;
172
+ status: "pending" | "signed" | "declined";
173
+ signedAt?: Date;
174
+ }
175
+ type SignatureStatus = "pending" | "signed" | "declined" | "expired" | "cancelled";
176
+ /**
177
+ * Identity Verification Adapter Interface for KYC document verification.
178
+ *
179
+ * Implementations:
180
+ * - OnfidoAdapter (schema-nestjs/adapters/identity/)
181
+ * - VeriffAdapter (schema-nestjs/adapters/identity/)
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * class OnfidoAdapter implements IdentityVerificationAdapter {
186
+ * readonly name = "onfido";
187
+ * readonly supportedDocumentTypes = ["passport", "national_id", "driving_license"];
188
+ *
189
+ * async verify(input): Promise<VerificationResult> {
190
+ * // Verify document via Onfido API
191
+ * }
192
+ * }
193
+ * ```
194
+ */
195
+ interface IdentityVerificationAdapter {
196
+ /** Provider name for identification */
197
+ readonly name: string;
198
+ /** Supported document types */
199
+ readonly supportedDocumentTypes: readonly string[];
200
+ /** Verify an identity document */
201
+ verify(input: VerifyInput): Promise<VerificationResult>;
202
+ }
203
+ interface VerifyInput {
204
+ /** Front side of the document */
205
+ frontBuffer: Buffer;
206
+ /** Back side of the document (optional for some document types) */
207
+ backBuffer?: Buffer;
208
+ /** Document type (e.g., "passport", "national_id") */
209
+ documentType: string;
210
+ /** Country code (ISO 3166-1 alpha-3) */
211
+ countryCode?: string;
212
+ }
213
+ interface VerificationResult {
214
+ /** Overall verification passed */
215
+ verified: boolean;
216
+ /** Confidence score (0-1) */
217
+ confidence: number;
218
+ /** Extracted document data */
219
+ documentData?: DocumentData;
220
+ /** Individual verification checks */
221
+ checks: VerificationCheck[];
222
+ /** Provider-specific raw response */
223
+ rawResponse?: Record<string, unknown>;
224
+ }
225
+ interface DocumentData {
226
+ /** First name */
227
+ firstName?: string;
228
+ /** Last name */
229
+ lastName?: string;
230
+ /** Full name if not split */
231
+ fullName?: string;
232
+ /** Date of birth (ISO 8601) */
233
+ dateOfBirth?: string;
234
+ /** Document number */
235
+ documentNumber?: string;
236
+ /** Expiry date (ISO 8601) */
237
+ expiryDate?: string;
238
+ /** Issue date (ISO 8601) */
239
+ issueDate?: string;
240
+ /** Nationality (ISO 3166-1 alpha-3) */
241
+ nationality?: string;
242
+ /** Gender */
243
+ gender?: "M" | "F" | "X";
244
+ /** Address if present on document */
245
+ address?: string;
246
+ /** MRZ data if available */
247
+ mrz?: string;
248
+ }
249
+ interface VerificationCheck {
250
+ /** Check name (e.g., "document_authenticity", "face_match") */
251
+ name: string;
252
+ /** Check result */
253
+ status: "passed" | "failed" | "warning" | "not_applicable";
254
+ /** Human-readable message */
255
+ message?: string;
256
+ /** Detailed sub-checks */
257
+ details?: Record<string, unknown>;
258
+ }
259
+
4
260
  /**
5
261
  * Message role in a conversation
6
262
  */
@@ -156,6 +412,39 @@ type AIQuestionAnswer = {
156
412
  type: "multiselect";
157
413
  value: string[];
158
414
  };
415
+ /**
416
+ * Option for batch questions
417
+ */
418
+ interface AIBatchQuestionOption {
419
+ /** Value returned when selected */
420
+ value: string;
421
+ /** Display label */
422
+ label: string;
423
+ }
424
+ /**
425
+ * Question in a batch (for ask_questions tool)
426
+ */
427
+ interface AIBatchQuestion {
428
+ /** Unique question ID */
429
+ id: string;
430
+ /** Question text to display */
431
+ question: string;
432
+ /** Predefined options (if provided, displayed as buttons) */
433
+ options?: AIBatchQuestionOption[];
434
+ /** Allow custom text input in addition to options */
435
+ allowCustomAnswer?: boolean;
436
+ /** Placeholder for custom input field */
437
+ placeholder?: string;
438
+ }
439
+ /**
440
+ * Answer returned by the AgentQuestions widget
441
+ */
442
+ interface AIBatchQuestionAnswer {
443
+ /** True if user skipped all questions */
444
+ skipped: boolean;
445
+ /** Map of question ID to answer value */
446
+ answers: Record<string, string>;
447
+ }
159
448
  /**
160
449
  * Todo item status
161
450
  */
@@ -381,8 +670,46 @@ declare function generateId(): Uuid;
381
670
  * ```
382
671
  */
383
672
  declare function generatePrefixedId(prefix: string): Uuid;
673
+ /**
674
+ * Convert a string to a valid kebab-case slug.
675
+ * Removes accents, special chars, and normalizes spaces.
676
+ *
677
+ * @param input - The string to slugify
678
+ * @returns A kebab-case slug matching pattern ^[a-z][a-z0-9-]*$
679
+ *
680
+ * @example
681
+ * ```typescript
682
+ * slugify("Contrat de Vente");
683
+ * // "contrat-de-vente"
684
+ *
685
+ * slugify("Éléphant café");
686
+ * // "elephant-cafe"
687
+ *
688
+ * slugify(" Multiple Spaces ");
689
+ * // "multiple-spaces"
690
+ * ```
691
+ */
692
+ declare function slugify(input: string): string;
693
+ /**
694
+ * Generate a unique template name from a label.
695
+ * Format: {slugified-label}-{8-char-suffix}
696
+ * Matches DB constraint: ^[a-z][a-z0-9_-]*$
697
+ *
698
+ * @param label - The label to generate a name from
699
+ * @returns A unique kebab-case name
700
+ *
701
+ * @example
702
+ * ```typescript
703
+ * generateTemplateName("Contrat de Vente");
704
+ * // "contrat-de-vente-a1b2c3d4"
705
+ *
706
+ * generateTemplateName("");
707
+ * // "template-a1b2c3d4"
708
+ * ```
709
+ */
710
+ declare function generateTemplateName(label: string): string;
384
711
 
385
- type AttributeType = "text" | "textarea" | "richtext" | "number" | "checkbox" | "date" | "phone" | "currency" | "status" | "location" | "select" | "multiselect" | "file" | "user" | "relation" | "rating" | "formula" | "rollup";
712
+ type AttributeType = "text" | "textarea" | "richtext" | "number" | "checkbox" | "date" | "phone" | "currency" | "status" | "location" | "select" | "multiselect" | "file" | "user" | "relation" | "rating" | "formula" | "rollup" | "document";
386
713
  /**
387
714
  * Status group categorization
388
715
  */
@@ -748,7 +1075,57 @@ interface RollupAttribute extends Omit<BaseAttribute<never>, "defaultValue" | "r
748
1075
  */
749
1076
  targetAttributeOptions?: Option[];
750
1077
  }
751
- type Attribute = TextAttribute | TextAreaAttribute | RichtextAttribute | NumberAttribute | CheckboxAttribute | DateAttribute | PhoneAttribute | CurrencyAttribute | StatusAttribute | LocationAttribute | SelectAttribute | MultiselectAttribute | FileAttribute | UserAttribute | RelationAttribute | RatingAttribute | FormulaAttribute | RollupAttribute;
1078
+ /**
1079
+ * DocumentAttribute - References one or multiple documents with templates.
1080
+ *
1081
+ * Unlike FileAttribute which stores raw file references, DocumentAttribute
1082
+ * provides structured document handling with templates, multi-file support,
1083
+ * and automatic processing (OCR, signature, identity verification).
1084
+ *
1085
+ * @example Single document with template choice
1086
+ * ```typescript
1087
+ * document({ name: "identityDocument", label: "Pièce d'identité" })
1088
+ * .templates(["french_id_card", "passport"])
1089
+ * .autoProcess()
1090
+ * .required()
1091
+ * ```
1092
+ *
1093
+ * @example Multiple documents with fixed template
1094
+ * ```typescript
1095
+ * document({ name: "contracts", label: "Contrats" })
1096
+ * .template("signable_contract")
1097
+ * .multiple()
1098
+ * .maxDocuments(10)
1099
+ * ```
1100
+ */
1101
+ interface DocumentAttribute extends BaseAttribute<string | string[]> {
1102
+ type: "document";
1103
+ /**
1104
+ * Single template ID (strict mode).
1105
+ * If set, only documents using this template can be attached.
1106
+ */
1107
+ templateId?: string;
1108
+ /**
1109
+ * Multiple allowed template IDs.
1110
+ * User can choose which template to use when uploading.
1111
+ */
1112
+ allowedTemplates?: string[];
1113
+ /**
1114
+ * Allow multiple documents.
1115
+ * If true, value is string[] (document IDs).
1116
+ * If false/undefined, value is string (single document ID).
1117
+ */
1118
+ multiple?: boolean;
1119
+ /**
1120
+ * Maximum number of documents when multiple: true.
1121
+ */
1122
+ maxDocuments?: number;
1123
+ /**
1124
+ * Automatically trigger processing (OCR, verification) on upload.
1125
+ */
1126
+ autoProcess?: boolean;
1127
+ }
1128
+ type Attribute = TextAttribute | TextAreaAttribute | RichtextAttribute | NumberAttribute | CheckboxAttribute | DateAttribute | PhoneAttribute | CurrencyAttribute | StatusAttribute | LocationAttribute | SelectAttribute | MultiselectAttribute | FileAttribute | UserAttribute | RelationAttribute | RatingAttribute | FormulaAttribute | RollupAttribute | DocumentAttribute;
752
1129
 
753
1130
  /**
754
1131
  * Type of resource that can be audited
@@ -853,6 +1230,175 @@ interface AuditServiceOptions {
853
1230
  flushIntervalMs?: number;
854
1231
  }
855
1232
 
1233
+ /**
1234
+ * Variable mapping from template placeholder to context path
1235
+ */
1236
+ interface VariableMapping {
1237
+ /** Placeholder name in the template */
1238
+ variableName: string;
1239
+ /** Path in WorkflowExecutionContext (e.g., "slots.client.firstName") */
1240
+ contextPath: string;
1241
+ /** Display label for the UI */
1242
+ label: string;
1243
+ /** Whether this variable is required */
1244
+ required?: boolean;
1245
+ /** Fallback value if the context path resolves to null/undefined */
1246
+ fallback?: string;
1247
+ }
1248
+ /**
1249
+ * Field positioned on a PDF template
1250
+ * Coordinates are in PDF points (72 dpi)
1251
+ */
1252
+ interface PdfTemplateField {
1253
+ /** Unique field identifier */
1254
+ id: string;
1255
+ /** Page number (0-indexed) */
1256
+ page: number;
1257
+ /** X coordinate in PDF points */
1258
+ x: number;
1259
+ /** Y coordinate in PDF points */
1260
+ y: number;
1261
+ /** Field width in PDF points */
1262
+ width: number;
1263
+ /** Field height in PDF points */
1264
+ height: number;
1265
+ /** Font size in points */
1266
+ fontSize?: number;
1267
+ /** Font family name */
1268
+ fontFamily?: string;
1269
+ /** Font weight */
1270
+ fontWeight?: "normal" | "bold";
1271
+ /** Text alignment */
1272
+ align?: "left" | "center" | "right";
1273
+ /** Path in WorkflowExecutionContext (e.g., "slots.client.firstName") */
1274
+ contextPath: string;
1275
+ /** Display label for the UI */
1276
+ label: string;
1277
+ /** Fallback value if the context path resolves to null/undefined */
1278
+ fallback?: string;
1279
+ }
1280
+ /**
1281
+ * Template source - discriminated union for PDF vs DOCX modes
1282
+ */
1283
+ type TemplateSource = {
1284
+ type: "pdf";
1285
+ /** ID of the uploaded PDF file */
1286
+ fileId: string;
1287
+ /** Positioned fields on the PDF */
1288
+ fields: PdfTemplateField[];
1289
+ } | {
1290
+ type: "docx";
1291
+ /** ID of the uploaded DOCX file */
1292
+ fileId: string;
1293
+ /** Variables detected in the DOCX (e.g., {{firstName}}) */
1294
+ detectedVariables: string[];
1295
+ };
1296
+ /**
1297
+ * Document generation template
1298
+ *
1299
+ * Templates define how to generate PDF documents by injecting
1300
+ * workflow context data into a PDF template file.
1301
+ *
1302
+ * @example
1303
+ * ```typescript
1304
+ * const template: DocumentGenerationTemplate = {
1305
+ * id: "tmpl_123",
1306
+ * name: "sales-contract",
1307
+ * label: "Sales Contract",
1308
+ * source: {
1309
+ * type: "pdf",
1310
+ * fileId: "file_456",
1311
+ * fields: [
1312
+ * {
1313
+ * id: "f1",
1314
+ * page: 0,
1315
+ * x: 120, y: 340,
1316
+ * width: 150, height: 20,
1317
+ * contextPath: "slots.client.firstName",
1318
+ * label: "Client First Name"
1319
+ * }
1320
+ * ]
1321
+ * },
1322
+ * variableMappings: [],
1323
+ * createdAt: new Date(),
1324
+ * updatedAt: new Date()
1325
+ * };
1326
+ * ```
1327
+ */
1328
+ interface DocumentGenerationTemplate {
1329
+ /** Unique identifier */
1330
+ id: string;
1331
+ /** Tenant ID (optional for system templates) */
1332
+ tenantId?: string;
1333
+ /** Unique name within tenant (kebab-case) */
1334
+ name: string;
1335
+ /** Display label */
1336
+ label: string;
1337
+ /** Optional description */
1338
+ description?: string;
1339
+ /** Template source (PDF) */
1340
+ source: TemplateSource;
1341
+ /** Variable mappings (for DOCX mode, deprecated) */
1342
+ variableMappings: VariableMapping[];
1343
+ /** Creation timestamp */
1344
+ createdAt: Date;
1345
+ /** Last update timestamp */
1346
+ updatedAt: Date;
1347
+ }
1348
+ /**
1349
+ * Input for creating a document generation template
1350
+ */
1351
+ interface CreateDocumentGenerationTemplate {
1352
+ name: string;
1353
+ label: string;
1354
+ description?: string;
1355
+ source: TemplateSource;
1356
+ variableMappings?: VariableMapping[];
1357
+ }
1358
+ /**
1359
+ * Input for updating a document generation template
1360
+ */
1361
+ interface UpdateDocumentGenerationTemplate {
1362
+ label?: string;
1363
+ description?: string;
1364
+ source?: TemplateSource;
1365
+ variableMappings?: VariableMapping[];
1366
+ }
1367
+ /**
1368
+ * Pending document generation request in execution context.
1369
+ * The consumer (NestJS, Supabase) is responsible for fulfilling this request.
1370
+ */
1371
+ interface PendingDocumentRequest {
1372
+ /** Unique request identifier (same as node ID) */
1373
+ id: string;
1374
+ /** Template ID to use for generation */
1375
+ templateId: string;
1376
+ /** Custom filename (supports variable interpolation) */
1377
+ filename?: string;
1378
+ /** Slot IDs of records to attach the generated document to */
1379
+ targetSlotIds?: string[];
1380
+ /** Request status */
1381
+ status: "pending" | "processing" | "completed" | "failed";
1382
+ /** Error message if failed */
1383
+ error?: string;
1384
+ /** Generated document URL (when completed) */
1385
+ url?: string;
1386
+ /** File size in bytes (when completed) */
1387
+ size?: number;
1388
+ }
1389
+ /**
1390
+ * Check if a template source is PDF type
1391
+ */
1392
+ declare function isPdfTemplateSource(source: TemplateSource): source is Extract<TemplateSource, {
1393
+ type: "pdf";
1394
+ }>;
1395
+ /**
1396
+ * Check if a template source is DOCX type
1397
+ */
1398
+ declare function isDocxTemplateSource(source: TemplateSource): source is Extract<TemplateSource, {
1399
+ type: "docx";
1400
+ }>;
1401
+
856
1402
  /**
857
1403
  * Timestamps for tracking creation and updates
858
1404
  */
@@ -1022,52 +1568,339 @@ declare const RESERVED_ATTRIBUTE_NAMES: readonly ["id", "createdAt", "updatedAt"
1022
1568
  type ReservedAttributeName = (typeof RESERVED_ATTRIBUTE_NAMES)[number];
1023
1569
 
1024
1570
  /**
1025
- * Storage provider type
1571
+ * DocumentTemplate defines the structure and processing rules for a document type.
1572
+ *
1573
+ * Templates can be:
1574
+ * - System templates: Defined in code, available to all tenants (tenantId: null)
1575
+ * - Custom templates: Created by tenants for their specific needs
1576
+ *
1577
+ * @example
1578
+ * ```typescript
1579
+ * const FRENCH_ID_CARD: DocumentTemplate = {
1580
+ * name: "french_id_card",
1581
+ * label: "Carte d'identité française",
1582
+ * system: true,
1583
+ * slots: [
1584
+ * { name: "front", label: "Recto", required: true, order: 1 },
1585
+ * { name: "back", label: "Verso", required: true, order: 2 },
1586
+ * ],
1587
+ * autoProcessing: {
1588
+ * ocr: { enabled: true },
1589
+ * identityVerification: { enabled: true, documentType: "national_id" },
1590
+ * },
1591
+ * };
1592
+ * ```
1026
1593
  */
1027
- type StorageProvider = "s3" | "gcs" | "azure" | "local" | "cloudflare-r2" | string;
1594
+ interface DocumentTemplate extends Timestamps {
1595
+ id: Uuid;
1596
+ /** null = system template available to all tenants */
1597
+ tenantId?: Uuid | null;
1598
+ /** Technical name (kebab-case, unique per tenant) */
1599
+ name: string;
1600
+ /** Display name */
1601
+ label: string;
1602
+ description?: string;
1603
+ icon?: IconName;
1604
+ /** Slot definitions for multi-file documents */
1605
+ slots: DocumentSlotDefinition[];
1606
+ /** Allow uploading additional files beyond defined slots */
1607
+ allowAdditionalFiles: boolean;
1608
+ /** Auto-processing configuration */
1609
+ autoProcessing?: DocumentAutoProcessing;
1610
+ /** Mapping for extracting data to record attributes */
1611
+ extractionMapping?: ExtractionMapping;
1612
+ /** System templates are defined in code and cannot be modified */
1613
+ system: boolean;
1614
+ }
1028
1615
  /**
1029
- * File visibility level
1616
+ * Defines a file slot within a document template.
1617
+ *
1618
+ * @example ID card with front/back
1619
+ * ```typescript
1620
+ * slots: [
1621
+ * { name: "front", label: "Recto", required: true, order: 1 },
1622
+ * { name: "back", label: "Verso", required: true, order: 2 },
1623
+ * ]
1624
+ * ```
1030
1625
  */
1031
- type FileVisibility = "public" | "private" | "restricted";
1626
+ interface DocumentSlotDefinition {
1627
+ /** Technical name (e.g., "front", "back", "main") */
1628
+ name: string;
1629
+ /** Display label */
1630
+ label: string;
1631
+ description?: string;
1632
+ /** Whether this slot must be filled */
1633
+ required: boolean;
1634
+ /** Allowed MIME types (e.g., ["image/jpeg", "application/pdf"]) */
1635
+ allowedMimeTypes?: MimeType[];
1636
+ /** Max file size in bytes */
1637
+ maxSize?: number;
1638
+ /** Display order */
1639
+ order: number;
1640
+ }
1032
1641
  /**
1033
- * File - Represents uploaded file metadata and storage info
1642
+ * Auto-processing configuration for document templates.
1643
+ * Defines which processing jobs to run automatically on upload.
1644
+ */
1645
+ interface DocumentAutoProcessing {
1646
+ ocr?: {
1647
+ enabled: boolean;
1648
+ provider?: string;
1649
+ languages?: string[];
1650
+ };
1651
+ identityVerification?: {
1652
+ enabled: boolean;
1653
+ provider?: string;
1654
+ documentType?: string;
1655
+ };
1656
+ signature?: {
1657
+ enabled: boolean;
1658
+ provider?: string;
1659
+ };
1660
+ }
1661
+ /**
1662
+ * Mapping configuration for extracting OCR data to record attributes.
1663
+ */
1664
+ interface ExtractionMapping {
1665
+ fields: ExtractionField[];
1666
+ }
1667
+ interface ExtractionField {
1668
+ /** Source field path in OCR result */
1669
+ source: string;
1670
+ /** Target attribute name on the record */
1671
+ target: string;
1672
+ /** Optional transformation function name */
1673
+ transform?: string;
1674
+ }
1675
+ /**
1676
+ * Document wraps one or more files with metadata, status, and processing results.
1034
1677
  *
1035
- * ARCHITECTURE:
1036
- * - Fixed table (no custom attributes)
1037
- * - Manages file storage, permissions, and metadata
1038
- * - uploadedBy links to user_profiles table
1039
- * - Supports soft delete via deletedAt
1678
+ * Documents are linked to records via the record's `values` (document attribute).
1679
+ * Each document references a template that defines its structure.
1040
1680
  *
1041
1681
  * @example
1042
1682
  * ```typescript
1043
- * const file: File = {
1044
- * id: "file-123",
1683
+ * const document: Document = {
1684
+ * id: "doc-123",
1045
1685
  * tenantId: "tenant-456",
1046
- * name: "contract-2025.pdf",
1047
- * originalName: "Contract Acme Corp 2025.pdf",
1048
- * mimeType: "application/pdf",
1049
- * size: 2458624,
1050
- * storageProvider: "s3",
1051
- * storagePath: "tenants/456/files/2025/11/contract-2025.pdf",
1052
- * storageBucket: "my-app-files",
1053
- * url: "https://cdn.example.com/files/file-123",
1054
- * uploadedBy: "profile-789",
1055
- * folderPath: "/contracts/2025",
1056
- * tags: ["contract", "legal"],
1057
- * visibility: "restricted",
1058
- * allowedUsers: ["profile-789", "profile-456"],
1059
- * createdAt: new Date(),
1060
- * updatedAt: new Date(),
1686
+ * templateId: "tpl-french-id",
1687
+ * status: "completed",
1688
+ * title: "CNI - Jean Dupont",
1689
+ * tags: ["identity", "verified"],
1061
1690
  * };
1062
1691
  * ```
1063
1692
  */
1064
- interface File extends Timestamps {
1693
+ interface Document extends Timestamps {
1065
1694
  id: Uuid;
1066
1695
  tenantId: Uuid;
1067
- /**
1068
- * File name (sanitized for storage)
1069
- */
1070
- name: string;
1696
+ templateId: Uuid;
1697
+ /** Current processing/lifecycle status */
1698
+ status: DocumentStatus;
1699
+ /** Display title */
1700
+ title: string;
1701
+ description?: string;
1702
+ /** Tags for categorization and search */
1703
+ tags: string[];
1704
+ /** Hash of all slot file contents for deduplication */
1705
+ contentHash?: string;
1706
+ /** PostgreSQL tsvector for full-text search */
1707
+ searchVector?: unknown;
1708
+ /** User who created this document */
1709
+ createdBy?: Uuid;
1710
+ /** User who last updated this document */
1711
+ updatedBy?: Uuid;
1712
+ /** Soft delete timestamp */
1713
+ deletedAt?: Date | null;
1714
+ }
1715
+ /**
1716
+ * Document lifecycle status.
1717
+ *
1718
+ * - `draft`: Missing required slots, incomplete
1719
+ * - `pending`: All slots uploaded, awaiting processing
1720
+ * - `processing`: One or more jobs running
1721
+ * - `completed`: All jobs completed successfully
1722
+ * - `failed`: At least one job failed
1723
+ * - `signed`: Signature workflow completed
1724
+ */
1725
+ type DocumentStatus = "draft" | "pending" | "processing" | "completed" | "failed" | "signed";
1726
+ /**
1727
+ * DocumentSlot represents a single file within a document.
1728
+ *
1729
+ * Each slot corresponds to a slot definition in the template,
1730
+ * or is marked as "additional" for extra files.
1731
+ */
1732
+ interface DocumentSlot extends Timestamps {
1733
+ id: Uuid;
1734
+ documentId: Uuid;
1735
+ /** Slot name from template definition */
1736
+ slotName: string;
1737
+ /** True if this is an additional file beyond template slots */
1738
+ isAdditional: boolean;
1739
+ /** Reference to the uploaded file */
1740
+ fileId: Uuid;
1741
+ /** Processing status for this slot */
1742
+ status: SlotStatus;
1743
+ /** Extracted text from OCR */
1744
+ ocrText?: string;
1745
+ /** OCR confidence score (0-1) */
1746
+ ocrConfidence?: number;
1747
+ }
1748
+ /**
1749
+ * Slot processing status.
1750
+ */
1751
+ type SlotStatus = "uploaded" | "processing" | "completed" | "failed";
1752
+ /**
1753
+ * ProcessingJob tracks an async processing task for a document.
1754
+ *
1755
+ * Jobs are created for OCR, identity verification, or signature requests.
1756
+ * They can be document-level or slot-level.
1757
+ */
1758
+ interface ProcessingJob extends Timestamps {
1759
+ id: Uuid;
1760
+ tenantId: Uuid;
1761
+ documentId: Uuid;
1762
+ /** Slot name if job is slot-specific, null for document-level jobs */
1763
+ slotName?: string | null;
1764
+ /** Job type */
1765
+ type: ProcessingJobType;
1766
+ /** Provider used (e.g., "google-vision", "yousign") */
1767
+ provider: string;
1768
+ /** Current job status */
1769
+ status: ProcessingJobStatus;
1770
+ /** Provider-specific input data */
1771
+ input?: Record<string, unknown>;
1772
+ /** Provider response data */
1773
+ result?: Record<string, unknown>;
1774
+ /** Error message if failed */
1775
+ error?: string;
1776
+ /** When processing started */
1777
+ startedAt?: Date | null;
1778
+ /** When processing completed */
1779
+ completedAt?: Date | null;
1780
+ /** Expiration time (for signature requests) */
1781
+ expiresAt?: Date | null;
1782
+ /** User who initiated the job */
1783
+ createdBy?: Uuid;
1784
+ }
1785
+ type ProcessingJobType = "ocr" | "identity_verification" | "signature";
1786
+ type ProcessingJobStatus = "pending" | "processing" | "completed" | "failed" | "cancelled";
1787
+ interface CreateDocument {
1788
+ templateId: Uuid;
1789
+ title: string;
1790
+ description?: string;
1791
+ tags?: string[];
1792
+ }
1793
+ interface UpdateDocument {
1794
+ title?: string;
1795
+ description?: string;
1796
+ tags?: string[];
1797
+ status?: DocumentStatus;
1798
+ }
1799
+ interface CreateDocumentTemplate {
1800
+ name: string;
1801
+ label: string;
1802
+ description?: string;
1803
+ icon?: IconName;
1804
+ slots: DocumentSlotDefinition[];
1805
+ allowAdditionalFiles?: boolean;
1806
+ autoProcessing?: DocumentAutoProcessing;
1807
+ extractionMapping?: ExtractionMapping;
1808
+ }
1809
+ interface UpdateDocumentTemplate {
1810
+ label?: string;
1811
+ description?: string;
1812
+ icon?: IconName;
1813
+ slots?: DocumentSlotDefinition[];
1814
+ allowAdditionalFiles?: boolean;
1815
+ autoProcessing?: DocumentAutoProcessing;
1816
+ extractionMapping?: ExtractionMapping;
1817
+ }
1818
+ interface CreateDocumentSlot {
1819
+ documentId: Uuid;
1820
+ slotName: string;
1821
+ fileId: Uuid;
1822
+ isAdditional?: boolean;
1823
+ }
1824
+ interface UpdateDocumentSlot {
1825
+ status?: SlotStatus;
1826
+ ocrText?: string;
1827
+ ocrConfidence?: number;
1828
+ }
1829
+ interface CreateProcessingJob {
1830
+ documentId: Uuid;
1831
+ slotName?: string;
1832
+ type: ProcessingJobType;
1833
+ provider: string;
1834
+ input?: Record<string, unknown>;
1835
+ expiresAt?: Date;
1836
+ }
1837
+ interface UpdateProcessingJob {
1838
+ status?: ProcessingJobStatus;
1839
+ result?: Record<string, unknown>;
1840
+ error?: string;
1841
+ startedAt?: Date;
1842
+ completedAt?: Date;
1843
+ }
1844
+ interface DocumentListOptions {
1845
+ limit?: number;
1846
+ offset?: number;
1847
+ templateId?: Uuid;
1848
+ status?: DocumentStatus;
1849
+ tags?: string[];
1850
+ }
1851
+ interface DocumentTemplateListOptions {
1852
+ systemOnly?: boolean;
1853
+ limit?: number;
1854
+ offset?: number;
1855
+ }
1856
+
1857
+ /**
1858
+ * Storage provider type
1859
+ */
1860
+ type StorageProvider = "s3" | "gcs" | "azure" | "local" | "cloudflare-r2" | string;
1861
+ /**
1862
+ * File visibility level
1863
+ */
1864
+ type FileVisibility = "public" | "private" | "restricted";
1865
+ /**
1866
+ * File - Represents uploaded file metadata and storage info
1867
+ *
1868
+ * ARCHITECTURE:
1869
+ * - Fixed table (no custom attributes)
1870
+ * - Manages file storage, permissions, and metadata
1871
+ * - uploadedBy links to user_profiles table
1872
+ * - Supports soft delete via deletedAt
1873
+ *
1874
+ * @example
1875
+ * ```typescript
1876
+ * const file: File = {
1877
+ * id: "file-123",
1878
+ * tenantId: "tenant-456",
1879
+ * name: "contract-2025.pdf",
1880
+ * originalName: "Contract Acme Corp 2025.pdf",
1881
+ * mimeType: "application/pdf",
1882
+ * size: 2458624,
1883
+ * storageProvider: "s3",
1884
+ * storagePath: "tenants/456/files/2025/11/contract-2025.pdf",
1885
+ * storageBucket: "my-app-files",
1886
+ * url: "https://cdn.example.com/files/file-123",
1887
+ * uploadedBy: "profile-789",
1888
+ * folderPath: "/contracts/2025",
1889
+ * tags: ["contract", "legal"],
1890
+ * visibility: "restricted",
1891
+ * allowedUsers: ["profile-789", "profile-456"],
1892
+ * createdAt: new Date(),
1893
+ * updatedAt: new Date(),
1894
+ * };
1895
+ * ```
1896
+ */
1897
+ interface File extends Timestamps {
1898
+ id: Uuid;
1899
+ tenantId: Uuid;
1900
+ /**
1901
+ * File name (sanitized for storage)
1902
+ */
1903
+ name: string;
1071
1904
  /**
1072
1905
  * Original file name (as uploaded by user)
1073
1906
  */
@@ -1576,6 +2409,8 @@ type AttributeValueMap = {
1576
2409
  user: string;
1577
2410
  relation: string;
1578
2411
  rating: number;
2412
+ /** Document ID(s) - string if single, string[] if multiple */
2413
+ document: string | string[];
1579
2414
  };
1580
2415
  /**
1581
2416
  * Infer status value from options (union of option values)
@@ -2094,7 +2929,7 @@ interface AssignRoleInput {
2094
2929
  * Document generated during workflow execution
2095
2930
  */
2096
2931
  interface GeneratedDocument {
2097
- /** Document ID */
2932
+ /** Document ID (file ID) */
2098
2933
  id: string;
2099
2934
  /** URL to access the document */
2100
2935
  url: string;
@@ -2106,6 +2941,8 @@ interface GeneratedDocument {
2106
2941
  size?: number;
2107
2942
  /** Additional metadata */
2108
2943
  metadata?: Record<string, unknown>;
2944
+ /** IDs of Document records created (one per target slot) */
2945
+ attachedDocumentIds?: string[];
2109
2946
  }
2110
2947
  /**
2111
2948
  * Accumulated context during workflow execution.
@@ -2453,6 +3290,44 @@ interface ConditionNode extends BaseNode {
2453
3290
  /** ID of node to execute if condition is false (optional for drafts) */
2454
3291
  onFalse?: string | null;
2455
3292
  }
3293
+ /**
3294
+ * Document generation node.
3295
+ * Generates a PDF document by injecting workflow data into a template.
3296
+ *
3297
+ * The actual generation is delegated to the consumer (NestJS, Supabase).
3298
+ * The executor creates a pending document request in the context.
3299
+ *
3300
+ * @example
3301
+ * ```typescript
3302
+ * const node: DocumentNode = {
3303
+ * type: "document",
3304
+ * id: "generate-contract",
3305
+ * label: "Generate Contract",
3306
+ * templateId: "tmpl_sales-contract",
3307
+ * outputFormat: "pdf",
3308
+ * filename: "contract_{{slots.client.lastName}}.pdf",
3309
+ * targetSlotIds: ["client", "vendor"],
3310
+ * next: "send-email"
3311
+ * };
3312
+ * ```
3313
+ */
3314
+ interface DocumentNode extends BaseNode {
3315
+ type: "document";
3316
+ /** Display label for the node */
3317
+ label: string;
3318
+ /** Optional description */
3319
+ description?: string;
3320
+ /** ID of the DocumentGenerationTemplate to use */
3321
+ templateId: string;
3322
+ /** Output format for generated document */
3323
+ outputFormat: "pdf" | "docx";
3324
+ /** Custom filename (supports variable interpolation like {{slots.client.lastName}}) */
3325
+ filename?: string;
3326
+ /** ID of the next node to execute */
3327
+ next?: string | null;
3328
+ /** Slot IDs of records to attach the generated document to */
3329
+ targetSlotIds?: string[];
3330
+ }
2456
3331
  /**
2457
3332
  * Terminal node marking the end of a workflow path.
2458
3333
  * A workflow can have multiple EndNodes for different outcomes.
@@ -2488,7 +3363,7 @@ interface EndNode extends BaseNode {
2488
3363
  * Union of all workflow node types.
2489
3364
  * Use discriminated union on `type` field for type narrowing.
2490
3365
  */
2491
- type WorkflowNode = StartNode | FormNode | ConditionNode | EndNode;
3366
+ type WorkflowNode = StartNode | FormNode | ConditionNode | DocumentNode | EndNode;
2492
3367
  /**
2493
3368
  * All possible node types
2494
3369
  */
@@ -2505,6 +3380,10 @@ declare function isFormNode(node: WorkflowNode): node is FormNode;
2505
3380
  * Check if a node is a ConditionNode
2506
3381
  */
2507
3382
  declare function isConditionNode(node: WorkflowNode): node is ConditionNode;
3383
+ /**
3384
+ * Check if a node is a DocumentNode
3385
+ */
3386
+ declare function isDocumentNode(node: WorkflowNode): node is DocumentNode;
2508
3387
  /**
2509
3388
  * Check if a node is an EndNode
2510
3389
  */
@@ -2667,70 +3546,6 @@ interface WorkflowLayout {
2667
3546
  /** Canvas viewport state */
2668
3547
  viewport?: CanvasViewport;
2669
3548
  }
2670
- /**
2671
- * Authentication method for external participants
2672
- */
2673
- type AuthMethod = "signed_link" | "pin_code";
2674
- /**
2675
- * Channel for sending authentication credentials
2676
- */
2677
- type AuthChannel = "email" | "sms";
2678
- /**
2679
- * Default authentication configuration for a participant
2680
- */
2681
- interface ParticipantAuthConfig {
2682
- /** Authentication method */
2683
- method: AuthMethod;
2684
- /** Link/code expiration (e.g., "7d", "24h") */
2685
- expiresIn?: string;
2686
- /** Channel for sending credentials */
2687
- channel?: AuthChannel;
2688
- }
2689
- /**
2690
- * Template for a participant in the workflow.
2691
- * Defines who can participate and how they authenticate.
2692
- *
2693
- * Note: This is a template defined in WorkflowDefinition.
2694
- * At runtime, WorkflowParticipation instances are created from this.
2695
- *
2696
- * @example
2697
- * ```typescript
2698
- * const externalClient: ParticipantTemplate = {
2699
- * id: "external-client",
2700
- * label: "Client Externe",
2701
- * type: "external",
2702
- * emailSource: "slots.client.email",
2703
- * defaultAuth: {
2704
- * method: "signed_link",
2705
- * expiresIn: "7d",
2706
- * channel: "email"
2707
- * },
2708
- * allowedNodeIds: ["client-form", "signature-step"]
2709
- * };
2710
- * ```
2711
- */
2712
- interface ParticipantTemplate {
2713
- /** Unique identifier */
2714
- id: string;
2715
- /** Display label */
2716
- label: string;
2717
- /** Type of participant */
2718
- type: "internal" | "external";
2719
- /**
2720
- * Path to email in execution context (for external participants).
2721
- * Supports dot notation: "slots.client.email"
2722
- */
2723
- emailSource?: string;
2724
- /**
2725
- * Path to phone in execution context (for SMS auth).
2726
- * Supports dot notation: "slots.client.phone"
2727
- */
2728
- phoneSource?: string;
2729
- /** Default authentication configuration */
2730
- defaultAuth: ParticipantAuthConfig;
2731
- /** IDs of nodes this participant can execute */
2732
- allowedNodeIds: string[];
2733
- }
2734
3549
  /**
2735
3550
  * Global configuration options for a workflow
2736
3551
  */
@@ -2765,8 +3580,7 @@ type WorkflowStatus = "draft" | "published" | "archived";
2765
3580
  * "form-1": { type: "form", id: "form-1", label: "Info", slotId: "client", fields: ["name"], next: "end" },
2766
3581
  * "end": { type: "end", id: "end" }
2767
3582
  * },
2768
- * startNodeId: "start",
2769
- * layout: { positions: { "start": { x: 0, y: 0 }, "form-1": { x: 200, y: 0 }, "end": { x: 400, y: 0 } } }
3583
+ * startNodeId: "start"
2770
3584
  * };
2771
3585
  * ```
2772
3586
  */
@@ -2791,10 +3605,8 @@ interface WorkflowDefinition {
2791
3605
  nodes: Record<string, WorkflowNode>;
2792
3606
  /** ID of the start node */
2793
3607
  startNodeId: string;
2794
- /** Layout information for the visual builder */
2795
- layout: WorkflowLayout;
2796
- /** Participant templates (for external users) */
2797
- participants?: ParticipantTemplate[];
3608
+ /** Layout information for the visual builder (optional, used by legacy canvas) */
3609
+ layout?: WorkflowLayout;
2798
3610
  /** Theming for external-facing interface */
2799
3611
  theme?: WorkflowTheme;
2800
3612
  /** Global configuration options */
@@ -3005,7 +3817,7 @@ interface Group {
3005
3817
  collapsed?: boolean;
3006
3818
  order?: number;
3007
3819
  }
3008
- type TabType = "form" | "table" | "custom" | "activity" | "notes" | "flows";
3820
+ type TabType = "form" | "table" | "custom" | "activity" | "notes" | "flows" | "documents";
3009
3821
  /**
3010
3822
  * Base properties shared by all tab types
3011
3823
  */
@@ -3160,10 +3972,45 @@ interface FlowsTab extends BaseTab {
3160
3972
  /** Columns to display in the instances table */
3161
3973
  columns?: ("workflow" | "status" | "startedBy" | "createdAt" | "updatedAt")[];
3162
3974
  }
3975
+ /**
3976
+ * Documents tab - displays all documents attached to the record
3977
+ *
3978
+ * Shows documents from:
3979
+ * - Document attributes defined on the object
3980
+ * - System `attachments` attribute (free-form documents)
3981
+ *
3982
+ * Allows uploading new documents either to a specific attribute or as attachments.
3983
+ *
3984
+ * @example
3985
+ * ```typescript
3986
+ * {
3987
+ * type: "documents",
3988
+ * id: "documents",
3989
+ * name: "documents",
3990
+ * label: "Documents",
3991
+ * allowUpload: true,
3992
+ * allowRemove: true,
3993
+ * showProcessing: true
3994
+ * }
3995
+ * ```
3996
+ */
3997
+ interface DocumentsTab extends BaseTab {
3998
+ type: "documents";
3999
+ /** Allow uploading new documents (default: true) */
4000
+ allowUpload?: boolean;
4001
+ /** Allow removing documents (default: true) */
4002
+ allowRemove?: boolean;
4003
+ /** Show processing actions (OCR, verify, sign) (default: true) */
4004
+ showProcessing?: boolean;
4005
+ /** Highlight empty required document attributes (default: true) */
4006
+ showRequiredWarnings?: boolean;
4007
+ /** Hide system attachments section (default: false) */
4008
+ hideAttachments?: boolean;
4009
+ }
3163
4010
  /**
3164
4011
  * Union of all tab types
3165
4012
  */
3166
- type Tab = FormTab | TableTab | CustomTab | ActivityTab | NotesTab | FlowsTab;
4013
+ type Tab = FormTab | TableTab | CustomTab | ActivityTab | NotesTab | FlowsTab | DocumentsTab;
3167
4014
  /**
3168
4015
  * View layout mode
3169
4016
  * - `page`: Full view with multiple tabs (form, table, activity, notes, custom)
@@ -3249,125 +4096,173 @@ declare function isNotesTab(tab: Tab): tab is NotesTab;
3249
4096
  * Check if a tab is a flows tab
3250
4097
  */
3251
4098
  declare function isFlowsTab(tab: Tab): tab is FlowsTab;
4099
+ /**
4100
+ * Check if a tab is a documents tab
4101
+ */
4102
+ declare function isDocumentsTab(tab: Tab): tab is DocumentsTab;
3252
4103
 
3253
4104
  /**
3254
- * Status of a workflow participation
4105
+ * Status of a workflow invitation
3255
4106
  */
3256
- type ParticipationStatus = "pending" | "active" | "completed" | "expired" | "revoked";
4107
+ type InvitationStatus = "pending" | "accepted" | "expired" | "revoked";
3257
4108
  /**
3258
- * Signed link authentication (JWT-based)
4109
+ * Represents an invitation to access a workflow instance.
4110
+ *
4111
+ * When an admin wants to share a workflow with an external user,
4112
+ * they create an invitation. The invitation generates a magic link
4113
+ * that the user clicks to get an access grant.
4114
+ *
4115
+ * @example
4116
+ * ```typescript
4117
+ * const invitation: WorkflowInvitation = {
4118
+ * id: "inv_123",
4119
+ * instanceId: "inst_456",
4120
+ * recipientEmail: "client@example.com",
4121
+ * recipientName: "John Doe",
4122
+ * status: "pending",
4123
+ * createdBy: "user_789",
4124
+ * createdAt: new Date(),
4125
+ * expiresAt: new Date("2024-02-15")
4126
+ * };
4127
+ * ```
3259
4128
  */
3260
- interface SignedLinkAuth {
3261
- type: "signed_link";
3262
- /** JWT token for authentication */
3263
- token: string;
3264
- /** Token expiration date */
4129
+ interface WorkflowInvitation {
4130
+ /** Unique invitation ID */
4131
+ id: Uuid;
4132
+ /** ID of the workflow instance */
4133
+ instanceId: Uuid;
4134
+ /** Recipient's email */
4135
+ recipientEmail: string;
4136
+ /** Recipient's display name */
4137
+ recipientName?: string;
4138
+ /** Current invitation status */
4139
+ status: InvitationStatus;
4140
+ /** ID of the user who created the invitation */
4141
+ createdBy: string;
4142
+ /** When the invitation was created */
4143
+ createdAt: Date;
4144
+ /** When the invitation was accepted */
4145
+ acceptedAt?: Date;
4146
+ /** When the invitation expires */
3265
4147
  expiresAt: Date;
3266
- /** Whether the link has been used */
3267
- used: boolean;
3268
- /** IP address that used the link (for audit) */
3269
- usedFromIp?: string;
3270
4148
  }
3271
4149
  /**
3272
- * PIN code authentication
4150
+ * Input for creating a workflow invitation
3273
4151
  */
3274
- interface PinCodeAuth {
3275
- type: "pin_code";
3276
- /** Hashed PIN code */
3277
- codeHash: string;
3278
- /** Code expiration date */
3279
- expiresAt: Date;
3280
- /** Number of failed attempts */
3281
- attempts: number;
3282
- /** Max allowed attempts before lockout */
3283
- maxAttempts: number;
3284
- /** Whether currently locked out */
3285
- lockedOut: boolean;
3286
- /** When lockout expires */
3287
- lockedUntil?: Date;
4152
+ interface CreateInvitationInput {
4153
+ /** Workflow instance ID */
4154
+ instanceId: string;
4155
+ /** Recipient email */
4156
+ recipientEmail: string;
4157
+ /** Recipient name (optional) */
4158
+ recipientName?: string;
4159
+ /** Expiration in days (default: 7) */
4160
+ expiresInDays?: number;
4161
+ /** Whether to send notification email */
4162
+ sendEmail?: boolean;
4163
+ }
4164
+ /**
4165
+ * Result of creating a workflow invitation
4166
+ */
4167
+ interface CreateInvitationResult {
4168
+ /** The created invitation */
4169
+ invitation: WorkflowInvitation;
4170
+ /** Full magic link URL to access the workflow */
4171
+ magicLink: string;
3288
4172
  }
3289
4173
  /**
3290
- * Union of all authentication types
4174
+ * Check if invitation is still valid (not expired, not revoked)
4175
+ */
4176
+ declare function isInvitationValid(invitation: WorkflowInvitation): boolean;
4177
+ /**
4178
+ * Check if invitation has been accepted
3291
4179
  */
3292
- type ParticipationAuth = SignedLinkAuth | PinCodeAuth;
4180
+ declare function isInvitationAccepted(invitation: WorkflowInvitation): boolean;
3293
4181
  /**
3294
- * Represents an external or internal user's participation in a workflow instance.
4182
+ * Check if invitation has expired
4183
+ */
4184
+ declare function isInvitationExpired(invitation: WorkflowInvitation): boolean;
4185
+
4186
+ /**
4187
+ * Represents an access grant to a workflow instance.
4188
+ *
4189
+ * A grant is created after a user successfully authenticates via magic link.
4190
+ * It allows them to access the workflow forms with JWT access tokens.
3295
4191
  *
3296
- * Created at runtime from ParticipantTemplate when the workflow reaches
3297
- * a node that requires participation.
4192
+ * The grant can be revoked entirely (revokedAt) or individual tokens
4193
+ * can be revoked via the revokedTokenJtis array.
3298
4194
  *
3299
4195
  * @example
3300
4196
  * ```typescript
3301
- * const participation: WorkflowParticipation = {
3302
- * id: "part_123",
3303
- * instanceId: "inst_456",
3304
- * participantTemplateId: "external-client",
3305
- * type: "external",
3306
- * email: "client@example.com",
3307
- * name: "John Doe",
3308
- * auth: {
3309
- * type: "signed_link",
3310
- * token: "eyJ...",
3311
- * expiresAt: new Date("2024-01-15"),
3312
- * used: false
3313
- * },
3314
- * allowedNodeIds: ["client-form", "signature-step"],
3315
- * status: "pending",
4197
+ * const grant: WorkflowAccessGrant = {
4198
+ * id: "grant_123",
4199
+ * invitationId: "inv_456",
4200
+ * instanceId: "inst_789",
4201
+ * grantedTo: "client@example.com",
4202
+ * scope: ["*"],
4203
+ * revokedTokenJtis: [],
4204
+ * validUntil: new Date("2024-03-15"),
3316
4205
  * createdAt: new Date()
3317
4206
  * };
3318
4207
  * ```
3319
4208
  */
3320
- interface WorkflowParticipation {
3321
- /** Unique participation ID */
4209
+ interface WorkflowAccessGrant {
4210
+ /** Unique grant ID */
3322
4211
  id: Uuid;
4212
+ /** ID of the invitation that created this grant */
4213
+ invitationId: Uuid;
3323
4214
  /** ID of the workflow instance */
3324
4215
  instanceId: Uuid;
3325
- /** ID of the participant template this was created from */
3326
- participantTemplateId: string;
3327
- /** Type of participant */
3328
- type: "internal" | "external";
3329
- /** Participant's email */
3330
- email: string;
3331
- /** Participant's display name */
3332
- name?: string;
3333
- /** Participant's phone (for SMS auth) */
3334
- phone?: string;
3335
- /** Authentication credentials */
3336
- auth: ParticipationAuth;
3337
- /** IDs of nodes this participant can execute */
3338
- allowedNodeIds: string[];
3339
- /** Current participation status */
3340
- status: ParticipationStatus;
3341
- /** When the participant authenticated */
3342
- authenticatedAt?: Date;
3343
- /** Last activity timestamp */
3344
- lastActivityAt?: Date;
3345
- /** Completed node IDs */
3346
- completedNodeIds: string[];
3347
- /** Timestamps */
4216
+ /** Email of the user who has access */
4217
+ grantedTo: string;
4218
+ /** Scope of access: ["*"] for full access, or ["node:xyz"] for specific nodes */
4219
+ scope: string[];
4220
+ /** Array of JWT IDs (jti) that have been revoked */
4221
+ revokedTokenJtis: string[];
4222
+ /** When the entire grant was revoked (null if active) */
4223
+ revokedAt?: Date;
4224
+ /** When this grant expires */
4225
+ validUntil: Date;
4226
+ /** When the grant was created */
3348
4227
  createdAt: Date;
3349
- updatedAt: Date;
4228
+ /** Last time the grant was used */
4229
+ lastUsedAt?: Date;
4230
+ }
4231
+ /**
4232
+ * Input for creating an access grant
4233
+ */
4234
+ interface CreateGrantInput {
4235
+ /** Invitation ID that originated this grant */
4236
+ invitationId: string;
4237
+ /** Instance ID to grant access to */
4238
+ instanceId: string;
4239
+ /** Email of the user getting access */
4240
+ grantedTo: string;
4241
+ /** Scope of access (default: ["*"]) */
4242
+ scope?: string[];
4243
+ /** Validity in days (default: 30) */
4244
+ validDays?: number;
3350
4245
  }
3351
4246
  /**
3352
- * Check if auth is signed link type
4247
+ * Check if grant is still valid (not revoked, not expired)
3353
4248
  */
3354
- declare function isSignedLinkAuth(auth: ParticipationAuth): auth is SignedLinkAuth;
4249
+ declare function isGrantValid(grant: WorkflowAccessGrant): boolean;
3355
4250
  /**
3356
- * Check if auth is PIN code type
4251
+ * Check if grant has been revoked
3357
4252
  */
3358
- declare function isPinCodeAuth(auth: ParticipationAuth): auth is PinCodeAuth;
4253
+ declare function isGrantRevoked(grant: WorkflowAccessGrant): boolean;
3359
4254
  /**
3360
- * Check if participation is active and can execute nodes
4255
+ * Check if a specific token has been revoked
3361
4256
  */
3362
- declare function canParticipate(participation: WorkflowParticipation): boolean;
4257
+ declare function isTokenRevoked(grant: WorkflowAccessGrant, jti: string): boolean;
3363
4258
  /**
3364
- * Check if participation can be authenticated (pending and not expired)
4259
+ * Check if grant has expired
3365
4260
  */
3366
- declare function canAuthenticate(participation: WorkflowParticipation): boolean;
4261
+ declare function isGrantExpired(grant: WorkflowAccessGrant): boolean;
3367
4262
  /**
3368
- * Check if a participation can execute a specific node
4263
+ * Check if scope allows access to a specific node
3369
4264
  */
3370
- declare function canExecuteNode(participation: WorkflowParticipation, nodeId: string): boolean;
4265
+ declare function canAccessNode(grant: WorkflowAccessGrant, nodeId: string): boolean;
3371
4266
 
3372
4267
  /**
3373
4268
  * Workflow access mode - determines how the user is authenticated
@@ -3379,7 +4274,7 @@ type WorkflowAccessMode = {
3379
4274
  } | {
3380
4275
  type: "external";
3381
4276
  token: string;
3382
- participationId: string;
4277
+ grantId: string;
3383
4278
  };
3384
4279
  /**
3385
4280
  * Reason why a field is read-only
@@ -3727,8 +4622,7 @@ interface DBWorkflow {
3727
4622
  slots: WorkflowSlot[];
3728
4623
  nodes: Record<string, WorkflowNode>;
3729
4624
  start_node_id: string;
3730
- layout: WorkflowLayout;
3731
- participants: ParticipantTemplate[] | null;
4625
+ layout?: WorkflowLayout;
3732
4626
  theme: WorkflowTheme | null;
3733
4627
  config: WorkflowConfig | null;
3734
4628
  system: boolean;
@@ -3750,8 +4644,7 @@ interface CreateDBWorkflow {
3750
4644
  slots: WorkflowSlot[];
3751
4645
  nodes: Record<string, WorkflowNode>;
3752
4646
  startNodeId: string;
3753
- layout: WorkflowLayout;
3754
- participants?: ParticipantTemplate[];
4647
+ layout?: WorkflowLayout;
3755
4648
  theme?: WorkflowTheme;
3756
4649
  config?: WorkflowConfig;
3757
4650
  system?: boolean;
@@ -3770,7 +4663,6 @@ interface UpdateDBWorkflow {
3770
4663
  nodes?: Record<string, WorkflowNode>;
3771
4664
  startNodeId?: string;
3772
4665
  layout?: WorkflowLayout;
3773
- participants?: ParticipantTemplate[];
3774
4666
  theme?: WorkflowTheme;
3775
4667
  config?: WorkflowConfig;
3776
4668
  metadata?: Record<string, unknown>;
@@ -3835,51 +4727,77 @@ interface UpdateDBWorkflowInstance {
3835
4727
  completedAt?: Date | null;
3836
4728
  }
3837
4729
  /**
3838
- * Workflow participation as stored in database.
4730
+ * Workflow invitation as stored in database.
3839
4731
  * Uses snake_case to match database column names.
3840
4732
  */
3841
- interface DBWorkflowParticipation {
4733
+ interface DBWorkflowInvitation {
3842
4734
  id: string;
3843
4735
  tenant_id: string;
3844
4736
  instance_id: string;
3845
- participant_template_id: string;
3846
- type: "internal" | "external";
3847
- email: string;
3848
- name: string | null;
3849
- phone: string | null;
3850
- auth: ParticipationAuth;
3851
- allowed_node_ids: string[];
3852
- status: ParticipationStatus;
3853
- authenticated_at: string | null;
3854
- last_activity_at: string | null;
3855
- completed_node_ids: string[];
4737
+ recipient_email: string;
4738
+ recipient_name: string | null;
4739
+ status: InvitationStatus;
4740
+ created_by: string;
3856
4741
  created_at: string;
3857
- updated_at: string;
4742
+ accepted_at: string | null;
4743
+ expires_at: string;
3858
4744
  }
3859
4745
  /**
3860
- * Data for creating a workflow participation.
4746
+ * Data for creating a workflow invitation.
3861
4747
  * Tenant ID is automatically set from the execution context.
3862
4748
  */
3863
- interface CreateDBWorkflowParticipation {
4749
+ interface CreateDBWorkflowInvitation {
3864
4750
  instanceId: string;
3865
- participantTemplateId: string;
3866
- type: "internal" | "external";
3867
- email: string;
3868
- name?: string;
3869
- phone?: string;
3870
- auth: ParticipationAuth;
3871
- allowedNodeIds: string[];
3872
- status?: ParticipationStatus;
4751
+ recipientEmail: string;
4752
+ recipientName?: string;
4753
+ status?: InvitationStatus;
4754
+ createdBy: string;
4755
+ expiresAt: Date;
4756
+ }
4757
+ /**
4758
+ * Data for updating a workflow invitation.
4759
+ */
4760
+ interface UpdateDBWorkflowInvitation {
4761
+ status?: InvitationStatus;
4762
+ acceptedAt?: Date | null;
4763
+ expiresAt?: Date;
4764
+ }
4765
+ /**
4766
+ * Workflow access grant as stored in database.
4767
+ * Uses snake_case to match database column names.
4768
+ */
4769
+ interface DBWorkflowAccessGrant {
4770
+ id: string;
4771
+ tenant_id: string;
4772
+ invitation_id: string;
4773
+ instance_id: string;
4774
+ granted_to: string;
4775
+ scope: string[];
4776
+ revoked_token_jtis: string[];
4777
+ created_at: string;
4778
+ last_used_at: string | null;
4779
+ valid_until: string;
4780
+ revoked_at: string | null;
4781
+ }
4782
+ /**
4783
+ * Data for creating a workflow access grant.
4784
+ * Tenant ID is automatically set from the execution context.
4785
+ */
4786
+ interface CreateDBWorkflowAccessGrant {
4787
+ invitationId: string;
4788
+ instanceId: string;
4789
+ grantedTo: string;
4790
+ scope?: string[];
4791
+ revokedTokenJtis?: string[];
4792
+ validUntil: Date;
3873
4793
  }
3874
4794
  /**
3875
- * Data for updating a workflow participation.
4795
+ * Data for updating a workflow access grant.
3876
4796
  */
3877
- interface UpdateDBWorkflowParticipation {
3878
- status?: ParticipationStatus;
3879
- auth?: ParticipationAuth;
3880
- authenticatedAt?: Date | null;
3881
- lastActivityAt?: Date | null;
3882
- completedNodeIds?: string[];
4797
+ interface UpdateDBWorkflowAccessGrant {
4798
+ lastUsedAt?: Date;
4799
+ revokedTokenJtis?: string[];
4800
+ revokedAt?: Date | null;
3883
4801
  }
3884
4802
  /**
3885
4803
  * Result of an operation
@@ -4800,6 +5718,26 @@ declare const rollupConfigSchema: z.ZodObject<{
4800
5718
  }>>;
4801
5719
  }, z.core.$strip>>>;
4802
5720
  }, z.core.$strip>;
5721
+ /**
5722
+ * Document attribute config schema
5723
+ */
5724
+ declare const documentConfigSchema: z.ZodObject<{
5725
+ disabled: z.ZodOptional<z.ZodBoolean>;
5726
+ placeholder: z.ZodOptional<z.ZodString>;
5727
+ description: z.ZodOptional<z.ZodString>;
5728
+ defaultValue: z.ZodOptional<z.ZodUnknown>;
5729
+ icon: z.ZodOptional<z.ZodString>;
5730
+ order: z.ZodOptional<z.ZodNumber>;
5731
+ hidden: z.ZodOptional<z.ZodBoolean>;
5732
+ archived: z.ZodOptional<z.ZodBoolean>;
5733
+ deprecated: z.ZodOptional<z.ZodBoolean>;
5734
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
5735
+ templateId: z.ZodOptional<z.ZodString>;
5736
+ allowedTemplates: z.ZodOptional<z.ZodArray<z.ZodString>>;
5737
+ multiple: z.ZodOptional<z.ZodBoolean>;
5738
+ maxDocuments: z.ZodOptional<z.ZodNumber>;
5739
+ autoProcess: z.ZodOptional<z.ZodBoolean>;
5740
+ }, z.core.$strip>;
4803
5741
  /**
4804
5742
  * Map of attribute type to config schema
4805
5743
  */
@@ -4968,7 +5906,8 @@ declare function createFormAttributeValidator(attr: Attribute, messages?: Valida
4968
5906
  /**
4969
5907
  * Create a Zod schema for an entire object
4970
5908
  *
4971
- * Uses strict mode to reject unknown keys, preventing invalid data from being stored.
5909
+ * Uses passthrough mode to allow computed fields (formula, rollup) that may be
5910
+ * present in record data but are not part of the mutable schema.
4972
5911
  */
4973
5912
  declare function createObjectValidator(objectDef: ObjectDefinition): z.ZodType<Record<string, unknown>>;
4974
5913
  /**
@@ -4998,7 +5937,8 @@ declare function validateObjectOrThrow(objectDef: ObjectDefinition, data: Record
4998
5937
  * Create a Zod schema for draft validation.
4999
5938
  * All attributes become optional, but provided values are still validated.
5000
5939
  *
5001
- * Uses strict mode to reject unknown keys, preventing invalid data from being stored.
5940
+ * Uses passthrough mode to allow computed fields (formula, rollup) that may be
5941
+ * present in record data but are not part of the mutable schema.
5002
5942
  */
5003
5943
  declare function createDraftValidator(objectDef: ObjectDefinition): z.ZodType<Record<string, unknown>>;
5004
5944
  /**
@@ -5088,7 +6028,7 @@ declare function computeRecordStatus(objectDef: ObjectDefinition, data: Record<s
5088
6028
  * Supported cache key types for type-safe cache operations.
5089
6029
  * Used by `cachedBy()` and `cachedList()` helpers in BaseService.
5090
6030
  */
5091
- type CacheKeyType = "record" | "objectSchema" | "objectSchemaByName" | "objectSchemaList" | "objectAttributes" | "attributeById" | "userProfileById" | "userProfileByAuthId" | "userProfileByEmail" | "viewsByObject" | "workflowByName" | "workflowById" | "workflowList" | "relationOptions" | "resolvedRelation" | "rollupValue" | "userPermissions" | "recordList" | "searchResults" | "globalSearch" | "allRecordLists" | "allSearchResults" | "allGlobalSearch" | "allSchemas" | "allAttributes" | "allPermissions" | "allRelations" | "allResolvedRelations" | "resolvedRelationsByRecord" | "resolvedRelationsByAttr" | "allRollups" | "rollupsByRecord" | "allRecords" | "allViews" | "allUserProfiles" | "allWorkflows" | "allForTenant";
6031
+ type CacheKeyType = "record" | "objectSchema" | "objectSchemaByName" | "objectSchemaList" | "objectOwnerInfo" | "objectAttributes" | "attributeById" | "userProfileById" | "userProfileByAuthId" | "userProfileByEmail" | "viewsByObject" | "workflowByName" | "workflowById" | "workflowList" | "relationOptions" | "resolvedRelation" | "rollupValue" | "userPermissions" | "recordList" | "searchResults" | "globalSearch" | "allRecordLists" | "allSearchResults" | "allGlobalSearch" | "allSchemas" | "allAttributes" | "allPermissions" | "allRelations" | "allResolvedRelations" | "resolvedRelationsByRecord" | "resolvedRelationsByAttr" | "allRollups" | "rollupsByRecord" | "allRecords" | "allViews" | "allUserProfiles" | "allWorkflows" | "allForTenant";
5092
6032
  /**
5093
6033
  * Generate a deterministic hash from query options.
5094
6034
  * Keys are sorted recursively to ensure same hash regardless of property order.
@@ -5176,6 +6116,7 @@ declare const cacheKeys: {
5176
6116
  readonly objectSchemaByName: (tenantId: string, name: string) => string;
5177
6117
  /** List of all object schemas */
5178
6118
  readonly objectSchemaList: (tenantId: string) => string;
6119
+ readonly objectOwnerInfo: (tenantId: string, objectId: string) => string;
5179
6120
  /** Attributes for an object */
5180
6121
  readonly objectAttributes: (tenantId: string, objectId: string) => string;
5181
6122
  /** Single attribute by ID (covered by allAttributes pattern) */
@@ -5190,7 +6131,15 @@ declare const cacheKeys: {
5190
6131
  * Used by cachedByMany in RelationService.resolveIds()
5191
6132
  */
5192
6133
  readonly resolvedRelation: (tenantId: string, compositeId: string) => string;
5193
- /** Computed rollup value for a record */
6134
+ /**
6135
+ * Computed rollup value for a record.
6136
+ *
6137
+ * NOTE: When used via `cachedBy("rollupValue", compositeId, ...)`, the compositeId
6138
+ * is `${recordId}:${attrName}`. Since `cachedBy` calls `keyFn(tenantId, compositeId)`,
6139
+ * the third parameter receives the composite string, producing the same key as
6140
+ * calling `rollupValue(tenantId, recordId, attrName)` directly. This works because
6141
+ * the colon separator in the composite matches the key format, but is intentional.
6142
+ */
5194
6143
  readonly rollupValue: (tenantId: string, recordId: string, attrName: string) => string;
5195
6144
  /** Individual record by ID */
5196
6145
  readonly record: (tenantId: string, recordId: string) => string;
@@ -5408,152 +6357,32 @@ interface AttributesRepository {
5408
6357
  */
5409
6358
  upsert(data: UpsertDBAttribute): Promise<DBAttribute>;
5410
6359
  }
6360
+
5411
6361
  /**
5412
- * Repository for user_profiles table.
6362
+ * Repository for object_records table (unified JSONB).
5413
6363
  *
5414
6364
  * All operations are automatically scoped to the current tenant
5415
6365
  * from the execution context (via AsyncLocalStorage).
5416
6366
  */
5417
- interface UserProfilesRepository {
6367
+ interface ObjectRecordsRepository {
5418
6368
  /**
5419
- * Find user profile by ID.
6369
+ * Find record by ID.
5420
6370
  * Automatically filtered by current tenant context.
5421
6371
  */
5422
- findById(id: Uuid): Promise<UserProfile | null>;
6372
+ findById(id: Uuid): Promise<ObjectRecord | null>;
5423
6373
  /**
5424
- * Find multiple user profiles by IDs.
6374
+ * Find multiple records by IDs (batch fetch).
6375
+ * Returns records in no particular order. Missing IDs are simply not included.
5425
6376
  * Automatically filtered by current tenant context.
5426
- * Returns only profiles that exist and belong to the current tenant.
5427
6377
  */
5428
- findByIds(ids: Uuid[]): Promise<UserProfile[]>;
6378
+ findByIds(ids: Uuid[]): Promise<ObjectRecord[]>;
5429
6379
  /**
5430
- * Find user profile by auth ID (external auth provider).
5431
- * Automatically filtered by current tenant context.
6380
+ * Create record.
6381
+ * Tenant ID is automatically set from context.
5432
6382
  */
5433
- findByAuthId(authId: string): Promise<UserProfile | null>;
6383
+ create(data: CreateObjectRecord): Promise<ObjectRecord>;
5434
6384
  /**
5435
- * Find user profile by email.
5436
- * Automatically filtered by current tenant context.
5437
- */
5438
- findByEmail(email: string): Promise<UserProfile | null>;
5439
- /**
5440
- * Create user profile.
5441
- * Tenant ID is automatically set from context.
5442
- */
5443
- create(data: CreateUserProfile): Promise<UserProfile>;
5444
- /**
5445
- * Update user profile.
5446
- * Automatically filtered by current tenant context.
5447
- */
5448
- update(id: Uuid, data: UpdateUserProfile): Promise<UserProfile>;
5449
- /**
5450
- * Delete user profile.
5451
- * Automatically filtered by current tenant context.
5452
- */
5453
- delete(id: Uuid): Promise<void>;
5454
- /**
5455
- * List all user profiles for current tenant.
5456
- * Automatically filtered by current tenant context.
5457
- */
5458
- list(options?: ListOptions): Promise<UserProfile[]>;
5459
- /**
5460
- * Count user profiles by role within current tenant.
5461
- * Useful for checking if last admin before deletion.
5462
- */
5463
- countByRole(role: string): Promise<number>;
5464
- /**
5465
- * Update last login timestamp.
5466
- * Automatically filtered by current tenant context.
5467
- */
5468
- updateLastLogin(id: Uuid): Promise<void>;
5469
- /**
5470
- * Invite a user by email.
5471
- * Creates a pending user profile with a temporary authId.
5472
- * Tenant ID is automatically set from context.
5473
- *
5474
- * @param data - Invitation data (email, firstName, lastName, role)
5475
- * @returns Created pending user profile
5476
- */
5477
- invite(data: InviteUserInput): Promise<UserProfile>;
5478
- }
5479
- /**
5480
- * Repository for files table.
5481
- *
5482
- * All operations are automatically scoped to the current tenant
5483
- * from the execution context (via AsyncLocalStorage).
5484
- */
5485
- interface FilesRepository {
5486
- /**
5487
- * Find file by ID.
5488
- * Returns file with signed URL. Automatically filtered by current tenant context.
5489
- */
5490
- findById(id: Uuid): Promise<File | null>;
5491
- /**
5492
- * Find multiple files by IDs.
5493
- * Returns files with signed URLs. Automatically filtered by current tenant context.
5494
- */
5495
- findByIds(ids: Uuid[]): Promise<File[]>;
5496
- /**
5497
- * Create file.
5498
- * Returns file with signed URL. Tenant ID is automatically set from context.
5499
- */
5500
- create(data: CreateFile): Promise<File>;
5501
- /**
5502
- * Update file.
5503
- * Automatically filtered by current tenant context.
5504
- */
5505
- update(id: Uuid, data: UpdateFile): Promise<File>;
5506
- /**
5507
- * Delete file (soft delete).
5508
- * Automatically filtered by current tenant context.
5509
- */
5510
- delete(id: Uuid): Promise<void>;
5511
- /**
5512
- * Hard delete file (permanent).
5513
- * Automatically filtered by current tenant context.
5514
- */
5515
- hardDelete(id: Uuid): Promise<void>;
5516
- /**
5517
- * List files for current tenant.
5518
- * Automatically filtered by current tenant context.
5519
- */
5520
- list(options?: FileListOptions): Promise<File[]>;
5521
- /**
5522
- * Find files by folder path.
5523
- * Automatically filtered by current tenant context.
5524
- */
5525
- findByFolder(folderPath: string): Promise<File[]>;
5526
- /**
5527
- * Find files by uploader.
5528
- * Automatically filtered by current tenant context.
5529
- */
5530
- findByUploader(uploadedBy: Uuid): Promise<File[]>;
5531
- }
5532
- /**
5533
- * Repository for object_records table (unified JSONB).
5534
- *
5535
- * All operations are automatically scoped to the current tenant
5536
- * from the execution context (via AsyncLocalStorage).
5537
- */
5538
- interface ObjectRecordsRepository {
5539
- /**
5540
- * Find record by ID.
5541
- * Automatically filtered by current tenant context.
5542
- */
5543
- findById(id: Uuid): Promise<ObjectRecord | null>;
5544
- /**
5545
- * Find multiple records by IDs (batch fetch).
5546
- * Returns records in no particular order. Missing IDs are simply not included.
5547
- * Automatically filtered by current tenant context.
5548
- */
5549
- findByIds(ids: Uuid[]): Promise<ObjectRecord[]>;
5550
- /**
5551
- * Create record.
5552
- * Tenant ID is automatically set from context.
5553
- */
5554
- create(data: CreateObjectRecord): Promise<ObjectRecord>;
5555
- /**
5556
- * Update record.
6385
+ * Update record.
5557
6386
  * Automatically filtered by current tenant context.
5558
6387
  */
5559
6388
  update(id: Uuid, data: Partial<Record<string, unknown>>): Promise<ObjectRecord>;
@@ -5604,19 +6433,10 @@ interface ObjectRecordsRepository {
5604
6433
  * Count records that reference a given record ID in any relation attribute.
5605
6434
  * Used to implement the "Restrict" delete behavior.
5606
6435
  *
5607
- * This method scans all relation attributes across all objects to find
5608
- * records that contain the target ID in their relation values.
5609
- *
5610
6436
  * **Important:** This method should exclude soft-deleted records from the count.
5611
6437
  *
5612
6438
  * @param targetId - The record ID being checked for references
5613
6439
  * @returns Array of objects with reference counts, grouped by object
5614
- *
5615
- * @example
5616
- * ```typescript
5617
- * const refs = await repo.countRecordsReferencingId("rec-123");
5618
- * // [{ objectName: "contacts", objectLabel: "Contacts", count: 3 }]
5619
- * ```
5620
6440
  */
5621
6441
  countRecordsReferencingId(targetId: Uuid): Promise<Array<{
5622
6442
  objectName: string;
@@ -5627,43 +6447,18 @@ interface ObjectRecordsRepository {
5627
6447
  * Remove an attribute's data from all records of an object.
5628
6448
  * Used after attribute deletion to clean up orphaned data.
5629
6449
  *
5630
- * This efficiently removes the key from the JSONB values column
5631
- * for all records belonging to the specified object.
5632
- *
5633
6450
  * @param objectId - Object UUID
5634
6451
  * @param attributeName - Name of the attribute to remove
5635
6452
  * @returns Number of records that were updated
5636
- *
5637
- * @example
5638
- * ```typescript
5639
- * const updated = await repo.removeAttributeData("obj-123", "oldField");
5640
- * console.log(`Cleaned up ${updated} records`);
5641
- * ```
5642
6453
  */
5643
6454
  removeAttributeData(objectId: Uuid, attributeName: string): Promise<number>;
5644
6455
  /**
5645
6456
  * Batch update labels for all records of an object.
5646
6457
  * Used after labelExpression changes to refresh all record labels.
5647
6458
  *
5648
- * Supports both sync and async compute functions to allow for
5649
- * relation resolution when the label expression references relations.
5650
- *
5651
6459
  * @param objectId - Object UUID
5652
6460
  * @param computeLabel - Function to compute label from record values (sync or async)
5653
6461
  * @returns Number of records that were updated
5654
- *
5655
- * @example
5656
- * ```typescript
5657
- * // Sync compute (simple labels)
5658
- * const updated = await repo.batchRefreshLabels("obj-123", (values) => {
5659
- * return `${values.sku} - ${values.name}`;
5660
- * });
5661
- *
5662
- * // Async compute (with relation resolution)
5663
- * const updated = await repo.batchRefreshLabels("obj-123", async (values) => {
5664
- * return await computeLabelWithRelations(template, values, attributes, resolver);
5665
- * });
5666
- * ```
5667
6462
  */
5668
6463
  batchRefreshLabels(objectId: Uuid, computeLabel: (values: Record<string, unknown>) => Promise<string> | string): Promise<number>;
5669
6464
  /**
@@ -5680,22 +6475,10 @@ interface ObjectRecordsRepository {
5680
6475
  * Used by rollup calculations to find related records.
5681
6476
  * Automatically filtered by current tenant context.
5682
6477
  *
5683
- * For example, find all orders where values->'companyId' = 'company-123'
5684
- *
5685
- * @param objectId - Object ID of the records to search (e.g., Orders object)
5686
- * @param relationAttribute - Name of the relation attribute (e.g., "companyId")
6478
+ * @param objectId - Object ID of the records to search
6479
+ * @param relationAttribute - Name of the relation attribute
5687
6480
  * @param targetId - The ID to search for in the relation attribute
5688
6481
  * @returns Records that reference the target ID
5689
- *
5690
- * @example
5691
- * ```typescript
5692
- * // Find all orders for a specific company
5693
- * const orders = await repo.findByRelation(
5694
- * "orders-object-id",
5695
- * "companyId",
5696
- * "company-123"
5697
- * );
5698
- * ```
5699
6482
  */
5700
6483
  findByRelation(objectId: Uuid, relationAttribute: string, targetId: Uuid): Promise<ObjectRecord[]>;
5701
6484
  }
@@ -5763,211 +6546,135 @@ interface ViewsRepository {
5763
6546
  */
5764
6547
  upsert(data: UpsertDBView): Promise<DBView>;
5765
6548
  }
6549
+
5766
6550
  /**
5767
- * Repository for workflow definitions.
5768
- *
5769
- * This repository is optional - if not provided in the DatabaseAdapter,
5770
- * workflow features are disabled.
6551
+ * Repository for user_profiles table.
5771
6552
  *
5772
6553
  * All operations are automatically scoped to the current tenant
5773
6554
  * from the execution context (via AsyncLocalStorage).
5774
6555
  */
5775
- interface WorkflowsRepository {
6556
+ interface UserProfilesRepository {
5776
6557
  /**
5777
- * Find workflow by ID.
6558
+ * Find user profile by ID.
5778
6559
  * Automatically filtered by current tenant context.
5779
6560
  */
5780
- findById(id: Uuid): Promise<DBWorkflow | null>;
6561
+ findById(id: Uuid): Promise<UserProfile | null>;
5781
6562
  /**
5782
- * Find workflow by name.
6563
+ * Find multiple user profiles by IDs.
5783
6564
  * Automatically filtered by current tenant context.
5784
6565
  */
5785
- findByName(name: string): Promise<DBWorkflow | null>;
5786
- /**
5787
- * Find system workflow by name (for sync).
5788
- * System workflows are shared across tenants.
5789
- */
5790
- findSystemByName(name: string): Promise<DBWorkflow | null>;
6566
+ findByIds(ids: Uuid[]): Promise<UserProfile[]>;
5791
6567
  /**
5792
- * List all workflows for current tenant.
6568
+ * Find user profile by auth ID (external auth provider).
5793
6569
  * Automatically filtered by current tenant context.
5794
6570
  */
5795
- list(): Promise<DBWorkflow[]>;
6571
+ findByAuthId(authId: string): Promise<UserProfile | null>;
5796
6572
  /**
5797
- * List workflows by status.
6573
+ * Find user profile by email.
5798
6574
  * Automatically filtered by current tenant context.
5799
6575
  */
5800
- listByStatus(status: WorkflowStatus): Promise<DBWorkflow[]>;
6576
+ findByEmail(email: string): Promise<UserProfile | null>;
5801
6577
  /**
5802
- * Create workflow.
6578
+ * Create user profile.
5803
6579
  * Tenant ID is automatically set from context.
5804
6580
  */
5805
- create(data: CreateDBWorkflow): Promise<DBWorkflow>;
6581
+ create(data: CreateUserProfile): Promise<UserProfile>;
5806
6582
  /**
5807
- * Update workflow.
6583
+ * Update user profile.
5808
6584
  * Automatically filtered by current tenant context.
5809
6585
  */
5810
- update(id: Uuid, data: Partial<UpdateDBWorkflow>): Promise<DBWorkflow>;
6586
+ update(id: Uuid, data: UpdateUserProfile): Promise<UserProfile>;
5811
6587
  /**
5812
- * Delete workflow.
6588
+ * Delete user profile.
5813
6589
  * Automatically filtered by current tenant context.
5814
6590
  */
5815
6591
  delete(id: Uuid): Promise<void>;
5816
6592
  /**
5817
- * Upsert workflow (create or update based on name + system flag).
6593
+ * List all user profiles for current tenant.
6594
+ * Automatically filtered by current tenant context.
6595
+ */
6596
+ list(options?: ListOptions): Promise<UserProfile[]>;
6597
+ /**
6598
+ * Count user profiles by role within current tenant.
6599
+ */
6600
+ countByRole(role: string): Promise<number>;
6601
+ /**
6602
+ * Update last login timestamp.
6603
+ * Automatically filtered by current tenant context.
6604
+ */
6605
+ updateLastLogin(id: Uuid): Promise<void>;
6606
+ /**
6607
+ * Invite a user by email.
6608
+ * Creates a pending user profile with a temporary authId.
5818
6609
  * Tenant ID is automatically set from context.
5819
6610
  */
5820
- upsert(data: CreateDBWorkflow): Promise<DBWorkflow>;
6611
+ invite(data: InviteUserInput): Promise<UserProfile>;
5821
6612
  }
5822
6613
  /**
5823
- * Repository for workflow instances (running/completed workflows).
5824
- *
5825
- * This repository is optional - if not provided in the DatabaseAdapter,
5826
- * workflow execution features are disabled.
6614
+ * Repository for files table.
5827
6615
  *
5828
6616
  * All operations are automatically scoped to the current tenant
5829
6617
  * from the execution context (via AsyncLocalStorage).
5830
6618
  */
5831
- interface WorkflowInstancesRepository {
6619
+ interface FilesRepository {
5832
6620
  /**
5833
- * Find instance by ID.
5834
- * Automatically filtered by current tenant context.
6621
+ * Find file by ID.
6622
+ * Returns file with signed URL.
5835
6623
  */
5836
- findById(id: Uuid): Promise<DBWorkflowInstance | null>;
6624
+ findById(id: Uuid): Promise<File | null>;
5837
6625
  /**
5838
- * Find instances by workflow ID.
5839
- * Automatically filtered by current tenant context.
6626
+ * Find multiple files by IDs.
6627
+ * Returns files with signed URLs.
5840
6628
  */
5841
- findByWorkflowId(workflowId: Uuid): Promise<DBWorkflowInstance[]>;
6629
+ findByIds(ids: Uuid[]): Promise<File[]>;
5842
6630
  /**
5843
- * Find instances by workflow name.
5844
- * Automatically filtered by current tenant context.
6631
+ * Create file.
6632
+ * Returns file with signed URL.
5845
6633
  */
5846
- findByWorkflowName(workflowName: string): Promise<DBWorkflowInstance[]>;
6634
+ create(data: CreateFile): Promise<File>;
5847
6635
  /**
5848
- * List all instances for current tenant.
5849
- * Automatically filtered by current tenant context.
6636
+ * Update file.
5850
6637
  */
5851
- list(options?: ListOptions): Promise<{
5852
- instances: DBWorkflowInstance[];
5853
- total: number;
5854
- }>;
6638
+ update(id: Uuid, data: UpdateFile): Promise<File>;
5855
6639
  /**
5856
- * List instances by status.
5857
- * Automatically filtered by current tenant context.
6640
+ * Delete file (soft delete).
5858
6641
  */
5859
- listByStatus(status: InstanceStatus): Promise<DBWorkflowInstance[]>;
6642
+ delete(id: Uuid): Promise<void>;
5860
6643
  /**
5861
- * Create instance.
5862
- * Tenant ID is automatically set from context.
6644
+ * Hard delete file (permanent).
5863
6645
  */
5864
- create(data: CreateDBWorkflowInstance): Promise<DBWorkflowInstance>;
6646
+ hardDelete(id: Uuid): Promise<void>;
5865
6647
  /**
5866
- * Update instance.
5867
- * Automatically filtered by current tenant context.
6648
+ * List files for current tenant.
5868
6649
  */
5869
- update(id: Uuid, data: Partial<UpdateDBWorkflowInstance>): Promise<DBWorkflowInstance>;
6650
+ list(options?: FileListOptions): Promise<File[]>;
5870
6651
  /**
5871
- * Upsert instance (create or update based on ID).
5872
- * Tenant ID is automatically set from context.
6652
+ * Find files by folder path.
5873
6653
  */
5874
- upsert(data: CreateDBWorkflowInstance & {
5875
- id: string;
5876
- }): Promise<DBWorkflowInstance>;
6654
+ findByFolder(folderPath: string): Promise<File[]>;
5877
6655
  /**
5878
- * Find instances that reference a specific record in their slot context.
5879
- * Searches in context.slots for slots where objectName and id match.
5880
- * Automatically filtered by current tenant context.
5881
- *
5882
- * This method is required and must be implemented by all adapters.
5883
- * No fallback is provided for performance reasons - all implementations
5884
- * must use database-level optimizations (e.g., JSONB queries in PostgreSQL).
5885
- *
5886
- * @param objectName - Object name to match in slot data
5887
- * @param recordId - Record ID to match in slot data
5888
- * @param options - Optional filtering options
6656
+ * Find files by uploader.
5889
6657
  */
5890
- findByRecordInSlots(objectName: string, recordId: string, options?: {
5891
- status?: InstanceStatus;
5892
- limit?: number;
5893
- offset?: number;
5894
- }): Promise<{
5895
- instances: DBWorkflowInstance[];
5896
- total: number;
5897
- }>;
6658
+ findByUploader(uploadedBy: Uuid): Promise<File[]>;
5898
6659
  }
6660
+
5899
6661
  /**
5900
- * Repository for workflow participations (external user access to workflows).
6662
+ * Repository for audit logs.
5901
6663
  *
5902
6664
  * This repository is optional - if not provided in the DatabaseAdapter,
5903
- * external participation features are disabled.
5904
- *
5905
- * All operations are automatically scoped to the current tenant
5906
- * from the execution context (via AsyncLocalStorage).
6665
+ * audit logging is disabled.
5907
6666
  */
5908
- interface WorkflowParticipationsRepository {
6667
+ interface AuditRepository {
5909
6668
  /**
5910
- * Find participation by ID.
5911
- * Automatically filtered by current tenant context.
5912
- */
5913
- findById(id: Uuid): Promise<DBWorkflowParticipation | null>;
5914
- /**
5915
- * Find participations by instance ID.
5916
- * Automatically filtered by current tenant context.
5917
- */
5918
- findByInstanceId(instanceId: Uuid): Promise<DBWorkflowParticipation[]>;
5919
- /**
5920
- * Find participations by email.
5921
- * Automatically filtered by current tenant context.
5922
- */
5923
- findByEmail(email: string): Promise<DBWorkflowParticipation[]>;
5924
- /**
5925
- * Create participation.
5926
- * Tenant ID is automatically set from context.
5927
- */
5928
- create(data: CreateDBWorkflowParticipation): Promise<DBWorkflowParticipation>;
5929
- /**
5930
- * Update participation.
5931
- * Automatically filtered by current tenant context.
5932
- */
5933
- update(id: Uuid, data: Partial<UpdateDBWorkflowParticipation>): Promise<DBWorkflowParticipation>;
5934
- /**
5935
- * Upsert participation (create or update based on ID).
5936
- * Tenant ID is automatically set from context.
5937
- */
5938
- upsert(data: CreateDBWorkflowParticipation & {
5939
- id: string;
5940
- }): Promise<DBWorkflowParticipation>;
5941
- /**
5942
- * Update only the auth field of a participation.
5943
- * Used for recording failed PIN attempts without touching other fields.
5944
- * Automatically filtered by current tenant context.
5945
- */
5946
- updateAuth(id: Uuid, auth: ParticipationAuth): Promise<void>;
5947
- }
5948
- /**
5949
- * Repository for audit logs.
5950
- *
5951
- * This repository is optional - if not provided in the DatabaseAdapter,
5952
- * audit logging is disabled (backward compatible behavior).
5953
- *
5954
- * All operations are automatically scoped to the current tenant
5955
- * from the execution context (via AsyncLocalStorage).
5956
- */
5957
- interface AuditRepository {
5958
- /**
5959
- * Create a new audit log entry.
5960
- * Tenant ID is automatically set from context.
6669
+ * Create a new audit log entry.
5961
6670
  */
5962
6671
  create(entry: CreateAuditLogInput): Promise<AuditLogEntry>;
5963
6672
  /**
5964
- * Create multiple audit log entries (batch insert for performance).
5965
- * Tenant ID is automatically set from context.
6673
+ * Create multiple audit log entries (batch insert).
5966
6674
  */
5967
6675
  createMany(entries: CreateAuditLogInput[]): Promise<void>;
5968
6676
  /**
5969
6677
  * List audit logs with filtering and pagination.
5970
- * Automatically filtered by current tenant context.
5971
6678
  */
5972
6679
  list(options?: AuditListOptions): Promise<{
5973
6680
  entries: AuditLogEntry[];
@@ -5975,17 +6682,14 @@ interface AuditRepository {
5975
6682
  }>;
5976
6683
  /**
5977
6684
  * Get audit logs for a specific resource.
5978
- * Automatically filtered by current tenant context.
5979
6685
  */
5980
6686
  getByResource(resourceType: AuditResourceType, resourceId: Uuid, options?: AuditListOptions): Promise<AuditLogEntry[]>;
5981
6687
  /**
5982
6688
  * Get audit logs by actor.
5983
- * Automatically filtered by current tenant context.
5984
6689
  */
5985
6690
  getByActor(actorId: Uuid, options?: AuditListOptions): Promise<AuditLogEntry[]>;
5986
6691
  /**
5987
6692
  * Delete old audit logs (for retention policy).
5988
- * Automatically filtered by current tenant context.
5989
6693
  * @returns Number of deleted entries
5990
6694
  */
5991
6695
  deleteOlderThan(date: Date): Promise<number>;
@@ -5994,78 +6698,191 @@ interface AuditRepository {
5994
6698
  * Repository for roles, permissions, and user role assignments.
5995
6699
  *
5996
6700
  * This repository is optional - if not provided in the DatabaseAdapter,
5997
- * permission checks are disabled (backward compatible behavior).
5998
- *
5999
- * All operations are automatically scoped to the current tenant
6000
- * from the execution context (via AsyncLocalStorage).
6701
+ * permission checks are disabled.
6001
6702
  */
6002
6703
  interface PermissionsRepository {
6003
- /**
6004
- * Get all roles for current tenant.
6005
- * Automatically filtered by current tenant context.
6006
- */
6007
6704
  getRoles(): Promise<Role[]>;
6008
- /**
6009
- * Get a role by ID.
6010
- * Automatically filtered by current tenant context.
6011
- */
6012
6705
  getRoleById(roleId: Uuid): Promise<Role | null>;
6013
- /**
6014
- * Get a role by name.
6015
- * Automatically filtered by current tenant context.
6016
- */
6017
6706
  getRoleByName(name: string): Promise<Role | null>;
6018
- /**
6019
- * Create a new role.
6020
- * Tenant ID is automatically set from context.
6021
- */
6022
6707
  createRole(input: CreateRoleInput): Promise<Role>;
6023
- /**
6024
- * Update an existing role.
6025
- * Automatically filtered by current tenant context.
6026
- */
6027
6708
  updateRole(roleId: Uuid, updates: UpdateRoleInput): Promise<Role>;
6028
- /**
6029
- * Delete a role (fails if role is system role).
6030
- * Automatically filtered by current tenant context.
6031
- */
6032
6709
  deleteRole(roleId: Uuid): Promise<void>;
6033
- /**
6034
- * Get all permissions for a role.
6035
- * Automatically filtered by current tenant context.
6036
- */
6037
6710
  getPermissionsByRole(roleId: Uuid): Promise<Permission[]>;
6038
- /**
6039
- * Set permissions for a role (replaces existing permissions).
6040
- * Automatically filtered by current tenant context.
6041
- */
6042
6711
  setPermissions(roleId: Uuid, permissions: CreatePermissionInput[]): Promise<void>;
6043
- /**
6044
- * Get all roles assigned to a user profile.
6045
- * Automatically filtered by current tenant context.
6046
- */
6047
6712
  getUserRoles(userProfileId: Uuid): Promise<Role[]>;
6048
- /**
6049
- * Assign a role to a user profile.
6050
- * Tenant ID is automatically set from context.
6051
- */
6052
6713
  assignRole(input: AssignRoleInput): Promise<UserRoleAssignment>;
6053
- /**
6054
- * Revoke a role from a user profile.
6055
- * Automatically filtered by current tenant context.
6056
- */
6057
6714
  revokeRole(userProfileId: Uuid, roleId: Uuid): Promise<void>;
6715
+ getEffectivePermissions(userProfileId: Uuid): Promise<EffectivePermissions>;
6716
+ }
6717
+
6718
+ /**
6719
+ * Repository for workflow definitions.
6720
+ *
6721
+ * This repository is optional - if not provided in the DatabaseAdapter,
6722
+ * workflow features are disabled.
6723
+ */
6724
+ interface WorkflowsRepository {
6725
+ findById(id: Uuid): Promise<DBWorkflow | null>;
6726
+ findByName(name: string): Promise<DBWorkflow | null>;
6727
+ findSystemByName(name: string): Promise<DBWorkflow | null>;
6728
+ list(): Promise<DBWorkflow[]>;
6729
+ listByStatus(status: WorkflowStatus): Promise<DBWorkflow[]>;
6730
+ create(data: CreateDBWorkflow): Promise<DBWorkflow>;
6731
+ update(id: Uuid, data: Partial<UpdateDBWorkflow>): Promise<DBWorkflow>;
6732
+ delete(id: Uuid): Promise<void>;
6733
+ upsert(data: CreateDBWorkflow): Promise<DBWorkflow>;
6734
+ }
6735
+ /**
6736
+ * Repository for workflow instances (running/completed workflows).
6737
+ *
6738
+ * This repository is optional - if not provided in the DatabaseAdapter,
6739
+ * workflow execution features are disabled.
6740
+ */
6741
+ interface WorkflowInstancesRepository {
6742
+ findById(id: Uuid): Promise<DBWorkflowInstance | null>;
6743
+ findByWorkflowId(workflowId: Uuid, options?: {
6744
+ limit?: number;
6745
+ offset?: number;
6746
+ status?: InstanceStatus;
6747
+ }): Promise<DBWorkflowInstance[]>;
6748
+ findByWorkflowName(workflowName: string, options?: {
6749
+ limit?: number;
6750
+ offset?: number;
6751
+ status?: InstanceStatus;
6752
+ }): Promise<DBWorkflowInstance[]>;
6753
+ list(options?: ListOptions): Promise<{
6754
+ instances: DBWorkflowInstance[];
6755
+ total: number;
6756
+ }>;
6757
+ listByStatus(status: InstanceStatus): Promise<DBWorkflowInstance[]>;
6758
+ create(data: CreateDBWorkflowInstance): Promise<DBWorkflowInstance>;
6759
+ update(id: Uuid, data: Partial<UpdateDBWorkflowInstance>): Promise<DBWorkflowInstance>;
6760
+ upsert(data: CreateDBWorkflowInstance & {
6761
+ id: string;
6762
+ }): Promise<DBWorkflowInstance>;
6058
6763
  /**
6059
- * Get effective permissions for a user profile (merged from all assigned roles).
6060
- * Automatically filtered by current tenant context.
6764
+ * Find instances that reference a specific record in their slot context.
6765
+ * Searches in context.slots for slots where objectName and id match.
6061
6766
  *
6062
- * This method should:
6063
- * 1. Get all roles assigned to the user profile
6064
- * 2. Get all permissions for those roles
6065
- * 3. Merge permissions (union of actions per object)
6066
- * 4. Determine if user has admin privileges
6767
+ * @param objectName - Object name to match in slot data
6768
+ * @param recordId - Record ID to match in slot data
6769
+ * @param options - Optional filtering options
6067
6770
  */
6068
- getEffectivePermissions(userProfileId: Uuid): Promise<EffectivePermissions>;
6771
+ findByRecordInSlots(objectName: string, recordId: string, options?: {
6772
+ status?: InstanceStatus;
6773
+ limit?: number;
6774
+ offset?: number;
6775
+ }): Promise<{
6776
+ instances: DBWorkflowInstance[];
6777
+ total: number;
6778
+ }>;
6779
+ }
6780
+ /**
6781
+ * Repository for workflow invitations.
6782
+ */
6783
+ interface WorkflowInvitationsRepository {
6784
+ findById(id: Uuid): Promise<DBWorkflowInvitation | null>;
6785
+ findByInstanceId(instanceId: Uuid): Promise<DBWorkflowInvitation[]>;
6786
+ findByEmail(email: string): Promise<DBWorkflowInvitation[]>;
6787
+ create(data: CreateDBWorkflowInvitation): Promise<DBWorkflowInvitation>;
6788
+ update(id: Uuid, data: UpdateDBWorkflowInvitation): Promise<DBWorkflowInvitation>;
6789
+ }
6790
+ /**
6791
+ * Repository for workflow access grants.
6792
+ */
6793
+ interface WorkflowAccessGrantsRepository {
6794
+ findById(id: Uuid): Promise<DBWorkflowAccessGrant | null>;
6795
+ findByInvitationId(invitationId: Uuid): Promise<DBWorkflowAccessGrant[]>;
6796
+ findByInstanceId(instanceId: Uuid): Promise<DBWorkflowAccessGrant[]>;
6797
+ findByEmail(email: string): Promise<DBWorkflowAccessGrant[]>;
6798
+ create(data: CreateDBWorkflowAccessGrant): Promise<DBWorkflowAccessGrant>;
6799
+ update(id: Uuid, data: UpdateDBWorkflowAccessGrant): Promise<DBWorkflowAccessGrant>;
6800
+ }
6801
+
6802
+ /**
6803
+ * Repository for document templates.
6804
+ *
6805
+ * Templates define the structure of documents (slots, processing, etc.).
6806
+ */
6807
+ interface DocumentTemplatesRepository {
6808
+ findById(id: Uuid): Promise<DocumentTemplate | null>;
6809
+ findByName(name: string): Promise<DocumentTemplate | null>;
6810
+ findByNames(names: string[]): Promise<DocumentTemplate[]>;
6811
+ list(options?: DocumentTemplateListOptions): Promise<DocumentTemplate[]>;
6812
+ create(data: CreateDocumentTemplate): Promise<DocumentTemplate>;
6813
+ update(id: Uuid, data: UpdateDocumentTemplate): Promise<DocumentTemplate>;
6814
+ delete(id: Uuid): Promise<void>;
6815
+ }
6816
+ /**
6817
+ * Repository for documents.
6818
+ *
6819
+ * Documents are wrappers around files with templates, slots, and processing.
6820
+ */
6821
+ interface DocumentsRepository {
6822
+ create(data: CreateDocument): Promise<Document>;
6823
+ findById(id: Uuid): Promise<Document | null>;
6824
+ findByIds(ids: Uuid[]): Promise<Document[]>;
6825
+ update(id: Uuid, data: UpdateDocument): Promise<Document>;
6826
+ updateStatus(id: Uuid, status: DocumentStatus): Promise<Document>;
6827
+ delete(id: Uuid): Promise<void>;
6828
+ hardDelete(id: Uuid): Promise<void>;
6829
+ list(options?: DocumentListOptions): Promise<Document[]>;
6830
+ search(query: string, options?: DocumentListOptions): Promise<Document[]>;
6831
+ }
6832
+ /**
6833
+ * Repository for document slots.
6834
+ *
6835
+ * Slots are individual file entries within a document.
6836
+ */
6837
+ interface DocumentSlotsRepository {
6838
+ create(data: CreateDocumentSlot): Promise<DocumentSlot>;
6839
+ findById(id: Uuid): Promise<DocumentSlot | null>;
6840
+ findByDocumentId(documentId: Uuid): Promise<DocumentSlot[]>;
6841
+ findByDocumentAndSlot(documentId: Uuid, slotName: string): Promise<DocumentSlot | null>;
6842
+ update(id: Uuid, data: UpdateDocumentSlot): Promise<DocumentSlot>;
6843
+ updateStatus(id: Uuid, status: SlotStatus): Promise<DocumentSlot>;
6844
+ delete(id: Uuid): Promise<void>;
6845
+ deleteByDocumentId(documentId: Uuid): Promise<void>;
6846
+ }
6847
+ /**
6848
+ * Repository for document processing jobs.
6849
+ *
6850
+ * Jobs track async processing tasks (OCR, signature, verification).
6851
+ */
6852
+ interface DocumentJobsRepository {
6853
+ create(data: CreateProcessingJob): Promise<ProcessingJob>;
6854
+ findById(id: Uuid): Promise<ProcessingJob | null>;
6855
+ findByDocumentId(documentId: Uuid): Promise<ProcessingJob[]>;
6856
+ findByStatus(status: ProcessingJobStatus, limit?: number): Promise<ProcessingJob[]>;
6857
+ findPending(limit?: number): Promise<ProcessingJob[]>;
6858
+ update(id: Uuid, data: UpdateProcessingJob): Promise<ProcessingJob>;
6859
+ markStarted(id: Uuid): Promise<ProcessingJob>;
6860
+ markCompleted(id: Uuid, result: Record<string, unknown>): Promise<ProcessingJob>;
6861
+ markFailed(id: Uuid, error: string): Promise<ProcessingJob>;
6862
+ cancel(id: Uuid): Promise<ProcessingJob>;
6863
+ findByExternalId?(externalId: string): Promise<ProcessingJob | null>;
6864
+ }
6865
+ /**
6866
+ * List options for document generation templates
6867
+ */
6868
+ interface DocumentGenerationTemplateListOptions {
6869
+ /** Filter by source type */
6870
+ sourceType?: "pdf" | "docx";
6871
+ /** Limit results */
6872
+ limit?: number;
6873
+ /** Offset for pagination */
6874
+ offset?: number;
6875
+ }
6876
+ /**
6877
+ * Repository for document generation templates.
6878
+ */
6879
+ interface DocumentGenerationTemplatesRepository {
6880
+ findById(id: Uuid): Promise<DocumentGenerationTemplate | null>;
6881
+ findByName(name: string): Promise<DocumentGenerationTemplate | null>;
6882
+ list(options?: DocumentGenerationTemplateListOptions): Promise<DocumentGenerationTemplate[]>;
6883
+ create(data: CreateDocumentGenerationTemplate): Promise<DocumentGenerationTemplate>;
6884
+ update(id: Uuid, data: UpdateDocumentGenerationTemplate): Promise<DocumentGenerationTemplate>;
6885
+ delete(id: Uuid): Promise<void>;
6069
6886
  }
6070
6887
 
6071
6888
  /**
@@ -6073,20 +6890,9 @@ interface PermissionsRepository {
6073
6890
  *
6074
6891
  * This repository is optional - if not provided in the DatabaseAdapter,
6075
6892
  * AI conversation history features are disabled.
6076
- *
6077
- * All operations are automatically scoped to the current tenant
6078
- * from the execution context (via AsyncLocalStorage).
6079
6893
  */
6080
6894
  interface AIConversationsRepository {
6081
- /**
6082
- * Find conversation by ID.
6083
- * Automatically filtered by current tenant context.
6084
- */
6085
6895
  findById(id: Uuid): Promise<AIConversation | null>;
6086
- /**
6087
- * List conversations for current user.
6088
- * Automatically filtered by current tenant and user context.
6089
- */
6090
6896
  list(options?: {
6091
6897
  limit?: number;
6092
6898
  offset?: number;
@@ -6095,32 +6901,12 @@ interface AIConversationsRepository {
6095
6901
  conversations: AIConversation[];
6096
6902
  total: number;
6097
6903
  }>;
6098
- /**
6099
- * Create conversation.
6100
- * Tenant ID and User ID are automatically set from context.
6101
- */
6102
6904
  create(data: {
6103
6905
  title?: string;
6104
6906
  }): Promise<AIConversation>;
6105
- /**
6106
- * Update conversation title.
6107
- * Automatically filtered by current tenant context.
6108
- */
6109
6907
  updateTitle(id: Uuid, title: string): Promise<AIConversation | null>;
6110
- /**
6111
- * Soft delete conversation.
6112
- * Automatically filtered by current tenant context.
6113
- */
6114
6908
  delete(id: Uuid): Promise<boolean>;
6115
- /**
6116
- * Add message to conversation.
6117
- * Automatically updates conversation stats.
6118
- */
6119
6909
  addMessage(input: CreateAIMessageInput): Promise<AIMessage>;
6120
- /**
6121
- * List messages in a conversation.
6122
- * Automatically filtered by current tenant context (via conversation ownership).
6123
- */
6124
6910
  listMessages(conversationId: Uuid, options?: {
6125
6911
  limit?: number;
6126
6912
  offset?: number;
@@ -6128,10 +6914,6 @@ interface AIConversationsRepository {
6128
6914
  messages: AIMessage[];
6129
6915
  total: number;
6130
6916
  }>;
6131
- /**
6132
- * Get recent messages for context (last N messages).
6133
- * Returns messages ordered by created_at ASC.
6134
- */
6135
6917
  getRecentMessages(conversationId: Uuid, count?: number): Promise<AIMessage[]>;
6136
6918
  }
6137
6919
  /**
@@ -6139,41 +6921,16 @@ interface AIConversationsRepository {
6139
6921
  *
6140
6922
  * This repository is optional - if not provided in the DatabaseAdapter,
6141
6923
  * AI personalization features are disabled.
6142
- *
6143
- * All operations are automatically scoped to the current tenant and user
6144
- * from the execution context (via AsyncLocalStorage).
6145
6924
  */
6146
6925
  interface AIUserMemoryRepository {
6147
- /**
6148
- * Get memory for current user.
6149
- * Automatically filtered by current tenant and user context.
6150
- * Returns null if no memory exists yet.
6151
- */
6152
6926
  get(): Promise<AIUserMemory | null>;
6153
- /**
6154
- * Create or update memory for current user.
6155
- * Tenant ID and User ID are automatically set from context.
6156
- */
6157
6927
  upsert(data: {
6158
6928
  preferences?: Record<string, unknown>;
6159
6929
  facts?: string[];
6160
6930
  }): Promise<AIUserMemory>;
6161
- /**
6162
- * Add a fact to user memory.
6163
- * Automatically appends to existing facts.
6164
- */
6165
6931
  addFact(fact: string): Promise<AIUserMemory>;
6166
- /**
6167
- * Remove a fact from user memory.
6168
- */
6169
6932
  removeFact(fact: string): Promise<AIUserMemory>;
6170
- /**
6171
- * Update a specific preference.
6172
- */
6173
6933
  setPreference(key: string, value: unknown): Promise<AIUserMemory>;
6174
- /**
6175
- * Clear all memory for current user.
6176
- */
6177
6934
  clear(): Promise<void>;
6178
6935
  }
6179
6936
  /**
@@ -6181,30 +6938,15 @@ interface AIUserMemoryRepository {
6181
6938
  *
6182
6939
  * This repository is optional - if not provided in the DatabaseAdapter,
6183
6940
  * AI usage tracking is disabled.
6184
- *
6185
- * All operations are automatically scoped to the current tenant
6186
- * from the execution context (via AsyncLocalStorage).
6187
6941
  */
6188
6942
  interface AIUsageMetricsRepository {
6189
- /**
6190
- * Record a usage event (increments counters for the current date).
6191
- * Automatically handles upsert for the current date.
6192
- */
6193
6943
  recordUsage(data: {
6194
6944
  provider: string;
6195
6945
  tokens: number;
6196
6946
  cost: number;
6197
6947
  toolName?: string;
6198
6948
  }): Promise<void>;
6199
- /**
6200
- * Get usage metrics for a date range.
6201
- * Automatically filtered by current tenant context.
6202
- */
6203
6949
  getByDateRange(startDate: Date, endDate: Date): Promise<AIUsageMetrics[]>;
6204
- /**
6205
- * Get aggregated usage for current month.
6206
- * Automatically filtered by current tenant context.
6207
- */
6208
6950
  getCurrentMonthUsage(): Promise<{
6209
6951
  requestCount: number;
6210
6952
  totalTokens: number;
@@ -6369,6 +7111,16 @@ interface StorageAdapter {
6369
7111
  * @returns true if file exists
6370
7112
  */
6371
7113
  exists?(storagePath: string): Promise<boolean>;
7114
+ /**
7115
+ * Download file content from storage
7116
+ *
7117
+ * Optional method - required for document processing features.
7118
+ * If not implemented, processing features will be unavailable.
7119
+ *
7120
+ * @param storagePath - Path to the file in storage
7121
+ * @returns File content as Buffer
7122
+ */
7123
+ download?(storagePath: string): Promise<Buffer>;
6372
7124
  }
6373
7125
  /**
6374
7126
  * Input for FileService.uploadFile() method
@@ -6439,7 +7191,8 @@ interface DatabaseAdapter {
6439
7191
  views: ViewsRepository;
6440
7192
  workflows?: WorkflowsRepository;
6441
7193
  workflowInstances?: WorkflowInstancesRepository;
6442
- workflowParticipations?: WorkflowParticipationsRepository;
7194
+ workflowInvitations?: WorkflowInvitationsRepository;
7195
+ workflowAccessGrants?: WorkflowAccessGrantsRepository;
6443
7196
  userProfiles: UserProfilesRepository;
6444
7197
  files: FilesRepository;
6445
7198
  objectRecords: ObjectRecordsRepository;
@@ -6450,155 +7203,178 @@ interface DatabaseAdapter {
6450
7203
  aiConversations?: AIConversationsRepository;
6451
7204
  aiUserMemory?: AIUserMemoryRepository;
6452
7205
  aiUsageMetrics?: AIUsageMetricsRepository;
7206
+ documents?: DocumentsRepository;
7207
+ documentTemplates?: DocumentTemplatesRepository;
7208
+ documentSlots?: DocumentSlotsRepository;
7209
+ documentJobs?: DocumentJobsRepository;
7210
+ documentGenerationTemplates?: DocumentGenerationTemplatesRepository;
6453
7211
  transaction<T>(callback: (adapter: DatabaseAdapter) => Promise<T>): Promise<T>;
6454
7212
  }
6455
7213
 
6456
7214
  /**
6457
- * Payload encoded in the participation token
7215
+ * Base JWT claims for workflow tokens
6458
7216
  */
6459
- interface ParticipationTokenPayload {
6460
- /** Participation ID */
6461
- participationId: string;
6462
- /** Instance ID */
6463
- instanceId: string;
6464
- /** Tenant ID */
6465
- tenantId: string;
6466
- /** Expiration timestamp (unix ms) */
7217
+ interface BaseWorkflowClaims extends JWTPayload {
7218
+ /** Issuer */
7219
+ iss: string;
7220
+ /** Audience (tenant ID) */
7221
+ aud: string;
7222
+ /** Subject (invitation or grant ID) */
7223
+ sub: string;
7224
+ /** Expiration timestamp */
6467
7225
  exp: number;
6468
- /** Issued at timestamp (unix ms) */
7226
+ /** Issued at timestamp */
6469
7227
  iat: number;
6470
- /** Token ID (for revocation) */
7228
+ /** JWT ID (for revocation) */
6471
7229
  jti: string;
6472
7230
  }
6473
7231
  /**
6474
- * Options for token generation
7232
+ * Magic link JWT payload (one-time use for accepting invitation)
6475
7233
  */
6476
- interface TokenGenerationOptions {
6477
- /** Expiration duration (e.g., "7d", "24h", "1h") */
6478
- expiresIn?: string;
7234
+ interface MagicLinkPayload extends BaseWorkflowClaims {
7235
+ /** Token type */
7236
+ typ: "magic_link";
7237
+ /** Workflow instance ID */
7238
+ instance: string;
7239
+ /** Tenant ID */
7240
+ tenant: string;
6479
7241
  }
6480
7242
  /**
6481
- * Result of token verification
7243
+ * Access token JWT payload (long-lived for accessing workflow)
6482
7244
  */
6483
- interface TokenVerificationResult {
7245
+ interface WorkflowAccessPayload extends BaseWorkflowClaims {
7246
+ /** Token type */
7247
+ typ: "workflow_access";
7248
+ /** Grant ID */
7249
+ sub: string;
7250
+ /** Workflow instance ID */
7251
+ instance: string;
7252
+ /** Tenant ID */
7253
+ tenant: string;
7254
+ /** Access scope */
7255
+ scope: string[];
7256
+ }
7257
+ type WorkflowJwtPayload = MagicLinkPayload | WorkflowAccessPayload;
7258
+ interface JwtVerificationResult {
6484
7259
  valid: boolean;
6485
- payload?: ParticipationTokenPayload;
7260
+ payload?: WorkflowJwtPayload;
6486
7261
  error?: string;
7262
+ errorCode?: "EXPIRED" | "INVALID_SIGNATURE" | "MALFORMED" | "UNKNOWN";
7263
+ }
7264
+ interface WorkflowJwtConfig {
7265
+ /** Private key for signing (PEM string or CryptoKey) */
7266
+ privateKey: string | CryptoKey;
7267
+ /** Public key for verification (PEM string or CryptoKey) */
7268
+ publicKey: string | CryptoKey;
7269
+ /** Issuer claim (default: "stndrds/workflows") */
7270
+ issuer?: string;
7271
+ /** Access token TTL (default: "7d") */
7272
+ accessTokenTTL?: string;
7273
+ /** Magic link TTL (default: "15m") */
7274
+ magicLinkTTL?: string;
6487
7275
  }
6488
7276
  /**
6489
- * Service for generating and verifying participation tokens.
7277
+ * Service for generating and verifying workflow JWT tokens.
7278
+ *
7279
+ * Uses ES256 (ECDSA with P-256 curve) for signing, which is:
7280
+ * - More secure than HMAC (asymmetric)
7281
+ * - Smaller signatures than RSA
7282
+ * - Edge-runtime compatible (via jose)
7283
+ *
7284
+ * @example
7285
+ * ```typescript
7286
+ * const jwtService = await WorkflowJwtService.create({
7287
+ * privateKey: process.env.WORKFLOW_JWT_PRIVATE_KEY!,
7288
+ * publicKey: process.env.WORKFLOW_JWT_PUBLIC_KEY!,
7289
+ * });
6490
7290
  *
6491
- * This is a minimal implementation that encodes data in base64.
6492
- * In production, this should use proper JWT with HMAC/RSA signing.
7291
+ * // Generate magic link
7292
+ * const token = await jwtService.signMagicLink({
7293
+ * invitationId: "inv_123",
7294
+ * instanceId: "inst_456",
7295
+ * tenantId: "tenant_789",
7296
+ * });
6493
7297
  *
6494
- * The signing key should be injected from environment configuration.
7298
+ * // Verify token
7299
+ * const result = await jwtService.verify(token);
7300
+ * if (result.valid && result.payload?.typ === "magic_link") {
7301
+ * // Handle magic link
7302
+ * }
7303
+ * ```
6495
7304
  */
6496
- declare class ParticipationTokenService {
6497
- private secret;
6498
- constructor(secret?: string);
7305
+ declare class WorkflowJwtService {
7306
+ private config;
7307
+ private privateKey;
7308
+ private publicKey;
7309
+ private issuer;
7310
+ private accessTokenTTL;
7311
+ private magicLinkTTL;
7312
+ private initialized;
7313
+ private constructor();
7314
+ /**
7315
+ * Create and initialize the JWT service.
7316
+ * Handles async key import from PEM strings.
7317
+ */
7318
+ static create(config: WorkflowJwtConfig): Promise<WorkflowJwtService>;
7319
+ private initialize;
7320
+ /**
7321
+ * Sign a magic link JWT (one-time use, short-lived)
7322
+ *
7323
+ * @param params - Magic link parameters
7324
+ * @returns Signed JWT token
7325
+ */
7326
+ signMagicLink(params: {
7327
+ invitationId: string;
7328
+ instanceId: string;
7329
+ tenantId: string;
7330
+ expiresIn?: string;
7331
+ }): Promise<string>;
6499
7332
  /**
6500
- * Generate a participation token (signed link)
7333
+ * Sign an access token JWT (long-lived)
7334
+ *
7335
+ * @param params - Access token parameters
7336
+ * @returns Signed JWT token
6501
7337
  */
6502
- generateToken(participation: Pick<WorkflowParticipation, "id" | "instanceId"> & {
7338
+ signAccessToken(params: {
7339
+ grantId: string;
7340
+ instanceId: string;
6503
7341
  tenantId: string;
6504
- }, options?: TokenGenerationOptions): SignedLinkAuth;
7342
+ scope: string[];
7343
+ expiresIn?: string;
7344
+ }): Promise<string>;
7345
+ /**
7346
+ * Verify and decode a JWT token.
7347
+ *
7348
+ * Returns a result object with:
7349
+ * - valid: boolean
7350
+ * - payload: the decoded payload if valid
7351
+ * - error: human-readable error message if invalid
7352
+ * - errorCode: machine-readable error code if invalid
7353
+ *
7354
+ * @param token - JWT token to verify
7355
+ * @returns Verification result
7356
+ */
7357
+ verify(token: string): Promise<JwtVerificationResult>;
6505
7358
  /**
6506
- * Verify a participation token
7359
+ * Verify token and return payload directly.
7360
+ * Throws on invalid token.
7361
+ *
7362
+ * @param token - JWT token to verify
7363
+ * @returns Decoded payload
7364
+ * @throws Error if token is invalid
6507
7365
  */
6508
- verifyToken(token: string): TokenVerificationResult;
7366
+ verifyOrThrow(token: string): Promise<WorkflowJwtPayload>;
7367
+ private handleVerifyError;
6509
7368
  /**
6510
- * Generate a shareable link URL
7369
+ * Generate a magic link URL from a token
6511
7370
  */
6512
- generateLink(baseUrl: string, token: string): string;
7371
+ generateMagicLinkUrl(baseUrl: string, token: string): string;
6513
7372
  /**
6514
- * Extract token from a participation link
7373
+ * Extract token from a magic link URL
6515
7374
  */
6516
- extractTokenFromLink(url: string): string | null;
6517
- private encodeToken;
6518
- private decodeToken;
6519
- private sign;
6520
- private parseExpiration;
6521
- private base64Encode;
6522
- private base64Decode;
7375
+ extractTokenFromUrl(url: string): string | null;
6523
7376
  }
6524
- /**
6525
- * Get the default token service instance
6526
- */
6527
- declare function getDefaultTokenService(): ParticipationTokenService;
6528
- /**
6529
- * Initialize the token service with a custom secret
6530
- */
6531
- declare function initializeTokenService(secret: string): ParticipationTokenService;
6532
-
6533
- /**
6534
- * Options for PIN code generation
6535
- */
6536
- interface PinCodeGenerationOptions {
6537
- /** Length of the PIN code (default: 6) */
6538
- length?: number;
6539
- /** Expiration duration (e.g., "24h", "7d") */
6540
- expiresIn?: string;
6541
- /** Maximum attempts before lockout (default: 3) */
6542
- maxAttempts?: number;
6543
- }
6544
- /**
6545
- * Result of PIN code verification
6546
- */
6547
- interface PinCodeVerificationResult {
6548
- valid: boolean;
6549
- error?: string;
6550
- attemptsRemaining?: number;
6551
- lockedUntil?: Date;
6552
- }
6553
- /**
6554
- * Service for generating and verifying PIN codes.
6555
- *
6556
- * PIN codes are hashed before storage for security.
6557
- * This implementation uses a simple hash for demonstration.
6558
- * In production, use bcrypt or argon2.
6559
- */
6560
- declare class PinCodeService {
6561
- private salt;
6562
- constructor(salt?: string);
6563
- /**
6564
- * Generate a PIN code and its auth object
6565
- */
6566
- generate(options?: PinCodeGenerationOptions): {
6567
- code: string;
6568
- auth: PinCodeAuth;
6569
- };
6570
- /**
6571
- * Verify a PIN code against stored auth
6572
- */
6573
- verify(inputCode: string, auth: PinCodeAuth): PinCodeVerificationResult;
6574
- /**
6575
- * Record a failed attempt and return updated auth
6576
- */
6577
- recordFailedAttempt(auth: PinCodeAuth): PinCodeAuth;
6578
- /**
6579
- * Reset attempts (after successful verification or admin reset)
6580
- */
6581
- resetAttempts(auth: PinCodeAuth): PinCodeAuth;
6582
- /**
6583
- * Generate a new PIN code (for resend functionality)
6584
- */
6585
- regenerate(auth: PinCodeAuth, options?: PinCodeGenerationOptions): {
6586
- code: string;
6587
- auth: PinCodeAuth;
6588
- };
6589
- private generateNumericCode;
6590
- private hashCode;
6591
- private parseExpiration;
6592
- }
6593
- /**
6594
- * Get the default PIN code service instance
6595
- */
6596
- declare function getDefaultPinCodeService(): PinCodeService;
6597
- /**
6598
- * Initialize the PIN code service with a custom salt
6599
- */
6600
- declare function initializePinCodeService(salt: string): PinCodeService;
6601
-
7377
+
6602
7378
  /**
6603
7379
  * Formatted record with values flattened to root level.
6604
7380
  * This is the default return type for queries (easier to use).
@@ -7163,14 +7939,6 @@ declare abstract class SchemaContextAwareRepository extends BaseRepository {
7163
7939
  */
7164
7940
  protected getSchemaByNameFromContext(objectName: string): ObjectDefinition | undefined;
7165
7941
  }
7166
- /**
7167
- * @deprecated Use `BaseRepository` instead. Will be removed in a future version.
7168
- */
7169
- declare const TenantAwareRepository: typeof BaseRepository;
7170
- /**
7171
- * @deprecated Use `BaseService` instead. Will be removed in a future version.
7172
- */
7173
- declare const TenantAwareService: typeof BaseService;
7174
7942
 
7175
7943
  /**
7176
7944
  * Service for audit logging.
@@ -8004,6 +8772,11 @@ declare class RecordService extends BaseService {
8004
8772
  skipHooks?: boolean;
8005
8773
  hookMetadata?: Record<string, unknown>;
8006
8774
  }): Promise<ObjectRecord>;
8775
+ /**
8776
+ * Invalidate all caches related to a record (record cache + lists + global search)
8777
+ * @private
8778
+ */
8779
+ private invalidateRecordCaches;
8007
8780
  /**
8008
8781
  * List records for an object with pagination.
8009
8782
  * Delegates to RecordQueryService for permissions and policy handling.
@@ -9656,6 +10429,12 @@ interface ExecutorContext {
9656
10429
  input?: Record<string, unknown>;
9657
10430
  /** ID of the user/participant executing */
9658
10431
  executorId?: string;
10432
+ /**
10433
+ * Object definitions for field validation (optional).
10434
+ * When provided, executors like FormExecutor can validate required fields
10435
+ * against attribute metadata.
10436
+ */
10437
+ objectDefinitions?: ObjectDefinition[];
9659
10438
  }
9660
10439
  /**
9661
10440
  * Interface for node executors.
@@ -9749,6 +10528,47 @@ declare class ConditionExecutor implements NodeExecutor<ConditionNode> {
9749
10528
  validate(node: ConditionNode): string[];
9750
10529
  }
9751
10530
 
10531
+ /**
10532
+ * Executor for DocumentNode.
10533
+ *
10534
+ * This executor handles document generation nodes. It validates the node configuration
10535
+ * and creates a pending document request in the execution context.
10536
+ *
10537
+ * The actual document generation is delegated to the consumer (NestJS, Supabase, etc.)
10538
+ * which processes pending document requests before advancing to the next node.
10539
+ *
10540
+ * Behavior:
10541
+ * - Validates that templateId is set
10542
+ * - Creates a pending document request in context.documents
10543
+ * - Returns success with the next node ID
10544
+ *
10545
+ * The consumer is responsible for:
10546
+ * 1. Detecting pending document requests (status: "pending")
10547
+ * 2. Loading the template from DocumentGenerationTemplatesRepository
10548
+ * 3. Resolving variable values from the execution context
10549
+ * 4. Generating the PDF using pdf-lib
10550
+ * 5. Uploading the generated document to storage
10551
+ * 6. Attaching to target records via DocumentsRepository
10552
+ * 7. Updating context.documents with the final URL and metadata
10553
+ */
10554
+ declare class DocumentExecutor implements NodeExecutor<DocumentNode> {
10555
+ readonly nodeType: "document";
10556
+ execute(node: DocumentNode, _context: ExecutorContext): ExecutorResult;
10557
+ canExecute(_node: DocumentNode, _context: ExecutorContext): boolean;
10558
+ validate(node: DocumentNode): string[];
10559
+ /**
10560
+ * Validate that targetSlotIds reference existing slots in the workflow definition.
10561
+ * This is a context-aware validation that requires the workflow's slot definitions.
10562
+ *
10563
+ * @param node - The document node to validate
10564
+ * @param workflowSlots - All slots defined in the workflow
10565
+ * @returns Array of validation error messages
10566
+ */
10567
+ validateSlotReferences(node: DocumentNode, workflowSlots: {
10568
+ id: string;
10569
+ }[]): string[];
10570
+ }
10571
+
9752
10572
  /**
9753
10573
  * Executor for EndNode.
9754
10574
  * Marks the workflow as completed with an optional status.
@@ -10157,12 +10977,14 @@ interface MockStores {
10157
10977
  userRoles: Map<Uuid, UserRoleAssignment>;
10158
10978
  workflows: Map<Uuid, DBWorkflow>;
10159
10979
  workflowInstances: Map<Uuid, DBWorkflowInstance>;
10160
- workflowParticipations: Map<Uuid, DBWorkflowParticipation>;
10980
+ workflowInvitations: Map<Uuid, DBWorkflowInvitation>;
10981
+ workflowAccessGrants: Map<Uuid, DBWorkflowAccessGrant>;
10161
10982
  aiConversations: Map<Uuid, AIConversation>;
10162
10983
  aiMessages: Map<Uuid, AIMessage>;
10163
10984
  aiUserMemory: Map<string, AIUserMemory>;
10164
10985
  aiUsageMetrics: Map<string, AIUsageMetrics>;
10165
10986
  }
10987
+
10166
10988
  /**
10167
10989
  * Create an in-memory mock adapter for testing and development
10168
10990
  *
@@ -10219,18 +11041,852 @@ declare function createMockAdapter(): DatabaseAdapter & {
10219
11041
  declare const notesPolicy: RecordPolicy;
10220
11042
 
10221
11043
  /**
10222
- * Input for creating a workflow
11044
+ * Document Generation Service
11045
+ *
11046
+ * Manages document generation templates used in workflow document nodes.
11047
+ * Templates define how to generate PDF documents by injecting workflow
11048
+ * context data into PDF template files.
10223
11049
  */
10224
- interface CreateWorkflowInput {
10225
- name: string;
10226
- label: string;
10227
- description?: string;
10228
- icon?: IconName;
10229
- slots: WorkflowSlot[];
10230
- nodes: Record<string, WorkflowNode>;
10231
- startNodeId: string;
10232
- layout: WorkflowLayout;
10233
- participants?: ParticipantTemplate[];
11050
+
11051
+ /**
11052
+ * Error thrown when document generation template is not found
11053
+ */
11054
+ declare class DocumentGenerationTemplateNotFoundError extends Error {
11055
+ readonly templateId: string;
11056
+ constructor(templateId: string);
11057
+ }
11058
+ /**
11059
+ * Error thrown when document generation templates repository is not available
11060
+ */
11061
+ declare class DocumentGenerationNotConfiguredError extends Error {
11062
+ constructor();
11063
+ }
11064
+ /**
11065
+ * Service for managing document generation templates.
11066
+ *
11067
+ * Used by:
11068
+ * - Workflow builder UI (create/edit templates)
11069
+ * - Workflow document nodes (load template for generation)
11070
+ * - NestJS controller (CRUD API)
11071
+ *
11072
+ * @example
11073
+ * ```typescript
11074
+ * const service = new DocumentGenerationService(adapter);
11075
+ *
11076
+ * // Create a new template
11077
+ * const template = await service.create({
11078
+ * name: "sales-contract",
11079
+ * label: "Sales Contract",
11080
+ * source: {
11081
+ * type: "pdf",
11082
+ * fileId: "file_123",
11083
+ * fields: [
11084
+ * { id: "f1", page: 0, x: 100, y: 200, width: 150, height: 20, contextPath: "slots.client.name", label: "Client Name" }
11085
+ * ]
11086
+ * }
11087
+ * });
11088
+ *
11089
+ * // Get template for workflow execution
11090
+ * const template = await service.getById(templateId);
11091
+ * ```
11092
+ */
11093
+ declare class DocumentGenerationService extends BaseService {
11094
+ /**
11095
+ * Get the document generation templates repository.
11096
+ * @throws DocumentGenerationNotConfiguredError if repository not available
11097
+ */
11098
+ private get repo();
11099
+ /**
11100
+ * Get a template by ID.
11101
+ *
11102
+ * @param id - Template ID
11103
+ * @returns Template or null if not found
11104
+ */
11105
+ getById(id: Uuid): Promise<DocumentGenerationTemplate | null>;
11106
+ /**
11107
+ * Get a template by ID, throwing if not found.
11108
+ *
11109
+ * @param id - Template ID
11110
+ * @returns Template
11111
+ * @throws DocumentGenerationTemplateNotFoundError if not found
11112
+ */
11113
+ getByIdOrThrow(id: Uuid): Promise<DocumentGenerationTemplate>;
11114
+ /**
11115
+ * Get a template by name.
11116
+ *
11117
+ * @param name - Template name (unique within tenant)
11118
+ * @returns Template or null if not found
11119
+ */
11120
+ getByName(name: string): Promise<DocumentGenerationTemplate | null>;
11121
+ /**
11122
+ * List templates for the current tenant.
11123
+ *
11124
+ * @param options - List options (sourceType filter, pagination)
11125
+ * @returns Array of templates
11126
+ */
11127
+ list(options?: {
11128
+ sourceType?: "pdf" | "docx";
11129
+ limit?: number;
11130
+ offset?: number;
11131
+ }): Promise<DocumentGenerationTemplate[]>;
11132
+ /**
11133
+ * Create a new document generation template.
11134
+ *
11135
+ * @param input - Template data
11136
+ * @returns Created template
11137
+ */
11138
+ create(input: CreateDocumentGenerationTemplate): Promise<DocumentGenerationTemplate>;
11139
+ /**
11140
+ * Update a template.
11141
+ *
11142
+ * @param id - Template ID
11143
+ * @param input - Fields to update
11144
+ * @returns Updated template
11145
+ */
11146
+ update(id: Uuid, input: UpdateDocumentGenerationTemplate): Promise<DocumentGenerationTemplate>;
11147
+ /**
11148
+ * Delete a template.
11149
+ *
11150
+ * @param id - Template ID
11151
+ */
11152
+ delete(id: Uuid): Promise<void>;
11153
+ }
11154
+
11155
+ /**
11156
+ * Options for FileService constructor
11157
+ */
11158
+ interface FileServiceOptions {
11159
+ /**
11160
+ * Audit service for logging file operations.
11161
+ * If provided, audit logging is enabled using userId from context.
11162
+ * If not provided, no audit logs are created (backward compatible).
11163
+ */
11164
+ auditService?: AuditService;
11165
+ }
11166
+ /**
11167
+ * Service for managing files.
11168
+ *
11169
+ * Handles file metadata CRUD, permissions, storage operations, and audit logging.
11170
+ * Works with optional StorageAdapter for file upload/download operations.
11171
+ * Automatically uses tenant context from AsyncLocalStorage.
11172
+ *
11173
+ * @example
11174
+ * ```typescript
11175
+ * // Basic usage (metadata only)
11176
+ * const service = new FileService(adapter);
11177
+ *
11178
+ * // With audit logging
11179
+ * const auditService = new AuditService(adapter);
11180
+ * const service = new FileService(adapter, { auditService });
11181
+ *
11182
+ * // Upload file (requires StorageAdapter)
11183
+ * const file = await service.uploadFile({
11184
+ * content: fileBuffer,
11185
+ * fileName: "contract.pdf",
11186
+ * mimeType: "application/pdf",
11187
+ * size: 12345,
11188
+ * uploadedBy: "user-456",
11189
+ * });
11190
+ * ```
11191
+ */
11192
+ declare class FileService extends BaseService {
11193
+ private auditService?;
11194
+ constructor(adapter: DatabaseAdapter, options?: FileServiceOptions);
11195
+ /**
11196
+ * Upload a file to storage and create metadata record.
11197
+ *
11198
+ * This method orchestrates:
11199
+ * 1. Upload to storage (via StorageAdapter)
11200
+ * 2. Create file metadata in database
11201
+ * 3. Audit log the operation
11202
+ *
11203
+ * Requires `adapter.storage` to be configured.
11204
+ *
11205
+ * @param input - File content and metadata
11206
+ * @returns Created file record
11207
+ * @throws Error if StorageAdapter is not configured
11208
+ *
11209
+ * @example
11210
+ * ```typescript
11211
+ * const file = await service.uploadFile({
11212
+ * content: fileBuffer,
11213
+ * fileName: "document.pdf",
11214
+ * mimeType: "application/pdf",
11215
+ * size: 12345,
11216
+ * uploadedBy: "user-123",
11217
+ * visibility: "private",
11218
+ * folderPath: "/documents",
11219
+ * tags: ["contract", "2025"],
11220
+ * });
11221
+ * ```
11222
+ */
11223
+ uploadFile(input: UploadFileInput): Promise<File>;
11224
+ /**
11225
+ * Create a new file record (after upload to storage).
11226
+ *
11227
+ * Use this method when handling storage externally (e.g., with Multer + S3).
11228
+ * For integrated upload, use `uploadFile()` instead.
11229
+ *
11230
+ * @param data - File metadata
11231
+ * @returns Created file record
11232
+ *
11233
+ * @example
11234
+ * ```typescript
11235
+ * // After uploading to S3 with Multer
11236
+ * const file = await service.createFile({
11237
+ * tenantId: "tenant-123",
11238
+ * name: "contract-2025.pdf",
11239
+ * originalName: "Contract Acme Corp 2025.pdf",
11240
+ * mimeType: "application/pdf",
11241
+ * size: 2458624,
11242
+ * storageProvider: "s3",
11243
+ * storagePath: "tenants/123/files/2025/contract.pdf",
11244
+ * storageBucket: "my-app-files",
11245
+ * url: "https://cdn.example.com/files/file-123",
11246
+ * uploadedBy: "profile-456",
11247
+ * visibility: "private"
11248
+ * });
11249
+ * ```
11250
+ */
11251
+ createFile(data: CreateFile): Promise<File>;
11252
+ /**
11253
+ * Get file by ID
11254
+ */
11255
+ getFile(fileId: string): Promise<File | null>;
11256
+ /**
11257
+ * Get file by ID or throw
11258
+ */
11259
+ getFileOrThrow(fileId: string): Promise<File>;
11260
+ /**
11261
+ * Update file metadata
11262
+ *
11263
+ * @param fileId - File UUID
11264
+ * @param data - Data to update
11265
+ * @returns Updated file
11266
+ */
11267
+ updateFile(fileId: string, data: UpdateFile): Promise<File>;
11268
+ /**
11269
+ * Delete file (soft delete by default)
11270
+ *
11271
+ * @param fileId - File UUID
11272
+ * @param options - Delete options
11273
+ */
11274
+ deleteFile(fileId: string, options?: {
11275
+ hard?: boolean;
11276
+ checkOwnership?: boolean;
11277
+ userId?: string;
11278
+ }): Promise<void>;
11279
+ /**
11280
+ * Delete file from both storage and database.
11281
+ *
11282
+ * Requires `adapter.storage` to be configured.
11283
+ *
11284
+ * @param fileId - File UUID
11285
+ * @param options - Delete options
11286
+ * @throws Error if StorageAdapter is not configured
11287
+ */
11288
+ deleteFileWithStorage(fileId: string, options?: {
11289
+ hard?: boolean;
11290
+ }): Promise<void>;
11291
+ /**
11292
+ * Delete multiple files
11293
+ *
11294
+ * @param fileIds - Array of file UUIDs
11295
+ * @param options - Delete options
11296
+ */
11297
+ bulkDelete(fileIds: string[], options?: {
11298
+ hard?: boolean;
11299
+ deleteFromStorage?: boolean;
11300
+ }): Promise<void>;
11301
+ /**
11302
+ * List files for the tenant
11303
+ */
11304
+ listFiles(options?: FileListOptions): Promise<File[]>;
11305
+ /**
11306
+ * List files by folder
11307
+ */
11308
+ listFilesByFolder(folderPath: string): Promise<File[]>;
11309
+ /**
11310
+ * List files uploaded by a specific user
11311
+ */
11312
+ listFilesByUploader(uploadedBy: string): Promise<File[]>;
11313
+ /**
11314
+ * Get a signed URL for private file access.
11315
+ *
11316
+ * Checks access permissions before generating URL.
11317
+ * Requires `adapter.storage` to be configured.
11318
+ *
11319
+ * @param fileId - File UUID
11320
+ * @param userId - User requesting access
11321
+ * @param options - Signed URL options
11322
+ * @returns Signed URL
11323
+ * @throws Error if user doesn't have access or StorageAdapter is not configured
11324
+ *
11325
+ * @example
11326
+ * ```typescript
11327
+ * const url = await service.getSignedUrl("file-123", "user-456", {
11328
+ * expiresIn: 3600, // 1 hour
11329
+ * });
11330
+ * ```
11331
+ */
11332
+ getSignedUrl(fileId: string, userId: string, options?: SignedUrlOptions): Promise<string>;
11333
+ /**
11334
+ * Check if user has access to a file
11335
+ *
11336
+ * @param fileId - File UUID
11337
+ * @param userId - User ID to check
11338
+ * @returns true if user can access the file
11339
+ */
11340
+ checkAccess(fileId: string, userId: string, options?: {
11341
+ isAdmin?: boolean;
11342
+ }): Promise<boolean>;
11343
+ /**
11344
+ * @deprecated Use checkAccess() instead
11345
+ */
11346
+ canAccess(fileId: string, userId: string): Promise<boolean>;
11347
+ /**
11348
+ * Change file visibility
11349
+ *
11350
+ * @param fileId - File UUID
11351
+ * @param visibility - New visibility level
11352
+ * @param allowedUsers - Users allowed to access (if restricted)
11353
+ */
11354
+ changeVisibility(fileId: string, visibility: FileVisibility, allowedUsers?: string[]): Promise<File>;
11355
+ /**
11356
+ * Grant access to a file for specific users
11357
+ *
11358
+ * @param fileId - File UUID
11359
+ * @param userIds - User IDs to grant access
11360
+ */
11361
+ grantAccess(fileId: string, userIds: string[]): Promise<File>;
11362
+ /**
11363
+ * Revoke access to a file for specific users
11364
+ *
11365
+ * @param fileId - File UUID
11366
+ * @param userIds - User IDs to revoke access
11367
+ */
11368
+ revokeAccess(fileId: string, userIds: string[]): Promise<File>;
11369
+ /**
11370
+ * Move file to different folder
11371
+ */
11372
+ moveToFolder(fileId: string, newFolderPath: string): Promise<File>;
11373
+ /**
11374
+ * Add tags to file
11375
+ */
11376
+ addTags(fileId: string, tags: string[]): Promise<File>;
11377
+ /**
11378
+ * Remove tags from file
11379
+ */
11380
+ removeTags(fileId: string, tags: string[]): Promise<File>;
11381
+ }
11382
+
11383
+ /**
11384
+ * Service for managing document templates.
11385
+ *
11386
+ * Templates define the structure of documents (slots, auto-processing, etc.).
11387
+ * System templates are defined in code and available to all tenants.
11388
+ * Custom templates can be created by tenants for specific needs.
11389
+ *
11390
+ * @example
11391
+ * ```typescript
11392
+ * const service = new DocumentTemplateService(adapter);
11393
+ *
11394
+ * // Get a template by name (checks custom first, then system)
11395
+ * const template = await service.getTemplateByName("french_id_card");
11396
+ *
11397
+ * // List all available templates
11398
+ * const templates = await service.listTemplates();
11399
+ *
11400
+ * // Create a custom template
11401
+ * const customTemplate = await service.createTemplate({
11402
+ * name: "company_contract",
11403
+ * label: "Contrat d'entreprise",
11404
+ * slots: [{ name: "contract", label: "Contrat", required: true, order: 1 }],
11405
+ * });
11406
+ * ```
11407
+ */
11408
+ declare class DocumentTemplateService extends BaseService {
11409
+ constructor(adapter: DatabaseAdapter);
11410
+ /**
11411
+ * Get a template by ID.
11412
+ * Checks custom templates first, then system templates.
11413
+ */
11414
+ getTemplate(templateId: string): Promise<DocumentTemplate | null>;
11415
+ /**
11416
+ * Get a template by name.
11417
+ * Checks custom templates first (tenant-specific), then system templates.
11418
+ */
11419
+ getTemplateByName(name: string): Promise<DocumentTemplate | null>;
11420
+ /**
11421
+ * Get multiple templates by names.
11422
+ */
11423
+ getTemplatesByNames(names: string[]): Promise<DocumentTemplate[]>;
11424
+ /**
11425
+ * Get a template or throw if not found.
11426
+ */
11427
+ getTemplateOrThrow(templateId: string): Promise<DocumentTemplate>;
11428
+ /**
11429
+ * Get a template by name or throw if not found.
11430
+ */
11431
+ getTemplateByNameOrThrow(name: string): Promise<DocumentTemplate>;
11432
+ /**
11433
+ * List all available templates.
11434
+ * Includes both system templates and tenant-specific templates.
11435
+ */
11436
+ listTemplates(options?: DocumentTemplateListOptions): Promise<DocumentTemplate[]>;
11437
+ /**
11438
+ * Get only system templates.
11439
+ */
11440
+ getSystemTemplates(): DocumentTemplate[];
11441
+ /**
11442
+ * Create a custom template.
11443
+ * System templates cannot be created via this method.
11444
+ */
11445
+ createTemplate(data: CreateDocumentTemplate): Promise<DocumentTemplate>;
11446
+ /**
11447
+ * Update a custom template.
11448
+ * System templates cannot be updated.
11449
+ */
11450
+ updateTemplate(templateId: string, data: UpdateDocumentTemplate): Promise<DocumentTemplate>;
11451
+ /**
11452
+ * Delete a custom template.
11453
+ * System templates cannot be deleted.
11454
+ */
11455
+ deleteTemplate(templateId: string): Promise<void>;
11456
+ }
11457
+
11458
+ interface RecordDocumentsResult {
11459
+ /** Documents grouped by attribute name (includes system 'attachments' attribute) */
11460
+ byAttribute: Record<string, Document[]>;
11461
+ /** Total count of all documents */
11462
+ total: number;
11463
+ }
11464
+ interface CreateRecordDocumentInput {
11465
+ /** Object name (used for folder path) */
11466
+ objectName: string;
11467
+ /** Record ID (used for folder path) */
11468
+ recordId: string;
11469
+ /** File content */
11470
+ fileContent: Buffer;
11471
+ /** Original file name */
11472
+ fileName: string;
11473
+ /** MIME type */
11474
+ mimeType: string;
11475
+ /** File size */
11476
+ fileSize: number;
11477
+ /** User ID who uploads */
11478
+ uploadedBy: string;
11479
+ /** Optional document title (defaults to fileName) */
11480
+ title?: string;
11481
+ /** Optional template ID (defaults to generic_document) */
11482
+ templateId?: string;
11483
+ }
11484
+ interface CreateRecordDocumentResult {
11485
+ document: Document;
11486
+ file: {
11487
+ id: string;
11488
+ url?: string;
11489
+ };
11490
+ slot: DocumentSlot;
11491
+ }
11492
+ interface DocumentServiceOptions {
11493
+ /**
11494
+ * Template service instance.
11495
+ * If not provided, a new one will be created.
11496
+ */
11497
+ templateService?: DocumentTemplateService;
11498
+ /**
11499
+ * File service instance (required for createRecordDocument).
11500
+ */
11501
+ fileService?: FileService;
11502
+ }
11503
+ /**
11504
+ * Service for managing documents.
11505
+ *
11506
+ * Documents are structured wrappers around files with:
11507
+ * - Template-based structure (slots)
11508
+ * - Status tracking (draft, pending, processing, completed, failed, signed)
11509
+ * - Processing jobs (OCR, signature, verification)
11510
+ *
11511
+ * Documents are linked to records via `record.values` (document attribute).
11512
+ *
11513
+ * @example
11514
+ * ```typescript
11515
+ * const service = new DocumentService(adapter);
11516
+ *
11517
+ * // Create a document
11518
+ * const document = await service.createDocument({
11519
+ * templateId: SYSTEM_TEMPLATE_IDS.FRENCH_ID_CARD,
11520
+ * title: "CNI - Jean Dupont",
11521
+ * });
11522
+ *
11523
+ * // Add files to slots
11524
+ * await service.addSlot(document.id, {
11525
+ * slotName: "front",
11526
+ * fileId: "file-123",
11527
+ * });
11528
+ *
11529
+ * // Get document with slots
11530
+ * const doc = await service.getDocument(document.id);
11531
+ * const slots = await service.getSlots(document.id);
11532
+ * ```
11533
+ */
11534
+ declare class DocumentService extends BaseService {
11535
+ private templateService;
11536
+ private fileService;
11537
+ constructor(adapter: DatabaseAdapter, options?: DocumentServiceOptions);
11538
+ /**
11539
+ * Create a new document.
11540
+ *
11541
+ * @param data - Document creation data
11542
+ * @returns Created document with status "draft"
11543
+ */
11544
+ createDocument(data: CreateDocument): Promise<Document>;
11545
+ /**
11546
+ * Create a document with a template name instead of ID.
11547
+ */
11548
+ createDocumentByTemplateName(templateName: string, data: Omit<CreateDocument, "templateId">): Promise<Document>;
11549
+ /**
11550
+ * Get a document by ID.
11551
+ */
11552
+ getDocument(documentId: string): Promise<Document | null>;
11553
+ /**
11554
+ * Get a document by ID or throw if not found.
11555
+ */
11556
+ getDocumentOrThrow(documentId: string): Promise<Document>;
11557
+ /**
11558
+ * Get multiple documents by IDs.
11559
+ */
11560
+ getDocuments(documentIds: string[]): Promise<Document[]>;
11561
+ /**
11562
+ * Get the template for a document.
11563
+ */
11564
+ getDocumentTemplate(documentId: string): Promise<DocumentTemplate>;
11565
+ /**
11566
+ * List documents with optional filters.
11567
+ */
11568
+ listDocuments(options?: DocumentListOptions): Promise<Document[]>;
11569
+ /**
11570
+ * Search documents by text.
11571
+ */
11572
+ searchDocuments(query: string, options?: DocumentListOptions): Promise<Document[]>;
11573
+ /**
11574
+ * Update a document's metadata.
11575
+ */
11576
+ updateDocument(documentId: string, data: {
11577
+ title?: string;
11578
+ description?: string;
11579
+ tags?: string[];
11580
+ }): Promise<Document>;
11581
+ /**
11582
+ * Update document status.
11583
+ * This is usually called automatically based on slots and jobs.
11584
+ */
11585
+ updateStatus(documentId: string, status: DocumentStatus): Promise<Document>;
11586
+ /**
11587
+ * Soft delete a document.
11588
+ */
11589
+ deleteDocument(documentId: string): Promise<void>;
11590
+ /**
11591
+ * Hard delete a document and all its slots.
11592
+ */
11593
+ hardDeleteDocument(documentId: string): Promise<void>;
11594
+ /**
11595
+ * Get all slots for a document.
11596
+ */
11597
+ getSlots(documentId: string): Promise<DocumentSlot[]>;
11598
+ /**
11599
+ * Add a file to a document slot.
11600
+ */
11601
+ addSlot(documentId: string, data: Omit<CreateDocumentSlot, "documentId">): Promise<DocumentSlot>;
11602
+ /**
11603
+ * Remove a slot from a document.
11604
+ */
11605
+ removeSlot(slotId: string): Promise<void>;
11606
+ /**
11607
+ * Recalculate and update document status based on slots and jobs.
11608
+ *
11609
+ * Status flow:
11610
+ * - draft: Missing required slots
11611
+ * - pending: All required slots filled, no processing started
11612
+ * - processing: At least one job is pending or processing
11613
+ * - completed: All jobs completed successfully (no signature)
11614
+ * - signed: Signature job completed successfully
11615
+ * - failed: At least one job failed
11616
+ */
11617
+ recalculateStatus(documentId: string): Promise<Document>;
11618
+ /**
11619
+ * Check if a document is complete (all required slots filled).
11620
+ */
11621
+ isComplete(documentId: string): Promise<boolean>;
11622
+ /**
11623
+ * Get document with its template and slots.
11624
+ */
11625
+ getDocumentWithDetails(documentId: string): Promise<{
11626
+ document: Document;
11627
+ template: DocumentTemplate;
11628
+ slots: DocumentSlot[];
11629
+ }>;
11630
+ /**
11631
+ * Get all documents attached to a record.
11632
+ *
11633
+ * Retrieves documents from document attributes in record values.
11634
+ * This includes the system 'attachments' attribute for free-form documents.
11635
+ *
11636
+ * @param schema - Object schema with attributes
11637
+ * @param recordValues - Record values containing document IDs
11638
+ */
11639
+ getRecordDocuments(schema: ObjectDefinition, recordValues: Record<string, unknown>): Promise<RecordDocumentsResult>;
11640
+ /**
11641
+ * Create a document for a record.
11642
+ *
11643
+ * This method:
11644
+ * 1. Uploads the file
11645
+ * 2. Creates a document with the specified template
11646
+ * 3. Adds the file to the document slot
11647
+ *
11648
+ * Note: The caller is responsible for updating record.values with the document ID.
11649
+ *
11650
+ * @param input - Document creation input
11651
+ */
11652
+ createRecordDocument(input: CreateRecordDocumentInput): Promise<CreateRecordDocumentResult>;
11653
+ }
11654
+
11655
+ /**
11656
+ * Document Processing Hook
11657
+ *
11658
+ * Processes pending document generation requests in workflow execution context.
11659
+ * Called after each node execution to fulfill document generation.
11660
+ */
11661
+
11662
+ /**
11663
+ * Options for the document processing hook
11664
+ */
11665
+ interface DocumentProcessingHookOptions {
11666
+ /** Document generation service for loading templates */
11667
+ documentGenerationService: DocumentGenerationService;
11668
+ /** Document service for creating record documents */
11669
+ documentService?: DocumentService;
11670
+ /** Record service for updating records with attachments */
11671
+ recordService?: RecordService;
11672
+ /** Schema service for attribute definitions (enables intelligent formatting) */
11673
+ schemaService?: ObjectSchemaService;
11674
+ /** Relation service for resolving relation labels */
11675
+ relationService?: RelationService;
11676
+ }
11677
+ /**
11678
+ * Hook for processing pending document generation requests.
11679
+ *
11680
+ * This hook is called after each node execution in WorkflowInstanceService.
11681
+ * It detects pending document requests in context.documents and:
11682
+ * 1. Loads the template
11683
+ * 2. Renders the PDF using DocumentRendererService
11684
+ * 3. Uploads the generated PDF
11685
+ * 4. Attaches to target records
11686
+ * 5. Updates context.documents with the result
11687
+ *
11688
+ * @example
11689
+ * ```typescript
11690
+ * const hook = new DocumentProcessingHook(
11691
+ * adapter,
11692
+ * storageAdapter,
11693
+ * {
11694
+ * documentGenerationService,
11695
+ * documentService,
11696
+ * recordService,c
11697
+ * }
11698
+ * );
11699
+ *
11700
+ * // In WorkflowInstanceService.executeCurrentNode()
11701
+ * const processedContext = await hook.process(context, workflow, userId);
11702
+ * ```
11703
+ */
11704
+ declare class DocumentProcessingHook extends BaseService {
11705
+ readonly adapter: DatabaseAdapter;
11706
+ private readonly storageAdapter;
11707
+ private readonly options;
11708
+ private readonly renderer;
11709
+ constructor(adapter: DatabaseAdapter, storageAdapter: StorageAdapter, options: DocumentProcessingHookOptions);
11710
+ /**
11711
+ * Process all pending document requests in the context.
11712
+ *
11713
+ * @param context - Current workflow execution context
11714
+ * @param workflow - Workflow definition (for slot/object info)
11715
+ * @param userId - User ID for audit/permissions
11716
+ * @returns Updated context with processed documents
11717
+ */
11718
+ process(context: WorkflowExecutionContext, workflow: WorkflowDefinition, userId: string): Promise<WorkflowExecutionContext>;
11719
+ /**
11720
+ * Find node IDs with pending document requests
11721
+ */
11722
+ private findPendingDocuments;
11723
+ /**
11724
+ * Upload the generated PDF to storage
11725
+ */
11726
+ private uploadGeneratedDocument;
11727
+ /**
11728
+ * Attach generated document to target records
11729
+ */
11730
+ private attachToRecords;
11731
+ }
11732
+
11733
+ declare class GrantNotFoundError extends Error {
11734
+ grantId: string;
11735
+ constructor(grantId: string);
11736
+ }
11737
+ declare class GrantExpiredError extends Error {
11738
+ grantId: string;
11739
+ constructor(grantId: string);
11740
+ }
11741
+ declare class GrantRevokedError extends Error {
11742
+ grantId: string;
11743
+ constructor(grantId: string);
11744
+ }
11745
+ declare class TokenRevokedError extends Error {
11746
+ grantId: string;
11747
+ jti: string;
11748
+ constructor(grantId: string, jti: string);
11749
+ }
11750
+ interface GrantServiceConfig {
11751
+ /** Default grant validity in days (default: 30) */
11752
+ defaultValidityDays?: number;
11753
+ /** Access token TTL (default: "7d") */
11754
+ accessTokenTTL?: string;
11755
+ }
11756
+ interface CreateGrantResult {
11757
+ grant: WorkflowAccessGrant;
11758
+ accessToken: string;
11759
+ }
11760
+ /**
11761
+ * Service for managing workflow access grants.
11762
+ *
11763
+ * Grants are created after a user successfully authenticates via magic link.
11764
+ * They allow the user to access the workflow with JWT access tokens.
11765
+ *
11766
+ * Key features:
11767
+ * - Grants have an expiration date (validUntil)
11768
+ * - Grants can be revoked entirely (revokedAt)
11769
+ * - Individual tokens can be revoked (revokedTokenJtis)
11770
+ *
11771
+ * @example
11772
+ * ```typescript
11773
+ * const grantService = new WorkflowAccessGrantService(adapter, jwtService, {
11774
+ * defaultValidityDays: 30,
11775
+ * });
11776
+ *
11777
+ * // Create grant after magic link acceptance
11778
+ * const { grant, accessToken } = await grantService.createGrant({
11779
+ * invitationId: "inv_123",
11780
+ * instanceId: "inst_456",
11781
+ * grantedTo: "client@example.com",
11782
+ * });
11783
+ *
11784
+ * // Later: revoke a specific token
11785
+ * await grantService.revokeToken(grant.id, "jti_to_revoke");
11786
+ *
11787
+ * // Or revoke the entire grant
11788
+ * await grantService.revokeGrant(grant.id);
11789
+ * ```
11790
+ */
11791
+ declare class WorkflowAccessGrantService extends BaseService {
11792
+ private jwtService;
11793
+ private config;
11794
+ constructor(adapter: DatabaseAdapter, jwtService: WorkflowJwtService, config?: GrantServiceConfig);
11795
+ /**
11796
+ * Find grant by ID
11797
+ */
11798
+ findById(id: Uuid): Promise<WorkflowAccessGrant | null>;
11799
+ /**
11800
+ * Find grants by invitation ID
11801
+ */
11802
+ findByInvitationId(invitationId: Uuid): Promise<WorkflowAccessGrant[]>;
11803
+ /**
11804
+ * Find grants by instance ID
11805
+ */
11806
+ findByInstanceId(instanceId: Uuid): Promise<WorkflowAccessGrant[]>;
11807
+ /**
11808
+ * Find grants by email
11809
+ */
11810
+ findByEmail(email: string): Promise<WorkflowAccessGrant[]>;
11811
+ /**
11812
+ * Create a new access grant and generate an access token.
11813
+ *
11814
+ * This is called after a magic link has been successfully verified.
11815
+ */
11816
+ createGrant(input: CreateGrantInput): Promise<CreateGrantResult>;
11817
+ /**
11818
+ * Revoke an entire grant.
11819
+ *
11820
+ * After revocation, all tokens issued for this grant will be invalid.
11821
+ */
11822
+ revokeGrant(grantId: Uuid): Promise<WorkflowAccessGrant>;
11823
+ /**
11824
+ * Revoke a specific token by its JTI.
11825
+ *
11826
+ * This allows revoking a single token without invalidating other tokens.
11827
+ * Useful for logout or token refresh scenarios.
11828
+ */
11829
+ revokeToken(grantId: Uuid, jti: string): Promise<WorkflowAccessGrant>;
11830
+ /**
11831
+ * Update the last used timestamp for a grant.
11832
+ */
11833
+ updateLastUsed(grantId: Uuid): Promise<void>;
11834
+ /**
11835
+ * Issue a new access token for an existing grant.
11836
+ *
11837
+ * Used for token refresh scenarios.
11838
+ */
11839
+ refreshAccessToken(grantId: Uuid): Promise<{
11840
+ accessToken: string;
11841
+ grant: WorkflowAccessGrant;
11842
+ }>;
11843
+ /**
11844
+ * Validate that a grant is still valid (sync version for internal use).
11845
+ * Throws appropriate error if validation fails.
11846
+ */
11847
+ validateGrantSync(dbGrant: DBWorkflowAccessGrant): void;
11848
+ /**
11849
+ * Validate that a grant is still valid by ID.
11850
+ * Fetches the grant and validates it.
11851
+ */
11852
+ validateGrant(grantId: Uuid): Promise<WorkflowAccessGrant>;
11853
+ /**
11854
+ * Validate that a specific token is still valid.
11855
+ * Calls validateGrantSync first, then checks token-specific revocation.
11856
+ */
11857
+ validateTokenSync(dbGrant: DBWorkflowAccessGrant, jti: string): void;
11858
+ /**
11859
+ * Validate that a specific token is still valid by grant ID.
11860
+ * Fetches the grant and validates both grant and token.
11861
+ */
11862
+ validateToken(grantId: Uuid, jti: string): Promise<void>;
11863
+ /**
11864
+ * Check if a specific token has been revoked.
11865
+ */
11866
+ isTokenRevoked(dbGrant: DBWorkflowAccessGrant, jti: string): boolean;
11867
+ /**
11868
+ * Validate access token payload against the grant.
11869
+ */
11870
+ validateAccessPayload(payload: WorkflowAccessPayload): Promise<{
11871
+ valid: boolean;
11872
+ grant?: WorkflowAccessGrant;
11873
+ error?: string;
11874
+ }>;
11875
+ private mapFromDB;
11876
+ }
11877
+
11878
+ /**
11879
+ * Input for creating a workflow
11880
+ */
11881
+ interface CreateWorkflowInput {
11882
+ name: string;
11883
+ label: string;
11884
+ description?: string;
11885
+ icon?: IconName;
11886
+ slots: WorkflowSlot[];
11887
+ nodes: Record<string, WorkflowNode>;
11888
+ startNodeId: string;
11889
+ layout?: WorkflowLayout;
10234
11890
  theme?: WorkflowTheme;
10235
11891
  config?: WorkflowConfig;
10236
11892
  metadata?: Record<string, unknown>;
@@ -10246,7 +11902,6 @@ interface UpdateWorkflowInput {
10246
11902
  nodes?: Record<string, WorkflowNode>;
10247
11903
  startNodeId?: string;
10248
11904
  layout?: WorkflowLayout;
10249
- participants?: ParticipantTemplate[];
10250
11905
  theme?: WorkflowTheme;
10251
11906
  config?: WorkflowConfig;
10252
11907
  metadata?: Record<string, unknown>;
@@ -10366,6 +12021,8 @@ interface WorkflowInstanceServiceOptions {
10366
12021
  schemaService?: ObjectSchemaService;
10367
12022
  /** Record service for persisting slots at workflow completion */
10368
12023
  recordService?: RecordService;
12024
+ /** Document processing hook for generating PDFs in document nodes */
12025
+ documentProcessingHook?: DocumentProcessingHook;
10369
12026
  }
10370
12027
  /**
10371
12028
  * Service for executing and managing workflow instances.
@@ -10376,6 +12033,7 @@ declare class WorkflowInstanceService extends BaseService {
10376
12033
  private executorRegistry;
10377
12034
  private schemaService?;
10378
12035
  private recordService?;
12036
+ private documentProcessingHook?;
10379
12037
  constructor(adapter: DatabaseAdapter, workflowService: WorkflowService, options?: WorkflowInstanceServiceOptions);
10380
12038
  /**
10381
12039
  * Start a new workflow instance
@@ -10390,7 +12048,8 @@ declare class WorkflowInstanceService extends BaseService {
10390
12048
  */
10391
12049
  cancelWorkflow(instanceId: string, reason?: string): Promise<WorkflowInstance>;
10392
12050
  /**
10393
- * Get an instance by ID
12051
+ * Get an instance by ID.
12052
+ * Automatically marks expired instances as "failed" if their expiresAt has passed.
10394
12053
  */
10395
12054
  getInstance(id: string): Promise<WorkflowInstance | null>;
10396
12055
  /**
@@ -10438,17 +12097,41 @@ declare class WorkflowInstanceService extends BaseService {
10438
12097
  * Execute the current node and continue until wait/complete/error
10439
12098
  */
10440
12099
  private executeCurrentNode;
12100
+ /**
12101
+ * Check a list of instances for expiration and mark any expired non-terminal
12102
+ * instances as "failed". Saves updated instances to the database.
12103
+ */
12104
+ private markExpiredInstances;
10441
12105
  private mergeContext;
10442
12106
  private getNodeLabel;
10443
12107
  /**
10444
- * Persist all slots as records in the database.
12108
+ * Persist all slots as records in the database using a saga pattern.
10445
12109
  * - Slots with mode "create" create new records
10446
12110
  * - Slots with mode "select" or "optional" with existing ID update the record
10447
12111
  * - Slots with mode "optional" without ID create new records
10448
12112
  *
12113
+ * If any slot fails to persist, all previously persisted slots in this batch
12114
+ * are rolled back (best-effort): created records are deleted, updated records
12115
+ * are restored to their previous state.
12116
+ *
10449
12117
  * Returns updated context with createdRecordIds populated.
10450
12118
  */
10451
12119
  private persistSlots;
12120
+ /**
12121
+ * Snapshot a record's current data for potential rollback.
12122
+ * Returns the record data or undefined if the record cannot be read.
12123
+ */
12124
+ private snapshotRecord;
12125
+ /**
12126
+ * Rollback completed slot persistence operations in reverse order (saga compensation).
12127
+ *
12128
+ * This is BEST EFFORT: errors during rollback are logged but never re-thrown.
12129
+ * - For "create" operations: deletes the created record
12130
+ * - For "update" operations: restores the previous data snapshot
12131
+ *
12132
+ * @returns Array of slot IDs that were successfully rolled back
12133
+ */
12134
+ private rollbackSlotOperations;
10452
12135
  /**
10453
12136
  * Clean slot data by removing undefined and null values.
10454
12137
  * This prevents form submissions from overwriting existing record values
@@ -10476,85 +12159,101 @@ declare class WorkflowInstanceService extends BaseService {
10476
12159
  private convertDBInstanceToInstance;
10477
12160
  }
10478
12161
 
10479
- /**
10480
- * Input for creating a participation
10481
- */
10482
- interface CreateParticipationInput {
10483
- /** Workflow instance ID */
10484
- instanceId: string;
10485
- /** Participant template ID */
10486
- participantTemplateId: string;
10487
- /** Override email (if not using emailSource) */
10488
- email?: string;
10489
- /** Override name */
10490
- name?: string;
10491
- /** Override phone */
10492
- phone?: string;
10493
- /** Override auth method */
10494
- authMethod?: "signed_link" | "pin_code";
10495
- }
10496
- /**
10497
- * Result of creating a participation
10498
- */
10499
- interface CreateParticipationResult {
10500
- participation: WorkflowParticipation;
10501
- /** For signed_link: the shareable URL */
10502
- link?: string;
10503
- /** For pin_code: the plain PIN (only returned once!) */
10504
- pinCode?: string;
10505
- }
10506
- /**
10507
- * Result of authentication
10508
- */
10509
- interface AuthenticationResult {
10510
- success: boolean;
10511
- participation?: WorkflowParticipation;
10512
- error?: string;
10513
- attemptsRemaining?: number;
10514
- }
10515
- /**
10516
- * Service for managing external participant access to workflow instances.
10517
- * Handles invitation, authentication, and participation tracking.
12162
+ interface InvitationServiceConfig {
12163
+ /** Base URL for the magic link (e.g., "https://app.example.com") */
12164
+ baseUrl: string;
12165
+ /** Default invitation expiry in days (default: 7) */
12166
+ defaultExpiryDays?: number;
12167
+ /** Callback to send notification email */
12168
+ sendEmailCallback?: (params: {
12169
+ recipientEmail: string;
12170
+ recipientName?: string;
12171
+ magicLink: string;
12172
+ instanceId: string;
12173
+ }) => Promise<void>;
12174
+ }
12175
+ declare class InvitationNotFoundError extends Error {
12176
+ invitationId: string;
12177
+ constructor(invitationId: string);
12178
+ }
12179
+ declare class InvitationExpiredError extends Error {
12180
+ invitationId: string;
12181
+ constructor(invitationId: string);
12182
+ }
12183
+ declare class InvitationAlreadyAcceptedError extends Error {
12184
+ invitationId: string;
12185
+ constructor(invitationId: string);
12186
+ }
12187
+ declare class InvitationRevokedError extends Error {
12188
+ invitationId: string;
12189
+ constructor(invitationId: string);
12190
+ }
12191
+ /**
12192
+ * Service for managing workflow invitations.
12193
+ *
12194
+ * Invitations are the first step in the external user authentication flow:
12195
+ * 1. Admin creates an invitation → generates magic link
12196
+ * 2. External user clicks magic link → invitation is accepted
12197
+ * 3. Grant is created → user gets access token
12198
+ *
12199
+ * @example
12200
+ * ```typescript
12201
+ * const invitationService = new WorkflowInvitationService(adapter, jwtService, {
12202
+ * baseUrl: "https://app.example.com",
12203
+ * sendEmailCallback: async ({ recipientEmail, magicLink }) => {
12204
+ * await sendMagicLinkEmail(recipientEmail, magicLink);
12205
+ * },
12206
+ * });
12207
+ *
12208
+ * const { invitation, magicLink } = await invitationService.createInvitation({
12209
+ * instanceId: "inst_123",
12210
+ * recipientEmail: "client@example.com",
12211
+ * recipientName: "John Doe",
12212
+ * sendEmail: true,
12213
+ * });
12214
+ * ```
10518
12215
  */
10519
- declare class WorkflowParticipationService extends BaseService {
10520
- private instanceService;
10521
- private tokenService;
10522
- private pinCodeService;
10523
- constructor(adapter: DatabaseAdapter, instanceService: WorkflowInstanceService, tokenService?: ParticipationTokenService, pinCodeService?: PinCodeService);
12216
+ declare class WorkflowInvitationService extends BaseService {
12217
+ private jwtService;
12218
+ private config;
12219
+ constructor(adapter: DatabaseAdapter, jwtService: WorkflowJwtService, config: InvitationServiceConfig);
10524
12220
  /**
10525
- * Create a participation for an external user
12221
+ * Find invitation by ID
10526
12222
  */
10527
- createParticipation(input: CreateParticipationInput, baseUrl: string): Promise<CreateParticipationResult>;
12223
+ findById(id: Uuid): Promise<WorkflowInvitation | null>;
10528
12224
  /**
10529
- * Authenticate using a signed link token
12225
+ * Find invitations by instance ID
10530
12226
  */
10531
- authenticateWithToken(token: string): Promise<AuthenticationResult>;
12227
+ findByInstanceId(instanceId: Uuid): Promise<WorkflowInvitation[]>;
10532
12228
  /**
10533
- * Authenticate using a PIN code
12229
+ * Find invitations by recipient email
10534
12230
  */
10535
- authenticateWithPin(participationId: string, pinCode: string): Promise<AuthenticationResult>;
12231
+ findByEmail(email: string): Promise<WorkflowInvitation[]>;
10536
12232
  /**
10537
- * Get a participation by ID
12233
+ * Create a new invitation and generate a magic link.
12234
+ *
12235
+ * Optionally sends an email notification to the recipient.
10538
12236
  */
10539
- getParticipation(id: string): Promise<WorkflowParticipation | null>;
12237
+ createInvitation(input: CreateInvitationInput): Promise<CreateInvitationResult>;
10540
12238
  /**
10541
- * Get participations for an instance
12239
+ * Mark an invitation as accepted.
12240
+ *
12241
+ * This is called internally when a magic link is exchanged for an access token.
12242
+ * It should not be called directly.
10542
12243
  */
10543
- getParticipationsForInstance(instanceId: string): Promise<WorkflowParticipation[]>;
12244
+ markAsAccepted(invitationId: Uuid): Promise<WorkflowInvitation>;
10544
12245
  /**
10545
- * Mark a node as completed by a participation
12246
+ * Revoke an invitation.
12247
+ *
12248
+ * Once revoked, the magic link will no longer work.
10546
12249
  */
10547
- markNodeCompleted(participationId: string, nodeId: string): Promise<WorkflowParticipation>;
12250
+ revoke(invitationId: Uuid): Promise<WorkflowInvitation>;
10548
12251
  /**
10549
- * Revoke a participation
12252
+ * Validate that an invitation can be accepted.
12253
+ * Throws appropriate error if validation fails.
10550
12254
  */
10551
- revokeParticipation(id: string): Promise<WorkflowParticipation>;
10552
- private resolveEmailFromContext;
10553
- private resolvePhoneFromContext;
10554
- private markAuthenticated;
10555
- private updateParticipationAuth;
10556
- private saveParticipation;
10557
- private convertDBToParticipation;
12255
+ validateForAcceptance(dbInvitation: DBWorkflowInvitation): void;
12256
+ private mapFromDB;
10558
12257
  }
10559
12258
 
10560
12259
  /**
@@ -10587,7 +12286,7 @@ interface FieldReadOnlyResult {
10587
12286
  * // Check if a field is read-only for external users
10588
12287
  * const { readOnly, reason } = service.isFieldReadOnly(
10589
12288
  * userAttribute,
10590
- * { type: "external", token: "...", participationId: "..." }
12289
+ * { type: "external", token: "...", grantId: "..." }
10591
12290
  * );
10592
12291
  * ```
10593
12292
  */
@@ -10909,229 +12608,283 @@ declare class UserProfileService extends BaseService {
10909
12608
  declare function buildAuditChanges<T extends Record<string, unknown>>(oldValues: T, newValues: Partial<T>, fieldsToCheck: (keyof T)[]): AuditChange[];
10910
12609
 
10911
12610
  /**
10912
- * Options for FileService constructor
12611
+ * Configuration for document processing adapters.
12612
+ * All adapters are optional - features are disabled if not provided.
10913
12613
  */
10914
- interface FileServiceOptions {
10915
- /**
10916
- * Audit service for logging file operations.
10917
- * If provided, audit logging is enabled using userId from context.
10918
- * If not provided, no audit logs are created (backward compatible).
10919
- */
10920
- auditService?: AuditService;
12614
+ interface DocumentProcessingConfig {
12615
+ /** OCR adapter for text extraction */
12616
+ ocrAdapter?: OcrAdapter;
12617
+ /** Signature adapter for electronic signatures */
12618
+ signatureAdapter?: SignatureAdapter;
12619
+ /** Identity verification adapter for KYC */
12620
+ identityAdapter?: IdentityVerificationAdapter;
10921
12621
  }
10922
12622
  /**
10923
- * Service for managing files.
12623
+ * Service for orchestrating document processing jobs.
10924
12624
  *
10925
- * Handles file metadata CRUD, permissions, storage operations, and audit logging.
10926
- * Works with optional StorageAdapter for file upload/download operations.
10927
- * Automatically uses tenant context from AsyncLocalStorage.
12625
+ * This service is AGNOSTIC - it receives adapters via dependency injection.
12626
+ * Concrete adapter implementations live in @stndrds/schema-nestjs or dedicated packages.
10928
12627
  *
10929
12628
  * @example
10930
12629
  * ```typescript
10931
- * // Basic usage (metadata only)
10932
- * const service = new FileService(adapter);
12630
+ * // In NestJS, adapters are injected via DI
12631
+ * const service = new DocumentProcessingService(adapter, {
12632
+ * ocrAdapter: googleVisionAdapter,
12633
+ * signatureAdapter: yousignAdapter,
12634
+ * identityAdapter: onfidoAdapter,
12635
+ * });
10933
12636
  *
10934
- * // With audit logging
10935
- * const auditService = new AuditService(adapter);
10936
- * const service = new FileService(adapter, { auditService });
12637
+ * // Process OCR on a document slot
12638
+ * const job = await service.processOcr(documentId, "front");
10937
12639
  *
10938
- * // Upload file (requires StorageAdapter)
10939
- * const file = await service.uploadFile({
10940
- * content: fileBuffer,
10941
- * fileName: "contract.pdf",
10942
- * mimeType: "application/pdf",
10943
- * size: 12345,
10944
- * uploadedBy: "user-456",
10945
- * });
12640
+ * // Start signature workflow
12641
+ * const signJob = await service.startSignature(documentId, [
12642
+ * { email: "signer@example.com", firstName: "John", lastName: "Doe" }
12643
+ * ]);
10946
12644
  * ```
10947
12645
  */
10948
- declare class FileService extends BaseService {
10949
- private auditService?;
10950
- constructor(adapter: DatabaseAdapter, options?: FileServiceOptions);
12646
+ declare class DocumentProcessingService extends BaseService {
12647
+ private readonly config;
12648
+ private readonly documentService;
12649
+ private readonly templateService;
12650
+ constructor(adapter: DatabaseAdapter, config: DocumentProcessingConfig);
10951
12651
  /**
10952
- * Upload a file to storage and create metadata record.
10953
- *
10954
- * This method orchestrates:
10955
- * 1. Upload to storage (via StorageAdapter)
10956
- * 2. Create file metadata in database
10957
- * 3. Audit log the operation
10958
- *
10959
- * Requires `adapter.storage` to be configured.
10960
- *
10961
- * @param input - File content and metadata
10962
- * @returns Created file record
10963
- * @throws Error if StorageAdapter is not configured
12652
+ * Process OCR on a document slot.
10964
12653
  *
10965
- * @example
10966
- * ```typescript
10967
- * const file = await service.uploadFile({
10968
- * content: fileBuffer,
10969
- * fileName: "document.pdf",
10970
- * mimeType: "application/pdf",
10971
- * size: 12345,
10972
- * uploadedBy: "user-123",
10973
- * visibility: "private",
10974
- * folderPath: "/documents",
10975
- * tags: ["contract", "2025"],
10976
- * });
10977
- * ```
12654
+ * @param documentId - Document ID
12655
+ * @param slotName - Slot name to process
12656
+ * @returns Created processing job
10978
12657
  */
10979
- uploadFile(input: UploadFileInput): Promise<File>;
12658
+ processOcr(documentId: string, slotName: string): Promise<ProcessingJob>;
10980
12659
  /**
10981
- * Create a new file record (after upload to storage).
10982
- *
10983
- * Use this method when handling storage externally (e.g., with Multer + S3).
10984
- * For integrated upload, use `uploadFile()` instead.
10985
- *
10986
- * @param data - File metadata
10987
- * @returns Created file record
10988
- *
10989
- * @example
10990
- * ```typescript
10991
- * // After uploading to S3 with Multer
10992
- * const file = await service.createFile({
10993
- * tenantId: "tenant-123",
10994
- * name: "contract-2025.pdf",
10995
- * originalName: "Contract Acme Corp 2025.pdf",
10996
- * mimeType: "application/pdf",
10997
- * size: 2458624,
10998
- * storageProvider: "s3",
10999
- * storagePath: "tenants/123/files/2025/contract.pdf",
11000
- * storageBucket: "my-app-files",
11001
- * url: "https://cdn.example.com/files/file-123",
11002
- * uploadedBy: "profile-456",
11003
- * visibility: "private"
11004
- * });
11005
- * ```
12660
+ * Execute pending OCR job.
12661
+ * This is typically called by a background worker.
11006
12662
  */
11007
- createFile(data: CreateFile): Promise<File>;
12663
+ executeOcrJob(jobId: string): Promise<ProcessingJob>;
11008
12664
  /**
11009
- * Get file by ID
12665
+ * Start a signature workflow for a document.
12666
+ *
12667
+ * @param documentId - Document ID
12668
+ * @param signers - List of signers
12669
+ * @param options - Signature options
12670
+ * @returns Created processing job
11010
12671
  */
11011
- getFile(fileId: string): Promise<File | null>;
12672
+ startSignature(documentId: string, signers: SignerRequest[], options?: {
12673
+ expiresAt?: Date;
12674
+ webhookUrl?: string;
12675
+ }): Promise<ProcessingJob>;
11012
12676
  /**
11013
- * Get file by ID or throw
12677
+ * Execute pending signature job.
12678
+ * This sends the document to the signature provider.
11014
12679
  */
11015
- getFileOrThrow(fileId: string): Promise<File>;
12680
+ executeSignatureJob(jobId: string): Promise<ProcessingJob>;
11016
12681
  /**
11017
- * Update file metadata
12682
+ * Handle signature webhook callback.
12683
+ * Updates job status based on provider response.
11018
12684
  *
11019
- * @param fileId - File UUID
11020
- * @param data - Data to update
11021
- * @returns Updated file
12685
+ * @param externalId - External ID from the signature provider
12686
+ * @returns Updated job, or null if job not found
11022
12687
  */
11023
- updateFile(fileId: string, data: UpdateFile): Promise<File>;
12688
+ handleSignatureWebhook(externalId: string): Promise<ProcessingJob | null>;
11024
12689
  /**
11025
- * Delete file (soft delete by default)
12690
+ * Verify identity document.
11026
12691
  *
11027
- * @param fileId - File UUID
11028
- * @param options - Delete options
12692
+ * @param documentId - Document ID (must be an identity document)
12693
+ * @returns Created processing job
11029
12694
  */
11030
- deleteFile(fileId: string, options?: {
11031
- hard?: boolean;
11032
- checkOwnership?: boolean;
11033
- userId?: string;
11034
- }): Promise<void>;
12695
+ verifyIdentity(documentId: string): Promise<ProcessingJob>;
11035
12696
  /**
11036
- * Delete file from both storage and database.
11037
- *
11038
- * Requires `adapter.storage` to be configured.
11039
- *
11040
- * @param fileId - File UUID
11041
- * @param options - Delete options
11042
- * @throws Error if StorageAdapter is not configured
12697
+ * Execute pending identity verification job.
11043
12698
  */
11044
- deleteFileWithStorage(fileId: string, options?: {
11045
- hard?: boolean;
11046
- }): Promise<void>;
12699
+ executeIdentityVerificationJob(jobId: string): Promise<ProcessingJob>;
11047
12700
  /**
11048
- * Delete multiple files
11049
- *
11050
- * @param fileIds - Array of file UUIDs
11051
- * @param options - Delete options
12701
+ * Trigger auto-processing based on template configuration.
12702
+ * Called after all required slots are uploaded.
11052
12703
  */
11053
- bulkDelete(fileIds: string[], options?: {
11054
- hard?: boolean;
11055
- deleteFromStorage?: boolean;
11056
- }): Promise<void>;
12704
+ triggerAutoProcessing(documentId: string): Promise<ProcessingJob[]>;
11057
12705
  /**
11058
- * List files for the tenant
12706
+ * Get all jobs for a document.
11059
12707
  */
11060
- listFiles(options?: FileListOptions): Promise<File[]>;
12708
+ getJobsForDocument(documentId: string): Promise<ProcessingJob[]>;
11061
12709
  /**
11062
- * List files by folder
12710
+ * Get pending jobs for processing.
11063
12711
  */
11064
- listFilesByFolder(folderPath: string): Promise<File[]>;
12712
+ getPendingJobs(limit?: number): Promise<ProcessingJob[]>;
11065
12713
  /**
11066
- * List files uploaded by a specific user
12714
+ * Cancel a pending job.
11067
12715
  */
11068
- listFilesByUploader(uploadedBy: string): Promise<File[]>;
12716
+ cancelJob(jobId: string): Promise<ProcessingJob>;
11069
12717
  /**
11070
- * Get a signed URL for private file access.
11071
- *
11072
- * Checks access permissions before generating URL.
11073
- * Requires `adapter.storage` to be configured.
11074
- *
11075
- * @param fileId - File UUID
11076
- * @param userId - User requesting access
11077
- * @param options - Signed URL options
11078
- * @returns Signed URL
11079
- * @throws Error if user doesn't have access or StorageAdapter is not configured
11080
- *
11081
- * @example
11082
- * ```typescript
11083
- * const url = await service.getSignedUrl("file-123", "user-456", {
11084
- * expiresIn: 3600, // 1 hour
11085
- * });
11086
- * ```
12718
+ * Check if OCR is available.
11087
12719
  */
11088
- getSignedUrl(fileId: string, userId: string, options?: SignedUrlOptions): Promise<string>;
12720
+ isOcrAvailable(): boolean;
11089
12721
  /**
11090
- * Check if user has access to a file
11091
- *
11092
- * @param fileId - File UUID
11093
- * @param userId - User ID to check
11094
- * @returns true if user can access the file
12722
+ * Check if signature is available.
11095
12723
  */
11096
- checkAccess(fileId: string, userId: string): Promise<boolean>;
12724
+ isSignatureAvailable(): boolean;
11097
12725
  /**
11098
- * @deprecated Use checkAccess() instead
12726
+ * Check if identity verification is available.
11099
12727
  */
11100
- canAccess(fileId: string, userId: string): Promise<boolean>;
12728
+ isIdentityVerificationAvailable(): boolean;
11101
12729
  /**
11102
- * Change file visibility
11103
- *
11104
- * @param fileId - File UUID
11105
- * @param visibility - New visibility level
11106
- * @param allowedUsers - Users allowed to access (if restricted)
12730
+ * Get available processing capabilities.
11107
12731
  */
11108
- changeVisibility(fileId: string, visibility: FileVisibility, allowedUsers?: string[]): Promise<File>;
12732
+ getCapabilities(): {
12733
+ ocr: {
12734
+ available: boolean;
12735
+ provider?: string;
12736
+ };
12737
+ signature: {
12738
+ available: boolean;
12739
+ provider?: string;
12740
+ };
12741
+ identityVerification: {
12742
+ available: boolean;
12743
+ provider?: string;
12744
+ };
12745
+ };
12746
+ }
12747
+
12748
+ /**
12749
+ * Document Renderer Service
12750
+ *
12751
+ * Generates PDF documents by injecting workflow context data into PDF templates.
12752
+ * Uses pdf-lib for PDF manipulation.
12753
+ *
12754
+ * Supports intelligent attribute formatting when SchemaService is provided:
12755
+ * - Currency, dates, numbers formatted according to attribute config
12756
+ * - Relations resolved to their display labels
12757
+ * - Select/multiselect values resolved to option labels
12758
+ */
12759
+
12760
+ /**
12761
+ * Input for rendering a document
12762
+ */
12763
+ interface RenderDocumentInput {
12764
+ /** The document generation template to use */
12765
+ template: DocumentGenerationTemplate;
12766
+ /** The workflow execution context containing the data */
12767
+ context: WorkflowExecutionContext;
12768
+ /** The workflow definition (for slot metadata) */
12769
+ workflow?: WorkflowDefinition;
12770
+ /** Custom filename (supports {{path}} interpolation) */
12771
+ filename?: string;
12772
+ }
12773
+ /**
12774
+ * Options for DocumentRendererService
12775
+ */
12776
+ interface DocumentRendererOptions {
12777
+ /** Schema service for attribute definitions (enables intelligent formatting) */
12778
+ schemaService?: ObjectSchemaService;
12779
+ /** Relation service for resolving relation labels */
12780
+ relationService?: RelationService;
12781
+ /** Files repository for resolving fileId to storagePath */
12782
+ filesRepository?: FilesRepository;
12783
+ }
12784
+ /**
12785
+ * Result of document rendering
12786
+ */
12787
+ interface RenderDocumentResult {
12788
+ /** The generated PDF as a buffer */
12789
+ buffer: Buffer;
12790
+ /** The resolved filename */
12791
+ filename: string;
12792
+ /** MIME type (always application/pdf) */
12793
+ mimeType: "application/pdf";
12794
+ /** Number of pages in the document */
12795
+ pageCount: number;
12796
+ }
12797
+ /**
12798
+ * Error thrown when document rendering fails
12799
+ */
12800
+ declare class DocumentRenderError extends Error {
12801
+ readonly templateId: string;
12802
+ readonly cause?: unknown | undefined;
12803
+ constructor(message: string, templateId: string, cause?: unknown | undefined);
12804
+ }
12805
+ /**
12806
+ * Error thrown when storage adapter doesn't support download
12807
+ */
12808
+ declare class StorageDownloadNotSupportedError extends Error {
12809
+ constructor();
12810
+ }
12811
+ /**
12812
+ * Service for rendering PDF documents from templates.
12813
+ *
12814
+ * Responsibilities:
12815
+ * - Load template PDF from storage
12816
+ * - Resolve field values from workflow context
12817
+ * - Format values using attribute definitions (if available)
12818
+ * - Resolve relation labels (if RelationService provided)
12819
+ * - Inject text into PDF using pdf-lib
12820
+ * - Return generated PDF buffer
12821
+ *
12822
+ * @example
12823
+ * ```typescript
12824
+ * // Basic usage
12825
+ * const renderer = new DocumentRendererService(storageAdapter);
12826
+ *
12827
+ * // With intelligent formatting
12828
+ * const renderer = new DocumentRendererService(storageAdapter, {
12829
+ * schemaService,
12830
+ * relationService,
12831
+ * });
12832
+ *
12833
+ * const result = await renderer.render({
12834
+ * template,
12835
+ * context: workflowContext,
12836
+ * workflow: workflowDefinition,
12837
+ * filename: "contract-{{slots.client.name}}.pdf"
12838
+ * });
12839
+ * ```
12840
+ */
12841
+ declare class DocumentRendererService {
12842
+ private readonly storageAdapter;
12843
+ private readonly options?;
12844
+ private schemaCache;
12845
+ constructor(storageAdapter: StorageAdapter, options?: DocumentRendererOptions | undefined);
11109
12846
  /**
11110
- * Grant access to a file for specific users
12847
+ * Render a document from a template and context.
11111
12848
  *
11112
- * @param fileId - File UUID
11113
- * @param userIds - User IDs to grant access
12849
+ * @param input - Template, context, and optional filename
12850
+ * @returns Generated PDF buffer with metadata
12851
+ * @throws DocumentRenderError if rendering fails
12852
+ * @throws StorageDownloadNotSupportedError if storage doesn't support download
11114
12853
  */
11115
- grantAccess(fileId: string, userIds: string[]): Promise<File>;
12854
+ render(input: RenderDocumentInput): Promise<RenderDocumentResult>;
11116
12855
  /**
11117
- * Revoke access to a file for specific users
11118
- *
11119
- * @param fileId - File UUID
11120
- * @param userIds - User IDs to revoke access
12856
+ * Download the template PDF from storage
11121
12857
  */
11122
- revokeAccess(fileId: string, userIds: string[]): Promise<File>;
12858
+ private downloadTemplate;
11123
12859
  /**
11124
- * Move file to different folder
12860
+ * Resolve all field values, including relations and formatted attributes
11125
12861
  */
11126
- moveToFolder(fileId: string, newFolderPath: string): Promise<File>;
12862
+ private resolveAllFieldValues;
11127
12863
  /**
11128
- * Add tags to file
12864
+ * Get attribute info from contextPath
12865
+ * Parses paths like "slots.client.firstName" to find the attribute definition
11129
12866
  */
11130
- addTags(fileId: string, tags: string[]): Promise<File>;
12867
+ private getAttributeInfo;
11131
12868
  /**
11132
- * Remove tags from file
12869
+ * Draw a single field on the PDF
11133
12870
  */
11134
- removeTags(fileId: string, tags: string[]): Promise<File>;
12871
+ private drawField;
12872
+ /**
12873
+ * Simple value formatting (fallback when no attribute definition available)
12874
+ */
12875
+ private formatValueSimple;
12876
+ /**
12877
+ * Interpolate filename with context values
12878
+ *
12879
+ * Supports {{path}} syntax for variable interpolation.
12880
+ *
12881
+ * @example
12882
+ * ```typescript
12883
+ * interpolateFilename("contract-{{slots.client.name}}.pdf", context, template)
12884
+ * // => "contract-John Doe.pdf"
12885
+ * ```
12886
+ */
12887
+ private interpolateFilename;
11135
12888
  }
11136
12889
 
11137
12890
  /**
@@ -11153,7 +12906,10 @@ declare class FileService extends BaseService {
11153
12906
  */
11154
12907
  declare class GeocodingService {
11155
12908
  private readonly adapter;
11156
- constructor(adapter: GeocodingAdapter);
12909
+ private readonly timeoutMs;
12910
+ constructor(adapter: GeocodingAdapter, options?: {
12911
+ timeoutMs?: number;
12912
+ });
11157
12913
  /**
11158
12914
  * Search for address suggestions as the user types
11159
12915
  */
@@ -11228,7 +12984,9 @@ declare class GlobalSearchService extends BaseService {
11228
12984
  * @param options - Search options
11229
12985
  * @returns Results grouped by object name
11230
12986
  */
11231
- searchGrouped(query: string, options?: Omit<GlobalSearchOptions, "limit" | "offset">): Promise<{
12987
+ searchGrouped(query: string, options?: Omit<GlobalSearchOptions, "limit" | "offset"> & {
12988
+ limitPerGroup?: number;
12989
+ }): Promise<{
11232
12990
  groups: Array<{
11233
12991
  objectName: string;
11234
12992
  objectLabel: string;
@@ -11380,12 +13138,19 @@ interface ViewSyncResult {
11380
13138
  error: string;
11381
13139
  }>;
11382
13140
  }
13141
+ /**
13142
+ * Logger interface for view sync operations
13143
+ */
13144
+ interface ViewSyncLogger {
13145
+ info(message: string): void;
13146
+ }
11383
13147
  /**
11384
13148
  * Options for view sync
11385
13149
  */
11386
13150
  interface ViewSyncOptions {
11387
13151
  dryRun?: boolean;
11388
13152
  verbose?: boolean;
13153
+ logger?: ViewSyncLogger;
11389
13154
  }
11390
13155
  /**
11391
13156
  * Sync native views from registry to database
@@ -11579,4 +13344,4 @@ interface FullSyncOptions extends SyncOptions, ViewSyncOptions {
11579
13344
  */
11580
13345
  declare function syncAll(adapter: DatabaseAdapter, objectRegistry: typeof registry, nativeViewRegistry: typeof viewRegistry, options?: FullSyncOptions): Promise<FullSyncResult>;
11581
13346
 
11582
- export { type FlowRow as $, type Attribute as A, type DirectTableTab as B, type CheckboxAttribute as C, type DateAttribute as D, type WorkflowConfig as E, type FileAttribute as F, type Group as G, type SlotMode as H, type InferAttributeValue as I, type AuthMethod as J, type AuthChannel as K, type LocationAttribute as L, type MultiselectAttribute as M, type NumberAttribute as N, type ObjectAction as O, type PhoneAttribute as P, type ParticipantTemplate as Q, type RichtextAttribute as R, type SystemResource as S, type TextAttribute as T, type UserAttribute as U, type ViewLayout as V, type WorkflowTheme as W, type ConditionGroup as X, type ConditionRule as Y, type WorkflowNode as Z, type WorkflowDefinition as _, type SystemAction as a, type FilterValue as a$, type AIMessageRole as a0, type AIThinkingLevel as a1, type AIToolCallStatus as a2, type AIToolCall as a3, type AIChatMessagePartType as a4, type TextPartData as a5, type ToolPartData as a6, type ThinkingPartData as a7, type ReasoningPartData as a8, type AIChatMessagePart as a9, RELATION_TARGET_ANY as aA, type RelationAttribute as aB, isUniversalRelation as aC, type AuditResourceType as aD, type AuditAction as aE, type AuditActorType as aF, type AuditChange as aG, type AuditLogEntry as aH, type CreateAuditLogInput as aI, type AuditListOptions as aJ, type AuditServiceOptions as aK, type StorageProvider as aL, type FileVisibility as aM, type File as aN, type CreateFile as aO, type UpdateFile as aP, type TextFilterOperator as aQ, type NumberFilterOperator as aR, type CheckboxFilterOperator as aS, type DateFilterOperator as aT, type SelectFilterOperator as aU, type MultiselectFilterOperator as aV, type RelationFilterOperator as aW, type FilterOperator as aX, type RelativeDateValue as aY, type CurrencyFilterValue as aZ, type PhoneFilterValue as a_, type AIChatMessage as aa, type AIQuestionType as ab, type AIQuestionOption as ac, type AIQuestion as ad, type AIQuestionAnswer as ae, type AITodoStatus as af, type AITodoItem as ag, type AITodoList as ah, type AIMessageAttachment as ai, type AIConversation as aj, type AIMessage as ak, type AIToolCallRecord as al, type AIUserMemory as am, type AIUsageMetrics as an, type AIProviderMetrics as ao, type CreateAIMessageInput as ap, type StatusGroup as aq, type AttributeGroup as ar, type BaseAttribute as as, type NumberUnit as at, type DateFormat as au, type DateValue as av, type Phone as aw, type Currency as ax, type Location as ay, type LocationGranularity as az, type TextAreaAttribute as b, type Permission as b$, type FilterRule as b0, type ExtendedFilterRule as b1, type FilterCombinator as b2, type FilterGroup as b3, type AdvancedFilterState as b4, isAdvancedFilterState as b5, toAdvancedFilterState as b6, toSimpleFilterState as b7, type SortDirection as b8, type QueryState as b9, type InferRecordInput as bA, type InferRecordUpdate as bB, type CustomAttributeValue as bC, type WithCustomAttributes as bD, type RecordMetadata as bE, type SystemFields as bF, type ExtractRecord as bG, type ExtractRecordStrict as bH, type ExtractRecordInput as bI, type ExtractRecordInputStrict as bJ, type ExtractRecordUpdate as bK, type ExtractRecordUpdateStrict as bL, type ExtractAttributes as bM, type TypedObjectRecord as bN, type ExtractObjectRecord as bO, type ExtractObjectRecordWithCustom as bP, RESERVED_ATTRIBUTE_NAMES as bQ, SYSTEM_FIELD_NAMES as bR, type ReservedAttributeName as bS, type SystemFieldName as bT, type Timestamps as bU, type SharingMode as bV, type ObjectAttribute as bW, type CompletionStatus as bX, type ObjectRecord as bY, type PermissionScope as bZ, type Role as b_, OPERATORS_BY_TYPE as ba, type NoValueOperator as bb, NO_VALUE_OPERATORS as bc, isNoValueOperator as bd, type FlowSlot as be, type FlowRowField as bf, type FlowPage as bg, type FlowRelation as bh, type FlowStatus as bi, type FlowDefinition as bj, isFlowDefinition as bk, isFlowPublished as bl, isSystemFlow as bm, type GeocodingSuggestion as bn, type GeocodingAutocompleteParams as bo, type ReverseGeocodingParams as bp, type GeocodingParams as bq, type GeocodingAdapter as br, NoopGeocodingAdapter as bs, type AttributeSchema as bt, type InferRecordFromSchema as bu, type InferRecordWithRequirements as bv, type TypedAttribute as bw, type AttributeMap as bx, type AddAttribute as by, type InferRecord as bz, type RichtextFeature as c, type WorkflowTransition as c$, type UserRoleAssignment as c0, type EffectivePermissions as c1, type ObjectPermissions as c2, type SystemPermissions as c3, type CreateRoleInput as c4, type UpdateRoleInput as c5, type CreatePermissionInput as c6, type AssignRoleInput as c7, type PolicyContext as c8, type RecordPolicy as c9, type WorkflowNodeType as cA, isStartNode as cB, isFormNode as cC, isConditionNode as cD, isEndNode as cE, isSimpleFormNode as cF, isAdvancedFormNode as cG, getNodeOutputs as cH, type ConditionOperator as cI, isConditionRule as cJ, isConditionGroup as cK, eq as cL, neq as cM, and as cN, or as cO, inValues as cP, isEmpty as cQ, isNotEmpty as cR, type WorkflowSlot as cS, type NodePosition as cT, type CanvasViewport as cU, type WorkflowLayout as cV, type ParticipantAuthConfig as cW, type WorkflowStatus as cX, isWorkflowDefinition as cY, isWorkflowPublished as cZ, isSystemWorkflow as c_, PolicyViolationError as ca, type UserRole as cb, type UserStatus as cc, type UserProfile as cd, type CreateUserProfile as ce, type UpdateUserProfile as cf, type InviteUserInput as cg, type TabType as ch, type FormTab as ci, type CustomTab as cj, type ActivityTab as ck, type NotesTab as cl, type FlowsTab as cm, isFormTab as cn, isTableTab as co, isDirectTableTab as cp, isInverseTableTab as cq, isCustomTab as cr, isActivityTab as cs, isNotesTab as ct, isFlowsTab as cu, type StartNode as cv, type FormNode as cw, type FormFieldRef as cx, type ConditionNode as cy, type EndNode as cz, type CurrencyAttribute as d, formulaConfigSchema as d$, type WorkflowError as d0, type PendingAction as d1, type WorkflowInstance as d2, isInstanceTerminal as d3, isInstanceWaiting as d4, canResumeInstance as d5, createStartTransition as d6, type ParticipationStatus as d7, type SignedLinkAuth as d8, type PinCodeAuth as d9, type Uuid as dA, type TenantId as dB, type UserId as dC, asTenantId as dD, asUserId as dE, generateId as dF, generatePrefixedId as dG, registry as dH, viewRegistry as dI, type ValidationMessages as dJ, DEFAULT_VALIDATION_MESSAGES as dK, textConfigSchema as dL, textareaConfigSchema as dM, richtextConfigSchema as dN, numberConfigSchema as dO, checkboxConfigSchema as dP, dateConfigSchema as dQ, phoneConfigSchema as dR, currencyConfigSchema as dS, statusConfigSchema as dT, locationConfigSchema as dU, selectConfigSchema as dV, multiselectConfigSchema as dW, fileConfigSchema as dX, userConfigSchema as dY, relationConfigSchema as dZ, ratingConfigSchema as d_, type ParticipationAuth as da, type WorkflowParticipation as db, isSignedLinkAuth as dc, isPinCodeAuth as dd, canParticipate as de, canAuthenticate as df, canExecuteNode as dg, type GeneratedDocument as dh, type WorkflowExecutionContext as di, createEmptyContext as dj, getContextValue as dk, setContextValue as dl, mergeFormToSlot as dm, type WorkflowAccessMode as dn, type ReadOnlyReason as dp, type FormFieldContext as dq, type FormFieldRow as dr, type FormNodeInfo as ds, type FormContextResponse as dt, type ThemeLogo as du, type ThemeColors as dv, type ThemeTypography as dw, DEFAULT_THEME as dx, mergeWithDefaults as dy, generateCssVariables as dz, type Option as e, type QueryBuilderState as e$, rollupConfigSchema as e0, attributeConfigSchemas as e1, getAttributeConfigSchema as e2, validateAttributeConfig as e3, parseAttributeConfig as e4, safeParseAttributeConfig as e5, createTextValidator as e6, createNumberValidator as e7, createCheckboxValidator as e8, createDateValidator as e9, getMissingRequiredAttributes as eA, isRecordComplete as eB, computeRecordStatus as eC, type DatabaseAdapter as eD, ParticipationTokenService as eE, getDefaultTokenService as eF, initializeTokenService as eG, type ParticipationTokenPayload as eH, type TokenGenerationOptions as eI, type TokenVerificationResult as eJ, PinCodeService as eK, getDefaultPinCodeService as eL, initializePinCodeService as eM, type PinCodeGenerationOptions as eN, type PinCodeVerificationResult as eO, type CacheKeyType as eP, hashOptions as eQ, type CacheAdapter as eR, type CacheOptions as eS, cacheKeys as eT, cacheTtl as eU, defaultTtl as eV, NoopCacheAdapter as eW, type FetchResult as eX, type FormattedRecord as eY, type GroupedFetchResult as eZ, type InsertOptions as e_, createPhoneValidator as ea, createCurrencyValidator as eb, createStatusValidator as ec, createSelectValidator as ed, createMultiselectValidator as ee, createLocationValidator as ef, createFileValidator as eg, createUserValidator as eh, createSingleRelationValidator as ei, createMultiRelationValidator as ej, createRelationValidator as ek, createRatingValidator as el, createFormulaValidator as em, createRollupValidator as en, createTextAreaValidator as eo, createRichtextValidator as ep, createAttributeValidator as eq, createFormAttributeValidator as er, createObjectValidator as es, type ValidationResult as et, validateAttribute as eu, validateObject as ev, validateObjectOrThrow as ew, createDraftValidator as ex, validateDraft as ey, validateDraftOrThrow as ez, type StatusAttribute as f, type FormulaResult as f$, type RegistryMap as f0, type RegistryObjectNames as f1, type ShortcutOperator as f2, createDefaultState as f3, formatRecord as f4, formatRecords as f5, QueryMultipleResultsError as f6, QueryNoResultError as f7, SHORTCUT_TO_FILTER_OPERATOR as f8, createQueryBuilder as f9, type ExecutorContext as fA, type ExecutorErrorResult as fB, type ExecutorResult as fC, type ExecutorSuccessResult as fD, type ExecutorWaitResult as fE, type NodeExecutor as fF, complete as fG, error as fH, ExecutorRegistry as fI, success as fJ, wait as fK, ConditionExecutor as fL, EndExecutor as fM, FormExecutor as fN, StartExecutor as fO, evaluateFormula as fP, evaluateFormulaAttribute as fQ, evaluateFormulaAttributeWithRelations as fR, evaluateFormulaWithRelations as fS, evaluateFormulaWithResult as fT, extractFormulaVariables as fU, extractRelationNames as fV, extractRelationReferences as fW, flattenRelationsForEval as fX, formatFormulaResult as fY, hasRelationReferences as fZ, validateFormulaExpression as f_, QueryBuilder as fa, type QueryBuilderOptions as fb, type EvaluationResult as fc, type EvaluationTrace as fd, evaluateCondition as fe, evaluate as ff, evaluateWithTrace as fg, TenantContextError as fh, addSchemaToContext as fi, getSchemaByNameFromContext as fj, getSchemaContext as fk, getSchemaFromContext as fl, hasSchemaContext as fm, runWithMergedSchemaContext as fn, runWithSchemaContext as fo, type SchemaContext as fp, getContext as fq, getTenantId as fr, getUserId as fs, hasContext as ft, runWithContext as fu, withTenantContext as fv, type TenantContext as fw, createDefaultExecutorRegistry as fx, getDefaultExecutorRegistry as fy, type ExecutorCompleteResult as fz, type SelectAttribute as g, type RelationOptionsResponse as g$, getPathDepth as g0, getRelationPath as g1, getTargetAttributeName as g2, InvalidPathError as g3, MaxDepthExceededError as g4, parsePath as g5, pathHasManyCardinality as g6, validatePath as g7, type PathCardinality as g8, type PathSegment as g9, type WorkflowParticipationsRepository as gA, type AuditRepository as gB, type PermissionsRepository as gC, type AIConversationsRepository as gD, type AIUserMemoryRepository as gE, type AIUsageMetricsRepository as gF, BaseService as gG, BaseRepository as gH, type SchemaContextAware as gI, SchemaContextAwareRepository as gJ, TenantAwareRepository as gK, TenantAwareService as gL, type CreateCustomObjectInput as gM, type AddAttributeInput as gN, type UpdateObjectInput as gO, type ObjectSchemaServiceOptions as gP, ObjectSchemaService as gQ, type RecordServiceOptions as gR, RecordService as gS, type RecordQueryServiceOptions as gT, type QueryOptions as gU, type SearchQueryOptions as gV, type QueryResult as gW, RecordQueryService as gX, type RelationValidationResult as gY, type RelationValidationError as gZ, type RelationOption as g_, type PathSegmentType as ga, type SchemaResolver as gb, resolveMultiplePaths as gc, resolveSingleValue as gd, traversePath as ge, type TraversalOptions as gf, type TraversalResult as gg, type AttributeChange as gh, type HookContext as gi, type HookDefinition as gj, type HookHandler as gk, type HookType as gl, NoopHookRegistry as gm, type HookRegistry as gn, createMockAdapter as go, defaultPolicyRegistry as gp, PolicyRegistry as gq, notesPolicy as gr, type ObjectsRepository as gs, type AttributesRepository as gt, type UserProfilesRepository as gu, type FilesRepository as gv, type ObjectRecordsRepository as gw, type ViewsRepository as gx, type WorkflowsRepository as gy, type WorkflowInstancesRepository as gz, type SingleRelationAttribute as h, type StorageUploadInput as h$, type GetRelationOptionsParams as h0, type RelationServiceOptions as h1, type ResolveIdsBatchRequest as h2, type ResolveIdsBatchResponse as h3, RelationService as h4, RecordResolverService as h5, type ResolvedRelations as h6, type FormulaResolverServiceOptions as h7, FormulaResolverService as h8, type RollupResult as h9, type StartWorkflowInput as hA, type ResumeWorkflowInput as hB, type WorkflowInstanceServiceOptions as hC, WorkflowInstanceService as hD, type CreateParticipationInput as hE, type CreateParticipationResult as hF, type AuthenticationResult as hG, WorkflowParticipationService as hH, type FieldReadOnlyResult as hI, WorkflowRelationService as hJ, type UserValidationResult as hK, type UserValidationError as hL, UserService as hM, type UserProfileServiceOptions as hN, UserProfileService as hO, AuditService as hP, buildAuditChanges as hQ, type FileServiceOptions as hR, FileService as hS, GeocodingService as hT, GlobalSearchService as hU, type PermissionServiceOptions as hV, PermissionService as hW, type CreateViewInput as hX, type UpdateViewInput as hY, ViewService as hZ, type FileContent as h_, type RollupServiceOptions as ha, RollupService as hb, type RollupSchedulerOptions as hc, RollupScheduler as hd, applyDefaultValues as he, checkPermission as hf, getPolicy as hg, buildPolicyContext as hh, checkRecordAccess as hi, checkRecordModifyOrThrow as hj, checkRecordDeleteOrThrow as hk, checkSharedObjectWriteAccess as hl, computeLabel as hm, type LabelResolver as hn, enrichWithFormulas as ho, enrichRecordsWithFormulas as hp, createContextForCreate as hq, createContextForUpdate as hr, createContextForDelete as hs, createContextForRestore as ht, recalculateParentRollups as hu, type RollupCascadeContext as hv, type CreateWorkflowInput as hw, type UpdateWorkflowInput as hx, type WorkflowServiceOptions as hy, WorkflowService as hz, type MultiRelationAttribute as i, type StorageUploadResult as i0, type SignedUrlOptions as i1, type StorageAdapter as i2, type UploadFileInput as i3, type SyncResult as i4, type SyncOptions as i5, syncNativeObjects as i6, verifyNativeObjectsSync as i7, getSyncPreview as i8, type FullSyncResult as i9, type FileListOptions as iA, type DBView as iB, type CreateDBView as iC, type UpdateDBView as iD, type UpsertDBView as iE, type DBWorkflow as iF, type CreateDBWorkflow as iG, type UpdateDBWorkflow as iH, type DBWorkflowInstance as iI, type CreateDBWorkflowInstance as iJ, type UpdateDBWorkflowInstance as iK, type DBWorkflowParticipation as iL, type CreateDBWorkflowParticipation as iM, type UpdateDBWorkflowParticipation as iN, type OperationResult as iO, type ViewSyncResult as iP, type ViewSyncOptions as iQ, syncNativeViews as iR, verifyNativeViewsSync as iS, getViewSyncPreview as iT, type FullSyncOptions as ia, syncAll as ib, DEFAULT_LABEL_FALLBACK as ic, renderLabelExpression as id, isLabelExpression as ie, extractAttributeNames as ig, enrichValuesForDisplay as ih, enrichValuesWithSelectLabels as ii, extractRelationIds as ij, type RelationLabelResolver as ik, computeLabelWithRelations as il, type DBObject as im, type CreateDBObject as io, type UpdateDBObject as ip, type UpsertDBObject as iq, type DBAttribute as ir, type CreateDBAttribute as is, type UpdateDBAttribute as it, type UpsertDBAttribute as iu, type CreateObjectRecord as iv, type ListOptions as iw, type SearchOptions as ix, type GlobalSearchOptions as iy, type GlobalSearchResultItem as iz, type RelationTarget as j, type RatingAttribute as k, type FormulaAttribute as l, type FormulaReturnType as m, type RollupAttribute as n, type RollupFunction as o, type AttributeType as p, type ObjectDefinition as q, type Field as r, type AttributeGroupField as s, type TableTab as t, type InverseTableTab as u, type ViewDefinition as v, type InstanceStatus as w, type Tab as x, type FilterState as y, type SortRule as z };
13347
+ export { type OcrAdapter as $, type Attribute as A, type SortRule as B, type CheckboxAttribute as C, type DateAttribute as D, type DirectTableTab as E, type FileAttribute as F, type Group as G, type WorkflowConfig as H, type InferAttributeValue as I, type SlotMode as J, type ConditionGroup as K, type LocationAttribute as L, type MultiselectAttribute as M, type NumberAttribute as N, type ObjectAction as O, type PhoneAttribute as P, type ConditionRule as Q, type RichtextAttribute as R, type SystemResource as S, type TextAttribute as T, type UserAttribute as U, type ViewLayout as V, type WorkflowTheme as W, type WorkflowNode as X, type WorkflowDefinition as Y, type FlowRow as Z, type DocumentTemplate as _, type DocumentAttribute as a, type AuditActorType as a$, type OcrInput as a0, type OcrOptions as a1, type OcrResult as a2, type OcrPage as a3, type OcrTextBlock as a4, type BoundingBox as a5, type SignatureAdapter as a6, type CreateSignatureInput as a7, type SignerRequest as a8, type SignaturePosition as a9, type AIBatchQuestionAnswer as aA, type AITodoStatus as aB, type AITodoItem as aC, type AITodoList as aD, type AIMessageAttachment as aE, type AIConversation as aF, type AIMessage as aG, type AIToolCallRecord as aH, type AIUserMemory as aI, type AIUsageMetrics as aJ, type AIProviderMetrics as aK, type CreateAIMessageInput as aL, type StatusGroup as aM, type AttributeGroup as aN, type BaseAttribute as aO, type NumberUnit as aP, type DateFormat as aQ, type DateValue as aR, type Phone as aS, type Currency as aT, type Location as aU, type LocationGranularity as aV, RELATION_TARGET_ANY as aW, type RelationAttribute as aX, isUniversalRelation as aY, type AuditResourceType as aZ, type AuditAction as a_, type SignatureRequestResult as aa, type SignatureStatusResult as ab, type SignerStatus as ac, type SignatureStatus as ad, type IdentityVerificationAdapter as ae, type VerifyInput as af, type VerificationResult as ag, type DocumentData as ah, type VerificationCheck as ai, type AIMessageRole as aj, type AIThinkingLevel as ak, type AIToolCallStatus as al, type AIToolCall as am, type AIChatMessagePartType as an, type TextPartData as ao, type ToolPartData as ap, type ThinkingPartData as aq, type ReasoningPartData as ar, type AIChatMessagePart as as, type AIChatMessage as at, type AIQuestionType as au, type AIQuestionOption as av, type AIQuestion as aw, type AIQuestionAnswer as ax, type AIBatchQuestionOption as ay, type AIBatchQuestion as az, type SystemAction as b, type NoValueOperator as b$, type AuditChange as b0, type AuditLogEntry as b1, type CreateAuditLogInput as b2, type AuditListOptions as b3, type AuditServiceOptions as b4, type VariableMapping as b5, type PdfTemplateField as b6, type TemplateSource as b7, type DocumentGenerationTemplate as b8, type CreateDocumentGenerationTemplate as b9, type FileVisibility as bA, type File as bB, type CreateFile as bC, type UpdateFile as bD, type TextFilterOperator as bE, type NumberFilterOperator as bF, type CheckboxFilterOperator as bG, type DateFilterOperator as bH, type SelectFilterOperator as bI, type MultiselectFilterOperator as bJ, type RelationFilterOperator as bK, type FilterOperator as bL, type RelativeDateValue as bM, type CurrencyFilterValue as bN, type PhoneFilterValue as bO, type FilterValue as bP, type FilterRule as bQ, type ExtendedFilterRule as bR, type FilterCombinator as bS, type FilterGroup as bT, type AdvancedFilterState as bU, isAdvancedFilterState as bV, toAdvancedFilterState as bW, toSimpleFilterState as bX, type SortDirection as bY, type QueryState as bZ, OPERATORS_BY_TYPE as b_, type UpdateDocumentGenerationTemplate as ba, type PendingDocumentRequest as bb, isPdfTemplateSource as bc, isDocxTemplateSource as bd, type DocumentSlotDefinition as be, type DocumentAutoProcessing as bf, type ExtractionMapping as bg, type ExtractionField as bh, type Document as bi, type DocumentStatus as bj, type DocumentSlot as bk, type SlotStatus as bl, type ProcessingJob as bm, type ProcessingJobType as bn, type ProcessingJobStatus as bo, type CreateDocument as bp, type UpdateDocument as bq, type CreateDocumentTemplate as br, type UpdateDocumentTemplate as bs, type CreateDocumentSlot as bt, type UpdateDocumentSlot as bu, type CreateProcessingJob as bv, type UpdateProcessingJob as bw, type DocumentListOptions as bx, type DocumentTemplateListOptions as by, type StorageProvider as bz, type TextAreaAttribute as c, type UserRole as c$, NO_VALUE_OPERATORS as c0, isNoValueOperator as c1, type FlowSlot as c2, type FlowRowField as c3, type FlowPage as c4, type FlowRelation as c5, type FlowStatus as c6, type FlowDefinition as c7, isFlowDefinition as c8, isFlowPublished as c9, type ExtractAttributes as cA, type TypedObjectRecord as cB, type ExtractObjectRecord as cC, type ExtractObjectRecordWithCustom as cD, RESERVED_ATTRIBUTE_NAMES as cE, SYSTEM_FIELD_NAMES as cF, type ReservedAttributeName as cG, type SystemFieldName as cH, type Timestamps as cI, type SharingMode as cJ, type ObjectAttribute as cK, type CompletionStatus as cL, type ObjectRecord as cM, type PermissionScope as cN, type Role as cO, type Permission as cP, type UserRoleAssignment as cQ, type EffectivePermissions as cR, type ObjectPermissions as cS, type SystemPermissions as cT, type CreateRoleInput as cU, type UpdateRoleInput as cV, type CreatePermissionInput as cW, type AssignRoleInput as cX, type PolicyContext as cY, type RecordPolicy as cZ, PolicyViolationError as c_, isSystemFlow as ca, type GeocodingSuggestion as cb, type GeocodingAutocompleteParams as cc, type ReverseGeocodingParams as cd, type GeocodingParams as ce, type GeocodingAdapter as cf, NoopGeocodingAdapter as cg, type AttributeSchema as ch, type InferRecordFromSchema as ci, type InferRecordWithRequirements as cj, type TypedAttribute as ck, type AttributeMap as cl, type AddAttribute as cm, type InferRecord as cn, type InferRecordInput as co, type InferRecordUpdate as cp, type CustomAttributeValue as cq, type WithCustomAttributes as cr, type RecordMetadata as cs, type SystemFields as ct, type ExtractRecord as cu, type ExtractRecordStrict as cv, type ExtractRecordInput as cw, type ExtractRecordInputStrict as cx, type ExtractRecordUpdate as cy, type ExtractRecordUpdateStrict as cz, type RichtextFeature as d, type CreateInvitationInput as d$, type UserStatus as d0, type UserProfile as d1, type CreateUserProfile as d2, type UpdateUserProfile as d3, type InviteUserInput as d4, type TabType as d5, type FormTab as d6, type CustomTab as d7, type ActivityTab as d8, type NotesTab as d9, isStartNode as dA, type ConditionOperator as dB, and as dC, eq as dD, inValues as dE, isConditionGroup as dF, isConditionRule as dG, isEmpty as dH, isNotEmpty as dI, neq as dJ, or as dK, type CanvasViewport as dL, type NodePosition as dM, type WorkflowLayout as dN, type WorkflowSlot as dO, type WorkflowStatus as dP, isSystemWorkflow as dQ, isWorkflowDefinition as dR, isWorkflowPublished as dS, type PendingAction as dT, type WorkflowError as dU, type WorkflowInstance as dV, type WorkflowTransition as dW, canResumeInstance as dX, createStartTransition as dY, isInstanceTerminal as dZ, isInstanceWaiting as d_, type FlowsTab as da, type DocumentsTab as db, isFormTab as dc, isTableTab as dd, isDirectTableTab as de, isInverseTableTab as df, isCustomTab as dg, isActivityTab as dh, isNotesTab as di, isFlowsTab as dj, isDocumentsTab as dk, type ConditionNode as dl, type DocumentNode as dm, type EndNode as dn, type FormFieldRef as dp, type FormNode as dq, type StartNode as dr, type WorkflowNodeType as ds, getNodeOutputs as dt, isAdvancedFormNode as du, isConditionNode as dv, isDocumentNode as dw, isEndNode as dx, isFormNode as dy, isSimpleFormNode as dz, type CurrencyAttribute as e, attributeConfigSchemas as e$, type CreateInvitationResult as e0, type InvitationStatus as e1, type WorkflowInvitation as e2, isInvitationAccepted as e3, isInvitationExpired as e4, isInvitationValid as e5, type CreateGrantInput as e6, type WorkflowAccessGrant as e7, canAccessNode as e8, isGrantExpired as e9, generateId as eA, generatePrefixedId as eB, slugify as eC, generateTemplateName as eD, registry as eE, viewRegistry as eF, type ValidationMessages as eG, DEFAULT_VALIDATION_MESSAGES as eH, textConfigSchema as eI, textareaConfigSchema as eJ, richtextConfigSchema as eK, numberConfigSchema as eL, checkboxConfigSchema as eM, dateConfigSchema as eN, phoneConfigSchema as eO, currencyConfigSchema as eP, statusConfigSchema as eQ, locationConfigSchema as eR, selectConfigSchema as eS, multiselectConfigSchema as eT, fileConfigSchema as eU, userConfigSchema as eV, relationConfigSchema as eW, ratingConfigSchema as eX, formulaConfigSchema as eY, rollupConfigSchema as eZ, documentConfigSchema as e_, isGrantRevoked as ea, isGrantValid as eb, isTokenRevoked as ec, type GeneratedDocument as ed, type WorkflowExecutionContext as ee, createEmptyContext as ef, getContextValue as eg, mergeFormToSlot as eh, setContextValue as ei, type FormContextResponse as ej, type FormFieldContext as ek, type FormFieldRow as el, type FormNodeInfo as em, type ReadOnlyReason as en, type WorkflowAccessMode as eo, type ThemeColors as ep, type ThemeLogo as eq, type ThemeTypography as er, DEFAULT_THEME as es, generateCssVariables as et, mergeWithDefaults as eu, type Uuid as ev, type TenantId as ew, type UserId as ex, asTenantId as ey, asUserId as ez, type Option as f, QueryMultipleResultsError as f$, getAttributeConfigSchema as f0, validateAttributeConfig as f1, parseAttributeConfig as f2, safeParseAttributeConfig as f3, createTextValidator as f4, createNumberValidator as f5, createCheckboxValidator as f6, createDateValidator as f7, createPhoneValidator as f8, createCurrencyValidator as f9, computeRecordStatus as fA, type DatabaseAdapter as fB, WorkflowJwtService as fC, type JwtVerificationResult as fD, type MagicLinkPayload as fE, type WorkflowAccessPayload as fF, type WorkflowJwtConfig as fG, type WorkflowJwtPayload as fH, type CacheKeyType as fI, hashOptions as fJ, type CacheAdapter as fK, type CacheOptions as fL, cacheKeys as fM, cacheTtl as fN, defaultTtl as fO, NoopCacheAdapter as fP, type FetchResult as fQ, type FormattedRecord as fR, type GroupedFetchResult as fS, type InsertOptions as fT, type QueryBuilderState as fU, type RegistryMap as fV, type RegistryObjectNames as fW, type ShortcutOperator as fX, createDefaultState as fY, formatRecord as fZ, formatRecords as f_, createStatusValidator as fa, createSelectValidator as fb, createMultiselectValidator as fc, createLocationValidator as fd, createFileValidator as fe, createUserValidator as ff, createSingleRelationValidator as fg, createMultiRelationValidator as fh, createRelationValidator as fi, createRatingValidator as fj, createFormulaValidator as fk, createRollupValidator as fl, createTextAreaValidator as fm, createRichtextValidator as fn, createAttributeValidator as fo, createFormAttributeValidator as fp, createObjectValidator as fq, type ValidationResult as fr, validateAttribute as fs, validateObject as ft, validateObjectOrThrow as fu, createDraftValidator as fv, validateDraft as fw, validateDraftOrThrow as fx, getMissingRequiredAttributes as fy, isRecordComplete as fz, type StatusAttribute as g, parsePath as g$, QueryNoResultError as g0, SHORTCUT_TO_FILTER_OPERATOR as g1, createQueryBuilder as g2, QueryBuilder as g3, type QueryBuilderOptions as g4, type EvaluationResult as g5, type EvaluationTrace as g6, evaluateCondition as g7, evaluate as g8, evaluateWithTrace as g9, error as gA, ExecutorRegistry as gB, success as gC, wait as gD, ConditionExecutor as gE, DocumentExecutor as gF, EndExecutor as gG, FormExecutor as gH, StartExecutor as gI, evaluateFormula as gJ, evaluateFormulaAttribute as gK, evaluateFormulaAttributeWithRelations as gL, evaluateFormulaWithRelations as gM, evaluateFormulaWithResult as gN, extractFormulaVariables as gO, extractRelationNames as gP, extractRelationReferences as gQ, flattenRelationsForEval as gR, formatFormulaResult as gS, hasRelationReferences as gT, validateFormulaExpression as gU, type FormulaResult as gV, getPathDepth as gW, getRelationPath as gX, getTargetAttributeName as gY, InvalidPathError as gZ, MaxDepthExceededError as g_, TenantContextError as ga, addSchemaToContext as gb, getSchemaByNameFromContext as gc, getSchemaContext as gd, getSchemaFromContext as ge, hasSchemaContext as gf, runWithMergedSchemaContext as gg, runWithSchemaContext as gh, type SchemaContext as gi, getContext as gj, getTenantId as gk, getUserId as gl, hasContext as gm, runWithContext as gn, withTenantContext as go, type TenantContext as gp, createDefaultExecutorRegistry as gq, getDefaultExecutorRegistry as gr, type ExecutorCompleteResult as gs, type ExecutorContext as gt, type ExecutorErrorResult as gu, type ExecutorResult as gv, type ExecutorSuccessResult as gw, type ExecutorWaitResult as gx, type NodeExecutor as gy, complete as gz, type SelectAttribute as h, type RelationOptionsResponse as h$, pathHasManyCardinality as h0, validatePath as h1, type PathCardinality as h2, type PathSegment as h3, type PathSegmentType as h4, type SchemaResolver as h5, resolveMultiplePaths as h6, resolveSingleValue as h7, traversePath as h8, type TraversalOptions as h9, type DocumentsRepository as hA, type DocumentSlotsRepository as hB, type DocumentJobsRepository as hC, type DocumentGenerationTemplateListOptions as hD, type DocumentGenerationTemplatesRepository as hE, type AIConversationsRepository as hF, type AIUserMemoryRepository as hG, type AIUsageMetricsRepository as hH, BaseService as hI, BaseRepository as hJ, type SchemaContextAware as hK, SchemaContextAwareRepository as hL, type CreateCustomObjectInput as hM, type AddAttributeInput as hN, type UpdateObjectInput as hO, type ObjectSchemaServiceOptions as hP, ObjectSchemaService as hQ, type RecordServiceOptions as hR, RecordService as hS, type RecordQueryServiceOptions as hT, type QueryOptions as hU, type SearchQueryOptions as hV, type QueryResult as hW, RecordQueryService as hX, type RelationValidationResult as hY, type RelationValidationError as hZ, type RelationOption as h_, type TraversalResult as ha, type AttributeChange as hb, type HookContext as hc, type HookDefinition as hd, type HookHandler as he, type HookType as hf, NoopHookRegistry as hg, type HookRegistry as hh, createMockAdapter as hi, type MockStores as hj, defaultPolicyRegistry as hk, PolicyRegistry as hl, notesPolicy as hm, type ObjectsRepository as hn, type AttributesRepository as ho, type ObjectRecordsRepository as hp, type ViewsRepository as hq, type UserProfilesRepository as hr, type FilesRepository as hs, type AuditRepository as ht, type PermissionsRepository as hu, type WorkflowsRepository as hv, type WorkflowInstancesRepository as hw, type WorkflowInvitationsRepository as hx, type WorkflowAccessGrantsRepository as hy, type DocumentTemplatesRepository as hz, type SingleRelationAttribute as i, UserProfileService as i$, type GetRelationOptionsParams as i0, type RelationServiceOptions as i1, type ResolveIdsBatchRequest as i2, type ResolveIdsBatchResponse as i3, RelationService as i4, RecordResolverService as i5, type ResolvedRelations as i6, type FormulaResolverServiceOptions as i7, FormulaResolverService as i8, type RollupResult as i9, GrantNotFoundError as iA, GrantExpiredError as iB, GrantRevokedError as iC, TokenRevokedError as iD, type GrantServiceConfig as iE, type CreateGrantResult as iF, WorkflowAccessGrantService as iG, type StartWorkflowInput as iH, type ResumeWorkflowInput as iI, type WorkflowInstanceServiceOptions as iJ, WorkflowInstanceService as iK, type InvitationServiceConfig as iL, InvitationNotFoundError as iM, InvitationExpiredError as iN, InvitationAlreadyAcceptedError as iO, InvitationRevokedError as iP, WorkflowInvitationService as iQ, type FieldReadOnlyResult as iR, WorkflowRelationService as iS, type CreateWorkflowInput as iT, type UpdateWorkflowInput as iU, type WorkflowServiceOptions as iV, WorkflowService as iW, type UserValidationResult as iX, type UserValidationError as iY, UserService as iZ, type UserProfileServiceOptions as i_, type RollupServiceOptions as ia, RollupService as ib, type RollupSchedulerOptions as ic, RollupScheduler as id, applyDefaultValues as ie, checkPermission as ig, getPolicy as ih, buildPolicyContext as ii, checkRecordAccess as ij, checkRecordModifyOrThrow as ik, checkRecordDeleteOrThrow as il, checkSharedObjectWriteAccess as im, computeLabel as io, type LabelResolver as ip, enrichWithFormulas as iq, enrichRecordsWithFormulas as ir, createContextForCreate as is, createContextForUpdate as it, createContextForDelete as iu, createContextForRestore as iv, recalculateParentRollups as iw, type RollupCascadeContext as ix, type DocumentProcessingHookOptions as iy, DocumentProcessingHook as iz, type MultiRelationAttribute as j, type GlobalSearchResultItem as j$, AuditService as j0, buildAuditChanges as j1, DocumentGenerationTemplateNotFoundError as j2, DocumentGenerationNotConfiguredError as j3, DocumentGenerationService as j4, type DocumentProcessingConfig as j5, DocumentProcessingService as j6, type RenderDocumentInput as j7, type DocumentRendererOptions as j8, type RenderDocumentResult as j9, syncNativeObjects as jA, verifyNativeObjectsSync as jB, getSyncPreview as jC, type FullSyncResult as jD, type FullSyncOptions as jE, syncAll as jF, DEFAULT_LABEL_FALLBACK as jG, renderLabelExpression as jH, isLabelExpression as jI, extractAttributeNames as jJ, enrichValuesForDisplay as jK, enrichValuesWithSelectLabels as jL, extractRelationIds as jM, type RelationLabelResolver as jN, computeLabelWithRelations as jO, type DBObject as jP, type CreateDBObject as jQ, type UpdateDBObject as jR, type UpsertDBObject as jS, type DBAttribute as jT, type CreateDBAttribute as jU, type UpdateDBAttribute as jV, type UpsertDBAttribute as jW, type CreateObjectRecord as jX, type ListOptions as jY, type SearchOptions as jZ, type GlobalSearchOptions as j_, DocumentRenderError as ja, StorageDownloadNotSupportedError as jb, DocumentRendererService as jc, DocumentTemplateService as jd, type RecordDocumentsResult as je, type CreateRecordDocumentInput as jf, type CreateRecordDocumentResult as jg, type DocumentServiceOptions as jh, DocumentService as ji, type FileServiceOptions as jj, FileService as jk, GeocodingService as jl, GlobalSearchService as jm, type PermissionServiceOptions as jn, PermissionService as jo, type CreateViewInput as jp, type UpdateViewInput as jq, ViewService as jr, type FileContent as js, type StorageUploadInput as jt, type StorageUploadResult as ju, type SignedUrlOptions as jv, type StorageAdapter as jw, type UploadFileInput as jx, type SyncResult as jy, type SyncOptions as jz, type RelationTarget as k, type FileListOptions as k0, type DBView as k1, type CreateDBView as k2, type UpdateDBView as k3, type UpsertDBView as k4, type DBWorkflow as k5, type CreateDBWorkflow as k6, type UpdateDBWorkflow as k7, type DBWorkflowInstance as k8, type CreateDBWorkflowInstance as k9, type UpdateDBWorkflowInstance as ka, type DBWorkflowInvitation as kb, type CreateDBWorkflowInvitation as kc, type UpdateDBWorkflowInvitation as kd, type DBWorkflowAccessGrant as ke, type CreateDBWorkflowAccessGrant as kf, type UpdateDBWorkflowAccessGrant as kg, type OperationResult as kh, type ViewSyncResult as ki, type ViewSyncLogger as kj, type ViewSyncOptions as kk, syncNativeViews as kl, verifyNativeViewsSync as km, getViewSyncPreview as kn, type RatingAttribute as l, type FormulaAttribute as m, type FormulaReturnType as n, type RollupAttribute as o, type RollupFunction as p, type AttributeType as q, type ObjectDefinition as r, type Field as s, type AttributeGroupField as t, type TableTab as u, type InverseTableTab as v, type ViewDefinition as w, type InstanceStatus as x, type Tab as y, type FilterState as z };