@aarmos/avar-core 1.0.0-rc.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aarmatix LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # @aarmos/avar-core
2
+
3
+ Reference implementation of the [AVAR specification](../../docs/avar/SPEC.md) — canonical JSON, Ed25519 signature verification, hash-chain math, and bundle verification.
4
+
5
+ **Pure.** No DOM references, no Node built-ins, no external dependencies. Runs identically in browsers (WebCrypto) and Node.js 20+ (`globalThis.crypto.subtle`).
6
+
7
+ **Normative.** Consumed by:
8
+ - The Aarmos PWA at `/trust/verify` (browser drop-zone).
9
+ - The `aarmos verify` CLI in [`packages/cli`](../cli/).
10
+ - The internal recorder in `src/lib/avar/` (chain + signature production).
11
+
12
+ All three call the same `verifyBundle()`. Divergence between them is guarded by the golden fixtures in [`test/fixtures/`](./test/fixtures/) — see spec §9.
13
+
14
+ ## API
15
+
16
+ ```ts
17
+ import {
18
+ // Types
19
+ type AvarEntry, type AvarBundle, type VerificationReport,
20
+ // Canonical JSON
21
+ canonicalize,
22
+ // Hash / chain
23
+ sha256Hex, computeEntryHash, computeStepHash,
24
+ GENESIS_PREV_HASH, GENESIS_PREV_STEP_HASH,
25
+ // Signature
26
+ verifySignature, computeDeviceFingerprint,
27
+ // Verification (top-level)
28
+ verifyBundle,
29
+ } from "@avar/core";
30
+ ```
31
+
32
+ ## Spec revision
33
+
34
+ Tracks `avar/1` spec revision `1.0-rc1`. See [`../../docs/avar/CHANGELOG.md`](../../docs/avar/CHANGELOG.md).
@@ -0,0 +1,197 @@
1
+ type TraceStep = ToolStep | TextStep | DecisionStep;
2
+ type ToolStep = {
3
+ kind: "tool";
4
+ ts: number;
5
+ tool: string;
6
+ argsRedacted: unknown;
7
+ outputPreview?: string;
8
+ ok: boolean;
9
+ ms?: number;
10
+ error?: string;
11
+ policyHits?: PolicyHit[];
12
+ prevStepHash?: string;
13
+ stepHash?: string;
14
+ };
15
+ type TextStep = {
16
+ kind: "text";
17
+ ts: number;
18
+ preview: string;
19
+ prevStepHash?: string;
20
+ stepHash?: string;
21
+ };
22
+ type DecisionStep = {
23
+ kind: "decision";
24
+ ts: number;
25
+ tool: string;
26
+ /**
27
+ * Decision label. `ALLOW | MODIFY | DENY | STEP_UP | DEFER` are the
28
+ * classic policy decisions. Minor spec revisions add sources:
29
+ * - `KILL` (Wave 1.2, kill-switch)
30
+ * - `ROTATE | REVOKE` (Wave 1.3, vault)
31
+ * - `FIRST_CONTACT` (Wave 1.4, egress)
32
+ * - future additive values.
33
+ * Verifiers MUST treat unknown decision strings as opaque data.
34
+ */
35
+ decision: string;
36
+ source: string;
37
+ reason?: string;
38
+ note?: string;
39
+ gates?: {
40
+ kind: string;
41
+ source: string;
42
+ }[];
43
+ policyFingerprint?: string;
44
+ policyIssuer?: string;
45
+ bundleState?: "unknown" | "none" | "valid" | "grace" | "invalid";
46
+ killSwitchAt?: boolean;
47
+ /**
48
+ * Kill-switch scope at the time of the decision (Wave 1.2, `avar/1.1`).
49
+ * Present on `decision: "KILL"` entries produced by the kill-switch;
50
+ * MAY appear on other decisions as advisory context. Verifiers treat
51
+ * unknown values as opaque data.
52
+ */
53
+ killScope?: "all" | "writes" | "destructive";
54
+ /** Optional per-step framework tags — see spec §8. */
55
+ frameworks?: string[];
56
+ prevStepHash?: string;
57
+ stepHash?: string;
58
+ };
59
+ type PolicyHit = {
60
+ ruleId: string;
61
+ action: "block" | "downgrade" | "warn" | "allow";
62
+ reason?: string;
63
+ };
64
+ type AvarEntry = {
65
+ id: string;
66
+ ts: number;
67
+ finishedAt?: number;
68
+ workspaceId: string;
69
+ agentId?: string;
70
+ agentName?: string;
71
+ agentEmoji?: string;
72
+ agentColor?: string;
73
+ queryRedacted: string;
74
+ steps: TraceStep[];
75
+ outcome: "ok" | "error" | "aborted";
76
+ provider?: string;
77
+ model?: string;
78
+ inputTokens?: number;
79
+ outputTokens?: number;
80
+ costUsd?: number;
81
+ seed?: number | string;
82
+ systemFingerprint?: string;
83
+ signature?: string;
84
+ devicePubKey?: string;
85
+ deviceFingerprint?: string;
86
+ policyFingerprint?: string;
87
+ policyIssuer?: string;
88
+ parentTraceId?: string | null;
89
+ delegationChain?: {
90
+ agentId: string;
91
+ traceId?: string | null;
92
+ at: number;
93
+ }[];
94
+ prevHash?: string;
95
+ entryHash?: string;
96
+ /**
97
+ * Reserved for multi-seat aggregation (Wave 4). Absent in `avar/1.0`.
98
+ * When present, verifiers treat it as opaque data and include it in
99
+ * canonical JSON per §2.
100
+ */
101
+ seatId?: string;
102
+ /** Optional framework tags — see spec §8. */
103
+ frameworks?: string[];
104
+ } & {
105
+ [k: `x-${string}`]: unknown;
106
+ };
107
+ type BundleManifest = {
108
+ format: "avar/1";
109
+ generatedAt: string;
110
+ producer: {
111
+ name: string;
112
+ version: string;
113
+ };
114
+ entryCount: number;
115
+ entriesSha256: string;
116
+ chainHead: {
117
+ entryHash: string;
118
+ index: number;
119
+ };
120
+ devicePublicKeys: string[];
121
+ };
122
+ type BundlePubKeys = {
123
+ keys: Array<{
124
+ kid: string;
125
+ algorithm: "Ed25519";
126
+ publicKey: string;
127
+ }>;
128
+ };
129
+ type AvarBundle = {
130
+ /** Contents of `SPEC-VERSION` file — MUST equal `"avar/1"`. */
131
+ specVersion: string;
132
+ manifest: BundleManifest;
133
+ /** Raw bytes of `entries.ndjson` — used to verify `entriesSha256`. */
134
+ entriesNdjsonBytes: Uint8Array;
135
+ entries: AvarEntry[];
136
+ pubkeys: BundlePubKeys;
137
+ };
138
+ type VerificationIssue = {
139
+ index: number;
140
+ kind: "spec-version-mismatch" | "manifest-invalid" | "entries-parse-failed" | "entries-sha256-mismatch" | "fingerprint-mismatch" | "signature-invalid" | "signature-unsupported" | "chain-broken" | "partial-step-chain" | "step-chain-broken";
141
+ detail?: string;
142
+ };
143
+ type VerificationReport = {
144
+ formatOk: boolean;
145
+ entriesSha256Ok: boolean;
146
+ chainOk: boolean;
147
+ perStepChainOk: boolean;
148
+ signaturesOk: boolean;
149
+ fingerprintsOk: boolean;
150
+ entryCount: number;
151
+ signedCount: number;
152
+ unsignedCount: number;
153
+ unchainedCount: number;
154
+ chainHead: {
155
+ entryHash: string;
156
+ index: number;
157
+ };
158
+ issues: VerificationIssue[];
159
+ verdict: "valid" | "invalid" | "valid-with-warnings";
160
+ };
161
+
162
+ declare function canonicalize(value: unknown): string;
163
+ /** UTF-8 encode a canonical string for hashing. */
164
+ declare function utf8(s: string): Uint8Array;
165
+
166
+ declare const GENESIS_PREV_HASH = "0000000000000000000000000000000000000000000000000000000000000000";
167
+ declare const GENESIS_PREV_STEP_HASH = "step-genesis:0000000000000000000000000000000000000000000000000000000000000000";
168
+ declare function sha256Hex(input: string | Uint8Array): Promise<string>;
169
+ /**
170
+ * Compute entry hash per spec §4.1.
171
+ *
172
+ * chainBody = canonicalize(entry with { entryHash: undefined,
173
+ * signature: undefined,
174
+ * devicePubKey: undefined })
175
+ *
176
+ * NOTE: signature and devicePubKey are ALSO excluded because they are not
177
+ * part of the signed body (spec §3.2). Including them would make the chain
178
+ * hash change when the signature is added, creating an ordering paradox.
179
+ */
180
+ declare function computeEntryHash(entry: AvarEntry, prevHash: string): Promise<string>;
181
+ /** Compute per-step hash per spec §4.3. */
182
+ declare function computeStepHash(step: TraceStep, prevStepHash: string): Promise<string>;
183
+
184
+ /**
185
+ * Verify an Ed25519 signature over canonical JSON of `signedBody`.
186
+ * Never throws — returns false on any parse/import/verify failure so
187
+ * verifier callers can classify the outcome per spec §6.
188
+ */
189
+ declare function verifySignature(signedBody: unknown, signatureB64u: string, publicKeyB64u: string): Promise<boolean>;
190
+ /** Compute the 12-hex device fingerprint per spec §3.2. */
191
+ declare function computeDeviceFingerprint(publicKeyB64u: string): Promise<string>;
192
+ /** Extract the signed-body view of an AvarEntry per spec §3.2. */
193
+ declare function signedBodyOf(entry: AvarEntry): Omit<AvarEntry, "signature" | "devicePubKey">;
194
+
195
+ declare function verifyBundle(bundle: AvarBundle): Promise<VerificationReport>;
196
+
197
+ export { type AvarBundle, type AvarEntry, type BundleManifest, type BundlePubKeys, type DecisionStep, GENESIS_PREV_HASH, GENESIS_PREV_STEP_HASH, type PolicyHit, type TextStep, type ToolStep, type TraceStep, type VerificationIssue, type VerificationReport, canonicalize, computeDeviceFingerprint, computeEntryHash, computeStepHash, sha256Hex, signedBodyOf, utf8, verifyBundle, verifySignature };
package/dist/index.js ADDED
@@ -0,0 +1,309 @@
1
+ // src/canonicalize.ts
2
+ var NFC = (s) => s.normalize("NFC");
3
+ function encodeString(s) {
4
+ return JSON.stringify(NFC(s));
5
+ }
6
+ function encodeNumber(n) {
7
+ if (!Number.isFinite(n)) {
8
+ throw new Error(`avar-core/canonicalize: non-finite number (${n}) is forbidden.`);
9
+ }
10
+ return JSON.stringify(n);
11
+ }
12
+ function canonicalize(value) {
13
+ if (value === null) return "null";
14
+ if (typeof value === "boolean") return value ? "true" : "false";
15
+ if (typeof value === "number") return encodeNumber(value);
16
+ if (typeof value === "string") return encodeString(value);
17
+ if (typeof value === "undefined") {
18
+ throw new Error("avar-core/canonicalize: undefined is forbidden at value position.");
19
+ }
20
+ if (typeof value === "function" || typeof value === "symbol" || typeof value === "bigint") {
21
+ throw new Error(`avar-core/canonicalize: ${typeof value} is forbidden.`);
22
+ }
23
+ if (Array.isArray(value)) {
24
+ return "[" + value.map((v) => canonicalize(v)).join(",") + "]";
25
+ }
26
+ if (typeof value === "object") {
27
+ const obj = value;
28
+ const keys = [];
29
+ for (const k of Object.keys(obj)) {
30
+ if (obj[k] === void 0) continue;
31
+ keys.push(NFC(k));
32
+ }
33
+ keys.sort();
34
+ const parts = new Array(keys.length);
35
+ for (let i = 0; i < keys.length; i++) {
36
+ const k = keys[i];
37
+ const rawVal = obj[k] ?? findKey(obj, k);
38
+ parts[i] = encodeString(k) + ":" + canonicalize(rawVal);
39
+ }
40
+ return "{" + parts.join(",") + "}";
41
+ }
42
+ throw new Error(`avar-core/canonicalize: unsupported type ${typeof value}.`);
43
+ }
44
+ function findKey(obj, nfcKey) {
45
+ for (const k of Object.keys(obj)) {
46
+ if (NFC(k) === nfcKey) return obj[k];
47
+ }
48
+ return void 0;
49
+ }
50
+ function utf8(s) {
51
+ return new TextEncoder().encode(s);
52
+ }
53
+
54
+ // src/hash.ts
55
+ var GENESIS_PREV_HASH = "0000000000000000000000000000000000000000000000000000000000000000";
56
+ var GENESIS_PREV_STEP_HASH = "step-genesis:0000000000000000000000000000000000000000000000000000000000000000";
57
+ function getSubtle() {
58
+ const c = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
59
+ if (!c || !c.subtle) {
60
+ throw new Error(
61
+ "avar-core: WebCrypto SubtleCrypto is unavailable. Requires Node 20+ or a modern browser."
62
+ );
63
+ }
64
+ return c.subtle;
65
+ }
66
+ async function sha256Hex(input) {
67
+ const bytes = typeof input === "string" ? utf8(input) : input;
68
+ const digest = await getSubtle().digest("SHA-256", bytes);
69
+ return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
70
+ }
71
+ async function computeEntryHash(entry, prevHash) {
72
+ const withPrev = { ...entry, prevHash };
73
+ const {
74
+ entryHash: _e,
75
+ signature: _sig,
76
+ devicePubKey: _pk,
77
+ ...rest
78
+ } = withPrev;
79
+ void _e;
80
+ void _sig;
81
+ void _pk;
82
+ return sha256Hex(prevHash + "\n" + canonicalize(rest));
83
+ }
84
+ async function computeStepHash(step, prevStepHash) {
85
+ const asRec = step;
86
+ const { stepHash: _s, prevStepHash: _p, ...rest } = asRec;
87
+ void _s;
88
+ void _p;
89
+ const withPrev = { ...rest, prevStepHash };
90
+ return sha256Hex(prevStepHash + "\n" + canonicalize(withPrev));
91
+ }
92
+
93
+ // src/signature.ts
94
+ function getSubtle2() {
95
+ const c = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
96
+ if (!c || !c.subtle) {
97
+ throw new Error("avar-core: WebCrypto SubtleCrypto is unavailable.");
98
+ }
99
+ return c.subtle;
100
+ }
101
+ function b64uDecode(s) {
102
+ const b64 = s.replace(/-/g, "+").replace(/_/g, "/") + "===".slice((s.length + 3) % 4);
103
+ const bin = typeof atob === "function" ? atob(b64) : globalThis.Buffer.from(b64, "base64").toString("binary");
104
+ const out = new Uint8Array(bin.length);
105
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
106
+ return out;
107
+ }
108
+ async function verifySignature(signedBody, signatureB64u, publicKeyB64u) {
109
+ try {
110
+ const raw = b64uDecode(publicKeyB64u);
111
+ const key = await getSubtle2().importKey("raw", raw, "Ed25519", false, [
112
+ "verify"
113
+ ]);
114
+ const sig = b64uDecode(signatureB64u);
115
+ const bytes = utf8(canonicalize(signedBody));
116
+ return await getSubtle2().verify(
117
+ "Ed25519",
118
+ key,
119
+ sig,
120
+ bytes
121
+ );
122
+ } catch {
123
+ return false;
124
+ }
125
+ }
126
+ async function computeDeviceFingerprint(publicKeyB64u) {
127
+ const hex = await sha256Hex(utf8(publicKeyB64u));
128
+ return hex.slice(0, 12);
129
+ }
130
+ function signedBodyOf(entry) {
131
+ const { signature: _sig, devicePubKey: _pk, ...rest } = entry;
132
+ void _sig;
133
+ void _pk;
134
+ return rest;
135
+ }
136
+
137
+ // src/verify.ts
138
+ var SPEC_VERSION = "avar/1";
139
+ async function verifyBundle(bundle) {
140
+ const issues = [];
141
+ let formatOk = true;
142
+ const specV = bundle.specVersion.trim();
143
+ if (specV !== SPEC_VERSION) {
144
+ formatOk = false;
145
+ issues.push({
146
+ index: -1,
147
+ kind: "spec-version-mismatch",
148
+ detail: `Expected "${SPEC_VERSION}", got "${specV}".`
149
+ });
150
+ }
151
+ if (bundle.manifest.format !== SPEC_VERSION) {
152
+ formatOk = false;
153
+ issues.push({
154
+ index: -1,
155
+ kind: "manifest-invalid",
156
+ detail: `manifest.format expected "${SPEC_VERSION}", got "${bundle.manifest.format}".`
157
+ });
158
+ }
159
+ const actualSha = await sha256Hex(bundle.entriesNdjsonBytes);
160
+ const entriesSha256Ok = actualSha === bundle.manifest.entriesSha256;
161
+ if (!entriesSha256Ok) {
162
+ issues.push({
163
+ index: -1,
164
+ kind: "entries-sha256-mismatch",
165
+ detail: `Expected ${bundle.manifest.entriesSha256}, got ${actualSha}.`
166
+ });
167
+ }
168
+ const entries = bundle.entries;
169
+ const entryCount = entries.length;
170
+ let signaturesOk = true;
171
+ let fingerprintsOk = true;
172
+ let signedCount = 0;
173
+ let unsignedCount = 0;
174
+ for (let i = 0; i < entries.length; i++) {
175
+ const e = entries[i];
176
+ const hasSig = typeof e.signature === "string" && typeof e.devicePubKey === "string";
177
+ if (!hasSig) {
178
+ unsignedCount++;
179
+ continue;
180
+ }
181
+ signedCount++;
182
+ if (typeof e.deviceFingerprint === "string") {
183
+ const expected = await computeDeviceFingerprint(e.devicePubKey);
184
+ if (expected !== e.deviceFingerprint) {
185
+ fingerprintsOk = false;
186
+ issues.push({
187
+ index: i,
188
+ kind: "fingerprint-mismatch",
189
+ detail: `Expected ${expected}, got ${e.deviceFingerprint}.`
190
+ });
191
+ }
192
+ }
193
+ const ok = await verifySignature(signedBodyOf(e), e.signature, e.devicePubKey);
194
+ if (!ok) {
195
+ signaturesOk = false;
196
+ issues.push({ index: i, kind: "signature-invalid" });
197
+ }
198
+ }
199
+ let chainOk = true;
200
+ let unchainedCount = 0;
201
+ let expectedPrev = GENESIS_PREV_HASH;
202
+ for (let i = 0; i < entries.length; i++) {
203
+ const e = entries[i];
204
+ const isLegacyUnchained = !e.entryHash || !e.prevHash;
205
+ if (isLegacyUnchained) {
206
+ unchainedCount++;
207
+ expectedPrev = GENESIS_PREV_HASH;
208
+ continue;
209
+ }
210
+ if (e.prevHash !== expectedPrev) {
211
+ chainOk = false;
212
+ issues.push({
213
+ index: i,
214
+ kind: "chain-broken",
215
+ detail: `prevHash mismatch at entry ${i}.`
216
+ });
217
+ }
218
+ const recomputed = await computeEntryHash(e, e.prevHash);
219
+ if (recomputed !== e.entryHash) {
220
+ chainOk = false;
221
+ issues.push({
222
+ index: i,
223
+ kind: "chain-broken",
224
+ detail: `entryHash mismatch at entry ${i} (body modified after signing).`
225
+ });
226
+ }
227
+ expectedPrev = e.entryHash;
228
+ }
229
+ const perStepChainOk = await verifyAllStepChains(entries, issues);
230
+ const chainHead = computeChainHead(entries);
231
+ const anyHardFail = !formatOk || !entriesSha256Ok || !chainOk || !perStepChainOk || !signaturesOk || !fingerprintsOk;
232
+ const verdict = anyHardFail ? "invalid" : unsignedCount > 0 || unchainedCount > 0 ? "valid-with-warnings" : "valid";
233
+ return {
234
+ formatOk,
235
+ entriesSha256Ok,
236
+ chainOk,
237
+ perStepChainOk,
238
+ signaturesOk,
239
+ fingerprintsOk,
240
+ entryCount,
241
+ signedCount,
242
+ unsignedCount,
243
+ unchainedCount,
244
+ chainHead,
245
+ issues,
246
+ verdict
247
+ };
248
+ }
249
+ async function verifyAllStepChains(entries, issues) {
250
+ let ok = true;
251
+ for (let i = 0; i < entries.length; i++) {
252
+ const e = entries[i];
253
+ if (!Array.isArray(e.steps) || e.steps.length === 0) continue;
254
+ const anyChained = e.steps.some(hasChainFields);
255
+ const allChained = e.steps.every(hasChainFields);
256
+ if (anyChained && !allChained) {
257
+ ok = false;
258
+ issues.push({ index: i, kind: "partial-step-chain" });
259
+ continue;
260
+ }
261
+ if (!anyChained) continue;
262
+ let prev = "step-genesis:0000000000000000000000000000000000000000000000000000000000000000";
263
+ for (let j = 0; j < e.steps.length; j++) {
264
+ const s = e.steps[j];
265
+ if (s.prevStepHash !== prev) {
266
+ ok = false;
267
+ issues.push({
268
+ index: i,
269
+ kind: "step-chain-broken",
270
+ detail: `entry ${i} step ${j}: prevStepHash mismatch.`
271
+ });
272
+ }
273
+ const recomputed = await computeStepHash(s, s.prevStepHash);
274
+ if (recomputed !== s.stepHash) {
275
+ ok = false;
276
+ issues.push({
277
+ index: i,
278
+ kind: "step-chain-broken",
279
+ detail: `entry ${i} step ${j}: stepHash mismatch (step body modified).`
280
+ });
281
+ }
282
+ prev = s.stepHash;
283
+ }
284
+ }
285
+ return ok;
286
+ }
287
+ function hasChainFields(s) {
288
+ return typeof s.prevStepHash === "string" && typeof s.stepHash === "string";
289
+ }
290
+ function computeChainHead(entries) {
291
+ for (let i = entries.length - 1; i >= 0; i--) {
292
+ const e = entries[i];
293
+ if (e.entryHash) return { entryHash: e.entryHash, index: i };
294
+ }
295
+ return { entryHash: "", index: -1 };
296
+ }
297
+ export {
298
+ GENESIS_PREV_HASH,
299
+ GENESIS_PREV_STEP_HASH,
300
+ canonicalize,
301
+ computeDeviceFingerprint,
302
+ computeEntryHash,
303
+ computeStepHash,
304
+ sha256Hex,
305
+ signedBodyOf,
306
+ utf8,
307
+ verifyBundle,
308
+ verifySignature
309
+ };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@aarmos/avar-core",
3
+ "version": "1.0.0-rc.1",
4
+ "description": "Reference implementation of the AVAR (Aarmos Verifiable Action Record) spec — canonical JSON, Ed25519 signature verification, hash-chain math, and bundle verification. Pure, zero-dep, browser + Node.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "sideEffects": false,
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "keywords": [
25
+ "aarmos",
26
+ "avar",
27
+ "audit",
28
+ "hash-chain",
29
+ "ed25519",
30
+ "verifier"
31
+ ],
32
+ "license": "MIT",
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/aarmatix/aarmos.git",
39
+ "directory": "packages/avar-core"
40
+ },
41
+ "devDependencies": {
42
+ "tsup": "^8.3.0",
43
+ "typescript": "^5.6.2"
44
+ }
45
+ }