@whooshbang/sdk 7.0.0 → 7.1.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.
@@ -1,5 +1,14 @@
1
- /** Browser-safe result encryption. No dashboard authority or readable credential
2
- * is persisted by the handoff: only the invoking CLI holds the private key. */
1
+ /**
2
+ * One credential operation a signed-in person approves in the dashboard.
3
+ *
4
+ * Two handoffs share the page. The CLI's carries a public key and a loopback
5
+ * callback, and the result goes back to the CLI encrypted, so no dashboard
6
+ * authority or readable credential is persisted. An agent's (`reveal`) carries
7
+ * neither: the person sees the secret once on the page and copies it, and the
8
+ * agent only ever reads the result's metadata (FXO-3726). An agent may also
9
+ * hand off creating or rotating a webhook endpoint, whose signing secret is
10
+ * revealed the same way.
11
+ */
3
12
  export interface CredentialConfirmation {
4
13
  apiOrigin: string;
5
14
  organizationId: string;
@@ -11,7 +20,31 @@ export interface CredentialConfirmation {
11
20
  state: string;
12
21
  expiresAt: number;
13
22
  }
23
+ /** An agent's handoff: the person approves it and sees any secret on the page. */
24
+ export interface RevealCredentialConfirmation {
25
+ apiOrigin: string;
26
+ organizationId: string;
27
+ method: "POST";
28
+ path: string;
29
+ body?: unknown;
30
+ reveal: true;
31
+ state: string;
32
+ expiresAt: number;
33
+ }
34
+ /** How long an agent's link stays usable: long enough for a person to open it. */
35
+ export declare const REVEAL_CONFIRMATION_LIFETIME_MS: number;
36
+ /**
37
+ * A reveal link is stamped by the server and checked by the person's browser,
38
+ * whose clock may run behind. Allow two minutes so a slow clock does not refuse
39
+ * a fresh link. CLI links are stamped and checked on one computer.
40
+ */
41
+ export declare const REVEAL_CLOCK_SKEW_MS: number;
42
+ /** The CLI handoff: credential operations only, answered to the CLI encrypted. */
14
43
  export declare function parseCredentialConfirmation(value: string): CredentialConfirmation;
44
+ /** An agent's handoff (FXO-3726): revealed on the page, never sent anywhere. */
45
+ export declare function parseRevealConfirmation(value: string): RevealCredentialConfirmation;
46
+ /** Either handoff, whichever this one is. */
47
+ export declare function parseAnyCredentialConfirmation(value: string): CredentialConfirmation | RevealCredentialConfirmation;
15
48
  export declare function encryptCredentialResult(publicKey: JsonWebKey, state: string, result: unknown): Promise<string>;
16
49
  export declare function decryptCredentialResult(privateKey: CryptoKey, state: string, encrypted: string): Promise<unknown>;
17
50
  export declare function credentialConfirmationDigest(request: CredentialConfirmation): Promise<string>;
@@ -1,4 +1,14 @@
1
- import { validateProblem, validateCreateOrganizationCredentialRequest, validateCreateApiCredentialRequest, validateRotateOrganizationCredentialRequest, validateRotateApiCredentialRequest, validateOrganizationCredentialCollection, validateApiCredentialCollection, validateOrganizationCredentialSecretReveal, validateApiCredentialSecretReveal, validateOrganizationCredentialRotation, validateApiCredentialRotation, validateOrganizationCredential, validateApiCredential, } from "@whooshbang/contracts";
1
+ import { validateProblem, validateCreateOrganizationCredentialRequest, validateCreateApiCredentialRequest, validateRotateOrganizationCredentialRequest, validateRotateApiCredentialRequest, validateOrganizationCredentialCollection, validateApiCredentialCollection, validateOrganizationCredentialSecretReveal, validateApiCredentialSecretReveal, validateOrganizationCredentialRotation, validateApiCredentialRotation, validateOrganizationCredential, validateApiCredential, validateCreateCustomerEndpointRequest, validateRotateCustomerEndpointRequest, } from "@whooshbang/contracts";
2
+ /** How long an agent's link stays usable: long enough for a person to open it. */
3
+ export const REVEAL_CONFIRMATION_LIFETIME_MS = 15 * 60_000;
4
+ /**
5
+ * A reveal link is stamped by the server and checked by the person's browser,
6
+ * whose clock may run behind. Allow two minutes so a slow clock does not refuse
7
+ * a fresh link. CLI links are stamped and checked on one computer.
8
+ */
9
+ export const REVEAL_CLOCK_SKEW_MS = 2 * 60_000;
10
+ const CREDENTIAL_PATH = /^\/v1\/(?:organization|projects\/[A-Za-z0-9_-]+\/environments\/[A-Za-z0-9_-]+)\/credentials(?:\/[A-Za-z0-9_-]+\/(?:rotate|revoke))?$/u;
11
+ const ENDPOINT_PATH = /^\/v1\/projects\/[A-Za-z0-9_-]+\/environments\/[A-Za-z0-9_-]+\/customer-endpoints(?:\/[A-Za-z0-9_-]+\/rotate)?$/u;
2
12
  function encoded(bytes) {
3
13
  return btoa(Array.from(new Uint8Array(bytes), (byte) => String.fromCharCode(byte)).join(""))
4
14
  .replaceAll("+", "-")
@@ -8,9 +18,28 @@ function encoded(bytes) {
8
18
  function decoded(value) {
9
19
  return Uint8Array.from(atob(value.replaceAll("-", "+").replaceAll("_", "/")), (c) => c.charCodeAt(0));
10
20
  }
21
+ /** The CLI handoff: credential operations only, answered to the CLI encrypted. */
11
22
  export function parseCredentialConfirmation(value) {
12
23
  const parsed = JSON.parse(value);
13
- const callback = new URL(parsed.redirectUri);
24
+ if (parsed.reveal !== undefined)
25
+ throw new Error("Invalid or expired credential confirmation.");
26
+ return checkedConfirmation(parsed);
27
+ }
28
+ /** An agent's handoff (FXO-3726): revealed on the page, never sent anywhere. */
29
+ export function parseRevealConfirmation(value) {
30
+ const parsed = JSON.parse(value);
31
+ if (parsed.reveal !== true)
32
+ throw new Error("Invalid or expired credential confirmation.");
33
+ return checkedConfirmation(parsed);
34
+ }
35
+ /** Either handoff, whichever this one is. */
36
+ export function parseAnyCredentialConfirmation(value) {
37
+ return JSON.parse(value).reveal === true
38
+ ? parseRevealConfirmation(value)
39
+ : parseCredentialConfirmation(value);
40
+ }
41
+ function checkedConfirmation(raw) {
42
+ const parsed = raw;
14
43
  const api = new URL(parsed.apiOrigin);
15
44
  if (api.origin !== parsed.apiOrigin ||
16
45
  api.username ||
@@ -19,43 +48,68 @@ export function parseCredentialConfirmation(value) {
19
48
  !(api.protocol === "http:" &&
20
49
  ["127.0.0.1", "localhost"].includes(api.hostname))))
21
50
  throw new Error("Invalid API origin.");
22
- if (callback.protocol !== "http:" ||
23
- callback.hostname !== "127.0.0.1" ||
24
- !callback.port ||
25
- callback.pathname !== "/callback" ||
26
- callback.username ||
27
- callback.password ||
28
- callback.search ||
29
- callback.hash ||
30
- !/^[A-Za-z0-9_-]{32,128}$/u.test(parsed.state) ||
51
+ const reveal = parsed.reveal === true;
52
+ const lifetime = reveal
53
+ ? REVEAL_CONFIRMATION_LIFETIME_MS + REVEAL_CLOCK_SKEW_MS
54
+ : 300_000;
55
+ if (!/^[A-Za-z0-9_-]{32,128}$/u.test(parsed.state) ||
31
56
  !Number.isFinite(parsed.expiresAt) ||
32
57
  parsed.expiresAt <= Date.now() ||
33
- parsed.expiresAt > Date.now() + 300_000 ||
58
+ parsed.expiresAt > Date.now() + lifetime ||
34
59
  typeof parsed.organizationId !== "string" ||
35
60
  parsed.organizationId.length > 100 ||
36
- !["GET", "POST"].includes(parsed.method) ||
37
- !/^\/v1\/(?:organization|projects\/[A-Za-z0-9_-]+\/environments\/[A-Za-z0-9_-]+)\/credentials(?:\/[A-Za-z0-9_-]+\/(?:rotate|revoke))?$/u.test(parsed.path) ||
61
+ !["GET", "POST"].includes(parsed.method))
62
+ throw new Error("Invalid or expired credential confirmation.");
63
+ if (reveal) {
64
+ // Nothing leaves the page: no key to encrypt to, no callback to call.
65
+ if (parsed.publicKey !== undefined || parsed.redirectUri !== undefined)
66
+ throw new Error("Invalid or expired credential confirmation.");
67
+ }
68
+ else {
69
+ const callback = new URL(parsed.redirectUri ?? "");
70
+ const key = parsed.publicKey;
71
+ if (parsed.reveal !== undefined ||
72
+ callback.protocol !== "http:" ||
73
+ callback.hostname !== "127.0.0.1" ||
74
+ !callback.port ||
75
+ callback.pathname !== "/callback" ||
76
+ callback.username ||
77
+ callback.password ||
78
+ callback.search ||
79
+ callback.hash ||
80
+ !key ||
81
+ key.kty !== "RSA" ||
82
+ key.e !== "AQAB" ||
83
+ typeof key.n !== "string" ||
84
+ key.n.length !== 342 ||
85
+ key.d !== undefined)
86
+ throw new Error("Invalid or expired credential confirmation.");
87
+ }
88
+ const credential = CREDENTIAL_PATH.test(parsed.path);
89
+ const endpoint = reveal && ENDPOINT_PATH.test(parsed.path);
90
+ if ((!credential && !endpoint) ||
38
91
  (parsed.method === "GET" &&
39
- (parsed.path.endsWith("/rotate") ||
92
+ (endpoint ||
93
+ parsed.path.endsWith("/rotate") ||
40
94
  parsed.path.endsWith("/revoke") ||
41
95
  parsed.body !== undefined)) ||
42
- parsed.publicKey.kty !== "RSA" ||
43
- parsed.publicKey.e !== "AQAB" ||
44
- typeof parsed.publicKey.n !== "string" ||
45
- parsed.publicKey.n.length !== 342 ||
46
- parsed.publicKey.d !== undefined) {
96
+ // An agent hands off a change; reading the inventory is its own tool.
97
+ (reveal && parsed.method === "GET"))
47
98
  throw new Error("Invalid or expired credential confirmation.");
48
- }
49
99
  const organization = parsed.path.startsWith("/v1/organization/");
50
- const validBody = parsed.method === "GET" || parsed.path.endsWith("/revoke")
51
- ? parsed.body === undefined
52
- : parsed.path.endsWith("/rotate")
53
- ? organization
54
- ? validateRotateOrganizationCredentialRequest(parsed.body)
55
- : validateRotateApiCredentialRequest(parsed.body)
56
- : organization
57
- ? validateCreateOrganizationCredentialRequest(parsed.body)
58
- : validateCreateApiCredentialRequest(parsed.body);
100
+ const validBody = endpoint
101
+ ? parsed.path.endsWith("/rotate")
102
+ ? validateRotateCustomerEndpointRequest(parsed.body ?? {})
103
+ : validateCreateCustomerEndpointRequest(parsed.body)
104
+ : parsed.method === "GET" || parsed.path.endsWith("/revoke")
105
+ ? parsed.body === undefined
106
+ : parsed.path.endsWith("/rotate")
107
+ ? organization
108
+ ? validateRotateOrganizationCredentialRequest(parsed.body)
109
+ : validateRotateApiCredentialRequest(parsed.body)
110
+ : organization
111
+ ? validateCreateOrganizationCredentialRequest(parsed.body)
112
+ : validateCreateApiCredentialRequest(parsed.body);
59
113
  if (!validBody ||
60
114
  Object.keys(parsed).some((key) => ![
61
115
  "apiOrigin",
@@ -65,6 +119,7 @@ export function parseCredentialConfirmation(value) {
65
119
  "body",
66
120
  "publicKey",
67
121
  "redirectUri",
122
+ "reveal",
68
123
  "state",
69
124
  "expiresAt",
70
125
  ].includes(key)))
@@ -1 +1 @@
1
- {"version":3,"file":"browser-confirmation.js","sourceRoot":"","sources":["../src/browser-confirmation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-confirmation.js","sourceRoot":"","sources":["../src/browser-confirmation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,2CAA2C,EAC3C,kCAAkC,EAClC,2CAA2C,EAC3C,kCAAkC,EAClC,wCAAwC,EACxC,+BAA+B,EAC/B,0CAA0C,EAC1C,iCAAiC,EACjC,sCAAsC,EACtC,6BAA6B,EAC7B,8BAA8B,EAC9B,qBAAqB,EACrB,qCAAqC,EACrC,qCAAqC,GACtC,MAAM,uBAAuB,CAAC;AAqC/B,kFAAkF;AAClF,MAAM,CAAC,MAAM,+BAA+B,GAAG,EAAE,GAAG,MAAM,CAAC;AAC3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,MAAM,CAAC;AAE/C,MAAM,eAAe,GACnB,uIAAuI,CAAC;AAC1I,MAAM,aAAa,GACjB,kHAAkH,CAAC;AAErH,SAAS,OAAO,CAAC,KAAkB;IACjC,OAAO,IAAI,CACT,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CACzE,EAAE,CACH,CACF;SACE,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;SACpB,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;SACpB,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC;AACD,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,UAAU,CAAC,IAAI,CACpB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EACrD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CACvB,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,2BAA2B,CACzC,KAAa;IAEb,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAA4B,CAAC;IAC5D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAC7B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,OAAO,mBAAmB,CAAC,MAAM,CAA2B,CAAC;AAC/D,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,uBAAuB,CACrC,KAAa;IAEb,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAA4B,CAAC;IAC5D,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;QACxB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,OAAO,mBAAmB,CAAC,MAAM,CAAiC,CAAC;AACrE,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,8BAA8B,CAC5C,KAAa;IAEb,OAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,CAA0B,CAAC,MAAM,KAAK,IAAI;QAChE,CAAC,CAAC,uBAAuB,CAAC,KAAK,CAAC;QAChC,CAAC,CAAC,2BAA2B,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,mBAAmB,CAAC,GAA4B;IACvD,MAAM,MAAM,GAAG,GAWd,CAAC;IACF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtC,IACE,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,SAAS;QAC/B,GAAG,CAAC,QAAQ;QACZ,GAAG,CAAC,QAAQ;QACZ,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ;YACxB,CAAC,CACC,GAAG,CAAC,QAAQ,KAAK,OAAO;gBACxB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAClD,CAAC;QAEJ,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC;IACtC,MAAM,QAAQ,GAAG,MAAM;QACrB,CAAC,CAAC,+BAA+B,GAAG,oBAAoB;QACxD,CAAC,CAAC,OAAO,CAAC;IACZ,IACE,CAAC,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAC9C,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;QAClC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE;QAC9B,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ;QACxC,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ;QACzC,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,GAAG;QAClC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;QAExC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,IAAI,MAAM,EAAE,CAAC;QACX,sEAAsE;QACtE,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS;YACpE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACnE,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC;QAC7B,IACE,MAAM,CAAC,MAAM,KAAK,SAAS;YAC3B,QAAQ,CAAC,QAAQ,KAAK,OAAO;YAC7B,QAAQ,CAAC,QAAQ,KAAK,WAAW;YACjC,CAAC,QAAQ,CAAC,IAAI;YACd,QAAQ,CAAC,QAAQ,KAAK,WAAW;YACjC,QAAQ,CAAC,QAAQ;YACjB,QAAQ,CAAC,QAAQ;YACjB,QAAQ,CAAC,MAAM;YACf,QAAQ,CAAC,IAAI;YACb,CAAC,GAAG;YACJ,GAAG,CAAC,GAAG,KAAK,KAAK;YACjB,GAAG,CAAC,CAAC,KAAK,MAAM;YAChB,OAAO,GAAG,CAAC,CAAC,KAAK,QAAQ;YACzB,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG;YACpB,GAAG,CAAC,CAAC,KAAK,SAAS;YAEnB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3D,IACE,CAAC,CAAC,UAAU,IAAI,CAAC,QAAQ,CAAC;QAC1B,CAAC,MAAM,CAAC,MAAM,KAAK,KAAK;YACtB,CAAC,QAAQ;gBACP,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAC/B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAC/B,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;QAC/B,sEAAsE;QACtE,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,CAAC;QAEnC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,QAAQ;QACxB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YAC/B,CAAC,CAAC,qCAAqC,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YAC1D,CAAC,CAAC,qCAAqC,CAAC,MAAM,CAAC,IAAI,CAAC;QACtD,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YAC1D,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;YAC3B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAC/B,CAAC,CAAC,YAAY;oBACZ,CAAC,CAAC,2CAA2C,CAAC,MAAM,CAAC,IAAI,CAAC;oBAC1D,CAAC,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC;gBACnD,CAAC,CAAC,YAAY;oBACZ,CAAC,CAAC,2CAA2C,CAAC,MAAM,CAAC,IAAI,CAAC;oBAC1D,CAAC,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1D,IACE,CAAC,SAAS;QACV,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CACtB,CAAC,GAAG,EAAE,EAAE,CACN,CAAC;YACC,WAAW;YACX,gBAAgB;YAChB,QAAQ;YACR,MAAM;YACN,MAAM;YACN,WAAW;YACX,aAAa;YACb,QAAQ;YACR,OAAO;YACP,WAAW;SACZ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAClB;QAED,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,SAAqB,EACrB,KAAa,EACb,MAAe;IAEf,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CACvC,KAAK,EACL,SAAS,EACT,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EACrC,KAAK,EACL,CAAC,SAAS,CAAC,CACZ,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CACzC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,EAChC,IAAI,EACJ,CAAC,SAAS,CAAC,CACZ,CAAC;IACF,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC5C,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EACxE,GAAG,EACH,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CACjD,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACzC,UAAU,EACV,GAAG,EACH,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAC1C,CAAC;IACF,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,UAAqB,EACrB,KAAa,EACb,SAAiB;IAEjB,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC;IACxC,IACE,KAAK,CAAC,MAAM,KAAK,CAAC;QAClB,CAAC,OAAO;QACR,CAAC,EAAE;QACH,CAAC,UAAU;QACX,SAAS,CAAC,MAAM,GAAG,MAAM;QAEzB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACxC,UAAU,EACV,UAAU,EACV,OAAO,CAAC,OAAO,CAAC,CACjB,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE;QACzE,SAAS;KACV,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,KAAK,CACf,IAAI,WAAW,EAAE,CAAC,MAAM,CACtB,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACzB;QACE,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;QACf,cAAc,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;KAChD,EACD,GAAG,EACH,OAAO,CAAC,UAAU,CAAC,CACpB,CACF,CACS,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,OAA+B;IAE/B,OAAO,OAAO,CACZ,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CACxB,SAAS,EACT,IAAI,WAAW,EAAE,CAAC,MAAM,CACtB,IAAI,CAAC,SAAS,CAAC;QACb,OAAO,CAAC,SAAS;QACjB,OAAO,CAAC,cAAc;QACtB,OAAO,CAAC,MAAM;QACd,OAAO,CAAC,IAAI;QACZ,OAAO,CAAC,IAAI,IAAI,IAAI;QACpB,OAAO,CAAC,SAAS,CAAC,CAAC;QACnB,OAAO,CAAC,WAAW;QACnB,OAAO,CAAC,KAAK;QACb,OAAO,CAAC,SAAS;KAClB,CAAC,CACH,CACF,CACF,CAAC;AACJ,CAAC;AAQD,MAAM,UAAU,8BAA8B,CAC5C,OAA+B,EAC/B,KAAgC;IAEhC,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC;IACvD,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QACrB,OAAO,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC;IAC3E,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAClE,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;QAC1B,OAAO,CACL,KAAK,CAAC,MAAM,KAAK,GAAG;YACpB,CAAC,YAAY;gBACX,CAAC,CAAC,wCAAwC,CAAC,KAAK,CAAC,IAAI,CAAC;gBACtD,CAAC,CAAC,+BAA+B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CACjD,CAAC;IACJ,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAClC,OAAO,CACL,KAAK,CAAC,MAAM,KAAK,GAAG;YACpB,CAAC,YAAY;gBACX,CAAC,CAAC,8BAA8B,CAAC,KAAK,CAAC,IAAI,CAAC;gBAC5C,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CACvC,CAAC;IACJ,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAClC,OAAO,CACL,KAAK,CAAC,MAAM,KAAK,GAAG;YACpB,CAAC,YAAY;gBACX,CAAC,CAAC,sCAAsC,CAAC,KAAK,CAAC,IAAI,CAAC;gBACpD,CAAC,CAAC,6BAA6B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAC/C,CAAC;IACJ,OAAO,CACL,KAAK,CAAC,MAAM,KAAK,GAAG;QACpB,CAAC,YAAY;YACX,CAAC,CAAC,0CAA0C,CAAC,KAAK,CAAC,IAAI,CAAC;YACxD,CAAC,CAAC,iCAAiC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CACnD,CAAC;AACJ,CAAC"}
package/dist/client.d.ts CHANGED
@@ -319,6 +319,81 @@ export interface TemplateMessageSendResult {
319
319
  readonly layout_locale?: string;
320
320
  };
321
321
  }
322
+ /** A template as its author sees it: the editable draft and the published revision. */
323
+ export interface MessageTemplate extends MessageTemplateCatalogEntry {
324
+ readonly draftVersion: number;
325
+ readonly createdAt?: string;
326
+ readonly updatedAt?: string;
327
+ }
328
+ export interface CreateMessageTemplateRequest {
329
+ readonly name: string;
330
+ readonly display_name: string;
331
+ readonly description?: string;
332
+ readonly category?: string;
333
+ /** Editable draft; complete validation runs at publish. */
334
+ readonly definition: Readonly<Record<string, unknown>>;
335
+ }
336
+ export interface UpdateMessageTemplateRequest {
337
+ readonly name?: string;
338
+ readonly display_name?: string;
339
+ readonly description?: string;
340
+ readonly category?: string;
341
+ readonly disabled?: boolean;
342
+ }
343
+ export interface PublishedTemplateRevision {
344
+ readonly revision: number;
345
+ readonly definition: Readonly<Record<string, unknown>>;
346
+ readonly publishedAt: string;
347
+ readonly publishedBy?: string;
348
+ }
349
+ export interface PreviewMessageTemplateRequest {
350
+ readonly input: Readonly<Record<string, unknown>>;
351
+ /** `default` renders the message every channel falls back to. Omitted means email. */
352
+ readonly channel?: "default" | "generic" | "email" | "telegram" | "slack";
353
+ readonly locale?: string;
354
+ readonly revision?: number;
355
+ /** An unsaved definition to render; cannot be combined with `revision`. */
356
+ readonly definition?: Readonly<Record<string, unknown>>;
357
+ }
358
+ export interface MessageTemplatePreview {
359
+ readonly channel: "default" | "email" | "telegram" | "slack";
360
+ readonly subject?: string;
361
+ readonly html?: string;
362
+ readonly text?: string;
363
+ readonly normalizedInput: Readonly<Record<string, unknown>>;
364
+ readonly templateLocale: string;
365
+ readonly layoutLocale?: string;
366
+ readonly layoutId?: string;
367
+ readonly layoutRevision?: number;
368
+ readonly approximate?: true;
369
+ readonly payload?: Readonly<Record<string, unknown>>;
370
+ }
371
+ export interface DraftTemplateTestSendRequest {
372
+ readonly draft_version: number;
373
+ readonly input: Readonly<Record<string, unknown>>;
374
+ readonly to: {
375
+ readonly subscriber_id: string;
376
+ };
377
+ readonly connection_id?: string;
378
+ readonly notifier_id?: string;
379
+ readonly category_key?: string;
380
+ readonly purpose?: "service" | "marketing";
381
+ readonly correlation_id?: string;
382
+ readonly metadata?: Readonly<Record<string, unknown>>;
383
+ readonly expires_at?: string;
384
+ }
385
+ export interface EmailLayout {
386
+ readonly id: string;
387
+ readonly name: string;
388
+ readonly isDefault: boolean;
389
+ readonly disabled: boolean;
390
+ readonly draft: Readonly<Record<string, unknown>>;
391
+ readonly draftVersion: number;
392
+ readonly latestPublishedRevision: number;
393
+ readonly published?: PublishedTemplateRevision;
394
+ readonly createdAt?: string;
395
+ readonly updatedAt?: string;
396
+ }
322
397
  export declare class WhooshBangClient {
323
398
  #private;
324
399
  whoAmI(projectId: string, environmentId: string, options?: RequestOptions): Promise<WhoAmI>;
@@ -408,6 +483,46 @@ export declare class WhooshBangClient {
408
483
  }, options?: RequestOptions): Promise<MessageTemplateCatalog>;
409
484
  sendTemplateMessage(projectId: string, environmentId: string, request: TemplateMessageSendRequest, options?: SideEffectRequestOptions): Promise<TemplateMessageSendResult>;
410
485
  getMessageTemplate(projectId: string, reference: string, options?: RequestOptions): Promise<MessageTemplateCatalogEntry>;
486
+ /** The template as its author sees it, including the editable draft. */
487
+ getMessageTemplateForAuthoring(projectId: string, reference: string, options?: RequestOptions): Promise<MessageTemplate>;
488
+ /** Every template, drafts and disabled ones included, for authoring. */
489
+ listMessageTemplatesForAuthoring(projectId: string, query?: {
490
+ search?: string;
491
+ category?: string;
492
+ after?: string;
493
+ limit?: number;
494
+ page?: number;
495
+ }, options?: RequestOptions): Promise<Omit<MessageTemplateCatalog, "items"> & {
496
+ readonly items: readonly MessageTemplate[];
497
+ }>;
498
+ createMessageTemplate(projectId: string, request: CreateMessageTemplateRequest, options?: RequestOptions): Promise<MessageTemplate>;
499
+ /** Renames, recategorises, disables or re-enables a template. */
500
+ updateMessageTemplate(projectId: string, templateId: string, request: UpdateMessageTemplateRequest, options?: RequestOptions): Promise<MessageTemplate>;
501
+ /** Replaces the draft. `draftVersion` is the version last read; a newer save refuses this one. */
502
+ saveMessageTemplateDraft(projectId: string, templateId: string, draftVersion: number, definition: Readonly<Record<string, unknown>>, options?: RequestOptions): Promise<MessageTemplate>;
503
+ /** Validates the draft completely and publishes it as the next revision. */
504
+ publishMessageTemplate(projectId: string, templateId: string, draftVersion: number, options?: RequestOptions): Promise<PublishedTemplateRevision>;
505
+ listMessageTemplateRevisions(projectId: string, templateId: string, options?: RequestOptions): Promise<{
506
+ readonly items: readonly PublishedTemplateRevision[];
507
+ }>;
508
+ /** Renders the draft, a revision or an unsaved definition. Nothing is sent. */
509
+ previewMessageTemplate(projectId: string, templateId: string, request: PreviewMessageTemplateRequest, options?: RequestOptions): Promise<MessageTemplatePreview>;
510
+ /** Sends the exact draft to one subscriber as a test. It never publishes. */
511
+ testSendMessageTemplateDraft(projectId: string, environmentId: string, templateId: string, request: DraftTemplateTestSendRequest, options?: SideEffectRequestOptions): Promise<TemplateMessageSendResult>;
512
+ listEmailLayouts(projectId: string, options?: RequestOptions): Promise<{
513
+ readonly items: readonly EmailLayout[];
514
+ }>;
515
+ getEmailLayout(projectId: string, layoutId: string, options?: RequestOptions): Promise<EmailLayout>;
516
+ createEmailLayout(projectId: string, request: {
517
+ readonly name: string;
518
+ readonly definition: Readonly<Record<string, unknown>>;
519
+ }, options?: RequestOptions): Promise<EmailLayout>;
520
+ saveEmailLayoutDraft(projectId: string, layoutId: string, draftVersion: number, definition: Readonly<Record<string, unknown>>, options?: RequestOptions): Promise<EmailLayout>;
521
+ publishEmailLayout(projectId: string, layoutId: string, draftVersion: number, options?: RequestOptions): Promise<PublishedTemplateRevision>;
522
+ /** Makes a published layout the project's default for email templates. */
523
+ setDefaultEmailLayout(projectId: string, layoutId: string, options?: RequestOptions): Promise<{
524
+ readonly default_layout_id: string;
525
+ }>;
411
526
  createMessageCategory(projectId: string, request: CreateMessageCategoryRequest, options?: RequestOptions): Promise<MessageCategory>;
412
527
  updateMessageCategory(projectId: string, key: string, request: UpdateMessageCategoryRequest, options?: RequestOptions): Promise<MessageCategory>;
413
528
  deleteMessageCategory(projectId: string, key: string, options?: RequestOptions): Promise<void>;
package/dist/client.js CHANGED
@@ -80,6 +80,45 @@ function usageQuery(operation, options) {
80
80
  return search.size === 0 ? "" : `?${search.toString()}`;
81
81
  }
82
82
  const templateRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
83
+ function validateAuthoredTemplate(value) {
84
+ return (validateTemplateCatalogEntry(value) &&
85
+ Number.isSafeInteger(value.draftVersion));
86
+ }
87
+ function validatePublishedRevision(value) {
88
+ return (templateRecord(value) &&
89
+ Number.isSafeInteger(value.revision) &&
90
+ templateRecord(value.definition) &&
91
+ typeof value.publishedAt === "string");
92
+ }
93
+ function validateRevisionCollection(value) {
94
+ return (templateRecord(value) &&
95
+ Array.isArray(value.items) &&
96
+ value.items.every((item) => validatePublishedRevision(item)));
97
+ }
98
+ function validateTemplatePreview(value) {
99
+ return (templateRecord(value) &&
100
+ typeof value.channel === "string" &&
101
+ templateRecord(value.normalizedInput) &&
102
+ typeof value.templateLocale === "string");
103
+ }
104
+ function validateEmailLayout(value) {
105
+ return (templateRecord(value) &&
106
+ typeof value.id === "string" &&
107
+ typeof value.name === "string" &&
108
+ typeof value.isDefault === "boolean" &&
109
+ typeof value.disabled === "boolean" &&
110
+ templateRecord(value.draft) &&
111
+ Number.isSafeInteger(value.draftVersion) &&
112
+ Number.isSafeInteger(value.latestPublishedRevision));
113
+ }
114
+ function validateEmailLayoutCollection(value) {
115
+ return (templateRecord(value) &&
116
+ Array.isArray(value.items) &&
117
+ value.items.every((item) => validateEmailLayout(item)));
118
+ }
119
+ function validateDefaultLayout(value) {
120
+ return templateRecord(value) && typeof value.default_layout_id === "string";
121
+ }
83
122
  function validateTemplateCatalog(value) {
84
123
  return (templateRecord(value) &&
85
124
  Array.isArray(value.items) &&
@@ -1477,6 +1516,202 @@ export class WhooshBangClient {
1477
1516
  strictResponse: true,
1478
1517
  });
1479
1518
  }
1519
+ /** The template as its author sees it, including the editable draft. */
1520
+ async getMessageTemplateForAuthoring(projectId, reference, options = {}) {
1521
+ const operation = "getMessageTemplate";
1522
+ return this.#request({
1523
+ method: "GET",
1524
+ operation,
1525
+ options,
1526
+ sideEffect: false,
1527
+ path: `${templateRoot(operation, projectId)}/${pathSegment(operation, reference, "reference")}`,
1528
+ validator: validateAuthoredTemplate,
1529
+ });
1530
+ }
1531
+ /** Every template, drafts and disabled ones included, for authoring. */
1532
+ async listMessageTemplatesForAuthoring(projectId, query = {}, options = {}) {
1533
+ const operation = "listMessageTemplates";
1534
+ const params = new URLSearchParams();
1535
+ if (query.search !== undefined)
1536
+ params.set("search", query.search);
1537
+ if (query.category !== undefined)
1538
+ params.set("category", query.category);
1539
+ if (query.after !== undefined)
1540
+ params.set("after", query.after);
1541
+ if (query.limit !== undefined)
1542
+ params.set("limit", String(query.limit));
1543
+ if (query.page !== undefined)
1544
+ params.set("page", String(query.page));
1545
+ const suffix = params.size === 0 ? "" : `?${params}`;
1546
+ return this.#request({
1547
+ method: "GET",
1548
+ operation,
1549
+ options,
1550
+ sideEffect: false,
1551
+ path: `${templateRoot(operation, projectId)}${suffix}`,
1552
+ validator: (value) => validateTemplateCatalog(value) &&
1553
+ value.items.every((item) => validateAuthoredTemplate(item)),
1554
+ });
1555
+ }
1556
+ async createMessageTemplate(projectId, request, options = {}) {
1557
+ const operation = "createMessageTemplate";
1558
+ return this.#request({
1559
+ body: request,
1560
+ method: "POST",
1561
+ operation,
1562
+ options,
1563
+ sideEffect: true,
1564
+ path: templateRoot(operation, projectId),
1565
+ validator: validateAuthoredTemplate,
1566
+ });
1567
+ }
1568
+ /** Renames, recategorises, disables or re-enables a template. */
1569
+ async updateMessageTemplate(projectId, templateId, request, options = {}) {
1570
+ const operation = "updateMessageTemplateMetadata";
1571
+ return this.#request({
1572
+ body: request,
1573
+ method: "PATCH",
1574
+ operation,
1575
+ options,
1576
+ sideEffect: true,
1577
+ path: `${templateRoot(operation, projectId)}/${pathSegment(operation, templateId, "templateId")}`,
1578
+ validator: validateAuthoredTemplate,
1579
+ });
1580
+ }
1581
+ /** Replaces the draft. `draftVersion` is the version last read; a newer save refuses this one. */
1582
+ async saveMessageTemplateDraft(projectId, templateId, draftVersion, definition, options = {}) {
1583
+ const operation = "saveMessageTemplateDraft";
1584
+ return this.#request({
1585
+ body: { draft_version: draftVersion, definition },
1586
+ method: "PUT",
1587
+ operation,
1588
+ options,
1589
+ sideEffect: true,
1590
+ path: `${templateRoot(operation, projectId)}/${pathSegment(operation, templateId, "templateId")}/draft`,
1591
+ validator: validateAuthoredTemplate,
1592
+ });
1593
+ }
1594
+ /** Validates the draft completely and publishes it as the next revision. */
1595
+ async publishMessageTemplate(projectId, templateId, draftVersion, options = {}) {
1596
+ const operation = "publishMessageTemplate";
1597
+ return this.#request({
1598
+ body: { draft_version: draftVersion },
1599
+ method: "POST",
1600
+ operation,
1601
+ options,
1602
+ sideEffect: true,
1603
+ path: `${templateRoot(operation, projectId)}/${pathSegment(operation, templateId, "templateId")}/publish`,
1604
+ validator: validatePublishedRevision,
1605
+ });
1606
+ }
1607
+ async listMessageTemplateRevisions(projectId, templateId, options = {}) {
1608
+ const operation = "listMessageTemplateRevisions";
1609
+ return this.#request({
1610
+ method: "GET",
1611
+ operation,
1612
+ options,
1613
+ sideEffect: false,
1614
+ path: `${templateRoot(operation, projectId)}/${pathSegment(operation, templateId, "templateId")}/revisions`,
1615
+ validator: validateRevisionCollection,
1616
+ });
1617
+ }
1618
+ /** Renders the draft, a revision or an unsaved definition. Nothing is sent. */
1619
+ async previewMessageTemplate(projectId, templateId, request, options = {}) {
1620
+ const operation = "previewMessageTemplate";
1621
+ return this.#request({
1622
+ body: request,
1623
+ method: "POST",
1624
+ operation,
1625
+ options,
1626
+ sideEffect: false,
1627
+ path: `${templateRoot(operation, projectId)}/${pathSegment(operation, templateId, "templateId")}/preview`,
1628
+ validator: validateTemplatePreview,
1629
+ });
1630
+ }
1631
+ /** Sends the exact draft to one subscriber as a test. It never publishes. */
1632
+ async testSendMessageTemplateDraft(projectId, environmentId, templateId, request, options = {}) {
1633
+ const operation = "testSendMessageTemplateDraft";
1634
+ return this.#request({
1635
+ body: request,
1636
+ method: "POST",
1637
+ operation,
1638
+ options,
1639
+ idempotencyKey: options.idempotencyKey,
1640
+ sideEffect: true,
1641
+ path: `${environmentRoot(operation, projectId, environmentId)}/message-templates/${pathSegment(operation, templateId, "templateId")}/test-send`,
1642
+ validator: validateTemplateMessageSendResult,
1643
+ });
1644
+ }
1645
+ async listEmailLayouts(projectId, options = {}) {
1646
+ const operation = "listEmailLayouts";
1647
+ return this.#request({
1648
+ method: "GET",
1649
+ operation,
1650
+ options,
1651
+ sideEffect: false,
1652
+ path: layoutRoot(operation, projectId),
1653
+ validator: validateEmailLayoutCollection,
1654
+ });
1655
+ }
1656
+ async getEmailLayout(projectId, layoutId, options = {}) {
1657
+ const operation = "getEmailLayout";
1658
+ return this.#request({
1659
+ method: "GET",
1660
+ operation,
1661
+ options,
1662
+ sideEffect: false,
1663
+ path: `${layoutRoot(operation, projectId)}/${pathSegment(operation, layoutId, "layoutId")}`,
1664
+ validator: validateEmailLayout,
1665
+ });
1666
+ }
1667
+ async createEmailLayout(projectId, request, options = {}) {
1668
+ const operation = "createEmailLayout";
1669
+ return this.#request({
1670
+ body: request,
1671
+ method: "POST",
1672
+ operation,
1673
+ options,
1674
+ sideEffect: true,
1675
+ path: layoutRoot(operation, projectId),
1676
+ validator: validateEmailLayout,
1677
+ });
1678
+ }
1679
+ async saveEmailLayoutDraft(projectId, layoutId, draftVersion, definition, options = {}) {
1680
+ const operation = "saveEmailLayoutDraft";
1681
+ return this.#request({
1682
+ body: { draft_version: draftVersion, definition },
1683
+ method: "PUT",
1684
+ operation,
1685
+ options,
1686
+ sideEffect: true,
1687
+ path: `${layoutRoot(operation, projectId)}/${pathSegment(operation, layoutId, "layoutId")}/draft`,
1688
+ validator: validateEmailLayout,
1689
+ });
1690
+ }
1691
+ async publishEmailLayout(projectId, layoutId, draftVersion, options = {}) {
1692
+ const operation = "publishEmailLayout";
1693
+ return this.#request({
1694
+ body: { draft_version: draftVersion },
1695
+ method: "POST",
1696
+ operation,
1697
+ options,
1698
+ sideEffect: true,
1699
+ path: `${layoutRoot(operation, projectId)}/${pathSegment(operation, layoutId, "layoutId")}/publish`,
1700
+ validator: validatePublishedRevision,
1701
+ });
1702
+ }
1703
+ /** Makes a published layout the project's default for email templates. */
1704
+ async setDefaultEmailLayout(projectId, layoutId, options = {}) {
1705
+ const operation = "setDefaultEmailLayout";
1706
+ return this.#request({
1707
+ method: "POST",
1708
+ operation,
1709
+ options,
1710
+ sideEffect: true,
1711
+ path: `${layoutRoot(operation, projectId)}/${pathSegment(operation, layoutId, "layoutId")}/default`,
1712
+ validator: validateDefaultLayout,
1713
+ });
1714
+ }
1480
1715
  async createMessageCategory(projectId, request, options = {}) {
1481
1716
  const operation = "createMessageCategory";
1482
1717
  assertInput(operation, request, validateCreateMessageCategoryRequest);
@@ -4257,6 +4492,12 @@ function environmentRoot(operation, projectId, environmentId) {
4257
4492
  const environment = pathSegment(operation, environmentId, "environmentId");
4258
4493
  return `v1/projects/${project}/environments/${environment}`;
4259
4494
  }
4495
+ function templateRoot(operation, projectId) {
4496
+ return `v1/projects/${pathSegment(operation, projectId, "projectId")}/message-templates`;
4497
+ }
4498
+ function layoutRoot(operation, projectId) {
4499
+ return `v1/projects/${pathSegment(operation, projectId, "projectId")}/email-layouts`;
4500
+ }
4260
4501
  function subscriberGroupPath(operation, root, groupKey) {
4261
4502
  return `${root}/subscriber-groups/${pathSegment(operation, groupKey, "groupKey")}`;
4262
4503
  }