@substrat-run/connector-scrive 0.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IACpF,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7C,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAChF;AAED,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,UAAU;IACrB,QAAQ,CAAC,SAAS,4BAAmC;IACrD,OAAO,CAAC,GAAG,CAAK;IAChB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEjB,OAAO,GAAE,iBAAsB;IAI3C,4FAA4F;IAC5F,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAU9D,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIjC,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,IAAI;IAaZ,kCAAkC;IAClC,IAAI,KAAK,IAAI,SAAS,CAiGrB;CACF"}
package/dist/mock.js ADDED
@@ -0,0 +1,131 @@
1
+ export class ScriveMock {
2
+ documents = new Map();
3
+ seq = 0;
4
+ failWith;
5
+ constructor(options = {}) {
6
+ this.failWith = options.failWith;
7
+ }
8
+ /** Simulate a party completing BankID. The provider-side event we cannot cause for real. */
9
+ sign(documentId, partyIndex, at) {
10
+ const doc = this.mustGet(documentId);
11
+ const party = doc.parties[partyIndex];
12
+ if (!party)
13
+ throw new Error(`mock: no party ${partyIndex} on ${documentId}`);
14
+ party.signTime = at;
15
+ // Scrive closes a document only when EVERY party has signed — the same rule
16
+ // engine-protocol applies to its own request set, arrived at independently.
17
+ if (doc.parties.every((p) => p.signTime))
18
+ doc.status = 'closed';
19
+ }
20
+ decline(documentId) {
21
+ this.mustGet(documentId).status = 'rejected';
22
+ }
23
+ mustGet(id) {
24
+ const doc = this.documents.get(id);
25
+ if (!doc)
26
+ throw new Error(`mock: unknown document ${id}`);
27
+ return doc;
28
+ }
29
+ wire(doc) {
30
+ return {
31
+ id: doc.id,
32
+ status: doc.status,
33
+ title: doc.title,
34
+ parties: doc.parties.map((p) => ({
35
+ id: p.id,
36
+ sign_time: p.signTime,
37
+ fields: [{ type: 'name', value: p.name }],
38
+ })),
39
+ };
40
+ }
41
+ /** The `fetch` to hand a host. */
42
+ get fetch() {
43
+ return (url, init) => {
44
+ const respond = (status, body) => Promise.resolve({
45
+ ok: status >= 200 && status < 300,
46
+ status,
47
+ text: () => Promise.resolve(JSON.stringify(body)),
48
+ json: () => Promise.resolve(body),
49
+ });
50
+ if (this.failWith)
51
+ return respond(this.failWith, { error_message: 'mock failure' });
52
+ // OAuth1 PLAINTEXT, matching the real testbed: the connector sends an
53
+ // `authorization` header starting `oauth_signature_method="PLAINTEXT"`.
54
+ // A `Bearer` header (the old, wrong scheme) must NOT authenticate here, or
55
+ // the mock would keep passing a shape the real API rejects.
56
+ const auth = init?.headers?.authorization ?? init?.headers?.Authorization ?? '';
57
+ if (!auth.includes('oauth_signature_method="PLAINTEXT"')) {
58
+ return respond(401, { error_message: 'No valid access credentials were provided.' });
59
+ }
60
+ const path = new URL(url).pathname;
61
+ if (path === '/api/v2/documents/new') {
62
+ this.seq += 1;
63
+ const doc = {
64
+ id: `doc-${this.seq}`,
65
+ status: 'preparation',
66
+ title: '',
67
+ callbackUrl: null,
68
+ file: null,
69
+ parties: [],
70
+ };
71
+ this.documents.set(doc.id, doc);
72
+ return respond(200, this.wire(doc));
73
+ }
74
+ const m = /^\/api\/v2\/documents\/([^/]+)\/(setfile|update|start|get)$/.exec(path);
75
+ if (!m)
76
+ return respond(404, { error: `mock: no route for ${path}` });
77
+ const [, id, action] = m;
78
+ const doc = this.documents.get(id);
79
+ if (!doc)
80
+ return respond(404, { error: `mock: unknown document ${id}` });
81
+ if (action === 'setfile') {
82
+ // The real body is multipart/form-data bytes (a Uint8Array), not a
83
+ // string — the length is all the mock needs to know a file arrived.
84
+ const size = typeof init?.body === 'string' ? init.body.length : (init?.body?.length ?? 0);
85
+ doc.file = { name: 'document.pdf', bytes: size };
86
+ return respond(200, this.wire(doc));
87
+ }
88
+ if (action === 'update') {
89
+ // The real API takes `document=<url-encoded JSON>` as a form field, not a
90
+ // JSON request body — the mock parses it the same way so the connector's
91
+ // encoding is under test.
92
+ const raw = typeof init?.body === 'string' ? init.body : '';
93
+ const encoded = /(?:^|&)document=([^&]*)/.exec(raw)?.[1] ?? '';
94
+ const patch = JSON.parse(decodeURIComponent(encoded) || '{}');
95
+ if (patch.title)
96
+ doc.title = patch.title;
97
+ if (patch.api_callback_url)
98
+ doc.callbackUrl = patch.api_callback_url;
99
+ if (patch.parties) {
100
+ const authors = patch.parties.filter((p) => p.is_author).length;
101
+ if (authors !== 1) {
102
+ // Scrive requires exactly one author across the party set. The mock
103
+ // enforces it so a regression in the connector's party mapping fails
104
+ // here rather than silently against the real API.
105
+ return respond(400, { error_message: `exactly one author required, got ${authors}` });
106
+ }
107
+ doc.parties = patch.parties.map((p, i) => ({
108
+ id: `party-${i}`,
109
+ name: String(p.fields.find((f) => f.type === 'name')?.value ?? ''),
110
+ signTime: null,
111
+ auth: p.authentication_method_to_sign,
112
+ }));
113
+ }
114
+ return respond(200, this.wire(doc));
115
+ }
116
+ if (action === 'start') {
117
+ if (!doc.file) {
118
+ // The constraint that forced the whole PDF question: Scrive signs a
119
+ // file, and refuses to start without one.
120
+ return respond(409, { error: 'mock: cannot start a document with no file' });
121
+ }
122
+ if (doc.parties.length === 0)
123
+ return respond(409, { error: 'mock: no parties' });
124
+ doc.status = 'pending';
125
+ return respond(200, this.wire(doc));
126
+ }
127
+ return respond(200, this.wire(doc));
128
+ };
129
+ }
130
+ }
131
+ //# sourceMappingURL=mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.js","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"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"}
package/dist/pdf.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A minimal, dependency-free PDF writer.
3
+ *
4
+ * PDF is a text format, and Helvetica is one of the base-14 fonts every reader
5
+ * ships, so a single page of text needs no library and no font embedding. Web
6
+ * standards only — this runs unchanged in Node, Workers and a browser.
7
+ *
8
+ * ## What this is NOT
9
+ *
10
+ * It is not the documents engine (master plan §6), and it is deliberately not
11
+ * where an *avtal* gets laid out. Rendering a contract belongs to the vertical
12
+ * that owns its content — a connector cannot read another module's tables, and
13
+ * should not learn a vertical's vocabulary to try.
14
+ *
15
+ * What this renders is an **attestation sheet**: what is being signed, by whom,
16
+ * and the hash it is identified by. That is honest for a hash-attestation model
17
+ * and enough to exercise the seam end to end. A real contract needs the
18
+ * vertical's own rendering plus somewhere to put the bytes, and neither exists
19
+ * yet (see the connector's README).
20
+ */
21
+ export interface PdfPage {
22
+ title: string;
23
+ lines: string[];
24
+ }
25
+ /** A one-page A4 document. Returns the bytes, ready to upload. */
26
+ export declare function renderPdf(page: PdfPage): Uint8Array;
27
+ //# sourceMappingURL=pdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../src/pdf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAyCH,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CA+BnD"}
package/dist/pdf.js ADDED
@@ -0,0 +1,87 @@
1
+ /**
2
+ * A minimal, dependency-free PDF writer.
3
+ *
4
+ * PDF is a text format, and Helvetica is one of the base-14 fonts every reader
5
+ * ships, so a single page of text needs no library and no font embedding. Web
6
+ * standards only — this runs unchanged in Node, Workers and a browser.
7
+ *
8
+ * ## What this is NOT
9
+ *
10
+ * It is not the documents engine (master plan §6), and it is deliberately not
11
+ * where an *avtal* gets laid out. Rendering a contract belongs to the vertical
12
+ * that owns its content — a connector cannot read another module's tables, and
13
+ * should not learn a vertical's vocabulary to try.
14
+ *
15
+ * What this renders is an **attestation sheet**: what is being signed, by whom,
16
+ * and the hash it is identified by. That is honest for a hash-attestation model
17
+ * and enough to exercise the seam end to end. A real contract needs the
18
+ * vertical's own rendering plus somewhere to put the bytes, and neither exists
19
+ * yet (see the connector's README).
20
+ */
21
+ const CP1252_HIGH = {
22
+ '€': 0x80, '‚': 0x82, 'ƒ': 0x83, '„': 0x84, '…': 0x85,
23
+ '†': 0x86, '‡': 0x87, 'ˆ': 0x88, '‰': 0x89, 'Š': 0x8a,
24
+ '‹': 0x8b, 'Œ': 0x8c, 'Ž': 0x8e, '‘': 0x91, '’': 0x92,
25
+ '“': 0x93, '”': 0x94, '•': 0x95, '–': 0x96, '—': 0x97,
26
+ '˜': 0x98, '™': 0x99, 'š': 0x9a, '›': 0x9b, 'œ': 0x9c,
27
+ 'ž': 0x9e, 'Ÿ': 0x9f,
28
+ };
29
+ /**
30
+ * Encode one string to WinAnsi, or throw.
31
+ *
32
+ * **Never approximate.** PDF text is WinAnsi (CP1252), which differs from
33
+ * Latin-1 exactly in `0x80`–`0x9F` — exactly where typographic punctuation
34
+ * lives. An unmapped character therefore does not fail, it SILENTLY
35
+ * SUBSTITUTES: the first draft of this renderer produced a document whose
36
+ * em-dash read as `€24`, which `file(1)` accepted and a parser read cleanly.
37
+ * On a document someone signs, that is the worst available failure mode, and it
38
+ * is invisible to every check short of looking at the rendered page.
39
+ */
40
+ function encodeWinAnsi(text) {
41
+ return [...text]
42
+ .map((ch) => {
43
+ if (ch === '(' || ch === ')' || ch === '\\')
44
+ return `\\${ch}`;
45
+ const cp = ch.codePointAt(0);
46
+ const code = cp <= 0x7e ? cp : (CP1252_HIGH[ch] ?? (cp <= 0xff ? cp : undefined));
47
+ if (code === undefined) {
48
+ throw new Error(`character not representable in WinAnsi: ${JSON.stringify(ch)} ` +
49
+ `(U+${cp.toString(16).toUpperCase().padStart(4, '0')}) — refusing to substitute`);
50
+ }
51
+ return code > 126 ? `\\${code.toString(8).padStart(3, '0')}` : String.fromCharCode(code);
52
+ })
53
+ .join('');
54
+ }
55
+ /** A one-page A4 document. Returns the bytes, ready to upload. */
56
+ export function renderPdf(page) {
57
+ const content = `BT /F1 16 Tf 56 780 Td (${encodeWinAnsi(page.title)}) Tj ET\n` +
58
+ page.lines
59
+ .map((l, i) => `BT /F1 11 Tf 56 ${748 - i * 18} Td (${encodeWinAnsi(l)}) Tj ET`)
60
+ .join('\n');
61
+ const objects = [
62
+ '<< /Type /Catalog /Pages 2 0 R >>',
63
+ '<< /Type /Pages /Kids [3 0 R] /Count 1 >>',
64
+ '<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] ' +
65
+ '/Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >>',
66
+ '<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>',
67
+ `<< /Length ${content.length} >>\nstream\n${content}\nendstream`,
68
+ ];
69
+ let pdf = '%PDF-1.4\n';
70
+ const offsets = [];
71
+ objects.forEach((body, i) => {
72
+ offsets.push(pdf.length);
73
+ pdf += `${i + 1} 0 obj\n${body}\nendobj\n`;
74
+ });
75
+ const xrefAt = pdf.length;
76
+ pdf += `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n`;
77
+ for (const off of offsets)
78
+ pdf += `${String(off).padStart(10, '0')} 00000 n \n`;
79
+ pdf += `trailer\n<< /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xrefAt}\n%%EOF\n`;
80
+ // Latin-1 out: every byte in `pdf` is already <= 0xFF by construction above.
81
+ const bytes = new Uint8Array(pdf.length);
82
+ for (let i = 0; i < pdf.length; i += 1)
83
+ bytes[i] = pdf.charCodeAt(i) & 0xff;
84
+ void TextEncoder;
85
+ return bytes;
86
+ }
87
+ //# sourceMappingURL=pdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.js","sourceRoot":"","sources":["../src/pdf.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@substrat-run/connector-scrive",
3
+ "version": "0.0.2",
4
+ "description": "Substrat connector: Scrive eSign (Swedish BankID). Turns a protocol.signatures-requested event into a Scrive signing flow (create → set file → parties → start) and records the completed signature back into the scope through the #97 authority seam. Host code — registered on a ScopeHost, never module code.",
5
+ "license": "AGPL-3.0-only",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "type": "module",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "zod": "^4.4.3",
23
+ "@substrat-run/contracts": "^0.11.0",
24
+ "@substrat-run/kernel": "^0.11.0"
25
+ },
26
+ "devDependencies": {
27
+ "typescript": "^5.6.0",
28
+ "vitest": "^3.0.0",
29
+ "@substrat-run/engine-protocol": "^0.4.2",
30
+ "@substrat-run/adapter-sqlite": "^0.11.0"
31
+ },
32
+ "scripts": {
33
+ "build": "tsc -p tsconfig.json",
34
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
35
+ "test": "vitest run"
36
+ }
37
+ }