@brightbeamai/chap-coordinator 0.2.9 → 0.2.12
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 +6 -1
- package/dist/{api-CPEk0V6i.d.ts → api-BOGEBNmX.d.ts} +15 -0
- package/dist/{api-DE78DA0o.d.cts → api-DiiL0sil.d.cts} +15 -0
- package/dist/api.d.cts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/index.cjs +190 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +190 -23
- package/dist/index.js.map +1 -1
- package/dist/jsonrpc.cjs +2 -0
- package/dist/jsonrpc.cjs.map +1 -1
- package/dist/jsonrpc.d.cts +2 -0
- package/dist/jsonrpc.d.ts +2 -0
- package/dist/jsonrpc.js +2 -0
- package/dist/jsonrpc.js.map +1 -1
- package/dist/methods.cjs.map +1 -1
- package/dist/methods.d.cts +22 -2
- package/dist/methods.d.ts +22 -2
- package/dist/patch.cjs +8 -7
- package/dist/patch.cjs.map +1 -1
- package/dist/patch.js +8 -7
- package/dist/patch.js.map +1 -1
- package/dist/storage/sqlite.cjs +5 -2
- package/dist/storage/sqlite.cjs.map +1 -1
- package/dist/storage/sqlite.js +4 -9
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/storage/store.cjs.map +1 -1
- package/dist/storage/store.d.cts +26 -1
- package/dist/storage/store.d.ts +26 -1
- package/dist/storage/store.js.map +1 -1
- package/package.json +79 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/sqlite.ts"],"sourcesContent":["/**\n * SQLite-backed store using better-sqlite3.\n *\n * Schema:\n * CREATE TABLE chap_workspaces (\n * id TEXT PRIMARY KEY,\n * data TEXT NOT NULL, -- JSON.stringify of snapshot\n * version INTEGER NOT NULL,\n * updated_at TEXT NOT NULL -- ISO-8601\n * )\n *\n * Usage:\n * import { Coordinator } from \"@brightbeamai/chap-coordinator\";\n * import { SqliteStore } from \"@brightbeamai/chap-coordinator/storage/sqlite\";\n *\n * const coord = new Coordinator({\n * store: new SqliteStore(\"./chap.db\"),\n * });\n *\n * Pass `\":memory:\"` for an in-memory SQLite instance (faster than the\n * MemoryStore for tests that need transactional semantics).\n *\n * better-sqlite3 is declared as an optionalDependency. If the binary\n * cannot be built (rare on Linux/macOS, common on locked-down CI), the\n * SqliteStore import will throw with a clear message and applications\n * can fall back to MemoryStore or another implementation.\n */\n\nimport type { Store, WorkspaceRecord } from \"./store.js\";\n\n// better-sqlite3 has no published types in its own package, but the\n// `@types/better-sqlite3` package provides them. We require a structural\n// subset so the file type-checks even if the typings are absent.\ninterface SqliteDatabase {\n exec(sql: string): unknown;\n prepare(sql: string): SqliteStatement;\n pragma(name: string, options?: { simple?: boolean }): unknown;\n close(): void;\n}\ninterface SqliteStatement {\n run(...params: unknown[]): { changes: number; lastInsertRowid: number | bigint };\n get(...params: unknown[]): unknown;\n all(...params: unknown[]): unknown[];\n}\n\nexport interface SqliteStoreOptions {\n /**\n * Enable WAL journal mode for better concurrent-read performance.\n * Default true. Set false for `:memory:` databases or when the\n * filesystem does not support WAL (some network filesystems).\n */\n wal?: boolean;\n}\n\nexport class SqliteStore implements Store {\n readonly db: SqliteDatabase;\n private readonly stmtLoad: SqliteStatement;\n private readonly stmtSave: SqliteStatement;\n private readonly stmtDelete: SqliteStatement;\n\n constructor(path: string, options: SqliteStoreOptions = {}) {\n let Database: new (path: string) => SqliteDatabase;\n try {\n //
|
|
1
|
+
{"version":3,"sources":["../../src/storage/sqlite.ts"],"sourcesContent":["/**\n * SQLite-backed store using better-sqlite3.\n *\n * Schema:\n * CREATE TABLE chap_workspaces (\n * id TEXT PRIMARY KEY,\n * data TEXT NOT NULL, -- JSON.stringify of snapshot\n * version INTEGER NOT NULL,\n * updated_at TEXT NOT NULL -- ISO-8601\n * )\n *\n * Usage:\n * import { Coordinator } from \"@brightbeamai/chap-coordinator\";\n * import { SqliteStore } from \"@brightbeamai/chap-coordinator/storage/sqlite\";\n *\n * const coord = new Coordinator({\n * store: new SqliteStore(\"./chap.db\"),\n * });\n *\n * Pass `\":memory:\"` for an in-memory SQLite instance (faster than the\n * MemoryStore for tests that need transactional semantics).\n *\n * better-sqlite3 is declared as an optionalDependency. If the binary\n * cannot be built (rare on Linux/macOS, common on locked-down CI), the\n * SqliteStore import will throw with a clear message and applications\n * can fall back to MemoryStore or another implementation.\n */\n\nimport { createRequire } from \"node:module\";\nimport type { Store, WorkspaceRecord } from \"./store.js\";\n\n// better-sqlite3 has no published types in its own package, but the\n// `@types/better-sqlite3` package provides them. We require a structural\n// subset so the file type-checks even if the typings are absent.\ninterface SqliteDatabase {\n exec(sql: string): unknown;\n prepare(sql: string): SqliteStatement;\n pragma(name: string, options?: { simple?: boolean }): unknown;\n close(): void;\n}\ninterface SqliteStatement {\n run(...params: unknown[]): { changes: number; lastInsertRowid: number | bigint };\n get(...params: unknown[]): unknown;\n all(...params: unknown[]): unknown[];\n}\n\nexport interface SqliteStoreOptions {\n /**\n * Enable WAL journal mode for better concurrent-read performance.\n * Default true. Set false for `:memory:` databases or when the\n * filesystem does not support WAL (some network filesystems).\n */\n wal?: boolean;\n}\n\nexport class SqliteStore implements Store {\n readonly db: SqliteDatabase;\n private readonly stmtLoad: SqliteStatement;\n private readonly stmtSave: SqliteStatement;\n private readonly stmtDelete: SqliteStatement;\n\n constructor(path: string, options: SqliteStoreOptions = {}) {\n let Database: new (path: string) => SqliteDatabase;\n try {\n // Resolved at construction so the dependency stays optional: importing\n // this module costs nothing if you never build a SqliteStore.\n //\n // createRequire rather than a bare require(). A bare one is undefined in\n // an ES module, so from source it threw ReferenceError and this catch\n // reported the dependency as missing when it was installed. The bundled\n // build masked it by shimming require, which is why it went unnoticed.\n Database = createRequire(import.meta.url)(\"better-sqlite3\");\n } catch (err) {\n const detail = err instanceof Error ? `: ${err.message.split(\"\\n\")[0]}` : \"\";\n throw new Error(\n \"SqliteStore requires the `better-sqlite3` package. \" +\n \"Install it with `npm install better-sqlite3` \" +\n `or use MemoryStore for non-persistent workloads${detail}`,\n );\n }\n\n this.db = new Database(path);\n if (path !== \":memory:\" && options.wal !== false) {\n this.db.pragma(\"journal_mode = WAL\");\n }\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS chap_workspaces (\n id TEXT PRIMARY KEY,\n data TEXT NOT NULL,\n version INTEGER NOT NULL,\n updated_at TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_chap_workspaces_updated_at\n ON chap_workspaces (updated_at);\n `);\n\n this.stmtLoad = this.db.prepare(\n \"SELECT id, data, version, updated_at FROM chap_workspaces\",\n );\n this.stmtSave = this.db.prepare(\n \"INSERT INTO chap_workspaces (id, data, version, updated_at) \" +\n \"VALUES (?, ?, ?, ?) \" +\n \"ON CONFLICT(id) DO UPDATE SET \" +\n \"data = excluded.data, \" +\n \"version = excluded.version, \" +\n \"updated_at = excluded.updated_at\",\n );\n this.stmtDelete = this.db.prepare(\n \"DELETE FROM chap_workspaces WHERE id = ?\",\n );\n }\n\n load(): WorkspaceRecord[] {\n const rows = this.stmtLoad.all() as Array<{\n id: string;\n data: string;\n version: number;\n updated_at: string;\n }>;\n const out: WorkspaceRecord[] = [];\n for (const r of rows) {\n try {\n out.push({ id: r.id, data: JSON.parse(r.data), version: r.version, updated_at: r.updated_at });\n } catch {\n // A single unreadable row must not discard every other workspace; skip it.\n }\n }\n return out;\n }\n\n save(record: WorkspaceRecord): void {\n this.stmtSave.run(\n record.id,\n JSON.stringify(record.data),\n record.version,\n record.updated_at,\n );\n }\n\n delete(id: string): void {\n this.stmtDelete.run(id);\n }\n\n close(): void {\n this.db.close();\n }\n}\n"],"mappings":";AA4BA,SAAS,qBAAqB;AA2BvB,IAAM,cAAN,MAAmC;AAAA,EAC/B;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,MAAc,UAA8B,CAAC,GAAG;AAC1D,QAAI;AACJ,QAAI;AAQF,iBAAW,cAAc,YAAY,GAAG,EAAE,gBAAgB;AAAA,IAC5D,SAAS,KAAK;AACZ,YAAM,SAAS,eAAe,QAAQ,KAAK,IAAI,QAAQ,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK;AAC1E,YAAM,IAAI;AAAA,QACR,sJAEkD,MAAM;AAAA,MAC1D;AAAA,IACF;AAEA,SAAK,KAAK,IAAI,SAAS,IAAI;AAC3B,QAAI,SAAS,cAAc,QAAQ,QAAQ,OAAO;AAChD,WAAK,GAAG,OAAO,oBAAoB;AAAA,IACrC;AACA,SAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KASZ;AAED,SAAK,WAAW,KAAK,GAAG;AAAA,MACtB;AAAA,IACF;AACA,SAAK,WAAW,KAAK,GAAG;AAAA,MACtB;AAAA,IAMF;AACA,SAAK,aAAa,KAAK,GAAG;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAA0B;AACxB,UAAM,OAAO,KAAK,SAAS,IAAI;AAM/B,UAAM,MAAyB,CAAC;AAChC,eAAW,KAAK,MAAM;AACpB,UAAI;AACF,YAAI,KAAK,EAAE,IAAI,EAAE,IAAI,MAAM,KAAK,MAAM,EAAE,IAAI,GAAG,SAAS,EAAE,SAAS,YAAY,EAAE,WAAW,CAAC;AAAA,MAC/F,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,QAA+B;AAClC,SAAK,SAAS;AAAA,MACZ,OAAO;AAAA,MACP,KAAK,UAAU,OAAO,IAAI;AAAA,MAC1B,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,OAAO,IAAkB;AACvB,SAAK,WAAW,IAAI,EAAE;AAAA,EACxB;AAAA,EAEA,QAAc;AACZ,SAAK,GAAG,MAAM;AAAA,EAChB;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/store.ts"],"sourcesContent":["/**\n * Pluggable persistence for the Coordinator.\n *\n * A Store persists workspace state between process restarts. Coordinators\n * call `store.save(workspaceId, snapshot)` after every mutation that\n * appends to the audit chain, and `store.load()` on startup to restore.\n *\n * Two implementations ship in-tree:\n * - MemoryStore (default, no persistence; existing behaviour)\n * - SqliteStore (real SQLite via better-sqlite3, opt-in)\n *\n * Third-party stores (Postgres, Redis, etc.) implement this interface.\n *\n * Stores hold per-workspace JSON snapshots, not a decomposed relational\n * model. The Coordinator's snapshot/restore methods produce JSON-safe\n * payloads; this is fast for workspaces in the low-thousands of audit\n * entries and trades query flexibility for simplicity. Production\n * deployments needing rich query semantics should project the audit log\n * into their own analytics store via the `onAudit` listener.\n */\n\nexport interface WorkspaceRecord {\n /** Workspace identifier. */\n id: string;\n /** JSON-serialisable payload produced by `Coordinator.snapshot()`. */\n data: unknown;\n
|
|
1
|
+
{"version":3,"sources":["../../src/storage/store.ts"],"sourcesContent":["/**\n * Pluggable persistence for the Coordinator.\n *\n * A Store persists workspace state between process restarts. Coordinators\n * call `store.save(workspaceId, snapshot)` after every mutation that\n * appends to the audit chain, and `store.load()` on startup to restore.\n *\n * Two implementations ship in-tree:\n * - MemoryStore (default, no persistence; existing behaviour)\n * - SqliteStore (real SQLite via better-sqlite3, opt-in)\n *\n * Third-party stores (Postgres, Redis, etc.) implement this interface.\n *\n * Concurrency model\n * -----------------\n *\n * A Coordinator is a **single-writer** component: dispatch is serial, workspace\n * state is held in memory, and each chain link is computed from the head the\n * instance holds. This interface is a persistence mechanism, not a\n * concurrency-control one. `save` is an unconditional write and no\n * implementation rejects a stale record.\n *\n * Running two or more Coordinator instances against one shared store is\n * therefore not supported. A stale instance's write replaces a newer one\n * wholesale: entries written by the other instance are lost, the chain is\n * re-linked from the surviving head, and `audit.verify_chain` still reports\n * `ok`, because the surviving chain is internally consistent. The loss is\n * silent and CHAP's own verification will not reveal it.\n *\n * If you need more than one instance, serialise writes above the Coordinator by\n * partitioning workspaces so no workspace is ever written by two, or by holding\n * an external lock. See SPECIFICATION.md section 10.3.\n *\n * Stores hold per-workspace JSON snapshots, not a decomposed relational\n * model. The Coordinator's snapshot/restore methods produce JSON-safe\n * payloads; this is fast for workspaces in the low-thousands of audit\n * entries and trades query flexibility for simplicity. Production\n * deployments needing rich query semantics should project the audit log\n * into their own analytics store via the `onAudit` listener.\n */\n\nexport interface WorkspaceRecord {\n /** Workspace identifier. */\n id: string;\n /** JSON-serialisable payload produced by `Coordinator.snapshot()`. */\n data: unknown;\n /**\n * Incremented on each save. Recorded for diagnostics and for stores that\n * want it; it is NOT enforced. Nothing here performs a compare-and-swap,\n * so this field does not give you optimistic concurrency. See the\n * concurrency model in this module's header.\n */\n version: number;\n /** Wall-clock timestamp of the last write, ISO-8601. */\n updated_at: string;\n}\n\nexport interface Store {\n /** Load all workspace records into memory. Called once on coordinator start. */\n load(): Promise<WorkspaceRecord[]> | WorkspaceRecord[];\n\n /** Persist one workspace record. Called after every mutation. */\n save(record: WorkspaceRecord): Promise<void> | void;\n\n /** Remove one workspace. Used by `workspace.delete` semantics (not in v0.2). */\n delete(id: string): Promise<void> | void;\n\n /** Release resources. Idempotent. */\n close?(): Promise<void> | void;\n}\n\n/**\n * In-memory store. Default behaviour: no persistence, fast tests.\n * State lives in a Map; closing it discards everything.\n */\nexport class MemoryStore implements Store {\n private records = new Map<string, WorkspaceRecord>();\n\n load(): WorkspaceRecord[] {\n return Array.from(this.records.values());\n }\n\n save(record: WorkspaceRecord): void {\n this.records.set(record.id, record);\n }\n\n delete(id: string): void {\n this.records.delete(id);\n }\n\n close(): void {\n this.records.clear();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2EO,IAAM,cAAN,MAAmC;AAAA,EAChC,UAAU,oBAAI,IAA6B;AAAA,EAEnD,OAA0B;AACxB,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AAAA,EACzC;AAAA,EAEA,KAAK,QAA+B;AAClC,SAAK,QAAQ,IAAI,OAAO,IAAI,MAAM;AAAA,EACpC;AAAA,EAEA,OAAO,IAAkB;AACvB,SAAK,QAAQ,OAAO,EAAE;AAAA,EACxB;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,MAAM;AAAA,EACrB;AACF;","names":[]}
|
package/dist/storage/store.d.cts
CHANGED
|
@@ -11,6 +11,26 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Third-party stores (Postgres, Redis, etc.) implement this interface.
|
|
13
13
|
*
|
|
14
|
+
* Concurrency model
|
|
15
|
+
* -----------------
|
|
16
|
+
*
|
|
17
|
+
* A Coordinator is a **single-writer** component: dispatch is serial, workspace
|
|
18
|
+
* state is held in memory, and each chain link is computed from the head the
|
|
19
|
+
* instance holds. This interface is a persistence mechanism, not a
|
|
20
|
+
* concurrency-control one. `save` is an unconditional write and no
|
|
21
|
+
* implementation rejects a stale record.
|
|
22
|
+
*
|
|
23
|
+
* Running two or more Coordinator instances against one shared store is
|
|
24
|
+
* therefore not supported. A stale instance's write replaces a newer one
|
|
25
|
+
* wholesale: entries written by the other instance are lost, the chain is
|
|
26
|
+
* re-linked from the surviving head, and `audit.verify_chain` still reports
|
|
27
|
+
* `ok`, because the surviving chain is internally consistent. The loss is
|
|
28
|
+
* silent and CHAP's own verification will not reveal it.
|
|
29
|
+
*
|
|
30
|
+
* If you need more than one instance, serialise writes above the Coordinator by
|
|
31
|
+
* partitioning workspaces so no workspace is ever written by two, or by holding
|
|
32
|
+
* an external lock. See SPECIFICATION.md section 10.3.
|
|
33
|
+
*
|
|
14
34
|
* Stores hold per-workspace JSON snapshots, not a decomposed relational
|
|
15
35
|
* model. The Coordinator's snapshot/restore methods produce JSON-safe
|
|
16
36
|
* payloads; this is fast for workspaces in the low-thousands of audit
|
|
@@ -23,7 +43,12 @@ interface WorkspaceRecord {
|
|
|
23
43
|
id: string;
|
|
24
44
|
/** JSON-serialisable payload produced by `Coordinator.snapshot()`. */
|
|
25
45
|
data: unknown;
|
|
26
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Incremented on each save. Recorded for diagnostics and for stores that
|
|
48
|
+
* want it; it is NOT enforced. Nothing here performs a compare-and-swap,
|
|
49
|
+
* so this field does not give you optimistic concurrency. See the
|
|
50
|
+
* concurrency model in this module's header.
|
|
51
|
+
*/
|
|
27
52
|
version: number;
|
|
28
53
|
/** Wall-clock timestamp of the last write, ISO-8601. */
|
|
29
54
|
updated_at: string;
|
package/dist/storage/store.d.ts
CHANGED
|
@@ -11,6 +11,26 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Third-party stores (Postgres, Redis, etc.) implement this interface.
|
|
13
13
|
*
|
|
14
|
+
* Concurrency model
|
|
15
|
+
* -----------------
|
|
16
|
+
*
|
|
17
|
+
* A Coordinator is a **single-writer** component: dispatch is serial, workspace
|
|
18
|
+
* state is held in memory, and each chain link is computed from the head the
|
|
19
|
+
* instance holds. This interface is a persistence mechanism, not a
|
|
20
|
+
* concurrency-control one. `save` is an unconditional write and no
|
|
21
|
+
* implementation rejects a stale record.
|
|
22
|
+
*
|
|
23
|
+
* Running two or more Coordinator instances against one shared store is
|
|
24
|
+
* therefore not supported. A stale instance's write replaces a newer one
|
|
25
|
+
* wholesale: entries written by the other instance are lost, the chain is
|
|
26
|
+
* re-linked from the surviving head, and `audit.verify_chain` still reports
|
|
27
|
+
* `ok`, because the surviving chain is internally consistent. The loss is
|
|
28
|
+
* silent and CHAP's own verification will not reveal it.
|
|
29
|
+
*
|
|
30
|
+
* If you need more than one instance, serialise writes above the Coordinator by
|
|
31
|
+
* partitioning workspaces so no workspace is ever written by two, or by holding
|
|
32
|
+
* an external lock. See SPECIFICATION.md section 10.3.
|
|
33
|
+
*
|
|
14
34
|
* Stores hold per-workspace JSON snapshots, not a decomposed relational
|
|
15
35
|
* model. The Coordinator's snapshot/restore methods produce JSON-safe
|
|
16
36
|
* payloads; this is fast for workspaces in the low-thousands of audit
|
|
@@ -23,7 +43,12 @@ interface WorkspaceRecord {
|
|
|
23
43
|
id: string;
|
|
24
44
|
/** JSON-serialisable payload produced by `Coordinator.snapshot()`. */
|
|
25
45
|
data: unknown;
|
|
26
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Incremented on each save. Recorded for diagnostics and for stores that
|
|
48
|
+
* want it; it is NOT enforced. Nothing here performs a compare-and-swap,
|
|
49
|
+
* so this field does not give you optimistic concurrency. See the
|
|
50
|
+
* concurrency model in this module's header.
|
|
51
|
+
*/
|
|
27
52
|
version: number;
|
|
28
53
|
/** Wall-clock timestamp of the last write, ISO-8601. */
|
|
29
54
|
updated_at: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/store.ts"],"sourcesContent":["/**\n * Pluggable persistence for the Coordinator.\n *\n * A Store persists workspace state between process restarts. Coordinators\n * call `store.save(workspaceId, snapshot)` after every mutation that\n * appends to the audit chain, and `store.load()` on startup to restore.\n *\n * Two implementations ship in-tree:\n * - MemoryStore (default, no persistence; existing behaviour)\n * - SqliteStore (real SQLite via better-sqlite3, opt-in)\n *\n * Third-party stores (Postgres, Redis, etc.) implement this interface.\n *\n * Stores hold per-workspace JSON snapshots, not a decomposed relational\n * model. The Coordinator's snapshot/restore methods produce JSON-safe\n * payloads; this is fast for workspaces in the low-thousands of audit\n * entries and trades query flexibility for simplicity. Production\n * deployments needing rich query semantics should project the audit log\n * into their own analytics store via the `onAudit` listener.\n */\n\nexport interface WorkspaceRecord {\n /** Workspace identifier. */\n id: string;\n /** JSON-serialisable payload produced by `Coordinator.snapshot()`. */\n data: unknown;\n
|
|
1
|
+
{"version":3,"sources":["../../src/storage/store.ts"],"sourcesContent":["/**\n * Pluggable persistence for the Coordinator.\n *\n * A Store persists workspace state between process restarts. Coordinators\n * call `store.save(workspaceId, snapshot)` after every mutation that\n * appends to the audit chain, and `store.load()` on startup to restore.\n *\n * Two implementations ship in-tree:\n * - MemoryStore (default, no persistence; existing behaviour)\n * - SqliteStore (real SQLite via better-sqlite3, opt-in)\n *\n * Third-party stores (Postgres, Redis, etc.) implement this interface.\n *\n * Concurrency model\n * -----------------\n *\n * A Coordinator is a **single-writer** component: dispatch is serial, workspace\n * state is held in memory, and each chain link is computed from the head the\n * instance holds. This interface is a persistence mechanism, not a\n * concurrency-control one. `save` is an unconditional write and no\n * implementation rejects a stale record.\n *\n * Running two or more Coordinator instances against one shared store is\n * therefore not supported. A stale instance's write replaces a newer one\n * wholesale: entries written by the other instance are lost, the chain is\n * re-linked from the surviving head, and `audit.verify_chain` still reports\n * `ok`, because the surviving chain is internally consistent. The loss is\n * silent and CHAP's own verification will not reveal it.\n *\n * If you need more than one instance, serialise writes above the Coordinator by\n * partitioning workspaces so no workspace is ever written by two, or by holding\n * an external lock. See SPECIFICATION.md section 10.3.\n *\n * Stores hold per-workspace JSON snapshots, not a decomposed relational\n * model. The Coordinator's snapshot/restore methods produce JSON-safe\n * payloads; this is fast for workspaces in the low-thousands of audit\n * entries and trades query flexibility for simplicity. Production\n * deployments needing rich query semantics should project the audit log\n * into their own analytics store via the `onAudit` listener.\n */\n\nexport interface WorkspaceRecord {\n /** Workspace identifier. */\n id: string;\n /** JSON-serialisable payload produced by `Coordinator.snapshot()`. */\n data: unknown;\n /**\n * Incremented on each save. Recorded for diagnostics and for stores that\n * want it; it is NOT enforced. Nothing here performs a compare-and-swap,\n * so this field does not give you optimistic concurrency. See the\n * concurrency model in this module's header.\n */\n version: number;\n /** Wall-clock timestamp of the last write, ISO-8601. */\n updated_at: string;\n}\n\nexport interface Store {\n /** Load all workspace records into memory. Called once on coordinator start. */\n load(): Promise<WorkspaceRecord[]> | WorkspaceRecord[];\n\n /** Persist one workspace record. Called after every mutation. */\n save(record: WorkspaceRecord): Promise<void> | void;\n\n /** Remove one workspace. Used by `workspace.delete` semantics (not in v0.2). */\n delete(id: string): Promise<void> | void;\n\n /** Release resources. Idempotent. */\n close?(): Promise<void> | void;\n}\n\n/**\n * In-memory store. Default behaviour: no persistence, fast tests.\n * State lives in a Map; closing it discards everything.\n */\nexport class MemoryStore implements Store {\n private records = new Map<string, WorkspaceRecord>();\n\n load(): WorkspaceRecord[] {\n return Array.from(this.records.values());\n }\n\n save(record: WorkspaceRecord): void {\n this.records.set(record.id, record);\n }\n\n delete(id: string): void {\n this.records.delete(id);\n }\n\n close(): void {\n this.records.clear();\n }\n}\n"],"mappings":";AA2EO,IAAM,cAAN,MAAmC;AAAA,EAChC,UAAU,oBAAI,IAA6B;AAAA,EAEnD,OAA0B;AACxB,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AAAA,EACzC;AAAA,EAEA,KAAK,QAA+B;AAClC,SAAK,QAAQ,IAAI,OAAO,IAAI,MAAM;AAAA,EACpC;AAAA,EAEA,OAAO,IAAkB;AACvB,SAAK,QAAQ,OAAO,EAAE;AAAA,EACxB;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,MAAM;AAAA,EACrB;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,52 +1,104 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightbeamai/chap-coordinator",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12",
|
|
4
4
|
"description": "Collaborative Human-Agent Protocol (CHAP): reference TypeScript implementation. Coordinator with Core + every shipped profile, plus pluggable storage and typed method facade.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Brightbeam AI <oss@brightbeam.com>",
|
|
7
7
|
"homepage": "https://github.com/BrightbeamAI/chap",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/BrightbeamAI/chap.git",
|
|
10
|
+
"url": "git+https://github.com/BrightbeamAI/chap.git",
|
|
11
11
|
"directory": "packages/coordinator"
|
|
12
12
|
},
|
|
13
13
|
"bugs": {
|
|
14
14
|
"url": "https://github.com/BrightbeamAI/chap/issues"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
|
-
"chap",
|
|
18
|
-
"
|
|
17
|
+
"chap",
|
|
18
|
+
"agent",
|
|
19
|
+
"protocol",
|
|
20
|
+
"audit",
|
|
21
|
+
"json-rpc",
|
|
22
|
+
"human-ai",
|
|
23
|
+
"human-agent",
|
|
24
|
+
"review",
|
|
25
|
+
"override",
|
|
26
|
+
"scitt",
|
|
27
|
+
"mcp",
|
|
28
|
+
"a2a"
|
|
19
29
|
],
|
|
20
30
|
"type": "module",
|
|
21
|
-
"engines": {
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"main": "./dist/index.cjs",
|
|
24
40
|
"module": "./dist/index.js",
|
|
25
|
-
"types":
|
|
41
|
+
"types": "./dist/index.d.ts",
|
|
26
42
|
"exports": {
|
|
27
|
-
".":
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"./
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./dist/index.d.ts",
|
|
45
|
+
"import": "./dist/index.js",
|
|
46
|
+
"require": "./dist/index.cjs"
|
|
47
|
+
},
|
|
48
|
+
"./jsonrpc": {
|
|
49
|
+
"types": "./dist/jsonrpc.d.ts",
|
|
50
|
+
"import": "./dist/jsonrpc.js",
|
|
51
|
+
"require": "./dist/jsonrpc.cjs"
|
|
52
|
+
},
|
|
53
|
+
"./patch": {
|
|
54
|
+
"types": "./dist/patch.d.ts",
|
|
55
|
+
"import": "./dist/patch.js",
|
|
56
|
+
"require": "./dist/patch.cjs"
|
|
57
|
+
},
|
|
58
|
+
"./types": {
|
|
59
|
+
"types": "./dist/types.d.ts",
|
|
60
|
+
"import": "./dist/types.js",
|
|
61
|
+
"require": "./dist/types.cjs"
|
|
62
|
+
},
|
|
63
|
+
"./methods": {
|
|
64
|
+
"types": "./dist/methods.d.ts",
|
|
65
|
+
"import": "./dist/methods.js",
|
|
66
|
+
"require": "./dist/methods.cjs"
|
|
67
|
+
},
|
|
68
|
+
"./api": {
|
|
69
|
+
"types": "./dist/api.d.ts",
|
|
70
|
+
"import": "./dist/api.js",
|
|
71
|
+
"require": "./dist/api.cjs"
|
|
72
|
+
},
|
|
73
|
+
"./storage/store": {
|
|
74
|
+
"types": "./dist/storage/store.d.ts",
|
|
75
|
+
"import": "./dist/storage/store.js",
|
|
76
|
+
"require": "./dist/storage/store.cjs"
|
|
77
|
+
},
|
|
78
|
+
"./storage/sqlite": {
|
|
79
|
+
"types": "./dist/storage/sqlite.d.ts",
|
|
80
|
+
"import": "./dist/storage/sqlite.js",
|
|
81
|
+
"require": "./dist/storage/sqlite.cjs"
|
|
82
|
+
}
|
|
35
83
|
},
|
|
36
84
|
"scripts": {
|
|
37
|
-
"build":
|
|
38
|
-
"test":
|
|
39
|
-
"typecheck":
|
|
40
|
-
"check:schemas":
|
|
85
|
+
"build": "tsup",
|
|
86
|
+
"test": "tsx --test tests/*.test.ts",
|
|
87
|
+
"typecheck": "tsc",
|
|
88
|
+
"check:schemas": "tsx scripts/check-method-coverage.ts",
|
|
41
89
|
"prepublishOnly": "npm run check:schemas && npm run typecheck && npm run test && npm run build"
|
|
42
90
|
},
|
|
43
|
-
"optionalDependencies": {
|
|
91
|
+
"optionalDependencies": {
|
|
92
|
+
"better-sqlite3": "^12.11.1"
|
|
93
|
+
},
|
|
44
94
|
"devDependencies": {
|
|
45
|
-
"@types/node":
|
|
46
|
-
"better-sqlite3":
|
|
47
|
-
"tsup":
|
|
48
|
-
"tsx":
|
|
49
|
-
"typescript":
|
|
95
|
+
"@types/node": "^20.11.0",
|
|
96
|
+
"better-sqlite3": "^12.11.1",
|
|
97
|
+
"tsup": "^8.0.0",
|
|
98
|
+
"tsx": "^4.7.0",
|
|
99
|
+
"typescript": "^5.3.0"
|
|
50
100
|
},
|
|
51
|
-
"publishConfig": {
|
|
101
|
+
"publishConfig": {
|
|
102
|
+
"access": "public"
|
|
103
|
+
}
|
|
52
104
|
}
|