@axivoy/api 0.0.0-stage → 1.0.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.
@@ -0,0 +1,5 @@
1
+ /**
2
+ * This file was auto-generated by openapi-typescript.
3
+ * Do not make direct changes to the file.
4
+ */
5
+ export {};
@@ -0,0 +1,5 @@
1
+ export { AxivoyClient, createAxivoyClient, DEFAULT_BASE_URL, type AxivoyClientOptions, type CallOptions, type DryRunResult, type OperationInput, type OperationKey, type OperationResult, type TokenSource, } from './client.js';
2
+ export { clientCredentials, DEFAULT_TOKEN_URL, type ClientCredentialsOptions } from './auth.js';
3
+ export { AxivoyError, AxivoyProposal, type AxivoyErrorBody, type ProposalBody } from './errors.js';
4
+ export { AxivoyWebhookError, verifyWebhook, type AxivoyEvent, type VerifyOptions } from './webhooks.js';
5
+ export type { paths as AxivoyPaths, webhooks as AxivoyWebhooks } from './generated/schema.js';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { AxivoyClient, createAxivoyClient, DEFAULT_BASE_URL, } from './client.js';
2
+ export { clientCredentials, DEFAULT_TOKEN_URL } from './auth.js';
3
+ export { AxivoyError, AxivoyProposal } from './errors.js';
4
+ export { AxivoyWebhookError, verifyWebhook } from './webhooks.js';
@@ -0,0 +1,41 @@
1
+ /** A webhook request body: one domain event. */
2
+ export interface AxivoyEvent<Facts = Record<string, unknown>> {
3
+ id: string;
4
+ type: string;
5
+ version: number;
6
+ occurred_at: string;
7
+ effective_at: string | null;
8
+ tenant: number;
9
+ subject: {
10
+ type: string;
11
+ id: number | string;
12
+ };
13
+ sequence: number;
14
+ facts: Facts;
15
+ causation: {
16
+ invocation_id: string | null;
17
+ event_id: string | null;
18
+ subscription_id: number | null;
19
+ };
20
+ chain_depth: number;
21
+ fetch: {
22
+ operation: string;
23
+ input: Record<string, unknown>;
24
+ } | null;
25
+ }
26
+ export interface VerifyOptions {
27
+ /** Oldest signature age accepted, in seconds. Defaults to 300. */
28
+ toleranceSeconds?: number;
29
+ /** Clock for tests, in Unix seconds. */
30
+ now?: number;
31
+ }
32
+ export declare class AxivoyWebhookError extends Error {
33
+ constructor(message: string);
34
+ }
35
+ /**
36
+ * Checks the `Axivoy-Signature` header (`t=<unix>,v1=<hex>`: HMAC-SHA256 of
37
+ * `{t}.{raw body}` with the endpoint secret) and returns the parsed event.
38
+ * Pass the raw body exactly as received; parsing and re-encoding it breaks
39
+ * the signature. Throws `AxivoyWebhookError` when it does not match.
40
+ */
41
+ export declare function verifyWebhook<Facts = Record<string, unknown>>(rawBody: string, signatureHeader: string | null | undefined, secret: string, options?: VerifyOptions): Promise<AxivoyEvent<Facts>>;
@@ -0,0 +1,51 @@
1
+ export class AxivoyWebhookError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'AxivoyWebhookError';
5
+ }
6
+ }
7
+ /**
8
+ * Checks the `Axivoy-Signature` header (`t=<unix>,v1=<hex>`: HMAC-SHA256 of
9
+ * `{t}.{raw body}` with the endpoint secret) and returns the parsed event.
10
+ * Pass the raw body exactly as received; parsing and re-encoding it breaks
11
+ * the signature. Throws `AxivoyWebhookError` when it does not match.
12
+ */
13
+ export async function verifyWebhook(rawBody, signatureHeader, secret, options = {}) {
14
+ const parts = new Map();
15
+ for (const piece of (signatureHeader ?? '').split(',')) {
16
+ const [name, value] = piece.trim().split('=', 2);
17
+ if (name && value) {
18
+ parts.set(name, [...(parts.get(name) ?? []), value]);
19
+ }
20
+ }
21
+ const timestamp = Number(parts.get('t')?.[0]);
22
+ const signatures = parts.get('v1') ?? [];
23
+ if (!Number.isInteger(timestamp) || signatures.length === 0) {
24
+ throw new AxivoyWebhookError('Missing or malformed Axivoy-Signature header.');
25
+ }
26
+ const now = options.now ?? Math.floor(Date.now() / 1000);
27
+ if (Math.abs(now - timestamp) > (options.toleranceSeconds ?? 300)) {
28
+ throw new AxivoyWebhookError('Signature timestamp is outside the tolerance.');
29
+ }
30
+ const expected = await hmacHex(secret, `${timestamp}.${rawBody}`);
31
+ if (!signatures.some((signature) => constantTimeEqual(signature, expected))) {
32
+ throw new AxivoyWebhookError('Signature does not match.');
33
+ }
34
+ return JSON.parse(rawBody);
35
+ }
36
+ async function hmacHex(secret, message) {
37
+ const encoder = new TextEncoder();
38
+ const key = await globalThis.crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
39
+ const signature = new Uint8Array(await globalThis.crypto.subtle.sign('HMAC', key, encoder.encode(message)));
40
+ return Array.from(signature, (byte) => byte.toString(16).padStart(2, '0')).join('');
41
+ }
42
+ function constantTimeEqual(a, b) {
43
+ if (a.length !== b.length) {
44
+ return false;
45
+ }
46
+ let diff = 0;
47
+ for (let i = 0; i < a.length; i++) {
48
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
49
+ }
50
+ return diff === 0;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,41 @@
1
1
  {
2
2
  "name": "@axivoy/api",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "Typed client for the Axivoy API: operations, webhooks and errors.",
5
+ "license": "MIT",
6
+ "homepage": "https://app.axivoy.ai/developers",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/meesam-cmd/tooli-middleware.git",
10
+ "directory": "clients/typescript"
11
+ },
12
+ "type": "module",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "engines": {
26
+ "node": ">=20"
27
+ },
28
+ "sideEffects": false,
29
+ "scripts": {
30
+ "generate": "openapi-typescript ../../docs/api/openapi-public.json --output src/generated/schema.ts",
31
+ "build": "tsc -p tsconfig.json",
32
+ "typecheck": "tsc -p tsconfig.test.json",
33
+ "test": "npm run typecheck && node --test test/client.test.mjs",
34
+ "smoke": "node scripts/smoke.mjs"
35
+ },
36
+ "devDependencies": {
37
+ "openapi-typescript": "^7.4.0",
38
+ "typescript": "^5.6.0",
39
+ "undici": "^6.21.0"
40
+ }
41
+ }