@atlasauth/backend 0.8.0 → 0.9.1
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/CHANGELOG.md +22 -0
- package/README.md +147 -0
- package/dist/client/branding.d.ts +20 -0
- package/dist/client/branding.js.map +1 -1
- package/dist/client/diagnostics.d.ts +16 -0
- package/dist/client/diagnostics.js.map +1 -1
- package/dist/client/email-templates.d.ts +1 -1
- package/dist/client/email-templates.js.map +1 -1
- package/dist/client/error.d.ts +10 -0
- package/dist/client/error.js +10 -0
- package/dist/client/error.js.map +1 -1
- package/dist/client/index.d.ts +11 -1
- package/dist/client/instance.d.ts +30 -2
- package/dist/client/instance.js.map +1 -1
- package/dist/client/messaging.d.ts +85 -8
- package/dist/client/messaging.js +19 -1
- package/dist/client/messaging.js.map +1 -1
- package/dist/client/oauth-clients.d.ts +25 -1
- package/dist/client/oauth-clients.js +11 -2
- package/dist/client/oauth-clients.js.map +1 -1
- package/dist/client/platform.d.ts +22 -5
- package/dist/client/platform.js.map +1 -1
- package/dist/client/users.d.ts +15 -0
- package/dist/client/users.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/oidc.d.ts +225 -0
- package/dist/oidc.js +631 -0
- package/dist/oidc.js.map +1 -0
- package/dist/testing.d.ts +90 -1
- package/dist/testing.js +202 -3
- package/dist/testing.js.map +1 -1
- package/dist/verify.d.ts +21 -0
- package/dist/verify.js +20 -0
- package/dist/verify.js.map +1 -1
- package/dist/webhooks.js +32 -7
- package/dist/webhooks.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @atlasauth/backend changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.1
|
|
4
|
+
- **Allowed origins with an integration.** `UpdateInstanceBody.allowed_origins` and the platform app, instance and accountless-app bodies accept `AllowedOriginInput` entries: an origin string or `{ origin, integration }` (`OriginIntegration`: `redirect` | `embedded` | `auto`, or `null` to clear). `Instance`, `InstanceUpdateResult` and `PlatformApp` gain optional `allowed_origin_integrations`. New types: `AllowedOriginEntry`, `AllowedOriginInput`, `OriginIntegration`.
|
|
5
|
+
- **Login readiness.** `LoginReadiness` gains `integration` (`LoginReadinessIntegration`: `assumed`, `source`, `reason`); `LoginReadinessCheck` gains `applies`.
|
|
6
|
+
- **Branding audiences.** `Branding` accepts `audiences` (hint → `BrandingAudience` `{ heading, subheading, logoUrl, primaryColor }`, `null` deletes one); `ResolvedBranding` gains `audiences`. Start a hosted sign-in with `audienceHint` (or `audience_hint` on the URL) to use one.
|
|
7
|
+
- **Error codes.** `AtlasErrorCodes` adds `READ_ONLY_FIELD`, `DEVELOPMENT_EMAIL_NOT_ALLOWED`, `DEVELOPMENT_EMAIL_UNAVAILABLE`, `DEVELOPMENT_EMAIL_LIMIT_REACHED` and `DEVELOPMENT_EMAIL_TEMPLATE_NOT_ALLOWED`.
|
|
8
|
+
- **Webhooks, several signatures.** `verifyWebhook` accepts an `atlas-signature` header with several space-separated `v1,<signature>` entries and verifies when any one matches (each compared in constant time). This prepares for webhook secret rotation with an overlap. A header with a single signature works as before.
|
|
9
|
+
- **Compatible.** New types, optional fields and error codes only; a single-signature webhook header verifies as before.
|
|
10
|
+
|
|
11
|
+
## 0.9.0
|
|
12
|
+
- **OIDC relying party.** New `oidc` namespace and standalone functions for the hosted-redirect sign-in: `oidcStart` (`oidc.start`), `oidcCallback` (`oidc.callback`), `oidcLogoutUrl` (`oidc.logoutUrl`), `oidcVerifyIdToken` (`oidc.verifyIdToken`), `oidcClearCookie` (`oidc.clearCookie`). `start({ issuer, clientId, redirectUri, scope?, prompt?, loginHint?, audienceHint?, extraParams?, cookieName?, secret? })` returns `{ url, cookie, state, nonce }`: a PKCE (S256) authorize URL from discovery and a `Set-Cookie` for a 10-minute, httpOnly, `SameSite=Lax`, callback-path flow cookie, AES-GCM sealed when `secret` is set. `callback({ …, clientSecret?, clientAuth?: 'client_secret_basic' | 'client_secret_post' | 'none', query, cookie, secret?, clockToleranceSec? })` returns `OidcIdentity` (`sub`, `namespacedSub` = `${issuer}#${sub}`, `email`, `emailVerified`, `name`, `idToken`, `accessToken`, `refreshToken?`, `expiresAt` in epoch ms, `claims`, `clearCookie`). The ID token is verified with RS256 pinned, exact `iss`, `aud` containing the client id (and `azp` when present or when there are several audiences), `nonce`, `exp`/`iat` with tolerance, and `at_hash`. Discovery is cached per issuer for an hour.
|
|
13
|
+
- **Errors.** `AtlasOidcError` with `code` (`AtlasOidcErrorCode`: `state_mismatch`, `issuer_mismatch`, `invalid_request`, `invalid_token`, `token_exchange_failed`, `access_denied`, `discovery_failed`), `oauthError`, `description`, `status`, `clearCookie` and `cause`.
|
|
14
|
+
- **`AtlasBackend#oidc`.** The same helpers with the backend's `issuer`, `fetchImpl` and `now` filled in (`AtlasBackendOidc`).
|
|
15
|
+
- **Test issuer.** `createTestIssuer` accepts `clientId`, `clientSecret` and `idTokenTtlSeconds`, and the returned `TestIssuer` gains `clientId`, `mintIdToken(claims?, { aud?, nonce?, accessToken?, ttlSeconds?, tamper? })`, `authorize(authorizeUrl, { sub?, claims?, tamper?, error? })`, `fetch` (an offline discovery, JWKS and token endpoint) and `endpoints`. `mintSession(claims?, { tamper? })` accepts a tamper too. `TestTokenTamper` is `wrong_aud`, `wrong_iss`, `foreign_key`, `expired`, `wrong_nonce` or `alg_none`; `TEST_TOKEN_TAMPERS` lists all six. New types: `MintIdTokenOptions`, `TestAuthorizeOptions`, `TestAuthorizeResult`.
|
|
16
|
+
- **OAuth client secret rotation with overlap.** `oauthClients.rotateSecret(id, { overlap_seconds? }, idempotencyKey?)` takes how long the previous secret keeps working: default 86400 (24 hours), `0` revokes it now, at most 604800 (7 days). It returns `OAuthClientSecretRotation` (`client_secret`, `overlap_seconds`, `previous_secret_expires_at`: epoch ms, or null when the old secret already stopped working). New type `RotateOAuthClientSecretBody`. `OAuthClient` gains optional `previous_secret_expires_at`.
|
|
17
|
+
- **Issuer and verification endpoints.** `Instance` (`instance.get()`) and the platform client's `PlatformApp` gain `issuer`, `discovery_url` and `jwks_uri`; `PlatformApp` also gains `frontend_api_host`. They change when a custom domain goes active, so read them rather than hard-coding them.
|
|
18
|
+
- **Email verification.** `EmailAddress` gains optional `verification` (`{ status: 'verified' | 'unverified', strategy?: string | null }`). `verified` and `email_verified` are now true only for a proven address: one that signed up while `requireEmailVerification` was false reads `verified: false`, with `verification.strategy: 'skipped'`. Do not grant access on an unverified address.
|
|
19
|
+
- **Email templates.** `EmailTemplateName` adds `account_secured` (variable `when`): sent when the owner of an address proves it and the account is secured from whoever had set it up without proof.
|
|
20
|
+
- **Managed email uses your own provider account.** `messaging.managedEmail.create` now sets the domain up on YOUR Resend or Brevo account: `CreateManagedEmailBody` gains `transport` (`resend` | `brevo`) + `config.api_key`, or `provider_id`. `ManagedEmail` gains `backend`, `provider_id` and `feedback_webhook`; `limits` is now always `null` and `reputation` is `your_provider_account`. `DeletedManagedEmail` gains `provider_removed`. `ManagedEmailRecord.purpose` adds `ownership` and `dmarc`.
|
|
21
|
+
- **Development email sender.** New `messaging.developmentEmail.get / enable / disable` (`DevelopmentEmail`, `EnableDevelopmentEmailBody`): your own email provider in development mode, for a development instance without a verified domain. `MessagingProviders` gains `development_email`.
|
|
22
|
+
- **Provider mode.** Email provider bodies accept `mode` (`standard` | `development`); provider responses gain optional `id` and `mode` (`standard` | `development` | `managed_domain`).
|
|
23
|
+
- **Compatible** except `ManagedEmail.limits` (was `{ hourly, daily }`, now `null`) and `ManagedEmail.reputation` (new constant). Everything else is new exports, optional parameters and fields; `rotateSecret(id)` behaves as before.
|
|
24
|
+
|
|
3
25
|
## 0.8.0
|
|
4
26
|
- **Back-channel logout, retryable failures.** A failed `LogoutTokenResult` gains `retryable: boolean`. It is `true` for `no_keys` (the issuer's keys could not be fetched: a network error, a JWKS outage, or a just-rotated key whose refetch failed) and `false` for `malformed`, `invalid` and `replayed`. Answer `503` with `Retry-After` when it is true, so Atlas retries the delivery, and `400` otherwise. The README example does this.
|
|
5
27
|
- **Back-channel delivery log and test.** `oauthClients.listBackchannelDeliveries(id, { limit?, starting_after? })` returns `BackchannelLogoutDeliveryPage` (`BackchannelLogoutDelivery`: `status`, `http_status`, `latency_ms`, `attempt_number`, `error`, `location`, `test`, timestamps). `oauthClients.testBackchannelLogout(id)` returns `BackchannelLogoutTest` (`ok`, `status`, `latency_ms`, `error`, `location`, `blocked_reason`, `body_excerpt`, `sid`, `delivery_id`). The platform client's `atlasIdApps` gains the same two methods plus `preflight(id)` (`AtlasIdAppPreflight`).
|
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Server-side Atlas for Node, Deno, Bun and edge runtimes. It does three things:
|
|
4
4
|
|
|
5
5
|
- verifies Atlas session tokens, webhooks and back-channel logout tokens
|
|
6
|
+
- runs the server side of a hosted-redirect (OpenID Connect) sign-in
|
|
6
7
|
- gives you a typed client for the Backend API, using your secret key (`sk_...`)
|
|
7
8
|
- gives you a typed client for the Platform API, using your platform key (`psk_...`)
|
|
8
9
|
|
|
@@ -24,6 +25,150 @@ if (result.ok) console.log(result.claims.sub);
|
|
|
24
25
|
|
|
25
26
|
The JWKS is found from the issuer and cached. Instances on the shared host also pass `instanceId` (or `publishableKey`).
|
|
26
27
|
|
|
28
|
+
## Sign in with a redirect (OpenID Connect)
|
|
29
|
+
|
|
30
|
+
`oidc` runs the relying-party side of the hosted-redirect integration: state, nonce and PKCE, the flow cookie, the code exchange and the ID-token checks (RS256 only, `iss`, `aud` = your client id, `nonce`, `exp`).
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { oidc, AtlasOidcError } from '@atlasauth/backend';
|
|
34
|
+
|
|
35
|
+
const config = {
|
|
36
|
+
issuer: 'https://bright-fox-42-fapi.atlasauth.net', // https:// + frontend_api_host
|
|
37
|
+
clientId: process.env.ATLAS_CLIENT_ID!,
|
|
38
|
+
redirectUri: 'https://app.example.com/auth/callback',
|
|
39
|
+
secret: process.env.OIDC_COOKIE_SECRET!, // 32+ random characters; seals the flow cookie
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Start: set the flow cookie, redirect.
|
|
43
|
+
const { url, cookie } = await oidc.start({ ...config, scope: 'openid profile email' });
|
|
44
|
+
|
|
45
|
+
// Callback: one call does every check.
|
|
46
|
+
const identity = await oidc.callback({
|
|
47
|
+
...config,
|
|
48
|
+
clientSecret: process.env.ATLAS_CLIENT_SECRET!,
|
|
49
|
+
query: request.url, // or URLSearchParams, or req.query
|
|
50
|
+
cookie: request.headers.get('cookie'),
|
|
51
|
+
});
|
|
52
|
+
// identity: { sub, namespacedSub, email, emailVerified, name, idToken, accessToken, refreshToken?, expiresAt, claims, clearCookie }
|
|
53
|
+
|
|
54
|
+
// Sign out: end your session, then end the Atlas one.
|
|
55
|
+
const logout = await oidc.logoutUrl({ ...config, postLogoutRedirectUri: 'https://app.example.com/', idTokenHint });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- The flow cookie is `httpOnly`, `SameSite=Lax`, `Secure` (except on a `http://localhost` callback), scoped to the callback path, and lasts 10 minutes. With `secret` it is encrypted (AES-GCM), so it can't be read or forged. Without `secret` it is only encoded. Always pass one in production.
|
|
59
|
+
- `namespacedSub` is `${issuer}#${sub}`. Key users on it if you accept more than one instance, so two instances' users never collide.
|
|
60
|
+
- `clientAuth` is `client_secret_basic` (default with a secret), `client_secret_post`, or `none` (public client, PKCE only).
|
|
61
|
+
- `new AtlasBackend({ issuer }).oidc` has the same methods with `issuer` filled in.
|
|
62
|
+
- Did your own code exchange? `oidc.verifyIdToken(idToken, { issuer, clientId, nonce })` runs just the token checks.
|
|
63
|
+
|
|
64
|
+
Failures throw `AtlasOidcError` with a stable `code`:
|
|
65
|
+
|
|
66
|
+
| `code` | Meaning |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `state_mismatch` | No flow cookie, a different `state`, a cookie from another sign-in or secret, or a flow older than 10 minutes. Start again. |
|
|
69
|
+
| `access_denied` | Atlas redirected back with an OAuth `error`. The exact value is in `oauthError` (`access_denied`, `login_required`, …). |
|
|
70
|
+
| `issuer_mismatch` | The callback's `iss` parameter names a different server. |
|
|
71
|
+
| `invalid_request` | The callback has no `code`. |
|
|
72
|
+
| `token_exchange_failed` | The token endpoint refused the code or client (`oauthError`, `status`). |
|
|
73
|
+
| `invalid_token` | The ID token failed a check: algorithm, signature, `iss`, `aud`/`azp`, `nonce`, `exp`/`iat` or `at_hash`. |
|
|
74
|
+
| `discovery_failed` | The discovery document or the signing keys could not be fetched or don't match the issuer. |
|
|
75
|
+
|
|
76
|
+
Every error from `callback` carries `clearCookie`: send it with your error page too.
|
|
77
|
+
|
|
78
|
+
### Next.js (App Router)
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
// app/auth/login/route.ts
|
|
82
|
+
import { oidc } from '@atlasauth/backend';
|
|
83
|
+
import { config } from '@/lib/atlas';
|
|
84
|
+
|
|
85
|
+
export async function GET() {
|
|
86
|
+
const { url, cookie } = await oidc.start(config);
|
|
87
|
+
return new Response(null, { status: 302, headers: { location: url, 'set-cookie': cookie } });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// app/auth/callback/route.ts
|
|
91
|
+
import { oidc, AtlasOidcError } from '@atlasauth/backend';
|
|
92
|
+
import { config } from '@/lib/atlas';
|
|
93
|
+
|
|
94
|
+
export async function GET(request: Request) {
|
|
95
|
+
try {
|
|
96
|
+
const user = await oidc.callback({
|
|
97
|
+
...config,
|
|
98
|
+
clientSecret: process.env.ATLAS_CLIENT_SECRET!,
|
|
99
|
+
query: request.url,
|
|
100
|
+
cookie: request.headers.get('cookie'),
|
|
101
|
+
});
|
|
102
|
+
const headers = new Headers({ location: '/' });
|
|
103
|
+
headers.append('set-cookie', user.clearCookie);
|
|
104
|
+
headers.append('set-cookie', await createAppSession(user)); // your own session cookie
|
|
105
|
+
return new Response(null, { status: 302, headers });
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (!(error instanceof AtlasOidcError)) throw error;
|
|
108
|
+
return new Response(`Sign-in failed (${error.code})`, {
|
|
109
|
+
status: 400,
|
|
110
|
+
headers: error.clearCookie ? { 'set-cookie': error.clearCookie } : {},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Express
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import express from 'express';
|
|
120
|
+
import { oidc, AtlasOidcError } from '@atlasauth/backend';
|
|
121
|
+
|
|
122
|
+
const app = express();
|
|
123
|
+
|
|
124
|
+
app.get('/auth/login', async (req, res) => {
|
|
125
|
+
const { url, cookie } = await oidc.start(config);
|
|
126
|
+
res.append('Set-Cookie', cookie).redirect(url);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
app.get('/auth/callback', async (req, res) => {
|
|
130
|
+
try {
|
|
131
|
+
const user = await oidc.callback({
|
|
132
|
+
...config,
|
|
133
|
+
clientSecret: process.env.ATLAS_CLIENT_SECRET!,
|
|
134
|
+
query: req.originalUrl,
|
|
135
|
+
cookie: req.headers.cookie,
|
|
136
|
+
});
|
|
137
|
+
res.append('Set-Cookie', user.clearCookie);
|
|
138
|
+
await startYourSession(req, res, user.namespacedSub);
|
|
139
|
+
res.redirect('/');
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (!(error instanceof AtlasOidcError)) throw error;
|
|
142
|
+
if (error.clearCookie) res.append('Set-Cookie', error.clearCookie);
|
|
143
|
+
res.status(400).send(`Sign-in failed (${error.code})`);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Test offline
|
|
149
|
+
|
|
150
|
+
`createTestIssuer()` mints session tokens and ID tokens with a throwaway key, and its `fetch` serves discovery, the JWKS and a token endpoint, so a full redirect sign-in runs in a unit test with no network.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { createTestIssuer, oidc, TEST_TOKEN_TAMPERS } from '@atlasauth/backend';
|
|
154
|
+
|
|
155
|
+
const fx = await createTestIssuer({ clientSecret: 'test-secret' });
|
|
156
|
+
const config = { issuer: fx.issuer, clientId: fx.clientId, redirectUri: 'https://app.example.com/auth/callback', secret: '…32+ chars…', fetchImpl: fx.fetch };
|
|
157
|
+
|
|
158
|
+
const { url, cookie } = await oidc.start(config);
|
|
159
|
+
const { callbackUrl } = await fx.authorize(url, { sub: 'user_1', claims: { email: 'a@example.com', email_verified: true } });
|
|
160
|
+
const user = await oidc.callback({ ...config, clientSecret: 'test-secret', query: callbackUrl, cookie });
|
|
161
|
+
|
|
162
|
+
// Negative cases: wrong_aud, wrong_iss, foreign_key, expired, wrong_nonce, alg_none.
|
|
163
|
+
for (const tamper of TEST_TOKEN_TAMPERS) {
|
|
164
|
+
const { url, cookie } = await oidc.start(config);
|
|
165
|
+
const { callbackUrl } = await fx.authorize(url, { tamper });
|
|
166
|
+
await expect(oidc.callback({ ...config, clientSecret: 'test-secret', query: callbackUrl, cookie })).rejects.toMatchObject({ code: 'invalid_token' });
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`fx.mintIdToken(claims, { aud, nonce, tamper })` and `fx.mintSession(claims, { tamper })` mint single tokens. `@atlasauth/testing` re-exports `createTestIssuer`.
|
|
171
|
+
|
|
27
172
|
## Management client (secret key)
|
|
28
173
|
|
|
29
174
|
```ts
|
|
@@ -254,3 +399,5 @@ To check the route end to end, `oauthClients.testBackchannelLogout(id)` sends a
|
|
|
254
399
|
## Webhooks
|
|
255
400
|
|
|
256
401
|
`verifyWebhook` checks the signature on events Atlas sends to your webhook endpoints. You manage endpoints with `atlas.webhooks.endpoints`: create, update, reveal or rotate a secret, send a test event, and redeliver a past delivery.
|
|
402
|
+
|
|
403
|
+
The `atlas-signature` header can carry more than one signature, separated by spaces (`v1,<sig> v1,<sig>`). While an endpoint secret rotates, Atlas may sign each delivery with the old and the new secret. `verifyWebhook` accepts the delivery when any one signature matches your secret.
|
|
@@ -51,6 +51,13 @@ export interface Branding {
|
|
|
51
51
|
};
|
|
52
52
|
/** How a verification code is entered — segmented `boxes` (default) or `single`. */
|
|
53
53
|
codeInput?: 'boxes' | 'single';
|
|
54
|
+
/**
|
|
55
|
+
* Per-audience branding for the hosted pages, keyed by audience hint
|
|
56
|
+
* (`[a-z0-9_-]{1,32}`, at most 20). A sign-in started with
|
|
57
|
+
* `audience_hint=<hint>` uses that entry. An update merges per hint: an entry
|
|
58
|
+
* replaces that hint, `null` deletes it, `audiences: null` removes them all.
|
|
59
|
+
*/
|
|
60
|
+
audiences?: Record<string, BrandingAudience | null> | null;
|
|
54
61
|
card?: {
|
|
55
62
|
width?: 'narrow' | 'default' | 'wide';
|
|
56
63
|
align?: 'left' | 'center';
|
|
@@ -108,6 +115,17 @@ export interface HostedBackground {
|
|
|
108
115
|
angle?: number;
|
|
109
116
|
imageUrl?: string;
|
|
110
117
|
}
|
|
118
|
+
/** The hosted-page branding for one audience hint. */
|
|
119
|
+
export interface BrandingAudience {
|
|
120
|
+
/** Replaces the card heading (up to 120 characters). */
|
|
121
|
+
heading?: string;
|
|
122
|
+
/** Replaces the line under the heading (up to 240 characters). */
|
|
123
|
+
subheading?: string;
|
|
124
|
+
/** Replaces the logo (https). */
|
|
125
|
+
logoUrl?: string;
|
|
126
|
+
/** Replaces the primary colour (hex, rgb() or a CSS colour name). */
|
|
127
|
+
primaryColor?: string;
|
|
128
|
+
}
|
|
111
129
|
/** What the renderers actually use — everything already escaped or dropped. */
|
|
112
130
|
export interface ResolvedBranding {
|
|
113
131
|
applicationName: string;
|
|
@@ -137,6 +155,8 @@ export interface ResolvedBranding {
|
|
|
137
155
|
providerHidden?: string[];
|
|
138
156
|
socialButtons?: Record<string, unknown>;
|
|
139
157
|
codeInput?: 'boxes' | 'single';
|
|
158
|
+
/** Every audience the hosted page can theme for, as it reads them (invalid values dropped). */
|
|
159
|
+
audiences?: Record<string, BrandingAudience>;
|
|
140
160
|
card?: {
|
|
141
161
|
width: string;
|
|
142
162
|
align: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branding.js","sourceRoot":"","sources":["../../src/client/branding.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"branding.js","sourceRoot":"","sources":["../../src/client/branding.ts"],"names":[],"mappings":";;AAuMA,4CAcC;AAdD,SAAgB,gBAAgB,CAAC,OAAkB;IACjD,OAAO;QACL,GAAG;YACD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,kEAAkE;QAClE,MAAM,CAAC,IAAuB;YAC5B,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,0EAA0E;QAC1E,OAAO,CAAC,IAAuB;YAC7B,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -8,6 +8,11 @@ export interface LoginReadinessParams {
|
|
|
8
8
|
export interface LoginReadinessCheck {
|
|
9
9
|
name: string;
|
|
10
10
|
pass: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* `false` when the check does not matter for the assumed integration (it
|
|
13
|
+
* then never makes `ready` false). Absent from older servers.
|
|
14
|
+
*/
|
|
15
|
+
applies?: boolean;
|
|
11
16
|
observed: unknown;
|
|
12
17
|
/** What was seen, and the fix when it fails. */
|
|
13
18
|
detail: string;
|
|
@@ -17,9 +22,20 @@ export interface LoginReadiness {
|
|
|
17
22
|
origin: string;
|
|
18
23
|
live: boolean;
|
|
19
24
|
data_region?: string | null;
|
|
25
|
+
/** Every check that applies to the assumed integration passes. */
|
|
20
26
|
ready: boolean;
|
|
27
|
+
/** The integration the checks assumed for this origin, and why. */
|
|
28
|
+
integration?: LoginReadinessIntegration;
|
|
21
29
|
checks: LoginReadinessCheck[];
|
|
22
30
|
}
|
|
31
|
+
export interface LoginReadinessIntegration {
|
|
32
|
+
/** `redirect`: hosted-redirect OIDC, so the `cors` and `session_cookie` checks do not apply. */
|
|
33
|
+
assumed: 'redirect' | 'embedded';
|
|
34
|
+
/** `declared` | `embedded_traffic` | `redirect_clients` | `default`. */
|
|
35
|
+
source: 'declared' | 'embedded_traffic' | 'redirect_clients' | 'default';
|
|
36
|
+
/** A plain sentence saying why. */
|
|
37
|
+
reason: string;
|
|
38
|
+
}
|
|
23
39
|
export interface RequestInspectorParams {
|
|
24
40
|
/** The browser origin making the request. */
|
|
25
41
|
origin: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/client/diagnostics.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/client/diagnostics.ts"],"names":[],"mappings":";;AAuEA,kDAmBC;AAnBD,SAAgB,mBAAmB,CAAC,OAAkB;IACpD,OAAO;QACL,yGAAyG;QACzG,cAAc,CAAC,MAA4B;YACzC,OAAO,OAAO,CAAC;gBACb,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,iCAAiC;gBACvC,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;aACpD,CAAC,CAAC;QACL,CAAC;QACD,uFAAuF;QACvF,gBAAgB,CAAC,MAA8B;YAC7C,OAAO,OAAO,CAAC;gBACb,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,mCAAmC;gBACzC,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE;aACrB,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type RequestFn } from './request';
|
|
2
2
|
import type { ListPage } from './types';
|
|
3
3
|
/** The transactional email a template drives. */
|
|
4
|
-
export type EmailTemplateName = 'verification_code' | 'magic_link' | 'password_reset' | 'password_changed' | 'account_exists_notice' | 'organization_invitation' | 'new_device_sign_in' | 'session_revoked_token_reuse' | 'account_locked' | 'team_member_added' | 'team_role_changed';
|
|
4
|
+
export type EmailTemplateName = 'verification_code' | 'magic_link' | 'password_reset' | 'password_changed' | 'account_exists_notice' | 'organization_invitation' | 'new_device_sign_in' | 'session_revoked_token_reuse' | 'account_locked' | 'account_secured' | 'team_member_added' | 'team_role_changed';
|
|
5
5
|
/** The customizable body of a template: a subject line and a text body. */
|
|
6
6
|
export interface EmailTemplateBody {
|
|
7
7
|
subject?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-templates.js","sourceRoot":"","sources":["../../src/client/email-templates.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"email-templates.js","sourceRoot":"","sources":["../../src/client/email-templates.ts"],"names":[],"mappings":";;AAyDA,wDAkBC;AA3ED,uCAAgD;AAyDhD,SAAgB,sBAAsB,CAAC,OAAkB;IACvD,OAAO;QACL,IAAI;YACF,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,2EAA2E;QAC3E,OAAO,CAAC,IAAY,EAAE,OAA0B,EAAE;YAChD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,IAAA,aAAG,EAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7F,CAAC;QACD,2DAA2D;QAC3D,MAAM,CAAC,IAAY,EAAE,IAAuB;YAC1C,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,uBAAuB,IAAA,aAAG,EAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,CAAC;QACD,8BAA8B;QAC9B,MAAM,CAAC,IAAY;YACjB,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,uBAAuB,IAAA,aAAG,EAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACjF,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/client/error.d.ts
CHANGED
|
@@ -47,6 +47,16 @@ export declare const AtlasErrorCodes: {
|
|
|
47
47
|
readonly CAPTCHA_IN_USE: "CAPTCHA_IN_USE";
|
|
48
48
|
/** Strict mode: the body had a field this endpoint does not accept (`param` names it). */
|
|
49
49
|
readonly UNKNOWN_FIELD: "UNKNOWN_FIELD";
|
|
50
|
+
/** 422 — the body set a field that is not writable on this endpoint (`param` names it; the message names the call that changes it). */
|
|
51
|
+
readonly READ_ONLY_FIELD: "READ_ONLY_FIELD";
|
|
52
|
+
/** 409 — the development email sender is not available on a production instance. */
|
|
53
|
+
readonly DEVELOPMENT_EMAIL_NOT_ALLOWED: "DEVELOPMENT_EMAIL_NOT_ALLOWED";
|
|
54
|
+
/** 503 — the development email sender is not available on this deployment. */
|
|
55
|
+
readonly DEVELOPMENT_EMAIL_UNAVAILABLE: "DEVELOPMENT_EMAIL_UNAVAILABLE";
|
|
56
|
+
/** 429 — the development sender's daily or per-recipient hourly cap is spent (`meta.window`, `meta.retry_after_seconds`). */
|
|
57
|
+
readonly DEVELOPMENT_EMAIL_LIMIT_REACHED: "DEVELOPMENT_EMAIL_LIMIT_REACHED";
|
|
58
|
+
/** 422 — the development sender sends only Atlas's own sign-in emails, never custom templates. */
|
|
59
|
+
readonly DEVELOPMENT_EMAIL_TEMPLATE_NOT_ALLOWED: "DEVELOPMENT_EMAIL_TEMPLATE_NOT_ALLOWED";
|
|
50
60
|
/** The billing plan still has subscribers and cannot be removed. */
|
|
51
61
|
readonly PLAN_IN_USE: "PLAN_IN_USE";
|
|
52
62
|
/** The key is valid but for another API surface (e.g. a platform key on the Backend API). */
|
package/dist/client/error.js
CHANGED
|
@@ -43,6 +43,16 @@ exports.AtlasErrorCodes = {
|
|
|
43
43
|
CAPTCHA_IN_USE: 'CAPTCHA_IN_USE',
|
|
44
44
|
/** Strict mode: the body had a field this endpoint does not accept (`param` names it). */
|
|
45
45
|
UNKNOWN_FIELD: 'UNKNOWN_FIELD',
|
|
46
|
+
/** 422 — the body set a field that is not writable on this endpoint (`param` names it; the message names the call that changes it). */
|
|
47
|
+
READ_ONLY_FIELD: 'READ_ONLY_FIELD',
|
|
48
|
+
/** 409 — the development email sender is not available on a production instance. */
|
|
49
|
+
DEVELOPMENT_EMAIL_NOT_ALLOWED: 'DEVELOPMENT_EMAIL_NOT_ALLOWED',
|
|
50
|
+
/** 503 — the development email sender is not available on this deployment. */
|
|
51
|
+
DEVELOPMENT_EMAIL_UNAVAILABLE: 'DEVELOPMENT_EMAIL_UNAVAILABLE',
|
|
52
|
+
/** 429 — the development sender's daily or per-recipient hourly cap is spent (`meta.window`, `meta.retry_after_seconds`). */
|
|
53
|
+
DEVELOPMENT_EMAIL_LIMIT_REACHED: 'DEVELOPMENT_EMAIL_LIMIT_REACHED',
|
|
54
|
+
/** 422 — the development sender sends only Atlas's own sign-in emails, never custom templates. */
|
|
55
|
+
DEVELOPMENT_EMAIL_TEMPLATE_NOT_ALLOWED: 'DEVELOPMENT_EMAIL_TEMPLATE_NOT_ALLOWED',
|
|
46
56
|
/** The billing plan still has subscribers and cannot be removed. */
|
|
47
57
|
PLAN_IN_USE: 'PLAN_IN_USE',
|
|
48
58
|
/** The key is valid but for another API surface (e.g. a platform key on the Backend API). */
|
package/dist/client/error.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/client/error.ts"],"names":[],"mappings":";;;AAoBA,MAAa,aAAc,SAAQ,KAAK;IACpB,IAAI,GAAG,eAAe,CAAC;IACzC,0CAA0C;IACjC,MAAM,CAAS;IACxB,8CAA8C;IACrC,MAAM,CAAmB;IAElC,YAAY,MAAc,EAAE,MAAwB,EAAE,OAAgB;QACpE,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,wCAAwC,MAAM,EAAE,CAAC,CAAC;QACzF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,uEAAuE;QACvE,sEAAsE;QACtE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,uEAAuE;IACvE,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IAC9B,CAAC;IAED,yEAAyE;IACzE,OAAO,CAAC,IAAY;QAClB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAClD,CAAC;CACF;AAzBD,sCAyBC;AAED;;;;GAIG;AACU,QAAA,eAAe,GAAG;IAC7B,+EAA+E;IAC/E,6BAA6B,EAAE,+BAA+B;IAC9D,mEAAmE;IACnE,uBAAuB,EAAE,yBAAyB;IAClD,oGAAoG;IACpG,qBAAqB,EAAE,uBAAuB;IAC9C,oGAAoG;IACpG,qBAAqB,EAAE,uBAAuB;IAC9C,wGAAwG;IACxG,cAAc,EAAE,gBAAgB;IAChC,0FAA0F;IAC1F,aAAa,EAAE,eAAe;IAC9B,oEAAoE;IACpE,WAAW,EAAE,aAAa;IAC1B,6FAA6F;IAC7F,iBAAiB,EAAE,mBAAmB;IACtC,gDAAgD;IAChD,WAAW,EAAE,aAAa;IAC1B,SAAS,EAAE,WAAW;IACtB,iBAAiB,EAAE,mBAAmB;IACtC,YAAY,EAAE,cAAc;IAC5B,4FAA4F;IAC5F,oBAAoB,EAAE,sBAAsB;IAC5C,yFAAyF;IACzF,cAAc,EAAE,gBAAgB;IAChC,eAAe,EAAE,iBAAiB;IAClC,oBAAoB,EAAE,sBAAsB;IAC5C,eAAe,EAAE,iBAAiB;IAClC,aAAa,EAAE,eAAe;IAC9B,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;CACZ,CAAC"}
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/client/error.ts"],"names":[],"mappings":";;;AAoBA,MAAa,aAAc,SAAQ,KAAK;IACpB,IAAI,GAAG,eAAe,CAAC;IACzC,0CAA0C;IACjC,MAAM,CAAS;IACxB,8CAA8C;IACrC,MAAM,CAAmB;IAElC,YAAY,MAAc,EAAE,MAAwB,EAAE,OAAgB;QACpE,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,wCAAwC,MAAM,EAAE,CAAC,CAAC;QACzF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,uEAAuE;QACvE,sEAAsE;QACtE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,uEAAuE;IACvE,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IAC9B,CAAC;IAED,yEAAyE;IACzE,OAAO,CAAC,IAAY;QAClB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAClD,CAAC;CACF;AAzBD,sCAyBC;AAED;;;;GAIG;AACU,QAAA,eAAe,GAAG;IAC7B,+EAA+E;IAC/E,6BAA6B,EAAE,+BAA+B;IAC9D,mEAAmE;IACnE,uBAAuB,EAAE,yBAAyB;IAClD,oGAAoG;IACpG,qBAAqB,EAAE,uBAAuB;IAC9C,oGAAoG;IACpG,qBAAqB,EAAE,uBAAuB;IAC9C,wGAAwG;IACxG,cAAc,EAAE,gBAAgB;IAChC,0FAA0F;IAC1F,aAAa,EAAE,eAAe;IAC9B,uIAAuI;IACvI,eAAe,EAAE,iBAAiB;IAClC,oFAAoF;IACpF,6BAA6B,EAAE,+BAA+B;IAC9D,8EAA8E;IAC9E,6BAA6B,EAAE,+BAA+B;IAC9D,6HAA6H;IAC7H,+BAA+B,EAAE,iCAAiC;IAClE,kGAAkG;IAClG,sCAAsC,EAAE,wCAAwC;IAChF,oEAAoE;IACpE,WAAW,EAAE,aAAa;IAC1B,6FAA6F;IAC7F,iBAAiB,EAAE,mBAAmB;IACtC,gDAAgD;IAChD,WAAW,EAAE,aAAa;IAC1B,SAAS,EAAE,WAAW;IACtB,iBAAiB,EAAE,mBAAmB;IACtC,YAAY,EAAE,cAAc;IAC5B,4FAA4F;IAC5F,oBAAoB,EAAE,sBAAsB;IAC5C,yFAAyF;IACzF,cAAc,EAAE,gBAAgB;IAChC,eAAe,EAAE,iBAAiB;IAClC,oBAAoB,EAAE,sBAAsB;IAC5C,eAAe,EAAE,iBAAiB;IAClC,aAAa,EAAE,eAAe;IAC9B,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;CACZ,CAAC"}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -341,7 +341,7 @@ declare function buildNamespaces(request: RequestFn): {
|
|
|
341
341
|
get(id: string): Promise<import("./oauth-clients").OAuthClient>;
|
|
342
342
|
create(body: import("./oauth-clients").CreateOAuthClientBody, idempotencyKey?: string): Promise<import("./oauth-clients").OAuthClientWithSecret>;
|
|
343
343
|
update(id: string, body: import("./oauth-clients").UpdateOAuthClientBody): Promise<import("./oauth-clients").OAuthClient>;
|
|
344
|
-
rotateSecret(id: string): Promise<import("./oauth-clients").
|
|
344
|
+
rotateSecret(id: string, body?: import("./oauth-clients").RotateOAuthClientSecretBody, idempotencyKey?: string): Promise<import("./oauth-clients").OAuthClientSecretRotation>;
|
|
345
345
|
delete(id: string): Promise<{
|
|
346
346
|
object: "oauth_client";
|
|
347
347
|
id: string;
|
|
@@ -841,6 +841,16 @@ declare function buildNamespaces(request: RequestFn): {
|
|
|
841
841
|
deleteChannel(channel: "email" | "sms", options?: {
|
|
842
842
|
force?: boolean;
|
|
843
843
|
}): Promise<import("./messaging").DeletedMessagingProvider>;
|
|
844
|
+
developmentEmail: {
|
|
845
|
+
get(): Promise<import("./messaging").DevelopmentEmail>;
|
|
846
|
+
enable(body: import("./messaging").EnableDevelopmentEmailBody): Promise<import("./messaging").DevelopmentEmail>;
|
|
847
|
+
disable(): Promise<{
|
|
848
|
+
object: "development_email";
|
|
849
|
+
deleted: true;
|
|
850
|
+
provider_id: string;
|
|
851
|
+
mode: "standard";
|
|
852
|
+
}>;
|
|
853
|
+
};
|
|
844
854
|
managedEmail: {
|
|
845
855
|
get(): Promise<import("./messaging").ManagedEmail>;
|
|
846
856
|
create(body: import("./messaging").CreateManagedEmailBody): Promise<import("./messaging").ManagedEmail>;
|
|
@@ -12,13 +12,40 @@ export interface Instance {
|
|
|
12
12
|
environment: string;
|
|
13
13
|
publishable_key: string;
|
|
14
14
|
frontend_api_host: string;
|
|
15
|
+
/**
|
|
16
|
+
* The `iss` this instance's session tokens carry. It changes when a custom
|
|
17
|
+
* domain goes active, so read it (and the two URLs below) rather than hard-coding it.
|
|
18
|
+
*/
|
|
19
|
+
issuer: string;
|
|
20
|
+
/** The OpenID discovery document whose `issuer` equals {@link issuer}. */
|
|
21
|
+
discovery_url: string;
|
|
22
|
+
/** The JWKS holding this instance's signing keys. */
|
|
23
|
+
jwks_uri: string;
|
|
15
24
|
allowed_origins: string[];
|
|
25
|
+
/**
|
|
26
|
+
* The declared integration per allowed origin (`redirect` or `embedded`). An
|
|
27
|
+
* origin not listed is inferred by preflight and login readiness.
|
|
28
|
+
*/
|
|
29
|
+
allowed_origin_integrations?: Record<string, 'redirect' | 'embedded'>;
|
|
16
30
|
auth_config: Metadata;
|
|
17
31
|
created_at: number;
|
|
18
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* How an allowed origin signs in: `redirect` (hosted-redirect OIDC: the app
|
|
35
|
+
* never runs the embedded components), `embedded` (the sign-in components run
|
|
36
|
+
* on the origin), or `auto` / `null` (clear the hint; Atlas infers it).
|
|
37
|
+
*/
|
|
38
|
+
export type OriginIntegration = 'redirect' | 'embedded' | 'auto';
|
|
39
|
+
/** An `allowed_origins` entry that also declares how the origin signs in. */
|
|
40
|
+
export interface AllowedOriginEntry {
|
|
41
|
+
origin: string;
|
|
42
|
+
integration?: OriginIntegration | null;
|
|
43
|
+
}
|
|
44
|
+
/** An origin string, or `{ origin, integration }`. A plain string keeps the origin's current hint. */
|
|
45
|
+
export type AllowedOriginInput = string | AllowedOriginEntry;
|
|
19
46
|
export interface UpdateInstanceBody {
|
|
20
|
-
/** Exact origins only — a wildcard or a path is rejected (§13.1). */
|
|
21
|
-
allowed_origins?:
|
|
47
|
+
/** Exact origins only — a wildcard or a path is rejected (§13.1). The list replaces the stored one. */
|
|
48
|
+
allowed_origins?: AllowedOriginInput[];
|
|
22
49
|
auth_config?: Record<string, unknown>;
|
|
23
50
|
}
|
|
24
51
|
/** `PATCH /v1/instance` echoes only the mutable fields, not a full Instance. */
|
|
@@ -26,6 +53,7 @@ export interface InstanceUpdateResult {
|
|
|
26
53
|
object: 'instance';
|
|
27
54
|
id: string;
|
|
28
55
|
allowed_origins: string[];
|
|
56
|
+
allowed_origin_integrations?: Record<string, 'redirect' | 'embedded'>;
|
|
29
57
|
auth_config: Metadata;
|
|
30
58
|
}
|
|
31
59
|
/** One problem (or note) the setup check found. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance.js","sourceRoot":"","sources":["../../src/client/instance.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"instance.js","sourceRoot":"","sources":["../../src/client/instance.ts"],"names":[],"mappings":";;AAwTA,4CAiEC;AAjED,SAAgB,gBAAgB,CAAC,OAAkB;IACjD,OAAO;QACL,GAAG;YACD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,CAAC,IAAwB;YAC7B,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,yFAAyF;QACzF,SAAS;YACP,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAAC,CAAC;QACpE,CAAC;QACD;;;;WAIG;QACH,UAAU,CAAC,IAAuB;YAChC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,2EAA2E;QAC3E,WAAW;YACT,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,+CAA+C;QAC/C,YAAY,EAAE;YACZ,MAAM,EAAE;gBACN,GAAG;oBACD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,kCAAkC,EAAE,CAAC,CAAC;gBAC9E,CAAC;gBACD,GAAG,CAAC,IAA8B;oBAChC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,kCAAkC,EAAE,IAAI,EAAE,CAAC,CAAC;gBACpF,CAAC;gBACD,MAAM;oBACJ,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,kCAAkC,EAAE,CAAC,CAAC;gBACjF,CAAC;aACF;YACD,UAAU,EAAE;gBACV,GAAG;oBACD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,sCAAsC,EAAE,CAAC,CAAC;gBAClF,CAAC;gBACD,qCAAqC;gBACrC,GAAG,CAAC,IAAkC;oBACpC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,sCAAsC,EAAE,IAAI,EAAE,CAAC,CAAC;gBACxF,CAAC;gBACD,MAAM;oBACJ,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,sCAAsC,EAAE,CAAC,CAAC;gBACrF,CAAC;aACF;SACF;QACD,oEAAoE;QACpE,aAAa,EAAE;YACb,GAAG;gBACD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,6BAA6B,EAAE,CAAC,CAAC;YACzE,CAAC;YACD,kCAAkC;YAClC,GAAG,CAAC,IAA0B;gBAC5B,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,6BAA6B,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/E,CAAC;YACD,+EAA+E;YAC/E,MAAM;gBACJ,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,6BAA6B,EAAE,CAAC,CAAC;YAC5E,CAAC;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -193,6 +193,12 @@ interface ProviderBodyBase<T extends MessagingTransport> {
|
|
|
193
193
|
* provider accepts. SMS: the sender number in E.164 format, e.g. `+15551234567`.
|
|
194
194
|
*/
|
|
195
195
|
from_address?: string;
|
|
196
|
+
/**
|
|
197
|
+
* Email only. `development`: a development instance sends without a verified
|
|
198
|
+
* domain (Atlas sign-in templates only, `[Atlas test] ` subjects, capped);
|
|
199
|
+
* 409 on a production instance. Omitted on an update: the stored mode is kept.
|
|
200
|
+
*/
|
|
201
|
+
mode?: 'standard' | 'development';
|
|
196
202
|
}
|
|
197
203
|
/**
|
|
198
204
|
* First setup of transport `T` (or a switch to it): `config` carries every
|
|
@@ -246,8 +252,12 @@ type PublicConfigKey<T extends MessagingTransport> = Exclude<keyof MessagingTran
|
|
|
246
252
|
*/
|
|
247
253
|
export interface MessagingProviderOf<C extends 'email' | 'sms', T extends MessagingTransport> {
|
|
248
254
|
object: 'messaging_provider';
|
|
255
|
+
/** The provider id: pass it as `provider_id` to managed email or the development sender. */
|
|
256
|
+
id?: string;
|
|
249
257
|
channel: C;
|
|
250
258
|
transport: T;
|
|
259
|
+
/** How it sends: `standard` | `development` | `managed_domain`. */
|
|
260
|
+
mode?: 'standard' | 'development' | 'managed_domain';
|
|
251
261
|
from_address: string | null;
|
|
252
262
|
status: string;
|
|
253
263
|
/** Non-secret config only — secret values are never returned. */
|
|
@@ -280,10 +290,16 @@ export interface MessagingProviders {
|
|
|
280
290
|
status: string;
|
|
281
291
|
verified: boolean;
|
|
282
292
|
} | null;
|
|
293
|
+
/** The email provider in development mode, when it is. */
|
|
294
|
+
development_email?: {
|
|
295
|
+
object: 'development_email';
|
|
296
|
+
enabled: true;
|
|
297
|
+
from_address: string | null;
|
|
298
|
+
} | null;
|
|
283
299
|
}
|
|
284
300
|
/** A DNS record to publish for the managed sending domain. */
|
|
285
301
|
export interface ManagedEmailRecord {
|
|
286
|
-
purpose: 'dkim' | 'spf' | 'return_path' | 'other';
|
|
302
|
+
purpose: 'dkim' | 'spf' | 'return_path' | 'ownership' | 'dmarc' | 'other';
|
|
287
303
|
type: 'TXT' | 'MX' | 'CNAME';
|
|
288
304
|
/** Fully-qualified record name. */
|
|
289
305
|
name: string;
|
|
@@ -291,22 +307,24 @@ export interface ManagedEmailRecord {
|
|
|
291
307
|
priority?: number;
|
|
292
308
|
status?: string;
|
|
293
309
|
}
|
|
294
|
-
/**
|
|
310
|
+
/** Managed email: Atlas sets your sending domain up on your own Resend or Brevo account and sends through your key. */
|
|
295
311
|
export interface ManagedEmail {
|
|
296
312
|
object: 'managed_email';
|
|
297
313
|
id: string;
|
|
298
314
|
from_address: string;
|
|
299
315
|
domain: string;
|
|
300
316
|
provider: string;
|
|
317
|
+
/** The email service the domain lives on (your own account there): `resend` | `brevo`. */
|
|
318
|
+
backend?: 'resend' | 'brevo';
|
|
319
|
+
/** Your email provider (mode `managed_domain`) that holds the API key. */
|
|
320
|
+
provider_id?: string | null;
|
|
301
321
|
region: string | null;
|
|
302
322
|
/** `not_started` | `pending` | `verified` | `failed` | `temporary_failure`. Email sends only when verified. */
|
|
303
323
|
status: string;
|
|
304
324
|
verified: boolean;
|
|
305
325
|
records: ManagedEmailRecord[];
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
daily: number;
|
|
309
|
-
};
|
|
326
|
+
/** Always null: no Atlas limits apply, your provider account's own do. */
|
|
327
|
+
limits: null;
|
|
310
328
|
usage: {
|
|
311
329
|
sent: number;
|
|
312
330
|
bounces: number;
|
|
@@ -314,7 +332,9 @@ export interface ManagedEmail {
|
|
|
314
332
|
last_bounce_at: number | null;
|
|
315
333
|
last_complaint_at: number | null;
|
|
316
334
|
};
|
|
317
|
-
reputation: '
|
|
335
|
+
reputation: 'your_provider_account';
|
|
336
|
+
/** Brevo, on create: whether the bounce / complaint webhook was registered on your account. */
|
|
337
|
+
feedback_webhook?: 'registered' | 'not_registered';
|
|
318
338
|
/** DNS automation, when set. The token is never returned. */
|
|
319
339
|
dns: {
|
|
320
340
|
provider: string;
|
|
@@ -332,6 +352,14 @@ export interface ManagedEmail {
|
|
|
332
352
|
export interface CreateManagedEmailBody {
|
|
333
353
|
/** The From address, bare or `"Name <address>"`. Its domain becomes the sending domain. */
|
|
334
354
|
from_address: string;
|
|
355
|
+
/** Your own provider account Atlas sets the domain up on. Required with `config` unless `provider_id` is given. */
|
|
356
|
+
transport?: 'resend' | 'brevo';
|
|
357
|
+
/** Your provider API key (write-only). */
|
|
358
|
+
config?: {
|
|
359
|
+
api_key: string;
|
|
360
|
+
};
|
|
361
|
+
/** Instead of `transport` + `config`: your configured Resend or Brevo email provider. */
|
|
362
|
+
provider_id?: string;
|
|
335
363
|
region?: 'us-east-1' | 'eu-west-1' | 'sa-east-1' | 'ap-northeast-1';
|
|
336
364
|
/** Let Atlas write the DNS records. The token is write-only. */
|
|
337
365
|
dns?: {
|
|
@@ -346,7 +374,39 @@ export interface DeletedManagedEmail {
|
|
|
346
374
|
object: 'managed_email';
|
|
347
375
|
domain: string;
|
|
348
376
|
deleted: true;
|
|
377
|
+
/** Whether the email provider that held the key (mode `managed_domain`) was removed too. */
|
|
378
|
+
provider_removed?: boolean;
|
|
349
379
|
}
|
|
380
|
+
/** Your own email provider in development mode (development instances, no verified domain). */
|
|
381
|
+
export interface DevelopmentEmail {
|
|
382
|
+
object: 'development_email';
|
|
383
|
+
provider_id: string;
|
|
384
|
+
enabled: true;
|
|
385
|
+
/** False on a production instance (never sends) or when the provider is disabled. */
|
|
386
|
+
active: boolean;
|
|
387
|
+
transport: string;
|
|
388
|
+
from_address: string | null;
|
|
389
|
+
subject_prefix: string;
|
|
390
|
+
footer: string;
|
|
391
|
+
templates: string[];
|
|
392
|
+
limits: {
|
|
393
|
+
daily: number;
|
|
394
|
+
per_recipient_hourly: number;
|
|
395
|
+
};
|
|
396
|
+
/** Present for onboarding@resend.dev: Resend delivers it only to your Resend account address. */
|
|
397
|
+
note?: string;
|
|
398
|
+
next_step?: string;
|
|
399
|
+
updated_at: number;
|
|
400
|
+
}
|
|
401
|
+
/** `{ provider_id }`, or your provider exactly as `messaging.setEmail` takes it. */
|
|
402
|
+
export type EnableDevelopmentEmailBody = {
|
|
403
|
+
provider_id: string;
|
|
404
|
+
from_address?: string;
|
|
405
|
+
} | {
|
|
406
|
+
transport: 'resend' | 'ses' | 'smtp' | 'brevo' | 'mailgun';
|
|
407
|
+
config?: Record<string, string>;
|
|
408
|
+
from_address?: string;
|
|
409
|
+
};
|
|
350
410
|
export interface MessagingTestResult {
|
|
351
411
|
object: 'messaging_test';
|
|
352
412
|
channel: string;
|
|
@@ -397,7 +457,24 @@ export declare function messagingResource(request: RequestFn): {
|
|
|
397
457
|
deleteChannel(channel: "email" | "sms", options?: {
|
|
398
458
|
force?: boolean;
|
|
399
459
|
}): Promise<DeletedMessagingProvider>;
|
|
400
|
-
/**
|
|
460
|
+
/**
|
|
461
|
+
* Your own email provider in development mode: a development instance sends
|
|
462
|
+
* Atlas's sign-in emails without a verified domain ([Atlas test] subjects, capped).
|
|
463
|
+
*/
|
|
464
|
+
developmentEmail: {
|
|
465
|
+
/** 404 when the provider is not in development mode. */
|
|
466
|
+
get(): Promise<DevelopmentEmail>;
|
|
467
|
+
/** Turn development mode on. 409 `DEVELOPMENT_EMAIL_NOT_ALLOWED` on a production instance. */
|
|
468
|
+
enable(body: EnableDevelopmentEmailBody): Promise<DevelopmentEmail>;
|
|
469
|
+
/** Back to standard mode; the provider stays. */
|
|
470
|
+
disable(): Promise<{
|
|
471
|
+
object: "development_email";
|
|
472
|
+
deleted: true;
|
|
473
|
+
provider_id: string;
|
|
474
|
+
mode: "standard";
|
|
475
|
+
}>;
|
|
476
|
+
};
|
|
477
|
+
/** Managed email: Atlas sets your sending domain up on your own Resend or Brevo account. */
|
|
401
478
|
managedEmail: {
|
|
402
479
|
/** 404 when none is configured. */
|
|
403
480
|
get(): Promise<ManagedEmail>;
|
package/dist/client/messaging.js
CHANGED
|
@@ -40,7 +40,25 @@ function messagingResource(request) {
|
|
|
40
40
|
...(options.force ? { query: { force: 'true' } } : {}),
|
|
41
41
|
});
|
|
42
42
|
},
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Your own email provider in development mode: a development instance sends
|
|
45
|
+
* Atlas's sign-in emails without a verified domain ([Atlas test] subjects, capped).
|
|
46
|
+
*/
|
|
47
|
+
developmentEmail: {
|
|
48
|
+
/** 404 when the provider is not in development mode. */
|
|
49
|
+
get() {
|
|
50
|
+
return request({ method: 'GET', path: '/v1/messaging_providers/email/development' });
|
|
51
|
+
},
|
|
52
|
+
/** Turn development mode on. 409 `DEVELOPMENT_EMAIL_NOT_ALLOWED` on a production instance. */
|
|
53
|
+
enable(body) {
|
|
54
|
+
return request({ method: 'POST', path: '/v1/messaging_providers/email/development', body });
|
|
55
|
+
},
|
|
56
|
+
/** Back to standard mode; the provider stays. */
|
|
57
|
+
disable() {
|
|
58
|
+
return request({ method: 'DELETE', path: '/v1/messaging_providers/email/development' });
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
/** Managed email: Atlas sets your sending domain up on your own Resend or Brevo account. */
|
|
44
62
|
managedEmail: {
|
|
45
63
|
/** 404 when none is configured. */
|
|
46
64
|
get() {
|