@auths-dev/sdk 0.0.1 → 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.
Files changed (60) hide show
  1. package/Cargo.toml +45 -0
  2. package/README.md +163 -4
  3. package/__test__/client.spec.ts +78 -0
  4. package/__test__/exports.spec.ts +57 -0
  5. package/__test__/integration.spec.ts +407 -0
  6. package/__test__/policy.spec.ts +202 -0
  7. package/__test__/verify.spec.ts +88 -0
  8. package/build.rs +5 -0
  9. package/index.d.ts +259 -0
  10. package/index.js +622 -1
  11. package/lib/artifacts.ts +124 -0
  12. package/lib/attestations.ts +126 -0
  13. package/lib/audit.ts +189 -0
  14. package/lib/client.ts +293 -0
  15. package/lib/commits.ts +70 -0
  16. package/lib/devices.ts +178 -0
  17. package/lib/errors.ts +306 -0
  18. package/lib/identity.ts +280 -0
  19. package/lib/index.ts +125 -0
  20. package/lib/native.ts +255 -0
  21. package/lib/org.ts +235 -0
  22. package/lib/pairing.ts +271 -0
  23. package/lib/policy.ts +669 -0
  24. package/lib/signing.ts +204 -0
  25. package/lib/trust.ts +152 -0
  26. package/lib/types.ts +179 -0
  27. package/lib/verify.ts +241 -0
  28. package/lib/witness.ts +91 -0
  29. package/npm/darwin-arm64/README.md +3 -0
  30. package/npm/darwin-arm64/package.json +23 -0
  31. package/npm/linux-arm64-gnu/README.md +3 -0
  32. package/npm/linux-arm64-gnu/package.json +26 -0
  33. package/npm/linux-x64-gnu/README.md +3 -0
  34. package/npm/linux-x64-gnu/package.json +26 -0
  35. package/npm/win32-arm64-msvc/README.md +3 -0
  36. package/npm/win32-arm64-msvc/package.json +23 -0
  37. package/npm/win32-x64-msvc/README.md +3 -0
  38. package/npm/win32-x64-msvc/package.json +23 -0
  39. package/package.json +51 -16
  40. package/src/artifact.rs +217 -0
  41. package/src/attestation_query.rs +104 -0
  42. package/src/audit.rs +128 -0
  43. package/src/commit_sign.rs +63 -0
  44. package/src/device.rs +212 -0
  45. package/src/diagnostics.rs +106 -0
  46. package/src/error.rs +5 -0
  47. package/src/helpers.rs +60 -0
  48. package/src/identity.rs +467 -0
  49. package/src/lib.rs +26 -0
  50. package/src/org.rs +430 -0
  51. package/src/pairing.rs +454 -0
  52. package/src/policy.rs +147 -0
  53. package/src/sign.rs +215 -0
  54. package/src/trust.rs +189 -0
  55. package/src/types.rs +205 -0
  56. package/src/verify.rs +447 -0
  57. package/src/witness.rs +138 -0
  58. package/tsconfig.json +19 -0
  59. package/typedoc.json +18 -0
  60. package/vitest.config.ts +12 -0
package/lib/pairing.ts ADDED
@@ -0,0 +1,271 @@
1
+ import native from './native'
2
+ import { mapNativeError, PairingError } from './errors'
3
+ import type { Auths } from './client'
4
+
5
+ /** An active pairing session awaiting a device connection. */
6
+ export interface PairingSession {
7
+ /** Unique session identifier. */
8
+ sessionId: string
9
+ /** Six-character code the device enters to pair. */
10
+ shortCode: string
11
+ /** HTTP endpoint the device connects to. */
12
+ endpoint: string
13
+ /** Authentication token for the session. */
14
+ token: string
15
+ /** DID of the controller identity running the session. */
16
+ controllerDid: string
17
+ }
18
+
19
+ /** Response received when a device connects to a pairing session. */
20
+ export interface PairingResponse {
21
+ /** DID of the connecting device. */
22
+ deviceDid: string
23
+ /** Optional name of the device, or `null`. */
24
+ deviceName: string | null
25
+ /** Hex-encoded Ed25519 public key of the device. */
26
+ devicePublicKeyHex: string
27
+ }
28
+
29
+ /** Result of completing a pairing and authorizing the device. */
30
+ export interface PairingResult {
31
+ /** DID of the paired device. */
32
+ deviceDid: string
33
+ /** Optional name of the device, or `null`. */
34
+ deviceName: string | null
35
+ /** Resource identifier of the authorization attestation. */
36
+ attestationRid: string
37
+ }
38
+
39
+ /** Options for {@link PairingService.createSession}. */
40
+ export interface CreatePairingSessionOptions {
41
+ /** Capabilities to offer the pairing device (e.g. `['sign:commit']`). */
42
+ capabilities?: string[]
43
+ /** Timeout in seconds for the session. */
44
+ timeoutSecs?: number
45
+ /** Bind address for the pairing server (e.g. `'127.0.0.1'`). */
46
+ bindAddress?: string
47
+ /** Whether to enable mDNS discovery. */
48
+ enableMdns?: boolean
49
+ /** Override the client's passphrase. */
50
+ passphrase?: string
51
+ }
52
+
53
+ /** Options for {@link PairingService.waitForResponse}. */
54
+ export interface WaitForPairingResponseOptions {
55
+ /** Timeout in seconds to wait for a device. */
56
+ timeoutSecs?: number
57
+ }
58
+
59
+ /** Options for {@link PairingService.join}. */
60
+ export interface JoinPairingOptions {
61
+ /** Six-character short code from the pairing session. */
62
+ shortCode: string
63
+ /** HTTP endpoint of the pairing session. */
64
+ endpoint: string
65
+ /** Authentication token for the session. */
66
+ token: string
67
+ /** Optional name for this device. */
68
+ deviceName?: string
69
+ /** Override the client's passphrase. */
70
+ passphrase?: string
71
+ }
72
+
73
+ /** Options for {@link PairingService.complete}. */
74
+ export interface CompletePairingOptions {
75
+ /** DID of the device to authorize. */
76
+ deviceDid: string
77
+ /** Hex-encoded Ed25519 public key of the device. */
78
+ devicePublicKeyHex: string
79
+ /** Capabilities to grant the device. */
80
+ capabilities?: string[]
81
+ /** Override the client's passphrase. */
82
+ passphrase?: string
83
+ }
84
+
85
+ /**
86
+ * Handles device pairing for cross-device identity authorization.
87
+ *
88
+ * The pairing flow: controller creates a session, device joins with the
89
+ * short code, controller completes pairing to authorize the device.
90
+ *
91
+ * Access via {@link Auths.pairing}.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const session = await auths.pairing.createSession({
96
+ * bindAddress: '127.0.0.1',
97
+ * capabilities: ['sign:commit'],
98
+ * })
99
+ * console.log(session.shortCode) // e.g. 'A3F7K2'
100
+ *
101
+ * // On the device side:
102
+ * const response = await auths.pairing.join({
103
+ * shortCode: 'A3F7K2',
104
+ * endpoint: session.endpoint,
105
+ * token: session.token,
106
+ * })
107
+ * ```
108
+ */
109
+ export class PairingService {
110
+ private handle: any | null = null
111
+
112
+ constructor(private client: Auths) {}
113
+
114
+ /**
115
+ * Creates a pairing session and starts listening for device connections.
116
+ *
117
+ * @param opts - Session options.
118
+ * @returns The active pairing session with its short code and endpoint.
119
+ * @throws {@link PairingError} if session creation fails.
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const session = await auths.pairing.createSession({
124
+ * bindAddress: '127.0.0.1',
125
+ * enableMdns: false,
126
+ * })
127
+ * console.log(session.shortCode) // 6-char code
128
+ * ```
129
+ */
130
+ async createSession(opts?: CreatePairingSessionOptions): Promise<PairingSession> {
131
+ const pp = opts?.passphrase ?? this.client.passphrase
132
+ const capsJson = opts?.capabilities ? JSON.stringify(opts.capabilities) : null
133
+ try {
134
+ this.handle = await native.NapiPairingHandle.createSession(
135
+ this.client.repoPath,
136
+ capsJson,
137
+ opts?.timeoutSecs ?? null,
138
+ opts?.bindAddress ?? null,
139
+ opts?.enableMdns ?? null,
140
+ pp,
141
+ )
142
+ const session = this.handle.session
143
+ return {
144
+ sessionId: session.sessionId,
145
+ shortCode: session.shortCode,
146
+ endpoint: session.endpoint,
147
+ token: session.token,
148
+ controllerDid: session.controllerDid,
149
+ }
150
+ } catch (err) {
151
+ throw mapNativeError(err, PairingError)
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Waits for a device to connect to the active pairing session.
157
+ *
158
+ * @param opts - Wait options.
159
+ * @returns The connecting device's information.
160
+ * @throws {@link PairingError} if no session is active or timeout is reached.
161
+ */
162
+ async waitForResponse(opts?: WaitForPairingResponseOptions): Promise<PairingResponse> {
163
+ if (!this.handle) {
164
+ throw new PairingError('No active pairing session. Call createSession first.', 'AUTHS_PAIRING_ERROR')
165
+ }
166
+ try {
167
+ const result = await this.handle.waitForResponse(opts?.timeoutSecs ?? null)
168
+ return {
169
+ deviceDid: result.deviceDid,
170
+ deviceName: result.deviceName ?? null,
171
+ devicePublicKeyHex: result.devicePublicKeyHex,
172
+ }
173
+ } catch (err) {
174
+ throw mapNativeError(err, PairingError)
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Stops the active pairing session. Idempotent — safe to call multiple times.
180
+ *
181
+ * @throws {@link PairingError} if stopping the session fails.
182
+ */
183
+ async stop(): Promise<void> {
184
+ if (this.handle) {
185
+ try {
186
+ await this.handle.stop()
187
+ } catch (err) {
188
+ throw mapNativeError(err, PairingError)
189
+ } finally {
190
+ this.handle = null
191
+ }
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Joins an existing pairing session from the device side.
197
+ *
198
+ * @param opts - Join options with short code and endpoint from the controller.
199
+ * @returns The pairing response with device identity information.
200
+ * @throws {@link PairingError} if joining fails.
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * const response = await auths.pairing.join({
205
+ * shortCode: 'A3F7K2',
206
+ * endpoint: 'http://127.0.0.1:8080',
207
+ * token: sessionToken,
208
+ * })
209
+ * ```
210
+ */
211
+ async join(opts: JoinPairingOptions): Promise<PairingResponse> {
212
+ const pp = opts.passphrase ?? this.client.passphrase
213
+ try {
214
+ const result = await native.joinPairingSession(
215
+ opts.shortCode,
216
+ opts.endpoint,
217
+ opts.token,
218
+ this.client.repoPath,
219
+ opts.deviceName ?? null,
220
+ pp,
221
+ )
222
+ return {
223
+ deviceDid: result.deviceDid,
224
+ deviceName: result.deviceName ?? null,
225
+ devicePublicKeyHex: result.devicePublicKeyHex,
226
+ }
227
+ } catch (err) {
228
+ throw mapNativeError(err, PairingError)
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Completes pairing by authorizing the connected device.
234
+ *
235
+ * @param opts - Completion options with device identity and capabilities.
236
+ * @returns The pairing result with the device's authorization attestation.
237
+ * @throws {@link PairingError} if no session is active or completion fails.
238
+ */
239
+ async complete(opts: CompletePairingOptions): Promise<PairingResult> {
240
+ if (!this.handle) {
241
+ throw new PairingError('No active pairing session. Call createSession first.', 'AUTHS_PAIRING_ERROR')
242
+ }
243
+ const pp = opts.passphrase ?? this.client.passphrase
244
+ const capsJson = opts.capabilities ? JSON.stringify(opts.capabilities) : null
245
+ try {
246
+ const result = await this.handle.complete(
247
+ opts.deviceDid,
248
+ opts.devicePublicKeyHex,
249
+ this.client.repoPath,
250
+ capsJson,
251
+ pp,
252
+ )
253
+ return {
254
+ deviceDid: result.deviceDid,
255
+ deviceName: result.deviceName ?? null,
256
+ attestationRid: result.attestationRid,
257
+ }
258
+ } catch (err) {
259
+ throw mapNativeError(err, PairingError)
260
+ }
261
+ }
262
+
263
+ [Symbol.dispose](): void {
264
+ // Fire-and-forget stop for sync dispose
265
+ this.stop().catch(() => {})
266
+ }
267
+
268
+ async [Symbol.asyncDispose](): Promise<void> {
269
+ await this.stop()
270
+ }
271
+ }