@wtfalch/foundry 0.56.0 → 0.57.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.
@@ -2022,7 +2022,7 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
2022
2022
  /** Whether the held keys can store a new company's sign-in database CA and certificate (#746). */
2023
2023
  ownSigninDbKeysPuttable(): boolean;
2024
2024
  /**
2025
- * Whether the host says its company ZITADEL port has `ensureEmailOtpMessageText` and `ensureLabelPolicy`
2025
+ * Whether the host says its company ZITADEL port has `ensureEmailOtpMessageText`, `ensureLabelPolicy` and `ensureEmailOtpGenerator`
2026
2026
  * (`provision.auth.signinMailWritable`). The port is a lazy proxy that answers any name, so it cannot be probed.
2027
2027
  */
2028
2028
  ownSigninMailWritable(): boolean;
@@ -1014,7 +1014,7 @@ export class FoundryStepExecutor {
1014
1014
  return Boolean(this.ports.ownServices?.provision.auth.heldKeys?.put);
1015
1015
  }
1016
1016
  /**
1017
- * Whether the host says its company ZITADEL port has `ensureEmailOtpMessageText` and `ensureLabelPolicy`
1017
+ * Whether the host says its company ZITADEL port has `ensureEmailOtpMessageText`, `ensureLabelPolicy` and `ensureEmailOtpGenerator`
1018
1018
  * (`provision.auth.signinMailWritable`). The port is a lazy proxy that answers any name, so it cannot be probed.
1019
1019
  */
1020
1020
  ownSigninMailWritable() {
@@ -2551,11 +2551,12 @@ export async function provisionAuthStack(scope, deps, target, input) {
2551
2551
  throw new Error(`${label}: could not configure ZITADEL's SMTP provider for ${hostname}: ${cause}`);
2552
2552
  }
2553
2553
  // A company's own sign-in: its name and design in the code mail. Idempotent; the marker is
2554
- // recorded after both writes, so a failure halfway is repeated.
2554
+ // recorded after all three writes, so a failure halfway is repeated.
2555
2555
  if (input.mailBranding &&
2556
2556
  (deps.signinMailWritable !== true ||
2557
2557
  typeof mailZitadel.ensureEmailOtpMessageText !== 'function' ||
2558
- typeof mailZitadel.ensureLabelPolicy !== 'function')) {
2558
+ typeof mailZitadel.ensureLabelPolicy !== 'function' ||
2559
+ typeof mailZitadel.ensureEmailOtpGenerator !== 'function')) {
2559
2560
  console.info(`${label}: the host cannot write message texts, so the sign-in mail keeps ZITADEL's default text`);
2560
2561
  }
2561
2562
  else if (input.mailBranding) {
@@ -2,17 +2,23 @@
2
2
  * The sign-in code mail of a company that runs its own sign-in: the company's name in the sender and
3
3
  * the text, the platform's design tokens for the look. ZITADEL's email-code message is built from the
4
4
  * instance's custom text and label policy; both are written through `PlatformZitadelMailBranding`
5
- * (`@wtfalch/providers` 0.13.0), each only when it differs.
5
+ * (`@wtfalch/providers` 0.14.0), each only when it differs. The code itself (six digits, five minutes)
6
+ * is the instance's email-OTP generator.
6
7
  *
7
8
  * The look: no company declares a design foundry can read (an `OrgTheme` lives in cms and reaches
8
9
  * Agora, Boule and the site as data), so every company gets the login's house colours
9
10
  * (`SIGNIN_MAIL_LABEL_POLICY`). No logo: ZITADEL takes it as a multipart upload the client does not make.
10
11
  */
11
12
  /** Raise it when the text or the look changes, so an applied company plans its sign-in step again. */
12
- export declare const AUTH_SIGNIN_MAIL_VERSION = "1";
13
+ export declare const AUTH_SIGNIN_MAIL_VERSION = "2";
13
14
  /** `signinMailMarker` of the company name and version last written, recorded after both writes. */
14
15
  export declare const PLATFORM_AUTH_SIGNIN_MAIL_SCOPE_KEY = "auth_signin_mail_applied";
15
- /** The two ZITADEL calls the sign-in mail needs. `@wtfalch/providers` 0.13.0's `ZitadelClient` has both. */
16
+ /** The code the mail carries: six digits, valid five minutes (`123-456` in the mail, see `signinMailText`). */
17
+ export declare const SIGNIN_MAIL_CODE: {
18
+ readonly length: 6;
19
+ readonly expirySeconds: 300;
20
+ };
21
+ /** The three ZITADEL calls the sign-in mail needs. `@wtfalch/providers` 0.14.0's `ZitadelClient` has all. */
16
22
  export interface PlatformZitadelMailBranding {
17
23
  ensureEmailOtpMessageText(language: string, text: {
18
24
  title: string;
@@ -38,6 +44,12 @@ export interface PlatformZitadelMailBranding {
38
44
  }): Promise<{
39
45
  changed: boolean;
40
46
  }>;
47
+ ensureEmailOtpGenerator(generator: {
48
+ length: number;
49
+ expirySeconds: number;
50
+ }): Promise<{
51
+ changed: boolean;
52
+ }>;
41
53
  }
42
54
  /** What the marker holds: the version and the company name, so a rename writes the mail again. */
43
55
  export declare function signinMailMarker(companyName: string): string;
@@ -49,7 +61,9 @@ export declare function signinMailName(companyName: string): string;
49
61
  export declare const SIGNIN_MAIL_LANGUAGE = "en";
50
62
  /**
51
63
  * English text. `{{.OTP}}` is the code variable of this message (ZITADEL's `otp.go` sets it; the link
52
- * behind the button carries the code as `{{.Code}}` from the login's `urlTemplate`). No greeting by
64
+ * behind the button carries the code as `{{.Code}}` from the login's `urlTemplate`). The greeting
65
+ * holds the code, split in the middle with Go's `slice` (`123-456`), because ZITADEL renders the
66
+ * greeting as the large heading, so the code is the first thing the reader sees. No greeting by
53
67
  * name: the login fills names from the email address, so it would read "Wtfalch Wtfalch".
54
68
  */
55
69
  export declare function signinMailText(companyName: string): {
@@ -77,7 +91,7 @@ export declare const SIGNIN_MAIL_LABEL_POLICY: {
77
91
  readonly warnColorDark: "#FF9C8C";
78
92
  readonly disableWatermark: true;
79
93
  };
80
- /** Writes the text and the look, each only when it differs. Throws the client's fixed-text error. */
94
+ /** Writes the text, the look and the code, each only when it differs. Throws the client's fixed-text error. */
81
95
  export declare function applySigninMail(zitadel: PlatformZitadelMailBranding, companyName: string): Promise<{
82
96
  changed: boolean;
83
97
  }>;
@@ -2,16 +2,19 @@
2
2
  * The sign-in code mail of a company that runs its own sign-in: the company's name in the sender and
3
3
  * the text, the platform's design tokens for the look. ZITADEL's email-code message is built from the
4
4
  * instance's custom text and label policy; both are written through `PlatformZitadelMailBranding`
5
- * (`@wtfalch/providers` 0.13.0), each only when it differs.
5
+ * (`@wtfalch/providers` 0.14.0), each only when it differs. The code itself (six digits, five minutes)
6
+ * is the instance's email-OTP generator.
6
7
  *
7
8
  * The look: no company declares a design foundry can read (an `OrgTheme` lives in cms and reaches
8
9
  * Agora, Boule and the site as data), so every company gets the login's house colours
9
10
  * (`SIGNIN_MAIL_LABEL_POLICY`). No logo: ZITADEL takes it as a multipart upload the client does not make.
10
11
  */
11
12
  /** Raise it when the text or the look changes, so an applied company plans its sign-in step again. */
12
- export const AUTH_SIGNIN_MAIL_VERSION = '1';
13
+ export const AUTH_SIGNIN_MAIL_VERSION = '2';
13
14
  /** `signinMailMarker` of the company name and version last written, recorded after both writes. */
14
15
  export const PLATFORM_AUTH_SIGNIN_MAIL_SCOPE_KEY = 'auth_signin_mail_applied';
16
+ /** The code the mail carries: six digits, valid five minutes (`123-456` in the mail, see `signinMailText`). */
17
+ export const SIGNIN_MAIL_CODE = { length: 6, expirySeconds: 300 };
15
18
  /** What the marker holds: the version and the company name, so a rename writes the mail again. */
16
19
  export function signinMailMarker(companyName) {
17
20
  return `${AUTH_SIGNIN_MAIL_VERSION}:${signinMailName(companyName)}`;
@@ -30,7 +33,9 @@ export function signinMailName(companyName) {
30
33
  export const SIGNIN_MAIL_LANGUAGE = 'en';
31
34
  /**
32
35
  * English text. `{{.OTP}}` is the code variable of this message (ZITADEL's `otp.go` sets it; the link
33
- * behind the button carries the code as `{{.Code}}` from the login's `urlTemplate`). No greeting by
36
+ * behind the button carries the code as `{{.Code}}` from the login's `urlTemplate`). The greeting
37
+ * holds the code, split in the middle with Go's `slice` (`123-456`), because ZITADEL renders the
38
+ * greeting as the large heading, so the code is the first thing the reader sees. No greeting by
34
39
  * name: the login fills names from the email address, so it would read "Wtfalch Wtfalch".
35
40
  */
36
41
  export function signinMailText(companyName) {
@@ -39,8 +44,8 @@ export function signinMailText(companyName) {
39
44
  title: 'Your sign-in code',
40
45
  preHeader: `Your ${name} sign-in code`,
41
46
  subject: `Your ${name} sign-in code`,
42
- greeting: 'Hello,',
43
- text: 'Your code is {{.OTP}}. It works for five minutes. Or use the button to sign in on this device.',
47
+ greeting: '{{slice .OTP 0 3}}-{{slice .OTP 3}}',
48
+ text: 'Enter this code to sign in. It works for five minutes. Or use the button to sign in on this device.',
44
49
  buttonText: 'Sign in',
45
50
  footerText: name,
46
51
  };
@@ -61,9 +66,10 @@ export const SIGNIN_MAIL_LABEL_POLICY = {
61
66
  warnColorDark: '#FF9C8C',
62
67
  disableWatermark: true,
63
68
  };
64
- /** Writes the text and the look, each only when it differs. Throws the client's fixed-text error. */
69
+ /** Writes the text, the look and the code, each only when it differs. Throws the client's fixed-text error. */
65
70
  export async function applySigninMail(zitadel, companyName) {
66
71
  const text = await zitadel.ensureEmailOtpMessageText(SIGNIN_MAIL_LANGUAGE, signinMailText(companyName));
67
72
  const look = await zitadel.ensureLabelPolicy({ ...SIGNIN_MAIL_LABEL_POLICY });
68
- return { changed: text.changed || look.changed };
73
+ const code = await zitadel.ensureEmailOtpGenerator({ ...SIGNIN_MAIL_CODE });
74
+ return { changed: text.changed || look.changed || code.changed };
69
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wtfalch/foundry",
3
- "version": "0.56.0",
3
+ "version": "0.57.0",
4
4
  "description": "Foundry's SDK: the declared org's types, the plan and apply contracts, and the state store's interface.",
5
5
  "repository": {
6
6
  "type": "git",