@homespunapps/core 1.6.48 → 1.6.49

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
@@ -804,6 +804,35 @@ export declare class HomespunClient {
804
804
  * new app's id, slug, and url.
805
805
  */
806
806
  installCommunityTemplate(ref: string, config?: Record<string, unknown>): Promise<CommunityInstallResult>;
807
+ /**
808
+ * GET /v1/apps/:id/upgrade: is a newer version of this app's source template
809
+ * available, would it apply cleanly, and what would it newly be allowed to
810
+ * reach. No side effects; the verdict is computed by the same validation the
811
+ * apply path re-runs.
812
+ */
813
+ checkTemplateUpgrade(appId: string): Promise<TemplateUpgradePreview>;
814
+ /**
815
+ * POST /v1/apps/:id/upgrade: apply it.
816
+ *
817
+ * `acceptPermissions` is REQUIRED when the preview reports a non-empty
818
+ * permission diff, and is deliberately not defaulted: an agent must state
819
+ * that its owner accepted the widening rather than have the absence of a
820
+ * field satisfy the gate. `expectVersion` refuses if the offer moved since
821
+ * the preview, so an agent never applies a version it did not describe.
822
+ *
823
+ * Refuses outright, with no override, when the new version would strand rows
824
+ * the app already holds.
825
+ */
826
+ upgradeTemplate(appId: string, opts?: {
827
+ acceptPermissions?: boolean;
828
+ expectVersion?: string;
829
+ }): Promise<TemplateUpgradeResult>;
830
+ /**
831
+ * POST /v1/apps/:id/upgrade/revert: put back the version the app ran before
832
+ * its last template upgrade. Refuses when rows written since would have
833
+ * nowhere to live under the older version.
834
+ */
835
+ revertTemplateUpgrade(appId: string): Promise<TemplateRevertResult>;
807
836
  /** GET /v1/publisher: the caller's own publisher profile. */
808
837
  getPublisher(): Promise<PublisherProfile>;
809
838
  /** POST /v1/publisher/claim: set the handle once (permanent after claiming). */
@@ -1492,6 +1521,57 @@ export interface CommunityInstallResult {
1492
1521
  slug: string;
1493
1522
  url: string;
1494
1523
  }
1524
+ /** One narrowing the compat gate reports, in the manifest author's words. */
1525
+ export interface TemplateUpgradeBreak {
1526
+ path: string;
1527
+ message: string;
1528
+ }
1529
+ /** Everything a caller needs to decide whether to apply a template update. */
1530
+ export interface TemplateUpgradePreview {
1531
+ /** Is a newer live version of this app's template line available at all? */
1532
+ available: boolean;
1533
+ from_version: string | null;
1534
+ to_version: string | null;
1535
+ changelog: unknown;
1536
+ snapshot_id: string | null;
1537
+ compat: "clean" | "forced" | "incompatible" | null;
1538
+ /**
1539
+ * Breaks that BLOCK the update: it would strand rows the app already holds.
1540
+ * No acceptance clears these.
1541
+ */
1542
+ breaks: TemplateUpgradeBreak[];
1543
+ /**
1544
+ * Breaks saying the new version discloses more than the installed one. These
1545
+ * are what `accept_permissions` clears, and the human-readable peer is
1546
+ * `permission_lines`.
1547
+ */
1548
+ disclosure_breaks: TemplateUpgradeBreak[];
1549
+ permissions: {
1550
+ external_hosts: string[];
1551
+ embeds: string[];
1552
+ capabilities: string[];
1553
+ cdn: boolean;
1554
+ offline: boolean;
1555
+ webhook_rules: number;
1556
+ is_empty: boolean;
1557
+ };
1558
+ /** One plain sentence per widening, for showing a person before accepting. */
1559
+ permission_lines: string[];
1560
+ blocked: boolean;
1561
+ blocked_reason: "incompatible" | null;
1562
+ revert_available: boolean;
1563
+ }
1564
+ export interface TemplateUpgradeResult {
1565
+ from_version: string | null;
1566
+ to_version: string;
1567
+ snapshot_id: string;
1568
+ /** The version now available to revert to. */
1569
+ previous_version_id: string;
1570
+ }
1571
+ export interface TemplateRevertResult {
1572
+ version_id: string;
1573
+ template_version: string | null;
1574
+ }
1495
1575
  export interface PublishCommunityTemplateRequest {
1496
1576
  /** The owned app to publish. */
1497
1577
  appId: string;
package/dist/client.js CHANGED
@@ -1370,6 +1370,62 @@ export class HomespunClient {
1370
1370
  return this.asObject(r);
1371
1371
  }
1372
1372
  // -------------------------------------------------------------------------
1373
+ // Template updates (#1502). An installed template is a fork, so these act on
1374
+ // an APP, not on a template ref: the question is "is there a newer version of
1375
+ // the template THIS app came from", which only the app can answer.
1376
+ //
1377
+ // Nothing here happens on its own. There is no follow/pin policy, so an agent
1378
+ // that wants its owner's apps current has to ask, every time.
1379
+ // -------------------------------------------------------------------------
1380
+ /**
1381
+ * GET /v1/apps/:id/upgrade: is a newer version of this app's source template
1382
+ * available, would it apply cleanly, and what would it newly be allowed to
1383
+ * reach. No side effects; the verdict is computed by the same validation the
1384
+ * apply path re-runs.
1385
+ */
1386
+ async checkTemplateUpgrade(appId) {
1387
+ const r = await this.call("GET", `/v1/apps/${encodeURIComponent(appId)}/upgrade`);
1388
+ if (!r.ok)
1389
+ this.fail(r);
1390
+ return this.asObject(r);
1391
+ }
1392
+ /**
1393
+ * POST /v1/apps/:id/upgrade: apply it.
1394
+ *
1395
+ * `acceptPermissions` is REQUIRED when the preview reports a non-empty
1396
+ * permission diff, and is deliberately not defaulted: an agent must state
1397
+ * that its owner accepted the widening rather than have the absence of a
1398
+ * field satisfy the gate. `expectVersion` refuses if the offer moved since
1399
+ * the preview, so an agent never applies a version it did not describe.
1400
+ *
1401
+ * Refuses outright, with no override, when the new version would strand rows
1402
+ * the app already holds.
1403
+ */
1404
+ async upgradeTemplate(appId, opts) {
1405
+ const r = await this.call("POST", `/v1/apps/${encodeURIComponent(appId)}/upgrade`, {
1406
+ ...(opts?.acceptPermissions !== undefined
1407
+ ? { accept_permissions: opts.acceptPermissions }
1408
+ : {}),
1409
+ ...(opts?.expectVersion !== undefined
1410
+ ? { expect_version: opts.expectVersion }
1411
+ : {}),
1412
+ });
1413
+ if (!r.ok)
1414
+ this.fail(r);
1415
+ return this.asObject(r);
1416
+ }
1417
+ /**
1418
+ * POST /v1/apps/:id/upgrade/revert: put back the version the app ran before
1419
+ * its last template upgrade. Refuses when rows written since would have
1420
+ * nowhere to live under the older version.
1421
+ */
1422
+ async revertTemplateUpgrade(appId) {
1423
+ const r = await this.call("POST", `/v1/apps/${encodeURIComponent(appId)}/upgrade/revert`, {});
1424
+ if (!r.ok)
1425
+ this.fail(r);
1426
+ return this.asObject(r);
1427
+ }
1428
+ // -------------------------------------------------------------------------
1373
1429
  // Community publisher identity (marketplace PR 1). All three act AS the
1374
1430
  // calling agent's owning human. claim/update additionally need a verified
1375
1431
  // email server-side.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homespunapps/core",
3
- "version": "1.6.48",
3
+ "version": "1.6.49",
4
4
  "description": "Homespun relay client: typed HTTP + WebSocket operations against a Homespun relay. Framework-free.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,7 +36,7 @@
36
36
  ],
37
37
  "scripts": {
38
38
  "build": "tsc",
39
- "typecheck": "tsc --noEmit",
39
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.tests.json",
40
40
  "test": "vitest run",
41
41
  "test:unit": "vitest run"
42
42
  },