@rekey.dev/node 2.1.0 → 2.2.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -6
- package/dist/index.d.ts +530 -96
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +553 -98
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @rekey.dev/node
|
|
2
|
+
* @rekey.dev/node, server SDK for Rekey.
|
|
3
3
|
*
|
|
4
4
|
* One client instance per Application. Construct with the Application's
|
|
5
5
|
* secret key (`rp_live_…` or `rp_test_…`) and the URL of your Rekey
|
|
6
|
-
* deployment. Never ship the secret key to the browser
|
|
6
|
+
* deployment. Never ship the secret key to the browser, for browser code
|
|
7
7
|
* use `@rekey.dev/react` with the Application's public key instead.
|
|
8
8
|
*
|
|
9
9
|
* @example Smoke-test your credentials
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
* console.log(`Connected to "${me.name}" (${me.slug})`);
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
-
import type { ApplicationDto, AuthResultDto, ListPage, Paged, JwksDto, ChangePasswordRequest, CheckoutResultDto, ConsumeCreditsRequest, ConsumeCreditsResultDto, CreateCheckoutRequest, CreditBalanceDto, CreditLedgerEntryDto, EndUserDto, ForgotPasswordRequest, ForgotPasswordResultDto, LicenseVerifyResultDto, MfaVerifyRequest, OAuthAuthServerMetadata, OAuthIntrospectionResponse, OrganizationDto, OrganizationInvitationDto, OrganizationMemberDto, OrganizationWithRoleDto, OrganizationRoleDefDto, OrganizationRole, OrganizationBaseRole,
|
|
22
|
+
import type { ApplicationDto, AuthResultDto, MeInclude, MeIncludedFor, ListPage, Paged, JwksDto, ChangePasswordRequest, CheckoutResultDto, ConsumeCreditsRequest, ConsumeCreditsResultDto, CreateCheckoutRequest, CreditBalanceDto, CreditLedgerEntryDto, CurrentUserDto, EndUserDto, EndUserLicenseDto, FeatureCheckDto, ForgotPasswordRequest, ForgotPasswordResultDto, LicenseVerifyResultDto, LicenseDeactivateRequest, LicenseDeactivateResultDto, DeviceDto, EndUserDeviceDto, TrialEligibilityDto, DeviceStatusType, MfaVerifyRequest, OAuthAuthServerMetadata, OAuthIntrospectionResponse, OrganizationDto, OrganizationInvitationDto, OrganizationMemberDto, OrganizationWithRoleDto, OrganizationRoleDefDto, OrganizationRole, OrganizationBaseRole, PublicPlanDto, ProvidersListDto, ResetPasswordRequest, SignInOutcomeDto, SignInRequest, DeviceBindingRequest, SignUpRequest, SubscriptionDto, UsageAggregateDto, UsageMeterCatalogueEntryDto, UsageRecordDto, UsageRemainingDto, KeyGrantCreditsRequest, SelfCreditLedgerEntryDto, ValidateCouponRequest, ValidateCouponResultDto } from '@rekey.dev/shared-types';
|
|
23
23
|
import { RekeyError } from '@rekey.dev/shared-types/error';
|
|
24
|
-
export type { ApplicationDto, EndUserDto, ApiKeyDto, AuthResultDto, MfaChallengeResultDto, MfaVerifyRequest, SignInOutcomeDto, SignInRequest, SignUpRequest, RefreshRequest, ForgotPasswordRequest, ForgotPasswordResultDto, ResetPasswordRequest, ChangePasswordRequest, PlanDto, SubscriptionDto, CreateCheckoutRequest, CheckoutResultDto, CouponDto, ProvidersListDto, BillingProviderInfoDto, ValidateCouponRequest, ValidateCouponResultDto, CouponDiscountTypeValue, PlanIntervalType, PlanKindType, LicenseKindType, CreditReasonType, CreditBalanceDto, CreditLedgerEntryDto, ConsumeCreditsRequest, ConsumeCreditsResultDto, OrganizationDto, OrganizationWithRoleDto, OrganizationRoleDefDto, OrganizationMemberDto, OrganizationInvitationDto, OrganizationRole, OrganizationBaseRole, LicenseDto, LicenseStatusType, LicenseVerifyResultDto, UsageRecordDto, UsageAggregateDto, SubscriptionStatusType, RekeyErrorShape, AuthConfig, BillingConfig, BillingProvider, TokenAlg, JwkRsaPublic, JwksDto, OAuthIntrospectionResponse, OAuthAuthServerMetadata, } from '@rekey.dev/shared-types';
|
|
24
|
+
export type { ApplicationDto, EndUserDto, CurrentUserDto, EndUserLicenseDto, FeatureCheckDto, PublicPlanDto, PublicPlanCheckoutDto, MeInclude, MeIncluded, MeIncludedFor, MeIncludedFields, ResolvedEntitlementsDto, ApiKeyDto, AuthResultDto, MfaChallengeResultDto, MfaVerifyRequest, SignInOutcomeDto, SignInRequest, DeviceBindingRequest, SignUpRequest, RefreshRequest, ForgotPasswordRequest, ForgotPasswordResultDto, ResetPasswordRequest, ChangePasswordRequest, PlanDto, SubscriptionDto, CreateCheckoutRequest, CheckoutResultDto, CouponDto, ProvidersListDto, BillingProviderInfoDto, ValidateCouponRequest, ValidateCouponResultDto, BillingProviderCapabilities, TrialEligibilityDto, TrialEligibilityItemDto, TrialPolicyType, CouponDiscountTypeValue, PlanIntervalType, PlanKindType, LicenseKindType, CreditReasonType, CreditBalanceDto, CreditLedgerEntryDto, ConsumeCreditsRequest, ConsumeCreditsResultDto, OrganizationDto, OrganizationWithRoleDto, OrganizationRoleDefDto, OrganizationMemberDto, OrganizationInvitationDto, OrganizationRole, OrganizationBaseRole, LicenseDto, LicenseStatusType, LicenseVerifyResultDto, LicenseActivationDto, LicenseDeactivateRequest, LicenseDeactivateResultDto, DeviceDto, EndUserDeviceDto, DeviceLimitDetails, DeviceStatusType, UsageRecordDto, UsageAggregateDto, UsageRemainingDto, UsageMeterRemainingDto, UsageMeterCatalogueEntryDto, KeyGrantCreditsRequest, SelfCreditLedgerEntryDto, CreditWebhookData, SubscriptionStatusType, RekeyErrorShape, AuthConfig, BillingConfig, BillingProvider, TokenAlg, JwkRsaPublic, JwksDto, OAuthIntrospectionResponse, OAuthAuthServerMetadata, } from '@rekey.dev/shared-types';
|
|
25
25
|
/**
|
|
26
26
|
* Default per-request deadline, in milliseconds. Matches the timeout the Rekey
|
|
27
27
|
* API itself uses when it POSTs your outbound webhooks.
|
|
28
28
|
*
|
|
29
|
-
* Without a deadline the effective timeout is undici's `headersTimeout
|
|
30
|
-
* minutes
|
|
29
|
+
* Without a deadline the effective timeout is undici's `headersTimeout`, five
|
|
30
|
+
* minutes, so a single unreachable Rekey deployment can pin one of your
|
|
31
31
|
* request handlers for that long. Ten seconds is long enough for any endpoint
|
|
32
32
|
* this SDK calls and short enough to fail a page instead of hanging it.
|
|
33
33
|
*/
|
|
@@ -36,13 +36,13 @@ export declare const DEFAULT_TIMEOUT_MS = 10000;
|
|
|
36
36
|
export interface RekeyConfig {
|
|
37
37
|
/** Base URL of the Rekey API. e.g. `https://rekey.example.com` */
|
|
38
38
|
apiUrl: string;
|
|
39
|
-
/** Secret key for one Application
|
|
39
|
+
/** Secret key for one Application, `rp_live_…` or `rp_test_…`. Never ship to the browser. */
|
|
40
40
|
secretKey: string;
|
|
41
41
|
/** Optional fetch override (test stubs, custom keep-alive agents, etc.). */
|
|
42
42
|
fetch?: typeof fetch;
|
|
43
43
|
/**
|
|
44
44
|
* Deadline for every request this client makes, in milliseconds.
|
|
45
|
-
* Default {@link DEFAULT_TIMEOUT_MS} (10 000). Pass `0` to disable
|
|
45
|
+
* Default {@link DEFAULT_TIMEOUT_MS} (10 000). Pass `0` to disable, only do
|
|
46
46
|
* that if something upstream of you already bounds the call.
|
|
47
47
|
*
|
|
48
48
|
* On expiry the promise rejects with a `RekeyError` whose code is
|
|
@@ -50,7 +50,7 @@ export interface RekeyConfig {
|
|
|
50
50
|
*/
|
|
51
51
|
timeoutMs?: number | undefined;
|
|
52
52
|
/**
|
|
53
|
-
* Client-wide abort signal
|
|
53
|
+
* Client-wide abort signal, aborting it cancels every in-flight request
|
|
54
54
|
* (server shutdown, request-scoped cancellation). Composed with, not
|
|
55
55
|
* replaced by, any per-call `signal`.
|
|
56
56
|
*/
|
|
@@ -62,7 +62,7 @@ export interface RekeyConfig {
|
|
|
62
62
|
* addable without a new overload.
|
|
63
63
|
*/
|
|
64
64
|
export interface RekeyRequestOptions {
|
|
65
|
-
/** JSON request body. Omit for GET/DELETE
|
|
65
|
+
/** JSON request body. Omit for GET/DELETE, a present body sets `Content-Type`. */
|
|
66
66
|
body?: unknown;
|
|
67
67
|
/** Extra headers, merged over the SDK's own (`Authorization`, `Content-Type`). */
|
|
68
68
|
headers?: Record<string, string> | undefined;
|
|
@@ -80,7 +80,7 @@ export interface RekeyCallOptions {
|
|
|
80
80
|
}
|
|
81
81
|
export { RekeyError };
|
|
82
82
|
/**
|
|
83
|
-
* Outbound webhook event registry
|
|
83
|
+
* Outbound webhook event registry, the events Rekey can POST to your app
|
|
84
84
|
* (verify them with `verifyWebhookSignature` below). `WEBHOOK_EVENTS` carries
|
|
85
85
|
* `{ name, description }` pairs for introspection/autocomplete;
|
|
86
86
|
* `KNOWN_WEBHOOK_EVENTS` is just the names. Mirrors the API's registry exactly.
|
|
@@ -89,7 +89,7 @@ export { RekeyError };
|
|
|
89
89
|
* ```ts
|
|
90
90
|
* import { WEBHOOK_EVENTS, isKnownWebhookEvent, type WebhookEventEnvelope } from '@rekey.dev/node';
|
|
91
91
|
*
|
|
92
|
-
* for (const e of WEBHOOK_EVENTS) console.log(`${e.name}
|
|
92
|
+
* for (const e of WEBHOOK_EVENTS) console.log(`${e.name}, ${e.description}`);
|
|
93
93
|
*
|
|
94
94
|
* const event = req.body as WebhookEventEnvelope; // after verifyWebhookSignature(...)
|
|
95
95
|
* if (event.type === 'subscription.activated') unlockPlan(event.data);
|
|
@@ -102,7 +102,7 @@ export type { WebhookEventType, WebhookEventEnvelope } from '@rekey.dev/shared-t
|
|
|
102
102
|
* this subscriber the rest of the period they paid for?
|
|
103
103
|
*
|
|
104
104
|
* Exported because a cancel confirmation has to say which outcome the customer
|
|
105
|
-
* is about to get, and it has to say so BEFORE the call
|
|
105
|
+
* is about to get, and it has to say so BEFORE the call, there is no response
|
|
106
106
|
* to read it off. It is the same function the API decides from, not a
|
|
107
107
|
* description of it, so a UI built on it cannot promise a behaviour the server
|
|
108
108
|
* does not have. See its docblock for the cases that still end immediately.
|
|
@@ -131,23 +131,27 @@ export declare class Rekey {
|
|
|
131
131
|
private readonly config;
|
|
132
132
|
/** Operations on the calling Application itself. */
|
|
133
133
|
readonly applications: ApplicationsClient;
|
|
134
|
-
/** Auth operations
|
|
134
|
+
/** Auth operations, sign-in, sign-up, sessions, passkeys, magic-link. */
|
|
135
135
|
readonly auth: AuthClient;
|
|
136
|
-
/** Billing operations
|
|
136
|
+
/** Billing operations, plans, checkout, subscriptions, coupons. */
|
|
137
137
|
readonly billing: BillingClient;
|
|
138
|
-
/** End-user organizations
|
|
138
|
+
/** End-user organizations, create, invite, members, role changes. */
|
|
139
139
|
readonly organizations: OrganizationsClient;
|
|
140
140
|
/** License key verification + activation. */
|
|
141
141
|
readonly licenses: LicensesClient;
|
|
142
|
-
/**
|
|
142
|
+
/** Devices, list and release the machines an end-user signs in from. */
|
|
143
|
+
readonly devices: DevicesClient;
|
|
144
|
+
/** End-users, lookup by id or email, bulk import. */
|
|
145
|
+
readonly users: UsersClient;
|
|
146
|
+
/** Usage metering, record events, aggregate windows. */
|
|
143
147
|
readonly usage: UsageClient;
|
|
144
|
-
/** Prepaid credits
|
|
148
|
+
/** Prepaid credits, balance reads, idempotent drawdown, ledger. */
|
|
145
149
|
readonly credits: CreditsClient;
|
|
146
|
-
/** MCP
|
|
150
|
+
/** MCP, validate Rekey-issued MCP tokens from your own MCP server. */
|
|
147
151
|
readonly mcp: McpClient;
|
|
148
152
|
constructor(config: RekeyConfig);
|
|
149
153
|
/**
|
|
150
|
-
* A clone of this client with different call options
|
|
154
|
+
* A clone of this client with different call options, the per-call knob for
|
|
151
155
|
* every wrapped method.
|
|
152
156
|
*
|
|
153
157
|
* Each namespace method (`billing.getPlans()`, `auth.signIn()`, …) has a
|
|
@@ -167,7 +171,7 @@ export declare class Rekey {
|
|
|
167
171
|
* });
|
|
168
172
|
* ```
|
|
169
173
|
*
|
|
170
|
-
* Cheap
|
|
174
|
+
* Cheap, it rebuilds the namespace objects, holds no connections, and
|
|
171
175
|
* shares the same `fetch`.
|
|
172
176
|
*/
|
|
173
177
|
with(options: RekeyCallOptions): Rekey;
|
|
@@ -175,7 +179,7 @@ export declare class Rekey {
|
|
|
175
179
|
* Call a Rekey endpoint this SDK does not wrap yet.
|
|
176
180
|
*
|
|
177
181
|
* This is a **supported** escape hatch, not an internal: when the API grows a
|
|
178
|
-
* route before the SDK does, use this instead of hand-rolling `fetch
|
|
182
|
+
* route before the SDK does, use this instead of hand-rolling `fetch`, you
|
|
179
183
|
* keep the auth header, the `{ success, data }` unwrapping, the `RekeyError`
|
|
180
184
|
* mapping (including transport failures) and the deadline. It takes an
|
|
181
185
|
* options object precisely so a future knob does not need a new overload.
|
|
@@ -200,7 +204,7 @@ export declare class Rekey {
|
|
|
200
204
|
}
|
|
201
205
|
/**
|
|
202
206
|
* MCP helpers for customers running their OWN MCP server behind Rekey auth.
|
|
203
|
-
* The hosted MCP server (account tools) is consumed by MCP clients directly
|
|
207
|
+
* The hosted MCP server (account tools) is consumed by MCP clients directly,
|
|
204
208
|
* this client is for the "bring your own MCP server" path: validate incoming
|
|
205
209
|
* Rekey-issued tokens, and read the OAuth metadata.
|
|
206
210
|
*/
|
|
@@ -230,7 +234,7 @@ declare class ApplicationsClient {
|
|
|
230
234
|
constructor(client: Rekey);
|
|
231
235
|
/**
|
|
232
236
|
* Verify credentials and fetch the calling Application. Use this as your
|
|
233
|
-
* SDK smoke test
|
|
237
|
+
* SDK smoke test, if it returns, your secret key is good and you're
|
|
234
238
|
* pointed at the right Rekey deployment.
|
|
235
239
|
*
|
|
236
240
|
* @example
|
|
@@ -252,7 +256,7 @@ declare class AuthClient {
|
|
|
252
256
|
* (e.g. `getCurrentUser(accessToken)`) and a `refreshToken` to renew it.
|
|
253
257
|
*
|
|
254
258
|
* Unless the Application turns `authConfig.sendVerificationEmailOnSignUp`
|
|
255
|
-
* off, Rekey also emails the verification link
|
|
259
|
+
* off, Rekey also emails the verification link, best-effort, so it never
|
|
256
260
|
* fails the sign-up, and `sendVerificationEmail` re-sends on demand.
|
|
257
261
|
*
|
|
258
262
|
* @example
|
|
@@ -261,7 +265,7 @@ declare class AuthClient {
|
|
|
261
265
|
* email: 'alice@example.com',
|
|
262
266
|
* password: 'correct-horse-battery-staple',
|
|
263
267
|
* });
|
|
264
|
-
* // store both in your session
|
|
268
|
+
* // store both in your session, the access token expires in 15 minutes
|
|
265
269
|
* ```
|
|
266
270
|
*
|
|
267
271
|
* @throws {RekeyError} `EMAIL_ALREADY_EXISTS` (409) if the email is taken in this Application.
|
|
@@ -278,14 +282,14 @@ declare class AuthClient {
|
|
|
278
282
|
* Prompt the user for their TOTP / backup code and call
|
|
279
283
|
* `mfaVerify({ mfaChallengeToken, code })` to receive a real session.
|
|
280
284
|
*
|
|
281
|
-
* **Branch on `result.mfaRequired` before reading `accessToken
|
|
285
|
+
* **Branch on `result.mfaRequired` before reading `accessToken`**, the
|
|
282
286
|
* MFA-required branch has no session tokens.
|
|
283
287
|
*
|
|
284
|
-
* @throws {RekeyError} `INVALID_CREDENTIALS` (401)
|
|
288
|
+
* @throws {RekeyError} `INVALID_CREDENTIALS` (401), single code on purpose.
|
|
285
289
|
* Don't try to distinguish wrong-email from wrong-password from the SDK side either.
|
|
286
290
|
* @throws {RekeyError} `EMAIL_NOT_VERIFIED` (403) when the Application sets
|
|
287
291
|
* `authConfig.requireEmailVerification` and the user hasn't confirmed their
|
|
288
|
-
* address. The password was correct
|
|
292
|
+
* address. The password was correct, prompt for the emailed link (or call
|
|
289
293
|
* `sendVerificationEmail`), not for the password again.
|
|
290
294
|
*/
|
|
291
295
|
signIn(input: SignInRequest): Promise<SignInOutcomeDto>;
|
|
@@ -316,18 +320,23 @@ declare class AuthClient {
|
|
|
316
320
|
magicLinkToken: string | null;
|
|
317
321
|
}>;
|
|
318
322
|
/**
|
|
319
|
-
* Consume a magic-link token. Returns `SignInOutcome
|
|
323
|
+
* Consume a magic-link token. Returns `SignInOutcome`, branch on
|
|
320
324
|
* `mfaRequired` before reading `accessToken`. For MFA-enrolled users
|
|
321
325
|
* the response carries `mfaChallengeToken` and you must complete via
|
|
322
326
|
* `mfaVerify(...)`.
|
|
323
327
|
*/
|
|
324
328
|
verifyMagicLink(input: {
|
|
325
329
|
token: string;
|
|
330
|
+
/** Bind the session to a device, see docs/devices.md. */
|
|
331
|
+
device?: {
|
|
332
|
+
fingerprint: string;
|
|
333
|
+
label?: string;
|
|
334
|
+
};
|
|
326
335
|
}): Promise<SignInOutcomeDto>;
|
|
327
336
|
/**
|
|
328
337
|
* Begin a passkey authentication ceremony. Returns the WebAuthn options
|
|
329
338
|
* to forward to the browser (`navigator.credentials.get(...)`) along
|
|
330
|
-
* with `expectedChallenge
|
|
339
|
+
* with `expectedChallenge`, bind the challenge to your session and
|
|
331
340
|
* pass both back via `verifyPasskeyAuthentication(...)`.
|
|
332
341
|
*/
|
|
333
342
|
startPasskeyAuthentication(input?: {
|
|
@@ -338,12 +347,17 @@ declare class AuthClient {
|
|
|
338
347
|
}>;
|
|
339
348
|
/**
|
|
340
349
|
* Complete a passkey authentication. Returns the same `SignInOutcome`
|
|
341
|
-
* shape as `signIn
|
|
350
|
+
* shape as `signIn`, but passkeys are themselves a strong factor, so
|
|
342
351
|
* `mfaRequired` will always be `false` in practice.
|
|
343
352
|
*/
|
|
344
353
|
verifyPasskeyAuthentication(input: {
|
|
345
354
|
response: unknown;
|
|
346
355
|
expectedChallenge: string;
|
|
356
|
+
/** Bind the session to a device, see docs/devices.md. */
|
|
357
|
+
device?: {
|
|
358
|
+
fingerprint: string;
|
|
359
|
+
label?: string;
|
|
360
|
+
};
|
|
347
361
|
}): Promise<SignInOutcomeDto>;
|
|
348
362
|
/**
|
|
349
363
|
* Begin a passkey registration ceremony for an authenticated user.
|
|
@@ -366,7 +380,7 @@ declare class AuthClient {
|
|
|
366
380
|
/**
|
|
367
381
|
* List the user's registered passkeys, newest first.
|
|
368
382
|
*
|
|
369
|
-
* Returns `{items, page}
|
|
383
|
+
* Returns `{items, page}`, `page.total` is the number of passkeys the user
|
|
370
384
|
* has, independent of the window served.
|
|
371
385
|
*/
|
|
372
386
|
listPasskeys(accessToken: string, page?: ListPage): Promise<Paged<{
|
|
@@ -383,15 +397,37 @@ declare class AuthClient {
|
|
|
383
397
|
/**
|
|
384
398
|
* Resolve the end-user behind a presented access token.
|
|
385
399
|
*
|
|
386
|
-
*
|
|
400
|
+
* Pass `include` to get more of what a backend needs to authorise the
|
|
401
|
+
* request in the same round trip: `entitlements` (as `billing.getEntitlements`
|
|
402
|
+
* returns them), `device` (the device the session is bound to, or null),
|
|
403
|
+
* `subscription` (as `billing.getSubscription` returns it), `organization`
|
|
404
|
+
* (the active organization with the caller's role) and `licenses` (as
|
|
405
|
+
* `{ items, truncated }`, the first 100 of `licenses.listMine`). With a literal list
|
|
406
|
+
* (inline or `as const`) the return type gains exactly those properties;
|
|
407
|
+
* with a list typed `MeInclude[]` they are optional, since the compiler
|
|
408
|
+
* cannot know which it holds.
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* ```ts
|
|
412
|
+
* const me = await rekey.auth.getCurrentUser(accessToken, { include: ['entitlements', 'device'] });
|
|
413
|
+
* if (!me.entitlements.features.reports) throw new Forbidden();
|
|
414
|
+
* me.device?.status; // 'ACTIVE' when bound; a released or blocked device is a 401 instead
|
|
415
|
+
* ```
|
|
416
|
+
*
|
|
417
|
+
* @throws {RekeyError} `USER_TOKEN_INVALID` (401) if expired/forged/wrong-secret, or
|
|
418
|
+
* if the session's device was released or blocked.
|
|
387
419
|
* @throws {RekeyError} `USER_TOKEN_WRONG_APPLICATION` (401) if the token was issued
|
|
388
420
|
* by a different Application than the calling secret key represents.
|
|
421
|
+
* @throws {RekeyError} `VALIDATION_ERROR` (400) for an unknown `include` value.
|
|
422
|
+
* @throws {RekeyError} `BILLING_DISABLED` (403) or `API_KEY_SCOPE_INSUFFICIENT` (403)
|
|
423
|
+
* when `entitlements`, `subscription` or `licenses` is asked for and billing is off,
|
|
424
|
+
* or the key lacks `billing:read`.
|
|
389
425
|
*/
|
|
390
|
-
getCurrentUser(accessToken: string
|
|
391
|
-
|
|
392
|
-
}
|
|
426
|
+
getCurrentUser<const L extends readonly MeInclude[] = []>(accessToken: string, options?: {
|
|
427
|
+
include?: L;
|
|
428
|
+
}): Promise<CurrentUserDto & MeIncludedFor<L>>;
|
|
393
429
|
/**
|
|
394
|
-
* Update the end-user behind a presented access token
|
|
430
|
+
* Update the end-user behind a presented access token, their OWN record,
|
|
395
431
|
* and only ever their own: the token identifies the subject, so there is no
|
|
396
432
|
* user id to pass and no way to aim this at anyone else.
|
|
397
433
|
*
|
|
@@ -419,21 +455,21 @@ declare class AuthClient {
|
|
|
419
455
|
*/
|
|
420
456
|
updateCurrentUser(accessToken: string, input: {
|
|
421
457
|
metadata?: Record<string, unknown> | null;
|
|
422
|
-
}): Promise<
|
|
423
|
-
activeOrganizationId: string | null;
|
|
424
|
-
}>;
|
|
458
|
+
}): Promise<CurrentUserDto>;
|
|
425
459
|
/**
|
|
426
460
|
* Exchange a refresh token for a fresh {access, refresh} pair. The presented
|
|
427
|
-
* refresh is revoked atomically
|
|
461
|
+
* refresh is revoked atomically, call this **once** and store the new
|
|
428
462
|
* `refreshToken` from the response immediately.
|
|
429
463
|
*
|
|
430
464
|
* @throws {RekeyError} `REFRESH_TOKEN_REUSED` (401) if you replay an already-used token.
|
|
431
465
|
* This is a strong signal the original was leaked; treat as compromise.
|
|
432
466
|
* @throws {RekeyError} `REFRESH_TOKEN_EXPIRED` (401) after the 30-day refresh window.
|
|
433
467
|
*/
|
|
434
|
-
refresh(refreshToken: string
|
|
468
|
+
refresh(refreshToken: string, options?: {
|
|
469
|
+
device?: DeviceBindingRequest;
|
|
470
|
+
}): Promise<AuthResultDto>;
|
|
435
471
|
/**
|
|
436
|
-
* Revoke a refresh token. Idempotent
|
|
472
|
+
* Revoke a refresh token. Idempotent, no-op for unknown tokens. The
|
|
437
473
|
* access token paired with this refresh remains valid until its short
|
|
438
474
|
* (15 min) expiry; for true "log out everywhere" semantics, also clear
|
|
439
475
|
* the access token from your client.
|
|
@@ -442,14 +478,14 @@ declare class AuthClient {
|
|
|
442
478
|
signedOut: true;
|
|
443
479
|
}>;
|
|
444
480
|
/**
|
|
445
|
-
* Request a password reset for an email. Always succeeds
|
|
481
|
+
* Request a password reset for an email. Always succeeds, never tells you
|
|
446
482
|
* whether the email exists.
|
|
447
483
|
*
|
|
448
484
|
* **Branch on the result.** When the Application has an email transport
|
|
449
485
|
* (BYO Resend/SMTP, or a deployment-wide `RESEND_DEFAULT_API_KEY`) Rekey sends
|
|
450
486
|
* the mail itself and `resetToken` is null. With no transport it falls back to
|
|
451
|
-
* the original contract and hands the raw token to you
|
|
452
|
-
* only
|
|
487
|
+
* the original contract and hands the raw token to you, a secret-key caller
|
|
488
|
+
* only, so you can deliver it with your own provider.
|
|
453
489
|
*
|
|
454
490
|
* @example
|
|
455
491
|
* ```ts
|
|
@@ -473,7 +509,7 @@ declare class AuthClient {
|
|
|
473
509
|
}>;
|
|
474
510
|
/**
|
|
475
511
|
* Authenticated password change. Pass the user's *current* access token.
|
|
476
|
-
* On success, every refresh token for the user is revoked
|
|
512
|
+
* On success, every refresh token for the user is revoked, other devices
|
|
477
513
|
* are signed out.
|
|
478
514
|
*/
|
|
479
515
|
changePassword(accessToken: string, input: ChangePasswordRequest): Promise<{
|
|
@@ -481,8 +517,8 @@ declare class AuthClient {
|
|
|
481
517
|
}>;
|
|
482
518
|
/**
|
|
483
519
|
* Revoke every refresh token for the calling user. "Sign out of all
|
|
484
|
-
* devices." The caller's access token remains valid until 15-min expiry
|
|
485
|
-
*
|
|
520
|
+
* devices." The caller's access token remains valid until 15-min expiry,
|
|
521
|
+
* clear it client-side for full logout.
|
|
486
522
|
*/
|
|
487
523
|
signOutEverywhere(accessToken: string): Promise<{
|
|
488
524
|
revokedCount: number;
|
|
@@ -503,7 +539,7 @@ declare class AuthClient {
|
|
|
503
539
|
verificationToken: string | null;
|
|
504
540
|
}>;
|
|
505
541
|
/**
|
|
506
|
-
* Re-send a verification link to an address, with **no session
|
|
542
|
+
* Re-send a verification link to an address, with **no session**, the
|
|
507
543
|
* sessionless sibling of `sendVerificationEmail`.
|
|
508
544
|
*
|
|
509
545
|
* This is the route for a user locked out by
|
|
@@ -511,17 +547,17 @@ declare class AuthClient {
|
|
|
511
547
|
* session `sendVerificationEmail` needs, so a user whose first mail never
|
|
512
548
|
* arrived cannot ask for another. Takes the address instead of a token.
|
|
513
549
|
*
|
|
514
|
-
* **Branch on the result**, exactly as with `requestPasswordReset
|
|
550
|
+
* **Branch on the result**, exactly as with `requestPasswordReset`, the
|
|
515
551
|
* contract is the same one. It never throws for an unknown address and never
|
|
516
552
|
* discloses whether the address exists, is already verified, or was mailed:
|
|
517
553
|
* a publishable-key caller gets one constant body whatever happened. A
|
|
518
|
-
* secret-key caller
|
|
554
|
+
* secret-key caller, this SDK, gets the real outcome, and the raw
|
|
519
555
|
* `verificationToken` when the Application has no email transport configured,
|
|
520
556
|
* so you can deliver it with your own provider.
|
|
521
557
|
*
|
|
522
558
|
* Pass `verifyUrl` containing `{token}` to template the link target. Unlike
|
|
523
559
|
* `sendVerificationEmail`, nothing is sent and no token is minted when no
|
|
524
|
-
* link can be built at all
|
|
560
|
+
* link can be built at all, pass `verifyUrl`, or set the Application URL
|
|
525
561
|
* (Panel → Application → Auth). Mailing a locked-out user a verification
|
|
526
562
|
* message with no button in it helps nobody.
|
|
527
563
|
*
|
|
@@ -565,7 +601,7 @@ declare class AuthClient {
|
|
|
565
601
|
userAgent: string | null;
|
|
566
602
|
ip: string | null;
|
|
567
603
|
}>>;
|
|
568
|
-
/** Revoke one session by id. Idempotent
|
|
604
|
+
/** Revoke one session by id. Idempotent, `{ revoked: false }` if it isn't this user's. */
|
|
569
605
|
revokeSession(accessToken: string, sessionId: string): Promise<{
|
|
570
606
|
revoked: boolean;
|
|
571
607
|
}>;
|
|
@@ -578,7 +614,7 @@ declare class AuthClient {
|
|
|
578
614
|
/**
|
|
579
615
|
* Begin TOTP enrollment: mints a secret (as an `otpauthUrl` for the QR) and
|
|
580
616
|
* 10 single-show backup codes. **Not enrolled until `confirmMfaSetup(...)`.**
|
|
581
|
-
* Only SHA-256 hashes of the backup codes are stored
|
|
617
|
+
* Only SHA-256 hashes of the backup codes are stored, show them once.
|
|
582
618
|
*/
|
|
583
619
|
mfaSetup(accessToken: string): Promise<{
|
|
584
620
|
otpauthUrl: string;
|
|
@@ -591,7 +627,7 @@ declare class AuthClient {
|
|
|
591
627
|
}>;
|
|
592
628
|
/**
|
|
593
629
|
* Verify a TOTP or backup code as a step-up check (does NOT issue a session).
|
|
594
|
-
* Backup codes are single-use
|
|
630
|
+
* Backup codes are single-use, consumed on success. Returns `{ ok }`.
|
|
595
631
|
*/
|
|
596
632
|
mfaChallenge(accessToken: string, code: string): Promise<{
|
|
597
633
|
ok: boolean;
|
|
@@ -609,10 +645,16 @@ declare class AuthClient {
|
|
|
609
645
|
}>;
|
|
610
646
|
/**
|
|
611
647
|
* Exchange the provider `code` for a Rekey session. Returns a
|
|
612
|
-
* `SignInOutcome
|
|
648
|
+
* `SignInOutcome`, branch on `mfaRequired` before reading `accessToken`.
|
|
613
649
|
* Verify the `state` CSRF value yourself before calling.
|
|
614
650
|
*/
|
|
615
|
-
completeOAuth(provider: string, code: string
|
|
651
|
+
completeOAuth(provider: string, code: string, options?: {
|
|
652
|
+
/** Bind the session to a device, see docs/devices.md. */
|
|
653
|
+
device?: {
|
|
654
|
+
fingerprint: string;
|
|
655
|
+
label?: string;
|
|
656
|
+
};
|
|
657
|
+
}): Promise<SignInOutcomeDto>;
|
|
616
658
|
/** List the OAuth providers linked to the current user. */
|
|
617
659
|
listOAuthIdentities(accessToken: string): Promise<Array<{
|
|
618
660
|
provider: string;
|
|
@@ -625,7 +667,7 @@ declare class AuthClient {
|
|
|
625
667
|
authorizationUrl: string;
|
|
626
668
|
}>;
|
|
627
669
|
/**
|
|
628
|
-
* Complete an OAuth link
|
|
670
|
+
* Complete an OAuth link, attaches the provider identity to the current
|
|
629
671
|
* user. Refuses on unverified provider emails (account-takeover guard) or
|
|
630
672
|
* when the provider account already belongs to a different user.
|
|
631
673
|
*/
|
|
@@ -648,7 +690,7 @@ declare class AuthClient {
|
|
|
648
690
|
*
|
|
649
691
|
* Re-exported from `@rekey.dev/shared-types` so the SDK, the API and the panel
|
|
650
692
|
* all name one shape. Every list method returns {@link Paged}, whose `page`
|
|
651
|
-
* tells you whether there is another window
|
|
693
|
+
* tells you whether there is another window, you no longer have to infer it
|
|
652
694
|
* by asking for one row more than you need.
|
|
653
695
|
*/
|
|
654
696
|
export type { ListPage, PageMeta, Paged } from '@rekey.dev/shared-types';
|
|
@@ -706,7 +748,7 @@ declare class OrganizationsClient {
|
|
|
706
748
|
*/
|
|
707
749
|
listMembers(accessToken: string, organizationId: string, page?: ListPage): Promise<Paged<OrganizationMemberDto>>;
|
|
708
750
|
/**
|
|
709
|
-
* Invite a user. Returns the raw token ONCE
|
|
751
|
+
* Invite a user. Returns the raw token ONCE, surface via your own
|
|
710
752
|
* email/share channel. OWNER + ADMIN only.
|
|
711
753
|
*/
|
|
712
754
|
invite(accessToken: string, organizationId: string,
|
|
@@ -745,7 +787,7 @@ declare class OrganizationsClient {
|
|
|
745
787
|
* Remove a member (or self). Refuses removing the last OWNER.
|
|
746
788
|
*
|
|
747
789
|
* Idempotent: `removed` is `false` when the target was not a member (e.g.
|
|
748
|
-
* already removed)
|
|
790
|
+
* already removed), a no-op removal is not an error. Branch on `removed`
|
|
749
791
|
* rather than assuming it is always `true`.
|
|
750
792
|
*/
|
|
751
793
|
removeMember(accessToken: string, organizationId: string, targetEndUserId: string): Promise<{
|
|
@@ -753,7 +795,7 @@ declare class OrganizationsClient {
|
|
|
753
795
|
}>;
|
|
754
796
|
/**
|
|
755
797
|
* Self-leave. An OWNER cannot leave (payment + benefits are tied to the
|
|
756
|
-
* owner
|
|
798
|
+
* owner, `ORGANIZATION_OWNER_CANNOT_LEAVE`); transfer ownership via support
|
|
757
799
|
* first, or demote yourself to ADMIN if there is another OWNER.
|
|
758
800
|
*/
|
|
759
801
|
leave(accessToken: string, organizationId: string): Promise<{
|
|
@@ -774,7 +816,7 @@ declare class OrganizationsClient {
|
|
|
774
816
|
}>;
|
|
775
817
|
/**
|
|
776
818
|
* Make `organizationId` the active org for this session (member-only).
|
|
777
|
-
* Returns a fresh {accessToken, refreshToken} pair carrying the active org
|
|
819
|
+
* Returns a fresh {accessToken, refreshToken} pair carrying the active org,
|
|
778
820
|
* **store both**. Subsequent entitlement reads (`billing.getEntitlements`)
|
|
779
821
|
* then default to this org's view + shared pool without passing
|
|
780
822
|
* `organizationId` explicitly. The active org survives token refresh until
|
|
@@ -782,7 +824,7 @@ declare class OrganizationsClient {
|
|
|
782
824
|
*/
|
|
783
825
|
switch(accessToken: string, organizationId: string): Promise<AuthResultDto>;
|
|
784
826
|
/**
|
|
785
|
-
* Clear the active org
|
|
827
|
+
* Clear the active org, switch the session back to the personal pool.
|
|
786
828
|
* Returns a fresh token pair (no active org); **store both**.
|
|
787
829
|
*/
|
|
788
830
|
clearActive(accessToken: string): Promise<AuthResultDto>;
|
|
@@ -793,7 +835,7 @@ declare class LicensesClient {
|
|
|
793
835
|
/**
|
|
794
836
|
* Verify a license key + record an activation for this machine. Call
|
|
795
837
|
* once at app startup; you'll get a deterministic body (`ok=false` for
|
|
796
|
-
* invalid licenses
|
|
838
|
+
* invalid licenses, never an HTTP error, so your software can loop
|
|
797
839
|
* on the result without try/catch noise).
|
|
798
840
|
*
|
|
799
841
|
* `machineFingerprint` should be a stable identifier you derive client-
|
|
@@ -815,6 +857,173 @@ declare class LicensesClient {
|
|
|
815
857
|
machineFingerprint: string;
|
|
816
858
|
label?: string;
|
|
817
859
|
}): Promise<LicenseVerifyResultDto>;
|
|
860
|
+
/**
|
|
861
|
+
* Give back the seat this machine holds; call it before a re-image or on
|
|
862
|
+
* uninstall so the next machine can verify. Same deterministic body as
|
|
863
|
+
* `verify`; `released: false` means the machine held no seat.
|
|
864
|
+
*
|
|
865
|
+
* @example
|
|
866
|
+
* ```ts
|
|
867
|
+
* await rekey.licenses.deactivate({ key, machineFingerprint });
|
|
868
|
+
* ```
|
|
869
|
+
*/
|
|
870
|
+
deactivate(input: LicenseDeactivateRequest): Promise<LicenseDeactivateResultDto>;
|
|
871
|
+
/**
|
|
872
|
+
* The signed-in end-user's own licences, newest first:
|
|
873
|
+
* `GET /api/v1/users/me/licenses`, authorized by their access token. In an
|
|
874
|
+
* org-billed Application whose session acts for an organization, that
|
|
875
|
+
* organization's pooled licences are included too.
|
|
876
|
+
*
|
|
877
|
+
* No raw keys: only a hash is stored, so each row carries its display
|
|
878
|
+
* `keyPrefix`. Needs `billing:read` on a secret key.
|
|
879
|
+
*
|
|
880
|
+
* @example
|
|
881
|
+
* ```ts
|
|
882
|
+
* const { items } = await rekey.licenses.listMine(accessToken);
|
|
883
|
+
* const active = items.filter((l) => l.status === 'ACTIVE');
|
|
884
|
+
* ```
|
|
885
|
+
*/
|
|
886
|
+
listMine(accessToken: string, page?: ListPage): Promise<Paged<EndUserLicenseDto>>;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* End-users' devices (docs/devices.md), both surfaces.
|
|
890
|
+
*
|
|
891
|
+
* `list` / `release` are the SERVER surface: secret key only, addressed by
|
|
892
|
+
* end-user id, because they read and mutate OTHER users' devices.
|
|
893
|
+
*
|
|
894
|
+
* `listMine` / `releaseMine` are the END-USER surface, the one
|
|
895
|
+
* `DEVICE_LIMIT_REACHED` tells you to offer. They take that user's own access
|
|
896
|
+
* token and act only on their own devices, so they are what a "your signed-in
|
|
897
|
+
* machines" screen calls, and what lets a user release a machine themselves
|
|
898
|
+
* instead of contacting support.
|
|
899
|
+
*/
|
|
900
|
+
declare class DevicesClient {
|
|
901
|
+
private readonly client;
|
|
902
|
+
constructor(client: Rekey);
|
|
903
|
+
/** An end-user's devices, newest activity first. Optional `status` filter. */
|
|
904
|
+
list(endUserId: string, options?: {
|
|
905
|
+
status?: DeviceStatusType;
|
|
906
|
+
limit?: number;
|
|
907
|
+
offset?: number;
|
|
908
|
+
}): Promise<Paged<DeviceDto>>;
|
|
909
|
+
/** Release a device: gives its slot back and revokes every session on it. */
|
|
910
|
+
release(deviceId: string, endUserId: string): Promise<{
|
|
911
|
+
device: DeviceDto;
|
|
912
|
+
sessionsRevoked: number;
|
|
913
|
+
}>;
|
|
914
|
+
/**
|
|
915
|
+
* The calling end-user's OWN devices, newest activity first.
|
|
916
|
+
*
|
|
917
|
+
* `GET /api/v1/users/me/devices`, authorized by the user's access token
|
|
918
|
+
* rather than by an end-user id. Operator notes (`blockedReason`) and IPs are
|
|
919
|
+
* not on this surface, which is why it resolves to `EndUserDeviceDto`.
|
|
920
|
+
*
|
|
921
|
+
* The device the current session is bound to is the one whose `id` matches
|
|
922
|
+
* the access token's `dev` claim (see {@link VerifiedAccessTokenClaims}), so
|
|
923
|
+
* a "your devices" screen can mark "this device" without a second call.
|
|
924
|
+
*
|
|
925
|
+
* @example
|
|
926
|
+
* ```ts
|
|
927
|
+
* const { items } = await rekey.devices.listMine(accessToken, { status: 'ACTIVE' });
|
|
928
|
+
* ```
|
|
929
|
+
*/
|
|
930
|
+
listMine(accessToken: string, options?: {
|
|
931
|
+
status?: DeviceStatusType;
|
|
932
|
+
limit?: number;
|
|
933
|
+
offset?: number;
|
|
934
|
+
}): Promise<Paged<EndUserDeviceDto>>;
|
|
935
|
+
/**
|
|
936
|
+
* Release one of the calling end-user's own devices.
|
|
937
|
+
*
|
|
938
|
+
* This is the flow `DEVICE_LIMIT_REACHED` names: that refusal carries
|
|
939
|
+
* `details.limit` and `details.devices` (typed as `DeviceLimitDetails`), so
|
|
940
|
+
* you can show the user their machines and release one here rather than
|
|
941
|
+
* leaving them at a dead end.
|
|
942
|
+
*
|
|
943
|
+
* Gives the slot back and revokes every session minted on that device,
|
|
944
|
+
* INCLUDING the current one when it is the same device, so treat a release of
|
|
945
|
+
* `claims.dev` as a sign-out. Idempotent for an already-released device; a
|
|
946
|
+
* BLOCKED device refuses with `DEVICE_BLOCKED` (only an operator can unblock).
|
|
947
|
+
*
|
|
948
|
+
* @example
|
|
949
|
+
* ```ts
|
|
950
|
+
* try {
|
|
951
|
+
* await rekey.auth.signIn({ email, password, device: { fingerprint } });
|
|
952
|
+
* } catch (e) {
|
|
953
|
+
* if (e instanceof RekeyError && e.code === 'DEVICE_LIMIT_REACHED') {
|
|
954
|
+
* const { devices } = e.details as DeviceLimitDetails;
|
|
955
|
+
* // …let the user pick one, then, with a token from a session that has one:
|
|
956
|
+
* await rekey.devices.releaseMine(accessToken, devices[0]!.id);
|
|
957
|
+
* }
|
|
958
|
+
* }
|
|
959
|
+
* ```
|
|
960
|
+
*/
|
|
961
|
+
releaseMine(accessToken: string, deviceId: string): Promise<{
|
|
962
|
+
device: EndUserDeviceDto;
|
|
963
|
+
sessionsRevoked: number;
|
|
964
|
+
}>;
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Server-side end-user lookup (secret key only). `/users/me` answers "who is
|
|
968
|
+
* this token"; these answer "who is this id / email" for a backend that holds
|
|
969
|
+
* no token.
|
|
970
|
+
*/
|
|
971
|
+
declare class UsersClient {
|
|
972
|
+
private readonly client;
|
|
973
|
+
constructor(client: Rekey);
|
|
974
|
+
/** Exact, case-insensitive email match in the calling Application. Throws END_USER_NOT_FOUND. */
|
|
975
|
+
getByEmail(email: string): Promise<EndUserDto>;
|
|
976
|
+
/** By id, scoped to the calling Application. Throws END_USER_NOT_FOUND. */
|
|
977
|
+
get(endUserId: string): Promise<EndUserDto>;
|
|
978
|
+
/**
|
|
979
|
+
* Import up to 500 users from another auth system in one call. Password
|
|
980
|
+
* hashes (argon2id or bcrypt) are stored as given and verified as-is at
|
|
981
|
+
* sign-in; bcrypt is upgraded to argon2id on first success. Existing
|
|
982
|
+
* addresses are skipped, never updated.
|
|
983
|
+
*
|
|
984
|
+
* @example
|
|
985
|
+
* ```ts
|
|
986
|
+
* const { created, skipped } = await rekey.users.import([
|
|
987
|
+
* { email: 'a@example.com', passwordHash: '$2b$10$…', emailVerified: true },
|
|
988
|
+
* { email: 'b@example.com', oauthIdentities: [{ provider: 'google', providerAccountId: '1234' }] },
|
|
989
|
+
* ]);
|
|
990
|
+
* ```
|
|
991
|
+
*/
|
|
992
|
+
import(users: ImportUserInput[]): Promise<ImportUsersResult>;
|
|
993
|
+
}
|
|
994
|
+
export interface ImportUserInput {
|
|
995
|
+
email: string;
|
|
996
|
+
/** `$argon2id$…` or `$2a$`/`$2b$`/`$2y$…`. Omit for OAuth-only users. */
|
|
997
|
+
passwordHash?: string;
|
|
998
|
+
emailVerified?: boolean;
|
|
999
|
+
role?: string;
|
|
1000
|
+
metadata?: Record<string, unknown>;
|
|
1001
|
+
oauthIdentities?: Array<{
|
|
1002
|
+
provider: string;
|
|
1003
|
+
providerAccountId: string;
|
|
1004
|
+
email?: string;
|
|
1005
|
+
}>;
|
|
1006
|
+
}
|
|
1007
|
+
export interface ImportUsersResult {
|
|
1008
|
+
created: Array<{
|
|
1009
|
+
id: string;
|
|
1010
|
+
email: string;
|
|
1011
|
+
}>;
|
|
1012
|
+
skipped: Array<{
|
|
1013
|
+
email: string;
|
|
1014
|
+
reason: string;
|
|
1015
|
+
}>;
|
|
1016
|
+
/**
|
|
1017
|
+
* OAuth identities that were NOT linked because the provider account is
|
|
1018
|
+
* already attached to another end-user in this Application. The user was
|
|
1019
|
+
* still created; their sign-in through that provider lands on the OTHER
|
|
1020
|
+
* account until one of the two is fixed.
|
|
1021
|
+
*/
|
|
1022
|
+
unlinked: Array<{
|
|
1023
|
+
email: string;
|
|
1024
|
+
provider: string;
|
|
1025
|
+
providerAccountId: string;
|
|
1026
|
+
}>;
|
|
818
1027
|
}
|
|
819
1028
|
declare class UsageClient {
|
|
820
1029
|
private readonly client;
|
|
@@ -846,9 +1055,50 @@ declare class UsageClient {
|
|
|
846
1055
|
endUserId?: string;
|
|
847
1056
|
organizationId?: string;
|
|
848
1057
|
}): Promise<UsageAggregateDto>;
|
|
1058
|
+
/**
|
|
1059
|
+
* The signed-in end-user's included quota, usage and remaining units this
|
|
1060
|
+
* period, per meter (or one meter with `{ meter }`). Computed by the code
|
|
1061
|
+
* `record` enforces with: a record of more than `remaining` is the one that
|
|
1062
|
+
* is refused (402 `USAGE_QUOTA_EXCEEDED`) or, on a priced meter, charged.
|
|
1063
|
+
*
|
|
1064
|
+
* Reads the personal quota, or the active organization's in an Application
|
|
1065
|
+
* that bills organizations; `{ organizationId }` (member-only) picks one.
|
|
1066
|
+
*
|
|
1067
|
+
* @example
|
|
1068
|
+
* ```ts
|
|
1069
|
+
* const { meters } = await rekey.usage.getRemaining(accessToken, { meter: 'api_calls' });
|
|
1070
|
+
* if (meters[0].remaining === 0) showUpgradePrompt();
|
|
1071
|
+
* ```
|
|
1072
|
+
*/
|
|
1073
|
+
getRemaining(accessToken: string, opts?: {
|
|
1074
|
+
meter?: string;
|
|
1075
|
+
organizationId?: string;
|
|
1076
|
+
}): Promise<UsageRemainingDto>;
|
|
1077
|
+
/**
|
|
1078
|
+
* The same answer as `getRemaining`, for a subject you name instead of one
|
|
1079
|
+
* whose token you hold: `{ endUserId }`, `{ organizationId }`, or both to
|
|
1080
|
+
* read the organization as that member. Secret key only.
|
|
1081
|
+
*/
|
|
1082
|
+
getRemainingFor(subject: {
|
|
1083
|
+
endUserId: string;
|
|
1084
|
+
organizationId?: string;
|
|
1085
|
+
} | {
|
|
1086
|
+
organizationId: string;
|
|
1087
|
+
endUserId?: string;
|
|
1088
|
+
}, opts?: {
|
|
1089
|
+
meter?: string;
|
|
1090
|
+
}): Promise<UsageRemainingDto>;
|
|
1091
|
+
/**
|
|
1092
|
+
* The Application's usage meters: the slugs `record` takes, their units,
|
|
1093
|
+
* whether each accepts records, and its fallback credit price. Secret key.
|
|
1094
|
+
*/
|
|
1095
|
+
listMeters(opts?: {
|
|
1096
|
+
limit?: number;
|
|
1097
|
+
offset?: number;
|
|
1098
|
+
}): Promise<Paged<UsageMeterCatalogueEntryDto>>;
|
|
849
1099
|
}
|
|
850
1100
|
/**
|
|
851
|
-
* A credit subject
|
|
1101
|
+
* A credit subject, pass `endUserId` for a personal balance, or
|
|
852
1102
|
* `organizationId` for a shared org pool (owner+beneficiary billing).
|
|
853
1103
|
*/
|
|
854
1104
|
export type CreditSubject = {
|
|
@@ -857,11 +1107,11 @@ export type CreditSubject = {
|
|
|
857
1107
|
organizationId: string;
|
|
858
1108
|
};
|
|
859
1109
|
/**
|
|
860
|
-
* Prepaid credits
|
|
1110
|
+
* Prepaid credits, the "lead pack" / pay-as-you-go drawdown model. The
|
|
861
1111
|
* customer's backend grants credits (by selling a CREDIT-kind plan, which
|
|
862
1112
|
* grants automatically on payment) and draws them down per unit consumed.
|
|
863
1113
|
*
|
|
864
|
-
* All calls are server-to-server (secret key) and scoped to a `CreditSubject
|
|
1114
|
+
* All calls are server-to-server (secret key) and scoped to a `CreditSubject`,
|
|
865
1115
|
* an end-user's personal balance, or an organization's shared pool.
|
|
866
1116
|
*/
|
|
867
1117
|
declare class CreditsClient {
|
|
@@ -874,7 +1124,7 @@ declare class CreditsClient {
|
|
|
874
1124
|
* `code: "CREDITS_INSUFFICIENT"` (HTTP 402) when the balance is too low.
|
|
875
1125
|
*
|
|
876
1126
|
* Pass `idempotencyKey` (e.g. the lead id) so a retried call never
|
|
877
|
-
* double-charges
|
|
1127
|
+
* double-charges, a repeat returns the original result with `applied: false`.
|
|
878
1128
|
*/
|
|
879
1129
|
consume(input: ConsumeCreditsRequest & CreditSubject): Promise<ConsumeCreditsResultDto>;
|
|
880
1130
|
/**
|
|
@@ -883,8 +1133,33 @@ declare class CreditsClient {
|
|
|
883
1133
|
* subject); `limit` is capped at 200 server-side.
|
|
884
1134
|
*/
|
|
885
1135
|
listLedger(subject: CreditSubject, limit?: number, offset?: number): Promise<Paged<CreditLedgerEntryDto>>;
|
|
1136
|
+
/**
|
|
1137
|
+
* Grant credits to an end-user or organization pool with the Application
|
|
1138
|
+
* key. Needs a key minted with the elevated `credits:grant` scope named:
|
|
1139
|
+
* `*` does not include it, so a default key gets 403
|
|
1140
|
+
* `API_KEY_SCOPE_INSUFFICIENT`.
|
|
1141
|
+
*
|
|
1142
|
+
* `idempotencyKey` is required; a repeat returns the original entry with
|
|
1143
|
+
* `applied: false` and grants nothing. `amount` is 1 to 1,000,000 per call.
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* ```ts
|
|
1147
|
+
* await rekey.credits.grant({ endUserId, amount: 500, idempotencyKey: `referral:${referralId}` });
|
|
1148
|
+
* ```
|
|
1149
|
+
*/
|
|
1150
|
+
grant(input: KeyGrantCreditsRequest): Promise<ConsumeCreditsResultDto>;
|
|
1151
|
+
/**
|
|
1152
|
+
* The signed-in end-user's own credit ledger, newest first (the active
|
|
1153
|
+
* organization's pool in an Application that bills organizations, or the one
|
|
1154
|
+
* `{ organizationId }` names, member-only). Entries carry no `metadata`.
|
|
1155
|
+
*/
|
|
1156
|
+
listMyLedger(accessToken: string, opts?: {
|
|
1157
|
+
organizationId?: string;
|
|
1158
|
+
limit?: number;
|
|
1159
|
+
offset?: number;
|
|
1160
|
+
}): Promise<Paged<SelfCreditLedgerEntryDto>>;
|
|
886
1161
|
}
|
|
887
|
-
/** What an end-user (or org) is entitled to right now
|
|
1162
|
+
/** What an end-user (or org) is entitled to right now, from active subs. */
|
|
888
1163
|
export interface EntitlementsDto {
|
|
889
1164
|
/** Feature flags + numeric limits, keyed by code. Gate your app on these. */
|
|
890
1165
|
features: Record<string, boolean | number | string>;
|
|
@@ -907,7 +1182,7 @@ export interface EntitlementsDto {
|
|
|
907
1182
|
* default 300) AND (b) the signature matches a constant-time compare.
|
|
908
1183
|
*
|
|
909
1184
|
* Use against the `X-Rekey-Signature` header and the raw request body
|
|
910
|
-
* BYTES (not the parsed JSON
|
|
1185
|
+
* BYTES (not the parsed JSON, any reserialization breaks the HMAC).
|
|
911
1186
|
*
|
|
912
1187
|
* @example
|
|
913
1188
|
* ```ts
|
|
@@ -933,16 +1208,37 @@ export declare function verifyWebhookSignature(args: {
|
|
|
933
1208
|
}): boolean;
|
|
934
1209
|
/** Verified claims of an RS256 end-user access token. */
|
|
935
1210
|
export interface VerifiedAccessTokenClaims {
|
|
936
|
-
/** Always `"eu_access"
|
|
1211
|
+
/** Always `"eu_access"`, other token types are refused. */
|
|
937
1212
|
typ: 'eu_access';
|
|
938
1213
|
/** EndUser id. */
|
|
939
1214
|
sub: string;
|
|
940
|
-
/** Application the token is bound to
|
|
1215
|
+
/** Application the token is bound to, check it against YOUR application id. */
|
|
941
1216
|
applicationId: string;
|
|
942
1217
|
/** Active organization id, when the session is acting as an org. */
|
|
943
1218
|
oid?: string;
|
|
944
1219
|
/** Operator id when this is an impersonation session (treat with care). */
|
|
945
1220
|
imp?: string;
|
|
1221
|
+
/**
|
|
1222
|
+
* Refresh-token family this access token belongs to, the `sid` claim.
|
|
1223
|
+
*
|
|
1224
|
+
* Optional because the API only mints it when the session flow supplies one
|
|
1225
|
+
* (see `issueUserAccessToken`), so treat an absent `sid` as "this deployment
|
|
1226
|
+
* or flow did not bind one", never as a session that ended.
|
|
1227
|
+
*
|
|
1228
|
+
* Offline verification cannot see a revocation, the whole point of not
|
|
1229
|
+
* calling the API. Use this to correlate a token with your own record of the
|
|
1230
|
+
* session, so you can drop one you already know is gone.
|
|
1231
|
+
*/
|
|
1232
|
+
sid?: string;
|
|
1233
|
+
/**
|
|
1234
|
+
* Device this session is bound to, the `dev` claim. Present only when the
|
|
1235
|
+
* sign-in bound a device.
|
|
1236
|
+
*
|
|
1237
|
+
* This is the id that matches a row from `devices.listMine()`, so a client
|
|
1238
|
+
* can mark "this device" in its own device list, and the id to pass to
|
|
1239
|
+
* `devices.releaseMine()` to sign the CURRENT machine out.
|
|
1240
|
+
*/
|
|
1241
|
+
dev?: string;
|
|
946
1242
|
/** App `tokenGeneration` at mint time (the API checks this; offline can't). */
|
|
947
1243
|
gen?: number;
|
|
948
1244
|
iat: number;
|
|
@@ -953,7 +1249,7 @@ export interface VerifyAccessTokenOptions {
|
|
|
953
1249
|
* The Application this token must belong to. **Required.**
|
|
954
1250
|
*
|
|
955
1251
|
* This helper verifies RS256 tokens against the deployment's JWKS, and the
|
|
956
|
-
* RS256 keypair is deployment-wide
|
|
1252
|
+
* RS256 keypair is deployment-wide, `SigningKey` has no `applicationId`
|
|
957
1253
|
* column, and `eu_access` tokens carry no `iss`/`aud`. So a token minted for
|
|
958
1254
|
* ANY Application on the same deployment is cryptographically valid here.
|
|
959
1255
|
* Without this, a multi-app self-host accepts another Application's end-user
|
|
@@ -961,24 +1257,24 @@ export interface VerifyAccessTokenOptions {
|
|
|
961
1257
|
*
|
|
962
1258
|
* (The HS256 default path is not affected: that key is derived per
|
|
963
1259
|
* Application as `HMAC-SHA256(JWT_SECRET, applicationId:tokenGeneration)`, so
|
|
964
|
-
* a foreign token fails the signature. This is the RS256 opt-in only
|
|
1260
|
+
* a foreign token fails the signature. This is the RS256 opt-in only, which
|
|
965
1261
|
* is exactly the path this function exists for.)
|
|
966
1262
|
*
|
|
967
1263
|
* Required rather than optional-with-a-warning: a security check nobody is
|
|
968
1264
|
* forced to make is one most callers will not make, and the docblock used to
|
|
969
|
-
* tell them to compare `claims.applicationId` afterwards
|
|
1265
|
+
* tell them to compare `claims.applicationId` afterwards, which made the
|
|
970
1266
|
* shortest correct path the insecure one. 2.0.0 is not out yet, so this
|
|
971
1267
|
* breaks rc callers rather than a stable contract.
|
|
972
1268
|
*/
|
|
973
1269
|
applicationId: string;
|
|
974
1270
|
/**
|
|
975
|
-
* URL of the deployment's JWKS
|
|
1271
|
+
* URL of the deployment's JWKS, `https://<your-rekey>/.well-known/jwks.json`.
|
|
976
1272
|
* Fetched lazily and cached in-process for `cacheTtlMs` (default 5 minutes);
|
|
977
1273
|
* an unknown `kid` triggers one immediate refetch so freshly rotated keys
|
|
978
1274
|
* are picked up without waiting out the TTL.
|
|
979
1275
|
*/
|
|
980
1276
|
jwksUrl?: string;
|
|
981
|
-
/** Pre-fetched key set
|
|
1277
|
+
/** Pre-fetched key set, skips all network access. Takes precedence over `jwksUrl`. */
|
|
982
1278
|
jwks?: JwksDto;
|
|
983
1279
|
/** Optional fetch override (test stubs, custom agents). */
|
|
984
1280
|
fetch?: typeof fetch;
|
|
@@ -998,14 +1294,14 @@ export interface VerifyAccessTokenOptions {
|
|
|
998
1294
|
now?: () => number;
|
|
999
1295
|
}
|
|
1000
1296
|
/**
|
|
1001
|
-
* Verify an end-user ACCESS token **offline
|
|
1297
|
+
* Verify an end-user ACCESS token **offline**, no round-trip to the Rekey
|
|
1002
1298
|
* API. Works only for Applications that opted into RS256 tokens
|
|
1003
1299
|
* (`authConfig.tokenAlg = "RS256"`, Panel → Application → Auth); the default
|
|
1004
1300
|
* HS256 tokens are symmetric and can only be verified by the API itself
|
|
1005
1301
|
* (use `rekey.auth.getCurrentUser(token)` for those).
|
|
1006
1302
|
*
|
|
1007
1303
|
* Checks performed (same posture as the API's verifier):
|
|
1008
|
-
* - header `alg` must be `RS256` and `kid` must exist in the JWKS
|
|
1304
|
+
* - header `alg` must be `RS256` and `kid` must exist in the JWKS,
|
|
1009
1305
|
* a strict allowlist, immune to alg-confusion;
|
|
1010
1306
|
* - RSA-SHA256 signature against that public key;
|
|
1011
1307
|
* - `exp` in the future, `typ === "eu_access"` (refresh/MFA/MCP tokens
|
|
@@ -1015,6 +1311,11 @@ export interface VerifyAccessTokenOptions {
|
|
|
1015
1311
|
* user deletion. The 15-minute access lifetime bounds both; for hard
|
|
1016
1312
|
* revocation guarantees keep using `auth.getCurrentUser`.
|
|
1017
1313
|
*
|
|
1314
|
+
* Nor can it see any server-side revocation: a locally verified token stays
|
|
1315
|
+
* valid until it expires, even after sign-out everywhere, a password change,
|
|
1316
|
+
* a session revoke or a device release. Call the API when immediate
|
|
1317
|
+
* revocation matters.
|
|
1318
|
+
*
|
|
1018
1319
|
* Node-only (uses `node:crypto`). Returns the verified claims; throws
|
|
1019
1320
|
* `RekeyError` on any failure.
|
|
1020
1321
|
*
|
|
@@ -1037,24 +1338,29 @@ export interface VerifyAccessTokenOptions {
|
|
|
1037
1338
|
* it moved inside: the shortest correct path should not be the one nobody
|
|
1038
1339
|
* takes.
|
|
1039
1340
|
*
|
|
1040
|
-
* @throws {RekeyError} `TOKEN_ALG_NOT_RS256
|
|
1041
|
-
* @throws {RekeyError} `TOKEN_KID_UNKNOWN
|
|
1042
|
-
* @throws {RekeyError} `USER_TOKEN_EXPIRED
|
|
1043
|
-
* @throws {RekeyError} `USER_TOKEN_INVALID
|
|
1341
|
+
* @throws {RekeyError} `TOKEN_ALG_NOT_RS256`, token is HS256 (app hasn't opted in) or another alg.
|
|
1342
|
+
* @throws {RekeyError} `TOKEN_KID_UNKNOWN`, `kid` not in the JWKS (forged, or key deleted).
|
|
1343
|
+
* @throws {RekeyError} `USER_TOKEN_EXPIRED`, `exp` passed; refresh the session.
|
|
1344
|
+
* @throws {RekeyError} `USER_TOKEN_INVALID`, malformed, bad signature, or wrong `typ`.
|
|
1044
1345
|
*/
|
|
1045
1346
|
export declare function verifyAccessToken(token: string, options: VerifyAccessTokenOptions): Promise<VerifiedAccessTokenClaims>;
|
|
1046
1347
|
declare class BillingClient {
|
|
1047
1348
|
private readonly client;
|
|
1048
1349
|
constructor(client: Rekey);
|
|
1049
1350
|
/**
|
|
1050
|
-
* List the calling Application's active plans. Public
|
|
1351
|
+
* List the calling Application's active plans. Public, pricing pages
|
|
1051
1352
|
* typically render straight from this. Application API key only; no
|
|
1052
1353
|
* user JWT needed.
|
|
1053
1354
|
*
|
|
1054
|
-
* `amount` is in the smallest currency unit (cents/paise/sen)
|
|
1355
|
+
* `amount` is in the smallest currency unit (cents/paise/sen), never
|
|
1055
1356
|
* a float. Format on display: `${amount / 100} ${currency}`.
|
|
1357
|
+
*
|
|
1358
|
+
* `checkout.ready` is false when a buyer sent to checkout for the plan would
|
|
1359
|
+
* be refused, so a pricing page can hide it. Why is on the operator plan
|
|
1360
|
+
* list, not here. Keep the free tier in: with no provider connected it reads
|
|
1361
|
+
* `ready: false` and still applies to every signed-in user.
|
|
1056
1362
|
*/
|
|
1057
|
-
getPlans(page?: ListPage): Promise<Paged<
|
|
1363
|
+
getPlans(page?: ListPage): Promise<Paged<PublicPlanDto>>;
|
|
1058
1364
|
/**
|
|
1059
1365
|
* Fetch the current end-user's active subscription, or `null` if they
|
|
1060
1366
|
* have none. Returns the most recent ACTIVE / PENDING / PAST_DUE row.
|
|
@@ -1062,7 +1368,7 @@ declare class BillingClient {
|
|
|
1062
1368
|
* Pass the user's access token (the SDK puts it in `X-Rekey-User-Token`).
|
|
1063
1369
|
*
|
|
1064
1370
|
* `opts.includeEnded` falls back to the most recent CANCELED/EXPIRED
|
|
1065
|
-
* subscription **only when the answer would otherwise be null
|
|
1371
|
+
* subscription **only when the answer would otherwise be null**, for a
|
|
1066
1372
|
* billing page that has to tell a former subscriber what they were on and
|
|
1067
1373
|
* when it ended, rather than showing them the same blank state as somebody
|
|
1068
1374
|
* who never subscribed. It can never replace a live subscription, so it is
|
|
@@ -1079,13 +1385,22 @@ declare class BillingClient {
|
|
|
1079
1385
|
/**
|
|
1080
1386
|
* Start a hosted-checkout session. Returns the URL to redirect the user
|
|
1081
1387
|
* to and the local PENDING Subscription row. Subscription activation
|
|
1082
|
-
* happens via the provider's webhook
|
|
1388
|
+
* happens via the provider's webhook, not synchronously here.
|
|
1083
1389
|
*
|
|
1084
1390
|
* Pass `couponCode` to apply a discount. The whole checkout fails if the
|
|
1085
1391
|
* coupon doesn't validate (typed `RekeyError` with the precise reason).
|
|
1086
1392
|
*
|
|
1393
|
+
* A buyer who has already used their free trial is refused with
|
|
1394
|
+
* `BILLING_TRIAL_ALREADY_USED` (409). The escape hatch is
|
|
1395
|
+
* `allowWithoutTrial: true` AND a fresh `Idempotency-Key`, but send it only
|
|
1396
|
+
* after the buyer has been told they are paying today. Read
|
|
1397
|
+
* {@link getTrialEligibility} and render the paid price instead of retrying
|
|
1398
|
+
* blindly: a buyer who merely abandoned a trial checkout still reads
|
|
1399
|
+
* `eligible: true`, and acknowledging on their behalf charges them today for
|
|
1400
|
+
* the trial the next checkout was about to grant.
|
|
1401
|
+
*
|
|
1087
1402
|
* If the Application's billing subject is **org** (Panel → Application →
|
|
1088
|
-
* Billing → Subject), an individual can't hold a subscription
|
|
1403
|
+
* Billing → Subject), an individual can't hold a subscription, you MUST
|
|
1089
1404
|
* pass `organizationId` of a team the user owns/admins. Omitting it throws
|
|
1090
1405
|
* `RekeyError` `code: "BILLING_ORGANIZATION_REQUIRED"`.
|
|
1091
1406
|
*
|
|
@@ -1103,6 +1418,74 @@ declare class BillingClient {
|
|
|
1103
1418
|
createCheckout(accessToken: string, input: CreateCheckoutRequest & {
|
|
1104
1419
|
couponCode?: string;
|
|
1105
1420
|
}): Promise<CheckoutResultDto>;
|
|
1421
|
+
/**
|
|
1422
|
+
* Put the calling end-user on the Application's free tier
|
|
1423
|
+
* (`billingConfig.defaultPlanSlug`). No payment provider is involved and none
|
|
1424
|
+
* needs to be configured: the plan costs nothing.
|
|
1425
|
+
*
|
|
1426
|
+
* This is how a freemium product hands a new signup their included credits,
|
|
1427
|
+
* licence or quota. `defaultPlanSlug` alone covers only the read-time half
|
|
1428
|
+
* (feature flags and included usage); CREDIT and LICENSE entitlements are
|
|
1429
|
+
* stateful and need a real subscription, which is what this creates.
|
|
1430
|
+
*
|
|
1431
|
+
* **Idempotent**, and the answer says which happened: `activated: true` is a
|
|
1432
|
+
* first activation (201, `subscription.activated` emitted), `activated:
|
|
1433
|
+
* false` means they were already entitled and nothing was written,
|
|
1434
|
+
* re-provisioned or re-announced.
|
|
1435
|
+
*
|
|
1436
|
+
* Pass `organizationId` on an org-billed Application; the caller must be an
|
|
1437
|
+
* OWNER or ADMIN of it. Omit it and the session's active organization is used.
|
|
1438
|
+
*
|
|
1439
|
+
* @throws {RekeyError} `BILLING_NO_FREE_PLAN` (404) when the Application
|
|
1440
|
+
* nominates no default plan; `BILLING_FREE_PLAN_NOT_FREE` (409) when that
|
|
1441
|
+
* plan charges money, use {@link createCheckout} instead;
|
|
1442
|
+
* `BILLING_FREE_TIER_ALREADY_CLAIMED` (409) when the plan grants credits or a
|
|
1443
|
+
* licence and this caller already claimed it for a different beneficiary.
|
|
1444
|
+
*
|
|
1445
|
+
* @example
|
|
1446
|
+
* ```ts
|
|
1447
|
+
* const { subscription, activated } = await rekey.billing.subscribe(accessToken);
|
|
1448
|
+
* if (activated) welcomeWithStarterCredits(subscription);
|
|
1449
|
+
* ```
|
|
1450
|
+
*/
|
|
1451
|
+
subscribe(accessToken: string, input?: {
|
|
1452
|
+
organizationId?: string;
|
|
1453
|
+
}): Promise<{
|
|
1454
|
+
subscription: SubscriptionDto;
|
|
1455
|
+
activated: boolean;
|
|
1456
|
+
}>;
|
|
1457
|
+
/**
|
|
1458
|
+
* Whether THIS buyer may start each plan's free trial, under the
|
|
1459
|
+
* Application's `trialPolicy`.
|
|
1460
|
+
*
|
|
1461
|
+
* Read this before offering a trial: a buyer who is not eligible should be
|
|
1462
|
+
* shown the paid price, not a trial that checkout refuses with
|
|
1463
|
+
* `BILLING_TRIAL_ALREADY_USED`. Feed the result straight into
|
|
1464
|
+
* `<PricingTable trialEligibility={…}>` from `@rekey.dev/react`.
|
|
1465
|
+
*
|
|
1466
|
+
* **Advisory.** The authoritative decision is taken under a lock at checkout,
|
|
1467
|
+
* so two tabs can both read `eligible: true` and only one gets the trial.
|
|
1468
|
+
* Treat a 409 at checkout as normal, not as a contradiction.
|
|
1469
|
+
*
|
|
1470
|
+
* **Provider-dependent.** `PLAN_TRIAL_MISCONFIGURED` can be the resolved
|
|
1471
|
+
* provider's answer, so the response echoes `provider`; re-read this when the
|
|
1472
|
+
* buyer changes processor. Pass `country` (ISO 3166-1 alpha-2) to steer the
|
|
1473
|
+
* geo router the way {@link getProviders} does.
|
|
1474
|
+
*
|
|
1475
|
+
* @example
|
|
1476
|
+
* ```ts
|
|
1477
|
+
* const { items, policy } = await rekey.billing.getTrialEligibility(accessToken);
|
|
1478
|
+
* const pro = items.find((i) => i.planSlug === 'pro');
|
|
1479
|
+
* const label = pro?.eligible ? `Start ${pro.trialDays} days free` : 'Subscribe';
|
|
1480
|
+
* ```
|
|
1481
|
+
*/
|
|
1482
|
+
getTrialEligibility(accessToken: string, opts?: {
|
|
1483
|
+
organizationId?: string;
|
|
1484
|
+
planSlug?: string;
|
|
1485
|
+
limit?: number;
|
|
1486
|
+
offset?: number;
|
|
1487
|
+
country?: string;
|
|
1488
|
+
}): Promise<TrialEligibilityDto>;
|
|
1106
1489
|
/**
|
|
1107
1490
|
* Validate a coupon for the current user against a plan, *without*
|
|
1108
1491
|
* applying it. Render "$50 off" on a pricing page before submit.
|
|
@@ -1116,7 +1499,7 @@ declare class BillingClient {
|
|
|
1116
1499
|
/**
|
|
1117
1500
|
* List the billing providers configured + enabled for this Application,
|
|
1118
1501
|
* in the order the geo router would prefer them. Forward the end-user's
|
|
1119
|
-
* `country` (ISO 3166-1 alpha-2) when you have it
|
|
1502
|
+
* `country` (ISO 3166-1 alpha-2) when you have it, the panel/SDK will
|
|
1120
1503
|
* surface India-specific providers (Razorpay) for IN-country users, etc.
|
|
1121
1504
|
*
|
|
1122
1505
|
* Returns the resolved country (echoed back from the server's view of
|
|
@@ -1125,7 +1508,7 @@ declare class BillingClient {
|
|
|
1125
1508
|
*/
|
|
1126
1509
|
getProviders(country?: string): Promise<ProvidersListDto>;
|
|
1127
1510
|
/**
|
|
1128
|
-
* Resolve the calling end-user's current entitlements
|
|
1511
|
+
* Resolve the calling end-user's current entitlements, feature flags +
|
|
1129
1512
|
* limits, the live credit balance, and the raw entitlement list, unioned
|
|
1130
1513
|
* across their active subscriptions (and subscriptions of orgs they belong
|
|
1131
1514
|
* to). Pass `{ organizationId }` (member-only) for that org's view + shared
|
|
@@ -1140,10 +1523,61 @@ declare class BillingClient {
|
|
|
1140
1523
|
getEntitlements(accessToken: string, opts?: {
|
|
1141
1524
|
organizationId?: string;
|
|
1142
1525
|
}): Promise<EntitlementsDto>;
|
|
1526
|
+
/**
|
|
1527
|
+
* The same union as `getEntitlements`, for an end-user you name rather than
|
|
1528
|
+
* one whose token you hold. Secret key only, for a licence server, a
|
|
1529
|
+
* support tool or a batch job.
|
|
1530
|
+
*
|
|
1531
|
+
* @example
|
|
1532
|
+
* ```ts
|
|
1533
|
+
* const { features } = await rekey.billing.getEntitlementsFor(endUserId);
|
|
1534
|
+
* if (features.max_devices !== undefined) capDevices(features.max_devices);
|
|
1535
|
+
* ```
|
|
1536
|
+
*/
|
|
1537
|
+
getEntitlementsFor(endUserId: string, opts?: {
|
|
1538
|
+
organizationId?: string;
|
|
1539
|
+
}): Promise<EntitlementsDto>;
|
|
1540
|
+
/**
|
|
1541
|
+
* One feature for the calling end-user: `{ key, granted, value }`, where
|
|
1542
|
+
* `value` is what `features[key]` holds in `getEntitlements` (null when
|
|
1543
|
+
* nothing grants it) and `granted` is `Boolean(value)`. The subject is the
|
|
1544
|
+
* one `getCurrentUser(token, { include: ['entitlements'] })` resolves, or
|
|
1545
|
+
* the organization you pass (member-only).
|
|
1546
|
+
*
|
|
1547
|
+
* @example
|
|
1548
|
+
* ```ts
|
|
1549
|
+
* const { value } = await rekey.billing.getFeature(accessToken, 'projects');
|
|
1550
|
+
* if (typeof value === 'number' && count >= value) throw new LimitReached();
|
|
1551
|
+
* ```
|
|
1552
|
+
*/
|
|
1553
|
+
getFeature(accessToken: string, key: string, opts?: {
|
|
1554
|
+
organizationId?: string;
|
|
1555
|
+
}): Promise<FeatureCheckDto>;
|
|
1556
|
+
/**
|
|
1557
|
+
* Whether the calling end-user holds a feature: `Boolean(value)`, the test
|
|
1558
|
+
* `if (features[key])` makes, so a false flag, a 0 limit and an unknown key
|
|
1559
|
+
* are all `false`. Use `getFeature` to read a numeric limit.
|
|
1560
|
+
*
|
|
1561
|
+
* @example
|
|
1562
|
+
* ```ts
|
|
1563
|
+
* if (!(await rekey.billing.hasFeature(accessToken, 'reports'))) throw new Forbidden();
|
|
1564
|
+
* ```
|
|
1565
|
+
*/
|
|
1566
|
+
hasFeature(accessToken: string, key: string, opts?: {
|
|
1567
|
+
organizationId?: string;
|
|
1568
|
+
}): Promise<boolean>;
|
|
1569
|
+
/** `getFeature` for an end-user you name. Secret key only, like `getEntitlementsFor`. */
|
|
1570
|
+
getFeatureFor(endUserId: string, key: string, opts?: {
|
|
1571
|
+
organizationId?: string;
|
|
1572
|
+
}): Promise<FeatureCheckDto>;
|
|
1573
|
+
/** `hasFeature` for an end-user you name. Secret key only. */
|
|
1574
|
+
hasFeatureFor(endUserId: string, key: string, opts?: {
|
|
1575
|
+
organizationId?: string;
|
|
1576
|
+
}): Promise<boolean>;
|
|
1143
1577
|
/**
|
|
1144
1578
|
* Cancel the calling end-user's current subscription.
|
|
1145
1579
|
*
|
|
1146
|
-
* Defaults to cancelling **at period end
|
|
1580
|
+
* Defaults to cancelling **at period end**, the user keeps what they paid
|
|
1147
1581
|
* for until the period they already bought runs out. A provider-backed
|
|
1148
1582
|
* subscription therefore stays ACTIVE with `cancelAt` set, and the provider
|
|
1149
1583
|
* webhook is what eventually terminates it; read `cancelAt` on the returned
|
|
@@ -1151,7 +1585,7 @@ declare class BillingClient {
|
|
|
1151
1585
|
* `{ atPeriodEnd: false }` to end it immediately, forfeiting the remainder.
|
|
1152
1586
|
*
|
|
1153
1587
|
* PENDING checkouts (and anything with no provider-side record) are
|
|
1154
|
-
* cancelled locally straight away regardless of the flag
|
|
1588
|
+
* cancelled locally straight away regardless of the flag, there is nothing
|
|
1155
1589
|
* at the provider to schedule against.
|
|
1156
1590
|
*
|
|
1157
1591
|
* Pass `organizationId` when the subscription belongs to a team; the caller
|