pactium 0.2.0

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 (42) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +92 -0
  3. package/README.zh-CN.md +90 -0
  4. package/SECURITY.md +7 -0
  5. package/bin/pactium.mjs +121 -0
  6. package/docs/LICOLITE-ASPECT.md +57 -0
  7. package/docs/README.md +13 -0
  8. package/docs/TERM.md +289 -0
  9. package/docs/architecture/ARCHITECTURE.md +62 -0
  10. package/docs/protocols/PROFILE.md +124 -0
  11. package/docs/protocols/PROTOCOLS.md +62 -0
  12. package/examples/record-operation.mjs +26 -0
  13. package/package.json +69 -0
  14. package/src/README.md +13 -0
  15. package/src/aspects/licolite/aspect.js +278 -0
  16. package/src/aspects/licolite/constants.js +13 -0
  17. package/src/aspects/licolite/evidence.js +47 -0
  18. package/src/aspects/licolite/index.d.ts +51 -0
  19. package/src/aspects/licolite/index.js +19 -0
  20. package/src/aspects/licolite/signing.js +78 -0
  21. package/src/canonical/value.js +40 -0
  22. package/src/core/append-condition.js +102 -0
  23. package/src/core/pactium-core.js +1073 -0
  24. package/src/core/tracking-cursor.js +68 -0
  25. package/src/http.js +99 -0
  26. package/src/index-engine/snapshot-merkle-index.js +994 -0
  27. package/src/index.d.ts +244 -0
  28. package/src/index.js +73 -0
  29. package/src/ledger/signed-head.js +204 -0
  30. package/src/ledger/transparency-log.js +702 -0
  31. package/src/maintenance/task-engine.js +36 -0
  32. package/src/proof/bundle-format.js +265 -0
  33. package/src/proof/bundle.js +77 -0
  34. package/src/proof/envelope.js +548 -0
  35. package/src/proof/registry.js +18 -0
  36. package/src/protocol/constants.js +69 -0
  37. package/src/protocol/hashing.js +47 -0
  38. package/src/quality/profile-runner.js +291 -0
  39. package/src/repair/planner.js +62 -0
  40. package/src/shared/records.js +32 -0
  41. package/src/storage/local-json-storage-port.js +360 -0
  42. package/src/verification/failure.js +31 -0
@@ -0,0 +1,68 @@
1
+ import { PACTIUM_PROTOCOL, PACTIUM_SCHEMA_VERSION } from "../protocol/constants.js";
2
+ import { createId } from "../protocol/hashing.js";
3
+ import { asArray, safeText } from "../shared/records.js";
4
+
5
+ export function createTrackingCursor({
6
+ scope = "ledger",
7
+ workspaceId = "",
8
+ position = 0,
9
+ gaps = [],
10
+ headRef = "",
11
+ orderRoot = ""
12
+ } = {}) {
13
+ const normalizedPosition = Number(position || 0);
14
+ const payload = {
15
+ protocol: PACTIUM_PROTOCOL,
16
+ schema: PACTIUM_SCHEMA_VERSION,
17
+ cursorType: "pactium.tracking-cursor",
18
+ scope,
19
+ workspaceId: scope === "workspace" ? safeText(workspaceId, "default") : "",
20
+ position: normalizedPosition,
21
+ gaps: [...new Set(asArray(gaps)
22
+ .map(Number)
23
+ .filter((gap) => Number.isInteger(gap) && gap >= 0 && gap < normalizedPosition))]
24
+ .sort((left, right) => left - right),
25
+ headRef: safeText(headRef),
26
+ orderRoot: safeText(orderRoot)
27
+ };
28
+ return {
29
+ ...payload,
30
+ cursorId: createId("tracking_cursor", payload)
31
+ };
32
+ }
33
+
34
+ export function samePositionAs(left, right) {
35
+ return left?.scope === right?.scope &&
36
+ safeText(left?.workspaceId) === safeText(right?.workspaceId) &&
37
+ Number(left?.position || 0) === Number(right?.position || 0);
38
+ }
39
+
40
+ export function covers(cursor, position) {
41
+ const target = Number(position || 0);
42
+ return Number(cursor?.position || 0) >= target && !asArray(cursor?.gaps).includes(target);
43
+ }
44
+
45
+ export function advanceTo(cursor, position, options = {}) {
46
+ const target = Number(position || 0);
47
+ const current = Number(cursor?.position || 0);
48
+ const gaps = new Set(asArray(cursor?.gaps).map(Number));
49
+ for (let index = current; index < target; index += 1) {
50
+ if (options.gaps?.includes(index)) gaps.add(index);
51
+ }
52
+ gaps.delete(target);
53
+ return createTrackingCursor({
54
+ scope: cursor?.scope || "ledger",
55
+ workspaceId: cursor?.workspaceId || "",
56
+ position: Math.max(current, target),
57
+ gaps: [...gaps],
58
+ headRef: options.headRef || cursor?.headRef || "",
59
+ orderRoot: options.orderRoot || cursor?.orderRoot || ""
60
+ });
61
+ }
62
+
63
+ export function verifyTrackingCursor(cursor, { head = {}, orderRoot = "" } = {}) {
64
+ if (!cursor || cursor.protocol !== PACTIUM_PROTOCOL || cursor.cursorType !== "pactium.tracking-cursor") return false;
65
+ if (cursor.headRef && cursor.headRef !== head.headId && cursor.headRef !== head.root && cursor.headRef !== head.rootHash) return false;
66
+ if (cursor.scope === "workspace" && cursor.orderRoot && orderRoot && cursor.orderRoot !== orderRoot) return false;
67
+ return createTrackingCursor(cursor).cursorId === cursor.cursorId;
68
+ }
package/src/http.js ADDED
@@ -0,0 +1,99 @@
1
+ import http from "node:http";
2
+ import { URL } from "node:url";
3
+ import { PACTIUM_PROTOCOL } from "./protocol/constants.js";
4
+ import { createPactium } from "./core/pactium-core.js";
5
+ import { createLicoLiteAspect } from "./aspects/licolite/index.js";
6
+
7
+ export const PACTIUM_HTTP_PROTOCOL = "pactium.v0.2.http";
8
+
9
+ function sendJson(response, statusCode, payload) {
10
+ const body = JSON.stringify(payload, null, 2);
11
+ response.writeHead(statusCode, {
12
+ "content-type": "application/json; charset=utf-8",
13
+ "content-length": Buffer.byteLength(body)
14
+ });
15
+ response.end(body);
16
+ }
17
+
18
+ async function readJson(request) {
19
+ const chunks = [];
20
+ for await (const chunk of request) chunks.push(chunk);
21
+ const text = Buffer.concat(chunks).toString("utf8").trim();
22
+ return text ? JSON.parse(text) : {};
23
+ }
24
+
25
+ async function routeRequest({ pactium, licolite, request, response }) {
26
+ const baseUrl = `http://${request.headers.host || "127.0.0.1"}`;
27
+ const url = new URL(request.url || "/", baseUrl);
28
+ try {
29
+ if (request.method === "GET" && url.pathname === "/health") {
30
+ return sendJson(response, 200, {
31
+ protocol: PACTIUM_HTTP_PROTOCOL,
32
+ coreProtocol: PACTIUM_PROTOCOL,
33
+ ok: true,
34
+ dataDir: pactium.dataDir
35
+ });
36
+ }
37
+ if (request.method === "GET" && url.pathname === "/protocols") {
38
+ return sendJson(response, 200, await pactium.protocolCatalog());
39
+ }
40
+ if (request.method === "POST" && url.pathname === "/intents") {
41
+ return sendJson(response, 200, await pactium.beginOperationIntent(await readJson(request)));
42
+ }
43
+ if (request.method === "POST" && url.pathname === "/outcomes") {
44
+ return sendJson(response, 200, await pactium.appendOperationOutcome(await readJson(request)));
45
+ }
46
+ if (request.method === "POST" && url.pathname === "/operations") {
47
+ return sendJson(response, 200, await pactium.recordOperation(await readJson(request)));
48
+ }
49
+ if (request.method === "POST" && url.pathname === "/licolite/operations") {
50
+ return sendJson(response, 200, await licolite.recordWorkspaceOperation(await readJson(request)));
51
+ }
52
+ if (request.method === "POST" && url.pathname === "/verify/envelope") {
53
+ return sendJson(response, 200, await pactium.verifyEnvelope(await readJson(request)));
54
+ }
55
+ if (request.method === "POST" && url.pathname === "/licolite/verify/envelope") {
56
+ return sendJson(response, 200, await licolite.verifyEnvelope(await readJson(request)));
57
+ }
58
+ return sendJson(response, 404, {
59
+ protocol: PACTIUM_HTTP_PROTOCOL,
60
+ code: "not_found",
61
+ error: "Pactium endpoint not found."
62
+ });
63
+ } catch (error) {
64
+ return sendJson(response, 500, {
65
+ protocol: PACTIUM_HTTP_PROTOCOL,
66
+ code: "pactium_http_error",
67
+ error: error instanceof Error ? error.message : String(error)
68
+ });
69
+ }
70
+ }
71
+
72
+ export function createPactiumHttpServer({ dataDir = "", userDataPath = "", pactium = null, licolite = null } = {}) {
73
+ const core = pactium || createPactium({ dataDir, userDataPath });
74
+ const aspect = licolite || createLicoLiteAspect({ pactium: core, evidencePolicy: "opportunistic" });
75
+ return http.createServer((request, response) => {
76
+ routeRequest({ pactium: core, licolite: aspect, request, response }).catch((error) => {
77
+ sendJson(response, 500, {
78
+ protocol: PACTIUM_HTTP_PROTOCOL,
79
+ code: "pactium_http_error",
80
+ error: error instanceof Error ? error.message : String(error)
81
+ });
82
+ });
83
+ });
84
+ }
85
+
86
+ export async function startPactiumHttpServer({ dataDir = "", userDataPath = "", host = "127.0.0.1", port = 7288 } = {}) {
87
+ const server = createPactiumHttpServer({ dataDir, userDataPath });
88
+ await new Promise((resolve, reject) => {
89
+ server.once("error", reject);
90
+ server.listen(Number(port), host, resolve);
91
+ });
92
+ return {
93
+ protocol: PACTIUM_HTTP_PROTOCOL,
94
+ server,
95
+ host,
96
+ port: Number(port),
97
+ url: `http://${host}:${Number(port)}`
98
+ };
99
+ }