@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.
- package/LICENSE +661 -0
- package/README.md +98 -0
- package/dist/api.d.ts +134 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +203 -0
- package/dist/api.js.map +1 -0
- package/dist/index.d.ts +223 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +353 -0
- package/dist/index.js.map +1 -0
- package/dist/mock.d.ts +60 -0
- package/dist/mock.d.ts.map +1 -0
- package/dist/mock.js +131 -0
- package/dist/mock.js.map +1 -0
- package/dist/pdf.d.ts +27 -0
- package/dist/pdf.d.ts.map +1 -0
- package/dist/pdf.js +87 -0
- package/dist/pdf.js.map +1 -0
- package/package.json +37 -0
|
@@ -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
|
package/dist/mock.js.map
ADDED
|
@@ -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
|
package/dist/pdf.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf.js","sourceRoot":"","sources":["../src/pdf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,GAA2B;IAC1C,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;IACrD,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;IACrD,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;IACrD,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;IACrD,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;IACrD,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;CACrB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,CAAC,GAAG,IAAI,CAAC;SACb,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;QACV,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI;YAAE,OAAO,KAAK,EAAE,EAAE,CAAC;QAC9D,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAClF,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,2CAA2C,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;gBAC9D,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,4BAA4B,CACnF,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3F,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AASD,kEAAkE;AAClE,MAAM,UAAU,SAAS,CAAC,IAAa;IACrC,MAAM,OAAO,GACX,2BAA2B,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW;QAC/D,IAAI,CAAC,KAAK;aACP,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,mBAAmB,GAAG,GAAG,CAAC,GAAG,EAAE,QAAQ,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;aAC/E,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhB,MAAM,OAAO,GAAG;QACd,mCAAmC;QACnC,2CAA2C;QAC3C,uDAAuD;YACrD,2DAA2D;QAC7D,mFAAmF;QACnF,cAAc,OAAO,CAAC,MAAM,gBAAgB,OAAO,aAAa;KACjE,CAAC;IAEF,IAAI,GAAG,GAAG,YAAY,CAAC;IACvB,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QAC1B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzB,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,YAAY,CAAC;IAC7C,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC1B,GAAG,IAAI,WAAW,OAAO,CAAC,MAAM,GAAG,CAAC,yBAAyB,CAAC;IAC9D,KAAK,MAAM,GAAG,IAAI,OAAO;QAAE,GAAG,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,aAAa,CAAC;IAChF,GAAG,IAAI,qBAAqB,OAAO,CAAC,MAAM,GAAG,CAAC,+BAA+B,MAAM,WAAW,CAAC;IAC/F,6EAA6E;IAC7E,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;QAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC5E,KAAK,WAAW,CAAC;IACjB,OAAO,KAAK,CAAC;AACf,CAAC"}
|
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
|
+
}
|