@nauticana/sail 0.8.3 → 0.8.4

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/README.md CHANGED
@@ -1102,6 +1102,78 @@ Expected errors after the upgrade:
1102
1102
 
1103
1103
  v0.8.1 targets **keel v0.8.3**. The shared keel API surface didn't grow in this release; the version pin tracks keel's matching v0.8.x line. See [keel/README.md → Migration Guide](https://github.com/nauticana/keel/blob/main/README.md) for the matching backend changes.
1104
1104
 
1105
+ ## Migrating to v0.8.2 — server-driven OTP resend cooldown
1106
+
1107
+ Additive change. v0.8.1 consumers keep compiling.
1108
+
1109
+ ### What changed
1110
+
1111
+ `OtpResponse` (model/auth.ts) gained an optional `resendCountdownSec?: number` field. keel v0.8.4 populates it from `--otp_ttl_seconds` so the resend timer in `OtpInputComponent` can match the OTP code's actual server-side lifetime instead of relying on the client-side fallback (still 30s for back-compat with older keel deployments / dev mocks that don't return the field).
1112
+
1113
+ ```ts
1114
+ export interface OtpResponse {
1115
+ otpToken: string;
1116
+ resendCountdownSec?: number; // NEW — present when keel >= v0.8.4
1117
+ }
1118
+ ```
1119
+
1120
+ `OtpInputComponent.resendCountdownSec` (input, default 30) is **unchanged**. The recommended pattern is for the page that calls `sendOtp` to capture `res.resendCountdownSec` from the response and pass it to the input so the timer reflects server intent.
1121
+
1122
+ ### Adoption
1123
+
1124
+ Two-step plumbing on the page that owns the OTP screen:
1125
+
1126
+ 1. **Capture from the send response.** After `auth.sendOtp({...}).subscribe(...)`, store `res.resendCountdownSec` in component state and forward it via router state when navigating to the confirm screen.
1127
+
1128
+ ```ts
1129
+ this.auth.sendOtp({ contact, contactType, purpose: 'login' }).subscribe({
1130
+ next: (res) => {
1131
+ this.router.navigate(['/login/confirm'], {
1132
+ state: {
1133
+ otpToken: res.otpToken,
1134
+ contact,
1135
+ resendCountdownSec: res.resendCountdownSec, // forward server value
1136
+ },
1137
+ });
1138
+ },
1139
+ });
1140
+ ```
1141
+
1142
+ 2. **Read on the confirm screen + bind to the input.** Default a local signal to 30 (the legacy fallback) so older keels and the dev OTP mock keep working, then overwrite from router state and from `onResend` responses.
1143
+
1144
+ ```ts
1145
+ readonly resendCountdownSec = signal(30);
1146
+
1147
+ constructor() {
1148
+ const state = this.router.getCurrentNavigation()?.extras.state;
1149
+ if (state && typeof state['resendCountdownSec'] === 'number') {
1150
+ this.resendCountdownSec.set(state['resendCountdownSec']);
1151
+ }
1152
+ }
1153
+
1154
+ onResend() {
1155
+ this.auth.sendOtp({...}).subscribe({
1156
+ next: (res) => {
1157
+ if (typeof res.resendCountdownSec === 'number') {
1158
+ this.resendCountdownSec.set(res.resendCountdownSec);
1159
+ }
1160
+ },
1161
+ });
1162
+ }
1163
+ ```
1164
+
1165
+ ```html
1166
+ <sail-otp-input
1167
+ [contact]="contact()"
1168
+ [resendCountdownSec]="resendCountdownSec()"
1169
+ (codeComplete)="verifyOtp($event)"
1170
+ (resend)="onResend()" />
1171
+ ```
1172
+
1173
+ ### Backend alignment
1174
+
1175
+ v0.8.2 targets **keel v0.8.4**. The new `resendCountdownSec` response field is documented in [keel/README.md → Migration Guide (v0.8.4)](https://github.com/nauticana/keel/blob/main/README.md). Sail will tolerate older keels that don't return the field — the input falls back to its 30s default.
1176
+
1105
1177
  ## Modernization items
1106
1178
 
1107
1179
  When you extend sail in your own app, apply the same patterns sail itself follows. Downstream projects that copied templates or scaffolding from earlier sail versions will benefit from the same sweep. This list is a checklist — none are sail-specific.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nauticana/sail",
3
- "version": "0.8.3",
3
+ "version": "0.8.4",
4
4
  "description": "Metadata-driven Angular component library for CRUD admin frontends backed by the keel Go backend. Tables, forms, navigation, OTP/2FA/social auth, billing, payout onboarding.",
5
5
  "main": "src/index.ts",
6
6
  "files": [
@@ -24,7 +24,13 @@ export class OtpInputComponent implements OnInit {
24
24
 
25
25
  readonly length = input(6);
26
26
  readonly contact = input('');
27
- readonly resendCountdownSec = input(30);
27
+ // Fallback only. Consumers should pass the value returned by
28
+ // /public/otp/send in `resendCountdownSec` on the response — that is
29
+ // the authoritative value (sourced from the keel server's
30
+ // --otp_token_ttl_seconds flag and matches the lifetime of the OTP
31
+ // code itself). 300s is the legacy default, kept so existing callers
32
+ // without the new field don't break.
33
+ readonly resendCountdownSec = input(300);
28
34
  readonly disabled = input(false);
29
35
 
30
36
  readonly codeComplete = output<string>();
package/src/model/auth.ts CHANGED
@@ -80,6 +80,10 @@ export interface OtpRequest {
80
80
  // wrong code.
81
81
  export interface OtpResponse {
82
82
  otpToken: string;
83
+ // Seconds the client should wait before allowing a resend; mirrors
84
+ // the server's --otp_ttl_seconds. Optional for back-compat with
85
+ // older keel versions that didn't return it.
86
+ resendCountdownSec?: number;
83
87
  }
84
88
 
85
89
  export interface OtpVerifyRequest {