@signedby/sdk 0.1.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/README.md +101 -0
- package/dist/index.d.mts +242 -0
- package/dist/index.d.ts +242 -0
- package/dist/index.js +320 -0
- package/dist/index.mjs +292 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# SignedByMe TypeScript SDK
|
|
2
|
+
|
|
3
|
+
Human-controlled identity for autonomous agents.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @signedby/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### For Agents - Authenticate to Enterprises
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { SignedByClient } from '@signedby/sdk';
|
|
17
|
+
|
|
18
|
+
// Load delegation from your human owner
|
|
19
|
+
const client = await SignedByClient.fromDelegation('./delegation.json');
|
|
20
|
+
|
|
21
|
+
console.log(`Your npub: ${client.npub}`);
|
|
22
|
+
console.log(`Authorized for: ${JSON.stringify(client.scopes)}`);
|
|
23
|
+
|
|
24
|
+
// Authenticate to an enterprise
|
|
25
|
+
const token = await client.login({
|
|
26
|
+
clientId: 'acme-corp',
|
|
27
|
+
nonce: 'random_nonce_here'
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Use the OIDC token
|
|
31
|
+
console.log(`ID Token: ${token.idToken}`);
|
|
32
|
+
console.log(`Subject: ${token.sub}`);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### For Agent Setup - Initialize Identity
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { SignedByAgent } from '@signedby/sdk';
|
|
39
|
+
|
|
40
|
+
// Initialize agent (creates DID if first run)
|
|
41
|
+
const agent = await SignedByAgent.init('./agent_data');
|
|
42
|
+
|
|
43
|
+
console.log(`Agent npub: ${agent.npub}`);
|
|
44
|
+
|
|
45
|
+
// Configure email mapping for enterprises
|
|
46
|
+
agent.setEmailMapping({
|
|
47
|
+
'amazon.com': 'you@gmail.com',
|
|
48
|
+
'acme.com': 'you@gmail.com'
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Connect to relay and watch for authorizations
|
|
52
|
+
await agent.connectRelay('wss://relay.privacy-lion.com');
|
|
53
|
+
|
|
54
|
+
for await (const event of agent.watchForAuthorizations()) {
|
|
55
|
+
console.log(`New authorization from: ${event.enterprise}`);
|
|
56
|
+
console.log(`Scopes: ${event.scopes}`);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Error Handling
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import {
|
|
64
|
+
SignedByClient,
|
|
65
|
+
SignedByError,
|
|
66
|
+
DelegationRevokedError,
|
|
67
|
+
DelegationExpiredError,
|
|
68
|
+
ScopeDeniedError,
|
|
69
|
+
} from '@signedby/sdk';
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const token = await client.login({ clientId: 'acme-corp', nonce });
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error instanceof DelegationRevokedError) {
|
|
75
|
+
console.log('Delegation was revoked. Contact your human owner.');
|
|
76
|
+
} else if (error instanceof DelegationExpiredError) {
|
|
77
|
+
console.log('Delegation expired. Request renewal from your human owner.');
|
|
78
|
+
} else if (error instanceof ScopeDeniedError) {
|
|
79
|
+
console.log('Not authorized for this enterprise.');
|
|
80
|
+
} else if (error instanceof SignedByError) {
|
|
81
|
+
console.log(`Authentication failed: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Requirements
|
|
87
|
+
|
|
88
|
+
- Node.js 18+
|
|
89
|
+
- Supported platforms: Linux (x86_64, arm64), macOS (x86_64, arm64), Windows (x86_64)
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
- [SDK Quick Start](https://signedbyme.com/docs/sdk-quickstart.html)
|
|
94
|
+
- [API Reference](https://signedbyme.com/docs/api-reference.html)
|
|
95
|
+
- [Understanding Delegation](https://signedbyme.com/docs/delegation.html)
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
SignedByMe Source-Available License v1.0 (SSAL-1.0)
|
|
100
|
+
|
|
101
|
+
See [LICENSE](https://github.com/PrivacyLion/SignedByMe/blob/main/LICENSE) for details.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for SignedByMe SDK.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* OIDC token returned from successful authentication.
|
|
6
|
+
*/
|
|
7
|
+
interface LoginToken {
|
|
8
|
+
/** The OIDC id_token (JWT) */
|
|
9
|
+
idToken: string;
|
|
10
|
+
/** Token type, always "Bearer" */
|
|
11
|
+
tokenType: string;
|
|
12
|
+
/** Seconds until token expires */
|
|
13
|
+
expiresIn: number;
|
|
14
|
+
/** Subject - agent's npub in bech32 format */
|
|
15
|
+
sub: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Request parameters for login.
|
|
19
|
+
*/
|
|
20
|
+
interface LoginRequest {
|
|
21
|
+
/** Enterprise client ID */
|
|
22
|
+
clientId: string;
|
|
23
|
+
/** Random nonce for replay protection */
|
|
24
|
+
nonce: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Delegation scopes mapping enterprise to permissions.
|
|
28
|
+
*/
|
|
29
|
+
type Scopes = Record<string, string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* An authorization request from an enterprise (kind 28200).
|
|
32
|
+
*/
|
|
33
|
+
interface AuthorizationEvent {
|
|
34
|
+
/** Enterprise name/domain */
|
|
35
|
+
enterprise: string;
|
|
36
|
+
/** Enterprise client ID */
|
|
37
|
+
clientId: string;
|
|
38
|
+
/** Offered permission scopes */
|
|
39
|
+
scopes: string[];
|
|
40
|
+
/** NOSTR event ID */
|
|
41
|
+
eventId: string;
|
|
42
|
+
/** Unix timestamp of event creation */
|
|
43
|
+
createdAt: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Login options for customizing authentication.
|
|
47
|
+
*/
|
|
48
|
+
interface LoginOptions {
|
|
49
|
+
/** NOSTR relay URL (default: wss://relay.privacy-lion.com) */
|
|
50
|
+
relayUrl?: string;
|
|
51
|
+
/** SignedByMe API URL (default: https://api.beta.privacy-lion.com) */
|
|
52
|
+
apiUrl?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* SignedByClient - Core client for agent authentication.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Client for authenticating to enterprises using SignedByMe.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const client = await SignedByClient.fromDelegation('./delegation.json');
|
|
65
|
+
* const token = await client.login({
|
|
66
|
+
* clientId: 'acme-corp',
|
|
67
|
+
* nonce: 'random123'
|
|
68
|
+
* });
|
|
69
|
+
* console.log(`ID Token: ${token.idToken}`);
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare class SignedByClient {
|
|
73
|
+
private readonly nativeClient;
|
|
74
|
+
private readonly delegation;
|
|
75
|
+
private constructor();
|
|
76
|
+
/**
|
|
77
|
+
* Load a SignedByClient from a delegation file.
|
|
78
|
+
*
|
|
79
|
+
* @param path - Path to the delegation JSON file (kind 28250 event)
|
|
80
|
+
* @returns SignedByClient instance ready for authentication
|
|
81
|
+
* @throws {Error} If delegation file doesn't exist or is invalid
|
|
82
|
+
*/
|
|
83
|
+
static fromDelegation(path: string): Promise<SignedByClient>;
|
|
84
|
+
/**
|
|
85
|
+
* Get the agent's npub (public key in bech32 format).
|
|
86
|
+
*/
|
|
87
|
+
get npub(): string;
|
|
88
|
+
/**
|
|
89
|
+
* Get the delegation scopes (enterprise -> permissions mapping).
|
|
90
|
+
*/
|
|
91
|
+
get scopes(): Scopes;
|
|
92
|
+
/**
|
|
93
|
+
* Authenticate to an enterprise and receive an OIDC token.
|
|
94
|
+
*
|
|
95
|
+
* @param request - Login request parameters
|
|
96
|
+
* @param options - Optional configuration
|
|
97
|
+
* @returns LoginToken containing the OIDC id_token
|
|
98
|
+
* @throws {DelegationRevokedError} If delegation has been revoked
|
|
99
|
+
* @throws {DelegationExpiredError} If delegation has expired
|
|
100
|
+
* @throws {ScopeDeniedError} If client_id not in delegation scopes
|
|
101
|
+
* @throws {MerkleRootExpiredError} If proof uses stale merkle root
|
|
102
|
+
*/
|
|
103
|
+
login(request: LoginRequest, options?: LoginOptions): Promise<LoginToken>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* SignedByAgent - Agent initialization and management.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Agent for managing identity and watching for authorization requests.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const agent = await SignedByAgent.init('./agent_data');
|
|
116
|
+
* agent.setEmailMapping({
|
|
117
|
+
* 'amazon.com': 'me@gmail.com',
|
|
118
|
+
* 'acme.com': 'me@gmail.com'
|
|
119
|
+
* });
|
|
120
|
+
* await agent.connectRelay('wss://relay.privacy-lion.com');
|
|
121
|
+
* agent.watchForAuthorizations();
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
declare class SignedByAgent {
|
|
125
|
+
private readonly nativeAgent;
|
|
126
|
+
private relayConnected;
|
|
127
|
+
private _emailMapping;
|
|
128
|
+
private constructor();
|
|
129
|
+
/**
|
|
130
|
+
* Initialize a new agent or load existing identity.
|
|
131
|
+
*
|
|
132
|
+
* Creates DID keys and stores them securely if this is first run.
|
|
133
|
+
* Loads existing identity if storage already exists.
|
|
134
|
+
*
|
|
135
|
+
* @param storagePath - Directory for agent data (keys, witness cache)
|
|
136
|
+
* @returns SignedByAgent instance
|
|
137
|
+
*/
|
|
138
|
+
static init(storagePath: string): Promise<SignedByAgent>;
|
|
139
|
+
/**
|
|
140
|
+
* Get the agent's npub (public key in bech32 format).
|
|
141
|
+
*/
|
|
142
|
+
get npub(): string;
|
|
143
|
+
/**
|
|
144
|
+
* Set email mapping for enterprises.
|
|
145
|
+
*
|
|
146
|
+
* This tells the agent which email to provide during Gate 1
|
|
147
|
+
* enrollment for each enterprise domain.
|
|
148
|
+
*
|
|
149
|
+
* @param mapping - Dict of enterprise domain -> email address
|
|
150
|
+
*/
|
|
151
|
+
setEmailMapping(mapping: Record<string, string>): void;
|
|
152
|
+
/**
|
|
153
|
+
* Connect to a NOSTR relay.
|
|
154
|
+
*
|
|
155
|
+
* @param relayUrl - WebSocket URL of the relay
|
|
156
|
+
*/
|
|
157
|
+
connectRelay(relayUrl: string): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* Watch for kind 28200 authorization events addressed to this agent.
|
|
160
|
+
*
|
|
161
|
+
* @yields AuthorizationEvent for each incoming authorization request
|
|
162
|
+
*/
|
|
163
|
+
watchForAuthorizations(): AsyncGenerator<AuthorizationEvent>;
|
|
164
|
+
/**
|
|
165
|
+
* Get recent agent activity (kinds 28101, 28102, 28103).
|
|
166
|
+
*
|
|
167
|
+
* @param limit - Maximum number of events to return
|
|
168
|
+
* @returns List of activity events
|
|
169
|
+
*/
|
|
170
|
+
getActivityLog(limit?: number): Array<Record<string, unknown>>;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* SignedByMe SDK Errors.
|
|
175
|
+
*/
|
|
176
|
+
/**
|
|
177
|
+
* Base error class for all SignedByMe errors.
|
|
178
|
+
*/
|
|
179
|
+
declare class SignedByError extends Error {
|
|
180
|
+
constructor(message: string);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Raised when the delegation has been revoked.
|
|
184
|
+
*
|
|
185
|
+
* The human owner published a kind 28251 revocation event.
|
|
186
|
+
* Contact your human owner for a new delegation.
|
|
187
|
+
*/
|
|
188
|
+
declare class DelegationRevokedError extends SignedByError {
|
|
189
|
+
constructor(message?: string);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Raised when the delegation has expired.
|
|
193
|
+
*
|
|
194
|
+
* The expires_at timestamp in the delegation has passed.
|
|
195
|
+
* Request a renewed delegation from your human owner.
|
|
196
|
+
*/
|
|
197
|
+
declare class DelegationExpiredError extends SignedByError {
|
|
198
|
+
constructor(message?: string);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Raised when Groth16 proof verification fails.
|
|
202
|
+
*
|
|
203
|
+
* This typically indicates corrupted proof data or
|
|
204
|
+
* a mismatch between proof and public inputs.
|
|
205
|
+
*/
|
|
206
|
+
declare class InvalidProofError extends SignedByError {
|
|
207
|
+
constructor(message?: string);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Raised when the proof references a stale merkle root.
|
|
211
|
+
*
|
|
212
|
+
* The merkle root in the proof is not in the last 30 valid roots.
|
|
213
|
+
* Refresh witness data and regenerate the proof.
|
|
214
|
+
*/
|
|
215
|
+
declare class MerkleRootExpiredError extends SignedByError {
|
|
216
|
+
constructor(message?: string);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Raised when attempting to access an unauthorized enterprise.
|
|
220
|
+
*
|
|
221
|
+
* The client_id is not in the delegation scopes.
|
|
222
|
+
* Request an updated delegation that includes this enterprise.
|
|
223
|
+
*/
|
|
224
|
+
declare class ScopeDeniedError extends SignedByError {
|
|
225
|
+
constructor(message?: string);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Raised when unable to connect to a NOSTR relay.
|
|
229
|
+
*/
|
|
230
|
+
declare class RelayConnectionError extends SignedByError {
|
|
231
|
+
constructor(message?: string);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Raised when the SignedByMe API returns an error.
|
|
235
|
+
*/
|
|
236
|
+
declare class ApiError extends SignedByError {
|
|
237
|
+
readonly errorCode?: string;
|
|
238
|
+
readonly statusCode?: number;
|
|
239
|
+
constructor(message: string, errorCode?: string, statusCode?: number);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export { ApiError, type AuthorizationEvent, DelegationExpiredError, DelegationRevokedError, InvalidProofError, type LoginRequest, type LoginToken, MerkleRootExpiredError, RelayConnectionError, ScopeDeniedError, type Scopes, SignedByAgent, SignedByClient, SignedByError };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for SignedByMe SDK.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* OIDC token returned from successful authentication.
|
|
6
|
+
*/
|
|
7
|
+
interface LoginToken {
|
|
8
|
+
/** The OIDC id_token (JWT) */
|
|
9
|
+
idToken: string;
|
|
10
|
+
/** Token type, always "Bearer" */
|
|
11
|
+
tokenType: string;
|
|
12
|
+
/** Seconds until token expires */
|
|
13
|
+
expiresIn: number;
|
|
14
|
+
/** Subject - agent's npub in bech32 format */
|
|
15
|
+
sub: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Request parameters for login.
|
|
19
|
+
*/
|
|
20
|
+
interface LoginRequest {
|
|
21
|
+
/** Enterprise client ID */
|
|
22
|
+
clientId: string;
|
|
23
|
+
/** Random nonce for replay protection */
|
|
24
|
+
nonce: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Delegation scopes mapping enterprise to permissions.
|
|
28
|
+
*/
|
|
29
|
+
type Scopes = Record<string, string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* An authorization request from an enterprise (kind 28200).
|
|
32
|
+
*/
|
|
33
|
+
interface AuthorizationEvent {
|
|
34
|
+
/** Enterprise name/domain */
|
|
35
|
+
enterprise: string;
|
|
36
|
+
/** Enterprise client ID */
|
|
37
|
+
clientId: string;
|
|
38
|
+
/** Offered permission scopes */
|
|
39
|
+
scopes: string[];
|
|
40
|
+
/** NOSTR event ID */
|
|
41
|
+
eventId: string;
|
|
42
|
+
/** Unix timestamp of event creation */
|
|
43
|
+
createdAt: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Login options for customizing authentication.
|
|
47
|
+
*/
|
|
48
|
+
interface LoginOptions {
|
|
49
|
+
/** NOSTR relay URL (default: wss://relay.privacy-lion.com) */
|
|
50
|
+
relayUrl?: string;
|
|
51
|
+
/** SignedByMe API URL (default: https://api.beta.privacy-lion.com) */
|
|
52
|
+
apiUrl?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* SignedByClient - Core client for agent authentication.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Client for authenticating to enterprises using SignedByMe.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const client = await SignedByClient.fromDelegation('./delegation.json');
|
|
65
|
+
* const token = await client.login({
|
|
66
|
+
* clientId: 'acme-corp',
|
|
67
|
+
* nonce: 'random123'
|
|
68
|
+
* });
|
|
69
|
+
* console.log(`ID Token: ${token.idToken}`);
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare class SignedByClient {
|
|
73
|
+
private readonly nativeClient;
|
|
74
|
+
private readonly delegation;
|
|
75
|
+
private constructor();
|
|
76
|
+
/**
|
|
77
|
+
* Load a SignedByClient from a delegation file.
|
|
78
|
+
*
|
|
79
|
+
* @param path - Path to the delegation JSON file (kind 28250 event)
|
|
80
|
+
* @returns SignedByClient instance ready for authentication
|
|
81
|
+
* @throws {Error} If delegation file doesn't exist or is invalid
|
|
82
|
+
*/
|
|
83
|
+
static fromDelegation(path: string): Promise<SignedByClient>;
|
|
84
|
+
/**
|
|
85
|
+
* Get the agent's npub (public key in bech32 format).
|
|
86
|
+
*/
|
|
87
|
+
get npub(): string;
|
|
88
|
+
/**
|
|
89
|
+
* Get the delegation scopes (enterprise -> permissions mapping).
|
|
90
|
+
*/
|
|
91
|
+
get scopes(): Scopes;
|
|
92
|
+
/**
|
|
93
|
+
* Authenticate to an enterprise and receive an OIDC token.
|
|
94
|
+
*
|
|
95
|
+
* @param request - Login request parameters
|
|
96
|
+
* @param options - Optional configuration
|
|
97
|
+
* @returns LoginToken containing the OIDC id_token
|
|
98
|
+
* @throws {DelegationRevokedError} If delegation has been revoked
|
|
99
|
+
* @throws {DelegationExpiredError} If delegation has expired
|
|
100
|
+
* @throws {ScopeDeniedError} If client_id not in delegation scopes
|
|
101
|
+
* @throws {MerkleRootExpiredError} If proof uses stale merkle root
|
|
102
|
+
*/
|
|
103
|
+
login(request: LoginRequest, options?: LoginOptions): Promise<LoginToken>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* SignedByAgent - Agent initialization and management.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Agent for managing identity and watching for authorization requests.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const agent = await SignedByAgent.init('./agent_data');
|
|
116
|
+
* agent.setEmailMapping({
|
|
117
|
+
* 'amazon.com': 'me@gmail.com',
|
|
118
|
+
* 'acme.com': 'me@gmail.com'
|
|
119
|
+
* });
|
|
120
|
+
* await agent.connectRelay('wss://relay.privacy-lion.com');
|
|
121
|
+
* agent.watchForAuthorizations();
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
declare class SignedByAgent {
|
|
125
|
+
private readonly nativeAgent;
|
|
126
|
+
private relayConnected;
|
|
127
|
+
private _emailMapping;
|
|
128
|
+
private constructor();
|
|
129
|
+
/**
|
|
130
|
+
* Initialize a new agent or load existing identity.
|
|
131
|
+
*
|
|
132
|
+
* Creates DID keys and stores them securely if this is first run.
|
|
133
|
+
* Loads existing identity if storage already exists.
|
|
134
|
+
*
|
|
135
|
+
* @param storagePath - Directory for agent data (keys, witness cache)
|
|
136
|
+
* @returns SignedByAgent instance
|
|
137
|
+
*/
|
|
138
|
+
static init(storagePath: string): Promise<SignedByAgent>;
|
|
139
|
+
/**
|
|
140
|
+
* Get the agent's npub (public key in bech32 format).
|
|
141
|
+
*/
|
|
142
|
+
get npub(): string;
|
|
143
|
+
/**
|
|
144
|
+
* Set email mapping for enterprises.
|
|
145
|
+
*
|
|
146
|
+
* This tells the agent which email to provide during Gate 1
|
|
147
|
+
* enrollment for each enterprise domain.
|
|
148
|
+
*
|
|
149
|
+
* @param mapping - Dict of enterprise domain -> email address
|
|
150
|
+
*/
|
|
151
|
+
setEmailMapping(mapping: Record<string, string>): void;
|
|
152
|
+
/**
|
|
153
|
+
* Connect to a NOSTR relay.
|
|
154
|
+
*
|
|
155
|
+
* @param relayUrl - WebSocket URL of the relay
|
|
156
|
+
*/
|
|
157
|
+
connectRelay(relayUrl: string): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* Watch for kind 28200 authorization events addressed to this agent.
|
|
160
|
+
*
|
|
161
|
+
* @yields AuthorizationEvent for each incoming authorization request
|
|
162
|
+
*/
|
|
163
|
+
watchForAuthorizations(): AsyncGenerator<AuthorizationEvent>;
|
|
164
|
+
/**
|
|
165
|
+
* Get recent agent activity (kinds 28101, 28102, 28103).
|
|
166
|
+
*
|
|
167
|
+
* @param limit - Maximum number of events to return
|
|
168
|
+
* @returns List of activity events
|
|
169
|
+
*/
|
|
170
|
+
getActivityLog(limit?: number): Array<Record<string, unknown>>;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* SignedByMe SDK Errors.
|
|
175
|
+
*/
|
|
176
|
+
/**
|
|
177
|
+
* Base error class for all SignedByMe errors.
|
|
178
|
+
*/
|
|
179
|
+
declare class SignedByError extends Error {
|
|
180
|
+
constructor(message: string);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Raised when the delegation has been revoked.
|
|
184
|
+
*
|
|
185
|
+
* The human owner published a kind 28251 revocation event.
|
|
186
|
+
* Contact your human owner for a new delegation.
|
|
187
|
+
*/
|
|
188
|
+
declare class DelegationRevokedError extends SignedByError {
|
|
189
|
+
constructor(message?: string);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Raised when the delegation has expired.
|
|
193
|
+
*
|
|
194
|
+
* The expires_at timestamp in the delegation has passed.
|
|
195
|
+
* Request a renewed delegation from your human owner.
|
|
196
|
+
*/
|
|
197
|
+
declare class DelegationExpiredError extends SignedByError {
|
|
198
|
+
constructor(message?: string);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Raised when Groth16 proof verification fails.
|
|
202
|
+
*
|
|
203
|
+
* This typically indicates corrupted proof data or
|
|
204
|
+
* a mismatch between proof and public inputs.
|
|
205
|
+
*/
|
|
206
|
+
declare class InvalidProofError extends SignedByError {
|
|
207
|
+
constructor(message?: string);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Raised when the proof references a stale merkle root.
|
|
211
|
+
*
|
|
212
|
+
* The merkle root in the proof is not in the last 30 valid roots.
|
|
213
|
+
* Refresh witness data and regenerate the proof.
|
|
214
|
+
*/
|
|
215
|
+
declare class MerkleRootExpiredError extends SignedByError {
|
|
216
|
+
constructor(message?: string);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Raised when attempting to access an unauthorized enterprise.
|
|
220
|
+
*
|
|
221
|
+
* The client_id is not in the delegation scopes.
|
|
222
|
+
* Request an updated delegation that includes this enterprise.
|
|
223
|
+
*/
|
|
224
|
+
declare class ScopeDeniedError extends SignedByError {
|
|
225
|
+
constructor(message?: string);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Raised when unable to connect to a NOSTR relay.
|
|
229
|
+
*/
|
|
230
|
+
declare class RelayConnectionError extends SignedByError {
|
|
231
|
+
constructor(message?: string);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Raised when the SignedByMe API returns an error.
|
|
235
|
+
*/
|
|
236
|
+
declare class ApiError extends SignedByError {
|
|
237
|
+
readonly errorCode?: string;
|
|
238
|
+
readonly statusCode?: number;
|
|
239
|
+
constructor(message: string, errorCode?: string, statusCode?: number);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export { ApiError, type AuthorizationEvent, DelegationExpiredError, DelegationRevokedError, InvalidProofError, type LoginRequest, type LoginToken, MerkleRootExpiredError, RelayConnectionError, ScopeDeniedError, type Scopes, SignedByAgent, SignedByClient, SignedByError };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
7
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
8
|
+
};
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
|
+
|
|
23
|
+
// src/native.ts
|
|
24
|
+
var require_native = __commonJS({
|
|
25
|
+
"src/native.ts"(exports2, module2) {
|
|
26
|
+
"use strict";
|
|
27
|
+
var import_os = require("os");
|
|
28
|
+
var import_path = require("path");
|
|
29
|
+
function loadNativeBinding() {
|
|
30
|
+
const platformName = (0, import_os.platform)();
|
|
31
|
+
const archName = (0, import_os.arch)();
|
|
32
|
+
let nativeBinding;
|
|
33
|
+
const platformMap = {
|
|
34
|
+
darwin: {
|
|
35
|
+
x64: "@signedby/core-darwin-x64",
|
|
36
|
+
arm64: "@signedby/core-darwin-arm64"
|
|
37
|
+
},
|
|
38
|
+
linux: {
|
|
39
|
+
x64: "@signedby/core-linux-x64-gnu",
|
|
40
|
+
arm64: "@signedby/core-linux-arm64-gnu"
|
|
41
|
+
},
|
|
42
|
+
win32: {
|
|
43
|
+
x64: "@signedby/core-win32-x64-msvc"
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const packageName = platformMap[platformName]?.[archName];
|
|
47
|
+
if (!packageName) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`Unsupported platform: ${platformName}-${archName}. SignedByMe SDK supports: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
nativeBinding = require(packageName);
|
|
54
|
+
} catch (loadError) {
|
|
55
|
+
try {
|
|
56
|
+
nativeBinding = require((0, import_path.join)(__dirname, "..", "native", `signedby_core.${platformName}.node`));
|
|
57
|
+
} catch {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Failed to load native module for ${platformName}-${archName}. Install with: npm install ${packageName}
|
|
60
|
+
Original error: ${loadError}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return nativeBinding;
|
|
65
|
+
}
|
|
66
|
+
module2.exports = loadNativeBinding();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// src/index.ts
|
|
71
|
+
var index_exports = {};
|
|
72
|
+
__export(index_exports, {
|
|
73
|
+
ApiError: () => ApiError,
|
|
74
|
+
DelegationExpiredError: () => DelegationExpiredError,
|
|
75
|
+
DelegationRevokedError: () => DelegationRevokedError,
|
|
76
|
+
InvalidProofError: () => InvalidProofError,
|
|
77
|
+
MerkleRootExpiredError: () => MerkleRootExpiredError,
|
|
78
|
+
RelayConnectionError: () => RelayConnectionError,
|
|
79
|
+
ScopeDeniedError: () => ScopeDeniedError,
|
|
80
|
+
SignedByAgent: () => SignedByAgent,
|
|
81
|
+
SignedByClient: () => SignedByClient,
|
|
82
|
+
SignedByError: () => SignedByError
|
|
83
|
+
});
|
|
84
|
+
module.exports = __toCommonJS(index_exports);
|
|
85
|
+
|
|
86
|
+
// src/client.ts
|
|
87
|
+
var import_fs = require("fs");
|
|
88
|
+
|
|
89
|
+
// src/errors.ts
|
|
90
|
+
var SignedByError = class extends Error {
|
|
91
|
+
constructor(message) {
|
|
92
|
+
super(message);
|
|
93
|
+
this.name = "SignedByError";
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var DelegationRevokedError = class extends SignedByError {
|
|
97
|
+
constructor(message = "Delegation has been revoked") {
|
|
98
|
+
super(message);
|
|
99
|
+
this.name = "DelegationRevokedError";
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var DelegationExpiredError = class extends SignedByError {
|
|
103
|
+
constructor(message = "Delegation has expired") {
|
|
104
|
+
super(message);
|
|
105
|
+
this.name = "DelegationExpiredError";
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var InvalidProofError = class extends SignedByError {
|
|
109
|
+
constructor(message = "Invalid Groth16 proof") {
|
|
110
|
+
super(message);
|
|
111
|
+
this.name = "InvalidProofError";
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var MerkleRootExpiredError = class extends SignedByError {
|
|
115
|
+
constructor(message = "Merkle root is expired") {
|
|
116
|
+
super(message);
|
|
117
|
+
this.name = "MerkleRootExpiredError";
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var ScopeDeniedError = class extends SignedByError {
|
|
121
|
+
constructor(message = "Enterprise not in delegation scopes") {
|
|
122
|
+
super(message);
|
|
123
|
+
this.name = "ScopeDeniedError";
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
var RelayConnectionError = class extends SignedByError {
|
|
127
|
+
constructor(message = "Failed to connect to relay") {
|
|
128
|
+
super(message);
|
|
129
|
+
this.name = "RelayConnectionError";
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
var ApiError = class extends SignedByError {
|
|
133
|
+
errorCode;
|
|
134
|
+
statusCode;
|
|
135
|
+
constructor(message, errorCode, statusCode) {
|
|
136
|
+
super(message);
|
|
137
|
+
this.name = "ApiError";
|
|
138
|
+
this.errorCode = errorCode;
|
|
139
|
+
this.statusCode = statusCode;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/client.ts
|
|
144
|
+
var native = require_native();
|
|
145
|
+
var DEFAULT_RELAY_URL = "wss://relay.privacy-lion.com";
|
|
146
|
+
var DEFAULT_API_URL = "https://api.beta.privacy-lion.com";
|
|
147
|
+
var SignedByClient = class _SignedByClient {
|
|
148
|
+
nativeClient;
|
|
149
|
+
delegation;
|
|
150
|
+
constructor(nativeClient, delegation) {
|
|
151
|
+
this.nativeClient = nativeClient;
|
|
152
|
+
this.delegation = delegation;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Load a SignedByClient from a delegation file.
|
|
156
|
+
*
|
|
157
|
+
* @param path - Path to the delegation JSON file (kind 28250 event)
|
|
158
|
+
* @returns SignedByClient instance ready for authentication
|
|
159
|
+
* @throws {Error} If delegation file doesn't exist or is invalid
|
|
160
|
+
*/
|
|
161
|
+
static async fromDelegation(path) {
|
|
162
|
+
const delegationJson = (0, import_fs.readFileSync)(path, "utf-8");
|
|
163
|
+
const event = JSON.parse(delegationJson);
|
|
164
|
+
const content = JSON.parse(event.content);
|
|
165
|
+
const expiresAt = new Date(content.expiresAt);
|
|
166
|
+
if (expiresAt < /* @__PURE__ */ new Date()) {
|
|
167
|
+
throw new DelegationExpiredError();
|
|
168
|
+
}
|
|
169
|
+
const nativeClient = await native.SignedByClient.fromDelegationJson(delegationJson);
|
|
170
|
+
return new _SignedByClient(nativeClient, content);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get the agent's npub (public key in bech32 format).
|
|
174
|
+
*/
|
|
175
|
+
get npub() {
|
|
176
|
+
return native.getNpub(this.nativeClient);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get the delegation scopes (enterprise -> permissions mapping).
|
|
180
|
+
*/
|
|
181
|
+
get scopes() {
|
|
182
|
+
return this.delegation.scopes;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Authenticate to an enterprise and receive an OIDC token.
|
|
186
|
+
*
|
|
187
|
+
* @param request - Login request parameters
|
|
188
|
+
* @param options - Optional configuration
|
|
189
|
+
* @returns LoginToken containing the OIDC id_token
|
|
190
|
+
* @throws {DelegationRevokedError} If delegation has been revoked
|
|
191
|
+
* @throws {DelegationExpiredError} If delegation has expired
|
|
192
|
+
* @throws {ScopeDeniedError} If client_id not in delegation scopes
|
|
193
|
+
* @throws {MerkleRootExpiredError} If proof uses stale merkle root
|
|
194
|
+
*/
|
|
195
|
+
async login(request, options = {}) {
|
|
196
|
+
const { clientId, nonce } = request;
|
|
197
|
+
const relayUrl = options.relayUrl ?? DEFAULT_RELAY_URL;
|
|
198
|
+
const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
|
|
199
|
+
if (!this.scopes[clientId] && !Object.keys(this.scopes).some((k) => clientId.includes(k))) {
|
|
200
|
+
throw new ScopeDeniedError(`Not authorized for enterprise: ${clientId}`);
|
|
201
|
+
}
|
|
202
|
+
const proofResult = await native.generateLoginProof(this.nativeClient, clientId, nonce);
|
|
203
|
+
await native.publishProofEvent(this.nativeClient, relayUrl, proofResult);
|
|
204
|
+
const tokenResponse = await native.verifyAndGetToken(
|
|
205
|
+
this.nativeClient,
|
|
206
|
+
apiUrl,
|
|
207
|
+
proofResult,
|
|
208
|
+
clientId,
|
|
209
|
+
nonce
|
|
210
|
+
);
|
|
211
|
+
return {
|
|
212
|
+
idToken: tokenResponse.id_token,
|
|
213
|
+
tokenType: tokenResponse.token_type ?? "Bearer",
|
|
214
|
+
expiresIn: tokenResponse.expires_in ?? 3600,
|
|
215
|
+
sub: tokenResponse.sub
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/agent.ts
|
|
221
|
+
var import_fs2 = require("fs");
|
|
222
|
+
var native2 = require_native();
|
|
223
|
+
var SignedByAgent = class _SignedByAgent {
|
|
224
|
+
nativeAgent;
|
|
225
|
+
relayConnected = false;
|
|
226
|
+
_emailMapping = {};
|
|
227
|
+
constructor(nativeAgent) {
|
|
228
|
+
this.nativeAgent = nativeAgent;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Initialize a new agent or load existing identity.
|
|
232
|
+
*
|
|
233
|
+
* Creates DID keys and stores them securely if this is first run.
|
|
234
|
+
* Loads existing identity if storage already exists.
|
|
235
|
+
*
|
|
236
|
+
* @param storagePath - Directory for agent data (keys, witness cache)
|
|
237
|
+
* @returns SignedByAgent instance
|
|
238
|
+
*/
|
|
239
|
+
static async init(storagePath) {
|
|
240
|
+
if (!(0, import_fs2.existsSync)(storagePath)) {
|
|
241
|
+
(0, import_fs2.mkdirSync)(storagePath, { recursive: true });
|
|
242
|
+
}
|
|
243
|
+
const nativeAgent = await native2.SignedByAgent.init(storagePath);
|
|
244
|
+
return new _SignedByAgent(nativeAgent);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get the agent's npub (public key in bech32 format).
|
|
248
|
+
*/
|
|
249
|
+
get npub() {
|
|
250
|
+
return native2.getAgentNpub(this.nativeAgent);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Set email mapping for enterprises.
|
|
254
|
+
*
|
|
255
|
+
* This tells the agent which email to provide during Gate 1
|
|
256
|
+
* enrollment for each enterprise domain.
|
|
257
|
+
*
|
|
258
|
+
* @param mapping - Dict of enterprise domain -> email address
|
|
259
|
+
*/
|
|
260
|
+
setEmailMapping(mapping) {
|
|
261
|
+
this._emailMapping = mapping;
|
|
262
|
+
native2.setEmailMapping(this.nativeAgent, mapping);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Connect to a NOSTR relay.
|
|
266
|
+
*
|
|
267
|
+
* @param relayUrl - WebSocket URL of the relay
|
|
268
|
+
*/
|
|
269
|
+
async connectRelay(relayUrl) {
|
|
270
|
+
try {
|
|
271
|
+
await native2.connectRelay(this.nativeAgent, relayUrl);
|
|
272
|
+
this.relayConnected = true;
|
|
273
|
+
} catch (error) {
|
|
274
|
+
throw new RelayConnectionError(`Failed to connect to ${relayUrl}: ${error}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Watch for kind 28200 authorization events addressed to this agent.
|
|
279
|
+
*
|
|
280
|
+
* @yields AuthorizationEvent for each incoming authorization request
|
|
281
|
+
*/
|
|
282
|
+
async *watchForAuthorizations() {
|
|
283
|
+
if (!this.relayConnected) {
|
|
284
|
+
throw new Error("Not connected to relay. Call connectRelay() first.");
|
|
285
|
+
}
|
|
286
|
+
const eventIterator = native2.subscribeAuthorizations(this.nativeAgent);
|
|
287
|
+
for await (const eventJson of eventIterator) {
|
|
288
|
+
const event = JSON.parse(eventJson);
|
|
289
|
+
yield {
|
|
290
|
+
enterprise: event.enterprise ?? "unknown",
|
|
291
|
+
clientId: event.client_id,
|
|
292
|
+
scopes: event.scopes ?? [],
|
|
293
|
+
eventId: event.id,
|
|
294
|
+
createdAt: event.created_at
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get recent agent activity (kinds 28101, 28102, 28103).
|
|
300
|
+
*
|
|
301
|
+
* @param limit - Maximum number of events to return
|
|
302
|
+
* @returns List of activity events
|
|
303
|
+
*/
|
|
304
|
+
getActivityLog(limit = 100) {
|
|
305
|
+
return native2.getActivityLog(this.nativeAgent, limit);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
309
|
+
0 && (module.exports = {
|
|
310
|
+
ApiError,
|
|
311
|
+
DelegationExpiredError,
|
|
312
|
+
DelegationRevokedError,
|
|
313
|
+
InvalidProofError,
|
|
314
|
+
MerkleRootExpiredError,
|
|
315
|
+
RelayConnectionError,
|
|
316
|
+
ScopeDeniedError,
|
|
317
|
+
SignedByAgent,
|
|
318
|
+
SignedByClient,
|
|
319
|
+
SignedByError
|
|
320
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/native.ts
|
|
13
|
+
import { platform, arch } from "os";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
var require_native = __commonJS({
|
|
16
|
+
"src/native.ts"(exports, module) {
|
|
17
|
+
"use strict";
|
|
18
|
+
function loadNativeBinding() {
|
|
19
|
+
const platformName = platform();
|
|
20
|
+
const archName = arch();
|
|
21
|
+
let nativeBinding;
|
|
22
|
+
const platformMap = {
|
|
23
|
+
darwin: {
|
|
24
|
+
x64: "@signedby/core-darwin-x64",
|
|
25
|
+
arm64: "@signedby/core-darwin-arm64"
|
|
26
|
+
},
|
|
27
|
+
linux: {
|
|
28
|
+
x64: "@signedby/core-linux-x64-gnu",
|
|
29
|
+
arm64: "@signedby/core-linux-arm64-gnu"
|
|
30
|
+
},
|
|
31
|
+
win32: {
|
|
32
|
+
x64: "@signedby/core-win32-x64-msvc"
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const packageName = platformMap[platformName]?.[archName];
|
|
36
|
+
if (!packageName) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Unsupported platform: ${platformName}-${archName}. SignedByMe SDK supports: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
nativeBinding = __require(packageName);
|
|
43
|
+
} catch (loadError) {
|
|
44
|
+
try {
|
|
45
|
+
nativeBinding = __require(join(__dirname, "..", "native", `signedby_core.${platformName}.node`));
|
|
46
|
+
} catch {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Failed to load native module for ${platformName}-${archName}. Install with: npm install ${packageName}
|
|
49
|
+
Original error: ${loadError}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return nativeBinding;
|
|
54
|
+
}
|
|
55
|
+
module.exports = loadNativeBinding();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// src/client.ts
|
|
60
|
+
import { readFileSync } from "fs";
|
|
61
|
+
|
|
62
|
+
// src/errors.ts
|
|
63
|
+
var SignedByError = class extends Error {
|
|
64
|
+
constructor(message) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = "SignedByError";
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var DelegationRevokedError = class extends SignedByError {
|
|
70
|
+
constructor(message = "Delegation has been revoked") {
|
|
71
|
+
super(message);
|
|
72
|
+
this.name = "DelegationRevokedError";
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var DelegationExpiredError = class extends SignedByError {
|
|
76
|
+
constructor(message = "Delegation has expired") {
|
|
77
|
+
super(message);
|
|
78
|
+
this.name = "DelegationExpiredError";
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
var InvalidProofError = class extends SignedByError {
|
|
82
|
+
constructor(message = "Invalid Groth16 proof") {
|
|
83
|
+
super(message);
|
|
84
|
+
this.name = "InvalidProofError";
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var MerkleRootExpiredError = class extends SignedByError {
|
|
88
|
+
constructor(message = "Merkle root is expired") {
|
|
89
|
+
super(message);
|
|
90
|
+
this.name = "MerkleRootExpiredError";
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var ScopeDeniedError = class extends SignedByError {
|
|
94
|
+
constructor(message = "Enterprise not in delegation scopes") {
|
|
95
|
+
super(message);
|
|
96
|
+
this.name = "ScopeDeniedError";
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
var RelayConnectionError = class extends SignedByError {
|
|
100
|
+
constructor(message = "Failed to connect to relay") {
|
|
101
|
+
super(message);
|
|
102
|
+
this.name = "RelayConnectionError";
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
var ApiError = class extends SignedByError {
|
|
106
|
+
errorCode;
|
|
107
|
+
statusCode;
|
|
108
|
+
constructor(message, errorCode, statusCode) {
|
|
109
|
+
super(message);
|
|
110
|
+
this.name = "ApiError";
|
|
111
|
+
this.errorCode = errorCode;
|
|
112
|
+
this.statusCode = statusCode;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// src/client.ts
|
|
117
|
+
var native = require_native();
|
|
118
|
+
var DEFAULT_RELAY_URL = "wss://relay.privacy-lion.com";
|
|
119
|
+
var DEFAULT_API_URL = "https://api.beta.privacy-lion.com";
|
|
120
|
+
var SignedByClient = class _SignedByClient {
|
|
121
|
+
nativeClient;
|
|
122
|
+
delegation;
|
|
123
|
+
constructor(nativeClient, delegation) {
|
|
124
|
+
this.nativeClient = nativeClient;
|
|
125
|
+
this.delegation = delegation;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Load a SignedByClient from a delegation file.
|
|
129
|
+
*
|
|
130
|
+
* @param path - Path to the delegation JSON file (kind 28250 event)
|
|
131
|
+
* @returns SignedByClient instance ready for authentication
|
|
132
|
+
* @throws {Error} If delegation file doesn't exist or is invalid
|
|
133
|
+
*/
|
|
134
|
+
static async fromDelegation(path) {
|
|
135
|
+
const delegationJson = readFileSync(path, "utf-8");
|
|
136
|
+
const event = JSON.parse(delegationJson);
|
|
137
|
+
const content = JSON.parse(event.content);
|
|
138
|
+
const expiresAt = new Date(content.expiresAt);
|
|
139
|
+
if (expiresAt < /* @__PURE__ */ new Date()) {
|
|
140
|
+
throw new DelegationExpiredError();
|
|
141
|
+
}
|
|
142
|
+
const nativeClient = await native.SignedByClient.fromDelegationJson(delegationJson);
|
|
143
|
+
return new _SignedByClient(nativeClient, content);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get the agent's npub (public key in bech32 format).
|
|
147
|
+
*/
|
|
148
|
+
get npub() {
|
|
149
|
+
return native.getNpub(this.nativeClient);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get the delegation scopes (enterprise -> permissions mapping).
|
|
153
|
+
*/
|
|
154
|
+
get scopes() {
|
|
155
|
+
return this.delegation.scopes;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Authenticate to an enterprise and receive an OIDC token.
|
|
159
|
+
*
|
|
160
|
+
* @param request - Login request parameters
|
|
161
|
+
* @param options - Optional configuration
|
|
162
|
+
* @returns LoginToken containing the OIDC id_token
|
|
163
|
+
* @throws {DelegationRevokedError} If delegation has been revoked
|
|
164
|
+
* @throws {DelegationExpiredError} If delegation has expired
|
|
165
|
+
* @throws {ScopeDeniedError} If client_id not in delegation scopes
|
|
166
|
+
* @throws {MerkleRootExpiredError} If proof uses stale merkle root
|
|
167
|
+
*/
|
|
168
|
+
async login(request, options = {}) {
|
|
169
|
+
const { clientId, nonce } = request;
|
|
170
|
+
const relayUrl = options.relayUrl ?? DEFAULT_RELAY_URL;
|
|
171
|
+
const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
|
|
172
|
+
if (!this.scopes[clientId] && !Object.keys(this.scopes).some((k) => clientId.includes(k))) {
|
|
173
|
+
throw new ScopeDeniedError(`Not authorized for enterprise: ${clientId}`);
|
|
174
|
+
}
|
|
175
|
+
const proofResult = await native.generateLoginProof(this.nativeClient, clientId, nonce);
|
|
176
|
+
await native.publishProofEvent(this.nativeClient, relayUrl, proofResult);
|
|
177
|
+
const tokenResponse = await native.verifyAndGetToken(
|
|
178
|
+
this.nativeClient,
|
|
179
|
+
apiUrl,
|
|
180
|
+
proofResult,
|
|
181
|
+
clientId,
|
|
182
|
+
nonce
|
|
183
|
+
);
|
|
184
|
+
return {
|
|
185
|
+
idToken: tokenResponse.id_token,
|
|
186
|
+
tokenType: tokenResponse.token_type ?? "Bearer",
|
|
187
|
+
expiresIn: tokenResponse.expires_in ?? 3600,
|
|
188
|
+
sub: tokenResponse.sub
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/agent.ts
|
|
194
|
+
import { mkdirSync, existsSync } from "fs";
|
|
195
|
+
var native2 = require_native();
|
|
196
|
+
var SignedByAgent = class _SignedByAgent {
|
|
197
|
+
nativeAgent;
|
|
198
|
+
relayConnected = false;
|
|
199
|
+
_emailMapping = {};
|
|
200
|
+
constructor(nativeAgent) {
|
|
201
|
+
this.nativeAgent = nativeAgent;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Initialize a new agent or load existing identity.
|
|
205
|
+
*
|
|
206
|
+
* Creates DID keys and stores them securely if this is first run.
|
|
207
|
+
* Loads existing identity if storage already exists.
|
|
208
|
+
*
|
|
209
|
+
* @param storagePath - Directory for agent data (keys, witness cache)
|
|
210
|
+
* @returns SignedByAgent instance
|
|
211
|
+
*/
|
|
212
|
+
static async init(storagePath) {
|
|
213
|
+
if (!existsSync(storagePath)) {
|
|
214
|
+
mkdirSync(storagePath, { recursive: true });
|
|
215
|
+
}
|
|
216
|
+
const nativeAgent = await native2.SignedByAgent.init(storagePath);
|
|
217
|
+
return new _SignedByAgent(nativeAgent);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get the agent's npub (public key in bech32 format).
|
|
221
|
+
*/
|
|
222
|
+
get npub() {
|
|
223
|
+
return native2.getAgentNpub(this.nativeAgent);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Set email mapping for enterprises.
|
|
227
|
+
*
|
|
228
|
+
* This tells the agent which email to provide during Gate 1
|
|
229
|
+
* enrollment for each enterprise domain.
|
|
230
|
+
*
|
|
231
|
+
* @param mapping - Dict of enterprise domain -> email address
|
|
232
|
+
*/
|
|
233
|
+
setEmailMapping(mapping) {
|
|
234
|
+
this._emailMapping = mapping;
|
|
235
|
+
native2.setEmailMapping(this.nativeAgent, mapping);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Connect to a NOSTR relay.
|
|
239
|
+
*
|
|
240
|
+
* @param relayUrl - WebSocket URL of the relay
|
|
241
|
+
*/
|
|
242
|
+
async connectRelay(relayUrl) {
|
|
243
|
+
try {
|
|
244
|
+
await native2.connectRelay(this.nativeAgent, relayUrl);
|
|
245
|
+
this.relayConnected = true;
|
|
246
|
+
} catch (error) {
|
|
247
|
+
throw new RelayConnectionError(`Failed to connect to ${relayUrl}: ${error}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Watch for kind 28200 authorization events addressed to this agent.
|
|
252
|
+
*
|
|
253
|
+
* @yields AuthorizationEvent for each incoming authorization request
|
|
254
|
+
*/
|
|
255
|
+
async *watchForAuthorizations() {
|
|
256
|
+
if (!this.relayConnected) {
|
|
257
|
+
throw new Error("Not connected to relay. Call connectRelay() first.");
|
|
258
|
+
}
|
|
259
|
+
const eventIterator = native2.subscribeAuthorizations(this.nativeAgent);
|
|
260
|
+
for await (const eventJson of eventIterator) {
|
|
261
|
+
const event = JSON.parse(eventJson);
|
|
262
|
+
yield {
|
|
263
|
+
enterprise: event.enterprise ?? "unknown",
|
|
264
|
+
clientId: event.client_id,
|
|
265
|
+
scopes: event.scopes ?? [],
|
|
266
|
+
eventId: event.id,
|
|
267
|
+
createdAt: event.created_at
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Get recent agent activity (kinds 28101, 28102, 28103).
|
|
273
|
+
*
|
|
274
|
+
* @param limit - Maximum number of events to return
|
|
275
|
+
* @returns List of activity events
|
|
276
|
+
*/
|
|
277
|
+
getActivityLog(limit = 100) {
|
|
278
|
+
return native2.getActivityLog(this.nativeAgent, limit);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
export {
|
|
282
|
+
ApiError,
|
|
283
|
+
DelegationExpiredError,
|
|
284
|
+
DelegationRevokedError,
|
|
285
|
+
InvalidProofError,
|
|
286
|
+
MerkleRootExpiredError,
|
|
287
|
+
RelayConnectionError,
|
|
288
|
+
ScopeDeniedError,
|
|
289
|
+
SignedByAgent,
|
|
290
|
+
SignedByClient,
|
|
291
|
+
SignedByError
|
|
292
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@signedby/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SignedByMe SDK - Human-controlled identity for autonomous agents",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
21
|
+
"test": "vitest",
|
|
22
|
+
"lint": "eslint src/",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"signedby",
|
|
27
|
+
"identity",
|
|
28
|
+
"zk-proofs",
|
|
29
|
+
"zero-knowledge",
|
|
30
|
+
"nostr",
|
|
31
|
+
"bitcoin",
|
|
32
|
+
"lightning",
|
|
33
|
+
"authentication",
|
|
34
|
+
"oidc",
|
|
35
|
+
"did"
|
|
36
|
+
],
|
|
37
|
+
"author": "Privacy Lion <contact@privacy-lion.com>",
|
|
38
|
+
"license": "SSAL-1.0",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/PrivacyLion/SignedByMe.git",
|
|
42
|
+
"directory": "sdk/typescript"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://signedbyme.com",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/PrivacyLion/SignedByMe/issues"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18.0.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^20.0.0",
|
|
53
|
+
"tsup": "^8.0.0",
|
|
54
|
+
"typescript": "^5.0.0",
|
|
55
|
+
"vitest": "^1.0.0",
|
|
56
|
+
"eslint": "^8.0.0",
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
58
|
+
"@typescript-eslint/parser": "^6.0.0"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@noble/curves": "^1.3.0",
|
|
62
|
+
"@noble/hashes": "^1.3.0"
|
|
63
|
+
},
|
|
64
|
+
"optionalDependencies": {
|
|
65
|
+
"@signedby/core-linux-x64-gnu": "0.1.0",
|
|
66
|
+
"@signedby/core-linux-arm64-gnu": "0.1.0",
|
|
67
|
+
"@signedby/core-darwin-x64": "0.1.0",
|
|
68
|
+
"@signedby/core-darwin-arm64": "0.1.0",
|
|
69
|
+
"@signedby/core-win32-x64-msvc": "0.1.0"
|
|
70
|
+
}
|
|
71
|
+
}
|