@tempoxyz/id 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/server/.vite/manifest.json +65 -65
- package/dist/app/server/assets/Grant-D_tun0mF.js.map +1 -1
- package/dist/app/server/assets/authorize-DXYo-K2n-B-6vqhvc.js +56 -0
- package/dist/app/server/assets/authorize-DXYo-K2n-B-6vqhvc.js.map +1 -0
- package/dist/app/server/assets/core-FSS9-r35.js +56 -0
- package/dist/app/server/assets/core-FSS9-r35.js.map +1 -0
- package/dist/app/server/assets/default-u_dwuiYb-Bby14ucv.js +2 -0
- package/dist/app/server/assets/{default-u_dwuiYb-DOrMMcg9.js.map → default-u_dwuiYb-Bby14ucv.js.map} +1 -1
- package/dist/app/server/assets/{dist-CoH0hD1s.js → dist-B9KiBJYw.js} +2 -2
- package/dist/app/server/assets/{dist-CoH0hD1s.js.map → dist-B9KiBJYw.js.map} +1 -1
- package/dist/app/server/assets/{dist-DcICI3fd.js → dist-CU1NXSiz.js} +2 -2
- package/dist/app/server/assets/{dist-DcICI3fd.js.map → dist-CU1NXSiz.js.map} +1 -1
- package/dist/app/server/assets/dist-CetH4JSY.js +1 -0
- package/dist/app/server/assets/{effect-QlVUlMFu-mXPkuQTb.js → effect-QlVUlMFu-Cm-eTtaO.js} +2 -2
- package/dist/app/server/assets/{effect-QlVUlMFu-mXPkuQTb.js.map → effect-QlVUlMFu-Cm-eTtaO.js.map} +1 -1
- package/dist/app/server/assets/factory-g3i_Ffi5.js +5 -0
- package/dist/app/server/assets/{factory-dvoOlKer.js.map → factory-g3i_Ffi5.js.map} +1 -1
- package/dist/app/server/assets/get-id-field-BpOAoqqI.js +6 -0
- package/dist/app/server/assets/get-id-field-BpOAoqqI.js.map +1 -0
- package/dist/app/server/assets/{index-CLddUTqr-CC33CMvS.js → index-CLddUTqr-CmgkbWi9.js} +2 -2
- package/dist/app/server/assets/{index-CLddUTqr-CC33CMvS.js.map → index-CLddUTqr-CmgkbWi9.js.map} +1 -1
- package/dist/app/server/assets/{index-DZEfthgZ-Ec2MMQ_e.js → index-DZEfthgZ-BnPmps9O.js} +2 -2
- package/dist/app/server/assets/{index-DZEfthgZ-Ec2MMQ_e.js.map → index-DZEfthgZ-BnPmps9O.js.map} +1 -1
- package/dist/app/server/assets/kysely-adapter-B8VoPArC.js +1 -0
- package/dist/app/server/assets/{schema-check-oLqvHR8y.js → schema-check-Bgwl1v0_.js} +2 -2
- package/dist/app/server/assets/{schema-check-oLqvHR8y.js.map → schema-check-Bgwl1v0_.js.map} +1 -1
- package/dist/app/server/assets/{sury-CWZTCd75-CDaOS2oM.js → sury-CWZTCd75-Bd_PzqCV.js} +2 -2
- package/dist/app/server/assets/{sury-CWZTCd75-CDaOS2oM.js.map → sury-CWZTCd75-Bd_PzqCV.js.map} +1 -1
- package/dist/app/server/assets/{valibot--1zFm7rT-CIKoH3MS.js → valibot--1zFm7rT-Dd2aEhWG.js} +2 -2
- package/dist/app/server/assets/{valibot--1zFm7rT-CIKoH3MS.js.map → valibot--1zFm7rT-Dd2aEhWG.js.map} +1 -1
- package/dist/app/server/assets/{valibot-D_HTw1Gn-BdPyLkXt.js → valibot-D_HTw1Gn-C1l3va6F.js} +2 -2
- package/dist/app/server/assets/{valibot-D_HTw1Gn-BdPyLkXt.js.map → valibot-D_HTw1Gn-C1l3va6F.js.map} +1 -1
- package/dist/app/server/assets/{zod-Bwrt9trS-BezI5Gi1.js → zod-Bwrt9trS-Dry2w0in.js} +2 -2
- package/dist/app/server/assets/{zod-Bwrt9trS-BezI5Gi1.js.map → zod-Bwrt9trS-Dry2w0in.js.map} +1 -1
- package/dist/app/server/assets/{zod-DSgpEGAE-DZ7M_Q33.js → zod-DSgpEGAE-BZMP86UA.js} +2 -2
- package/dist/app/server/assets/{zod-DSgpEGAE-DZ7M_Q33.js.map → zod-DSgpEGAE-BZMP86UA.js.map} +1 -1
- package/dist/app/server/index.js +35 -35
- package/dist/app/server/index.js.map +1 -1
- package/dist/client/Auth.d.ts +1 -1
- package/dist/client/Auth.d.ts.map +1 -1
- package/dist/client/Auth.js.map +1 -1
- package/dist/client/Decorator.d.ts +3 -1
- package/dist/client/Decorator.d.ts.map +1 -1
- package/dist/client/Decorator.js +1 -0
- package/dist/client/Decorator.js.map +1 -1
- package/dist/client/actions/passkey.d.ts +63 -2
- package/dist/client/actions/passkey.d.ts.map +1 -1
- package/dist/client/actions/passkey.js +121 -3
- package/dist/client/actions/passkey.js.map +1 -1
- package/dist/internal/Apps.d.ts +14 -0
- package/dist/internal/Apps.d.ts.map +1 -1
- package/dist/internal/Apps.js +14 -2
- package/dist/internal/Apps.js.map +1 -1
- package/dist/internal/Auth.d.ts +7 -0
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +2 -1
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Authorize.d.ts.map +1 -1
- package/dist/internal/Authorize.js +13 -13
- package/dist/internal/Authorize.js.map +1 -1
- package/dist/internal/ErrorResponse.d.ts +5 -0
- package/dist/internal/ErrorResponse.d.ts.map +1 -1
- package/dist/internal/ErrorResponse.js +8 -0
- package/dist/internal/ErrorResponse.js.map +1 -1
- package/dist/internal/KeyAuthorization.d.ts.map +1 -1
- package/dist/internal/KeyAuthorization.js +28 -28
- package/dist/internal/KeyAuthorization.js.map +1 -1
- package/dist/internal/Owner.d.ts +16 -0
- package/dist/internal/Owner.d.ts.map +1 -1
- package/dist/internal/Owner.js.map +1 -1
- package/dist/internal/Passkey.d.ts +66 -4
- package/dist/internal/Passkey.d.ts.map +1 -1
- package/dist/internal/Passkey.js +66 -30
- package/dist/internal/Passkey.js.map +1 -1
- package/dist/internal/Privy.d.ts +27 -0
- package/dist/internal/Privy.d.ts.map +1 -1
- package/dist/internal/Privy.js +82 -0
- package/dist/internal/Privy.js.map +1 -1
- package/dist/internal/TempoAccount.d.ts +57 -0
- package/dist/internal/TempoAccount.d.ts.map +1 -1
- package/dist/internal/TempoAccount.js +118 -5
- package/dist/internal/TempoAccount.js.map +1 -1
- package/dist/internal/owners/Privy.d.ts.map +1 -1
- package/dist/internal/owners/Privy.js +11 -2
- package/dist/internal/owners/Privy.js.map +1 -1
- package/package.json +1 -1
- package/src/api/account.ts +140 -103
- package/src/api/authenticate.ts +48 -51
- package/src/api/authorize.ts +35 -36
- package/src/api/device.ts +20 -23
- package/src/api/health.ts +1 -2
- package/src/api/lib/AccountStep.ts +75 -0
- package/src/api/lib/Auth.ts +6 -0
- package/src/api/lib/Cors.ts +3 -0
- package/src/api/lib/KeySigner.ts +1 -1
- package/src/api/oauth.ts +23 -22
- package/src/client/Auth.ts +1 -0
- package/src/client/Decorator.ts +6 -1
- package/src/client/actions/passkey.ts +197 -3
- package/src/internal/Apps.ts +26 -2
- package/src/internal/Auth.ts +4 -0
- package/src/internal/Authorize.ts +13 -15
- package/src/internal/ErrorResponse.ts +10 -0
- package/src/internal/KeyAuthorization.ts +28 -31
- package/src/internal/OpenApi.ts +35 -0
- package/src/internal/Owner.ts +16 -0
- package/src/internal/Passkey.ts +99 -34
- package/src/internal/Privy.ts +128 -0
- package/src/internal/TempoAccount.ts +221 -7
- package/src/internal/owners/Privy.ts +19 -6
- package/dist/app/server/assets/authorize-DXYo-K2n-rmQQ42x1.js +0 -56
- package/dist/app/server/assets/authorize-DXYo-K2n-rmQQ42x1.js.map +0 -1
- package/dist/app/server/assets/core-BBrZXfrB.js +0 -56
- package/dist/app/server/assets/core-BBrZXfrB.js.map +0 -1
- package/dist/app/server/assets/default-u_dwuiYb-DOrMMcg9.js +0 -2
- package/dist/app/server/assets/dist-CR6FW-yS.js +0 -1
- package/dist/app/server/assets/factory-dvoOlKer.js +0 -5
- package/dist/app/server/assets/get-id-field-OwLpfjj2.js +0 -6
- package/dist/app/server/assets/get-id-field-OwLpfjj2.js.map +0 -1
- package/dist/app/server/assets/kysely-adapter-B8tQwTcu.js +0 -1
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { and, eq, inArray, notExists, sql } from 'drizzle-orm'
|
|
11
11
|
import { createMiddleware } from 'hono/factory'
|
|
12
|
+
import { Address } from 'ox'
|
|
12
13
|
import { AccountConfig } from 'viem/tempo'
|
|
13
14
|
import { z } from 'zod'
|
|
14
15
|
import * as Schema from '../app/db/schema.js'
|
|
15
16
|
import * as ConfigurableAccount from './ConfigurableAccount.js'
|
|
16
17
|
import type { Env } from './Env.js'
|
|
17
18
|
import * as ErrorResponse from './ErrorResponse.js'
|
|
19
|
+
import type * as Log from './Log.js'
|
|
18
20
|
import * as Owner from './Owner.js'
|
|
19
21
|
import * as Passkey from './owners/Passkey.js'
|
|
20
22
|
import * as Privy from './owners/Privy.js'
|
|
@@ -46,6 +48,22 @@ export declare namespace ForeignAccountError {
|
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
/** A kind of owner key did not list within the deadline that {@link addresses} received. */
|
|
52
|
+
export class TimeoutError extends Error {
|
|
53
|
+
override readonly name = 'TempoAccount.TimeoutError'
|
|
54
|
+
|
|
55
|
+
constructor(options: TimeoutError.Options) {
|
|
56
|
+
super(`The owner keys did not list within ${options.timeout} ms.`)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export declare namespace TimeoutError {
|
|
61
|
+
type Options = {
|
|
62
|
+
/** The deadline, in milliseconds. */
|
|
63
|
+
timeout: number
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
49
67
|
/**
|
|
50
68
|
* The kinds of owner keys, in the order that breaks a tie in creation time: a passkey comes before a
|
|
51
69
|
* Privy wallet created in the same second, and a Privy wallet before a secp256k1 key. The first kind
|
|
@@ -105,7 +123,7 @@ export namespace schema {
|
|
|
105
123
|
})
|
|
106
124
|
.meta({
|
|
107
125
|
description:
|
|
108
|
-
'A realm, which holds Tempo Accounts. An app reaches only the accounts
|
|
126
|
+
'A realm, which holds Tempo Accounts. An app reaches only the accounts in its realms.',
|
|
109
127
|
id: 'Realm',
|
|
110
128
|
})
|
|
111
129
|
|
|
@@ -113,8 +131,7 @@ export namespace schema {
|
|
|
113
131
|
export const tempoAccount = z
|
|
114
132
|
.object({
|
|
115
133
|
address: address.meta({
|
|
116
|
-
description:
|
|
117
|
-
"The address on the request's chain: the owner key's address, or the initial configuration's address on a chain with configurable accounts. A linked wallet.tempo passkey keeps its own address, also after its upgrade.",
|
|
134
|
+
description: "The account's address on the request's chain.",
|
|
118
135
|
examples: ['0x8C3b5d0e2A4f6B1c9D7e3F5a0B2c4D6e8F1a3B5c'],
|
|
119
136
|
}),
|
|
120
137
|
config: z
|
|
@@ -125,7 +142,7 @@ export namespace schema {
|
|
|
125
142
|
.optional()
|
|
126
143
|
.meta({
|
|
127
144
|
description:
|
|
128
|
-
'The ID of the chain where the configuration applies
|
|
145
|
+
'The ID of the chain where the configuration applies. Absent if the account is not configurable on the chain.',
|
|
129
146
|
examples: [31318],
|
|
130
147
|
}),
|
|
131
148
|
owners: z
|
|
@@ -138,7 +155,7 @@ export namespace schema {
|
|
|
138
155
|
}),
|
|
139
156
|
type: z.enum(kinds.map((kind) => kind.type)).meta({
|
|
140
157
|
description:
|
|
141
|
-
|
|
158
|
+
"The owner key's holder: a Privy wallet (`privy`), a development key (`secp256k1`), or a passkey (`webAuthn`).",
|
|
142
159
|
examples: ['webAuthn'],
|
|
143
160
|
}),
|
|
144
161
|
weight: z.number().meta({
|
|
@@ -157,8 +174,7 @@ export namespace schema {
|
|
|
157
174
|
examples: [`0x${'0'.repeat(64)}`],
|
|
158
175
|
}),
|
|
159
176
|
threshold: z.number().meta({
|
|
160
|
-
description:
|
|
161
|
-
'The total owner weight that a signature needs to act for the account.',
|
|
177
|
+
description: 'The total owner weight that a signature needs.',
|
|
162
178
|
examples: [1],
|
|
163
179
|
}),
|
|
164
180
|
version: z.templateLiteral(['0x', z.string()]).meta({
|
|
@@ -390,6 +406,163 @@ export namespace list {
|
|
|
390
406
|
export const errors = create.errors
|
|
391
407
|
}
|
|
392
408
|
|
|
409
|
+
/**
|
|
410
|
+
* Returns every address of the user's Tempo Accounts in `realms`, de-duplicated and in no meaningful
|
|
411
|
+
* order: each account's address on a chain whose accounts are not configurable, and its address on
|
|
412
|
+
* each chain that `CONFIGURABLE_ACCOUNTS` names. It creates no account. Each kind lists on its own,
|
|
413
|
+
* so a kind that reads an upstream service and fails, such as Privy during an outage, leaves out its
|
|
414
|
+
* addresses and returns its error in `errors` instead of throwing. A failure of the database throws.
|
|
415
|
+
*/
|
|
416
|
+
export async function addresses(
|
|
417
|
+
c: Context,
|
|
418
|
+
options: addresses.Options,
|
|
419
|
+
): Promise<addresses.ReturnType> {
|
|
420
|
+
const {
|
|
421
|
+
db,
|
|
422
|
+
env,
|
|
423
|
+
maxAge,
|
|
424
|
+
timeout,
|
|
425
|
+
upstream = true,
|
|
426
|
+
userId,
|
|
427
|
+
waitUntil,
|
|
428
|
+
warn,
|
|
429
|
+
} = options
|
|
430
|
+
|
|
431
|
+
// A request that already listed the user's keys in these realms, such as a headless sign-in, reads
|
|
432
|
+
// them again from its lists. A failed list fails as a whole, so each kind lists again below, and a
|
|
433
|
+
// failure of the database throws there. A list that misses the deadline already spent the upstream
|
|
434
|
+
// kinds' time, so the upstream kinds list no more.
|
|
435
|
+
const listed = await (async () => {
|
|
436
|
+
const reading = c.var.ownerLists?.get(listKey(options))
|
|
437
|
+
if (!reading) return undefined
|
|
438
|
+
try {
|
|
439
|
+
const lists = await Timing.measure(
|
|
440
|
+
c,
|
|
441
|
+
within(reading, { timeout, waitUntil }),
|
|
442
|
+
'TempoAccount.owners',
|
|
443
|
+
)
|
|
444
|
+
return { lists }
|
|
445
|
+
} catch (error) {
|
|
446
|
+
if (error instanceof TimeoutError) return { error }
|
|
447
|
+
return undefined
|
|
448
|
+
}
|
|
449
|
+
})()
|
|
450
|
+
const errors: unknown[] = listed && 'error' in listed ? [listed.error] : []
|
|
451
|
+
const remoteAllowed = upstream && errors.length === 0
|
|
452
|
+
const lists =
|
|
453
|
+
(listed && 'lists' in listed ? listed.lists : undefined) ??
|
|
454
|
+
(await Promise.all(
|
|
455
|
+
kinds.map(async (kind): Promise<readonly Owner.Owner<Type>[]> => {
|
|
456
|
+
// Only a kind that reads an upstream service, such as Privy, declares refusals. The deadline
|
|
457
|
+
// applies to that kind alone, so a slow database leaves out no key that it holds.
|
|
458
|
+
const remote = kind.errors.length > 0
|
|
459
|
+
if (remote && !remoteAllowed) return []
|
|
460
|
+
// `load` reads only the database, such as a realm's Privy app, so its failure fails the call,
|
|
461
|
+
// as any other read of the database does.
|
|
462
|
+
const loaded = await Timing.measure(
|
|
463
|
+
c,
|
|
464
|
+
kind.load(c, options),
|
|
465
|
+
'TempoAccount.load',
|
|
466
|
+
)
|
|
467
|
+
try {
|
|
468
|
+
return await Timing.measure(
|
|
469
|
+
c,
|
|
470
|
+
within<readonly Owner.Owner<Type>[]>(
|
|
471
|
+
loaded.list(c, { db, maxAge, waitUntil, warn }),
|
|
472
|
+
{ timeout: remote ? timeout : undefined, waitUntil },
|
|
473
|
+
),
|
|
474
|
+
'TempoAccount.owners',
|
|
475
|
+
)
|
|
476
|
+
} catch (error) {
|
|
477
|
+
if (!remote) throw error
|
|
478
|
+
errors.push(error)
|
|
479
|
+
return []
|
|
480
|
+
}
|
|
481
|
+
}),
|
|
482
|
+
))
|
|
483
|
+
const merged = Owner.merge(lists)
|
|
484
|
+
|
|
485
|
+
const chains = ConfigurableAccount.chains({
|
|
486
|
+
rpcUrl: env.TEMPO_RPC_URL,
|
|
487
|
+
rpcUrls: env.RPC_URLS,
|
|
488
|
+
value: env.CONFIGURABLE_ACCOUNTS,
|
|
489
|
+
})
|
|
490
|
+
const views = await Promise.all(
|
|
491
|
+
chains.map(async (chain) => {
|
|
492
|
+
const configs = await Timing.measure(
|
|
493
|
+
c,
|
|
494
|
+
ConfigurableAccount.list(db, { chainId: chain.chainId, userId }),
|
|
495
|
+
'db.accountConfig.list',
|
|
496
|
+
)
|
|
497
|
+
const applied = ConfigurableAccount.apply(merged, {
|
|
498
|
+
chainId: chain.chainId,
|
|
499
|
+
configs,
|
|
500
|
+
})
|
|
501
|
+
// `apply` lists a configuration through its key's owner, which a kind that failed leaves out.
|
|
502
|
+
// A configuration that names a listed key among its owners is the user's through that key.
|
|
503
|
+
const owned = configs.filter((config) =>
|
|
504
|
+
config.owners.some((member) =>
|
|
505
|
+
merged.some((entry) =>
|
|
506
|
+
Address.isEqual(Owner.key(entry), member.address),
|
|
507
|
+
),
|
|
508
|
+
),
|
|
509
|
+
)
|
|
510
|
+
return [
|
|
511
|
+
...applied.map((owner) => Owner.address(owner)),
|
|
512
|
+
...owned.map((config) => config.address),
|
|
513
|
+
]
|
|
514
|
+
}),
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
const unique = new Map<string, Address.Address>()
|
|
518
|
+
for (const entry of [
|
|
519
|
+
...merged.map((owner) => Owner.address(owner)),
|
|
520
|
+
...views.flat(),
|
|
521
|
+
]) {
|
|
522
|
+
const address = Address.checksum(entry)
|
|
523
|
+
unique.set(address.toLowerCase(), address)
|
|
524
|
+
}
|
|
525
|
+
return { addresses: [...unique.values()], errors }
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export declare namespace addresses {
|
|
529
|
+
type Options = Omit<list.Options, 'chainId'> & {
|
|
530
|
+
/**
|
|
531
|
+
* How old, in seconds, a cached read of an upstream service, such as Privy's wallets, may be.
|
|
532
|
+
* Absent, each kind reads its upstream service.
|
|
533
|
+
*/
|
|
534
|
+
maxAge?: number | undefined
|
|
535
|
+
/**
|
|
536
|
+
* How long each kind that reads an upstream service, such as Privy, may list, in milliseconds.
|
|
537
|
+
* Such a kind that takes longer leaves out its addresses, and returns a {@link TimeoutError} in
|
|
538
|
+
* `errors`. The kinds that read only the database have no deadline. Absent, no deadline applies.
|
|
539
|
+
*/
|
|
540
|
+
timeout?: number | undefined
|
|
541
|
+
/**
|
|
542
|
+
* Whether the kinds that read an upstream service, such as Privy, list. Defaults to `true`.
|
|
543
|
+
* `false` leaves out their addresses without an error.
|
|
544
|
+
*/
|
|
545
|
+
upstream?: boolean | undefined
|
|
546
|
+
/**
|
|
547
|
+
* Keeps a read that missed `timeout` alive after the response, such as
|
|
548
|
+
* `c.executionCtx.waitUntil`, so it still fills its cache. Absent, the runtime may end it.
|
|
549
|
+
*/
|
|
550
|
+
waitUntil?: ((promise: Promise<unknown>) => void) | undefined
|
|
551
|
+
/**
|
|
552
|
+
* Logs a recoverable problem with the request's details, such as a failure of the cache of
|
|
553
|
+
* Privy's wallets. Absent, the kinds log without them.
|
|
554
|
+
*/
|
|
555
|
+
warn?: ((options: Log.Options) => void) | undefined
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
type ReturnType = {
|
|
559
|
+
/** The addresses, checksummed, each once. */
|
|
560
|
+
addresses: readonly Address.Address[]
|
|
561
|
+
/** The failures of the kinds whose addresses are left out. Empty when every kind listed. */
|
|
562
|
+
errors: readonly unknown[]
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
393
566
|
/**
|
|
394
567
|
* Empties the owner keys that the request listed. Call it after a write that changes a user's owner
|
|
395
568
|
* keys outside {@link create}, such as a passkey's link or registration, so a later list in the same
|
|
@@ -543,3 +716,44 @@ export function serialize(owner: Owner.Owner): TempoAccount {
|
|
|
543
716
|
realm: { id: owner.realm.id, name: owner.realm.name },
|
|
544
717
|
})
|
|
545
718
|
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Returns the value of `promise`, or rejects with a {@link TimeoutError} once `timeout` milliseconds
|
|
722
|
+
* pass. Without `timeout`, it waits for `promise`.
|
|
723
|
+
*/
|
|
724
|
+
async function within<value>(
|
|
725
|
+
promise: Promise<value>,
|
|
726
|
+
options: within.Options,
|
|
727
|
+
): Promise<value> {
|
|
728
|
+
const { timeout, waitUntil } = options
|
|
729
|
+
if (timeout === undefined) return await promise
|
|
730
|
+
|
|
731
|
+
// A read that rejects after the deadline has no caller left, so its rejection is dropped.
|
|
732
|
+
const settled = promise.then(
|
|
733
|
+
() => undefined,
|
|
734
|
+
() => undefined,
|
|
735
|
+
)
|
|
736
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
737
|
+
const expired = new Promise<never>((_, reject) => {
|
|
738
|
+
timer = setTimeout(() => {
|
|
739
|
+
// The read continues past the response, so a late answer still fills its cache, such as the
|
|
740
|
+
// Privy wallets that the next grant reads.
|
|
741
|
+
waitUntil?.(settled)
|
|
742
|
+
reject(new TimeoutError({ timeout }))
|
|
743
|
+
}, timeout)
|
|
744
|
+
})
|
|
745
|
+
try {
|
|
746
|
+
return await Promise.race([promise, expired])
|
|
747
|
+
} finally {
|
|
748
|
+
clearTimeout(timer)
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
declare namespace within {
|
|
753
|
+
type Options = {
|
|
754
|
+
/** The deadline, in milliseconds. Absent, none applies. */
|
|
755
|
+
timeout?: number | undefined
|
|
756
|
+
/** Keeps the read alive after the response when the deadline passes. Absent, the runtime may end it. */
|
|
757
|
+
waitUntil?: ((promise: Promise<unknown>) => void) | undefined
|
|
758
|
+
}
|
|
759
|
+
}
|
|
@@ -61,16 +61,29 @@ export const owner = Owner.kind({
|
|
|
61
61
|
return toOwner(app, realm, wallet)
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
|
-
async list(c) {
|
|
64
|
+
async list(c, listOptions) {
|
|
65
|
+
const { maxAge, waitUntil, warn } = listOptions
|
|
65
66
|
const lists = await Promise.all(
|
|
66
67
|
realms.map(async (realm) => {
|
|
67
68
|
const app = apps.get(realm.id)
|
|
68
69
|
if (!app) return []
|
|
69
|
-
const wallets = await
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
const wallets = await (maxAge === undefined
|
|
71
|
+
? Timing.measure(
|
|
72
|
+
c,
|
|
73
|
+
Privy.listWallets(c, { app, userId }),
|
|
74
|
+
'Privy.listWallets',
|
|
75
|
+
)
|
|
76
|
+
: Timing.measure(
|
|
77
|
+
c,
|
|
78
|
+
Privy.cachedWallets(c, {
|
|
79
|
+
app,
|
|
80
|
+
maxAge,
|
|
81
|
+
userId,
|
|
82
|
+
waitUntil,
|
|
83
|
+
warn,
|
|
84
|
+
}),
|
|
85
|
+
'Privy.cachedWallets',
|
|
86
|
+
))
|
|
74
87
|
return wallets.map((wallet) => toOwner(app, realm, wallet))
|
|
75
88
|
}),
|
|
76
89
|
)
|