@homespunapps/core 1.4.2 → 1.5.0
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 +133 -0
- package/dist/client.js +73 -3
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -421,6 +421,34 @@ export declare class HomespunClient {
|
|
|
421
421
|
url: string;
|
|
422
422
|
};
|
|
423
423
|
}>;
|
|
424
|
+
/**
|
|
425
|
+
* PUT /v1/apps/:id/ingest-hooks/:name/signing-secret provisions or rotates a
|
|
426
|
+
* hook's SIGNING secret (opt-in webhook signature verification, issue #935,
|
|
427
|
+
* shipped dark: nothing verifies a signature yet). This is a DIFFERENT secret
|
|
428
|
+
* from the URL secret rotateIngestHook rotates: it is what a provider (GitHub,
|
|
429
|
+
* Stripe, ...) HMACs the request body with.
|
|
430
|
+
*
|
|
431
|
+
* Omit `secret` to have the relay MINT one (`ihk_...`): the response includes
|
|
432
|
+
* the value ONCE (paste it into the provider). Pass `secret` to store a
|
|
433
|
+
* provider-generated value verbatim: the value is never echoed back, only the
|
|
434
|
+
* fingerprint. A rotation keeps the previous secret valid for `graceSeconds`
|
|
435
|
+
* (default 3600, max 86400) so deliveries verify while you update the provider.
|
|
436
|
+
*/
|
|
437
|
+
setIngestSigningSecret(appId: string, name: string, opts?: {
|
|
438
|
+
secret?: string;
|
|
439
|
+
graceSeconds?: number;
|
|
440
|
+
}): Promise<{
|
|
441
|
+
secret?: string;
|
|
442
|
+
fingerprint: string;
|
|
443
|
+
setAt: string;
|
|
444
|
+
}>;
|
|
445
|
+
/**
|
|
446
|
+
* DELETE /v1/apps/:id/ingest-hooks/:name/signing-secret clears a hook's
|
|
447
|
+
* signing secret (current + previous + grace window). Idempotent.
|
|
448
|
+
*/
|
|
449
|
+
clearIngestSigningSecret(appId: string, name: string): Promise<{
|
|
450
|
+
ok: boolean;
|
|
451
|
+
}>;
|
|
424
452
|
/**
|
|
425
453
|
* POST /v1/apps/:id/grants: mint a grant link. `role` must be a declared
|
|
426
454
|
* custom role for the app. `mode` is "once" (one-time, first-browser-claims)
|
|
@@ -553,6 +581,22 @@ export declare class HomespunClient {
|
|
|
553
581
|
decision: "approve" | "reject";
|
|
554
582
|
note?: string;
|
|
555
583
|
}): Promise<CommunitySubmissionDetail>;
|
|
584
|
+
/**
|
|
585
|
+
* GET /v1/community/templates/:ref/config-contract: the install-time config
|
|
586
|
+
* contract for an installable template (its settings collection + the ordered
|
|
587
|
+
* keyed config/upload steps). Use it to discover what a template needs and to
|
|
588
|
+
* pre-upload files for `upload` steps (POST /v1/attachments) before install.
|
|
589
|
+
*/
|
|
590
|
+
getCommunityConfigContract(ref: string): Promise<CommunityConfigContract>;
|
|
591
|
+
/**
|
|
592
|
+
* POST /v1/community/templates/:ref/install: install a community template for
|
|
593
|
+
* the calling agent's owning human. `config` is `{ [stepKey]: value }` where a
|
|
594
|
+
* `config` step's value is a string and an `upload` step's value is an
|
|
595
|
+
* attachment id the agent pre-uploaded (agent-scoped) via `uploadBlob()` /
|
|
596
|
+
* `uploadBlobInline()`; the relay re-points it to the new app on install.
|
|
597
|
+
* Installs always create; returns the new app's id, slug, and url.
|
|
598
|
+
*/
|
|
599
|
+
installCommunityTemplate(ref: string, config?: Record<string, unknown>): Promise<CommunityInstallResult>;
|
|
556
600
|
/** GET /v1/publisher: the caller's own publisher profile. */
|
|
557
601
|
getPublisher(): Promise<PublisherProfile>;
|
|
558
602
|
/** POST /v1/publisher/claim: set the handle once (permanent after claiming). */
|
|
@@ -790,6 +834,20 @@ export interface IngestHookInfo {
|
|
|
790
834
|
handshake: string | null;
|
|
791
835
|
disabledAt: string | null;
|
|
792
836
|
createdAt: string;
|
|
837
|
+
/**
|
|
838
|
+
* Opt-in signature verification state (issue #935), shipped dark. `configured`
|
|
839
|
+
* is true when a signing secret is set; `fingerprint` identifies WHICH one
|
|
840
|
+
* (plaintext-derived, matches the value in the provider's settings) without
|
|
841
|
+
* ever exposing it; `previousUntil` is set during a rotation's grace window.
|
|
842
|
+
*/
|
|
843
|
+
signingSecret: {
|
|
844
|
+
configured: boolean;
|
|
845
|
+
fingerprint: string | null;
|
|
846
|
+
setAt: string | null;
|
|
847
|
+
previousUntil: string | null;
|
|
848
|
+
};
|
|
849
|
+
/** Placeholder for the D3 manifest `verify` grammar; always null for now. */
|
|
850
|
+
verify: null;
|
|
793
851
|
deliveries: {
|
|
794
852
|
accepted: number;
|
|
795
853
|
failed: number;
|
|
@@ -1001,6 +1059,61 @@ export interface CommunitySetupStep {
|
|
|
1001
1059
|
* (letters, digits, '_', up to 64 chars).
|
|
1002
1060
|
*/
|
|
1003
1061
|
key?: string;
|
|
1062
|
+
/**
|
|
1063
|
+
* The manifest `ingest` rule this step wires up (D7). Allowed ONLY on a
|
|
1064
|
+
* `connect` step, optional there. Publish rejects a name the manifest does
|
|
1065
|
+
* not declare. After install, the installer pastes that rule's freshly
|
|
1066
|
+
* provisioned hook URL into the external service.
|
|
1067
|
+
*/
|
|
1068
|
+
ingestRule?: string;
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* One keyed config/upload step in a template's install-time config contract
|
|
1072
|
+
* (install-config programme, PR 4). Field names are the wire shape (snake_case
|
|
1073
|
+
* `value_hint`). An `upload` step's answer is an attachment id string.
|
|
1074
|
+
*/
|
|
1075
|
+
export interface CommunityConfigStep {
|
|
1076
|
+
key: string;
|
|
1077
|
+
kind: "config" | "upload";
|
|
1078
|
+
label: string;
|
|
1079
|
+
description?: string;
|
|
1080
|
+
required: boolean;
|
|
1081
|
+
secret: boolean;
|
|
1082
|
+
choices?: string[];
|
|
1083
|
+
default?: string;
|
|
1084
|
+
value_hint?: string;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* One `connect` step in a template's contract that wires up an INBOUND hook:
|
|
1088
|
+
* after install, the app's own freshly provisioned hook URL for `ingest_rule`
|
|
1089
|
+
* has to be pasted into the external service the step describes. Read the URLs
|
|
1090
|
+
* from `GET /v1/apps/:app_id/ingest-hooks` once the install returns.
|
|
1091
|
+
*/
|
|
1092
|
+
export interface CommunityConnectStep {
|
|
1093
|
+
label: string;
|
|
1094
|
+
description?: string;
|
|
1095
|
+
ingest_rule: string;
|
|
1096
|
+
/** Collection the hook writes into, or null when the rule went missing. */
|
|
1097
|
+
collection: string | null;
|
|
1098
|
+
mode: "append" | "upsert" | null;
|
|
1099
|
+
}
|
|
1100
|
+
/** The install-time config contract for an installable community template. */
|
|
1101
|
+
export interface CommunityConfigContract {
|
|
1102
|
+
snapshot_id: string;
|
|
1103
|
+
name: string;
|
|
1104
|
+
slug: string | null;
|
|
1105
|
+
/** The manifest's declared settings collection, or null when none. */
|
|
1106
|
+
settings_collection: string | null;
|
|
1107
|
+
/** Ordered keyed config/upload steps; empty when the template needs none. */
|
|
1108
|
+
config_steps: CommunityConfigStep[];
|
|
1109
|
+
/** Ordered connect steps that name an ingest rule; empty when none. */
|
|
1110
|
+
connect_steps: CommunityConnectStep[];
|
|
1111
|
+
}
|
|
1112
|
+
/** Result of an agent-key community install (installs always create). */
|
|
1113
|
+
export interface CommunityInstallResult {
|
|
1114
|
+
app_id: string;
|
|
1115
|
+
slug: string;
|
|
1116
|
+
url: string;
|
|
1004
1117
|
}
|
|
1005
1118
|
export interface PublishCommunityTemplateRequest {
|
|
1006
1119
|
/** The owned app to publish. */
|
|
@@ -1149,6 +1262,26 @@ export interface CommunitySubmissionDetail extends CommunitySubmissionSummary {
|
|
|
1149
1262
|
* the template declares no steps.
|
|
1150
1263
|
*/
|
|
1151
1264
|
setup_steps: CommunitySetupStep[] | null;
|
|
1265
|
+
/**
|
|
1266
|
+
* Every external destination the manifest declares (D6 disclosure): outbound
|
|
1267
|
+
* webhook targets, the app's fetch allowance and its framing allowance,
|
|
1268
|
+
* deduplicated and HOSTS ONLY, so a reviewer sees where the app can send
|
|
1269
|
+
* data without reading the raw manifest. Empty when it talks to nothing
|
|
1270
|
+
* outside Homespun.
|
|
1271
|
+
*/
|
|
1272
|
+
external_destinations: CommunityExternalDestination[];
|
|
1273
|
+
}
|
|
1274
|
+
/** One disclosed external destination on a submission (D6). */
|
|
1275
|
+
export interface CommunityExternalDestination {
|
|
1276
|
+
/** `webhook` = the relay POSTs row data there; `fetch` / `embed` = the app's
|
|
1277
|
+
* own page may call or frame it. */
|
|
1278
|
+
kind: "webhook" | "embed" | "fetch";
|
|
1279
|
+
/** Destination host, or null when the manifest alone cannot name it. */
|
|
1280
|
+
host: string | null;
|
|
1281
|
+
/** Settings field an install-time webhook target is read from. */
|
|
1282
|
+
fromSetting?: string;
|
|
1283
|
+
/** Stored connection a relative webhook target resolves against. */
|
|
1284
|
+
viaConnection?: string;
|
|
1152
1285
|
}
|
|
1153
1286
|
/** A publisher's own profile, as returned by the `/v1/publisher` routes. */
|
|
1154
1287
|
export interface PublisherProfile {
|
package/dist/client.js
CHANGED
|
@@ -675,9 +675,13 @@ export class HomespunClient {
|
|
|
675
675
|
// (humanId/createdAt), matching packages/relay/src/http/routes/app-members.ts
|
|
676
676
|
// exactly rather than the usual snake_case convention.
|
|
677
677
|
//
|
|
678
|
-
//
|
|
679
|
-
//
|
|
680
|
-
//
|
|
678
|
+
// Community template install IS agent-key authorizable and wrapped below
|
|
679
|
+
// (getCommunityConfigContract + installCommunityTemplate): the calling agent
|
|
680
|
+
// installs a community template for its OWNING human, who becomes the app's
|
|
681
|
+
// installer/owner, reusing the SAME core install path as the human web form.
|
|
682
|
+
// Trials, keep, and the first-party app `uninstall` stay human-only web flows
|
|
683
|
+
// (a countdown banner and a confirm page have no agent-key equivalent), so
|
|
684
|
+
// those remain intentionally unwrapped here.
|
|
681
685
|
// -------------------------------------------------------------------------
|
|
682
686
|
/**
|
|
683
687
|
* POST /v1/apps/:id/members — add or invite a member by email. If a Human
|
|
@@ -773,6 +777,40 @@ export class HomespunClient {
|
|
|
773
777
|
this.fail(r);
|
|
774
778
|
return this.asObject(r);
|
|
775
779
|
}
|
|
780
|
+
/**
|
|
781
|
+
* PUT /v1/apps/:id/ingest-hooks/:name/signing-secret provisions or rotates a
|
|
782
|
+
* hook's SIGNING secret (opt-in webhook signature verification, issue #935,
|
|
783
|
+
* shipped dark: nothing verifies a signature yet). This is a DIFFERENT secret
|
|
784
|
+
* from the URL secret rotateIngestHook rotates: it is what a provider (GitHub,
|
|
785
|
+
* Stripe, ...) HMACs the request body with.
|
|
786
|
+
*
|
|
787
|
+
* Omit `secret` to have the relay MINT one (`ihk_...`): the response includes
|
|
788
|
+
* the value ONCE (paste it into the provider). Pass `secret` to store a
|
|
789
|
+
* provider-generated value verbatim: the value is never echoed back, only the
|
|
790
|
+
* fingerprint. A rotation keeps the previous secret valid for `graceSeconds`
|
|
791
|
+
* (default 3600, max 86400) so deliveries verify while you update the provider.
|
|
792
|
+
*/
|
|
793
|
+
async setIngestSigningSecret(appId, name, opts = {}) {
|
|
794
|
+
const body = {};
|
|
795
|
+
if (opts.secret !== undefined)
|
|
796
|
+
body.secret = opts.secret;
|
|
797
|
+
if (opts.graceSeconds !== undefined)
|
|
798
|
+
body.graceSeconds = opts.graceSeconds;
|
|
799
|
+
const r = await this.call("PUT", `/v1/apps/${encodeURIComponent(appId)}/ingest-hooks/${encodeURIComponent(name)}/signing-secret`, body);
|
|
800
|
+
if (!r.ok)
|
|
801
|
+
this.fail(r);
|
|
802
|
+
return this.asObject(r);
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* DELETE /v1/apps/:id/ingest-hooks/:name/signing-secret clears a hook's
|
|
806
|
+
* signing secret (current + previous + grace window). Idempotent.
|
|
807
|
+
*/
|
|
808
|
+
async clearIngestSigningSecret(appId, name) {
|
|
809
|
+
const r = await this.call("DELETE", `/v1/apps/${encodeURIComponent(appId)}/ingest-hooks/${encodeURIComponent(name)}/signing-secret`);
|
|
810
|
+
if (!r.ok)
|
|
811
|
+
this.fail(r);
|
|
812
|
+
return this.asObject(r);
|
|
813
|
+
}
|
|
776
814
|
// -------------------------------------------------------------------------
|
|
777
815
|
// v2 grant links (M5). An owner/agent mints a capability URL carrying a
|
|
778
816
|
// DECLARED custom role (x-homespun-manifest.roles) plus an optional row/filter
|
|
@@ -1012,6 +1050,38 @@ export class HomespunClient {
|
|
|
1012
1050
|
return this.asObject(r);
|
|
1013
1051
|
}
|
|
1014
1052
|
// -------------------------------------------------------------------------
|
|
1053
|
+
// Agent-key community install (install-config programme, PR 4). Both act AS
|
|
1054
|
+
// the calling agent's owning human, who becomes the installed app's owner. A
|
|
1055
|
+
// `ref` is a namespaced `<handle>/<slug>` OR a community snapshot id;
|
|
1056
|
+
// encodeURIComponent keeps a namespaced ref one path segment on the wire.
|
|
1057
|
+
// -------------------------------------------------------------------------
|
|
1058
|
+
/**
|
|
1059
|
+
* GET /v1/community/templates/:ref/config-contract: the install-time config
|
|
1060
|
+
* contract for an installable template (its settings collection + the ordered
|
|
1061
|
+
* keyed config/upload steps). Use it to discover what a template needs and to
|
|
1062
|
+
* pre-upload files for `upload` steps (POST /v1/attachments) before install.
|
|
1063
|
+
*/
|
|
1064
|
+
async getCommunityConfigContract(ref) {
|
|
1065
|
+
const r = await this.call("GET", `/v1/community/templates/${encodeURIComponent(ref)}/config-contract`);
|
|
1066
|
+
if (!r.ok)
|
|
1067
|
+
this.fail(r);
|
|
1068
|
+
return this.asObject(r);
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* POST /v1/community/templates/:ref/install: install a community template for
|
|
1072
|
+
* the calling agent's owning human. `config` is `{ [stepKey]: value }` where a
|
|
1073
|
+
* `config` step's value is a string and an `upload` step's value is an
|
|
1074
|
+
* attachment id the agent pre-uploaded (agent-scoped) via `uploadBlob()` /
|
|
1075
|
+
* `uploadBlobInline()`; the relay re-points it to the new app on install.
|
|
1076
|
+
* Installs always create; returns the new app's id, slug, and url.
|
|
1077
|
+
*/
|
|
1078
|
+
async installCommunityTemplate(ref, config) {
|
|
1079
|
+
const r = await this.call("POST", `/v1/community/templates/${encodeURIComponent(ref)}/install`, config !== undefined ? { config } : {});
|
|
1080
|
+
if (!r.ok)
|
|
1081
|
+
this.fail(r);
|
|
1082
|
+
return this.asObject(r);
|
|
1083
|
+
}
|
|
1084
|
+
// -------------------------------------------------------------------------
|
|
1015
1085
|
// Community publisher identity (marketplace PR 1). All three act AS the
|
|
1016
1086
|
// calling agent's owning human. claim/update additionally need a verified
|
|
1017
1087
|
// email server-side.
|