@substrat-run/engine-protocol 0.7.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,322 @@
1
+ /**
2
+ * The shapes this engine ACCEPTS — every operation's input, and the template
3
+ * content vocabulary the inputs are built from.
4
+ *
5
+ * A file of their own for the same reason `schemas.ts` is one, and the reason is
6
+ * mechanical rather than tidiness. `index.ts` re-exports `operations.ts` so that
7
+ * a vertical importing the engine gets the declared surface from the package
8
+ * root; `operations.ts` declares each operation against the schema the handler
9
+ * parses. With those schemas living in `index.ts`, importing the engine ran
10
+ * `operations.ts` before `defineTemplateInput` was initialised — a require cycle
11
+ * that a warm `dist` hides and `pnpm lint:permissions`, which really imports the
12
+ * module, finds on the first run.
13
+ *
14
+ * So this module imports nothing from `index.ts`. It is a leaf, and the whole
15
+ * declared surface — entities, row schemas, input schemas — sits below the
16
+ * implementation rather than interleaved with it.
17
+ *
18
+ * Everything here stays exported from the package root: these are what a
19
+ * composing vertical passes in, and `index.ts` re-exports each one.
20
+ */
21
+ import { z } from 'zod';
22
+ export declare const protocolItem: z.ZodObject<{
23
+ key: z.ZodString;
24
+ label: z.ZodString;
25
+ type: z.ZodEnum<{
26
+ check: "check";
27
+ text: "text";
28
+ value: "value";
29
+ }>;
30
+ unit: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strip>;
32
+ export type ProtocolItem = z.infer<typeof protocolItem>;
33
+ /** The original shape: sections of items, filled response-by-response. */
34
+ export declare const checklistContent: z.ZodObject<{
35
+ kind: z.ZodLiteral<"checklist">;
36
+ sections: z.ZodArray<z.ZodObject<{
37
+ title: z.ZodString;
38
+ items: z.ZodArray<z.ZodObject<{
39
+ key: z.ZodString;
40
+ label: z.ZodString;
41
+ type: z.ZodEnum<{
42
+ check: "check";
43
+ text: "text";
44
+ value: "value";
45
+ }>;
46
+ unit: z.ZodOptional<z.ZodString>;
47
+ }, z.core.$strip>>;
48
+ }, z.core.$strip>>;
49
+ }, z.core.$strip>;
50
+ export type ChecklistContent = z.infer<typeof checklistContent>;
51
+ /**
52
+ * Content the engine never sees. The template says what KIND of document this
53
+ * is and how to render it; the instance carries the vertical's `EntityRef` and
54
+ * the hash the vertical computed over its own rows.
55
+ *
56
+ * `hashRecipe` is free text, and it is the load-bearing honesty of this kind:
57
+ * a document signature attests to a hash the engine did not compute, so the
58
+ * recipe for reproducing it must be written down where an auditor reading the
59
+ * template finds it. The engine cannot enforce that the text is true — but a
60
+ * signature over an unreproducible hash is worth nothing, and a required field
61
+ * is what makes the vertical say out loud how to reproduce it.
62
+ */
63
+ export declare const documentContent: z.ZodObject<{
64
+ kind: z.ZodLiteral<"document">;
65
+ documentType: z.ZodString;
66
+ hashRecipe: z.ZodString;
67
+ description: z.ZodOptional<z.ZodString>;
68
+ }, z.core.$strip>;
69
+ export type DocumentContent = z.infer<typeof documentContent>;
70
+ /**
71
+ * The content VALUE, either kind — what a parsed template holds.
72
+ *
73
+ * Exported alongside `protocolTemplateContent` because the two describe
74
+ * different moments and only one of them is a parser for stored bytes. This is
75
+ * the shape a caller RECEIVES (`protocol/get` returns it); the preprocessing
76
+ * schema below is what turns a stored row into it, discriminant-less legacy rows
77
+ * included. Declaring a return against a `z.preprocess` would publish the
78
+ * normalisation as though it were the contract.
79
+ */
80
+ export declare const contentUnion: z.ZodDiscriminatedUnion<[z.ZodObject<{
81
+ kind: z.ZodLiteral<"checklist">;
82
+ sections: z.ZodArray<z.ZodObject<{
83
+ title: z.ZodString;
84
+ items: z.ZodArray<z.ZodObject<{
85
+ key: z.ZodString;
86
+ label: z.ZodString;
87
+ type: z.ZodEnum<{
88
+ check: "check";
89
+ text: "text";
90
+ value: "value";
91
+ }>;
92
+ unit: z.ZodOptional<z.ZodString>;
93
+ }, z.core.$strip>>;
94
+ }, z.core.$strip>>;
95
+ }, z.core.$strip>, z.ZodObject<{
96
+ kind: z.ZodLiteral<"document">;
97
+ documentType: z.ZodString;
98
+ hashRecipe: z.ZodString;
99
+ description: z.ZodOptional<z.ZodString>;
100
+ }, z.core.$strip>], "kind">;
101
+ /**
102
+ * Parses either kind, defaulting a missing discriminant to 'checklist' so
103
+ * every template defined before milestone D still parses. Note this is a
104
+ * READ-time normalisation: `defineTemplate` stores what it is given after
105
+ * parsing, so new templates carry an explicit `kind`, and old rows keep their
106
+ * bytes (and therefore their hashes) exactly as signed.
107
+ */
108
+ export declare const protocolTemplateContent: z.ZodPreprocess<z.ZodDiscriminatedUnion<[z.ZodObject<{
109
+ kind: z.ZodLiteral<"checklist">;
110
+ sections: z.ZodArray<z.ZodObject<{
111
+ title: z.ZodString;
112
+ items: z.ZodArray<z.ZodObject<{
113
+ key: z.ZodString;
114
+ label: z.ZodString;
115
+ type: z.ZodEnum<{
116
+ check: "check";
117
+ text: "text";
118
+ value: "value";
119
+ }>;
120
+ unit: z.ZodOptional<z.ZodString>;
121
+ }, z.core.$strip>>;
122
+ }, z.core.$strip>>;
123
+ }, z.core.$strip>, z.ZodObject<{
124
+ kind: z.ZodLiteral<"document">;
125
+ documentType: z.ZodString;
126
+ hashRecipe: z.ZodString;
127
+ description: z.ZodOptional<z.ZodString>;
128
+ }, z.core.$strip>], "kind">>;
129
+ export type ProtocolTemplateContent = z.infer<typeof contentUnion>;
130
+ /**
131
+ * Who signed. Two kinds, and the difference is the whole point of milestone D:
132
+ *
133
+ * - `principal` — an authenticated principal in this scope. `ref` is their
134
+ * `PrincipalId`. Every in-app signature.
135
+ * - `external` — a human with no account, identified by an external provider
136
+ * (BankID via Scrive). `ref` is an OPAQUE `DataSubjectId` the vertical minted
137
+ * for that person.
138
+ *
139
+ * A personnummer, an email or a name must NEVER land in `ref`. It is `direct`
140
+ * PII, and `subjectId` on the emitted event is what crypto-shredding keys the
141
+ * erasure on (§5.3) — a `DataSubjectId` is shreddable, a personnummer written
142
+ * into a signature row is a GDPR liability that immutability makes permanent.
143
+ * The provider's own party identifier belongs in `evidenceRef`, which is where
144
+ * the sealed PDF and the provider audit log are reachable from.
145
+ *
146
+ * This follows `engines/booking`'s `partyRef`: a participant is a person with
147
+ * no principal, and it names them with a `DataSubjectId` for exactly this
148
+ * reason.
149
+ */
150
+ export declare const signatory: z.ZodDiscriminatedUnion<[z.ZodObject<{
151
+ kind: z.ZodLiteral<"principal">;
152
+ ref: z.core.$ZodBranded<z.ZodString, "PrincipalId", "out">;
153
+ label: z.ZodOptional<z.ZodString>;
154
+ }, z.core.$strip>, z.ZodObject<{
155
+ kind: z.ZodLiteral<"external">;
156
+ ref: z.core.$ZodBranded<z.ZodString, "DataSubjectId", "out">;
157
+ label: z.ZodOptional<z.ZodString>;
158
+ }, z.core.$strip>], "kind">;
159
+ export type Signatory = z.infer<typeof signatory>;
160
+ export declare const defineTemplateInput: z.ZodObject<{
161
+ key: z.ZodString;
162
+ title: z.ZodString;
163
+ content: z.ZodPreprocess<z.ZodDiscriminatedUnion<[z.ZodObject<{
164
+ kind: z.ZodLiteral<"checklist">;
165
+ sections: z.ZodArray<z.ZodObject<{
166
+ title: z.ZodString;
167
+ items: z.ZodArray<z.ZodObject<{
168
+ key: z.ZodString;
169
+ label: z.ZodString;
170
+ type: z.ZodEnum<{
171
+ check: "check";
172
+ text: "text";
173
+ value: "value";
174
+ }>;
175
+ unit: z.ZodOptional<z.ZodString>;
176
+ }, z.core.$strip>>;
177
+ }, z.core.$strip>>;
178
+ }, z.core.$strip>, z.ZodObject<{
179
+ kind: z.ZodLiteral<"document">;
180
+ documentType: z.ZodString;
181
+ hashRecipe: z.ZodString;
182
+ description: z.ZodOptional<z.ZodString>;
183
+ }, z.core.$strip>], "kind">>;
184
+ }, z.core.$strip>;
185
+ /**
186
+ * What a template author writes. Spelled out rather than inferred because the
187
+ * `kind` normalisation is a `z.preprocess`, whose inferred INPUT type is
188
+ * `unknown` — which would silently drop type-checking on exactly the object a
189
+ * vertical hand-writes most often. `kind` is optional only for checklists, so
190
+ * every template that predates the discriminant still compiles unchanged.
191
+ */
192
+ export type ProtocolTemplateContentInput = (Omit<ChecklistContent, 'kind'> & {
193
+ kind?: 'checklist';
194
+ }) | DocumentContent;
195
+ export interface DefineTemplateInput {
196
+ key: string;
197
+ title: string;
198
+ content: ProtocolTemplateContentInput;
199
+ }
200
+ export declare const instantiateProtocolInput: z.ZodObject<{
201
+ templateKey: z.ZodString;
202
+ entity: z.ZodObject<{
203
+ entityType: z.ZodString;
204
+ entityId: z.ZodString;
205
+ }, z.core.$strip>;
206
+ }, z.core.$strip>;
207
+ export type InstantiateProtocolInput = z.infer<typeof instantiateProtocolInput>;
208
+ export declare const fillProtocolInput: z.ZodObject<{
209
+ instanceId: z.ZodString;
210
+ itemKey: z.ZodString;
211
+ value: z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>;
212
+ note: z.ZodOptional<z.ZodString>;
213
+ }, z.core.$strip>;
214
+ export type FillProtocolInput = z.infer<typeof fillProtocolInput>;
215
+ export declare const bindDocumentInput: z.ZodObject<{
216
+ instanceId: z.ZodString;
217
+ contentRef: z.ZodObject<{
218
+ entityType: z.ZodString;
219
+ entityId: z.ZodString;
220
+ }, z.core.$strip>;
221
+ contentHash: z.ZodString;
222
+ documentAttachmentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
223
+ }, z.core.$strip>;
224
+ export type BindDocumentInput = z.infer<typeof bindDocumentInput>;
225
+ /**
226
+ * How a signing party is REACHED (#687) — a delivery address, and nothing else.
227
+ *
228
+ * Typed rather than an opaque blob the engine never interprets, and the reason is
229
+ * the `authLevel` argument from #620 one level down: a provider-agnostic engine
230
+ * that cannot say what "how to reach a party" means is an engine every vertical
231
+ * has to guess around, and every connector has to re-derive. The type is small,
232
+ * provider-agnostic, and — with no personal number in it — free of anything a
233
+ * provider-specific vocabulary would be needed for.
234
+ *
235
+ * **No `personalNumber`, deliberately, and not merely as an omission.** An
236
+ * optional PII field on an engine surface is a carrier that exists, and this one
237
+ * is not needed by any path in the tree: a signatory enters their personnummer
238
+ * into the BankID ceremony itself, and it comes back in the completion data.
239
+ * Adding it would recreate exactly the problem this carrier was built to avoid.
240
+ */
241
+ export declare const partyContact: z.ZodObject<{
242
+ email: z.ZodOptional<z.ZodString>;
243
+ mobile: z.ZodOptional<z.ZodString>;
244
+ }, z.core.$strip>;
245
+ export type PartyContact = z.infer<typeof partyContact>;
246
+ export declare const signatureRequestParty: z.ZodObject<{
247
+ label: z.ZodString;
248
+ kind: z.ZodEnum<{
249
+ external: "external";
250
+ principal: "principal";
251
+ }>;
252
+ ref: z.ZodOptional<z.ZodString>;
253
+ signatureKind: z.ZodOptional<z.ZodEnum<{
254
+ counter: "counter";
255
+ primary: "primary";
256
+ }>>;
257
+ authLevel: z.ZodOptional<z.ZodEnum<{
258
+ basic: "basic";
259
+ strong: "strong";
260
+ }>>;
261
+ contact: z.ZodOptional<z.ZodObject<{
262
+ email: z.ZodOptional<z.ZodString>;
263
+ mobile: z.ZodOptional<z.ZodString>;
264
+ }, z.core.$strip>>;
265
+ }, z.core.$strip>;
266
+ export type SignatureRequestParty = z.input<typeof signatureRequestParty>;
267
+ export declare const requestSignaturesInput: z.ZodObject<{
268
+ instanceId: z.ZodString;
269
+ method: z.ZodString;
270
+ parties: z.ZodArray<z.ZodObject<{
271
+ label: z.ZodString;
272
+ kind: z.ZodEnum<{
273
+ external: "external";
274
+ principal: "principal";
275
+ }>;
276
+ ref: z.ZodOptional<z.ZodString>;
277
+ signatureKind: z.ZodOptional<z.ZodEnum<{
278
+ counter: "counter";
279
+ primary: "primary";
280
+ }>>;
281
+ authLevel: z.ZodOptional<z.ZodEnum<{
282
+ basic: "basic";
283
+ strong: "strong";
284
+ }>>;
285
+ contact: z.ZodOptional<z.ZodObject<{
286
+ email: z.ZodOptional<z.ZodString>;
287
+ mobile: z.ZodOptional<z.ZodString>;
288
+ }, z.core.$strip>>;
289
+ }, z.core.$strip>>;
290
+ }, z.core.$strip>;
291
+ export type RequestSignaturesInput = z.input<typeof requestSignaturesInput>;
292
+ export declare const recordSignatureInput: z.ZodObject<{
293
+ requestId: z.ZodString;
294
+ signatory: z.ZodDiscriminatedUnion<[z.ZodObject<{
295
+ kind: z.ZodLiteral<"principal">;
296
+ ref: z.core.$ZodBranded<z.ZodString, "PrincipalId", "out">;
297
+ label: z.ZodOptional<z.ZodString>;
298
+ }, z.core.$strip>, z.ZodObject<{
299
+ kind: z.ZodLiteral<"external">;
300
+ ref: z.core.$ZodBranded<z.ZodString, "DataSubjectId", "out">;
301
+ label: z.ZodOptional<z.ZodString>;
302
+ }, z.core.$strip>], "kind">;
303
+ signedAt: z.core.$ZodBranded<z.ZodString, "Instant", "out">;
304
+ contentHash: z.ZodString;
305
+ evidenceRef: z.ZodOptional<z.ZodString>;
306
+ }, z.core.$strip>;
307
+ export type RecordSignatureInput = z.input<typeof recordSignatureInput>;
308
+ export declare const declineSignatureInput: z.ZodObject<{
309
+ requestId: z.ZodString;
310
+ reason: z.ZodString;
311
+ outcome: z.ZodDefault<z.ZodEnum<{
312
+ declined: "declined";
313
+ expired: "expired";
314
+ }>>;
315
+ }, z.core.$strip>;
316
+ export type DeclineSignatureInput = z.input<typeof declineSignatureInput>;
317
+ export declare const cancelSignatureRequestsInput: z.ZodObject<{
318
+ instanceId: z.ZodString;
319
+ reason: z.ZodString;
320
+ }, z.core.$strip>;
321
+ export type CancelSignatureRequestsInput = z.infer<typeof cancelSignatureRequestsInput>;
322
+ //# sourceMappingURL=inputs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../src/inputs.ts"],"names":[],"mappings":"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"}
package/dist/inputs.js ADDED
@@ -0,0 +1,285 @@
1
+ /**
2
+ * The shapes this engine ACCEPTS — every operation's input, and the template
3
+ * content vocabulary the inputs are built from.
4
+ *
5
+ * A file of their own for the same reason `schemas.ts` is one, and the reason is
6
+ * mechanical rather than tidiness. `index.ts` re-exports `operations.ts` so that
7
+ * a vertical importing the engine gets the declared surface from the package
8
+ * root; `operations.ts` declares each operation against the schema the handler
9
+ * parses. With those schemas living in `index.ts`, importing the engine ran
10
+ * `operations.ts` before `defineTemplateInput` was initialised — a require cycle
11
+ * that a warm `dist` hides and `pnpm lint:permissions`, which really imports the
12
+ * module, finds on the first run.
13
+ *
14
+ * So this module imports nothing from `index.ts`. It is a leaf, and the whole
15
+ * declared surface — entities, row schemas, input schemas — sits below the
16
+ * implementation rather than interleaved with it.
17
+ *
18
+ * Everything here stays exported from the package root: these are what a
19
+ * composing vertical passes in, and `index.ts` re-exports each one.
20
+ */
21
+ import { z } from 'zod';
22
+ import { dataSubjectId, entityRef, instant, principalId } from '@substrat-run/contracts';
23
+ // ---------------------------------------------------------------------------
24
+ // Template content SHAPE — engine-owned so fills can be validated against the
25
+ // pinned template. The content VALUES (sections, items, vocabulary,
26
+ // branschprotokoll packs) are written by verticals.
27
+ //
28
+ // Two kinds, discriminated on `kind`. Content stored before the discriminant
29
+ // existed carries no `kind` and is normalised to 'checklist' at PARSE time
30
+ // only — never rewritten in the database, because the hash covers the stored
31
+ // string byte-for-byte.
32
+ // ---------------------------------------------------------------------------
33
+ export const protocolItem = z.object({
34
+ key: z.string().min(1),
35
+ label: z.string().min(1),
36
+ type: z.enum(['check', 'value', 'text']),
37
+ unit: z.string().optional(), // 'MΩ' on measurements
38
+ });
39
+ /** The original shape: sections of items, filled response-by-response. */
40
+ export const checklistContent = z.object({
41
+ kind: z.literal('checklist'),
42
+ sections: z
43
+ .array(z.object({ title: z.string().min(1), items: z.array(protocolItem).min(1) }))
44
+ .min(1),
45
+ });
46
+ /**
47
+ * Content the engine never sees. The template says what KIND of document this
48
+ * is and how to render it; the instance carries the vertical's `EntityRef` and
49
+ * the hash the vertical computed over its own rows.
50
+ *
51
+ * `hashRecipe` is free text, and it is the load-bearing honesty of this kind:
52
+ * a document signature attests to a hash the engine did not compute, so the
53
+ * recipe for reproducing it must be written down where an auditor reading the
54
+ * template finds it. The engine cannot enforce that the text is true — but a
55
+ * signature over an unreproducible hash is worth nothing, and a required field
56
+ * is what makes the vertical say out loud how to reproduce it.
57
+ */
58
+ export const documentContent = z.object({
59
+ kind: z.literal('document'),
60
+ /** Vertical vocabulary for what this is — 'avtal', 'styrelserapport'. */
61
+ documentType: z.string().min(1),
62
+ /** How to recompute `boundHash` from the vertical's own rows. */
63
+ hashRecipe: z.string().min(1),
64
+ description: z.string().optional(),
65
+ });
66
+ /**
67
+ * The content VALUE, either kind — what a parsed template holds.
68
+ *
69
+ * Exported alongside `protocolTemplateContent` because the two describe
70
+ * different moments and only one of them is a parser for stored bytes. This is
71
+ * the shape a caller RECEIVES (`protocol/get` returns it); the preprocessing
72
+ * schema below is what turns a stored row into it, discriminant-less legacy rows
73
+ * included. Declaring a return against a `z.preprocess` would publish the
74
+ * normalisation as though it were the contract.
75
+ */
76
+ export const contentUnion = z.discriminatedUnion('kind', [checklistContent, documentContent]);
77
+ /**
78
+ * Parses either kind, defaulting a missing discriminant to 'checklist' so
79
+ * every template defined before milestone D still parses. Note this is a
80
+ * READ-time normalisation: `defineTemplate` stores what it is given after
81
+ * parsing, so new templates carry an explicit `kind`, and old rows keep their
82
+ * bytes (and therefore their hashes) exactly as signed.
83
+ */
84
+ export const protocolTemplateContent = z.preprocess((value) => value && typeof value === 'object' && !Array.isArray(value) && !('kind' in value)
85
+ ? { ...value, kind: 'checklist' }
86
+ : value, contentUnion);
87
+ /** Booleans for checks; strings for measurements/text (decimals stay strings, K-14). */
88
+ const responseValue = z.union([z.boolean(), z.string()]);
89
+ /**
90
+ * Who signed. Two kinds, and the difference is the whole point of milestone D:
91
+ *
92
+ * - `principal` — an authenticated principal in this scope. `ref` is their
93
+ * `PrincipalId`. Every in-app signature.
94
+ * - `external` — a human with no account, identified by an external provider
95
+ * (BankID via Scrive). `ref` is an OPAQUE `DataSubjectId` the vertical minted
96
+ * for that person.
97
+ *
98
+ * A personnummer, an email or a name must NEVER land in `ref`. It is `direct`
99
+ * PII, and `subjectId` on the emitted event is what crypto-shredding keys the
100
+ * erasure on (§5.3) — a `DataSubjectId` is shreddable, a personnummer written
101
+ * into a signature row is a GDPR liability that immutability makes permanent.
102
+ * The provider's own party identifier belongs in `evidenceRef`, which is where
103
+ * the sealed PDF and the provider audit log are reachable from.
104
+ *
105
+ * This follows `engines/booking`'s `partyRef`: a participant is a person with
106
+ * no principal, and it names them with a `DataSubjectId` for exactly this
107
+ * reason.
108
+ */
109
+ export const signatory = z.discriminatedUnion('kind', [
110
+ z.object({
111
+ kind: z.literal('principal'),
112
+ ref: principalId,
113
+ label: z.string().min(1).optional(),
114
+ }),
115
+ z.object({
116
+ kind: z.literal('external'),
117
+ ref: dataSubjectId,
118
+ label: z.string().min(1).optional(),
119
+ }),
120
+ ]);
121
+ export const defineTemplateInput = z.object({
122
+ key: z.string().min(1),
123
+ title: z.string().min(1),
124
+ content: protocolTemplateContent,
125
+ });
126
+ export const instantiateProtocolInput = z.object({
127
+ templateKey: z.string().min(1),
128
+ entity: entityRef,
129
+ });
130
+ export const fillProtocolInput = z.object({
131
+ instanceId: z.string().min(1),
132
+ itemKey: z.string().min(1),
133
+ value: responseValue,
134
+ note: z.string().optional(),
135
+ });
136
+ export const bindDocumentInput = z.object({
137
+ instanceId: z.string().min(1),
138
+ /** The vertical entity that holds the real content — an avtal, a report. */
139
+ contentRef: entityRef,
140
+ /** The hash the VERTICAL computed over its own rows, per `hashRecipe`. */
141
+ contentHash: z.string().regex(/^[0-9a-f]{64}$/, 'contentHash must be lowercase hex SHA-256'),
142
+ /**
143
+ * The RENDERED document — an attachment on this instance holding the bytes a
144
+ * signatory will be shown (#711). Optional, and absence is a complete answer:
145
+ * a vertical that renders nothing keeps the behaviour it had, and a signing
146
+ * connector falls back to its own attestation sheet.
147
+ *
148
+ * Naming an id rather than searching for one is deliberate. A connector that
149
+ * had to PICK among an instance's attachments would need a rule, and the
150
+ * return path lands the sealed signed copy on this same instance — so a wrong
151
+ * rule mails a counterparty their own signed contract to sign again. The
152
+ * caller says which bytes; nothing downstream has to guess.
153
+ */
154
+ documentAttachmentId: z.string().min(1).nullable().optional(),
155
+ });
156
+ /**
157
+ * How a signing party is REACHED (#687) — a delivery address, and nothing else.
158
+ *
159
+ * Typed rather than an opaque blob the engine never interprets, and the reason is
160
+ * the `authLevel` argument from #620 one level down: a provider-agnostic engine
161
+ * that cannot say what "how to reach a party" means is an engine every vertical
162
+ * has to guess around, and every connector has to re-derive. The type is small,
163
+ * provider-agnostic, and — with no personal number in it — free of anything a
164
+ * provider-specific vocabulary would be needed for.
165
+ *
166
+ * **No `personalNumber`, deliberately, and not merely as an omission.** An
167
+ * optional PII field on an engine surface is a carrier that exists, and this one
168
+ * is not needed by any path in the tree: a signatory enters their personnummer
169
+ * into the BankID ceremony itself, and it comes back in the completion data.
170
+ * Adding it would recreate exactly the problem this carrier was built to avoid.
171
+ */
172
+ export const partyContact = z
173
+ .object({
174
+ email: z.string().email().optional(),
175
+ /** E.164 preferred; the provider decides what it accepts. */
176
+ mobile: z.string().min(1).optional(),
177
+ })
178
+ .refine((c) => c.email !== undefined || c.mobile !== undefined, {
179
+ message: 'a party contact must carry an email or a mobile — an empty contact reaches nobody',
180
+ });
181
+ export const signatureRequestParty = z.object({
182
+ /** Display name for the role, never PII: 'Beställare', 'Leverantör'. */
183
+ label: z.string().min(1),
184
+ kind: z.enum(['principal', 'external']),
185
+ /**
186
+ * Who is expected to sign, when that is known up front. A `PrincipalId` for
187
+ * `principal`, an opaque `DataSubjectId` for `external`.
188
+ *
189
+ * Optional because it often is NOT known: a BankID flow addressed to a
190
+ * company mailbox is signed by whichever firmatecknare opens it, and their
191
+ * identity only becomes known when the provider reports it. Left unset, the
192
+ * signatory is whoever `recordSignature` reports; set, it is a constraint
193
+ * the recorded signatory must match.
194
+ */
195
+ ref: z.string().min(1).optional(),
196
+ /**
197
+ * 'primary' for the issuing party, 'counter' for accepting parties.
198
+ *
199
+ * Optional, and resolved so that a request set ALWAYS has exactly one
200
+ * primary: declare one explicitly, or the first party becomes it. A set with
201
+ * no primary would leave a signed instance whose issuing signature is null —
202
+ * `requireCountersigned` would then pass on a document nobody issued.
203
+ */
204
+ signatureKind: z.enum(['primary', 'counter']).optional(),
205
+ /**
206
+ * How hard the provider must work to prove WHO signed (#620).
207
+ *
208
+ * - `basic` — the provider establishes control of a contact address (a signing
209
+ * link to an email or mobile). The default, and what a request that says
210
+ * nothing gets.
211
+ * - `strong` — a national eID: BankID, and its equivalents. The signatory
212
+ * proves a legal identity, not the possession of a mailbox.
213
+ *
214
+ * Deliberately NOT the provider's own vocabulary. `se_bankid` is Scrive's word
215
+ * for this and belongs in the connector that speaks to Scrive; an engine that
216
+ * learned it would have to learn the next provider's too, and a vertical would
217
+ * be choosing a Scrive enum through a provider-agnostic engine. The connector
218
+ * maps this pair onto whatever its provider calls them (star topology).
219
+ *
220
+ * **`strong` needs a delivery address, never a personal number** (#687, #688).
221
+ * The earlier reading of this field — that a national eID flow must carry the
222
+ * signatory's personnummer, and is therefore unsatisfiable — was measured and
223
+ * is false: what a provider validates is that a BankID party HAS a personal
224
+ * number field, not that it holds a value, and BankID has not accepted one
225
+ * from the relying party since API v6. So there is no `personalNumber` on this
226
+ * shape, and its absence is a decision rather than an omission: an optional
227
+ * PII field on an engine surface is a carrier that exists. If some future
228
+ * provider genuinely needs one, that is a provider-specific refusal at egress
229
+ * in that connector, with its own carrier argument.
230
+ *
231
+ * What both levels need is `contact` below, and neither can do without it.
232
+ */
233
+ authLevel: z.enum(['basic', 'strong']).optional(),
234
+ /**
235
+ * How this party is REACHED (#687) — the thing whose absence made every
236
+ * external signature this platform ever sent fail at the provider.
237
+ *
238
+ * Required for any party that will be INVITED, which is every party except the
239
+ * one issuing the document (see `signatureKind`): the issuer is the author at
240
+ * the provider, reached through the platform's own account, and an author is
241
+ * never invited. `requestSignatures` refuses a set that would send a document
242
+ * to somebody it cannot reach, rather than letting the provider answer
243
+ * `invalid_invitation_delivery_info` a layer later where the caller cannot see
244
+ * it.
245
+ *
246
+ * **This is `direct` PII and the engine never stores it in the clear.** It is
247
+ * sealed to the receiving connector's public key inside the operation, before
248
+ * anything is emitted, and only the envelope reaches the row and the event
249
+ * (design/signature-contact-carrier.md). A vertical passes a plain address in;
250
+ * from the operation's return onward nothing in the platform can read it back.
251
+ */
252
+ contact: partyContact.optional(),
253
+ });
254
+ export const requestSignaturesInput = z.object({
255
+ instanceId: z.string().min(1),
256
+ /** 'scrive', 'bankid' — the provider a connector will dispatch to. */
257
+ method: z.string().min(1),
258
+ parties: z.array(signatureRequestParty).min(1),
259
+ });
260
+ export const recordSignatureInput = z.object({
261
+ requestId: z.string().min(1),
262
+ signatory,
263
+ /** When the party actually signed, per the provider — NOT when we heard. */
264
+ signedAt: instant,
265
+ /**
266
+ * The hash the provider signed over, as the provider reports it. Checked
267
+ * against the frozen hash: a mismatch means the document that was signed is
268
+ * not the document we froze, and that must fail closed rather than record a
269
+ * signature over unknown content.
270
+ */
271
+ contentHash: z.string().regex(/^[0-9a-f]{64}$/),
272
+ /** Sealed PDF, provider transaction id, audit log — where the proof lives. */
273
+ evidenceRef: z.string().min(1).optional(),
274
+ });
275
+ export const declineSignatureInput = z.object({
276
+ requestId: z.string().min(1),
277
+ reason: z.string().min(1),
278
+ /** 'declined' when a party refused; 'expired' when the provider timed out. */
279
+ outcome: z.enum(['declined', 'expired']).default('declined'),
280
+ });
281
+ export const cancelSignatureRequestsInput = z.object({
282
+ instanceId: z.string().min(1),
283
+ reason: z.string().min(1),
284
+ });
285
+ //# sourceMappingURL=inputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.js","sourceRoot":"","sources":["../src/inputs.ts"],"names":[],"mappings":"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"}