@parley-im/parley 0.2.11 → 0.2.13

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/dist/account.js CHANGED
@@ -32,9 +32,11 @@ async function call(creds, path, init = {}) {
32
32
  signal: AbortSignal.timeout(15_000),
33
33
  });
34
34
  if (res.status === 401)
35
- throw Object.assign(new Error("This computer isn't linked to your parley account anymore. Run parley login."), { unlinked: true });
36
- if (!res.ok)
37
- throw new Error((await res.json().catch(() => null))?.message ?? `Parley's servers answered ${res.status}`);
35
+ throw Object.assign(new Error("This computer isn't linked to your Parley account anymore. Run parley login."), { unlinked: true });
36
+ if (!res.ok) {
37
+ const body = (await res.json().catch(() => null));
38
+ throw Object.assign(new Error(body?.message ?? `Parley's servers answered ${res.status}`), { status: res.status, code: body?.error });
39
+ }
38
40
  return res.json();
39
41
  }
40
42
  // What parley.im is told about a session: its id and a title for link
@@ -74,7 +76,7 @@ export async function login(config, show) {
74
76
  }
75
77
  // Signed in on parley.im, but not let in yet: no computer links until then.
76
78
  if (poll.status === "waitlisted") {
77
- throw new Error(`You're on the parley waitlist as ${poll.email}. You'll get an email when you're let in; then run parley login again.`);
79
+ throw new Error(`You're on the Parley waitlist as ${poll.email}. You'll get an email when you're let in; then run parley login again.`);
78
80
  }
79
81
  if (poll.status === "expired")
80
82
  break;
package/dist/server.js CHANGED
@@ -105,6 +105,12 @@ export async function serve() {
105
105
  return problem(res, 400, "invalid", error.message);
106
106
  }
107
107
  const shared = await share(session);
108
+ // Parley's servers refused it for good (the account is at its limit
109
+ // of open sessions), so it isn't kept here either.
110
+ if (typeof shared === "string") {
111
+ store.deleteSession(session.id);
112
+ return problem(res, 429, "too_many", shared);
113
+ }
108
114
  return json(res, { ...api.ownerView(session), session, shared });
109
115
  }
110
116
  const action = url.pathname.match(/^\/api\/sessions\/([a-z0-9]+)\/(end|delete|limit)$/);
@@ -137,6 +143,8 @@ export async function serve() {
137
143
  return handleSession(req, res, { session, base: `/o/${m[1]}`, owner: true, images: "url" }, m[2] ?? "/", url);
138
144
  }
139
145
  // Registers a new session with parley.im so its link works there.
146
+ // True once parley.im has it; false if it couldn't be reached (the next
147
+ // connection's sync catches up); the reason if it refused for good.
140
148
  async function share(session) {
141
149
  const creds = readCredentials(config);
142
150
  if (!creds)
@@ -147,7 +155,7 @@ export async function serve() {
147
155
  }
148
156
  catch (error) {
149
157
  console.error(`parley.im didn't take ${session.id}: ${error.message}`);
150
- return false;
158
+ return error.code === "too_many" ? error.message : false;
151
159
  }
152
160
  }
153
161
  async function handleSession(req, res, scope, rest, url) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parley-im/parley",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "Send someone a link. They talk to a read-only Claude or Codex in your project, on your computer, and you get everything they said.",
5
5
  "keywords": [
6
6
  "claude",
package/web/app.css CHANGED
@@ -513,6 +513,18 @@ span.live { display: inline-flex; align-items: center; gap: 7px; font-size: 13px
513
513
  .docs .flow { grid-template-columns: 1fr; gap: 26px; }
514
514
  .docs .flow div + div::before { left: 50%; top: -21px; transform: translateX(-50%) rotate(90deg); }
515
515
  }
516
+ /* Admin: letting people in a batch at a time. */
517
+ .let-in-next { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 6px; font-size: 14px; }
518
+ .let-in-next .search { flex: none; width: 76px; }
519
+ /* Admin: page views and where visitors came from. */
520
+ .table-wrap { overflow-x: auto; }
521
+ table.views { width: 100%; border-collapse: collapse; font-size: 14px; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
522
+ table.views th { text-align: right; font-weight: 600; font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--faint); padding: 8px 14px; border-bottom: 1px solid var(--line); }
523
+ table.views td { text-align: right; padding: 7px 14px; border-bottom: 1px solid var(--line); }
524
+ table.views th:first-child, table.views td:first-child { text-align: left; white-space: nowrap; }
525
+ table.views tfoot td { font-weight: 600; border-bottom: 0; }
526
+ .referrers { list-style: none; padding: 0; margin: 0 0 40px; max-width: 420px; }
527
+ .referrers li { display: flex; justify-content: space-between; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
516
528
  .trow.site-row { grid-template-columns: 1fr auto; }
517
529
  /* Long details shorten instead of pushing the buttons off a phone screen. */
518
530
  .trow.site-row .who-cell { min-width: 0; }
package/web/chat.js CHANGED
@@ -367,7 +367,7 @@
367
367
  ? el(
368
368
  "p",
369
369
  {},
370
- `Messages and screenshots are end-to-end encrypted between this page and ${theirs} computer. Parley passes them along but can't read them; it knows who sent this link, the project's name and when messages go by. The key is the part of your link after the #, so anyone with the whole link can read this chat: keep it to yourself. (This page's code comes from Parley's servers, so that promise relies on Parley serving it honestly. And ${agentName()} reads the conversation to reply, as with any ${agentName()} chat.)`,
370
+ `Messages and screenshots are end-to-end encrypted between this page and ${theirs} computer. Parley passes them along but can't read them; it knows who sent this link, the project's name and when messages go by, and counts how many times pages are opened each day. The key is the part of your link after the #, so anyone with the whole link can read this chat: keep it to yourself. (This page's code comes from Parley's servers, so that promise relies on Parley serving it honestly. And ${agentName()} reads the conversation to reply, as with any ${agentName()} chat.)`,
371
371
  )
372
372
  : null,
373
373
  el("p", {}, `When the replies run out, the chat pauses until ${whom} adds more. Replies come from ${theirs} computer, so it needs to be on, and the link stops working for good once the chat ends.`),