@hraness/suite-accounts 0.9.20

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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +496 -0
  3. package/compiler-foundation.css +1 -0
  4. package/dist/auth-client.js +16 -0
  5. package/dist/auth-proxy.js +757 -0
  6. package/dist/bearer-verifier.js +1119 -0
  7. package/dist/browser-session.js +208 -0
  8. package/dist/client-configuration.js +470 -0
  9. package/dist/convex-browser-auth-browser.js +923 -0
  10. package/dist/convex-browser-auth-server.js +846 -0
  11. package/dist/convex-browser-auth.js +597 -0
  12. package/dist/entitlements.js +502 -0
  13. package/dist/identity/functions.js +44 -0
  14. package/dist/identity/index.js +1716 -0
  15. package/dist/identity/return-targets.js +33 -0
  16. package/dist/index.js +1133 -0
  17. package/dist/oidc-device-code.js +253 -0
  18. package/dist/oidc-rp.js +2259 -0
  19. package/dist/oidc-session-policy.js +5 -0
  20. package/dist/oidc-surface-server.js +2332 -0
  21. package/dist/profile-form.js +1934 -0
  22. package/dist/profile.js +17 -0
  23. package/dist/public-config.js +462 -0
  24. package/dist/react.js +137 -0
  25. package/dist/receipt-verifier.js +619 -0
  26. package/dist/registry.js +327 -0
  27. package/dist/stylex-manifest.json +1 -0
  28. package/dist/stylex.css +435 -0
  29. package/dist/urls.js +391 -0
  30. package/package.json +263 -0
  31. package/portfolio-inventory.json +37 -0
  32. package/src/auth-client.ts +37 -0
  33. package/src/auth-proxy.ts +473 -0
  34. package/src/bearer-verifier.ts +478 -0
  35. package/src/browser-session.ts +260 -0
  36. package/src/client-configuration.ts +172 -0
  37. package/src/convex-browser-auth-browser.ts +238 -0
  38. package/src/convex-browser-auth-server.ts +492 -0
  39. package/src/convex-browser-auth.ts +208 -0
  40. package/src/convex-url.ts +74 -0
  41. package/src/entitlements.ts +317 -0
  42. package/src/identity/catalog.ts +227 -0
  43. package/src/identity/consumers.ts +53 -0
  44. package/src/identity/functions.ts +70 -0
  45. package/src/identity/identifiers.ts +82 -0
  46. package/src/identity/index.ts +10 -0
  47. package/src/identity/links.ts +280 -0
  48. package/src/identity/membership.ts +156 -0
  49. package/src/identity/principals.ts +301 -0
  50. package/src/identity/profiles-v2.ts +330 -0
  51. package/src/identity/profiles.ts +524 -0
  52. package/src/identity/return-targets.ts +20 -0
  53. package/src/identity/usernames.ts +101 -0
  54. package/src/identity/views.ts +289 -0
  55. package/src/immutable.ts +25 -0
  56. package/src/index.ts +7 -0
  57. package/src/oidc-continuation.ts +59 -0
  58. package/src/oidc-device-code.ts +401 -0
  59. package/src/oidc-rp.ts +2217 -0
  60. package/src/oidc-session-policy.ts +6 -0
  61. package/src/oidc-surface-server.ts +186 -0
  62. package/src/profile-form.css +1 -0
  63. package/src/profile-form.stylex.ts +226 -0
  64. package/src/profile-form.tsx +314 -0
  65. package/src/profile.ts +33 -0
  66. package/src/public-config.ts +294 -0
  67. package/src/public-profile-form-result.ts +82 -0
  68. package/src/public-profile-form.tsx +319 -0
  69. package/src/public-profile-links.ts +100 -0
  70. package/src/react.tsx +196 -0
  71. package/src/receipt-verifier.ts +273 -0
  72. package/src/registry.ts +600 -0
  73. package/src/urls.ts +234 -0
@@ -0,0 +1,600 @@
1
+ import {
2
+ SUITE_CONSUMER_IDS,
3
+ type SuiteConsumerId,
4
+ } from "./identity/consumers.js";
5
+ import { deepFreeze } from "./immutable.js";
6
+
7
+ export { SUITE_CONSUMER_IDS };
8
+ export type SuiteAccountsConsumerId = SuiteConsumerId;
9
+
10
+ export const SUITE_ACCOUNTS_REMOTE_ENVIRONMENTS = deepFreeze([
11
+ "production",
12
+ ] as const);
13
+
14
+ export type SuiteAccountsRemoteEnvironment =
15
+ (typeof SUITE_ACCOUNTS_REMOTE_ENVIRONMENTS)[number];
16
+ export type SuiteAccountsEnvironment =
17
+ | "local"
18
+ | SuiteAccountsRemoteEnvironment;
19
+
20
+ export type SuiteAccountsCookieName =
21
+ | "account_data"
22
+ | "convex_jwt"
23
+ | "dont_remember"
24
+ | "session_data"
25
+ | "session_token";
26
+
27
+ export type SuiteAccountsCookieCapabilities = Readonly<{
28
+ chunked: readonly SuiteAccountsCookieName[];
29
+ names: readonly SuiteAccountsCookieName[];
30
+ }>;
31
+
32
+ export type SuiteAccountsAuthConfiguration =
33
+ | Readonly<{
34
+ basePath: "/api/auth";
35
+ cookies: SuiteAccountsCookieCapabilities;
36
+ kind: "authority";
37
+ }>
38
+ | Readonly<{
39
+ basePath: "/api/suite-auth";
40
+ kind: "oidc-rp";
41
+ }>
42
+ | Readonly<{
43
+ basePath: "/api/auth";
44
+ cookies: SuiteAccountsCookieCapabilities;
45
+ kind: "proxy";
46
+ }>;
47
+
48
+ export type SuiteAccountsRemoteDeployment = Readonly<{
49
+ accountsOrigin: string;
50
+ convexSiteUrl: string;
51
+ convexUrl: string;
52
+ }>;
53
+
54
+ export type SuiteAccountsConsumerEnvironment = Readonly<{
55
+ billingReturn:
56
+ | Readonly<{ kind: "supported"; path: `/${string}` }>
57
+ | Readonly<{ kind: "unsupported" }>;
58
+ siteUrl: string;
59
+ }>;
60
+
61
+ export type SuiteAccountsConsumerEnvironments = Readonly<{
62
+ production: SuiteAccountsConsumerEnvironment;
63
+ }>;
64
+
65
+ export type SuiteAccountsConsumerRegistration = Readonly<{
66
+ auth: SuiteAccountsAuthConfiguration;
67
+ displayName: string;
68
+ environments: SuiteAccountsConsumerEnvironments;
69
+ id: SuiteAccountsConsumerId;
70
+ }>;
71
+
72
+ const accountsCookies = deepFreeze({
73
+ chunked: ["account_data", "session_data"],
74
+ names: [
75
+ "account_data",
76
+ "convex_jwt",
77
+ "dont_remember",
78
+ "session_data",
79
+ "session_token",
80
+ ],
81
+ } as const satisfies SuiteAccountsCookieCapabilities);
82
+
83
+ const consumerCookies = deepFreeze({
84
+ chunked: ["session_data"],
85
+ names: ["dont_remember", "session_data", "session_token"],
86
+ } as const satisfies SuiteAccountsCookieCapabilities);
87
+
88
+ /**
89
+ * Frozen v1 deployment data for already-released clients.
90
+ *
91
+ * @deprecated New consumers must use `createSuiteAccountsClientConfiguration`
92
+ * and must be registered by the Accounts authority before release.
93
+ */
94
+ export const SUITE_ACCOUNTS_DEPLOYMENTS = deepFreeze({
95
+ production: {
96
+ accountsOrigin: "https://account.hraness.com",
97
+ convexSiteUrl: "https://qualified-marmot-22.convex.site",
98
+ convexUrl: "https://qualified-marmot-22.convex.cloud",
99
+ },
100
+ } as const satisfies Readonly<
101
+ Record<SuiteAccountsRemoteEnvironment, SuiteAccountsRemoteDeployment>
102
+ >);
103
+
104
+ function unsupported(siteUrl: string): SuiteAccountsConsumerEnvironment {
105
+ return { billingReturn: { kind: "unsupported" }, siteUrl };
106
+ }
107
+
108
+ function oidcSite<const Consumer extends SuiteAccountsConsumerId>(
109
+ id: Consumer,
110
+ displayName: string,
111
+ productionSiteUrl: string,
112
+ ) {
113
+ return {
114
+ auth: { basePath: "/api/suite-auth", kind: "oidc-rp" },
115
+ displayName,
116
+ environments: {
117
+ production: unsupported(productionSiteUrl),
118
+ },
119
+ id,
120
+ } as const;
121
+ }
122
+
123
+ /** Consumer identities that still have a deprecated v1 registration. */
124
+ export const SUITE_ACCOUNTS_REGISTERED_CONSUMER_IDS = deepFreeze([
125
+ "accounts",
126
+ "act60",
127
+ "soundfish",
128
+ "oh-computer",
129
+ "draw-money",
130
+ "sponge",
131
+ ] as const satisfies readonly SuiteAccountsConsumerId[]);
132
+
133
+ export type SuiteAccountsRegisteredConsumerId =
134
+ (typeof SUITE_ACCOUNTS_REGISTERED_CONSUMER_IDS)[number];
135
+
136
+ /**
137
+ * Deprecated v1 registrations for clients that remain registered.
138
+ *
139
+ * Historical identity parsing is intentionally separate from client trust:
140
+ * a retired identity may remain parseable without retaining an origin or
141
+ * OAuth registration here.
142
+ *
143
+ * @deprecated New consumers must use `createSuiteAccountsClientConfiguration`
144
+ * and must not extend or copy this object.
145
+ */
146
+ export const SUITE_ACCOUNTS_CONSUMERS = deepFreeze({
147
+ accounts: {
148
+ auth: {
149
+ basePath: "/api/auth",
150
+ cookies: accountsCookies,
151
+ kind: "authority",
152
+ },
153
+ displayName: "Accounts",
154
+ environments: {
155
+ production: {
156
+ billingReturn: { kind: "supported", path: "/account" },
157
+ siteUrl: "https://account.hraness.com",
158
+ },
159
+ },
160
+ id: "accounts",
161
+ },
162
+ act60: oidcSite(
163
+ "act60",
164
+ "ACT60",
165
+ "https://act60.me",
166
+ ),
167
+ soundfish: {
168
+ auth: { basePath: "/api/suite-auth", kind: "oidc-rp" },
169
+ displayName: "Soundfish",
170
+ environments: {
171
+ production: unsupported("https://sound.fish"),
172
+ },
173
+ id: "soundfish",
174
+ },
175
+ "oh-computer": oidcSite(
176
+ "oh-computer",
177
+ "Oh",
178
+ "https://oh.computer",
179
+ ),
180
+ "draw-money": {
181
+ auth: {
182
+ basePath: "/api/auth",
183
+ cookies: consumerCookies,
184
+ kind: "proxy",
185
+ },
186
+ displayName: "Draw Money",
187
+ environments: {
188
+ production: unsupported("https://draw.money"),
189
+ },
190
+ id: "draw-money",
191
+ },
192
+ sponge: oidcSite(
193
+ "sponge",
194
+ "Sponge",
195
+ "https://spongesearch.com",
196
+ ),
197
+ } as const satisfies Readonly<
198
+ Record<SuiteAccountsRegisteredConsumerId, SuiteAccountsConsumerRegistration>
199
+ >);
200
+
201
+ /**
202
+ * Previously published production-origin overrides retained for source
203
+ * compatibility. The current registry below incorporates these values rather
204
+ * than mutating the released-v1 registrations.
205
+ */
206
+ export const SUITE_ACCOUNTS_CURRENT_ORIGIN_OVERRIDES = deepFreeze({
207
+ sponge: {
208
+ production: unsupported("https://sponge.computer"),
209
+ },
210
+ } as const satisfies Partial<Readonly<Record<
211
+ SuiteAccountsConsumerId,
212
+ SuiteAccountsConsumerEnvironments
213
+ >>>);
214
+
215
+ /** Consumers that may establish new production trust through current APIs. */
216
+ export const SUITE_ACCOUNTS_CURRENT_CONSUMER_IDS = deepFreeze([
217
+ "accounts",
218
+ "act60",
219
+ "soundfish",
220
+ "oh-computer",
221
+ "sponge",
222
+ "peopleblade",
223
+ "aicharts",
224
+ "hraness",
225
+ "soulscrape",
226
+ "platonik",
227
+ "ghostget",
228
+ "alt",
229
+ "algal",
230
+ ] as const);
231
+
232
+ export type SuiteAccountsCurrentConsumerId =
233
+ (typeof SUITE_ACCOUNTS_CURRENT_CONSUMER_IDS)[number];
234
+
235
+ export type SuiteAccountsCurrentConsumerRegistration = Readonly<{
236
+ auth: SuiteAccountsAuthConfiguration;
237
+ displayName: string;
238
+ environments: SuiteAccountsConsumerEnvironments;
239
+ id: SuiteAccountsCurrentConsumerId;
240
+ }>;
241
+
242
+ function currentOidcSite<const Consumer extends SuiteAccountsCurrentConsumerId>(
243
+ id: Consumer,
244
+ displayName: string,
245
+ productionSiteUrl: string,
246
+ ) {
247
+ return {
248
+ auth: { basePath: "/api/suite-auth", kind: "oidc-rp" },
249
+ displayName,
250
+ environments: {
251
+ production: unsupported(productionSiteUrl),
252
+ },
253
+ id,
254
+ } as const;
255
+ }
256
+
257
+ /**
258
+ * Current Accounts authority registrations.
259
+ *
260
+ * Retired Elders, Subcounter, Oompa and predecessor identities remain
261
+ * parseable as historical evidence, but neither current nor deprecated
262
+ * registration helpers retain their browser origins or OAuth clients.
263
+ */
264
+ export const SUITE_ACCOUNTS_CURRENT_CONSUMERS = deepFreeze({
265
+ accounts: SUITE_ACCOUNTS_CONSUMERS.accounts,
266
+ act60: SUITE_ACCOUNTS_CONSUMERS.act60,
267
+ soundfish: SUITE_ACCOUNTS_CONSUMERS.soundfish,
268
+ "oh-computer": SUITE_ACCOUNTS_CONSUMERS["oh-computer"],
269
+ sponge: currentOidcSite(
270
+ "sponge",
271
+ "Sponge",
272
+ SUITE_ACCOUNTS_CURRENT_ORIGIN_OVERRIDES.sponge.production.siteUrl,
273
+ ),
274
+ peopleblade: currentOidcSite(
275
+ "peopleblade",
276
+ "PeopleBlade",
277
+ "https://peopleblade.com",
278
+ ),
279
+ aicharts: currentOidcSite(
280
+ "aicharts",
281
+ "AI Charts",
282
+ "https://aicharts.io",
283
+ ),
284
+ hraness: currentOidcSite("hraness", "Hraness", "https://hraness.com"),
285
+ soulscrape: currentOidcSite("soulscrape", "Soulscrape", "https://soulscrape.com"),
286
+ platonik: currentOidcSite("platonik", "Platonik", "https://platonik.space"),
287
+ ghostget: currentOidcSite("ghostget", "Ghostget", "https://ghostget.com"),
288
+ alt: currentOidcSite("alt", "Alt", "https://alt.dog"),
289
+ algal: currentOidcSite("algal", "Algal", "https://algal.cloud"),
290
+ } as const satisfies Readonly<
291
+ Record<
292
+ SuiteAccountsCurrentConsumerId,
293
+ SuiteAccountsCurrentConsumerRegistration
294
+ >
295
+ >);
296
+
297
+ /**
298
+ * Frozen v0.2 compatibility name for the consumers that were active before the
299
+ * current registry became a distinct authority surface.
300
+ *
301
+ * @deprecated Use `SUITE_ACCOUNTS_CURRENT_CONSUMER_IDS`.
302
+ */
303
+ export const SUITE_ACCOUNTS_ACTIVE_CONSUMER_IDS = deepFreeze([
304
+ "accounts",
305
+ "act60",
306
+ "soundfish",
307
+ "oh-computer",
308
+ "sponge",
309
+ ] as const satisfies readonly SuiteAccountsConsumerId[]);
310
+ export type SuiteAccountsActiveConsumerId =
311
+ (typeof SUITE_ACCOUNTS_ACTIVE_CONSUMER_IDS)[number];
312
+
313
+ export type SuiteAccountsOidcConsumerId = {
314
+ [Consumer in SuiteAccountsRegisteredConsumerId]:
315
+ (typeof SUITE_ACCOUNTS_CONSUMERS)[Consumer]["auth"]["kind"] extends "oidc-rp"
316
+ ? Consumer
317
+ : never;
318
+ }[SuiteAccountsRegisteredConsumerId];
319
+
320
+ /** Every canonical browser OIDC product accepts only email-code sessions. */
321
+ export const SUITE_EMAIL_OTP_REQUIRED_OIDC_CONSUMER_IDS:
322
+ readonly SuiteAccountsOidcConsumerId[] = deepFreeze(
323
+ SUITE_ACCOUNTS_REGISTERED_CONSUMER_IDS.filter(
324
+ (consumer): consumer is SuiteAccountsOidcConsumerId =>
325
+ SUITE_ACCOUNTS_CONSUMERS[consumer].auth.kind === "oidc-rp",
326
+ ),
327
+ );
328
+
329
+ export type SuiteEmailOtpRequiredOidcConsumerId = SuiteAccountsOidcConsumerId;
330
+
331
+ export function suiteAccountsConsumerRequiresEmailOtp(
332
+ consumer: SuiteAccountsOidcConsumerId,
333
+ ): consumer is SuiteEmailOtpRequiredOidcConsumerId {
334
+ return (SUITE_EMAIL_OTP_REQUIRED_OIDC_CONSUMER_IDS as readonly string[])
335
+ .includes(consumer);
336
+ }
337
+
338
+ /**
339
+ * Product clients that can exchange signed product-link and entitlement
340
+ * receipts. Editorial site clients authenticate the same suite account but do
341
+ * not gain a product identity-link boundary.
342
+ */
343
+ export const SUITE_ACCOUNTS_LINKED_OIDC_CONSUMER_IDS = deepFreeze([
344
+ "soundfish",
345
+ ] as const satisfies readonly SuiteAccountsOidcConsumerId[]);
346
+
347
+ export type SuiteAccountsLinkedOidcConsumerId =
348
+ (typeof SUITE_ACCOUNTS_LINKED_OIDC_CONSUMER_IDS)[number];
349
+
350
+ export type SuiteAccountsCurrentOidcConsumerId = {
351
+ [Consumer in SuiteAccountsCurrentConsumerId]:
352
+ (typeof SUITE_ACCOUNTS_CURRENT_CONSUMERS)[Consumer]["auth"]["kind"] extends
353
+ "oidc-rp"
354
+ ? Consumer
355
+ : never;
356
+ }[SuiteAccountsCurrentConsumerId];
357
+
358
+ export type SuiteAccountsCurrentOAuthConsumerId =
359
+ SuiteAccountsCurrentOidcConsumerId;
360
+
361
+ export const SUITE_ACCOUNTS_CURRENT_EMAIL_OTP_REQUIRED_OIDC_CONSUMER_IDS:
362
+ readonly SuiteAccountsCurrentOidcConsumerId[] = deepFreeze(
363
+ SUITE_ACCOUNTS_CURRENT_CONSUMER_IDS.filter(
364
+ (consumer): consumer is SuiteAccountsCurrentOidcConsumerId =>
365
+ SUITE_ACCOUNTS_CURRENT_CONSUMERS[consumer].auth.kind === "oidc-rp",
366
+ ),
367
+ );
368
+
369
+ export type SuiteAccountsCurrentEmailOtpRequiredOidcConsumerId =
370
+ SuiteAccountsCurrentOidcConsumerId;
371
+
372
+ export const SUITE_ACCOUNTS_CURRENT_LINKED_OIDC_CONSUMER_IDS = deepFreeze([
373
+ "soundfish",
374
+ "peopleblade",
375
+ "ghostget",
376
+ ] as const satisfies readonly SuiteAccountsCurrentOidcConsumerId[]);
377
+
378
+ export type SuiteAccountsCurrentLinkedOidcConsumerId =
379
+ (typeof SUITE_ACCOUNTS_CURRENT_LINKED_OIDC_CONSUMER_IDS)[number];
380
+
381
+ /**
382
+ * Browser clients that accepted the device-code grant before dedicated device
383
+ * clients existed. The list is closed: a newly registered product gets a
384
+ * dedicated device client instead, and its browser client never starts a
385
+ * device-code grant.
386
+ */
387
+ export const SUITE_ACCOUNTS_CURRENT_BROWSER_DEVICE_CODE_CONSUMER_IDS =
388
+ deepFreeze([
389
+ "act60",
390
+ "soundfish",
391
+ "oh-computer",
392
+ "sponge",
393
+ "peopleblade",
394
+ "aicharts",
395
+ "hraness",
396
+ "soulscrape",
397
+ "platonik",
398
+ "ghostget",
399
+ "alt",
400
+ ] as const satisfies readonly SuiteAccountsCurrentOidcConsumerId[]);
401
+
402
+ export type SuiteAccountsCurrentBrowserDeviceCodeConsumerId =
403
+ (typeof SUITE_ACCOUNTS_CURRENT_BROWSER_DEVICE_CODE_CONSUMER_IDS)[number];
404
+
405
+ /**
406
+ * Dedicated public device-authorization clients. Each one belongs to exactly
407
+ * one current browser product, has no redirect URI, and may use only the
408
+ * device-code grant.
409
+ */
410
+ export const SUITE_ACCOUNTS_CURRENT_DEVICE_CLIENT_IDS = deepFreeze([
411
+ "algal-cli",
412
+ ] as const);
413
+
414
+ export type SuiteAccountsCurrentDeviceClientId =
415
+ (typeof SUITE_ACCOUNTS_CURRENT_DEVICE_CLIENT_IDS)[number];
416
+
417
+ export type SuiteAccountsCurrentDeviceClient = Readonly<{
418
+ consumer: Exclude<
419
+ SuiteAccountsCurrentOidcConsumerId,
420
+ SuiteAccountsCurrentBrowserDeviceCodeConsumerId
421
+ >;
422
+ displayName: string;
423
+ environments: readonly SuiteAccountsRemoteEnvironment[];
424
+ id: SuiteAccountsCurrentDeviceClientId;
425
+ }>;
426
+
427
+ export const SUITE_ACCOUNTS_CURRENT_DEVICE_CLIENTS = deepFreeze({
428
+ "algal-cli": {
429
+ consumer: "algal",
430
+ displayName: "Algal CLI",
431
+ environments: ["production"],
432
+ id: "algal-cli",
433
+ },
434
+ } as const satisfies Readonly<
435
+ Record<SuiteAccountsCurrentDeviceClientId, SuiteAccountsCurrentDeviceClient>
436
+ >);
437
+
438
+ export type SuiteAccountsOAuthConsumerId = {
439
+ [Consumer in SuiteAccountsRegisteredConsumerId]:
440
+ (typeof SUITE_ACCOUNTS_CONSUMERS)[Consumer]["auth"]["kind"] extends
441
+ "oidc-rp"
442
+ ? Consumer
443
+ : never;
444
+ }[SuiteAccountsRegisteredConsumerId];
445
+
446
+ export type SuiteAccountsOidcClientId =
447
+ `hraness:${SuiteAccountsOAuthConsumerId}:${SuiteAccountsRemoteEnvironment}:v1`;
448
+
449
+ export type SuiteAccountsOidcClientRegistration = Readonly<{
450
+ callbackUrl: string;
451
+ clientId: SuiteAccountsOidcClientId;
452
+ }>;
453
+
454
+ export type SuiteAccountsCurrentOidcClientId =
455
+ `hraness:${SuiteAccountsCurrentOAuthConsumerId}:${SuiteAccountsRemoteEnvironment}:v1`;
456
+
457
+ export type SuiteAccountsCurrentOidcClientRegistration = Readonly<{
458
+ callbackUrl: string;
459
+ clientId: SuiteAccountsCurrentOidcClientId;
460
+ }>;
461
+
462
+ export function isSuiteAccountsConsumerId(
463
+ value: unknown,
464
+ ): value is SuiteAccountsConsumerId {
465
+ return typeof value === "string"
466
+ && (SUITE_CONSUMER_IDS as readonly string[]).includes(value);
467
+ }
468
+
469
+ export function isSuiteAccountsRegisteredConsumerId(
470
+ value: unknown,
471
+ ): value is SuiteAccountsRegisteredConsumerId {
472
+ return typeof value === "string"
473
+ && (SUITE_ACCOUNTS_REGISTERED_CONSUMER_IDS as readonly string[])
474
+ .includes(value);
475
+ }
476
+
477
+ export function isSuiteAccountsOidcConsumerId(
478
+ value: SuiteAccountsConsumerId,
479
+ ): value is SuiteAccountsOidcConsumerId {
480
+ return isSuiteAccountsRegisteredConsumerId(value)
481
+ && SUITE_ACCOUNTS_CONSUMERS[value].auth.kind === "oidc-rp";
482
+ }
483
+
484
+ export function isSuiteAccountsLinkedOidcConsumerId(
485
+ value: SuiteAccountsOidcConsumerId,
486
+ ): value is SuiteAccountsLinkedOidcConsumerId {
487
+ return (
488
+ SUITE_ACCOUNTS_LINKED_OIDC_CONSUMER_IDS as readonly string[]
489
+ ).includes(value);
490
+ }
491
+
492
+ export function isSuiteAccountsOAuthConsumerId(
493
+ value: SuiteAccountsConsumerId,
494
+ ): value is SuiteAccountsOAuthConsumerId {
495
+ return isSuiteAccountsRegisteredConsumerId(value)
496
+ && SUITE_ACCOUNTS_CONSUMERS[value].auth.kind === "oidc-rp";
497
+ }
498
+
499
+ export function isSuiteAccountsCurrentConsumerId(
500
+ value: unknown,
501
+ ): value is SuiteAccountsCurrentConsumerId {
502
+ return typeof value === "string"
503
+ && (SUITE_ACCOUNTS_CURRENT_CONSUMER_IDS as readonly string[])
504
+ .includes(value);
505
+ }
506
+
507
+ export function isSuiteAccountsCurrentOidcConsumerId(
508
+ value: SuiteAccountsCurrentConsumerId,
509
+ ): value is SuiteAccountsCurrentOidcConsumerId {
510
+ return getSuiteAccountsCurrentConsumer(value).auth.kind === "oidc-rp";
511
+ }
512
+
513
+ export function isSuiteAccountsCurrentLinkedOidcConsumerId(
514
+ value: SuiteAccountsCurrentOidcConsumerId,
515
+ ): value is SuiteAccountsCurrentLinkedOidcConsumerId {
516
+ return (
517
+ SUITE_ACCOUNTS_CURRENT_LINKED_OIDC_CONSUMER_IDS as readonly string[]
518
+ ).includes(value);
519
+ }
520
+
521
+ export function isSuiteAccountsCurrentOAuthConsumerId(
522
+ value: SuiteAccountsCurrentConsumerId,
523
+ ): value is SuiteAccountsCurrentOAuthConsumerId {
524
+ return getSuiteAccountsCurrentConsumer(value).auth.kind === "oidc-rp";
525
+ }
526
+
527
+ export function isSuiteAccountsCurrentBrowserDeviceCodeConsumerId(
528
+ value: unknown,
529
+ ): value is SuiteAccountsCurrentBrowserDeviceCodeConsumerId {
530
+ return typeof value === "string"
531
+ && (
532
+ SUITE_ACCOUNTS_CURRENT_BROWSER_DEVICE_CODE_CONSUMER_IDS as
533
+ readonly string[]
534
+ ).includes(value);
535
+ }
536
+
537
+ export function isSuiteAccountsCurrentDeviceClientId(
538
+ value: unknown,
539
+ ): value is SuiteAccountsCurrentDeviceClientId {
540
+ return typeof value === "string"
541
+ && (SUITE_ACCOUNTS_CURRENT_DEVICE_CLIENT_IDS as readonly string[])
542
+ .includes(value);
543
+ }
544
+
545
+ export function suiteAccountsCurrentConsumerRequiresEmailOtp(
546
+ consumer: SuiteAccountsCurrentOidcConsumerId,
547
+ ): consumer is SuiteAccountsCurrentEmailOtpRequiredOidcConsumerId {
548
+ return (
549
+ SUITE_ACCOUNTS_CURRENT_EMAIL_OTP_REQUIRED_OIDC_CONSUMER_IDS as
550
+ readonly string[]
551
+ ).includes(consumer);
552
+ }
553
+
554
+ export function getSuiteAccountsConsumer<
555
+ const Consumer extends SuiteAccountsRegisteredConsumerId,
556
+ >(
557
+ consumer: Consumer,
558
+ ): (typeof SUITE_ACCOUNTS_CONSUMERS)[Consumer] {
559
+ return SUITE_ACCOUNTS_CONSUMERS[consumer];
560
+ }
561
+
562
+ export function getSuiteAccountsConsumerEnvironment(
563
+ consumer: unknown,
564
+ environment: SuiteAccountsRemoteEnvironment,
565
+ ): SuiteAccountsConsumerEnvironment | null {
566
+ if (!isSuiteAccountsRegisteredConsumerId(consumer)) return null;
567
+ const registration: SuiteAccountsConsumerRegistration =
568
+ getSuiteAccountsConsumer(consumer);
569
+ return registration.environments[environment] ?? null;
570
+ }
571
+
572
+ export function getSuiteAccountsCurrentConsumer<
573
+ const Consumer extends SuiteAccountsCurrentConsumerId,
574
+ >(
575
+ consumer: Consumer,
576
+ ): (typeof SUITE_ACCOUNTS_CURRENT_CONSUMERS)[Consumer] {
577
+ return SUITE_ACCOUNTS_CURRENT_CONSUMERS[consumer];
578
+ }
579
+
580
+ export function getSuiteAccountsCurrentConsumerEnvironment(
581
+ consumer: unknown,
582
+ environment: SuiteAccountsRemoteEnvironment,
583
+ ): SuiteAccountsConsumerEnvironment | null {
584
+ if (!isSuiteAccountsCurrentConsumerId(consumer)) return null;
585
+ return getSuiteAccountsCurrentConsumer(consumer).environments[environment]
586
+ ?? null;
587
+ }
588
+
589
+ export function isSuiteAccountsActiveConsumerId(
590
+ value: SuiteAccountsConsumerId,
591
+ ): value is SuiteAccountsActiveConsumerId {
592
+ return (SUITE_ACCOUNTS_ACTIVE_CONSUMER_IDS as readonly string[])
593
+ .includes(value);
594
+ }
595
+
596
+ export function getSuiteAccountsDeployment(
597
+ environment: SuiteAccountsRemoteEnvironment,
598
+ ): SuiteAccountsRemoteDeployment {
599
+ return SUITE_ACCOUNTS_DEPLOYMENTS[environment];
600
+ }