@xyo-network/event-kit-xl1 0.0.1

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 ADDED
@@ -0,0 +1,42 @@
1
+ # `@xyo-network/event-kit-xl1`
2
+
3
+ XL1 chain adapters for Event Kit.
4
+
5
+ - `createXl1FinalizedHeadSource` — reads the finalized XL1 head for publisher
6
+ filters and for the receiver's grant-freshness check
7
+
8
+ ```ts
9
+ const gateway = await new GatewayBuilder().name('local').rpcUrl(RPC).build()
10
+ const headSource = createXl1FinalizedHeadSource({ viewer: gateway.connection.viewer })
11
+ ```
12
+
13
+ The result satisfies both the publisher's `FinalizedHeadSource` and the
14
+ receiver's `TrustedFinalizedHeadSource` — structurally identical ports, declared
15
+ locally so this package depends on neither.
16
+
17
+ ## Why it validates rather than forwards
18
+
19
+ Both sides treat this number as trusted: the publisher decides which range to
20
+ emit, and the gate computes grant lag from it. So the reading is checked, not
21
+ passed through.
22
+
23
+ - A head that is not a nonnegative JSON safe integer is rejected here, rather
24
+ than surfacing later as an opaque `grant-view-invalid`.
25
+ - A head lower than one already observed is rejected by default. Finalized
26
+ heights are immutable, so a regression means the endpoint was rolled back,
27
+ swapped, or is lying — failing closed beats admitting against a rewound view.
28
+ Disable with `rejectRegression: false` only when a caller genuinely tolerates
29
+ it.
30
+
31
+ ## Evidence
32
+
33
+ Offline specs cover the validation and regression guard. Live specs under
34
+ `src/spec/api-local/` run against a real local XL1 chain booted by the
35
+ `api-local` vitest project: the head reads conforming, advances through real
36
+ block production, and never regresses.
37
+
38
+ Run them with `pnpm test:live` from the repository root. They are opt-in — the
39
+ default suite stays offline.
40
+
41
+ This qualifies the adapter against a local dev chain, which uses simplified dev
42
+ consensus and in-memory storage. It is not Sequence or mainnet qualification.
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Structural shape shared by the publisher's `FinalizedHeadSource` and the
3
+ * receiver's `TrustedFinalizedHeadSource`. Declared here so this adapter depends
4
+ * on neither package.
5
+ */
6
+ export interface FinalizedHeadReader {
7
+ headNumber: () => Promise<number>;
8
+ }
9
+ /** The slice of the XL1 viewer this adapter reads. */
10
+ export interface Xl1FinalizationViewer {
11
+ readonly finalization: {
12
+ headNumber: () => Promise<number>;
13
+ };
14
+ }
15
+ export interface Xl1FinalizedHeadSourceOptions {
16
+ /**
17
+ * Reject a head lower than one already observed.
18
+ *
19
+ * Finalized heights are immutable, so a regression means the endpoint was
20
+ * rolled back, swapped, or is lying. Defaults to `true`: admission and cursor
21
+ * decisions both treat this value as trusted, and failing closed is safer than
22
+ * admitting against a rewound view.
23
+ */
24
+ readonly rejectRegression?: boolean;
25
+ readonly viewer: Xl1FinalizationViewer;
26
+ }
27
+ /**
28
+ * Reads the finalized XL1 head for publisher filters and receiver grant
29
+ * freshness.
30
+ *
31
+ * The value is validated rather than forwarded: D-002 requires nonnegative JSON
32
+ * safe integers for every head input, and a non-conforming reading is rejected
33
+ * here instead of surfacing later as an opaque `grant-view-invalid`.
34
+ */
35
+ export declare function createXl1FinalizedHeadSource(options: Xl1FinalizedHeadSourceOptions): FinalizedHeadReader;
36
+ //# sourceMappingURL=finalizedHeadSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finalizedHeadSource.d.ts","sourceRoot":"","sources":["../../src/finalizedHeadSource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAClC;AAED,sDAAsD;AACtD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,YAAY,EAAE;QAAE,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;KAAE,CAAA;CAC7D;AAED,MAAM,WAAW,6BAA6B;IAC5C;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAA;CACvC;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,mBAAmB,CAiBrB"}
@@ -0,0 +1,3 @@
1
+ export type { FinalizedHeadReader, Xl1FinalizationViewer, Xl1FinalizedHeadSourceOptions, } from './finalizedHeadSource.ts';
2
+ export { createXl1FinalizedHeadSource } from './finalizedHeadSource.ts';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,mBAAmB,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,22 @@
1
+ // src/finalizedHeadSource.ts
2
+ function createXl1FinalizedHeadSource(options) {
3
+ const rejectRegression = options.rejectRegression ?? true;
4
+ let highest = -1;
5
+ return {
6
+ async headNumber() {
7
+ const head = await options.viewer.finalization.headNumber();
8
+ if (typeof head !== "number" || !Number.isSafeInteger(head) || head < 0) {
9
+ throw new TypeError(`XL1 finalized head must be a nonnegative safe integer, received ${String(head)}`);
10
+ }
11
+ if (rejectRegression && head < highest) {
12
+ throw new RangeError(`XL1 finalized head regressed from ${highest} to ${head}`);
13
+ }
14
+ if (head > highest) highest = head;
15
+ return head;
16
+ }
17
+ };
18
+ }
19
+ export {
20
+ createXl1FinalizedHeadSource
21
+ };
22
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/finalizedHeadSource.ts"],
4
+ "sourcesContent": ["/**\n * Structural shape shared by the publisher's `FinalizedHeadSource` and the\n * receiver's `TrustedFinalizedHeadSource`. Declared here so this adapter depends\n * on neither package.\n */\nexport interface FinalizedHeadReader {\n headNumber: () => Promise<number>\n}\n\n/** The slice of the XL1 viewer this adapter reads. */\nexport interface Xl1FinalizationViewer {\n readonly finalization: { headNumber: () => Promise<number> }\n}\n\nexport interface Xl1FinalizedHeadSourceOptions {\n /**\n * Reject a head lower than one already observed.\n *\n * Finalized heights are immutable, so a regression means the endpoint was\n * rolled back, swapped, or is lying. Defaults to `true`: admission and cursor\n * decisions both treat this value as trusted, and failing closed is safer than\n * admitting against a rewound view.\n */\n readonly rejectRegression?: boolean\n readonly viewer: Xl1FinalizationViewer\n}\n\n/**\n * Reads the finalized XL1 head for publisher filters and receiver grant\n * freshness.\n *\n * The value is validated rather than forwarded: D-002 requires nonnegative JSON\n * safe integers for every head input, and a non-conforming reading is rejected\n * here instead of surfacing later as an opaque `grant-view-invalid`.\n */\nexport function createXl1FinalizedHeadSource(\n options: Xl1FinalizedHeadSourceOptions,\n): FinalizedHeadReader {\n const rejectRegression = options.rejectRegression ?? true\n let highest = -1\n\n return {\n async headNumber(): Promise<number> {\n const head = await options.viewer.finalization.headNumber()\n if (typeof head !== 'number' || !Number.isSafeInteger(head) || head < 0) {\n throw new TypeError(`XL1 finalized head must be a nonnegative safe integer, received ${String(head)}`)\n }\n if (rejectRegression && head < highest) {\n throw new RangeError(`XL1 finalized head regressed from ${highest} to ${head}`)\n }\n if (head > highest) highest = head\n return head\n },\n }\n}\n"],
5
+ "mappings": ";AAmCO,SAAS,6BACd,SACqB;AACrB,QAAM,mBAAmB,QAAQ,oBAAoB;AACrD,MAAI,UAAU;AAEd,SAAO;AAAA,IACL,MAAM,aAA8B;AAClC,YAAM,OAAO,MAAM,QAAQ,OAAO,aAAa,WAAW;AAC1D,UAAI,OAAO,SAAS,YAAY,CAAC,OAAO,cAAc,IAAI,KAAK,OAAO,GAAG;AACvE,cAAM,IAAI,UAAU,mEAAmE,OAAO,IAAI,CAAC,EAAE;AAAA,MACvG;AACA,UAAI,oBAAoB,OAAO,SAAS;AACtC,cAAM,IAAI,WAAW,qCAAqC,OAAO,OAAO,IAAI,EAAE;AAAA,MAChF;AACA,UAAI,OAAO,QAAS,WAAU;AAC9B,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@xyo-network/event-kit-xl1",
3
+ "version": "0.0.1",
4
+ "description": "XL1 chain adapters for Event Kit (finalized head source)",
5
+ "keywords": [
6
+ "xyo",
7
+ "xl1",
8
+ "event-kit",
9
+ "typescript"
10
+ ],
11
+ "bugs": {
12
+ "url": "https://github.com/XYOracleNetwork/event-kit/issues"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/XYOracleNetwork/event-kit.git",
17
+ "directory": "packages/xl1"
18
+ },
19
+ "license": "UNLICENSED",
20
+ "sideEffects": false,
21
+ "type": "module",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/neutral/index.d.ts",
25
+ "default": "./dist/neutral/index.mjs"
26
+ },
27
+ "./package.json": "./package.json",
28
+ "./README.md": "./README.md"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
34
+ "devDependencies": {
35
+ "@ariestools/lib-neutral": "~9.1.0",
36
+ "@ariestools/sdk": "~8.1.9",
37
+ "@ariestools/toolchain": "~9.1.0",
38
+ "@ariestools/tsconfig": "~9.1.0",
39
+ "@opentelemetry/api": "~1.9.1",
40
+ "@xyo-network/sdk": "~7.2.3",
41
+ "@xyo-network/sdk-protocol": "~7.2.4",
42
+ "@xyo-network/xl1-sdk": "~5.3.1",
43
+ "async-mutex": "~0.5.0",
44
+ "eslint": "~10.8.1",
45
+ "eslint-import-resolver-typescript": "~4.4.5",
46
+ "ethers": "~6.17.0",
47
+ "typescript": "~6.0.3",
48
+ "vite": "~8.2.1",
49
+ "vitest": "~4.1.11",
50
+ "zod": "~4.4.3"
51
+ },
52
+ "engines": {
53
+ "node": ">=22"
54
+ },
55
+ "publishConfig": {
56
+ "access": "restricted"
57
+ },
58
+ "scripts": {
59
+ "test": "vitest run"
60
+ }
61
+ }