@msgboard/history 0.0.30 → 0.0.32
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 +1 -1
- package/dist/archive.d.ts +2 -2
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +20 -4
- package/dist/archive.js.map +1 -1
- package/dist/cosign/categories.d.ts +14 -0
- package/dist/cosign/categories.d.ts.map +1 -0
- package/dist/cosign/categories.js +13 -0
- package/dist/cosign/categories.js.map +1 -0
- package/dist/cosign/fetch.d.ts +36 -0
- package/dist/cosign/fetch.d.ts.map +1 -0
- package/dist/cosign/fetch.js +64 -0
- package/dist/cosign/fetch.js.map +1 -0
- package/dist/cosign/handler.d.ts +28 -0
- package/dist/cosign/handler.d.ts.map +1 -0
- package/dist/cosign/handler.js +111 -0
- package/dist/cosign/handler.js.map +1 -0
- package/dist/cosign/index.d.ts +17 -0
- package/dist/cosign/index.d.ts.map +1 -0
- package/dist/cosign/index.js +12 -0
- package/dist/cosign/index.js.map +1 -0
- package/dist/cosign/router.d.ts +26 -0
- package/dist/cosign/router.d.ts.map +1 -0
- package/dist/cosign/router.js +31 -0
- package/dist/cosign/router.js.map +1 -0
- package/dist/cosign/team-file.d.ts +46 -0
- package/dist/cosign/team-file.d.ts.map +1 -0
- package/dist/cosign/team-file.js +48 -0
- package/dist/cosign/team-file.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +13 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +38 -3
- package/dist/server.js.map +1 -1
- package/package.json +17 -5
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ older than the retention window.
|
|
|
45
45
|
const recent = await archive.query({
|
|
46
46
|
chainId: 943,
|
|
47
47
|
category: 'lorem', // bytes32 hex or its decoded text
|
|
48
|
-
contains: 'hello', // substring match on decoded
|
|
48
|
+
contains: 'hello', // substring match on the decoded data text
|
|
49
49
|
since: new Date('2026-01-01'),
|
|
50
50
|
limit: 20,
|
|
51
51
|
})
|
package/dist/archive.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type ArchiveQuery = {
|
|
|
20
20
|
category?: string;
|
|
21
21
|
since?: Date;
|
|
22
22
|
until?: Date;
|
|
23
|
-
/** Substring match on decoded
|
|
23
|
+
/** Substring match on the decoded message data (the `data_text` column). */
|
|
24
24
|
contains?: string;
|
|
25
25
|
limit?: number;
|
|
26
26
|
offset?: number;
|
|
@@ -32,7 +32,7 @@ export type ArchivedMessage = {
|
|
|
32
32
|
category: string | null;
|
|
33
33
|
category_text: string | null;
|
|
34
34
|
data: string | null;
|
|
35
|
-
|
|
35
|
+
data_text: string | null;
|
|
36
36
|
block_number: string | null;
|
|
37
37
|
block_hash: string | null;
|
|
38
38
|
first_seen_at: string;
|
package/dist/archive.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,kGAAkG;AAClG,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAA;IACf,SAAS,EAAE,gBAAgB,CAAA;CAC5B,CAAA;AAED,mDAAmD;AACnD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ,
|
|
1
|
+
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,kGAAkG;AAClG,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAA;IACf,SAAS,EAAE,gBAAgB,CAAA;CAC5B,CAAA;AAED,mDAAmD;AACnD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,uCAAuC;AACvC,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,wCAAwC;AACxC,MAAM,MAAM,OAAO,GAAG;IACpB,2DAA2D;IAC3D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,6EAA6E;IAC7E,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,oDAAoD;IACpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,oEAAoE;IACpE,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;CACxD,CAAA;AAeD;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,cAAc,KAAG,OA2FvD,CAAA"}
|
package/dist/archive.js
CHANGED
|
@@ -33,19 +33,35 @@ export const createArchive = (options) => {
|
|
|
33
33
|
category TEXT,
|
|
34
34
|
category_text TEXT,
|
|
35
35
|
data TEXT,
|
|
36
|
-
|
|
36
|
+
data_text TEXT,
|
|
37
37
|
block_number BIGINT,
|
|
38
38
|
block_hash TEXT,
|
|
39
39
|
first_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
40
40
|
PRIMARY KEY (hash, chain_id)
|
|
41
41
|
)`);
|
|
42
|
+
// The decoded-data column was originally named `content`; it is now `data_text`
|
|
43
|
+
// to mirror `category`/`category_text` and the node's own `data` field key.
|
|
44
|
+
// Rename in place on existing databases — guarded so it runs at most once and
|
|
45
|
+
// never fires on a fresh table (which is already created with `data_text`).
|
|
46
|
+
await pool.query(`DO $$
|
|
47
|
+
BEGIN
|
|
48
|
+
IF EXISTS (
|
|
49
|
+
SELECT 1 FROM information_schema.columns
|
|
50
|
+
WHERE table_name = 'message_archive' AND column_name = 'content'
|
|
51
|
+
) AND NOT EXISTS (
|
|
52
|
+
SELECT 1 FROM information_schema.columns
|
|
53
|
+
WHERE table_name = 'message_archive' AND column_name = 'data_text'
|
|
54
|
+
) THEN
|
|
55
|
+
ALTER TABLE message_archive RENAME COLUMN content TO data_text;
|
|
56
|
+
END IF;
|
|
57
|
+
END $$`);
|
|
42
58
|
await pool.query(`CREATE INDEX IF NOT EXISTS message_archive_seen_idx ON message_archive (first_seen_at)`);
|
|
43
59
|
await pool.query(`CREATE INDEX IF NOT EXISTS message_archive_chain_seen ON message_archive (chain_id, first_seen_at)`);
|
|
44
60
|
await pool.query(`CREATE INDEX IF NOT EXISTS message_archive_category_idx ON message_archive (category)`);
|
|
45
61
|
};
|
|
46
62
|
const record = async (message, chainId) => {
|
|
47
63
|
await pool.query(`INSERT INTO message_archive
|
|
48
|
-
(hash, chain_id, category, category_text, data,
|
|
64
|
+
(hash, chain_id, category, category_text, data, data_text, block_number, block_hash)
|
|
49
65
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
50
66
|
ON CONFLICT (hash, chain_id) DO NOTHING`, [
|
|
51
67
|
message.hash,
|
|
@@ -77,12 +93,12 @@ export const createArchive = (options) => {
|
|
|
77
93
|
if (filter.until)
|
|
78
94
|
add('first_seen_at <= $?', filter.until.toISOString());
|
|
79
95
|
if (filter.contains)
|
|
80
|
-
add('
|
|
96
|
+
add('data_text ILIKE $?', `%${filter.contains}%`);
|
|
81
97
|
const where = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';
|
|
82
98
|
// limit/offset are interpolated, so coerce to bounded integers (never user SQL).
|
|
83
99
|
const limit = Math.min(Math.max(Number.parseInt(String(filter.limit ?? 100), 10) || 100, 1), 1000);
|
|
84
100
|
const offset = Math.max(Number.parseInt(String(filter.offset ?? 0), 10) || 0, 0);
|
|
85
|
-
const { rows } = await pool.query(`SELECT hash, chain_id, category, category_text, data,
|
|
101
|
+
const { rows } = await pool.query(`SELECT hash, chain_id, category, category_text, data, data_text, block_number, block_hash, first_seen_at FROM message_archive ${where} ORDER BY first_seen_at DESC LIMIT ${limit} OFFSET ${offset}`, params);
|
|
86
102
|
return rows;
|
|
87
103
|
};
|
|
88
104
|
return { migrate, record, prune, query };
|
package/dist/archive.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,WAAW,EAAE,MAAM,MAAM,CAAA;AAwD5C,8FAA8F;AAC9F,MAAM,aAAa,GAAG,CAAC,GAAQ,EAAiB,EAAE;IAChD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QACzD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QAClC,qDAAqD;QACrD,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QAC9C,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,OAAuB,EAAW,EAAE;IAChE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IACxB,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,CAAA;IAE5C,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;QACxC,MAAM,IAAI,CAAC,KAAK,CACd;;;;;;;;;;;QAWE,CACH,CAAA;QACD,gFAAgF;QAChF,4EAA4E;QAC5E,8EAA8E;QAC9E,4EAA4E;QAC5E,MAAM,IAAI,CAAC,KAAK,CACd;;;;;;;;;;;cAWQ,CACT,CAAA;QACD,MAAM,IAAI,CAAC,KAAK,CAAC,wFAAwF,CAAC,CAAA;QAC1G,MAAM,IAAI,CAAC,KAAK,CACd,oGAAoG,CACrG,CAAA;QACD,MAAM,IAAI,CAAC,KAAK,CAAC,uFAAuF,CAAC,CAAA;IAC3G,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,KAAK,EAAE,OAAmB,EAAE,OAAe,EAAiB,EAAE;QAC3E,MAAM,IAAI,CAAC,KAAK,CACd;;;+CAGyC,EACzC;YACE,OAAO,CAAC,IAAI;YACZ,OAAO;YACP,OAAO,CAAC,QAAQ;YAChB,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC;YAC/B,OAAO,CAAC,IAAI;YACZ,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;YAC3B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE;YACtC,OAAO,CAAC,SAAS;SAClB,CACF,CAAA;IACH,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,KAAK,IAAmB,EAAE;QACtC,MAAM,IAAI,CAAC,KAAK,CAAC,uEAAuE,aAAa,QAAQ,CAAC,CAAA;IAChH,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,KAAK,EAAE,MAAoB,EAA8B,EAAE;QACvE,MAAM,OAAO,GAAa,EAAE,CAAA;QAC5B,MAAM,MAAM,GAAc,EAAE,CAAA;QAC5B,MAAM,GAAG,GAAG,CAAC,MAAc,EAAE,KAAc,EAAQ,EAAE;YACnD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAClB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAC5D,CAAC,CAAA;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;QACtE,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;YAAE,GAAG,CAAC,uCAAuC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QAChG,IAAI,MAAM,CAAC,KAAK;YAAE,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;QACxE,IAAI,MAAM,CAAC,KAAK;YAAE,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;QACxE,IAAI,MAAM,CAAC,QAAQ;YAAE,GAAG,CAAC,oBAAoB,EAAE,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAA;QACtE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QACxE,iFAAiF;QACjF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QAClG,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QAChF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAC/B,iIAAiI,KAAK,sCAAsC,KAAK,WAAW,MAAM,EAAE,EACpM,MAAM,CACP,CAAA;QACD,OAAO,IAAyB,CAAA;IAClC,CAAC,CAAA;IAED,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AAC1C,CAAC,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Hex } from 'viem';
|
|
2
|
+
/** A resolved category: its hash plus the UTC day it buckets (for the board-vs-archive split). */
|
|
3
|
+
export type ResolvedCategory = {
|
|
4
|
+
category: Hex;
|
|
5
|
+
/** `YYYY-MM-DD` UTC day this category buckets. */
|
|
6
|
+
isoDay: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Expands `(namespace, scope) × {today + prior days-1 UTC days}` into concrete category
|
|
10
|
+
* hashes via the cosign SDK's `keysForWindow` (the single source of truth for the key scheme),
|
|
11
|
+
* tagging each with its UTC `isoDay`. Today-first, descending. Throws when `days < 1`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const resolveCategories: (namespace: string, scope: string, days: number, now?: Date) => ResolvedCategory[];
|
|
14
|
+
//# sourceMappingURL=categories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../src/cosign/categories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAG/B,kGAAkG;AAClG,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,GAAG,CAAA;IACb,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,OAAO,MAAM,EACb,MAAM,MAAM,EACZ,MAAK,IAAiB,KACrB,gBAAgB,EAKlB,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { isoDay, keysForWindow } from '@msgboard/cosign';
|
|
2
|
+
/**
|
|
3
|
+
* Expands `(namespace, scope) × {today + prior days-1 UTC days}` into concrete category
|
|
4
|
+
* hashes via the cosign SDK's `keysForWindow` (the single source of truth for the key scheme),
|
|
5
|
+
* tagging each with its UTC `isoDay`. Today-first, descending. Throws when `days < 1`.
|
|
6
|
+
*/
|
|
7
|
+
export const resolveCategories = (namespace, scope, days, now = new Date()) => {
|
|
8
|
+
const categories = keysForWindow(namespace, scope, days, now);
|
|
9
|
+
const dayMs = 24 * 60 * 60 * 1000;
|
|
10
|
+
const base = now.getTime();
|
|
11
|
+
return categories.map((category, i) => ({ category, isoDay: isoDay(new Date(base - i * dayMs)) }));
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=categories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.js","sourceRoot":"","sources":["../../src/cosign/categories.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AASxD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,SAAiB,EACjB,KAAa,EACb,IAAY,EACZ,MAAY,IAAI,IAAI,EAAE,EACF,EAAE;IACtB,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;IAC7D,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;IACjC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;IAC1B,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AACpG,CAAC,CAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type Hex } from 'viem';
|
|
2
|
+
import { type BoardClient, type CosignAdapter, type SignatureRecord } from '@msgboard/cosign';
|
|
3
|
+
import type { Archive } from '../archive.js';
|
|
4
|
+
import type { ResolvedCategory } from './categories.js';
|
|
5
|
+
/** A decoded, validated record plus provenance — the route's internal row. */
|
|
6
|
+
export type CosignRecordView = SignatureRecord & {
|
|
7
|
+
/** The bytes32 category hash this record was fetched under. */
|
|
8
|
+
category: Hex;
|
|
9
|
+
/** Optional human-readable category label (`namespace:scope:isoDay`). */
|
|
10
|
+
category_text?: string;
|
|
11
|
+
/** Where the record was fetched from. */
|
|
12
|
+
source: 'board' | 'archive';
|
|
13
|
+
};
|
|
14
|
+
export type FetchRecordsArgs = {
|
|
15
|
+
categories: ResolvedCategory[];
|
|
16
|
+
board: BoardClient;
|
|
17
|
+
/** The long-tail fallback; required only if the window reaches past `boardRetentionDays`. */
|
|
18
|
+
archive?: Archive;
|
|
19
|
+
/** Days within this many of `now` are read from the board; older days from the archive. */
|
|
20
|
+
boardRetentionDays: number;
|
|
21
|
+
/** Validation adapter; when omitted, every decodable record is kept (kind:"none"). */
|
|
22
|
+
adapter?: CosignAdapter;
|
|
23
|
+
/** Injectable clock; defaults to now. */
|
|
24
|
+
now?: Date;
|
|
25
|
+
/** Optional label builder for `category_text`. */
|
|
26
|
+
categoryText?: (c: ResolvedCategory) => string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Reads the resolved categories, splitting recent days (board) from older days (archive),
|
|
30
|
+
* decodes each entry (skipping junk that `decodeRecord` throws on), validates via
|
|
31
|
+
* `adapter.verify` (dropping `false`; dropping-with-reason on a throw), dedupes by
|
|
32
|
+
* `keccak256(rawData)`, and tags provenance. Source errors PROPAGATE (the route fails the
|
|
33
|
+
* request rather than returning a misleadingly-short window — the §9 statelessness trade).
|
|
34
|
+
*/
|
|
35
|
+
export declare const fetchRecords: (args: FetchRecordsArgs) => Promise<CosignRecordView[]>;
|
|
36
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/cosign/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAa,MAAM,MAAM,CAAA;AAC1C,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,eAAe,EAErB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEvD,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG;IAC/C,+DAA+D;IAC/D,QAAQ,EAAE,GAAG,CAAA;IACb,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yCAAyC;IACzC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,gBAAgB,EAAE,CAAA;IAC9B,KAAK,EAAE,WAAW,CAAA;IAClB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2FAA2F;IAC3F,kBAAkB,EAAE,MAAM,CAAA;IAC1B,sFAAsF;IACtF,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,yCAAyC;IACzC,GAAG,CAAC,EAAE,IAAI,CAAA;IACV,kDAAkD;IAClD,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,MAAM,CAAA;CAC/C,CAAA;AAID;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAU,MAAM,gBAAgB,KAAG,OAAO,CAAC,gBAAgB,EAAE,CAiErF,CAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { keccak256 } from 'viem';
|
|
2
|
+
import { decodeRecord, } from '@msgboard/cosign';
|
|
3
|
+
const dayMs = 24 * 60 * 60 * 1000;
|
|
4
|
+
/**
|
|
5
|
+
* Reads the resolved categories, splitting recent days (board) from older days (archive),
|
|
6
|
+
* decodes each entry (skipping junk that `decodeRecord` throws on), validates via
|
|
7
|
+
* `adapter.verify` (dropping `false`; dropping-with-reason on a throw), dedupes by
|
|
8
|
+
* `keccak256(rawData)`, and tags provenance. Source errors PROPAGATE (the route fails the
|
|
9
|
+
* request rather than returning a misleadingly-short window — the §9 statelessness trade).
|
|
10
|
+
*/
|
|
11
|
+
export const fetchRecords = async (args) => {
|
|
12
|
+
const { categories, board, archive, boardRetentionDays, adapter, now = new Date(), categoryText, } = args;
|
|
13
|
+
const today = Math.floor(now.getTime() / dayMs);
|
|
14
|
+
const seen = new Set();
|
|
15
|
+
const out = [];
|
|
16
|
+
for (const cat of categories) {
|
|
17
|
+
const dayIndex = today - Math.floor(Date.parse(`${cat.isoDay}T00:00:00.000Z`) / dayMs);
|
|
18
|
+
const fromBoard = dayIndex < boardRetentionDays;
|
|
19
|
+
// Each row is the hex `data` blob, whatever the source.
|
|
20
|
+
let datas;
|
|
21
|
+
if (fromBoard) {
|
|
22
|
+
const content = await board.content({ category: cat.category });
|
|
23
|
+
datas = (content[cat.category] ?? []).map((m) => m.data).filter((d) => Boolean(d));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
if (!archive)
|
|
27
|
+
throw new Error(`fetchRecords: archive required for older day ${cat.isoDay} but none provided`);
|
|
28
|
+
const rows = await archive.query({ category: cat.category, limit: 1000 });
|
|
29
|
+
datas = rows.map((r) => r.data).filter((d) => Boolean(d));
|
|
30
|
+
}
|
|
31
|
+
for (const data of datas) {
|
|
32
|
+
const dedupeKey = keccak256(data);
|
|
33
|
+
if (seen.has(dedupeKey))
|
|
34
|
+
continue;
|
|
35
|
+
let record;
|
|
36
|
+
try {
|
|
37
|
+
record = decodeRecord(data);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
continue; // undecodable junk under an open category — skip (expected; debug-level)
|
|
41
|
+
}
|
|
42
|
+
if (adapter) {
|
|
43
|
+
let ok;
|
|
44
|
+
try {
|
|
45
|
+
ok = await adapter.verify(record);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
continue; // verify-errored (e.g. RPC failure / stubbed adapter) — drop with reason, do not crash
|
|
49
|
+
}
|
|
50
|
+
if (!ok)
|
|
51
|
+
continue; // invalid signature — drop
|
|
52
|
+
}
|
|
53
|
+
seen.add(dedupeKey);
|
|
54
|
+
out.push({
|
|
55
|
+
...record,
|
|
56
|
+
category: cat.category,
|
|
57
|
+
category_text: categoryText?.(cat),
|
|
58
|
+
source: fromBoard ? 'board' : 'archive',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/cosign/fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type BoardClient, type CosignAdapter } from '@msgboard/cosign';
|
|
2
|
+
import type { Archive } from '../archive.js';
|
|
3
|
+
import type { CosignRoute } from './router.js';
|
|
4
|
+
import type { TeamFile } from './team-file.js';
|
|
5
|
+
/** Everything the cosign handler needs, injected by the server (and by tests). */
|
|
6
|
+
export type CosignDeps = {
|
|
7
|
+
teamFile: TeamFile;
|
|
8
|
+
board: BoardClient;
|
|
9
|
+
archive?: Archive;
|
|
10
|
+
adapter?: CosignAdapter;
|
|
11
|
+
/** Conservative board-retention cutoff (days) for the board-vs-archive split (§8/§14). */
|
|
12
|
+
boardRetentionDays: number;
|
|
13
|
+
/** Injectable clock; defaults to `() => new Date()`. */
|
|
14
|
+
now?: () => Date;
|
|
15
|
+
};
|
|
16
|
+
/** A handler result the server maps onto `respond(res, status, body)`. */
|
|
17
|
+
export type CosignResult = {
|
|
18
|
+
status: number;
|
|
19
|
+
body: unknown;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The cosign endpoint group, transport-agnostic: validates the scope against the team-file,
|
|
23
|
+
* clamps `days`, fetches+decodes+validates over the board (+archive fallback), then
|
|
24
|
+
* `groupByDigest`/`aggregate`s and shapes the §6 JSON. Board/archive errors → 502; the
|
|
25
|
+
* unknown scope → 404; owners-unimplemented → 501; anything else → 500.
|
|
26
|
+
*/
|
|
27
|
+
export declare const handleCosignRequest: (route: CosignRoute, params: URLSearchParams, deps: CosignDeps) => Promise<CosignResult>;
|
|
28
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/cosign/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAA4B,MAAM,kBAAkB,CAAA;AACjG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAG5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE9C,kFAAkF;AAClF,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,QAAQ,CAAA;IAClB,KAAK,EAAE,WAAW,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,0FAA0F;IAC1F,kBAAkB,EAAE,MAAM,CAAA;IAC1B,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAED,0EAA0E;AAC1E,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAA;AAoB5D;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,WAAW,EAClB,QAAQ,eAAe,EACvB,MAAM,UAAU,KACf,OAAO,CAAC,YAAY,CAuFtB,CAAA"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { aggregate, groupByDigest } from '@msgboard/cosign';
|
|
2
|
+
import { resolveCategories } from './categories.js';
|
|
3
|
+
import { fetchRecords } from './fetch.js';
|
|
4
|
+
/** Maps a raw record to its JSON view (§6 SignatureRecordView). */
|
|
5
|
+
const toView = (r) => ({
|
|
6
|
+
digest: r.digest,
|
|
7
|
+
signer: r.signer,
|
|
8
|
+
signature: r.signature,
|
|
9
|
+
scheme: r.scheme,
|
|
10
|
+
meta: r.meta,
|
|
11
|
+
category: r.category,
|
|
12
|
+
category_text: r.category_text,
|
|
13
|
+
source: r.source,
|
|
14
|
+
});
|
|
15
|
+
const num = (params, key) => {
|
|
16
|
+
const raw = params.get(key);
|
|
17
|
+
if (raw === null || !Number.isFinite(Number(raw)))
|
|
18
|
+
return undefined;
|
|
19
|
+
return Number(raw);
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The cosign endpoint group, transport-agnostic: validates the scope against the team-file,
|
|
23
|
+
* clamps `days`, fetches+decodes+validates over the board (+archive fallback), then
|
|
24
|
+
* `groupByDigest`/`aggregate`s and shapes the §6 JSON. Board/archive errors → 502; the
|
|
25
|
+
* unknown scope → 404; owners-unimplemented → 501; anything else → 500.
|
|
26
|
+
*/
|
|
27
|
+
export const handleCosignRequest = async (route, params, deps) => {
|
|
28
|
+
const now = (deps.now ?? (() => new Date()))();
|
|
29
|
+
const team = deps.teamFile.resolve(route.namespace, route.scope);
|
|
30
|
+
if (!team)
|
|
31
|
+
return { status: 404, body: { ok: false, error: 'unknown scope' } };
|
|
32
|
+
// owners passthrough — independent of fetch
|
|
33
|
+
if (route.kind === 'owners') {
|
|
34
|
+
const adapter = deps.adapter;
|
|
35
|
+
if (!adapter?.owners || !adapter?.threshold)
|
|
36
|
+
return { status: 501, body: { ok: false, error: 'owners not supported by adapter' } };
|
|
37
|
+
try {
|
|
38
|
+
const [owners, threshold] = await Promise.all([adapter.owners(), adapter.threshold()]);
|
|
39
|
+
return { status: 200, body: { owners, threshold } };
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return {
|
|
43
|
+
status: 502,
|
|
44
|
+
body: { ok: false, error: error instanceof Error ? error.message : 'owners failed' },
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const days = deps.teamFile.clampDays(num(params, 'days'));
|
|
49
|
+
const categories = resolveCategories(route.namespace, route.scope, days, now);
|
|
50
|
+
let records;
|
|
51
|
+
try {
|
|
52
|
+
records = await fetchRecords({
|
|
53
|
+
categories,
|
|
54
|
+
board: deps.board,
|
|
55
|
+
archive: deps.archive,
|
|
56
|
+
boardRetentionDays: deps.boardRetentionDays,
|
|
57
|
+
adapter: deps.adapter,
|
|
58
|
+
now,
|
|
59
|
+
categoryText: (c) => `${route.namespace}:${route.scope}:${c.isoDay}`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
// Board/archive unavailable at query time — fail loudly (§9), do not return a short window.
|
|
64
|
+
return {
|
|
65
|
+
status: 502,
|
|
66
|
+
body: { ok: false, error: error instanceof Error ? error.message : 'fetch failed' },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
if (route.kind === 'signatures') {
|
|
71
|
+
return { status: 200, body: { signatures: records.map(toView) } };
|
|
72
|
+
}
|
|
73
|
+
const digest = route.digest;
|
|
74
|
+
// groupByDigest preserves the exact CosignRecordView objects passed in (it is generic over
|
|
75
|
+
// SignatureRecord), so the views' provenance fields survive — narrow the type back to the view.
|
|
76
|
+
const group = (groupByDigest(records).get(digest) ?? []);
|
|
77
|
+
if (route.kind === 'digest') {
|
|
78
|
+
const signers = group.map((r) => r.signer);
|
|
79
|
+
return {
|
|
80
|
+
status: 200,
|
|
81
|
+
body: { digest, signatures: group.map(toView), signers, count: signers.length },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// route.kind === 'aggregate' — the headline endpoint
|
|
85
|
+
const ordered = deps.adapter
|
|
86
|
+
? await aggregate(group, deps.adapter)
|
|
87
|
+
: group.map((r) => ({ signer: r.signer, signature: r.signature }));
|
|
88
|
+
const withScheme = ordered.map((o) => {
|
|
89
|
+
const match = group.find((g) => g.signer === o.signer);
|
|
90
|
+
return { signer: o.signer, signature: o.signature, scheme: match?.scheme ?? 0 };
|
|
91
|
+
});
|
|
92
|
+
const threshold = num(params, 'threshold');
|
|
93
|
+
return {
|
|
94
|
+
status: 200,
|
|
95
|
+
body: {
|
|
96
|
+
digest,
|
|
97
|
+
signers: withScheme,
|
|
98
|
+
count: withScheme.length,
|
|
99
|
+
threshold,
|
|
100
|
+
ready: threshold === undefined ? undefined : withScheme.length >= threshold,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
status: 500,
|
|
107
|
+
body: { ok: false, error: error instanceof Error ? error.message : 'cosign query failed' },
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/cosign/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @msgboard/history cosign route (v1, stateless) — a cosign-aware HTTP endpoint group
|
|
3
|
+
* mounted on the archive server. Decodes/validates/aggregates cosign records fetched
|
|
4
|
+
* live from the board (recent window) + this server's archive.query() (long tail).
|
|
5
|
+
* No store, no daemon, no prune. See docs/superpowers/specs/2026-06-13-msgboard-cosign-archivist-design.md.
|
|
6
|
+
*/
|
|
7
|
+
export { loadTeamFile } from './team-file.js';
|
|
8
|
+
export type { TeamFile, TeamFileInput, TeamEntry, TeamAdapterConfig } from './team-file.js';
|
|
9
|
+
export { resolveCategories } from './categories.js';
|
|
10
|
+
export type { ResolvedCategory } from './categories.js';
|
|
11
|
+
export { matchCosignRoute } from './router.js';
|
|
12
|
+
export type { CosignRoute } from './router.js';
|
|
13
|
+
export { fetchRecords } from './fetch.js';
|
|
14
|
+
export type { CosignRecordView, FetchRecordsArgs } from './fetch.js';
|
|
15
|
+
export { handleCosignRequest } from './handler.js';
|
|
16
|
+
export type { CosignDeps, CosignResult } from './handler.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cosign/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAClD,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @msgboard/history cosign route (v1, stateless) — a cosign-aware HTTP endpoint group
|
|
3
|
+
* mounted on the archive server. Decodes/validates/aggregates cosign records fetched
|
|
4
|
+
* live from the board (recent window) + this server's archive.query() (long tail).
|
|
5
|
+
* No store, no daemon, no prune. See docs/superpowers/specs/2026-06-13-msgboard-cosign-archivist-design.md.
|
|
6
|
+
*/
|
|
7
|
+
export { loadTeamFile } from './team-file.js';
|
|
8
|
+
export { resolveCategories } from './categories.js';
|
|
9
|
+
export { matchCosignRoute } from './router.js';
|
|
10
|
+
export { fetchRecords } from './fetch.js';
|
|
11
|
+
export { handleCosignRequest } from './handler.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cosign/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** A parsed cosign route. */
|
|
2
|
+
export type CosignRoute = {
|
|
3
|
+
kind: 'signatures';
|
|
4
|
+
namespace: string;
|
|
5
|
+
scope: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'digest';
|
|
8
|
+
namespace: string;
|
|
9
|
+
scope: string;
|
|
10
|
+
digest: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'aggregate';
|
|
13
|
+
namespace: string;
|
|
14
|
+
scope: string;
|
|
15
|
+
digest: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'owners';
|
|
18
|
+
namespace: string;
|
|
19
|
+
scope: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Matches `/cosign/:namespace/:scope/...` into a typed route, or null when the path
|
|
23
|
+
* is not a (well-formed) cosign route. Segments are URL-decoded.
|
|
24
|
+
*/
|
|
25
|
+
export declare const matchCosignRoute: (pathname: string) => CosignRoute | null;
|
|
26
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/cosign/router.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAExD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,KAAG,WAAW,GAAG,IAwBjE,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matches `/cosign/:namespace/:scope/...` into a typed route, or null when the path
|
|
3
|
+
* is not a (well-formed) cosign route. Segments are URL-decoded.
|
|
4
|
+
*/
|
|
5
|
+
export const matchCosignRoute = (pathname) => {
|
|
6
|
+
const parts = pathname
|
|
7
|
+
.split('/')
|
|
8
|
+
.filter((s) => s.length > 0)
|
|
9
|
+
.map((s) => decodeURIComponent(s));
|
|
10
|
+
// parts[0] must be 'cosign' (the group prefix)
|
|
11
|
+
if (parts[0] !== 'cosign')
|
|
12
|
+
return null;
|
|
13
|
+
const namespace = parts[1];
|
|
14
|
+
const scope = parts[2];
|
|
15
|
+
if (!namespace || !scope)
|
|
16
|
+
return null;
|
|
17
|
+
// /cosign/:ns/:scope/signatures
|
|
18
|
+
if (parts.length === 4 && parts[3] === 'signatures')
|
|
19
|
+
return { kind: 'signatures', namespace, scope };
|
|
20
|
+
// /cosign/:ns/:scope/owners
|
|
21
|
+
if (parts.length === 4 && parts[3] === 'owners')
|
|
22
|
+
return { kind: 'owners', namespace, scope };
|
|
23
|
+
// /cosign/:ns/:scope/digest/:digest
|
|
24
|
+
if (parts.length === 5 && parts[3] === 'digest' && parts[4])
|
|
25
|
+
return { kind: 'digest', namespace, scope, digest: parts[4] };
|
|
26
|
+
// /cosign/:ns/:scope/digest/:digest/aggregate
|
|
27
|
+
if (parts.length === 6 && parts[3] === 'digest' && parts[4] && parts[5] === 'aggregate')
|
|
28
|
+
return { kind: 'aggregate', namespace, scope, digest: parts[4] };
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/cosign/router.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAsB,EAAE;IACvE,MAAM,KAAK,GAAG,QAAQ;SACnB,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAA;IACpC,+CAA+C;IAC/C,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IACtC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;IAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;IACtB,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAErC,gCAAgC;IAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,YAAY;QACjD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;IACjD,4BAA4B;IAC5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;IAC5F,oCAAoC;IACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC;QACzD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/D,8CAA8C;IAC9C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,WAAW;QACrF,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IAElE,OAAO,IAAI,CAAA;AACb,CAAC,CAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Validation/ordering adapter selector. `kind: "none"` = accept every decodable record. */
|
|
2
|
+
export type TeamAdapterConfig = {
|
|
3
|
+
kind: string;
|
|
4
|
+
config?: Record<string, unknown>;
|
|
5
|
+
};
|
|
6
|
+
/** A single served team — a cosign `scope` under the file's `namespace`. `"*"` matches any scope. */
|
|
7
|
+
export type TeamEntry = {
|
|
8
|
+
scope: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
};
|
|
11
|
+
/** The raw on-disk team-file shape (Registry v1). No `store` block — v1 is stateless. */
|
|
12
|
+
export type TeamFileInput = {
|
|
13
|
+
version: number;
|
|
14
|
+
namespace: string;
|
|
15
|
+
/** Default + clamp for the rolling window; defaults to 7 when omitted. */
|
|
16
|
+
windowDays?: number;
|
|
17
|
+
teams: TeamEntry[];
|
|
18
|
+
/** Board node to read from (optional here; the server is handed the board client directly). */
|
|
19
|
+
chain?: {
|
|
20
|
+
chainId?: number;
|
|
21
|
+
rpcUrl?: string;
|
|
22
|
+
};
|
|
23
|
+
adapter: TeamAdapterConfig;
|
|
24
|
+
};
|
|
25
|
+
/** A loaded, validated team-file with resolution + clamp helpers. */
|
|
26
|
+
export type TeamFile = {
|
|
27
|
+
version: number;
|
|
28
|
+
namespace: string;
|
|
29
|
+
windowDays: number;
|
|
30
|
+
teams: TeamEntry[];
|
|
31
|
+
chain?: {
|
|
32
|
+
chainId?: number;
|
|
33
|
+
rpcUrl?: string;
|
|
34
|
+
};
|
|
35
|
+
adapter: TeamAdapterConfig;
|
|
36
|
+
/** Returns the served team for (namespace, scope), or undefined when unknown. */
|
|
37
|
+
resolve(namespace: string, scope: string): TeamEntry | undefined;
|
|
38
|
+
/** Clamps a requested days to [1, windowDays]; NaN/undefined → windowDays. */
|
|
39
|
+
clampDays(days: number | undefined): number;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Loads + validates a team-file from a JSON path or an in-memory object, returning a
|
|
43
|
+
* {@link TeamFile} with `resolve` / `clampDays`. Throws on a malformed file.
|
|
44
|
+
*/
|
|
45
|
+
export declare const loadTeamFile: (source: string | TeamFileInput) => TeamFile;
|
|
46
|
+
//# sourceMappingURL=team-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-file.d.ts","sourceRoot":"","sources":["../../src/cosign/team-file.ts"],"names":[],"mappings":"AAEA,4FAA4F;AAC5F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC,CAAA;AAED,qGAAqG;AACrG,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,yFAAyF;AACzF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,+FAA+F;IAC/F,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,OAAO,EAAE,iBAAiB,CAAA;CAC3B,CAAA;AAED,qEAAqE;AACrE,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,OAAO,EAAE,iBAAiB,CAAA;IAC1B,iFAAiF;IACjF,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAA;IAChE,8EAA8E;IAC9E,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;CAC5C,CAAA;AAID;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,GAAG,aAAa,KAAG,QA6C7D,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
const DEFAULT_WINDOW_DAYS = 7;
|
|
3
|
+
/**
|
|
4
|
+
* Loads + validates a team-file from a JSON path or an in-memory object, returning a
|
|
5
|
+
* {@link TeamFile} with `resolve` / `clampDays`. Throws on a malformed file.
|
|
6
|
+
*/
|
|
7
|
+
export const loadTeamFile = (source) => {
|
|
8
|
+
const raw = typeof source === 'string'
|
|
9
|
+
? JSON.parse(readFileSync(source, 'utf8'))
|
|
10
|
+
: source;
|
|
11
|
+
if (raw.version !== 1)
|
|
12
|
+
throw new Error(`loadTeamFile: unsupported version ${raw.version} (expected 1)`);
|
|
13
|
+
if (typeof raw.namespace !== 'string' || raw.namespace.length === 0)
|
|
14
|
+
throw new Error('loadTeamFile: namespace is required');
|
|
15
|
+
if (!Array.isArray(raw.teams) || raw.teams.length === 0)
|
|
16
|
+
throw new Error('loadTeamFile: teams must list at least one team (or a "*" wildcard)');
|
|
17
|
+
if (!raw.adapter || typeof raw.adapter.kind !== 'string')
|
|
18
|
+
throw new Error('loadTeamFile: adapter.kind is required');
|
|
19
|
+
const windowDays = typeof raw.windowDays === 'number' && Number.isFinite(raw.windowDays) && raw.windowDays >= 1
|
|
20
|
+
? Math.floor(raw.windowDays)
|
|
21
|
+
: DEFAULT_WINDOW_DAYS;
|
|
22
|
+
const teams = raw.teams;
|
|
23
|
+
const namespace = raw.namespace;
|
|
24
|
+
const resolve = (ns, scope) => {
|
|
25
|
+
if (ns !== namespace)
|
|
26
|
+
return undefined;
|
|
27
|
+
return teams.find((t) => t.scope === scope || t.scope === '*');
|
|
28
|
+
};
|
|
29
|
+
const clampDays = (days) => {
|
|
30
|
+
if (days === undefined || !Number.isFinite(days))
|
|
31
|
+
return windowDays;
|
|
32
|
+
const floored = Math.floor(days);
|
|
33
|
+
if (floored < 1)
|
|
34
|
+
return 1;
|
|
35
|
+
return Math.min(floored, windowDays);
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
version: 1,
|
|
39
|
+
namespace,
|
|
40
|
+
windowDays,
|
|
41
|
+
teams,
|
|
42
|
+
chain: raw.chain,
|
|
43
|
+
adapter: raw.adapter,
|
|
44
|
+
resolve,
|
|
45
|
+
clampDays,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=team-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-file.js","sourceRoot":"","sources":["../../src/cosign/team-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAwCtC,MAAM,mBAAmB,GAAG,CAAC,CAAA;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAA8B,EAAY,EAAE;IACvE,MAAM,GAAG,GACP,OAAO,MAAM,KAAK,QAAQ;QACxB,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAmB;QAC7D,CAAC,CAAC,MAAM,CAAA;IAEZ,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,qCAAqC,GAAG,CAAC,OAAO,eAAe,CAAC,CAAA;IAClF,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAA;IACxF,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ;QACtD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAE3D,MAAM,UAAU,GACd,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,UAAU,IAAI,CAAC;QAC1F,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;QAC5B,CAAC,CAAC,mBAAmB,CAAA;IAEzB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAA;IACvB,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAA;IAE/B,MAAM,OAAO,GAAG,CAAC,EAAU,EAAE,KAAa,EAAyB,EAAE;QACnE,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,SAAS,CAAA;QACtC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAA;IAChE,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,CAAC,IAAwB,EAAU,EAAE;QACrD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,UAAU,CAAA;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,OAAO,GAAG,CAAC;YAAE,OAAO,CAAC,CAAA;QACzB,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IACtC,CAAC,CAAA;IAED,OAAO;QACL,OAAO,EAAE,CAAC;QACV,SAAS;QACT,UAAU;QACV,KAAK;QACL,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,OAAO;QACP,SAAS;KACV,CAAA;AACH,CAAC,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,9 @@ export { createArchive } from './archive.js';
|
|
|
2
2
|
export type { Archive, ArchiveOptions, ArchiveQuery, ArchiveRetention, ArchivedMessage, Queryable, } from './archive.js';
|
|
3
3
|
export { archiveServer } from './server.js';
|
|
4
4
|
export type { ArchiveServer, ArchiveServerOptions } from './server.js';
|
|
5
|
+
export { loadTeamFile } from './cosign/team-file.js';
|
|
6
|
+
export type { TeamFile, TeamFileInput, TeamEntry } from './cosign/team-file.js';
|
|
7
|
+
export type { CosignDeps, CosignResult } from './cosign/handler.js';
|
|
8
|
+
export type { CosignOption } from './server.js';
|
|
9
|
+
export type { CosignRecordView } from './cosign/fetch.js';
|
|
5
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,YAAY,EACV,OAAO,EACP,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,SAAS,GACV,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,YAAY,EACV,OAAO,EACP,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,SAAS,GACV,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAEtE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAC/E,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACnE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAU5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAU5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG3C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { Archive } from './archive.js';
|
|
2
|
+
import { type CosignDeps } from './cosign/handler.js';
|
|
3
|
+
import { type TeamFile, type TeamFileInput } from './cosign/team-file.js';
|
|
4
|
+
export type CosignOption = Omit<CosignDeps, 'teamFile'> & {
|
|
5
|
+
/** The registry team-file: a loaded TeamFile, a raw object, or a JSON path. */
|
|
6
|
+
teamFile: TeamFile | TeamFileInput | string;
|
|
7
|
+
};
|
|
2
8
|
export type ArchiveServerOptions = {
|
|
3
9
|
/** The archive to serve. */
|
|
4
10
|
archive: Archive;
|
|
@@ -15,6 +21,12 @@ export type ArchiveServerOptions = {
|
|
|
15
21
|
* `Authorization: Bearer <token>` receive a 401.
|
|
16
22
|
*/
|
|
17
23
|
token?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Opt-in cosign endpoint group. When present, the same server answers
|
|
26
|
+
* `/cosign/:namespace/:scope/...` (decoded cosign view) alongside `/messages`.
|
|
27
|
+
* Absent → the server is unchanged (only `/health` + `/messages`).
|
|
28
|
+
*/
|
|
29
|
+
cosign?: CosignOption;
|
|
18
30
|
};
|
|
19
31
|
export type ArchiveServer = {
|
|
20
32
|
/** Closes the HTTP server. */
|
|
@@ -26,7 +38,7 @@ export type ArchiveServer = {
|
|
|
26
38
|
* - `GET /health` → `{ ok: true }`
|
|
27
39
|
* - `GET /messages` → `{ messages: ArchivedMessage[] }`, filtered by query params:
|
|
28
40
|
* `chainId`, `category` (hex or decoded text), `since`/`until` (ISO dates),
|
|
29
|
-
* `contains` (substring on decoded
|
|
41
|
+
* `contains` (substring on decoded data text), `limit` (≤ 1000), `offset`.
|
|
30
42
|
*
|
|
31
43
|
* Security defaults mirror the relayer's push source: binds to `127.0.0.1`
|
|
32
44
|
* unless `host` is set, and a non-loopback bind requires `token`. Slow
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,KAAK,UAAU,EAAuB,MAAM,qBAAqB,CAAA;AAE1E,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAEvF,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG;IACxD,+EAA+E;IAC/E,QAAQ,EAAE,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAA;CAC5C,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,8BAA8B;IAC9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB,CAAA;AAuCD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,oBAAoB,KAAG,aA0E7D,CAAA"}
|
package/dist/server.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
|
+
import { handleCosignRequest } from './cosign/handler.js';
|
|
3
|
+
import { matchCosignRoute } from './cosign/router.js';
|
|
4
|
+
import { loadTeamFile } from './cosign/team-file.js';
|
|
2
5
|
const respond = (res, status, body) => {
|
|
3
6
|
const json = JSON.stringify(body);
|
|
4
|
-
res.writeHead(status, {
|
|
7
|
+
res.writeHead(status, {
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
'Content-Length': Buffer.byteLength(json),
|
|
10
|
+
});
|
|
5
11
|
res.end(json);
|
|
6
12
|
};
|
|
7
13
|
/** Parses the `/messages` query string into an ArchiveQuery, ignoring unparseable values. */
|
|
@@ -36,7 +42,7 @@ const parseQuery = (params) => {
|
|
|
36
42
|
* - `GET /health` → `{ ok: true }`
|
|
37
43
|
* - `GET /messages` → `{ messages: ArchivedMessage[] }`, filtered by query params:
|
|
38
44
|
* `chainId`, `category` (hex or decoded text), `since`/`until` (ISO dates),
|
|
39
|
-
* `contains` (substring on decoded
|
|
45
|
+
* `contains` (substring on decoded data text), `limit` (≤ 1000), `offset`.
|
|
40
46
|
*
|
|
41
47
|
* Security defaults mirror the relayer's push source: binds to `127.0.0.1`
|
|
42
48
|
* unless `host` is set, and a non-loopback bind requires `token`. Slow
|
|
@@ -50,6 +56,15 @@ export const archiveServer = (options) => {
|
|
|
50
56
|
throw new Error(`archiveServer: non-loopback bind (${host}) requires a token to be set — pass token or set host to '127.0.0.1'`);
|
|
51
57
|
}
|
|
52
58
|
const authorized = (req) => !options.token || req.headers['authorization'] === `Bearer ${options.token}`;
|
|
59
|
+
const cosignDeps = options.cosign
|
|
60
|
+
? {
|
|
61
|
+
...options.cosign,
|
|
62
|
+
archive: options.cosign.archive ?? options.archive, // default the fallback to this server's archive
|
|
63
|
+
teamFile: typeof options.cosign.teamFile === 'string' || !('resolve' in options.cosign.teamFile)
|
|
64
|
+
? loadTeamFile(options.cosign.teamFile)
|
|
65
|
+
: options.cosign.teamFile,
|
|
66
|
+
}
|
|
67
|
+
: undefined;
|
|
53
68
|
const server = createServer(async (req, res) => {
|
|
54
69
|
const url = new URL(req.url ?? '/', `http://${host}:${port}`);
|
|
55
70
|
if (req.method === 'GET' && url.pathname === '/health') {
|
|
@@ -63,7 +78,27 @@ export const archiveServer = (options) => {
|
|
|
63
78
|
return respond(res, 200, { messages });
|
|
64
79
|
}
|
|
65
80
|
catch (error) {
|
|
66
|
-
return respond(res, 500, {
|
|
81
|
+
return respond(res, 500, {
|
|
82
|
+
ok: false,
|
|
83
|
+
error: error instanceof Error ? error.message : 'query failed',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (cosignDeps && req.method === 'GET') {
|
|
88
|
+
const route = matchCosignRoute(url.pathname);
|
|
89
|
+
if (route) {
|
|
90
|
+
if (!authorized(req))
|
|
91
|
+
return respond(res, 401, { ok: false, error: 'unauthorized' });
|
|
92
|
+
try {
|
|
93
|
+
const result = await handleCosignRequest(route, url.searchParams, cosignDeps);
|
|
94
|
+
return respond(res, result.status, result.body);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
return respond(res, 500, {
|
|
98
|
+
ok: false,
|
|
99
|
+
error: error instanceof Error ? error.message : 'cosign query failed',
|
|
100
|
+
});
|
|
101
|
+
}
|
|
67
102
|
}
|
|
68
103
|
}
|
|
69
104
|
return respond(res, 404, { ok: false, error: 'not found' });
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@msgboard/history",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"description": "Historical archive for the msgboard board: durable storage and an HTTP query API",
|
|
5
5
|
"repository": "github:valve-tech/msgboard",
|
|
6
6
|
"author": "MsgBoard",
|
|
@@ -20,25 +20,37 @@
|
|
|
20
20
|
"default": "./dist/index.js"
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
|
-
"keywords": [
|
|
23
|
+
"keywords": [
|
|
24
|
+
"msgboard",
|
|
25
|
+
"history",
|
|
26
|
+
"archive",
|
|
27
|
+
"indexer",
|
|
28
|
+
"pulsechain"
|
|
29
|
+
],
|
|
24
30
|
"scripts": {
|
|
25
31
|
"prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
26
32
|
"build": "tsc",
|
|
27
33
|
"watch": "tsc -w",
|
|
34
|
+
"typecheck": "tsc --noEmit -p tsconfig.test.json",
|
|
28
35
|
"test": "vitest run",
|
|
29
36
|
"test:watch": "vitest",
|
|
30
37
|
"lint": "prettier --check ."
|
|
31
38
|
},
|
|
32
|
-
"files": [
|
|
39
|
+
"files": [
|
|
40
|
+
"dist/"
|
|
41
|
+
],
|
|
33
42
|
"dependencies": {
|
|
34
|
-
"@msgboard/
|
|
43
|
+
"@msgboard/cosign": "^0.0.32",
|
|
44
|
+
"@msgboard/sdk": "^0.0.32",
|
|
35
45
|
"viem": "^2.25.0"
|
|
36
46
|
},
|
|
37
47
|
"peerDependencies": {
|
|
38
48
|
"pg": "^8.14.1"
|
|
39
49
|
},
|
|
40
50
|
"peerDependenciesMeta": {
|
|
41
|
-
"pg": {
|
|
51
|
+
"pg": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
42
54
|
},
|
|
43
55
|
"devDependencies": {
|
|
44
56
|
"@types/pg": "^8.11.11",
|