@synonymdev/pubky 0.5.4 → 0.6.0-rc.6

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 (6) hide show
  1. package/README.md +265 -154
  2. package/index.cjs +1932 -400
  3. package/index.js +2068 -475
  4. package/package.json +10 -5
  5. package/pubky.d.ts +818 -84
  6. package/pubky_bg.wasm +0 -0
package/pubky.d.ts CHANGED
@@ -1,16 +1,175 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
3
  /**
4
- * Create a recovery file of the `keypair`, containing the secret key encrypted
5
- * using the `passphrase`.
4
+ * Set the global logging verbosity for the WASM Pubky SDK. Routes Rust `log` output to the browser console.
5
+ *
6
+ * Accepted values (case-sensitive): "error" | "warn" | "info" | "debug" | "trace".
7
+ * Effects:
8
+ * - Initializes the logger once; subsequent calls may throw if the logger is already set.
9
+ * - Emits a single info log: `Log level set to: <level>`.
10
+ * - Messages at or above `level` are forwarded to the appropriate `console.*` method.
11
+ *
12
+ * @param {Level} level
13
+ * Minimum log level to enable. One of: "error" | "warn" | "info" | "debug" | "trace".
14
+ *
15
+ * @returns {void}
16
+ *
17
+ * @throws {Error}
18
+ * If `level` is invalid ("Invalid log level") or the logger cannot be initialized
19
+ * (e.g., already initialized).
20
+ *
21
+ * Usage:
22
+ * Call once at application startup, before invoking other SDK APIs.
6
23
  */
7
- export function createRecoveryFile(keypair: Keypair, passphrase: string): Uint8Array;
24
+ export function setLogLevel(level: Level): void;
8
25
  /**
9
- * Create a recovery file of the `keypair`, containing the secret key encrypted
10
- * using the `passphrase`.
26
+ * Resolve a `pubky://` or `pubky<pk>/…` identifier into the homeserver transport URL.
27
+ *
28
+ * @param {string} identifier Either `pubky<pk>/...` (preferred) or `pubky://<pk>/...`.
29
+ * @returns {string} HTTPS URL in the form `https://_pubky.<pk>/...`.
11
30
  */
12
- export function decryptRecoveryFile(recovery_file: Uint8Array, passphrase: string): Keypair;
13
- export function setLogLevel(level: string): void;
31
+ export function resolvePubky(identifier: string): string;
32
+ /**
33
+ * Validate and normalize a capabilities string.
34
+ *
35
+ * - Normalizes action order (`wr` -> `rw`)
36
+ * - Throws `InvalidInput` listing malformed entries.
37
+ *
38
+ * @param {string} input
39
+ * @returns {string} Normalized string (same shape as input).
40
+ * @throws {PubkyError} `{ name: "InvalidInput" }` with a helpful message.
41
+ * The error's `data` field is `{ invalidEntries: string[] }` listing malformed tokens.
42
+ */
43
+ export function validateCapabilities(input: string): string;
44
+ /**
45
+ * An enum representing the available verbosity levels of the logger.
46
+ */
47
+ type Level = "error" | "warn" | "info" | "debug" | "trace";
48
+ /**
49
+ * The `ReadableStreamType` enum.
50
+ *
51
+ * *This API requires the following crate features to be activated: `ReadableStreamType`*
52
+ */
53
+ type ReadableStreamType = "bytes";
54
+ /**
55
+ * Resource metadata returned by `SessionStorage.stats()` and `PublicStorage.stats()`.
56
+ *
57
+ * @typedef {Object} ResourceStats
58
+ * @property {number=} contentLength Size in bytes.
59
+ * @property {string=} contentType Media type (e.g. \"application/json; charset=utf-8\").
60
+ * @property {number=} lastModifiedMs Unix epoch milliseconds.
61
+ * @property {string=} etag Opaque server ETag for the current version.
62
+ *
63
+ * @example
64
+ * const stats = await pubky.publicStorage.stats(`${user}/pub/app/file.json`);
65
+ * if (stats) {
66
+ * console.log(stats.contentLength, stats.contentType, stats.lastModifiedMs);
67
+ * }
68
+ *
69
+ * Notes:
70
+ * - `contentLength` equals `getBytes(...).length`.
71
+ * - `etag` may be absent and is opaque; compare values to detect updates.
72
+ * - `lastModifiedMs` increases when the resource is updated.
73
+ */
74
+ export interface ResourceStats {
75
+ /**
76
+ * Size in bytes of the stored object.
77
+ */
78
+ contentLength?: number;
79
+ /**
80
+ * Media type of the stored object (e.g., `\"application/json\"`).
81
+ */
82
+ contentType?: string;
83
+ /**
84
+ * Unix epoch **milliseconds** for the last modification time.
85
+ */
86
+ lastModifiedMs?: number;
87
+ /**
88
+ * Opaque entity tag identifying the current stored version.
89
+ */
90
+ etag?: string;
91
+ }
92
+
93
+ export type Path = `/pub/${string}`;
94
+
95
+ /**
96
+ * A union type of all possible machine-readable codes for the `name` property
97
+ * of a {@link PubkyError}.
98
+ *
99
+ * Provides a simplified, actionable set of error categories for developers
100
+ * to handle in their code.
101
+ */
102
+ export type PubkyErrorName = "RequestError" | "InvalidInput" | "AuthenticationError" | "PkarrError" | "ClientStateError" | "InternalError";
103
+
104
+ /**
105
+ * Represents the standard error structure for all exceptions thrown by the Pubky
106
+ * WASM client.
107
+ *
108
+ * @property name - A machine-readable error code from {@link PubkyErrorName}. Use this for programmatic error handling.
109
+ * @property message - A human-readable, descriptive error message suitable for logging.
110
+ * @property data - An optional payload containing structured context for an error. For a `RequestError`, this may contain an object with the HTTP status code, e.g., `{ statusCode: 404 }`.
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * try {
115
+ * await client.signup(...);
116
+ * } catch (e) {
117
+ * const error = e as PubkyError;
118
+ * if (
119
+ * error.name === \'RequestError\' &&
120
+ * typeof error.data === \'object\' &&
121
+ * error.data !== null &&
122
+ * \'statusCode\' in error.data &&
123
+ * (error.data as { statusCode?: number }).statusCode === 404
124
+ * ) {
125
+ * // Handle not found...
126
+ * }
127
+ * }
128
+ * ```
129
+ */
130
+ export interface PubkyError {
131
+ name: PubkyErrorName;
132
+ message: string;
133
+ /**
134
+ * Optional structured context associated with the error.
135
+ */
136
+ data?: unknown;
137
+ }
138
+
139
+ /**
140
+ * Represents the standard error structure for all exceptions thrown by the Pubky
141
+ * WASM client.
142
+ *
143
+ * @property name - A machine-readable error code from {@link PubkyErrorName}. Use this for programmatic error handling.
144
+ * @property message - A human-readable, descriptive error message suitable for logging.
145
+ * @property data - An optional payload containing structured context for an error. For a `RequestError`, this may contain an object with the HTTP status code, e.g., `{ statusCode: 404 }`.
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * try {
150
+ * await client.signup(...);
151
+ * } catch (e) {
152
+ * const error = e as PubkyError;
153
+ * if (
154
+ * error.name === "RequestError" &&
155
+ * typeof error.data === "object" &&
156
+ * error.data !== null &&
157
+ * "statusCode" in error.data &&
158
+ * (error.data as { statusCode?: number }).statusCode === 404
159
+ * ) {
160
+ * // Handle not found...
161
+ * }
162
+ * }
163
+ * ```
164
+ */
165
+ export interface PubkyError extends Error {
166
+ name: PubkyErrorName;
167
+ message: string;
168
+ data?: unknown;
169
+ }
170
+
171
+ export type Address = `pubky${string}/pub/${string}` | `pubky://${string}/pub/${string}`;
172
+
14
173
  /**
15
174
  * Pkarr Config
16
175
  */
@@ -23,7 +182,7 @@ export interface PkarrConfig {
23
182
  * The timeout for DHT requests in milliseconds.
24
183
  * Default is 2000ms.
25
184
  */
26
- requestTimeout?: NonZeroU64;
185
+ requestTimeout?: number;
27
186
  }
28
187
 
29
188
  /**
@@ -34,114 +193,261 @@ export interface PubkyClientConfig {
34
193
  * Configuration on how to access pkarr packets on the mainline DHT.
35
194
  */
36
195
  pkarr?: PkarrConfig;
37
- /**
38
- * The maximum age of a record in seconds.
39
- * If the user pkarr record is older than this, it will be automatically refreshed.
40
- */
41
- userMaxRecordAge?: NonZeroU64;
42
196
  }
43
197
 
44
- export class AuthRequest {
198
+ export type CapabilityAction = "r" | "w" | "rw";
199
+ export type CapabilityScope = `/${string}`;
200
+ export type CapabilityEntry = `${CapabilityScope}:${CapabilityAction}`;
201
+ type CapabilitiesTail = `,${CapabilityEntry}${string}`;
202
+ export type Capabilities = "" | CapabilityEntry | `${CapabilityEntry}${CapabilitiesTail}`;
203
+
204
+ /**
205
+ * Start and control a pubkyauth authorization flow.
206
+ *
207
+ * Typical flow:
208
+ * 1) `AuthFlow.start(...)` or `pubky.startAuthFlow(...)`
209
+ * 2) Show `authorizationUrl()` as QR/deeplink to the user’s signing device
210
+ * 3) `awaitApproval()` to receive a ready `Session`
211
+ */
212
+ export class AuthFlow {
45
213
  private constructor();
46
214
  free(): void;
47
215
  /**
48
- * Returns the Pubky Auth url, which you should show to the user
49
- * to request an authentication or authorization token.
216
+ * Start a flow (standalone).
217
+ * Prefer `pubky.startAuthFlow()` to reuse a facade client.
218
+ *
219
+ * @param {string} capabilities
220
+ * Comma-separated capabilities, e.g. `"/pub/app/:rw,/priv/foo.txt:r"`.
221
+ * Each entry must be `"<scope>:<actions>"`, where:
222
+ * - `scope` starts with `/` (e.g. `/pub/example.app/`)
223
+ * - `actions` is any combo of `r` and/or `w` (order is normalized; `wr` -> `rw`)
224
+ * Empty string is allowed (no scopes).
50
225
  *
51
- * Wait for this token using `this.response()`.
226
+ * @param {string} [relay]
227
+ * Optional HTTP relay base, e.g. `"https://demo.httprelay.io/link/"`.
228
+ * Defaults to the default Synonym-hosted relay when omitted.
229
+ *
230
+ * @returns {AuthFlow}
231
+ * A running auth flow. Call `authorizationUrl()` to show the deep link,
232
+ * then `awaitApproval()` to receive a `Session`.
233
+ * @throws {PubkyError}
234
+ * - `{ name: "InvalidInput", message: string }` if any capability entry is invalid
235
+ * or for an invalid relay URL.
236
+ * @example
237
+ * const flow = AuthFlow.start("/pub/my.app/:rw,/pub/pubky.app/:w");
238
+ * renderQRCode(flow.authorizationUrl());
239
+ * const session = await flow.awaitApproval();
52
240
  */
53
- url(): string;
241
+ static start(capabilities: Capabilities, relay?: string | null): AuthFlow;
54
242
  /**
55
- * Wait for the user to send an authentication or authorization proof.
243
+ * Block until the user approves on their signer device; returns a `Session`.
56
244
  *
57
- * If successful, you should expect an instance of [PublicKey]
245
+ * @returns {Promise<Session>}
246
+ * Resolves when approved; rejects on timeout/cancel/network errors.
58
247
  *
59
- * Otherwise it will throw an error.
248
+ * @throws {PubkyError}
249
+ * - `RequestError` if relay/network fails
250
+ * - `AuthenticationError` if approval is denied/invalid
60
251
  */
61
- response(): Promise<PublicKey>;
62
- }
63
- export class Client {
64
- free(): void;
252
+ awaitApproval(): Promise<Session>;
65
253
  /**
66
- * Signup to a homeserver and update Pkarr accordingly.
254
+ * Block until the user approves on their signer device; returns an `AuthToken`.
67
255
  *
68
- * The homeserver is a Pkarr domain name, where the TLD is a Pkarr public key
69
- * for example "pubky.o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy"
256
+ * @returns {Promise<AuthToken>}
257
+ * Resolves when approved; rejects on timeout/cancel/network errors.
258
+ *
259
+ * @throws {PubkyError}
260
+ * - `RequestError` if relay/network fails
70
261
  */
71
- signup(keypair: Keypair, homeserver: PublicKey, signup_token?: string | null): Promise<Session>;
262
+ awaitToken(): Promise<AuthToken>;
72
263
  /**
73
- * Check the current session for a given Pubky in its homeserver.
264
+ * Non-blocking single poll step (advanced UIs).
74
265
  *
75
- * Returns [Session] or `None` (if received `404 NOT_FOUND`),
76
- * or throws the received error if the response has any other `>=400` status code.
266
+ * @returns {Promise<Session|undefined>} A session if the approval arrived, otherwise `undefined`.
77
267
  */
78
- session(pubky: PublicKey): Promise<Session | undefined>;
268
+ tryPollOnce(): Promise<Session | undefined>;
79
269
  /**
80
- * Signout from a homeserver.
270
+ * Return the authorization deep link (URL) to show as QR or open on the signer device.
271
+ *
272
+ * @returns {string} A `pubkyauth://…` or `https://…` URL with channel info.
273
+ *
274
+ * @example
275
+ * renderQr(flow.authorizationUrl());
81
276
  */
82
- signout(pubky: PublicKey): Promise<void>;
277
+ readonly authorizationUrl: string;
278
+ }
279
+ /**
280
+ * AuthToken: signed, time-bound proof of key ownership.
281
+ *
282
+ * Returned by [`AuthFlow.awaitToken()`] on the 3rd-party app side when doing **authentication-only**
283
+ * flows (no homeserver session). You can inspect who authenticated and which capabilities were
284
+ * requested, or serialize the token and send it to a backend to verify.
285
+ *
286
+ * ### Typical usage
287
+ * ```js
288
+ * // Start an auth-only flow (no capabilities)
289
+ * const flow = pubky.startAuthFlow("", relay);
290
+ *
291
+ * // Wait for the signer to approve; returns an AuthToken
292
+ * const token = await flow.awaitToken();
293
+ *
294
+ * // Identify the user
295
+ * console.log(token.publicKey().z32());
296
+ *
297
+ * // Optionally forward to a server for verification:
298
+ * await fetch("/api/verify", { method: "POST", body: token.toBytes() });
299
+ * ```
300
+ *
301
+ * ### Binary format
302
+ * `AuthToken` serializes to a canonical binary (postcard) form; use [`AuthToken.toBytes()`] to get a
303
+ * `Uint8Array`, and [`AuthToken.verify()`] to parse + verify on the server.
304
+ */
305
+ export class AuthToken {
306
+ private constructor();
307
+ free(): void;
83
308
  /**
84
- * Signin to a homeserver using the root Keypair.
309
+ * Parse and verify an `AuthToken` from its canonical bytes.
310
+ *
311
+ * - Verifies version, timestamp freshness window, and signature.
312
+ * - Throws on invalid/expired/unknown version.
313
+ *
314
+ * Use this on your server after receiving `Uint8Array` from the client.
315
+ *
316
+ * ```js
317
+ * import { AuthToken } from "@synonymdev/pubky";
318
+ *
319
+ * export async function POST(req) {
320
+ * const bytes = new Uint8Array(await req.arrayBuffer());
321
+ * const token = AuthToken.verify(bytes); // throws on failure
322
+ * return new Response(token.publicKey().z32(), { status: 200 });
323
+ * }
324
+ * ```
85
325
  */
86
- signin(keypair: Keypair): Promise<void>;
326
+ static verify(bytes: Uint8Array): AuthToken;
87
327
  /**
88
- * Return `pubkyauth://` url and wait for the incoming [AuthToken]
89
- * verifying that AuthToken, and if capabilities were requested, signing in to
90
- * the Pubky's homeserver and returning the [Session] information.
328
+ * Deserialize an `AuthToken` **without** verification.
329
+ *
330
+ * Most apps should call [`AuthToken.verify()`]. This is provided for tooling or diagnostics
331
+ * where you want to inspect the structure first.
91
332
  *
92
- * Returns a [AuthRequest]
333
+ * Throws if the bytes cannot be parsed as a valid serialized token.
93
334
  */
94
- authRequest(relay: string, capabilities: string): AuthRequest;
335
+ static fromBytes(bytes: Uint8Array): AuthToken;
95
336
  /**
96
- * Sign an [pubky_common::auth::AuthToken], encrypt it and send it to the
97
- * source of the pubkyauth request url.
337
+ * Serialize the token to a `Uint8Array` in its **canonical** (postcard) binary format.
338
+ *
339
+ * Use this to send the token to a backend for verification.
340
+ *
341
+ * ```js
342
+ * const bytes = token.toBytes();
343
+ * await fetch("/api/verify", { method: "POST", body: bytes });
344
+ * ```
98
345
  */
99
- sendAuthToken(keypair: Keypair, pubkyauth_url: string): Promise<void>;
346
+ toBytes(): Uint8Array;
100
347
  /**
101
- * Get the homeserver id for a given Pubky public key.
102
- * Looks up the pkarr packet for the given public key and returns the content of the first `_pubky` SVCB record.
103
- * Throws an error if no homeserver is found.
348
+ * Returns the **public key** that authenticated with this token.
349
+ *
350
+ * Use `.z32()` on the returned `PublicKey` to get the string form.
351
+ *
352
+ * @example
353
+ * const who = sessionInfo.publicKey.z32();
104
354
  */
105
- getHomeserver(public_key: PublicKey): Promise<PublicKey>;
355
+ readonly publicKey: PublicKey;
106
356
  /**
107
- * Republish the user's PKarr record pointing to their homeserver.
357
+ * Returns the **capabilities** requested by the flow at the time this token was signed.
108
358
  *
109
- * This method will republish the record if no record exists or if the existing record
110
- * is older than 6 hours.
359
+ * Most auth-only flows pass an empty string to `startAuthFlow("", relay)`, so this will
360
+ * commonly be an empty array.
111
361
  *
112
- * The method is intended for clients and key managers (e.g., pubky-ring) to
113
- * keep the records of active users fresh and available in the DHT and relays.
114
- * It is intended to be used only after failed signin due to homeserver resolution
115
- * failure. This method is lighter than performing a re-signup into the last known
116
- * homeserver, but does not return a session token, so a signin must be done after
117
- * republishing. On a failed signin due to homeserver resolution failure, a key
118
- * manager should always attempt to republish the last known homeserver.
362
+ * Returns: `string[]`, where each item is the canonical entry `"<scope>:<actions>"`.
363
+ *
364
+ * Example entry: `"/pub/my.app/:rw"`
119
365
  */
120
- republishHomeserver(keypair: Keypair, host: PublicKey): Promise<void>;
366
+ readonly capabilities: string[];
367
+ }
368
+ /**
369
+ * Low-level HTTP bridge used by the Pubky facade and actors.
370
+ *
371
+ * - Supports `http(s)://` URLs targeting Pubky or ICANN hosts.
372
+ * - In browsers/undici, passes `credentials: "include"` to send cookies.
373
+ */
374
+ export class Client {
375
+ free(): void;
121
376
  /**
122
- * Returns a list of Pubky urls (as strings).
377
+ * Perform a raw fetch. Works with `http(s)://` URLs.
123
378
  *
124
- * - `url`: The Pubky url (string) to the directory you want to list its content.
125
- * - `cursor`: Either a full `pubky://` Url (from previous list response),
126
- * or a path (to a file or directory) relative to the `url`
127
- * - `reverse`: List in reverse order
128
- * - `limit` Limit the number of urls in the response
129
- * - `shallow`: List directories and files, instead of flat list of files.
379
+ * @param {string} url
380
+ * @param {RequestInit} init Standard fetch options; `credentials: "include"` recommended for session I/O.
381
+ * @returns {Promise<Response>}
382
+ *
383
+ * @example
384
+ * const client = pubky.client;
385
+ * const res = await client.fetch(`https://_pubky.${user}/pub/app/file.txt`, { method: "PUT", body: "hi", credentials: "include" });
130
386
  */
131
- list(url: string, cursor?: string | null, reverse?: boolean | null, limit?: number | null, shallow?: boolean | null): Promise<Array<any>>;
132
- fetch(url: string, init?: any | null): Promise<Promise<any>>;
387
+ fetch(url: string, init?: RequestInit | null): Promise<Response>;
133
388
  /**
134
- * Create a new Pubky Client with an optional configuration.
389
+ * Create a Pubky HTTP client.
390
+ *
391
+ * @param {PubkyClientConfig} [config]
392
+ * Optional transport overrides:
393
+ * `{ pkarr?: { relays?: string[], request_timeout?: number } }`.
394
+ *
395
+ * @returns {Client}
396
+ * A configured low-level client. Prefer `new Pubky().client` unless you
397
+ * need custom relays/timeouts.
398
+ *
399
+ * @throws {InvalidInput}
400
+ * If any PKARR relay URL is invalid.
401
+ *
402
+ * @example
403
+ * const client = new Client({
404
+ * pkarr: { relays: ["https://relay1/","https://relay2/"], request_timeout: 8000 }
405
+ * });
406
+ * const pubky = Pubky.withClient(client);
135
407
  */
136
408
  constructor(config_opt?: PubkyClientConfig | null);
137
409
  /**
138
- * Create a client with with configurations appropriate for local testing:
139
- * - set Pkarr relays to `http://<host>:15411` (defaults to `localhost`).
140
- * - transform `pubky://<pkarr public key>` to `http://<host>` instead of `https:`
141
- * and read the homeserver HTTP port from the PKarr record.
410
+ * Create a client wired for **local testnet**.
411
+ *
412
+ * Configures PKARR relays for the testnet and remembers the hostname for WASM `_pubky` mapping.
413
+ *
414
+ * @param {string} [host="localhost"]
415
+ * Testnet hostname or IP.
416
+ *
417
+ * @returns {Client}
418
+ * A client ready to talk to your local testnet.
419
+ *
420
+ * @example
421
+ * const client = Client.testnet(); // localhost
422
+ * const pubky = Pubky.withClient(client);
423
+ *
424
+ * @example
425
+ * const client = Client.testnet("docker0"); // custom host
142
426
  */
143
427
  static testnet(host?: string | null): Client;
144
428
  }
429
+ export class IntoUnderlyingByteSource {
430
+ private constructor();
431
+ free(): void;
432
+ start(controller: ReadableByteStreamController): void;
433
+ pull(controller: ReadableByteStreamController): Promise<any>;
434
+ cancel(): void;
435
+ readonly type: ReadableStreamType;
436
+ readonly autoAllocateChunkSize: number;
437
+ }
438
+ export class IntoUnderlyingSink {
439
+ private constructor();
440
+ free(): void;
441
+ write(chunk: any): Promise<any>;
442
+ close(): Promise<any>;
443
+ abort(reason: any): Promise<any>;
444
+ }
445
+ export class IntoUnderlyingSource {
446
+ private constructor();
447
+ free(): void;
448
+ pull(controller: ReadableStreamDefaultController): Promise<any>;
449
+ cancel(): void;
450
+ }
145
451
  export class Keypair {
146
452
  private constructor();
147
453
  free(): void;
@@ -157,19 +463,182 @@ export class Keypair {
157
463
  * Returns the secret key of this keypair.
158
464
  */
159
465
  secretKey(): Uint8Array;
466
+ /**
467
+ * Create a recovery file for this keypair (encrypted with the given passphrase).
468
+ */
469
+ createRecoveryFile(passphrase: string): Uint8Array;
470
+ /**
471
+ * Decrypt a recovery file and return a Keypair (decrypted with the given passphrase).
472
+ */
473
+ static fromRecoveryFile(recovery_file: Uint8Array, passphrase: string): Keypair;
160
474
  /**
161
475
  * Returns the [PublicKey] of this keypair.
476
+ *
477
+ * Use `.z32()` on the returned `PublicKey` to get the string form.
478
+ *
479
+ * @example
480
+ * const who = keypair.publicKey.z32();
162
481
  */
163
- publicKey(): PublicKey;
482
+ readonly publicKey: PublicKey;
164
483
  }
165
- export class PublicKey {
166
- private constructor();
484
+ /**
485
+ * Resolve/publish `_pubky` PKDNS records (homeserver pointers).
486
+ */
487
+ export class Pkdns {
167
488
  free(): void;
168
489
  /**
169
- * Convert the PublicKey to Uint8Array
170
- * @deprecated Use `toUint8Array` instead
490
+ * Read-only PKDNS actor (no keypair; resolve only).
491
+ */
492
+ constructor();
493
+ /**
494
+ * PKDNS actor with publishing enabled (requires a keypair).
495
+ */
496
+ static fromKeypair(keypair: Keypair): Pkdns;
497
+ /**
498
+ * Resolve the homeserver for a given public key (read-only).
499
+ *
500
+ * @param {PublicKey} user
501
+ * @returns {Promise<PublicKey|undefined>} Homeserver public key or `undefined` if not found.
502
+ */
503
+ getHomeserverOf(pubky: PublicKey): Promise<PublicKey | undefined>;
504
+ /**
505
+ * Resolve the homeserver for **this** user (requires keypair).
506
+ *
507
+ * @returns {Promise<PublicKey|undefined>} Homeserver public key or `undefined` if not found.
508
+ */
509
+ getHomeserver(): Promise<PublicKey | undefined>;
510
+ /**
511
+ * Force publish homeserver immediately (even if fresh).
512
+ *
513
+ * Requires keypair or to be signer bound.
514
+ *
515
+ * @param {PublicKey=} overrideHost Optional new homeserver to publish (migration).
516
+ * @returns {Promise<void>}
517
+ */
518
+ publishHomeserverForce(host_override?: PublicKey | null): Promise<void>;
519
+ /**
520
+ * Republish homeserver if record is missing/stale.
521
+ *
522
+ * Requires keypair or to be signer bound.
523
+ *
524
+ * @param {PublicKey=} overrideHost Optional new homeserver to publish (migration).
525
+ * @returns {Promise<void>}
526
+ */
527
+ publishHomeserverIfStale(host_override?: PublicKey | null): Promise<void>;
528
+ }
529
+ /**
530
+ * High-level entrypoint to the Pubky SDK.
531
+ */
532
+ export class Pubky {
533
+ free(): void;
534
+ /**
535
+ * Create a Pubky facade wired for **mainnet** defaults (public relays).
536
+ *
537
+ * @returns {Pubky}
538
+ * A new facade instance. Use this to create signers, start auth flows, etc.
539
+ *
540
+ * @example
541
+ * const pubky = new Pubky();
542
+ * const signer = pubky.signer(Keypair.random());
543
+ */
544
+ constructor();
545
+ /**
546
+ * Create a Pubky facade preconfigured for a **local testnet**.
547
+ *
548
+ * If `host` is provided, PKARR and HTTP endpoints are derived as `http://<host>:ports/...`.
549
+ * If omitted, `"localhost"` is assumed (handy for `cargo install pubky-testnet`).
550
+ *
551
+ * @param {string=} host Optional host (e.g. `"localhost"`, `"docker-host"`, `"127.0.0.1"`).
552
+ * @returns {Pubky}
553
+ *
554
+ * @example
555
+ * const pubky = Pubky.testnet(); // localhost default
556
+ * const pubky = Pubky.testnet("docker-host"); // custom hostname/IP
557
+ */
558
+ static testnet(host?: string | null): Pubky;
559
+ /**
560
+ * Wrap an existing configured HTTP client into a Pubky facade.
561
+ *
562
+ * @param {Client} client A previously constructed client.
563
+ * @returns {Pubky}
564
+ *
565
+ * @example
566
+ * const client = Client.testnet();
567
+ * const pubky = Pubky.withClient(client);
568
+ */
569
+ static withClient(client: Client): Pubky;
570
+ /**
571
+ * Start a **pubkyauth** flow.
572
+ *
573
+ * Provide a **capabilities string** and (optionally) a relay base URL.
574
+ * The capabilities string is a comma-separated list of entries:
575
+ * `"<scope>:<actions>"`, where:
576
+ * - `scope` starts with `/` (e.g. `/pub/example.app/`).
577
+ * - `actions` is any combo of `r` and/or `w` (order normalized; `wr` -> `rw`).
578
+ * Pass `""` for no scopes (read-only public session).
579
+ *
580
+ * @param {string} capabilities Comma-separated caps, e.g. `"/pub/app/:rw,/pub/foo/file:r"`.
581
+ * @param {string=} relay Optional HTTP relay base (e.g. `"https://…/link/"`).
582
+ * @returns {AuthFlow}
583
+ * A running auth flow. Show `authorizationUrl` as QR/deeplink,
584
+ * then `awaitApproval()` to obtain a `Session`.
585
+ *
586
+ * @throws {PubkyError}
587
+ * - `{ name: "InvalidInput" }` for malformed capabilities or bad relay URL
588
+ * - `{ name: "RequestError" }` if the flow cannot be started (network/relay)
589
+ *
590
+ * @example
591
+ * const flow = pubky.startAuthFlow("/pub/my.app/:rw");
592
+ * renderQr(flow.authorizationUrl);
593
+ * const session = await flow.awaitApproval();
594
+ */
595
+ startAuthFlow(capabilities: Capabilities, relay?: string | null): AuthFlow;
596
+ /**
597
+ * Create a `Signer` from an existing `Keypair`.
598
+ *
599
+ * @param {Keypair} keypair The user’s keys.
600
+ * @returns {Signer}
601
+ *
602
+ * @example
603
+ * const signer = pubky.signer(Keypair.random());
604
+ * const session = await signer.signup(homeserverPk, null);
171
605
  */
172
- to_uint8array(): Uint8Array;
606
+ signer(keypair: Keypair): Signer;
607
+ /**
608
+ * Resolve the homeserver for a given public key (read-only).
609
+ *
610
+ * Uses an internal read-only Pkdns actor.
611
+ *
612
+ * @param {PublicKey} user
613
+ * @returns {Promise<PublicKey|undefined>} Homeserver public key (z32) or `undefined` if not found.
614
+ */
615
+ getHomeserverOf(user_public_key: PublicKey): Promise<PublicKey | undefined>;
616
+ /**
617
+ * Public, unauthenticated storage API.
618
+ *
619
+ * Use for **read-only** public access via addressed paths:
620
+ * `"<user-z32>/pub/…"`.
621
+ *
622
+ * @returns {PublicStorage}
623
+ *
624
+ * @example
625
+ * const text = await pubky.publicStorage.getText(`${userPk.z32()}/pub/example.com/hello.txt`);
626
+ */
627
+ readonly publicStorage: PublicStorage;
628
+ /**
629
+ * Access the underlying HTTP client (advanced).
630
+ *
631
+ * @returns {Client}
632
+ * Use this for low-level `fetch()` calls or testing with raw URLs.
633
+ *
634
+ * @example
635
+ * const r = await pubky.client.fetch(`pubky://${user}/pub/app/file.txt`, { credentials: "include" });
636
+ */
637
+ readonly client: Client;
638
+ }
639
+ export class PublicKey {
640
+ private constructor();
641
+ free(): void;
173
642
  /**
174
643
  * Convert the PublicKey to Uint8Array
175
644
  */
@@ -183,15 +652,280 @@ export class PublicKey {
183
652
  */
184
653
  static from(value: string): PublicKey;
185
654
  }
655
+ /**
656
+ * Read-only public storage using addressed paths (`"<user-z32>/pub/...")`.
657
+ */
658
+ export class PublicStorage {
659
+ free(): void;
660
+ /**
661
+ * Construct PublicStorage using global client (mainline relays).
662
+ */
663
+ constructor();
664
+ /**
665
+ * List a directory. Results are `pubky://…` identifier URLs.
666
+ *
667
+ * @param {Address} address Addressed directory (must end with `/`).
668
+ * @param {string|null=} cursor Optional suffix or full URL to start **after**.
669
+ * @param {boolean=} reverse Default `false`. When `true`, newest/lexicographically-last first.
670
+ * @param {number=} limit Optional result limit.
671
+ * @param {boolean=} shallow Default `false`. When `true`, lists only first-level entries.
672
+ * @returns {Promise<string[]>}
673
+ */
674
+ list(address: Address, cursor?: string | null, reverse?: boolean | null, limit?: number | null, shallow?: boolean | null): Promise<string[]>;
675
+ /**
676
+ * Perform a streaming `GET` and expose the raw `Response` object.
677
+ *
678
+ * @param {Address} address
679
+ * @returns {Promise<Response>}
680
+ */
681
+ get(address: Address): Promise<Response>;
682
+ /**
683
+ * Fetch bytes from an addressed path.
684
+ *
685
+ * @param {Address} address
686
+ * @returns {Promise<Uint8Array>}
687
+ */
688
+ getBytes(address: Address): Promise<Uint8Array>;
689
+ /**
690
+ * Fetch text from an addressed path as UTF-8 text.
691
+ *
692
+ * @param {Address} address
693
+ * @returns {Promise<string>}
694
+ */
695
+ getText(address: Address): Promise<string>;
696
+ /**
697
+ * Fetch JSON from an addressed path.
698
+ *
699
+ * @param {Address} address `"pubky<user>/pub/.../file.json"` (preferred) or `pubky://<user>/pub/...`.
700
+ * @returns {Promise<any>}
701
+ */
702
+ getJson(address: Address): Promise<any>;
703
+ /**
704
+ * Check if a path exists.
705
+ *
706
+ * @param {Address} address
707
+ * @returns {Promise<boolean>}
708
+ */
709
+ exists(address: Address): Promise<boolean>;
710
+ /**
711
+ * Get metadata for an address
712
+ *
713
+ * @param {Address} address `"pubky<user>/pub/.../file.json"` (preferred) or `pubky://<user>/pub/...`.
714
+ * @returns {Promise<ResourceStats|undefined>} `undefined` if the resource does not exist.
715
+ * @throws {PubkyError} On invalid input or transport/server errors.
716
+ */
717
+ stats(address: Address): Promise<ResourceStats | undefined>;
718
+ }
719
+ /**
720
+ * An authenticated context “as the user”.
721
+ * - Use `storage` for reads/writes (absolute paths like `/pub/app/file.txt`)
722
+ * - Cookie is managed automatically by the underlying fetch client
723
+ */
186
724
  export class Session {
187
725
  private constructor();
188
726
  free(): void;
189
727
  /**
190
- * Return the [PublicKey] of this session
728
+ * Invalidate the session on the server (clears server cookie).
729
+ * Further calls to storage API will fail.
730
+ *
731
+ * @returns {Promise<void>}
732
+ */
733
+ signout(): Promise<void>;
734
+ /**
735
+ * Retrieve immutable info about this session (user & capabilities).
736
+ *
737
+ * @returns {SessionInfo}
738
+ */
739
+ readonly info: SessionInfo;
740
+ /**
741
+ * Access the session-scoped storage API (read/write).
742
+ *
743
+ * @returns {SessionStorage}
744
+ */
745
+ readonly storage: SessionStorage;
746
+ }
747
+ /**
748
+ * Static snapshot of session metadata.
749
+ */
750
+ export class SessionInfo {
751
+ private constructor();
752
+ free(): void;
753
+ /**
754
+ * The user’s public key for this session.
755
+ *
756
+ * Use `.z32()` on the returned `PublicKey` to get the string form.
757
+ *
758
+ * @returns {PublicKey}
759
+ *
760
+ * @example
761
+ * const who = sessionInfo.publicKey.z32();
762
+ */
763
+ readonly publicKey: PublicKey;
764
+ /**
765
+ * Effective capabilities granted to this session.
766
+ *
767
+ * @returns {string[]} Normalized capability entries (e.g. `"/pub/app/:rw"`).
768
+ */
769
+ readonly capabilities: string[];
770
+ }
771
+ /**
772
+ * Read/write storage scoped to **your** session (absolute paths: `/pub/...`).
773
+ */
774
+ export class SessionStorage {
775
+ private constructor();
776
+ free(): void;
777
+ /**
778
+ * List a directory (absolute session path). Returns `pubky://…` URLs.
779
+ *
780
+ * @param {Path} path Must end with `/`.
781
+ * @param {string|null=} cursor Optional suffix or full URL to start **after**.
782
+ * @param {boolean=} reverse Default `false`.
783
+ * @param {number=} limit Optional result limit.
784
+ * @param {boolean=} shallow Default `false`.
785
+ * @returns {Promise<string[]>}
786
+ */
787
+ list(path: Path, cursor?: string | null, reverse?: boolean | null, limit?: number | null, shallow?: boolean | null): Promise<string[]>;
788
+ /**
789
+ * GET a streaming response for an absolute session path.
790
+ *
791
+ * @param {Path} path
792
+ * @returns {Promise<Response>}
793
+ */
794
+ get(path: Path): Promise<Response>;
795
+ /**
796
+ * GET bytes from an absolute session path.
797
+ *
798
+ * @param {Path} path
799
+ * @returns {Promise<Uint8Array>}
800
+ */
801
+ getBytes(path: Path): Promise<Uint8Array>;
802
+ /**
803
+ * GET text from an absolute session path.
804
+ *
805
+ * @param {Path} path
806
+ * @returns {Promise<string>}
807
+ */
808
+ getText(path: Path): Promise<string>;
809
+ /**
810
+ * GET JSON from an absolute session path.
811
+ *
812
+ * @param {Path} path
813
+ * @returns {Promise<any>}
814
+ */
815
+ getJson(path: Path): Promise<any>;
816
+ /**
817
+ * Check existence.
818
+ *
819
+ * @param {Path} path
820
+ * @returns {Promise<boolean>}
821
+ */
822
+ exists(path: Path): Promise<boolean>;
823
+ /**
824
+ * Get metadata for an absolute, session-scoped path (e.g. `"/pub/app/file.json"`).
825
+ *
826
+ * @param {Path} path Absolute path under your user (starts with `/`).
827
+ * @returns {Promise<ResourceStats|undefined>} `undefined` if the resource does not exist.
828
+ * @throws {PubkyError} On invalid input or transport/server errors.
829
+ */
830
+ stats(path: Path): Promise<ResourceStats | undefined>;
831
+ /**
832
+ * PUT binary at an absolute session path.
833
+ *
834
+ * @param {Path} path
835
+ * @param {Uint8Array} bytes
836
+ * @returns {Promise<void>}
837
+ */
838
+ putBytes(path: Path, body: Uint8Array): Promise<void>;
839
+ /**
840
+ * PUT text at an absolute session path.
841
+ *
842
+ * @param {Path} path
843
+ * @param {string} text
844
+ * @returns {Promise<void>}
845
+ */
846
+ putText(path: Path, body: string): Promise<void>;
847
+ /**
848
+ * PUT JSON at an absolute session path.
849
+ *
850
+ * @param {Path} path Absolute path (e.g. `"/pub/app/data.json"`).
851
+ * @param {any} value JSON-serializable value.
852
+ * @returns {Promise<void>}
853
+ */
854
+ putJson(path: Path, body: any): Promise<void>;
855
+ /**
856
+ * Delete a path (file or empty directory).
857
+ *
858
+ * @param {Path} path
859
+ * @returns {Promise<void>}
860
+ */
861
+ delete(path: Path): Promise<void>;
862
+ }
863
+ /**
864
+ * Holds a user’s `Keypair` and performs identity operations:
865
+ * - `signup` creates a new homeserver user.
866
+ * - `signin` creates a homeserver session for an existing user.
867
+ * - Approve pubkyauth requests
868
+ * - Publish PKDNS when signer-bound
869
+ */
870
+ export class Signer {
871
+ private constructor();
872
+ free(): void;
873
+ /**
874
+ * Create a signer from a `Keypair` (prefer `pubky.signer(kp)`).
875
+ *
876
+ * @param {Keypair} keypair
877
+ * @returns {Signer}
878
+ */
879
+ static fromKeypair(keypair: Keypair): Signer;
880
+ /**
881
+ * Sign up at a homeserver. Returns a ready `Session`.
882
+ *
883
+ * Creates a valid homeserver Session with root capabilities
884
+ *
885
+ * @param {PublicKey} homeserver The homeserver’s public key.
886
+ * @param {string|null} signupToken Invite/registration token or `null`.
887
+ * @returns {Promise<Session>}
888
+ *
889
+ * @throws {PubkyError}
890
+ * - `AuthenticationError` (bad/expired token)
891
+ * - `RequestError` (network/server)
892
+ */
893
+ signup(homeserver: PublicKey, signup_token?: string | null): Promise<Session>;
894
+ /**
895
+ * Fast sign-in for a returning user. Publishes PKDNS in the background.
896
+ *
897
+ * Creates a valid homeserver Session with root capabilities
898
+ *
899
+ * @returns {Promise<Session>}
900
+ *
901
+ * @throws {PubkyError}
191
902
  */
192
- pubky(): PublicKey;
903
+ signin(): Promise<Session>;
193
904
  /**
194
- * Return the capabilities that this session has.
905
+ * Blocking sign-in. Waits for PKDNS publish to complete (slower; safer).
906
+ *
907
+ * Creates a valid homeserver Session with root capabilities
908
+ *
909
+ * @returns {Promise<Session>}
910
+ */
911
+ signinBlocking(): Promise<Session>;
912
+ /**
913
+ * Approve a `pubkyauth://` request URL (encrypts & POSTs the signed AuthToken).
914
+ */
915
+ approveAuthRequest(pubkyauth_url: string): Promise<void>;
916
+ /**
917
+ * Get the public key of this signer.
918
+ *
919
+ * @returns {PublicKey}
920
+ */
921
+ readonly publicKey: PublicKey;
922
+ /**
923
+ * Get a PKDNS actor bound to this signer's client & keypair (publishing enabled).
924
+ *
925
+ * @returns {Pkdns}
926
+ *
927
+ * @example
928
+ * await signer.pkdns.publishHomeserverIfStale(homeserverPk);
195
929
  */
196
- capabilities(): string[];
930
+ readonly pkdns: Pkdns;
197
931
  }