@paneui/core 0.0.5 → 0.0.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.
- package/dist/client.d.ts +195 -1
- package/dist/client.js +277 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/schemas.d.ts +67 -170
- package/dist/schemas.js +33 -4
- package/dist/types.d.ts +65 -0
- package/package.json +4 -4
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ArtifactRecord, ArtifactSummary, ArtifactType, ArtifactVersion, CreateArtifactResponse, CreateSessionRequest, CreateSessionResponse, EventsPage, FeedbackPage, FeedbackSubmission, FeedbackType, KeyInfo, PaneEvent, SessionState, TasteInfo } from "./types.js";
|
|
1
|
+
import type { ArtifactRecord, ArtifactSummary, ArtifactType, ArtifactVersion, CreateArtifactResponse, CreateSessionRequest, CreateSessionResponse, EventsPage, FeedbackPage, FeedbackSubmission, FeedbackType, KeyInfo, MintParticipantResponse, PaneEvent, ParticipantsList, SessionState, SessionsPage, TasteInfo } from "./types.js";
|
|
2
|
+
import type { ListSessionsQuery } from "./schemas.js";
|
|
2
3
|
export interface ClientOptions {
|
|
3
4
|
/** Relay base URL, e.g. https://pane.example.com. Trailing slash is trimmed. */
|
|
4
5
|
url: string;
|
|
@@ -202,6 +203,47 @@ export declare class PaneClient {
|
|
|
202
203
|
limit?: number;
|
|
203
204
|
before?: string;
|
|
204
205
|
}): Promise<FeedbackPage>;
|
|
206
|
+
/**
|
|
207
|
+
* GET /v1/sessions — list the calling agent's sessions. Default filter is
|
|
208
|
+
* `status=open` (effective status — respects expiresAt). Response items
|
|
209
|
+
* carry NO secrets: no participant token plaintext, no callback URL, no
|
|
210
|
+
* metadata or input_data. Use `participant_id` from the list as the handle
|
|
211
|
+
* for {@link revokeParticipant}; use {@link mintParticipant} to issue a
|
|
212
|
+
* fresh URL when the original was lost.
|
|
213
|
+
*/
|
|
214
|
+
listSessions(opts?: ListSessionsQuery): Promise<SessionsPage>;
|
|
215
|
+
/**
|
|
216
|
+
* GET /v1/sessions/:id/participants — list every participant on one
|
|
217
|
+
* session (active and revoked). Bounded by MAX_PARTICIPANTS_PER_SESSION
|
|
218
|
+
* on the relay, so the full list is returned with no pagination.
|
|
219
|
+
* Use this to find the `participant_id` you need to pass to
|
|
220
|
+
* {@link revokeParticipant}, or to audit revoked rows.
|
|
221
|
+
*/
|
|
222
|
+
listParticipants(sessionId: string): Promise<ParticipantsList>;
|
|
223
|
+
/**
|
|
224
|
+
* POST /v1/sessions/:id/participants — mint a fresh participant URL for an
|
|
225
|
+
* existing session. The one-shot recovery primitive when the original URL
|
|
226
|
+
* was dropped: the session keeps its event log, artifact pin, and created_at.
|
|
227
|
+
* v1 supports `kind: "human"` only.
|
|
228
|
+
*
|
|
229
|
+
* The plaintext token is returned EXACTLY ONCE in the response — the relay
|
|
230
|
+
* stores only the hash. Save the response (e.g. pipe to a JSONL log) before
|
|
231
|
+
* delivering the URL to the human.
|
|
232
|
+
*/
|
|
233
|
+
mintParticipant(sessionId: string, opts?: {
|
|
234
|
+
kind?: "human";
|
|
235
|
+
}): Promise<MintParticipantResponse>;
|
|
236
|
+
/**
|
|
237
|
+
* DELETE /v1/sessions/:id/participants/:participant_id — revoke a single
|
|
238
|
+
* participant URL. The session's other participants (and the agent's own
|
|
239
|
+
* WebSocket) are untouched. Idempotent: revoking an unknown or already-
|
|
240
|
+
* revoked participant returns 204. The agent participant cannot be revoked
|
|
241
|
+
* via this endpoint — use {@link deleteSession} instead.
|
|
242
|
+
*
|
|
243
|
+
* Existing WebSocket connections held under the revoked token are NOT
|
|
244
|
+
* actively kicked in v1; new HTTP and WS connections are refused.
|
|
245
|
+
*/
|
|
246
|
+
revokeParticipant(sessionId: string, participantId: string): Promise<void>;
|
|
205
247
|
/**
|
|
206
248
|
* DELETE /v1/sessions/:id — close/delete a session. Idempotent on the relay
|
|
207
249
|
* side (an already-closed session still returns 204 with no body).
|
|
@@ -215,4 +257,156 @@ export declare class PaneClient {
|
|
|
215
257
|
* instead of swallowing it.
|
|
216
258
|
*/
|
|
217
259
|
deleteArtifact(idOrSlug: string): Promise<void>;
|
|
260
|
+
/**
|
|
261
|
+
* Upload a blob to the relay. Returns a `BlobRef` that can be referenced
|
|
262
|
+
* in event payloads (the relay's `format: pane-blob-id` schema vocab
|
|
263
|
+
* validates the id) or in `pane create --input-data`.
|
|
264
|
+
*
|
|
265
|
+
* Scope defaults to "agent" (reusable across the agent's sessions). For
|
|
266
|
+
* `scope: "session"` pass `sessionId`; for `scope: "artifact"` pass
|
|
267
|
+
* `artifactId`. The agent must own the referenced session / artifact;
|
|
268
|
+
* cross-tenant attempts return blob_not_found.
|
|
269
|
+
*
|
|
270
|
+
* MIME is inferred from `mime` if supplied; otherwise the relay sniffs
|
|
271
|
+
* leading bytes and may reject with mime_mismatch / mime_disallowed.
|
|
272
|
+
*
|
|
273
|
+
* Backed by the relay's multipart `POST /v1/blobs` (the fallback path).
|
|
274
|
+
* For large uploads (>1 MB on hosted Azure) call `presignBlob()` +
|
|
275
|
+
* `confirmBlob()` instead — those use SAS direct-to-storage and don't
|
|
276
|
+
* stream bytes through the relay.
|
|
277
|
+
*/
|
|
278
|
+
uploadBlob(file: Blob | Buffer | Uint8Array, opts?: UploadBlobOptions): Promise<BlobRef>;
|
|
279
|
+
/** GET /v1/blobs/:id — download bytes as an ArrayBuffer. */
|
|
280
|
+
downloadBlob(blobId: string): Promise<ArrayBuffer>;
|
|
281
|
+
/**
|
|
282
|
+
* GET a blob's metadata only — useful before downloading large blobs, or
|
|
283
|
+
* for `pane blob show <id>` which doesn't want the bytes. Returns the full
|
|
284
|
+
* BlobRef (the same shape POST /v1/blobs returns): id, scope, mime, size,
|
|
285
|
+
* sha256, filename, width, height, status, scope FKs, timestamps.
|
|
286
|
+
*
|
|
287
|
+
* Backed by GET /v1/blobs/:id/metadata which serves the JSON BlobRef
|
|
288
|
+
* without streaming the bytes — cheap on the relay and avoids the
|
|
289
|
+
* encrypt-at-rest decrypt cost when only the metadata is needed.
|
|
290
|
+
*/
|
|
291
|
+
getBlob(blobId: string): Promise<BlobRef>;
|
|
292
|
+
/** DELETE /v1/blobs/:id — soft-delete (idempotent). */
|
|
293
|
+
deleteBlob(blobId: string): Promise<{
|
|
294
|
+
deleted: true;
|
|
295
|
+
}>;
|
|
296
|
+
/**
|
|
297
|
+
* Mint a `/b/<token>` capability URL for `blobId`. Default TTL is set by
|
|
298
|
+
* the relay (24h agent, session-TTL session, 30d artifact). `once: true`
|
|
299
|
+
* tokens self-delete on first GET.
|
|
300
|
+
*/
|
|
301
|
+
mintBlobToken(blobId: string, opts?: {
|
|
302
|
+
ttlSeconds?: number;
|
|
303
|
+
once?: boolean;
|
|
304
|
+
}): Promise<BlobTokenMintResponse>;
|
|
305
|
+
/** Revoke a previously-minted token. Idempotent. */
|
|
306
|
+
revokeBlobToken(blobId: string, tokenId: string): Promise<{
|
|
307
|
+
token_id: string;
|
|
308
|
+
revoked: true;
|
|
309
|
+
}>;
|
|
310
|
+
/**
|
|
311
|
+
* GET /v1/blobs — list YOUR agent's non-deleted blobs (newest first).
|
|
312
|
+
* Paginated via opaque cursor: when `next_cursor` is non-null, pass it
|
|
313
|
+
* back as `cursor` on the next call.
|
|
314
|
+
*/
|
|
315
|
+
listBlobs(opts?: ListBlobsOptions): Promise<{
|
|
316
|
+
items: BlobRef[];
|
|
317
|
+
next_cursor: string | null;
|
|
318
|
+
}>;
|
|
319
|
+
/**
|
|
320
|
+
* GET /v1/blobs/:id/tokens — enumerate the capability tokens minted
|
|
321
|
+
* against one blob, including revoked rows (for audit). The plaintext
|
|
322
|
+
* token is NEVER returned — it isn't stored, only its sha256 is.
|
|
323
|
+
*/
|
|
324
|
+
listBlobTokens(blobId: string): Promise<BlobTokenListResponse>;
|
|
325
|
+
/**
|
|
326
|
+
* Issue a presigned PUT URL for direct-to-storage upload. Returns the
|
|
327
|
+
* upload URL + the blob_id (already reserved in the relay's DB with
|
|
328
|
+
* status=pending) + expiry. After PUTting the bytes to the URL, call
|
|
329
|
+
* `confirmBlob(blob_id)` to finalise.
|
|
330
|
+
*
|
|
331
|
+
* Filesystem backend returns 501 not_implemented — use uploadBlob()
|
|
332
|
+
* (multipart fallback) instead. Azure backend returns a SAS URL.
|
|
333
|
+
*/
|
|
334
|
+
presignBlob(opts: PresignBlobOptions): Promise<{
|
|
335
|
+
blob_id: string;
|
|
336
|
+
upload_url: string;
|
|
337
|
+
expires_at: string;
|
|
338
|
+
}>;
|
|
339
|
+
/** Finalise a presigned upload — relay HEADs the bytes, verifies, flips ready. */
|
|
340
|
+
confirmBlob(blobId: string): Promise<BlobRef>;
|
|
341
|
+
}
|
|
342
|
+
/** Per-blob metadata as returned by `POST /v1/blobs` and friends. */
|
|
343
|
+
export interface BlobRef {
|
|
344
|
+
blob_id: string;
|
|
345
|
+
scope: "agent" | "session" | "artifact";
|
|
346
|
+
mime: string;
|
|
347
|
+
size: number;
|
|
348
|
+
sha256: string;
|
|
349
|
+
url?: string;
|
|
350
|
+
width?: number | null;
|
|
351
|
+
height?: number | null;
|
|
352
|
+
filename?: string | null;
|
|
353
|
+
status?: string;
|
|
354
|
+
session_id?: string | null;
|
|
355
|
+
artifact_id?: string | null;
|
|
356
|
+
created_at?: string;
|
|
357
|
+
confirmed_at?: string | null;
|
|
358
|
+
deleted_at?: string | null;
|
|
359
|
+
}
|
|
360
|
+
export interface UploadBlobOptions {
|
|
361
|
+
scope?: "agent" | "session" | "artifact";
|
|
362
|
+
sessionId?: string;
|
|
363
|
+
artifactId?: string;
|
|
364
|
+
/** Declared Content-Type. Defaults to `application/octet-stream`. The
|
|
365
|
+
* relay sniffs leading bytes and may reject with `mime_mismatch`. */
|
|
366
|
+
mime?: string;
|
|
367
|
+
/** Optional display name (the relay records it for UX; never a path component). */
|
|
368
|
+
filename?: string;
|
|
369
|
+
}
|
|
370
|
+
export interface PresignBlobOptions {
|
|
371
|
+
mime: string;
|
|
372
|
+
size: number;
|
|
373
|
+
sha256: string;
|
|
374
|
+
scope?: "agent" | "session" | "artifact";
|
|
375
|
+
sessionId?: string;
|
|
376
|
+
artifactId?: string;
|
|
377
|
+
filename?: string;
|
|
378
|
+
}
|
|
379
|
+
export interface BlobTokenMintResponse {
|
|
380
|
+
token_id: string;
|
|
381
|
+
token: string;
|
|
382
|
+
token_prefix: string;
|
|
383
|
+
url: string;
|
|
384
|
+
expires_at: string;
|
|
385
|
+
once: boolean;
|
|
386
|
+
}
|
|
387
|
+
/** Options for `listBlobs()` — opaque cursor + page-size knob. */
|
|
388
|
+
export interface ListBlobsOptions {
|
|
389
|
+
/** Opaque pagination cursor from a prior `next_cursor`. */
|
|
390
|
+
cursor?: string;
|
|
391
|
+
/** Page size; relay clamps to 1..100. Defaults to the relay default (50). */
|
|
392
|
+
limit?: number;
|
|
393
|
+
}
|
|
394
|
+
/** One row in the response from `listBlobTokens()`. */
|
|
395
|
+
export interface BlobTokenAuditEntry {
|
|
396
|
+
token_id: string;
|
|
397
|
+
token_prefix: string;
|
|
398
|
+
expires_at: string;
|
|
399
|
+
once: boolean;
|
|
400
|
+
created_at: string;
|
|
401
|
+
last_used_at: string | null;
|
|
402
|
+
use_count: number;
|
|
403
|
+
/** Non-null when the token has been revoked. Expired-but-unrevoked rows
|
|
404
|
+
* carry `revoked_at: null` and an `expires_at` in the past — both are
|
|
405
|
+
* useful for audit. */
|
|
406
|
+
revoked_at: string | null;
|
|
407
|
+
}
|
|
408
|
+
/** Shape returned by `listBlobTokens()`. */
|
|
409
|
+
export interface BlobTokenListResponse {
|
|
410
|
+
blob_id: string;
|
|
411
|
+
items: BlobTokenAuditEntry[];
|
|
218
412
|
}
|
package/dist/client.js
CHANGED
|
@@ -125,6 +125,7 @@ export class PaneClient {
|
|
|
125
125
|
async createSession(req) {
|
|
126
126
|
const r = await this.call("POST", "/v1/sessions", {
|
|
127
127
|
artifact: req.artifact,
|
|
128
|
+
title: req.title,
|
|
128
129
|
input_data: req.input_data,
|
|
129
130
|
participants: req.participants,
|
|
130
131
|
ttl: req.ttl,
|
|
@@ -341,6 +342,74 @@ export class PaneClient {
|
|
|
341
342
|
this.fail(r);
|
|
342
343
|
return this.asObject(r);
|
|
343
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* GET /v1/sessions — list the calling agent's sessions. Default filter is
|
|
347
|
+
* `status=open` (effective status — respects expiresAt). Response items
|
|
348
|
+
* carry NO secrets: no participant token plaintext, no callback URL, no
|
|
349
|
+
* metadata or input_data. Use `participant_id` from the list as the handle
|
|
350
|
+
* for {@link revokeParticipant}; use {@link mintParticipant} to issue a
|
|
351
|
+
* fresh URL when the original was lost.
|
|
352
|
+
*/
|
|
353
|
+
async listSessions(opts = {}) {
|
|
354
|
+
const q = new URLSearchParams();
|
|
355
|
+
if (opts.status !== undefined)
|
|
356
|
+
q.set("status", opts.status);
|
|
357
|
+
if (opts.limit !== undefined)
|
|
358
|
+
q.set("limit", String(opts.limit));
|
|
359
|
+
if (opts.cursor !== undefined && opts.cursor !== "")
|
|
360
|
+
q.set("cursor", opts.cursor);
|
|
361
|
+
if (opts.artifact_id !== undefined && opts.artifact_id !== "")
|
|
362
|
+
q.set("artifact_id", opts.artifact_id);
|
|
363
|
+
const qs = q.toString();
|
|
364
|
+
const r = await this.call("GET", `/v1/sessions${qs ? "?" + qs : ""}`);
|
|
365
|
+
if (!r.ok)
|
|
366
|
+
this.fail(r);
|
|
367
|
+
return this.asObject(r);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* GET /v1/sessions/:id/participants — list every participant on one
|
|
371
|
+
* session (active and revoked). Bounded by MAX_PARTICIPANTS_PER_SESSION
|
|
372
|
+
* on the relay, so the full list is returned with no pagination.
|
|
373
|
+
* Use this to find the `participant_id` you need to pass to
|
|
374
|
+
* {@link revokeParticipant}, or to audit revoked rows.
|
|
375
|
+
*/
|
|
376
|
+
async listParticipants(sessionId) {
|
|
377
|
+
const r = await this.call("GET", `/v1/sessions/${encodeURIComponent(sessionId)}/participants`);
|
|
378
|
+
if (!r.ok)
|
|
379
|
+
this.fail(r);
|
|
380
|
+
return this.asObject(r);
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* POST /v1/sessions/:id/participants — mint a fresh participant URL for an
|
|
384
|
+
* existing session. The one-shot recovery primitive when the original URL
|
|
385
|
+
* was dropped: the session keeps its event log, artifact pin, and created_at.
|
|
386
|
+
* v1 supports `kind: "human"` only.
|
|
387
|
+
*
|
|
388
|
+
* The plaintext token is returned EXACTLY ONCE in the response — the relay
|
|
389
|
+
* stores only the hash. Save the response (e.g. pipe to a JSONL log) before
|
|
390
|
+
* delivering the URL to the human.
|
|
391
|
+
*/
|
|
392
|
+
async mintParticipant(sessionId, opts = {}) {
|
|
393
|
+
const r = await this.call("POST", `/v1/sessions/${encodeURIComponent(sessionId)}/participants`, { kind: opts.kind ?? "human" });
|
|
394
|
+
if (!r.ok)
|
|
395
|
+
this.fail(r);
|
|
396
|
+
return this.asObject(r);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* DELETE /v1/sessions/:id/participants/:participant_id — revoke a single
|
|
400
|
+
* participant URL. The session's other participants (and the agent's own
|
|
401
|
+
* WebSocket) are untouched. Idempotent: revoking an unknown or already-
|
|
402
|
+
* revoked participant returns 204. The agent participant cannot be revoked
|
|
403
|
+
* via this endpoint — use {@link deleteSession} instead.
|
|
404
|
+
*
|
|
405
|
+
* Existing WebSocket connections held under the revoked token are NOT
|
|
406
|
+
* actively kicked in v1; new HTTP and WS connections are refused.
|
|
407
|
+
*/
|
|
408
|
+
async revokeParticipant(sessionId, participantId) {
|
|
409
|
+
const r = await this.call("DELETE", `/v1/sessions/${encodeURIComponent(sessionId)}/participants/${encodeURIComponent(participantId)}`);
|
|
410
|
+
if (!r.ok)
|
|
411
|
+
this.fail(r);
|
|
412
|
+
}
|
|
344
413
|
/**
|
|
345
414
|
* DELETE /v1/sessions/:id — close/delete a session. Idempotent on the relay
|
|
346
415
|
* side (an already-closed session still returns 204 with no body).
|
|
@@ -362,4 +431,212 @@ export class PaneClient {
|
|
|
362
431
|
if (!r.ok)
|
|
363
432
|
this.fail(r);
|
|
364
433
|
}
|
|
434
|
+
// ------------------------------------------------------------------------
|
|
435
|
+
// Blobs (v0.1.0). Three-scope binary attachments with multipart upload.
|
|
436
|
+
// See proposal pane#152 for the full design.
|
|
437
|
+
// ------------------------------------------------------------------------
|
|
438
|
+
/**
|
|
439
|
+
* Upload a blob to the relay. Returns a `BlobRef` that can be referenced
|
|
440
|
+
* in event payloads (the relay's `format: pane-blob-id` schema vocab
|
|
441
|
+
* validates the id) or in `pane create --input-data`.
|
|
442
|
+
*
|
|
443
|
+
* Scope defaults to "agent" (reusable across the agent's sessions). For
|
|
444
|
+
* `scope: "session"` pass `sessionId`; for `scope: "artifact"` pass
|
|
445
|
+
* `artifactId`. The agent must own the referenced session / artifact;
|
|
446
|
+
* cross-tenant attempts return blob_not_found.
|
|
447
|
+
*
|
|
448
|
+
* MIME is inferred from `mime` if supplied; otherwise the relay sniffs
|
|
449
|
+
* leading bytes and may reject with mime_mismatch / mime_disallowed.
|
|
450
|
+
*
|
|
451
|
+
* Backed by the relay's multipart `POST /v1/blobs` (the fallback path).
|
|
452
|
+
* For large uploads (>1 MB on hosted Azure) call `presignBlob()` +
|
|
453
|
+
* `confirmBlob()` instead — those use SAS direct-to-storage and don't
|
|
454
|
+
* stream bytes through the relay.
|
|
455
|
+
*/
|
|
456
|
+
async uploadBlob(file, opts = {}) {
|
|
457
|
+
const fd = new FormData();
|
|
458
|
+
let blob;
|
|
459
|
+
if (file instanceof Blob) {
|
|
460
|
+
blob = file;
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
// Buffer / Uint8Array path — wrap in a Blob with the declared MIME.
|
|
464
|
+
// Copy into a freshly allocated Uint8Array so the buffer type
|
|
465
|
+
// narrows from `ArrayBufferLike` (which includes SharedArrayBuffer)
|
|
466
|
+
// to `ArrayBuffer` specifically — the Blob constructor accepts only
|
|
467
|
+
// the latter under @types/node ≥25 + TS ≥5.7's generic narrowing of
|
|
468
|
+
// Uint8Array<TArrayBuffer>. `new Uint8Array(length)` returns
|
|
469
|
+
// `Uint8Array<ArrayBuffer>` by construction, satisfying BlobPart
|
|
470
|
+
// without a type cast. The extra copy is one walk over the bytes —
|
|
471
|
+
// negligible vs the network upload that follows.
|
|
472
|
+
const src = file instanceof Uint8Array ? file : new Uint8Array(file);
|
|
473
|
+
const u8 = new Uint8Array(src.byteLength);
|
|
474
|
+
u8.set(src);
|
|
475
|
+
blob = new Blob([u8], {
|
|
476
|
+
type: opts.mime ?? "application/octet-stream",
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
fd.set("file", blob, opts.filename ?? "blob");
|
|
480
|
+
if (opts.scope)
|
|
481
|
+
fd.set("scope", opts.scope);
|
|
482
|
+
if (opts.sessionId)
|
|
483
|
+
fd.set("session_id", opts.sessionId);
|
|
484
|
+
if (opts.artifactId)
|
|
485
|
+
fd.set("artifact_id", opts.artifactId);
|
|
486
|
+
if (opts.filename)
|
|
487
|
+
fd.set("filename", opts.filename);
|
|
488
|
+
const url = this.base + "/v1/blobs";
|
|
489
|
+
let res;
|
|
490
|
+
try {
|
|
491
|
+
res = await this.fetchImpl(url, {
|
|
492
|
+
method: "POST",
|
|
493
|
+
headers: {
|
|
494
|
+
authorization: "Bearer " + this.apiKey,
|
|
495
|
+
...(this.cliVersion ? { "x-pane-cli-version": this.cliVersion } : {}),
|
|
496
|
+
},
|
|
497
|
+
body: fd,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
catch (e) {
|
|
501
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
502
|
+
throw new PaneApiError(0, "fetch_error", msg);
|
|
503
|
+
}
|
|
504
|
+
const text = await res.text().catch(() => "");
|
|
505
|
+
let data;
|
|
506
|
+
try {
|
|
507
|
+
data = text ? JSON.parse(text) : null;
|
|
508
|
+
}
|
|
509
|
+
catch {
|
|
510
|
+
throw new PaneApiError(res.status, "non_json_response", `relay returned a non-JSON body (status ${res.status})`);
|
|
511
|
+
}
|
|
512
|
+
if (!res.ok) {
|
|
513
|
+
this.fail({ ok: false, status: res.status, data });
|
|
514
|
+
}
|
|
515
|
+
return data;
|
|
516
|
+
}
|
|
517
|
+
/** GET /v1/blobs/:id — download bytes as an ArrayBuffer. */
|
|
518
|
+
async downloadBlob(blobId) {
|
|
519
|
+
const url = this.base + "/v1/blobs/" + encodeURIComponent(blobId);
|
|
520
|
+
const res = await this.fetchImpl(url, {
|
|
521
|
+
method: "GET",
|
|
522
|
+
headers: {
|
|
523
|
+
authorization: "Bearer " + this.apiKey,
|
|
524
|
+
...(this.cliVersion ? { "x-pane-cli-version": this.cliVersion } : {}),
|
|
525
|
+
},
|
|
526
|
+
});
|
|
527
|
+
if (!res.ok) {
|
|
528
|
+
const text = await res.text().catch(() => "");
|
|
529
|
+
let data;
|
|
530
|
+
try {
|
|
531
|
+
data = text ? JSON.parse(text) : null;
|
|
532
|
+
}
|
|
533
|
+
catch {
|
|
534
|
+
data = null;
|
|
535
|
+
}
|
|
536
|
+
this.fail({ ok: false, status: res.status, data });
|
|
537
|
+
}
|
|
538
|
+
return res.arrayBuffer();
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* GET a blob's metadata only — useful before downloading large blobs, or
|
|
542
|
+
* for `pane blob show <id>` which doesn't want the bytes. Returns the full
|
|
543
|
+
* BlobRef (the same shape POST /v1/blobs returns): id, scope, mime, size,
|
|
544
|
+
* sha256, filename, width, height, status, scope FKs, timestamps.
|
|
545
|
+
*
|
|
546
|
+
* Backed by GET /v1/blobs/:id/metadata which serves the JSON BlobRef
|
|
547
|
+
* without streaming the bytes — cheap on the relay and avoids the
|
|
548
|
+
* encrypt-at-rest decrypt cost when only the metadata is needed.
|
|
549
|
+
*/
|
|
550
|
+
async getBlob(blobId) {
|
|
551
|
+
const r = await this.call("GET", "/v1/blobs/" + encodeURIComponent(blobId) + "/metadata");
|
|
552
|
+
if (!r.ok)
|
|
553
|
+
this.fail(r);
|
|
554
|
+
return this.asObject(r);
|
|
555
|
+
}
|
|
556
|
+
/** DELETE /v1/blobs/:id — soft-delete (idempotent). */
|
|
557
|
+
async deleteBlob(blobId) {
|
|
558
|
+
const r = await this.call("DELETE", "/v1/blobs/" + encodeURIComponent(blobId));
|
|
559
|
+
if (!r.ok)
|
|
560
|
+
this.fail(r);
|
|
561
|
+
return { deleted: true };
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Mint a `/b/<token>` capability URL for `blobId`. Default TTL is set by
|
|
565
|
+
* the relay (24h agent, session-TTL session, 30d artifact). `once: true`
|
|
566
|
+
* tokens self-delete on first GET.
|
|
567
|
+
*/
|
|
568
|
+
async mintBlobToken(blobId, opts = {}) {
|
|
569
|
+
const r = await this.call("POST", "/v1/blobs/" + encodeURIComponent(blobId) + "/tokens", { ttl_seconds: opts.ttlSeconds, once: opts.once });
|
|
570
|
+
if (!r.ok)
|
|
571
|
+
this.fail(r);
|
|
572
|
+
return r.data;
|
|
573
|
+
}
|
|
574
|
+
/** Revoke a previously-minted token. Idempotent. */
|
|
575
|
+
async revokeBlobToken(blobId, tokenId) {
|
|
576
|
+
const r = await this.call("DELETE", "/v1/blobs/" +
|
|
577
|
+
encodeURIComponent(blobId) +
|
|
578
|
+
"/tokens/" +
|
|
579
|
+
encodeURIComponent(tokenId));
|
|
580
|
+
if (!r.ok)
|
|
581
|
+
this.fail(r);
|
|
582
|
+
return r.data;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* GET /v1/blobs — list YOUR agent's non-deleted blobs (newest first).
|
|
586
|
+
* Paginated via opaque cursor: when `next_cursor` is non-null, pass it
|
|
587
|
+
* back as `cursor` on the next call.
|
|
588
|
+
*/
|
|
589
|
+
async listBlobs(opts = {}) {
|
|
590
|
+
const params = new URLSearchParams();
|
|
591
|
+
if (opts.cursor !== undefined)
|
|
592
|
+
params.set("cursor", opts.cursor);
|
|
593
|
+
if (opts.limit !== undefined)
|
|
594
|
+
params.set("limit", String(opts.limit));
|
|
595
|
+
const qs = params.toString();
|
|
596
|
+
const r = await this.call("GET", "/v1/blobs" + (qs ? "?" + qs : ""));
|
|
597
|
+
if (!r.ok)
|
|
598
|
+
this.fail(r);
|
|
599
|
+
return r.data;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* GET /v1/blobs/:id/tokens — enumerate the capability tokens minted
|
|
603
|
+
* against one blob, including revoked rows (for audit). The plaintext
|
|
604
|
+
* token is NEVER returned — it isn't stored, only its sha256 is.
|
|
605
|
+
*/
|
|
606
|
+
async listBlobTokens(blobId) {
|
|
607
|
+
const r = await this.call("GET", "/v1/blobs/" + encodeURIComponent(blobId) + "/tokens");
|
|
608
|
+
if (!r.ok)
|
|
609
|
+
this.fail(r);
|
|
610
|
+
return r.data;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Issue a presigned PUT URL for direct-to-storage upload. Returns the
|
|
614
|
+
* upload URL + the blob_id (already reserved in the relay's DB with
|
|
615
|
+
* status=pending) + expiry. After PUTting the bytes to the URL, call
|
|
616
|
+
* `confirmBlob(blob_id)` to finalise.
|
|
617
|
+
*
|
|
618
|
+
* Filesystem backend returns 501 not_implemented — use uploadBlob()
|
|
619
|
+
* (multipart fallback) instead. Azure backend returns a SAS URL.
|
|
620
|
+
*/
|
|
621
|
+
async presignBlob(opts) {
|
|
622
|
+
const r = await this.call("POST", "/v1/blobs/presign", {
|
|
623
|
+
mime: opts.mime,
|
|
624
|
+
size: opts.size,
|
|
625
|
+
sha256: opts.sha256,
|
|
626
|
+
scope: opts.scope,
|
|
627
|
+
session_id: opts.sessionId,
|
|
628
|
+
artifact_id: opts.artifactId,
|
|
629
|
+
filename: opts.filename,
|
|
630
|
+
});
|
|
631
|
+
if (!r.ok)
|
|
632
|
+
this.fail(r);
|
|
633
|
+
return r.data;
|
|
634
|
+
}
|
|
635
|
+
/** Finalise a presigned upload — relay HEADs the bytes, verifies, flips ready. */
|
|
636
|
+
async confirmBlob(blobId) {
|
|
637
|
+
const r = await this.call("POST", "/v1/blobs/" + encodeURIComponent(blobId) + "/confirm");
|
|
638
|
+
if (!r.ok)
|
|
639
|
+
this.fail(r);
|
|
640
|
+
return r.data;
|
|
641
|
+
}
|
|
365
642
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export { PaneClient, PaneApiError } from "./client.js";
|
|
2
|
-
export type { ClientOptions, RelayResponse, CreateArtifactRequest, CreateArtifactVersionRequest, PatchArtifactMetadataRequest, } from "./client.js";
|
|
2
|
+
export type { ClientOptions, RelayResponse, CreateArtifactRequest, CreateArtifactVersionRequest, PatchArtifactMetadataRequest, BlobRef, UploadBlobOptions, PresignBlobOptions, BlobTokenMintResponse, ListBlobsOptions, BlobTokenAuditEntry, BlobTokenListResponse, } from "./client.js";
|
|
3
3
|
export { openStream } from "./stream.js";
|
|
4
4
|
export type { OpenStreamOptions, StreamHandlers, StreamHandle, } from "./stream.js";
|
|
5
5
|
export { registerAgent } from "./register.js";
|
|
6
6
|
export type { RegisterAgentOptions, RegisterAgentResult } from "./register.js";
|
|
7
|
-
export { artifactSchema, callbackSchema, createSessionSchema, artifactTypeSchema, createArtifactSchema, createArtifactVersionSchema, patchArtifactMetadataSchema, feedbackTypeSchema, submitFeedbackSchema, } from "./schemas.js";
|
|
8
|
-
export type { CreateSessionInput } from "./schemas.js";
|
|
7
|
+
export { artifactSchema, callbackSchema, createSessionSchema, artifactTypeSchema, createArtifactSchema, createArtifactVersionSchema, patchArtifactMetadataSchema, feedbackTypeSchema, submitFeedbackSchema, listSessionsStatusSchema, listSessionsQuerySchema, mintParticipantSchema, } from "./schemas.js";
|
|
8
|
+
export type { CreateSessionInput, ListSessionsStatus, ListSessionsQuery, MintParticipantInput, } from "./schemas.js";
|
|
9
9
|
export { MAX_EVENT_TYPE_LENGTH, MAX_IDEMPOTENCY_KEY_LENGTH, MAX_RESPONSE_SNIPPET_LENGTH, MAX_FRAME_SNIPPET_LENGTH, } from "./limits.js";
|
|
10
|
-
export type { AuthorKind, PaneEvent, Artifact, ArtifactType, ArtifactVersion, ArtifactRecord, ArtifactSummary, CreateArtifactResponse, KeyInfo, TasteInfo, FeedbackType, FeedbackSubmission, FeedbackRecord, FeedbackPage, Callback, CreateSessionRequest, CreateSessionResponse, SessionState, EventsPage, RelayError, } from "./types.js";
|
|
10
|
+
export type { AuthorKind, PaneEvent, Artifact, ArtifactType, ArtifactVersion, ArtifactRecord, ArtifactSummary, CreateArtifactResponse, KeyInfo, TasteInfo, FeedbackType, FeedbackSubmission, FeedbackRecord, FeedbackPage, Callback, CreateSessionRequest, CreateSessionResponse, SessionState, EventsPage, ParticipantSummary, ParticipantsList, SessionSummary, SessionsPage, MintParticipantResponse, RelayError, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
export { PaneClient, PaneApiError } from "./client.js";
|
|
4
4
|
export { openStream } from "./stream.js";
|
|
5
5
|
export { registerAgent } from "./register.js";
|
|
6
|
-
export { artifactSchema, callbackSchema, createSessionSchema, artifactTypeSchema, createArtifactSchema, createArtifactVersionSchema, patchArtifactMetadataSchema, feedbackTypeSchema, submitFeedbackSchema, } from "./schemas.js";
|
|
6
|
+
export { artifactSchema, callbackSchema, createSessionSchema, artifactTypeSchema, createArtifactSchema, createArtifactVersionSchema, patchArtifactMetadataSchema, feedbackTypeSchema, submitFeedbackSchema, listSessionsStatusSchema, listSessionsQuerySchema, mintParticipantSchema, } from "./schemas.js";
|
|
7
7
|
export { MAX_EVENT_TYPE_LENGTH, MAX_IDEMPOTENCY_KEY_LENGTH, MAX_RESPONSE_SNIPPET_LENGTH, MAX_FRAME_SNIPPET_LENGTH, } from "./limits.js";
|
package/dist/schemas.d.ts
CHANGED
|
@@ -1,211 +1,108 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare const artifactTypeSchema: z.ZodEnum<
|
|
3
|
-
|
|
2
|
+
export declare const artifactTypeSchema: z.ZodEnum<{
|
|
3
|
+
"html-inline": "html-inline";
|
|
4
|
+
"html-ref": "html-ref";
|
|
5
|
+
}>;
|
|
6
|
+
export declare const artifactSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
4
7
|
type: z.ZodLiteral<"html-inline">;
|
|
5
8
|
source: z.ZodString;
|
|
6
|
-
},
|
|
7
|
-
type: "html-inline";
|
|
8
|
-
source: string;
|
|
9
|
-
}, {
|
|
10
|
-
type: "html-inline";
|
|
11
|
-
source: string;
|
|
12
|
-
}>, z.ZodObject<{
|
|
9
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
13
10
|
type: z.ZodLiteral<"html-ref">;
|
|
14
11
|
source: z.ZodString;
|
|
15
|
-
},
|
|
16
|
-
type: "html-ref";
|
|
17
|
-
source: string;
|
|
18
|
-
}, {
|
|
19
|
-
type: "html-ref";
|
|
20
|
-
source: string;
|
|
21
|
-
}>]>;
|
|
12
|
+
}, z.core.$strip>], "type">;
|
|
22
13
|
export declare const callbackSchema: z.ZodObject<{
|
|
23
14
|
url: z.ZodString;
|
|
24
|
-
events: z.ZodArray<z.ZodString
|
|
15
|
+
events: z.ZodArray<z.ZodString>;
|
|
25
16
|
secret: z.ZodString;
|
|
26
|
-
},
|
|
27
|
-
url: string;
|
|
28
|
-
events: string[];
|
|
29
|
-
secret: string;
|
|
30
|
-
}, {
|
|
31
|
-
url: string;
|
|
32
|
-
events: string[];
|
|
33
|
-
secret: string;
|
|
34
|
-
}>;
|
|
17
|
+
}, z.core.$strip>;
|
|
35
18
|
export declare const createSessionSchema: z.ZodObject<{
|
|
36
|
-
artifact: z.
|
|
19
|
+
artifact: z.ZodUnion<readonly [z.ZodObject<{
|
|
37
20
|
id: z.ZodString;
|
|
38
21
|
version: z.ZodOptional<z.ZodNumber>;
|
|
39
|
-
},
|
|
40
|
-
id: string;
|
|
41
|
-
version?: number | undefined;
|
|
42
|
-
}, {
|
|
43
|
-
id: string;
|
|
44
|
-
version?: number | undefined;
|
|
45
|
-
}>, z.ZodObject<{
|
|
22
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
46
23
|
source: z.ZodString;
|
|
47
|
-
type: z.ZodEnum<
|
|
24
|
+
type: z.ZodEnum<{
|
|
25
|
+
"html-inline": "html-inline";
|
|
26
|
+
"html-ref": "html-ref";
|
|
27
|
+
}>;
|
|
48
28
|
event_schema: z.ZodOptional<z.ZodUnknown>;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
source: string;
|
|
52
|
-
event_schema?: unknown;
|
|
53
|
-
}, {
|
|
54
|
-
type: "html-inline" | "html-ref";
|
|
55
|
-
source: string;
|
|
56
|
-
event_schema?: unknown;
|
|
57
|
-
}>]>, {
|
|
58
|
-
type: "html-inline" | "html-ref";
|
|
59
|
-
source: string;
|
|
60
|
-
event_schema?: unknown;
|
|
61
|
-
} | {
|
|
62
|
-
id: string;
|
|
63
|
-
version?: number | undefined;
|
|
64
|
-
}, {
|
|
65
|
-
type: "html-inline" | "html-ref";
|
|
66
|
-
source: string;
|
|
67
|
-
event_schema?: unknown;
|
|
68
|
-
} | {
|
|
69
|
-
id: string;
|
|
70
|
-
version?: number | undefined;
|
|
71
|
-
}>;
|
|
29
|
+
input_schema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
30
|
+
}, z.core.$strip>]>;
|
|
72
31
|
input_data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
73
32
|
participants: z.ZodOptional<z.ZodObject<{
|
|
74
33
|
humans: z.ZodNumber;
|
|
75
|
-
},
|
|
76
|
-
humans: number;
|
|
77
|
-
}, {
|
|
78
|
-
humans: number;
|
|
79
|
-
}>>;
|
|
34
|
+
}, z.core.$strip>>;
|
|
80
35
|
ttl: z.ZodOptional<z.ZodNumber>;
|
|
81
36
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
82
37
|
callback: z.ZodOptional<z.ZodObject<{
|
|
83
38
|
url: z.ZodString;
|
|
84
|
-
events: z.ZodArray<z.ZodString
|
|
39
|
+
events: z.ZodArray<z.ZodString>;
|
|
85
40
|
secret: z.ZodString;
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
secret: string;
|
|
90
|
-
}, {
|
|
91
|
-
url: string;
|
|
92
|
-
events: string[];
|
|
93
|
-
secret: string;
|
|
94
|
-
}>>;
|
|
95
|
-
}, "strip", z.ZodTypeAny, {
|
|
96
|
-
artifact: {
|
|
97
|
-
type: "html-inline" | "html-ref";
|
|
98
|
-
source: string;
|
|
99
|
-
event_schema?: unknown;
|
|
100
|
-
} | {
|
|
101
|
-
id: string;
|
|
102
|
-
version?: number | undefined;
|
|
103
|
-
};
|
|
104
|
-
input_data?: Record<string, unknown> | undefined;
|
|
105
|
-
participants?: {
|
|
106
|
-
humans: number;
|
|
107
|
-
} | undefined;
|
|
108
|
-
ttl?: number | undefined;
|
|
109
|
-
metadata?: Record<string, unknown> | undefined;
|
|
110
|
-
callback?: {
|
|
111
|
-
url: string;
|
|
112
|
-
events: string[];
|
|
113
|
-
secret: string;
|
|
114
|
-
} | undefined;
|
|
115
|
-
}, {
|
|
116
|
-
artifact: {
|
|
117
|
-
type: "html-inline" | "html-ref";
|
|
118
|
-
source: string;
|
|
119
|
-
event_schema?: unknown;
|
|
120
|
-
} | {
|
|
121
|
-
id: string;
|
|
122
|
-
version?: number | undefined;
|
|
123
|
-
};
|
|
124
|
-
input_data?: Record<string, unknown> | undefined;
|
|
125
|
-
participants?: {
|
|
126
|
-
humans: number;
|
|
127
|
-
} | undefined;
|
|
128
|
-
ttl?: number | undefined;
|
|
129
|
-
metadata?: Record<string, unknown> | undefined;
|
|
130
|
-
callback?: {
|
|
131
|
-
url: string;
|
|
132
|
-
events: string[];
|
|
133
|
-
secret: string;
|
|
134
|
-
} | undefined;
|
|
135
|
-
}>;
|
|
41
|
+
}, z.core.$strip>>;
|
|
42
|
+
title: z.ZodOptional<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>;
|
|
136
44
|
export declare const createArtifactSchema: z.ZodObject<{
|
|
137
45
|
name: z.ZodString;
|
|
138
46
|
slug: z.ZodOptional<z.ZodString>;
|
|
139
47
|
description: z.ZodOptional<z.ZodString>;
|
|
140
|
-
tags: z.ZodOptional<z.ZodArray<z.ZodString
|
|
48
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
141
49
|
source: z.ZodString;
|
|
142
|
-
type: z.ZodEnum<
|
|
50
|
+
type: z.ZodEnum<{
|
|
51
|
+
"html-inline": "html-inline";
|
|
52
|
+
"html-ref": "html-ref";
|
|
53
|
+
}>;
|
|
143
54
|
event_schema: z.ZodOptional<z.ZodUnknown>;
|
|
144
55
|
input_schema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
145
|
-
},
|
|
146
|
-
type: "html-inline" | "html-ref";
|
|
147
|
-
source: string;
|
|
148
|
-
name: string;
|
|
149
|
-
event_schema?: unknown;
|
|
150
|
-
slug?: string | undefined;
|
|
151
|
-
description?: string | undefined;
|
|
152
|
-
tags?: string[] | undefined;
|
|
153
|
-
input_schema?: Record<string, unknown> | undefined;
|
|
154
|
-
}, {
|
|
155
|
-
type: "html-inline" | "html-ref";
|
|
156
|
-
source: string;
|
|
157
|
-
name: string;
|
|
158
|
-
event_schema?: unknown;
|
|
159
|
-
slug?: string | undefined;
|
|
160
|
-
description?: string | undefined;
|
|
161
|
-
tags?: string[] | undefined;
|
|
162
|
-
input_schema?: Record<string, unknown> | undefined;
|
|
163
|
-
}>;
|
|
56
|
+
}, z.core.$strip>;
|
|
164
57
|
export declare const createArtifactVersionSchema: z.ZodObject<{
|
|
165
58
|
source: z.ZodString;
|
|
166
|
-
type: z.ZodEnum<
|
|
59
|
+
type: z.ZodEnum<{
|
|
60
|
+
"html-inline": "html-inline";
|
|
61
|
+
"html-ref": "html-ref";
|
|
62
|
+
}>;
|
|
167
63
|
event_schema: z.ZodOptional<z.ZodUnknown>;
|
|
168
64
|
input_schema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
169
|
-
},
|
|
170
|
-
type: "html-inline" | "html-ref";
|
|
171
|
-
source: string;
|
|
172
|
-
event_schema?: unknown;
|
|
173
|
-
input_schema?: Record<string, unknown> | undefined;
|
|
174
|
-
}, {
|
|
175
|
-
type: "html-inline" | "html-ref";
|
|
176
|
-
source: string;
|
|
177
|
-
event_schema?: unknown;
|
|
178
|
-
input_schema?: Record<string, unknown> | undefined;
|
|
179
|
-
}>;
|
|
65
|
+
}, z.core.$strip>;
|
|
180
66
|
export declare const patchArtifactMetadataSchema: z.ZodObject<{
|
|
181
67
|
name: z.ZodOptional<z.ZodString>;
|
|
182
68
|
slug: z.ZodOptional<z.ZodString>;
|
|
183
69
|
description: z.ZodOptional<z.ZodString>;
|
|
184
|
-
tags: z.ZodOptional<z.ZodArray<z.ZodString
|
|
185
|
-
},
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}, {
|
|
191
|
-
name?: string | undefined;
|
|
192
|
-
slug?: string | undefined;
|
|
193
|
-
description?: string | undefined;
|
|
194
|
-
tags?: string[] | undefined;
|
|
70
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
export declare const feedbackTypeSchema: z.ZodEnum<{
|
|
73
|
+
bug: "bug";
|
|
74
|
+
feature: "feature";
|
|
75
|
+
note: "note";
|
|
195
76
|
}>;
|
|
196
|
-
export declare const feedbackTypeSchema: z.ZodEnum<["bug", "feature", "note"]>;
|
|
197
77
|
export declare const submitFeedbackSchema: z.ZodObject<{
|
|
198
|
-
type: z.ZodEnum<
|
|
199
|
-
|
|
78
|
+
type: z.ZodEnum<{
|
|
79
|
+
bug: "bug";
|
|
80
|
+
feature: "feature";
|
|
81
|
+
note: "note";
|
|
82
|
+
}>;
|
|
83
|
+
message: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodString>;
|
|
200
84
|
session_id: z.ZodOptional<z.ZodString>;
|
|
201
|
-
},
|
|
202
|
-
type: "bug" | "feature" | "note";
|
|
203
|
-
message: string;
|
|
204
|
-
session_id?: string | undefined;
|
|
205
|
-
}, {
|
|
206
|
-
type: "bug" | "feature" | "note";
|
|
207
|
-
message: string;
|
|
208
|
-
session_id?: string | undefined;
|
|
209
|
-
}>;
|
|
85
|
+
}, z.core.$strip>;
|
|
210
86
|
/** @deprecated use `CreateSessionRequest` from ./types.js (same type). */
|
|
211
87
|
export type CreateSessionInput = z.infer<typeof createSessionSchema>;
|
|
88
|
+
export declare const listSessionsStatusSchema: z.ZodEnum<{
|
|
89
|
+
open: "open";
|
|
90
|
+
closed: "closed";
|
|
91
|
+
all: "all";
|
|
92
|
+
}>;
|
|
93
|
+
export type ListSessionsStatus = z.infer<typeof listSessionsStatusSchema>;
|
|
94
|
+
export declare const listSessionsQuerySchema: z.ZodObject<{
|
|
95
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
96
|
+
open: "open";
|
|
97
|
+
closed: "closed";
|
|
98
|
+
all: "all";
|
|
99
|
+
}>>;
|
|
100
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
101
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
102
|
+
artifact_id: z.ZodOptional<z.ZodString>;
|
|
103
|
+
}, z.core.$strip>;
|
|
104
|
+
export type ListSessionsQuery = z.infer<typeof listSessionsQuerySchema>;
|
|
105
|
+
export declare const mintParticipantSchema: z.ZodObject<{
|
|
106
|
+
kind: z.ZodLiteral<"human">;
|
|
107
|
+
}, z.core.$strip>;
|
|
108
|
+
export type MintParticipantInput = z.infer<typeof mintParticipantSchema>;
|
package/dist/schemas.js
CHANGED
|
@@ -25,6 +25,14 @@ const inlineArtifactSchema = z.object({
|
|
|
25
25
|
// Optional: omit for a view-only one-off (a report/dashboard the human only
|
|
26
26
|
// views — the session then accepts no page/agent events).
|
|
27
27
|
event_schema: z.unknown().optional(),
|
|
28
|
+
// Optional: when present, the session's `input_data` is validated against
|
|
29
|
+
// this JSON Schema before the session row is created — and any blob refs
|
|
30
|
+
// declared at `format: pane-blob-id` sites become reachable from the page
|
|
31
|
+
// via `window.pane.downloadBlob()`. Without this, blob refs in
|
|
32
|
+
// `input_data` are silently unreachable for inline sessions (the
|
|
33
|
+
// participant blob-download bridge walks input_data against the artifact
|
|
34
|
+
// version's inputSchema; no schema means no walkable sites). See #208.
|
|
35
|
+
input_schema: z.record(z.string(), z.unknown()).optional(),
|
|
28
36
|
});
|
|
29
37
|
// The reference form for POST /v1/sessions — instances an existing named
|
|
30
38
|
// artifact. `id` accepts the artifact id or its slug; `version` is optional
|
|
@@ -47,11 +55,16 @@ const sessionArtifactSchema = z
|
|
|
47
55
|
});
|
|
48
56
|
export const createSessionSchema = z.object({
|
|
49
57
|
artifact: sessionArtifactSchema,
|
|
50
|
-
input_data: z.record(z.unknown()).optional(),
|
|
58
|
+
input_data: z.record(z.string(), z.unknown()).optional(),
|
|
51
59
|
participants: z.object({ humans: z.number().int().positive() }).optional(),
|
|
52
60
|
ttl: z.number().int().positive().optional(),
|
|
53
|
-
metadata: z.record(z.unknown()).optional(),
|
|
61
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
54
62
|
callback: callbackSchema.optional(),
|
|
63
|
+
// Tab title for the human's browser. Optional on the wire because the relay
|
|
64
|
+
// also accepts the implicit fallback (an Artifact.name on the reference
|
|
65
|
+
// form). The relay enforces "required-or-fallback" + length/control-char
|
|
66
|
+
// rules — Zod only confirms it's a string here.
|
|
67
|
+
title: z.string().optional(),
|
|
55
68
|
});
|
|
56
69
|
// POST /v1/artifacts — create a named, reusable artifact plus its v1 content.
|
|
57
70
|
export const createArtifactSchema = z.object({
|
|
@@ -63,7 +76,7 @@ export const createArtifactSchema = z.object({
|
|
|
63
76
|
type: artifactTypeSchema,
|
|
64
77
|
// Optional: omit for a view-only artifact (no event vocabulary).
|
|
65
78
|
event_schema: z.unknown().optional(),
|
|
66
|
-
input_schema: z.record(z.unknown()).optional(),
|
|
79
|
+
input_schema: z.record(z.string(), z.unknown()).optional(),
|
|
67
80
|
});
|
|
68
81
|
// POST /v1/artifacts/:id/versions — append a new version (content only).
|
|
69
82
|
export const createArtifactVersionSchema = z.object({
|
|
@@ -71,7 +84,7 @@ export const createArtifactVersionSchema = z.object({
|
|
|
71
84
|
type: artifactTypeSchema,
|
|
72
85
|
// Optional: omit for a view-only artifact (no event vocabulary).
|
|
73
86
|
event_schema: z.unknown().optional(),
|
|
74
|
-
input_schema: z.record(z.unknown()).optional(),
|
|
87
|
+
input_schema: z.record(z.string(), z.unknown()).optional(),
|
|
75
88
|
});
|
|
76
89
|
// PATCH /v1/artifacts/:id — update head metadata only (never content).
|
|
77
90
|
export const patchArtifactMetadataSchema = z.object({
|
|
@@ -92,3 +105,19 @@ export const submitFeedbackSchema = z.object({
|
|
|
92
105
|
.pipe(z.string().min(1).max(4000)),
|
|
93
106
|
session_id: z.string().min(1).optional(),
|
|
94
107
|
});
|
|
108
|
+
// GET /v1/sessions — list the calling agent's sessions. The relay also
|
|
109
|
+
// re-parses these on its side (defence in depth); this schema is for the CLI
|
|
110
|
+
// to fail fast with a clear error before a round trip.
|
|
111
|
+
export const listSessionsStatusSchema = z.enum(["open", "closed", "all"]);
|
|
112
|
+
export const listSessionsQuerySchema = z.object({
|
|
113
|
+
status: listSessionsStatusSchema.optional(),
|
|
114
|
+
limit: z.number().int().positive().max(200).optional(),
|
|
115
|
+
cursor: z.string().min(1).optional(),
|
|
116
|
+
artifact_id: z.string().min(1).optional(),
|
|
117
|
+
});
|
|
118
|
+
// POST /v1/sessions/:id/participants — mint a fresh participant URL for an
|
|
119
|
+
// existing session. v1 supports human participants only (the agent token is
|
|
120
|
+
// minted at session-create and cannot be re-minted via this endpoint).
|
|
121
|
+
export const mintParticipantSchema = z.object({
|
|
122
|
+
kind: z.literal("human"),
|
|
123
|
+
});
|
package/dist/types.d.ts
CHANGED
|
@@ -52,6 +52,9 @@ export interface CreateSessionResponse {
|
|
|
52
52
|
agent_stream: string;
|
|
53
53
|
};
|
|
54
54
|
expires_at: string;
|
|
55
|
+
/** The resolved tab title persisted on the session (the agent's value, or
|
|
56
|
+
* the Artifact.name fallback). */
|
|
57
|
+
title: string;
|
|
55
58
|
}
|
|
56
59
|
/** Response from GET /v1/sessions/:id. */
|
|
57
60
|
export interface SessionState {
|
|
@@ -61,6 +64,8 @@ export interface SessionState {
|
|
|
61
64
|
artifact_id: string;
|
|
62
65
|
artifact_version_id: string;
|
|
63
66
|
artifact_version: number;
|
|
67
|
+
/** The tab title this session was created with (frozen for its lifetime). */
|
|
68
|
+
title: string;
|
|
64
69
|
metadata: Record<string, unknown> | null;
|
|
65
70
|
input_data: Record<string, unknown> | null;
|
|
66
71
|
created_at: string;
|
|
@@ -71,6 +76,66 @@ export interface EventsPage {
|
|
|
71
76
|
events: PaneEvent[];
|
|
72
77
|
next_cursor: string | null;
|
|
73
78
|
}
|
|
79
|
+
/** A non-secret summary of one participant on a session — safe to list. */
|
|
80
|
+
export interface ParticipantSummary {
|
|
81
|
+
/** The revoke handle (Participant.id). */
|
|
82
|
+
participant_id: string;
|
|
83
|
+
/** "agent" or "human". The agent's own participant is always present. */
|
|
84
|
+
kind: "agent" | "human";
|
|
85
|
+
/** Short, non-secret correlator for a saved URL ("tok_h_..." / "tok_a_..."). */
|
|
86
|
+
token_prefix: string;
|
|
87
|
+
/** ISO timestamp of first WebSocket connect, or null if never joined. */
|
|
88
|
+
joined_at: string | null;
|
|
89
|
+
/** ISO timestamp the participant was revoked; null while still active. */
|
|
90
|
+
revoked_at: string | null;
|
|
91
|
+
}
|
|
92
|
+
/** A row in the GET /v1/sessions list response (no secrets, lean). */
|
|
93
|
+
export interface SessionSummary {
|
|
94
|
+
session_id: string;
|
|
95
|
+
/** Tab title (required column; agent input or Artifact.name fallback). */
|
|
96
|
+
title: string;
|
|
97
|
+
/** Effective status — respects expiresAt projection (the column may say
|
|
98
|
+
* "open" while `expires_at` is in the past; the projection reports "closed"). */
|
|
99
|
+
status: "open" | "closed";
|
|
100
|
+
/** Owning artifact's head id. Null for inline (anonymous) artifacts. */
|
|
101
|
+
artifact_id: string | null;
|
|
102
|
+
artifact_version_id: string;
|
|
103
|
+
artifact_version: number;
|
|
104
|
+
/** Count of active (non-revoked) human participants. The full participant
|
|
105
|
+
* array is intentionally NOT inlined here — agents with many sessions
|
|
106
|
+
* would pay the bandwidth on every list call. Fetch
|
|
107
|
+
* `GET /v1/sessions/:id/participants` when you need the rows. */
|
|
108
|
+
active_human_participants: number;
|
|
109
|
+
created_at: string;
|
|
110
|
+
expires_at: string;
|
|
111
|
+
/** Whether the session has a webhook callback configured (URL is NOT
|
|
112
|
+
* returned — it may carry a secret in the path). */
|
|
113
|
+
has_callback: boolean;
|
|
114
|
+
}
|
|
115
|
+
/** Response from GET /v1/sessions/:id/participants — every participant on
|
|
116
|
+
* one session (active and revoked). Bounded by MAX_PARTICIPANTS_PER_SESSION
|
|
117
|
+
* on the relay so no pagination is needed. */
|
|
118
|
+
export interface ParticipantsList {
|
|
119
|
+
session_id: string;
|
|
120
|
+
items: ParticipantSummary[];
|
|
121
|
+
}
|
|
122
|
+
/** Response from GET /v1/sessions. */
|
|
123
|
+
export interface SessionsPage {
|
|
124
|
+
items: SessionSummary[];
|
|
125
|
+
/** Opaque cursor for the next page; null when no more rows. */
|
|
126
|
+
next_cursor: string | null;
|
|
127
|
+
}
|
|
128
|
+
/** Response from POST /v1/sessions/:id/participants — one-shot, includes the
|
|
129
|
+
* plaintext token exactly once. The relay stores only the hash. */
|
|
130
|
+
export interface MintParticipantResponse {
|
|
131
|
+
participant_id: string;
|
|
132
|
+
kind: "human";
|
|
133
|
+
/** The plaintext participant token. Returned ONCE — not recoverable. */
|
|
134
|
+
token: string;
|
|
135
|
+
/** The shareable human URL containing the token. */
|
|
136
|
+
url: string;
|
|
137
|
+
created_at: string;
|
|
138
|
+
}
|
|
74
139
|
/** One immutable version of an artifact's content. */
|
|
75
140
|
export interface ArtifactVersion {
|
|
76
141
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paneui/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Pane relay client: typed HTTP + WebSocket operations against a Pane relay. Framework-free.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"ws": "^8.20.1",
|
|
50
|
-
"zod": "^
|
|
50
|
+
"zod": "^4.4.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@types/node": "^
|
|
53
|
+
"@types/node": "^25.9.1",
|
|
54
54
|
"@types/ws": "^8.18.1",
|
|
55
|
-
"typescript": "^
|
|
55
|
+
"typescript": "^6.0.3",
|
|
56
56
|
"vitest": "^4.1.6"
|
|
57
57
|
}
|
|
58
58
|
}
|