@homespunapps/core 1.0.0 → 1.4.2
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 +776 -4
- package/dist/client.js +505 -7
- package/dist/index.d.ts +1 -1
- package/package.json +11 -11
package/dist/client.d.ts
CHANGED
|
@@ -90,6 +90,20 @@ export declare class HomespunClient {
|
|
|
90
90
|
* self-destruct. Returns 204 with no body on success.
|
|
91
91
|
*/
|
|
92
92
|
revokeKey(id: string): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* POST /v1/keys: mint a NEW sibling API key for the calling agent's OWN
|
|
95
|
+
* identity. The relay derives the identity from the bearer token, so a caller
|
|
96
|
+
* can only ever mint a sibling of itself (never another agent's key). The new
|
|
97
|
+
* key has the same scope/ownership as the caller and shows up in a subsequent
|
|
98
|
+
* `listKeys()` call made WITH the new key.
|
|
99
|
+
*
|
|
100
|
+
* The raw `api_key` is returned exactly ONCE in this response and is never
|
|
101
|
+
* retrievable again (only its hash is stored). Bootstraps a fresh CLI /
|
|
102
|
+
* process credential from an MCP-driven agent that has no key of its own to
|
|
103
|
+
* hand off. The owner can revoke any minted sibling via the normal revoke
|
|
104
|
+
* path.
|
|
105
|
+
*/
|
|
106
|
+
mintKey(): Promise<KeyMintResult>;
|
|
93
107
|
/**
|
|
94
108
|
* POST /v1/agents/claim — bind this agent to a human via a one-shot
|
|
95
109
|
* claim code the human generated in their settings UI. After a
|
|
@@ -159,6 +173,25 @@ export declare class HomespunClient {
|
|
|
159
173
|
* stream bytes through the relay.
|
|
160
174
|
*/
|
|
161
175
|
uploadBlob(file: Blob | Buffer | Uint8Array, opts?: UploadBlobOptions): Promise<AttachmentRef>;
|
|
176
|
+
/**
|
|
177
|
+
* Upload a attachment from INLINE base64 bytes: the no-filesystem sibling of
|
|
178
|
+
* `uploadBlob()`. Use this when the bytes were produced in memory (an image
|
|
179
|
+
* the agent generated, a document it assembled) and there is no local file to
|
|
180
|
+
* stream: an MCP client running inside a Claude session has no filesystem to
|
|
181
|
+
* point `uploadBlob()` at.
|
|
182
|
+
*
|
|
183
|
+
* The bytes are sent as base64 in a JSON body to the relay's
|
|
184
|
+
* `POST /v1/attachments` inline variant ({ content_base64, filename?, mime?,
|
|
185
|
+
* scope?, app_id? }). The relay decodes them behind a pre-decode size guard and runs
|
|
186
|
+
* the IDENTICAL validation pipeline the multipart `uploadBlob()` path runs:
|
|
187
|
+
* magic-byte MIME sniff, BLOB_MIME_ALLOWLIST, per-attachment size cap, and the
|
|
188
|
+
* per-agent / per-app / per-account quota reservation. `mime` is advisory
|
|
189
|
+
* (the relay sniffs the real type regardless), and an oversized or disallowed
|
|
190
|
+
* inline upload returns the same errors the file path would.
|
|
191
|
+
*
|
|
192
|
+
* @param contentBase64 standard base64 (e.g. `Buffer.from(bytes).toString("base64")`).
|
|
193
|
+
*/
|
|
194
|
+
uploadBlobInline(contentBase64: string, opts?: UploadBlobOptions): Promise<AttachmentRef>;
|
|
162
195
|
/** GET /v1/attachments/:id — download bytes as an ArrayBuffer. */
|
|
163
196
|
downloadBlob(attachmentId: string): Promise<ArrayBuffer>;
|
|
164
197
|
/**
|
|
@@ -219,12 +252,36 @@ export declare class HomespunClient {
|
|
|
219
252
|
upload_url: string;
|
|
220
253
|
expires_at: string;
|
|
221
254
|
}>;
|
|
222
|
-
/**
|
|
255
|
+
/**
|
|
256
|
+
* Finalise a presigned upload. After the client PUTs the bytes to the
|
|
257
|
+
* `upload_url` from `presignBlob()`, the relay re-reads the stored bytes and
|
|
258
|
+
* runs the SAME validation a normal upload runs: it BYTE-SNIFFS the actual
|
|
259
|
+
* content and derives the stored/served mime from that (never the
|
|
260
|
+
* presign-declared mime), re-verifies size + sha256, enforces the allowlist +
|
|
261
|
+
* quota, and runs the scan hook, before flipping the attachment to `ready`.
|
|
262
|
+
* A finalize whose bytes fail any check leaves the attachment unready (it is
|
|
263
|
+
* never served) and returns a clean error. Returns the ready `AttachmentRef`.
|
|
264
|
+
*/
|
|
223
265
|
confirmBlob(attachmentId: string): Promise<AttachmentRef>;
|
|
266
|
+
/**
|
|
267
|
+
* Alias for {@link confirmBlob}: the "finalize" half of the presign ->
|
|
268
|
+
* PUT -> finalize flow, named to match the MCP `attachments` action.
|
|
269
|
+
*/
|
|
270
|
+
finalizeBlob(attachmentId: string): Promise<AttachmentRef>;
|
|
224
271
|
/** POST /v1/apps — create (deploy) a new App + its first AppVersion. */
|
|
225
272
|
deployApp(req: DeployAppRequest): Promise<DeployAppResponse>;
|
|
226
273
|
/** POST /v1/apps/:id/versions — redeploy (compat-gated unless force). */
|
|
227
274
|
redeployApp(appId: string, req: RedeployAppRequest): Promise<RedeployAppResponse>;
|
|
275
|
+
/**
|
|
276
|
+
* Dry-run a deploy: validate the manifest + asset shapes, run the compat gate
|
|
277
|
+
* (for a redeploy) and compute the deploy advisories, WITHOUT creating a
|
|
278
|
+
* version or mutating anything. Posts the deploy body with `dry_run: true` to
|
|
279
|
+
* the same route the real deploy uses (`POST /v1/apps` for a create check,
|
|
280
|
+
* `POST /v1/apps/:id/versions` for a redeploy check), so the relay returns the
|
|
281
|
+
* SAME validation error a real deploy would for an invalid manifest, and the
|
|
282
|
+
* SAME warnings/compat result for a valid one. Nothing is persisted.
|
|
283
|
+
*/
|
|
284
|
+
checkDeploy(req: DeployCheckRequest): Promise<DeployCheckResult>;
|
|
228
285
|
/**
|
|
229
286
|
* GET /v1/apps — list apps scoped to the calling agent's owning human.
|
|
230
287
|
* `slug` is an exact-match filter — the one case a caller resolves a
|
|
@@ -238,10 +295,35 @@ export declare class HomespunClient {
|
|
|
238
295
|
}): Promise<AppsPage>;
|
|
239
296
|
/** GET /v1/apps/:id — full app detail (manifest, current_version, quota). */
|
|
240
297
|
getApp(appId: string): Promise<AppDetail>;
|
|
241
|
-
/**
|
|
242
|
-
|
|
298
|
+
/**
|
|
299
|
+
* PATCH /v1/apps/:id updates the app's mutable settings. Both fields are
|
|
300
|
+
* optional but at least one must be given: `visibility` (private|link|public)
|
|
301
|
+
* and/or `timezone` (an IANA zone name like "Europe/Berlin", used for
|
|
302
|
+
* `schedules` reminders). Returns the updated `{ id, visibility, timezone }`.
|
|
303
|
+
* A transition INTO `link` visibility also returns a `share_url` carrying the
|
|
304
|
+
* app's freshly minted share token in its `#k=` fragment, shown ONCE (the
|
|
305
|
+
* token is hashed at rest and never recoverable). A transition AWAY from
|
|
306
|
+
* `link` clears the token (every prior share URL stops working).
|
|
307
|
+
*/
|
|
308
|
+
updateApp(appId: string, update: {
|
|
309
|
+
visibility?: "private" | "link" | "public";
|
|
310
|
+
timezone?: string;
|
|
311
|
+
}): Promise<{
|
|
243
312
|
id: string;
|
|
244
313
|
visibility: string;
|
|
314
|
+
timezone: string | null;
|
|
315
|
+
share_url?: string;
|
|
316
|
+
}>;
|
|
317
|
+
/**
|
|
318
|
+
* POST /v1/apps/:id/share-link/rotate rotates a `link` app's share token.
|
|
319
|
+
* Mints a fresh token and returns the new `share_url` (its `#k=` fragment
|
|
320
|
+
* carries the raw token, shown ONCE). Rotating instantly revokes the previous
|
|
321
|
+
* share URL and every pass derived from it. Also serves as "generate" for a
|
|
322
|
+
* `link` app that has no share token yet. Only valid for a `link` app; a
|
|
323
|
+
* public/private app returns a conflict.
|
|
324
|
+
*/
|
|
325
|
+
rotateShareLink(appId: string): Promise<{
|
|
326
|
+
share_url: string;
|
|
245
327
|
}>;
|
|
246
328
|
/** DELETE /v1/apps/:id — soft-delete (idempotent). */
|
|
247
329
|
deleteApp(appId: string): Promise<void>;
|
|
@@ -250,6 +332,23 @@ export declare class HomespunClient {
|
|
|
250
332
|
id: string;
|
|
251
333
|
status: string;
|
|
252
334
|
}>;
|
|
335
|
+
/**
|
|
336
|
+
* POST /v1/apps/:id/domain - bind a custom domain to the app. Returns the
|
|
337
|
+
* record including `dns_records`: the DNS entries the domain owner must
|
|
338
|
+
* publish (the routing CNAME plus any Cloudflare validation records).
|
|
339
|
+
*/
|
|
340
|
+
setAppDomain(appId: string, domain: string): Promise<AppDomain>;
|
|
341
|
+
/**
|
|
342
|
+
* GET /v1/apps/:id/domain - the app's domain record, live-refreshed against
|
|
343
|
+
* Cloudflare when the feature is enabled (status/last_error/last_checked_at
|
|
344
|
+
* update as a side effect).
|
|
345
|
+
*/
|
|
346
|
+
getAppDomain(appId: string): Promise<AppDomain>;
|
|
347
|
+
/**
|
|
348
|
+
* DELETE /v1/apps/:id/domain - remove the domain binding (Cloudflare
|
|
349
|
+
* hostname best-effort + record + quota release). Idempotent.
|
|
350
|
+
*/
|
|
351
|
+
deleteAppDomain(appId: string): Promise<void>;
|
|
253
352
|
/**
|
|
254
353
|
* POST /v1/apps/:id/members — add or invite a member by email. If a Human
|
|
255
354
|
* already exists for the email, the member row is created immediately
|
|
@@ -260,21 +359,107 @@ export declare class HomespunClient {
|
|
|
260
359
|
addAppMember(appId: string, opts: {
|
|
261
360
|
email: string;
|
|
262
361
|
role?: "member";
|
|
362
|
+
customRole?: string;
|
|
263
363
|
}): Promise<AddAppMemberResult>;
|
|
264
364
|
/** GET /v1/apps/:id/members — list the app's owner + member rows. */
|
|
265
365
|
listAppMembers(appId: string): Promise<{
|
|
266
366
|
members: AppMember[];
|
|
267
367
|
}>;
|
|
368
|
+
/**
|
|
369
|
+
* PATCH /v1/apps/:id/members/:humanId — change an existing member's custom
|
|
370
|
+
* role in place. `customRole: null` clears it back to a plain member. The
|
|
371
|
+
* role must be one the app's manifest declares (a reserved base role or an
|
|
372
|
+
* undeclared name is a 400), and the app owner's own membership cannot be
|
|
373
|
+
* re-roled.
|
|
374
|
+
*
|
|
375
|
+
* Unlike remove-then-re-add, this does NOT revoke the member's live app
|
|
376
|
+
* sessions: they stay signed in and pick up the new role on their next
|
|
377
|
+
* request. Roles are not cached: they are re-derived from the Member row on
|
|
378
|
+
* every request, so a downgrade takes effect immediately and a live session
|
|
379
|
+
* can never escalate.
|
|
380
|
+
*/
|
|
381
|
+
setAppMemberRole(appId: string, humanId: string, opts: {
|
|
382
|
+
customRole: string | null;
|
|
383
|
+
}): Promise<{
|
|
384
|
+
member: AppMember;
|
|
385
|
+
}>;
|
|
386
|
+
/**
|
|
387
|
+
* GET /v1/apps/:id/roles — the derived roles summary: every custom role the
|
|
388
|
+
* app's manifest declares, what holding it actually allows per collection
|
|
389
|
+
* (reported separately for members and for grant-link holders, whose role
|
|
390
|
+
* floors differ), and how many members and live grant links hold it.
|
|
391
|
+
* Read-only and computed on the fly; permissions themselves stay
|
|
392
|
+
* manifest-declared. An app that declares no roles returns an empty list.
|
|
393
|
+
*/
|
|
394
|
+
listAppRoles(appId: string): Promise<{
|
|
395
|
+
roles: AppRoleSummary[];
|
|
396
|
+
}>;
|
|
268
397
|
/**
|
|
269
398
|
* DELETE /v1/apps/:id/members/:humanId — remove a member (idempotent);
|
|
270
399
|
* cascades to revoke that human's live app sessions. The app owner cannot
|
|
271
400
|
* be removed — the relay refuses with a 409 conflict.
|
|
272
401
|
*/
|
|
273
402
|
removeAppMember(appId: string, humanId: string): Promise<void>;
|
|
274
|
-
/**
|
|
403
|
+
/**
|
|
404
|
+
* GET /v1/apps/:id/ingest-hooks lists the app's inbound catch-hooks with the
|
|
405
|
+
* full secret URL (decrypted server-side), the current rule metadata
|
|
406
|
+
* (collection/mode/wake/handshake), and per-hook delivery counts by status.
|
|
407
|
+
* The URL is the app owner's to share with a sender; it is never exposed on a
|
|
408
|
+
* public path, only here to the app's own owner/agent.
|
|
409
|
+
*/
|
|
410
|
+
listIngestHooks(appId: string): Promise<{
|
|
411
|
+
hooks: IngestHookInfo[];
|
|
412
|
+
}>;
|
|
413
|
+
/**
|
|
414
|
+
* POST /v1/apps/:id/ingest-hooks/:name/rotate mints a fresh secret for one
|
|
415
|
+
* hook and return its new full URL once. No redeploy needed; the old URL stops
|
|
416
|
+
* working immediately.
|
|
417
|
+
*/
|
|
418
|
+
rotateIngestHook(appId: string, name: string): Promise<{
|
|
419
|
+
hook: {
|
|
420
|
+
name: string;
|
|
421
|
+
url: string;
|
|
422
|
+
};
|
|
423
|
+
}>;
|
|
424
|
+
/**
|
|
425
|
+
* POST /v1/apps/:id/grants: mint a grant link. `role` must be a declared
|
|
426
|
+
* custom role for the app. `mode` is "once" (one-time, first-browser-claims)
|
|
427
|
+
* or "multi" (shared, capped by `maxUses` within expiry); defaults to "multi".
|
|
428
|
+
* An optional `pin` NARROWS the holder to a single `rowKey` OR a `where`
|
|
429
|
+
* filter (never widens). Returns the once-only `grant_url` carrying the token.
|
|
430
|
+
*/
|
|
431
|
+
mintAppGrant(appId: string, opts: {
|
|
432
|
+
role: string;
|
|
433
|
+
mode?: "once" | "multi";
|
|
434
|
+
maxUses?: number;
|
|
435
|
+
label?: string;
|
|
436
|
+
ttlSeconds?: number;
|
|
437
|
+
pin?: {
|
|
438
|
+
rowKey?: string;
|
|
439
|
+
where?: ListWhereCondition[];
|
|
440
|
+
};
|
|
441
|
+
}): Promise<MintAppGrantResult>;
|
|
442
|
+
/** GET /v1/apps/:id/grants: list the app's grant links (never any token). */
|
|
443
|
+
listAppGrants(appId: string): Promise<{
|
|
444
|
+
grants: AppGrantSummary[];
|
|
445
|
+
}>;
|
|
446
|
+
/** DELETE /v1/apps/:id/grants/:grantId: revoke one grant link (idempotent). */
|
|
447
|
+
revokeAppGrant(appId: string, grantId: string): Promise<void>;
|
|
448
|
+
/**
|
|
449
|
+
* GET /v1/apps/:id/collections/:name — list rows (current-state page).
|
|
450
|
+
*
|
|
451
|
+
* Wave C2 structured read query: pass `where` (an AND of `{field, op, value}`
|
|
452
|
+
* conditions) and/or `sort` (`{field, dir}` list) to filter/order DB-side. The
|
|
453
|
+
* relay applies read permission + author scoping FIRST, then the filter, so a
|
|
454
|
+
* filtered read is always a subset of what the caller could already read. The
|
|
455
|
+
* query is serialized into the `q` param as URL-encoded JSON. Note: a custom
|
|
456
|
+
* `sort` cannot be combined with cursor pagination (`since`) in this version.
|
|
457
|
+
*/
|
|
275
458
|
listAppRows(appId: string, collection: string, opts?: {
|
|
276
459
|
since?: string;
|
|
277
460
|
limit?: number;
|
|
461
|
+
where?: ListWhereCondition[];
|
|
462
|
+
sort?: ListSortSpec[];
|
|
278
463
|
}): Promise<AppRowsPage>;
|
|
279
464
|
/**
|
|
280
465
|
* GET /v1/apps/:id/collections/:name/:key — read one row. A dedicated
|
|
@@ -293,10 +478,28 @@ export declare class HomespunClient {
|
|
|
293
478
|
upsertAppRow(appId: string, collection: string, body: {
|
|
294
479
|
key?: string;
|
|
295
480
|
data: unknown;
|
|
481
|
+
on?: string;
|
|
296
482
|
}): Promise<{
|
|
297
483
|
row: AppRow;
|
|
298
484
|
deduped?: true;
|
|
299
485
|
}>;
|
|
486
|
+
/**
|
|
487
|
+
* POST /v1/apps/:id/collections/:name with `{ on, data }`, natural-key upsert
|
|
488
|
+
* (Wave C1). Matches the existing row whose `<field>` value equals data[field]
|
|
489
|
+
* and updates it in place (idempotent re-import), else creates a fresh row.
|
|
490
|
+
* `field` must be declared in the collection's manifest `unique` list.
|
|
491
|
+
*/
|
|
492
|
+
upsertAppRowOn(appId: string, collection: string, field: string, data: unknown): Promise<{
|
|
493
|
+
row: AppRow;
|
|
494
|
+
deduped?: true;
|
|
495
|
+
}>;
|
|
496
|
+
/**
|
|
497
|
+
* DELETE /v1/apps/:id/collections/:name/:key/purge, owner/agent-only removal
|
|
498
|
+
* that bypasses an append-only collection (Wave C1). Frees the row's unique
|
|
499
|
+
* values and writes an audited delete feed entry. A missing/already-deleted key
|
|
500
|
+
* is a 404 (HomespunApiError `row_not_found`), matching a normal delete.
|
|
501
|
+
*/
|
|
502
|
+
purgeAppRow(appId: string, collection: string, key: string): Promise<void>;
|
|
300
503
|
/** PATCH /v1/apps/:id/collections/:name/:key — optimistic-locked update. */
|
|
301
504
|
updateAppRow(appId: string, collection: string, key: string, body: {
|
|
302
505
|
data: unknown;
|
|
@@ -308,6 +511,20 @@ export declare class HomespunClient {
|
|
|
308
511
|
deleteAppRow(appId: string, collection: string, key: string, opts?: {
|
|
309
512
|
ifMatch?: number;
|
|
310
513
|
}): Promise<void>;
|
|
514
|
+
/**
|
|
515
|
+
* POST /v1/apps/:id/collections/:name/batch: bulk create/upsert (Wave B).
|
|
516
|
+
* Returns a per-row result array: a single invalid row is reported by index
|
|
517
|
+
* without aborting the good rows. A batch over the server's BATCH_MAX_ROWS cap
|
|
518
|
+
* is a clean 400 (throws HomespunApiError `invalid_request`). DEFAULTS TO
|
|
519
|
+
* SILENT (suppresses notify + webhooks): pass `{emitEffects:true}` or
|
|
520
|
+
* `{suppress:[]}` to fire effects. Owner/agent key only for suppression control.
|
|
521
|
+
*/
|
|
522
|
+
batchRows(appId: string, collection: string, rows: BatchRowInput[], opts?: BatchWriteOptions): Promise<BatchResult>;
|
|
523
|
+
/**
|
|
524
|
+
* DELETE /v1/apps/:id/collections/:name/batch: bulk soft-delete (Wave B).
|
|
525
|
+
* Same per-row result shape + cap as `batchRows`.
|
|
526
|
+
*/
|
|
527
|
+
deleteRows(appId: string, collection: string, keys: string[]): Promise<BatchResult>;
|
|
311
528
|
/**
|
|
312
529
|
* GET /v1/apps/:id/feed — change-feed catch-up; the long-poll fallback
|
|
313
530
|
* transport for `watch` (spec-cli §2.3/§5). `wait` (0-30s) long-polls when
|
|
@@ -318,6 +535,61 @@ export declare class HomespunClient {
|
|
|
318
535
|
limit?: number;
|
|
319
536
|
wait?: number;
|
|
320
537
|
}): Promise<AppFeedPage>;
|
|
538
|
+
/** POST /v1/community/publish: publish an owned app as a pending template. */
|
|
539
|
+
publishCommunityTemplate(req: PublishCommunityTemplateRequest): Promise<PublishCommunityTemplateResponse>;
|
|
540
|
+
/** GET /v1/community/pending (operator): list pending submissions. */
|
|
541
|
+
listCommunitySubmissions(opts?: {
|
|
542
|
+
limit?: number;
|
|
543
|
+
cursor?: string;
|
|
544
|
+
}): Promise<CommunitySubmissionsPage>;
|
|
545
|
+
/** GET /v1/community/submissions/:id (operator): a submission's full content. */
|
|
546
|
+
getCommunitySubmission(snapshotId: string): Promise<CommunitySubmissionDetail>;
|
|
547
|
+
/**
|
|
548
|
+
* POST /v1/community/submissions/:id/{approve,reject} (operator): review a
|
|
549
|
+
* submission. `decision` "reject" requires a `note` (delivered to the
|
|
550
|
+
* publisher's app feed).
|
|
551
|
+
*/
|
|
552
|
+
reviewCommunitySubmission(snapshotId: string, review: {
|
|
553
|
+
decision: "approve" | "reject";
|
|
554
|
+
note?: string;
|
|
555
|
+
}): Promise<CommunitySubmissionDetail>;
|
|
556
|
+
/** GET /v1/publisher: the caller's own publisher profile. */
|
|
557
|
+
getPublisher(): Promise<PublisherProfile>;
|
|
558
|
+
/** POST /v1/publisher/claim: set the handle once (permanent after claiming). */
|
|
559
|
+
claimPublisherHandle(handle: string): Promise<PublisherProfile>;
|
|
560
|
+
/** POST /v1/publisher/update: update displayName/bio/url. */
|
|
561
|
+
updatePublisher(update: PublisherProfileUpdate): Promise<PublisherProfile>;
|
|
562
|
+
/**
|
|
563
|
+
* POST /v1/community/publishers/:handle/trust (operator, marketplace PR 11):
|
|
564
|
+
* set a publisher's trust level ("new" | "established"), the MVP promotion
|
|
565
|
+
* path for the review fast-track. Operator-gated server-side; returns the
|
|
566
|
+
* updated publisher profile.
|
|
567
|
+
*/
|
|
568
|
+
setPublisherTrustLevel(handle: string, trustLevel: "new" | "established"): Promise<PublisherProfile>;
|
|
569
|
+
/**
|
|
570
|
+
* POST /v1/reviews: review a template the caller installed. Identify the
|
|
571
|
+
* template by its namespaced `<handle>/<slug>` OR by explicit handle + slug.
|
|
572
|
+
*/
|
|
573
|
+
createReview(req: CreateCommunityReviewRequest): Promise<CommunityReview>;
|
|
574
|
+
/** POST /v1/reviews/:id/respond: respond to a review as the publisher. */
|
|
575
|
+
respondToReview(reviewId: string, response: string | null): Promise<CommunityReview>;
|
|
576
|
+
/** POST /v1/reviews/:id/report: flag a review for operator attention. */
|
|
577
|
+
reportReview(reviewId: string, reason: string): Promise<CommunityReviewReportResult>;
|
|
578
|
+
/** POST /v1/reviews/:id/remove (operator): take a review down. */
|
|
579
|
+
removeReview(reviewId: string): Promise<CommunityReview>;
|
|
580
|
+
/** POST /v1/reviews/:id/unhold (operator): publish a held review. */
|
|
581
|
+
unholdReview(reviewId: string): Promise<CommunityReview>;
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* One multi-file-deploy asset: bytes the deployed page references by a stable,
|
|
585
|
+
* app-relative, same-origin path (e.g. `frames/000.jpg`). `content_base64` is the
|
|
586
|
+
* standard base64 of the raw bytes; `mime` is advisory (the relay sniffs the
|
|
587
|
+
* real type from the leading bytes).
|
|
588
|
+
*/
|
|
589
|
+
export interface AppAsset {
|
|
590
|
+
path: string;
|
|
591
|
+
content_base64: string;
|
|
592
|
+
mime?: string;
|
|
321
593
|
}
|
|
322
594
|
/** Request body for `POST /v1/apps` — create (deploy) a new App. */
|
|
323
595
|
export interface DeployAppRequest {
|
|
@@ -327,6 +599,13 @@ export interface DeployAppRequest {
|
|
|
327
599
|
visibility?: "private" | "link" | "public";
|
|
328
600
|
/** Accepted for visibility public|private (including the omitted default); rejected for link. */
|
|
329
601
|
slug?: string;
|
|
602
|
+
/**
|
|
603
|
+
* Optional asset bundle shipped alongside the HTML in ONE deploy. Each asset
|
|
604
|
+
* is validated + stored app-scoped exactly like an attachment and served at
|
|
605
|
+
* its `path` on the app's own origin, so `<img src="frames/000.jpg">` just
|
|
606
|
+
* works. Rejected atomically if any asset fails validation.
|
|
607
|
+
*/
|
|
608
|
+
assets?: AppAsset[];
|
|
330
609
|
}
|
|
331
610
|
export interface DeployAppResponse {
|
|
332
611
|
app_id: string;
|
|
@@ -335,6 +614,20 @@ export interface DeployAppResponse {
|
|
|
335
614
|
url: string;
|
|
336
615
|
version: number;
|
|
337
616
|
created: true;
|
|
617
|
+
/**
|
|
618
|
+
* The tokenized share URL, present ONLY when the app was created as `link`. Its
|
|
619
|
+
* `#k=` fragment carries the raw share token and is shown exactly ONCE (the
|
|
620
|
+
* token is hashed at rest and never recoverable). Anyone with this exact URL
|
|
621
|
+
* can open the app until it is rotated (`rotateShareLink`).
|
|
622
|
+
*/
|
|
623
|
+
share_url?: string;
|
|
624
|
+
/**
|
|
625
|
+
* Non-fatal deploy advisories, present only when there is at least one. Today
|
|
626
|
+
* the schedules-without-timezone case: an app that declares `schedules` but has
|
|
627
|
+
* no timezone set will fire reminders at 08:00 UTC until one is set. Relay these
|
|
628
|
+
* to the human.
|
|
629
|
+
*/
|
|
630
|
+
warnings?: string[];
|
|
338
631
|
}
|
|
339
632
|
/** Request body for `POST /v1/apps/:id/versions` — redeploy (compat-gated). */
|
|
340
633
|
export interface RedeployAppRequest {
|
|
@@ -342,6 +635,11 @@ export interface RedeployAppRequest {
|
|
|
342
635
|
manifest: unknown;
|
|
343
636
|
/** Bypass the compat gate; a narrowing collection is detached, not deleted. */
|
|
344
637
|
force?: boolean;
|
|
638
|
+
/**
|
|
639
|
+
* Optional asset bundle for this version. Replaces the previous version's asset
|
|
640
|
+
* set atomically (the new version carries its own map; old assets are detached).
|
|
641
|
+
*/
|
|
642
|
+
assets?: AppAsset[];
|
|
345
643
|
}
|
|
346
644
|
export interface RedeployAppResponse {
|
|
347
645
|
app_id: string;
|
|
@@ -351,6 +649,66 @@ export interface RedeployAppResponse {
|
|
|
351
649
|
path: string;
|
|
352
650
|
message: string;
|
|
353
651
|
}>;
|
|
652
|
+
/**
|
|
653
|
+
* Non-fatal deploy advisories, present only when there is at least one; see
|
|
654
|
+
* DeployAppResponse.warnings. On redeploy the schedules-without-timezone
|
|
655
|
+
* warning fires only when the app STILL has no timezone set.
|
|
656
|
+
*/
|
|
657
|
+
warnings?: string[];
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Result of a DRY-RUN deploy (`checkDeploy`): the deploy validation + compat
|
|
661
|
+
* gate run WITHOUT creating a version or mutating anything. Mirrors what a real
|
|
662
|
+
* deploy would report: the manifest is validated (a structurally invalid
|
|
663
|
+
* manifest throws the SAME error a real deploy would), asset shapes are checked,
|
|
664
|
+
* the schedule-timezone / migration-mode advisories are computed, and (for a
|
|
665
|
+
* redeploy) the compat gate runs against the current version.
|
|
666
|
+
*
|
|
667
|
+
* - `ok` is true when a REAL deploy with the same inputs would succeed: a
|
|
668
|
+
* clean deploy, or a narrowing redeploy with `force: true`. It is false
|
|
669
|
+
* when a real un-forced redeploy would be REJECTED for narrowing the
|
|
670
|
+
* manifest (see `compat: "incompatible"` + `breaks`).
|
|
671
|
+
* - `compat` is present only for a redeploy check: "clean" (no narrowing),
|
|
672
|
+
* "forced" (narrows, but force was set so the real deploy would detach and
|
|
673
|
+
* proceed), or "incompatible" (narrows and force was NOT set, so the real
|
|
674
|
+
* deploy would return manifest_incompatible_redeploy).
|
|
675
|
+
* - `breaks` lists the narrowings, present only when there is at least one.
|
|
676
|
+
*/
|
|
677
|
+
export interface DeployCheckResult {
|
|
678
|
+
ok: boolean;
|
|
679
|
+
warnings: string[];
|
|
680
|
+
compat?: "clean" | "forced" | "incompatible";
|
|
681
|
+
breaks?: Array<{
|
|
682
|
+
path: string;
|
|
683
|
+
message: string;
|
|
684
|
+
}>;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Request for a dry-run deploy check. Omit `app_id` to check a CREATE; pass it
|
|
688
|
+
* to check a REDEPLOY of an existing app (the compat gate then runs against its
|
|
689
|
+
* current version, and `force` decides whether a narrowing would be accepted).
|
|
690
|
+
*/
|
|
691
|
+
export interface DeployCheckRequest {
|
|
692
|
+
app_id?: string;
|
|
693
|
+
html: string;
|
|
694
|
+
manifest: unknown;
|
|
695
|
+
force?: boolean;
|
|
696
|
+
assets?: AppAsset[];
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Result of minting a sibling API key for the calling agent's own identity
|
|
700
|
+
* (`mintKey`). The raw `api_key` is returned exactly ONCE here and is never
|
|
701
|
+
* retrievable again (only its hash is stored). The new key has the same
|
|
702
|
+
* scope/ownership as the caller and can be revoked by the owner via the normal
|
|
703
|
+
* revoke path.
|
|
704
|
+
*/
|
|
705
|
+
export interface KeyMintResult {
|
|
706
|
+
agent_id: string;
|
|
707
|
+
/** The raw sibling key, shown ONCE, never returned again. */
|
|
708
|
+
api_key: string;
|
|
709
|
+
key_prefix: string;
|
|
710
|
+
name: string | null;
|
|
711
|
+
created_at: string;
|
|
354
712
|
}
|
|
355
713
|
/** Lean per-app summary — the shape `listApps` returns. */
|
|
356
714
|
export interface AppSummary {
|
|
@@ -359,6 +717,12 @@ export interface AppSummary {
|
|
|
359
717
|
visibility: string;
|
|
360
718
|
status: string;
|
|
361
719
|
url: string;
|
|
720
|
+
/**
|
|
721
|
+
* Whether the app currently has an active share token (a `link` app with a
|
|
722
|
+
* live, revocable share link). NEVER the token itself: the raw token is
|
|
723
|
+
* returned only at create/rotate. False for public/private apps.
|
|
724
|
+
*/
|
|
725
|
+
has_share_token: boolean;
|
|
362
726
|
created_at: string;
|
|
363
727
|
last_activity_at: string;
|
|
364
728
|
}
|
|
@@ -369,11 +733,35 @@ export interface AppDetail extends AppSummary {
|
|
|
369
733
|
owner_human_id: string;
|
|
370
734
|
row_count: number;
|
|
371
735
|
storage_bytes: string;
|
|
736
|
+
/**
|
|
737
|
+
* The app's IANA timezone for `schedules` reminders, or null when unset. Set
|
|
738
|
+
* it with `updateApp(id, { timezone })`; an app that declares schedules with no
|
|
739
|
+
* timezone fires reminders at 08:00 UTC.
|
|
740
|
+
*/
|
|
741
|
+
timezone: string | null;
|
|
372
742
|
}
|
|
373
743
|
export interface AppsPage {
|
|
374
744
|
items: AppSummary[];
|
|
375
745
|
next_cursor: string | null;
|
|
376
746
|
}
|
|
747
|
+
/** One DNS record the domain owner must publish (custom domains). */
|
|
748
|
+
export interface AppDomainDnsRecord {
|
|
749
|
+
type: string;
|
|
750
|
+
name: string;
|
|
751
|
+
value: string;
|
|
752
|
+
purpose: "routing" | "ownership" | "certificate_validation";
|
|
753
|
+
}
|
|
754
|
+
/** The app's custom-domain record - the shape the /domain routes return. */
|
|
755
|
+
export interface AppDomain {
|
|
756
|
+
domain: string;
|
|
757
|
+
status: "pending" | "active" | "error" | "removed";
|
|
758
|
+
dns_records: AppDomainDnsRecord[];
|
|
759
|
+
cf_hostname_id: string | null;
|
|
760
|
+
last_error: string | null;
|
|
761
|
+
last_checked_at: string | null;
|
|
762
|
+
created_at: string;
|
|
763
|
+
updated_at: string;
|
|
764
|
+
}
|
|
377
765
|
/**
|
|
378
766
|
* One member row — the shape `listAppMembers` returns and the `member` half
|
|
379
767
|
* of `addAppMember`'s union returns. Fields are camelCase on the wire (see
|
|
@@ -383,8 +771,71 @@ export interface AppMember {
|
|
|
383
771
|
humanId: string;
|
|
384
772
|
email: string;
|
|
385
773
|
role: string;
|
|
774
|
+
/** M5: an optional DECLARED custom role attached alongside base member powers. */
|
|
775
|
+
customRole?: string | null;
|
|
386
776
|
createdAt: string;
|
|
387
777
|
}
|
|
778
|
+
/**
|
|
779
|
+
* One inbound catch-hook row from `listIngestHooks`. `url` is the full secret
|
|
780
|
+
* ingest URL to hand a sender. Rule-derived fields (collection/mode/wake/
|
|
781
|
+
* handshake) are null when the hook's rule has left the manifest (disabledAt
|
|
782
|
+
* set). `deliveries` are per-status counts of the hook's inbound journal.
|
|
783
|
+
*/
|
|
784
|
+
export interface IngestHookInfo {
|
|
785
|
+
name: string;
|
|
786
|
+
url: string;
|
|
787
|
+
collection: string | null;
|
|
788
|
+
mode: string | null;
|
|
789
|
+
wake: boolean | null;
|
|
790
|
+
handshake: string | null;
|
|
791
|
+
disabledAt: string | null;
|
|
792
|
+
createdAt: string;
|
|
793
|
+
deliveries: {
|
|
794
|
+
accepted: number;
|
|
795
|
+
failed: number;
|
|
796
|
+
dropped_duplicate: number;
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Effective per-verb access from `listAppRoles`: "all" = every row, "own" =
|
|
801
|
+
* only rows the holder authored (the `:own` / author narrowing), "none" =
|
|
802
|
+
* nothing. `create` is never "own" (no pre-existing row to be the author of).
|
|
803
|
+
* The relay computes these by probing its real enforcement functions, so they
|
|
804
|
+
* report what a holder can ACTUALLY do, including floors like `anyone`.
|
|
805
|
+
*/
|
|
806
|
+
export interface AppRoleVerbAccess {
|
|
807
|
+
read: "all" | "own" | "none";
|
|
808
|
+
create: "all" | "none";
|
|
809
|
+
update: "all" | "own" | "none";
|
|
810
|
+
delete: "all" | "own" | "none";
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* One collection's access from `listAppRoles`, reported PER POPULATION:
|
|
814
|
+
* `member_access` is what a signed-in member holding the role can do (their
|
|
815
|
+
* principal also carries the member floor), `grant_access` what a grant-link
|
|
816
|
+
* holder of the same role can do (no member floor, so the two can differ).
|
|
817
|
+
* `append_only` is context: such a collection refuses update/delete for every
|
|
818
|
+
* role while still allowing create, and the access tables reflect that.
|
|
819
|
+
*/
|
|
820
|
+
export interface AppRoleCollectionAccess {
|
|
821
|
+
name: string;
|
|
822
|
+
member_access: AppRoleVerbAccess;
|
|
823
|
+
grant_access: AppRoleVerbAccess;
|
|
824
|
+
append_only: boolean;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* One declared custom role from `listAppRoles`. `member_count` and
|
|
828
|
+
* `active_grant_count` are separate numbers, never summed: members are
|
|
829
|
+
* signed-in Humans, grant-link holders are anonymous per-holder identities.
|
|
830
|
+
*/
|
|
831
|
+
export interface AppRoleSummary {
|
|
832
|
+
name: string;
|
|
833
|
+
label: string;
|
|
834
|
+
description: string | null;
|
|
835
|
+
collections: AppRoleCollectionAccess[];
|
|
836
|
+
member_count: number;
|
|
837
|
+
active_grant_count: number;
|
|
838
|
+
}
|
|
388
839
|
/**
|
|
389
840
|
* `POST /v1/apps/:id/members` response — either the member was attached
|
|
390
841
|
* immediately (existing Human) or an invite email was sent (no Human yet).
|
|
@@ -396,6 +847,32 @@ export type AddAppMemberResult = {
|
|
|
396
847
|
invited: string;
|
|
397
848
|
expires_at: string;
|
|
398
849
|
};
|
|
850
|
+
/** `POST /v1/apps/:id/grants` response. `grant_url` carries the raw link token
|
|
851
|
+
* in its #g= fragment and is shown ONCE (it is never recoverable afterward). */
|
|
852
|
+
export interface MintAppGrantResult {
|
|
853
|
+
id: string;
|
|
854
|
+
grant_url: string;
|
|
855
|
+
role: string;
|
|
856
|
+
mode: string;
|
|
857
|
+
max_uses: number | null;
|
|
858
|
+
expires_at: string;
|
|
859
|
+
}
|
|
860
|
+
/** One grant-link row from `listAppGrants` (never carries any token material). */
|
|
861
|
+
export interface AppGrantSummary {
|
|
862
|
+
id: string;
|
|
863
|
+
role: string;
|
|
864
|
+
mode: string;
|
|
865
|
+
max_uses: number | null;
|
|
866
|
+
use_count: number;
|
|
867
|
+
claim_count: number;
|
|
868
|
+
pin_row_key: string | null;
|
|
869
|
+
pin_where: unknown;
|
|
870
|
+
label: string | null;
|
|
871
|
+
active: boolean;
|
|
872
|
+
expires_at: string;
|
|
873
|
+
revoked_at: string | null;
|
|
874
|
+
created_at: string;
|
|
875
|
+
}
|
|
399
876
|
/** One row in an app collection — the shape every row CRUD op returns. */
|
|
400
877
|
export interface AppRow {
|
|
401
878
|
key: string;
|
|
@@ -414,6 +891,68 @@ export interface AppRowsPage {
|
|
|
414
891
|
next_cursor: string | null;
|
|
415
892
|
has_more: boolean;
|
|
416
893
|
}
|
|
894
|
+
/** A scalar operand for a structured read-query condition (Wave C2). */
|
|
895
|
+
export type ListScalar = string | number | boolean;
|
|
896
|
+
/**
|
|
897
|
+
* One structured read-query condition (Wave C2). `op` is one of eq / neq / in /
|
|
898
|
+
* notIn / gt / lt / gte / lte, with the SAME type semantics as a notify `when`:
|
|
899
|
+
* comparisons are same-type only (a number never matches a string operand), and
|
|
900
|
+
* dates are compared as ISO-8601 strings. `value` is a single scalar for the
|
|
901
|
+
* scalar ops and a non-empty scalar array for `in`/`notIn`.
|
|
902
|
+
*/
|
|
903
|
+
export interface ListWhereCondition {
|
|
904
|
+
field: string;
|
|
905
|
+
op: "eq" | "neq" | "in" | "notIn" | "gt" | "lt" | "gte" | "lte";
|
|
906
|
+
value: ListScalar | ListScalar[];
|
|
907
|
+
}
|
|
908
|
+
/** One structured read-query sort key (Wave C2). `dir` defaults to "asc". */
|
|
909
|
+
export interface ListSortSpec {
|
|
910
|
+
field: string;
|
|
911
|
+
dir?: "asc" | "desc";
|
|
912
|
+
}
|
|
913
|
+
/** One row of a batch write (Wave B). `key` absent => create; present => upsert. */
|
|
914
|
+
export interface BatchRowInput {
|
|
915
|
+
key?: string;
|
|
916
|
+
data: unknown;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* The outcome of one row in a batch, addressed by its `index` in the input array
|
|
920
|
+
* so a caller maps a failure back to the exact row it sent. `ok:true` carries the
|
|
921
|
+
* written `key`; `ok:false` carries the per-row `error`.
|
|
922
|
+
*/
|
|
923
|
+
export interface BatchRowResult {
|
|
924
|
+
index: number;
|
|
925
|
+
ok: boolean;
|
|
926
|
+
key?: string;
|
|
927
|
+
error?: {
|
|
928
|
+
code: string;
|
|
929
|
+
message: string;
|
|
930
|
+
status: number;
|
|
931
|
+
details?: unknown;
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
/** The batch write / delete envelope: per-row results plus convenience counts. */
|
|
935
|
+
export interface BatchResult {
|
|
936
|
+
results: BatchRowResult[];
|
|
937
|
+
ok_count: number;
|
|
938
|
+
error_count: number;
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Effect-suppression options for a batch (silent migration, Wave B). The batch
|
|
942
|
+
* endpoint DEFAULTS to silent (suppresses both notify and webhooks). Pass
|
|
943
|
+
* `emitEffects:true` (or `suppress:[]`) to fire effects, or `suppress` to mute a
|
|
944
|
+
* specific subset. Honored only for an owner/agent key.
|
|
945
|
+
*/
|
|
946
|
+
export interface BatchWriteOptions {
|
|
947
|
+
suppress?: ("notify" | "webhooks")[];
|
|
948
|
+
emitEffects?: boolean;
|
|
949
|
+
/**
|
|
950
|
+
* Wave C1 natural-key upsert: match (or create) each row on this
|
|
951
|
+
* declared-unique field's value instead of the row id, making a re-import
|
|
952
|
+
* idempotent. Mutually exclusive with per-row `key`.
|
|
953
|
+
*/
|
|
954
|
+
on?: string;
|
|
955
|
+
}
|
|
417
956
|
/**
|
|
418
957
|
* One entry in an app's change feed — the SAME shape whether it arrives via
|
|
419
958
|
* `GET /v1/apps/:id/feed` (long-poll) or the `/_hs/ws` live/batch frames
|
|
@@ -438,6 +977,239 @@ export interface AppFeedPage {
|
|
|
438
977
|
cursor: number;
|
|
439
978
|
truncated: boolean;
|
|
440
979
|
}
|
|
980
|
+
/** Request body for `publishCommunityTemplate()`. */
|
|
981
|
+
/**
|
|
982
|
+
* One typed agent-setup step (marketplace PR 9). An ordered list of these tells
|
|
983
|
+
* an installing agent what to configure after install. Carries only the
|
|
984
|
+
* publisher's own defaults + hints, never an installer's value; `secret: true`
|
|
985
|
+
* marks a step whose eventual value is sensitive (its default is masked on the
|
|
986
|
+
* public detail page). The relay validates + normalizes on publish.
|
|
987
|
+
*/
|
|
988
|
+
export interface CommunitySetupStep {
|
|
989
|
+
kind: "config" | "seed-data" | "connect" | "note" | "upload";
|
|
990
|
+
label: string;
|
|
991
|
+
description?: string;
|
|
992
|
+
required?: boolean;
|
|
993
|
+
secret?: boolean;
|
|
994
|
+
default?: string;
|
|
995
|
+
choices?: string[];
|
|
996
|
+
valueHint?: string;
|
|
997
|
+
/**
|
|
998
|
+
* The settings-collection field this step's answer is written into
|
|
999
|
+
* (install-config programme). Required for an `upload` step, optional for a
|
|
1000
|
+
* `config` step, and not allowed on the other kinds. Field-key identifier
|
|
1001
|
+
* (letters, digits, '_', up to 64 chars).
|
|
1002
|
+
*/
|
|
1003
|
+
key?: string;
|
|
1004
|
+
}
|
|
1005
|
+
export interface PublishCommunityTemplateRequest {
|
|
1006
|
+
/** The owned app to publish. */
|
|
1007
|
+
appId: string;
|
|
1008
|
+
/** Listing title; defaults server-side to the app's manifest name. */
|
|
1009
|
+
title?: string;
|
|
1010
|
+
/** Listing blurb; defaults server-side to the manifest description. */
|
|
1011
|
+
description?: string;
|
|
1012
|
+
/**
|
|
1013
|
+
* Optional long-form description (template-experience PR 5a): richer prose
|
|
1014
|
+
* rendered on the detail page below the short blurb. Plain text, length-capped
|
|
1015
|
+
* server-side; blank lines become escaped paragraph breaks (never raw HTML).
|
|
1016
|
+
*/
|
|
1017
|
+
longDescription?: string;
|
|
1018
|
+
/** Optional category (validated server-side against the fixed enum). */
|
|
1019
|
+
category?: string;
|
|
1020
|
+
/** Optional curation tags. */
|
|
1021
|
+
tags?: string[];
|
|
1022
|
+
/**
|
|
1023
|
+
* Optional per-publisher slug (marketplace PR 2). When set, the template gets
|
|
1024
|
+
* a namespaced id `<handle>/<slug>` and joins a versioned line.
|
|
1025
|
+
*/
|
|
1026
|
+
slug?: string;
|
|
1027
|
+
/** Optional semver version; defaults server-side to "1.0.0". */
|
|
1028
|
+
version?: string;
|
|
1029
|
+
/** Optional note recorded in this version's changelog entry. */
|
|
1030
|
+
changelogNote?: string;
|
|
1031
|
+
/**
|
|
1032
|
+
* Optional ordered typed setup steps (marketplace PR 9). Validated + stored
|
|
1033
|
+
* server-side; read back through the detail page + get_submission.
|
|
1034
|
+
*/
|
|
1035
|
+
setupSteps?: CommunitySetupStep[];
|
|
1036
|
+
/** Optional remix/fork lineage: the snapshot id this was derived from. */
|
|
1037
|
+
derivedFromSnapshotId?: string;
|
|
1038
|
+
/**
|
|
1039
|
+
* The example-only attestation (marketplace PR 10). Set true to attest the
|
|
1040
|
+
* captured template content AND its captured seed rows contain no real
|
|
1041
|
+
* personal data: publishing makes both PUBLIC to all platform users. Recorded
|
|
1042
|
+
* (not a hard gate) and surfaced to the operator review payload; omitting it
|
|
1043
|
+
* still publishes but is shown to the reviewer as "not attested".
|
|
1044
|
+
*/
|
|
1045
|
+
attestExampleOnly?: boolean;
|
|
1046
|
+
}
|
|
1047
|
+
export interface PublishCommunityTemplateResponse {
|
|
1048
|
+
snapshot_id: string;
|
|
1049
|
+
review_status: "pending" | "approved" | "rejected";
|
|
1050
|
+
name: string;
|
|
1051
|
+
seeded_row_count: number;
|
|
1052
|
+
slug: string | null;
|
|
1053
|
+
version: string;
|
|
1054
|
+
/** How many typed setup steps were stored (marketplace PR 9). */
|
|
1055
|
+
setup_step_count: number;
|
|
1056
|
+
/**
|
|
1057
|
+
* The example-only attestation as recorded (marketplace PR 10): true/false as
|
|
1058
|
+
* attested, or null when the publish carried no attestation.
|
|
1059
|
+
*/
|
|
1060
|
+
attest_example_only: boolean | null;
|
|
1061
|
+
/**
|
|
1062
|
+
* Fast-track outcome (marketplace PR 11). `expedited`: the publisher is
|
|
1063
|
+
* `established` and the submission still landed `pending`, flagged to sort
|
|
1064
|
+
* first in the operator review queue. `auto_approved`: the publisher is
|
|
1065
|
+
* `established` AND the relay enables true auto-approve, so it was approved
|
|
1066
|
+
* immediately at publish (review_status === "approved"). Both false for a
|
|
1067
|
+
* `new` publisher (ordinary full review).
|
|
1068
|
+
*/
|
|
1069
|
+
expedited: boolean;
|
|
1070
|
+
auto_approved: boolean;
|
|
1071
|
+
}
|
|
1072
|
+
/** A pending-submission summary in the operator review queue. */
|
|
1073
|
+
export interface CommunitySubmissionSummary {
|
|
1074
|
+
snapshot_id: string;
|
|
1075
|
+
name: string;
|
|
1076
|
+
description: string | null;
|
|
1077
|
+
/**
|
|
1078
|
+
* Publisher-provided long-form description (template-experience PR 5a),
|
|
1079
|
+
* surfaced in the review payload so the operator sees the full prose that
|
|
1080
|
+
* renders on the detail page. Null when the publish carried none.
|
|
1081
|
+
*/
|
|
1082
|
+
long_description: string | null;
|
|
1083
|
+
category: string | null;
|
|
1084
|
+
tags: string[];
|
|
1085
|
+
review_status: "pending" | "approved" | "rejected";
|
|
1086
|
+
publisher_human_id: string | null;
|
|
1087
|
+
publisher_name: string | null;
|
|
1088
|
+
source_app_id: string | null;
|
|
1089
|
+
seeded_row_count: number;
|
|
1090
|
+
published_at: string;
|
|
1091
|
+
/** Namespaced identity + version (marketplace PR 2); null when unset. */
|
|
1092
|
+
slug: string | null;
|
|
1093
|
+
version: string | null;
|
|
1094
|
+
/**
|
|
1095
|
+
* Publish-time PII attestation (marketplace PR 10): true/false as attested by
|
|
1096
|
+
* the publisher, or null when the publish carried no attestation. Surfaced in
|
|
1097
|
+
* the review queue so a missing attestation is visible to the operator.
|
|
1098
|
+
*/
|
|
1099
|
+
attest_example_only: boolean | null;
|
|
1100
|
+
/**
|
|
1101
|
+
* Fast-track flag (marketplace PR 11): true when this pending submission was
|
|
1102
|
+
* expedited (published by an `established` publisher, sorted first in the
|
|
1103
|
+
* queue). False for a `new` publisher and pre-PR-11 rows.
|
|
1104
|
+
*/
|
|
1105
|
+
expedited: boolean;
|
|
1106
|
+
/** The publisher's trust level (marketplace PR 11): "new" | "established". */
|
|
1107
|
+
publisher_trust_level: string;
|
|
1108
|
+
}
|
|
1109
|
+
export interface CommunitySubmissionsPage {
|
|
1110
|
+
items: CommunitySubmissionSummary[];
|
|
1111
|
+
next_cursor: string | null;
|
|
1112
|
+
}
|
|
1113
|
+
/** One collection's captured-seed footprint (marketplace PR 10). */
|
|
1114
|
+
export interface CommunitySeedCollectionSummary {
|
|
1115
|
+
collection: string;
|
|
1116
|
+
row_count: number;
|
|
1117
|
+
bytes: number;
|
|
1118
|
+
}
|
|
1119
|
+
/** A per-collection digest of a submission's captured seed rows (PR 10). */
|
|
1120
|
+
export interface CommunitySeedRowSummary {
|
|
1121
|
+
collections: CommunitySeedCollectionSummary[];
|
|
1122
|
+
total_rows: number;
|
|
1123
|
+
total_bytes: number;
|
|
1124
|
+
}
|
|
1125
|
+
/** A submission's FULL content, for operator review. */
|
|
1126
|
+
export interface CommunitySubmissionDetail extends CommunitySubmissionSummary {
|
|
1127
|
+
html: string;
|
|
1128
|
+
manifest: unknown;
|
|
1129
|
+
seed_rows: unknown;
|
|
1130
|
+
/**
|
|
1131
|
+
* A digest of seed_rows (marketplace PR 10): per-collection row counts + byte
|
|
1132
|
+
* sizes plus totals, so the operator sees how much (and which) captured
|
|
1133
|
+
* starter data would become public without parsing the raw rows.
|
|
1134
|
+
*/
|
|
1135
|
+
seed_summary: CommunitySeedRowSummary;
|
|
1136
|
+
version_id: string | null;
|
|
1137
|
+
reviewed_at: string | null;
|
|
1138
|
+
review_note: string | null;
|
|
1139
|
+
superseded_at: string | null;
|
|
1140
|
+
/** Namespaced identity + fork/license fields (marketplace PR 2). */
|
|
1141
|
+
changelog: unknown;
|
|
1142
|
+
license: string | null;
|
|
1143
|
+
license_terms: string | null;
|
|
1144
|
+
derived_from_snapshot_id: string | null;
|
|
1145
|
+
/**
|
|
1146
|
+
* Typed agent-setup steps (marketplace PR 9): the machine-readable structure
|
|
1147
|
+
* an agent reads. Full structure incl. secret-flagged steps (a step stores
|
|
1148
|
+
* only the publisher's default/hint, never an installer value). `null` when
|
|
1149
|
+
* the template declares no steps.
|
|
1150
|
+
*/
|
|
1151
|
+
setup_steps: CommunitySetupStep[] | null;
|
|
1152
|
+
}
|
|
1153
|
+
/** A publisher's own profile, as returned by the `/v1/publisher` routes. */
|
|
1154
|
+
export interface PublisherProfile {
|
|
1155
|
+
handle: string;
|
|
1156
|
+
display_name: string | null;
|
|
1157
|
+
bio: string | null;
|
|
1158
|
+
url: string | null;
|
|
1159
|
+
/** True once the handle has been claimed (and is therefore permanent). */
|
|
1160
|
+
claimed: boolean;
|
|
1161
|
+
claimed_at: string | null;
|
|
1162
|
+
created_at: string;
|
|
1163
|
+
first_published_at: string | null;
|
|
1164
|
+
approved_template_count: number;
|
|
1165
|
+
rating_count: number;
|
|
1166
|
+
rating_sum: number;
|
|
1167
|
+
trust_level: string;
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* The mutable profile fields for `updatePublisher()`. A field left `undefined`
|
|
1171
|
+
* is untouched; `null` clears it.
|
|
1172
|
+
*/
|
|
1173
|
+
export interface PublisherProfileUpdate {
|
|
1174
|
+
displayName?: string | null;
|
|
1175
|
+
bio?: string | null;
|
|
1176
|
+
url?: string | null;
|
|
1177
|
+
}
|
|
1178
|
+
/** Request body for `createReview()`. Give `template` OR (`handle` + `slug`). */
|
|
1179
|
+
export interface CreateCommunityReviewRequest {
|
|
1180
|
+
/** Namespaced template id, "<handle>/<slug>". */
|
|
1181
|
+
template?: string;
|
|
1182
|
+
/** Publisher handle (with `slug`, as an alternative to `template`). */
|
|
1183
|
+
handle?: string;
|
|
1184
|
+
/** Per-publisher slug (with `handle`). */
|
|
1185
|
+
slug?: string;
|
|
1186
|
+
/** Star rating, integer 1..5. */
|
|
1187
|
+
stars: number;
|
|
1188
|
+
/** Optional written review body. */
|
|
1189
|
+
body?: string;
|
|
1190
|
+
}
|
|
1191
|
+
/** A review as returned by the `/v1/reviews` routes. */
|
|
1192
|
+
export interface CommunityReview {
|
|
1193
|
+
id: string;
|
|
1194
|
+
template_publisher_human_id: string;
|
|
1195
|
+
template_slug: string | null;
|
|
1196
|
+
snapshot_id: string;
|
|
1197
|
+
install_id: string | null;
|
|
1198
|
+
reviewer_human_id: string;
|
|
1199
|
+
stars: number;
|
|
1200
|
+
body: string | null;
|
|
1201
|
+
/** "visible" | "held" | "removed". A body with a link/email lands "held". */
|
|
1202
|
+
status: string;
|
|
1203
|
+
held_reason: string | null;
|
|
1204
|
+
publisher_response: string | null;
|
|
1205
|
+
publisher_responded_at: string | null;
|
|
1206
|
+
created_at: string;
|
|
1207
|
+
}
|
|
1208
|
+
/** Result of `reportReview()`. */
|
|
1209
|
+
export interface CommunityReviewReportResult {
|
|
1210
|
+
report_id: string;
|
|
1211
|
+
review_id: string;
|
|
1212
|
+
}
|
|
441
1213
|
/** Per-attachment metadata as returned by `POST /v1/attachments` and friends. */
|
|
442
1214
|
export interface AttachmentRef {
|
|
443
1215
|
attachment_id: string;
|