@synonymdev/pubky 0.9.3 → 0.10.0-alpha.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 (6) hide show
  1. package/README.md +51 -40
  2. package/index.cjs +1247 -222
  3. package/index.js +1248 -223
  4. package/package.json +1 -1
  5. package/pubky.d.ts +493 -26
  6. package/pubky_bg.wasm +0 -0
package/README.md CHANGED
@@ -31,21 +31,29 @@ const homeserver = PublicKey.from(
31
31
  "8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo"
32
32
  );
33
33
  const signupToken = "<your-invite-code-or-null>";
34
- const session = await signer.signup(homeserver, signupToken);
34
+ await signer.signup(homeserver, signupToken);
35
35
 
36
- // 3) Write a public JSON file (session-scoped storage uses cookies automatically)
37
- const path = "/pub/example.com/hello.json";
36
+ // 3a) Signin with the signer directly
37
+ const session = await signer.signin("example.com");
38
+
39
+ // 3b) Alternatively if you do not have the keypair available, authenticate on a 3rd-party app
40
+ // by delegating the authentication to a signer with a QR code.
41
+ const authFlow = pubky.startGrantAuthFlow(
42
+ "/pub/my-cool-app/:rw",
43
+ AuthFlowKind.signin(),
44
+ { clientId: "my-cool-app.example" },
45
+ );
46
+ renderQr(authFlow.authorizationUrl); // Show to user the signin deeplink via a QR code
47
+ const session = await authFlow.awaitApproval();
48
+
49
+ // 4) Write a public JSON file
50
+ const path = "/pub/my-cool-app/hello.json";
38
51
  await session.storage.putJson(path, { hello: "world" });
39
52
 
40
- // 4) Read it publicly (no auth needed)
53
+ // 5) Read it publicly (no auth needed)
41
54
  const userPk = session.info.publicKey.toString();
42
- const addr = `${userPk}/pub/example.com/hello.json`;
55
+ const addr = `${userPk}/pub/my-cool-app/hello.json`;
43
56
  const json = await pubky.publicStorage.getJson(addr); // -> { hello: "world" }
44
-
45
- // 5) Authenticate on a 3rd-party app
46
- const authFlow = pubky.startAuthFlow("/pub/my-cool-app/:rw", AuthFlowKind::signin()); // require permissions to read and write into `my.app`
47
- renderQr(authFlow.authorizationUrl); // show to user
48
- const session = await authFlow.awaitApproval();
49
57
  ```
50
58
 
51
59
  Find here [**ready-to-run examples**](https://github.com/pubky/pubky-core/tree/main/examples).
@@ -84,8 +92,12 @@ const pubkyLocal = Pubky.testnet("localhost");
84
92
  // Signer (bind your keypair to a new Signer actor)
85
93
  const signer = pubky.signer(Keypair.random());
86
94
 
87
- // Pubky Auth flow (with capabilities)
88
- const authFlow = pubky.startAuthFlow("/pub/my-cool-app/:rw", AuthFlowKind::signin());
95
+ // Grant Pubky Auth flow (with capabilities)
96
+ const authFlow = pubky.startGrantAuthFlow(
97
+ "/pub/my-cool-app/:rw",
98
+ AuthFlowKind.signin(),
99
+ { clientId: "my-cool-app.example" },
100
+ );
89
101
 
90
102
  // Public storage (read-only)
91
103
  const publicStorage = pubky.publicStorage;
@@ -106,7 +118,7 @@ const client = new Client(); // or: pubky.client.fetch(); instead of constructin
106
118
 
107
119
  // Convert the identifier into a transport URL before fetching.
108
120
  const userId = PublicKey.from("pubky<z32>").toString();
109
- const url = resolvePubky(`${userId}/pub/example.com/file.txt`);
121
+ const url = resolvePubky(`${userId}/pub/my-cool-app/file.txt`);
110
122
  const res = await client.fetch(url);
111
123
  ```
112
124
 
@@ -155,12 +167,12 @@ const keypair = Keypair.random();
155
167
  const signer = pubky.signer(keypair);
156
168
 
157
169
  const homeserver = PublicKey.from("8pinxxgq…");
158
- const session = await signer.signup(homeserver, /* invite */ null);
170
+ await signer.signup(homeserver); // Add optional signup code here if required
159
171
 
160
- const session2 = await signer.signin(); // fast, prefer this; publishes PKDNS in background
161
- const session3 = await signer.signinBlocking(); // slower but safer; waits for PKDNS publish
172
+ const session1 = await signer.signin("example.com"); // fast, prefer this; publishes PKDNS in background
173
+ const session2 = await signer.signinBlocking("example.com"); // slower but safer; waits for PKDNS publish
162
174
 
163
- await session.signout(); // invalidates server session
175
+ await session1.signout(); // invalidates server session
164
176
  ```
165
177
 
166
178
  **Session details**
@@ -172,29 +184,29 @@ const caps = session.info.capabilities; // -> string[] permissions and paths
172
184
  const storage = session.storage; // -> This User's storage API (absolute paths)
173
185
  ```
174
186
 
175
- **Persist a session across tab refreshes (browser)**
187
+ **Persist a grant session**
176
188
 
177
189
  ```js
178
- // Save the session snapshot (no secrets inside; relies on the HTTP-only cookie).
179
- const snapshot = session.export();
180
- localStorage.setItem("pubky-session", snapshot);
190
+ // Save the session secret. Treat this string like a bearer token.
191
+ const secret = await session.exportSecret();
192
+ localStorage.setItem("pubky-session", secret);
181
193
 
182
- // Later (after a reload), rehydrate using the browser's stored cookie.
194
+ // Later, restore by minting a fresh short-lived bearer.
183
195
  const restored = await pubky.restoreSession(localStorage.getItem("pubky-session")!);
184
196
  ```
185
197
 
186
- > The exported string contains only public session metadata. The browser must keep the
187
- > HTTP-only cookie alive for the restored session to remain authenticated.
198
+ > `session.export()` is still available for legacy cookie sessions, but new
199
+ > applications should use grant auth plus `exportSecret()`.
188
200
 
189
201
  **Approve a pubkyauth request URL**
190
202
 
191
203
  ```js
192
- await signer.approveAuthRequest("pubkyauth:///?caps=...&secret=...&relay=...");
204
+ await signer.approveAuthRequest("pubkyauth://signin?caps=...&secret=...&relay=...");
193
205
  ```
194
206
 
195
207
  ---
196
208
 
197
- ### AuthFlow (pubkyauth)
209
+ ### GrantAuthFlow (pubkyauth)
198
210
 
199
211
  End-to-end auth (3rd-party app asks a user to approve via QR/deeplink, E.g. Pubky Ring).
200
212
 
@@ -208,8 +220,12 @@ const caps = "/pub/my-cool-app/:rw,/pub/another-app/folder/:w";
208
220
  // Optional relay; defaults to Synonym-hosted relay if omitted
209
221
  const relay = "https://httprelay.pubky.app/inbox/"; // optional (defaults to this)
210
222
 
211
- // Start the auth polling
212
- const flow = pubky.startAuthFlow(caps, AuthFlowKind::signin(), relay);
223
+ // Start grant auth polling
224
+ const flow = pubky.startGrantAuthFlow(
225
+ caps,
226
+ AuthFlowKind.signin(),
227
+ { clientId: "my-cool-app.example", relay },
228
+ );
213
229
 
214
230
  renderQr(flow.authorizationUrl); // show to user
215
231
 
@@ -220,7 +236,7 @@ const session = await flow.awaitApproval();
220
236
  #### Validate and normalize capabilities
221
237
 
222
238
  If you accept capability strings from user input (forms, CLI arguments, etc.),
223
- use `validateCapabilities` before calling `startAuthFlow`. The helper returns a
239
+ use `validateCapabilities` before calling `startGrantAuthFlow`. The helper returns a
224
240
  normalized string (ordering actions like `:rw`) and throws a structured error
225
241
  when the input is malformed.
226
242
 
@@ -233,7 +249,9 @@ const rawCaps = formData.get("caps");
233
249
 
234
250
  try {
235
251
  const caps = validateCapabilities(rawCaps ?? "");
236
- const flow = pubky.startAuthFlow(caps, AuthFlowKind::signin());
252
+ const flow = pubky.startGrantAuthFlow(caps, AuthFlowKind.signin(), {
253
+ clientId: "my-cool-app.example",
254
+ });
237
255
  renderQr(flow.authorizationUrl);
238
256
  const session = await flow.awaitApproval();
239
257
  // ...
@@ -252,9 +270,8 @@ surface precise feedback to the user.
252
270
 
253
271
  #### Http Relay & reliability
254
272
 
255
- - If you don’t specify a relay, `PubkyAuthFlow` defaults to a Synonym-hosted relay. If that relay is down, logins won’t complete.
256
- - For production and larger apps, run **your own http relay** (MIT, Docker): [https://httprelay.io](https://httprelay.io).
257
- The channel is derived as `base64url(hash(secret))`; the token is end-to-end encrypted with the `secret` and cannot be decrypted by the relay.
273
+ - If you don’t specify a relay, the auth flow defaults to a Synonym-hosted relay. If that relay is down, logins won’t complete.
274
+ - For production and larger apps, run **your own http relay** (MIT, Docker): [https://github.com/pubky/http-relay](https://github.com/pubky/http-relay).
258
275
 
259
276
  ---
260
277
 
@@ -290,7 +307,7 @@ await pub.list(
290
307
 
291
308
  Use `get()` when you need the raw `Response` for streaming or custom parsing.
292
309
 
293
- #### SessionStorage (read/write; uses cookies)
310
+ #### SessionStorage (read/write)
294
311
 
295
312
  ```js
296
313
  const s = session.storage;
@@ -423,12 +440,6 @@ try {
423
440
  }
424
441
  ```
425
442
 
426
- ## Browser environment notes
427
-
428
- - 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.
429
- - 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).
430
- - When troubleshooting auth/session caching: open a fresh incognito window, clear site data for the target origin, and verify the request includes credentials.
431
-
432
443
  ---
433
444
 
434
445
  ## Local Test & Development