@synonymdev/pubky 0.6.0-rc.6 → 0.6.0-rc.7

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 CHANGED
@@ -17,7 +17,7 @@ Module system + TS types: ESM and CommonJS both supported; TypeScript typings ge
17
17
  ## Getting Started
18
18
 
19
19
  ```js
20
- import { Pubky, PublicKey, Keypair } from "@synonymdev/pubky";
20
+ import { Pubky, PublicKey, Keypair, AuthFlowKind } from "@synonymdev/pubky";
21
21
 
22
22
  // Initiate a Pubky SDK facade wired for default mainnet Pkarr relays.
23
23
  const pubky = new Pubky(); // or: const pubky = Pubky.testnet(); for localhost testnet.
@@ -28,7 +28,7 @@ const signer = pubky.signer(keypair);
28
28
 
29
29
  // 2) Sign up at a homeserver (optionally with an invite)
30
30
  const homeserver = PublicKey.from(
31
- "8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo",
31
+ "8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo"
32
32
  );
33
33
  const signupToken = "<your-invite-code-or-null>";
34
34
  const session = await signer.signup(homeserver, signupToken);
@@ -43,19 +43,23 @@ const addr = `pubky${userPk}/pub/example.com/hello.json`;
43
43
  const json = await pubky.publicStorage.getJson(addr); // -> { hello: "world" }
44
44
 
45
45
  // 5) Authenticate on a 3rd-party app
46
- const authFlow = pubky.startAuthFlow("/pub/my.app/:rw"); // require permissions to read and write into `my.app`
46
+ const authFlow = pubky.startAuthFlow("/pub/my-cool-app/:rw", AuthFlowKind::signin()); // require permissions to read and write into `my.app`
47
47
  renderQr(authFlow.authorizationUrl); // show to user
48
48
  const session = await authFlow.awaitApproval();
49
49
  ```
50
50
 
51
51
  Find here [**ready-to-run examples**](https://github.com/pubky/pubky-core/tree/main/examples).
52
52
 
53
+ ### Initialization & events
54
+
55
+ The npm package bundles the WebAssembly module and **initializes it before exposing any APIs**. This avoids the common wasm-pack pitfall where events fire before the module finishes instantiating. Long-polling flows such as `authFlow.awaitApproval()` or `authFlow.tryPollOnce()` only start their relay calls after the underlying module is ready, so you won't miss approvals while the bundle is loading.
56
+
53
57
  ## API Overview
54
58
 
55
59
  Use `new Pubky()` to quickly get any flow started:
56
60
 
57
61
  ```js
58
- import { Pubky, Keypair } from "@synonymdev/pubky";
62
+ import { Pubky, Keypair, AuthFlowKind } from "@synonymdev/pubky";
59
63
 
60
64
  // Mainnet (default relays)
61
65
  const pubky = new Pubky();
@@ -68,7 +72,7 @@ const pubkyLocal = Pubky.testnet("localhost");
68
72
  const signer = pubky.signer(Keypair.random());
69
73
 
70
74
  // Pubky Auth flow (with capabilities)
71
- const authFlow = pubky.startAuthFlow("/pub/my.app/:rw");
75
+ const authFlow = pubky.startAuthFlow("/pub/my-cool-app/:rw", AuthFlowKind::signin());
72
76
 
73
77
  // Public storage (read-only)
74
78
  const publicStorage = pubky.publicStorage;
@@ -153,6 +157,20 @@ const caps = session.info.capabilities; // -> string[] permissions and paths
153
157
  const storage = session.storage; // -> This User's storage API (absolute paths)
154
158
  ```
155
159
 
160
+ **Persist a session across tab refreshes (browser)**
161
+
162
+ ```js
163
+ // Save the session snapshot (no secrets inside; relies on the HTTP-only cookie).
164
+ const snapshot = session.export();
165
+ localStorage.setItem("pubky-session", snapshot);
166
+
167
+ // Later (after a reload), rehydrate using the browser's stored cookie.
168
+ const restored = await pubky.restoreSession(localStorage.getItem("pubky-session")!);
169
+ ```
170
+
171
+ > The exported string contains only public session metadata. The browser must keep the
172
+ > HTTP-only cookie alive for the restored session to remain authenticated.
173
+
156
174
  **Approve a pubkyauth request URL**
157
175
 
158
176
  ```js
@@ -166,17 +184,17 @@ await signer.approveAuthRequest("pubkyauth:///?caps=...&secret=...&relay=...");
166
184
  End-to-end auth (3rd-party app asks a user to approve via QR/deeplink, E.g. Pubky Ring).
167
185
 
168
186
  ```js
169
- import { Pubky } from "@synonymdev/pubky";
187
+ import { Pubky, AuthFlowKind } from "@synonymdev/pubky";
170
188
  const pubky = new Pubky();
171
189
 
172
190
  // Comma-separated capabilities string
173
- const caps = "/pub/my.app/:rw,/pub/another.app/folder/:w";
191
+ const caps = "/pub/my-cool-app/:rw,/pub/another-app/folder/:w";
174
192
 
175
193
  // Optional relay; defaults to Synonym-hosted relay if omitted
176
194
  const relay = "https://httprelay.pubky.app/link/"; // optional (defaults to this)
177
195
 
178
196
  // Start the auth polling
179
- const flow = pubky.startAuthFlow(caps, relay);
197
+ const flow = pubky.startAuthFlow(caps, AuthFlowKind::signin(), relay);
180
198
 
181
199
  renderQr(flow.authorizationUrl); // show to user
182
200
 
@@ -192,7 +210,7 @@ normalized string (ordering actions like `:rw`) and throws a structured error
192
210
  when the input is malformed.
193
211
 
194
212
  ```js
195
- import { Pubky, validateCapabilities } from "@synonymdev/pubky";
213
+ import { Pubky, validateCapabilities, AuthFlowKind } from "@synonymdev/pubky";
196
214
 
197
215
  const pubky = new Pubky();
198
216
 
@@ -200,7 +218,7 @@ const rawCaps = formData.get("caps");
200
218
 
201
219
  try {
202
220
  const caps = validateCapabilities(rawCaps ?? "");
203
- const flow = pubky.startAuthFlow(caps);
221
+ const flow = pubky.startAuthFlow(caps, AuthFlowKind::signin());
204
222
  renderQr(flow.authorizationUrl);
205
223
  const session = await flow.awaitApproval();
206
224
  // ...
@@ -233,6 +251,9 @@ surface precise feedback to the user.
233
251
  const pub = pubky.publicStorage;
234
252
 
235
253
  // Reads
254
+ const response = await pub.get(
255
+ `pubky${userPk.z32()}/pub/example.com/data.json`
256
+ ); // -> Response (stream it)
236
257
  await pub.getJson(`pubky${userPk.z32()}/pub/example.com/data.json`);
237
258
  await pub.getText(`pubky${userPk.z32()}/pub/example.com/readme.txt`);
238
259
  await pub.getBytes(`pubky${userPk.z32()}/pub/example.com/icon.png`); // Uint8Array
@@ -243,9 +264,17 @@ await pub.stats(`pubky${userPk.z32()}/pub/example.com/foo`); // { content_length
243
264
 
244
265
  // List directory (addressed path "<pubky>/pub/.../") must include trailing `/`.
245
266
  // list(addr, cursor=null|suffix|fullUrl, reverse=false, limit?, shallow=false)
246
- await pub.list(`pubky${userPk.z32()}/pub/example.com/`, null, false, 100, false);
267
+ await pub.list(
268
+ `pubky${userPk.z32()}/pub/example.com/`,
269
+ null,
270
+ false,
271
+ 100,
272
+ false
273
+ );
247
274
  ```
248
275
 
276
+ Use `get()` when you need the raw `Response` for streaming or custom parsing.
277
+
249
278
  #### SessionStorage (read/write; uses cookies)
250
279
 
251
280
  ```js
@@ -257,6 +286,7 @@ await s.putText("/pub/example.com/note.txt", "hello");
257
286
  await s.putBytes("/pub/example.com/img.bin", new Uint8Array([1, 2, 3]));
258
287
 
259
288
  // Reads
289
+ const response = await s.get("/pub/example.com/data.json"); // -> Response (stream it)
260
290
  await s.getJson("/pub/example.com/data.json");
261
291
  await s.getText("/pub/example.com/note.txt");
262
292
  await s.getBytes("/pub/example.com/img.bin");
@@ -272,12 +302,14 @@ await s.list("/pub/example.com/", null, false, 100, false);
272
302
  await s.delete("/pub/example.com/data.json");
273
303
  ```
274
304
 
305
+ `get()` exposes the underlying `Response`, which is handy for streaming bodies or inspecting headers before consuming content.
306
+
275
307
  Path rules:
276
308
 
277
309
  - Session storage uses **absolute** paths like `"/pub/app/file.txt"`.
278
310
  - Public storage uses **addressed** form `pubky<user>/pub/app/file.txt` (preferred) or `pubky://<user>/...`.
279
311
 
280
- **Convention:** put your app’s public data under a domain-like folder in `/pub`, e.g. `/pub/mycoolnew.app/`.
312
+ **Convention:** put your app’s public data under a domain-like folder in `/pub`, e.g. `/pub/my-new-app/`.
281
313
 
282
314
  ---
283
315
 
@@ -323,7 +355,8 @@ Use `resolvePubky()` when you need to feed an addressed resource into a raw HTTP
323
355
  ```js
324
356
  import { resolvePubky } from "@synonymdev/pubky";
325
357
 
326
- const identifier = "pubkyoperrr8wsbpr3ue9d4qj41ge1kcc6r7fdiy6o3ugjrrhi4y77rdo/pub/pubky.app/posts/0033X02JAN0SG";
358
+ const identifier =
359
+ "pubkyoperrr8wsbpr3ue9d4qj41ge1kcc6r7fdiy6o3ugjrrhi4y77rdo/pub/pubky.app/posts/0033X02JAN0SG";
327
360
  const url = resolvePubky(identifier);
328
361
  // -> "https://_pubky.operrr8wsbpr3ue9d4qj41ge1kcc6r7fdiy6o3ugjrrhi4y77rdo/pub/pubky.app/posts/0033X02JAN0SG"
329
362
  ```
@@ -332,6 +365,12 @@ Both `pubky<pk>/…` (preferred) and `pubky://<pk>/…` resolve to the same HTTP
332
365
 
333
366
  ---
334
367
 
368
+ ## WASM memory (`free()` helpers)
369
+
370
+ `wasm-bindgen` generates `free()` methods on exported classes (for example `Pubky`, `AuthFlow` `PublicKey`). JavaScript's GC eventually releases the underlying Rust structs on its own, but calling `free()` lets you drop them **immediately** if you are creating many short-lived instances (e.g. in a long-running worker). It is safe to skip manual frees in typical browser or Node apps.
371
+
372
+ ---
373
+
335
374
  ## Errors
336
375
 
337
376
  All async methods throw a structured `PubkyError`:
@@ -369,6 +408,12 @@ try {
369
408
  }
370
409
  ```
371
410
 
411
+ ## Browser environment notes
412
+
413
+ - Keep the Pubky client UI and the homeserver on the **same origin family** (both local or both remote). Browsers partition cookies by scheme/host, and cross-site requests (e.g., http://localhost calling https://staging…​) can silently drop or cache `SameSite`/`Secure` session cookies.
414
+ - If you must mix environments, use a reverse proxy so the browser always talks to one consistent origin (or disable caching via devtools and clear cookies between switches).
415
+ - When troubleshooting auth/session caching: open a fresh incognito window, clear site data for the target origin, and verify the request includes credentials.
416
+
372
417
  ---
373
418
 
374
419
  ## Local Test & Development