@homespunapps/core 1.6.68 → 1.6.70

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 CHANGED
@@ -313,7 +313,11 @@ export declare class HomespunClient {
313
313
  * human-given slug to an id (see the class-level note above).
314
314
  */
315
315
  listApps(opts?: {
316
- status?: "active" | "dormant" | "archived" | "suspended" | "all";
316
+ /**
317
+ * `deleted` is the trash listing and the only value that returns
318
+ * soft-deleted apps; `all` means every LIVE status, as it always has.
319
+ */
320
+ status?: "active" | "dormant" | "archived" | "suspended" | "deleted" | "all";
317
321
  limit?: number;
318
322
  cursor?: string;
319
323
  slug?: string;
@@ -333,7 +337,9 @@ export declare class HomespunClient {
333
337
  severity?: "high" | "medium" | "low";
334
338
  }): Promise<AppAdvisoriesReport>;
335
339
  /** GET /v1/apps/:id — full app detail (manifest, current_version, quota). */
336
- getApp(appId: string): Promise<AppDetail>;
340
+ getApp(appId: string, opts?: {
341
+ includeDeleted?: boolean;
342
+ }): Promise<AppDetail>;
337
343
  /**
338
344
  * GET /v1/apps/:id/document: the app's AUTHORED HTML source (its current
339
345
  * version), before the served page's injected prelude (SDK script, favicon,
@@ -372,8 +378,33 @@ export declare class HomespunClient {
372
378
  rotateShareLink(appId: string): Promise<{
373
379
  share_url: string;
374
380
  }>;
375
- /** DELETE /v1/apps/:id — soft-delete (idempotent). */
381
+ /**
382
+ * DELETE /v1/apps/:id — soft-delete (idempotent).
383
+ *
384
+ * Recoverable, not destructive: the app stops serving immediately but keeps
385
+ * every version, collection, row, attachment, member and grant it had, and
386
+ * `restoreApp` brings all of it back until the retention window elapses.
387
+ * `purgeApp` is the irreversible one.
388
+ */
376
389
  deleteApp(appId: string): Promise<void>;
390
+ /**
391
+ * POST /v1/apps/:id/restore — undo a soft delete, with all the app's data.
392
+ *
393
+ * Idempotent on a live app. Fails with 409 when the account is at its app
394
+ * cap (the delete released the slot, so the restore has to re-take it), when
395
+ * the app was an expired trial, or when the owning account is itself
396
+ * deleted. An app suspended by an operator comes back SUSPENDED, not active.
397
+ */
398
+ restoreApp(appId: string): Promise<AppDetail>;
399
+ /**
400
+ * POST /v1/apps/:id/purge — destroy a deleted app and all its data NOW,
401
+ * without waiting out the retention window. Irreversible.
402
+ *
403
+ * The app must already be soft-deleted; purging a live one fails with 409.
404
+ * That two-step is deliberate, so no single call takes a serving app to
405
+ * unrecoverable.
406
+ */
407
+ purgeApp(appId: string): Promise<void>;
377
408
  /** POST /v1/apps/:id/wake — wake a dormant app; a no-op on a non-dormant one. */
378
409
  wakeApp(appId: string): Promise<{
379
410
  id: string;
@@ -1108,6 +1139,22 @@ export interface AppSummary {
1108
1139
  has_share_token: boolean;
1109
1140
  created_at: string;
1110
1141
  last_activity_at: string;
1142
+ /**
1143
+ * When the app was soft-deleted. PRESENT ONLY on a deleted app, so its
1144
+ * absence is a reliable "this app is live" test. A deleted app keeps all of
1145
+ * its data and is restorable with `restoreApp` until `purges_at`.
1146
+ */
1147
+ deleted_at?: string;
1148
+ /**
1149
+ * When the app becomes eligible to be purged forever, or `null` meaning
1150
+ * never. Present alongside `deleted_at`, so a null here is unambiguously
1151
+ * "never purged" rather than "not deleted".
1152
+ *
1153
+ * An eligibility boundary, not an exact moment: the relay's sweeper runs on
1154
+ * an interval, so the real purge lands at or after this. Word it as "purges
1155
+ * after", never "purges at".
1156
+ */
1157
+ purges_at?: string | null;
1111
1158
  }
1112
1159
  /** Full app detail — the shape `getApp` returns. */
1113
1160
  export interface AppDetail extends AppSummary {
package/dist/client.js CHANGED
@@ -632,8 +632,12 @@ export class HomespunClient {
632
632
  return this.asObject(r);
633
633
  }
634
634
  /** GET /v1/apps/:id — full app detail (manifest, current_version, quota). */
635
- async getApp(appId) {
636
- const r = await this.call("GET", `/v1/apps/${encodeURIComponent(appId)}`);
635
+ async getApp(appId, opts = {}) {
636
+ // Opt-in, matching the route: without it a soft-deleted app reads as
637
+ // app_not_found, so an unaware caller never gets a live-looking record for
638
+ // something that serves nothing.
639
+ const qs = opts.includeDeleted ? "?include_deleted=true" : "";
640
+ const r = await this.call("GET", `/v1/apps/${encodeURIComponent(appId)}${qs}`);
637
641
  if (!r.ok)
638
642
  this.fail(r);
639
643
  return this.asObject(r);
@@ -686,12 +690,46 @@ export class HomespunClient {
686
690
  this.fail(r);
687
691
  return this.asObject(r);
688
692
  }
689
- /** DELETE /v1/apps/:id — soft-delete (idempotent). */
693
+ /**
694
+ * DELETE /v1/apps/:id — soft-delete (idempotent).
695
+ *
696
+ * Recoverable, not destructive: the app stops serving immediately but keeps
697
+ * every version, collection, row, attachment, member and grant it had, and
698
+ * `restoreApp` brings all of it back until the retention window elapses.
699
+ * `purgeApp` is the irreversible one.
700
+ */
690
701
  async deleteApp(appId) {
691
702
  const r = await this.call("DELETE", `/v1/apps/${encodeURIComponent(appId)}`);
692
703
  if (!r.ok)
693
704
  this.fail(r);
694
705
  }
706
+ /**
707
+ * POST /v1/apps/:id/restore — undo a soft delete, with all the app's data.
708
+ *
709
+ * Idempotent on a live app. Fails with 409 when the account is at its app
710
+ * cap (the delete released the slot, so the restore has to re-take it), when
711
+ * the app was an expired trial, or when the owning account is itself
712
+ * deleted. An app suspended by an operator comes back SUSPENDED, not active.
713
+ */
714
+ async restoreApp(appId) {
715
+ const r = await this.call("POST", `/v1/apps/${encodeURIComponent(appId)}/restore`);
716
+ if (!r.ok)
717
+ this.fail(r);
718
+ return this.asObject(r);
719
+ }
720
+ /**
721
+ * POST /v1/apps/:id/purge — destroy a deleted app and all its data NOW,
722
+ * without waiting out the retention window. Irreversible.
723
+ *
724
+ * The app must already be soft-deleted; purging a live one fails with 409.
725
+ * That two-step is deliberate, so no single call takes a serving app to
726
+ * unrecoverable.
727
+ */
728
+ async purgeApp(appId) {
729
+ const r = await this.call("POST", `/v1/apps/${encodeURIComponent(appId)}/purge`);
730
+ if (!r.ok)
731
+ this.fail(r);
732
+ }
695
733
  /** POST /v1/apps/:id/wake — wake a dormant app; a no-op on a non-dormant one. */
696
734
  async wakeApp(appId) {
697
735
  const r = await this.call("POST", `/v1/apps/${encodeURIComponent(appId)}/wake`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homespunapps/core",
3
- "version": "1.6.68",
3
+ "version": "1.6.70",
4
4
  "description": "Homespun relay client: typed HTTP + WebSocket operations against a Homespun relay. Framework-free.",
5
5
  "license": "MIT",
6
6
  "type": "module",