@voyantjs/crm 0.26.0 → 0.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/index.d.ts +18 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +25 -6
  4. package/dist/route-runtime.d.ts +21 -0
  5. package/dist/route-runtime.d.ts.map +1 -0
  6. package/dist/route-runtime.js +28 -0
  7. package/dist/routes/accounts.d.ts +50 -2
  8. package/dist/routes/accounts.d.ts.map +1 -1
  9. package/dist/routes/index.d.ts +496 -2
  10. package/dist/routes/index.d.ts.map +1 -1
  11. package/dist/routes/index.js +2 -0
  12. package/dist/routes/person-documents.d.ts +458 -0
  13. package/dist/routes/person-documents.d.ts.map +1 -0
  14. package/dist/routes/person-documents.js +160 -0
  15. package/dist/schema-accounts.d.ts +367 -0
  16. package/dist/schema-accounts.d.ts.map +1 -1
  17. package/dist/schema-accounts.js +68 -2
  18. package/dist/schema-activities.js +2 -2
  19. package/dist/schema-relations.js +3 -3
  20. package/dist/schema-sales.js +2 -2
  21. package/dist/schema.d.ts +6 -6
  22. package/dist/schema.d.ts.map +1 -1
  23. package/dist/schema.js +6 -6
  24. package/dist/service/accounts-people.d.ts +49 -1
  25. package/dist/service/accounts-people.d.ts.map +1 -1
  26. package/dist/service/accounts-shared.d.ts +12 -0
  27. package/dist/service/accounts-shared.d.ts.map +1 -1
  28. package/dist/service/accounts-shared.js +4 -0
  29. package/dist/service/accounts.d.ts +49 -1
  30. package/dist/service/accounts.d.ts.map +1 -1
  31. package/dist/service/index.d.ts +1172 -1
  32. package/dist/service/index.d.ts.map +1 -1
  33. package/dist/service/index.js +3 -0
  34. package/dist/service/person-documents.d.ts +1188 -0
  35. package/dist/service/person-documents.d.ts.map +1 -0
  36. package/dist/service/person-documents.js +216 -0
  37. package/dist/validation.d.ts +168 -0
  38. package/dist/validation.d.ts.map +1 -1
  39. package/dist/validation.js +68 -0
  40. package/package.json +6 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"person-documents.d.ts","sourceRoot":"","sources":["../../src/service/person-documents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,216 @@
1
+ import { decryptOptionalJsonEnvelope } from "@voyantjs/utils";
2
+ import { and, asc, eq, gte, isNotNull, lte, sql } from "drizzle-orm";
3
+ import { z } from "zod";
4
+ import { people, personDocuments } from "../schema.js";
5
+ /**
6
+ * Canonical plaintext shape for free-text PII blobs encrypted as
7
+ * `accessibilityEncrypted` / `dietaryEncrypted` / `loyaltyEncrypted` /
8
+ * `insuranceEncrypted` on `crm.people`. Wrapped so future fields can
9
+ * be added without breaking existing ciphertexts.
10
+ *
11
+ * Writers (customer-portal) and readers (crm + bookings snapshot)
12
+ * must use this shape — drift between sides means decryption fails
13
+ * silently and pre-fill stops working.
14
+ */
15
+ export const personPiiBlobPlaintextSchema = z.object({ text: z.string() });
16
+ /**
17
+ * Canonical plaintext shape for `numberEncrypted` on
18
+ * `crm.person_documents`. Same compatibility contract as
19
+ * `personPiiBlobPlaintextSchema`.
20
+ */
21
+ export const personDocumentNumberPlaintextSchema = z.object({ number: z.string() });
22
+ async function personExists(db, personId) {
23
+ const [row] = await db
24
+ .select({ id: people.id })
25
+ .from(people)
26
+ .where(eq(people.id, personId))
27
+ .limit(1);
28
+ return Boolean(row);
29
+ }
30
+ async function clearPrimaryForType(db, personId, type, exceptDocumentId) {
31
+ const conditions = [
32
+ eq(personDocuments.personId, personId),
33
+ eq(personDocuments.type, type),
34
+ eq(personDocuments.isPrimary, true),
35
+ ];
36
+ if (exceptDocumentId) {
37
+ conditions.push(sql `${personDocuments.id} <> ${exceptDocumentId}`);
38
+ }
39
+ await db
40
+ .update(personDocuments)
41
+ .set({ isPrimary: false, updatedAt: new Date() })
42
+ .where(and(...conditions));
43
+ }
44
+ export const personDocumentsService = {
45
+ listPersonDocuments(db, personId, query) {
46
+ const conditions = [eq(personDocuments.personId, personId)];
47
+ if (query?.type)
48
+ conditions.push(eq(personDocuments.type, query.type));
49
+ if (query?.expiringBefore) {
50
+ conditions.push(isNotNull(personDocuments.expiryDate));
51
+ conditions.push(lte(personDocuments.expiryDate, query.expiringBefore));
52
+ }
53
+ const limit = query?.limit ?? 50;
54
+ const offset = query?.offset ?? 0;
55
+ return db
56
+ .select()
57
+ .from(personDocuments)
58
+ .where(and(...conditions))
59
+ .orderBy(asc(personDocuments.type), asc(personDocuments.createdAt))
60
+ .limit(limit)
61
+ .offset(offset);
62
+ },
63
+ async getPersonDocument(db, documentId) {
64
+ const [row] = await db
65
+ .select()
66
+ .from(personDocuments)
67
+ .where(eq(personDocuments.id, documentId))
68
+ .limit(1);
69
+ return row ?? null;
70
+ },
71
+ /**
72
+ * Returns the primary document of a given type for a person, or
73
+ * `null` if no primary is set. Used by booking-traveler create to
74
+ * snapshot the person's passport.
75
+ */
76
+ async getPrimaryPersonDocument(db, personId, type) {
77
+ const [row] = await db
78
+ .select()
79
+ .from(personDocuments)
80
+ .where(and(eq(personDocuments.personId, personId), eq(personDocuments.type, type), eq(personDocuments.isPrimary, true)))
81
+ .limit(1);
82
+ return row ?? null;
83
+ },
84
+ async createPersonDocument(db, personId, data) {
85
+ if (!(await personExists(db, personId)))
86
+ return null;
87
+ return db.transaction(async (tx) => {
88
+ if (data.isPrimary) {
89
+ await clearPrimaryForType(tx, personId, data.type);
90
+ }
91
+ const [row] = await tx
92
+ .insert(personDocuments)
93
+ .values({ ...data, personId })
94
+ .returning();
95
+ return row ?? null;
96
+ });
97
+ },
98
+ async updatePersonDocument(db, documentId, data) {
99
+ return db.transaction(async (tx) => {
100
+ const [existing] = await tx
101
+ .select()
102
+ .from(personDocuments)
103
+ .where(eq(personDocuments.id, documentId))
104
+ .limit(1);
105
+ if (!existing)
106
+ return null;
107
+ // Clear prior primary of the *target* type whenever the row
108
+ // will end up primary after this update — including the case
109
+ // where `isPrimary` is unchanged but `type` is being switched
110
+ // and the existing row is already primary. Without this, the
111
+ // partial unique index `(person_id, type) WHERE is_primary`
112
+ // rejects type-only edits on a primary doc.
113
+ const effectiveIsPrimary = data.isPrimary ?? existing.isPrimary;
114
+ if (effectiveIsPrimary) {
115
+ const targetType = data.type ?? existing.type;
116
+ await clearPrimaryForType(tx, existing.personId, targetType, documentId);
117
+ }
118
+ const [row] = await tx
119
+ .update(personDocuments)
120
+ .set({ ...data, updatedAt: new Date() })
121
+ .where(eq(personDocuments.id, documentId))
122
+ .returning();
123
+ return row ?? null;
124
+ });
125
+ },
126
+ async deletePersonDocument(db, documentId) {
127
+ const [row] = await db
128
+ .delete(personDocuments)
129
+ .where(eq(personDocuments.id, documentId))
130
+ .returning({ id: personDocuments.id });
131
+ return row ?? null;
132
+ },
133
+ /**
134
+ * Atomically promotes a document to primary, demoting any prior
135
+ * primary of the same type for the same person.
136
+ */
137
+ async setPrimaryPersonDocument(db, documentId) {
138
+ return db.transaction(async (tx) => {
139
+ const [existing] = await tx
140
+ .select()
141
+ .from(personDocuments)
142
+ .where(eq(personDocuments.id, documentId))
143
+ .limit(1);
144
+ if (!existing)
145
+ return null;
146
+ await clearPrimaryForType(tx, existing.personId, existing.type, documentId);
147
+ const [row] = await tx
148
+ .update(personDocuments)
149
+ .set({ isPrimary: true, updatedAt: new Date() })
150
+ .where(eq(personDocuments.id, documentId))
151
+ .returning();
152
+ return row ?? null;
153
+ });
154
+ },
155
+ /**
156
+ * Plaintext snapshot of the fields a booking-traveler creation
157
+ * pulls from a person record: dietary, accessibility, primary
158
+ * passport (number + expiry + country + authority + provenance id),
159
+ * and date-of-birth from `people.birthday`.
160
+ *
161
+ * Caller passes a KMS provider so decryption happens in-process.
162
+ * Missing person → returns null. Missing document or blob → that
163
+ * field returns null in the snapshot.
164
+ */
165
+ async loadPersonTravelSnapshot(db, personId, options) {
166
+ const [personRow] = await db
167
+ .select({
168
+ birthday: people.birthday,
169
+ accessibilityEncrypted: people.accessibilityEncrypted,
170
+ dietaryEncrypted: people.dietaryEncrypted,
171
+ })
172
+ .from(people)
173
+ .where(eq(people.id, personId))
174
+ .limit(1);
175
+ if (!personRow)
176
+ return null;
177
+ const keyRef = options.keyRef ?? { keyType: "people" };
178
+ const [accessibilityBlob, dietaryBlob, primaryPassport] = await Promise.all([
179
+ decryptOptionalJsonEnvelope(options.kms, keyRef, personRow.accessibilityEncrypted, personPiiBlobPlaintextSchema),
180
+ decryptOptionalJsonEnvelope(options.kms, keyRef, personRow.dietaryEncrypted, personPiiBlobPlaintextSchema),
181
+ personDocumentsService.getPrimaryPersonDocument(db, personId, "passport"),
182
+ ]);
183
+ let passportNumber = null;
184
+ if (primaryPassport?.numberEncrypted) {
185
+ const decrypted = await decryptOptionalJsonEnvelope(options.kms, keyRef, primaryPassport.numberEncrypted, personDocumentNumberPlaintextSchema);
186
+ passportNumber = decrypted?.number ?? null;
187
+ }
188
+ return {
189
+ dateOfBirth: personRow.birthday ?? null,
190
+ dietaryRequirements: dietaryBlob?.text ?? null,
191
+ accessibilityNeeds: accessibilityBlob?.text ?? null,
192
+ passportNumber,
193
+ passportExpiry: primaryPassport?.expiryDate ?? null,
194
+ passportIssuingCountry: primaryPassport?.issuingCountry ?? null,
195
+ passportIssuingAuthority: primaryPassport?.issuingAuthority ?? null,
196
+ passportPersonDocumentId: primaryPassport?.id ?? null,
197
+ };
198
+ },
199
+ /**
200
+ * Documents whose `expiryDate` falls within the next `daysAhead`
201
+ * days. Used by the future `crm.detect-expiring-documents` cron;
202
+ * shipped now since the helper is free.
203
+ */
204
+ listExpiringPersonDocuments(db, daysAhead = 90) {
205
+ const today = new Date();
206
+ const horizon = new Date(today);
207
+ horizon.setUTCDate(horizon.getUTCDate() + daysAhead);
208
+ const todayIso = today.toISOString().slice(0, 10);
209
+ const horizonIso = horizon.toISOString().slice(0, 10);
210
+ return db
211
+ .select()
212
+ .from(personDocuments)
213
+ .where(and(isNotNull(personDocuments.expiryDate), gte(personDocuments.expiryDate, todayIso), lte(personDocuments.expiryDate, horizonIso)))
214
+ .orderBy(asc(personDocuments.expiryDate));
215
+ },
216
+ };
@@ -205,6 +205,18 @@ export declare const personCoreSchema: z.ZodObject<{
205
205
  tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
206
206
  birthday: z.ZodOptional<z.ZodNullable<z.ZodString>>;
207
207
  notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
208
+ accessibilityEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
209
+ enc: z.ZodString;
210
+ }, z.core.$strip>>>;
211
+ dietaryEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
212
+ enc: z.ZodString;
213
+ }, z.core.$strip>>>;
214
+ loyaltyEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
215
+ enc: z.ZodString;
216
+ }, z.core.$strip>>>;
217
+ insuranceEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
218
+ enc: z.ZodString;
219
+ }, z.core.$strip>>>;
208
220
  email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
209
221
  phone: z.ZodOptional<z.ZodNullable<z.ZodString>>;
210
222
  website: z.ZodPipe<z.ZodUnion<[z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodLiteral<"">]>, z.ZodTransform<string | null, string | null | undefined>>;
@@ -239,6 +251,18 @@ export declare const insertPersonSchema: z.ZodObject<{
239
251
  tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
240
252
  birthday: z.ZodOptional<z.ZodNullable<z.ZodString>>;
241
253
  notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
254
+ accessibilityEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
255
+ enc: z.ZodString;
256
+ }, z.core.$strip>>>;
257
+ dietaryEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
258
+ enc: z.ZodString;
259
+ }, z.core.$strip>>>;
260
+ loyaltyEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
261
+ enc: z.ZodString;
262
+ }, z.core.$strip>>>;
263
+ insuranceEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
264
+ enc: z.ZodString;
265
+ }, z.core.$strip>>>;
242
266
  email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
243
267
  phone: z.ZodOptional<z.ZodNullable<z.ZodString>>;
244
268
  website: z.ZodPipe<z.ZodUnion<[z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodLiteral<"">]>, z.ZodTransform<string | null, string | null | undefined>>;
@@ -273,6 +297,18 @@ export declare const updatePersonSchema: z.ZodObject<{
273
297
  tags: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
274
298
  birthday: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
275
299
  notes: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
300
+ accessibilityEncrypted: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodObject<{
301
+ enc: z.ZodString;
302
+ }, z.core.$strip>>>>;
303
+ dietaryEncrypted: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodObject<{
304
+ enc: z.ZodString;
305
+ }, z.core.$strip>>>>;
306
+ loyaltyEncrypted: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodObject<{
307
+ enc: z.ZodString;
308
+ }, z.core.$strip>>>>;
309
+ insuranceEncrypted: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodObject<{
310
+ enc: z.ZodString;
311
+ }, z.core.$strip>>>>;
276
312
  email: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
277
313
  phone: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
278
314
  website: z.ZodOptional<z.ZodPipe<z.ZodUnion<[z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodLiteral<"">]>, z.ZodTransform<string | null, string | null | undefined>>>;
@@ -816,6 +852,138 @@ export declare const customFieldValueListQuerySchema: z.ZodObject<{
816
852
  entityId: z.ZodOptional<z.ZodString>;
817
853
  definitionId: z.ZodOptional<z.ZodString>;
818
854
  }, z.core.$strip>;
855
+ export declare const personDocumentTypeSchema: z.ZodEnum<{
856
+ passport: "passport";
857
+ visa: "visa";
858
+ other: "other";
859
+ id_card: "id_card";
860
+ driver_license: "driver_license";
861
+ }>;
862
+ export declare const personDocumentCoreSchema: z.ZodObject<{
863
+ type: z.ZodEnum<{
864
+ passport: "passport";
865
+ visa: "visa";
866
+ other: "other";
867
+ id_card: "id_card";
868
+ driver_license: "driver_license";
869
+ }>;
870
+ numberEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
871
+ enc: z.ZodString;
872
+ }, z.core.$strip>>>;
873
+ issuingAuthority: z.ZodOptional<z.ZodNullable<z.ZodString>>;
874
+ issuingCountry: z.ZodOptional<z.ZodNullable<z.ZodString>>;
875
+ issueDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
876
+ expiryDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
877
+ attachmentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
878
+ isPrimary: z.ZodDefault<z.ZodBoolean>;
879
+ notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
880
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
881
+ }, z.core.$strip>;
882
+ export declare const insertPersonDocumentSchema: z.ZodObject<{
883
+ type: z.ZodEnum<{
884
+ passport: "passport";
885
+ visa: "visa";
886
+ other: "other";
887
+ id_card: "id_card";
888
+ driver_license: "driver_license";
889
+ }>;
890
+ numberEncrypted: z.ZodOptional<z.ZodNullable<z.ZodObject<{
891
+ enc: z.ZodString;
892
+ }, z.core.$strip>>>;
893
+ issuingAuthority: z.ZodOptional<z.ZodNullable<z.ZodString>>;
894
+ issuingCountry: z.ZodOptional<z.ZodNullable<z.ZodString>>;
895
+ issueDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
896
+ expiryDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
897
+ attachmentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
898
+ isPrimary: z.ZodDefault<z.ZodBoolean>;
899
+ notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
900
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
901
+ }, z.core.$strip>;
902
+ export declare const updatePersonDocumentSchema: z.ZodObject<{
903
+ type: z.ZodOptional<z.ZodEnum<{
904
+ passport: "passport";
905
+ visa: "visa";
906
+ other: "other";
907
+ id_card: "id_card";
908
+ driver_license: "driver_license";
909
+ }>>;
910
+ numberEncrypted: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodObject<{
911
+ enc: z.ZodString;
912
+ }, z.core.$strip>>>>;
913
+ issuingAuthority: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
914
+ issuingCountry: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
915
+ issueDate: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
916
+ expiryDate: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
917
+ attachmentId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
918
+ isPrimary: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
919
+ notes: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
920
+ metadata: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>>;
921
+ }, z.core.$strip>;
922
+ export declare const personDocumentListQuerySchema: z.ZodObject<{
923
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
924
+ offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
925
+ type: z.ZodOptional<z.ZodEnum<{
926
+ passport: "passport";
927
+ visa: "visa";
928
+ other: "other";
929
+ id_card: "id_card";
930
+ driver_license: "driver_license";
931
+ }>>;
932
+ expiringBefore: z.ZodOptional<z.ZodString>;
933
+ }, z.core.$strip>;
934
+ export declare const insertPersonDocumentFromPlaintextSchema: z.ZodObject<{
935
+ type: z.ZodEnum<{
936
+ passport: "passport";
937
+ visa: "visa";
938
+ other: "other";
939
+ id_card: "id_card";
940
+ driver_license: "driver_license";
941
+ }>;
942
+ number: z.ZodOptional<z.ZodNullable<z.ZodString>>;
943
+ issuingAuthority: z.ZodOptional<z.ZodNullable<z.ZodString>>;
944
+ issuingCountry: z.ZodOptional<z.ZodNullable<z.ZodString>>;
945
+ issueDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
946
+ expiryDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
947
+ attachmentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
948
+ isPrimary: z.ZodDefault<z.ZodBoolean>;
949
+ notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
950
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
951
+ }, z.core.$strip>;
952
+ export declare const updatePersonDocumentFromPlaintextSchema: z.ZodObject<{
953
+ type: z.ZodOptional<z.ZodEnum<{
954
+ passport: "passport";
955
+ visa: "visa";
956
+ other: "other";
957
+ id_card: "id_card";
958
+ driver_license: "driver_license";
959
+ }>>;
960
+ number: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
961
+ issuingAuthority: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
962
+ issuingCountry: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
963
+ issueDate: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
964
+ expiryDate: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
965
+ attachmentId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
966
+ isPrimary: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
967
+ notes: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
968
+ metadata: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>>;
969
+ }, z.core.$strip>;
970
+ /**
971
+ * Plaintext input shape for the four free-text PII slots on
972
+ * `crm.people` (accessibility / dietary / loyalty / insurance). The
973
+ * admin endpoint encrypts each provided value server-side; `null`
974
+ * clears the slot.
975
+ */
976
+ export declare const updatePersonProfilePiiSchema: z.ZodObject<{
977
+ accessibility: z.ZodOptional<z.ZodNullable<z.ZodString>>;
978
+ dietary: z.ZodOptional<z.ZodNullable<z.ZodString>>;
979
+ loyalty: z.ZodOptional<z.ZodNullable<z.ZodString>>;
980
+ insurance: z.ZodOptional<z.ZodNullable<z.ZodString>>;
981
+ }, z.core.$strip>;
982
+ export type PersonDocumentInput = z.infer<typeof insertPersonDocumentSchema>;
983
+ export type PersonDocumentUpdate = z.infer<typeof updatePersonDocumentSchema>;
984
+ export type PersonDocumentPlaintextInput = z.infer<typeof insertPersonDocumentFromPlaintextSchema>;
985
+ export type PersonDocumentPlaintextUpdate = z.infer<typeof updatePersonDocumentFromPlaintextSchema>;
986
+ export type UpdatePersonProfilePiiInput = z.infer<typeof updatePersonProfilePiiSchema>;
819
987
  export declare const insertPersonNoteSchema: z.ZodObject<{
820
988
  content: z.ZodString;
821
989
  }, z.core.$strip>;
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { kmsEnvelopeSchema } from "@voyantjs/db/schema/iam/kms";
1
2
  import { z } from "zod";
2
3
  const paginationSchema = z.object({
3
4
  limit: z.coerce.number().int().min(1).max(200).default(50),
@@ -101,6 +102,11 @@ export const personCoreSchema = z.object({
101
102
  tags: z.array(z.string()).default([]),
102
103
  birthday: z.string().date().nullable().optional(),
103
104
  notes: z.string().nullable().optional(),
105
+ // Encrypted PII slots (canonical store; documents live in person_documents)
106
+ accessibilityEncrypted: kmsEnvelopeSchema.optional(),
107
+ dietaryEncrypted: kmsEnvelopeSchema.optional(),
108
+ loyaltyEncrypted: kmsEnvelopeSchema.optional(),
109
+ insuranceEncrypted: kmsEnvelopeSchema.optional(),
104
110
  // Inline identity fields — synced to identity module on create/update
105
111
  email: z.string().email().nullable().optional(),
106
112
  phone: z.string().nullable().optional(),
@@ -279,6 +285,68 @@ export const customFieldValueListQuerySchema = paginationSchema.extend({
279
285
  entityId: z.string().optional(),
280
286
  definitionId: z.string().optional(),
281
287
  });
288
+ // ---------- person documents ----------
289
+ export const personDocumentTypeSchema = z.enum([
290
+ "passport",
291
+ "id_card",
292
+ "driver_license",
293
+ "visa",
294
+ "other",
295
+ ]);
296
+ export const personDocumentCoreSchema = z.object({
297
+ type: personDocumentTypeSchema,
298
+ numberEncrypted: kmsEnvelopeSchema.optional(),
299
+ issuingAuthority: z.string().nullable().optional(),
300
+ issuingCountry: z.string().nullable().optional(),
301
+ issueDate: z.string().date().nullable().optional(),
302
+ expiryDate: z.string().date().nullable().optional(),
303
+ attachmentId: z.string().nullable().optional(),
304
+ isPrimary: z.boolean().default(false),
305
+ notes: z.string().nullable().optional(),
306
+ metadata: z.record(z.string(), z.unknown()).nullable().optional(),
307
+ });
308
+ export const insertPersonDocumentSchema = personDocumentCoreSchema;
309
+ export const updatePersonDocumentSchema = personDocumentCoreSchema.partial();
310
+ export const personDocumentListQuerySchema = paginationSchema.extend({
311
+ type: personDocumentTypeSchema.optional(),
312
+ expiringBefore: z.string().date().optional(),
313
+ });
314
+ /**
315
+ * Plaintext input shape for admin-facing create/update endpoints —
316
+ * the route encrypts `number` server-side using the people KMS key
317
+ * before persisting. Operator UIs prefer this over hand-encrypted
318
+ * envelopes.
319
+ */
320
+ const personDocumentPlaintextCoreSchema = z.object({
321
+ type: personDocumentTypeSchema,
322
+ number: z.string().max(255).nullable().optional(),
323
+ issuingAuthority: z.string().nullable().optional(),
324
+ issuingCountry: z.string().nullable().optional(),
325
+ issueDate: z.string().date().nullable().optional(),
326
+ expiryDate: z.string().date().nullable().optional(),
327
+ attachmentId: z.string().nullable().optional(),
328
+ isPrimary: z.boolean().default(false),
329
+ notes: z.string().nullable().optional(),
330
+ metadata: z.record(z.string(), z.unknown()).nullable().optional(),
331
+ });
332
+ export const insertPersonDocumentFromPlaintextSchema = personDocumentPlaintextCoreSchema;
333
+ export const updatePersonDocumentFromPlaintextSchema = personDocumentPlaintextCoreSchema.partial();
334
+ /**
335
+ * Plaintext input shape for the four free-text PII slots on
336
+ * `crm.people` (accessibility / dietary / loyalty / insurance). The
337
+ * admin endpoint encrypts each provided value server-side; `null`
338
+ * clears the slot.
339
+ */
340
+ export const updatePersonProfilePiiSchema = z
341
+ .object({
342
+ accessibility: z.string().max(4000).nullable().optional(),
343
+ dietary: z.string().max(4000).nullable().optional(),
344
+ loyalty: z.string().max(4000).nullable().optional(),
345
+ insurance: z.string().max(4000).nullable().optional(),
346
+ })
347
+ .refine((value) => Object.keys(value).length > 0, {
348
+ message: "At least one field must be provided",
349
+ });
282
350
  // ---------- notes ----------
283
351
  export const insertPersonNoteSchema = z.object({
284
352
  content: z.string().min(1).max(10000),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/crm",
3
- "version": "0.26.0",
3
+ "version": "0.26.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -34,10 +34,11 @@
34
34
  "drizzle-orm": "^0.45.2",
35
35
  "hono": "^4.12.10",
36
36
  "zod": "^4.3.6",
37
- "@voyantjs/core": "0.26.0",
38
- "@voyantjs/db": "0.26.0",
39
- "@voyantjs/hono": "0.26.0",
40
- "@voyantjs/identity": "0.26.0"
37
+ "@voyantjs/core": "0.26.2",
38
+ "@voyantjs/db": "0.26.2",
39
+ "@voyantjs/hono": "0.26.2",
40
+ "@voyantjs/identity": "0.26.2",
41
+ "@voyantjs/utils": "0.26.2"
41
42
  },
42
43
  "devDependencies": {
43
44
  "typescript": "^6.0.2",