diff --git a/package.json b/package.json index b8d32dd1c..5e9807050 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "prettier": "2.7.1", "simple-git-hooks": "^2.8.1", "typescript": "^4.8.4", - "wrangler": "^2.1.12" + "wrangler": "^2.1.13" }, "simple-git-hooks": { "pre-commit": "npx lint-staged" diff --git a/packages/access-api/package.json b/packages/access-api/package.json index 598bb81b5..6dadf27e5 100644 --- a/packages/access-api/package.json +++ b/packages/access-api/package.json @@ -9,7 +9,7 @@ "scripts": { "lint": "tsc --build && eslint '**/*.{js,ts}' && prettier --check '**/*.{js,ts,yml,json}' --ignore-path ../../.gitignore", "deploy": "wrangler publish", - "dev": "miniflare --modules --watch --debug --wrangler-env dev --env ../../.env", + "dev": "scripts/cli.js dev", "build": "scripts/cli.js build", "check": "tsc --build", "test": "tsc --build && ava --timeout 10s" @@ -30,23 +30,29 @@ "multiformats": "^9.8.1", "nanoid": "^4.0.0", "p-retry": "^5.1.1", + "preact": "^10.11.2", + "preact-render-to-string": "^5.2.6", + "qrcode": "^1.5.1", "toucan-js": "^2.7.0", "workers-qb": "^0.1.2" }, "devDependencies": { - "@cloudflare/workers-types": "^3.16.0", - "@sentry/cli": "^2.7.0", + "@cloudflare/workers-types": "^3.18.0", + "@databases/escape-identifier": "^1.0.3", + "@databases/sql": "^3.2.0", + "@sentry/cli": "^2.8.0", "@sentry/webpack-plugin": "^1.19.1", "@types/assert": "^1.5.6", "@types/git-rev-sync": "^2.0.0", - "@types/node": "^18.11.0", + "@types/node": "^18.11.7", + "@types/qrcode": "^1.5.0", "assert": "^2.0.0", - "ava": "^4.3.3", + "ava": "^5.0.1", "better-sqlite3": "7.6.2", "buffer": "^6.0.3", "delay": "^5.0.0", "dotenv": "^16.0.3", - "esbuild": "^0.15.10", + "esbuild": "^0.15.12", "execa": "^6.1.0", "git-rev-sync": "^3.0.1", "hd-scripts": "^3.0.2", @@ -55,7 +61,7 @@ "readable-stream": "^4.1.0", "sade": "^1.7.4", "typescript": "4.8.4", - "wrangler": "^2.1.12" + "wrangler": "^2.1.13" }, "eslintConfig": { "extends": [ @@ -74,6 +80,9 @@ "BUCKET": "writable", "W3ACCESS_METRICS": "writable", "WebSocketPair": "readonly" + }, + "rules": { + "unicorn/prefer-number-properties": "off" } }, "eslintIgnore": [ @@ -84,6 +93,8 @@ ], "ava": { "failFast": true, + "concurrency": 1, + "workerThreads": false, "files": [ "test/**/*.test.js" ], @@ -92,7 +103,8 @@ "--experimental-vm-modules" ], "ignoredByWatcher": [ - "./dist/*" + "./dist/*", + "./wrangler/**" ] } } diff --git a/packages/access-api/scripts/cli.js b/packages/access-api/scripts/cli.js index 80ac643b7..a6e0c429c 100755 --- a/packages/access-api/scripts/cli.js +++ b/packages/access-api/scripts/cli.js @@ -1,4 +1,4 @@ -#!/usr/bin/env node +#!/usr/bin/env -S node --experimental-vm-modules --no-warnings /* eslint-disable no-console */ import path from 'path' import dotenv from 'dotenv' @@ -8,8 +8,11 @@ import { fileURLToPath } from 'url' import { build } from 'esbuild' import Sentry from '@sentry/cli' import { createRequire } from 'module' +import { Miniflare } from 'miniflare' + // @ts-ignore import git from 'git-rev-sync' +import { migrate } from '../sql/migrate.js' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const require = createRequire(__dirname) @@ -65,6 +68,9 @@ prog }, minify: opts.env !== 'dev', sourcemap: true, + jsxImportSource: 'preact', + jsx: 'automatic', + loader: { '.js': 'jsx' }, }) // Sentry release and sourcemap upload @@ -98,4 +104,22 @@ prog } }) +prog + .command('dev') + .describe('Start dev server.') + .action(async () => { + const mf = new Miniflare({ + packagePath: true, + wranglerConfigPath: true, + wranglerConfigEnv: 'dev', + sourceMap: true, + modules: true, + watch: true, + envPath: path.resolve(__dirname, '../../../.env'), + }) + + const binds = await mf.getBindings() + const db = /** @type {D1Database} */ (binds.__D1_BETA__) + await migrate(db) + }) prog.parse(process.argv) diff --git a/packages/access-api/sql/migrate.js b/packages/access-api/sql/migrate.js new file mode 100644 index 000000000..345775097 --- /dev/null +++ b/packages/access-api/sql/migrate.js @@ -0,0 +1,37 @@ +import { escapeSQLiteIdentifier } from '@databases/escape-identifier' +import sql from '@databases/sql' +import path from 'path' +import { fileURLToPath } from 'url' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +/** @type {import('@databases/sql').FormatConfig} */ +const sqliteFormat = { + escapeIdentifier: (str) => escapeSQLiteIdentifier(str), + formatValue: (value) => ({ placeholder: '?', value }), +} + +const migrations = [sql.file(`${__dirname}/tables.sql`)] + +/** + * Probably should batch queries and use https://www.atdatabases.org/docs/split-sql-query to split inlined queries + * + * @see https://docs.google.com/document/d/1QpUryGBWaGbAIjkw2URwpV6Btp5S-XQVkBJJs85dLRc/edit# + * + * @param {D1Database} db + */ +export async function migrate(db) { + try { + for (const m of migrations) { + await db.exec(m.format(sqliteFormat).text.replace(/\n/g, '')) + } + } catch (error) { + const err = /** @type {Error} */ (error) + // eslint-disable-next-line no-console + console.log({ + message: err.message, + // @ts-ignore + cause: err.cause?.message, + }) + } +} diff --git a/packages/access-api/sql/reset.sql b/packages/access-api/sql/reset.sql new file mode 100644 index 000000000..7e74df081 --- /dev/null +++ b/packages/access-api/sql/reset.sql @@ -0,0 +1,2 @@ +DROP TABLE + IF EXISTS accounts; \ No newline at end of file diff --git a/packages/access-api/sql/tables.sql b/packages/access-api/sql/tables.sql index 74d537b0a..7b1ba2512 100644 --- a/packages/access-api/sql/tables.sql +++ b/packages/access-api/sql/tables.sql @@ -1,11 +1,10 @@ -DROP TABLE IF EXISTS accounts; - -CREATE TABLE accounts ( - did TEXT NOT NULL PRIMARY KEY - , product TEXT NOT NULL - , email TEXT NOT NULL - , agent TEXT NOT NULL - , inserted_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) - , updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) - , UNIQUE(did) -) \ No newline at end of file +CREATE TABLE + IF NOT EXISTS accounts ( + did TEXT NOT NULL PRIMARY KEY, + product TEXT NOT NULL, + email TEXT NOT NULL, + agent TEXT NOT NULL, + inserted_at TEXT NOT NULL DEFAULT (strftime ('%Y-%m-%dT%H:%M:%fZ', 'now')), + updated_at TEXT NOT NULL DEFAULT (strftime ('%Y-%m-%dT%H:%M:%fZ', 'now')), + UNIQUE (did) + ) \ No newline at end of file diff --git a/packages/access-api/src/bindings.d.ts b/packages/access-api/src/bindings.d.ts index 0df8b2568..f4a7781be 100644 --- a/packages/access-api/src/bindings.d.ts +++ b/packages/access-api/src/bindings.d.ts @@ -1,11 +1,11 @@ import type { Logging } from '@web3-storage/worker-utils/logging' import type { Handler as _Handler } from '@web3-storage/worker-utils/router' -import type { SigningPrincipal } from '@ucanto/interface' -import type { config } from './config' +import type { Signer } from '@ucanto/interface' import { Email } from './utils/email.js' import { Accounts } from './kvs/accounts.js' import { Validations } from './kvs/validations.js' import { D1QB } from 'workers-qb' +import { loadConfig } from './config.js' export {} @@ -38,8 +38,8 @@ export interface Env { export interface RouteContext { log: Logging - keypair: SigningPrincipal - config: typeof config + signer: Signer + config: ReturnType url: URL email: Email kvs: { diff --git a/packages/access-api/src/index.js b/packages/access-api/src/index.js index 2eb617e6a..b67819f83 100644 --- a/packages/access-api/src/index.js +++ b/packages/access-api/src/index.js @@ -6,7 +6,6 @@ import { postRaw } from './routes/raw.js' import { postRoot } from './routes/root.js' import { validateEmail } from './routes/validate-email.js' import { validateWS } from './routes/validate-ws.js' -import { validate } from './routes/validate.js' import { version } from './routes/version.js' import { getContext } from './utils/context.js' @@ -15,7 +14,6 @@ const r = new Router({ onNotFound: notFound }) r.add('options', '*', preflight) r.add('get', '/version', version) -r.add('get', '/validate', validate) r.add('get', '/validate-email', validateEmail) r.add('get', '/validate-ws', validateWS) r.add('post', '/', postRoot) diff --git a/packages/access-api/src/kvs/accounts.js b/packages/access-api/src/kvs/accounts.js index ae402407f..bf2c47020 100644 --- a/packages/access-api/src/kvs/accounts.js +++ b/packages/access-api/src/kvs/accounts.js @@ -1,5 +1,11 @@ +// @ts-ignore +// eslint-disable-next-line no-unused-vars +import * as Ucanto from '@ucanto/interface' +import { delegationToString } from '@web3-storage/access/encoding' + /** * @typedef {{account: string, proof: string}} AccountValue + * @typedef {import('@web3-storage/access/types').Account} Account */ /** @@ -9,45 +15,85 @@ export class Accounts { /** * * @param {KVNamespace} kv + * @param {import('workers-qb').D1QB} db */ - constructor(kv) { + constructor(kv, db) { this.kv = kv + this.db = db } /** - * - * @param {string} issuerDID - * @param {string} resourceDID - * @param {import('@ucanto/interface').Link} proof + * @param {import('@web3-storage/access/capabilities/types').VoucherRedeem} capability + * @param {Ucanto.Invocation} invocation */ - async register(issuerDID, resourceDID, proof) { - const did = await this.get(issuerDID) - if (did) { - throw new Error(`did: ${issuerDID} already registered.`) - } - const account = `did:ipld:${proof}` - await this.kv.put( - issuerDID, - JSON.stringify({ account, proof: proof.toString() }) - ) - await this.kv.put( - resourceDID, - JSON.stringify({ account, proof: proof.toString() }) - ) + async create(capability, invocation) { + await this.db.insert({ + tableName: 'accounts', + data: { + did: capability.nb.account, + product: capability.nb.product, + email: capability.nb.identity.replace('mailto:', ''), + agent: invocation.issuer.did(), + }, + }) } /** + * Get account by DID + * * @param {string} did */ async get(did) { - const value = /** @type {AccountValue} */ ( - await this.kv.get(did, { + const { results } = await this.db.fetchOne({ + tableName: 'accounts', + fields: '*', + where: { + conditions: 'did =?1', + params: [did], + }, + }) + + if (!results) { + return + } + + return /** @type {Account} */ ({ + did: results.did, + agent: results.agent, + email: results.email, + product: results.product, + updated_at: results.update_at, + inserted_at: results.inserted_at, + }) + } + + /** + * @param {string} email + * @param {Ucanto.Delegation} delegation + */ + async saveAccount(email, delegation) { + const accs = /** @type {string[] | undefined} */ ( + await this.kv.get(email, { type: 'json', }) ) - if (value) { - return value + if (accs) { + accs.push(await delegationToString(delegation)) + await this.kv.put(email, JSON.stringify(accs)) + } else { + await this.kv.put( + email, + JSON.stringify([await delegationToString(delegation)]) + ) } } + + /** + * @param {string} email + */ + async hasAccounts(email) { + const r = await this.kv.get(email) + return Boolean(r) + } } diff --git a/packages/access-api/src/kvs/validations.js b/packages/access-api/src/kvs/validations.js index b6fc4bf40..e9a9d7757 100644 --- a/packages/access-api/src/kvs/validations.js +++ b/packages/access-api/src/kvs/validations.js @@ -1,4 +1,4 @@ -import * as UCAN from '@ipld/dag-ucan' +import { stringToDelegation } from '@web3-storage/access/encoding' /** * Validations @@ -13,17 +13,19 @@ export class Validations { } /** - * - * @param {string} delegation + * @param {string} ucan */ - async create(delegation) { - // @ts-ignore - const ucan = UCAN.parse(delegation) - await this.kv.put(ucan.audience.did(), delegation, { - expirationTtl: 20 * 60, + async put(ucan) { + const delegation = + /** @type {import('@ucanto/interface').Delegation<[import('@web3-storage/access/capabilities/types').VoucherClaim]>} */ ( + await stringToDelegation(ucan) + ) + + await this.kv.put(delegation.audience.did(), ucan, { + expiration: delegation.expiration, }) - return ucan + return delegation } /** diff --git a/packages/access-api/src/routes/raw.js b/packages/access-api/src/routes/raw.js index 648dc903a..081cee104 100644 --- a/packages/access-api/src/routes/raw.js +++ b/packages/access-api/src/routes/raw.js @@ -8,7 +8,7 @@ import { service } from '../service/index.js' */ export async function postRaw(request, env) { const server = Server.create({ - id: env.keypair, + id: env.signer, encoder: serverCodec, decoder: serverCodec, service: service(env), diff --git a/packages/access-api/src/routes/root.js b/packages/access-api/src/routes/root.js index 5b96d0e07..95a8deedc 100644 --- a/packages/access-api/src/routes/root.js +++ b/packages/access-api/src/routes/root.js @@ -9,7 +9,7 @@ import { service } from '../service/index.js' */ export async function postRoot(request, env) { const server = Server.create({ - id: env.keypair, + id: env.signer, encoder: CBOR, decoder: CAR, service: service(env), diff --git a/packages/access-api/src/routes/validate-email.js b/packages/access-api/src/routes/validate-email.js index f877fc5a5..e0d826688 100644 --- a/packages/access-api/src/routes/validate-email.js +++ b/packages/access-api/src/routes/validate-email.js @@ -1,15 +1,50 @@ +/* eslint-disable no-unused-vars */ +import QRCode from 'qrcode' +import { + HtmlResponse, + ValidateEmail, + ValidateEmailError, +} from '../utils/html.js' + /** * @param {import('@web3-storage/worker-utils/router').ParsedRequest} req * @param {import('../bindings.js').RouteContext} env */ export async function validateEmail(req, env) { - if (req.query && req.query.ucan && req.query.did) { - // TODO parse and set KV ttl to delegation ttl + if (req.query && req.query.ucan) { + try { + const delegation = await env.kvs.validations.put(req.query.ucan) + + return new HtmlResponse( + ( + + ) + ) + } catch (error) { + const err = /** @type {Error} */ (error) - await env.config.VALIDATIONS.put(req.query.did, req.query.ucan) + if (err.message.includes('Invalid expiration')) { + return new HtmlResponse( + + ) + } - return new Response('Done') + env.log.error(err) + return new HtmlResponse( + + ) + } } - throw new Error('needs ucan or did query') + return new HtmlResponse( + + ) } diff --git a/packages/access-api/src/routes/validate-ws.js b/packages/access-api/src/routes/validate-ws.js index 739145de8..031d620a5 100644 --- a/packages/access-api/src/routes/validate-ws.js +++ b/packages/access-api/src/routes/validate-ws.js @@ -1,25 +1,21 @@ import pRetry from 'p-retry' const run = async ( - /** @type {KVNamespace} */ kv, + /** @type {import('../kvs/validations').Validations} */ kv, /** @type {WebSocket} */ server, /** @type {any} */ did ) => { const d = await kv.get(did) - if (!d) { - throw new Error('Not found.') - } else { - server.send( - JSON.stringify({ - type: 'delegation', - delegation: d, - }) - ) - server.close() - await kv.delete(did) - return d - } + server.send( + JSON.stringify({ + type: 'delegation', + delegation: d, + }) + ) + server.close() + await kv.delete(did) + return d } /** @@ -33,13 +29,14 @@ export async function validateWS(req, env) { } const [client, server] = Object.values(new WebSocketPair()) + // @ts-ignore server.accept() server.addEventListener('message', async (msg) => { // @ts-ignore const { did } = JSON.parse(msg.data) try { - await pRetry(() => run(env.config.VALIDATIONS, server, did), { + await pRetry(() => run(env.kvs.validations, server, did), { retries: 200, minTimeout: 1000, factor: 1, diff --git a/packages/access-api/src/routes/validate.js b/packages/access-api/src/routes/validate.js deleted file mode 100644 index 5afb27b7e..000000000 --- a/packages/access-api/src/routes/validate.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @param {import('@web3-storage/worker-utils/router').ParsedRequest} req - * @param {import('../bindings.js').RouteContext} env - */ -export async function validate(req, env) { - const validations = env.kvs.validations - if (req.query && req.query.ucan) { - await validations.create(req.query.ucan) - - return new Response('Success', { - status: 307, - headers: { location: 'https://web3.storage/' }, - }) - } - - if (req.query && req.query.did) { - const ucan = await validations.get(req.query.did) - await validations.delete(req.query.did) - return new Response(ucan) - } - - throw new Error('needs ucan or did query') -} diff --git a/packages/access-api/src/routes/version.js b/packages/access-api/src/routes/version.js index d71763506..015f0223a 100644 --- a/packages/access-api/src/routes/version.js +++ b/packages/access-api/src/routes/version.js @@ -6,6 +6,6 @@ export async function version(event, env, ctx) { version: env.config.VERSION, commit: env.config.COMMITHASH, branch: env.config.BRANCH, - did: env.keypair.did(), + did: env.signer.did(), }) } diff --git a/packages/access-api/src/service/identity-register.js b/packages/access-api/src/service/identity-register.js deleted file mode 100644 index fae683e2a..000000000 --- a/packages/access-api/src/service/identity-register.js +++ /dev/null @@ -1,33 +0,0 @@ -import * as Server from '@ucanto/server' -import * as Identity from '@web3-storage/access/capabilities/identity' - -/** - * @param {import('../bindings').RouteContext} ctx - */ -export function identityRegisterProvider(ctx) { - return Server.provide( - Identity.register, - async ({ capability, context, invocation }) => { - await ctx.kvs.accounts.register( - capability.nb.as, - capability.with, - invocation.cid - ) - - ctx.config.METRICS.writeDataPoint({ - blobs: [ctx.config.ENV, 'new_account'], - doubles: [1], - }) - - if (ctx.config.ENV === 'production') { - ctx.email.send({ - to: 'david@dag.house,jchris@dag.house', - subject: 'New w3account Created', - textBody: `New account registered for ${ - capability.nb.as - } with email ${capability.with.replace('mailto:', '')}`, - }) - } - } - ) -} diff --git a/packages/access-api/src/service/identity-validate.js b/packages/access-api/src/service/identity-validate.js deleted file mode 100644 index 344a4bd93..000000000 --- a/packages/access-api/src/service/identity-validate.js +++ /dev/null @@ -1,42 +0,0 @@ -import { UCAN } from '@ucanto/core' -import * as Server from '@ucanto/server' -import { Verifier } from '@ucanto/principal/ed25519' -import * as Identity from '@web3-storage/access/capabilities/identity' - -/** - * @param {import('../bindings').RouteContext} ctx - */ -export function identityValidateProvider(ctx) { - return Server.provide( - Identity.validate, - async ({ capability, context, invocation }) => { - const delegation = await Identity.register - .invoke({ - audience: Verifier.parse(invocation.issuer.did()), - issuer: ctx.keypair, - with: capability.nb.as, - nb: { - as: capability.with, - }, - lifetimeInSeconds: 300, - }) - .delegate() - - const url = `${ctx.url.protocol}//${ - ctx.url.host - }/validate?ucan=${UCAN.format(delegation.data)}` - - // For testing - if (ctx.config.ENV === 'test') { - return { - delegation: url, - } - } - - await ctx.email.sendValidation({ - to: capability.nb.as.replace('mailto:', ''), - url, - }) - } - ) -} diff --git a/packages/access-api/src/service/index.js b/packages/access-api/src/service/index.js index 10111afe3..b9eabcdf3 100644 --- a/packages/access-api/src/service/index.js +++ b/packages/access-api/src/service/index.js @@ -1,11 +1,10 @@ import * as Server from '@ucanto/server' -import * as Identity from '@web3-storage/access/capabilities/identity' +import { Failure } from '@ucanto/server' import * as Account from '@web3-storage/access/capabilities/account' -import { identityRegisterProvider } from './identity-register.js' -import { identityValidateProvider } from './identity-validate.js' import { voucherClaimProvider } from './voucher-claim.js' import { voucherRedeemProvider } from './voucher-redeem.js' -import { Failure } from '@ucanto/server' +import * as DID from '@ipld/dag-ucan/did' +import { delegationToString } from '@web3-storage/access/encoding' /** * @param {import('../bindings').RouteContext} ctx @@ -13,46 +12,58 @@ import { Failure } from '@ucanto/server' */ export function service(ctx) { return { - identity: { - validate: identityValidateProvider(ctx), - register: identityRegisterProvider(ctx), - identify: Server.provide(Identity.identify, async ({ capability }) => { - const result = await ctx.kvs.accounts.get(capability.with) - return result?.account - }), - }, voucher: { claim: voucherClaimProvider(ctx), redeem: voucherRedeemProvider(ctx), }, account: { - // @ts-expect-error - types from query dont match handler output info: Server.provide(Account.info, async ({ capability }) => { - const { results } = await ctx.db.fetchOne({ - tableName: 'accounts', - fields: '*', - where: { - conditions: 'did =?1', - params: [capability.with], - }, - }) - + const results = await ctx.kvs.accounts.get(capability.with) if (!results) { throw new Failure('Account not found...') } - return { - did: results.did, - agent: results.agent, - email: results.email, - product: results.product, - updated_at: results.update_at, - inserted_at: results.inserted_at, - } + return results }), - // all: Server.provide(Account.all, async ({ capability }) => { - // return capability - // }), + + 'recover-validation': Server.provide( + Account.recoverValidation, + async ({ capability }) => { + // check if we have delegations in the KV for the email + // if yes send email with account/login + // if not error "no accounts for email X" + + const email = capability.nb.email + if (!(await ctx.kvs.accounts.hasAccounts(email))) { + throw new Failure( + `No accounts found for email: ${email.replace('mailto:', '')}.` + ) + } + + const inv = await Account.recover + .invoke({ + issuer: ctx.signer, + audience: DID.parse(capability.with), + with: ctx.signer.did(), + lifetimeInSeconds: 60 * 10, + proofs: [ + await Account.recover.delegate({ + audience: ctx.signer, + issuer: ctx.signer, + lifetimeInSeconds: 60 * 1000, + with: ctx.signer.did(), + }), + ], + }) + .delegate() + + const encoded = await delegationToString(inv) + // For testing + if (ctx.config.ENV === 'test') { + return encoded + } + } + ), }, // @ts-ignore testing: { diff --git a/packages/access-api/src/service/voucher-claim.js b/packages/access-api/src/service/voucher-claim.js index f15754ef9..395c99e5c 100644 --- a/packages/access-api/src/service/voucher-claim.js +++ b/packages/access-api/src/service/voucher-claim.js @@ -7,25 +7,23 @@ import { delegationToString } from '@web3-storage/access/encoding' */ export function voucherClaimProvider(ctx) { return Server.provide(Voucher.claim, async ({ capability, invocation }) => { - const proof = await Voucher.redeem - .invoke({ - audience: ctx.keypair, - issuer: ctx.keypair, - lifetimeInSeconds: 60 * 1000, - with: ctx.keypair.did(), - nb: { - product: 'product:*', - identity: 'mailto:*', - account: 'did:*', - }, - }) - .delegate() + const proof = await Voucher.redeem.delegate({ + audience: ctx.signer, + issuer: ctx.signer, + expiration: Infinity, + with: ctx.signer.did(), + nb: { + product: 'product:*', + identity: 'mailto:*', + account: 'did:*', + }, + }) const inv = await Voucher.redeem .invoke({ - issuer: ctx.keypair, + issuer: ctx.signer, audience: invocation.issuer, - with: ctx.keypair.did(), + with: ctx.signer.did(), lifetimeInSeconds: 60 * 10, // 10 mins nb: { account: capability.with, @@ -45,6 +43,7 @@ export function voucherClaimProvider(ctx) { const url = `${ctx.url.protocol}//${ ctx.url.host }/validate-email?ucan=${encoded}&did=${invocation.issuer.did()}` + await ctx.email.sendValidation({ to: capability.nb.identity.replace('mailto:', ''), url, diff --git a/packages/access-api/src/service/voucher-redeem.js b/packages/access-api/src/service/voucher-redeem.js index 6ffe378ea..54fe9a67c 100644 --- a/packages/access-api/src/service/voucher-redeem.js +++ b/packages/access-api/src/service/voucher-redeem.js @@ -1,20 +1,25 @@ import * as Server from '@ucanto/server' import * as Voucher from '@web3-storage/access/capabilities/voucher' - +import { Delegation } from '@ucanto/core' /** * @param {import('../bindings').RouteContext} ctx */ export function voucherRedeemProvider(ctx) { return Server.provide(Voucher.redeem, async ({ capability, invocation }) => { - await ctx.db.insert({ - tableName: 'accounts', - data: { - did: capability.nb.account, - product: capability.nb.product, - email: capability.nb.identity.replace('mailto:', ''), - agent: invocation.issuer.did(), - }, - }) + // @ts-ignore - TODO fix this + await ctx.kvs.accounts.create(capability, invocation) + + // We should only save delegation for redeems + if (capability.nb.identity.startsWith('mailto:')) { + for (const p of invocation.proofs) { + if ( + Delegation.isDelegation(p) && + p.audience.did() === ctx.signer.did() + ) { + await ctx.kvs.accounts.saveAccount(capability.nb.identity, p) + } + } + } ctx.config.METRICS.writeDataPoint({ blobs: [ctx.config.ENV, 'new_account_v1'], diff --git a/packages/access-api/src/utils/context.js b/packages/access-api/src/utils/context.js index 4aad152be..7a931c0e4 100644 --- a/packages/access-api/src/utils/context.js +++ b/packages/access-api/src/utils/context.js @@ -44,13 +44,14 @@ export function getContext(request, env, ctx) { const keypair = Signer.parse(config.PRIVATE_KEY) const url = new URL(request.url) + const db = new D1QB(config.DB) return { log, - keypair, + signer: keypair, config, url, kvs: { - accounts: new Accounts(config.ACCOUNTS), + accounts: new Accounts(config.ACCOUNTS, db), validations: new Validations(config.VALIDATIONS), }, email: new Email({ token: config.POSTMARK_TOKEN }), diff --git a/packages/access-api/src/utils/html.js b/packages/access-api/src/utils/html.js new file mode 100644 index 000000000..7cd1242a5 --- /dev/null +++ b/packages/access-api/src/utils/html.js @@ -0,0 +1,129 @@ +import { render } from 'preact-render-to-string' + +/** + * Build HTML document + * + * @param {string} body + */ +export function buildDocument(body) { + return ` + + + + + + + + + + + + +${body} + +` +} + +export class HtmlResponse extends Response { + /** + * + * @param {import('preact').VNode<{}>} body + * @param {ResponseInit} [init] + */ + constructor(body, init = {}) { + const headers = { + headers: { + 'content-type': 'text/html; charset=utf-8', + }, + } + super(buildDocument(render(body)), { ...init, ...headers }) + } + + /** + * @param {import('preact').VNode<{}>} body + * @param {ResponseInit} [init] + */ + static respond(body, init = {}) { + return new HtmlResponse(body, init) + } +} + +/** + * + * @param {object} param0 + * @param {import('@ucanto/interface').Delegation<[import('@web3-storage/access/capabilities/types').VoucherClaim]>} param0.delegation + * @param {string} param0.ucan + * @param {string} param0.qrcode + */ +export const ValidateEmail = ({ delegation, ucan, qrcode }) => ( +
+ +

Email Validated

+

+ {delegation.capabilities[0].nb.identity.replace('mailto:', '')} was + confirmed. You may close this window. +

+
+ {' '} + More details +
Validation requested by:
+

+ {delegation.audience.did()} +

+
QR Code:
+
+
UCAN:
+
+        {ucan}
+      
+
+
+) + +/** + * + * @param {object} param0 + * @param {string} param0.msg + */ +export const ValidateEmailError = ({ msg }) => ( +
+ +

Email Validation Failed

+

{msg} You may close this window and try again.

+
+) diff --git a/packages/access-api/test/account-recover.test.js b/packages/access-api/test/account-recover.test.js new file mode 100644 index 000000000..b8acfd48a --- /dev/null +++ b/packages/access-api/test/account-recover.test.js @@ -0,0 +1,64 @@ +import * as Account from '@web3-storage/access/capabilities/account' +import { stringToDelegation } from '@web3-storage/access/encoding' +import { context, test } from './helpers/context.js' + +import { createAccount } from './helpers/utils.js' + +test.before(async (t) => { + t.context = await context() +}) + +test('should fail before registering account', async (t) => { + const { issuer, service, conn } = t.context + + const inv = await Account.recoverValidation + .invoke({ + issuer, + audience: service, + with: issuer.did(), + nb: { + email: 'mailto:hello@dag.house', + }, + }) + .execute(conn) + + if (inv?.error) { + t.deepEqual( + inv.message, + `service handler {can: "account/recover-validation"} error: No accounts found for email: hello@dag.house.` + ) + } else { + return t.fail() + } +}) + +test('should return account/login', async (t) => { + const { issuer, service, conn } = t.context + + await createAccount(issuer, service, conn, 'account-login@dag.house') + + const inv = await Account.recoverValidation + .invoke({ + issuer, + audience: service, + with: issuer.did(), + nb: { + email: 'mailto:account-login@dag.house', + }, + }) + .execute(conn) + + if (!inv || inv.error) { + return t.fail('failed to recover') + } + + const del = await stringToDelegation( + /** @type {import('@web3-storage/access/types').EncodedDelegation<[import('@web3-storage/access/capabilities/types').Any]>} */ ( + inv + ) + ) + + t.deepEqual(del.audience.did(), issuer.did()) + t.deepEqual(del.issuer.did(), service.did()) + t.deepEqual(del.capabilities[0].can, 'account/recover') +}) diff --git a/packages/access-api/test/api.test.js b/packages/access-api/test/api.test.js deleted file mode 100644 index 4a1b6d7af..000000000 --- a/packages/access-api/test/api.test.js +++ /dev/null @@ -1,12 +0,0 @@ -import { context, test } from './helpers/context.js' - -test.beforeEach(async (t) => { - t.context = await context() -}) - -test('should work', async (t) => { - const { mf } = t.context - const res = await mf.dispatchFetch('http://localhost:8787/version') - const rsp = await res.json() - t.truthy(rsp.branch) -}) diff --git a/packages/access-api/test/helpers/context.js b/packages/access-api/test/helpers/context.js index b540eb755..6915afbd8 100644 --- a/packages/access-api/test/helpers/context.js +++ b/packages/access-api/test/helpers/context.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import { Signer } from '@ucanto/principal/ed25519' import { connection } from '@web3-storage/access' import anyTest from 'ava' @@ -5,6 +6,8 @@ import dotenv from 'dotenv' import { Miniflare } from 'miniflare' import path from 'path' import { fileURLToPath } from 'url' +import { migrate } from '../../sql/migrate.js' + const __dirname = path.dirname(fileURLToPath(import.meta.url)) dotenv.config({ @@ -37,7 +40,13 @@ export async function context() { sourceMap: true, modules: true, bindings, + d1Persist: undefined, }) + + const binds = await mf.getBindings() + const db = /** @type {D1Database} */ (binds.__D1_BETA__) + await migrate(db) + return { mf, conn: await connection( diff --git a/packages/access-api/test/helpers/utils.js b/packages/access-api/test/helpers/utils.js index 5ac628ab4..fbcd102f2 100644 --- a/packages/access-api/test/helpers/utils.js +++ b/packages/access-api/test/helpers/utils.js @@ -1,9 +1,11 @@ +/* eslint-disable unicorn/prefer-number-properties */ import * as UCAN from '@ipld/dag-ucan' -import { URI } from '@ucanto/validator' -import { Delegation } from '@ucanto/core' // eslint-disable-next-line no-unused-vars import * as Types from '@ucanto/interface' -import * as Identity from '@web3-storage/access/capabilities/identity' +import { StoreMemory } from '@web3-storage/access/stores/store-memory' +import * as Any from '@web3-storage/access/capabilities/any' +import * as Voucher from '@web3-storage/access/capabilities/voucher' +import { stringToDelegation } from '@web3-storage/access/encoding' /** * @param {Types.UCAN.View} ucan @@ -19,52 +21,66 @@ export async function send(ucan, mf) { } /** - * @param {Types.ConnectionView} con * @param {Types.Signer} issuer - * @param {Types.Principal} audience + * @param {Types.Principal} service + * @param {Types.ConnectionView} conn * @param {string} email */ -export async function validateEmail(con, issuer, audience, email) { - const validate = Identity.validate.invoke({ - audience, - issuer, - nb: { - as: URI.from(`mailto:${email}`), - }, - with: issuer.did(), - }) - - const out = await validate.execute(con) - if (out?.error) { - throw out +export async function createAccount(issuer, service, conn, email) { + const store = new StoreMemory() + const account = await store.createAccount() + const claim = await Voucher.claim + .invoke({ + issuer, + audience: service, + with: account.did(), + nb: { + // @ts-ignore + identity: `mailto:${email}`, + product: 'product:free', + service: service.did(), + }, + proofs: [ + await Any.any.delegate({ + issuer: account, + audience: issuer, + with: account.did(), + expiration: Infinity, + }), + ], + }) + .execute(conn) + if (!claim || claim.error) { + throw new Error('failed to create account') } - // @ts-ignore - const ucan = UCAN.parse( - // @ts-ignore - out.delegation.replace('http://localhost:8787/validate?ucan=', '') - ) - const root = await UCAN.write(ucan) - const proof = Delegation.create({ root }) - return proof -} + const delegation = await stringToDelegation(claim) -/** - * @param {Types.ConnectionView} con - * @param {Types.Signer} issuer - * @param {Types.Principal} audience - * @param {Types.Delegation<[import('@web3-storage/access/src/types').IdentityRegister]>} proof - */ -export async function register(con, issuer, audience, proof) { - const register = Identity.register.invoke({ - audience, - issuer, - with: proof.capabilities[0].with, - nb: { - as: proof.capabilities[0].nb.as, - }, - proofs: [proof], - }) + const redeem = await Voucher.redeem + .invoke({ + issuer, + audience: service, + with: service.did(), + nb: { + account: account.did(), + identity: delegation.capabilities[0].nb.identity, + product: delegation.capabilities[0].nb.product, + }, + proofs: [ + delegation, + await Any.any.delegate({ + issuer: account, + audience: service, + with: account.did(), + expiration: Infinity, + }), + ], + }) + .execute(conn) - await register.execute(con) + if (redeem?.error) { + // eslint-disable-next-line no-console + console.log(redeem) + throw new Error(redeem.message) + } } diff --git a/packages/access-api/test/identity-register.test.js b/packages/access-api/test/identity-register.test.js deleted file mode 100644 index 3f5a004fc..000000000 --- a/packages/access-api/test/identity-register.test.js +++ /dev/null @@ -1,106 +0,0 @@ -import * as UCAN from '@ipld/dag-ucan' -import { Delegation } from '@ucanto/core' -import * as Identity from '@web3-storage/access/capabilities/identity' -import { Accounts } from '../src/kvs/accounts.js' -import { context, test } from './helpers/context.js' -// eslint-disable-next-line no-unused-vars -import * as Ucanto from '@ucanto/interface' - -test.beforeEach(async (t) => { - t.context = await context() -}) - -test('register', async (t) => { - const { conn, issuer, mf, service } = t.context - - const validate = Identity.validate.invoke({ - audience: service, - issuer, - nb: { - as: 'mailto:hugo+register@dag.house', - }, - with: issuer.did(), - }) - - const out = await validate.execute(conn) - if (out?.error || !out) { - return t.fail() - } - const jwt = - /** @type UCAN.JWT<[import('@web3-storage/access/types').IdentityRegister]>} */ ( - out.delegation.replace('http://localhost:8787/validate?ucan=', '') - ) - const ucan = UCAN.parse(jwt) - const root = await UCAN.write(ucan) - const proof = Delegation.create({ root }) - - const register = Identity.register.invoke({ - audience: service, - issuer, - with: proof.capabilities[0].with, - nb: { - as: proof.capabilities[0].nb.as, - }, - proofs: [proof], - }) - - await register.execute(conn) - const invocation = await register.delegate() - // @ts-ignore - const accounts = new Accounts(await mf.getKVNamespace('ACCOUNTS')) - - const email = await accounts.get('mailto:hugo+register@dag.house') - t.is(email?.proof, invocation.cid.toString()) - - const did = await accounts.get(issuer.did()) - t.is(did?.proof, invocation.cid.toString()) -}) - -test('identify', async (t) => { - const { conn, issuer, mf, service } = t.context - const validate = Identity.validate.invoke({ - audience: service, - issuer, - nb: { - as: 'mailto:hugo+identify@dag.house', - }, - with: issuer.did(), - }) - - const out = await validate.execute(conn) - if (out?.error || !out) { - return - } - /** @type {Ucanto.UCAN.JWT<[import('@web3-storage/access/types').IdentityRegister]>} */ - const jwt = out.delegation.replace('http://localhost:8787/validate?ucan=', '') - const ucan = UCAN.parse(jwt) - const root = await UCAN.write(ucan) - const proof = Delegation.create({ root }) - - const register = Identity.register.invoke({ - audience: service, - issuer, - with: proof.capabilities[0].with, - nb: { - as: proof.capabilities[0].nb.as, - }, - proofs: [proof], - }) - - await register.execute(conn) - - const identify = Identity.identify.invoke({ - audience: service, - issuer, - with: issuer.did(), - }) - - const identifyResult = await identify.execute(conn) - if (identifyResult?.error || !identifyResult) { - return t.fail() - } - // @ts-ignore - const accounts = new Accounts(await mf.getKVNamespace('ACCOUNTS')) - const did = await accounts.get(issuer.did()) - t.is(did?.account, identifyResult) -}) diff --git a/packages/access-api/test/identity-validate.test.js b/packages/access-api/test/identity-validate.test.js deleted file mode 100644 index aa9b7aee8..000000000 --- a/packages/access-api/test/identity-validate.test.js +++ /dev/null @@ -1,88 +0,0 @@ -import { context, test } from './helpers/context.js' -import * as UCAN from '@ipld/dag-ucan' -import * as Identity from '@web3-storage/access/capabilities/identity' -import { send } from './helpers/utils.js' - -test.before(async (t) => { - t.context = await context() -}) - -test.skip('should route to validate without ucanto client', async (t) => { - const { issuer, mf, service } = t.context - - const ucan = await UCAN.issue({ - issuer, - audience: service, - capabilities: [ - { - can: 'identity/validate', - with: issuer.did(), - as: 'mailto:admin@dag.house', - }, - ], - }) - const res = await send(ucan, mf) - t.deepEqual(res.ok, true) -}) - -test.skip('should fail with bad scheme', async (t) => { - const { issuer, mf, service } = t.context - const ucan = await UCAN.issue({ - issuer, - audience: service, - capabilities: [{ can: 'identity/validate', with: 'mailt:admin@dag.house' }], - }) - const res = await send(ucan, mf) - const rsp = await res.json() - t.deepEqual(rsp, [ - { - error: true, - name: 'Unauthorized', - message: - `Encountered malformed 'identity/validate' capability: {"can":"identity/validate","with":"mailt:admin@dag.house"}\n` + - ' - Expected did: URI instead got mailt:admin@dag.house', - cause: { - error: true, - name: 'MalformedCapability', - message: - `Encountered malformed 'identity/validate' capability: {"can":"identity/validate","with":"mailt:admin@dag.house"}\n` + - ' - Expected did: URI instead got mailt:admin@dag.house', - }, - }, - ]) -}) - -test('should route correctly to identity/validate', async (t) => { - const { issuer, service, conn } = t.context - - const validate = Identity.validate.invoke({ - audience: service, - issuer, - nb: { - as: 'mailto:hugo@dag.house', - }, - with: issuer.did(), - }) - - const out = await validate.execute(conn) - if (out?.error || !out) { - return t.fail() - } - - const jwt = - /** @type UCAN.JWT<[import('@web3-storage/access/types').IdentityRegister]>} */ ( - out.delegation.replace('http://localhost:8787/validate?ucan=', '') - ) - const ucan = UCAN.parse(jwt) - t.is(ucan.audience.did(), issuer.did()) - t.is(ucan.issuer.did(), service.did()) - t.deepEqual(ucan.capabilities, [ - { - can: 'identity/register', - with: 'mailto:hugo@dag.house', - nb: { - as: issuer.did(), - }, - }, - ]) -}) diff --git a/packages/access-api/test/ucan.test.js b/packages/access-api/test/ucan.test.js index 82ff46b3c..2d34e1176 100644 --- a/packages/access-api/test/ucan.test.js +++ b/packages/access-api/test/ucan.test.js @@ -234,7 +234,7 @@ test('should multiple invocation should pass', async (t) => { const res = await mf.dispatchFetch('http://localhost:8787/raw', { method: 'POST', - headers, + headers: Object.fromEntries(headers.entries()), }) const rsp = await res.json() diff --git a/packages/access-api/test/voucher-redeem.test.js b/packages/access-api/test/voucher-redeem.test.js new file mode 100644 index 000000000..afb12bff0 --- /dev/null +++ b/packages/access-api/test/voucher-redeem.test.js @@ -0,0 +1,126 @@ +/* eslint-disable unicorn/prefer-number-properties */ +import * as Any from '@web3-storage/access/capabilities/any' +import * as Voucher from '@web3-storage/access/capabilities/voucher' +import { stringToDelegation } from '@web3-storage/access/encoding' +import { StoreMemory } from '@web3-storage/access/stores/store-memory' +import { context, test } from './helpers/context.js' +import { createAccount } from './helpers/utils.js' + +test.before(async (t) => { + t.context = await context() +}) + +test('should return account/redeem', async (t) => { + const { issuer, service, conn, mf } = t.context + + const store = new StoreMemory() + const account = await store.createAccount() + const claim = await Voucher.claim + .invoke({ + issuer, + audience: service, + with: account.did(), + nb: { + identity: 'mailto:email@dag.house', + product: 'product:free', + service: service.did(), + }, + proofs: [ + await Any.any.delegate({ + issuer: account, + audience: issuer, + with: account.did(), + expiration: Infinity, + }), + ], + }) + .execute(conn) + + if (!claim) { + return t.fail('no output') + } + if (claim.error) { + return t.fail(claim.message) + } + + const delegation = await stringToDelegation(claim) + + const redeem = await Voucher.redeem + .invoke({ + issuer, + audience: service, + with: service.did(), + nb: { + account: account.did(), + identity: delegation.capabilities[0].nb.identity, + product: delegation.capabilities[0].nb.product, + }, + proofs: [ + delegation, + await Any.any.delegate({ + issuer: account, + audience: service, + with: account.did(), + expiration: Infinity, + }), + ], + }) + + .execute(conn) + + if (redeem?.error) { + return t.fail() + } + + const accounts = await mf.getKVNamespace('ACCOUNTS') + + const delEncoded = /** @type {string[]|undefined} */ ( + await accounts.get('mailto:email@dag.house', { + type: 'json', + }) + ) + if (!delEncoded) { + return t.fail('no delegation for email') + } + + const del = await stringToDelegation( + /** @type {import('@web3-storage/access/types').EncodedDelegation<[import('@web3-storage/access/capabilities/types').Any]>} */ ( + delEncoded[0] + ) + ) + + t.deepEqual(del.audience.did(), service.did()) + t.deepEqual(del.capabilities[0].can, '*') + t.deepEqual(del.capabilities[0].with, account.did()) +}) + +test('should save first account delegation', async (t) => { + const { issuer, service, conn, mf } = t.context + + await createAccount(issuer, service, conn, 'first@dag.house') + + const accounts = await mf.getKVNamespace('ACCOUNTS') + + const delEncoded = await accounts.get('mailto:first@dag.house', { + type: 'json', + }) + + // @ts-ignore + t.assert(delEncoded.length === 1) +}) + +test('should save multiple account delegation', async (t) => { + const { issuer, service, conn, mf } = t.context + + await createAccount(issuer, service, conn, 'multiple@dag.house') + await createAccount(issuer, service, conn, 'multiple@dag.house') + + const accounts = await mf.getKVNamespace('ACCOUNTS') + + const delEncoded = await accounts.get('mailto:multiple@dag.house', { + type: 'json', + }) + + // @ts-ignore + t.assert(delEncoded.length === 2) +}) diff --git a/packages/access-api/tsconfig.json b/packages/access-api/tsconfig.json index cedc9dcc8..2fd4a2a4d 100644 --- a/packages/access-api/tsconfig.json +++ b/packages/access-api/tsconfig.json @@ -2,10 +2,11 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", - "lib": ["ESNext"], - "types": ["@cloudflare/workers-types"] + "types": ["@cloudflare/workers-types"], + "jsx": "react-jsx", + "jsxImportSource": "preact" }, - "include": ["src", "scripts", "test", "package.json"], + "include": ["src", "scripts", "test", "package.json", "sql"], "exclude": ["**/node_modules/**"], "references": [{ "path": "../access" }] } diff --git a/packages/access-ws/package.json b/packages/access-ws/package.json index 5f58515d4..c463cf3cb 100644 --- a/packages/access-ws/package.json +++ b/packages/access-ws/package.json @@ -22,21 +22,21 @@ "multiformats": "^9.8.1", "nanoid": "^4.0.0", "toucan-js": "^2.7.0", - "ws": "^8.8.1" + "ws": "^8.10.0" }, "devDependencies": { - "@cloudflare/workers-types": "^3.16.0", - "@sentry/cli": "^2.7.0", + "@cloudflare/workers-types": "^3.18.0", + "@sentry/cli": "^2.8.0", "@sentry/webpack-plugin": "^1.19.1", "@types/assert": "^1.5.6", "@types/git-rev-sync": "^2.0.0", - "@types/node": "^18.11.0", + "@types/node": "^18.11.7", "assert": "^2.0.0", - "ava": "^4.3.3", + "ava": "^5.0.1", "buffer": "^6.0.3", "delay": "^5.0.0", "dotenv": "^16.0.3", - "esbuild": "^0.15.10", + "esbuild": "^0.15.12", "execa": "^6.1.0", "git-rev-sync": "^3.0.1", "hd-scripts": "^3.0.2", @@ -46,7 +46,7 @@ "readable-stream": "^4.1.0", "sade": "^1.7.4", "typescript": "4.8.4", - "wrangler": "^2.1.12" + "wrangler": "^2.1.13" }, "eslintConfig": { "extends": [ diff --git a/packages/access/package.json b/packages/access/package.json index 97e84f2f7..fc5db49cc 100644 --- a/packages/access/package.json +++ b/packages/access/package.json @@ -83,15 +83,15 @@ "p-retry": "^5.1.1", "p-wait-for": "^5.0.0", "uint8arrays": "^4.0.2", - "undici": "^5.11.0", - "ws": "^8.8.1", + "undici": "^5.12.0", + "ws": "^8.10.0", "zod": "^3.19.1" }, "devDependencies": { "@types/assert": "^1.5.6", "@types/inquirer": "^9.0.2", "@types/mocha": "^10.0.0", - "@types/node": "^18.11.0", + "@types/node": "^18.11.7", "@web-std/fetch": "^4.1.0", "assert": "^2.0.0", "delay": "^5.0.0", @@ -106,10 +106,16 @@ }, "eslintConfig": { "extends": [ - "./node_modules/hd-scripts/eslint/index.js" + "./node_modules/hd-scripts/eslint/preact.js" ], "parserOptions": { - "project": "./tsconfig.json" + "project": "./tsconfig.json", + "ecmaFeatures": { + "jsx": true + } + }, + "rules": { + "unicorn/prefer-number-properties": "off" }, "env": { "mocha": true diff --git a/packages/access/src/agent.js b/packages/access/src/agent.js index 20a75a4f1..dbb3e4c01 100644 --- a/packages/access/src/agent.js +++ b/packages/access/src/agent.js @@ -1,6 +1,5 @@ import * as DID from '@ipld/dag-ucan/did' import * as Client from '@ucanto/client' -import { delegate } from '@ucanto/core' // @ts-ignore // eslint-disable-next-line no-unused-vars import * as Ucanto from '@ucanto/interface' @@ -11,6 +10,7 @@ import { URI } from '@ucanto/validator' import { Peer } from './awake/peer.js' import * as Account from './capabilities/account.js' import * as Voucher from './capabilities/voucher.js' +import { any as Any } from './capabilities/any.js' import { stringToDelegation } from './encoding.js' import { Websocket } from './utils/ws.js' @@ -133,26 +133,16 @@ export class Agent { async createAccount(email) { const account = await this.store.createAccount() const service = await this.service() - const accDelegation = await delegate({ - // @ts-ignore + const delegationToAgent = await Any.delegate({ issuer: account, - audience: this.data.principal, - capabilities: [ - { - can: 'voucher/*', - with: account.did(), - }, - { - can: 'account/*', - with: account.did(), - }, - ], - lifetimeInSeconds: 8_600_000, + audience: this.issuer, + with: account.did(), + expiration: Infinity, }) const inv = await Voucher.claim .invoke({ - issuer: this.data.principal, + issuer: this.issuer, audience: service, with: account.did(), nb: { @@ -160,7 +150,7 @@ export class Agent { product: 'product:free', service: service.did(), }, - proofs: [accDelegation], + proofs: [delegationToAgent], }) .execute(this.connection) @@ -169,7 +159,13 @@ export class Agent { } const voucherRedeem = await this.#waitForVoucherRedeem() - + // TODO save this delegation so we can revoke later + const delegationToService = await Any.delegate({ + issuer: account, + audience: service, + with: account.did(), + expiration: Infinity, + }) const accInv = await Voucher.redeem .invoke({ issuer: this.data.principal, @@ -180,7 +176,7 @@ export class Agent { identity: voucherRedeem.capabilities[0].nb.identity, product: voucherRedeem.capabilities[0].nb.product, }, - proofs: [voucherRedeem], + proofs: [voucherRedeem, delegationToService], }) .execute(this.connection) @@ -188,7 +184,7 @@ export class Agent { if (accInv && accInv.error) { throw new Error('Account registration failed', { cause: accInv }) } - this.data.delegations.addMany([voucherRedeem, accDelegation]) + this.data.delegations.addMany([voucherRedeem, delegationToAgent]) this.data.accounts.push(account) this.store.save(this.data) } diff --git a/packages/access/src/capabilities/account.js b/packages/access/src/capabilities/account.js index 1ab322789..337e92bda 100644 --- a/packages/access/src/capabilities/account.js +++ b/packages/access/src/capabilities/account.js @@ -27,3 +27,24 @@ export const info = base.or(store).derive({ }), derives: equalWith, }) + +export const recoverValidation = base.derive({ + to: capability({ + can: 'account/recover-validation', + with: URI.match({ protocol: 'did:' }), + nb: { + email: URI.match({ protocol: 'mailto:' }), + }, + derives: equalWith, + }), + derives: equalWith, +}) + +export const recover = base.derive({ + to: capability({ + can: 'account/recover', + with: URI.match({ protocol: 'did:' }), + derives: equalWith, + }), + derives: equalWith, +}) diff --git a/packages/access/src/capabilities/identity.js b/packages/access/src/capabilities/identity.js deleted file mode 100644 index 521fdb1da..000000000 --- a/packages/access/src/capabilities/identity.js +++ /dev/null @@ -1,41 +0,0 @@ -import { capability, URI } from '@ucanto/validator' -import * as Store from './store.js' -import { canDelegateURI, equalWith } from './utils.js' - -export const validate = capability({ - can: 'identity/validate', - with: URI.match({ protocol: 'did:' }), - nb: { - as: URI.match({ protocol: 'mailto:' }), - }, - derives: (child, parent) => { - return canDelegateURI(child.nb.as, parent.nb.as) && equalWith(child, parent) - }, -}) - -export const register = capability({ - can: 'identity/register', - with: URI.match({ protocol: 'mailto:' }), - nb: { - as: URI.match({ protocol: 'did:' }), - }, - derives: (child, parent) => - canDelegateURI(child.nb.as, parent.nb.as) && - canDelegateURI(child.with, parent.with), -}) - -/** - * `identity/identify` can be derived from any of the `store/*` - * capability that has matichng `with`. This allows store service - * to identify account based on any user request. - */ -export const identify = Store.all.derive({ - to: capability({ - can: 'identity/identify', - with: URI.match({ protocol: 'did:' }), - derives: equalWith, - }), - derives: equalWith, -}) - -export const identity = register.or(validate).or(identify) diff --git a/packages/access/src/capabilities/types.ts b/packages/access/src/capabilities/types.ts index f7183bc69..ce5d033eb 100644 --- a/packages/access/src/capabilities/types.ts +++ b/packages/access/src/capabilities/types.ts @@ -1,6 +1,6 @@ import { InferInvokedCapability } from '@ucanto/interface' -import { account, info } from './account.js' -import { identify, register, validate } from './identity.js' +import { account, info, recover, recoverValidation } from './account.js' +import { any } from './any.js' import { add, list, remove } from './store.js' import * as UploadCaps from './upload.js' import { claim, redeem } from './voucher.js' @@ -8,13 +8,13 @@ import { claim, redeem } from './voucher.js' // Account export type Account = InferInvokedCapability export type AccountInfo = InferInvokedCapability +export type AccountRecoverValidation = InferInvokedCapability< + typeof recoverValidation +> +export type AccountRecover = InferInvokedCapability // Voucher Protocol export type VoucherRedeem = InferInvokedCapability export type VoucherClaim = InferInvokedCapability -// Identity -export type IdentityValidate = InferInvokedCapability -export type IdentityRegister = InferInvokedCapability -export type IdentityIdentify = InferInvokedCapability // Upload export type Upload = InferInvokedCapability export type UploadAdd = InferInvokedCapability @@ -24,3 +24,5 @@ export type UploadList = InferInvokedCapability export type StoreAdd = InferInvokedCapability export type StoreRemove = InferInvokedCapability export type StoreList = InferInvokedCapability +// Any +export type Any = InferInvokedCapability diff --git a/packages/access/src/cli/cmd-setup.js b/packages/access/src/cli/cmd-setup.js index 846ce6fbc..3c1ab01c6 100644 --- a/packages/access/src/cli/cmd-setup.js +++ b/packages/access/src/cli/cmd-setup.js @@ -3,12 +3,16 @@ import inquirer from 'inquirer' import { StoreConf } from '../stores/store-conf.js' /** - * @param {{ profile: any; }} opts + * @param {{ profile: string, force: boolean }} opts */ export async function cmdSetup(opts) { const store = new StoreConf({ profile: opts.profile }) console.log('Path:', store.path) + if (opts.force) { + await store.reset() + } + if (await store.exists()) { console.log('Agent is already setup.') } else { diff --git a/packages/access/src/cli/index.js b/packages/access/src/cli/index.js index 6c154a0a9..0658a12f7 100755 --- a/packages/access/src/cli/index.js +++ b/packages/access/src/cli/index.js @@ -66,7 +66,11 @@ prog }) prog.command('link [channel]').describe('Link.').action(cmdLink) -prog.command('setup').describe('Print config file content.').action(cmdSetup) +prog + .command('setup') + .option('--reset', 'Reset current store.', false) + .describe('Print config file content.') + .action(cmdSetup) prog.command('whoami').describe('Print config file content.').action(cmdWhoami) prog .command('create-account') diff --git a/packages/access/src/delegations.js b/packages/access/src/delegations.js index f893b87dc..526f898e1 100644 --- a/packages/access/src/delegations.js +++ b/packages/access/src/delegations.js @@ -80,24 +80,6 @@ export class Delegations { } } - async full() { - const delegation = await delegate({ - // @ts-ignore - issuer: this.principal, - audience: this.principal, - capabilities: [ - { - can: 'identify/*', - with: this.principal.did(), - }, - ], - lifetimeInSeconds: 8_600_000, - }) - - this.received.push(delegation) - return this - } - /** * * @param {import('@ucanto/interface').Principal} audience diff --git a/packages/access/src/stores/store-conf.js b/packages/access/src/stores/store-conf.js index fec3d2452..6782a0ef9 100644 --- a/packages/access/src/stores/store-conf.js +++ b/packages/access/src/stores/store-conf.js @@ -37,6 +37,10 @@ export class StoreConf { async close() {} + async reset() { + this.#config.clear() + } + async exists() { return this.#config.has('meta') && this.#config.has('principal') } diff --git a/packages/access/src/stores/store-indexeddb.js b/packages/access/src/stores/store-indexeddb.js index ac0b92f57..0dff6ee04 100644 --- a/packages/access/src/stores/store-indexeddb.js +++ b/packages/access/src/stores/store-indexeddb.js @@ -217,6 +217,25 @@ export class StoreIndexedDB { async createAccount() { return await Signer.generate({ extractable: false }) } + + async reset() { + if (this.#db) { + withObjectStore(this.#db, 'readwrite', this.#dbStoreName, (s) => { + /** @type {import('p-defer').DeferredPromise} */ + const { resolve, reject, promise } = defer() + const req = s.clear() + req.addEventListener('success', () => { + resolve() + }) + + req.addEventListener('error', () => + reject(new Error('failed to query DB', { cause: req.error })) + ) + + return promise + }) + } + } } /** diff --git a/packages/access/src/stores/store-memory.js b/packages/access/src/stores/store-memory.js index 02293746e..e391dff9e 100644 --- a/packages/access/src/stores/store-memory.js +++ b/packages/access/src/stores/store-memory.js @@ -28,6 +28,11 @@ export class StoreMemory { async close() {} + async reset() { + // @ts-ignore + this.data = {} + } + async exists() { return this.data.meta !== undefined && this.data.principal !== undefined } diff --git a/packages/access/src/stores/types.ts b/packages/access/src/stores/types.ts index b80d6ddfe..757ed7e08 100644 --- a/packages/access/src/stores/types.ts +++ b/packages/access/src/stores/types.ts @@ -25,6 +25,7 @@ export interface Store { save: (data: StoreData) => Promise> load: () => Promise> createAccount: () => Promise + reset: () => Promise } export interface StoreKeyEd extends Store {} diff --git a/packages/access/src/types.ts b/packages/access/src/types.ts index 0f73871ca..23cbbb58e 100644 --- a/packages/access/src/types.ts +++ b/packages/access/src/types.ts @@ -12,9 +12,8 @@ import type { import type { AccountInfo, - IdentityIdentify, - IdentityRegister, - IdentityValidate, + AccountRecover, + AccountRecoverValidation, } from './capabilities/types' import { VoucherClaim, VoucherRedeem } from './capabilities/types.js' @@ -26,16 +25,6 @@ export type EncodedDelegation = string & Phantom export interface Service { - identity: { - validate: ServiceMethod< - IdentityValidate, - // eslint-disable-next-line @typescript-eslint/no-invalid-void-type - { delegation: string } | void, - never - > - register: ServiceMethod - identify: ServiceMethod - } voucher: { claim: ServiceMethod< VoucherClaim, @@ -45,21 +34,24 @@ export interface Service { redeem: ServiceMethod } account: { - info: ServiceMethod< - AccountInfo, - { - did: UCAN.DID - agent: UCAN.DID - email: URI<'mailto:'> - product: URI<'product:'> - updated_at: string - inserted_at: string - }, + info: ServiceMethod + 'recover-validation': ServiceMethod< + AccountRecoverValidation, + EncodedDelegation<[AccountRecover]> | undefined, Failure > } } +export interface Account { + did: UCAN.DID + agent: UCAN.DID + email: URI<'mailto:'> + product: URI<'product:'> + updated_at: string + inserted_at: string +} + export interface AgentMeta { name: string description?: string diff --git a/packages/wallet/package.json b/packages/wallet/package.json index c9d400c44..a90abb750 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -16,13 +16,13 @@ "react-dom": "18.2.0" }, "devDependencies": { - "@types/node": "^18.11.0", - "@types/react": "^18.0.20", - "eslint": "^8.25.0", + "@types/node": "^18.11.7", + "@types/react": "^18.0.24", + "eslint": "^8.26.0", "eslint-config-next": "12.3.1", "hd-scripts": "^3.0.2", "typescript": "4.8.4", - "wrangler": "^2.1.12" + "wrangler": "^2.1.13" }, "eslintConfig": { "extends": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60013e8ea..701125240 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,13 +8,13 @@ importers: prettier: 2.7.1 simple-git-hooks: ^2.8.1 typescript: ^4.8.4 - wrangler: ^2.1.12 + wrangler: ^2.1.13 devDependencies: lint-staged: 13.0.3 prettier: 2.7.1 simple-git-hooks: 2.8.1 typescript: 4.8.4 - wrangler: 2.1.12 + wrangler: 2.1.13 packages/access: specifiers: @@ -24,7 +24,7 @@ importers: '@types/assert': ^1.5.6 '@types/inquirer': ^9.0.2 '@types/mocha': ^10.0.0 - '@types/node': ^18.11.0 + '@types/node': ^18.11.7 '@types/ws': ^8.5.3 '@ucanto/client': ^2.0.0 '@ucanto/core': ^2.0.0 @@ -56,9 +56,9 @@ importers: sade: ^1.7.4 typescript: 4.8.4 uint8arrays: ^4.0.2 - undici: ^5.11.0 + undici: ^5.12.0 watch: ^1.0.2 - ws: ^8.8.1 + ws: ^8.10.0 zod: ^3.19.1 dependencies: '@ipld/car': 4.1.6 @@ -76,7 +76,7 @@ importers: bigint-mod-arith: 3.1.2 conf: 10.2.0 inquirer: 9.1.4 - isomorphic-ws: 5.0.0_ws@8.9.0 + isomorphic-ws: 5.0.0_ws@8.10.0 multiformats: 9.9.0 nanoid: 4.0.0 one-webcrypto: 1.0.3 @@ -86,14 +86,14 @@ importers: p-retry: 5.1.1 p-wait-for: 5.0.0 uint8arrays: 4.0.2 - undici: 5.11.0 - ws: 8.9.0 + undici: 5.12.0 + ws: 8.10.0 zod: 3.19.1 devDependencies: '@types/assert': 1.5.6 '@types/inquirer': 9.0.2 '@types/mocha': 10.0.0 - '@types/node': 18.11.0 + '@types/node': 18.11.7 assert: 2.0.0 delay: 5.0.0 dotenv: 16.0.3 @@ -107,13 +107,16 @@ importers: packages/access-api: specifiers: - '@cloudflare/workers-types': ^3.16.0 + '@cloudflare/workers-types': ^3.18.0 + '@databases/escape-identifier': ^1.0.3 + '@databases/sql': ^3.2.0 '@ipld/dag-ucan': 4.0.0-beta - '@sentry/cli': ^2.7.0 + '@sentry/cli': ^2.8.0 '@sentry/webpack-plugin': ^1.19.1 '@types/assert': ^1.5.6 '@types/git-rev-sync': ^2.0.0 - '@types/node': ^18.11.0 + '@types/node': ^18.11.7 + '@types/qrcode': ^1.5.0 '@ucanto/client': ^2.0.0 '@ucanto/core': ^2.0.0 '@ucanto/interface': ^2.0.0 @@ -124,12 +127,12 @@ importers: '@web3-storage/access': workspace:^ '@web3-storage/worker-utils': 0.4.3-dev assert: ^2.0.0 - ava: ^4.3.3 + ava: ^5.0.1 better-sqlite3: 7.6.2 buffer: ^6.0.3 delay: ^5.0.0 dotenv: ^16.0.3 - esbuild: ^0.15.10 + esbuild: ^0.15.12 execa: ^6.1.0 git-rev-sync: ^3.0.1 hd-scripts: ^3.0.2 @@ -137,13 +140,16 @@ importers: multiformats: ^9.8.1 nanoid: ^4.0.0 p-retry: ^5.1.1 + preact: ^10.11.2 + preact-render-to-string: ^5.2.6 process: ^0.11.10 + qrcode: ^1.5.1 readable-stream: ^4.1.0 sade: ^1.7.4 toucan-js: ^2.7.0 typescript: 4.8.4 workers-qb: ^0.1.2 - wrangler: ^2.1.12 + wrangler: ^2.1.13 dependencies: '@ipld/dag-ucan': 4.0.0-beta '@ucanto/client': 2.0.0 @@ -158,22 +164,28 @@ importers: multiformats: 9.9.0 nanoid: 4.0.0 p-retry: 5.1.1 + preact: 10.11.2 + preact-render-to-string: 5.2.6_preact@10.11.2 + qrcode: 1.5.1 toucan-js: 2.7.0 workers-qb: 0.1.2 devDependencies: - '@cloudflare/workers-types': 3.17.0 - '@sentry/cli': 2.7.0 + '@cloudflare/workers-types': 3.18.0 + '@databases/escape-identifier': 1.0.3 + '@databases/sql': 3.2.0 + '@sentry/cli': 2.8.0 '@sentry/webpack-plugin': 1.19.1 '@types/assert': 1.5.6 '@types/git-rev-sync': 2.0.0 - '@types/node': 18.11.0 + '@types/node': 18.11.7 + '@types/qrcode': 1.5.0 assert: 2.0.0 - ava: 4.3.3 + ava: 5.0.1 better-sqlite3: 7.6.2 buffer: 6.0.3 delay: 5.0.0 dotenv: 16.0.3 - esbuild: 0.15.11 + esbuild: 0.15.12 execa: 6.1.0 git-rev-sync: 3.0.2 hd-scripts: 3.0.2 @@ -182,24 +194,24 @@ importers: readable-stream: 4.2.0 sade: 1.8.1 typescript: 4.8.4 - wrangler: 2.1.12 + wrangler: 2.1.13 packages/access-ws: specifiers: - '@cloudflare/workers-types': ^3.16.0 - '@sentry/cli': ^2.7.0 + '@cloudflare/workers-types': ^3.18.0 + '@sentry/cli': ^2.8.0 '@sentry/webpack-plugin': ^1.19.1 '@types/assert': ^1.5.6 '@types/git-rev-sync': ^2.0.0 - '@types/node': ^18.11.0 + '@types/node': ^18.11.7 '@types/ws': ^8.5.3 '@web3-storage/worker-utils': 0.4.3-dev assert: ^2.0.0 - ava: ^4.3.3 + ava: ^5.0.1 buffer: ^6.0.3 delay: ^5.0.0 dotenv: ^16.0.3 - esbuild: ^0.15.10 + esbuild: ^0.15.12 execa: ^6.1.0 git-rev-sync: ^3.0.1 hd-scripts: ^3.0.2 @@ -213,29 +225,29 @@ importers: sade: ^1.7.4 toucan-js: ^2.7.0 typescript: 4.8.4 - wrangler: ^2.1.12 - ws: ^8.8.1 + wrangler: ^2.1.13 + ws: ^8.10.0 dependencies: '@types/ws': 8.5.3 '@web3-storage/worker-utils': 0.4.3-dev - isomorphic-ws: 5.0.0_ws@8.9.0 + isomorphic-ws: 5.0.0_ws@8.10.0 multiformats: 9.9.0 nanoid: 4.0.0 toucan-js: 2.7.0 - ws: 8.9.0 + ws: 8.10.0 devDependencies: - '@cloudflare/workers-types': 3.17.0 - '@sentry/cli': 2.7.0 + '@cloudflare/workers-types': 3.18.0 + '@sentry/cli': 2.8.0 '@sentry/webpack-plugin': 1.19.1 '@types/assert': 1.5.6 '@types/git-rev-sync': 2.0.0 - '@types/node': 18.11.0 + '@types/node': 18.11.7 assert: 2.0.0 - ava: 4.3.3 + ava: 5.0.1 buffer: 6.0.3 delay: 5.0.0 dotenv: 16.0.3 - esbuild: 0.15.11 + esbuild: 0.15.12 execa: 6.1.0 git-rev-sync: 3.0.2 hd-scripts: 3.0.2 @@ -245,7 +257,7 @@ importers: readable-stream: 4.2.0 sade: 1.8.1 typescript: 4.8.4 - wrangler: 2.1.12 + wrangler: 2.1.13 packages/store: specifiers: @@ -292,28 +304,28 @@ importers: packages/wallet: specifiers: - '@types/node': ^18.11.0 - '@types/react': ^18.0.20 - eslint: ^8.25.0 + '@types/node': ^18.11.7 + '@types/react': ^18.0.24 + eslint: ^8.26.0 eslint-config-next: 12.3.1 hd-scripts: ^3.0.2 next: 12.3.1 react: 18.2.0 react-dom: 18.2.0 typescript: 4.8.4 - wrangler: ^2.1.12 + wrangler: ^2.1.13 dependencies: next: 12.3.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 devDependencies: - '@types/node': 18.11.0 - '@types/react': 18.0.21 - eslint: 8.25.0 - eslint-config-next: 12.3.1_z4bbprzjrhnsfa24uvmcbu7f5q + '@types/node': 18.11.7 + '@types/react': 18.0.24 + eslint: 8.26.0 + eslint-config-next: 12.3.1_wyqvi574yv7oiwfeinomdzmc3m hd-scripts: 3.0.2 typescript: 4.8.4 - wrangler: 2.1.12 + wrangler: 2.1.13 packages: @@ -364,8 +376,22 @@ packages: mime: 3.0.0 dev: true - /@cloudflare/workers-types/3.17.0: - resolution: {integrity: sha512-u0cUQ4ntWFFwn5jx0ETa2ItvwvfOMjyaKF2fX2vFVujrSgNES/PnvRzPAhdt9CMYAMidInm0MGkIjxHRsFBaeg==} + /@cloudflare/workers-types/3.18.0: + resolution: {integrity: sha512-ehKOJVLMeR+tZkYhWEaLYQxl0TaIZu/kE86HF3/RidR8Xv5LuQxpbh+XXAoKVqsaphWLhIgBhgnlN5HGdheXSQ==} + dev: true + + /@databases/escape-identifier/1.0.3: + resolution: {integrity: sha512-Su36iSVzaHxpVdISVMViUX/32sLvzxVgjZpYhzhotxZUuLo11GVWsiHwqkvUZijTLUxcDmUqEwGJO3O/soLuZA==} + dependencies: + '@databases/validate-unicode': 1.0.0 + dev: true + + /@databases/sql/3.2.0: + resolution: {integrity: sha512-xQZzKIa0lvcdo0MYxnyFMVS1TRla9lpDSCYkobJl19vQEOJ9TqE4o8QBGRJNUfhSkbQIWyvMeBl3KBBbqyUVQQ==} + dev: true + + /@databases/validate-unicode/1.0.0: + resolution: {integrity: sha512-dLKqxGcymeVwEb/6c44KjOnzaAafFf0Wxa8xcfEjx/qOl3rdijsKYBAtIGhtVtOlpPf/PFKfgTuFurSPn/3B/g==} dev: true /@es-joy/jsdoccomment/0.32.0: @@ -395,8 +421,8 @@ packages: rollup-plugin-node-polyfills: 0.2.1 dev: true - /@esbuild/android-arm/0.15.11: - resolution: {integrity: sha512-PzMcQLazLBkwDEkrNPi9AbjFt6+3I7HKbiYF2XtWQ7wItrHvEOeO3T8Am434zAozWtVP7lrTue1bEfc2nYWeCA==} + /@esbuild/android-arm/0.15.12: + resolution: {integrity: sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -404,8 +430,8 @@ packages: dev: true optional: true - /@esbuild/linux-loong64/0.15.11: - resolution: {integrity: sha512-geWp637tUhNmhL3Xgy4Bj703yXB9dqiLJe05lCUfjSFDrQf9C/8pArusyPUbUbPwlC/EAUjBw32sxuIl/11dZw==} + /@esbuild/linux-loong64/0.15.12: + resolution: {integrity: sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -441,6 +467,17 @@ packages: - supports-color dev: true + /@humanwhocodes/config-array/0.11.6: + resolution: {integrity: sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + /@humanwhocodes/module-importer/1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} @@ -578,7 +615,7 @@ packages: kleur: 4.1.5 selfsigned: 2.1.1 undici: 5.9.1 - ws: 8.9.0 + ws: 8.10.0 youch: 2.2.2 transitivePeerDependencies: - bufferutil @@ -671,7 +708,7 @@ packages: '@miniflare/core': 2.10.0 '@miniflare/shared': 2.10.0 undici: 5.9.1 - ws: 8.9.0 + ws: 8.10.0 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -872,8 +909,8 @@ packages: - supports-color dev: true - /@sentry/cli/2.7.0: - resolution: {integrity: sha512-rSKPFun5mKxQCWOo3ERdhz9avdTsiz3A7GD5GcsML2iB0NQ5ErlNQIMFGC+8EXOHCjjsLSi13lh6cPeccz81nw==} + /@sentry/cli/2.8.0: + resolution: {integrity: sha512-tlYlFFvBN167/d4ussQcRThHNtYcr4SM+r58xP4/uiH3LmYNk1soRbVjiHMc2p3F5tWQ3Mu5JYT5ww39YT4m6w==} engines: {node: '>= 12'} hasBin: true requiresBuild: true @@ -955,7 +992,7 @@ packages: /@types/better-sqlite3/7.6.2: resolution: {integrity: sha512-RgmaapusqTq6IMAr4McMyAsC6RshYTCjXCnzwVV59WctUxC8bNPyUfT9t5F81lKcU41lLurhjqjoMHfauzfqGg==} dependencies: - '@types/node': 18.11.0 + '@types/node': 18.11.7 dev: true /@types/chai-subset/1.3.3: @@ -999,8 +1036,8 @@ packages: resolution: {integrity: sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg==} dev: true - /@types/node/18.11.0: - resolution: {integrity: sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==} + /@types/node/18.11.7: + resolution: {integrity: sha512-LhFTglglr63mNXUSRYD8A+ZAIu5sFqNJ4Y2fPuY7UlrySJH87rRRlhtVmMHplmfk5WkoJGmDjE9oiTfyX94CpQ==} /@types/normalize-package-data/2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} @@ -1010,8 +1047,14 @@ packages: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} dev: true - /@types/react/18.0.21: - resolution: {integrity: sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==} + /@types/qrcode/1.5.0: + resolution: {integrity: sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA==} + dependencies: + '@types/node': 18.11.7 + dev: true + + /@types/react/18.0.24: + resolution: {integrity: sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q==} dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 @@ -1037,13 +1080,13 @@ packages: /@types/through/0.0.30: resolution: {integrity: sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==} dependencies: - '@types/node': 18.11.0 + '@types/node': 18.11.7 dev: true /@types/ws/8.5.3: resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==} dependencies: - '@types/node': 18.11.0 + '@types/node': 18.11.7 dev: false /@types/yargs-parser/21.0.0: @@ -1095,6 +1138,26 @@ packages: - typescript dev: true + /@typescript-eslint/parser/5.40.1_wyqvi574yv7oiwfeinomdzmc3m: + resolution: {integrity: sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.40.1 + '@typescript-eslint/types': 5.40.1 + '@typescript-eslint/typescript-estree': 5.40.1_typescript@4.8.4 + debug: 4.3.4 + eslint: 8.26.0 + typescript: 4.8.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/parser/5.40.1_z4bbprzjrhnsfa24uvmcbu7f5q: resolution: {integrity: sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1346,6 +1409,12 @@ packages: hasBin: true dev: true + /acorn/8.8.1: + resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /agent-base/6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -1425,7 +1494,6 @@ packages: /ansi-regex/5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true /ansi-regex/6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} @@ -1443,7 +1511,6 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles/6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} @@ -1586,9 +1653,9 @@ packages: engines: {node: '>=10.12.0'} dev: false - /ava/4.3.3: - resolution: {integrity: sha512-9Egq/d9R74ExrWohHeqUlexjDbgZJX5jA1Wq4KCTqc3wIfpGEK79zVy4rBtofJ9YKIxs4PzhJ8BgbW5PlAYe6w==} - engines: {node: '>=12.22 <13 || >=14.17 <15 || >=16.4 <17 || >=18'} + /ava/5.0.1: + resolution: {integrity: sha512-nS1eK3HhWaC+eGHtteF5j4yZMjaIE+q2o+oyqD75xsmS87R5sGlxADYWkFIGyB28jrDmAATZAAx+s3JhYsnhNw==} + engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} hasBin: true peerDependencies: '@ava/typescript': '*' @@ -1596,7 +1663,7 @@ packages: '@ava/typescript': optional: true dependencies: - acorn: 8.8.0 + acorn: 8.8.1 acorn-walk: 8.2.0 ansi-styles: 6.2.1 arrgv: 1.0.2 @@ -1615,9 +1682,9 @@ packages: concordance: 5.0.4 currently-unhandled: 0.4.1 debug: 4.3.4 - del: 6.1.1 - emittery: 0.11.0 - figures: 4.0.1 + del: 7.0.0 + emittery: 1.0.0 + figures: 5.0.0 globby: 13.1.2 ignore-by-default: 2.1.0 indent-string: 5.0.0 @@ -1632,7 +1699,7 @@ packages: picomatch: 2.3.1 pkg-conf: 4.0.0 plur: 5.1.0 - pretty-ms: 7.0.1 + pretty-ms: 8.0.0 resolve-cwd: 3.0.0 slash: 3.0.0 stack-utils: 2.0.5 @@ -1786,6 +1853,11 @@ packages: engines: {node: '>=12.20'} dev: true + /camelcase/5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: false + /camelcase/6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} @@ -1947,6 +2019,14 @@ packages: engines: {node: '>= 12'} dev: false + /cliui/6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: false + /cliui/7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: @@ -1991,7 +2071,6 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name/1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -1999,7 +2078,6 @@ packages: /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true /color-support/1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} @@ -2215,6 +2293,11 @@ packages: supports-color: 8.1.1 dev: true + /decamelize/1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: false + /decamelize/4.0.0: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} @@ -2279,18 +2362,18 @@ packages: resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} dev: true - /del/6.1.1: - resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} - engines: {node: '>=10'} + /del/7.0.0: + resolution: {integrity: sha512-tQbV/4u5WVB8HMJr08pgw0b6nG4RGt/tj+7Numvq+zqcvUFeMaIWWOUFltiU+6go8BSO2/ogsB4EasDaj0y68Q==} + engines: {node: '>=14.16'} dependencies: - globby: 11.1.0 + globby: 13.1.2 graceful-fs: 4.2.10 is-glob: 4.0.3 - is-path-cwd: 2.2.0 - is-path-inside: 3.0.3 - p-map: 4.0.0 + is-path-cwd: 3.0.0 + is-path-inside: 4.0.0 + p-map: 5.5.0 rimraf: 3.0.2 - slash: 3.0.0 + slash: 4.0.0 dev: true /delay/5.0.0: @@ -2312,6 +2395,10 @@ packages: engines: {node: '>=0.3.1'} dev: true + /dijkstrajs/1.0.2: + resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==} + dev: false + /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2360,18 +2447,21 @@ packages: /eastasianwidth/0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - /emittery/0.11.0: - resolution: {integrity: sha512-S/7tzL6v5i+4iJd627Nhv9cLFIo5weAIlGccqJFpnBoDB8U1TF2k5tez4J/QNuxyyhWuFqHg1L84Kd3m7iXg6g==} - engines: {node: '>=12'} + /emittery/1.0.0: + resolution: {integrity: sha512-TD/u5aAn5W2HI2OukSIReNYXf/cH7U0QZHPxM4aIVYy0CmtrLCvf+7E8MuV2BbO02l6wq4sAKuFA8H16l6AHMA==} + engines: {node: '>=14.16'} dev: true /emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true /emoji-regex/9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + /encode-utf8/1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + dev: false + /end-of-stream/1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: @@ -2473,8 +2563,8 @@ packages: dev: true optional: true - /esbuild-android-64/0.15.11: - resolution: {integrity: sha512-rrwoXEiuI1kaw4k475NJpexs8GfJqQUKcD08VR8sKHmuW9RUuTR2VxcupVvHdiGh9ihxL9m3lpqB1kju92Ialw==} + /esbuild-android-64/0.15.12: + resolution: {integrity: sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -2500,8 +2590,8 @@ packages: dev: true optional: true - /esbuild-android-arm64/0.15.11: - resolution: {integrity: sha512-/hDubOg7BHOhUUsT8KUIU7GfZm5bihqssvqK5PfO4apag7YuObZRZSzViyEKcFn2tPeHx7RKbSBXvAopSHDZJQ==} + /esbuild-android-arm64/0.15.12: + resolution: {integrity: sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -2527,8 +2617,8 @@ packages: dev: true optional: true - /esbuild-darwin-64/0.15.11: - resolution: {integrity: sha512-1DqHD0ms3AhiwkKnjRUzmiW7JnaJJr5FKrPiR7xuyMwnjDqvNWDdMq4rKSD9OC0piFNK6n0LghsglNMe2MwJtA==} + /esbuild-darwin-64/0.15.12: + resolution: {integrity: sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -2554,8 +2644,8 @@ packages: dev: true optional: true - /esbuild-darwin-arm64/0.15.11: - resolution: {integrity: sha512-OMzhxSbS0lwwrW40HHjRCeVIJTURdXFA8c3GU30MlHKuPCcvWNUIKVucVBtNpJySXmbkQMDJdJNrXzNDyvoqvQ==} + /esbuild-darwin-arm64/0.15.12: + resolution: {integrity: sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -2581,8 +2671,8 @@ packages: dev: true optional: true - /esbuild-freebsd-64/0.15.11: - resolution: {integrity: sha512-8dKP26r0/Qyez8nTCwpq60QbuYKOeBygdgOAWGCRalunyeqWRoSZj9TQjPDnTTI9joxd3QYw3UhVZTKxO9QdRg==} + /esbuild-freebsd-64/0.15.12: + resolution: {integrity: sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -2608,8 +2698,8 @@ packages: dev: true optional: true - /esbuild-freebsd-arm64/0.15.11: - resolution: {integrity: sha512-aSGiODiukLGGnSg/O9+cGO2QxEacrdCtCawehkWYTt5VX1ni2b9KoxpHCT9h9Y6wGqNHmXFnB47RRJ8BIqZgmQ==} + /esbuild-freebsd-arm64/0.15.12: + resolution: {integrity: sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -2635,8 +2725,8 @@ packages: dev: true optional: true - /esbuild-linux-32/0.15.11: - resolution: {integrity: sha512-lsrAfdyJBGx+6aHIQmgqUonEzKYeBnyfJPkT6N2dOf1RoXYYV1BkWB6G02tjsrz1d5wZzaTc3cF+TKmuTo/ZwA==} + /esbuild-linux-32/0.15.12: + resolution: {integrity: sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -2662,8 +2752,8 @@ packages: dev: true optional: true - /esbuild-linux-64/0.15.11: - resolution: {integrity: sha512-Y2Rh+PcyVhQqXKBTacPCltINN3uIw2xC+dsvLANJ1SpK5NJUtxv8+rqWpjmBgaNWKQT1/uGpMmA9olALy9PLVA==} + /esbuild-linux-64/0.15.12: + resolution: {integrity: sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -2689,8 +2779,8 @@ packages: dev: true optional: true - /esbuild-linux-arm/0.15.11: - resolution: {integrity: sha512-TJllTVk5aSyqPFvvcHTvf6Wu1ZKhWpJ/qNmZO8LL/XeB+LXCclm7HQHNEIz6MT7IX8PmlC1BZYrOiw2sXSB95A==} + /esbuild-linux-arm/0.15.12: + resolution: {integrity: sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -2716,8 +2806,8 @@ packages: dev: true optional: true - /esbuild-linux-arm64/0.15.11: - resolution: {integrity: sha512-uhcXiTwTmD4OpxJu3xC5TzAAw6Wzf9O1XGWL448EE9bqGjgV1j+oK3lIHAfsHnuIn8K4nDW8yjX0Sv5S++oRuw==} + /esbuild-linux-arm64/0.15.12: + resolution: {integrity: sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -2743,8 +2833,8 @@ packages: dev: true optional: true - /esbuild-linux-mips64le/0.15.11: - resolution: {integrity: sha512-WD61y/R1M4BLe4gxXRypoQ0Ci+Vjf714QYzcPNkiYv5I8K8WDz2ZR8Bm6cqKxd6rD+e/rZgPDbhQ9PCf7TMHmA==} + /esbuild-linux-mips64le/0.15.12: + resolution: {integrity: sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -2770,8 +2860,8 @@ packages: dev: true optional: true - /esbuild-linux-ppc64le/0.15.11: - resolution: {integrity: sha512-JVleZS9oPVLTlBhPTWgOwxFWU/wMUdlBwTbGA4GF8c38sLbS13cupj+C8bLq929jU7EMWry4SaL+tKGIaTlqKg==} + /esbuild-linux-ppc64le/0.15.12: + resolution: {integrity: sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -2797,8 +2887,8 @@ packages: dev: true optional: true - /esbuild-linux-riscv64/0.15.11: - resolution: {integrity: sha512-9aLIalZ2HFHIOZpmVU11sEAS9F8TnHw49daEjcgMpBXHFF57VuT9f9/9LKJhw781Gda0P9jDkuCWJ0tFbErvJw==} + /esbuild-linux-riscv64/0.15.12: + resolution: {integrity: sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -2824,8 +2914,8 @@ packages: dev: true optional: true - /esbuild-linux-s390x/0.15.11: - resolution: {integrity: sha512-sZHtiXXOKsLI3XGBGoYO4qKBzJlb8xNsWmvFiwFMHFzA4AXgDP1KDp7Dawe9C2pavTRBDvl+Ok4n/DHQ59oaTg==} + /esbuild-linux-s390x/0.15.12: + resolution: {integrity: sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -2851,8 +2941,8 @@ packages: dev: true optional: true - /esbuild-netbsd-64/0.15.11: - resolution: {integrity: sha512-hUC9yN06K9sg7ju4Vgu9ChAPdsEgtcrcLfyNT5IKwKyfpLvKUwCMZSdF+gRD3WpyZelgTQfJ+pDx5XFbXTlB0A==} + /esbuild-netbsd-64/0.15.12: + resolution: {integrity: sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -2878,8 +2968,8 @@ packages: dev: true optional: true - /esbuild-openbsd-64/0.15.11: - resolution: {integrity: sha512-0bBo9SQR4t66Wd91LGMAqmWorzO0TTzVjYiifwoFtel8luFeXuPThQnEm5ztN4g0fnvcp7AnUPPzS/Depf17wQ==} + /esbuild-openbsd-64/0.15.12: + resolution: {integrity: sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -2905,8 +2995,8 @@ packages: dev: true optional: true - /esbuild-sunos-64/0.15.11: - resolution: {integrity: sha512-EuBdTGlsMTjEl1sQnBX2jfygy7iR6CKfvOzi+gEOfhDqbHXsmY1dcpbVtcwHAg9/2yUZSfMJHMAgf1z8M4yyyw==} + /esbuild-sunos-64/0.15.12: + resolution: {integrity: sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -2932,8 +3022,8 @@ packages: dev: true optional: true - /esbuild-windows-32/0.15.11: - resolution: {integrity: sha512-O0/Wo1Wk6dc0rZSxkvGpmTNIycEznHmkObTFz2VHBhjPsO4ZpCgfGxNkCpz4AdAIeMczpTXt/8d5vdJNKEGC+Q==} + /esbuild-windows-32/0.15.12: + resolution: {integrity: sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -2959,8 +3049,8 @@ packages: dev: true optional: true - /esbuild-windows-64/0.15.11: - resolution: {integrity: sha512-x977Q4HhNjnHx00b4XLAnTtj5vfbdEvkxaQwC1Zh5AN8g5EX+izgZ6e5QgqJgpzyRNJqh4hkgIJF1pyy1be0mQ==} + /esbuild-windows-64/0.15.12: + resolution: {integrity: sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -2986,8 +3076,8 @@ packages: dev: true optional: true - /esbuild-windows-arm64/0.15.11: - resolution: {integrity: sha512-VwUHFACuBahrvntdcMKZteUZ9HaYrBRODoKe4tIWxguQRvvYoYb7iu5LrcRS/FQx8KPZNaa72zuqwVtHeXsITw==} + /esbuild-windows-arm64/0.15.12: + resolution: {integrity: sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -3051,34 +3141,34 @@ packages: esbuild-windows-arm64: 0.14.51 dev: true - /esbuild/0.15.11: - resolution: {integrity: sha512-OgHGuhlfZ//mToxjte1D5iiiQgWfJ2GByVMwEC/IuoXsBGkuyK1+KrjYu0laSpnN/L1UmLUCv0s25vObdc1bVg==} + /esbuild/0.15.12: + resolution: {integrity: sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.15.11 - '@esbuild/linux-loong64': 0.15.11 - esbuild-android-64: 0.15.11 - esbuild-android-arm64: 0.15.11 - esbuild-darwin-64: 0.15.11 - esbuild-darwin-arm64: 0.15.11 - esbuild-freebsd-64: 0.15.11 - esbuild-freebsd-arm64: 0.15.11 - esbuild-linux-32: 0.15.11 - esbuild-linux-64: 0.15.11 - esbuild-linux-arm: 0.15.11 - esbuild-linux-arm64: 0.15.11 - esbuild-linux-mips64le: 0.15.11 - esbuild-linux-ppc64le: 0.15.11 - esbuild-linux-riscv64: 0.15.11 - esbuild-linux-s390x: 0.15.11 - esbuild-netbsd-64: 0.15.11 - esbuild-openbsd-64: 0.15.11 - esbuild-sunos-64: 0.15.11 - esbuild-windows-32: 0.15.11 - esbuild-windows-64: 0.15.11 - esbuild-windows-arm64: 0.15.11 + '@esbuild/android-arm': 0.15.12 + '@esbuild/linux-loong64': 0.15.12 + esbuild-android-64: 0.15.12 + esbuild-android-arm64: 0.15.12 + esbuild-darwin-64: 0.15.12 + esbuild-darwin-arm64: 0.15.12 + esbuild-freebsd-64: 0.15.12 + esbuild-freebsd-arm64: 0.15.12 + esbuild-linux-32: 0.15.12 + esbuild-linux-64: 0.15.12 + esbuild-linux-arm: 0.15.12 + esbuild-linux-arm64: 0.15.12 + esbuild-linux-mips64le: 0.15.12 + esbuild-linux-ppc64le: 0.15.12 + esbuild-linux-riscv64: 0.15.12 + esbuild-linux-s390x: 0.15.12 + esbuild-netbsd-64: 0.15.12 + esbuild-openbsd-64: 0.15.12 + esbuild-sunos-64: 0.15.12 + esbuild-windows-32: 0.15.12 + esbuild-windows-64: 0.15.12 + esbuild-windows-arm64: 0.15.12 dev: true /escalade/3.1.1: @@ -3105,7 +3195,7 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - /eslint-config-next/12.3.1_z4bbprzjrhnsfa24uvmcbu7f5q: + /eslint-config-next/12.3.1_wyqvi574yv7oiwfeinomdzmc3m: resolution: {integrity: sha512-EN/xwKPU6jz1G0Qi6Bd/BqMnHLyRAL0VsaQaWA7F3KkjAgZHi4f1uL1JKGWNxdQpHTW/sdGONBd0bzxUka/DJg==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 @@ -3116,14 +3206,14 @@ packages: dependencies: '@next/eslint-plugin-next': 12.3.1 '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/parser': 5.40.1_z4bbprzjrhnsfa24uvmcbu7f5q - eslint: 8.25.0 + '@typescript-eslint/parser': 5.40.1_wyqvi574yv7oiwfeinomdzmc3m + eslint: 8.26.0 eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1_fyln4uq2tv75svthy6prqvt6lm - eslint-plugin-import: 2.26.0_5vut3wpz4wsceb35kpfwryopom - eslint-plugin-jsx-a11y: 6.6.1_eslint@8.25.0 - eslint-plugin-react: 7.31.10_eslint@8.25.0 - eslint-plugin-react-hooks: 4.6.0_eslint@8.25.0 + eslint-import-resolver-typescript: 2.7.1_mynvxvmq5qtyojffiqgev4x7mm + eslint-plugin-import: 2.26.0_ktm3uujnlhunjxml6wzsncefba + eslint-plugin-jsx-a11y: 6.6.1_eslint@8.26.0 + eslint-plugin-react: 7.31.10_eslint@8.26.0 + eslint-plugin-react-hooks: 4.6.0_eslint@8.26.0 typescript: 4.8.4 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -3199,7 +3289,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript/2.7.1_fyln4uq2tv75svthy6prqvt6lm: + /eslint-import-resolver-typescript/2.7.1_mynvxvmq5qtyojffiqgev4x7mm: resolution: {integrity: sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==} engines: {node: '>=4'} peerDependencies: @@ -3207,8 +3297,8 @@ packages: eslint-plugin-import: '*' dependencies: debug: 4.3.4 - eslint: 8.25.0 - eslint-plugin-import: 2.26.0_5vut3wpz4wsceb35kpfwryopom + eslint: 8.26.0 + eslint-plugin-import: 2.26.0_ktm3uujnlhunjxml6wzsncefba glob: 7.2.3 is-glob: 4.0.3 resolve: 1.22.1 @@ -3217,7 +3307,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_h5tegsfcqrqox63x72ptubo4ii: + /eslint-module-utils/2.7.4_cpvribsnrifdnai62ae2t2h4ju: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -3238,11 +3328,11 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.40.1_z4bbprzjrhnsfa24uvmcbu7f5q + '@typescript-eslint/parser': 5.40.1_wyqvi574yv7oiwfeinomdzmc3m debug: 3.2.7 - eslint: 8.25.0 + eslint: 8.26.0 eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1_fyln4uq2tv75svthy6prqvt6lm + eslint-import-resolver-typescript: 2.7.1_mynvxvmq5qtyojffiqgev4x7mm transitivePeerDependencies: - supports-color dev: true @@ -3305,7 +3395,7 @@ packages: - supports-color dev: true - /eslint-plugin-import/2.26.0_5vut3wpz4wsceb35kpfwryopom: + /eslint-plugin-import/2.26.0_ktm3uujnlhunjxml6wzsncefba: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -3315,14 +3405,14 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.40.1_z4bbprzjrhnsfa24uvmcbu7f5q + '@typescript-eslint/parser': 5.40.1_wyqvi574yv7oiwfeinomdzmc3m array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 - eslint: 8.25.0 + eslint: 8.26.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_h5tegsfcqrqox63x72ptubo4ii + eslint-module-utils: 2.7.4_cpvribsnrifdnai62ae2t2h4ju has: 1.0.3 is-core-module: 2.10.0 is-glob: 4.0.3 @@ -3385,7 +3475,7 @@ packages: - supports-color dev: true - /eslint-plugin-jsx-a11y/6.6.1_eslint@8.25.0: + /eslint-plugin-jsx-a11y/6.6.1_eslint@8.26.0: resolution: {integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==} engines: {node: '>=4.0'} peerDependencies: @@ -3399,7 +3489,7 @@ packages: axobject-query: 2.2.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 8.25.0 + eslint: 8.26.0 has: 1.0.3 jsx-ast-utils: 3.3.3 language-tags: 1.0.5 @@ -3447,6 +3537,15 @@ packages: eslint: 8.25.0 dev: true + /eslint-plugin-react-hooks/4.6.0_eslint@8.26.0: + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.26.0 + dev: true + /eslint-plugin-react/7.31.10_eslint@8.25.0: resolution: {integrity: sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==} engines: {node: '>=4'} @@ -3470,6 +3569,29 @@ packages: string.prototype.matchall: 4.0.7 dev: true + /eslint-plugin-react/7.31.10_eslint@8.26.0: + resolution: {integrity: sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.5 + array.prototype.flatmap: 1.3.0 + doctrine: 2.1.0 + eslint: 8.26.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.3 + minimatch: 3.1.2 + object.entries: 1.1.5 + object.fromentries: 2.0.5 + object.hasown: 1.1.1 + object.values: 1.1.5 + prop-types: 15.8.1 + resolve: 2.0.0-next.4 + semver: 6.3.0 + string.prototype.matchall: 4.0.7 + dev: true + /eslint-plugin-unicorn/44.0.2_eslint@8.25.0: resolution: {integrity: sha512-GLIDX1wmeEqpGaKcnMcqRvMVsoabeF0Ton0EX4Th5u6Kmf7RM9WBl705AXFEsns56ESkEs0uyelLuUTvz9Tr0w==} engines: {node: '>=14.18'} @@ -3526,6 +3648,16 @@ packages: eslint-visitor-keys: 2.1.0 dev: true + /eslint-utils/3.0.0_eslint@8.26.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.26.0 + eslint-visitor-keys: 2.1.0 + dev: true + /eslint-visitor-keys/1.3.0: resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} engines: {node: '>=4'} @@ -3588,6 +3720,54 @@ packages: - supports-color dev: true + /eslint/8.26.0: + resolution: {integrity: sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.3.3 + '@humanwhocodes/config-array': 0.11.6 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0_eslint@8.26.0 + eslint-visitor-keys: 3.3.0 + espree: 9.4.0 + esquery: 1.4.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.17.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.0 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-sdsl: 4.1.5 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /espree/9.4.0: resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3717,21 +3897,12 @@ packages: reusify: 1.0.4 dev: true - /figures/4.0.1: - resolution: {integrity: sha512-rElJwkA/xS04Vfg+CaZodpso7VqBknOYbzi6I76hI4X80RUjkSxO2oAyPmGbuXUppywjqndOrQDl817hDnI++w==} - engines: {node: '>=12'} - dependencies: - escape-string-regexp: 5.0.0 - is-unicode-supported: 1.3.0 - dev: true - /figures/5.0.0: resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} engines: {node: '>=14'} dependencies: escape-string-regexp: 5.0.0 is-unicode-supported: 1.3.0 - dev: false /file-entry-cache/6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} @@ -3764,7 +3935,6 @@ packages: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - dev: true /find-up/5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -3865,7 +4035,6 @@ packages: /get-caller-file/2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - dev: true /get-func-name/2.0.0: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} @@ -4271,7 +4440,6 @@ packages: /is-fullwidth-code-point/3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true /is-fullwidth-code-point/4.0.0: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} @@ -4327,9 +4495,9 @@ packages: engines: {node: '>=8'} dev: false - /is-path-cwd/2.2.0: - resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} - engines: {node: '>=6'} + /is-path-cwd/3.0.0: + resolution: {integrity: sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true /is-path-inside/3.0.3: @@ -4337,6 +4505,11 @@ packages: engines: {node: '>=8'} dev: true + /is-path-inside/4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + dev: true + /is-plain-obj/2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} @@ -4431,12 +4604,12 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true - /isomorphic-ws/5.0.0_ws@8.9.0: + /isomorphic-ws/5.0.0_ws@8.10.0: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: ws: '*' dependencies: - ws: 8.9.0 + ws: 8.10.0 dev: false /js-sdsl/4.1.5: @@ -4608,7 +4781,6 @@ packages: engines: {node: '>=8'} dependencies: p-locate: 4.1.0 - dev: true /locate-path/6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} @@ -5260,7 +5432,6 @@ packages: engines: {node: '>=8'} dependencies: p-limit: 2.3.0 - dev: true /p-locate/5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} @@ -5355,9 +5526,9 @@ packages: lines-and-columns: 1.2.4 dev: true - /parse-ms/2.1.0: - resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} - engines: {node: '>=6'} + /parse-ms/3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} dev: true /parse-package-name/1.0.0: @@ -5376,7 +5547,6 @@ packages: /path-exists/4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - dev: true /path-exists/5.0.0: resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} @@ -5498,6 +5668,11 @@ packages: engines: {node: '>=4'} dev: true + /pngjs/5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + dev: false + /polka/0.5.2: resolution: {integrity: sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==} dependencies: @@ -5514,6 +5689,19 @@ packages: source-map-js: 1.0.2 dev: false + /preact-render-to-string/5.2.6_preact@10.11.2: + resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==} + peerDependencies: + preact: '>=10' + dependencies: + preact: 10.11.2 + pretty-format: 3.8.0 + dev: false + + /preact/10.11.2: + resolution: {integrity: sha512-skAwGDFmgxhq1DCBHke/9e12ewkhc7WYwjuhHB8HHS8zkdtITXLRmUMTeol2ldxvLwYtwbFeifZ9uDDWuyL4Iw==} + dev: false + /prebuild-install/7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} engines: {node: '>=10'} @@ -5550,11 +5738,15 @@ packages: hasBin: true dev: true - /pretty-ms/7.0.1: - resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} - engines: {node: '>=10'} + /pretty-format/3.8.0: + resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} + dev: false + + /pretty-ms/8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} dependencies: - parse-ms: 2.1.0 + parse-ms: 3.0.0 dev: true /process-nextick-args/2.0.1: @@ -5594,6 +5786,17 @@ packages: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} + /qrcode/1.5.1: + resolution: {integrity: sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + dijkstrajs: 1.0.2 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + dev: false + /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -5723,13 +5926,16 @@ packages: /require-directory/2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - dev: true /require-from-string/2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} dev: false + /require-main-filename/2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: false + /requireindex/1.2.0: resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} engines: {node: '>=0.10.5'} @@ -5930,7 +6136,6 @@ packages: /set-blocking/2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - dev: true /set-cookie-parser/2.5.1: resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==} @@ -6156,7 +6361,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true /string-width/5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -6225,7 +6429,6 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: true /strip-ansi/7.0.1: resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} @@ -6554,8 +6757,8 @@ packages: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - /undici/5.11.0: - resolution: {integrity: sha512-oWjWJHzFet0Ow4YZBkyiJwiK5vWqEYoH7BINzJAJOLedZ++JpAlCbUktW2GQ2DS2FpKmxD/JMtWUUWl1BtghGw==} + /undici/5.12.0: + resolution: {integrity: sha512-zMLamCG62PGjd9HHMpo05bSLvvwWOZgGeiWlN/vlqu3+lRo3elxktVGEyLMX+IO7c2eflLjcW74AlkhEZm15mg==} engines: {node: '>=12.18'} dependencies: busboy: 1.6.0 @@ -6695,6 +6898,10 @@ packages: is-weakset: 2.0.2 dev: true + /which-module/2.0.0: + resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} + dev: false + /which-typed-array/1.1.8: resolution: {integrity: sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==} engines: {node: '>= 0.4'} @@ -6717,7 +6924,7 @@ packages: /wide-align/1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} dependencies: - string-width: 4.2.3 + string-width: 1.0.2 dev: true /word-wrap/1.2.3: @@ -6733,8 +6940,8 @@ packages: resolution: {integrity: sha512-y38RiVOEJPmqSSQniVPKQrWE8XocqeRWO9TwgfXTMARzQa3aGwsaBwUdOBn5MJukZwIkGOYsljK76kMGLu5aOA==} dev: false - /wrangler/2.1.12: - resolution: {integrity: sha512-Oe3lBVR4b2o44A90S+3Bi6gOVw7pGA1qnkhSDkAFdxv1Ttsktb2B7yINRevCPm5wpPkwwpZXS8Dq3Gk0f3Ns8w==} + /wrangler/2.1.13: + resolution: {integrity: sha512-FWarJ9pBaXOU/wj3BoLo1Azi4VvadD0PfDIYfvY9hoKVyPMSr4dpPNUGgtMhsVuDp7K9mdixnmGEJxR7pbs3kQ==} engines: {node: '>=16.13.0'} hasBin: true dependencies: @@ -6770,7 +6977,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrap-ansi/7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} @@ -6802,8 +7008,8 @@ packages: signal-exit: 3.0.7 dev: true - /ws/8.9.0: - resolution: {integrity: sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==} + /ws/8.10.0: + resolution: {integrity: sha512-+s49uSmZpvtAsd2h37vIPy1RBusaLawVe8of+GyEPsaJTCMpj/2v8NpeK1SHXjBlQ95lQTmQofOJnFiLoaN3yw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -6818,6 +7024,10 @@ packages: resolution: {integrity: sha512-Lc9CTvDrH2vRoiaUzz25q7lRaviMhz90pkx6YxR9EPYtF99yOJnv2cB+CQ0hp/TLoqrUsk8z/W2EN31T568Azw==} dev: true + /y18n/4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: false + /y18n/5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -6831,6 +7041,14 @@ packages: engines: {node: '>= 14'} dev: true + /yargs-parser/18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: false + /yargs-parser/20.2.4: resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} engines: {node: '>=10'} @@ -6851,6 +7069,23 @@ packages: is-plain-obj: 2.1.0 dev: true + /yargs/15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.0 + y18n: 4.0.3 + yargs-parser: 18.1.3 + dev: false + /yargs/16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} diff --git a/tsconfig.json b/tsconfig.json index 13c2f28de..610b3e99b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "checkJs": true, "target": "ES2022", "module": "ES2022", - "lib": ["ES2021", "ES2021.Promise", "ES2021.String", "DOM"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "noEmit": false, "noEmitOnError": true, "emitDeclarationOnly": false,