@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 +42 -0
- package/dist/neutral/finalizedHeadSource.d.ts +36 -0
- package/dist/neutral/finalizedHeadSource.d.ts.map +1 -0
- package/dist/neutral/index.d.ts +3 -0
- package/dist/neutral/index.d.ts.map +1 -0
- package/dist/neutral/index.mjs +22 -0
- package/dist/neutral/index.mjs.map +7 -0
- package/package.json +61 -0
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 @@
|
|
|
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
|
+
}
|