@hivemind-os/collective-core 0.2.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.
- package/.test-data/05a845c4-1682-41b9-97e5-65a5263156c0/spending.sqlite +0 -0
- package/.test-data/10e18ba5-98f0-42e0-8899-06a09459ae85/agents.sqlite +0 -0
- package/.test-data/20464456-23cb-4ff7-8df5-3c129fb95a90/agents.sqlite +0 -0
- package/.test-data/2e2ec66c-e8b4-43eb-945f-cca84ed0a0f6/agents.sqlite +0 -0
- package/.test-data/2f5ef9b7-01da-4ba0-a6fa-af8063a2567c/agents.sqlite +0 -0
- package/.test-data/3ac13cd5-84c9-4e71-8b89-6d3ef4dd819c/agents.sqlite +0 -0
- package/.test-data/40b7dd4a-fae0-4a5d-a6a0-64c9048af35e/agents.sqlite +0 -0
- package/.test-data/59511a04-42f8-4286-bb1e-733795e08749/agents.sqlite +0 -0
- package/.test-data/6778e8c5-6eb5-416d-8aca-9d559cdf83e4/agents.sqlite +0 -0
- package/.test-data/7648dc86-df90-4460-8f9c-55cdb481324b/agents.sqlite +0 -0
- package/.test-data/77162d98-6b22-41b1-a50f-536fab739f8a/agents.sqlite +0 -0
- package/.test-data/798dbdab-cbe7-4edd-8a5b-ae99c285fe17/agents.sqlite +0 -0
- package/.test-data/8033d6ac-8b85-454d-b708-00ac695b22f8/agents.sqlite +0 -0
- package/.test-data/9155a4f4-cda3-487c-9eed-921c82d7550f/agents.sqlite +0 -0
- package/.test-data/9bfeee53-c231-46c3-8c93-2180933f5d50/agents.sqlite +0 -0
- package/.test-data/a4c64287-79f6-46e9-847d-2803c63a74fd/agents.sqlite +0 -0
- package/.test-data/b8f58952-1ed8-46ff-abd7-21fb86e9457f/agents.sqlite +0 -0
- package/.test-data/c3060504-3187-41ed-8532-82332be48b0b/spending.sqlite +0 -0
- package/.test-data/cc471629-8006-4fc1-b8a1-399d2df2cc4e/agents.sqlite +0 -0
- package/.test-data/dbca3bef-397d-4bbc-bd4c-4f7b14103e04/spending.sqlite +0 -0
- package/.test-data/f1283dd1-6602-4de7-a050-16aac7abc288/agents.sqlite +0 -0
- package/.turbo/turbo-build.log +14 -0
- package/dist/index.d.ts +1675 -0
- package/dist/index.js +8006 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
- package/src/auth/device-flow.ts +108 -0
- package/src/auth/ed25519-provider.ts +43 -0
- package/src/auth/errors.ts +82 -0
- package/src/auth/evm-key.ts +55 -0
- package/src/auth/index.ts +8 -0
- package/src/auth/session-state.ts +25 -0
- package/src/auth/session-store.ts +510 -0
- package/src/auth/types.ts +81 -0
- package/src/auth/zklogin-provider.ts +902 -0
- package/src/blobstore/WALRUS_FINDINGS.md +284 -0
- package/src/blobstore/encrypted-store.ts +56 -0
- package/src/blobstore/fs-store.ts +91 -0
- package/src/blobstore/hybrid-store.ts +144 -0
- package/src/blobstore/index.ts +5 -0
- package/src/blobstore/interface.ts +33 -0
- package/src/blobstore/walrus-spike.ts +345 -0
- package/src/blobstore/walrus-store.ts +551 -0
- package/src/cache/agent-cache.ts +403 -0
- package/src/cache/index.ts +1 -0
- package/src/crypto/encryption.ts +152 -0
- package/src/crypto/index.ts +2 -0
- package/src/crypto/x25519.ts +41 -0
- package/src/dispute/client.ts +191 -0
- package/src/dispute/index.ts +1 -0
- package/src/events/index.ts +2 -0
- package/src/events/parser.ts +291 -0
- package/src/events/subscription.ts +131 -0
- package/src/evm/constants.ts +6 -0
- package/src/evm/index.ts +2 -0
- package/src/evm/wallet.ts +136 -0
- package/src/identity/did.ts +36 -0
- package/src/identity/index.ts +4 -0
- package/src/identity/keypair.ts +199 -0
- package/src/identity/signing.ts +28 -0
- package/src/index.ts +22 -0
- package/src/internal/parsing.ts +416 -0
- package/src/marketplace/client.ts +349 -0
- package/src/marketplace/index.ts +1 -0
- package/src/metering/hash-chain.ts +94 -0
- package/src/metering/index.ts +4 -0
- package/src/metering/meter.ts +80 -0
- package/src/metering/streaming.ts +196 -0
- package/src/metering/verification.ts +104 -0
- package/src/payment/index.ts +1 -0
- package/src/payment/rail-selector.ts +41 -0
- package/src/registry/client.ts +328 -0
- package/src/registry/index.ts +1 -0
- package/src/relay/consumer-client.ts +497 -0
- package/src/relay/index.ts +1 -0
- package/src/relay-registry/client.ts +295 -0
- package/src/relay-registry/discovery.ts +109 -0
- package/src/relay-registry/index.ts +2 -0
- package/src/reputation/anchor-client.ts +126 -0
- package/src/reputation/event-publisher.ts +67 -0
- package/src/reputation/index.ts +5 -0
- package/src/reputation/merkle.ts +79 -0
- package/src/reputation/score-calculator.ts +133 -0
- package/src/reputation/serialization.ts +37 -0
- package/src/reputation/store.ts +165 -0
- package/src/reputation/validation.ts +135 -0
- package/src/routing/circuit-breaker.ts +111 -0
- package/src/routing/fan-out.ts +266 -0
- package/src/routing/index.ts +4 -0
- package/src/routing/performance.ts +244 -0
- package/src/routing/selector.ts +225 -0
- package/src/spending/index.ts +1 -0
- package/src/spending/policy.ts +271 -0
- package/src/staking/client.ts +319 -0
- package/src/staking/index.ts +1 -0
- package/src/sui/client.ts +214 -0
- package/src/sui/index.ts +2 -0
- package/src/sui/tx-helpers.ts +1070 -0
- package/src/task/client.ts +215 -0
- package/src/task/index.ts +1 -0
- package/src/x402/client.ts +295 -0
- package/src/x402/index.ts +1 -0
- package/tests/auth/device-flow.test.ts +62 -0
- package/tests/auth/ed25519-provider.test.ts +24 -0
- package/tests/auth/evm-key.test.ts +31 -0
- package/tests/auth/session-store.test.ts +201 -0
- package/tests/auth/zklogin-provider.test.ts +366 -0
- package/tests/blobstore/encrypted-store.test.ts +78 -0
- package/tests/blobstore.test.ts +91 -0
- package/tests/cache.test.ts +124 -0
- package/tests/crypto/encryption.test.ts +70 -0
- package/tests/crypto/x25519.test.ts +47 -0
- package/tests/dispute/client.test.ts +238 -0
- package/tests/events.test.ts +202 -0
- package/tests/evm/wallet.test.ts +101 -0
- package/tests/hybrid-store.test.ts +121 -0
- package/tests/identity.test.ts +161 -0
- package/tests/marketplace.test.ts +308 -0
- package/tests/metering/hash-chain.test.ts +32 -0
- package/tests/metering/meter.test.ts +23 -0
- package/tests/metering/streaming.test.ts +52 -0
- package/tests/metering/verification.test.ts +27 -0
- package/tests/payment/rail-selector.test.ts +95 -0
- package/tests/registry.test.ts +183 -0
- package/tests/relay-consumer-client.test.ts +119 -0
- package/tests/relay-registry/client.test.ts +261 -0
- package/tests/reputation/event-publisher.test.ts +70 -0
- package/tests/reputation/merkle.test.ts +44 -0
- package/tests/reputation/score-calculator.test.ts +104 -0
- package/tests/reputation/store.test.ts +94 -0
- package/tests/routing/circuit-breaker.test.ts +45 -0
- package/tests/routing/fan-out.test.ts +123 -0
- package/tests/routing/performance.test.ts +49 -0
- package/tests/routing/selector.test.ts +114 -0
- package/tests/spending.test.ts +133 -0
- package/tests/staking/client.test.ts +286 -0
- package/tests/sui-client.test.ts +85 -0
- package/tests/task.test.ts +249 -0
- package/tests/tx-helpers.test.ts +70 -0
- package/tests/walrus-spike.test.ts +100 -0
- package/tests/walrus-store.test.ts +196 -0
- package/tests/x402/client.test.ts +116 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +11 -0
- package/vitest.config.ts +8 -0
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hivemind-os/collective-core",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@mysten/sui": "^1.30.0",
|
|
15
|
+
"@noble/ciphers": "^1.3.0",
|
|
16
|
+
"@noble/curves": "^2.2.0",
|
|
17
|
+
"@noble/ed25519": "^2.0.0",
|
|
18
|
+
"@noble/hashes": "^1.4.0",
|
|
19
|
+
"@x402/core": "^2.12.0",
|
|
20
|
+
"@x402/evm": "^2.12.0",
|
|
21
|
+
"better-sqlite3": "^11.0.0",
|
|
22
|
+
"bs58": "^6.0.0",
|
|
23
|
+
"pino": "^9.0.0",
|
|
24
|
+
"viem": "^2.48.11",
|
|
25
|
+
"@hivemind-os/collective-types": "0.2.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
29
|
+
"tsup": "^8.0.0",
|
|
30
|
+
"typescript": "^5.7.0",
|
|
31
|
+
"vitest": "^3.0.0"
|
|
32
|
+
},
|
|
33
|
+
"optionalDependencies": {
|
|
34
|
+
"keytar": "^7.9.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"test": "vitest",
|
|
39
|
+
"lint": "eslint src/ tests/ vitest.config.ts"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { DeviceFlowStatus, OAuthConfig } from './types.js';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_ENDPOINTS = {
|
|
4
|
+
google: {
|
|
5
|
+
deviceCodeEndpoint: 'https://oauth2.googleapis.com/device/code',
|
|
6
|
+
tokenEndpoint: 'https://oauth2.googleapis.com/token',
|
|
7
|
+
},
|
|
8
|
+
apple: {
|
|
9
|
+
deviceCodeEndpoint: '',
|
|
10
|
+
tokenEndpoint: 'https://appleid.apple.com/auth/token',
|
|
11
|
+
},
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
export async function startDeviceFlow(config: OAuthConfig): Promise<DeviceFlowStatus> {
|
|
15
|
+
const endpoint = config.deviceCodeEndpoint ?? DEFAULT_ENDPOINTS[config.provider].deviceCodeEndpoint;
|
|
16
|
+
if (!endpoint) {
|
|
17
|
+
throw new Error(`Device authorization is not configured for provider ${config.provider}.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const response = await fetch(endpoint, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
24
|
+
},
|
|
25
|
+
body: new URLSearchParams({
|
|
26
|
+
client_id: config.clientId,
|
|
27
|
+
scope: (config.scopes ?? ['openid', 'email']).join(' '),
|
|
28
|
+
}).toString(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const payload = (await response.json()) as Record<string, unknown>;
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(readOAuthError(payload, response.status));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const userCode = readRequiredString(payload.user_code, 'user_code');
|
|
37
|
+
const verificationUri =
|
|
38
|
+
readOptionalString(payload.verification_uri) ?? readRequiredString(payload.verification_url, 'verification_url');
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
userCode,
|
|
42
|
+
verificationUri,
|
|
43
|
+
deviceCode: readRequiredString(payload.device_code, 'device_code'),
|
|
44
|
+
pollInterval: readOptionalNumber(payload.interval) ?? 5,
|
|
45
|
+
expiresIn: readOptionalNumber(payload.expires_in) ?? 600,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function pollDeviceFlow(
|
|
50
|
+
deviceCode: string,
|
|
51
|
+
config: OAuthConfig,
|
|
52
|
+
): Promise<{
|
|
53
|
+
jwt: string;
|
|
54
|
+
refreshToken?: string;
|
|
55
|
+
} | null> {
|
|
56
|
+
const endpoint = config.tokenEndpoint ?? DEFAULT_ENDPOINTS[config.provider].tokenEndpoint;
|
|
57
|
+
if (!endpoint) {
|
|
58
|
+
throw new Error(`Token polling is not configured for provider ${config.provider}.`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const response = await fetch(endpoint, {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: {
|
|
64
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
65
|
+
},
|
|
66
|
+
body: new URLSearchParams({
|
|
67
|
+
client_id: config.clientId,
|
|
68
|
+
device_code: deviceCode,
|
|
69
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
70
|
+
}).toString(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const payload = (await response.json()) as Record<string, unknown>;
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
const code = readOptionalString(payload.error);
|
|
76
|
+
if (code === 'authorization_pending' || code === 'slow_down') {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
throw new Error(readOAuthError(payload, response.status));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
jwt: readRequiredString(payload.id_token, 'id_token'),
|
|
85
|
+
refreshToken: readOptionalString(payload.refresh_token),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function readRequiredString(value: unknown, field: string): string {
|
|
90
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
91
|
+
throw new Error(`OAuth response is missing ${field}.`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function readOptionalString(value: unknown): string | undefined {
|
|
98
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function readOptionalNumber(value: unknown): number | undefined {
|
|
102
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function readOAuthError(payload: Record<string, unknown>, status: number): string {
|
|
106
|
+
const message = readOptionalString(payload.error_description) ?? readOptionalString(payload.error) ?? 'OAuth request failed';
|
|
107
|
+
return `${message} (${status})`;
|
|
108
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
|
|
2
|
+
|
|
3
|
+
import { createDID } from '../identity/did.js';
|
|
4
|
+
|
|
5
|
+
import type { AuthProvider } from './types.js';
|
|
6
|
+
|
|
7
|
+
const encoder = new TextEncoder();
|
|
8
|
+
|
|
9
|
+
export class Ed25519AuthProvider implements AuthProvider {
|
|
10
|
+
readonly mode = 'ed25519' as const;
|
|
11
|
+
|
|
12
|
+
constructor(private readonly keypair: Ed25519Keypair) {}
|
|
13
|
+
|
|
14
|
+
async getAddress(): Promise<string> {
|
|
15
|
+
return this.keypair.toSuiAddress();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getDID(): string {
|
|
19
|
+
return createDID(this.keypair.getPublicKey().toRawBytes());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async signTransaction(tx: Uint8Array): Promise<Uint8Array> {
|
|
23
|
+
const { signature } = await this.keypair.signTransaction(tx);
|
|
24
|
+
return encoder.encode(signature);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async signPersonalMessage(message: Uint8Array): Promise<{ signature: Uint8Array }> {
|
|
28
|
+
const { signature } = await this.keypair.signPersonalMessage(message);
|
|
29
|
+
return { signature: encoder.encode(signature) };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
isAuthenticated(): boolean {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getPublicKey(): Uint8Array {
|
|
37
|
+
return this.keypair.getPublicKey().toRawBytes();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
toSuiSigner(): Ed25519Keypair {
|
|
41
|
+
return this.keypair;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { SessionState } from './session-state.js';
|
|
2
|
+
import type { StoredZkLoginSession } from './types.js';
|
|
3
|
+
|
|
4
|
+
interface SessionContext {
|
|
5
|
+
address: string;
|
|
6
|
+
iss: string;
|
|
7
|
+
maxEpoch: number;
|
|
8
|
+
updatedAt: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function toSessionContext(session?: StoredZkLoginSession | null): SessionContext | undefined {
|
|
12
|
+
if (!session) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
address: session.address,
|
|
18
|
+
iss: session.iss,
|
|
19
|
+
maxEpoch: session.maxEpoch,
|
|
20
|
+
updatedAt: session.updatedAt,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SessionRefreshErrorOptions {
|
|
25
|
+
attempts: number;
|
|
26
|
+
maxAttempts: number;
|
|
27
|
+
retryDelaysMs: readonly number[];
|
|
28
|
+
consecutiveFailures: number;
|
|
29
|
+
sessionState: SessionState;
|
|
30
|
+
session?: StoredZkLoginSession | null;
|
|
31
|
+
cause?: unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class SessionRefreshError extends Error {
|
|
35
|
+
readonly attempts: number;
|
|
36
|
+
readonly maxAttempts: number;
|
|
37
|
+
readonly retryDelaysMs: readonly number[];
|
|
38
|
+
readonly consecutiveFailures: number;
|
|
39
|
+
readonly sessionState: SessionState;
|
|
40
|
+
readonly session?: SessionContext;
|
|
41
|
+
|
|
42
|
+
constructor(message: string, options: SessionRefreshErrorOptions) {
|
|
43
|
+
super(message, { cause: options.cause });
|
|
44
|
+
this.name = 'SessionRefreshError';
|
|
45
|
+
this.attempts = options.attempts;
|
|
46
|
+
this.maxAttempts = options.maxAttempts;
|
|
47
|
+
this.retryDelaysMs = options.retryDelaysMs;
|
|
48
|
+
this.consecutiveFailures = options.consecutiveFailures;
|
|
49
|
+
this.sessionState = options.sessionState;
|
|
50
|
+
this.session = toSessionContext(options.session);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface SessionExpiredErrorOptions {
|
|
55
|
+
attempts?: number;
|
|
56
|
+
maxAttempts?: number;
|
|
57
|
+
retryDelaysMs?: readonly number[];
|
|
58
|
+
consecutiveFailures?: number;
|
|
59
|
+
sessionState?: SessionState;
|
|
60
|
+
session?: StoredZkLoginSession | null;
|
|
61
|
+
cause?: unknown;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class SessionExpiredError extends Error {
|
|
65
|
+
readonly attempts?: number;
|
|
66
|
+
readonly maxAttempts?: number;
|
|
67
|
+
readonly retryDelaysMs?: readonly number[];
|
|
68
|
+
readonly consecutiveFailures?: number;
|
|
69
|
+
readonly sessionState: SessionState;
|
|
70
|
+
readonly session?: SessionContext;
|
|
71
|
+
|
|
72
|
+
constructor(message: string, options: SessionExpiredErrorOptions = {}) {
|
|
73
|
+
super(message, { cause: options.cause });
|
|
74
|
+
this.name = 'SessionExpiredError';
|
|
75
|
+
this.attempts = options.attempts;
|
|
76
|
+
this.maxAttempts = options.maxAttempts;
|
|
77
|
+
this.retryDelaysMs = options.retryDelaysMs;
|
|
78
|
+
this.consecutiveFailures = options.consecutiveFailures;
|
|
79
|
+
this.sessionState = options.sessionState ?? SessionState.NEEDS_REAUTH;
|
|
80
|
+
this.session = toSessionContext(options.session);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { hkdf } from '@noble/hashes/hkdf';
|
|
2
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
3
|
+
|
|
4
|
+
const DERIVED_KEY_LENGTH = 32;
|
|
5
|
+
const encoder = new TextEncoder();
|
|
6
|
+
|
|
7
|
+
export function deriveEvmKey(identityPrivateKey: Uint8Array, userSalt: string, oauthSub: string): Uint8Array {
|
|
8
|
+
if (identityPrivateKey.byteLength === 0) {
|
|
9
|
+
throw new Error('identityPrivateKey must not be empty.');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const normalizedUserSalt = normalizeRequiredString(userSalt, 'userSalt');
|
|
13
|
+
const normalizedOauthSub = normalizeRequiredString(oauthSub, 'oauthSub');
|
|
14
|
+
|
|
15
|
+
return hkdf(
|
|
16
|
+
sha256,
|
|
17
|
+
identityPrivateKey,
|
|
18
|
+
buildDerivationSalt(normalizedUserSalt, normalizedOauthSub),
|
|
19
|
+
encoder.encode('agentic-mesh:evm:v1'),
|
|
20
|
+
DERIVED_KEY_LENGTH,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function normalizeRequiredString(value: string, field: string): string {
|
|
25
|
+
const normalized = value.trim();
|
|
26
|
+
if (!normalized) {
|
|
27
|
+
throw new Error(`${field} must not be empty.`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return normalized;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function buildDerivationSalt(userSalt: string, oauthSub: string): Uint8Array {
|
|
34
|
+
return sha256(concatBytes(encodeLengthPrefixed(userSalt), encodeLengthPrefixed(oauthSub)));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function encodeLengthPrefixed(value: string): Uint8Array {
|
|
38
|
+
const encodedValue = encoder.encode(value);
|
|
39
|
+
const lengthPrefix = new Uint8Array(4);
|
|
40
|
+
new DataView(lengthPrefix.buffer).setUint32(0, encodedValue.length, false);
|
|
41
|
+
return concatBytes(lengthPrefix, encodedValue);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function concatBytes(...parts: Uint8Array[]): Uint8Array {
|
|
45
|
+
const totalLength = parts.reduce((sum, part) => sum + part.byteLength, 0);
|
|
46
|
+
const result = new Uint8Array(totalLength);
|
|
47
|
+
let offset = 0;
|
|
48
|
+
|
|
49
|
+
for (const part of parts) {
|
|
50
|
+
result.set(part, offset);
|
|
51
|
+
offset += part.byteLength;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './session-state.js';
|
|
3
|
+
export * from './errors.js';
|
|
4
|
+
export * from './ed25519-provider.js';
|
|
5
|
+
export * from './zklogin-provider.js';
|
|
6
|
+
export * from './session-store.js';
|
|
7
|
+
export * from './device-flow.js';
|
|
8
|
+
export * from './evm-key.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { StoredZkLoginSession } from './types.js';
|
|
2
|
+
|
|
3
|
+
export enum SessionState {
|
|
4
|
+
VALID = 'valid',
|
|
5
|
+
REFRESHING = 'refreshing',
|
|
6
|
+
NEEDS_REAUTH = 'needs_reauth',
|
|
7
|
+
EXPIRED = 'expired',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface SessionRefreshPolicy {
|
|
11
|
+
maxAttempts?: number;
|
|
12
|
+
backoffMs?: readonly number[];
|
|
13
|
+
maxConsecutiveFailures?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface SessionStateChangeEvent {
|
|
17
|
+
previousState: SessionState;
|
|
18
|
+
currentState: SessionState;
|
|
19
|
+
session: StoredZkLoginSession | null;
|
|
20
|
+
reason?: string;
|
|
21
|
+
refreshFailureCount: number;
|
|
22
|
+
error?: unknown;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type SessionStateChangeCallback = (event: SessionStateChangeEvent) => void;
|