axis-platform-sdk 0.2.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -2,7 +2,22 @@
2
2
 
3
3
  All notable changes to `axis-platform-sdk`. Pre-release; not yet published to npm.
4
4
 
5
- ## [0.2.0] — 2026-06-25 (unreleased)
5
+ ## [0.2.1] — 2026-06-25
6
+
7
+ ### Added — TypeScript declarations
8
+
9
+ - The package now ships `.d.ts` types (it stays authored in plain JS). A
10
+ complete `src/index.d.ts` covers the full main-entry surface (verify,
11
+ authorizer, scope, gate, client, ledger, blocklist, reportback); each subpath
12
+ export (`./scope`, `./gate`, `./authorizer`, `./ledger`, `./blocklist`,
13
+ `./reportback`) re-exports its slice. `package.json` exposes them via a
14
+ top-level `types` field and per-subpath `types` conditions in `exports`.
15
+ - This lets TypeScript consumers (e.g. Owyhee "The Door", swapping its vendored
16
+ copy for the npm dependency) drop their hand-maintained declaration and get
17
+ types from the package. Verified by a clean-room install + strict `tsc` of a
18
+ consumer importing from the root and a subpath.
19
+
20
+ ## [0.2.0] — 2026-06-25
6
21
 
7
22
  First npm publish + public repo. Adds the stateful half (ledger, blocklist,
8
23
  reputation report-back) and reconciles it with Owyhee "The Door" (governor#27)
package/README.md CHANGED
@@ -16,7 +16,7 @@ The registry already does the hard part. `GET /verify?token=<AIT>` checks the si
16
16
  npm install axis-platform-sdk
17
17
  ```
18
18
 
19
- Zero dependencies. Runs in Node 20+, Cloudflare Workers, and modern browsers.
19
+ Zero dependencies. Runs in Node 20+, Cloudflare Workers, and modern browsers. Ships TypeScript declarations (the package is authored in plain JS).
20
20
 
21
21
  ## Quickstart — gate a Worker endpoint
22
22
 
package/package.json CHANGED
@@ -1,17 +1,18 @@
1
1
  {
2
2
  "name": "axis-platform-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Platform-side SDK for the AXIS protocol. The verifier/'bouncer' side: when an AXIS agent shows up at your platform, verify its identity + delegation + scope and decide whether to accept, scope, or boot it. Zero runtime dependencies; runs in Node 20+, Cloudflare Workers, and modern browsers.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
+ "types": "./src/index.d.ts",
7
8
  "exports": {
8
- ".": "./src/index.js",
9
- "./scope": "./src/scope.js",
10
- "./gate": "./src/gate.js",
11
- "./authorizer": "./src/authorizer.js",
12
- "./ledger": "./src/ledger.js",
13
- "./blocklist": "./src/blocklist.js",
14
- "./reportback": "./src/reportback.js"
9
+ ".": { "types": "./src/index.d.ts", "default": "./src/index.js" },
10
+ "./scope": { "types": "./src/scope.d.ts", "default": "./src/scope.js" },
11
+ "./gate": { "types": "./src/gate.d.ts", "default": "./src/gate.js" },
12
+ "./authorizer": { "types": "./src/authorizer.d.ts", "default": "./src/authorizer.js" },
13
+ "./ledger": { "types": "./src/ledger.d.ts", "default": "./src/ledger.js" },
14
+ "./blocklist": { "types": "./src/blocklist.d.ts", "default": "./src/blocklist.js" },
15
+ "./reportback": { "types": "./src/reportback.d.ts", "default": "./src/reportback.js" }
15
16
  },
16
17
  "scripts": {
17
18
  "test": "node --test test/scope.test.js test/verify.test.js test/authorizer.test.js test/ledger.test.js test/blocklist.test.js test/reportback.test.js"
@@ -0,0 +1 @@
1
+ export { SwitchAuthorizer, SwitchPolicy, GateConfig, AuthorizeContext, Verdict } from './index.js';
@@ -0,0 +1,9 @@
1
+ export {
2
+ Blocklist,
3
+ MemoryBlocklistStore,
4
+ gatedWithBlocklist,
5
+ BlockKind,
6
+ BlockMeta,
7
+ BlockEntry,
8
+ BlocklistStore,
9
+ } from './index.js';
package/src/gate.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { aitGate, extractToken, denialResponse, VerifyOptions, Verdict } from './index.js';
package/src/index.d.ts ADDED
@@ -0,0 +1,288 @@
1
+ // Type declarations for axis-platform-sdk (the package is authored in plain JS).
2
+ // Covers the full main-entry surface. Subpath entry points (./scope, ./gate,
3
+ // ./authorizer, ./ledger, ./blocklist, ./reportback) re-export their slice of
4
+ // this declaration. Keep in sync with src/*.js.
5
+
6
+ export type Tier = 'email' | 'domain' | 'verified' | 'kyb_individual' | 'kyb_organization';
7
+
8
+ // --- verify -----------------------------------------------------------------
9
+
10
+ /** The single structured verdict verifyAgent / SwitchAuthorizer.authorize return. */
11
+ export interface Verdict {
12
+ accepted: boolean;
13
+ code?: string;
14
+ reason?: string;
15
+ agent_id?: string;
16
+ operator_id?: string;
17
+ effective_scope?: string[];
18
+ delegation_valid?: boolean;
19
+ tier?: Tier | null;
20
+ expires_at?: number | null;
21
+ /** present on an insufficient_scope denial */
22
+ missing?: string[];
23
+ }
24
+
25
+ export interface VerifyOptions {
26
+ audience?: string;
27
+ requireScopes?: string[];
28
+ minTier?: Tier;
29
+ blockedOperators?: string[];
30
+ approvedOperators?: string[] | null;
31
+ registryBaseUrl?: string;
32
+ fetchImpl?: typeof fetch;
33
+ }
34
+
35
+ export function verifyAgent(token: string, opts?: VerifyOptions): Promise<Verdict>;
36
+
37
+ // --- authorizer (the pluggable gate engine; SwitchAuthorizer = free tier) ----
38
+
39
+ export interface GateConfig {
40
+ enabled?: boolean;
41
+ minTier?: Tier;
42
+ requireScopes?: string[];
43
+ blockedOperators?: string[];
44
+ approvedOperators?: string[] | null;
45
+ }
46
+
47
+ /** Exactly what the "Door policy" screen edits + saves (door_policy.policy_json). */
48
+ export interface SwitchPolicy {
49
+ audience?: string;
50
+ defaultAllow?: boolean;
51
+ blockedOperators?: string[];
52
+ gates?: Record<string, GateConfig>;
53
+ }
54
+
55
+ export interface AuthorizeContext {
56
+ registryBaseUrl?: string;
57
+ fetchImpl?: typeof fetch;
58
+ }
59
+
60
+ export class SwitchAuthorizer {
61
+ constructor(policy?: SwitchPolicy);
62
+ policy: SwitchPolicy;
63
+ optsForGate(gateId: string): VerifyOptions;
64
+ authorize(token: string, gateId: string, ctx?: AuthorizeContext): Promise<Verdict>;
65
+ gate(gateId: string, opts?: AuthorizeContext): (request: Request) => Promise<Verdict>;
66
+ }
67
+
68
+ // --- scope ------------------------------------------------------------------
69
+
70
+ export function scopeCovers(granted: string, required: string): boolean;
71
+ /** Returns { ok, missing } — NOT a boolean. */
72
+ export function coversAll(granted: string[], required: string[]): { ok: boolean; missing: string[] };
73
+
74
+ // --- gate (Worker request middleware) ---------------------------------------
75
+
76
+ export function aitGate(opts: VerifyOptions): (request: Request) => Promise<Verdict>;
77
+ export function extractToken(request: Request): string | null;
78
+ export function denialResponse(verdict: Verdict): Response;
79
+
80
+ // --- client (registry-call helpers) -----------------------------------------
81
+
82
+ export interface EnrichResult {
83
+ agent_id: string;
84
+ did?: string | null;
85
+ display_name?: string | null;
86
+ tier?: Tier | null;
87
+ operator_id?: string;
88
+ status?: string | null;
89
+ raw?: unknown;
90
+ [k: string]: unknown;
91
+ }
92
+ export function enrich(
93
+ agentId: string,
94
+ token: string | null,
95
+ opts?: { registryBaseUrl?: string; fetchImpl?: typeof fetch },
96
+ ): Promise<EnrichResult>;
97
+
98
+ export function registryGet(
99
+ base: string,
100
+ path: string,
101
+ opts?: { headers?: Record<string, string>; fetchImpl?: typeof fetch },
102
+ ): Promise<{ status: number; body: any }>;
103
+
104
+ /** Read an operator's verification tier from a resolved agent record. */
105
+ export function pickTier(agentBody: any): Tier | null;
106
+
107
+ /** Load a platform's published `/.well-known/axis-access` door policy. */
108
+ export function loadAccessPolicy(
109
+ platformBaseUrl: string,
110
+ opts?: { fetchImpl?: typeof fetch },
111
+ ): Promise<SwitchPolicy & Record<string, unknown>>;
112
+
113
+ export function decodeAitPayload(token: string): Record<string, unknown> | null;
114
+ export const TIER_RANK: Record<string, number>;
115
+ export const DEFAULT_REGISTRY: string;
116
+
117
+ // --- ledger (the "who showed up" arrival record) ----------------------------
118
+
119
+ export type ArrivalDecision = 'auto_allow' | 'denied' | 'held' | 'approved' | 'booted';
120
+
121
+ /**
122
+ * One arrival record. Byte-compatible with Owyhee "The Door"'s `arrivals`
123
+ * columns / `ArrivalRecord` (minus the adapter's own id/org_id PKs).
124
+ * `created_at` is epoch ms.
125
+ */
126
+ export interface ArrivalEntry {
127
+ agent_id: string | null;
128
+ operator_id: string | null;
129
+ created_at: number;
130
+ tier: Tier | null;
131
+ delegation_valid: boolean;
132
+ effective_scope: string[];
133
+ gate_id: string | null;
134
+ requested_action: string | null;
135
+ display_name: string | null;
136
+ decision: ArrivalDecision;
137
+ reason: string | null;
138
+ audience: string | null;
139
+ }
140
+
141
+ /** Optional fields stamped onto an entry alongside the verdict. */
142
+ export interface RecordFields {
143
+ audience?: string;
144
+ gate_id?: string;
145
+ requested_action?: string;
146
+ display_name?: string;
147
+ decision?: ArrivalDecision;
148
+ created_at?: number;
149
+ }
150
+
151
+ export function recordEntry(verdict: Verdict, fields?: RecordFields): ArrivalEntry;
152
+
153
+ /** The pluggable ledger store port (the default is in-memory). */
154
+ export interface LedgerStore {
155
+ append(entry: ArrivalEntry): Promise<void>;
156
+ recent(opts?: { limit?: number }): Promise<ArrivalEntry[]>;
157
+ byOperator(operatorId: string, opts?: { limit?: number }): Promise<ArrivalEntry[]>;
158
+ }
159
+
160
+ export class MemoryLedgerStore implements LedgerStore {
161
+ constructor(opts?: { max?: number });
162
+ append(entry: ArrivalEntry): Promise<void>;
163
+ recent(opts?: { limit?: number }): Promise<ArrivalEntry[]>;
164
+ byOperator(operatorId: string, opts?: { limit?: number }): Promise<ArrivalEntry[]>;
165
+ }
166
+
167
+ export class AccessLedger {
168
+ constructor(opts?: { store?: LedgerStore });
169
+ store: LedgerStore;
170
+ record(verdict: Verdict, fields?: RecordFields): Promise<ArrivalEntry>;
171
+ recent(opts?: { limit?: number }): Promise<ArrivalEntry[]>;
172
+ byOperator(operatorId: string, opts?: { limit?: number }): Promise<ArrivalEntry[]>;
173
+ }
174
+
175
+ export function loggedGate(
176
+ gate: (request: Request) => Promise<Verdict>,
177
+ ledger: AccessLedger,
178
+ fields?: RecordFields,
179
+ ): (request: Request) => Promise<Verdict>;
180
+
181
+ // --- blocklist (runtime block/allow, by operator AND agent) -----------------
182
+
183
+ export type BlockKind = 'operator' | 'agent';
184
+ export interface BlockMeta { reason?: string; created_at?: number; [k: string]: unknown; }
185
+ export interface BlockEntry { id: string; meta: BlockMeta; }
186
+
187
+ /** The pluggable block-store port (the default is in-memory). */
188
+ export interface BlocklistStore {
189
+ add(kind: BlockKind, id: string, meta?: BlockMeta): Promise<void>;
190
+ remove(kind: BlockKind, id: string): Promise<void>;
191
+ has(kind: BlockKind, id: string): Promise<boolean>;
192
+ list(kind: BlockKind): Promise<BlockEntry[]>;
193
+ }
194
+
195
+ export class MemoryBlocklistStore implements BlocklistStore {
196
+ add(kind: BlockKind, id: string, meta?: BlockMeta): Promise<void>;
197
+ remove(kind: BlockKind, id: string): Promise<void>;
198
+ has(kind: BlockKind, id: string): Promise<boolean>;
199
+ list(kind: BlockKind): Promise<BlockEntry[]>;
200
+ }
201
+
202
+ export class Blocklist {
203
+ constructor(opts?: { store?: BlocklistStore });
204
+ store: BlocklistStore;
205
+ blockOperator(operatorId: string, reason?: string): Promise<void>;
206
+ blockAgent(agentId: string, reason?: string): Promise<void>;
207
+ unblockOperator(operatorId: string): Promise<void>;
208
+ unblockAgent(agentId: string): Promise<void>;
209
+ isOperatorBlocked(operatorId: string): Promise<boolean>;
210
+ isAgentBlocked(agentId: string): Promise<boolean>;
211
+ blockedOperatorIds(): Promise<string[]>;
212
+ listOperators(): Promise<BlockEntry[]>;
213
+ listAgents(): Promise<BlockEntry[]>;
214
+ verifyOpts(): Promise<{ blockedOperators: string[] }>;
215
+ checkVerdict(verdict: Verdict): Promise<Verdict>;
216
+ }
217
+
218
+ export function gatedWithBlocklist(
219
+ gate: (request: Request) => Promise<Verdict>,
220
+ blocklist: Blocklist,
221
+ ): (request: Request) => Promise<Verdict>;
222
+
223
+ // --- reportback (sign + emit a negative Trust Attestation) ------------------
224
+
225
+ export interface TrustAttestation {
226
+ axis_version: string;
227
+ type: 'TrustAttestation';
228
+ id: string;
229
+ issued_by: string;
230
+ subject: string;
231
+ issued_at: string;
232
+ scope: string;
233
+ statement: string;
234
+ signature?: string;
235
+ }
236
+
237
+ export interface KeyStore {
238
+ load(): Promise<JsonWebKey | null>;
239
+ save(jwk: JsonWebKey): Promise<void>;
240
+ }
241
+
242
+ export class MemoryKeyStore implements KeyStore {
243
+ load(): Promise<JsonWebKey | null>;
244
+ save(jwk: JsonWebKey): Promise<void>;
245
+ }
246
+
247
+ export function getPlatformKey(
248
+ opts?: { keyStore?: KeyStore },
249
+ ): Promise<{ privateKey: CryptoKey; publicKeyB64: string; jwk: JsonWebKey }>;
250
+
251
+ export function buildAttestation(args: {
252
+ platformId: string;
253
+ agentId: string;
254
+ category?: string;
255
+ reason?: string;
256
+ issuedAt?: string;
257
+ }): TrustAttestation;
258
+
259
+ export function signAttestation(attestation: TrustAttestation, privateKey: CryptoKey): Promise<TrustAttestation>;
260
+ export function verifyAttestation(attestation: TrustAttestation, publicKeyB64: string): Promise<boolean>;
261
+
262
+ export interface ReportArgs {
263
+ platformId: string;
264
+ agentId: string;
265
+ operatorId?: string;
266
+ category: string;
267
+ reason: string;
268
+ }
269
+ export interface ReportResult {
270
+ sent: boolean;
271
+ status?: number;
272
+ attestation?: TrustAttestation;
273
+ reason?: string;
274
+ }
275
+ export interface ReportOptions {
276
+ reputationUrl?: string | null;
277
+ keyStore?: KeyStore;
278
+ fetchImpl?: typeof fetch;
279
+ }
280
+
281
+ export function reportFlag(args: ReportArgs, opts?: ReportOptions): Promise<ReportResult>;
282
+ export function blockAndReport(
283
+ blocklist: Blocklist,
284
+ args: ReportArgs,
285
+ opts?: ReportOptions,
286
+ ): Promise<{ blocked: boolean; agent_id: string; report: ReportResult }>;
287
+
288
+ export const DEFAULT_REPUTATION_URL: string | null;
@@ -0,0 +1,10 @@
1
+ export {
2
+ AccessLedger,
3
+ MemoryLedgerStore,
4
+ loggedGate,
5
+ recordEntry,
6
+ ArrivalEntry,
7
+ ArrivalDecision,
8
+ RecordFields,
9
+ LedgerStore,
10
+ } from './index.js';
@@ -0,0 +1,15 @@
1
+ export {
2
+ reportFlag,
3
+ blockAndReport,
4
+ getPlatformKey,
5
+ buildAttestation,
6
+ signAttestation,
7
+ verifyAttestation,
8
+ MemoryKeyStore,
9
+ TrustAttestation,
10
+ KeyStore,
11
+ ReportArgs,
12
+ ReportResult,
13
+ ReportOptions,
14
+ DEFAULT_REPUTATION_URL,
15
+ } from './index.js';
package/src/scope.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { scopeCovers, coversAll } from './index.js';