@sealkeeper/schema 0.4.6 → 0.4.7
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/README.md +2 -2
- package/dist/api.d.ts +9 -32
- package/dist/api.js +32 -28
- package/dist/credential.d.ts +1 -66
- package/dist/credential.js +25 -63
- package/dist/events.d.ts +1 -0
- package/dist/events.js +13 -1
- package/dist/goal.js +2 -2
- package/dist/hidden.d.ts +1 -0
- package/dist/hidden.js +5 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/moderation.js +1 -4
- package/dist/seal-conformance.js +2 -2
- package/dist/seal-verify.d.ts +21 -0
- package/dist/seal-verify.js +63 -0
- package/dist/standing.js +1 -1
- package/package.json +2 -6
- package/dist/db/agent-milestones.d.ts +0 -75
- package/dist/db/agent-milestones.js +0 -16
- package/dist/db/agent-renames.d.ts +0 -126
- package/dist/db/agent-renames.js +0 -20
- package/dist/db/agents.d.ts +0 -351
- package/dist/db/agents.js +0 -99
- package/dist/db/client.d.ts +0 -2561
- package/dist/db/client.js +0 -61
- package/dist/db/credentials.d.ts +0 -143
- package/dist/db/credentials.js +0 -16
- package/dist/db/deleted-operators.d.ts +0 -75
- package/dist/db/deleted-operators.js +0 -13
- package/dist/db/events.d.ts +0 -160
- package/dist/db/events.js +0 -41
- package/dist/db/feed-items.d.ts +0 -109
- package/dist/db/feed-items.js +0 -21
- package/dist/db/index.d.ts +0 -76
- package/dist/db/index.js +0 -28
- package/dist/db/migrate.d.ts +0 -1
- package/dist/db/migrate.js +0 -34
- package/dist/db/migrator.d.ts +0 -6
- package/dist/db/migrator.js +0 -36
- package/dist/db/operator-identities.d.ts +0 -211
- package/dist/db/operator-identities.js +0 -49
- package/dist/db/operator-level-grants.d.ts +0 -109
- package/dist/db/operator-level-grants.js +0 -30
- package/dist/db/operator-slugs.d.ts +0 -92
- package/dist/db/operator-slugs.js +0 -25
- package/dist/db/operators.d.ts +0 -228
- package/dist/db/operators.js +0 -39
- package/dist/db/quota-counters.d.ts +0 -109
- package/dist/db/quota-counters.js +0 -17
- package/dist/db/ratings.d.ts +0 -160
- package/dist/db/ratings.js +0 -27
- package/dist/db/scores.d.ts +0 -160
- package/dist/db/scores.js +0 -15
- package/dist/db/standing.d.ts +0 -264
- package/dist/db/standing.js +0 -34
- package/dist/db/task-claim-failures.d.ts +0 -143
- package/dist/db/task-claim-failures.js +0 -37
- package/dist/db/task-outcomes.d.ts +0 -145
- package/dist/db/task-outcomes.js +0 -25
- package/dist/db/tasks.d.ts +0 -381
- package/dist/db/tasks.js +0 -106
- package/dist/db/timestamps.d.ts +0 -4
- package/dist/db/timestamps.js +0 -24
- package/dist/db/url.d.ts +0 -12
- package/dist/db/url.js +0 -25
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SealBrokenReason } from './api.js';
|
|
2
|
+
import { type SealPayload } from './credential.js';
|
|
3
|
+
export type SealKey = {
|
|
4
|
+
kid: string;
|
|
5
|
+
x: string;
|
|
6
|
+
};
|
|
7
|
+
export type SealVerified = {
|
|
8
|
+
ok: true;
|
|
9
|
+
kid: string;
|
|
10
|
+
payload: SealPayload;
|
|
11
|
+
expiresIn: number;
|
|
12
|
+
};
|
|
13
|
+
export type SealProblem = {
|
|
14
|
+
ok: false;
|
|
15
|
+
reason: SealBrokenReason;
|
|
16
|
+
kid: string | null;
|
|
17
|
+
signed?: unknown;
|
|
18
|
+
payload?: SealPayload;
|
|
19
|
+
};
|
|
20
|
+
export type SealVerification = SealVerified | SealProblem;
|
|
21
|
+
export declare function verifySeal(keys: readonly SealKey[], compact: string, nowSeconds: number): Promise<SealVerification>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { base64urlDecode } from './base64url.js';
|
|
2
|
+
import { parseSealPayload, sealIatProblem, } from './credential.js';
|
|
3
|
+
import { decodeHeader, EnvelopeError, verify } from './envelope.js';
|
|
4
|
+
/*
|
|
5
|
+
* Verifies a SEAL against the issuer's published keys, the steps of the
|
|
6
|
+
* standard (section 3) in order. The API's POST /v1/seal/verify, the web's
|
|
7
|
+
* verify tool and badge and `sealkeeper seal verify` all call this, and the
|
|
8
|
+
* SEAL conformance cases hold it to the standard's answers.
|
|
9
|
+
*
|
|
10
|
+
* 1. The header, which names the kid. Surrounding whitespace is dropped
|
|
11
|
+
* first, as a pasted SEAL often has it.
|
|
12
|
+
* 2. The key the kid names, among keys.
|
|
13
|
+
* 3. The signature over the exact header.payload bytes, and only then the
|
|
14
|
+
* payload as JSON. A signature that checks out over a payload that is
|
|
15
|
+
* not JSON is malformed, not bad_signature.
|
|
16
|
+
* 4. The issuer, then ver, then the shape for that ver, through
|
|
17
|
+
* parseSealPayload. So a SEAL from another issuer is wrong_issuer
|
|
18
|
+
* whatever its ver or shape.
|
|
19
|
+
* 5. exp, then iat, as the standard reads "Check exp is in the future and
|
|
20
|
+
* iat is not". An iat more than SEAL_CLOCK_SKEW_SECONDS ahead is
|
|
21
|
+
* not_yet_valid.
|
|
22
|
+
*
|
|
23
|
+
* nowSeconds is the verifier's clock in Unix seconds, passed in so tests
|
|
24
|
+
* can pin it.
|
|
25
|
+
*/
|
|
26
|
+
export async function verifySeal(keys, compact, nowSeconds) {
|
|
27
|
+
const jws = compact.trim();
|
|
28
|
+
let kid;
|
|
29
|
+
try {
|
|
30
|
+
kid = decodeHeader(jws).kid;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return { ok: false, reason: 'malformed', kid: null };
|
|
34
|
+
}
|
|
35
|
+
const key = keys.find((k) => k.kid === kid);
|
|
36
|
+
if (!key)
|
|
37
|
+
return { ok: false, reason: 'unknown_kid', kid };
|
|
38
|
+
let signed;
|
|
39
|
+
try {
|
|
40
|
+
signed = (await verify(jws, base64urlDecode(key.x))).payload;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
reason: error instanceof EnvelopeError && error.code === 'bad_signature'
|
|
46
|
+
? 'bad_signature'
|
|
47
|
+
: 'malformed',
|
|
48
|
+
kid,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const parsed = parseSealPayload(signed, nowSeconds);
|
|
52
|
+
if (!parsed.ok)
|
|
53
|
+
return { ok: false, reason: parsed.reason, kid, signed };
|
|
54
|
+
const payload = parsed.payload;
|
|
55
|
+
const expiresIn = Math.floor(payload.exp - nowSeconds);
|
|
56
|
+
if (expiresIn <= 0) {
|
|
57
|
+
return { ok: false, reason: 'expired', kid, signed, payload };
|
|
58
|
+
}
|
|
59
|
+
const early = sealIatProblem(payload.iat, nowSeconds);
|
|
60
|
+
if (early)
|
|
61
|
+
return { ok: false, reason: early, kid, signed, payload };
|
|
62
|
+
return { ok: true, kid, payload, expiresIn };
|
|
63
|
+
}
|
package/dist/standing.js
CHANGED
|
@@ -118,7 +118,7 @@ export const DORMANCY = {
|
|
|
118
118
|
// (SCORING.levels in the API) and the CLI explains them, so they live here.
|
|
119
119
|
// Task counts are counted evidence (CountedCounts), recalibrated on 26
|
|
120
120
|
// September 2026 (VOU-139) from the simulation in
|
|
121
|
-
// apps/api/src/
|
|
121
|
+
// apps/api/src/test/simulation.ts. Seed tasks count in verifiedTasks at
|
|
122
122
|
// every level (VOU-172, 26 September 2026), so an agent that does seed
|
|
123
123
|
// tasks every day reaches silver on them alone. Silver dropped its
|
|
124
124
|
// checked or confirmed, other operator and confirmed task clauses then,
|
package/package.json
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sealkeeper/schema",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Zod schemas, event taxonomy and signing helpers for SealKeeper.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"homepage": "https://sealkeeper.run/seal/standard",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/sealkeeper-dev/sealkeeper.git",
|
|
11
|
-
"directory": "packages/schema"
|
|
12
|
-
},
|
|
13
8
|
"bugs": {
|
|
14
9
|
"url": "https://github.com/sealkeeper-dev/cli/issues"
|
|
15
10
|
},
|
|
@@ -33,6 +28,7 @@
|
|
|
33
28
|
},
|
|
34
29
|
"files": [
|
|
35
30
|
"dist",
|
|
31
|
+
"!dist/db",
|
|
36
32
|
"README.md",
|
|
37
33
|
"LICENSE",
|
|
38
34
|
"NOTICE"
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
export declare const agentMilestones: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
-
name: "agent_milestones";
|
|
3
|
-
schema: undefined;
|
|
4
|
-
columns: {
|
|
5
|
-
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
-
name: "created_at";
|
|
7
|
-
tableName: "agent_milestones";
|
|
8
|
-
dataType: "date";
|
|
9
|
-
columnType: "PgTimestamp";
|
|
10
|
-
data: Date;
|
|
11
|
-
driverParam: string;
|
|
12
|
-
notNull: true;
|
|
13
|
-
hasDefault: true;
|
|
14
|
-
isPrimaryKey: false;
|
|
15
|
-
isAutoincrement: false;
|
|
16
|
-
hasRuntimeDefault: false;
|
|
17
|
-
enumValues: undefined;
|
|
18
|
-
baseColumn: never;
|
|
19
|
-
identity: undefined;
|
|
20
|
-
generated: undefined;
|
|
21
|
-
}, {}, {}>;
|
|
22
|
-
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
23
|
-
name: "updated_at";
|
|
24
|
-
tableName: "agent_milestones";
|
|
25
|
-
dataType: "date";
|
|
26
|
-
columnType: "PgTimestamp";
|
|
27
|
-
data: Date;
|
|
28
|
-
driverParam: string;
|
|
29
|
-
notNull: true;
|
|
30
|
-
hasDefault: true;
|
|
31
|
-
isPrimaryKey: false;
|
|
32
|
-
isAutoincrement: false;
|
|
33
|
-
hasRuntimeDefault: false;
|
|
34
|
-
enumValues: undefined;
|
|
35
|
-
baseColumn: never;
|
|
36
|
-
identity: undefined;
|
|
37
|
-
generated: undefined;
|
|
38
|
-
}, {}, {}>;
|
|
39
|
-
agentId: import("drizzle-orm/pg-core").PgColumn<{
|
|
40
|
-
name: "agent_id";
|
|
41
|
-
tableName: "agent_milestones";
|
|
42
|
-
dataType: "string";
|
|
43
|
-
columnType: "PgText";
|
|
44
|
-
data: string;
|
|
45
|
-
driverParam: string;
|
|
46
|
-
notNull: true;
|
|
47
|
-
hasDefault: false;
|
|
48
|
-
isPrimaryKey: false;
|
|
49
|
-
isAutoincrement: false;
|
|
50
|
-
hasRuntimeDefault: false;
|
|
51
|
-
enumValues: [string, ...string[]];
|
|
52
|
-
baseColumn: never;
|
|
53
|
-
identity: undefined;
|
|
54
|
-
generated: undefined;
|
|
55
|
-
}, {}, {}>;
|
|
56
|
-
milestone: import("drizzle-orm/pg-core").PgColumn<{
|
|
57
|
-
name: "milestone";
|
|
58
|
-
tableName: "agent_milestones";
|
|
59
|
-
dataType: "string";
|
|
60
|
-
columnType: "PgText";
|
|
61
|
-
data: string;
|
|
62
|
-
driverParam: string;
|
|
63
|
-
notNull: true;
|
|
64
|
-
hasDefault: false;
|
|
65
|
-
isPrimaryKey: false;
|
|
66
|
-
isAutoincrement: false;
|
|
67
|
-
hasRuntimeDefault: false;
|
|
68
|
-
enumValues: [string, ...string[]];
|
|
69
|
-
baseColumn: never;
|
|
70
|
-
identity: undefined;
|
|
71
|
-
generated: undefined;
|
|
72
|
-
}, {}, {}>;
|
|
73
|
-
};
|
|
74
|
-
dialect: 'pg';
|
|
75
|
-
}>;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { pgTable, primaryKey, text } from 'drizzle-orm/pg-core';
|
|
2
|
-
import { agents } from './agents.js';
|
|
3
|
-
import { timestamps } from './timestamps.js';
|
|
4
|
-
// The feed milestones an agent has reached, one row per (agent, milestone).
|
|
5
|
-
// The scoring run writes a milestone to the feed only when it has no row
|
|
6
|
-
// here, so each is written once per agent, ever. Migration 0019 seeded it
|
|
7
|
-
// from standing, so an agent that already stood above none, or already
|
|
8
|
-
// passed a verified task count, before milestones existed is not told it
|
|
9
|
-
// did so for the first time.
|
|
10
|
-
export const agentMilestones = pgTable('agent_milestones', {
|
|
11
|
-
agentId: text('agent_id')
|
|
12
|
-
.notNull()
|
|
13
|
-
.references(() => agents.id),
|
|
14
|
-
milestone: text('milestone').notNull(),
|
|
15
|
-
...timestamps,
|
|
16
|
-
}, (t) => [primaryKey({ columns: [t.agentId, t.milestone] })]);
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
export declare const agentRenames: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
-
name: "agent_renames";
|
|
3
|
-
schema: undefined;
|
|
4
|
-
columns: {
|
|
5
|
-
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
-
name: "created_at";
|
|
7
|
-
tableName: "agent_renames";
|
|
8
|
-
dataType: "date";
|
|
9
|
-
columnType: "PgTimestamp";
|
|
10
|
-
data: Date;
|
|
11
|
-
driverParam: string;
|
|
12
|
-
notNull: true;
|
|
13
|
-
hasDefault: true;
|
|
14
|
-
isPrimaryKey: false;
|
|
15
|
-
isAutoincrement: false;
|
|
16
|
-
hasRuntimeDefault: false;
|
|
17
|
-
enumValues: undefined;
|
|
18
|
-
baseColumn: never;
|
|
19
|
-
identity: undefined;
|
|
20
|
-
generated: undefined;
|
|
21
|
-
}, {}, {}>;
|
|
22
|
-
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
23
|
-
name: "updated_at";
|
|
24
|
-
tableName: "agent_renames";
|
|
25
|
-
dataType: "date";
|
|
26
|
-
columnType: "PgTimestamp";
|
|
27
|
-
data: Date;
|
|
28
|
-
driverParam: string;
|
|
29
|
-
notNull: true;
|
|
30
|
-
hasDefault: true;
|
|
31
|
-
isPrimaryKey: false;
|
|
32
|
-
isAutoincrement: false;
|
|
33
|
-
hasRuntimeDefault: false;
|
|
34
|
-
enumValues: undefined;
|
|
35
|
-
baseColumn: never;
|
|
36
|
-
identity: undefined;
|
|
37
|
-
generated: undefined;
|
|
38
|
-
}, {}, {}>;
|
|
39
|
-
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
40
|
-
name: "id";
|
|
41
|
-
tableName: "agent_renames";
|
|
42
|
-
dataType: "number";
|
|
43
|
-
columnType: "PgBigSerial53";
|
|
44
|
-
data: number;
|
|
45
|
-
driverParam: number;
|
|
46
|
-
notNull: true;
|
|
47
|
-
hasDefault: true;
|
|
48
|
-
isPrimaryKey: true;
|
|
49
|
-
isAutoincrement: false;
|
|
50
|
-
hasRuntimeDefault: false;
|
|
51
|
-
enumValues: undefined;
|
|
52
|
-
baseColumn: never;
|
|
53
|
-
identity: undefined;
|
|
54
|
-
generated: undefined;
|
|
55
|
-
}, {}, {}>;
|
|
56
|
-
agentId: import("drizzle-orm/pg-core").PgColumn<{
|
|
57
|
-
name: "agent_id";
|
|
58
|
-
tableName: "agent_renames";
|
|
59
|
-
dataType: "string";
|
|
60
|
-
columnType: "PgText";
|
|
61
|
-
data: string;
|
|
62
|
-
driverParam: string;
|
|
63
|
-
notNull: true;
|
|
64
|
-
hasDefault: false;
|
|
65
|
-
isPrimaryKey: false;
|
|
66
|
-
isAutoincrement: false;
|
|
67
|
-
hasRuntimeDefault: false;
|
|
68
|
-
enumValues: [string, ...string[]];
|
|
69
|
-
baseColumn: never;
|
|
70
|
-
identity: undefined;
|
|
71
|
-
generated: undefined;
|
|
72
|
-
}, {}, {}>;
|
|
73
|
-
oldName: import("drizzle-orm/pg-core").PgColumn<{
|
|
74
|
-
name: "old_name";
|
|
75
|
-
tableName: "agent_renames";
|
|
76
|
-
dataType: "string";
|
|
77
|
-
columnType: "PgText";
|
|
78
|
-
data: string;
|
|
79
|
-
driverParam: string;
|
|
80
|
-
notNull: true;
|
|
81
|
-
hasDefault: false;
|
|
82
|
-
isPrimaryKey: false;
|
|
83
|
-
isAutoincrement: false;
|
|
84
|
-
hasRuntimeDefault: false;
|
|
85
|
-
enumValues: [string, ...string[]];
|
|
86
|
-
baseColumn: never;
|
|
87
|
-
identity: undefined;
|
|
88
|
-
generated: undefined;
|
|
89
|
-
}, {}, {}>;
|
|
90
|
-
newName: import("drizzle-orm/pg-core").PgColumn<{
|
|
91
|
-
name: "new_name";
|
|
92
|
-
tableName: "agent_renames";
|
|
93
|
-
dataType: "string";
|
|
94
|
-
columnType: "PgText";
|
|
95
|
-
data: string;
|
|
96
|
-
driverParam: string;
|
|
97
|
-
notNull: true;
|
|
98
|
-
hasDefault: false;
|
|
99
|
-
isPrimaryKey: false;
|
|
100
|
-
isAutoincrement: false;
|
|
101
|
-
hasRuntimeDefault: false;
|
|
102
|
-
enumValues: [string, ...string[]];
|
|
103
|
-
baseColumn: never;
|
|
104
|
-
identity: undefined;
|
|
105
|
-
generated: undefined;
|
|
106
|
-
}, {}, {}>;
|
|
107
|
-
issuedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
108
|
-
name: "issued_at";
|
|
109
|
-
tableName: "agent_renames";
|
|
110
|
-
dataType: "date";
|
|
111
|
-
columnType: "PgTimestamp";
|
|
112
|
-
data: Date;
|
|
113
|
-
driverParam: string;
|
|
114
|
-
notNull: true;
|
|
115
|
-
hasDefault: false;
|
|
116
|
-
isPrimaryKey: false;
|
|
117
|
-
isAutoincrement: false;
|
|
118
|
-
hasRuntimeDefault: false;
|
|
119
|
-
enumValues: undefined;
|
|
120
|
-
baseColumn: never;
|
|
121
|
-
identity: undefined;
|
|
122
|
-
generated: undefined;
|
|
123
|
-
}, {}, {}>;
|
|
124
|
-
};
|
|
125
|
-
dialect: 'pg';
|
|
126
|
-
}>;
|
package/dist/db/agent-renames.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { bigserial, index, pgTable, text, timestamp, } from 'drizzle-orm/pg-core';
|
|
2
|
-
import { agents } from './agents.js';
|
|
3
|
-
import { timestamps } from './timestamps.js';
|
|
4
|
-
// One row per rename. An old handle keeps resolving, as a redirect, for
|
|
5
|
-
// RENAME_REDIRECT_DAYS after the rename, and the profile shows the old name
|
|
6
|
-
// for as long. issued_at is the signed issuedAt of the rename, so an older
|
|
7
|
-
// envelope sent again is refused.
|
|
8
|
-
//
|
|
9
|
-
// bigserial is a bigint filled from its own sequence. mode 'number' reads it
|
|
10
|
-
// as a JS number, which is safe well past any count of renames.
|
|
11
|
-
export const agentRenames = pgTable('agent_renames', {
|
|
12
|
-
id: bigserial('id', { mode: 'number' }).primaryKey(),
|
|
13
|
-
agentId: text('agent_id')
|
|
14
|
-
.notNull()
|
|
15
|
-
.references(() => agents.id),
|
|
16
|
-
oldName: text('old_name').notNull(),
|
|
17
|
-
newName: text('new_name').notNull(),
|
|
18
|
-
issuedAt: timestamp('issued_at', { withTimezone: true }).notNull(),
|
|
19
|
-
...timestamps,
|
|
20
|
-
}, (t) => [index('agent_renames_agent_created_idx').on(t.agentId, t.createdAt)]);
|