@authn-sh/sdk-node 0.4.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +117 -0
- package/dist/errors.cjs +45 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +46 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +1529 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +728 -0
- package/dist/index.d.ts +728 -0
- package/dist/index.js +1477 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1477 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual, createHash, randomUUID } from 'crypto';
|
|
2
|
+
import { createRemoteJWKSet, decodeProtectedHeader, jwtVerify } from 'jose';
|
|
3
|
+
|
|
4
|
+
// src/errors/index.ts
|
|
5
|
+
var AuthnHttpError = class extends Error {
|
|
6
|
+
constructor(status, errors, requestId, message) {
|
|
7
|
+
super(message ?? (errors[0]?.longMessage || errors[0]?.message) ?? `authn.sh API returned HTTP ${status}`);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.errors = errors;
|
|
10
|
+
this.requestId = requestId;
|
|
11
|
+
}
|
|
12
|
+
status;
|
|
13
|
+
errors;
|
|
14
|
+
requestId;
|
|
15
|
+
name = "AuthnHttpError";
|
|
16
|
+
/** The primary error code returned by the API (when present). */
|
|
17
|
+
get code() {
|
|
18
|
+
return this.errors[0]?.code ?? null;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var AuthnConfigError = class extends Error {
|
|
22
|
+
name = "AuthnConfigError";
|
|
23
|
+
};
|
|
24
|
+
var AuthnTokenInvalidError = class extends Error {
|
|
25
|
+
constructor(reason, message) {
|
|
26
|
+
super(message ?? `Token invalid: ${reason}`);
|
|
27
|
+
this.reason = reason;
|
|
28
|
+
}
|
|
29
|
+
reason;
|
|
30
|
+
name = "AuthnTokenInvalidError";
|
|
31
|
+
};
|
|
32
|
+
var AuthnWebhookSignatureInvalidError = class extends Error {
|
|
33
|
+
constructor(reason, message) {
|
|
34
|
+
super(message ?? `Webhook signature invalid: ${reason}`);
|
|
35
|
+
this.reason = reason;
|
|
36
|
+
}
|
|
37
|
+
reason;
|
|
38
|
+
name = "AuthnWebhookSignatureInvalidError";
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/resources/ListParams.ts
|
|
42
|
+
var ListParams = class {
|
|
43
|
+
constructor(limit, offset, orderBy) {
|
|
44
|
+
this.limit = limit;
|
|
45
|
+
this.offset = offset;
|
|
46
|
+
this.orderBy = orderBy;
|
|
47
|
+
}
|
|
48
|
+
limit;
|
|
49
|
+
offset;
|
|
50
|
+
orderBy;
|
|
51
|
+
toQuery() {
|
|
52
|
+
const q = {};
|
|
53
|
+
if (this.limit !== void 0) q.limit = this.limit;
|
|
54
|
+
if (this.offset !== void 0) q.offset = this.offset;
|
|
55
|
+
if (this.orderBy !== void 0) q.order_by = this.orderBy;
|
|
56
|
+
return q;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// src/resources/Manager.ts
|
|
61
|
+
var Manager = class {
|
|
62
|
+
constructor(transport) {
|
|
63
|
+
this.transport = transport;
|
|
64
|
+
}
|
|
65
|
+
transport;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/resources/PaginatedList.ts
|
|
69
|
+
function hydratePaginatedList(raw, hydrate) {
|
|
70
|
+
if (!raw || typeof raw !== "object") {
|
|
71
|
+
return { data: [], totalCount: 0 };
|
|
72
|
+
}
|
|
73
|
+
const obj = raw;
|
|
74
|
+
const data = Array.isArray(obj.data) ? obj.data.map(hydrate) : [];
|
|
75
|
+
const totalCount = typeof obj.total_count === "number" ? obj.total_count : data.length;
|
|
76
|
+
return { data, totalCount };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/resources/ExternalAccounts.ts
|
|
80
|
+
var ExternalAccountsListParams = class extends ListParams {
|
|
81
|
+
constructor(userId, oauthProviderId, limit, offset, orderBy) {
|
|
82
|
+
super(limit, offset, orderBy);
|
|
83
|
+
this.userId = userId;
|
|
84
|
+
this.oauthProviderId = oauthProviderId;
|
|
85
|
+
}
|
|
86
|
+
userId;
|
|
87
|
+
oauthProviderId;
|
|
88
|
+
toQuery() {
|
|
89
|
+
const q = super.toQuery();
|
|
90
|
+
if (this.userId) q.user_id = this.userId;
|
|
91
|
+
if (this.oauthProviderId) q.oauth_provider_id = this.oauthProviderId;
|
|
92
|
+
return q;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var ExternalAccountsManager = class extends Manager {
|
|
96
|
+
async list(params) {
|
|
97
|
+
const raw = await this.transport.send("GET", "/v1/external-accounts", {
|
|
98
|
+
query: (params ?? new ExternalAccountsListParams()).toQuery()
|
|
99
|
+
});
|
|
100
|
+
return hydratePaginatedList(raw, hydrateExternalAccount);
|
|
101
|
+
}
|
|
102
|
+
async get(externalAccountId) {
|
|
103
|
+
const raw = await this.transport.send("GET", `/v1/external-accounts/${encodeURIComponent(externalAccountId)}`);
|
|
104
|
+
return hydrateExternalAccount(raw);
|
|
105
|
+
}
|
|
106
|
+
async delete(externalAccountId) {
|
|
107
|
+
await this.transport.send("DELETE", `/v1/external-accounts/${encodeURIComponent(externalAccountId)}`);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
function hydrateExternalAccount(raw) {
|
|
111
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
112
|
+
const scopes = Array.isArray(obj.scopes) ? obj.scopes.filter((s) => typeof s === "string") : [];
|
|
113
|
+
const meta2 = obj.public_metadata && typeof obj.public_metadata === "object" ? obj.public_metadata : {};
|
|
114
|
+
return {
|
|
115
|
+
id: String(obj.id ?? ""),
|
|
116
|
+
object: "external_account",
|
|
117
|
+
provider: String(obj.provider ?? ""),
|
|
118
|
+
providerKey: String(obj.provider_key ?? ""),
|
|
119
|
+
providerUserId: String(obj.provider_user_id ?? ""),
|
|
120
|
+
emailAddress: obj.email_address ?? null,
|
|
121
|
+
scopes,
|
|
122
|
+
publicMetadata: meta2,
|
|
123
|
+
verified: Boolean(obj.verified),
|
|
124
|
+
linkedAt: obj.linked_at ?? null,
|
|
125
|
+
lastSignedInAt: obj.last_signed_in_at ?? null,
|
|
126
|
+
raw: obj
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/resources/Instance.ts
|
|
131
|
+
var InstanceManager = class extends Manager {
|
|
132
|
+
async get() {
|
|
133
|
+
const raw = await this.transport.send("GET", "/v1/instance");
|
|
134
|
+
return hydrateInstance(raw);
|
|
135
|
+
}
|
|
136
|
+
async update(patch) {
|
|
137
|
+
const raw = await this.transport.send("PATCH", "/v1/instance", { body: patch });
|
|
138
|
+
return hydrateInstance(raw);
|
|
139
|
+
}
|
|
140
|
+
async updateRestrictions(patch) {
|
|
141
|
+
const raw = await this.transport.send("PATCH", "/v1/instance/restrictions", { body: patch });
|
|
142
|
+
return hydrateInstance(raw);
|
|
143
|
+
}
|
|
144
|
+
async updateOrganizationSettings(patch) {
|
|
145
|
+
const raw = await this.transport.send("PATCH", "/v1/instance/organization-settings", { body: patch });
|
|
146
|
+
return hydrateInstance(raw);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
function hydrateInstance(raw) {
|
|
150
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
151
|
+
const meta2 = (key) => obj[key] && typeof obj[key] === "object" ? obj[key] : {};
|
|
152
|
+
return {
|
|
153
|
+
id: String(obj.id ?? ""),
|
|
154
|
+
object: "instance",
|
|
155
|
+
attributes: meta2("attributes"),
|
|
156
|
+
multiFactor: meta2("multi_factor"),
|
|
157
|
+
signUpMode: typeof obj.sign_up_mode === "string" ? obj.sign_up_mode : void 0,
|
|
158
|
+
raw: obj
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function idempotencyKeyFor(payload) {
|
|
162
|
+
try {
|
|
163
|
+
const json = JSON.stringify(payload ?? {});
|
|
164
|
+
return createHash("sha256").update(json).digest("hex").slice(0, 32);
|
|
165
|
+
} catch {
|
|
166
|
+
return randomUUID();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/resources/Invitations.ts
|
|
171
|
+
var InvitationsListParams = class extends ListParams {
|
|
172
|
+
constructor(status, emailAddress, limit, offset, orderBy) {
|
|
173
|
+
super(limit, offset, orderBy);
|
|
174
|
+
this.status = status;
|
|
175
|
+
this.emailAddress = emailAddress;
|
|
176
|
+
}
|
|
177
|
+
status;
|
|
178
|
+
emailAddress;
|
|
179
|
+
toQuery() {
|
|
180
|
+
const q = super.toQuery();
|
|
181
|
+
if (this.status?.length) q.status = this.status;
|
|
182
|
+
if (this.emailAddress) q.email_address = this.emailAddress;
|
|
183
|
+
return q;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
var InvitationsManager = class extends Manager {
|
|
187
|
+
async list(params) {
|
|
188
|
+
const raw = await this.transport.send("GET", "/v1/invitations", {
|
|
189
|
+
query: (params ?? new InvitationsListParams()).toQuery()
|
|
190
|
+
});
|
|
191
|
+
return hydratePaginatedList(raw, hydrateInvitation);
|
|
192
|
+
}
|
|
193
|
+
async create(data, idempotencyKey) {
|
|
194
|
+
const raw = await this.transport.send("POST", "/v1/invitations", {
|
|
195
|
+
body: data,
|
|
196
|
+
idempotencyKey: idempotencyKey ?? idempotencyKeyFor(data)
|
|
197
|
+
});
|
|
198
|
+
return hydrateInvitation(raw);
|
|
199
|
+
}
|
|
200
|
+
async bulkCreate(invitations, idempotencyKey) {
|
|
201
|
+
const raw = await this.transport.send("POST", "/v1/invitations/bulk", {
|
|
202
|
+
body: { invitations },
|
|
203
|
+
idempotencyKey: idempotencyKey ?? idempotencyKeyFor(invitations)
|
|
204
|
+
});
|
|
205
|
+
return (raw?.data ?? []).map(hydrateInvitation);
|
|
206
|
+
}
|
|
207
|
+
async revoke(invitationId) {
|
|
208
|
+
const raw = await this.transport.send("POST", `/v1/invitations/${encodeURIComponent(invitationId)}/revoke`);
|
|
209
|
+
return hydrateInvitation(raw);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function hydrateInvitation(raw) {
|
|
213
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
214
|
+
const meta2 = obj.public_metadata && typeof obj.public_metadata === "object" ? obj.public_metadata : {};
|
|
215
|
+
return {
|
|
216
|
+
id: String(obj.id ?? ""),
|
|
217
|
+
object: "invitation",
|
|
218
|
+
emailAddress: String(obj.email_address ?? ""),
|
|
219
|
+
status: String(obj.status ?? ""),
|
|
220
|
+
redirectUrl: obj.redirect_url ?? null,
|
|
221
|
+
publicMetadata: meta2,
|
|
222
|
+
expiresAt: obj.expires_at ?? null,
|
|
223
|
+
url: obj.url ?? null,
|
|
224
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
225
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
226
|
+
raw: obj
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/resources/Lists.ts
|
|
231
|
+
var AllowlistIdentifiersManager = class extends Manager {
|
|
232
|
+
async list(params) {
|
|
233
|
+
const raw = await this.transport.send("GET", "/v1/allowlist-identifiers", {
|
|
234
|
+
query: (params ?? new ListParams()).toQuery()
|
|
235
|
+
});
|
|
236
|
+
return hydratePaginatedList(raw, hydrateAllowlistIdentifier);
|
|
237
|
+
}
|
|
238
|
+
async create(data) {
|
|
239
|
+
const raw = await this.transport.send("POST", "/v1/allowlist-identifiers", { body: data });
|
|
240
|
+
return hydrateAllowlistIdentifier(raw);
|
|
241
|
+
}
|
|
242
|
+
async delete(id) {
|
|
243
|
+
await this.transport.send("DELETE", `/v1/allowlist-identifiers/${encodeURIComponent(id)}`);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
var BlocklistIdentifiersManager = class extends Manager {
|
|
247
|
+
async list(params) {
|
|
248
|
+
const raw = await this.transport.send("GET", "/v1/blocklist-identifiers", {
|
|
249
|
+
query: (params ?? new ListParams()).toQuery()
|
|
250
|
+
});
|
|
251
|
+
return hydratePaginatedList(raw, hydrateBlocklistIdentifier);
|
|
252
|
+
}
|
|
253
|
+
async create(data) {
|
|
254
|
+
const raw = await this.transport.send("POST", "/v1/blocklist-identifiers", { body: data });
|
|
255
|
+
return hydrateBlocklistIdentifier(raw);
|
|
256
|
+
}
|
|
257
|
+
async delete(id) {
|
|
258
|
+
await this.transport.send("DELETE", `/v1/blocklist-identifiers/${encodeURIComponent(id)}`);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
function hydrateIdentifier(raw, object) {
|
|
262
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
263
|
+
return {
|
|
264
|
+
id: String(obj.id ?? ""),
|
|
265
|
+
object,
|
|
266
|
+
identifier: String(obj.identifier ?? ""),
|
|
267
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
268
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
269
|
+
raw: obj
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function hydrateAllowlistIdentifier(raw) {
|
|
273
|
+
return hydrateIdentifier(raw, "allowlist_identifier");
|
|
274
|
+
}
|
|
275
|
+
function hydrateBlocklistIdentifier(raw) {
|
|
276
|
+
return hydrateIdentifier(raw, "blocklist_identifier");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/resources/OauthProviders.ts
|
|
280
|
+
var OauthProvidersManager = class extends Manager {
|
|
281
|
+
async list(params) {
|
|
282
|
+
const raw = await this.transport.send("GET", "/v1/oauth-providers", {
|
|
283
|
+
query: (params ?? new ListParams()).toQuery()
|
|
284
|
+
});
|
|
285
|
+
return hydratePaginatedList(raw, hydrateOauthProvider);
|
|
286
|
+
}
|
|
287
|
+
async create(data, idempotencyKey) {
|
|
288
|
+
const raw = await this.transport.send("POST", "/v1/oauth-providers", {
|
|
289
|
+
body: data,
|
|
290
|
+
idempotencyKey: idempotencyKey ?? idempotencyKeyFor(data)
|
|
291
|
+
});
|
|
292
|
+
return hydrateOauthProvider(raw);
|
|
293
|
+
}
|
|
294
|
+
async get(oauthProviderId) {
|
|
295
|
+
const raw = await this.transport.send("GET", `/v1/oauth-providers/${encodeURIComponent(oauthProviderId)}`);
|
|
296
|
+
return hydrateOauthProvider(raw);
|
|
297
|
+
}
|
|
298
|
+
async update(oauthProviderId, data, idempotencyKey) {
|
|
299
|
+
const raw = await this.transport.send("PATCH", `/v1/oauth-providers/${encodeURIComponent(oauthProviderId)}`, {
|
|
300
|
+
body: data,
|
|
301
|
+
idempotencyKey
|
|
302
|
+
});
|
|
303
|
+
return hydrateOauthProvider(raw);
|
|
304
|
+
}
|
|
305
|
+
async delete(oauthProviderId) {
|
|
306
|
+
await this.transport.send("DELETE", `/v1/oauth-providers/${encodeURIComponent(oauthProviderId)}`);
|
|
307
|
+
}
|
|
308
|
+
async test(oauthProviderId) {
|
|
309
|
+
const raw = await this.transport.send(
|
|
310
|
+
"POST",
|
|
311
|
+
`/v1/oauth-providers/${encodeURIComponent(oauthProviderId)}/test`
|
|
312
|
+
);
|
|
313
|
+
const errs = Array.isArray(raw?.errors) ? raw.errors.map((e) => {
|
|
314
|
+
const o = e && typeof e === "object" ? e : {};
|
|
315
|
+
return { code: String(o.code ?? "unknown"), message: String(o.message ?? o.long_message ?? "") };
|
|
316
|
+
}) : [];
|
|
317
|
+
return {
|
|
318
|
+
authorizeUrl: String(raw?.authorize_url ?? ""),
|
|
319
|
+
userinfoStatus: raw?.userinfo_status ?? null,
|
|
320
|
+
errors: errs
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
function hydrateOauthProvider(raw) {
|
|
325
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
326
|
+
const scopes = Array.isArray(obj.scopes) ? obj.scopes.filter((s) => typeof s === "string") : [];
|
|
327
|
+
const algs = Array.isArray(obj.id_token_signing_algs) ? obj.id_token_signing_algs.filter((s) => typeof s === "string") : [];
|
|
328
|
+
const mapping = {};
|
|
329
|
+
if (obj.attribute_mapping && typeof obj.attribute_mapping === "object") {
|
|
330
|
+
for (const [k, v] of Object.entries(obj.attribute_mapping)) {
|
|
331
|
+
if (typeof v === "string") mapping[k] = v;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const authParams = obj.additional_authorization_params && typeof obj.additional_authorization_params === "object" ? obj.additional_authorization_params : {};
|
|
335
|
+
return {
|
|
336
|
+
id: String(obj.id ?? ""),
|
|
337
|
+
object: "oauth_provider",
|
|
338
|
+
providerKind: obj.provider_kind ?? "preset",
|
|
339
|
+
providerKey: String(obj.provider_key ?? ""),
|
|
340
|
+
name: String(obj.name ?? ""),
|
|
341
|
+
enabled: Boolean(obj.enabled),
|
|
342
|
+
allowSignIn: Boolean(obj.allow_sign_in),
|
|
343
|
+
allowSignUp: Boolean(obj.allow_sign_up),
|
|
344
|
+
blockEmailSubaddresses: Boolean(obj.block_email_subaddresses),
|
|
345
|
+
clientId: String(obj.client_id ?? ""),
|
|
346
|
+
scopes,
|
|
347
|
+
additionalAuthorizationParams: authParams,
|
|
348
|
+
attributeMapping: mapping,
|
|
349
|
+
redirectUri: String(obj.redirect_uri ?? ""),
|
|
350
|
+
issuer: obj.issuer ?? null,
|
|
351
|
+
discoveryEndpoint: obj.discovery_endpoint ?? null,
|
|
352
|
+
authorizationEndpoint: obj.authorization_endpoint ?? null,
|
|
353
|
+
tokenEndpoint: obj.token_endpoint ?? null,
|
|
354
|
+
userinfoEndpoint: obj.userinfo_endpoint ?? null,
|
|
355
|
+
jwksUri: obj.jwks_uri ?? null,
|
|
356
|
+
idTokenSigningAlgs: algs,
|
|
357
|
+
userinfoMethod: obj.userinfo_method ?? null,
|
|
358
|
+
userinfoAuth: obj.userinfo_auth ?? null,
|
|
359
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
360
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
361
|
+
raw: obj
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// src/resources/Organizations.ts
|
|
366
|
+
var OrganizationsManager = class extends Manager {
|
|
367
|
+
async list(params) {
|
|
368
|
+
const raw = await this.transport.send("GET", "/v1/organizations", {
|
|
369
|
+
query: (params ?? new ListParams()).toQuery()
|
|
370
|
+
});
|
|
371
|
+
return hydratePaginatedList(raw, hydrateOrganization);
|
|
372
|
+
}
|
|
373
|
+
async create(data, idempotencyKey) {
|
|
374
|
+
const raw = await this.transport.send("POST", "/v1/organizations", {
|
|
375
|
+
body: data,
|
|
376
|
+
idempotencyKey: idempotencyKey ?? idempotencyKeyFor(data)
|
|
377
|
+
});
|
|
378
|
+
return hydrateOrganization(raw);
|
|
379
|
+
}
|
|
380
|
+
async get(orgId) {
|
|
381
|
+
const raw = await this.transport.send("GET", `/v1/organizations/${encodeURIComponent(orgId)}`);
|
|
382
|
+
return hydrateOrganization(raw);
|
|
383
|
+
}
|
|
384
|
+
async update(orgId, data, idempotencyKey) {
|
|
385
|
+
const raw = await this.transport.send("PATCH", `/v1/organizations/${encodeURIComponent(orgId)}`, {
|
|
386
|
+
body: data,
|
|
387
|
+
idempotencyKey
|
|
388
|
+
});
|
|
389
|
+
return hydrateOrganization(raw);
|
|
390
|
+
}
|
|
391
|
+
async delete(orgId) {
|
|
392
|
+
await this.transport.send("DELETE", `/v1/organizations/${encodeURIComponent(orgId)}`);
|
|
393
|
+
}
|
|
394
|
+
members(orgId) {
|
|
395
|
+
return new OrganizationMembershipsManager(this.transport, orgId);
|
|
396
|
+
}
|
|
397
|
+
invitations(orgId) {
|
|
398
|
+
return new OrganizationInvitationsManager(this.transport, orgId);
|
|
399
|
+
}
|
|
400
|
+
domains(orgId) {
|
|
401
|
+
return new OrganizationDomainsManager(this.transport, orgId);
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
var OrganizationMembershipsManager = class {
|
|
405
|
+
constructor(transport, orgId) {
|
|
406
|
+
this.transport = transport;
|
|
407
|
+
this.orgId = orgId;
|
|
408
|
+
}
|
|
409
|
+
transport;
|
|
410
|
+
orgId;
|
|
411
|
+
async list(params) {
|
|
412
|
+
const raw = await this.transport.send(
|
|
413
|
+
"GET",
|
|
414
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/memberships`,
|
|
415
|
+
{ query: (params ?? new ListParams()).toQuery() }
|
|
416
|
+
);
|
|
417
|
+
return hydratePaginatedList(raw, hydrateOrganizationMembership);
|
|
418
|
+
}
|
|
419
|
+
async create(data, idempotencyKey) {
|
|
420
|
+
const raw = await this.transport.send(
|
|
421
|
+
"POST",
|
|
422
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/memberships`,
|
|
423
|
+
{ body: { user_id: data.userId, role: data.role }, idempotencyKey: idempotencyKey ?? idempotencyKeyFor(data) }
|
|
424
|
+
);
|
|
425
|
+
return hydrateOrganizationMembership(raw);
|
|
426
|
+
}
|
|
427
|
+
async update(userId, role, idempotencyKey) {
|
|
428
|
+
const raw = await this.transport.send(
|
|
429
|
+
"PATCH",
|
|
430
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/memberships/${encodeURIComponent(userId)}`,
|
|
431
|
+
{ body: { role }, idempotencyKey }
|
|
432
|
+
);
|
|
433
|
+
return hydrateOrganizationMembership(raw);
|
|
434
|
+
}
|
|
435
|
+
async delete(userId) {
|
|
436
|
+
await this.transport.send(
|
|
437
|
+
"DELETE",
|
|
438
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/memberships/${encodeURIComponent(userId)}`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
var OrganizationInvitationsManager = class {
|
|
443
|
+
constructor(transport, orgId) {
|
|
444
|
+
this.transport = transport;
|
|
445
|
+
this.orgId = orgId;
|
|
446
|
+
}
|
|
447
|
+
transport;
|
|
448
|
+
orgId;
|
|
449
|
+
async list(params) {
|
|
450
|
+
const raw = await this.transport.send(
|
|
451
|
+
"GET",
|
|
452
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/invitations`,
|
|
453
|
+
{ query: (params ?? new ListParams()).toQuery() }
|
|
454
|
+
);
|
|
455
|
+
return hydratePaginatedList(raw, hydrateOrganizationInvitation);
|
|
456
|
+
}
|
|
457
|
+
async create(data, idempotencyKey) {
|
|
458
|
+
const raw = await this.transport.send(
|
|
459
|
+
"POST",
|
|
460
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/invitations`,
|
|
461
|
+
{ body: data, idempotencyKey: idempotencyKey ?? idempotencyKeyFor(data) }
|
|
462
|
+
);
|
|
463
|
+
return hydrateOrganizationInvitation(raw);
|
|
464
|
+
}
|
|
465
|
+
async bulkCreate(invitations, idempotencyKey) {
|
|
466
|
+
const raw = await this.transport.send(
|
|
467
|
+
"POST",
|
|
468
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/invitations/bulk`,
|
|
469
|
+
{ body: { invitations }, idempotencyKey: idempotencyKey ?? idempotencyKeyFor(invitations) }
|
|
470
|
+
);
|
|
471
|
+
return (raw?.data ?? []).map(hydrateOrganizationInvitation);
|
|
472
|
+
}
|
|
473
|
+
async revoke(invitationId) {
|
|
474
|
+
const raw = await this.transport.send(
|
|
475
|
+
"POST",
|
|
476
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/invitations/${encodeURIComponent(invitationId)}/revoke`
|
|
477
|
+
);
|
|
478
|
+
return hydrateOrganizationInvitation(raw);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
var OrganizationDomainsManager = class {
|
|
482
|
+
constructor(transport, orgId) {
|
|
483
|
+
this.transport = transport;
|
|
484
|
+
this.orgId = orgId;
|
|
485
|
+
}
|
|
486
|
+
transport;
|
|
487
|
+
orgId;
|
|
488
|
+
async list() {
|
|
489
|
+
const raw = await this.transport.send(
|
|
490
|
+
"GET",
|
|
491
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/domains`
|
|
492
|
+
);
|
|
493
|
+
return hydratePaginatedList(raw, hydrateOrganizationDomain);
|
|
494
|
+
}
|
|
495
|
+
async create(name, enrollmentMode = "manual_invitation") {
|
|
496
|
+
const raw = await this.transport.send(
|
|
497
|
+
"POST",
|
|
498
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/domains`,
|
|
499
|
+
{ body: { name, enrollment_mode: enrollmentMode } }
|
|
500
|
+
);
|
|
501
|
+
return hydrateOrganizationDomain(raw);
|
|
502
|
+
}
|
|
503
|
+
async get(domainId) {
|
|
504
|
+
const raw = await this.transport.send(
|
|
505
|
+
"GET",
|
|
506
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/domains/${encodeURIComponent(domainId)}`
|
|
507
|
+
);
|
|
508
|
+
return hydrateOrganizationDomain(raw);
|
|
509
|
+
}
|
|
510
|
+
async update(domainId, patch) {
|
|
511
|
+
const raw = await this.transport.send(
|
|
512
|
+
"PATCH",
|
|
513
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/domains/${encodeURIComponent(domainId)}`,
|
|
514
|
+
{ body: patch }
|
|
515
|
+
);
|
|
516
|
+
return hydrateOrganizationDomain(raw);
|
|
517
|
+
}
|
|
518
|
+
async delete(domainId) {
|
|
519
|
+
await this.transport.send(
|
|
520
|
+
"DELETE",
|
|
521
|
+
`/v1/organizations/${encodeURIComponent(this.orgId)}/domains/${encodeURIComponent(domainId)}`
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
function meta(obj, key) {
|
|
526
|
+
return obj[key] && typeof obj[key] === "object" ? obj[key] : {};
|
|
527
|
+
}
|
|
528
|
+
function hydrateOrganization(raw) {
|
|
529
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
530
|
+
return {
|
|
531
|
+
id: String(obj.id ?? ""),
|
|
532
|
+
object: "organization",
|
|
533
|
+
name: String(obj.name ?? ""),
|
|
534
|
+
slug: obj.slug ?? null,
|
|
535
|
+
imageUrl: obj.image_url ?? null,
|
|
536
|
+
membersCount: typeof obj.members_count === "number" ? obj.members_count : 0,
|
|
537
|
+
pendingInvitationsCount: typeof obj.pending_invitations_count === "number" ? obj.pending_invitations_count : 0,
|
|
538
|
+
maxAllowedMemberships: obj.max_allowed_memberships ?? null,
|
|
539
|
+
adminDeleteEnabled: Boolean(obj.admin_delete_enabled),
|
|
540
|
+
publicMetadata: meta(obj, "public_metadata"),
|
|
541
|
+
privateMetadata: meta(obj, "private_metadata"),
|
|
542
|
+
createdBy: obj.created_by ?? null,
|
|
543
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
544
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
545
|
+
raw: obj
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
function hydrateOrganizationMembership(raw) {
|
|
549
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
550
|
+
const perms = Array.isArray(obj.permissions) ? obj.permissions.filter((p) => typeof p === "string") : [];
|
|
551
|
+
return {
|
|
552
|
+
id: String(obj.id ?? ""),
|
|
553
|
+
object: "organization_membership",
|
|
554
|
+
organizationId: String(obj.organization_id ?? ""),
|
|
555
|
+
userId: String(obj.user_id ?? ""),
|
|
556
|
+
role: String(obj.role ?? ""),
|
|
557
|
+
permissions: perms,
|
|
558
|
+
publicMetadata: meta(obj, "public_metadata"),
|
|
559
|
+
privateMetadata: meta(obj, "private_metadata"),
|
|
560
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
561
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
562
|
+
raw: obj
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
function hydrateOrganizationInvitation(raw) {
|
|
566
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
567
|
+
return {
|
|
568
|
+
id: String(obj.id ?? ""),
|
|
569
|
+
object: "organization_invitation",
|
|
570
|
+
organizationId: String(obj.organization_id ?? ""),
|
|
571
|
+
emailAddress: String(obj.email_address ?? ""),
|
|
572
|
+
role: String(obj.role ?? ""),
|
|
573
|
+
status: String(obj.status ?? ""),
|
|
574
|
+
inviterUserId: obj.inviter_user_id ?? null,
|
|
575
|
+
redirectUrl: obj.redirect_url ?? null,
|
|
576
|
+
publicMetadata: meta(obj, "public_metadata"),
|
|
577
|
+
expiresAt: obj.expires_at ?? null,
|
|
578
|
+
url: obj.url ?? null,
|
|
579
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
580
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
581
|
+
raw: obj
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
function hydrateOrganizationDomain(raw) {
|
|
585
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
586
|
+
return {
|
|
587
|
+
id: String(obj.id ?? ""),
|
|
588
|
+
object: "organization_domain",
|
|
589
|
+
organizationId: String(obj.organization_id ?? ""),
|
|
590
|
+
name: String(obj.name ?? ""),
|
|
591
|
+
verified: Boolean(obj.verified),
|
|
592
|
+
enrollmentMode: String(obj.enrollment_mode ?? "manual_invitation"),
|
|
593
|
+
currentChallengeId: obj.current_challenge_id ?? null,
|
|
594
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
595
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
596
|
+
raw: obj
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/resources/PhoneNumbers.ts
|
|
601
|
+
var PhoneNumbersListParams = class extends ListParams {
|
|
602
|
+
constructor(userId, limit, offset, orderBy) {
|
|
603
|
+
super(limit, offset, orderBy);
|
|
604
|
+
this.userId = userId;
|
|
605
|
+
}
|
|
606
|
+
userId;
|
|
607
|
+
toQuery() {
|
|
608
|
+
const q = super.toQuery();
|
|
609
|
+
if (this.userId) q.user_id = this.userId;
|
|
610
|
+
return q;
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
var PhoneNumbersManager = class extends Manager {
|
|
614
|
+
async list(params) {
|
|
615
|
+
const raw = await this.transport.send("GET", "/v1/phone-numbers", {
|
|
616
|
+
query: (params ?? new PhoneNumbersListParams()).toQuery()
|
|
617
|
+
});
|
|
618
|
+
return hydratePaginatedList(raw, hydratePhoneNumber);
|
|
619
|
+
}
|
|
620
|
+
async create(data, idempotencyKey) {
|
|
621
|
+
const raw = await this.transport.send("POST", "/v1/phone-numbers", {
|
|
622
|
+
body: data,
|
|
623
|
+
idempotencyKey: idempotencyKey ?? idempotencyKeyFor(data)
|
|
624
|
+
});
|
|
625
|
+
return hydratePhoneNumber(raw);
|
|
626
|
+
}
|
|
627
|
+
async get(phoneNumberId) {
|
|
628
|
+
const raw = await this.transport.send("GET", `/v1/phone-numbers/${encodeURIComponent(phoneNumberId)}`);
|
|
629
|
+
return hydratePhoneNumber(raw);
|
|
630
|
+
}
|
|
631
|
+
async update(phoneNumberId, data, idempotencyKey) {
|
|
632
|
+
const raw = await this.transport.send("PATCH", `/v1/phone-numbers/${encodeURIComponent(phoneNumberId)}`, {
|
|
633
|
+
body: data,
|
|
634
|
+
idempotencyKey
|
|
635
|
+
});
|
|
636
|
+
return hydratePhoneNumber(raw);
|
|
637
|
+
}
|
|
638
|
+
async delete(phoneNumberId) {
|
|
639
|
+
await this.transport.send("DELETE", `/v1/phone-numbers/${encodeURIComponent(phoneNumberId)}`);
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
function hydratePhoneNumber(raw) {
|
|
643
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
644
|
+
return {
|
|
645
|
+
id: String(obj.id ?? ""),
|
|
646
|
+
object: "phone_number",
|
|
647
|
+
phoneNumber: String(obj.phone_number ?? ""),
|
|
648
|
+
verified: Boolean(obj.verified),
|
|
649
|
+
currentChallengeId: obj.current_challenge_id ?? null,
|
|
650
|
+
isPrimary: Boolean(obj.is_primary),
|
|
651
|
+
reservedForSecondFactor: Boolean(obj.reserved_for_second_factor),
|
|
652
|
+
defaultSecondFactor: Boolean(obj.default_second_factor),
|
|
653
|
+
linkedToExternalAccountId: obj.linked_to_external_account_id ?? null,
|
|
654
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
655
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
656
|
+
raw: obj
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/resources/RedirectUrls.ts
|
|
661
|
+
var RedirectUrlsManager = class extends Manager {
|
|
662
|
+
async list(params) {
|
|
663
|
+
const raw = await this.transport.send("GET", "/v1/redirect-urls", {
|
|
664
|
+
query: (params ?? new ListParams()).toQuery()
|
|
665
|
+
});
|
|
666
|
+
return hydratePaginatedList(raw, hydrateRedirectUrl);
|
|
667
|
+
}
|
|
668
|
+
async create(url) {
|
|
669
|
+
const raw = await this.transport.send("POST", "/v1/redirect-urls", { body: { url } });
|
|
670
|
+
return hydrateRedirectUrl(raw);
|
|
671
|
+
}
|
|
672
|
+
async get(id) {
|
|
673
|
+
const raw = await this.transport.send("GET", `/v1/redirect-urls/${encodeURIComponent(id)}`);
|
|
674
|
+
return hydrateRedirectUrl(raw);
|
|
675
|
+
}
|
|
676
|
+
async delete(id) {
|
|
677
|
+
await this.transport.send("DELETE", `/v1/redirect-urls/${encodeURIComponent(id)}`);
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
function hydrateRedirectUrl(raw) {
|
|
681
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
682
|
+
return {
|
|
683
|
+
id: String(obj.id ?? ""),
|
|
684
|
+
object: "redirect_url",
|
|
685
|
+
url: String(obj.url ?? ""),
|
|
686
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
687
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
688
|
+
raw: obj
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// src/resources/Roles.ts
|
|
693
|
+
var RolesManager = class extends Manager {
|
|
694
|
+
async list(params) {
|
|
695
|
+
const raw = await this.transport.send("GET", "/v1/roles", {
|
|
696
|
+
query: (params ?? new ListParams()).toQuery()
|
|
697
|
+
});
|
|
698
|
+
return hydratePaginatedList(raw, hydrateRole);
|
|
699
|
+
}
|
|
700
|
+
async create(data, idempotencyKey) {
|
|
701
|
+
const raw = await this.transport.send("POST", "/v1/roles", {
|
|
702
|
+
body: data,
|
|
703
|
+
idempotencyKey: idempotencyKey ?? idempotencyKeyFor(data)
|
|
704
|
+
});
|
|
705
|
+
return hydrateRole(raw);
|
|
706
|
+
}
|
|
707
|
+
async get(roleId) {
|
|
708
|
+
const raw = await this.transport.send("GET", `/v1/roles/${encodeURIComponent(roleId)}`);
|
|
709
|
+
return hydrateRole(raw);
|
|
710
|
+
}
|
|
711
|
+
async update(roleId, data, idempotencyKey) {
|
|
712
|
+
const raw = await this.transport.send("PATCH", `/v1/roles/${encodeURIComponent(roleId)}`, {
|
|
713
|
+
body: data,
|
|
714
|
+
idempotencyKey
|
|
715
|
+
});
|
|
716
|
+
return hydrateRole(raw);
|
|
717
|
+
}
|
|
718
|
+
async delete(roleId) {
|
|
719
|
+
await this.transport.send("DELETE", `/v1/roles/${encodeURIComponent(roleId)}`);
|
|
720
|
+
}
|
|
721
|
+
async setPermissions(roleId, permissionKeys) {
|
|
722
|
+
const raw = await this.transport.send("PUT", `/v1/roles/${encodeURIComponent(roleId)}/permissions`, {
|
|
723
|
+
body: { permissions: permissionKeys }
|
|
724
|
+
});
|
|
725
|
+
return hydrateRole(raw);
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
var PermissionsManager = class extends Manager {
|
|
729
|
+
async list(params) {
|
|
730
|
+
const raw = await this.transport.send("GET", "/v1/permissions", {
|
|
731
|
+
query: (params ?? new ListParams()).toQuery()
|
|
732
|
+
});
|
|
733
|
+
return hydratePaginatedList(raw, hydratePermission);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
function hydrateRole(raw) {
|
|
737
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
738
|
+
const perms = Array.isArray(obj.permissions) ? obj.permissions.filter((p) => typeof p === "string") : [];
|
|
739
|
+
return {
|
|
740
|
+
id: String(obj.id ?? ""),
|
|
741
|
+
object: "role",
|
|
742
|
+
key: String(obj.key ?? ""),
|
|
743
|
+
name: String(obj.name ?? ""),
|
|
744
|
+
description: obj.description ?? null,
|
|
745
|
+
isCreatorEligible: Boolean(obj.is_creator_eligible),
|
|
746
|
+
isDefault: Boolean(obj.is_default),
|
|
747
|
+
permissions: perms,
|
|
748
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
749
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
750
|
+
raw: obj
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
function hydratePermission(raw) {
|
|
754
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
755
|
+
return {
|
|
756
|
+
id: String(obj.id ?? ""),
|
|
757
|
+
object: "permission",
|
|
758
|
+
key: String(obj.key ?? ""),
|
|
759
|
+
name: String(obj.name ?? ""),
|
|
760
|
+
description: obj.description ?? null,
|
|
761
|
+
isSystem: Boolean(obj.is_system),
|
|
762
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
763
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
764
|
+
raw: obj
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// src/resources/Sessions.ts
|
|
769
|
+
var SessionsListParams = class extends ListParams {
|
|
770
|
+
constructor(userId, clientId, status, limit, offset, orderBy) {
|
|
771
|
+
super(limit, offset, orderBy);
|
|
772
|
+
this.userId = userId;
|
|
773
|
+
this.clientId = clientId;
|
|
774
|
+
this.status = status;
|
|
775
|
+
}
|
|
776
|
+
userId;
|
|
777
|
+
clientId;
|
|
778
|
+
status;
|
|
779
|
+
toQuery() {
|
|
780
|
+
const q = super.toQuery();
|
|
781
|
+
if (this.userId) q.user_id = this.userId;
|
|
782
|
+
if (this.clientId) q.client_id = this.clientId;
|
|
783
|
+
if (this.status?.length) q.status = this.status;
|
|
784
|
+
return q;
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
var SessionsManager = class extends Manager {
|
|
788
|
+
async list(params) {
|
|
789
|
+
const raw = await this.transport.send("GET", "/v1/sessions", {
|
|
790
|
+
query: (params ?? new SessionsListParams()).toQuery()
|
|
791
|
+
});
|
|
792
|
+
return hydratePaginatedList(raw, hydrateSession);
|
|
793
|
+
}
|
|
794
|
+
async get(sessionId) {
|
|
795
|
+
const raw = await this.transport.send("GET", `/v1/sessions/${encodeURIComponent(sessionId)}`);
|
|
796
|
+
return hydrateSession(raw);
|
|
797
|
+
}
|
|
798
|
+
async revoke(sessionId) {
|
|
799
|
+
const raw = await this.transport.send("POST", `/v1/sessions/${encodeURIComponent(sessionId)}/revoke`);
|
|
800
|
+
return hydrateSession(raw);
|
|
801
|
+
}
|
|
802
|
+
async getToken(sessionId, template) {
|
|
803
|
+
const path = template ? `/v1/sessions/${encodeURIComponent(sessionId)}/tokens/${encodeURIComponent(template)}` : `/v1/sessions/${encodeURIComponent(sessionId)}/tokens`;
|
|
804
|
+
const raw = await this.transport.send("POST", path);
|
|
805
|
+
return raw?.jwt ?? "";
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
function hydrateSession(raw) {
|
|
809
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
810
|
+
return {
|
|
811
|
+
id: String(obj.id ?? ""),
|
|
812
|
+
object: "session",
|
|
813
|
+
clientId: String(obj.client_id ?? ""),
|
|
814
|
+
userId: String(obj.user_id ?? ""),
|
|
815
|
+
status: String(obj.status ?? ""),
|
|
816
|
+
lastActiveAt: obj.last_active_at ?? null,
|
|
817
|
+
expireAt: obj.expire_at ?? null,
|
|
818
|
+
abandonAt: obj.abandon_at ?? null,
|
|
819
|
+
lastActiveOrganizationId: obj.last_active_organization_id ?? null,
|
|
820
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
821
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
822
|
+
raw: obj
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// src/resources/SmsTemplates.ts
|
|
827
|
+
var SmsTemplatesManager = class extends Manager {
|
|
828
|
+
async list() {
|
|
829
|
+
const raw = await this.transport.send("GET", "/v1/sms-templates");
|
|
830
|
+
if (!Array.isArray(raw)) return [];
|
|
831
|
+
return raw.map(hydrateSmsTemplate);
|
|
832
|
+
}
|
|
833
|
+
async get(slug) {
|
|
834
|
+
const raw = await this.transport.send("GET", `/v1/sms-templates/${encodeURIComponent(slug)}`);
|
|
835
|
+
return hydrateSmsTemplate(raw);
|
|
836
|
+
}
|
|
837
|
+
async update(slug, data, idempotencyKey) {
|
|
838
|
+
const raw = await this.transport.send("PATCH", `/v1/sms-templates/${encodeURIComponent(slug)}`, {
|
|
839
|
+
body: data,
|
|
840
|
+
idempotencyKey
|
|
841
|
+
});
|
|
842
|
+
return hydrateSmsTemplate(raw);
|
|
843
|
+
}
|
|
844
|
+
async revert(slug, idempotencyKey) {
|
|
845
|
+
const raw = await this.transport.send("POST", `/v1/sms-templates/${encodeURIComponent(slug)}/revert`, {
|
|
846
|
+
idempotencyKey
|
|
847
|
+
});
|
|
848
|
+
return hydrateSmsTemplate(raw);
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
function hydrateSmsTemplate(raw) {
|
|
852
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
853
|
+
return {
|
|
854
|
+
id: String(obj.id ?? ""),
|
|
855
|
+
object: "sms_template",
|
|
856
|
+
slug: String(obj.slug ?? ""),
|
|
857
|
+
body: String(obj.body ?? ""),
|
|
858
|
+
deliveredByUs: Boolean(obj.delivered_by_us ?? true),
|
|
859
|
+
fromNumberOverride: obj.from_number_override ?? null,
|
|
860
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
861
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
862
|
+
raw: obj
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/resources/Users.ts
|
|
867
|
+
var UsersListParams = class extends ListParams {
|
|
868
|
+
constructor(emailAddress, phoneNumber, username, externalId, query, limit, offset, orderBy) {
|
|
869
|
+
super(limit, offset, orderBy);
|
|
870
|
+
this.emailAddress = emailAddress;
|
|
871
|
+
this.phoneNumber = phoneNumber;
|
|
872
|
+
this.username = username;
|
|
873
|
+
this.externalId = externalId;
|
|
874
|
+
this.query = query;
|
|
875
|
+
}
|
|
876
|
+
emailAddress;
|
|
877
|
+
phoneNumber;
|
|
878
|
+
username;
|
|
879
|
+
externalId;
|
|
880
|
+
query;
|
|
881
|
+
toQuery() {
|
|
882
|
+
const q = super.toQuery();
|
|
883
|
+
if (this.emailAddress?.length) q.email_address = this.emailAddress;
|
|
884
|
+
if (this.phoneNumber?.length) q.phone_number = this.phoneNumber;
|
|
885
|
+
if (this.username?.length) q.username = this.username;
|
|
886
|
+
if (this.externalId?.length) q.external_id = this.externalId;
|
|
887
|
+
if (this.query) q.query = this.query;
|
|
888
|
+
return q;
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
var UsersManager = class extends Manager {
|
|
892
|
+
async list(params) {
|
|
893
|
+
const raw = await this.transport.send("GET", "/v1/users", {
|
|
894
|
+
query: (params ?? new UsersListParams()).toQuery()
|
|
895
|
+
});
|
|
896
|
+
return hydratePaginatedList(raw, hydrateUser);
|
|
897
|
+
}
|
|
898
|
+
async count(params) {
|
|
899
|
+
const raw = await this.transport.send("GET", "/v1/users/count", {
|
|
900
|
+
query: (params ?? new UsersListParams()).toQuery()
|
|
901
|
+
});
|
|
902
|
+
return raw?.total_count ?? 0;
|
|
903
|
+
}
|
|
904
|
+
async create(data, idempotencyKey) {
|
|
905
|
+
const raw = await this.transport.send("POST", "/v1/users", {
|
|
906
|
+
body: data,
|
|
907
|
+
idempotencyKey: idempotencyKey ?? idempotencyKeyFor(data)
|
|
908
|
+
});
|
|
909
|
+
return hydrateUser(raw);
|
|
910
|
+
}
|
|
911
|
+
async get(userId) {
|
|
912
|
+
const raw = await this.transport.send("GET", `/v1/users/${encodeURIComponent(userId)}`);
|
|
913
|
+
return hydrateUser(raw);
|
|
914
|
+
}
|
|
915
|
+
async update(userId, data, idempotencyKey) {
|
|
916
|
+
const raw = await this.transport.send("PATCH", `/v1/users/${encodeURIComponent(userId)}`, {
|
|
917
|
+
body: data,
|
|
918
|
+
idempotencyKey
|
|
919
|
+
});
|
|
920
|
+
return hydrateUser(raw);
|
|
921
|
+
}
|
|
922
|
+
async delete(userId) {
|
|
923
|
+
await this.transport.send("DELETE", `/v1/users/${encodeURIComponent(userId)}`);
|
|
924
|
+
}
|
|
925
|
+
async ban(userId) {
|
|
926
|
+
const raw = await this.transport.send("POST", `/v1/users/${encodeURIComponent(userId)}/ban`);
|
|
927
|
+
return hydrateUser(raw);
|
|
928
|
+
}
|
|
929
|
+
async unban(userId) {
|
|
930
|
+
const raw = await this.transport.send("POST", `/v1/users/${encodeURIComponent(userId)}/unban`);
|
|
931
|
+
return hydrateUser(raw);
|
|
932
|
+
}
|
|
933
|
+
async lock(userId) {
|
|
934
|
+
const raw = await this.transport.send("POST", `/v1/users/${encodeURIComponent(userId)}/lock`);
|
|
935
|
+
return hydrateUser(raw);
|
|
936
|
+
}
|
|
937
|
+
async unlock(userId) {
|
|
938
|
+
const raw = await this.transport.send("POST", `/v1/users/${encodeURIComponent(userId)}/unlock`);
|
|
939
|
+
return hydrateUser(raw);
|
|
940
|
+
}
|
|
941
|
+
async updateMetadata(userId, patch) {
|
|
942
|
+
const raw = await this.transport.send("PATCH", `/v1/users/${encodeURIComponent(userId)}/metadata`, {
|
|
943
|
+
body: patch
|
|
944
|
+
});
|
|
945
|
+
return hydrateUser(raw);
|
|
946
|
+
}
|
|
947
|
+
async verifyPassword(userId, password) {
|
|
948
|
+
const raw = await this.transport.send(
|
|
949
|
+
"POST",
|
|
950
|
+
`/v1/users/${encodeURIComponent(userId)}/verify-password`,
|
|
951
|
+
{ body: { password } }
|
|
952
|
+
);
|
|
953
|
+
return raw?.verified === true;
|
|
954
|
+
}
|
|
955
|
+
async verifyTotp(userId, code) {
|
|
956
|
+
const raw = await this.transport.send(
|
|
957
|
+
"POST",
|
|
958
|
+
`/v1/users/${encodeURIComponent(userId)}/verify-totp`,
|
|
959
|
+
{ body: { code } }
|
|
960
|
+
);
|
|
961
|
+
return { verified: raw?.verified === true, reason: raw?.reason ?? null };
|
|
962
|
+
}
|
|
963
|
+
async disableMfa(userId) {
|
|
964
|
+
const raw = await this.transport.send("DELETE", `/v1/users/${encodeURIComponent(userId)}/mfa`);
|
|
965
|
+
return hydrateUser(raw);
|
|
966
|
+
}
|
|
967
|
+
async uploadProfileImage(userId, bytes, mime) {
|
|
968
|
+
const headers = { "Content-Type": mime };
|
|
969
|
+
const raw = await this.transport.send("POST", `/v1/users/${encodeURIComponent(userId)}/profile-image`, {
|
|
970
|
+
body: bytes,
|
|
971
|
+
headers
|
|
972
|
+
});
|
|
973
|
+
return hydrateUser(raw);
|
|
974
|
+
}
|
|
975
|
+
async deleteProfileImage(userId) {
|
|
976
|
+
await this.transport.send("DELETE", `/v1/users/${encodeURIComponent(userId)}/profile-image`);
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
function hydrateUser(raw) {
|
|
980
|
+
const obj = raw && typeof raw === "object" ? raw : {};
|
|
981
|
+
const arr = (key) => Array.isArray(obj[key]) ? obj[key] : [];
|
|
982
|
+
const meta2 = (key) => obj[key] && typeof obj[key] === "object" ? obj[key] : {};
|
|
983
|
+
return {
|
|
984
|
+
id: String(obj.id ?? ""),
|
|
985
|
+
object: "user",
|
|
986
|
+
externalId: obj.external_id ?? null,
|
|
987
|
+
username: obj.username ?? null,
|
|
988
|
+
firstName: obj.first_name ?? null,
|
|
989
|
+
lastName: obj.last_name ?? null,
|
|
990
|
+
imageUrl: obj.image_url ?? null,
|
|
991
|
+
primaryEmailAddressId: obj.primary_email_address_id ?? null,
|
|
992
|
+
primaryPhoneNumberId: obj.primary_phone_number_id ?? null,
|
|
993
|
+
emailAddresses: arr("email_addresses"),
|
|
994
|
+
phoneNumbers: arr("phone_numbers"),
|
|
995
|
+
externalAccounts: arr("external_accounts"),
|
|
996
|
+
passwordEnabled: Boolean(obj.password_enabled),
|
|
997
|
+
totpEnabled: Boolean(obj.totp_enabled),
|
|
998
|
+
backupCodesEnabled: Boolean(obj.backup_codes_enabled),
|
|
999
|
+
twoFactorEnabled: Boolean(obj.two_factor_enabled),
|
|
1000
|
+
banned: Boolean(obj.banned),
|
|
1001
|
+
locked: Boolean(obj.locked),
|
|
1002
|
+
lastSignInAt: obj.last_sign_in_at ?? null,
|
|
1003
|
+
lastActiveAt: obj.last_active_at ?? null,
|
|
1004
|
+
publicMetadata: meta2("public_metadata"),
|
|
1005
|
+
privateMetadata: meta2("private_metadata"),
|
|
1006
|
+
unsafeMetadata: meta2("unsafe_metadata"),
|
|
1007
|
+
createdAt: typeof obj.created_at === "number" ? obj.created_at : 0,
|
|
1008
|
+
updatedAt: typeof obj.updated_at === "number" ? obj.updated_at : 0,
|
|
1009
|
+
raw: obj
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// src/transport/Transport.ts
|
|
1014
|
+
var Transport = class {
|
|
1015
|
+
apiUrl;
|
|
1016
|
+
secretKey;
|
|
1017
|
+
fetcher;
|
|
1018
|
+
defaultTimeoutMs;
|
|
1019
|
+
userAgent;
|
|
1020
|
+
constructor(opts) {
|
|
1021
|
+
this.apiUrl = opts.apiUrl.replace(/\/$/, "");
|
|
1022
|
+
this.secretKey = opts.secretKey;
|
|
1023
|
+
this.fetcher = opts.fetch ?? globalThis.fetch;
|
|
1024
|
+
this.defaultTimeoutMs = opts.timeoutMs ?? 1e4;
|
|
1025
|
+
const base = `@authn-sh/sdk-node`;
|
|
1026
|
+
this.userAgent = opts.userAgentSuffix ? `${base} ${opts.userAgentSuffix}` : base;
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Send a request and parse the response as JSON. For 204 returns `null`.
|
|
1030
|
+
* Throws AuthnHttpError on non-2xx.
|
|
1031
|
+
*/
|
|
1032
|
+
async send(method, path, opts = {}) {
|
|
1033
|
+
const url = this.buildUrl(path, opts.query);
|
|
1034
|
+
const headers = {
|
|
1035
|
+
Authorization: `Bearer ${this.secretKey}`,
|
|
1036
|
+
Accept: "application/json",
|
|
1037
|
+
"User-Agent": this.userAgent,
|
|
1038
|
+
...opts.headers ?? {}
|
|
1039
|
+
};
|
|
1040
|
+
let body;
|
|
1041
|
+
if (opts.body !== void 0 && opts.body !== null && method !== "GET" && method !== "DELETE") {
|
|
1042
|
+
if (opts.body instanceof Uint8Array) {
|
|
1043
|
+
body = opts.body;
|
|
1044
|
+
} else {
|
|
1045
|
+
headers["Content-Type"] = "application/json";
|
|
1046
|
+
body = JSON.stringify(opts.body);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
if (opts.idempotencyKey) {
|
|
1050
|
+
headers["Idempotency-Key"] = opts.idempotencyKey;
|
|
1051
|
+
}
|
|
1052
|
+
const controller = new AbortController();
|
|
1053
|
+
const timeoutId = setTimeout(() => controller.abort(), opts.timeoutMs ?? this.defaultTimeoutMs);
|
|
1054
|
+
let res;
|
|
1055
|
+
try {
|
|
1056
|
+
const init = { method, headers, signal: controller.signal };
|
|
1057
|
+
if (body !== void 0) {
|
|
1058
|
+
init.body = body;
|
|
1059
|
+
}
|
|
1060
|
+
res = await this.fetcher(url, init);
|
|
1061
|
+
} finally {
|
|
1062
|
+
clearTimeout(timeoutId);
|
|
1063
|
+
}
|
|
1064
|
+
const requestId = res.headers.get("x-request-id");
|
|
1065
|
+
if (res.status === 204) {
|
|
1066
|
+
return null;
|
|
1067
|
+
}
|
|
1068
|
+
const text = await res.text();
|
|
1069
|
+
let parsed = null;
|
|
1070
|
+
if (text.length > 0) {
|
|
1071
|
+
try {
|
|
1072
|
+
parsed = JSON.parse(text);
|
|
1073
|
+
} catch {
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
if (!res.ok) {
|
|
1077
|
+
const errors = this.extractApiErrors(parsed);
|
|
1078
|
+
throw new AuthnHttpError(res.status, errors, requestId);
|
|
1079
|
+
}
|
|
1080
|
+
return parsed;
|
|
1081
|
+
}
|
|
1082
|
+
buildUrl(path, query) {
|
|
1083
|
+
const base = `${this.apiUrl}${path.startsWith("/") ? path : "/" + path}`;
|
|
1084
|
+
if (!query) return base;
|
|
1085
|
+
const params = new URLSearchParams();
|
|
1086
|
+
for (const [k, v] of Object.entries(query)) {
|
|
1087
|
+
if (v === void 0 || v === null || v === "") continue;
|
|
1088
|
+
if (Array.isArray(v)) {
|
|
1089
|
+
for (const item of v) {
|
|
1090
|
+
if (item !== void 0 && item !== null) params.append(k, String(item));
|
|
1091
|
+
}
|
|
1092
|
+
} else {
|
|
1093
|
+
params.append(k, String(v));
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
const qs = params.toString();
|
|
1097
|
+
return qs ? `${base}?${qs}` : base;
|
|
1098
|
+
}
|
|
1099
|
+
extractApiErrors(payload) {
|
|
1100
|
+
if (payload && typeof payload === "object" && "errors" in payload && Array.isArray(payload.errors)) {
|
|
1101
|
+
const out = [];
|
|
1102
|
+
for (const entry of payload.errors) {
|
|
1103
|
+
if (entry && typeof entry === "object") {
|
|
1104
|
+
const e = entry;
|
|
1105
|
+
const err = {
|
|
1106
|
+
code: typeof e.code === "string" ? e.code : "unknown",
|
|
1107
|
+
message: typeof e.message === "string" ? e.message : "Unknown error"
|
|
1108
|
+
};
|
|
1109
|
+
if (typeof e.long_message === "string") err.longMessage = e.long_message;
|
|
1110
|
+
if (e.meta && typeof e.meta === "object") err.meta = e.meta;
|
|
1111
|
+
out.push(err);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (out.length > 0) return out;
|
|
1115
|
+
}
|
|
1116
|
+
return [{ code: "unknown", message: "Unknown error from authn.sh API" }];
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
|
|
1120
|
+
// src/Authn.ts
|
|
1121
|
+
var Authn = class {
|
|
1122
|
+
/** Underlying HTTP transport — exposed for advanced use cases. */
|
|
1123
|
+
transport;
|
|
1124
|
+
users;
|
|
1125
|
+
sessions;
|
|
1126
|
+
organizations;
|
|
1127
|
+
oauthProviders;
|
|
1128
|
+
phoneNumbers;
|
|
1129
|
+
externalAccounts;
|
|
1130
|
+
smsTemplates;
|
|
1131
|
+
invitations;
|
|
1132
|
+
allowlistIdentifiers;
|
|
1133
|
+
blocklistIdentifiers;
|
|
1134
|
+
redirectUrls;
|
|
1135
|
+
roles;
|
|
1136
|
+
permissions;
|
|
1137
|
+
instance;
|
|
1138
|
+
constructor(opts) {
|
|
1139
|
+
if (!opts.secretKey || typeof opts.secretKey !== "string") {
|
|
1140
|
+
throw new AuthnConfigError("Authn: secretKey is required.");
|
|
1141
|
+
}
|
|
1142
|
+
if (!opts.secretKey.startsWith("sk_test_") && !opts.secretKey.startsWith("sk_live_")) {
|
|
1143
|
+
throw new AuthnConfigError("Authn: secretKey must start with sk_test_ or sk_live_.");
|
|
1144
|
+
}
|
|
1145
|
+
const transportOpts = {
|
|
1146
|
+
apiUrl: opts.apiUrl ?? "https://api.authn.sh",
|
|
1147
|
+
secretKey: opts.secretKey
|
|
1148
|
+
};
|
|
1149
|
+
if (opts.fetch !== void 0) transportOpts.fetch = opts.fetch;
|
|
1150
|
+
if (opts.timeoutMs !== void 0) transportOpts.timeoutMs = opts.timeoutMs;
|
|
1151
|
+
if (opts.userAgentSuffix !== void 0) transportOpts.userAgentSuffix = opts.userAgentSuffix;
|
|
1152
|
+
this.transport = new Transport(transportOpts);
|
|
1153
|
+
this.users = new UsersManager(this.transport);
|
|
1154
|
+
this.sessions = new SessionsManager(this.transport);
|
|
1155
|
+
this.organizations = new OrganizationsManager(this.transport);
|
|
1156
|
+
this.oauthProviders = new OauthProvidersManager(this.transport);
|
|
1157
|
+
this.phoneNumbers = new PhoneNumbersManager(this.transport);
|
|
1158
|
+
this.externalAccounts = new ExternalAccountsManager(this.transport);
|
|
1159
|
+
this.smsTemplates = new SmsTemplatesManager(this.transport);
|
|
1160
|
+
this.invitations = new InvitationsManager(this.transport);
|
|
1161
|
+
this.allowlistIdentifiers = new AllowlistIdentifiersManager(this.transport);
|
|
1162
|
+
this.blocklistIdentifiers = new BlocklistIdentifiersManager(this.transport);
|
|
1163
|
+
this.redirectUrls = new RedirectUrlsManager(this.transport);
|
|
1164
|
+
this.roles = new RolesManager(this.transport);
|
|
1165
|
+
this.permissions = new PermissionsManager(this.transport);
|
|
1166
|
+
this.instance = new InstanceManager(this.transport);
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
// src/tokens/VerifiedClaims.ts
|
|
1171
|
+
var VerifiedClaims = class {
|
|
1172
|
+
constructor(sub, sid, iss, azp, exp, iat, nbf, actor, organization, wasTest, twoFactorVerified, secondFactorAgeSeconds, firstFactorAgeSeconds, phoneNumberVerified, defaultSecondFactor, raw) {
|
|
1173
|
+
this.sub = sub;
|
|
1174
|
+
this.sid = sid;
|
|
1175
|
+
this.iss = iss;
|
|
1176
|
+
this.azp = azp;
|
|
1177
|
+
this.exp = exp;
|
|
1178
|
+
this.iat = iat;
|
|
1179
|
+
this.nbf = nbf;
|
|
1180
|
+
this.actor = actor;
|
|
1181
|
+
this.organization = organization;
|
|
1182
|
+
this.wasTest = wasTest;
|
|
1183
|
+
this.twoFactorVerified = twoFactorVerified;
|
|
1184
|
+
this.secondFactorAgeSeconds = secondFactorAgeSeconds;
|
|
1185
|
+
this.firstFactorAgeSeconds = firstFactorAgeSeconds;
|
|
1186
|
+
this.phoneNumberVerified = phoneNumberVerified;
|
|
1187
|
+
this.defaultSecondFactor = defaultSecondFactor;
|
|
1188
|
+
this.raw = raw;
|
|
1189
|
+
}
|
|
1190
|
+
sub;
|
|
1191
|
+
sid;
|
|
1192
|
+
iss;
|
|
1193
|
+
azp;
|
|
1194
|
+
exp;
|
|
1195
|
+
iat;
|
|
1196
|
+
nbf;
|
|
1197
|
+
actor;
|
|
1198
|
+
organization;
|
|
1199
|
+
wasTest;
|
|
1200
|
+
twoFactorVerified;
|
|
1201
|
+
secondFactorAgeSeconds;
|
|
1202
|
+
firstFactorAgeSeconds;
|
|
1203
|
+
phoneNumberVerified;
|
|
1204
|
+
defaultSecondFactor;
|
|
1205
|
+
raw;
|
|
1206
|
+
hasRole(roleKey) {
|
|
1207
|
+
return this.organization?.role === roleKey;
|
|
1208
|
+
}
|
|
1209
|
+
hasPermission(permissionKey) {
|
|
1210
|
+
return this.organization?.permissions.includes(permissionKey) ?? false;
|
|
1211
|
+
}
|
|
1212
|
+
hasVerifiedPhoneNumber() {
|
|
1213
|
+
return this.phoneNumberVerified;
|
|
1214
|
+
}
|
|
1215
|
+
preferredSecondFactor() {
|
|
1216
|
+
return this.defaultSecondFactor;
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
function buildVerifiedClaims(claims) {
|
|
1220
|
+
const num = (k) => typeof claims[k] === "number" ? claims[k] : 0;
|
|
1221
|
+
const numOrNull = (k) => typeof claims[k] === "number" ? claims[k] : null;
|
|
1222
|
+
const str = (k) => typeof claims[k] === "string" ? claims[k] : "";
|
|
1223
|
+
const strOrNull = (k) => typeof claims[k] === "string" ? claims[k] : null;
|
|
1224
|
+
const actorRaw = claims["actor"];
|
|
1225
|
+
const actor = actorRaw && typeof actorRaw === "object" ? {
|
|
1226
|
+
iss: typeof actorRaw.iss === "string" ? actorRaw.iss : "",
|
|
1227
|
+
sub: typeof actorRaw.sub === "string" ? actorRaw.sub : "",
|
|
1228
|
+
sid: typeof actorRaw.sid === "string" ? actorRaw.sid : ""
|
|
1229
|
+
} : null;
|
|
1230
|
+
const orgRaw = claims["org"];
|
|
1231
|
+
let organization = null;
|
|
1232
|
+
if (orgRaw && typeof orgRaw === "object") {
|
|
1233
|
+
const o = orgRaw;
|
|
1234
|
+
const perms = Array.isArray(o.per) ? o.per.filter((p) => typeof p === "string") : [];
|
|
1235
|
+
organization = {
|
|
1236
|
+
id: typeof o.id === "string" ? o.id : "",
|
|
1237
|
+
slug: typeof o.slg === "string" ? o.slg : void 0,
|
|
1238
|
+
role: typeof o.rol === "string" ? o.rol : void 0,
|
|
1239
|
+
permissions: perms
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
const dsfRaw = claims["dsf"];
|
|
1243
|
+
const dsf = dsfRaw === "totp" || dsfRaw === "phone_code" || dsfRaw === "backup_code" ? dsfRaw : null;
|
|
1244
|
+
return new VerifiedClaims(
|
|
1245
|
+
str("sub"),
|
|
1246
|
+
str("sid"),
|
|
1247
|
+
str("iss"),
|
|
1248
|
+
strOrNull("azp"),
|
|
1249
|
+
num("exp"),
|
|
1250
|
+
num("iat"),
|
|
1251
|
+
numOrNull("nbf"),
|
|
1252
|
+
actor,
|
|
1253
|
+
organization,
|
|
1254
|
+
claims["wt"] === true,
|
|
1255
|
+
claims["tfv"] === true,
|
|
1256
|
+
numOrNull("sfa"),
|
|
1257
|
+
numOrNull("ffa"),
|
|
1258
|
+
claims["pnv"] === true,
|
|
1259
|
+
dsf,
|
|
1260
|
+
claims
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// src/tokens/TokenVerifier.ts
|
|
1265
|
+
var SUPPORTED_ALGS = ["RS256", "ES256", "ES384", "ES512"];
|
|
1266
|
+
var TokenVerifier = class {
|
|
1267
|
+
frontendApiUrl;
|
|
1268
|
+
jwks;
|
|
1269
|
+
allowedClockSkew;
|
|
1270
|
+
constructor(opts = {}) {
|
|
1271
|
+
if (!opts.publishableKey && !opts.frontendApiUrl) {
|
|
1272
|
+
throw new AuthnConfigError("TokenVerifier: either publishableKey or frontendApiUrl is required.");
|
|
1273
|
+
}
|
|
1274
|
+
this.frontendApiUrl = opts.frontendApiUrl ? opts.frontendApiUrl.replace(/\/$/, "") : decodeFrontendApiUrl(opts.publishableKey ?? "");
|
|
1275
|
+
const jwksUrl = new URL(`${this.frontendApiUrl}/v1/jwks`);
|
|
1276
|
+
this.jwks = createRemoteJWKSet(jwksUrl, {
|
|
1277
|
+
cacheMaxAge: (opts.jwksCacheTtlSeconds ?? 600) * 1e3,
|
|
1278
|
+
cooldownDuration: 3e4,
|
|
1279
|
+
...opts.fetch ? { [/* @__PURE__ */ Symbol.for("jose.fetch")]: opts.fetch } : {}
|
|
1280
|
+
});
|
|
1281
|
+
this.allowedClockSkew = opts.allowedClockSkewSeconds ?? 5;
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Verify a JWT and return its claims. Throws AuthnTokenInvalidError on failure.
|
|
1285
|
+
*
|
|
1286
|
+
* @param expectedAzp If provided, the token's `azp` must match one of these.
|
|
1287
|
+
*/
|
|
1288
|
+
async verify(jwt, expectedAzp = []) {
|
|
1289
|
+
if (typeof jwt !== "string" || jwt === "") {
|
|
1290
|
+
throw new AuthnTokenInvalidError("malformed", "Token is empty.");
|
|
1291
|
+
}
|
|
1292
|
+
let header;
|
|
1293
|
+
try {
|
|
1294
|
+
header = decodeProtectedHeader(jwt);
|
|
1295
|
+
} catch (e) {
|
|
1296
|
+
throw new AuthnTokenInvalidError("malformed", e.message);
|
|
1297
|
+
}
|
|
1298
|
+
if (!header.alg || !SUPPORTED_ALGS.includes(header.alg)) {
|
|
1299
|
+
throw new AuthnTokenInvalidError("signature_invalid", `Unsupported alg: ${String(header.alg)}`);
|
|
1300
|
+
}
|
|
1301
|
+
let claims;
|
|
1302
|
+
try {
|
|
1303
|
+
const result = await jwtVerify(jwt, this.jwks, {
|
|
1304
|
+
issuer: this.frontendApiUrl,
|
|
1305
|
+
clockTolerance: this.allowedClockSkew,
|
|
1306
|
+
algorithms: [...SUPPORTED_ALGS]
|
|
1307
|
+
});
|
|
1308
|
+
claims = result.payload;
|
|
1309
|
+
} catch (e) {
|
|
1310
|
+
const err = e;
|
|
1311
|
+
const reason = mapJoseError(err.code);
|
|
1312
|
+
throw new AuthnTokenInvalidError(reason, err.message);
|
|
1313
|
+
}
|
|
1314
|
+
if (expectedAzp.length > 0) {
|
|
1315
|
+
const azp = typeof claims.azp === "string" ? claims.azp : null;
|
|
1316
|
+
if (azp === null || !expectedAzp.includes(azp)) {
|
|
1317
|
+
throw new AuthnTokenInvalidError(
|
|
1318
|
+
"audience_mismatch",
|
|
1319
|
+
`azp claim "${String(azp)}" did not match the expected origins.`
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
return buildVerifiedClaims(claims);
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Same as `verify` but returns `null` on failure instead of throwing.
|
|
1327
|
+
* Useful for "best-effort" auth that falls back to unauthenticated.
|
|
1328
|
+
*/
|
|
1329
|
+
async tryVerify(jwt, expectedAzp = []) {
|
|
1330
|
+
try {
|
|
1331
|
+
return await this.verify(jwt, expectedAzp);
|
|
1332
|
+
} catch {
|
|
1333
|
+
return null;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
function mapJoseError(code) {
|
|
1338
|
+
switch (code) {
|
|
1339
|
+
case "ERR_JWT_EXPIRED":
|
|
1340
|
+
return "expired";
|
|
1341
|
+
case "ERR_JWT_CLAIM_VALIDATION_FAILED":
|
|
1342
|
+
return "issuer_mismatch";
|
|
1343
|
+
case "ERR_JWS_SIGNATURE_VERIFICATION_FAILED":
|
|
1344
|
+
case "ERR_JWS_INVALID":
|
|
1345
|
+
return "signature_invalid";
|
|
1346
|
+
case "ERR_JWKS_NO_MATCHING_KEY":
|
|
1347
|
+
return "key_not_found";
|
|
1348
|
+
case "ERR_JWKS_TIMEOUT":
|
|
1349
|
+
return "jwks_fetch_failed";
|
|
1350
|
+
default:
|
|
1351
|
+
return "signature_invalid";
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
function decodeFrontendApiUrl(publishableKey) {
|
|
1355
|
+
if (!publishableKey.startsWith("pk_test_") && !publishableKey.startsWith("pk_live_")) {
|
|
1356
|
+
throw new AuthnConfigError(
|
|
1357
|
+
`TokenVerifier: publishableKey must start with pk_test_ or pk_live_, got "${publishableKey.slice(0, 8)}\u2026".`
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1360
|
+
const payload = publishableKey.replace(/^pk_(test|live)_/, "").replace(/\$$/, "");
|
|
1361
|
+
let host;
|
|
1362
|
+
try {
|
|
1363
|
+
host = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
1364
|
+
} catch {
|
|
1365
|
+
throw new AuthnConfigError(`TokenVerifier: publishableKey "${publishableKey.slice(0, 16)}\u2026" is not base64url.`);
|
|
1366
|
+
}
|
|
1367
|
+
if (host === "") {
|
|
1368
|
+
throw new AuthnConfigError("TokenVerifier: publishableKey decoded to an empty host.");
|
|
1369
|
+
}
|
|
1370
|
+
return `https://${host.replace(/\/$/, "")}`;
|
|
1371
|
+
}
|
|
1372
|
+
var WebhookSignatureVerifier = class {
|
|
1373
|
+
secrets;
|
|
1374
|
+
tolerance;
|
|
1375
|
+
now;
|
|
1376
|
+
constructor(opts) {
|
|
1377
|
+
const list = Array.isArray(opts.signingSecret) ? opts.signingSecret : [opts.signingSecret];
|
|
1378
|
+
this.secrets = list.filter((s) => typeof s === "string" && s !== "");
|
|
1379
|
+
if (this.secrets.length === 0) {
|
|
1380
|
+
throw new Error("WebhookSignatureVerifier: at least one signing secret must be provided.");
|
|
1381
|
+
}
|
|
1382
|
+
this.tolerance = opts.toleranceSeconds ?? 300;
|
|
1383
|
+
this.now = opts.now ?? (() => Math.floor(Date.now() / 1e3));
|
|
1384
|
+
}
|
|
1385
|
+
verify(rawBody, headers) {
|
|
1386
|
+
const id = headerLine(headers, "svix-id");
|
|
1387
|
+
const timestamp = headerLine(headers, "svix-timestamp");
|
|
1388
|
+
const signature = headerLine(headers, "svix-signature");
|
|
1389
|
+
if (!id || !timestamp || !signature) {
|
|
1390
|
+
throw new AuthnWebhookSignatureInvalidError("missing_signature_header");
|
|
1391
|
+
}
|
|
1392
|
+
if (!/^\d+$/.test(timestamp)) {
|
|
1393
|
+
throw new AuthnWebhookSignatureInvalidError("malformed_signature_header", "svix-timestamp must be a unix-second integer.");
|
|
1394
|
+
}
|
|
1395
|
+
const tsInt = parseInt(timestamp, 10);
|
|
1396
|
+
if (Math.abs(this.now() - tsInt) > this.tolerance) {
|
|
1397
|
+
throw new AuthnWebhookSignatureInvalidError("timestamp_too_old");
|
|
1398
|
+
}
|
|
1399
|
+
const signedPayload = `${id}.${timestamp}.${rawBody}`;
|
|
1400
|
+
const providedSignatures = extractV1Signatures(signature);
|
|
1401
|
+
if (providedSignatures.length === 0) {
|
|
1402
|
+
throw new AuthnWebhookSignatureInvalidError("malformed_signature_header", "No v1 signatures found in svix-signature.");
|
|
1403
|
+
}
|
|
1404
|
+
if (!this.matchesAny(signedPayload, providedSignatures)) {
|
|
1405
|
+
throw new AuthnWebhookSignatureInvalidError("no_matching_signature");
|
|
1406
|
+
}
|
|
1407
|
+
let payload;
|
|
1408
|
+
try {
|
|
1409
|
+
const parsed = JSON.parse(rawBody);
|
|
1410
|
+
payload = parsed && typeof parsed === "object" ? parsed : {};
|
|
1411
|
+
} catch {
|
|
1412
|
+
throw new AuthnWebhookSignatureInvalidError("malformed_signature_header", "Webhook body is not JSON.");
|
|
1413
|
+
}
|
|
1414
|
+
return {
|
|
1415
|
+
type: typeof payload.type === "string" ? payload.type : "",
|
|
1416
|
+
data: payload.data && typeof payload.data === "object" ? payload.data : {},
|
|
1417
|
+
timestamp: tsInt,
|
|
1418
|
+
instanceId: typeof payload.instance_id === "string" ? payload.instance_id : "",
|
|
1419
|
+
wasTest: payload.was_test === true,
|
|
1420
|
+
messageId: id
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
tryVerify(rawBody, headers) {
|
|
1424
|
+
try {
|
|
1425
|
+
return this.verify(rawBody, headers);
|
|
1426
|
+
} catch {
|
|
1427
|
+
return null;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
matchesAny(signedPayload, providedSignatures) {
|
|
1431
|
+
for (const secret of this.secrets) {
|
|
1432
|
+
const key = stripWhsecPrefix(secret);
|
|
1433
|
+
const expected = createHmac("sha256", Buffer.from(key, "base64")).update(signedPayload).digest();
|
|
1434
|
+
for (const sig of providedSignatures) {
|
|
1435
|
+
let provided;
|
|
1436
|
+
try {
|
|
1437
|
+
provided = Buffer.from(sig, "base64");
|
|
1438
|
+
} catch {
|
|
1439
|
+
continue;
|
|
1440
|
+
}
|
|
1441
|
+
if (provided.length === expected.length && timingSafeEqual(provided, expected)) {
|
|
1442
|
+
return true;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
return false;
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
function headerLine(headers, name) {
|
|
1450
|
+
const lookup = name.toLowerCase();
|
|
1451
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
1452
|
+
if (k.toLowerCase() === lookup) {
|
|
1453
|
+
if (Array.isArray(v)) return v[0] ?? null;
|
|
1454
|
+
if (typeof v === "string") return v;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
return null;
|
|
1458
|
+
}
|
|
1459
|
+
function extractV1Signatures(header) {
|
|
1460
|
+
const parts = header.split(/\s+/);
|
|
1461
|
+
const out = [];
|
|
1462
|
+
for (const part of parts) {
|
|
1463
|
+
const eqIndex = part.indexOf(",");
|
|
1464
|
+
if (eqIndex === -1) continue;
|
|
1465
|
+
const scheme = part.slice(0, eqIndex);
|
|
1466
|
+
const value = part.slice(eqIndex + 1);
|
|
1467
|
+
if (scheme === "v1") out.push(value);
|
|
1468
|
+
}
|
|
1469
|
+
return out;
|
|
1470
|
+
}
|
|
1471
|
+
function stripWhsecPrefix(secret) {
|
|
1472
|
+
return secret.startsWith("whsec_") ? secret.slice(6) : secret;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
export { AllowlistIdentifiersManager, Authn, AuthnConfigError, AuthnHttpError, AuthnTokenInvalidError, AuthnWebhookSignatureInvalidError, BlocklistIdentifiersManager, ExternalAccountsListParams, ExternalAccountsManager, InstanceManager, InvitationsListParams, InvitationsManager, ListParams, OauthProvidersManager, OrganizationDomainsManager, OrganizationInvitationsManager, OrganizationMembershipsManager, OrganizationsManager, PermissionsManager, PhoneNumbersListParams, PhoneNumbersManager, RedirectUrlsManager, RolesManager, SessionsListParams, SessionsManager, SmsTemplatesManager, TokenVerifier, Transport, UsersListParams, UsersManager, VerifiedClaims, WebhookSignatureVerifier, buildVerifiedClaims, decodeFrontendApiUrl, hydrateAllowlistIdentifier, hydrateBlocklistIdentifier, hydrateExternalAccount, hydrateInstance, hydrateInvitation, hydrateOauthProvider, hydrateOrganization, hydrateOrganizationDomain, hydrateOrganizationInvitation, hydrateOrganizationMembership, hydratePermission, hydratePhoneNumber, hydrateRedirectUrl, hydrateRole, hydrateSession, hydrateSmsTemplate, hydrateUser };
|
|
1476
|
+
//# sourceMappingURL=index.js.map
|
|
1477
|
+
//# sourceMappingURL=index.js.map
|