@atlasauth/backend 0.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/dist/client/actions.d.ts +86 -0
- package/dist/client/actions.js +40 -0
- package/dist/client/actions.js.map +1 -0
- package/dist/client/actor-tokens.d.ts +28 -0
- package/dist/client/actor-tokens.js +15 -0
- package/dist/client/actor-tokens.js.map +1 -0
- package/dist/client/api-keys.d.ts +77 -0
- package/dist/client/api-keys.js +31 -0
- package/dist/client/api-keys.js.map +1 -0
- package/dist/client/attack-protection.d.ts +41 -0
- package/dist/client/attack-protection.js +14 -0
- package/dist/client/attack-protection.js.map +1 -0
- package/dist/client/audit-logs.d.ts +20 -0
- package/dist/client/audit-logs.js +11 -0
- package/dist/client/audit-logs.js.map +1 -0
- package/dist/client/billing-plans.d.ts +81 -0
- package/dist/client/billing-plans.js +27 -0
- package/dist/client/billing-plans.js.map +1 -0
- package/dist/client/bot-signals.d.ts +88 -0
- package/dist/client/bot-signals.js +24 -0
- package/dist/client/bot-signals.js.map +1 -0
- package/dist/client/branding.d.ts +140 -0
- package/dist/client/branding.js +19 -0
- package/dist/client/branding.js.map +1 -0
- package/dist/client/data-subject-requests.d.ts +40 -0
- package/dist/client/data-subject-requests.js +32 -0
- package/dist/client/data-subject-requests.js.map +1 -0
- package/dist/client/domains.d.ts +45 -0
- package/dist/client/domains.js +21 -0
- package/dist/client/domains.js.map +1 -0
- package/dist/client/email-templates.d.ts +51 -0
- package/dist/client/email-templates.js +24 -0
- package/dist/client/email-templates.js.map +1 -0
- package/dist/client/error.d.ts +31 -0
- package/dist/client/error.js +28 -0
- package/dist/client/error.js.map +1 -0
- package/dist/client/fga.d.ts +191 -0
- package/dist/client/fga.js +91 -0
- package/dist/client/fga.js.map +1 -0
- package/dist/client/import-export.d.ts +88 -0
- package/dist/client/import-export.js +28 -0
- package/dist/client/import-export.js.map +1 -0
- package/dist/client/index.d.ts +796 -0
- package/dist/client/index.js +174 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/instance-security.d.ts +79 -0
- package/dist/client/instance-security.js +44 -0
- package/dist/client/instance-security.js.map +1 -0
- package/dist/client/instance.d.ts +34 -0
- package/dist/client/instance.js +14 -0
- package/dist/client/instance.js.map +1 -0
- package/dist/client/invitations.d.ts +21 -0
- package/dist/client/invitations.js +18 -0
- package/dist/client/invitations.js.map +1 -0
- package/dist/client/jwt-templates.d.ts +26 -0
- package/dist/client/jwt-templates.js +26 -0
- package/dist/client/jwt-templates.js.map +1 -0
- package/dist/client/localizations.d.ts +43 -0
- package/dist/client/localizations.js +24 -0
- package/dist/client/localizations.js.map +1 -0
- package/dist/client/log-streams.d.ts +66 -0
- package/dist/client/log-streams.js +28 -0
- package/dist/client/log-streams.js.map +1 -0
- package/dist/client/lti-platforms.d.ts +49 -0
- package/dist/client/lti-platforms.js +24 -0
- package/dist/client/lti-platforms.js.map +1 -0
- package/dist/client/managed-waf.d.ts +100 -0
- package/dist/client/managed-waf.js +33 -0
- package/dist/client/managed-waf.js.map +1 -0
- package/dist/client/messaging.d.ts +56 -0
- package/dist/client/messaging.js +30 -0
- package/dist/client/messaging.js.map +1 -0
- package/dist/client/network-acls.d.ts +50 -0
- package/dist/client/network-acls.js +29 -0
- package/dist/client/network-acls.js.map +1 -0
- package/dist/client/oauth-clients.d.ts +75 -0
- package/dist/client/oauth-clients.js +45 -0
- package/dist/client/oauth-clients.js.map +1 -0
- package/dist/client/oauth-providers.d.ts +109 -0
- package/dist/client/oauth-providers.js +48 -0
- package/dist/client/oauth-providers.js.map +1 -0
- package/dist/client/organizations.d.ts +211 -0
- package/dist/client/organizations.js +136 -0
- package/dist/client/organizations.js.map +1 -0
- package/dist/client/paginate.d.ts +16 -0
- package/dist/client/paginate.js +35 -0
- package/dist/client/paginate.js.map +1 -0
- package/dist/client/radius-clients.d.ts +52 -0
- package/dist/client/radius-clients.js +24 -0
- package/dist/client/radius-clients.js.map +1 -0
- package/dist/client/rate-limit.d.ts +37 -0
- package/dist/client/rate-limit.js +20 -0
- package/dist/client/rate-limit.js.map +1 -0
- package/dist/client/request.d.ts +52 -0
- package/dist/client/request.js +102 -0
- package/dist/client/request.js.map +1 -0
- package/dist/client/resource-servers.d.ts +44 -0
- package/dist/client/resource-servers.js +24 -0
- package/dist/client/resource-servers.js.map +1 -0
- package/dist/client/restrictions.d.ts +39 -0
- package/dist/client/restrictions.js +29 -0
- package/dist/client/restrictions.js.map +1 -0
- package/dist/client/risk-based-mfa.d.ts +51 -0
- package/dist/client/risk-based-mfa.js +20 -0
- package/dist/client/risk-based-mfa.js.map +1 -0
- package/dist/client/roles.d.ts +84 -0
- package/dist/client/roles.js +57 -0
- package/dist/client/roles.js.map +1 -0
- package/dist/client/scim-provisioning.d.ts +94 -0
- package/dist/client/scim-provisioning.js +49 -0
- package/dist/client/scim-provisioning.js.map +1 -0
- package/dist/client/scim-tokens.d.ts +34 -0
- package/dist/client/scim-tokens.js +18 -0
- package/dist/client/scim-tokens.js.map +1 -0
- package/dist/client/sessions.d.ts +58 -0
- package/dist/client/sessions.js +26 -0
- package/dist/client/sessions.js.map +1 -0
- package/dist/client/sign-in-tokens.d.ts +18 -0
- package/dist/client/sign-in-tokens.js +11 -0
- package/dist/client/sign-in-tokens.js.map +1 -0
- package/dist/client/sms-templates.d.ts +46 -0
- package/dist/client/sms-templates.js +30 -0
- package/dist/client/sms-templates.js.map +1 -0
- package/dist/client/sso-connections.d.ts +76 -0
- package/dist/client/sso-connections.js +28 -0
- package/dist/client/sso-connections.js.map +1 -0
- package/dist/client/sso-onboarding.d.ts +76 -0
- package/dist/client/sso-onboarding.js +42 -0
- package/dist/client/sso-onboarding.js.map +1 -0
- package/dist/client/tokens.d.ts +37 -0
- package/dist/client/tokens.js +11 -0
- package/dist/client/tokens.js.map +1 -0
- package/dist/client/types.d.ts +41 -0
- package/dist/client/types.js +10 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/users.d.ts +204 -0
- package/dist/client/users.js +135 -0
- package/dist/client/users.js.map +1 -0
- package/dist/client/waitlist.d.ts +31 -0
- package/dist/client/waitlist.js +16 -0
- package/dist/client/waitlist.js.map +1 -0
- package/dist/client/webhooks.d.ts +50 -0
- package/dist/client/webhooks.js +24 -0
- package/dist/client/webhooks.js.map +1 -0
- package/dist/handshake.d.ts +76 -0
- package/dist/handshake.js +96 -0
- package/dist/handshake.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/jwks-cache.d.ts +62 -0
- package/dist/jwks-cache.js +114 -0
- package/dist/jwks-cache.js.map +1 -0
- package/dist/verify.d.ts +162 -0
- package/dist/verify.js +226 -0
- package/dist/verify.js.map +1 -0
- package/package.json +26 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { type RequestFn } from './request';
|
|
2
|
+
import type { CursorPage, CursorParams, DeletedObject, ListPage, Metadata } from './types';
|
|
3
|
+
/** A user as the BAPI serves it. `private_metadata` is never returned. */
|
|
4
|
+
export interface User {
|
|
5
|
+
object: 'user';
|
|
6
|
+
id: string;
|
|
7
|
+
username: string | null;
|
|
8
|
+
first_name: string | null;
|
|
9
|
+
last_name: string | null;
|
|
10
|
+
image_url: string | null;
|
|
11
|
+
public_metadata: Metadata;
|
|
12
|
+
mfa_enabled: boolean;
|
|
13
|
+
banned: boolean;
|
|
14
|
+
locked: boolean;
|
|
15
|
+
/** Epoch milliseconds, or null if never signed in. */
|
|
16
|
+
last_sign_in_at: number | null;
|
|
17
|
+
created_at: number;
|
|
18
|
+
updated_at: number;
|
|
19
|
+
}
|
|
20
|
+
export interface EmailAddress {
|
|
21
|
+
object: 'email_address';
|
|
22
|
+
id: string;
|
|
23
|
+
email_address: string;
|
|
24
|
+
verified: boolean;
|
|
25
|
+
primary: boolean;
|
|
26
|
+
created_at: number;
|
|
27
|
+
}
|
|
28
|
+
export interface UserSession {
|
|
29
|
+
object: 'session';
|
|
30
|
+
id: string;
|
|
31
|
+
user_id: string;
|
|
32
|
+
status: string;
|
|
33
|
+
last_active_at: number;
|
|
34
|
+
expire_at: number;
|
|
35
|
+
abandon_at: number;
|
|
36
|
+
created_at: number;
|
|
37
|
+
}
|
|
38
|
+
export type ListUsersParams = CursorParams;
|
|
39
|
+
export interface CreateUserBody {
|
|
40
|
+
email_address: string;
|
|
41
|
+
password?: string;
|
|
42
|
+
first_name?: string;
|
|
43
|
+
last_name?: string;
|
|
44
|
+
email_verified?: boolean;
|
|
45
|
+
public_metadata?: Metadata;
|
|
46
|
+
private_metadata?: Metadata;
|
|
47
|
+
unsafe_metadata?: Metadata;
|
|
48
|
+
}
|
|
49
|
+
export interface UpdateUserBody {
|
|
50
|
+
first_name?: string;
|
|
51
|
+
last_name?: string;
|
|
52
|
+
public_metadata?: Metadata;
|
|
53
|
+
private_metadata?: Metadata;
|
|
54
|
+
}
|
|
55
|
+
export interface ReplaceUserMetadataBody {
|
|
56
|
+
public_metadata?: Metadata;
|
|
57
|
+
private_metadata?: Metadata;
|
|
58
|
+
unsafe_metadata?: Metadata;
|
|
59
|
+
}
|
|
60
|
+
export declare function usersResource(request: RequestFn): {
|
|
61
|
+
/** `GET /v1/users` — cursor-paginated. */
|
|
62
|
+
list(params?: ListUsersParams): Promise<CursorPage<User>>;
|
|
63
|
+
get(id: string): Promise<User>;
|
|
64
|
+
create(body: CreateUserBody, idempotencyKey?: string): Promise<User>;
|
|
65
|
+
update(id: string, body: UpdateUserBody): Promise<User>;
|
|
66
|
+
/** `PUT /v1/users/:id/metadata` — replaces the named bags wholesale. */
|
|
67
|
+
replaceMetadata(id: string, body: ReplaceUserMetadataBody): Promise<User>;
|
|
68
|
+
ban(id: string): Promise<User>;
|
|
69
|
+
unban(id: string): Promise<User>;
|
|
70
|
+
lock(id: string, body?: {
|
|
71
|
+
duration_in_seconds?: number;
|
|
72
|
+
}): Promise<User>;
|
|
73
|
+
unlock(id: string): Promise<User>;
|
|
74
|
+
delete(id: string): Promise<DeletedObject>;
|
|
75
|
+
resetMfa(id: string): Promise<{
|
|
76
|
+
object: "user";
|
|
77
|
+
id: string;
|
|
78
|
+
mfa_enabled: false;
|
|
79
|
+
}>;
|
|
80
|
+
deleteMfaFactor(id: string, factorId: string): Promise<{
|
|
81
|
+
object: "mfa_factor";
|
|
82
|
+
id: string;
|
|
83
|
+
deleted: true;
|
|
84
|
+
}>;
|
|
85
|
+
listSessions(id: string): Promise<ListPage<UserSession>>;
|
|
86
|
+
revokeSessions(id: string): Promise<{
|
|
87
|
+
object: "user";
|
|
88
|
+
id: string;
|
|
89
|
+
sessions_revoked: number;
|
|
90
|
+
}>;
|
|
91
|
+
addEmail(id: string, body: {
|
|
92
|
+
email_address: string;
|
|
93
|
+
}): Promise<EmailAddress>;
|
|
94
|
+
verifyEmail(id: string, emailId: string): Promise<EmailAddress>;
|
|
95
|
+
setPrimaryEmail(id: string, emailId: string): Promise<EmailAddress>;
|
|
96
|
+
/** `GET /v1/users/:id/oauth_access_tokens/:provider` — a live provider credential. */
|
|
97
|
+
getOAuthAccessToken(id: string, provider: string): Promise<OAuthAccessToken>;
|
|
98
|
+
/**
|
|
99
|
+
* `GET /v1/users/:id/identities` — the base Atlas identity plus one entry per
|
|
100
|
+
* linked external account. Tokens are never included.
|
|
101
|
+
*/
|
|
102
|
+
listIdentities(id: string): Promise<ListPage<Identity>>;
|
|
103
|
+
/**
|
|
104
|
+
* `POST /v1/users/:id/identities` — merge a secondary user INTO this one
|
|
105
|
+
* (Auth0 `post_identities` parity). The secondary is retired by soft-delete;
|
|
106
|
+
* collisions (a provider/email the primary already holds) are reported, never
|
|
107
|
+
* clobbered.
|
|
108
|
+
*/
|
|
109
|
+
linkIdentity(id: string, body: {
|
|
110
|
+
secondary_user_id: string;
|
|
111
|
+
}, idempotencyKey?: string): Promise<ListPage<Identity> & {
|
|
112
|
+
collisions: Array<{
|
|
113
|
+
type: string;
|
|
114
|
+
detail: string;
|
|
115
|
+
}>;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* `POST /v1/users/:id/external_accounts/connect` — start an OAuth flow that
|
|
119
|
+
* links a NEW provider identity to THIS user (backend-initiated connect). For
|
|
120
|
+
* an app whose own backend knows the current user (not an Atlas session
|
|
121
|
+
* cookie): call this with the user's id, then redirect the browser to the
|
|
122
|
+
* returned `authorization_url`. The callback links the provider to this user
|
|
123
|
+
* WITHOUT creating a session, returning `__atlas_status=connected`. The
|
|
124
|
+
* `IDENTITY_ALREADY_LINKED` guard refuses an identity owned by another user.
|
|
125
|
+
*/
|
|
126
|
+
connectExternalAccount(id: string, body: {
|
|
127
|
+
provider: string;
|
|
128
|
+
redirect_url: string;
|
|
129
|
+
additional_scopes?: string[];
|
|
130
|
+
}, idempotencyKey?: string): Promise<{
|
|
131
|
+
object: "external_account_connection";
|
|
132
|
+
provider: string;
|
|
133
|
+
user_id: string;
|
|
134
|
+
attempt_id: string;
|
|
135
|
+
authorization_url: string;
|
|
136
|
+
scopes: string[];
|
|
137
|
+
}>;
|
|
138
|
+
/**
|
|
139
|
+
* `DELETE /v1/users/:id/identities/:identityId` — extract a linked provider
|
|
140
|
+
* identity into a brand-new standalone user. The base identity and a user's
|
|
141
|
+
* sole remaining sign-in identity cannot be unlinked.
|
|
142
|
+
*/
|
|
143
|
+
unlinkIdentity(id: string, identityId: string): Promise<{
|
|
144
|
+
object: "identity";
|
|
145
|
+
id: string;
|
|
146
|
+
provider: string;
|
|
147
|
+
unlinked: true;
|
|
148
|
+
new_user_id: string;
|
|
149
|
+
}>;
|
|
150
|
+
/** `GET /v1/users/:id/grants` — the OAuth clients this user has authorized. */
|
|
151
|
+
listGrants(id: string): Promise<ListPage<Grant>>;
|
|
152
|
+
/**
|
|
153
|
+
* `DELETE /v1/users/:id/grants` — revoke every consent grant the user holds,
|
|
154
|
+
* cascading to the associated access/refresh tokens so de-authorized apps
|
|
155
|
+
* stop on their next call.
|
|
156
|
+
*/
|
|
157
|
+
revokeAllGrants(id: string): Promise<{
|
|
158
|
+
object: "user";
|
|
159
|
+
id: string;
|
|
160
|
+
grants_revoked: number;
|
|
161
|
+
tokens_revoked: number;
|
|
162
|
+
}>;
|
|
163
|
+
/**
|
|
164
|
+
* `DELETE /v1/grants/:id` — revoke ONE consent grant (and its live tokens).
|
|
165
|
+
* Grants are instance-scoped, so this is not nested under a user id.
|
|
166
|
+
*/
|
|
167
|
+
revokeGrant(grantId: string): Promise<{
|
|
168
|
+
object: "grant";
|
|
169
|
+
id: string;
|
|
170
|
+
deleted: true;
|
|
171
|
+
tokens_revoked: number;
|
|
172
|
+
}>;
|
|
173
|
+
};
|
|
174
|
+
/** One sign-in identity on a user: the base Atlas anchor, or a linked provider. */
|
|
175
|
+
export interface Identity {
|
|
176
|
+
object: 'identity';
|
|
177
|
+
id: string;
|
|
178
|
+
type: 'atlas' | 'oauth';
|
|
179
|
+
provider: string;
|
|
180
|
+
provider_user_id?: string;
|
|
181
|
+
email?: string | null;
|
|
182
|
+
email_verified?: boolean;
|
|
183
|
+
is_primary: boolean;
|
|
184
|
+
has_password?: boolean;
|
|
185
|
+
}
|
|
186
|
+
/** An OAuth consent grant — the scopes a user authorized a client for. Never a token. */
|
|
187
|
+
export interface Grant {
|
|
188
|
+
object: 'grant';
|
|
189
|
+
id: string;
|
|
190
|
+
client_id: string | null;
|
|
191
|
+
client_name: string | null;
|
|
192
|
+
scopes: string[];
|
|
193
|
+
granted_at: number;
|
|
194
|
+
updated_at: number;
|
|
195
|
+
}
|
|
196
|
+
export interface OAuthAccessToken {
|
|
197
|
+
object: 'oauth_access_token';
|
|
198
|
+
provider: string;
|
|
199
|
+
/** The provider access token itself. Field is `token`, not `access_token`. */
|
|
200
|
+
token: string;
|
|
201
|
+
expires_at: number | null;
|
|
202
|
+
scopes: string[];
|
|
203
|
+
refreshed: boolean;
|
|
204
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usersResource = usersResource;
|
|
4
|
+
const request_1 = require("./request");
|
|
5
|
+
function usersResource(request) {
|
|
6
|
+
return {
|
|
7
|
+
/** `GET /v1/users` — cursor-paginated. */
|
|
8
|
+
list(params = {}) {
|
|
9
|
+
return request({ method: 'GET', path: '/v1/users', query: { ...params } });
|
|
10
|
+
},
|
|
11
|
+
get(id) {
|
|
12
|
+
return request({ method: 'GET', path: `/v1/users/${(0, request_1.enc)(id)}` });
|
|
13
|
+
},
|
|
14
|
+
create(body, idempotencyKey) {
|
|
15
|
+
return request({ method: 'POST', path: '/v1/users', body, idempotencyKey });
|
|
16
|
+
},
|
|
17
|
+
update(id, body) {
|
|
18
|
+
return request({ method: 'PATCH', path: `/v1/users/${(0, request_1.enc)(id)}`, body });
|
|
19
|
+
},
|
|
20
|
+
/** `PUT /v1/users/:id/metadata` — replaces the named bags wholesale. */
|
|
21
|
+
replaceMetadata(id, body) {
|
|
22
|
+
return request({ method: 'PUT', path: `/v1/users/${(0, request_1.enc)(id)}/metadata`, body });
|
|
23
|
+
},
|
|
24
|
+
ban(id) {
|
|
25
|
+
return request({ method: 'POST', path: `/v1/users/${(0, request_1.enc)(id)}/ban` });
|
|
26
|
+
},
|
|
27
|
+
unban(id) {
|
|
28
|
+
return request({ method: 'POST', path: `/v1/users/${(0, request_1.enc)(id)}/unban` });
|
|
29
|
+
},
|
|
30
|
+
lock(id, body = {}) {
|
|
31
|
+
return request({ method: 'POST', path: `/v1/users/${(0, request_1.enc)(id)}/lock`, body });
|
|
32
|
+
},
|
|
33
|
+
unlock(id) {
|
|
34
|
+
return request({ method: 'POST', path: `/v1/users/${(0, request_1.enc)(id)}/unlock` });
|
|
35
|
+
},
|
|
36
|
+
delete(id) {
|
|
37
|
+
return request({ method: 'DELETE', path: `/v1/users/${(0, request_1.enc)(id)}` });
|
|
38
|
+
},
|
|
39
|
+
resetMfa(id) {
|
|
40
|
+
return request({ method: 'POST', path: `/v1/users/${(0, request_1.enc)(id)}/reset_mfa` });
|
|
41
|
+
},
|
|
42
|
+
deleteMfaFactor(id, factorId) {
|
|
43
|
+
return request({ method: 'DELETE', path: `/v1/users/${(0, request_1.enc)(id)}/mfa/${(0, request_1.enc)(factorId)}` });
|
|
44
|
+
},
|
|
45
|
+
listSessions(id) {
|
|
46
|
+
return request({ method: 'GET', path: `/v1/users/${(0, request_1.enc)(id)}/sessions` });
|
|
47
|
+
},
|
|
48
|
+
revokeSessions(id) {
|
|
49
|
+
return request({ method: 'POST', path: `/v1/users/${(0, request_1.enc)(id)}/sessions/revoke` });
|
|
50
|
+
},
|
|
51
|
+
addEmail(id, body) {
|
|
52
|
+
return request({ method: 'POST', path: `/v1/users/${(0, request_1.enc)(id)}/email_addresses`, body });
|
|
53
|
+
},
|
|
54
|
+
verifyEmail(id, emailId) {
|
|
55
|
+
return request({
|
|
56
|
+
method: 'POST',
|
|
57
|
+
path: `/v1/users/${(0, request_1.enc)(id)}/email_addresses/${(0, request_1.enc)(emailId)}/verify`,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
setPrimaryEmail(id, emailId) {
|
|
61
|
+
return request({
|
|
62
|
+
method: 'POST',
|
|
63
|
+
path: `/v1/users/${(0, request_1.enc)(id)}/email_addresses/${(0, request_1.enc)(emailId)}/primary`,
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
/** `GET /v1/users/:id/oauth_access_tokens/:provider` — a live provider credential. */
|
|
67
|
+
getOAuthAccessToken(id, provider) {
|
|
68
|
+
return request({
|
|
69
|
+
method: 'GET',
|
|
70
|
+
path: `/v1/users/${(0, request_1.enc)(id)}/oauth_access_tokens/${(0, request_1.enc)(provider)}`,
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
/**
|
|
74
|
+
* `GET /v1/users/:id/identities` — the base Atlas identity plus one entry per
|
|
75
|
+
* linked external account. Tokens are never included.
|
|
76
|
+
*/
|
|
77
|
+
listIdentities(id) {
|
|
78
|
+
return request({ method: 'GET', path: `/v1/users/${(0, request_1.enc)(id)}/identities` });
|
|
79
|
+
},
|
|
80
|
+
/**
|
|
81
|
+
* `POST /v1/users/:id/identities` — merge a secondary user INTO this one
|
|
82
|
+
* (Auth0 `post_identities` parity). The secondary is retired by soft-delete;
|
|
83
|
+
* collisions (a provider/email the primary already holds) are reported, never
|
|
84
|
+
* clobbered.
|
|
85
|
+
*/
|
|
86
|
+
linkIdentity(id, body, idempotencyKey) {
|
|
87
|
+
return request({ method: 'POST', path: `/v1/users/${(0, request_1.enc)(id)}/identities`, body, idempotencyKey });
|
|
88
|
+
},
|
|
89
|
+
/**
|
|
90
|
+
* `POST /v1/users/:id/external_accounts/connect` — start an OAuth flow that
|
|
91
|
+
* links a NEW provider identity to THIS user (backend-initiated connect). For
|
|
92
|
+
* an app whose own backend knows the current user (not an Atlas session
|
|
93
|
+
* cookie): call this with the user's id, then redirect the browser to the
|
|
94
|
+
* returned `authorization_url`. The callback links the provider to this user
|
|
95
|
+
* WITHOUT creating a session, returning `__atlas_status=connected`. The
|
|
96
|
+
* `IDENTITY_ALREADY_LINKED` guard refuses an identity owned by another user.
|
|
97
|
+
*/
|
|
98
|
+
connectExternalAccount(id, body, idempotencyKey) {
|
|
99
|
+
return request({
|
|
100
|
+
method: 'POST',
|
|
101
|
+
path: `/v1/users/${(0, request_1.enc)(id)}/external_accounts/connect`,
|
|
102
|
+
body,
|
|
103
|
+
idempotencyKey,
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
/**
|
|
107
|
+
* `DELETE /v1/users/:id/identities/:identityId` — extract a linked provider
|
|
108
|
+
* identity into a brand-new standalone user. The base identity and a user's
|
|
109
|
+
* sole remaining sign-in identity cannot be unlinked.
|
|
110
|
+
*/
|
|
111
|
+
unlinkIdentity(id, identityId) {
|
|
112
|
+
return request({ method: 'DELETE', path: `/v1/users/${(0, request_1.enc)(id)}/identities/${(0, request_1.enc)(identityId)}` });
|
|
113
|
+
},
|
|
114
|
+
/** `GET /v1/users/:id/grants` — the OAuth clients this user has authorized. */
|
|
115
|
+
listGrants(id) {
|
|
116
|
+
return request({ method: 'GET', path: `/v1/users/${(0, request_1.enc)(id)}/grants` });
|
|
117
|
+
},
|
|
118
|
+
/**
|
|
119
|
+
* `DELETE /v1/users/:id/grants` — revoke every consent grant the user holds,
|
|
120
|
+
* cascading to the associated access/refresh tokens so de-authorized apps
|
|
121
|
+
* stop on their next call.
|
|
122
|
+
*/
|
|
123
|
+
revokeAllGrants(id) {
|
|
124
|
+
return request({ method: 'DELETE', path: `/v1/users/${(0, request_1.enc)(id)}/grants` });
|
|
125
|
+
},
|
|
126
|
+
/**
|
|
127
|
+
* `DELETE /v1/grants/:id` — revoke ONE consent grant (and its live tokens).
|
|
128
|
+
* Grants are instance-scoped, so this is not nested under a user id.
|
|
129
|
+
*/
|
|
130
|
+
revokeGrant(grantId) {
|
|
131
|
+
return request({ method: 'DELETE', path: `/v1/grants/${(0, request_1.enc)(grantId)}` });
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=users.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/client/users.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type RequestFn } from './request';
|
|
2
|
+
import type { CursorParams } from './types';
|
|
3
|
+
export interface WaitlistEntry {
|
|
4
|
+
object: 'waitlist_entry';
|
|
5
|
+
id: string;
|
|
6
|
+
email_address: string;
|
|
7
|
+
status: string;
|
|
8
|
+
note: string | null;
|
|
9
|
+
decided_by: string | null;
|
|
10
|
+
decided_at: number | null;
|
|
11
|
+
created_at: number;
|
|
12
|
+
}
|
|
13
|
+
export interface ListWaitlistParams extends CursorParams {
|
|
14
|
+
status?: string;
|
|
15
|
+
query?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ListWaitlistResponse {
|
|
18
|
+
object: 'list';
|
|
19
|
+
data: WaitlistEntry[];
|
|
20
|
+
counts: Record<string, number>;
|
|
21
|
+
has_more: boolean;
|
|
22
|
+
next_cursor: string | null;
|
|
23
|
+
}
|
|
24
|
+
export declare function waitlistResource(request: RequestFn): {
|
|
25
|
+
list(params?: ListWaitlistParams): Promise<ListWaitlistResponse>;
|
|
26
|
+
/** Approve or deny a waitlist entry. */
|
|
27
|
+
decide(id: string, body: {
|
|
28
|
+
status: "approved" | "denied";
|
|
29
|
+
note?: string;
|
|
30
|
+
}): Promise<WaitlistEntry>;
|
|
31
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.waitlistResource = waitlistResource;
|
|
4
|
+
const request_1 = require("./request");
|
|
5
|
+
function waitlistResource(request) {
|
|
6
|
+
return {
|
|
7
|
+
list(params = {}) {
|
|
8
|
+
return request({ method: 'GET', path: '/v1/waitlist_entries', query: { ...params } });
|
|
9
|
+
},
|
|
10
|
+
/** Approve or deny a waitlist entry. */
|
|
11
|
+
decide(id, body) {
|
|
12
|
+
return request({ method: 'POST', path: `/v1/waitlist_entries/${(0, request_1.enc)(id)}/decide`, body });
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=waitlist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waitlist.js","sourceRoot":"","sources":["../../src/client/waitlist.ts"],"names":[],"mappings":";;AA2BA,4CAaC;AAxCD,uCAAgD;AA2BhD,SAAgB,gBAAgB,CAAC,OAAkB;IACjD,OAAO;QACL,IAAI,CAAC,SAA6B,EAAE;YAClC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,CAAC;QACxF,CAAC;QACD,wCAAwC;QACxC,MAAM,CACJ,EAAU,EACV,IAAsD;YAEtD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,wBAAwB,IAAA,aAAG,EAAC,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3F,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type RequestFn } from './request';
|
|
2
|
+
export interface WebhookEndpoint {
|
|
3
|
+
object: 'webhook_endpoint';
|
|
4
|
+
id: string;
|
|
5
|
+
url: string;
|
|
6
|
+
enabled_events: string[];
|
|
7
|
+
active: boolean;
|
|
8
|
+
disabled_at: number | null;
|
|
9
|
+
created_at: number;
|
|
10
|
+
}
|
|
11
|
+
/** Create reveals the signing secret (`whsec_...`) exactly once. */
|
|
12
|
+
export interface WebhookEndpointWithSecret extends WebhookEndpoint {
|
|
13
|
+
secret: string;
|
|
14
|
+
}
|
|
15
|
+
export interface WebhookDelivery {
|
|
16
|
+
object: 'webhook_delivery';
|
|
17
|
+
id: string;
|
|
18
|
+
event_id: string;
|
|
19
|
+
attempt_number: number;
|
|
20
|
+
status: string;
|
|
21
|
+
http_status: number | null;
|
|
22
|
+
response_snippet: string | null;
|
|
23
|
+
next_retry_at: number | null;
|
|
24
|
+
delivered_at: number | null;
|
|
25
|
+
created_at: number;
|
|
26
|
+
}
|
|
27
|
+
export interface CreateWebhookEndpointBody {
|
|
28
|
+
url: string;
|
|
29
|
+
/** Each entry is `"*"` or a known event name. */
|
|
30
|
+
enabled_events?: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare function webhooksResource(request: RequestFn): {
|
|
33
|
+
endpoints: {
|
|
34
|
+
list(): Promise<{
|
|
35
|
+
data: WebhookEndpoint[];
|
|
36
|
+
has_more: false;
|
|
37
|
+
}>;
|
|
38
|
+
create(body: CreateWebhookEndpointBody, idempotencyKey?: string): Promise<WebhookEndpointWithSecret>;
|
|
39
|
+
delete(id: string): Promise<{
|
|
40
|
+
object: "webhook_endpoint";
|
|
41
|
+
id: string;
|
|
42
|
+
deleted: true;
|
|
43
|
+
}>;
|
|
44
|
+
};
|
|
45
|
+
/** Delivery log for an endpoint. */
|
|
46
|
+
deliveries(id: string): Promise<{
|
|
47
|
+
data: WebhookDelivery[];
|
|
48
|
+
has_more: false;
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.webhooksResource = webhooksResource;
|
|
4
|
+
const request_1 = require("./request");
|
|
5
|
+
function webhooksResource(request) {
|
|
6
|
+
return {
|
|
7
|
+
endpoints: {
|
|
8
|
+
list() {
|
|
9
|
+
return request({ method: 'GET', path: '/v1/webhook_endpoints' });
|
|
10
|
+
},
|
|
11
|
+
create(body, idempotencyKey) {
|
|
12
|
+
return request({ method: 'POST', path: '/v1/webhook_endpoints', body, idempotencyKey });
|
|
13
|
+
},
|
|
14
|
+
delete(id) {
|
|
15
|
+
return request({ method: 'DELETE', path: `/v1/webhook_endpoints/${(0, request_1.enc)(id)}` });
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
/** Delivery log for an endpoint. */
|
|
19
|
+
deliveries(id) {
|
|
20
|
+
return request({ method: 'GET', path: `/v1/webhook_endpoints/${(0, request_1.enc)(id)}/deliveries` });
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=webhooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/client/webhooks.ts"],"names":[],"mappings":";;AAoCA,4CAuBC;AA3DD,uCAAgD;AAoChD,SAAgB,gBAAgB,CAAC,OAAkB;IACjD,OAAO;QACL,SAAS,EAAE;YACT,IAAI;gBACF,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,CACJ,IAA+B,EAC/B,cAAuB;gBAEvB,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;YAC1F,CAAC;YACD,MAAM,CACJ,EAAU;gBAEV,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,yBAAyB,IAAA,aAAG,EAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YACjF,CAAC;SACF;QACD,oCAAoC;QACpC,UAAU,CAAC,EAAU;YACnB,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,yBAAyB,IAAA,aAAG,EAAC,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC;QACzF,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-property SSO handshake — the second property's server-side redeem step.
|
|
3
|
+
*
|
|
4
|
+
* When a satellite (a property on a DIFFERENT registrable domain than the main
|
|
5
|
+
* app) has no local session, the SDK middleware bounces the browser through
|
|
6
|
+
* `GET {fapiOrigin}/v1/client/handshake`, which — if the user has an Atlas
|
|
7
|
+
* session — redirects back with `?__atlas_hs=ok&__atlas_hu=<userId>&__atlas_hn=
|
|
8
|
+
* <nonce>`. This helper exchanges that single-use nonce for a fresh session,
|
|
9
|
+
* server-to-server, so the tokens are returned in the response BODY (never a
|
|
10
|
+
* URL). The caller sets them as its OWN first-party cookies:
|
|
11
|
+
*
|
|
12
|
+
* const s = await redeemHandshake({ fapiOrigin, publishableKey, userId, nonce });
|
|
13
|
+
* if (s) {
|
|
14
|
+
* res.cookies.set('__session', s.jwt, { path: '/', sameSite: 'lax', secure: true });
|
|
15
|
+
* res.cookies.set('__atlas_rt', s.refreshToken, { path: '/', httpOnly: true, sameSite: 'lax', secure: true });
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* (Same-registrable-domain SUBDOMAINS don't need this — the handshake sets a
|
|
19
|
+
* parent-domain cookie directly; this is only the cross-domain path.)
|
|
20
|
+
*/
|
|
21
|
+
export interface RedeemHandshakeOptions {
|
|
22
|
+
/** Origin of the Atlas Frontend API, e.g. `https://id.atlasauth.net`. */
|
|
23
|
+
fapiOrigin: string;
|
|
24
|
+
/** The instance publishable key (`pk_…`). */
|
|
25
|
+
publishableKey: string;
|
|
26
|
+
/**
|
|
27
|
+
* The `__atlas_hu` value from the return URL. Advisory only — the server
|
|
28
|
+
* issues the session for the subject the nonce was bound to, not this value.
|
|
29
|
+
*/
|
|
30
|
+
userId: string;
|
|
31
|
+
/** The single-use `__atlas_hn` nonce from the return URL. */
|
|
32
|
+
nonce: string;
|
|
33
|
+
/**
|
|
34
|
+
* The PKCE `code_verifier` this server generated (with {@link createPkcePair})
|
|
35
|
+
* BEFORE bouncing the browser to the handshake, stashed server-side (a
|
|
36
|
+
* short-lived HttpOnly cookie). Proves possession of the challenge the nonce
|
|
37
|
+
* was bound to — a stolen nonce without it is inert.
|
|
38
|
+
*/
|
|
39
|
+
codeVerifier: string;
|
|
40
|
+
fetchImpl?: typeof fetch;
|
|
41
|
+
}
|
|
42
|
+
export interface PkcePair {
|
|
43
|
+
/** Kept server-side; never leaves the redeeming server. */
|
|
44
|
+
verifier: string;
|
|
45
|
+
/** base64url(SHA-256(verifier)); the only half that reaches the handshake. */
|
|
46
|
+
challenge: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate a PKCE (RFC 7636, S256) pair for a cross-domain handshake. Uses only
|
|
50
|
+
* Web Crypto globals so it runs unchanged on the edge/worker runtimes the SDK
|
|
51
|
+
* middleware targets — no `node:crypto`. Send `challenge` on the handshake URL
|
|
52
|
+
* as `code_challenge`; stash `verifier` server-side and pass it to
|
|
53
|
+
* {@link redeemHandshake}.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createPkcePair(): Promise<PkcePair>;
|
|
56
|
+
export interface HandshakeSession {
|
|
57
|
+
/** The `__session` JWT value to set as a cookie (script-readable, short-lived). */
|
|
58
|
+
jwt: string;
|
|
59
|
+
/** The `__atlas_rt` refresh value to set as an HttpOnly cookie. */
|
|
60
|
+
refreshToken: string;
|
|
61
|
+
sessionId: string;
|
|
62
|
+
/** Seconds until the `__session` JWT expires. */
|
|
63
|
+
expiresIn: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Redeem a handshake nonce for a fresh session. Returns `null` when the nonce is
|
|
67
|
+
* missing/expired/already used (the caller should then fall back to sign-in).
|
|
68
|
+
* Never throws on an auth failure — a bad nonce is a signed-out signal, not an
|
|
69
|
+
* error that should take the page down.
|
|
70
|
+
*/
|
|
71
|
+
export declare function redeemHandshake(options: RedeemHandshakeOptions): Promise<HandshakeSession | null>;
|
|
72
|
+
/** Extract the handshake params from a return URL (or its query string). */
|
|
73
|
+
export declare function readHandshakeParams(urlOrSearch: string): {
|
|
74
|
+
userId: string;
|
|
75
|
+
nonce: string;
|
|
76
|
+
} | null;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cross-property SSO handshake — the second property's server-side redeem step.
|
|
4
|
+
*
|
|
5
|
+
* When a satellite (a property on a DIFFERENT registrable domain than the main
|
|
6
|
+
* app) has no local session, the SDK middleware bounces the browser through
|
|
7
|
+
* `GET {fapiOrigin}/v1/client/handshake`, which — if the user has an Atlas
|
|
8
|
+
* session — redirects back with `?__atlas_hs=ok&__atlas_hu=<userId>&__atlas_hn=
|
|
9
|
+
* <nonce>`. This helper exchanges that single-use nonce for a fresh session,
|
|
10
|
+
* server-to-server, so the tokens are returned in the response BODY (never a
|
|
11
|
+
* URL). The caller sets them as its OWN first-party cookies:
|
|
12
|
+
*
|
|
13
|
+
* const s = await redeemHandshake({ fapiOrigin, publishableKey, userId, nonce });
|
|
14
|
+
* if (s) {
|
|
15
|
+
* res.cookies.set('__session', s.jwt, { path: '/', sameSite: 'lax', secure: true });
|
|
16
|
+
* res.cookies.set('__atlas_rt', s.refreshToken, { path: '/', httpOnly: true, sameSite: 'lax', secure: true });
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* (Same-registrable-domain SUBDOMAINS don't need this — the handshake sets a
|
|
20
|
+
* parent-domain cookie directly; this is only the cross-domain path.)
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.createPkcePair = createPkcePair;
|
|
24
|
+
exports.redeemHandshake = redeemHandshake;
|
|
25
|
+
exports.readHandshakeParams = readHandshakeParams;
|
|
26
|
+
const base64url = (bytes) => {
|
|
27
|
+
let bin = '';
|
|
28
|
+
for (const b of bytes)
|
|
29
|
+
bin += String.fromCharCode(b);
|
|
30
|
+
// btoa is available in every SDK runtime (edge, workers, browser, Node ≥16).
|
|
31
|
+
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Generate a PKCE (RFC 7636, S256) pair for a cross-domain handshake. Uses only
|
|
35
|
+
* Web Crypto globals so it runs unchanged on the edge/worker runtimes the SDK
|
|
36
|
+
* middleware targets — no `node:crypto`. Send `challenge` on the handshake URL
|
|
37
|
+
* as `code_challenge`; stash `verifier` server-side and pass it to
|
|
38
|
+
* {@link redeemHandshake}.
|
|
39
|
+
*/
|
|
40
|
+
async function createPkcePair() {
|
|
41
|
+
const raw = new Uint8Array(32);
|
|
42
|
+
crypto.getRandomValues(raw);
|
|
43
|
+
const verifier = base64url(raw);
|
|
44
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
|
|
45
|
+
return { verifier, challenge: base64url(new Uint8Array(digest)) };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Redeem a handshake nonce for a fresh session. Returns `null` when the nonce is
|
|
49
|
+
* missing/expired/already used (the caller should then fall back to sign-in).
|
|
50
|
+
* Never throws on an auth failure — a bad nonce is a signed-out signal, not an
|
|
51
|
+
* error that should take the page down.
|
|
52
|
+
*/
|
|
53
|
+
async function redeemHandshake(options) {
|
|
54
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
55
|
+
const url = new URL('/v1/client/handshake/redeem', options.fapiOrigin).toString();
|
|
56
|
+
let res;
|
|
57
|
+
try {
|
|
58
|
+
res = await doFetch(url, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: {
|
|
61
|
+
'content-type': 'application/json',
|
|
62
|
+
'x-publishable-key': options.publishableKey,
|
|
63
|
+
},
|
|
64
|
+
body: JSON.stringify({
|
|
65
|
+
user_id: options.userId,
|
|
66
|
+
nonce: options.nonce,
|
|
67
|
+
code_verifier: options.codeVerifier,
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (!res.ok)
|
|
75
|
+
return null;
|
|
76
|
+
const data = (await res.json().catch(() => null));
|
|
77
|
+
if (!data?.jwt || !data.refresh_token)
|
|
78
|
+
return null;
|
|
79
|
+
return {
|
|
80
|
+
jwt: data.jwt,
|
|
81
|
+
refreshToken: data.refresh_token,
|
|
82
|
+
sessionId: data.session_id ?? '',
|
|
83
|
+
expiresIn: data.expires_in ?? 0,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Extract the handshake params from a return URL (or its query string). */
|
|
87
|
+
function readHandshakeParams(urlOrSearch) {
|
|
88
|
+
const q = urlOrSearch.includes('?') ? urlOrSearch.slice(urlOrSearch.indexOf('?')) : urlOrSearch;
|
|
89
|
+
const params = new URLSearchParams(q.startsWith('?') ? q : `?${q}`);
|
|
90
|
+
if (params.get('__atlas_hs') !== 'ok')
|
|
91
|
+
return null;
|
|
92
|
+
const userId = params.get('__atlas_hu');
|
|
93
|
+
const nonce = params.get('__atlas_hn');
|
|
94
|
+
return userId && nonce ? { userId, nonce } : null;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=handshake.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handshake.js","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AA6CH,wCAMC;AAkBD,0CAqCC;AAGD,kDAOC;AA5FD,MAAM,SAAS,GAAG,CAAC,KAAiB,EAAU,EAAE;IAC9C,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACrD,6EAA6E;IAC7E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC9E,CAAC,CAAC;AASF;;;;;;GAMG;AACI,KAAK,UAAU,cAAc;IAClC,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAC/B,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IACzF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC;AAYD;;;;;GAKG;AACI,KAAK,UAAU,eAAe,CAAC,OAA+B;IACnE,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,6BAA6B,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;IAElF,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE;YACvB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,mBAAmB,EAAE,OAAO,CAAC,cAAc;aAC5C;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,OAAO,EAAE,OAAO,CAAC,MAAM;gBACvB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,aAAa,EAAE,OAAO,CAAC,YAAY;aACpC,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAKxC,CAAC;IACT,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAEnD,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,YAAY,EAAE,IAAI,CAAC,aAAa;QAChC,SAAS,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;QAChC,SAAS,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,SAAgB,mBAAmB,CAAC,WAAmB;IACrD,MAAM,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAChG,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpE,IAAI,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACvC,OAAO,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC"}
|