keri 0.0.0-dev.0ddd65e

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.
Files changed (49) hide show
  1. package/dist/cli/main.d.ts +2 -0
  2. package/dist/cli/main.js +72 -0
  3. package/dist/data-type.d.ts +9 -0
  4. package/dist/data-type.js +1 -0
  5. package/dist/db/event-store.d.ts +20 -0
  6. package/dist/db/event-store.js +1 -0
  7. package/dist/db/sqlite-db.d.ts +13 -0
  8. package/dist/db/sqlite-db.js +123 -0
  9. package/dist/events/common.d.ts +6 -0
  10. package/dist/events/common.js +1 -0
  11. package/dist/events/incept.d.ts +26 -0
  12. package/dist/events/incept.js +28 -0
  13. package/dist/events/interact.d.ts +17 -0
  14. package/dist/events/interact.js +21 -0
  15. package/dist/events/main.d.ts +4 -0
  16. package/dist/events/main.js +4 -0
  17. package/dist/events/reply.d.ts +15 -0
  18. package/dist/events/reply.js +20 -0
  19. package/dist/keri/habitat.d.ts +20 -0
  20. package/dist/keri/habitat.js +130 -0
  21. package/dist/keri/keri.d.ts +26 -0
  22. package/dist/keri/keri.js +43 -0
  23. package/dist/keystore/encrypt.d.ts +2 -0
  24. package/dist/keystore/encrypt.js +38 -0
  25. package/dist/keystore/keystore-fs.d.ts +13 -0
  26. package/dist/keystore/keystore-fs.js +50 -0
  27. package/dist/keystore/keystore-web.d.ts +12 -0
  28. package/dist/keystore/keystore-web.js +48 -0
  29. package/dist/keystore/keystore.d.ts +15 -0
  30. package/dist/keystore/keystore.js +1 -0
  31. package/dist/main-common.d.ts +9 -0
  32. package/dist/main-common.js +8 -0
  33. package/dist/main-web.d.ts +2 -0
  34. package/dist/main-web.js +2 -0
  35. package/dist/main.d.ts +2 -0
  36. package/dist/main.js +2 -0
  37. package/dist/parser/base64.d.ts +6 -0
  38. package/dist/parser/base64.js +74 -0
  39. package/dist/parser/buffered-reader.d.ts +5 -0
  40. package/dist/parser/buffered-reader.js +47 -0
  41. package/dist/parser/cesr-encoding.d.ts +34 -0
  42. package/dist/parser/cesr-encoding.js +158 -0
  43. package/dist/parser/codes.d.ts +143 -0
  44. package/dist/parser/codes.js +266 -0
  45. package/dist/parser/parser.d.ts +16 -0
  46. package/dist/parser/parser.js +161 -0
  47. package/dist/parser/version.d.ts +11 -0
  48. package/dist/parser/version.js +56 -0
  49. package/package.json +45 -0
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ import { program } from "commander";
3
+ import { parse } from "../parser/parser.js";
4
+ import { FileSystemKeyStore } from "../keystore/keystore-fs.js";
5
+ import { SqliteEventStore } from "../db/sqlite-db.js";
6
+ import { Habitat } from "../keri/habitat.js";
7
+ const db = new SqliteEventStore({ filename: ".keri/db.sqlite" });
8
+ db.init();
9
+ program.command("parse").action(async () => {
10
+ const stream = process.stdin;
11
+ for await (const event of parse(ReadableStream.from(stream))) {
12
+ console.log(event);
13
+ }
14
+ });
15
+ program
16
+ .command("keygen")
17
+ .requiredOption("--passcode <passcode>")
18
+ .action(async ({ passcode }) => {
19
+ const keystore = new FileSystemKeyStore({ dir: ".keri/keys", passphrase: passcode });
20
+ await keystore.incept();
21
+ });
22
+ program.command("resolve <oobi>").action(async (oobi) => {
23
+ const response = await fetch(oobi);
24
+ if (!response.ok) {
25
+ throw new Error(`Failed to fetch oobi: ${response.status} ${response.statusText}`);
26
+ }
27
+ if (!response.body) {
28
+ throw new Error(`No body in response`);
29
+ }
30
+ for await (const event of parse(response.body)) {
31
+ db.saveEvent(event.payload);
32
+ }
33
+ });
34
+ program
35
+ .command("incept")
36
+ .requiredOption("--passcode <passcode>")
37
+ .option("--wit <wit>")
38
+ .action(async ({ passcode, wit }) => {
39
+ if (typeof passcode !== "string") {
40
+ throw new Error(`Invalid passcode`);
41
+ }
42
+ const keystore = new FileSystemKeyStore({ dir: ".keri/keys", passphrase: passcode });
43
+ const hab = new Habitat({ db, keystore });
44
+ const wits = [];
45
+ if (typeof wit === "string") {
46
+ wits.push(wit);
47
+ }
48
+ const result = await hab.create({ wits });
49
+ console.dir(result);
50
+ });
51
+ program
52
+ .command("interact")
53
+ .requiredOption("--passcode <passcode>")
54
+ .requiredOption("--aid <aid>")
55
+ .action(async ({ passcode, aid }) => {
56
+ if (typeof passcode !== "string") {
57
+ throw new Error(`Invalid passcode`);
58
+ }
59
+ if (typeof aid !== "string") {
60
+ throw new Error(`Invalid aid`);
61
+ }
62
+ const keystore = new FileSystemKeyStore({ dir: ".keri/keys", passphrase: passcode });
63
+ const hab = new Habitat({ db, keystore });
64
+ const payload = await hab.interact(aid);
65
+ console.dir(payload);
66
+ });
67
+ program.command("export").action(async () => {
68
+ for (const event of await db.list()) {
69
+ console.log(event);
70
+ }
71
+ });
72
+ program.parse(process.argv);
@@ -0,0 +1,9 @@
1
+ export type DataValue = string | number | boolean | DataObject | DataArray;
2
+ export type DataArray = DataValue[];
3
+ /**
4
+ * Defines a data object that can be serialized to JSON.
5
+ * E.g. key events and acdc objects
6
+ */
7
+ export interface DataObject {
8
+ [x: string]: DataValue;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { KeyEvent } from "../events/main.ts";
2
+ export interface KeyEventMessage<T extends KeyEvent = KeyEvent> {
3
+ event: T;
4
+ attachments: KeyEventAttachment[];
5
+ }
6
+ export interface ListArgs {
7
+ i?: string;
8
+ d?: string;
9
+ t?: string;
10
+ r?: string;
11
+ }
12
+ export interface KeyEventAttachment {
13
+ code: string;
14
+ value: string;
15
+ }
16
+ export interface EventStore {
17
+ list(args?: ListArgs): Promise<KeyEventMessage[]>;
18
+ saveEvent(event: KeyEvent): Promise<void>;
19
+ saveAttachment(eventId: string, attachment: KeyEventAttachment): Promise<void>;
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { KeyEvent } from "../events/main.ts";
2
+ import type { EventStore, KeyEventAttachment, KeyEventMessage, ListArgs } from "./event-store.ts";
3
+ export interface SqliteEventStoreOptions {
4
+ filename?: string;
5
+ }
6
+ export declare class SqliteEventStore implements EventStore {
7
+ #private;
8
+ constructor(options?: SqliteEventStoreOptions);
9
+ init(): void;
10
+ saveEvent(event: KeyEvent): Promise<void>;
11
+ saveAttachment(id: string, attachment: KeyEventAttachment): Promise<void>;
12
+ list(args?: ListArgs): Promise<KeyEventMessage[]>;
13
+ }
@@ -0,0 +1,123 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _SqliteEventStore_db;
13
+ import { DatabaseSync } from "node:sqlite";
14
+ import { existsSync, mkdirSync } from "node:fs";
15
+ import { dirname } from "node:path";
16
+ function parseRow(row) {
17
+ if (!row || typeof row !== "object") {
18
+ throw new Error(`Row not found`);
19
+ }
20
+ const data = "event_data" in row && row["event_data"];
21
+ if (!data || typeof data !== "string") {
22
+ throw new Error(`Unexpected row format`);
23
+ }
24
+ if ("attachments" in row && typeof row["attachments"] !== "string") {
25
+ throw new Error(`Unexpected row format`);
26
+ }
27
+ const attachments = JSON.parse(row["attachments"] || "[]");
28
+ if (!Array.isArray(attachments)) {
29
+ throw new Error(`Unexpected row format`);
30
+ }
31
+ return {
32
+ event: JSON.parse(data),
33
+ attachments: attachments.filter((att) => att.code && att.value),
34
+ };
35
+ }
36
+ function ensureDirSync(filename) {
37
+ const dir = dirname(filename);
38
+ if (!existsSync(dir)) {
39
+ mkdirSync(dir);
40
+ }
41
+ }
42
+ export class SqliteEventStore {
43
+ constructor(options = {}) {
44
+ _SqliteEventStore_db.set(this, void 0);
45
+ if (options.filename) {
46
+ ensureDirSync(options.filename);
47
+ }
48
+ __classPrivateFieldSet(this, _SqliteEventStore_db, new DatabaseSync(options.filename ?? ":memory:"), "f");
49
+ }
50
+ init() {
51
+ __classPrivateFieldGet(this, _SqliteEventStore_db, "f").exec(`
52
+ CREATE TABLE IF NOT EXISTS events (
53
+ event_id TEXT PRIMARY KEY,
54
+ event_data JSON NOT NULL
55
+ );
56
+ `);
57
+ __classPrivateFieldGet(this, _SqliteEventStore_db, "f").exec(`
58
+ CREATE TABLE IF NOT EXISTS attachments (
59
+ event_id TEXT NOT NULL,
60
+ attachment_code TEXT NOT NULL,
61
+ attachment_value TEXT NOT NULL,
62
+ FOREIGN KEY(event_id) REFERENCES events(event_id)
63
+ PRIMARY KEY(event_id, attachment_code, attachment_value)
64
+ );
65
+ `);
66
+ }
67
+ async saveEvent(event) {
68
+ const sql = `
69
+ INSERT INTO events (event_id, event_data)
70
+ VALUES ($id, $data) ON CONFLICT(event_id) DO NOTHING;
71
+ `;
72
+ __classPrivateFieldGet(this, _SqliteEventStore_db, "f").prepare(sql).run({
73
+ id: event.d,
74
+ data: JSON.stringify(event),
75
+ });
76
+ }
77
+ async saveAttachment(id, attachment) {
78
+ const sql = `
79
+ INSERT INTO attachments (event_id, attachment_code, attachment_value)
80
+ VALUES ($id, $group, $data)
81
+ ON CONFLICT(event_id, attachment_code, attachment_value) DO NOTHING;
82
+ `;
83
+ __classPrivateFieldGet(this, _SqliteEventStore_db, "f").prepare(sql).run({
84
+ id: id,
85
+ group: attachment.code,
86
+ data: attachment.value,
87
+ });
88
+ }
89
+ async list(args = {}) {
90
+ const filter = [];
91
+ const params = {};
92
+ if (args.i) {
93
+ filter.push("json_extract(event_data, '$.i') = $i");
94
+ params["i"] = args.i;
95
+ }
96
+ if (args.d) {
97
+ filter.push("json_extract(event_data, '$.d') = $d");
98
+ params["d"] = args.d;
99
+ }
100
+ if (args.t) {
101
+ filter.push("json_extract(event_data, '$.t') = $t");
102
+ params["t"] = args.t;
103
+ }
104
+ if (args.r) {
105
+ filter.push("json_extract(event_data, '$.r') = $r");
106
+ params["r"] = args.r;
107
+ }
108
+ const sql = `
109
+ SELECT
110
+ event_data,
111
+ json_group_array(json_object('code', attachment_code, 'value', attachment_value)) as attachments
112
+ FROM
113
+ events
114
+ LEFT JOIN attachments ON events.event_id = attachments.event_id
115
+ ${filter.length ? "WHERE " + filter.join(" AND ") : ""}
116
+ GROUP BY events.event_id
117
+ ORDER BY json_extract(event_data, '$.sn') DESC;
118
+ `;
119
+ const rows = __classPrivateFieldGet(this, _SqliteEventStore_db, "f").prepare(sql).all(params);
120
+ return rows.map(parseRow);
121
+ }
122
+ }
123
+ _SqliteEventStore_db = new WeakMap();
@@ -0,0 +1,6 @@
1
+ export interface KeyEvent {
2
+ v: string;
3
+ t: string;
4
+ d: string;
5
+ }
6
+ export type Threshold = string | string[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import type { DataArray } from "../data-type.ts";
2
+ import type { Threshold } from "./common.ts";
3
+ export interface InceptArgs {
4
+ k: string[];
5
+ kt: Threshold;
6
+ n: string[];
7
+ nt: Threshold;
8
+ b?: string[];
9
+ bt?: string;
10
+ }
11
+ export interface InceptEvent {
12
+ v: string;
13
+ t: "icp";
14
+ d: string;
15
+ i: string;
16
+ s: string;
17
+ kt: Threshold;
18
+ k: string[];
19
+ nt: Threshold;
20
+ n: string[];
21
+ bt: string;
22
+ b: string[];
23
+ c: string[];
24
+ a: DataArray;
25
+ }
26
+ export declare function incept(data: InceptArgs): InceptEvent;
@@ -0,0 +1,28 @@
1
+ import { blake3 } from "@noble/hashes/blake3";
2
+ import cesr from "../parser/cesr-encoding.js";
3
+ import { MatterCode } from "../parser/codes.js";
4
+ import { versify } from "../parser/version.js";
5
+ export function incept(data) {
6
+ const event = versify({
7
+ t: "icp",
8
+ d: "#".repeat(44),
9
+ i: "#".repeat(44),
10
+ s: "0",
11
+ kt: data.kt,
12
+ k: data.k,
13
+ nt: data.nt,
14
+ n: data.n,
15
+ bt: data.bt ?? "0",
16
+ b: data.b ?? [],
17
+ c: [],
18
+ a: [],
19
+ });
20
+ const encoder = new TextEncoder();
21
+ const digest = cesr.encode(MatterCode.Blake3_256, blake3
22
+ .create({ dkLen: 32 })
23
+ .update(encoder.encode(JSON.stringify(event)))
24
+ .digest());
25
+ event["d"] = digest;
26
+ event["i"] = digest;
27
+ return event;
28
+ }
@@ -0,0 +1,17 @@
1
+ import type { DataArray } from "../data-type.ts";
2
+ export interface InteractArgs {
3
+ i: string;
4
+ s: string;
5
+ p: string;
6
+ a: DataArray;
7
+ }
8
+ export interface InteractEvent {
9
+ v: string;
10
+ t: "ixn";
11
+ d: string;
12
+ i: string;
13
+ s: string;
14
+ p: string;
15
+ a: DataArray;
16
+ }
17
+ export declare function interact(data: InteractArgs): InteractEvent;
@@ -0,0 +1,21 @@
1
+ import { blake3 } from "@noble/hashes/blake3";
2
+ import cesr from "../parser/cesr-encoding.js";
3
+ import { MatterCode } from "../parser/codes.js";
4
+ import { versify } from "../parser/version.js";
5
+ export function interact(data) {
6
+ const event = versify({
7
+ t: "ixn",
8
+ d: "#".repeat(44),
9
+ i: data.i,
10
+ s: data.s,
11
+ p: data.p,
12
+ a: data.a,
13
+ });
14
+ const encoder = new TextEncoder();
15
+ const digest = cesr.encode(MatterCode.Blake3_256, blake3
16
+ .create({ dkLen: 32 })
17
+ .update(encoder.encode(JSON.stringify(event)))
18
+ .digest());
19
+ event["d"] = digest;
20
+ return Object.freeze(event);
21
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./common.ts";
2
+ export * from "./incept.ts";
3
+ export * from "./reply.ts";
4
+ export * from "./interact.ts";
@@ -0,0 +1,4 @@
1
+ export * from "./common.js";
2
+ export * from "./incept.js";
3
+ export * from "./reply.js";
4
+ export * from "./interact.js";
@@ -0,0 +1,15 @@
1
+ import type { DataObject } from "../data-type.ts";
2
+ export interface ReplyArgs {
3
+ dt?: string;
4
+ r: string;
5
+ a: DataObject;
6
+ }
7
+ export interface ReplyEvent {
8
+ v: string;
9
+ t: "rpy";
10
+ d: string;
11
+ dt: string;
12
+ r: string;
13
+ a: DataObject;
14
+ }
15
+ export declare function reply(data: ReplyArgs): ReplyEvent;
@@ -0,0 +1,20 @@
1
+ import { blake3 } from "@noble/hashes/blake3";
2
+ import cesr from "../parser/cesr-encoding.js";
3
+ import { MatterCode } from "../parser/codes.js";
4
+ import { versify } from "../parser/version.js";
5
+ export function reply(data) {
6
+ const event = versify({
7
+ t: "rpy",
8
+ d: "#".repeat(44),
9
+ dt: data.dt ?? new Date().toISOString(),
10
+ r: data.r,
11
+ a: data.a,
12
+ });
13
+ const encoder = new TextEncoder();
14
+ const digest = cesr.encode(MatterCode.Blake3_256, blake3
15
+ .create({ dkLen: 32 })
16
+ .update(encoder.encode(JSON.stringify(event)))
17
+ .digest());
18
+ event["d"] = digest;
19
+ return event;
20
+ }
@@ -0,0 +1,20 @@
1
+ import type { EventStore, KeyEventMessage } from "../db/event-store.ts";
2
+ import type { KeyStore } from "../keystore/keystore.ts";
3
+ import type { InteractEvent, InceptEvent } from "../events/main.ts";
4
+ export interface HabitatDeps {
5
+ keystore: KeyStore;
6
+ db: EventStore;
7
+ }
8
+ export interface InceptIdentifierArgs {
9
+ wits: string[];
10
+ toad?: number;
11
+ }
12
+ export declare class Habitat {
13
+ #private;
14
+ constructor(deps: HabitatDeps);
15
+ create(args: InceptIdentifierArgs): Promise<InceptEvent>;
16
+ interact(aid: string): Promise<InteractEvent>;
17
+ resolve(oobi: string): Promise<void>;
18
+ submit(eventId: string): Promise<void>;
19
+ list(id: string): Promise<KeyEventMessage[]>;
20
+ }
@@ -0,0 +1,130 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _Habitat_db, _Habitat_keystore;
13
+ import { cesr, CounterCode } from "../main-common.js";
14
+ import { parse } from "../parser/parser.js";
15
+ import { resolveKeyState, submit } from "./keri.js";
16
+ import { interact, incept } from "../events/main.js";
17
+ export class Habitat {
18
+ constructor(deps) {
19
+ _Habitat_db.set(this, void 0);
20
+ _Habitat_keystore.set(this, void 0);
21
+ __classPrivateFieldSet(this, _Habitat_db, deps.db, "f");
22
+ __classPrivateFieldSet(this, _Habitat_keystore, deps.keystore, "f");
23
+ }
24
+ async create(args) {
25
+ const keys = [await __classPrivateFieldGet(this, _Habitat_keystore, "f").incept(), await __classPrivateFieldGet(this, _Habitat_keystore, "f").incept()];
26
+ const toad = args.toad ?? (args.wits.length === 0 ? 0 : args.wits.length === 1 ? 1 : args.wits.length - 1);
27
+ const payload = incept({
28
+ kt: "1",
29
+ k: keys.map((key) => key.current),
30
+ nt: "1",
31
+ n: keys.map((key) => key.next),
32
+ bt: toad.toString(),
33
+ b: args.wits,
34
+ });
35
+ await __classPrivateFieldGet(this, _Habitat_db, "f").saveEvent(payload);
36
+ const raw = new TextEncoder().encode(JSON.stringify(payload));
37
+ await Promise.all(keys.map(async (key, index) => {
38
+ const sig = await __classPrivateFieldGet(this, _Habitat_keystore, "f").sign(key.current, raw);
39
+ await __classPrivateFieldGet(this, _Habitat_db, "f").saveAttachment(payload.d, {
40
+ code: CounterCode.ControllerIdxSigs,
41
+ value: cesr.index(sig, index),
42
+ });
43
+ }));
44
+ await this.submit(payload.d);
45
+ return payload;
46
+ }
47
+ async interact(aid) {
48
+ const events = await __classPrivateFieldGet(this, _Habitat_db, "f").list({ i: aid });
49
+ if (events.length === 0) {
50
+ throw new Error(`Could not find aid ${aid}`);
51
+ }
52
+ const state = resolveKeyState(events.map((e) => e.event));
53
+ const payload = interact({
54
+ i: aid,
55
+ s: (parseInt(state.s, 16) + 1).toString(),
56
+ a: [],
57
+ p: state.event,
58
+ });
59
+ await __classPrivateFieldGet(this, _Habitat_db, "f").saveEvent(payload);
60
+ const raw = new TextEncoder().encode(JSON.stringify(payload));
61
+ await Promise.all(state.keys.map(async (key, index) => {
62
+ const sig = await __classPrivateFieldGet(this, _Habitat_keystore, "f").sign(key, raw);
63
+ await __classPrivateFieldGet(this, _Habitat_db, "f").saveAttachment(payload.d, {
64
+ code: CounterCode.ControllerIdxSigs,
65
+ value: cesr.index(sig, index),
66
+ });
67
+ }));
68
+ await this.submit(payload.d);
69
+ return payload;
70
+ }
71
+ async resolve(oobi) {
72
+ const response = await fetch(oobi);
73
+ if (!response.ok) {
74
+ throw new Error(`Failed to fetch oobi: ${response.status} ${response.statusText}`);
75
+ }
76
+ if (!response.body) {
77
+ throw new Error(`No body in response`);
78
+ }
79
+ for await (const event of parse(response.body)) {
80
+ __classPrivateFieldGet(this, _Habitat_db, "f").saveEvent(event.payload);
81
+ }
82
+ }
83
+ async submit(eventId) {
84
+ const [event] = await __classPrivateFieldGet(this, _Habitat_db, "f").list({ d: eventId });
85
+ if (!event || !("i" in event.event && typeof event.event.i === "string")) {
86
+ throw new Error("No such event");
87
+ }
88
+ const [inception] = await __classPrivateFieldGet(this, _Habitat_db, "f").list({ i: event.event.i, t: "icp" });
89
+ if (!inception) {
90
+ throw new Error("No inception event found");
91
+ }
92
+ const state = resolveKeyState([inception.event]);
93
+ const locations = await __classPrivateFieldGet(this, _Habitat_db, "f").list({ t: "rpy", r: "/loc/scheme" });
94
+ const witnessEndpoints = await Promise.all(state.wits.map((wit) => {
95
+ const result = locations.map((loc) => loc.event).find((rpy) => rpy.a.eid === wit);
96
+ if (!result) {
97
+ throw new Error(`No location found for wit ${wit}`);
98
+ }
99
+ return result.a.url;
100
+ }));
101
+ for (const wit of witnessEndpoints) {
102
+ const response = await submit({
103
+ event: event.event,
104
+ signatures: {
105
+ controllers: event.attachments
106
+ .filter((attachment) => attachment.code === CounterCode.ControllerIdxSigs)
107
+ .map((attachment) => attachment.value),
108
+ witnesses: [],
109
+ },
110
+ }, wit);
111
+ for await (const receipt of parse(response)) {
112
+ await __classPrivateFieldGet(this, _Habitat_db, "f").saveEvent(receipt.payload);
113
+ let code = null;
114
+ for (const attachment of receipt.attachments) {
115
+ if (attachment.startsWith("-")) {
116
+ code = attachment;
117
+ }
118
+ else if (code) {
119
+ await __classPrivateFieldGet(this, _Habitat_db, "f").saveAttachment(receipt.payload.d, { code: code, value: attachment });
120
+ code = null;
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+ async list(id) {
127
+ return __classPrivateFieldGet(this, _Habitat_db, "f").list({ i: id });
128
+ }
129
+ }
130
+ _Habitat_db = new WeakMap(), _Habitat_keystore = new WeakMap();
@@ -0,0 +1,26 @@
1
+ import type { KeyEvent } from "../events/main.ts";
2
+ export interface WitnessSignature {
3
+ aid: string;
4
+ signature: string;
5
+ }
6
+ export interface KeyEventSignatures {
7
+ controllers: string[];
8
+ witnesses?: WitnessSignature[];
9
+ }
10
+ export interface KeyEventMessage {
11
+ event: KeyEvent;
12
+ signatures: KeyEventSignatures;
13
+ }
14
+ export declare function resolveKeyState(events: KeyEvent[]): {
15
+ s: string;
16
+ prefix: string;
17
+ event: string;
18
+ wits: string[];
19
+ keys: string[];
20
+ sith: import("../main-common.ts").Threshold;
21
+ };
22
+ export declare function serializeAttachment(message: KeyEventMessage): string;
23
+ export interface Receipt {
24
+ event: KeyEvent;
25
+ }
26
+ export declare function submit(message: KeyEventMessage, witnessEndpoint: string): Promise<ReadableStream<Uint8Array>>;
@@ -0,0 +1,43 @@
1
+ import { CounterCode, encodeBase64Int } from "../main-common.js";
2
+ export function resolveKeyState(events) {
3
+ const inception = events[0];
4
+ if (inception.t !== "icp") {
5
+ throw new Error("First event was not inception");
6
+ }
7
+ return {
8
+ s: "0",
9
+ prefix: inception.d,
10
+ event: inception.d,
11
+ wits: inception.b,
12
+ keys: inception.k,
13
+ sith: inception.kt,
14
+ };
15
+ }
16
+ export function serializeAttachment(message) {
17
+ const sigs = message.signatures.controllers;
18
+ const controllerSigs = `${CounterCode.ControllerIdxSigs}${encodeBase64Int(message.signatures.controllers.length, 2)}${sigs.join("")}`;
19
+ const attachmentSize = new TextEncoder().encode(controllerSigs).length / 4;
20
+ const attachment = `${CounterCode.AttachmentGroup}${encodeBase64Int(attachmentSize, 2)}${controllerSigs}`;
21
+ return attachment;
22
+ }
23
+ export async function submit(message, witnessEndpoint) {
24
+ const url = new URL("/receipts", witnessEndpoint);
25
+ const response = await fetch(url, {
26
+ method: "POST",
27
+ body: JSON.stringify(message.event),
28
+ headers: {
29
+ "Content-Type": "application/cesr+json",
30
+ "CESR-ATTACHMENT": serializeAttachment(message),
31
+ },
32
+ });
33
+ if (!response.ok) {
34
+ throw new Error(`Failed to send event to wit ${witnessEndpoint}: ${response.status} ${response.statusText}`);
35
+ }
36
+ if (response.status !== 200) {
37
+ throw new Error(`Failed to send event to wit ${witnessEndpoint}: ${response.status} ${response.statusText}`);
38
+ }
39
+ if (!response.body) {
40
+ throw new Error(`Failed to send event to wit ${witnessEndpoint}: ${response.status} ${response.statusText}`);
41
+ }
42
+ return response.body;
43
+ }
@@ -0,0 +1,2 @@
1
+ export declare function encrypt(passphrase: string, data: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
2
+ export declare function decrypt(passphrase: string, ciphertext: Uint8Array): Promise<Uint8Array>;