@parley-im/parley 0.2.12 → 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.12",
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,9 @@ 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; }
516
519
  /* Admin: page views and where visitors came from. */
517
520
  .table-wrap { overflow-x: auto; }
518
521
  table.views { width: 100%; border-collapse: collapse; font-size: 14px; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }