@homespunapps/core 1.0.0 → 1.0.1
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 +157 -1
- package/dist/client.js +143 -2
- package/dist/index.d.ts +1 -1
- package/package.json +3 -8
package/dist/client.d.ts
CHANGED
|
@@ -159,6 +159,25 @@ export declare class HomespunClient {
|
|
|
159
159
|
* stream bytes through the relay.
|
|
160
160
|
*/
|
|
161
161
|
uploadBlob(file: Blob | Buffer | Uint8Array, opts?: UploadBlobOptions): Promise<AttachmentRef>;
|
|
162
|
+
/**
|
|
163
|
+
* Upload a attachment from INLINE base64 bytes: the no-filesystem sibling of
|
|
164
|
+
* `uploadBlob()`. Use this when the bytes were produced in memory (an image
|
|
165
|
+
* the agent generated, a document it assembled) and there is no local file to
|
|
166
|
+
* stream: an MCP client running inside a Claude session has no filesystem to
|
|
167
|
+
* point `uploadBlob()` at.
|
|
168
|
+
*
|
|
169
|
+
* The bytes are sent as base64 in a JSON body to the relay's
|
|
170
|
+
* `POST /v1/attachments` inline variant ({ content_base64, filename?, mime?,
|
|
171
|
+
* scope?, app_id? }). The relay decodes them behind a pre-decode size guard and runs
|
|
172
|
+
* the IDENTICAL validation pipeline the multipart `uploadBlob()` path runs:
|
|
173
|
+
* magic-byte MIME sniff, BLOB_MIME_ALLOWLIST, per-attachment size cap, and the
|
|
174
|
+
* per-agent / per-app / per-account quota reservation. `mime` is advisory
|
|
175
|
+
* (the relay sniffs the real type regardless), and an oversized or disallowed
|
|
176
|
+
* inline upload returns the same errors the file path would.
|
|
177
|
+
*
|
|
178
|
+
* @param contentBase64 standard base64 (e.g. `Buffer.from(bytes).toString("base64")`).
|
|
179
|
+
*/
|
|
180
|
+
uploadBlobInline(contentBase64: string, opts?: UploadBlobOptions): Promise<AttachmentRef>;
|
|
162
181
|
/** GET /v1/attachments/:id — download bytes as an ArrayBuffer. */
|
|
163
182
|
downloadBlob(attachmentId: string): Promise<ArrayBuffer>;
|
|
164
183
|
/**
|
|
@@ -219,8 +238,22 @@ export declare class HomespunClient {
|
|
|
219
238
|
upload_url: string;
|
|
220
239
|
expires_at: string;
|
|
221
240
|
}>;
|
|
222
|
-
/**
|
|
241
|
+
/**
|
|
242
|
+
* Finalise a presigned upload. After the client PUTs the bytes to the
|
|
243
|
+
* `upload_url` from `presignBlob()`, the relay re-reads the stored bytes and
|
|
244
|
+
* runs the SAME validation a normal upload runs: it BYTE-SNIFFS the actual
|
|
245
|
+
* content and derives the stored/served mime from that (never the
|
|
246
|
+
* presign-declared mime), re-verifies size + sha256, enforces the allowlist +
|
|
247
|
+
* quota, and runs the scan hook, before flipping the attachment to `ready`.
|
|
248
|
+
* A finalize whose bytes fail any check leaves the attachment unready (it is
|
|
249
|
+
* never served) and returns a clean error. Returns the ready `AttachmentRef`.
|
|
250
|
+
*/
|
|
223
251
|
confirmBlob(attachmentId: string): Promise<AttachmentRef>;
|
|
252
|
+
/**
|
|
253
|
+
* Alias for {@link confirmBlob}: the "finalize" half of the presign ->
|
|
254
|
+
* PUT -> finalize flow, named to match the MCP `attachments` action.
|
|
255
|
+
*/
|
|
256
|
+
finalizeBlob(attachmentId: string): Promise<AttachmentRef>;
|
|
224
257
|
/** POST /v1/apps — create (deploy) a new App + its first AppVersion. */
|
|
225
258
|
deployApp(req: DeployAppRequest): Promise<DeployAppResponse>;
|
|
226
259
|
/** POST /v1/apps/:id/versions — redeploy (compat-gated unless force). */
|
|
@@ -250,6 +283,23 @@ export declare class HomespunClient {
|
|
|
250
283
|
id: string;
|
|
251
284
|
status: string;
|
|
252
285
|
}>;
|
|
286
|
+
/**
|
|
287
|
+
* POST /v1/apps/:id/domain - bind a custom domain to the app. Returns the
|
|
288
|
+
* record including `dns_records`: the DNS entries the domain owner must
|
|
289
|
+
* publish (the routing CNAME plus any Cloudflare validation records).
|
|
290
|
+
*/
|
|
291
|
+
setAppDomain(appId: string, domain: string): Promise<AppDomain>;
|
|
292
|
+
/**
|
|
293
|
+
* GET /v1/apps/:id/domain - the app's domain record, live-refreshed against
|
|
294
|
+
* Cloudflare when the feature is enabled (status/last_error/last_checked_at
|
|
295
|
+
* update as a side effect).
|
|
296
|
+
*/
|
|
297
|
+
getAppDomain(appId: string): Promise<AppDomain>;
|
|
298
|
+
/**
|
|
299
|
+
* DELETE /v1/apps/:id/domain - remove the domain binding (Cloudflare
|
|
300
|
+
* hostname best-effort + record + quota release). Idempotent.
|
|
301
|
+
*/
|
|
302
|
+
deleteAppDomain(appId: string): Promise<void>;
|
|
253
303
|
/**
|
|
254
304
|
* POST /v1/apps/:id/members — add or invite a member by email. If a Human
|
|
255
305
|
* already exists for the email, the member row is created immediately
|
|
@@ -318,6 +368,35 @@ export declare class HomespunClient {
|
|
|
318
368
|
limit?: number;
|
|
319
369
|
wait?: number;
|
|
320
370
|
}): Promise<AppFeedPage>;
|
|
371
|
+
/** POST /v1/community/publish: publish an owned app as a pending template. */
|
|
372
|
+
publishCommunityTemplate(req: PublishCommunityTemplateRequest): Promise<PublishCommunityTemplateResponse>;
|
|
373
|
+
/** GET /v1/community/pending (operator): list pending submissions. */
|
|
374
|
+
listCommunitySubmissions(opts?: {
|
|
375
|
+
limit?: number;
|
|
376
|
+
cursor?: string;
|
|
377
|
+
}): Promise<CommunitySubmissionsPage>;
|
|
378
|
+
/** GET /v1/community/submissions/:id (operator): a submission's full content. */
|
|
379
|
+
getCommunitySubmission(snapshotId: string): Promise<CommunitySubmissionDetail>;
|
|
380
|
+
/**
|
|
381
|
+
* POST /v1/community/submissions/:id/{approve,reject} (operator): review a
|
|
382
|
+
* submission. `decision` "reject" requires a `note` (delivered to the
|
|
383
|
+
* publisher's app feed).
|
|
384
|
+
*/
|
|
385
|
+
reviewCommunitySubmission(snapshotId: string, review: {
|
|
386
|
+
decision: "approve" | "reject";
|
|
387
|
+
note?: string;
|
|
388
|
+
}): Promise<CommunitySubmissionDetail>;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* One multi-file-deploy asset: bytes the deployed page references by a stable,
|
|
392
|
+
* app-relative, same-origin path (e.g. `frames/000.jpg`). `content_base64` is the
|
|
393
|
+
* standard base64 of the raw bytes; `mime` is advisory (the relay sniffs the
|
|
394
|
+
* real type from the leading bytes).
|
|
395
|
+
*/
|
|
396
|
+
export interface AppAsset {
|
|
397
|
+
path: string;
|
|
398
|
+
content_base64: string;
|
|
399
|
+
mime?: string;
|
|
321
400
|
}
|
|
322
401
|
/** Request body for `POST /v1/apps` — create (deploy) a new App. */
|
|
323
402
|
export interface DeployAppRequest {
|
|
@@ -327,6 +406,13 @@ export interface DeployAppRequest {
|
|
|
327
406
|
visibility?: "private" | "link" | "public";
|
|
328
407
|
/** Accepted for visibility public|private (including the omitted default); rejected for link. */
|
|
329
408
|
slug?: string;
|
|
409
|
+
/**
|
|
410
|
+
* Optional asset bundle shipped alongside the HTML in ONE deploy. Each asset
|
|
411
|
+
* is validated + stored app-scoped exactly like an attachment and served at
|
|
412
|
+
* its `path` on the app's own origin, so `<img src="frames/000.jpg">` just
|
|
413
|
+
* works. Rejected atomically if any asset fails validation.
|
|
414
|
+
*/
|
|
415
|
+
assets?: AppAsset[];
|
|
330
416
|
}
|
|
331
417
|
export interface DeployAppResponse {
|
|
332
418
|
app_id: string;
|
|
@@ -342,6 +428,11 @@ export interface RedeployAppRequest {
|
|
|
342
428
|
manifest: unknown;
|
|
343
429
|
/** Bypass the compat gate; a narrowing collection is detached, not deleted. */
|
|
344
430
|
force?: boolean;
|
|
431
|
+
/**
|
|
432
|
+
* Optional asset bundle for this version. Replaces the previous version's asset
|
|
433
|
+
* set atomically (the new version carries its own map; old assets are detached).
|
|
434
|
+
*/
|
|
435
|
+
assets?: AppAsset[];
|
|
345
436
|
}
|
|
346
437
|
export interface RedeployAppResponse {
|
|
347
438
|
app_id: string;
|
|
@@ -374,6 +465,24 @@ export interface AppsPage {
|
|
|
374
465
|
items: AppSummary[];
|
|
375
466
|
next_cursor: string | null;
|
|
376
467
|
}
|
|
468
|
+
/** One DNS record the domain owner must publish (custom domains). */
|
|
469
|
+
export interface AppDomainDnsRecord {
|
|
470
|
+
type: string;
|
|
471
|
+
name: string;
|
|
472
|
+
value: string;
|
|
473
|
+
purpose: "routing" | "ownership" | "certificate_validation";
|
|
474
|
+
}
|
|
475
|
+
/** The app's custom-domain record - the shape the /domain routes return. */
|
|
476
|
+
export interface AppDomain {
|
|
477
|
+
domain: string;
|
|
478
|
+
status: "pending" | "active" | "error" | "removed";
|
|
479
|
+
dns_records: AppDomainDnsRecord[];
|
|
480
|
+
cf_hostname_id: string | null;
|
|
481
|
+
last_error: string | null;
|
|
482
|
+
last_checked_at: string | null;
|
|
483
|
+
created_at: string;
|
|
484
|
+
updated_at: string;
|
|
485
|
+
}
|
|
377
486
|
/**
|
|
378
487
|
* One member row — the shape `listAppMembers` returns and the `member` half
|
|
379
488
|
* of `addAppMember`'s union returns. Fields are camelCase on the wire (see
|
|
@@ -438,6 +547,53 @@ export interface AppFeedPage {
|
|
|
438
547
|
cursor: number;
|
|
439
548
|
truncated: boolean;
|
|
440
549
|
}
|
|
550
|
+
/** Request body for `publishCommunityTemplate()`. */
|
|
551
|
+
export interface PublishCommunityTemplateRequest {
|
|
552
|
+
/** The owned app to publish. */
|
|
553
|
+
appId: string;
|
|
554
|
+
/** Listing title; defaults server-side to the app's manifest name. */
|
|
555
|
+
title?: string;
|
|
556
|
+
/** Listing blurb; defaults server-side to the manifest description. */
|
|
557
|
+
description?: string;
|
|
558
|
+
/** Optional single-word category. */
|
|
559
|
+
category?: string;
|
|
560
|
+
/** Optional curation tags. */
|
|
561
|
+
tags?: string[];
|
|
562
|
+
}
|
|
563
|
+
export interface PublishCommunityTemplateResponse {
|
|
564
|
+
snapshot_id: string;
|
|
565
|
+
review_status: "pending" | "approved" | "rejected";
|
|
566
|
+
name: string;
|
|
567
|
+
seeded_row_count: number;
|
|
568
|
+
}
|
|
569
|
+
/** A pending-submission summary in the operator review queue. */
|
|
570
|
+
export interface CommunitySubmissionSummary {
|
|
571
|
+
snapshot_id: string;
|
|
572
|
+
name: string;
|
|
573
|
+
description: string | null;
|
|
574
|
+
category: string | null;
|
|
575
|
+
tags: string[];
|
|
576
|
+
review_status: "pending" | "approved" | "rejected";
|
|
577
|
+
publisher_human_id: string | null;
|
|
578
|
+
publisher_name: string | null;
|
|
579
|
+
source_app_id: string | null;
|
|
580
|
+
seeded_row_count: number;
|
|
581
|
+
published_at: string;
|
|
582
|
+
}
|
|
583
|
+
export interface CommunitySubmissionsPage {
|
|
584
|
+
items: CommunitySubmissionSummary[];
|
|
585
|
+
next_cursor: string | null;
|
|
586
|
+
}
|
|
587
|
+
/** A submission's FULL content, for operator review. */
|
|
588
|
+
export interface CommunitySubmissionDetail extends CommunitySubmissionSummary {
|
|
589
|
+
html: string;
|
|
590
|
+
manifest: unknown;
|
|
591
|
+
seed_rows: unknown;
|
|
592
|
+
version_id: string | null;
|
|
593
|
+
reviewed_at: string | null;
|
|
594
|
+
review_note: string | null;
|
|
595
|
+
superseded_at: string | null;
|
|
596
|
+
}
|
|
441
597
|
/** Per-attachment metadata as returned by `POST /v1/attachments` and friends. */
|
|
442
598
|
export interface AttachmentRef {
|
|
443
599
|
attachment_id: string;
|
package/dist/client.js
CHANGED
|
@@ -305,6 +305,39 @@ export class HomespunClient {
|
|
|
305
305
|
}
|
|
306
306
|
return data;
|
|
307
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Upload a attachment from INLINE base64 bytes: the no-filesystem sibling of
|
|
310
|
+
* `uploadBlob()`. Use this when the bytes were produced in memory (an image
|
|
311
|
+
* the agent generated, a document it assembled) and there is no local file to
|
|
312
|
+
* stream: an MCP client running inside a Claude session has no filesystem to
|
|
313
|
+
* point `uploadBlob()` at.
|
|
314
|
+
*
|
|
315
|
+
* The bytes are sent as base64 in a JSON body to the relay's
|
|
316
|
+
* `POST /v1/attachments` inline variant ({ content_base64, filename?, mime?,
|
|
317
|
+
* scope?, app_id? }). The relay decodes them behind a pre-decode size guard and runs
|
|
318
|
+
* the IDENTICAL validation pipeline the multipart `uploadBlob()` path runs:
|
|
319
|
+
* magic-byte MIME sniff, BLOB_MIME_ALLOWLIST, per-attachment size cap, and the
|
|
320
|
+
* per-agent / per-app / per-account quota reservation. `mime` is advisory
|
|
321
|
+
* (the relay sniffs the real type regardless), and an oversized or disallowed
|
|
322
|
+
* inline upload returns the same errors the file path would.
|
|
323
|
+
*
|
|
324
|
+
* @param contentBase64 standard base64 (e.g. `Buffer.from(bytes).toString("base64")`).
|
|
325
|
+
*/
|
|
326
|
+
async uploadBlobInline(contentBase64, opts = {}) {
|
|
327
|
+
const body = { content_base64: contentBase64 };
|
|
328
|
+
if (opts.scope)
|
|
329
|
+
body.scope = opts.scope;
|
|
330
|
+
if (opts.appId)
|
|
331
|
+
body.app_id = opts.appId;
|
|
332
|
+
if (opts.filename)
|
|
333
|
+
body.filename = opts.filename;
|
|
334
|
+
if (opts.mime)
|
|
335
|
+
body.mime = opts.mime;
|
|
336
|
+
const r = await this.call("POST", "/v1/attachments", body);
|
|
337
|
+
if (!r.ok)
|
|
338
|
+
this.fail(r);
|
|
339
|
+
return this.asObject(r);
|
|
340
|
+
}
|
|
308
341
|
/** GET /v1/attachments/:id — download bytes as an ArrayBuffer. */
|
|
309
342
|
async downloadBlob(attachmentId) {
|
|
310
343
|
const url = this.base + "/v1/attachments/" + encodeURIComponent(attachmentId);
|
|
@@ -424,13 +457,29 @@ export class HomespunClient {
|
|
|
424
457
|
this.fail(r);
|
|
425
458
|
return r.data;
|
|
426
459
|
}
|
|
427
|
-
/**
|
|
460
|
+
/**
|
|
461
|
+
* Finalise a presigned upload. After the client PUTs the bytes to the
|
|
462
|
+
* `upload_url` from `presignBlob()`, the relay re-reads the stored bytes and
|
|
463
|
+
* runs the SAME validation a normal upload runs: it BYTE-SNIFFS the actual
|
|
464
|
+
* content and derives the stored/served mime from that (never the
|
|
465
|
+
* presign-declared mime), re-verifies size + sha256, enforces the allowlist +
|
|
466
|
+
* quota, and runs the scan hook, before flipping the attachment to `ready`.
|
|
467
|
+
* A finalize whose bytes fail any check leaves the attachment unready (it is
|
|
468
|
+
* never served) and returns a clean error. Returns the ready `AttachmentRef`.
|
|
469
|
+
*/
|
|
428
470
|
async confirmBlob(attachmentId) {
|
|
429
471
|
const r = await this.call("POST", "/v1/attachments/" + encodeURIComponent(attachmentId) + "/confirm");
|
|
430
472
|
if (!r.ok)
|
|
431
473
|
this.fail(r);
|
|
432
474
|
return r.data;
|
|
433
475
|
}
|
|
476
|
+
/**
|
|
477
|
+
* Alias for {@link confirmBlob}: the "finalize" half of the presign ->
|
|
478
|
+
* PUT -> finalize flow, named to match the MCP `attachments` action.
|
|
479
|
+
*/
|
|
480
|
+
async finalizeBlob(attachmentId) {
|
|
481
|
+
return this.confirmBlob(attachmentId);
|
|
482
|
+
}
|
|
434
483
|
// -------------------------------------------------------------------------
|
|
435
484
|
// v2 app lifecycle (spec-cli §2.1). `:id` on every route below is always the
|
|
436
485
|
// App.id (cuid) — a slug is resolved to an id via `listApps({ slug })`
|
|
@@ -443,6 +492,7 @@ export class HomespunClient {
|
|
|
443
492
|
manifest: req.manifest,
|
|
444
493
|
visibility: req.visibility,
|
|
445
494
|
slug: req.slug,
|
|
495
|
+
assets: req.assets,
|
|
446
496
|
});
|
|
447
497
|
if (!r.ok)
|
|
448
498
|
this.fail(r);
|
|
@@ -450,7 +500,12 @@ export class HomespunClient {
|
|
|
450
500
|
}
|
|
451
501
|
/** POST /v1/apps/:id/versions — redeploy (compat-gated unless force). */
|
|
452
502
|
async redeployApp(appId, req) {
|
|
453
|
-
const r = await this.call("POST", `/v1/apps/${encodeURIComponent(appId)}/versions`, {
|
|
503
|
+
const r = await this.call("POST", `/v1/apps/${encodeURIComponent(appId)}/versions`, {
|
|
504
|
+
html: req.html,
|
|
505
|
+
manifest: req.manifest,
|
|
506
|
+
force: req.force,
|
|
507
|
+
assets: req.assets,
|
|
508
|
+
});
|
|
454
509
|
if (!r.ok)
|
|
455
510
|
this.fail(r);
|
|
456
511
|
return this.asObject(r);
|
|
@@ -504,6 +559,42 @@ export class HomespunClient {
|
|
|
504
559
|
return this.asObject(r);
|
|
505
560
|
}
|
|
506
561
|
// -------------------------------------------------------------------------
|
|
562
|
+
// Custom domains (Cloudflare for SaaS). One primary domain per app. The
|
|
563
|
+
// relay rejects setAppDomain with `custom_domains_not_enabled` (501) when
|
|
564
|
+
// the deployment has no Cloudflare configuration.
|
|
565
|
+
// -------------------------------------------------------------------------
|
|
566
|
+
/**
|
|
567
|
+
* POST /v1/apps/:id/domain - bind a custom domain to the app. Returns the
|
|
568
|
+
* record including `dns_records`: the DNS entries the domain owner must
|
|
569
|
+
* publish (the routing CNAME plus any Cloudflare validation records).
|
|
570
|
+
*/
|
|
571
|
+
async setAppDomain(appId, domain) {
|
|
572
|
+
const r = await this.call("POST", `/v1/apps/${encodeURIComponent(appId)}/domain`, { domain });
|
|
573
|
+
if (!r.ok)
|
|
574
|
+
this.fail(r);
|
|
575
|
+
return this.asObject(r);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* GET /v1/apps/:id/domain - the app's domain record, live-refreshed against
|
|
579
|
+
* Cloudflare when the feature is enabled (status/last_error/last_checked_at
|
|
580
|
+
* update as a side effect).
|
|
581
|
+
*/
|
|
582
|
+
async getAppDomain(appId) {
|
|
583
|
+
const r = await this.call("GET", `/v1/apps/${encodeURIComponent(appId)}/domain`);
|
|
584
|
+
if (!r.ok)
|
|
585
|
+
this.fail(r);
|
|
586
|
+
return this.asObject(r);
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* DELETE /v1/apps/:id/domain - remove the domain binding (Cloudflare
|
|
590
|
+
* hostname best-effort + record + quota release). Idempotent.
|
|
591
|
+
*/
|
|
592
|
+
async deleteAppDomain(appId) {
|
|
593
|
+
const r = await this.call("DELETE", `/v1/apps/${encodeURIComponent(appId)}/domain`);
|
|
594
|
+
if (!r.ok)
|
|
595
|
+
this.fail(r);
|
|
596
|
+
}
|
|
597
|
+
// -------------------------------------------------------------------------
|
|
507
598
|
// v2 app membership (auth spec §6, spec-cli §2.5). Auth is owner-or-agent;
|
|
508
599
|
// this client always authenticates as the owning agent. Note: unlike most
|
|
509
600
|
// v1/v2 wire shapes, the member fields below are camelCase on the wire
|
|
@@ -616,4 +707,54 @@ export class HomespunClient {
|
|
|
616
707
|
this.fail(r);
|
|
617
708
|
return this.asObject(r);
|
|
618
709
|
}
|
|
710
|
+
// -------------------------------------------------------------------------
|
|
711
|
+
// Community publish + review (M4b). publishCommunityTemplate is an OWNER
|
|
712
|
+
// action (the calling agent's owning human); the review methods are
|
|
713
|
+
// operator-gated server-side.
|
|
714
|
+
// -------------------------------------------------------------------------
|
|
715
|
+
/** POST /v1/community/publish: publish an owned app as a pending template. */
|
|
716
|
+
async publishCommunityTemplate(req) {
|
|
717
|
+
const r = await this.call("POST", "/v1/community/publish", {
|
|
718
|
+
app_id: req.appId,
|
|
719
|
+
title: req.title,
|
|
720
|
+
description: req.description,
|
|
721
|
+
category: req.category,
|
|
722
|
+
tags: req.tags,
|
|
723
|
+
});
|
|
724
|
+
if (!r.ok)
|
|
725
|
+
this.fail(r);
|
|
726
|
+
return this.asObject(r);
|
|
727
|
+
}
|
|
728
|
+
/** GET /v1/community/pending (operator): list pending submissions. */
|
|
729
|
+
async listCommunitySubmissions(opts = {}) {
|
|
730
|
+
const q = new URLSearchParams();
|
|
731
|
+
if (opts.limit !== undefined)
|
|
732
|
+
q.set("limit", String(opts.limit));
|
|
733
|
+
if (opts.cursor !== undefined && opts.cursor !== "")
|
|
734
|
+
q.set("cursor", opts.cursor);
|
|
735
|
+
const qs = q.toString();
|
|
736
|
+
const r = await this.call("GET", `/v1/community/pending${qs ? "?" + qs : ""}`);
|
|
737
|
+
if (!r.ok)
|
|
738
|
+
this.fail(r);
|
|
739
|
+
return this.asObject(r);
|
|
740
|
+
}
|
|
741
|
+
/** GET /v1/community/submissions/:id (operator): a submission's full content. */
|
|
742
|
+
async getCommunitySubmission(snapshotId) {
|
|
743
|
+
const r = await this.call("GET", `/v1/community/submissions/${encodeURIComponent(snapshotId)}`);
|
|
744
|
+
if (!r.ok)
|
|
745
|
+
this.fail(r);
|
|
746
|
+
return this.asObject(r);
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* POST /v1/community/submissions/:id/{approve,reject} (operator): review a
|
|
750
|
+
* submission. `decision` "reject" requires a `note` (delivered to the
|
|
751
|
+
* publisher's app feed).
|
|
752
|
+
*/
|
|
753
|
+
async reviewCommunitySubmission(snapshotId, review) {
|
|
754
|
+
const path = `/v1/community/submissions/${encodeURIComponent(snapshotId)}/${review.decision}`;
|
|
755
|
+
const r = await this.call("POST", path, review.decision === "reject" ? { note: review.note } : undefined);
|
|
756
|
+
if (!r.ok)
|
|
757
|
+
this.fail(r);
|
|
758
|
+
return this.asObject(r);
|
|
759
|
+
}
|
|
619
760
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { HomespunClient, HomespunApiError } from "./client.js";
|
|
2
|
-
export type { ClientOptions, RelayResponse, AttachmentRef, UploadBlobOptions, PresignBlobOptions, AttachmentTokenMintResponse, ListBlobsOptions, AttachmentTokenAuditEntry, AttachmentTokenListResponse, QueryResponse, DeployAppRequest, DeployAppResponse, RedeployAppRequest, RedeployAppResponse, AppSummary, AppDetail, AppsPage, AppMember, AddAppMemberResult, AppRow, AppRowsPage, AppFeedEntry, AppFeedPage, } from "./client.js";
|
|
2
|
+
export type { ClientOptions, RelayResponse, AttachmentRef, UploadBlobOptions, PresignBlobOptions, AttachmentTokenMintResponse, ListBlobsOptions, AttachmentTokenAuditEntry, AttachmentTokenListResponse, QueryResponse, AppAsset, DeployAppRequest, DeployAppResponse, RedeployAppRequest, RedeployAppResponse, AppSummary, AppDetail, AppsPage, AppDomain, AppDomainDnsRecord, AppMember, AddAppMemberResult, AppRow, AppRowsPage, AppFeedEntry, AppFeedPage, } from "./client.js";
|
|
3
3
|
export { openStream } from "./stream.js";
|
|
4
4
|
export type { OpenStreamOptions, StreamHandlers, StreamHandle, } from "./stream.js";
|
|
5
5
|
export { openAppStream, appWsUrlFromAppUrl } from "./app-stream.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homespunapps/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Homespun relay client: typed HTTP + WebSocket operations against a Homespun relay. Framework-free.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -11,14 +11,9 @@
|
|
|
11
11
|
"relay",
|
|
12
12
|
"human-in-the-loop"
|
|
13
13
|
],
|
|
14
|
-
"homepage": "https://
|
|
15
|
-
"repository": {
|
|
16
|
-
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/aerolalit/homespun.git",
|
|
18
|
-
"directory": "packages/core"
|
|
19
|
-
},
|
|
14
|
+
"homepage": "https://homespun.dev",
|
|
20
15
|
"bugs": {
|
|
21
|
-
"url": "
|
|
16
|
+
"url": "mailto:support@homespun.dev"
|
|
22
17
|
},
|
|
23
18
|
"engines": {
|
|
24
19
|
"node": ">=20"
|