@k9o/gate 0.0.0-stage → 1.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.
package/src/types.ts ADDED
@@ -0,0 +1,264 @@
1
+ /**
2
+ * `@k9o/gate` — public type surface.
3
+ *
4
+ * The shapes here track verbatim. End-user IDs carry the `eu_`
5
+ * prefix; role and group identifiers compose against the
6
+ * role lattice (Trust-Zone-separate `PROJECT_END_USER` for project-
7
+ * level end-user identities). Sessions, passkeys, MFA factors, federation
8
+ * links, and the rest of the Gate-managed resources receive their per-
9
+ * resource prefixes as the end-user table family is specified.
10
+ *
11
+ * Envelope shape (`data` + `meta`) matches; failures land via
12
+ * the `GateError` family per `errors.ts`, which is `KError`-compatible
13
+ *.
14
+ */
15
+
16
+ /**
17
+ * Standard envelope. Generic over the `data` shape per function.
18
+ * Returned by every successful SDK call.
19
+ */
20
+ export type Envelope<T> = {
21
+ data: T;
22
+ meta: Record<string, unknown>;
23
+ };
24
+
25
+ /**
26
+ * Project-level end-user identity (the customers OF the customer as
27
+ * the `PROJECT_END_USER` 7th canonical role). End-user IDs carry the
28
+ * `eu_<base62>` prefix.
29
+ */
30
+ export type EndUser = {
31
+ /** `eu_<base62>` — see. */
32
+ id: string;
33
+ email: string;
34
+ status: "active" | "pending" | "disabled";
35
+ createdAt: string;
36
+ updatedAt: string | null;
37
+ lastSigninAt: string | null;
38
+ /** Project-level roles; `PROJECT_END_USER` is the floor membership. */
39
+ roles: ReadonlyArray<string>;
40
+ /** Project-level group memberships `_sys.end_user_groups`. */
41
+ groups: ReadonlyArray<string>;
42
+ };
43
+
44
+ /**
45
+ * Session tokens returned by sign-up / sign-in / refresh flows. Both
46
+ * tokens are opaque to consumers; `accessToken` carries the JWT shape
47
+ * for downstream Gate-aware services; `refreshToken` is opaque to the
48
+ * SDK consumer and is presented back to `gate.refreshToken({...})` to
49
+ * rotate the access token.
50
+ */
51
+ export type Session = {
52
+ accessToken: string;
53
+ refreshToken: string;
54
+ /** ISO 8601 instant the access token expires. */
55
+ expiresAt: string;
56
+ };
57
+
58
+ /**
59
+ * Marquee sign-up / sign-in shape:
60
+ * `{ user, session }`
61
+ */
62
+ export type AuthResult = {
63
+ user: EndUser;
64
+ session: Session;
65
+ };
66
+
67
+ /**
68
+ * `gate.whoami()` shape:
69
+ * `{ user }` — no fresh session is minted by `whoami` (it reflects the
70
+ * caller's current session).
71
+ */
72
+ export type WhoamiResult = {
73
+ user: EndUser;
74
+ };
75
+
76
+ /**
77
+ * `gate.verifySession()` shape — boolean plus the surfaced session
78
+ * details if valid. Returns `{ valid: false, user: null, session: null }`
79
+ * when the bearer session is missing or expired (no throw on invalid;
80
+ * throw only on transport / upstream failures).
81
+ */
82
+ export type VerifySessionResult =
83
+ | { valid: true; user: EndUser; session: Session }
84
+ | { valid: false; user: null; session: null };
85
+
86
+ /**
87
+ * Marquee request shapes. `gate.signUp` takes a CLOSED body: `{ email, password, displayName? }`.
88
+ * `displayName` is stored with the end user's PII (1 to 128 characters); any other field is refused by the
89
+ * gateway with `K9O_INVALID_FIELD_VALUE` (`context.reason: "unknown_field"`), so this type has no escape hatch.
90
+ */
91
+ export type SignUpInput = {
92
+ email: string;
93
+ password: string;
94
+ /** Optional display name (1 to 128 characters); surfaces in account-management UI. */
95
+ displayName?: string;
96
+ };
97
+
98
+ export type SignInInput = {
99
+ email: string;
100
+ password: string;
101
+ };
102
+
103
+ export type SignOutInput = {
104
+ /**
105
+ * Optional refresh token to revoke. When omitted the gateway revokes
106
+ * the access token's bound refresh token only; explicit refresh tokens
107
+ * let callers revoke a specific device/session.
108
+ */
109
+ refreshToken?: string;
110
+ };
111
+
112
+ export type RefreshTokenInput = {
113
+ refreshToken: string;
114
+ };
115
+
116
+ /**
117
+ * OTP purpose — scopes the one-time code to a flow. The gateway validates
118
+ * against this closed set (otp.ts) and defaults to "signin" when omitted.
119
+ */
120
+ export type OtpPurpose = "signin" | "magic_link" | "password_reset" | "mfa_challenge";
121
+
122
+ /**
123
+ * `gate.passwordless.requestOtp` input — emails an OTP code to the
124
+ * given address. Idempotent at the per-email rate-limit ceiling per
125
+ * the platform anti-abuse policy.
126
+ */
127
+ export type RequestOtpInput = {
128
+ email: string;
129
+ /** OTP purpose; defaults to "signin" server-side when omitted. */
130
+ purpose?: OtpPurpose;
131
+ };
132
+
133
+ /**
134
+ * `gate.passwordless.verifyOtp` input — caller supplies the OTP code
135
+ * received via email plus the originating email address so the
136
+ * gateway can resolve the right OTP row.
137
+ */
138
+ export type VerifyOtpInput = {
139
+ email: string;
140
+ code: string;
141
+ /** Must match the `purpose` supplied to `requestOtp` (defaults "signin")
142
+ * so the gateway resolves the right OTP row. */
143
+ purpose?: OtpPurpose;
144
+ };
145
+
146
+ /**
147
+ * `gate.passwordless.requestMagicLink` input — emails a magic-link
148
+ * token to the given address; the customer's frontend handles the
149
+ * post-redirect exchange via `verifyMagicLink`.
150
+ */
151
+ export type RequestMagicLinkInput = {
152
+ email: string;
153
+ /**
154
+ * Post-redeem landing URL. When supplied it MUST exact-match an entry in
155
+ * the project's magic-link redirect allowlist (Gate config); a
156
+ * non-allowlisted value is rejected with `GATE_REDIRECT_NOT_ALLOWED` (400).
157
+ * Omit to use the project's configured default redirect.
158
+ */
159
+ redirectUrl?: string;
160
+ };
161
+
162
+ /**
163
+ * `gate.passwordless.verifyMagicLink` input — caller supplies the
164
+ * opaque token from the magic-link query string.
165
+ */
166
+ export type VerifyMagicLinkInput = {
167
+ token: string;
168
+ };
169
+
170
+ /**
171
+ * Result of `gate.passwordless.parseMagicLinkCallback(window.location.search)`
172
+ * on the magic-link landing page. The gateway delivers the opaque token in the
173
+ * query string (`?token=…&project=…`); feed `token` to `verifyMagicLink`.
174
+ * Distinct from `parseSignInCallback`, which parses the SSO hash fragment.
175
+ */
176
+ export type MagicLinkCallbackResult =
177
+ | { ok: true; token: string }
178
+ | { ok: false; error: string };
179
+
180
+ /**
181
+ * JWT claim shape that `verifyJwt` resolves. Mirrors `subject.*`
182
+ * exposure for project-level JWTs plus the Gate-issued audience / issuer
183
+ * standard claims. Customer apps in Standalone mode consume this via the
184
+ * `verifyJwt` helper without needing the full SDK shape.
185
+ */
186
+ export type GateJwtClaims = {
187
+ /** Issuer — the Kilimanjaro gateway base URL or project-bound issuer. */
188
+ iss: string;
189
+ /** Audience — typically the project id (`proj_<base62>`). */
190
+ aud: string | string[];
191
+ /** Subject — the end-user id (`eu_<base62>`). */
192
+ sub: string;
193
+ /** Issued-at (seconds since Unix epoch). */
194
+ iat: number;
195
+ /** Expiry (seconds since Unix epoch). */
196
+ exp: number;
197
+ /** JWT id (for revocation tracking + idempotency). */
198
+ jti?: string;
199
+ /** Project-level role array; floor is `PROJECT_END_USER`. */
200
+ roles?: ReadonlyArray<string>;
201
+ /** Project-level group memberships. */
202
+ groups?: ReadonlyArray<string>;
203
+ /** Project-level scope strings — used by `requireScope`. */
204
+ scopes?: ReadonlyArray<string>;
205
+ /** Email of the underlying end-user; convenience copy of the database column. */
206
+ email?: string;
207
+ /**
208
+ * Additional claims that aren't part of the canonical set. The gateway
209
+ * is free to embed custom claims per project policy.
210
+ */
211
+ [key: string]: unknown;
212
+ };
213
+
214
+ /**
215
+ * `verifyJwt` result. `valid: true` resolves to the parsed claim set;
216
+ * `valid: false` carries a typed reason for the failure (signature
217
+ * mismatch, expiry, audience mismatch, etc.) without throwing.
218
+ */
219
+ export type VerifyJwtResult =
220
+ | { valid: true; claims: GateJwtClaims }
221
+ | { valid: false; reason: VerifyJwtFailure };
222
+
223
+ export type VerifyJwtFailure =
224
+ | "INVALID_SIGNATURE"
225
+ | "EXPIRED"
226
+ | "NOT_YET_VALID"
227
+ | "AUDIENCE_MISMATCH"
228
+ | "ISSUER_MISMATCH"
229
+ | "MALFORMED"
230
+ | "ALGORITHM_NOT_ALLOWED";
231
+
232
+ /**
233
+ * Result of `gate.parseSignInCallback(window.location.hash)` after the
234
+ * browser returns from an IdP-initiated sign-in. On success, carries
235
+ * the session tokens; on failure, carries an error subcode + description.
236
+ */
237
+ export type SignInCallbackResult =
238
+ | {
239
+ ok: true;
240
+ accessToken: string;
241
+ refreshToken: string;
242
+ /** ISO 8601 absolute expiry timestamp for the access token. */
243
+ expiresAt: string;
244
+ /** Always "Bearer" today; reserved for future schemes. */
245
+ tokenType: string;
246
+ }
247
+ | {
248
+ ok: false;
249
+ /** IdpErrorSubcode ("sso_failed" | "idp_provider_not_configured" | …)
250
+ * or the literal "malformed_callback" if the fragment can't be parsed. */
251
+ error: string;
252
+ errorDescription: string;
253
+ };
254
+
255
+ /**
256
+ * The project's hosted sign-in page and WebAuthn relying party (`GET /@<projectSlug>/gate/hosted`). Both values come from the platform: an SDK never composes a Gate host from a slug (the label is a hash of
257
+ * ids the SDK does not hold).
258
+ */
259
+ export type HostedGateInfo = {
260
+ /** Absolute hosted sign-in URL: the verified custom domain's when there is one, else the project's Gate host. */
261
+ signInUrl: string;
262
+ /** The WebAuthn relying-party id (the project's Gate host). Use it as given; never hard-code it. */
263
+ rpId: string;
264
+ };