@k9o/gate 1.0.0 → 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/CHANGELOG.md +4 -36
- package/README.md +236 -76
- package/dist/{chunk-PEW6HZFB.js → chunk-JEV37YEC.js} +1 -1
- package/dist/chunk-JEV37YEC.js.map +1 -0
- package/dist/{chunk-LZQ7MBXS.js → chunk-XP6U5QKF.js} +2 -2
- package/dist/chunk-XP6U5QKF.js.map +1 -0
- package/dist/{chunk-ZNFI2CQA.js → chunk-YINWOWJC.js} +2 -2
- package/dist/chunk-YINWOWJC.js.map +1 -0
- package/dist/errors.d.ts +5 -5
- package/dist/errors.js +1 -1
- package/dist/index.d.ts +28 -30
- package/dist/index.js +14 -15
- package/dist/index.js.map +1 -1
- package/dist/jwt.d.ts +1 -1
- package/dist/jwt.js +2 -2
- package/dist/mode.d.ts +7 -7
- package/dist/mode.js +1 -1
- package/dist/types.d.ts +21 -21
- package/package.json +1 -1
- package/src/client-factory.ts +2 -2
- package/src/client.ts +4 -4
- package/src/errors.ts +8 -10
- package/src/gate.ts +14 -15
- package/src/idp-providers/identity-providers.ts +7 -7
- package/src/index.ts +1 -1
- package/src/jwt.ts +1 -1
- package/src/mode.ts +8 -8
- package/src/paths.ts +1 -1
- package/src/types.ts +21 -21
- package/dist/chunk-LZQ7MBXS.js.map +0 -1
- package/dist/chunk-PEW6HZFB.js.map +0 -1
- package/dist/chunk-ZNFI2CQA.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,41 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 1.1.0 — 2026-10-25
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- Documentation rewritten with runnable examples and expected output; internal cross-references removed from the published sources. No change to the public API.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 1.0.0 — 2026-10-23
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## [0.3.0] — v2.5.58 — LDAP-bridge sub-namespace
|
|
12
|
-
|
|
13
|
-
- `gate.idpProviders.ldap.credentials.{create, list, rotate, revoke}` sub-namespace
|
|
14
|
-
- Wraps the LDAP-bridge credentials gateway API shipped in `services/gateway` v2.5.57
|
|
15
|
-
- Type-safe bindings to the 4 endpoints under `/v2/projects/{projectId}/auth/idp-providers/{idpId}/ldap-credentials`
|
|
16
|
-
- New public types: `LdapBridgeCredentialMetadata` / `CreateLdapCredentialInput` / `RotateLdapCredentialInput` / `ListLdapCredentialsOpts` / `RevokeResult` / `LdapCredentialsNamespace`
|
|
17
|
-
- Closes the Gate Studio LDAPEditor standing blocker (step 3 of 3)
|
|
18
|
-
- Passwords are sent over TLS to the gateway, encrypted-at-rest via AES-256-GCM, and never returned to clients
|
|
19
|
-
|
|
20
|
-
## [0.2.1] — v2.5.56 — Shipping config
|
|
21
|
-
|
|
22
|
-
- Removed `"private": true`; package is now publishable (pending internal npm registry config; consumption via workspace path or git+subdirectory until then)
|
|
23
|
-
- Added `files` allowlist (src + README + CHANGELOG)
|
|
24
|
-
- Added `publishConfig.access = "restricted"` for future internal-registry publish
|
|
25
|
-
- Added `repository` field pointing at canonical k9o-core source
|
|
26
|
-
- Added per-module export entries (`./types`, `./errors`, `./jwt`, `./mode`) for tree-shake-friendly imports
|
|
27
|
-
- Added README "Installation" section with workspace + cross-repo git+subdirectory patterns
|
|
28
|
-
- No API change; 56/56 tests pass; tsc clean
|
|
29
|
-
|
|
30
|
-
## [0.2.0] — v2.5.21 — Marquee `gate.*` namespace
|
|
31
|
-
|
|
32
|
-
- `gate.signUp` / `gate.signIn` / `gate.signOut` / `gate.whoami` / `gate.refreshToken` / `gate.verifySession`
|
|
33
|
-
- Project-scoped `/v2/projects/{projectId}/gate/*` path family per ch01 §12.1
|
|
34
|
-
- Standalone vs Native mode plumbing (`configureGate` / `getGateConfig` / `resetGateConfig`)
|
|
35
|
-
- Standalone JWT primitives (`verifyJwt` / `extractClaims` / `requireScope`)
|
|
36
|
-
- `GateError` + closed `GateErrorCode` taxonomy per ch01 §2
|
|
37
|
-
|
|
38
|
-
## [0.1.0] — Pre-shipping baseline
|
|
39
|
-
|
|
40
|
-
- Initial package scaffold
|
|
41
|
-
- Type-only surface declarations
|
|
9
|
+
First public release. See the README for the full API overview.
|
package/README.md
CHANGED
|
@@ -1,111 +1,271 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @k9o/gate
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Kilimanjaro v2 ships as both a standalone Auth0-parity surface and a composed
|
|
5
|
-
capability available through `@k9o/core` per ch01 §11 of the v2 idealised
|
|
6
|
-
specification.
|
|
3
|
+
Identity for your app's end users on Kilimanjaro. Sign-up, sign-in, sessions, one-time codes, magic links and JWT verification.
|
|
7
4
|
|
|
8
|
-
##
|
|
5
|
+
## Contents
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
- [Install](#install)
|
|
8
|
+
- [Quick start](#quick-start)
|
|
9
|
+
- [Client setup](#client-setup)
|
|
10
|
+
- [Signing users in](#signing-users-in)
|
|
11
|
+
- [Verifying tokens](#verifying-tokens)
|
|
12
|
+
- [Handling errors](#handling-errors)
|
|
13
|
+
- [Regional hosts](#regional-hosts)
|
|
14
|
+
- [Appendix](#appendix)
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
## Install
|
|
13
17
|
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"@k9o/gate": "workspace:*"
|
|
18
|
-
}
|
|
19
|
-
}
|
|
18
|
+
```bash
|
|
19
|
+
npm install @k9o/gate
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
```bash
|
|
23
|
+
bun add @k9o/gate
|
|
24
|
+
```
|
|
23
25
|
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
"dependencies": {
|
|
27
|
-
"@k9o/gate": "^1.0.0"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add @k9o/gate
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
Requires Node.js 18+, Bun 1.1+ or a browser with a global `fetch`. See [Requirements](#requirements).
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
## Quick start
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createGateClient } from "@k9o/gate";
|
|
36
|
+
|
|
37
|
+
const gate = createGateClient({
|
|
38
|
+
mode: "native",
|
|
39
|
+
baseUrl: "https://acme.api.k9o.io",
|
|
40
|
+
projectSlug: "member-portal",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const result = await gate.signIn({ email: "ada@example.com", password: "a-long-passphrase" });
|
|
44
|
+
const user = result.data.user;
|
|
45
|
+
|
|
46
|
+
console.log(user.email);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
ada@example.com
|
|
38
51
|
```
|
|
39
52
|
|
|
40
|
-
|
|
53
|
+
Every method resolves to `{ data, meta }`.
|
|
41
54
|
|
|
42
|
-
|
|
55
|
+
## Client setup
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
| ----------------------------- | ------------------------------------------ |
|
|
46
|
-
| `gate.*` (marquee) | scaffolded — `signUp` / `signIn` / `signOut` / `whoami` / `refreshToken` / `verifySession` |
|
|
47
|
-
| `gate.passwordless.*` | scaffolded at v0.2.0 — `requestOtp` / `verifyOtp` / `requestMagicLink` / `verifyMagicLink` (gateway endpoints land in subsequent v2.4.x cycle) |
|
|
48
|
-
| `gate.social.*` | deferred to v0.2.x |
|
|
49
|
-
| `gate.passkeys.*` | deferred to v0.2.x |
|
|
50
|
-
| `gate.mfa.*` | deferred to v0.3.x |
|
|
51
|
-
| `gate.password.*` | deferred to v0.2.x |
|
|
52
|
-
| `gate.users.*` | deferred to v0.3.x |
|
|
53
|
-
| `gate.email.*` / `gate.sms.*` | deferred to v0.3.x |
|
|
54
|
-
| `gate.federation.*` | deferred (Ridge+ tier-gated; post-v1) |
|
|
55
|
-
| `gate.admin.*` | deferred to v0.3.x |
|
|
57
|
+
The client is bound to one project. See [Client options](#client-options) for every option.
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
| Option | Meaning |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| `mode` | `"native"` or `"standalone"`. Required. |
|
|
62
|
+
| `projectSlug` | The project whose end users you manage. Required. |
|
|
63
|
+
| `baseUrl` | Gateway host. Required. |
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
- `createGateClient` returns an independent client. Create one per tenant if you need several.
|
|
66
|
+
- Inside `@k9o/core`, the same client is `client.gate`. It reuses the core client's host, project and API key.
|
|
67
|
+
- To share one config, see [Shared configuration](#shared-configuration).
|
|
68
|
+
|
|
69
|
+
## Signing users in
|
|
70
|
+
|
|
71
|
+
Create a user, then sign in with a password. The session holds the access and refresh tokens.
|
|
62
72
|
|
|
63
73
|
```ts
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// Standalone mode — Gate handles JWT issuance + verification only.
|
|
67
|
-
// Customer's data stays in their own infrastructure.
|
|
68
|
-
configureGate({
|
|
69
|
-
mode: "standalone",
|
|
70
|
-
projectId: "proj_abc123",
|
|
71
|
-
baseUrl: "https://api.k9o.io",
|
|
72
|
-
});
|
|
74
|
+
const signedUp = await gate.signUp({ email: "grace@example.com", password: "another-long-passphrase" });
|
|
75
|
+
const session = signedUp.data.session;
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// works too).
|
|
77
|
-
configureGate({
|
|
78
|
-
mode: "native",
|
|
79
|
-
projectId: "proj_abc123",
|
|
80
|
-
baseUrl: "https://api.k9o.io",
|
|
81
|
-
});
|
|
77
|
+
const refreshed = await gate.refreshToken({ refreshToken: session.refreshToken });
|
|
78
|
+
```
|
|
82
79
|
|
|
83
|
-
|
|
80
|
+
- Passwordless sign-in uses `passwordless.requestOtp` then `passwordless.verifyOtp`.
|
|
81
|
+
- Browser sign-in with a provider uses `signInWithProvider`.
|
|
82
|
+
- See [Methods](#methods) for everything else.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
await gate.passwordless.requestOtp({ email: "ada@example.com" });
|
|
86
|
+
const verified = await gate.passwordless.verifyOtp({ email: "ada@example.com", code: "123456" });
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
is a deployment-time decision and not visible in the surface shape.
|
|
89
|
+
A magic-link `redirectUrl` must exactly match an entry in the project's allowlist.
|
|
88
90
|
|
|
89
|
-
##
|
|
91
|
+
## Verifying tokens
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
Backends can verify Gate tokens without creating a client. `verifyJwt` returns a result and does not throw for a bad token.
|
|
92
94
|
|
|
93
95
|
```ts
|
|
94
|
-
|
|
96
|
+
import { verifyJwt } from "@k9o/gate";
|
|
97
|
+
|
|
98
|
+
const verification = await verifyJwt({
|
|
99
|
+
token: accessToken,
|
|
100
|
+
jwksUrl: "https://acme.api.k9o.io/@member-portal/gate/.well-known/jwks.json",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (verification.valid) {
|
|
104
|
+
console.log(verification.claims.sub);
|
|
105
|
+
} else {
|
|
106
|
+
console.warn(verification.reason);
|
|
107
|
+
}
|
|
95
108
|
```
|
|
96
109
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
110
|
+
- Set exactly one of `jwksUrl` or `jwks`. See [Verification options](#verification-options).
|
|
111
|
+
- A failed check returns one of the [Failure reasons](#failure-reasons).
|
|
112
|
+
- `requireScope(claims, scopes)` throws `RBAC_DENY` if a scope is missing.
|
|
100
113
|
|
|
101
|
-
##
|
|
114
|
+
## Handling errors
|
|
102
115
|
|
|
103
|
-
|
|
116
|
+
Failures throw `GateError`. Switch on `code`.
|
|
104
117
|
|
|
105
118
|
```ts
|
|
106
|
-
import {
|
|
119
|
+
import { GateError } from "@k9o/gate";
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
await gate.signIn({ email: "ada@example.com", password: "wrong" });
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error instanceof GateError && error.code === "INVALID_CREDENTIALS") {
|
|
125
|
+
console.warn("Wrong email or password");
|
|
126
|
+
} else {
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
107
130
|
```
|
|
108
131
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
132
|
+
See [Error codes](#error-codes) for the full list. The full wire code is kept in `context.originalCode`.
|
|
133
|
+
|
|
134
|
+
## Regional hosts
|
|
135
|
+
|
|
136
|
+
- On an organization host such as `https://acme.api.k9o.io`, the client sends one `HEAD` request first.
|
|
137
|
+
- The request carries no credentials. It finds the regional host for your organization.
|
|
138
|
+
- All later requests go to that host. The answer is cached.
|
|
139
|
+
- Any other `baseUrl` is used as given. If the lookup fails, the configured host is used.
|
|
140
|
+
|
|
141
|
+
## Appendix
|
|
142
|
+
|
|
143
|
+
### Requirements
|
|
144
|
+
|
|
145
|
+
| Requirement | Version |
|
|
146
|
+
| --- | --- |
|
|
147
|
+
| Node.js | 18 or newer |
|
|
148
|
+
| Bun | 1.1 or newer |
|
|
149
|
+
| TypeScript (optional) | 5.6 or newer |
|
|
150
|
+
| Browser | Any with a global `fetch` |
|
|
151
|
+
|
|
152
|
+
Token verification uses the `jose` library, which installs with the package.
|
|
153
|
+
|
|
154
|
+
### Client options
|
|
155
|
+
|
|
156
|
+
| Option | Meaning |
|
|
157
|
+
| --- | --- |
|
|
158
|
+
| `mode` | `"native"` or `"standalone"`. Required. |
|
|
159
|
+
| `projectSlug` | The project whose end users you manage. Required. |
|
|
160
|
+
| `baseUrl` | Gateway host, such as `https://acme.api.k9o.io`. Required. |
|
|
161
|
+
| `partnerToken` | Bearer token sent with requests that need one. |
|
|
162
|
+
| `fetch` | Custom `fetch` implementation. |
|
|
163
|
+
|
|
164
|
+
An invalid `mode`, or a missing `projectSlug` or `baseUrl`, throws a `TypeError`.
|
|
165
|
+
|
|
166
|
+
### Shared configuration
|
|
167
|
+
|
|
168
|
+
| Function | What it does |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| `configureGate(config)` | Sets the config used by the exported `gate` singleton. |
|
|
171
|
+
| `getGateConfig()` | Reads the shared config. |
|
|
172
|
+
| `resetGateConfig()` | Clears the shared config. |
|
|
173
|
+
|
|
174
|
+
### Methods
|
|
175
|
+
|
|
176
|
+
| Method | What it does |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| `signUp({ email, password, displayName? })` | Creates an end user and a session. |
|
|
179
|
+
| `signIn({ email, password })` | Authenticates with a password. |
|
|
180
|
+
| `signOut({ refreshToken? })` | Revokes the current session. |
|
|
181
|
+
| `whoami()` | Returns the signed-in user. |
|
|
182
|
+
| `refreshToken({ refreshToken })` | Exchanges a refresh token for a new session. |
|
|
183
|
+
| `verifySession()` | Checks whether the current session is valid. |
|
|
184
|
+
| `hosted()` | Returns the hosted sign-in page and WebAuthn `rpId`. |
|
|
185
|
+
| `signInWithProvider({ provider, redirectUri })` | Sends the browser to a provider. |
|
|
186
|
+
| `parseSignInCallback(hash)` | Reads tokens from the redirect URL fragment. |
|
|
187
|
+
| `passwordless.requestOtp({ email, purpose? })` | Emails a one-time code. |
|
|
188
|
+
| `passwordless.verifyOtp({ email, code, purpose? })` | Redeems the code and returns a session. |
|
|
189
|
+
| `passwordless.requestMagicLink({ email, redirectUrl? })` | Emails a magic link. |
|
|
190
|
+
| `passwordless.verifyMagicLink(input)` | Redeems the link and returns a session. |
|
|
191
|
+
| `identityProviders` | Project admins create end-user identity providers. |
|
|
192
|
+
| `magicLinkRedirects` | Project admins manage the redirect allowlist. |
|
|
193
|
+
|
|
194
|
+
- `provider` is `"google"`, `"github"`, `"microsoft"`, `"oidc"` or `"saml"`.
|
|
195
|
+
- Generic OIDC is not wired yet. Use a hosted provider.
|
|
196
|
+
|
|
197
|
+
### Token helpers
|
|
198
|
+
|
|
199
|
+
| Function | What it does |
|
|
200
|
+
| --- | --- |
|
|
201
|
+
| `verifyJwt(options)` | Verifies a token and returns a result. |
|
|
202
|
+
| `extractClaims(token)` | Decodes claims without verifying them. |
|
|
203
|
+
| `requireScope(claims, scopes)` | Throws `RBAC_DENY` if a scope is missing. |
|
|
204
|
+
|
|
205
|
+
### Verification options
|
|
206
|
+
|
|
207
|
+
| Option | Meaning |
|
|
208
|
+
| --- | --- |
|
|
209
|
+
| `token` | The JWT to verify. |
|
|
210
|
+
| `jwksUrl` | Remote key set URL. Set this or `jwks`. |
|
|
211
|
+
| `jwks` | Inline key set. Set this or `jwksUrl`. |
|
|
212
|
+
| `expectedIssuer` | Required `iss` claim. |
|
|
213
|
+
| `expectedAudience` | Required `aud` claim. |
|
|
214
|
+
| `allowedAlgorithms` | Defaults to `RS256` and `ES256`. |
|
|
215
|
+
| `clockToleranceSeconds` | Defaults to 30. |
|
|
216
|
+
|
|
217
|
+
### Failure reasons
|
|
218
|
+
|
|
219
|
+
| Reason | Meaning |
|
|
220
|
+
| --- | --- |
|
|
221
|
+
| `INVALID_SIGNATURE` | The signature does not match. |
|
|
222
|
+
| `EXPIRED` | The token has expired. |
|
|
223
|
+
| `NOT_YET_VALID` | The token is not valid yet. |
|
|
224
|
+
| `AUDIENCE_MISMATCH` | The audience differs. |
|
|
225
|
+
| `ISSUER_MISMATCH` | The issuer differs. |
|
|
226
|
+
| `MALFORMED` | The token cannot be parsed. |
|
|
227
|
+
| `ALGORITHM_NOT_ALLOWED` | The algorithm is not in the allowed list. |
|
|
228
|
+
|
|
229
|
+
### Error fields
|
|
230
|
+
|
|
231
|
+
| Field | Meaning |
|
|
232
|
+
| --- | --- |
|
|
233
|
+
| `code` | Stable string. Switch on this. |
|
|
234
|
+
| `message` | Human-readable explanation. |
|
|
235
|
+
| `context` | Per-code details. |
|
|
236
|
+
| `recommendation` | Suggested next step. |
|
|
237
|
+
|
|
238
|
+
### Error codes
|
|
239
|
+
|
|
240
|
+
Codes have no `K9O_` prefix.
|
|
241
|
+
|
|
242
|
+
| Code | Meaning |
|
|
243
|
+
| --- | --- |
|
|
244
|
+
| `UNAUTHENTICATED` | No valid credential was supplied. |
|
|
245
|
+
| `INVALID_CREDENTIALS` | Email or password is wrong. |
|
|
246
|
+
| `EMAIL_ALREADY_REGISTERED` | The email already has an account. |
|
|
247
|
+
| `INVALID_FIELD_VALUE` | Input failed validation. |
|
|
248
|
+
| `SESSION_EXPIRED` | The session has expired. |
|
|
249
|
+
| `REFRESH_TOKEN_INVALID` | The refresh token was rejected. |
|
|
250
|
+
| `RBAC_DENY` | The caller lacks a required role or scope. |
|
|
251
|
+
| `FORBIDDEN` | The caller may not do this. |
|
|
252
|
+
| `NOT_FOUND` | The resource does not exist. |
|
|
253
|
+
| `TIER_FEATURE_GATED` | The project's plan does not include this. |
|
|
254
|
+
| `GATE_REDIRECT_NOT_ALLOWED` | The redirect URL is not on the allowlist. |
|
|
255
|
+
| `POLICY_AUTHORING_AUTHORITY_INSUFFICIENT` | The caller may not author this policy. |
|
|
256
|
+
| `UPSTREAM_UNAVAILABLE` | The gateway could not be reached. |
|
|
257
|
+
| `INTERNAL_ERROR` | Unexpected failure, including unknown codes. |
|
|
258
|
+
|
|
259
|
+
### Related packages
|
|
260
|
+
|
|
261
|
+
| Package | What it does |
|
|
262
|
+
| --- | --- |
|
|
263
|
+
| `@k9o/core` | The full platform client. Exposes this package as `client.gate`. |
|
|
264
|
+
| `@k9o/extensions` | Typed bindings for platform extensions. |
|
|
265
|
+
| `@k9o/kibo` | Vault and key operations. |
|
|
266
|
+
|
|
267
|
+
Platform apex: https://api.k9o.io. Documentation: https://kilimanjaro.dev.
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
Apache-2.0 © Formelo Inc. See `LICENSE` and `NOTICE`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Gate error shapes. `GateError` is `KError`-compatible —\n * downstream catch blocks can `instanceof GateError`-narrow without\n * importing the gateway's `KError` class directly (the SDK is a customer-\n * facing dependency; reaching across to the gateway's internal error\n * type would be a layering violation).\n *\n * The taxonomy below is the closed set; additions follow the\n * error-catalogue freeze cycle.\n */\n\n/**\n * Closed-taxonomy error code. Strings are the wire format —\n * camelCase-cased KError families per the convention.\n */\nexport type GateErrorCode =\n | \"UNAUTHENTICATED\"\n | \"INVALID_FIELD_VALUE\"\n | \"EMAIL_ALREADY_REGISTERED\"\n | \"INVALID_CREDENTIALS\"\n | \"SESSION_EXPIRED\"\n | \"REFRESH_TOKEN_INVALID\"\n | \"TIER_FEATURE_GATED\"\n | \"RBAC_DENY\"\n // FORBIDDEN + NOT_FOUND are surfaced by the gate.idpProviders.*\n // sub-namespaces (project-membership gate + resource-existence checks).\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n // GATE_REDIRECT_NOT_ALLOWED — magic-link `redirectUrl` not in the project's\n // redirect allowlist (open-redirect-safe exact-match, per-project\n // allowlist capability).\n | \"GATE_REDIRECT_NOT_ALLOWED\"\n | \"POLICY_AUTHORING_AUTHORITY_INSUFFICIENT\"\n | \"UPSTREAM_UNAVAILABLE\"\n | \"INTERNAL_ERROR\";\n\n/**\n * Surface error thrown by the SDK. Mirrors the gateway's `KError` shape\n * — `code` (closed taxonomy), `message` (human-readable),\n * `context` (structured per-code payload), `recommendation` (action the\n * caller can take, or null when there's no canonical recommendation).\n */\nexport class GateError extends Error {\n readonly code: GateErrorCode;\n readonly context: Readonly<Record<string, unknown>>;\n readonly recommendation: string | null;\n /** HTTP status the gateway returned (if the error came from a wire response). */\n readonly status: number | null;\n\n constructor(init: {\n code: GateErrorCode;\n message: string;\n context?: Record<string, unknown>;\n recommendation?: string | null;\n status?: number | null;\n }) {\n super(init.message);\n this.name = \"GateError\";\n this.code = init.code;\n this.context = Object.freeze({ ...(init.context ?? {}) });\n this.recommendation = init.recommendation ?? null;\n this.status = init.status ?? null;\n }\n}\n\n/**\n * Wire-shape sentinel matching the gateway's `KError` JSON payload. The\n * client uses this to recognise gateway responses and rehydrate them\n * into a `GateError` instance with the right code + context preserved.\n */\nexport type KErrorWire = {\n code: string;\n message: string;\n context?: Record<string, unknown>;\n recommendation?: string | null;\n};\n\n/**\n * Narrow a wire `KError` to a strongly-typed `GateError`. Unknown codes\n * pass through as `INTERNAL_ERROR` with the original code preserved in\n * `context.originalCode` so consumers don't lose telemetry when the\n * server-side taxonomy outpaces the SDK's bundled enum.\n */\nexport function gateErrorFromWire(wire: KErrorWire, status: number): GateError {\n const knownCodes: ReadonlyArray<GateErrorCode> = [\n \"UNAUTHENTICATED\",\n \"INVALID_FIELD_VALUE\",\n \"EMAIL_ALREADY_REGISTERED\",\n \"INVALID_CREDENTIALS\",\n \"SESSION_EXPIRED\",\n \"REFRESH_TOKEN_INVALID\",\n \"TIER_FEATURE_GATED\",\n \"RBAC_DENY\",\n \"FORBIDDEN\",\n \"NOT_FOUND\",\n \"GATE_REDIRECT_NOT_ALLOWED\",\n \"POLICY_AUTHORING_AUTHORITY_INSUFFICIENT\",\n \"UPSTREAM_UNAVAILABLE\",\n \"INTERNAL_ERROR\",\n ];\n // Wire codes are platform-namespaced (`K9O_*`);\n // strip the prefix to match the SDK's bundled bare-code enum. The full wire\n // code is always preserved in `context.originalCode` for telemetry.\n const stripped = wire.code.replace(/^K9O_/, \"\");\n const isKnown = (knownCodes as ReadonlyArray<string>).includes(stripped);\n const code: GateErrorCode = isKnown ? (stripped as GateErrorCode) : \"INTERNAL_ERROR\";\n const context = { ...(wire.context ?? {}), originalCode: wire.code };\n return new GateError({\n code,\n message: wire.message,\n context,\n recommendation: wire.recommendation ?? null,\n status,\n });\n}\n"],"mappings":";AA0CO,IAAM,YAAN,cAAwB,MAAM;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EAET,YAAY,MAMT;AACD,UAAM,KAAK,OAAO;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO,KAAK;AACjB,SAAK,UAAU,OAAO,OAAO,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG,CAAC;AACxD,SAAK,iBAAiB,KAAK,kBAAkB;AAC7C,SAAK,SAAS,KAAK,UAAU;AAAA,EAC/B;AACF;AAoBO,SAAS,kBAAkB,MAAkB,QAA2B;AAC7E,QAAM,aAA2C;AAAA,IAC/C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAIA,QAAM,WAAW,KAAK,KAAK,QAAQ,SAAS,EAAE;AAC9C,QAAM,UAAW,WAAqC,SAAS,QAAQ;AACvE,QAAM,OAAsB,UAAW,WAA6B;AACpE,QAAM,UAAU,EAAE,GAAI,KAAK,WAAW,CAAC,GAAI,cAAc,KAAK,KAAK;AACnE,SAAO,IAAI,UAAU;AAAA,IACnB;AAAA,IACA,SAAS,KAAK;AAAA,IACd;AAAA,IACA,gBAAgB,KAAK,kBAAkB;AAAA,IACvC;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -13,7 +13,7 @@ function validateGateConfig(config) {
|
|
|
13
13
|
const hasSlug = typeof config.projectSlug === "string" && config.projectSlug.length > 0;
|
|
14
14
|
if (!hasSlug) {
|
|
15
15
|
throw new TypeError(
|
|
16
|
-
`Gate config missing projectSlug (required,
|
|
16
|
+
`Gate config missing projectSlug (required, slug grammar \u2014 project ids are internal-only and never customer-facing)`
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
19
|
if (typeof config.baseUrl !== "string" || config.baseUrl.length === 0) {
|
|
@@ -38,4 +38,4 @@ export {
|
|
|
38
38
|
getGateConfig,
|
|
39
39
|
resetGateConfig
|
|
40
40
|
};
|
|
41
|
-
//# sourceMappingURL=chunk-
|
|
41
|
+
//# sourceMappingURL=chunk-XP6U5QKF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mode.ts"],"sourcesContent":["/**\n * Standalone vs Native mode wiring.\n *\n * The SDK surface is identical across modes; mode determines gateway-\n * side behavior (whether the end-user row scope applies on read/write paths),\n * not SDK ergonomics. The mode boundary is a deployment-time decision\n *; the SDK does not branch behavior at function-call time.\n *\n * What mode affects (today + forward):\n *\n * - **Billing-identity routing** (commission callout):\n * Standalone customers are billed under the partner-credentialled\n * contract (Gate as Auth0/Clerk/Okta alternative — Trojan Horse\n * motion); Native customers compose with the broader Kilimanjaro\n * billing model. The SDK records the mode on every wire request via\n * the `X-Gate-Mode` header so the gateway routes consumption to the\n * correct billing surface without per-function branching.\n * - **Auto-scoping expectations** in marketing copy + docs hub copy\n * (per memory `feedback_gate_iak_brand_architecture.md` marketing-\n * honesty discipline). Standalone mode delivers Sovereign Ingress +\n * Hardware-Attested Identity + Forensic Attribution + Unlimited MAUs;\n * Native mode adds Automatic Identity-Aware Scoping on top.\n *\n * What mode does NOT affect:\n *\n * - Function names + signatures (identical across modes)\n * - Wire-envelope shape (identical)\n * - Error taxonomy (identical)\n */\n\n/**\n * Two-mode discriminant. The third candidate \"Hybrid\" was rejected per\n * memory `feedback_gate_iak_brand_architecture.md` — modes are\n * orthogonal deployment shapes, not interleaved.\n */\nexport type GateMode = \"standalone\" | \"native\";\n\n/**\n * Gate SDK configuration. Returned by `getGateConfig()` and consumed\n * internally by the HTTP client + JWT verifier. Set via `configureGate`\n * at process boot or per-test in unit tests.\n */\nexport type GateConfig = {\n mode: GateMode;\n /** Project slug per the URL grammar (e.g. `partner-console-staging`).\n * The only customer-facing project addressing form; routes resolve to\n * `/@<slug>/gate/...` (`feedback_slug_addressing_v2_5_68`). Required. */\n projectSlug: string;\n /** Gateway base URL — e.g. `https://<orgSlug>.api.k9o.io` per the URL grammar */\n baseUrl: string;\n /**\n * Optional partner-credentialled JWT for Standalone mode — used as the\n * default Authorization header when no per-call bearer is supplied.\n * Not required in Native mode; the gateway resolves credentials from\n * the standard project context.\n */\n partnerToken?: string;\n /**\n * Optional fetch override for testing + non-browser environments. The\n * SDK defaults to global `fetch` (available in Bun + Node 18+ +\n * browsers) when not set.\n */\n fetch?: typeof fetch;\n};\n\nlet _config: GateConfig | null = null;\n\n/**\n * Initialise the SDK. Must be called before any `gate.*` invocation.\n * Re-calling replaces the prior config wholesale (no per-field merge —\n * keeps the config-set-at-boot ergonomic clean).\n */\nexport function configureGate(config: GateConfig): void {\n validateGateConfig(config);\n _config = { ...config };\n}\n\n/**\n * Validate a config shape. Exposed for `createGateClient` so per-instance\n * configs go through identical checks as the singleton.\n */\nexport function validateGateConfig(config: GateConfig): void {\n if (config.mode !== \"standalone\" && config.mode !== \"native\") {\n throw new TypeError(\n `Invalid Gate mode \"${config.mode as string}\"; expected \"standalone\" or \"native\"`,\n );\n }\n const hasSlug = typeof config.projectSlug === \"string\" && config.projectSlug.length > 0;\n if (!hasSlug) {\n throw new TypeError(\n `Gate config missing projectSlug (required, slug grammar — project ids are internal-only and never customer-facing)`,\n );\n }\n if (typeof config.baseUrl !== \"string\" || config.baseUrl.length === 0) {\n throw new TypeError(`Invalid baseUrl \"${config.baseUrl}\"; expected non-empty string`);\n }\n}\n\n/**\n * Read the active config. Throws when called before `configureGate(...)`.\n * Tests can call `resetGateConfig()` to clear between cases.\n */\nexport function getGateConfig(): GateConfig {\n if (_config === null) {\n throw new Error(\n \"@k9o/gate: SDK is not configured. Call configureGate({ mode, projectSlug, baseUrl }) before invoking gate functions.\",\n );\n }\n return _config;\n}\n\n/** Reset the singleton — used by tests + by app-shutdown teardown paths. */\nexport function resetGateConfig(): void {\n _config = null;\n}\n"],"mappings":";AAiEA,IAAI,UAA6B;AAO1B,SAAS,cAAc,QAA0B;AACtD,qBAAmB,MAAM;AACzB,YAAU,EAAE,GAAG,OAAO;AACxB;AAMO,SAAS,mBAAmB,QAA0B;AAC3D,MAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,UAAU;AAC5D,UAAM,IAAI;AAAA,MACR,sBAAsB,OAAO,IAAc;AAAA,IAC7C;AAAA,EACF;AACA,QAAM,UAAU,OAAO,OAAO,gBAAgB,YAAY,OAAO,YAAY,SAAS;AACtF,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,OAAO,YAAY,YAAY,OAAO,QAAQ,WAAW,GAAG;AACrE,UAAM,IAAI,UAAU,oBAAoB,OAAO,OAAO,8BAA8B;AAAA,EACtF;AACF;AAMO,SAAS,gBAA4B;AAC1C,MAAI,YAAY,MAAM;AACpB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,kBAAwB;AACtC,YAAU;AACZ;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GateError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-JEV37YEC.js";
|
|
4
4
|
|
|
5
5
|
// src/jwt.ts
|
|
6
6
|
import { createRemoteJWKSet, jwtVerify, errors as joseErrors } from "jose";
|
|
@@ -122,4 +122,4 @@ export {
|
|
|
122
122
|
extractClaims,
|
|
123
123
|
requireScope
|
|
124
124
|
};
|
|
125
|
-
//# sourceMappingURL=chunk-
|
|
125
|
+
//# sourceMappingURL=chunk-YINWOWJC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/jwt.ts"],"sourcesContent":["/**\n * JWT verification primitives for external-app standalone consumption.\n *\n * Standalone-mode customers consume Gate-issued JWTs in their own\n * application code without needing the full SDK shape — they just need\n * to verify the signature, extract claims, and (optionally) check\n * scopes. This module is the canonical entry for that surface.\n *\n * Backed by `jose` (already a peer dependency in the gateway via the\n * same library; chose `jose` for consistency + JWK fetch support out\n * of the box).\n *\n * Native-mode customers don't typically reach for this directly — the\n * gateway verifies project-issued tokens on every request and rehydrates\n * `subject.*` claims. But the same primitives are\n * portable: Native customers running their own services downstream of\n * the gateway can verify Gate-issued JWTs identically.\n */\n\nimport { createRemoteJWKSet, jwtVerify, errors as joseErrors } from \"jose\";\nimport type { GateJwtClaims, VerifyJwtFailure, VerifyJwtResult } from \"./types.ts\";\nimport { GateError } from \"./errors.ts\";\n\n/**\n * Configuration for `verifyJwt`. The verifier can resolve signing keys\n * via either a remote JWKS URL (the typical Gate deployment shape) or\n * an inline key set (for tests + air-gapped deployments).\n */\nexport type VerifyJwtOptions = {\n token: string;\n /**\n * JWKS endpoint URL — the gateway exposes `/@<projectSlug>/gate/.well-known/jwks.json`\n * by convention. Either `jwksUrl` or `jwks` must be set; not both.\n */\n jwksUrl?: string;\n /**\n * Inline JWK set — used by tests + integration scenarios that want to\n * avoid the network hop. The shape is the standard JWKS `{keys: [...]}`\n * envelope; pass through unchanged to `jose`.\n */\n jwks?: { keys: ReadonlyArray<Record<string, unknown>> };\n /** Expected issuer (`iss` claim). Strict comparison. */\n expectedIssuer?: string;\n /** Expected audience (`aud` claim). Accepts either string or array per RFC 7519. */\n expectedAudience?: string;\n /**\n * Allowed signing algorithms. Defaults to `[\"RS256\", \"ES256\"]` per the\n * standard Gate issuer config. Reject anything outside this set\n * (defense against alg-confusion attacks).\n */\n allowedAlgorithms?: ReadonlyArray<string>;\n /**\n * Clock-skew tolerance in seconds. Defaults to 30. Applies to both\n * `exp` and `nbf` checks.\n */\n clockToleranceSeconds?: number;\n};\n\nconst DEFAULT_ALLOWED_ALGORITHMS = [\"RS256\", \"ES256\"] as const;\nconst DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;\n\n/**\n * Verify a Gate-issued JWT. Returns a typed result; does NOT throw on\n * verification failure (a `valid: false` result carries the reason).\n *\n * Throws `GateError` only when:\n * - `jwksUrl` and `jwks` are both unset or both set\n * - the JWKS fetch fails for transport reasons (UPSTREAM_UNAVAILABLE)\n */\nexport async function verifyJwt(opts: VerifyJwtOptions): Promise<VerifyJwtResult> {\n if (opts.jwksUrl !== undefined && opts.jwks !== undefined) {\n throw new GateError({\n code: \"INVALID_FIELD_VALUE\",\n message: \"verifyJwt: pass either jwksUrl OR jwks, not both\",\n context: {},\n recommendation: null,\n });\n }\n if (opts.jwksUrl === undefined && opts.jwks === undefined) {\n throw new GateError({\n code: \"INVALID_FIELD_VALUE\",\n message: \"verifyJwt: must pass exactly one of {jwksUrl, jwks}\",\n context: {},\n recommendation: null,\n });\n }\n\n const allowedAlgorithms = opts.allowedAlgorithms ?? DEFAULT_ALLOWED_ALGORITHMS;\n const clockTolerance = opts.clockToleranceSeconds ?? DEFAULT_CLOCK_TOLERANCE_SECONDS;\n\n let keyResolver: Parameters<typeof jwtVerify>[1];\n if (opts.jwksUrl !== undefined) {\n keyResolver = createRemoteJWKSet(new URL(opts.jwksUrl));\n } else {\n // Inline JWKS — implement the resolver inline since `jose`'s\n // `createLocalJWKSet` import path varies across versions.\n keyResolver = makeLocalJwksResolver(opts.jwks!);\n }\n\n try {\n const result = await jwtVerify(opts.token, keyResolver, {\n ...(opts.expectedIssuer !== undefined ? { issuer: opts.expectedIssuer } : {}),\n ...(opts.expectedAudience !== undefined ? { audience: opts.expectedAudience } : {}),\n algorithms: allowedAlgorithms as string[],\n clockTolerance,\n });\n return { valid: true, claims: result.payload as GateJwtClaims };\n } catch (e) {\n return { valid: false, reason: classifyJoseFailure(e) };\n }\n}\n\n/**\n * Extract claims from a JWT WITHOUT verifying the signature. Used by\n * SDK consumers that want to read claim data in client code where\n * signature verification has already happened at a trusted hop (e.g.,\n * a reverse proxy). Caller is responsible for confirming the upstream\n * trust path before consuming these claims for security decisions.\n *\n * Throws `GateError` on malformed input.\n */\nexport function extractClaims(token: string): GateJwtClaims {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n throw new GateError({\n code: \"INVALID_FIELD_VALUE\",\n message: `Malformed JWT: expected 3 dot-separated parts, got ${parts.length}`,\n context: {},\n recommendation: null,\n });\n }\n try {\n const payloadJson = base64UrlDecode(parts[1]!);\n return JSON.parse(payloadJson) as GateJwtClaims;\n } catch (e) {\n throw new GateError({\n code: \"INVALID_FIELD_VALUE\",\n message: `Malformed JWT payload: ${e instanceof Error ? e.message : String(e)}`,\n context: {},\n recommendation: null,\n });\n }\n}\n\n/**\n * Assert that the given claim set contains all of the required scopes.\n * Throws `GateError` with `code: \"RBAC_DENY\"` if any scope is missing.\n * Returns nothing on success — caller uses the throw-or-pass shape.\n */\nexport function requireScope(\n claims: GateJwtClaims,\n requiredScopes: ReadonlyArray<string>,\n): void {\n const present = new Set(claims.scopes ?? []);\n const missing = requiredScopes.filter((s) => !present.has(s));\n if (missing.length > 0) {\n throw new GateError({\n code: \"RBAC_DENY\",\n message: `Required scopes missing: ${missing.join(\", \")}`,\n context: { missingScopes: missing, presentScopes: Array.from(present) },\n recommendation: null,\n });\n }\n}\n\n// ----------------------------------------------------------------------\n// Internals\n// ----------------------------------------------------------------------\n\nfunction classifyJoseFailure(e: unknown): VerifyJwtFailure {\n // Map `jose`'s typed errors to our closed reason set per `VerifyJwtFailure`.\n if (e instanceof joseErrors.JWSSignatureVerificationFailed) return \"INVALID_SIGNATURE\";\n if (e instanceof joseErrors.JWTExpired) return \"EXPIRED\";\n if (e instanceof joseErrors.JWTClaimValidationFailed) {\n const claim = (e as { claim?: string }).claim;\n if (claim === \"aud\") return \"AUDIENCE_MISMATCH\";\n if (claim === \"iss\") return \"ISSUER_MISMATCH\";\n if (claim === \"nbf\") return \"NOT_YET_VALID\";\n return \"MALFORMED\";\n }\n if (e instanceof joseErrors.JOSEAlgNotAllowed) return \"ALGORITHM_NOT_ALLOWED\";\n // Fallback — `jose` raises other errors (parse failures, KID mismatches,\n // etc.) that we lump into `MALFORMED` rather than leaking the per-version\n // taxonomy.\n return \"MALFORMED\";\n}\n\nfunction base64UrlDecode(input: string): string {\n // Pad to a multiple of 4 + swap urlsafe alphabet -> standard alphabet.\n const padded = input + \"=\".repeat((4 - (input.length % 4)) % 4);\n const standard = padded.replace(/-/g, \"+\").replace(/_/g, \"/\");\n // Bun + Node 18+ + browsers all expose `atob`.\n const binary = globalThis.atob(standard);\n // Reassemble bytes back to UTF-8 text.\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder(\"utf-8\").decode(bytes);\n}\n\n/**\n * Build a key resolver compatible with `jose.jwtVerify` from an inline\n * JWKS object. `jose` exports `createLocalJWKSet` from its main module\n * but the import path / type shape can shift across minors; reimplement\n * the minimal resolver here for stability.\n */\nfunction makeLocalJwksResolver(\n jwks: { keys: ReadonlyArray<Record<string, unknown>> },\n): Parameters<typeof jwtVerify>[1] {\n // The `jose` resolver signature is `(header, token) => Promise<KeyLike>`\n // — pull the kid from the header, match against the JWKS, and import.\n return async (header) => {\n const { importJWK } = await import(\"jose\");\n const kid = (header as { kid?: string }).kid;\n let match: Record<string, unknown> | undefined;\n if (kid !== undefined) {\n match = jwks.keys.find((k) => k[\"kid\"] === kid);\n }\n if (match === undefined && jwks.keys.length === 1) {\n // Single-key JWKS — return the only key. Tests typically ship one\n // key in the inline set and may not bother with `kid`.\n match = jwks.keys[0];\n }\n if (match === undefined) {\n throw new joseErrors.JWKSNoMatchingKey(\"No matching key in inline JWKS for kid\");\n }\n const alg = (header as { alg?: string }).alg ?? (match[\"alg\"] as string | undefined);\n return importJWK(match as unknown as Parameters<typeof importJWK>[0], alg);\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Gate error shapes. `GateError` is `KError`-compatible
|
|
2
|
+
* Gate error shapes. `GateError` is `KError`-compatible —
|
|
3
3
|
* downstream catch blocks can `instanceof GateError`-narrow without
|
|
4
4
|
* importing the gateway's `KError` class directly (the SDK is a customer-
|
|
5
5
|
* facing dependency; reaching across to the gateway's internal error
|
|
6
6
|
* type would be a layering violation).
|
|
7
7
|
*
|
|
8
|
-
* The taxonomy below is the
|
|
9
|
-
*
|
|
8
|
+
* The taxonomy below is the closed set; additions follow the
|
|
9
|
+
* error-catalogue freeze cycle.
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
|
-
* Closed-taxonomy error code
|
|
12
|
+
* Closed-taxonomy error code. Strings are the wire format —
|
|
13
13
|
* camelCase-cased KError families per the convention.
|
|
14
14
|
*/
|
|
15
15
|
type GateErrorCode = "UNAUTHENTICATED" | "INVALID_FIELD_VALUE" | "EMAIL_ALREADY_REGISTERED" | "INVALID_CREDENTIALS" | "SESSION_EXPIRED" | "REFRESH_TOKEN_INVALID" | "TIER_FEATURE_GATED" | "RBAC_DENY" | "FORBIDDEN" | "NOT_FOUND" | "GATE_REDIRECT_NOT_ALLOWED" | "POLICY_AUTHORING_AUTHORITY_INSUFFICIENT" | "UPSTREAM_UNAVAILABLE" | "INTERNAL_ERROR";
|
|
16
16
|
/**
|
|
17
17
|
* Surface error thrown by the SDK. Mirrors the gateway's `KError` shape
|
|
18
|
-
*
|
|
18
|
+
* — `code` (closed taxonomy), `message` (human-readable),
|
|
19
19
|
* `context` (structured per-code payload), `recommendation` (action the
|
|
20
20
|
* caller can take, or null when there's no canonical recommendation).
|
|
21
21
|
*/
|