@sealkeeper/schema 0.5.0 → 0.5.1
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/dist/agent-name.js +5 -1
- package/dist/api.d.ts +143 -2
- package/dist/api.js +103 -23
- package/dist/conformance.d.ts +0 -1
- package/dist/conformance.js +3 -4
- package/dist/credential.d.ts +1 -0
- package/dist/credential.js +8 -3
- package/dist/duel-next.js +4 -1
- package/dist/envelope.d.ts +41 -1
- package/dist/envelope.js +71 -4
- package/dist/game.js +15 -11
- package/dist/handshake-conformance.d.ts +1 -0
- package/dist/handshake-conformance.js +41 -0
- package/dist/handshake.d.ts +15 -2
- package/dist/handshake.js +63 -14
- package/dist/policy.d.ts +1 -1
- package/dist/policy.js +1 -1
- package/dist/seal-conformance.d.ts +1 -0
- package/dist/seal-conformance.js +23 -1
- package/dist/seal-verify.d.ts +1 -1
- package/dist/seal-verify.js +7 -1
- package/dist/standing.js +7 -6
- package/dist/task-templates.d.ts +2 -22
- package/dist/task-templates.js +94 -469
- package/package.json +1 -1
- package/dist/template-conformance.d.ts +0 -10
- package/dist/template-conformance.js +0 -298
package/dist/handshake.d.ts
CHANGED
|
@@ -5,12 +5,15 @@ export declare const HANDSHAKE_MAX_AGE_SECONDS: number;
|
|
|
5
5
|
export declare function handshakeWindowProblem(iat: number, hasNonce: boolean, nowSeconds: number): 'stale' | null;
|
|
6
6
|
export declare const HANDSHAKE_NONCE_MAX = 64;
|
|
7
7
|
export declare const HandshakeNonce: z.ZodString;
|
|
8
|
+
export declare const HANDSHAKE_AUD_MAX = 64;
|
|
9
|
+
export declare const HandshakeAudience: z.ZodString;
|
|
8
10
|
export declare const HANDSHAKE_MAX_CHARS = 2048;
|
|
9
11
|
export declare const HandshakePayload: z.ZodObject<{
|
|
10
12
|
sub: z.ZodString;
|
|
11
13
|
fingerprint: z.ZodString;
|
|
12
14
|
at: z.ZodInt;
|
|
13
15
|
nonce: z.ZodOptional<z.ZodString>;
|
|
16
|
+
aud: z.ZodOptional<z.ZodString>;
|
|
14
17
|
iat: z.ZodInt;
|
|
15
18
|
}, z.core.$strict>;
|
|
16
19
|
export type HandshakePayload = z.infer<typeof HandshakePayload>;
|
|
@@ -20,6 +23,7 @@ export declare const HandshakeRefusal: z.ZodEnum<{
|
|
|
20
23
|
nonce_mismatch: "nonce_mismatch";
|
|
21
24
|
stale: "stale";
|
|
22
25
|
wrong_agent: "wrong_agent";
|
|
26
|
+
wrong_verifier: "wrong_verifier";
|
|
23
27
|
}>;
|
|
24
28
|
export type HandshakeRefusal = z.infer<typeof HandshakeRefusal>;
|
|
25
29
|
export declare const HandshakeResult: z.ZodEnum<{
|
|
@@ -33,6 +37,13 @@ export declare const HandshakeAgainst: z.ZodEnum<{
|
|
|
33
37
|
seal: "seal";
|
|
34
38
|
}>;
|
|
35
39
|
export type HandshakeAgainst = z.infer<typeof HandshakeAgainst>;
|
|
40
|
+
export declare const HandshakeProof: z.ZodEnum<{
|
|
41
|
+
nonce: "nonce";
|
|
42
|
+
none: "none";
|
|
43
|
+
verifier: "verifier";
|
|
44
|
+
}>;
|
|
45
|
+
export type HandshakeProof = z.infer<typeof HandshakeProof>;
|
|
46
|
+
export declare const handshakeProof: (nonce: string | undefined, aud: string | undefined) => HandshakeProof;
|
|
36
47
|
export declare const HANDSHAKE_RECORD_NOTE = "compared with the issuer's current record, the SEAL carries no fingerprint until version 3";
|
|
37
48
|
export type HandshakeVerification = {
|
|
38
49
|
ok: true;
|
|
@@ -45,12 +56,13 @@ export type HandshakeFingerprint = {
|
|
|
45
56
|
hash: string;
|
|
46
57
|
captured_at: number;
|
|
47
58
|
};
|
|
48
|
-
export declare function signHandshake(privateKey: Uint8Array, agentId: string, fingerprint: HandshakeFingerprint, nowSeconds: number, nonce?: string): Promise<string>;
|
|
49
|
-
export declare function verifyHandshake(compact: string, sub: string, nowSeconds: number, nonce?: string): Promise<HandshakeVerification>;
|
|
59
|
+
export declare function signHandshake(privateKey: Uint8Array, agentId: string, fingerprint: HandshakeFingerprint, nowSeconds: number, nonce?: string, aud?: string): Promise<string>;
|
|
60
|
+
export declare function verifyHandshake(compact: string, sub: string, nowSeconds: number, nonce?: string, aud?: string): Promise<HandshakeVerification>;
|
|
50
61
|
export type HandshakeCheck = {
|
|
51
62
|
ok: true;
|
|
52
63
|
result: HandshakeResult;
|
|
53
64
|
against: HandshakeAgainst;
|
|
65
|
+
proof: HandshakeProof;
|
|
54
66
|
payload: HandshakePayload;
|
|
55
67
|
} | {
|
|
56
68
|
ok: false;
|
|
@@ -61,6 +73,7 @@ export type HandshakeCheckOptions = {
|
|
|
61
73
|
seal: SealPayload;
|
|
62
74
|
nowSeconds: number;
|
|
63
75
|
nonce?: string;
|
|
76
|
+
aud?: string;
|
|
64
77
|
record: (sub: string) => Promise<string | null>;
|
|
65
78
|
};
|
|
66
79
|
export declare function checkHandshake(options: HandshakeCheckOptions): Promise<HandshakeCheck>;
|
package/dist/handshake.js
CHANGED
|
@@ -15,8 +15,19 @@ import { FINGERPRINT_MAX_CAPTURED_AT, Sha256Base64url } from './fingerprint.js';
|
|
|
15
15
|
* anything in the JWS is read. Then the header, whose kid must be the sub,
|
|
16
16
|
* and the payload, whose sub must be the sub too. That iat is inside its window
|
|
17
17
|
* (handshakeWindowProblem). That the nonce is the one the verifier asked
|
|
18
|
-
* for, when it asked for one.
|
|
19
|
-
* never read as
|
|
18
|
+
* for, when it asked for one. That aud is the verifier's own name, when it
|
|
19
|
+
* gave one. A handshake that fails any check is refused, never read as
|
|
20
|
+
* Changed.
|
|
21
|
+
*
|
|
22
|
+
* What a handshake that verified shows (HandshakeProof). Without a nonce it
|
|
23
|
+
* shows nothing about who presents it, since a copy in a card replays for
|
|
24
|
+
* as long as the SEAL beside it lives. With the verifier's nonce it shows
|
|
25
|
+
* the key holder signed after the nonce was made, to whoever holds that
|
|
26
|
+
* nonce, so a presenter could have relayed the nonce to the real agent and
|
|
27
|
+
* its answer back. With the nonce and the verifier's own name in aud it
|
|
28
|
+
* shows the key holder answered this verifier, so a handshake relayed from
|
|
29
|
+
* one made for another verifier is refused. A handshake without aud keeps
|
|
30
|
+
* verifying for a verifier that names none.
|
|
20
31
|
*
|
|
21
32
|
* checkHandshake then compares the signed fingerprint hash with the one the
|
|
22
33
|
* SEAL carries, version 3 on. A SEAL before version 3 carries none, so the
|
|
@@ -55,18 +66,30 @@ export const HANDSHAKE_NONCE_MAX = 64;
|
|
|
55
66
|
export const HandshakeNonce = z
|
|
56
67
|
.string()
|
|
57
68
|
.regex(/^[\x20-\x7e]{1,64}$/, 'A nonce is 1 to 64 printable ASCII characters');
|
|
69
|
+
// The verifier a handshake is made for, its aud, is a name the verifier
|
|
70
|
+
// picks and hands the agent with its nonce, such as its URL or its own
|
|
71
|
+
// agent id. The same rule as a nonce, 1 to 64 printable ASCII characters.
|
|
72
|
+
export const HANDSHAKE_AUD_MAX = 64;
|
|
73
|
+
export const HandshakeAudience = z
|
|
74
|
+
.string()
|
|
75
|
+
.regex(/^[\x20-\x7e]{1,64}$/, 'A verifier name is 1 to 64 printable ASCII characters');
|
|
58
76
|
// A handshake is a few hundred characters. Anything longer is not one.
|
|
59
77
|
export const HANDSHAKE_MAX_CHARS = 2048;
|
|
60
78
|
const Seconds = z.int().min(0).max(FINGERPRINT_MAX_CAPTURED_AT);
|
|
61
79
|
// sub is the agent id and the key that signed. fingerprint is the agent's
|
|
62
80
|
// fingerprint hash (fingerprintHash) and at when the CLI captured it, Unix
|
|
63
|
-
// seconds, never after iat.
|
|
81
|
+
// seconds, never after iat. aud is the verifier the handshake is made for,
|
|
82
|
+
// when the agent was given one. iat is when the agent signed, Unix seconds.
|
|
83
|
+
// A verifier on a schema before aud reads a handshake that carries it as
|
|
84
|
+
// malformed, since the payload is closed, so an agent adds aud only for a
|
|
85
|
+
// verifier that asked for it.
|
|
64
86
|
export const HandshakePayload = z
|
|
65
87
|
.strictObject({
|
|
66
88
|
sub: AgentId,
|
|
67
89
|
fingerprint: Sha256Base64url,
|
|
68
90
|
at: Seconds,
|
|
69
91
|
nonce: HandshakeNonce.optional(),
|
|
92
|
+
aud: HandshakeAudience.optional(),
|
|
70
93
|
iat: Seconds,
|
|
71
94
|
})
|
|
72
95
|
.refine((h) => h.at <= h.iat, 'at must not be after iat');
|
|
@@ -78,7 +101,8 @@ export const HandshakePayload = z
|
|
|
78
101
|
* wrong_agent is a verified handshake whose kid or payload sub is not the
|
|
79
102
|
* SEAL's sub. stale is an iat outside its window, 300 seconds either way with
|
|
80
103
|
* a nonce, up to 24 hours old without. nonce_mismatch is a handshake without the nonce the
|
|
81
|
-
* verifier asked for.
|
|
104
|
+
* verifier asked for. wrong_verifier is a handshake whose aud is not the
|
|
105
|
+
* name the verifier gave, or that carries none when the verifier gave one.
|
|
82
106
|
*/
|
|
83
107
|
export const HandshakeRefusal = z.enum([
|
|
84
108
|
'malformed',
|
|
@@ -86,6 +110,7 @@ export const HandshakeRefusal = z.enum([
|
|
|
86
110
|
'bad_signature',
|
|
87
111
|
'stale',
|
|
88
112
|
'nonce_mismatch',
|
|
113
|
+
'wrong_verifier',
|
|
89
114
|
]);
|
|
90
115
|
// What the comparison found. matches and changed compare the signed hash
|
|
91
116
|
// with the SEAL's or the record's. no_fingerprint is a valid handshake with
|
|
@@ -95,20 +120,34 @@ export const HandshakeResult = z.enum(['matches', 'changed', 'no_fingerprint']);
|
|
|
95
120
|
// What the hash was compared with. seal is the SEAL's own fingerprint,
|
|
96
121
|
// version 3 on. record is the issuer's current record, for a SEAL before.
|
|
97
122
|
export const HandshakeAgainst = z.enum(['seal', 'record']);
|
|
123
|
+
/*
|
|
124
|
+
* What a handshake that verified shows about who presents it, see the top
|
|
125
|
+
* of this file. none, the verifier asked for no nonce, so the handshake
|
|
126
|
+
* does not show the presenter holds the key. nonce, the key holder signed
|
|
127
|
+
* over the verifier's nonce, which shows key possession to whoever holds
|
|
128
|
+
* the nonce and no more. verifier, the nonce and the verifier's own name
|
|
129
|
+
* both, so the key holder answered this verifier.
|
|
130
|
+
*/
|
|
131
|
+
export const HandshakeProof = z.enum(['none', 'nonce', 'verifier']);
|
|
132
|
+
// The proof of a handshake that verified, from what the verifier asked for.
|
|
133
|
+
// verifyHandshake has already refused one that lacks either.
|
|
134
|
+
export const handshakeProof = (nonce, aud) => nonce === undefined ? 'none' : aud === undefined ? 'nonce' : 'verifier';
|
|
98
135
|
// The one line a verifier shows when it compared with the record.
|
|
99
136
|
export const HANDSHAKE_RECORD_NOTE = "compared with the issuer's current record, the SEAL carries no fingerprint until version 3";
|
|
100
137
|
/*
|
|
101
138
|
* Signs a handshake for agentId over its fingerprint, at nowSeconds, with
|
|
102
|
-
* an optional nonce. The only place a
|
|
103
|
-
* EnvelopeError invalid_input when the payload
|
|
104
|
-
* a nonce that is too long or a capture after
|
|
139
|
+
* an optional nonce and an optional verifier name, aud. The only place a
|
|
140
|
+
* handshake is signed. Throws EnvelopeError invalid_input when the payload
|
|
141
|
+
* is not in the shape, such as a nonce that is too long or a capture after
|
|
142
|
+
* now.
|
|
105
143
|
*/
|
|
106
|
-
export async function signHandshake(privateKey, agentId, fingerprint, nowSeconds, nonce) {
|
|
144
|
+
export async function signHandshake(privateKey, agentId, fingerprint, nowSeconds, nonce, aud) {
|
|
107
145
|
const parsed = HandshakePayload.safeParse({
|
|
108
146
|
sub: agentId,
|
|
109
147
|
fingerprint: fingerprint.hash,
|
|
110
148
|
at: fingerprint.captured_at,
|
|
111
149
|
...(nonce === undefined ? {} : { nonce }),
|
|
150
|
+
...(aud === undefined ? {} : { aud }),
|
|
112
151
|
iat: Math.floor(nowSeconds),
|
|
113
152
|
});
|
|
114
153
|
if (!parsed.success) {
|
|
@@ -119,11 +158,12 @@ export async function signHandshake(privateKey, agentId, fingerprint, nowSeconds
|
|
|
119
158
|
/*
|
|
120
159
|
* Verifies a handshake for the agent sub, the SEAL's sub, at nowSeconds.
|
|
121
160
|
* nonce is the one the verifier handed the agent, or undefined when it
|
|
122
|
-
* asked for none, in which case a nonce in the handshake is ignored.
|
|
123
|
-
*
|
|
124
|
-
*
|
|
161
|
+
* asked for none, in which case a nonce in the handshake is ignored. aud is
|
|
162
|
+
* the verifier's own name, or undefined when it gives none, in which case
|
|
163
|
+
* an aud in the handshake is ignored. Surrounding whitespace is dropped
|
|
164
|
+
* first, as a pasted handshake often has it. Verify first, parse second.
|
|
125
165
|
*/
|
|
126
|
-
export async function verifyHandshake(compact, sub, nowSeconds, nonce) {
|
|
166
|
+
export async function verifyHandshake(compact, sub, nowSeconds, nonce, aud) {
|
|
127
167
|
const jws = compact.trim();
|
|
128
168
|
if (jws.length > HANDSHAKE_MAX_CHARS) {
|
|
129
169
|
return { ok: false, reason: 'malformed' };
|
|
@@ -161,6 +201,9 @@ export async function verifyHandshake(compact, sub, nowSeconds, nonce) {
|
|
|
161
201
|
if (nonce !== undefined && payload.nonce !== nonce) {
|
|
162
202
|
return { ok: false, reason: 'nonce_mismatch' };
|
|
163
203
|
}
|
|
204
|
+
if (aud !== undefined && payload.aud !== aud) {
|
|
205
|
+
return { ok: false, reason: 'wrong_verifier' };
|
|
206
|
+
}
|
|
164
207
|
return { ok: true, payload };
|
|
165
208
|
}
|
|
166
209
|
/*
|
|
@@ -171,7 +214,7 @@ export async function verifyHandshake(compact, sub, nowSeconds, nonce) {
|
|
|
171
214
|
*/
|
|
172
215
|
export async function checkHandshake(options) {
|
|
173
216
|
const { seal } = options;
|
|
174
|
-
const v = await verifyHandshake(options.handshake, seal.sub, options.nowSeconds, options.nonce);
|
|
217
|
+
const v = await verifyHandshake(options.handshake, seal.sub, options.nowSeconds, options.nonce, options.aud);
|
|
175
218
|
if (!v.ok)
|
|
176
219
|
return v;
|
|
177
220
|
// Version 3 and 4 carry their own fingerprint.
|
|
@@ -184,5 +227,11 @@ export async function checkHandshake(options) {
|
|
|
184
227
|
: expected === v.payload.fingerprint
|
|
185
228
|
? 'matches'
|
|
186
229
|
: 'changed';
|
|
187
|
-
return {
|
|
230
|
+
return {
|
|
231
|
+
ok: true,
|
|
232
|
+
result,
|
|
233
|
+
against,
|
|
234
|
+
proof: handshakeProof(options.nonce, options.aud),
|
|
235
|
+
payload: v.payload,
|
|
236
|
+
};
|
|
188
237
|
}
|
package/dist/policy.d.ts
CHANGED
package/dist/policy.js
CHANGED
package/dist/seal-conformance.js
CHANGED
|
@@ -99,6 +99,27 @@ export async function sealConformanceCases() {
|
|
|
99
99
|
const altered = `${h}.${base64urlEncode(utf8Encode(JSON.stringify({ ...base, level: 'gold' })))}.${s}`;
|
|
100
100
|
const cases = [
|
|
101
101
|
['a valid SEAL', valid, 'valid'],
|
|
102
|
+
[
|
|
103
|
+
'a valid SEAL for the agent expected',
|
|
104
|
+
valid,
|
|
105
|
+
'valid',
|
|
106
|
+
undefined,
|
|
107
|
+
pair.agentId,
|
|
108
|
+
],
|
|
109
|
+
[
|
|
110
|
+
'a valid SEAL for another agent than expected',
|
|
111
|
+
valid,
|
|
112
|
+
'wrong_agent',
|
|
113
|
+
undefined,
|
|
114
|
+
other.agentId,
|
|
115
|
+
],
|
|
116
|
+
[
|
|
117
|
+
'an expired SEAL for another agent than expected',
|
|
118
|
+
signed({ ...base, iat: NOW - 25 * HOUR, exp: NOW - HOUR }),
|
|
119
|
+
'expired',
|
|
120
|
+
undefined,
|
|
121
|
+
other.agentId,
|
|
122
|
+
],
|
|
102
123
|
[
|
|
103
124
|
'iat ahead of now within the clock skew',
|
|
104
125
|
signed({
|
|
@@ -458,11 +479,12 @@ export async function sealConformanceCases() {
|
|
|
458
479
|
},
|
|
459
480
|
],
|
|
460
481
|
},
|
|
461
|
-
cases: await Promise.all(cases.map(async ([name, jws, expected, nowSeconds]) => ({
|
|
482
|
+
cases: await Promise.all(cases.map(async ([name, jws, expected, nowSeconds, agent]) => ({
|
|
462
483
|
name,
|
|
463
484
|
jws: await jws,
|
|
464
485
|
expected,
|
|
465
486
|
...(nowSeconds === undefined ? {} : { nowSeconds }),
|
|
487
|
+
...(agent === undefined ? {} : { agent }),
|
|
466
488
|
}))),
|
|
467
489
|
};
|
|
468
490
|
}
|
package/dist/seal-verify.d.ts
CHANGED
|
@@ -18,4 +18,4 @@ export type SealProblem = {
|
|
|
18
18
|
payload?: SealPayload;
|
|
19
19
|
};
|
|
20
20
|
export type SealVerification = SealVerified | SealProblem;
|
|
21
|
-
export declare function verifySeal(keys: readonly SealKey[], compact: string, nowSeconds: number): Promise<SealVerification>;
|
|
21
|
+
export declare function verifySeal(keys: readonly SealKey[], compact: string, nowSeconds: number, agent?: string): Promise<SealVerification>;
|
package/dist/seal-verify.js
CHANGED
|
@@ -19,11 +19,14 @@ import { decodeHeader, EnvelopeError, verify } from './envelope.js';
|
|
|
19
19
|
* 5. exp, then iat, as the standard reads "Check exp is in the future and
|
|
20
20
|
* iat is not". An iat more than SEAL_CLOCK_SKEW_SECONDS ahead is
|
|
21
21
|
* not_yet_valid.
|
|
22
|
+
* 6. sub, when the caller names the agent it expected. A valid SEAL for
|
|
23
|
+
* another agent is wrong_agent, so a copied SEAL is refused. Without
|
|
24
|
+
* agent this check is the caller's, as the standard says.
|
|
22
25
|
*
|
|
23
26
|
* nowSeconds is the verifier's clock in Unix seconds, passed in so tests
|
|
24
27
|
* can pin it.
|
|
25
28
|
*/
|
|
26
|
-
export async function verifySeal(keys, compact, nowSeconds) {
|
|
29
|
+
export async function verifySeal(keys, compact, nowSeconds, agent) {
|
|
27
30
|
const jws = compact.trim();
|
|
28
31
|
let kid;
|
|
29
32
|
try {
|
|
@@ -59,5 +62,8 @@ export async function verifySeal(keys, compact, nowSeconds) {
|
|
|
59
62
|
const early = sealIatProblem(payload.iat, nowSeconds);
|
|
60
63
|
if (early)
|
|
61
64
|
return { ok: false, reason: early, kid, signed, payload };
|
|
65
|
+
if (agent !== undefined && payload.sub !== agent) {
|
|
66
|
+
return { ok: false, reason: 'wrong_agent', kid, signed, payload };
|
|
67
|
+
}
|
|
62
68
|
return { ok: true, kid, payload, expiresIn };
|
|
63
69
|
}
|
package/dist/standing.js
CHANGED
|
@@ -218,8 +218,8 @@ export const COUNTED_EVIDENCE = {
|
|
|
218
218
|
export const POSTER_RESPONSE_HOURS = 48;
|
|
219
219
|
export const DAY_MS = 86_400_000;
|
|
220
220
|
// The dormancy ladder of the SEAL standard, section 5, in whole days since
|
|
221
|
-
// the agent was last active, its newest
|
|
222
|
-
//
|
|
221
|
+
// the agent was last active, its newest task work the API recorded
|
|
222
|
+
// (lastTaskWork in the API), never an event (VOU-642). At quietDays the level stays and the
|
|
223
223
|
// agent is quiet, which the agent answers carry (Standing.quiet, isQuiet)
|
|
224
224
|
// and the badge and profile show. At dropOneDays and dropTwoDays the level
|
|
225
225
|
// drops one step each. At noneDays the level is none and the scoring run
|
|
@@ -416,7 +416,8 @@ export const OPERATOR_SILVER_CAP = {
|
|
|
416
416
|
days: 30,
|
|
417
417
|
};
|
|
418
418
|
// Whole days from lastActive to now, never below zero. null when the agent
|
|
419
|
-
// has
|
|
419
|
+
// has no task work, since last active reads task work alone. The one place
|
|
420
|
+
// dormancy is counted.
|
|
420
421
|
export function dormantDays(lastActive, now) {
|
|
421
422
|
if (lastActive === null)
|
|
422
423
|
return null;
|
|
@@ -426,9 +427,9 @@ export function dormantDays(lastActive, now) {
|
|
|
426
427
|
export const isQuiet = (days) => days !== null && days >= DORMANCY.quietDays;
|
|
427
428
|
// What the agent answers carry beside level, read from the standing table
|
|
428
429
|
// for the current version. counts are the raw facts and counted what the
|
|
429
|
-
// level read, both with the posted counts (POST-3) beside the SEAL's.
|
|
430
|
-
//
|
|
431
|
-
//
|
|
430
|
+
// level read, both with the posted counts (POST-3) beside the SEAL's.
|
|
431
|
+
// last_active is the agent's newest task work the API recorded, never an
|
|
432
|
+
// event (VOU-642), null when it has none. dormant_days is whole
|
|
432
433
|
// days since last_active at the time of the answer, null with it. quiet is
|
|
433
434
|
// true when dormant_days is at DORMANCY.quietDays or more.
|
|
434
435
|
export const Standing = z.strictObject({
|
package/dist/task-templates.d.ts
CHANGED
|
@@ -8,29 +8,9 @@ export type TemplateSpec = {
|
|
|
8
8
|
input: string;
|
|
9
9
|
output: string;
|
|
10
10
|
};
|
|
11
|
-
export type TemplateDraftVerification = {
|
|
12
|
-
kind: 'hash';
|
|
13
|
-
} | {
|
|
14
|
-
kind: 'schema';
|
|
15
|
-
jsonSchema: Record<string, unknown>;
|
|
16
|
-
} | {
|
|
17
|
-
kind: 'counterparty';
|
|
18
|
-
};
|
|
19
|
-
export type TemplateDraft = {
|
|
20
|
-
taskType: TaskTemplateId;
|
|
21
|
-
spec: TemplateSpec;
|
|
22
|
-
verification: TemplateDraftVerification;
|
|
23
|
-
};
|
|
24
|
-
export type TemplateDraw = (lo: number, hi: number) => number;
|
|
25
11
|
export declare class TemplateInputError extends Error {
|
|
26
12
|
name: string;
|
|
27
13
|
}
|
|
28
|
-
export type TemplateSolveErrorCode = 'unknown_template' | 'no_server_check' | 'unknown_rule' | 'bad_input';
|
|
29
|
-
export declare class TemplateSolveError extends Error {
|
|
30
|
-
readonly code: TemplateSolveErrorCode;
|
|
31
|
-
name: string;
|
|
32
|
-
constructor(code: TemplateSolveErrorCode, message: string);
|
|
33
|
-
}
|
|
34
14
|
export type TaskTemplate = {
|
|
35
15
|
id: TaskTemplateId;
|
|
36
16
|
kind: TemplateKind;
|
|
@@ -38,11 +18,11 @@ export type TaskTemplate = {
|
|
|
38
18
|
category: TaskCategory;
|
|
39
19
|
size: TaskSize;
|
|
40
20
|
difficulty: TaskDifficulty;
|
|
41
|
-
make(input: string | undefined, draw: TemplateDraw): TemplateDraft;
|
|
42
21
|
};
|
|
43
22
|
export declare const TEMPLATE_MAX_INPUT_CHARS = 8000;
|
|
44
23
|
export declare const SUMMARISE_MIN_INPUT_WORDS = 40;
|
|
24
|
+
export declare const QUESTION_MIN_INPUT_WORDS = 3;
|
|
45
25
|
export declare const TASK_TEMPLATES: readonly TaskTemplate[];
|
|
46
26
|
export declare const CONFIRM_CANDIDATE_ONE_IN = 4;
|
|
47
27
|
export declare function taskTemplateById(id: string): TaskTemplate | undefined;
|
|
48
|
-
export declare function
|
|
28
|
+
export declare function cleanTemplateInput(id: TaskTemplateId, input: string | undefined): string | undefined;
|