Compare commits

..

1 Commits

Author SHA1 Message Date
Devin Zuczek ad2b84b358 pw/email recovery 2026-10-26 23:54:25 -04:00
29 changed files with 3847 additions and 525 deletions
+7
View File
@@ -77,6 +77,13 @@ RECFLARE_DOMAIN=rec.example.com
# Turning it on also needs the Turnstile keypair in the Secrets Store (see www). # Turning it on also needs the Turnstile keypair in the Secrets Store (see www).
# RECFLARE_PASSWORD_SIGNUP=off # RECFLARE_PASSWORD_SIGNUP=off
# The address the server's emails come from: password-recovery codes (`auth`) and
# email-change confirmations (`accounts`). Its domain has to be enabled for Cloudflare Email
# Sending once (`wrangler email sending enable <domain>`, see DEPLOYING.md) or no email can
# be sent — the player is told so, and nothing else is affected. Unset is no-reply@<RECFLARE_DOMAIN>; set this to send from another domain
# that IS enabled, or from a different mailbox on the same one.
# RECFLARE_EMAIL_FROM=no-reply@rec.example.com
# How far a ban reaches beyond the account it was handed to (`match` and `auth`), as a # How far a ban reaches beyond the account it was handed to (`match` and `auth`), as a
# comma-separated list out of `ip` and `platform` — or `off` for neither. Unset means # comma-separated list out of `ip` and `platform` — or `off` for neither. Unset means
# BOTH, so a ban also blocks accounts sharing a proven platform identity or an IP with a # BOTH, so a ban also blocks accounts sharing a proven platform identity or an IP with a
+12
View File
@@ -312,6 +312,18 @@ inconsistency here without checking the client first.
cannot name the file (its decoder wants `UnityAsset`/`UnityAssetHash`), and the room loads cannot name the file (its decoder wants `UnityAsset`/`UnityAssetHash`), and the room loads
nothing. Every imported first-party room broke when the splice moved from the Studio-only nothing. Every imported first-party room broke when the splice moved from the Studio-only
table to `unity_asset`, with every response looking correct. table to `unity_asset`, with every response looking correct.
- "Forgot password" (`auth`: `POST /account/recoverpassword`) posts only `email`, and the client
reads the PascalCase envelope `{ Success, Error, error_id }` — `Error` and `error_id` null on
success — not the lowercase `{ success, error }` the password change answers in. The address is
all the server gets, so an email is UNIQUE across accounts (`idx_account_email_lower`, enforced
by `accounts` `POST /account/me/email`). The recovery finishes on the WEBSITE
(`/reset-password`, posting `auth` `POST /account/resetpassword`): the game has no screen for it.
- Setting the email (`accounts`: `POST /account/me/email`) STAGES the address and still answers
`{ success: true }` — the game reads nothing else — while `/account/me` keeps serving the old
one until the emailed codes come back through `…/email/confirm` (website only, `/confirm-email`).
Two steps: the CURRENT address approves first (so a stolen session can't move the recovery
address), then the NEW address confirms itself (so a typo is never stored); an account with no
email gets only the second, and may re-enter a different address at any time.
- Accessibility is sent as the `RoomAccessibility` enum NAME on - Accessibility is sent as the `RoomAccessibility` enum NAME on
`rooms` `PUT /rooms/:id/subrooms/:sid/accessibility` (`accessibility=Private`), not the `rooms` `PUT /rooms/:id/subrooms/:sid/accessibility` (`accessibility=Private`), not the
ordinal the room-level `/rooms/:id/accessibility` takes. The enum has five members ordinal the room-level `/rooms/:id/accessibility` takes. The enum has five members
+19
View File
@@ -151,6 +151,25 @@ string.
wrangler secrets-store secret create <store-id> --name CLOUD_BUILD_KEY --scopes workers --remote wrangler secrets-store secret create <store-id> --name CLOUD_BUILD_KEY --scopes workers --remote
``` ```
**Enable Email Sending** for the domain, so the workers can send the two emails they have:
`auth`'s password-recovery code ("Forgot password" in the game sends a six-digit code to
the address on the account, with a link to `www.<domain>/reset-password`) and `accounts`'
email-change confirmation (changing the address on an account sends a code to the current
address to approve it and then one to the new address to confirm it, each with a link to
`www.<domain>/confirm-email`).
Both workers bind Cloudflare Email Sending (`send_email` in their `wrangler.jsonc`, nothing
to splice in), but Cloudflare only delivers from a domain that has been onboarded — once
per account:
```bash
wrangler email sending enable <domain>
```
Emails come from `no-reply@<domain>`; set `RECFLARE_EMAIL_FROM` in `.env` to send from a
different mailbox or domain (that one must be enabled instead). Without this step the
workers still deploy and everything else works; a recovery request or an email change is
answered with "the email could not be sent", and the failure is logged.
Then apply the schema. `just migrate` will set up the database and populate it with data. This runs non-interactively, so be careful! Then apply the schema. `just migrate` will set up the database and populate it with data. This runs non-interactively, so be careful!
```bash ```bash
+3 -1
View File
@@ -20,7 +20,9 @@ worker; this worker binds it read/write.
| GET | `/accountprivacysettings/:id` | | An account's privacy settings | | GET | `/accountprivacysettings/:id` | | An account's privacy settings |
| PUT | `/account/me/displayname` | ✓ | Set display name | | PUT | `/account/me/displayname` | ✓ | Set display name |
| PUT | `/account/me/username` | ✓ | Change username (unique + change remaining) | | PUT | `/account/me/username` | ✓ | Change username (unique + change remaining) |
| POST | `/account/me/email` | ✓ | Set email | | POST | `/account/me/email` | ✓ | Change email: stages it; codes to old, then new |
| GET | `/account/me/email/pending` | ✓ | The email change awaiting a code, and which |
| POST | `/account/me/email/confirm` | ✓ | Spend a code; the new address's one applies it |
| POST | `/account/me/phone` | ✓ | Set phone number | | POST | `/account/me/phone` | ✓ | Set phone number |
| PUT | `/account/me/identityflags` | ✓ | Set identity flags bitmask | | PUT | `/account/me/identityflags` | ✓ | Set identity flags bitmask |
| PUT | `/account/me/personalpronouns` | ✓ | Set personal pronouns (posted as `pronounFlags`) | | PUT | `/account/me/personalpronouns` | ✓ | Set personal pronouns (posted as `pronounFlags`) |
+284 -5
View File
@@ -3,12 +3,19 @@ import { describeRoute, openAPIRouteHandler, validator } from 'hono-openapi'
import { useWorkersLogger } from 'workers-tagged-logger' import { useWorkersLogger } from 'workers-tagged-logger'
import { import {
beginEmailCode,
cancelEmailCode,
completeEmailCode,
createAccount, createAccount,
DEFAULT_USERNAME_CHANGES, DEFAULT_USERNAME_CHANGES,
defaultAccount, defaultAccount,
EMAIL_CODE_TTL_SECONDS,
emailSender,
getAccount, getAccount,
getAccountByEmail,
getAccountByUsername, getAccountByUsername,
getAccountsByIds, getAccountsByIds,
pendingEmailCode,
SEARCH_LIMIT, SEARCH_LIMIT,
searchAccounts, searchAccounts,
updateAccount, updateAccount,
@@ -25,6 +32,8 @@ import { validateAndGetAccountId } from '@repo/jwt'
// The notification-type ids the hub carries (owned by the `notify` worker). Imported as a // The notification-type ids the hub carries (owned by the `notify` worker). Imported as a
// value — the enum has no runtime dependencies. // value — the enum has no runtime dependencies.
import { NotificationType } from '../../notify/src/notification-types' import { NotificationType } from '../../notify/src/notification-types'
import { buildEndpoints } from '../../ns/src/endpoints'
import { emailChangeEmail } from './email-change-email'
import { import {
AccountDto, AccountDto,
BannerImageRequest, BannerImageRequest,
@@ -34,6 +43,9 @@ import {
CreateAccountRequest, CreateAccountRequest,
CreateAccountResult, CreateAccountResult,
DisplayNameRequest, DisplayNameRequest,
EmailConfirmRequest,
EmailConfirmResponse,
EmailRefusal,
EmailRequest, EmailRequest,
EmojiRequest, EmojiRequest,
form, form,
@@ -41,6 +53,7 @@ import {
IdentityFlagsRequest, IdentityFlagsRequest,
json, json,
ParentalControl, ParentalControl,
PendingEmailResponse,
PhoneRequest, PhoneRequest,
PrivacySettings, PrivacySettings,
ProfileImageRequest, ProfileImageRequest,
@@ -241,6 +254,91 @@ async function pushAccountUpdate(c: Context<App>, account: Account): Promise<voi
/** The empty-body 401 every auth-gated route returns; reused across their specs. */ /** The empty-body 401 every auth-gated route returns; reused across their specs. */
const UNAUTHORIZED_RESPONSE = { description: 'Missing or invalid bearer token (empty body)' } const UNAUTHORIZED_RESPONSE = { description: 'Missing or invalid bearer token (empty body)' }
/** What the email routes say when the address is already on another account. */
const EMAIL_TAKEN = 'That email address is already on another account.'
/** What `POST /account/me/email/confirm` says to any code that doesn't take. */
const EMAIL_CODE_WRONG =
'That code is wrong or has expired. Save the address again to be sent a new one.'
/** What the email routes say to a repeat within the cooldown. */
const EMAIL_TOO_SOON =
'A code was emailed less than two minutes ago. Enter that one, or try again in a minute.'
/** What the email routes say when the mail service refused the send. */
const EMAIL_NOT_SENT = 'The confirmation email could not be sent. Please try again later.'
/** The account's current address, or null when it has none (absent or empty). */
const currentEmail = (account: Account | null): string | null => account?.email?.trim() || null
/**
* Send one of the email-change codes. False when the mail service refused it, in which case
* the code is dropped (cooldown included) — nothing went out, so nothing to wait on, and the
* player can try again at once. The usual cause is the sender's domain not being enabled for
* Email Sending (DEPLOYING.md): an operator's problem, hence the log.
*/
async function sendEmailCode(
c: Context<App>,
input: {
purpose: 'email_change' | 'email_verify'
to: string
code: string
newEmail: string
currentEmail: string | null
}
): Promise<boolean> {
const id = (await authedId(c))!
const message = emailChangeEmail({
to: input.to,
from: emailSender(c.env),
domain: c.env.DOMAIN,
www: buildEndpoints(c.env.DOMAIN, c.env.SUBDOMAINS).WWW,
code: input.code,
newEmail: input.newEmail,
// Step 2's letter reads as "confirm this address" whether or not there is a current
// one: by then the current address has had its say.
currentEmail: input.purpose === 'email_change' ? input.currentEmail : null,
validMinutes: Math.round(EMAIL_CODE_TTL_SECONDS / 60),
})
try {
await c.env.EMAIL.send(message)
} catch (err) {
await cancelEmailCode(c.env.DB, input.purpose, id)
logger.error('could not send the email-change code', {
accountId: id,
purpose: input.purpose,
error: err instanceof Error ? err.message : String(err),
})
return false
}
logger.info('email-change code sent', { accountId: id, purpose: input.purpose })
return true
}
/** What `GET /account/me/email/pending` serves: the live step, if any. */
async function pendingEmailChange(
c: Context<App>,
id: number
): Promise<{ pending: string | null; sentTo: string | null }> {
const verify = await pendingEmailCode(c.env.DB, 'email_verify', id)
if (verify?.payload) return { pending: verify.payload, sentTo: verify.payload }
const change = await pendingEmailCode(c.env.DB, 'email_change', id)
if (change?.payload) {
const current = currentEmail(await getAccount(c.env.DB, id))
return { pending: change.payload, sentTo: current ?? change.payload }
}
return { pending: null, sentTo: null }
}
/**
* Whether a D1 error is the `idx_account_email_lower` UNIQUE index refusing a second holder
* of an address — two saves racing past the lookup. D1 surfaces SQLite's message verbatim.
*/
function isUniqueEmailViolation(err: unknown): boolean {
const message = err instanceof Error ? err.message : String(err)
return message.includes('UNIQUE constraint failed') && message.includes('email_lower')
}
/** Bearer-JWT security requirement, for the auth-gated routes. */ /** Bearer-JWT security requirement, for the auth-gated routes. */
const AUTHED = [{ bearerAuth: [] }] const AUTHED = [{ bearerAuth: [] }]
@@ -631,18 +729,59 @@ const app = new Hono<App>()
} }
) )
// Set the player's email (persisted on the account row; surfaced by /account/me). // Change the player's email — STAGED, not applied. An address belongs to one account and is
// what password recovery goes to, so moving it is the one profile change a stolen session
// must not be able to make alone. Two steps, each a six-digit code (@repo/domain's
// email-code-db.ts: one attempt, half an hour, and a cooldown on resends):
//
// 1. `email_change` — to the CURRENT address, when the account has one: its owner approves
// giving it up. A stolen session can't pass this. Skipped for an account with no
// confirmed address, which has nobody to ask.
// 2. `email_verify` — to the NEW address: proves it is reachable before it becomes the
// recovery address, so a typo can never be stored. This is the step that applies the
// change. Issued as step 1 is spent, or at once when there was no step 1.
//
// `/account/me` keeps serving the old address until step 2 lands. A player with NO address
// who mistypes one just enters another: a different address always gets a fresh code (the
// cooldown only refuses a repeat to the SAME address), since nothing confirmed is at stake.
// With a confirmed address, every new attempt starts again at step 1, and step 1's cooldown
// applies whatever the new address is — it is the current inbox being written to.
//
// The game posts this and reads `{ success: true }`, as it always did; it has no screen for
// the code, so the emails' links finish the change on the website. A same-address save (a
// case change, or re-saving what is there) applies at once — nothing to approve.
//
// An address another account holds (case-insensitively) is refused with a sentence in the
// body, which the website shows, where the malformed-address refusal is an empty 400. Same
// status for both: a 400 is what the game client is known to cope with on this route. The
// lookup is what the player reads; the UNIQUE index on `email_lower` is the backstop for a
// race, re-checked when the change is applied.
.post( .post(
'/account/me/email', '/account/me/email',
describeRoute({ describeRoute({
tags: ['Profile'], tags: ['Profile'],
summary: 'Set email', summary: 'Change email (sends a confirmation code)',
description: 'Persisted; surfaced only by `/account/me`. Not broadcast.', description: [
'STAGES the change. An account with a confirmed address is sent a six-digit code',
'THERE first (its owner approves the change); once that code is posted to',
'`POST /account/me/email/confirm`, a second code goes to the NEW address, and',
'posting that one applies the change. An account with no address gets only the',
'second step. Each email links to the website’s `/confirm-email` page.',
'`{ success: true }` means a code was sent. Re-saving the current address applies',
'at once. An address on another account (case-insensitive) is refused with',
'`{ success: false, error }`; so is a repeat within two minutes of the last code,',
'except that an account with no address may enter a DIFFERENT address at any time.',
'The malformed-address refusal has no body.',
].join(' '),
security: AUTHED, security: AUTHED,
responses: { responses: {
200: json(SuccessResponse, 'Updated'), 200: json(SuccessResponse, 'Code sent (or the same address re-saved)'),
400: { description: 'Not a syntactically valid address (empty body)' }, 400: json(
EmailRefusal,
'Not a syntactically valid address (empty body), or already on another account / asked again too soon'
),
401: UNAUTHORIZED_RESPONSE, 401: UNAUTHORIZED_RESPONSE,
502: json(EmailRefusal, 'The confirmation email could not be sent'),
}, },
}), }),
validator('form', EmailRequest, (r, c) => (r.success ? undefined : c.body(null, 400))), validator('form', EmailRequest, (r, c) => (r.success ? undefined : c.body(null, 400))),
@@ -650,9 +789,149 @@ const app = new Hono<App>()
const id = await authedId(c) const id = await authedId(c)
if (id === null) return unauthorized(c) if (id === null) return unauthorized(c)
const { email } = c.req.valid('form') const { email } = c.req.valid('form')
const taken = { success: false, error: EMAIL_TAKEN }
const holder = await getAccountByEmail(c.env.DB, email)
if (holder !== null && holder.accountId !== id) return c.json(taken, 400)
const current = currentEmail(await getAccount(c.env.DB, id))
if (current !== null && current.toLowerCase() === email.toLowerCase()) {
await updateAccount(c.env.DB, id, { email }) await updateAccount(c.env.DB, id, { email })
return c.json({ success: true }) return c.json({ success: true })
} }
let code: string | null
if (current === null) {
// Step 2 straight away. A different address than the one last staged is never
// a repeat, so it skips the cooldown — the typo case.
const staged = await pendingEmailCode(c.env.DB, 'email_verify', id)
code = await beginEmailCode(c.env.DB, 'email_verify', id, email, {
force: staged?.payload !== email,
})
} else {
// Step 1; a step 2 left over from an earlier attempt is voided, since the current
// address has not approved THIS one.
await cancelEmailCode(c.env.DB, 'email_verify', id)
code = await beginEmailCode(c.env.DB, 'email_change', id, email)
}
if (code === null) return c.json({ success: false, error: EMAIL_TOO_SOON }, 400)
const sent = await sendEmailCode(c, {
purpose: current === null ? 'email_verify' : 'email_change',
to: current ?? email,
code,
newEmail: email,
currentEmail: current,
})
if (!sent) return c.json({ success: false, error: EMAIL_NOT_SENT }, 502)
return c.json({ success: true })
}
)
// The change awaiting a code, for the website to pick up where it left off after a reload
// (and right after signup, which saves the address and lands on the account page).
.get(
'/account/me/email/pending',
describeRoute({
tags: ['Profile'],
summary: 'The email change awaiting confirmation',
description: [
'The address a code is out for, and where the code went — the current address while',
'it is approving the change, the new one while it is confirming itself — or nulls when',
'no change is in flight (none staged, or the code lapsed or was spent by a wrong guess).',
].join(' '),
security: AUTHED,
responses: {
200: json(PendingEmailResponse, 'The pending change, or nulls'),
401: UNAUTHORIZED_RESPONSE,
},
}),
async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
return c.json(await pendingEmailChange(c, id))
}
)
// Spend the pending code. The code is what approves the step; the session says whose. One
// guess: a wrong code voids the step (and the change), and the address has to be saved again.
// The refusal reads the same whether the code was wrong, lapsed or never issued. Which step
// is being confirmed follows from what is pending — only one ever is.
.post(
'/account/me/email/confirm',
describeRoute({
tags: ['Profile'],
summary: 'Confirm an email change step with the emailed code',
description: [
'Spends the code staged by `POST /account/me/email`. When it was the CURRENT address',
'approving the change, a second code is sent to the new address and `applied` is',
'false, with `pending`/`sentTo` saying so; when it was the new address confirming',
'itself, the change is applied and `applied` is true. The code works ONCE: a wrong one',
'voids the change. The refusal is the same sentence whether the code was wrong, has',
'lapsed (30 minutes) or was never issued. The address is re-checked against other',
'accounts as it lands.',
].join(' '),
security: AUTHED,
responses: {
200: json(EmailConfirmResponse, 'Step confirmed; `applied` says whether the change landed'),
400: json(
EmailRefusal,
'No code, a code that is wrong / lapsed / not issued, or an address another account took meanwhile'
),
401: UNAUTHORIZED_RESPONSE,
502: json(EmailRefusal, 'The second code’s email could not be sent'),
},
}),
validator('form', EmailConfirmRequest, (r, c) =>
r.success
? undefined
: c.json({ success: false, error: 'Enter the code from the email.' }, 400)
),
async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
const { code } = c.req.valid('form')
// Step 2, if it is the one out; else step 1.
const verifying = (await pendingEmailCode(c.env.DB, 'email_verify', id)) !== null
const purpose = verifying ? 'email_verify' : 'email_change'
const result = await completeEmailCode(c.env.DB, purpose, id, code)
if (result.outcome !== 'ok' || !result.payload) {
logger.info('email change refused', { accountId: id, purpose, outcome: result.outcome })
return c.json({ success: false, error: EMAIL_CODE_WRONG }, 400)
}
const email = result.payload
const taken = { success: false, error: EMAIL_TAKEN }
const holder = await getAccountByEmail(c.env.DB, email)
if (holder !== null && holder.accountId !== id) return c.json(taken, 400)
if (!verifying) {
// The current address has approved; now the new one proves itself. Forced past the
// cooldown: step 1 just gated this, and the previous verify code (if any) went out
// at least a step-1 cooldown ago.
const next = await beginEmailCode(c.env.DB, 'email_verify', id, email, { force: true })
const sent =
next !== null &&
(await sendEmailCode(c, {
purpose: 'email_verify',
to: email,
code: next,
newEmail: email,
currentEmail: currentEmail(await getAccount(c.env.DB, id)),
}))
if (!sent) return c.json({ success: false, error: EMAIL_NOT_SENT }, 502)
logger.info('email change approved by the current address', { accountId: id })
return c.json({ success: true, applied: false, pending: email, sentTo: email })
}
try {
await updateAccount(c.env.DB, id, { email })
} catch (err) {
if (isUniqueEmailViolation(err)) return c.json(taken, 400)
throw err
}
logger.info('email changed', { accountId: id })
return c.json({ success: true, applied: true, pending: null, sentTo: null })
}
) )
// Set the player's phone (persisted on the account row). // Set the player's phone (persisted on the account row).
+18
View File
@@ -15,6 +15,24 @@ export type Env = SharedHonoEnv & {
// SignalR notifications hub (DO owned by the `notify` worker). Bound here to // SignalR notifications hub (DO owned by the `notify` worker). Bound here to
// push AccountUpdate/SelfAccountUpdate notifications on profile mutations. // push AccountUpdate/SelfAccountUpdate notifications on profile mutations.
RECFLARE_NOTIFICATIONS_HUB: DurableObjectNamespace<NotificationsHub> RECFLARE_NOTIFICATIONS_HUB: DurableObjectNamespace<NotificationsHub>
/**
* Cloudflare Email Sending (`send_email` in wrangler.jsonc). The one thing this worker
* mails is the code that confirms an email change (`POST /account/me/email`), from
* `EMAIL_FROM` below (read through `emailSender`); `auth` binds the same for password
* recovery. The sender's domain has to be onboarded onto Email Sending (see DEPLOYING.md)
* or every send fails — reported to the player as the email not going out. Locally and
* in tests the binding logs the message instead of sending it.
*/
EMAIL: SendEmail
/** See `auth`: the address emails come from; unset means `no-reply@<DOMAIN>`. */
EMAIL_FROM?: string
/**
* Base domain, e.g. `recflare.net`, injected for every worker at deploy time
* (`--var DOMAIN`). The confirmation email links to `www.<domain>/confirm-email`.
*/
DOMAIN: string
/** The same `SUBDOMAINS` JSON `ns` applies: a `www` override moves that link's host. */
SUBDOMAINS: string
} }
/** Variables can be extended */ /** Variables can be extended */
+86
View File
@@ -0,0 +1,86 @@
/**
* The email that confirms a change of address, as the message builder Cloudflare Email
* Sending takes (`env.EMAIL.send(...)`). A pure function of its inputs, so the message can
* be read in a test without a mail service in the way.
*
* Two different letters, one per step of the change (see `/account/me/email`):
*
* - To the CURRENT address, when the account has one: "someone signed in to your account
* wants to change its email to X". The point of confirming at all — a stolen session
* can't move the address, and with it the password recovery, somewhere else.
* - To the NEW address, once the current one has approved (or at once, when there is none):
* "confirm this is yours". Proves the address being added is reachable before it is
* stored, so a typo never becomes the recovery address.
*
* Either way the code is printed and prefilled into a link to the website's confirm page,
* which needs the account's own session to post it: the code approves the change, the
* session says whose.
*/
import { escapeHtml } from '@repo/domain'
/** The website's confirm page, which reads `code` off the query and wants a session. */
export const CONFIRM_EMAIL_PATH = '/confirm-email'
export interface EmailChangeEmailInput {
/** Where the email goes: the current address when there is one, else the new one. */
to: string
/** The address it comes from; must be on a domain enabled for Email Sending. */
from: string
/** The server's base domain, named as the sender and in the copy. */
domain: string
/** The website's origin (`https://www.<domain>`), which the confirm link is built on. */
www: string
/** The six-digit code, in plaintext — the only place it is written down. */
code: string
/** The address the account would change to. */
newEmail: string
/** The address this letter asks to give up, or null for the letter to the new address. */
currentEmail: string | null
/** How long the code is good for, in minutes, for the copy. */
validMinutes: number
}
/** The confirm link: the website's page with the code already filled in. */
export function confirmEmailUrl(www: string, code: string): string {
const url = new URL(CONFIRM_EMAIL_PATH, www)
url.searchParams.set('code', code)
return url.toString()
}
export function emailChangeEmail(input: EmailChangeEmailInput) {
const link = confirmEmailUrl(input.www, input.code)
const changing = input.currentEmail !== null
const subject = changing
? `Confirm the new email address on your ${input.domain} account`
: `Confirm your ${input.domain} email address`
const opening = changing
? `Someone signed in to your ${input.domain} account asked to change its email address from this one to ${input.newEmail}.`
: `This address is being set on a ${input.domain} account. Confirm it to finish.`
const closing = changing
? `The code works once and for ${input.validMinutes} minutes. If you didn't ask for this, don't enter it — nothing changes without it, and this address stays on the account. Someone else may have your password: sign in and change it, or use "Forgot password".`
: `The code works once and for ${input.validMinutes} minutes. If you didn't set this address on an account, ignore this email — nothing changes without the code.`
const text = [
opening,
'',
`Your code is: ${input.code}`,
'',
'Confirm it here (you will need to sign in):',
link,
'',
closing,
].join('\n')
const html = [
`<p>${escapeHtml(opening)}</p>`,
`<p>Your code is: <strong style="font-size:1.5em;letter-spacing:0.15em">${input.code}</strong></p>`,
`<p><a href="${escapeHtml(link)}">Confirm it here</a> (you will need to sign in).</p>`,
`<p>${escapeHtml(closing)}</p>`,
].join('\n')
return {
to: input.to,
from: { email: input.from, name: input.domain },
subject,
text,
html,
}
}
+32
View File
@@ -231,6 +231,38 @@ export const EmailRequest = z.object({
.describe('A syntactically valid address (RFC 5321/5322, so at most 254); otherwise 400'), .describe('A syntactically valid address (RFC 5321/5322, so at most 254); otherwise 400'),
}) })
/** `POST /account/me/email/confirm` form body. */
export const EmailConfirmRequest = z.object({
code: z
.string()
.trim()
.min(1, 'Enter the code from the email.')
.describe('The six digits from the email'),
})
/** `POST /account/me/email/confirm` response body. */
export const EmailConfirmResponse = z.object({
success: z.literal(true),
applied: z.boolean().describe('Whether the change has landed, or a second code is now out'),
pending: z.string().nullable().describe('The new address, while a second code is out'),
sentTo: z.string().nullable().describe('Where that second code went (the new address)'),
})
/** `GET /account/me/email/pending` response body. */
export const PendingEmailResponse = z.object({
pending: z
.string()
.nullable()
.describe('The address awaiting confirmation, or null when no change is in flight'),
sentTo: z
.string()
.nullable()
.describe('Where the code went: the current address, or the new one when there was none'),
})
/** The `{ success: false, error }` the email routes refuse with. */
export const EmailRefusal = z.object({ success: z.literal(false), error: z.string() })
export const PhoneRequest = z.object({ export const PhoneRequest = z.object({
// No shape rule on purpose: the client sends E.164 (`+15552223333`), which the name // No shape rule on purpose: the client sends E.164 (`+15552223333`), which the name
// rule above would reject outright by eating the leading `+`. // rule above would reject outright by eating the leading `+`.
+248 -12
View File
@@ -4,7 +4,7 @@ import { beforeAll, describe, expect, test } from 'vitest'
import '../../accounts.app' import '../../accounts.app'
import { SCHEMA_DDL } from '@repo/domain' import { EMAIL_CODE_SCHEMA_DDL, hashPassword, SCHEMA_DDL } from '@repo/domain'
import { WHITELISTED_EMOJIS } from '../../whitelisted-emojis' import { WHITELISTED_EMOJIS } from '../../whitelisted-emojis'
@@ -22,6 +22,8 @@ beforeAll(async () => {
// Seed the shared JWT signing key into the local Secrets Store so .get() resolves. // Seed the shared JWT signing key into the local Secrets Store so .get() resolves.
await adminSecretsStore(env.JWT_SECRET).create('test-signing-key') await adminSecretsStore(env.JWT_SECRET).create('test-signing-key')
for (const stmt of SCHEMA_DDL) await env.DB.prepare(stmt).run() for (const stmt of SCHEMA_DDL) await env.DB.prepare(stmt).run()
// The codes an email change is confirmed with (owned by `auth`'s migrations).
for (const stmt of EMAIL_CODE_SCHEMA_DDL) await env.DB.prepare(stmt).run()
const insert = env.DB.prepare('INSERT OR IGNORE INTO account (data) VALUES (?1)') const insert = env.DB.prepare('INSERT OR IGNORE INTO account (data) VALUES (?1)')
await env.DB.batch([ await env.DB.batch([
insert.bind(JSON.stringify({ accountId: 0, username: 'RecRoom', displayName: 'Rec Room' })), insert.bind(JSON.stringify({ accountId: 0, username: 'RecRoom', displayName: 'Rec Room' })),
@@ -668,18 +670,249 @@ describe('auth-gated endpoints', () => {
expect(res.status).toBe(400) expect(res.status).toBe(400)
}) })
test('POST /account/me/email persists the email, surfaced by /account/me', async () => { /** POST an address for an account, as the website and the game do. */
const res = await exports.default.fetch(`${ORIGIN}/account/me/email`, { const postEmail = async (id: string, email: string) =>
...form({ email: 'ners@recroom.com' }), exports.default.fetch(`${ORIGIN}/account/me/email`, {
...form({ email }),
method: 'POST', method: 'POST',
headers: { ...(await bearer('888')), 'Content-Type': 'application/x-www-form-urlencoded' }, headers: { ...(await bearer(id)), 'Content-Type': 'application/x-www-form-urlencoded' },
}) })
/** POST a code to confirm the account's staged change. */
const confirmEmail = async (id: string, code: string) =>
exports.default.fetch(`${ORIGIN}/account/me/email/confirm`, {
...form({ code }),
method: 'POST',
headers: { ...(await bearer(id)), 'Content-Type': 'application/x-www-form-urlencoded' },
})
const pendingEmail = async (id: string) =>
(await (
await exports.default.fetch(`${ORIGIN}/account/me/email/pending`, {
headers: await bearer(id),
})
).json()) as { pending: string | null; sentTo: string | null }
const emailOf = async (id: string) =>
(
(await (
await exports.default.fetch(`${ORIGIN}/account/me`, { headers: await bearer(id) })
).json()) as { email: string }
).email
type Purpose = 'email_change' | 'email_verify'
/** The staged step's row. Only the code's hash is stored; `plantCode` puts a known one in. */
const stagedRow = (id: string, purpose: Purpose) =>
env.DB.prepare(
'SELECT code_hash AS codeHash, payload, created_at AS createdAt FROM email_code WHERE account_id = ?1 AND purpose = ?2'
)
.bind(Number(id), purpose)
.first<{ codeHash: string | null; payload: string; createdAt: number }>()
const plantCode = async (id: string, purpose: Purpose, code: string) => {
await env.DB.prepare(
'UPDATE email_code SET code_hash = ?2 WHERE account_id = ?1 AND purpose = ?3'
)
.bind(Number(id), await hashPassword(code), purpose)
.run()
}
/** Set an address the way a player does, through every step the account needs. */
const setEmail = async (id: string, email: string) => {
const staged = await postEmail(id, email)
if (staged.status !== 200) return staged
if ((await pendingEmail(id)).sentTo !== email) {
await plantCode(id, 'email_change', '100000')
const approved = await confirmEmail(id, '100000')
if (approved.status !== 200) return approved
}
await plantCode(id, 'email_verify', '100001')
return confirmEmail(id, '100001')
}
test('POST /account/me/email on an account with no address: one code, to the new address', async () => {
const res = await postEmail('888', 'ners@recroom.com')
expect(res.status).toBe(200) expect(res.status).toBe(200)
expect(await res.json()).toEqual({ success: true }) expect(await res.json()).toEqual({ success: true })
// The stored email is now returned by the self account (was a null stub). // Staged, not applied: the self account still has no email, and the pending read says
const me = await exports.default.fetch(`${ORIGIN}/account/me`, { headers: await bearer('888') }) // where the code went — the NEW address, since there is nobody else to ask.
expect(((await me.json()) as { email: string }).email).toBe('ners@recroom.com') expect(await emailOf('888')).toBe('')
expect(await pendingEmail('888')).toEqual({
pending: 'ners@recroom.com',
sentTo: 'ners@recroom.com',
})
const row = await stagedRow('888', 'email_verify')
expect(row?.payload).toBe('ners@recroom.com')
expect(row?.codeHash).toMatch(/^[^:]+:[^:]+$/)
expect(await stagedRow('888', 'email_change')).toBeNull()
await plantCode('888', 'email_verify', '123456')
const ok = await confirmEmail('888', '123456')
expect(ok.status).toBe(200)
expect(await ok.json()).toEqual({ success: true, applied: true, pending: null, sentTo: null })
expect(await emailOf('888')).toBe('ners@recroom.com')
expect(await pendingEmail('888')).toEqual({ pending: null, sentTo: null })
// Spent: the same code again is refused.
expect((await confirmEmail('888', '123456')).status).toBe(400)
})
test('with no address on file, a mistyped address can be replaced at once; the same one waits', async () => {
await postEmail('892', 'typo@exmaple.com')
const first = await stagedRow('892', 'email_verify')
// A DIFFERENT address right away: a fresh code, to it.
expect((await postEmail('892', 'right@example.com')).status).toBe(200)
const second = await stagedRow('892', 'email_verify')
expect(second?.payload).toBe('right@example.com')
expect(second?.codeHash).not.toBe(first?.codeHash)
expect((await pendingEmail('892')).sentTo).toBe('right@example.com')
// The SAME address again within the cooldown is a repeat, and refused.
const repeat = await postEmail('892', 'right@example.com')
expect(repeat.status).toBe(400)
expect(((await repeat.json()) as { error: string }).error).toMatch(/less than two minutes/)
expect(await stagedRow('892', 'email_verify')).toEqual(second)
})
test('with an address on file, the current address approves and then the new one confirms', async () => {
expect((await setEmail('889', 'first@example.com')).status).toBe(200)
expect(await emailOf('889')).toBe('first@example.com')
// Step 1: the code goes to the address being given up, not the new one.
expect((await postEmail('889', 'second@example.com')).status).toBe(200)
expect(await pendingEmail('889')).toEqual({
pending: 'second@example.com',
sentTo: 'first@example.com',
})
expect(await stagedRow('889', 'email_verify')).toBeNull()
expect(await emailOf('889')).toBe('first@example.com')
// Approving it applies nothing yet: step 2's code goes to the new address.
await plantCode('889', 'email_change', '111111')
const approved = await confirmEmail('889', '111111')
expect(approved.status).toBe(200)
expect(await approved.json()).toEqual({
success: true,
applied: false,
pending: 'second@example.com',
sentTo: 'second@example.com',
})
expect(await stagedRow('889', 'email_change')).toBeNull()
expect(await pendingEmail('889')).toEqual({
pending: 'second@example.com',
sentTo: 'second@example.com',
})
expect(await emailOf('889')).toBe('first@example.com')
// Step 2 lands it.
await plantCode('889', 'email_verify', '222222')
const done = await confirmEmail('889', '222222')
expect(await done.json()).toEqual({ success: true, applied: true, pending: null, sentTo: null })
expect(await emailOf('889')).toBe('second@example.com')
})
test('a wrong code at either step voids the change; a new attempt starts again at step 1', async () => {
expect((await setEmail('893', 'keep@example.com')).status).toBe(200)
// Wrong at step 1: burned, and the right code no longer works.
await postEmail('893', 'next@example.com')
await plantCode('893', 'email_change', '333333')
const wrong = await confirmEmail('893', '999999')
expect(wrong.status).toBe(400)
expect(await wrong.json()).toEqual({
success: false,
error: 'That code is wrong or has expired. Save the address again to be sent a new one.',
})
expect((await stagedRow('893', 'email_change'))?.codeHash).toBeNull()
expect(await pendingEmail('893')).toEqual({ pending: null, sentTo: null })
expect((await confirmEmail('893', '333333')).status).toBe(400)
// Past the cooldown, try again: step 1 again, then wrong at step 2.
await env.DB.prepare(
"UPDATE email_code SET created_at = created_at - 600 WHERE account_id = 893 AND purpose = 'email_change'"
).run()
expect((await postEmail('893', 'next@example.com')).status).toBe(200)
await plantCode('893', 'email_change', '444444')
expect((await confirmEmail('893', '444444')).status).toBe(200)
await plantCode('893', 'email_verify', '555555')
expect((await confirmEmail('893', '000000')).status).toBe(400)
expect((await stagedRow('893', 'email_verify'))?.codeHash).toBeNull()
expect((await confirmEmail('893', '555555')).status).toBe(400)
expect(await emailOf('893')).toBe('keep@example.com')
// A fresh attempt (cooldown passed) starts at step 1 again, whatever the address: the
// current address has approved nothing yet.
await env.DB.prepare(
"UPDATE email_code SET created_at = created_at - 600 WHERE account_id = 893 AND purpose = 'email_change'"
).run()
expect((await postEmail('893', 'other@example.com')).status).toBe(200)
expect((await pendingEmail('893')).sentTo).toBe('keep@example.com')
expect(await stagedRow('893', 'email_verify')).toBeNull()
})
test('with an address on file, a second attempt within the cooldown is refused whatever the address, and re-saving the same address applies at once', async () => {
expect((await setEmail('890', 'cool@example.com')).status).toBe(200)
await postEmail('890', 'cooler@example.com')
const first = await stagedRow('890', 'email_change')
// A different new address is still the current inbox being written to: refused.
const again = await postEmail('890', 'coolest@example.com')
expect(again.status).toBe(400)
expect(((await again.json()) as { error: string }).error).toMatch(/less than two minutes/)
expect(await stagedRow('890', 'email_change')).toEqual(first)
// Re-saving the current address in another case: no code, applied directly.
expect((await postEmail('890', 'COOL@example.com')).status).toBe(200)
expect(await emailOf('890')).toBe('COOL@example.com')
})
test('POST /account/me/email/confirm refuses an empty code and a code with nothing staged', async () => {
const empty = await confirmEmail('891', '')
expect(empty.status).toBe(400)
const none = await confirmEmail('891', '123456')
expect(none.status).toBe(400)
expect(await none.json()).toEqual({
success: false,
error: 'That code is wrong or has expired. Save the address again to be sent a new one.',
})
})
test('the email routes 401 without a token', async () => {
const pending = await exports.default.fetch(`${ORIGIN}/account/me/email/pending`)
expect(pending.status).toBe(401)
// A well-formed body, so the refusal is for the missing token and not the form.
const confirm = await exports.default.fetch(`${ORIGIN}/account/me/email/confirm`, {
...form({ code: '123456' }),
method: 'POST',
})
expect(confirm.status).toBe(401)
})
test('POST /account/me/email refuses an address another account holds, case-insensitively', async () => {
expect((await setEmail('886', 'shared@example.com')).status).toBe(200)
// Another account, same address in different case: refused with a sentence the
// website shows — a 400 like the malformed-address refusal, but with a body.
const taken = await postEmail('887', 'Shared@Example.com')
expect(taken.status).toBe(400)
expect(await taken.json()).toEqual({
success: false,
error: 'That email address is already on another account.',
})
expect(await emailOf('887')).toBe('')
// The holder may save it again (a no-op), and may change case — no code either way.
expect((await postEmail('886', 'shared@example.com')).status).toBe(200)
expect((await postEmail('886', 'SHARED@example.com')).status).toBe(200)
expect(await emailOf('886')).toBe('SHARED@example.com')
// A change that was staged while the address was free is refused as it lands, if
// another account took the address meanwhile.
expect((await postEmail('887', 'contested@example.com')).status).toBe(200)
expect((await setEmail('886', 'contested@example.com')).status).toBe(200)
await plantCode('887', 'email_verify', '100002')
const late = await confirmEmail('887', '100002')
expect(late.status).toBe(400)
expect(((await late.json()) as { error: string }).error).toMatch(/already on another account/)
// Once the holder moves on, the address is free.
expect((await setEmail('886', 'moved@example.com')).status).toBe(200)
expect((await setEmail('887', 'shared@example.com')).status).toBe(200)
}) })
test('GET /openapi.json documents every route', async () => { test('GET /openapi.json documents every route', async () => {
@@ -706,6 +939,7 @@ describe('auth-gated endpoints', () => {
'GET /', 'GET /',
'GET /account/bulk', 'GET /account/bulk',
'GET /account/me', 'GET /account/me',
'GET /account/me/email/pending',
'GET /account/search', 'GET /account/search',
'GET /account/username/{name}', 'GET /account/username/{name}',
'GET /account/{id}', 'GET /account/{id}',
@@ -716,6 +950,7 @@ describe('auth-gated endpoints', () => {
'POST /account/bulk', 'POST /account/bulk',
'POST /account/create', 'POST /account/create',
'POST /account/me/email', 'POST /account/me/email',
'POST /account/me/email/confirm',
'POST /account/me/phone', 'POST /account/me/phone',
'PUT /account/me/bannerimage', 'PUT /account/me/bannerimage',
'PUT /account/me/bio', 'PUT /account/me/bio',
@@ -871,16 +1106,17 @@ describe('name, email and bio validation', () => {
} }
// `someone@localhost` is in the ACCEPTED list on purpose: it's valid per the RFC, // `someone@localhost` is in the ACCEPTED list on purpose: it's valid per the RFC,
// and an undeliverable address costs nothing here. // and an undeliverable address costs nothing here. One account per address: a second
for (const email of [ // save on the same account within two minutes is refused for the cooldown, not the syntax.
for (const [i, email] of [
'someone@example.com', 'someone@example.com',
'first.last+tag@mail.example.co.uk', 'first.last+tag@mail.example.co.uk',
'someone@localhost', 'someone@localhost',
]) { ].entries()) {
const res = await exports.default.fetch(`${ORIGIN}/account/me/email`, { const res = await exports.default.fetch(`${ORIGIN}/account/me/email`, {
...form({ email }), ...form({ email }),
method: 'POST', method: 'POST',
headers, headers: await authed(`881${i}`),
}) })
expect(res.status, email).toBe(200) expect(res.status, email).toBe(200)
} }
+950 -239
View File
@@ -1,5 +1,5 @@
/* eslint-disable */ /* eslint-disable */
// Runtime types generated with workerd@1.20260625.1 2025-09-20 nodejs_compat // Runtime types generated with workerd@1.20260831.1 2026-06-16 nodejs_compat
// Begin runtime types // Begin runtime types
/*! ***************************************************************************** /*! *****************************************************************************
Copyright (c) Cloudflare. All rights reserved. Copyright (c) Cloudflare. All rights reserved.
@@ -19,26 +19,26 @@ and limitations under the License.
// noinspection JSUnusedGlobalSymbols // noinspection JSUnusedGlobalSymbols
declare var onmessage: never; declare var onmessage: never;
/** /**
* The **`DOMException`** interface represents an abnormal event (called an **exception**) that occurs as a result of calling a method or accessing a property of a web API. * The **`DOMException`** interface represents an abnormal event (called an exception) that occurs as a result of calling a method or accessing a property of a web API. This is how error conditions are described in web APIs.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException)
*/ */
declare class DOMException extends Error { declare class DOMException extends Error {
constructor(message?: string, name?: string); constructor(message?: string, name?: string);
/** /**
* The **`message`** read-only property of the a message or description associated with the given error name. * The **`message`** read-only property of the DOMException interface returns a string representing a message or description associated with the given error name.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/message) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/message)
*/ */
readonly message: string; readonly message: string;
/** /**
* The **`name`** read-only property of the one of the strings associated with an error name. * The **`name`** read-only property of the DOMException interface returns a string that contains one of the strings associated with an error name.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/name) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/name)
*/ */
readonly name: string; readonly name: string;
/** /**
* The **`code`** read-only property of the DOMException interface returns one of the legacy error code constants, or `0` if none match. * The **`code`** read-only property of the DOMException interface returns one of the legacy error code constants, or 0 if none match.
* @deprecated * @deprecated
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/code) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/code)
@@ -96,61 +96,61 @@ interface Console {
*/ */
clear(): void; clear(): void;
/** /**
* The **`console.count()`** static method logs the number of times that this particular call to `count()` has been called. * The **`console.count()`** static method logs the number of times that this particular call to count() has been called.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static)
*/ */
count(label?: string): void; count(label?: string): void;
/** /**
* The **`console.countReset()`** static method resets counter used with console/count_static. * The **`console.countReset()`** static method resets counter used with console.count().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countReset_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countReset_static)
*/ */
countReset(label?: string): void; countReset(label?: string): void;
/** /**
* The **`console.debug()`** static method outputs a message to the console at the 'debug' log level. * The **`console.debug()`** static method outputs a message to the console at the "debug" log level. The message is only displayed to the user if the console is configured to display debug output. In most cases, the log level is configured within the console UI. This log level might correspond to the Debug or Verbose log level.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static)
*/ */
debug(...data: any[]): void; debug(...data: any[]): void;
/** /**
* The **`console.dir()`** static method displays a list of the properties of the specified JavaScript object. * The **`console.dir()`** static method displays a list of the properties of the specified JavaScript object. In browser consoles, the output is presented as a hierarchical listing with disclosure triangles that let you see the contents of child objects.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static)
*/ */
dir(item?: any, options?: any): void; dir(item?: any, options?: any): void;
/** /**
* The **`console.dirxml()`** static method displays an interactive tree of the descendant elements of the specified XML/HTML element. * The **`console.dirxml()`** static method displays an interactive tree of the descendant elements of the specified XML/HTML element. If it is not possible to display as an element the JavaScript Object view is shown instead. The output is presented as a hierarchical listing of expandable nodes that let you see the contents of child nodes.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static)
*/ */
dirxml(...data: any[]): void; dirxml(...data: any[]): void;
/** /**
* The **`console.error()`** static method outputs a message to the console at the 'error' log level. * The **`console.error()`** static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static)
*/ */
error(...data: any[]): void; error(...data: any[]): void;
/** /**
* The **`console.group()`** static method creates a new inline group in the Web console log, causing any subsequent console messages to be indented by an additional level, until console/groupEnd_static is called. * The **`console.group()`** static method creates a new inline group in the Web console log, causing any subsequent console messages to be indented by an additional level, until console.groupEnd() is called.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static)
*/ */
group(...data: any[]): void; group(...data: any[]): void;
/** /**
* The **`console.groupCollapsed()`** static method creates a new inline group in the console. * The **`console.groupCollapsed()`** static method creates a new inline group in the console. Unlike console.group(), however, the new group is created collapsed. The user will need to use the disclosure button next to it to expand it, revealing the entries created in the group.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupCollapsed_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupCollapsed_static)
*/ */
groupCollapsed(...data: any[]): void; groupCollapsed(...data: any[]): void;
/** /**
* The **`console.groupEnd()`** static method exits the current inline group in the console. * The **`console.groupEnd()`** static method exits the current inline group in the console. See Using groups in the console in the console documentation for details and examples.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupEnd_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupEnd_static)
*/ */
groupEnd(): void; groupEnd(): void;
/** /**
* The **`console.info()`** static method outputs a message to the console at the 'info' log level. * The **`console.info()`** static method outputs a message to the console at the "info" log level. The message is only displayed to the user if the console is configured to display info output. In most cases, the log level is configured within the console UI. The message may receive special formatting, such as a small "i" icon next to it.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static)
*/ */
@@ -168,23 +168,24 @@ interface Console {
*/ */
table(tabularData?: any, properties?: string[]): void; table(tabularData?: any, properties?: string[]): void;
/** /**
* The **`console.time()`** static method starts a timer you can use to track how long an operation takes. * The **`console.time()`** static method starts a timer you can use to track how long an operation takes. You give each timer a unique name, and may have up to 10,000 timers running on a given page. When you call console.timeEnd() with the same name, the browser will output the time, in milliseconds, that elapsed since the timer was started.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static)
*/ */
time(label?: string): void; time(label?: string): void;
/** /**
* The **`console.timeEnd()`** static method stops a timer that was previously started by calling console/time_static. * The **`console.timeEnd()`** static method stops a timer that was previously started by calling console.time().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeEnd_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeEnd_static)
*/ */
timeEnd(label?: string): void; timeEnd(label?: string): void;
/** /**
* The **`console.timeLog()`** static method logs the current value of a timer that was previously started by calling console/time_static. * The **`console.timeLog()`** static method logs the current value of a timer that was previously started by calling console.time().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeLog_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeLog_static)
*/ */
timeLog(label?: string, ...data: any[]): void; timeLog(label?: string, ...data: any[]): void;
/* The **`console.timeStamp()`** static method adds a single marker to the browser's Performance tool (Firefox bug 1387528, Chrome). This lets you correlate a point in your code with the other events recorded in the timeline, such as layout and paint events. */
timeStamp(label?: string): void; timeStamp(label?: string): void;
/** /**
* The **`console.trace()`** static method outputs a stack trace to the console. * The **`console.trace()`** static method outputs a stack trace to the console.
@@ -193,7 +194,7 @@ interface Console {
*/ */
trace(...data: any[]): void; trace(...data: any[]): void;
/** /**
* The **`console.warn()`** static method outputs a warning message to the console at the 'warning' log level. * The **`console.warn()`** static method outputs a warning message to the console at the "warning" log level. The message is only displayed to the user if the console is configured to display warning output. In most cases, the log level is configured within the console UI. The message may receive special formatting, such as yellow colors and a warning icon.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static)
*/ */
@@ -359,7 +360,7 @@ interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
declare function addEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void; declare function addEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void;
declare function removeEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void; declare function removeEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void;
/** /**
* The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. * The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent)
*/ */
@@ -404,6 +405,7 @@ declare const crypto: Crypto;
* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/) * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/)
*/ */
declare const caches: CacheStorage; declare const caches: CacheStorage;
/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/scheduler) */
declare const scheduler: Scheduler; declare const scheduler: Scheduler;
/** /**
* The Workers runtime supports a subset of the Performance API, used to measure timing and performance, * The Workers runtime supports a subset of the Performance API, used to measure timing and performance,
@@ -420,10 +422,12 @@ interface TestController {
interface ExecutionContext<Props = unknown> { interface ExecutionContext<Props = unknown> {
waitUntil(promise: Promise<any>): void; waitUntil(promise: Promise<any>): void;
passThroughOnException(): void; passThroughOnException(): void;
readonly exports: Cloudflare.Exports;
readonly props: Props; readonly props: Props;
cache?: CacheContext; cache?: CacheContext;
readonly access?: CloudflareAccessContext; readonly access?: CloudflareAccessContext;
tracing: Tracing; tracing: Tracing;
abort(reason?: any): void;
} }
type ExportedHandlerFetchHandler<Env = unknown, CfHostMetadata = unknown, Props = unknown> = (request: Request<CfHostMetadata, IncomingRequestCfProperties<CfHostMetadata>>, env: Env, ctx: ExecutionContext<Props>) => Response | Promise<Response>; type ExportedHandlerFetchHandler<Env = unknown, CfHostMetadata = unknown, Props = unknown> = (request: Request<CfHostMetadata, IncomingRequestCfProperties<CfHostMetadata>>, env: Env, ctx: ExecutionContext<Props>) => Response | Promise<Response>;
type ExportedHandlerConnectHandler<Env = unknown, Props = unknown> = (socket: Socket, env: Env, ctx: ExecutionContext<Props>) => void | Promise<void>; type ExportedHandlerConnectHandler<Env = unknown, Props = unknown> = (socket: Socket, env: Env, ctx: ExecutionContext<Props>) => void | Promise<void>;
@@ -512,7 +516,7 @@ declare abstract class DurableObjectNamespace<T extends Rpc.DurableObjectBranded
getByName(name: string, options?: DurableObjectNamespaceGetDurableObjectOptions): DurableObjectStub<T>; getByName(name: string, options?: DurableObjectNamespaceGetDurableObjectOptions): DurableObjectStub<T>;
jurisdiction(jurisdiction: DurableObjectJurisdiction): DurableObjectNamespace<T>; jurisdiction(jurisdiction: DurableObjectJurisdiction): DurableObjectNamespace<T>;
} }
type DurableObjectJurisdiction = "eu" | "fedramp" | "fedramp-high"; type DurableObjectJurisdiction = "eu" | "fedramp" | "fedramp-high" | "us";
interface DurableObjectNamespaceNewUniqueIdOptions { interface DurableObjectNamespaceNewUniqueIdOptions {
jurisdiction?: DurableObjectJurisdiction; jurisdiction?: DurableObjectJurisdiction;
} }
@@ -526,6 +530,7 @@ interface DurableObjectClass<_T extends Rpc.DurableObjectBranded | undefined = u
} }
interface DurableObjectState<Props = unknown> { interface DurableObjectState<Props = unknown> {
waitUntil(promise: Promise<any>): void; waitUntil(promise: Promise<any>): void;
readonly exports: Cloudflare.Exports;
readonly props: Props; readonly props: Props;
readonly id: DurableObjectId; readonly id: DurableObjectId;
readonly storage: DurableObjectStorage; readonly storage: DurableObjectStorage;
@@ -540,7 +545,7 @@ interface DurableObjectState<Props = unknown> {
setHibernatableWebSocketEventTimeout(timeoutMs?: number): void; setHibernatableWebSocketEventTimeout(timeoutMs?: number): void;
getHibernatableWebSocketEventTimeout(): number | null; getHibernatableWebSocketEventTimeout(): number | null;
getTags(ws: WebSocket): string[]; getTags(ws: WebSocket): string[];
abort(reason?: string): void; abort(reason?: string, options?: DurableObjectAbortOptions): void;
} }
interface DurableObjectTransaction { interface DurableObjectTransaction {
get<T = unknown>(key: string, options?: DurableObjectGetOptions): Promise<T | undefined>; get<T = unknown>(key: string, options?: DurableObjectGetOptions): Promise<T | undefined>;
@@ -576,6 +581,9 @@ interface DurableObjectStorage {
getBookmarkForTime(timestamp: number | Date): Promise<string>; getBookmarkForTime(timestamp: number | Date): Promise<string>;
onNextSessionRestoreBookmark(bookmark: string): Promise<string>; onNextSessionRestoreBookmark(bookmark: string): Promise<string>;
} }
interface DurableObjectAbortOptions {
retryAlarm?: boolean;
}
interface DurableObjectListOptions { interface DurableObjectListOptions {
start?: string; start?: string;
startAfter?: string; startAfter?: string;
@@ -626,26 +634,26 @@ interface AnalyticsEngineDataPoint {
blobs?: ((ArrayBuffer | string) | null)[]; blobs?: ((ArrayBuffer | string) | null)[];
} }
/** /**
* The **`Event`** interface represents an event which takes place on an `EventTarget`. * The **`Event`** interface represents an event which takes place on an EventTarget.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event)
*/ */
declare class Event { declare class Event {
constructor(type: string, init?: EventInit); constructor(type: string, init?: EventInit);
/** /**
* The **`type`** read-only property of the Event interface returns a string containing the event's type. * The **`type`** read-only property of the Event interface returns a string containing the event's type. It is set when the event is constructed and is the name commonly used to refer to the specific event, such as click, load, or error.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/type) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/type)
*/ */
get type(): string; get type(): string;
/** /**
* The **`eventPhase`** read-only property of the being evaluated. * The **`eventPhase`** read-only property of the Event interface indicates which phase of the event flow is currently being evaluated.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/eventPhase) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/eventPhase)
*/ */
get eventPhase(): number; get eventPhase(): number;
/** /**
* The read-only **`composed`** property of the or not the event will propagate across the shadow DOM boundary into the standard DOM. * The read-only **`composed`** property of the Event interface returns a boolean value which indicates whether or not the event will propagate across the shadow DOM boundary into the standard DOM.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composed) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composed)
*/ */
@@ -682,13 +690,13 @@ declare class Event {
*/ */
get currentTarget(): EventTarget | undefined; get currentTarget(): EventTarget | undefined;
/** /**
* The read-only **`target`** property of the dispatched. * The read-only **`target`** property of the Event interface is a reference to the object onto which the event was dispatched. It is different from Event.currentTarget when the event handler is called during the bubbling or capturing phase of the event.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target)
*/ */
get target(): EventTarget | undefined; get target(): EventTarget | undefined;
/** /**
* The deprecated **`Event.srcElement`** is an alias for the Event.target property. * The deprecated **`Event.srcElement`** is an alias for the Event.target property. Use Event.target instead.
* @deprecated * @deprecated
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/srcElement) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/srcElement)
@@ -701,45 +709,45 @@ declare class Event {
*/ */
get timeStamp(): number; get timeStamp(): number;
/** /**
* The **`isTrusted`** read-only property of the when the event was generated by the user agent (including via user actions and programmatic methods such as HTMLElement.focus()), and `false` when the event was dispatched via The only exception is the `click` event, which initializes the `isTrusted` property to `false` in user agents. * The **`isTrusted`** read-only property of the Event interface is a boolean value that is true when the event was generated by the user agent (including via user actions and programmatic methods such as HTMLElement.focus()), and false when the event was dispatched via EventTarget.dispatchEvent(). The only exception is the click event, which initializes the isTrusted property to false in user agents.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/isTrusted) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/isTrusted)
*/ */
get isTrusted(): boolean; get isTrusted(): boolean;
/** /**
* The **`cancelBubble`** property of the Event interface is deprecated. * The **`cancelBubble`** property of the Event interface is deprecated. Use Event.stopPropagation() instead. Setting its value to true before returning from an event handler prevents propagation of the event. In later implementations, setting this to false does nothing. See Browser compatibility for details.
* @deprecated * @deprecated
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble)
*/ */
get cancelBubble(): boolean; get cancelBubble(): boolean;
/** /**
* The **`cancelBubble`** property of the Event interface is deprecated. * The **`cancelBubble`** property of the Event interface is deprecated. Use Event.stopPropagation() instead. Setting its value to true before returning from an event handler prevents propagation of the event. In later implementations, setting this to false does nothing. See Browser compatibility for details.
* @deprecated * @deprecated
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble)
*/ */
set cancelBubble(value: boolean); set cancelBubble(value: boolean);
/** /**
* The **`stopImmediatePropagation()`** method of the If several listeners are attached to the same element for the same event type, they are called in the order in which they were added. * The **`stopImmediatePropagation()`** method of the Event interface prevents other listeners of the same event from being called.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopImmediatePropagation) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopImmediatePropagation)
*/ */
stopImmediatePropagation(): void; stopImmediatePropagation(): void;
/** /**
* The **`preventDefault()`** method of the Event interface tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be. * The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
*/ */
preventDefault(): void; preventDefault(): void;
/** /**
* The **`stopPropagation()`** method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases. * The **`stopPropagation()`** method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases. It does not, however, prevent any default behaviors from occurring; for instance, clicks on links are still processed. If you want to stop those behaviors, see the preventDefault() method. It also does not prevent propagation to other event-handlers of the current element. If you want to stop those, see stopImmediatePropagation().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation)
*/ */
stopPropagation(): void; stopPropagation(): void;
/** /**
* The **`composedPath()`** method of the Event interface returns the event's path which is an array of the objects on which listeners will be invoked. * The **`composedPath()`** method of the Event interface returns the event's path which is an array of the objects on which listeners will be invoked. This does not include nodes in shadow trees if the shadow root was created with its ShadowRoot.mode closed.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composedPath) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composedPath)
*/ */
@@ -760,7 +768,7 @@ interface EventListenerObject<EventType extends Event = Event> {
} }
type EventListenerOrEventListenerObject<EventType extends Event = Event> = EventListener<EventType> | EventListenerObject<EventType>; type EventListenerOrEventListenerObject<EventType extends Event = Event> = EventListener<EventType> | EventListenerObject<EventType>;
/** /**
* The **`EventTarget`** interface is implemented by objects that can receive events and may have listeners for them. * The **`EventTarget`** interface is implemented by objects that can receive events and may have listeners for them. In other words, any target of events implements the three methods associated with this interface.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget)
*/ */
@@ -773,13 +781,13 @@ declare class EventTarget<EventMap extends Record<string, Event> = Record<string
*/ */
addEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void; addEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void;
/** /**
* The **`removeEventListener()`** method of the EventTarget interface removes an event listener previously registered with EventTarget.addEventListener() from the target. * The **`removeEventListener()`** method of the EventTarget interface removes an event listener previously registered with EventTarget.addEventListener() from the target. The event listener to be removed is identified using a combination of the event type, the event listener function itself, and various optional options that may affect the matching process; see Matching event listeners for removal.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener)
*/ */
removeEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void; removeEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void;
/** /**
* The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. * The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent)
*/ */
@@ -811,7 +819,7 @@ declare class AbortController {
*/ */
get signal(): AbortSignal; get signal(): AbortSignal;
/** /**
* The **`abort()`** method of the AbortController interface aborts an asynchronous operation before it has completed. * The **`abort()`** method of the AbortController interface aborts an asynchronous operation before it has completed. This is able to abort fetch requests, the consumption of any response bodies, or streams.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/abort) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/abort)
*/ */
@@ -824,7 +832,7 @@ declare class AbortController {
*/ */
declare abstract class AbortSignal extends EventTarget { declare abstract class AbortSignal extends EventTarget {
/** /**
* The **`AbortSignal.abort()`** static method returns an AbortSignal that is already set as aborted (and which does not trigger an AbortSignal/abort_event event). * The **`AbortSignal.abort()`** static method returns an AbortSignal that is already set as aborted (and which does not trigger an abort event).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_static)
*/ */
@@ -836,13 +844,13 @@ declare abstract class AbortSignal extends EventTarget {
*/ */
static timeout(delay: number): AbortSignal; static timeout(delay: number): AbortSignal;
/** /**
* The **`AbortSignal.any()`** static method takes an iterable of abort signals and returns an AbortSignal. * The **`AbortSignal.any()`** static method takes an iterable of abort signals and returns an AbortSignal. The returned abort signal is aborted when any of the input iterable abort signals are aborted. The abort reason will be set to the reason of the first signal that is aborted. If any of the given abort signals are already aborted then so will be the returned AbortSignal.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/any_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/any_static)
*/ */
static any(signals: AbortSignal[]): AbortSignal; static any(signals: AbortSignal[]): AbortSignal;
/** /**
* The **`aborted`** read-only property returns a value that indicates whether the asynchronous operations the signal is communicating with are aborted (`true`) or not (`false`). * The **`aborted`** read-only property returns a value that indicates whether the asynchronous operations the signal is communicating with are aborted (true) or not (false).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/aborted) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/aborted)
*/ */
@@ -858,12 +866,17 @@ declare abstract class AbortSignal extends EventTarget {
/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_event) */ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_event) */
set onabort(value: any | null); set onabort(value: any | null);
/** /**
* The **`throwIfAborted()`** method throws the signal's abort AbortSignal.reason if the signal has been aborted; otherwise it does nothing. * The **`throwIfAborted()`** method throws the signal's abort reason if the signal has been aborted; otherwise it does nothing.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/throwIfAborted) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/throwIfAborted)
*/ */
throwIfAborted(): void; throwIfAborted(): void;
} }
/**
* The **`Scheduler`** interface of the Prioritized Task Scheduling API provides methods for scheduling prioritized tasks.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Scheduler)
*/
interface Scheduler { interface Scheduler {
wait(delay: number, maybeOptions?: SchedulerWaitOptions): Promise<void>; wait(delay: number, maybeOptions?: SchedulerWaitOptions): Promise<void>;
} }
@@ -871,20 +884,20 @@ interface SchedulerWaitOptions {
signal?: AbortSignal; signal?: AbortSignal;
} }
/** /**
* The **`ExtendableEvent`** interface extends the lifetime of the `install` and `activate` events dispatched on the global scope as part of the service worker lifecycle. * The **`ExtendableEvent`** interface extends the lifetime of the install and activate events dispatched on the global scope as part of the service worker lifecycle. This ensures that any functional events (like FetchEvent) are not dispatched until it upgrades database schemas and deletes the outdated cache entries.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent)
*/ */
declare abstract class ExtendableEvent extends Event { declare abstract class ExtendableEvent extends Event {
/** /**
* The **`ExtendableEvent.waitUntil()`** method tells the event dispatcher that work is ongoing. * The **`ExtendableEvent.waitUntil()`** method tells the event dispatcher that work is ongoing. It can also be used to detect whether that work was successful. In service workers, waitUntil() tells the browser that work is ongoing until the promise settles, and it shouldn't terminate the service worker if it wants that work to complete.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent/waitUntil) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent/waitUntil)
*/ */
waitUntil(promise: Promise<any>): void; waitUntil(promise: Promise<any>): void;
} }
/** /**
* The **`CustomEvent`** interface represents events initialized by an application for any purpose. * The **`CustomEvent`** interface can be used to attach custom data to an event generated by an application.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomEvent)
*/ */
@@ -923,7 +936,7 @@ declare class Blob {
*/ */
get type(): string; get type(): string;
/** /**
* The **`slice()`** method of the Blob interface creates and returns a new `Blob` object which contains data from a subset of the blob on which it's called. * The **`slice()`** method of the Blob interface creates and returns a new Blob object which contains data from a subset of the blob on which it's called.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice)
*/ */
@@ -941,13 +954,13 @@ declare class Blob {
*/ */
bytes(): Promise<Uint8Array>; bytes(): Promise<Uint8Array>;
/** /**
* The **`text()`** method of the string containing the contents of the blob, interpreted as UTF-8. * The **`text()`** method of the Blob interface returns a Promise that resolves with a string containing the contents of the blob, interpreted as UTF-8.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text)
*/ */
text(): Promise<string>; text(): Promise<string>;
/** /**
* The **`stream()`** method of the Blob interface returns a ReadableStream which upon reading returns the data contained within the `Blob`. * The **`stream()`** method of the Blob interface returns a ReadableStream which upon reading returns the data contained within the Blob.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/stream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/stream)
*/ */
@@ -964,13 +977,13 @@ interface BlobOptions {
declare class File extends Blob { declare class File extends Blob {
constructor(bits: ((ArrayBuffer | ArrayBufferView) | string | Blob)[] | undefined, name: string, options?: FileOptions); constructor(bits: ((ArrayBuffer | ArrayBufferView) | string | Blob)[] | undefined, name: string, options?: FileOptions);
/** /**
* The **`name`** read-only property of the File interface returns the name of the file represented by a File object. * The **`name`** read-only property of the File interface returns the name of the file represented by a File object. For security reasons, the path is excluded from this property.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name)
*/ */
get name(): string; get name(): string;
/** /**
* The **`lastModified`** read-only property of the File interface provides the last modified date of the file as the number of milliseconds since the Unix epoch (January 1, 1970 at midnight). * The **`lastModified`** read-only property of the File interface provides the last modified date of the file as the number of milliseconds since the Unix epoch (January 1, 1970 at midnight). Files without a known last modified date return the current date.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified)
*/ */
@@ -987,7 +1000,7 @@ interface FileOptions {
*/ */
declare abstract class CacheStorage { declare abstract class CacheStorage {
/** /**
* The **`open()`** method of the the Cache object matching the `cacheName`. * The **`open()`** method of the CacheStorage interface returns a Promise that resolves to the Cache object matching the cacheName.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CacheStorage/open) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CacheStorage/open)
*/ */
@@ -1020,14 +1033,14 @@ interface CacheQueryOptions {
*/ */
declare abstract class Crypto { declare abstract class Crypto {
/** /**
* The **`Crypto.subtle`** read-only property returns a cryptographic operations. * The **`Crypto.subtle`** read-only property returns a SubtleCrypto which can then be used to perform low-level cryptographic operations.
* Available only in secure contexts. * Available only in secure contexts.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/subtle) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/subtle)
*/ */
get subtle(): SubtleCrypto; get subtle(): SubtleCrypto;
/** /**
* The **`Crypto.getRandomValues()`** method lets you get cryptographically strong random values. * The **`Crypto.getRandomValues()`** method lets you get cryptographically strong random values. The array given as the parameter is filled with random numbers (random in its cryptographic meaning).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues)
*/ */
@@ -1055,7 +1068,7 @@ declare abstract class SubtleCrypto {
*/ */
encrypt(algorithm: string | SubtleCryptoEncryptAlgorithm, key: CryptoKey, plainText: ArrayBuffer | ArrayBufferView): Promise<ArrayBuffer>; encrypt(algorithm: string | SubtleCryptoEncryptAlgorithm, key: CryptoKey, plainText: ArrayBuffer | ArrayBufferView): Promise<ArrayBuffer>;
/** /**
* The **`decrypt()`** method of the SubtleCrypto interface decrypts some encrypted data. * The **`decrypt()`** method of the SubtleCrypto interface decrypts some encrypted data. It takes as arguments a key to decrypt with, some optional extra parameters, and the data to decrypt (also known as "ciphertext"). It returns a Promise which will be fulfilled with the decrypted data (also known as "plaintext").
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/decrypt) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/decrypt)
*/ */
@@ -1073,7 +1086,7 @@ declare abstract class SubtleCrypto {
*/ */
verify(algorithm: string | SubtleCryptoSignAlgorithm, key: CryptoKey, signature: ArrayBuffer | ArrayBufferView, data: ArrayBuffer | ArrayBufferView): Promise<boolean>; verify(algorithm: string | SubtleCryptoSignAlgorithm, key: CryptoKey, signature: ArrayBuffer | ArrayBufferView, data: ArrayBuffer | ArrayBufferView): Promise<boolean>;
/** /**
* The **`digest()`** method of the SubtleCrypto interface generates a _digest_ of the given data, using the specified hash function. * The **`digest()`** method of the SubtleCrypto interface generates a digest of the given data, using the specified hash function. A digest is a short fixed-length value derived from some variable-length input. Cryptographic digests should exhibit collision-resistance, meaning that it's hard to come up with two different inputs that have the same digest value.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/digest) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/digest)
*/ */
@@ -1091,7 +1104,7 @@ declare abstract class SubtleCrypto {
*/ */
deriveKey(algorithm: string | SubtleCryptoDeriveKeyAlgorithm, baseKey: CryptoKey, derivedKeyAlgorithm: string | SubtleCryptoImportKeyAlgorithm, extractable: boolean, keyUsages: string[]): Promise<CryptoKey>; deriveKey(algorithm: string | SubtleCryptoDeriveKeyAlgorithm, baseKey: CryptoKey, derivedKeyAlgorithm: string | SubtleCryptoImportKeyAlgorithm, extractable: boolean, keyUsages: string[]): Promise<CryptoKey>;
/** /**
* The **`deriveBits()`** method of the key. * The **`deriveBits()`** method of the SubtleCrypto interface can be used to derive an array of bits from a base key.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/deriveBits) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/deriveBits)
*/ */
@@ -1109,13 +1122,13 @@ declare abstract class SubtleCrypto {
*/ */
exportKey(format: string, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey>; exportKey(format: string, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey>;
/** /**
* The **`wrapKey()`** method of the SubtleCrypto interface 'wraps' a key. * The **`wrapKey()`** method of the SubtleCrypto interface "wraps" a key. This means that it exports the key in an external, portable format, then encrypts the exported key. Wrapping a key helps protect it in untrusted environments, such as inside an otherwise unprotected data store or in transmission over an unprotected network.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/wrapKey) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/wrapKey)
*/ */
wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: string | SubtleCryptoEncryptAlgorithm): Promise<ArrayBuffer>; wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: string | SubtleCryptoEncryptAlgorithm): Promise<ArrayBuffer>;
/** /**
* The **`unwrapKey()`** method of the SubtleCrypto interface 'unwraps' a key. * The **`unwrapKey()`** method of the SubtleCrypto interface "unwraps" a key. This means that it takes as its input a key that has been exported and then encrypted (also called "wrapped"). It decrypts the key and then imports it, returning a CryptoKey object that can be used in the Web Crypto API.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/unwrapKey) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/unwrapKey)
*/ */
@@ -1123,20 +1136,20 @@ declare abstract class SubtleCrypto {
timingSafeEqual(a: ArrayBuffer | ArrayBufferView, b: ArrayBuffer | ArrayBufferView): boolean; timingSafeEqual(a: ArrayBuffer | ArrayBufferView, b: ArrayBuffer | ArrayBufferView): boolean;
} }
/** /**
* The **`CryptoKey`** interface of the Web Crypto API represents a cryptographic key obtained from one of the SubtleCrypto methods SubtleCrypto.generateKey, SubtleCrypto.deriveKey, SubtleCrypto.importKey, or SubtleCrypto.unwrapKey. * The **`CryptoKey`** interface of the Web Crypto API represents a cryptographic key obtained from one of the SubtleCrypto methods generateKey(), deriveKey(), importKey(), or unwrapKey().
* Available only in secure contexts. * Available only in secure contexts.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey)
*/ */
declare abstract class CryptoKey { declare abstract class CryptoKey {
/** /**
* The read-only **`type`** property of the CryptoKey interface indicates which kind of key is represented by the object. * The read-only **`type`** property of the CryptoKey interface indicates which kind of key is represented by the object. It can have the following values:
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/type) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/type)
*/ */
readonly type: string; readonly type: string;
/** /**
* The read-only **`extractable`** property of the CryptoKey interface indicates whether or not the key may be extracted using `SubtleCrypto.exportKey()` or `SubtleCrypto.wrapKey()`. * The read-only **`extractable`** property of the CryptoKey interface indicates whether or not the key may be extracted using SubtleCrypto.exportKey() or SubtleCrypto.wrapKey().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/extractable) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/extractable)
*/ */
@@ -1253,12 +1266,15 @@ interface CryptoKeyArbitraryKeyAlgorithm {
length?: number; length?: number;
} }
declare class DigestStream extends WritableStream<ArrayBuffer | ArrayBufferView> { declare class DigestStream extends WritableStream<ArrayBuffer | ArrayBufferView> {
constructor(algorithm: string | SubtleCryptoHashAlgorithm); constructor(algorithm: string | SubtleCryptoHashAlgorithm, options?: DigestStreamOptions);
readonly digest: Promise<ArrayBuffer>; readonly digest: Promise<ArrayBuffer>;
get bytesWritten(): number | bigint; get bytesWritten(): number | bigint;
} }
interface DigestStreamOptions {
toWellFormed?: boolean;
}
/** /**
* The **`TextDecoder`** interface represents a decoder for a specific text encoding, such as `UTF-8`, `ISO-8859-2`, `KOI8-R`, `GBK`, etc. * The **`TextDecoder`** interface represents a decoder for a specific text encoding, such as UTF-8, ISO-8859-2, or GBK. A decoder takes an array of bytes as input and returns a JavaScript string.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder)
*/ */
@@ -1275,20 +1291,20 @@ declare class TextDecoder {
get ignoreBOM(): boolean; get ignoreBOM(): boolean;
} }
/** /**
* The **`TextEncoder`** interface takes a stream of code points as input and emits a stream of UTF-8 bytes. * The **`TextEncoder`** interface enables you to encode a JavaScript string using UTF-8.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder)
*/ */
declare class TextEncoder { declare class TextEncoder {
constructor(); constructor();
/** /**
* The **`TextEncoder.encode()`** method takes a string as input, and returns a Global_Objects/Uint8Array containing the text given in parameters encoded with the specific method for that TextEncoder object. * The **`TextEncoder.encode()`** method takes a string as input, and returns a Uint8Array containing the string encoded using UTF-8.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode)
*/ */
encode(input?: string): Uint8Array; encode(input?: string): Uint8Array;
/** /**
* The **`TextEncoder.encodeInto()`** method takes a string to encode and a destination Uint8Array to put resulting UTF-8 encoded text into, and returns a dictionary object indicating the progress of the encoding. * The **`TextEncoder.encodeInto()`** method takes a string to encode and a destination Uint8Array to put resulting UTF-8 encoded text into, and returns an object indicating the progress of the encoding. This is potentially more performant than the encode() method — especially when the target buffer is a view into a Wasm heap.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encodeInto) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encodeInto)
*/ */
@@ -1345,6 +1361,9 @@ declare class ErrorEvent extends Event {
get error(): any; get error(): any;
} }
interface ErrorEventErrorEventInit { interface ErrorEventErrorEventInit {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
message?: string; message?: string;
filename?: string; filename?: string;
lineno?: number; lineno?: number;
@@ -1357,135 +1376,139 @@ interface ErrorEventErrorEventInit {
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent)
*/ */
declare class MessageEvent extends Event { declare class MessageEvent extends Event {
constructor(type: string, initializer: MessageEventInit); constructor(type: string, initializer?: MessageEventInit);
/** /**
* The **`data`** read-only property of the The data sent by the message emitter; this can be any data type, depending on what originated this event. * The **`data`** read-only property of the MessageEvent interface represents the data sent by the message emitter.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/data) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/data)
*/ */
readonly data: any; readonly data: any;
/** /**
* The **`origin`** read-only property of the origin of the message emitter. * The **`origin`** read-only property of the MessageEvent interface is a string representing the origin of the message emitter.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/origin) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/origin)
*/ */
readonly origin: string | null; readonly origin: string | null;
/** /**
* The **`lastEventId`** read-only property of the unique ID for the event. * The **`lastEventId`** read-only property of the MessageEvent interface is a string representing a unique ID for the event.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/lastEventId) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/lastEventId)
*/ */
readonly lastEventId: string; readonly lastEventId: string;
/** /**
* The **`source`** read-only property of the a WindowProxy, MessagePort, or a `MessageEventSource` (which can be a WindowProxy, message emitter. * The **`source`** read-only property of the MessageEvent interface is a MessageEventSource (which can be a WindowProxy, MessagePort, or ServiceWorker object) representing the message emitter.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/source) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/source)
*/ */
readonly source: MessagePort | null; readonly source: MessagePort | null;
/** /**
* The **`ports`** read-only property of the containing all MessagePort objects sent with the message, in order. * The **`ports`** read-only property of the MessageEvent interface is an array of MessagePort objects containing all MessagePort objects sent with the message, in order.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/ports) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/ports)
*/ */
readonly ports: MessagePort[]; readonly ports: MessagePort[];
} }
interface MessageEventInit { interface MessageEventInit {
data: ArrayBuffer | string; bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
data?: any;
origin?: string;
lastEventId?: string;
source?: MessagePort;
ports?: MessagePort[];
} }
/** /**
* The **`PromiseRejectionEvent`** interface represents events which are sent to the global script context when JavaScript Promises are rejected. * The **`PromiseRejectionEvent`** interface represents events which are sent to the global script context when JavaScript Promises are rejected. These events are particularly useful for telemetry and debugging purposes.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent)
*/ */
declare abstract class PromiseRejectionEvent extends Event { declare abstract class PromiseRejectionEvent extends Event {
/** /**
* The PromiseRejectionEvent interface's **`promise`** read-only property indicates the JavaScript rejected. * The PromiseRejectionEvent interface's **`promise`** read-only property indicates the JavaScript Promise which was rejected. You can examine the event's PromiseRejectionEvent.reason property to learn why the promise was rejected.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/promise) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/promise)
*/ */
readonly promise: Promise<any>; readonly promise: Promise<any>;
/** /**
* The PromiseRejectionEvent **`reason`** read-only property is any JavaScript value or Object which provides the reason passed into Promise.reject(). * The PromiseRejectionEvent **`reason`** read-only property is any JavaScript value or Object which provides the reason passed into Promise.reject(). This in theory provides information about why the promise was rejected.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/reason) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/reason)
*/ */
readonly reason: any; readonly reason: any;
} }
/** /**
* The **`FormData`** interface provides a way to construct a set of key/value pairs representing form fields and their values, which can be sent using the Window/fetch, XMLHttpRequest.send() or navigator.sendBeacon() methods. * The **`FormData`** interface provides a way to construct a set of key/value pairs representing form fields and their values, which can be sent using the fetch(), XMLHttpRequest.send() or navigator.sendBeacon() methods. It uses the same format a form would use if the encoding type were set to "multipart/form-data".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData)
*/ */
declare class FormData { declare class FormData {
constructor(); constructor();
/** /**
* The **`append()`** method of the FormData interface appends a new value onto an existing key inside a `FormData` object, or adds the key if it does not already exist. * The **`append()`** method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append)
*/ */
append(name: string, value: string | Blob): void; append(name: string, value: string | Blob): void;
/** /**
* The **`append()`** method of the FormData interface appends a new value onto an existing key inside a `FormData` object, or adds the key if it does not already exist. * The **`append()`** method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append)
*/ */
append(name: string, value: string): void; append(name: string, value: string): void;
/** /**
* The **`append()`** method of the FormData interface appends a new value onto an existing key inside a `FormData` object, or adds the key if it does not already exist. * The **`append()`** method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append)
*/ */
append(name: string, value: Blob, filename?: string): void; append(name: string, value: Blob, filename?: string): void;
/** /**
* The **`delete()`** method of the FormData interface deletes a key and its value(s) from a `FormData` object. * The **`delete()`** method of the FormData interface deletes a key and its value(s) from a FormData object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/delete) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/delete)
*/ */
delete(name: string): void; delete(name: string): void;
/** /**
* The **`get()`** method of the FormData interface returns the first value associated with a given key from within a `FormData` object. * The **`get()`** method of the FormData interface returns the first value associated with a given key from within a FormData object. If you expect multiple values and want all of them, use the getAll() method instead.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/get) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/get)
*/ */
get(name: string): (File | string) | null; get(name: string): (File | string) | null;
/** /**
* The **`getAll()`** method of the FormData interface returns all the values associated with a given key from within a `FormData` object. * The **`getAll()`** method of the FormData interface returns all the values associated with a given key from within a FormData object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/getAll) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/getAll)
*/ */
getAll(name: string): (File | string)[]; getAll(name: string): (File | string)[];
/** /**
* The **`has()`** method of the FormData interface returns whether a `FormData` object contains a certain key. * The **`has()`** method of the FormData interface returns whether a FormData object contains a certain key.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/has) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/has)
*/ */
has(name: string): boolean; has(name: string): boolean;
/** /**
* The **`set()`** method of the FormData interface sets a new value for an existing key inside a `FormData` object, or adds the key/value if it does not already exist. * The **`set()`** method of the FormData interface sets a new value for an existing key inside a FormData object, or adds the key/value if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set)
*/ */
set(name: string, value: string | Blob): void; set(name: string, value: string | Blob): void;
/** /**
* The **`set()`** method of the FormData interface sets a new value for an existing key inside a `FormData` object, or adds the key/value if it does not already exist. * The **`set()`** method of the FormData interface sets a new value for an existing key inside a FormData object, or adds the key/value if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set)
*/ */
set(name: string, value: string): void; set(name: string, value: string): void;
/** /**
* The **`set()`** method of the FormData interface sets a new value for an existing key inside a `FormData` object, or adds the key/value if it does not already exist. * The **`set()`** method of the FormData interface sets a new value for an existing key inside a FormData object, or adds the key/value if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set)
*/ */
set(name: string, value: Blob, filename?: string): void; set(name: string, value: Blob, filename?: string): void;
/* Returns an array of key, value pairs for every entry in the list. */
entries(): IterableIterator<[ entries(): IterableIterator<[
key: string, key: string,
value: File | string value: File | string
]>; ]>;
/* Returns a list of keys in the list. */
keys(): IterableIterator<string>; keys(): IterableIterator<string>;
/* Returns a list of values in the list. */
values(): IterableIterator<(File | string)>; values(): IterableIterator<(File | string)>;
forEach<This = unknown>(callback: (this: This, value: File | string, key: string, parent: FormData) => void, thisArg?: This): void; forEach<This = unknown>(callback: (this: This, value: File | string, key: string, parent: FormData) => void, thisArg?: This): void;
[Symbol.iterator](): IterableIterator<[ [Symbol.iterator](): IterableIterator<[
@@ -1564,19 +1587,19 @@ interface DocumentEnd {
append(content: string, options?: ContentOptions): DocumentEnd; append(content: string, options?: ContentOptions): DocumentEnd;
} }
/** /**
* This is the event type for `fetch` events dispatched on the ServiceWorkerGlobalScope. * This is the event type for fetch events dispatched on the service worker global scope. It contains information about the fetch, including the request and how the receiver will treat the response. It provides the event.respondWith() method, which allows us to provide a response to this fetch.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent)
*/ */
declare abstract class FetchEvent extends ExtendableEvent { declare abstract class FetchEvent extends ExtendableEvent {
/** /**
* The **`request`** read-only property of the the event handler. * The **`request`** read-only property of the FetchEvent interface returns the Request that triggered the event handler.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/request) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/request)
*/ */
readonly request: Request; readonly request: Request;
/** /**
* The **`respondWith()`** method of allows you to provide a promise for a Response yourself. * The **`respondWith()`** method of FetchEvent prevents the browser's default fetch handling, and allows you to provide a promise for a Response yourself.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/respondWith) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/respondWith)
*/ */
@@ -1585,65 +1608,62 @@ declare abstract class FetchEvent extends ExtendableEvent {
} }
type HeadersInit = Headers | Iterable<Iterable<string>> | Record<string, string>; type HeadersInit = Headers | Iterable<Iterable<string>> | Record<string, string>;
/** /**
* The **`Headers`** interface of the Fetch API allows you to perform various actions on HTTP request and response headers. * The **`Headers`** interface of the Fetch API allows you to perform various actions on HTTP request and response headers. These actions include retrieving, setting, adding to, and removing headers from the list of the request's headers.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers)
*/ */
declare class Headers { declare class Headers {
constructor(init?: HeadersInit); constructor(init?: HeadersInit);
/** /**
* The **`get()`** method of the Headers interface returns a byte string of all the values of a header within a `Headers` object with a given name. * The **`get()`** method of the Headers interface returns a byte string of all the values of a header within a Headers object with a given name. If the requested header doesn't exist in the Headers object, it returns null.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/get) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/get)
*/ */
get(name: string): string | null; get(name: string): string | null;
getAll(name: string): string[]; getAll(name: string): string[];
/** /**
* The **`getSetCookie()`** method of the Headers interface returns an array containing the values of all Set-Cookie headers associated with a response. * The **`getSetCookie()`** method of the Headers interface returns an array containing the values of all Set-Cookie headers associated with a response. This allows Headers objects to handle having multiple Set-Cookie headers, which wasn't possible prior to its implementation.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/getSetCookie) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/getSetCookie)
*/ */
getSetCookie(): string[]; getSetCookie(): string[];
/** /**
* The **`has()`** method of the Headers interface returns a boolean stating whether a `Headers` object contains a certain header. * The **`has()`** method of the Headers interface returns a boolean stating whether a Headers object contains a certain header.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/has) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/has)
*/ */
has(name: string): boolean; has(name: string): boolean;
/** /**
* The **`set()`** method of the Headers interface sets a new value for an existing header inside a `Headers` object, or adds the header if it does not already exist. * The **`set()`** method of the Headers interface sets a new value for an existing header inside a Headers object, or adds the header if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/set)
*/ */
set(name: string, value: string): void; set(name: string, value: string): void;
/** /**
* The **`append()`** method of the Headers interface appends a new value onto an existing header inside a `Headers` object, or adds the header if it does not already exist. * The **`append()`** method of the Headers interface appends a new value onto an existing header inside a Headers object, or adds the header if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/append) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/append)
*/ */
append(name: string, value: string): void; append(name: string, value: string): void;
/** /**
* The **`delete()`** method of the Headers interface deletes a header from the current `Headers` object. * The **`delete()`** method of the Headers interface deletes a header from the current Headers object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/delete) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/delete)
*/ */
delete(name: string): void; delete(name: string): void;
forEach<This = unknown>(callback: (this: This, value: string, key: string, parent: Headers) => void, thisArg?: This): void; forEach<This = unknown>(callback: (this: This, value: string, key: string, parent: Headers) => void, thisArg?: This): void;
/* Returns an iterator allowing to go through all key/value pairs contained in this object. */
entries(): IterableIterator<[ entries(): IterableIterator<[
key: string, key: string,
value: string value: string
]>; ]>;
/* Returns an iterator allowing to go through all keys of the key/value pairs contained in this object. */
keys(): IterableIterator<string>; keys(): IterableIterator<string>;
/* Returns an iterator allowing to go through all values of the key/value pairs contained in this object. */
values(): IterableIterator<string>; values(): IterableIterator<string>;
[Symbol.iterator](): IterableIterator<[ [Symbol.iterator](): IterableIterator<[
key: string, key: string,
value: string value: string
]>; ]>;
} }
type BodyInit = ReadableStream<Uint8Array> | string | ArrayBuffer | ArrayBufferView | Blob | URLSearchParams | FormData; type BodyInit = ReadableStream<Uint8Array> | string | ArrayBuffer | ArrayBufferView | Blob | URLSearchParams | FormData | Iterable<ArrayBuffer | ArrayBufferView> | AsyncIterable<ArrayBuffer | ArrayBufferView>;
declare abstract class Body { declare abstract class Body {
/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body) */ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body) */
get body(): ReadableStream | null; get body(): ReadableStream | null;
@@ -1699,7 +1719,7 @@ interface Response extends Body {
*/ */
statusText: string; statusText: string;
/** /**
* The **`headers`** read-only property of the with the response. * The **`headers`** read-only property of the Response interface contains the Headers object associated with the response.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers)
*/ */
@@ -1717,7 +1737,7 @@ interface Response extends Body {
*/ */
redirected: boolean; redirected: boolean;
/** /**
* The **`url`** read-only property of the Response interface contains the URL of the response. * The **`url`** read-only property of the Response interface contains the URL of the response. The value of the url property will be the final URL obtained after any redirects.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/url) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/url)
*/ */
@@ -1725,7 +1745,7 @@ interface Response extends Body {
webSocket: WebSocket | null; webSocket: WebSocket | null;
cf: any | undefined; cf: any | undefined;
/** /**
* The **`type`** read-only property of the Response interface contains the type of the response. * The **`type`** read-only property of the Response interface contains the type of the response. The type determines whether scripts are able to access the response body and headers.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/type) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/type)
*/ */
@@ -1756,13 +1776,13 @@ declare var Request: {
*/ */
interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> extends Body { interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> extends Body {
/** /**
* The **`clone()`** method of the Request interface creates a copy of the current `Request` object. * The **`clone()`** method of the Request interface creates a copy of the current Request object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/clone) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/clone)
*/ */
clone(): Request<CfHostMetadata, Cf>; clone(): Request<CfHostMetadata, Cf>;
/** /**
* The **`method`** read-only property of the `POST`, etc.) A String indicating the method of the request. * The **`method`** read-only property of the Request interface contains the request's method (GET, POST, etc.)
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/method) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/method)
*/ */
@@ -1774,7 +1794,7 @@ interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> e
*/ */
url: string; url: string;
/** /**
* The **`headers`** read-only property of the with the request. * The **`headers`** read-only property of the Request interface contains the Headers object associated with the request.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/headers) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/headers)
*/ */
@@ -1800,13 +1820,13 @@ interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> e
*/ */
integrity: string; integrity: string;
/** /**
* The **`keepalive`** read-only property of the Request interface contains the request's `keepalive` setting (`true` or `false`), which indicates whether the browser will keep the associated request alive if the page that initiated it is unloaded before the request is complete. * The **`keepalive`** read-only property of the Request interface contains the request's keepalive setting (true or false), which indicates whether the browser will keep the associated request alive if the page that initiated it is unloaded before the request is complete.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/keepalive) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/keepalive)
*/ */
keepalive: boolean; keepalive: boolean;
/** /**
* The **`cache`** read-only property of the Request interface contains the cache mode of the request. * The **`cache`** read-only property of the Request interface contains the cache mode of the request. It controls how the request will interact with the browser's HTTP cache.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/cache) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/cache)
*/ */
@@ -2195,7 +2215,7 @@ type ReadableStreamReadResult<R = any> = {
value?: undefined; value?: undefined;
}; };
/** /**
* The `ReadableStream` interface of the Streams API represents a readable stream of byte data. * The **`ReadableStream`** interface of the Streams API represents a readable stream of byte data. The Fetch API offers a concrete instance of a ReadableStream through the body property of a Response object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream)
*/ */
@@ -2213,13 +2233,13 @@ interface ReadableStream<R = any> {
*/ */
cancel(reason?: any): Promise<void>; cancel(reason?: any): Promise<void>;
/** /**
* The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. * The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. While the stream is locked, no other reader can be acquired until this one is released.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader)
*/ */
getReader(): ReadableStreamDefaultReader<R>; getReader(): ReadableStreamDefaultReader<R>;
/** /**
* The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. * The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. While the stream is locked, no other reader can be acquired until this one is released.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader)
*/ */
@@ -2231,13 +2251,13 @@ interface ReadableStream<R = any> {
*/ */
pipeThrough<T>(transform: ReadableWritablePair<T, R>, options?: StreamPipeOptions): ReadableStream<T>; pipeThrough<T>(transform: ReadableWritablePair<T, R>, options?: StreamPipeOptions): ReadableStream<T>;
/** /**
* The **`pipeTo()`** method of the ReadableStream interface pipes the current `ReadableStream` to a given WritableStream and returns a Promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered. * The **`pipeTo()`** method of the ReadableStream interface pipes the current ReadableStream to a given WritableStream and returns a Promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/pipeTo) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/pipeTo)
*/ */
pipeTo(destination: WritableStream<R>, options?: StreamPipeOptions): Promise<void>; pipeTo(destination: WritableStream<R>, options?: StreamPipeOptions): Promise<void>;
/** /**
* The **`tee()`** method of the two-element array containing the two resulting branches as new ReadableStream instances. * The **`tee()`** method of the ReadableStream interface tees the current readable stream, returning a two-element array containing the two resulting branches as new ReadableStream instances.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/tee) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/tee)
*/ */
@@ -2249,7 +2269,7 @@ interface ReadableStream<R = any> {
[Symbol.asyncIterator](options?: ReadableStreamValuesOptions): AsyncIterableIterator<R>; [Symbol.asyncIterator](options?: ReadableStreamValuesOptions): AsyncIterableIterator<R>;
} }
/** /**
* The `ReadableStream` interface of the Streams API represents a readable stream of byte data. * The **`ReadableStream`** interface of the Streams API represents a readable stream of byte data. The Fetch API offers a concrete instance of a ReadableStream through the body property of a Response object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream)
*/ */
@@ -2281,7 +2301,7 @@ declare class ReadableStreamDefaultReader<R = any> {
releaseLock(): void; releaseLock(): void;
} }
/** /**
* The `ReadableStreamBYOBReader` interface of the Streams API defines a reader for a ReadableStream that supports zero-copy reading from an underlying byte source. * The **`ReadableStreamBYOBReader`** interface of the Streams API defines a reader for a ReadableStream that supports zero-copy reading from an underlying byte source. It is used for efficient copying from underlying sources where the data is delivered as an "anonymous" sequence of bytes, such as files.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader)
*/ */
@@ -2290,13 +2310,13 @@ declare class ReadableStreamBYOBReader {
get closed(): Promise<void>; get closed(): Promise<void>;
cancel(reason?: any): Promise<void>; cancel(reason?: any): Promise<void>;
/** /**
* The **`read()`** method of the ReadableStreamBYOBReader interface is used to read data into a view on a user-supplied buffer from an associated readable byte stream. * The **`read()`** method of the ReadableStreamBYOBReader interface is used to read data into a view on a user-supplied buffer from an associated readable byte stream. A request for data will be satisfied from the stream's internal queues if there is any data present. If the stream queues are empty, the request may be supplied as a zero-copy transfer from the underlying byte source.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/read) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/read)
*/ */
read<T extends ArrayBufferView>(view: T): Promise<ReadableStreamReadResult<T>>; read<T extends ArrayBufferView>(view: T): Promise<ReadableStreamReadResult<T>>;
/** /**
* The **`releaseLock()`** method of the ReadableStreamBYOBReader interface releases the reader's lock on the stream. * The **`releaseLock()`** method of the ReadableStreamBYOBReader interface releases the reader's lock on the stream. After the lock is released, the reader is no longer active.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/releaseLock) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/releaseLock)
*/ */
@@ -2315,7 +2335,7 @@ interface ReadableStreamGetReaderOptions {
mode: "byob"; mode: "byob";
} }
/** /**
* The **`ReadableStreamBYOBRequest`** interface of the Streams API represents a 'pull request' for data from an underlying source that will made as a zero-copy transfer to a consumer (bypassing the stream's internal queues). * The **`ReadableStreamBYOBRequest`** interface of the Streams API represents a "pull request" for data from an underlying source that will made as a zero-copy transfer to a consumer (bypassing the stream's internal queues).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest)
*/ */
@@ -2341,13 +2361,13 @@ declare abstract class ReadableStreamBYOBRequest {
get atLeast(): number | null; get atLeast(): number | null;
} }
/** /**
* The **`ReadableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a ReadableStream's state and internal queue. * The **`ReadableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a ReadableStream's state and internal queue. Default controllers are for streams that are not byte streams.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController)
*/ */
declare abstract class ReadableStreamDefaultController<R = any> { declare abstract class ReadableStreamDefaultController<R = any> {
/** /**
* The **`desiredSize`** read-only property of the required to fill the stream's internal queue. * The **`desiredSize`** read-only property of the ReadableStreamDefaultController interface returns the desired size required to fill the stream's internal queue.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/desiredSize) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/desiredSize)
*/ */
@@ -2359,32 +2379,32 @@ declare abstract class ReadableStreamDefaultController<R = any> {
*/ */
close(): void; close(): void;
/** /**
* The **`enqueue()`** method of the ```js-nolint enqueue(chunk) ``` - `chunk` - : The chunk to enqueue. * The **`enqueue()`** method of the ReadableStreamDefaultController interface enqueues a given chunk in the associated stream.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/enqueue) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/enqueue)
*/ */
enqueue(chunk?: R): void; enqueue(chunk?: R): void;
/** /**
* The **`error()`** method of the with the associated stream to error. * The **`error()`** method of the ReadableStreamDefaultController interface causes any future interactions with the associated stream to error.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/error) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/error)
*/ */
error(reason: any): void; error(reason: any): void;
} }
/** /**
* The **`ReadableByteStreamController`** interface of the Streams API represents a controller for a readable byte stream. * The **`ReadableByteStreamController`** interface of the Streams API represents a controller for a readable byte stream. It allows control of the state and internal queue of a ReadableStream with an underlying byte source, and enables efficient zero-copy transfer of data from the underlying source to a consumer when the stream's internal queue is empty.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController)
*/ */
declare abstract class ReadableByteStreamController { declare abstract class ReadableByteStreamController {
/** /**
* The **`byobRequest`** read-only property of the ReadableByteStreamController interface returns the current BYOB request, or `null` if there are no pending requests. * The **`byobRequest`** read-only property of the ReadableByteStreamController interface returns the current BYOB request, or null if there are no pending requests.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/byobRequest) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/byobRequest)
*/ */
get byobRequest(): ReadableStreamBYOBRequest | null; get byobRequest(): ReadableStreamBYOBRequest | null;
/** /**
* The **`desiredSize`** read-only property of the ReadableByteStreamController interface returns the number of bytes required to fill the stream's internal queue to its 'desired size'. * The **`desiredSize`** read-only property of the ReadableByteStreamController interface returns the number of bytes required to fill the stream's internal queue to its "desired size".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/desiredSize) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/desiredSize)
*/ */
@@ -2396,7 +2416,7 @@ declare abstract class ReadableByteStreamController {
*/ */
close(): void; close(): void;
/** /**
* The **`enqueue()`** method of the ReadableByteStreamController interface enqueues a given chunk on the associated readable byte stream (the chunk is copied into the stream's internal queues). * The **`enqueue()`** method of the ReadableByteStreamController interface enqueues a given chunk on the associated readable byte stream (the chunk is transferred into the stream's internal queues).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/enqueue) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/enqueue)
*/ */
@@ -2409,7 +2429,7 @@ declare abstract class ReadableByteStreamController {
error(reason: any): void; error(reason: any): void;
} }
/** /**
* The **`WritableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a WritableStream's state. * The **`WritableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a WritableStream's state. When constructing a WritableStream, the underlying sink is given a corresponding WritableStreamDefaultController instance to manipulate.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController)
*/ */
@@ -2421,7 +2441,7 @@ declare abstract class WritableStreamDefaultController {
*/ */
get signal(): AbortSignal; get signal(): AbortSignal;
/** /**
* The **`error()`** method of the with the associated stream to error. * The **`error()`** method of the WritableStreamDefaultController interface causes any future interactions with the associated stream to error.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController/error) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController/error)
*/ */
@@ -2446,7 +2466,7 @@ declare abstract class TransformStreamDefaultController<O = any> {
*/ */
enqueue(chunk?: O): void; enqueue(chunk?: O): void;
/** /**
* The **`error()`** method of the TransformStreamDefaultController interface errors both sides of the stream. * The **`error()`** method of the TransformStreamDefaultController interface errors both sides of the stream. Any further interactions with it will fail with the given error message, and any chunks in the queue will be discarded.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/error) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/error)
*/ */
@@ -2468,14 +2488,14 @@ interface ReadableWritablePair<R = any, W = any> {
writable: WritableStream<W>; writable: WritableStream<W>;
} }
/** /**
* The **`WritableStream`** interface of the Streams API provides a standard abstraction for writing streaming data to a destination, known as a sink. * The **`WritableStream`** interface of the Streams API provides a standard abstraction for writing streaming data to a destination, known as a sink. This object comes with built-in backpressure and queuing.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream)
*/ */
declare class WritableStream<W = any> { declare class WritableStream<W = any> {
constructor(underlyingSink?: UnderlyingSink, queuingStrategy?: QueuingStrategy); constructor(underlyingSink?: UnderlyingSink, queuingStrategy?: QueuingStrategy);
/** /**
* The **`locked`** read-only property of the WritableStream interface returns a boolean indicating whether the `WritableStream` is locked to a writer. * The **`locked`** read-only property of the WritableStream interface returns a boolean indicating whether the WritableStream is locked to a writer.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/locked) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/locked)
*/ */
@@ -2487,83 +2507,83 @@ declare class WritableStream<W = any> {
*/ */
abort(reason?: any): Promise<void>; abort(reason?: any): Promise<void>;
/** /**
* The **`close()`** method of the WritableStream interface closes the associated stream. * The **`close()`** method of the WritableStream interface closes the associated stream. All chunks written before this method is called are sent before the returned promise is fulfilled.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/close)
*/ */
close(): Promise<void>; close(): Promise<void>;
/** /**
* The **`getWriter()`** method of the WritableStream interface returns a new instance of WritableStreamDefaultWriter and locks the stream to that instance. * The **`getWriter()`** method of the WritableStream interface returns a new instance of WritableStreamDefaultWriter and locks the stream to that instance. While the stream is locked, no other writer can be acquired until this one is released.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/getWriter) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/getWriter)
*/ */
getWriter(): WritableStreamDefaultWriter<W>; getWriter(): WritableStreamDefaultWriter<W>;
} }
/** /**
* The **`WritableStreamDefaultWriter`** interface of the Streams API is the object returned by WritableStream.getWriter() and once created locks the writer to the `WritableStream` ensuring that no other streams can write to the underlying sink. * The **`WritableStreamDefaultWriter`** interface of the Streams API is the object returned by WritableStream.getWriter() and once created locks the writer to the WritableStream ensuring that no other streams can write to the underlying sink.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter)
*/ */
declare class WritableStreamDefaultWriter<W = any> { declare class WritableStreamDefaultWriter<W = any> {
constructor(stream: WritableStream); constructor(stream: WritableStream);
/** /**
* The **`closed`** read-only property of the the stream errors or the writer's lock is released. * The **`closed`** read-only property of the WritableStreamDefaultWriter interface returns a Promise that fulfills if the stream becomes closed, or rejects if the stream errors or the writer's lock is released.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/closed) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/closed)
*/ */
get closed(): Promise<void>; get closed(): Promise<void>;
/** /**
* The **`ready`** read-only property of the that resolves when the desired size of the stream's internal queue transitions from non-positive to positive, signaling that it is no longer applying backpressure. * The **`ready`** read-only property of the WritableStreamDefaultWriter interface returns a Promise that resolves when the desired size of the stream's internal queue transitions from non-positive to positive, signaling that it is no longer applying backpressure.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/ready) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/ready)
*/ */
get ready(): Promise<void>; get ready(): Promise<void>;
/** /**
* The **`desiredSize`** read-only property of the to fill the stream's internal queue. * The **`desiredSize`** read-only property of the WritableStreamDefaultWriter interface returns the desired size required to fill the stream's internal queue.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/desiredSize) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/desiredSize)
*/ */
get desiredSize(): number | null; get desiredSize(): number | null;
/** /**
* The **`abort()`** method of the the producer can no longer successfully write to the stream and it is to be immediately moved to an error state, with any queued writes discarded. * The **`abort()`** method of the WritableStreamDefaultWriter interface aborts the stream, signaling that the producer can no longer successfully write to the stream and it is to be immediately moved to an error state, with any queued writes discarded.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/abort) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/abort)
*/ */
abort(reason?: any): Promise<void>; abort(reason?: any): Promise<void>;
/** /**
* The **`close()`** method of the stream. * The **`close()`** method of the WritableStreamDefaultWriter interface closes the associated writable stream.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/close)
*/ */
close(): Promise<void>; close(): Promise<void>;
/** /**
* The **`write()`** method of the operation. * The **`write()`** method of the WritableStreamDefaultWriter interface writes a passed chunk of data to a WritableStream and its underlying sink, then returns a Promise that resolves to indicate the success or failure of the write operation.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/write) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/write)
*/ */
write(chunk?: W): Promise<void>; write(chunk?: W): Promise<void>;
/** /**
* The **`releaseLock()`** method of the corresponding stream. * The **`releaseLock()`** method of the WritableStreamDefaultWriter interface releases the writer's lock on the corresponding stream. After the lock is released, the writer is no longer active. If the associated stream is errored when the lock is released, the writer will appear errored in the same way from now on; otherwise, the writer will appear closed.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/releaseLock) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/releaseLock)
*/ */
releaseLock(): void; releaseLock(): void;
} }
/** /**
* The **`TransformStream`** interface of the Streams API represents a concrete implementation of the pipe chain _transform stream_ concept. * The **`TransformStream`** interface of the Streams API represents a concrete implementation of the pipe chain transform stream concept.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream)
*/ */
declare class TransformStream<I = any, O = any> { declare class TransformStream<I = any, O = any> {
constructor(transformer?: Transformer<I, O>, writableStrategy?: QueuingStrategy<I>, readableStrategy?: QueuingStrategy<O>); constructor(transformer?: Transformer<I, O>, writableStrategy?: QueuingStrategy<I>, readableStrategy?: QueuingStrategy<O>);
/** /**
* The **`readable`** read-only property of the TransformStream interface returns the ReadableStream instance controlled by this `TransformStream`. * The **`readable`** read-only property of the TransformStream interface returns the ReadableStream instance controlled by this TransformStream. This stream emits the transformed output data.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/readable) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/readable)
*/ */
get readable(): ReadableStream<O>; get readable(): ReadableStream<O>;
/** /**
* The **`writable`** read-only property of the TransformStream interface returns the WritableStream instance controlled by this `TransformStream`. * The **`writable`** read-only property of the TransformStream interface returns the WritableStream instance controlled by this TransformStream. This stream accepts input data that will be transformed and emitted to the readable stream.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/writable) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/writable)
*/ */
@@ -2582,7 +2602,7 @@ interface ReadableStreamValuesOptions {
preventCancel?: boolean; preventCancel?: boolean;
} }
/** /**
* The **`CompressionStream`** interface of the Compression Streams API is an API for compressing a stream of data. * The **`CompressionStream`** interface of the Compression Streams API compresses a stream of data. It implements the same shape as a TransformStream, allowing it to be used in ReadableStream.pipeThrough() and similar methods.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CompressionStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CompressionStream)
*/ */
@@ -2590,7 +2610,7 @@ declare class CompressionStream extends TransformStream<ArrayBuffer | ArrayBuffe
constructor(format: "gzip" | "deflate" | "deflate-raw"); constructor(format: "gzip" | "deflate" | "deflate-raw");
} }
/** /**
* The **`DecompressionStream`** interface of the Compression Streams API is an API for decompressing a stream of data. * The **`DecompressionStream`** interface of the Compression Streams API decompresses a stream of data. It implements the same shape as a TransformStream, allowing it to be used in ReadableStream.pipeThrough() and similar methods.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DecompressionStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DecompressionStream)
*/ */
@@ -2598,7 +2618,7 @@ declare class DecompressionStream extends TransformStream<ArrayBuffer | ArrayBuf
constructor(format: "gzip" | "deflate" | "deflate-raw"); constructor(format: "gzip" | "deflate" | "deflate-raw");
} }
/** /**
* The **`TextEncoderStream`** interface of the Encoding API converts a stream of strings into bytes in the UTF-8 encoding. * The **`TextEncoderStream`** interface of the Encoding API converts a stream of strings into bytes in the UTF-8 encoding. It is the streaming equivalent of TextEncoder. It implements the same shape as a TransformStream, allowing it to be used in ReadableStream.pipeThrough() and similar methods.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoderStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoderStream)
*/ */
@@ -2607,7 +2627,7 @@ declare class TextEncoderStream extends TransformStream<string, Uint8Array> {
get encoding(): string; get encoding(): string;
} }
/** /**
* The **`TextDecoderStream`** interface of the Encoding API converts a stream of text in a binary encoding, such as UTF-8 etc., to a stream of strings. * The **`TextDecoderStream`** interface of the Encoding API converts a stream of text in a binary encoding, such as UTF-8 etc., to a stream of strings. It is the streaming equivalent of TextDecoder. It implements the same shape as a TransformStream, allowing it to be used in ReadableStream.pipeThrough() and similar methods.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoderStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoderStream)
*/ */
@@ -2756,6 +2776,12 @@ interface TraceLog {
readonly timestamp: number; readonly timestamp: number;
readonly level: string; readonly level: string;
readonly message: any; readonly message: any;
readonly errorInfo?: (TraceLogErrorInfo | null)[];
}
interface TraceLogErrorInfo {
name: string;
message: string;
stack?: string;
} }
interface TraceException { interface TraceException {
readonly timestamp: number; readonly timestamp: number;
@@ -2776,7 +2802,7 @@ interface UnsafeTraceMetrics {
fromTrace(item: TraceItem): TraceMetrics; fromTrace(item: TraceItem): TraceMetrics;
} }
/** /**
* The **`URL`** interface is used to parse, construct, normalize, and encode URL. * The **`URL`** interface is used to parse, construct, normalize, and encode URLs. It works by providing properties which allow you to easily read and modify the components of a URL.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL)
*/ */
@@ -2801,121 +2827,121 @@ declare class URL {
*/ */
set href(value: string); set href(value: string);
/** /**
* The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final `':'`. * The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final ":".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol)
*/ */
get protocol(): string; get protocol(): string;
/** /**
* The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final `':'`. * The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final ":".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol)
*/ */
set protocol(value: string); set protocol(value: string);
/** /**
* The **`username`** property of the URL interface is a string containing the username component of the URL. * The **`username`** property of the URL interface is a string containing the username component of the URL. If the URL does not have a username, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username)
*/ */
get username(): string; get username(): string;
/** /**
* The **`username`** property of the URL interface is a string containing the username component of the URL. * The **`username`** property of the URL interface is a string containing the username component of the URL. If the URL does not have a username, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username)
*/ */
set username(value: string); set username(value: string);
/** /**
* The **`password`** property of the URL interface is a string containing the password component of the URL. * The **`password`** property of the URL interface is a string containing the password component of the URL. If the URL does not have a password, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password)
*/ */
get password(): string; get password(): string;
/** /**
* The **`password`** property of the URL interface is a string containing the password component of the URL. * The **`password`** property of the URL interface is a string containing the password component of the URL. If the URL does not have a password, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password)
*/ */
set password(value: string); set password(value: string);
/** /**
* The **`host`** property of the URL interface is a string containing the host, which is the URL.hostname, and then, if the port of the URL is nonempty, a `':'`, followed by the URL.port of the URL. * The **`host`** property of the URL interface is a string containing the host, which is the hostname, and then, if the port of the URL is nonempty, a ":", followed by the port of the URL. If the URL does not have a hostname, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host)
*/ */
get host(): string; get host(): string;
/** /**
* The **`host`** property of the URL interface is a string containing the host, which is the URL.hostname, and then, if the port of the URL is nonempty, a `':'`, followed by the URL.port of the URL. * The **`host`** property of the URL interface is a string containing the host, which is the hostname, and then, if the port of the URL is nonempty, a ":", followed by the port of the URL. If the URL does not have a hostname, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host)
*/ */
set host(value: string); set host(value: string);
/** /**
* The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. * The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. If the URL does not have a hostname, this property contains an empty string, "". IPv4 and IPv6 addresses are normalized, such as stripping leading zeros, and domain names are converted to IDN.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname)
*/ */
get hostname(): string; get hostname(): string;
/** /**
* The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. * The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. If the URL does not have a hostname, this property contains an empty string, "". IPv4 and IPv6 addresses are normalized, such as stripping leading zeros, and domain names are converted to IDN.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname)
*/ */
set hostname(value: string); set hostname(value: string);
/** /**
* The **`port`** property of the URL interface is a string containing the port number of the URL. * The **`port`** property of the URL interface is a string containing the port number of the URL. If the port is the default for the protocol (80 for ws: and http:, 443 for wss: and https:, and 21 for ftp:), this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port)
*/ */
get port(): string; get port(): string;
/** /**
* The **`port`** property of the URL interface is a string containing the port number of the URL. * The **`port`** property of the URL interface is a string containing the port number of the URL. If the port is the default for the protocol (80 for ws: and http:, 443 for wss: and https:, and 21 for ftp:), this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port)
*/ */
set port(value: string); set port(value: string);
/** /**
* The **`pathname`** property of the URL interface represents a location in a hierarchical structure. * The **`pathname`** property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname)
*/ */
get pathname(): string; get pathname(): string;
/** /**
* The **`pathname`** property of the URL interface represents a location in a hierarchical structure. * The **`pathname`** property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname)
*/ */
set pathname(value: string); set pathname(value: string);
/** /**
* The **`search`** property of the URL interface is a search string, also called a _query string_, that is a string containing a `'?'` followed by the parameters of the URL. * The **`search`** property of the URL interface is a search string, also called a query string, that is a string containing a "?" followed by the parameters of the URL. If the URL does not have a search query, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search)
*/ */
get search(): string; get search(): string;
/** /**
* The **`search`** property of the URL interface is a search string, also called a _query string_, that is a string containing a `'?'` followed by the parameters of the URL. * The **`search`** property of the URL interface is a search string, also called a query string, that is a string containing a "?" followed by the parameters of the URL. If the URL does not have a search query, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search)
*/ */
set search(value: string); set search(value: string);
/** /**
* The **`hash`** property of the URL interface is a string containing a `'#'` followed by the fragment identifier of the URL. * The **`hash`** property of the URL interface is a string containing a "#" followed by the fragment identifier of the URL. If the URL does not have a fragment identifier, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash)
*/ */
get hash(): string; get hash(): string;
/** /**
* The **`hash`** property of the URL interface is a string containing a `'#'` followed by the fragment identifier of the URL. * The **`hash`** property of the URL interface is a string containing a "#" followed by the fragment identifier of the URL. If the URL does not have a fragment identifier, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash)
*/ */
set hash(value: string); set hash(value: string);
/** /**
* The **`searchParams`** read-only property of the access to the [MISSING: httpmethod('GET')] decoded query arguments contained in the URL. * The **`searchParams`** read-only property of the URL interface returns a URLSearchParams object allowing access to the GET decoded query arguments contained in the URL.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/searchParams) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/searchParams)
*/ */
get searchParams(): URLSearchParams; get searchParams(): URLSearchParams;
/** /**
* The **`toJSON()`** method of the URL interface returns a string containing a serialized version of the URL, although in practice it seems to have the same effect as ```js-nolint toJSON() ``` None. * The **`toJSON()`** method of the URL interface returns a string containing a serialized version of the URL, although in practice it seems to have the same effect as URL.toString().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/toJSON) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/toJSON)
*/ */
@@ -2935,13 +2961,13 @@ declare class URL {
*/ */
static parse(url: string, base?: string): URL | null; static parse(url: string, base?: string): URL | null;
/** /**
* The **`createObjectURL()`** static method of the URL interface creates a string containing a URL representing the object given in the parameter. * The **`createObjectURL()`** static method of the URL interface creates a string containing a blob URL pointing to the object given in the parameter.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static)
*/ */
static createObjectURL(object: File | Blob): string; static createObjectURL(object: File | Blob): string;
/** /**
* The **`revokeObjectURL()`** static method of the URL interface releases an existing object URL which was previously created by calling Call this method when you've finished using an object URL to let the browser know not to keep the reference to the file any longer. * The **`revokeObjectURL()`** static method of the URL interface releases an existing object URL which was previously created by calling URL.createObjectURL().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static)
*/ */
@@ -2991,25 +3017,22 @@ declare class URLSearchParams {
*/ */
has(name: string, value?: string): boolean; has(name: string, value?: string): boolean;
/** /**
* The **`set()`** method of the URLSearchParams interface sets the value associated with a given search parameter to the given value. * The **`set()`** method of the URLSearchParams interface sets the value associated with a given search parameter to the given value. If there were several matching values, this method deletes the others. If the search parameter doesn't exist, this method creates it.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/set)
*/ */
set(name: string, value: string): void; set(name: string, value: string): void;
/** /**
* The **`URLSearchParams.sort()`** method sorts all key/value pairs contained in this object in place and returns `undefined`. * The **`URLSearchParams.sort()`** method sorts all key/value pairs contained in this object in place and returns undefined. Key/value pairs are sorted by the values of the UTF-16 code units of the keys. This method uses a stable sorting algorithm (i.e., the relative order between key/value pairs with equal keys will be preserved).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/sort) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/sort)
*/ */
sort(): void; sort(): void;
/* Returns an array of key, value pairs for every entry in the search params. */
entries(): IterableIterator<[ entries(): IterableIterator<[
key: string, key: string,
value: string value: string
]>; ]>;
/* Returns a list of keys in the search params. */
keys(): IterableIterator<string>; keys(): IterableIterator<string>;
/* Returns a list of values in the search params. */
values(): IterableIterator<string>; values(): IterableIterator<string>;
forEach<This = unknown>(callback: (this: This, value: string, key: string, parent: URLSearchParams) => void, thisArg?: This): void; forEach<This = unknown>(callback: (this: This, value: string, key: string, parent: URLSearchParams) => void, thisArg?: This): void;
/*function toString() { [native code] }*/ /*function toString() { [native code] }*/
@@ -3019,18 +3042,78 @@ declare class URLSearchParams {
value: string value: string
]>; ]>;
} }
/**
* The **`URLPattern`** interface of the URL Pattern API matches URLs or parts of URLs against a pattern. The pattern can contain capturing groups that extract parts of the matched URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern)
*/
declare class URLPattern { declare class URLPattern {
constructor(input?: (string | URLPatternInit), baseURL?: (string | URLPatternOptions), patternOptions?: URLPatternOptions); constructor(input?: (string | URLPatternInit), baseURL?: (string | URLPatternOptions), patternOptions?: URLPatternOptions);
/**
* The **`protocol`** read-only property of the URLPattern interface is a string containing the pattern used to match the protocol part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/protocol)
*/
get protocol(): string; get protocol(): string;
/**
* The **`username`** read-only property of the URLPattern interface is a string containing the pattern used to match the username part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/username)
*/
get username(): string; get username(): string;
/**
* The **`password`** read-only property of the URLPattern interface is a string containing the pattern used to match the password part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/password)
*/
get password(): string; get password(): string;
/**
* The **`hostname`** read-only property of the URLPattern interface is a string containing the pattern used to match the hostname part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/hostname)
*/
get hostname(): string; get hostname(): string;
/**
* The **`port`** read-only property of the URLPattern interface is a string containing the pattern used to match the port part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/port)
*/
get port(): string; get port(): string;
/**
* The **`pathname`** read-only property of the URLPattern interface is a string containing the pattern used to match the pathname part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/pathname)
*/
get pathname(): string; get pathname(): string;
/**
* The **`search`** read-only property of the URLPattern interface is a string containing the pattern used to match the search part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/search)
*/
get search(): string; get search(): string;
/**
* The **`hash`** read-only property of the URLPattern interface is a string containing the pattern used to match the fragment part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/hash)
*/
get hash(): string; get hash(): string;
/**
* The **`hasRegExpGroups`** read-only property of the URLPattern interface is a boolean indicating whether or not any of the URLPattern components contain regular expression capturing groups.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/hasRegExpGroups)
*/
get hasRegExpGroups(): boolean; get hasRegExpGroups(): boolean;
/**
* The **`test()`** method of the URLPattern interface takes a URL string or object of URL parts, and returns a boolean indicating if the given input matches the current pattern.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/test)
*/
test(input?: (string | URLPatternInit), baseURL?: string): boolean; test(input?: (string | URLPatternInit), baseURL?: string): boolean;
/**
* The **`exec()`** method of the URLPattern interface takes a URL or object of URL parts, and returns either an object containing the results of matching the URL to the pattern, or null if the URL does not match the pattern.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/exec)
*/
exec(input?: (string | URLPatternInit), baseURL?: string): URLPatternResult | null; exec(input?: (string | URLPatternInit), baseURL?: string): URLPatternResult | null;
} }
interface URLPatternInit { interface URLPatternInit {
@@ -3063,7 +3146,7 @@ interface URLPatternOptions {
ignoreCase?: boolean; ignoreCase?: boolean;
} }
/** /**
* A `CloseEvent` is sent to clients using WebSockets when the connection is closed. * A **`CloseEvent`** is sent to clients using WebSockets when the connection is closed. This is delivered to the listener indicated by the WebSocket object's onclose attribute.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent)
*/ */
@@ -3082,13 +3165,16 @@ declare class CloseEvent extends Event {
*/ */
readonly reason: string; readonly reason: string;
/** /**
* The **`wasClean`** read-only property of the CloseEvent interface returns `true` if the connection closed cleanly. * The **`wasClean`** read-only property of the CloseEvent interface returns true if the connection closed cleanly.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/wasClean) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/wasClean)
*/ */
readonly wasClean: boolean; readonly wasClean: boolean;
} }
interface CloseEventInit { interface CloseEventInit {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
code?: number; code?: number;
reason?: string; reason?: string;
wasClean?: boolean; wasClean?: boolean;
@@ -3100,7 +3186,7 @@ type WebSocketEventMap = {
error: ErrorEvent; error: ErrorEvent;
}; };
/** /**
* The `WebSocket` object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection. * The **`WebSocket`** object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket)
*/ */
@@ -3117,20 +3203,20 @@ declare var WebSocket: {
readonly CLOSED: number; readonly CLOSED: number;
}; };
/** /**
* The `WebSocket` object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection. * The **`WebSocket`** object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket)
*/ */
interface WebSocket extends EventTarget<WebSocketEventMap> { interface WebSocket extends EventTarget<WebSocketEventMap> {
accept(options?: WebSocketAcceptOptions): void; accept(options?: WebSocketAcceptOptions): void;
/** /**
* The **`WebSocket.send()`** method enqueues the specified data to be transmitted to the server over the WebSocket connection, increasing the value of `bufferedAmount` by the number of bytes needed to contain the data. * The **`WebSocket.send()`** method enqueues the specified data to be transmitted to the server over the WebSocket connection, increasing the value of bufferedAmount by the number of bytes needed to contain the data. If the data can't be sent (for example, because it needs to be buffered but the buffer is full), the socket is closed automatically. The browser will throw an exception if you call send() when the connection is in the CONNECTING state. If you call send() when the connection is in the CLOSING or CLOSED states, the browser will silently discard the data.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/send) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/send)
*/ */
send(message: (ArrayBuffer | ArrayBufferView) | string): void; send(message: (ArrayBuffer | ArrayBufferView) | string): void;
/** /**
* The **`WebSocket.close()`** method closes the already `CLOSED`, this method does nothing. * The **`WebSocket.close()`** method closes the WebSocket connection or connection attempt, if any. If the connection is already CLOSED, this method does nothing.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/close)
*/ */
@@ -3150,13 +3236,13 @@ interface WebSocket extends EventTarget<WebSocketEventMap> {
*/ */
url: string | null; url: string | null;
/** /**
* The **`WebSocket.protocol`** read-only property returns the name of the sub-protocol the server selected; this will be one of the strings specified in the `protocols` parameter when creating the WebSocket object, or the empty string if no connection is established. * The **`WebSocket.protocol`** read-only property returns the name of the sub-protocol the server selected; this will be one of the strings specified in the protocols parameter when creating the WebSocket object, or the empty string if no connection is established.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/protocol) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/protocol)
*/ */
protocol: string | null; protocol: string | null;
/** /**
* The **`WebSocket.extensions`** read-only property returns the extensions selected by the server. * The **`WebSocket.extensions`** read-only property returns the extensions selected by the server. This is currently only the empty string or a list of extensions as negotiated by the connection.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/extensions) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/extensions)
*/ */
@@ -3243,25 +3329,25 @@ interface SocketInfo {
declare class EventSource extends EventTarget { declare class EventSource extends EventTarget {
constructor(url: string, init?: EventSourceEventSourceInit); constructor(url: string, init?: EventSourceEventSourceInit);
/** /**
* The **`close()`** method of the EventSource interface closes the connection, if one is made, and sets the ```js-nolint close() ``` None. * The **`close()`** method of the EventSource interface closes the connection, if one is made, and sets the EventSource.readyState attribute to 2 (closed).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close)
*/ */
close(): void; close(): void;
/** /**
* The **`url`** read-only property of the URL of the source. * The **`url`** read-only property of the EventSource interface returns a string representing the URL of the source.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url)
*/ */
get url(): string; get url(): string;
/** /**
* The **`withCredentials`** read-only property of the the `EventSource` object was instantiated with CORS credentials set. * The **`withCredentials`** read-only property of the EventSource interface returns a boolean value indicating whether the EventSource object was instantiated with CORS credentials set.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials)
*/ */
get withCredentials(): boolean; get withCredentials(): boolean;
/** /**
* The **`readyState`** read-only property of the connection. * The **`readyState`** read-only property of the EventSource interface returns a number representing the state of the connection.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState)
*/ */
@@ -3296,18 +3382,26 @@ interface ContainerExecOptions {
cwd?: string; cwd?: string;
env?: Record<string, string>; env?: Record<string, string>;
user?: string; user?: string;
signal?: AbortSignal;
pty?: boolean | ContainerExecPtyOptions;
stdin?: ReadableStream | "pipe"; stdin?: ReadableStream | "pipe";
stdout?: "pipe" | "ignore"; stdout?: "pipe" | "ignore";
stderr?: "pipe" | "ignore" | "combined"; stderr?: "pipe" | "ignore" | "combined";
} }
interface ContainerExecPtyOptions {
cols?: number;
rows?: number;
}
interface ExecProcess { interface ExecProcess {
readonly stdin: WritableStream | null; readonly stdin: WritableStream | null;
readonly stdout: ReadableStream | null; readonly stdout: ReadableStream | null;
readonly stderr: ReadableStream | null; readonly stderr: ReadableStream | null;
readonly pid: number; readonly pid: number;
readonly isPty: boolean;
readonly exitCode: Promise<number>; readonly exitCode: Promise<number>;
output(): Promise<ExecOutput>; output(): Promise<ExecOutput>;
kill(signal?: number): void; kill(signal?: number): void;
resize(cols: number, rows: number): void;
} }
interface Container { interface Container {
get running(): boolean; get running(): boolean;
@@ -3334,25 +3428,42 @@ interface ContainerDirectorySnapshotOptions {
dir: string; dir: string;
name?: string; name?: string;
} }
interface ContainerDirectorySnapshotRestoreParams { type ContainerDirectorySnapshotRestoreParams = {
snapshot: ContainerDirectorySnapshot; snapshot: ContainerDirectorySnapshot;
mountPoint?: string; mountPoint?: string;
} } | {
snapshot?: undefined;
mountPoint: string;
};
interface ContainerSnapshot { interface ContainerSnapshot {
id: string; id: string;
size: number; size: number;
name?: string; name?: string;
} }
interface ContainerSnapshotRestoreParams {
id: string;
}
interface ContainerSnapshotOptions { interface ContainerSnapshotOptions {
name?: string; name?: string;
} }
interface ContainerStartupOptions { type ContainerStartupOptions = {
entrypoint?: string[]; entrypoint?: string[];
enableInternet: boolean; enableInternet: boolean;
env?: Record<string, string>; env?: Record<string, string>;
instance?: "lite" | "standard-1" | "standard-2" | "standard-3" | "standard-4" | ContainerStartResources;
labels?: Record<string, string>; labels?: Record<string, string>;
directorySnapshots?: ContainerDirectorySnapshotRestoreParams[]; directorySnapshots?: ContainerDirectorySnapshotRestoreParams[];
containerSnapshot?: ContainerSnapshot; } & ({
image: string;
containerSnapshot?: never;
} | {
image?: never;
containerSnapshot?: ContainerSnapshotRestoreParams;
});
interface ContainerStartResources {
vcpu: number;
memoryMib: number;
diskMb: number;
} }
/** /**
* The **`MessagePort`** interface of the Channel Messaging API represents one of the two ports of a MessageChannel, allowing messages to be sent from one port and listening out for them arriving at the other. * The **`MessagePort`** interface of the Channel Messaging API represents one of the two ports of a MessageChannel, allowing messages to be sent from one port and listening out for them arriving at the other.
@@ -3361,19 +3472,19 @@ interface ContainerStartupOptions {
*/ */
declare abstract class MessagePort extends EventTarget { declare abstract class MessagePort extends EventTarget {
/** /**
* The **`postMessage()`** method of the transfers ownership of objects to other browsing contexts. * The **`postMessage()`** method of the MessagePort interface sends a message from the port, and optionally, transfers ownership of objects to other browsing contexts.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/postMessage) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/postMessage)
*/ */
postMessage(data?: any, options?: (any[] | MessagePortPostMessageOptions)): void; postMessage(data?: any, options?: (any[] | MessagePortPostMessageOptions)): void;
/** /**
* The **`close()`** method of the MessagePort interface disconnects the port, so it is no longer active. * The **`close()`** method of the MessagePort interface disconnects the port, so it is no longer active. This stops the flow of messages to that port.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/close)
*/ */
close(): void; close(): void;
/** /**
* The **`start()`** method of the MessagePort interface starts the sending of messages queued on the port. * The **`start()`** method of the MessagePort interface starts the sending of messages queued on the port. This method is only needed when using EventTarget.addEventListener; it is implied when using onmessage.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/start) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/start)
*/ */
@@ -3389,13 +3500,13 @@ declare abstract class MessagePort extends EventTarget {
declare class MessageChannel { declare class MessageChannel {
constructor(); constructor();
/** /**
* The **`port1`** read-only property of the the port attached to the context that originated the channel. * The **`port1`** read-only property of the MessageChannel interface returns the first port of the message channel — the port attached to the context that originated the channel.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port1) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port1)
*/ */
readonly port1: MessagePort; readonly port1: MessagePort;
/** /**
* The **`port2`** read-only property of the the port attached to the context at the other end of the channel, which the message is initially sent to. * The **`port2`** read-only property of the MessageChannel interface returns the second port of the message channel — the port attached to the context at the other end of the channel, which the message is initially sent to.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port2) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port2)
*/ */
@@ -3455,7 +3566,7 @@ interface WorkerLoaderModule {
data?: ArrayBuffer; data?: ArrayBuffer;
json?: any; json?: any;
py?: string; py?: string;
wasm?: ArrayBuffer; wasm?: ArrayBuffer | ArrayBufferView | WebAssembly.Module;
} }
interface WorkerLoaderWorkerCode { interface WorkerLoaderWorkerCode {
compatibilityDate: string; compatibilityDate: string;
@@ -3463,7 +3574,7 @@ interface WorkerLoaderWorkerCode {
allowExperimental?: boolean; allowExperimental?: boolean;
limits?: workerdResourceLimits; limits?: workerdResourceLimits;
mainModule: string; mainModule: string;
modules: Record<string, WorkerLoaderModule | string>; modules: Record<string, string | WebAssembly.Module | WorkerLoaderModule>;
env?: any; env?: any;
globalOutbound?: (Fetcher | null); globalOutbound?: (Fetcher | null);
tails?: Fetcher[]; tails?: Fetcher[];
@@ -3485,7 +3596,7 @@ declare abstract class Performance {
/* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancenow) */ /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancenow) */
now(): number; now(): number;
/** /**
* The **`toJSON()`** method of the Performance interface is a Serialization; it returns a JSON representation of the Performance object. * The **`toJSON()`** method of the Performance interface is a serializer; it returns a JSON representation of the Performance object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Performance/toJSON) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Performance/toJSON)
*/ */
@@ -3494,11 +3605,13 @@ declare abstract class Performance {
interface Tracing { interface Tracing {
enterSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T; enterSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T;
startActiveSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T; startActiveSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T;
startSpan(name: string): Span;
Span: typeof Span; Span: typeof Span;
} }
declare abstract class Span { declare abstract class Span {
get isTraced(): boolean; get isTraced(): boolean;
setAttribute(key: string, value?: (boolean | number | string)): void; setAttribute(key: string, value: boolean | number | string): this;
setAttributes(attributes: Record<string, boolean | number | string | undefined>): this;
end(): void; end(): void;
} }
/** /**
@@ -4138,6 +4251,13 @@ type AiSearchListItemsParams = {
source?: string; source?: string;
/** JSON-encoded Vectorize filter for metadata filtering. */ /** JSON-encoded Vectorize filter for metadata filtering. */
metadata_filter?: string; metadata_filter?: string;
/** Filter items by their unique ID. Returns at most one item. */
item_id?: string;
/**
* Filter items by their exact key (object key / filename). Keys are unique
* per source, so combine with `source` to disambiguate across data sources.
*/
key?: string;
}; };
type AiSearchListItemsResponse = { type AiSearchListItemsResponse = {
result: AiSearchItemInfo[]; result: AiSearchItemInfo[];
@@ -10035,6 +10155,163 @@ declare abstract class Base_Ai_Cf_Google_Gemma_4_26B_A4B_IT {
inputs: ChatCompletionsInput; inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput; postProcessedOutputs: ChatCompletionsOutput;
} }
declare abstract class Base_Ai_Cf_Moonshotai_Kimi_K2_7_Code {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Zai_Org_Glm_5_2 {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
interface Ai_Cf_Moondream_Moondream3_1_9B_A2B_Input {
/**
* Which Moondream skill to run.
*/
task?: "query" | "caption" | "point" | "detect";
/**
* Input image as a public HTTPS URL or base64 data URI. Optional for `query`; required for `caption`, `point`, and `detect`.
*/
image?: string;
/**
* Question for the `query` task.
*/
question?: string;
/**
* Caption length for the `caption` task.
*/
caption_length?: "short" | "normal" | "long";
/**
* Object phrase to locate for `point` and `detect` tasks (e.g. 'person wearing a red shirt').
*/
target?: string;
/**
* Enable reasoning trace for the `query` task.
*/
reasoning?: boolean;
/**
* Sampling temperature.
*/
temperature?: number;
/**
* Top-p (nucleus) sampling.
*/
top_p?: number;
/**
* Max tokens to generate for `query` and `caption`.
*/
max_tokens?: number;
/**
* Max objects to return for `point` and `detect`.
*/
max_objects?: number;
/**
* Return incremental tokens for `query` and `caption`. `point` and `detect` do not support streaming.
*/
stream?: boolean;
}
interface Ai_Cf_Moondream_Moondream3_1_9B_A2B_Output {
/**
* Reason the generation finished.
*/
finish_reason: string;
metrics: {
/**
* Number of input tokens consumed.
*/
input_tokens: number;
/**
* Number of output tokens generated.
*/
output_tokens: number;
/**
* Prefill time in milliseconds.
*/
prefill_time_ms: number;
/**
* Decode time in milliseconds.
*/
decode_time_ms: number;
/**
* Time to first token in milliseconds.
*/
ttft_ms: number;
};
/**
* Answer text for the `query` task. Null for other tasks.
*/
answer?: string;
/**
* Caption text for the `caption` task. Null for other tasks.
*/
caption?: string;
/**
* Located points for the `point` task. Null for other tasks.
*/
points?: {
/**
* X coordinate.
*/
x: number;
/**
* Y coordinate.
*/
y: number;
}[];
/**
* Detected bounding boxes for the `detect` task. Null for other tasks.
*/
objects?: {
/**
* Minimum X coordinate.
*/
x_min: number;
/**
* Minimum Y coordinate.
*/
y_min: number;
/**
* Maximum X coordinate.
*/
x_max: number;
/**
* Maximum Y coordinate.
*/
y_max: number;
}[];
/**
* Reasoning trace for the `query` task when reasoning=true. Null otherwise.
*/
reasoning?: {
/**
* Reasoning text.
*/
text: string;
/**
* Grounding information.
*/
grounding?: {}[];
};
}
declare abstract class Base_Ai_Cf_Moondream_Moondream3_1_9B_A2B {
inputs: Ai_Cf_Moondream_Moondream3_1_9B_A2B_Input;
postProcessedOutputs: Ai_Cf_Moondream_Moondream3_1_9B_A2B_Output;
}
declare abstract class Base_Ai_Cf_Deepseek_Ai_Deepseek_V4_Flash_0731 {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Deepseek_Ai_Deepseek_V4_Pro_0813 {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Qwen_Qwen3_8_27B {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Zai_Org_Glm_5_3_Flash {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
interface AiModels { interface AiModels {
"@cf/huggingface/distilbert-sst-2-int8": BaseAiTextClassification; "@cf/huggingface/distilbert-sst-2-int8": BaseAiTextClassification;
"@cf/stabilityai/stable-diffusion-xl-base-1.0": BaseAiTextToImage; "@cf/stabilityai/stable-diffusion-xl-base-1.0": BaseAiTextToImage;
@@ -10127,6 +10404,13 @@ interface AiModels {
"@cf/moonshotai/kimi-k2.6": Base_Ai_Cf_Moonshotai_Kimi_K2_6; "@cf/moonshotai/kimi-k2.6": Base_Ai_Cf_Moonshotai_Kimi_K2_6;
"@cf/nvidia/nemotron-3-120b-a12b": Base_Ai_Cf_Nvidia_Nemotron_3_120B_A12B; "@cf/nvidia/nemotron-3-120b-a12b": Base_Ai_Cf_Nvidia_Nemotron_3_120B_A12B;
"@cf/google/gemma-4-26b-a4b-it": Base_Ai_Cf_Google_Gemma_4_26B_A4B_IT; "@cf/google/gemma-4-26b-a4b-it": Base_Ai_Cf_Google_Gemma_4_26B_A4B_IT;
"@cf/moonshotai/kimi-k2.7-code": Base_Ai_Cf_Moonshotai_Kimi_K2_7_Code;
"@cf/zai-org/glm-5.2": Base_Ai_Cf_Zai_Org_Glm_5_2;
"@cf/moondream/moondream3.1-9B-A2B": Base_Ai_Cf_Moondream_Moondream3_1_9B_A2B;
"@cf/deepseek-ai/deepseek-v4-flash-0731": Base_Ai_Cf_Deepseek_Ai_Deepseek_V4_Flash_0731;
"@cf/deepseek-ai/deepseek-v4-pro-0813": Base_Ai_Cf_Deepseek_Ai_Deepseek_V4_Pro_0813;
"@cf/qwen/qwen3.8-27b": Base_Ai_Cf_Qwen_Qwen3_8_27B;
"@cf/zai-org/glm-5.3-flash": Base_Ai_Cf_Zai_Org_Glm_5_3_Flash;
} }
type AiOptions = { type AiOptions = {
/** /**
@@ -10793,6 +11077,15 @@ interface BrowserRunBaseOptions {
*/ */
cacheTTL?: number; cacheTTL?: number;
} }
/**
* Backend selection, mixed into the options of the quick actions that support it.
* Deliberately not part of `BrowserRunBaseOptions`: `scrape`, `links` and `snapshot`
* reject an alternate backend, so they must not accept the field.
*/
interface BrowserRunAlternateBackendOptions {
/** Render with an alternate browser backend instead of the default one. */
browser?: 'kitesurf';
}
/** Common options shared by all quick actions. Exactly one of `url` or `html` must be provided.*/ /** Common options shared by all quick actions. Exactly one of `url` or `html` must be provided.*/
type BrowserRunCommonOptions = (BrowserRunBaseOptions & { type BrowserRunCommonOptions = (BrowserRunBaseOptions & {
/** URL to navigate to, e.g. `"https://example.com"`. */ /** URL to navigate to, e.g. `"https://example.com"`. */
@@ -10827,7 +11120,7 @@ type BrowserRunScreenshotOptions = BrowserRunCommonOptions & {
scrollPage?: boolean; scrollPage?: boolean;
/** @see https://pptr.dev/api/puppeteer.screenshotoptions */ /** @see https://pptr.dev/api/puppeteer.screenshotoptions */
screenshotOptions?: BrowserRunPuppeteerScreenshotOptions; screenshotOptions?: BrowserRunPuppeteerScreenshotOptions;
}; } & BrowserRunAlternateBackendOptions;
type BrowserRunPDFOptions = BrowserRunCommonOptions & { type BrowserRunPDFOptions = BrowserRunCommonOptions & {
/** @see https://pptr.dev/api/puppeteer.pdfoptions */ /** @see https://pptr.dev/api/puppeteer.pdfoptions */
pdfOptions?: { pdfOptions?: {
@@ -10863,7 +11156,7 @@ type BrowserRunPDFOptions = BrowserRunCommonOptions & {
/** @default 30000 */ /** @default 30000 */
timeout?: number; timeout?: number;
}; };
}; } & BrowserRunAlternateBackendOptions;
type BrowserRunScrapeOptions = BrowserRunCommonOptions & { type BrowserRunScrapeOptions = BrowserRunCommonOptions & {
/** CSS selectors to scrape. At least one element is required. */ /** CSS selectors to scrape. At least one element is required. */
elements: Array<{ elements: Array<{
@@ -10876,10 +11169,29 @@ type BrowserRunLinksOptions = BrowserRunCommonOptions & {
/** When true, exclude links pointing to external domains. @default false */ /** When true, exclude links pointing to external domains. @default false */
excludeExternalLinks?: boolean; excludeExternalLinks?: boolean;
}; };
type BrowserRunSnapshotFormat = 'content' | 'screenshot' | 'markdown' | 'accessibilityTree';
type BrowserRunSnapshotOptions = BrowserRunCommonOptions & { type BrowserRunSnapshotOptions = BrowserRunCommonOptions & {
/** Which representations of the page to return. At least two distinct formats
* are required; request a single format from its dedicated action instead.
* @default ["content","screenshot"]
*/
formats?: BrowserRunSnapshotFormat[];
/** @see https://pptr.dev/api/puppeteer.screenshotoptions */ /** @see https://pptr.dev/api/puppeteer.screenshotoptions */
screenshotOptions?: Omit<BrowserRunPuppeteerScreenshotOptions, 'encoding'>; screenshotOptions?: Omit<BrowserRunPuppeteerScreenshotOptions, 'encoding'>;
}; };
/** Options for the `accessibilityTree` quick action. */
type BrowserRunAccessibilityTreeOptions = BrowserRunCommonOptions & {
/** When true, prune nodes that carry no semantic meaning, such as generic
* containers. Defaults to true, or to false when `root` is set so that the
* requested subtree is returned as-is.
*/
interestingOnly?: boolean;
/** CSS selector limiting the tree to the matching element's subtree.
* A selector that matches nothing yields `accessibilityTree: null` with
* HTTP 200; a malformed selector is an error.
*/
root?: string;
} & BrowserRunAlternateBackendOptions;
interface BrowserRunJsonBaseOptions { interface BrowserRunJsonBaseOptions {
/** Custom AI models to try in order. Max 3. Falls back to next on error. */ /** Custom AI models to try in order. Max 3. Falls back to next on error. */
custom_ai?: Array<{ custom_ai?: Array<{
@@ -10893,7 +11205,7 @@ interface BrowserRunJsonBaseOptions {
* Options for the `json` quick action. * Options for the `json` quick action.
* At least one of `prompt` or `response_format` must be provided. * At least one of `prompt` or `response_format` must be provided.
*/ */
type BrowserRunJsonOptions = BrowserRunCommonOptions & BrowserRunJsonBaseOptions & ({ type BrowserRunJsonOptions = BrowserRunCommonOptions & BrowserRunAlternateBackendOptions & BrowserRunJsonBaseOptions & ({
/** Natural-language prompt describing what data to extract. */ /** Natural-language prompt describing what data to extract. */
prompt: string; prompt: string;
/** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */ /** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */
@@ -10904,14 +11216,80 @@ type BrowserRunJsonOptions = BrowserRunCommonOptions & BrowserRunJsonBaseOptions
/** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */ /** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */
response_format: AiTextGenerationResponseFormat; response_format: AiTextGenerationResponseFormat;
}); });
type BrowserRunContentOptions = BrowserRunCommonOptions; type BrowserRunContentOptions = BrowserRunCommonOptions & BrowserRunAlternateBackendOptions;
type BrowserRunMarkdownOptions = BrowserRunCommonOptions; type BrowserRunMarkdownOptions = BrowserRunCommonOptions & BrowserRunAlternateBackendOptions;
type BrowserRunRedirectHop = {
/** URL that returned the redirect. */
url: string;
/** HTTP status of the redirect. */
status: number;
/** Redirect response headers, including `location`. */
headers: Record<string, string>;
};
type BrowserRunResponseMeta = { type BrowserRunResponseMeta = {
/** HTTP status code of the rendered page */ /** HTTP status code of the rendered page */
status: number; status: number;
/** Page title */ /** Page title */
title: string; title: string;
/** Origin response headers, lowercased. Repeated headers are joined with a newline. Credential and transport-only headers that do not survive rendering are omitted. */
headers?: Record<string, string>;
/** URL that served the response, after any redirects the browser followed. */
finalUrl?: string;
/** HTTP redirects followed to reach `finalUrl`, oldest first. Omitted for direct navigation and for client-side redirects such as meta refresh. An empty array means redirects occurred but their intermediate responses could not be read. */
redirectChain?: BrowserRunRedirectHop[];
}; };
/**
* A node in the page's accessibility tree, as exposed to assistive technology.
* `role` is the only field always present; the rest are populated when the
* underlying element defines them.
* @see https://pptr.dev/api/puppeteer.serializedaxnode
*/
interface BrowserRunSerializedAXNode {
/** The ARIA role, e.g. `"button"`, `"heading"`, `"RootWebArea"`. */
role: string;
/** The `aria-autocomplete` value. */
autocomplete?: string;
/** Checked state of a checkbox, radio, or menu item. */
checked?: boolean | 'mixed';
/** Accessible description, typically from `aria-describedby` or `title`. */
description?: string;
disabled?: boolean;
expanded?: boolean;
/** Whether the element currently holds keyboard focus. */
focused?: boolean;
/** The kind of popup the element triggers, e.g. `"menu"`, `"dialog"`. */
haspopup?: string;
/** The `aria-invalid` value. */
invalid?: string;
/** Keyboard shortcuts bound to the element, from `aria-keyshortcuts`. */
keyshortcuts?: string;
/** Hierarchical level, e.g. the heading level of an `<h2>`. */
level?: number;
/** Whether the element is a modal dialog. */
modal?: boolean;
/** Whether a text input accepts multiple lines. */
multiline?: boolean;
/** Whether more than one option can be selected. */
multiselectable?: boolean;
/** Accessible name, e.g. a button's label or an image's alt text. */
name?: string;
orientation?: string;
/** Pressed state of a toggle button. */
pressed?: boolean | 'mixed';
readonly?: boolean;
required?: boolean;
/** Author-supplied role description, from `aria-roledescription`. */
roledescription?: string;
selected?: boolean;
/** Current value of an input or range element. */
value?: string | number;
valuemax?: number;
valuemin?: number;
/** Human-readable form of `value`, from `aria-valuetext`. */
valuetext?: string;
/** Child nodes. Absent for leaf nodes. */
children?: BrowserRunSerializedAXNode[];
}
/** Success response for `content` action. */ /** Success response for `content` action. */
type BrowserRunContentSuccessResponse = { type BrowserRunContentSuccessResponse = {
success: true; success: true;
@@ -10924,6 +11302,7 @@ type BrowserRunLinksSuccessResponse = {
success: true; success: true;
/** Extracted links */ /** Extracted links */
result: string[]; result: string[];
meta: BrowserRunResponseMeta;
}; };
/** Success response for `scrape` action. */ /** Success response for `scrape` action. */
type BrowserRunScrapeSuccessResponse = { type BrowserRunScrapeSuccessResponse = {
@@ -10954,15 +11333,33 @@ type BrowserRunScrapeSuccessResponse = {
}>; }>;
}>; }>;
}>; }>;
meta: BrowserRunResponseMeta;
}; };
/** Success response for `snapshot` action. */ /** Success response for `snapshot` action. Each field is present only when the
* corresponding entry was requested in `formats`.
*/
type BrowserRunSnapshotSuccessResponse = { type BrowserRunSnapshotSuccessResponse = {
success: true; success: true;
result: { result: {
/** HTML content of the page. */ /** HTML content of the page. */
content: string; content?: string;
/** Base64-encoded screenshot image. */ /** Base64-encoded screenshot image. */
screenshot: string; screenshot?: string;
/** Markdown content. Prefixed with YAML frontmatter (e.g. `title`) when the
* page provides that metadata.
*/
markdown?: string;
/** Root of the page's accessibility tree. */
accessibilityTree?: BrowserRunSerializedAXNode;
};
meta: BrowserRunResponseMeta;
};
/** Success response for `accessibilityTree` action. */
type BrowserRunAccessibilityTreeSuccessResponse = {
success: true;
result: {
/** Root of the accessibility tree, or `null` when `root` matched no element. */
accessibilityTree: BrowserRunSerializedAXNode | null;
}; };
meta: BrowserRunResponseMeta; meta: BrowserRunResponseMeta;
}; };
@@ -10971,12 +11368,14 @@ type BrowserRunJsonSuccessResponse = {
success: true; success: true;
/** JSON data extracted from the page using an AI model */ /** JSON data extracted from the page using an AI model */
result: Record<string, unknown>; result: Record<string, unknown>;
meta: BrowserRunResponseMeta;
}; };
/** Success response for `markdown` action. */ /** Success response for `markdown` action. */
type BrowserRunMarkdownSuccessResponse = { type BrowserRunMarkdownSuccessResponse = {
success: true; success: true;
/** Extracted markdown content */ /** Extracted markdown content */
result: string; result: string;
meta: BrowserRunResponseMeta;
}; };
/** Error response for BrowserRun actions. */ /** Error response for BrowserRun actions. */
type BrowserRunErrorResponse = { type BrowserRunErrorResponse = {
@@ -11086,9 +11485,10 @@ declare abstract class BrowserRun {
*/ */
quickAction(action: 'links', options: BrowserRunLinksOptions): Promise<Response>; quickAction(action: 'links', options: BrowserRunLinksOptions): Promise<Response>;
/** /**
* Get both the HTML content and a base64-encoded screenshot of a web page. * Get several representations of a web page in one request.
* @param action - Must be `'snapshot'`. * @param action - Must be `'snapshot'`.
* @param options - Snapshot options including screenshot settings (encoding is always base64). * @param options - Snapshot options including the `formats` to return and
* screenshot settings (encoding is always base64).
* @returns A `Response` containing one of: * @returns A `Response` containing one of:
* *
* **Success (HTTP 200):** * **Success (HTTP 200):**
@@ -11136,6 +11536,26 @@ declare abstract class BrowserRun {
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500) * - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/ */
quickAction(action: 'markdown', options: BrowserRunMarkdownOptions): Promise<Response>; quickAction(action: 'markdown', options: BrowserRunMarkdownOptions): Promise<Response>;
/**
* Get the accessibility tree of a web page.
* @param action - Must be `'accessibilityTree'`.
* @param options - Options to scope the tree to a subtree and to control
* whether semantically uninteresting nodes are pruned.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - `BrowserRunAccessibilityTreeSuccessResponse` JSON with `Content-Type: application/json`
* - `result.accessibilityTree` is `null` when `root` matched no element
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
* - HTTP 422 for a malformed `root` selector
* - HTTP 500 with code `2017` or `2018` when the tree could not be built
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'accessibilityTree', options: BrowserRunAccessibilityTreeOptions): Promise<Response>;
} }
/** /**
* In addition to the properties you can set in the RequestInit dict * In addition to the properties you can set in the RequestInit dict
@@ -12206,6 +12626,13 @@ interface ForwardableEmailMessage extends EmailMessage {
* @returns A promise that resolves when the email message is replied. * @returns A promise that resolves when the email message is replied.
*/ */
reply(message: EmailMessage): Promise<EmailSendResult>; reply(message: EmailMessage): Promise<EmailSendResult>;
/**
* Reply to the sender of this email message with a message built from the given
* fields. Threading headers (In-Reply-To/References) are set automatically.
* @param builder The reply message contents.
* @returns A promise that resolves when the email message is replied.
*/
reply(builder: EmailReplyMessageBuilder): Promise<EmailSendResult>;
} }
/** A file attachment for an email message */ /** A file attachment for an email message */
type EmailAttachment = { type EmailAttachment = {
@@ -12227,22 +12654,45 @@ interface EmailAddress {
email: string; email: string;
} }
/** /**
* A binding that allows a Worker to send email messages. * Recipient fields for `SendEmail.send()`. At least one of `to`, `cc`, or
* `bcc` must be provided.
*/ */
interface SendEmail { type EmailDestinations = {
send(message: EmailMessage): Promise<EmailSendResult>; to?: string | EmailAddress | (string | EmailAddress)[];
send(builder: {
from: string | EmailAddress;
to: string | EmailAddress | (string | EmailAddress)[];
subject: string;
replyTo?: string | EmailAddress;
cc?: string | EmailAddress | (string | EmailAddress)[]; cc?: string | EmailAddress | (string | EmailAddress)[];
bcc?: string | EmailAddress | (string | EmailAddress)[]; bcc?: string | EmailAddress | (string | EmailAddress)[];
} & ({
to: string | EmailAddress | (string | EmailAddress)[];
} | {
cc: string | EmailAddress | (string | EmailAddress)[];
} | {
bcc: string | EmailAddress | (string | EmailAddress)[];
});
/**
* Fields shared by all composed emails (no recipients). Used directly by
* `ForwardableEmailMessage.reply()`, which always replies to the original
* sender, and extended by `EmailMessageBuilder` for `SendEmail.send()`.
*/
interface EmailReplyMessageBuilder {
from: string | EmailAddress;
subject: string;
replyTo?: string | EmailAddress;
headers?: Record<string, string>; headers?: Record<string, string>;
text?: string; text?: string;
html?: string; html?: string;
attachments?: EmailAttachment[]; attachments?: EmailAttachment[];
}): Promise<EmailSendResult>; }
/**
* Fields for composing an email without constructing raw MIME, for
* `SendEmail.send()`. Requires at least one of `to`, `cc`, or `bcc`.
*/
type EmailMessageBuilder = EmailReplyMessageBuilder & EmailDestinations;
/**
* A binding that allows a Worker to send email messages.
*/
interface SendEmail {
send(message: EmailMessage): Promise<EmailSendResult>;
send(builder: EmailMessageBuilder): Promise<EmailSendResult>;
} }
declare abstract class EmailEvent extends ExtendableEvent { declare abstract class EmailEvent extends ExtendableEvent {
readonly message: ForwardableEmailMessage; readonly message: ForwardableEmailMessage;
@@ -12396,6 +12846,15 @@ interface Hyperdrive {
* for your database. * for your database.
*/ */
readonly host: string; readonly host: string;
/*
* A synthetic IPv4 address (in the reserved 240.0.0.0/4 range) that, like the
* host field, is only valid within the context of the currently running
* Worker and, when passed into the `connect()` function from the
* "cloudflare:sockets" module, will connect to the Hyperdrive instance for
* your database. This is provided for database drivers that require the host
* to be an IP literal rather than a hostname.
*/
readonly ip: string;
/* /*
* The port that must be paired the the host field when connecting. * The port that must be paired the the host field when connecting.
*/ */
@@ -12417,6 +12876,78 @@ interface Hyperdrive {
*/ */
readonly database: string; readonly database: string;
} }
/**
* A handle to a dynamically-provisioned Hyperdrive connection, returned by
* `HyperdriveApi.get()`.
*/
interface HyperdriveDynamic extends Disposable {
/**
* The database name to use when connecting through this Hyperdrive.
*/
readonly database: Promise<string>;
/*
* The randomly generated user to use when authenticating to your
* database via Hyperdrive.
*/
readonly user: Promise<string>;
/*
* The randomly generated password to use when authenticating to your
* database via Hyperdrive.
*/
readonly password: Promise<string>;
/**
* Open a TCP socket to the target database through this Hyperdrive.
*
*/
connect(): Promise<Socket>;
}
/**
* Binding that provisions Hyperdrive connections at request time, rather than
* from static configuration.
*/
interface HyperdriveDynamicApi {
/**
* Provision a connection for the database described by `args`.
*
*/
get(args: HyperdriveDynamicConfig): Promise<HyperdriveDynamic>;
/**
* Get a pre-generated connection string used for connecting to dynamic Hyperdrive.
*/
getHyperdriveConnectionString(connectionString: string): Promise<string>;
}
/**
* Parameters identifying the database that a dynamically-provisioned
* Hyperdrive connection should target.
*/
interface HyperdriveDynamicConfig {
/**
* Generated connection string to pass into the dynamic worker.
*
*/
dynamicHyperdriveConnectionString: string;
/**
* Connection string for the origin database Hyperdrive should connect to.
* Contains credentials, so treat it as a secret.
*
* The scheme selects the database engine. PostgreSQL origins are supported.
*/
connectionString: string;
/**
* Region in which to place the connection pool. See the Hyperdrive
* documentation for the set of supported regions.
*/
targetRegion: string;
/**
* Whether Hyperdrive should cache query results for this connection.
*/
cachingEnabled?: boolean;
/**
* Maximum number of connections the pool may open to the origin database.
* Defaults to 60.
*/
maxConnections?: number;
}
// Copyright (c) 2024 Cloudflare, Inc. // Copyright (c) 2024 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at: // Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0 // https://opensource.org/licenses/Apache-2.0
@@ -12428,6 +12959,27 @@ type ImageInfoResponse = {
width: number; width: number;
height: number; height: number;
}; };
/**
* Parameters for rasterizing text into an image.
*/
type TextRasterize = {
/** The text content to render */
content: string;
/** rasterization options for the text **/
options: TextOptions;
};
type TextOptions = {
/** Font configuration */
font: {
/** URL to a font file in TrueType (.ttf), OpenType (.otf), WOFF (.woff), or WOFF2 (.woff2) format */
url: string;
};
/** Font size in points (pt) */
size?: number;
/** Text color in CSS format: hex (#RRGGBB or #RRGGBBAA), rgb(r,g,b), rgba(r,g,b,a), or named colors */
color?: string;
};
type ImageSource = ReadableStream<Uint8Array> | TextRasterize;
type ImageTransform = { type ImageTransform = {
width?: number; width?: number;
height?: number; height?: number;
@@ -12517,6 +13069,9 @@ interface ImageUploadOptions {
requireSignedURLs?: boolean; requireSignedURLs?: boolean;
metadata?: Record<string, unknown>; metadata?: Record<string, unknown>;
creator?: string; creator?: string;
/**
* If 'base64', the input data will be decoded from base64 before processing
*/
encoding?: 'base64'; encoding?: 'base64';
} }
interface ImageUpdateOptions { interface ImageUpdateOptions {
@@ -12524,11 +13079,40 @@ interface ImageUpdateOptions {
metadata?: Record<string, unknown>; metadata?: Record<string, unknown>;
creator?: string; creator?: string;
} }
type ImageMetadataFilterOperators = {
eq?: string | number | boolean;
in?: string[] | number[];
gt?: number;
gte?: number;
lt?: number;
lte?: number;
};
type ImageMetadataFilterValue = string | number | boolean | ImageMetadataFilterOperators;
interface ImageListFilter {
metadata?: Record<string, ImageMetadataFilterValue>;
}
interface ImageListOptions { interface ImageListOptions {
limit?: number; limit?: number;
cursor?: string; cursor?: string;
sortOrder?: 'asc' | 'desc'; sortOrder?: 'asc' | 'desc';
creator?: string; creator?: string;
filter?: ImageListFilter;
}
interface ImageSignedUrlOptions {
variant: string;
expiresIn?: number;
keyName?: string;
}
interface ImageDirectUploadOptions {
id?: string;
requireSignedURLs?: boolean;
metadata?: Record<string, unknown>;
creator?: string;
expiresIn?: number;
}
interface ImageDirectUploadResult {
id: string;
uploadURL: string;
} }
interface ImageList { interface ImageList {
images: ImageMetadata[]; images: ImageMetadata[];
@@ -12546,6 +13130,13 @@ interface ImageHandle {
* @returns ReadableStream of image bytes, or null if not found * @returns ReadableStream of image bytes, or null if not found
*/ */
bytes(): Promise<ReadableStream<Uint8Array> | null>; bytes(): Promise<ReadableStream<Uint8Array> | null>;
/**
* Generate a signed delivery URL for this hosted image.
* @param options Signing configuration
* @returns A signed image delivery URL
* @throws {@link ImagesError} if signing fails
*/
signedUrl(options: ImageSignedUrlOptions): Promise<string>;
/** /**
* Update hosted image metadata * Update hosted image metadata
* @param options Properties to update * @param options Properties to update
@@ -12581,6 +13172,14 @@ interface HostedImagesBinding {
* @throws {@link ImagesError} if list fails * @throws {@link ImagesError} if list fails
*/ */
list(options?: ImageListOptions): Promise<ImageList>; list(options?: ImageListOptions): Promise<ImageList>;
/**
* Create a Direct Creator Upload link, letting an end user upload an
* image straight to Cloudflare without exposing an API token
* @param options Upload link configuration
* @returns The new image ID and the upload URL to hand to the end user
* @throws {@link ImagesError} if creation fails
*/
createDirectUpload(options?: ImageDirectUploadOptions): Promise<ImageDirectUploadResult>;
} }
interface ImagesBinding { interface ImagesBinding {
/** /**
@@ -12595,6 +13194,13 @@ interface ImagesBinding {
* @returns A transform handle * @returns A transform handle
*/ */
input(stream: ReadableStream<Uint8Array>, options?: ImageInputOptions): ImageTransformer; input(stream: ReadableStream<Uint8Array>, options?: ImageInputOptions): ImageTransformer;
/**
* Begin applying a series of transformations to text
* @param content string to be rendered
* @param options font, optional color and size to use in rendering text
* @returns A transform handle
*/
text(content: string, options: TextOptions): ImageTransformer;
/** /**
* Access hosted images CRUD operations * Access hosted images CRUD operations
*/ */
@@ -12624,11 +13230,15 @@ interface ImageTransformer {
type ImageTransformationOutputOptions = { type ImageTransformationOutputOptions = {
encoding?: 'base64'; encoding?: 'base64';
}; };
type ImageTransformationResponseOptions = {
headers?: HeadersInit;
};
interface ImageTransformationResult { interface ImageTransformationResult {
/** /**
* The image as a response, ready to store in cache or return to users * The image as a response, ready to store in cache or return to users
* @param options Options that apply to the returned response, e.g. additional headers
*/ */
response(): Response; response(options?: ImageTransformationResponseOptions): Response;
/** /**
* The content type of the returned image * The content type of the returned image
*/ */
@@ -13064,6 +13674,11 @@ declare namespace CloudflareWorkersModule {
export type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'; export type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
export type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number; export type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number;
export type WorkflowDelayDuration = WorkflowSleepDuration; export type WorkflowDelayDuration = WorkflowSleepDuration;
export type WorkflowDynamicDelayContext = {
ctx: WorkflowStepContext<WorkflowDelayFunction>;
error: Error;
};
export type WorkflowDelayFunction = (input: WorkflowDynamicDelayContext) => WorkflowDelayDuration | Promise<WorkflowDelayDuration>;
export type WorkflowTimeoutDuration = WorkflowSleepDuration; export type WorkflowTimeoutDuration = WorkflowSleepDuration;
export type WorkflowRetentionDuration = WorkflowSleepDuration; export type WorkflowRetentionDuration = WorkflowSleepDuration;
export type WorkflowBackoff = 'constant' | 'linear' | 'exponential'; export type WorkflowBackoff = 'constant' | 'linear' | 'exponential';
@@ -13071,12 +13686,32 @@ declare namespace CloudflareWorkersModule {
export type WorkflowStepConfig = { export type WorkflowStepConfig = {
retries?: { retries?: {
limit: number; limit: number;
delay: WorkflowDelayDuration | number; delay: WorkflowDelayDuration | number | WorkflowDelayFunction;
backoff?: WorkflowBackoff; backoff?: WorkflowBackoff;
}; };
timeout?: WorkflowTimeoutDuration | number; timeout?: WorkflowTimeoutDuration | number;
sensitive?: WorkflowStepSensitivity; sensitive?: WorkflowStepSensitivity;
}; };
// Internal discriminators used only for `WorkflowStep.do` overload
// resolution. They mirror `WorkflowStepConfig` but pin `retries.delay` to a
// single kind so the callback context can be narrowed based on the shape of
// the config argument (rather than on an inferred type parameter, which is
// lost when the caller supplies an explicit return-type argument). Not
// exported: they must not widen the public type surface.
type WorkflowStepConfigWithStaticDelay = Omit<WorkflowStepConfig, 'retries'> & {
retries?: {
limit: number;
delay: WorkflowDelayDuration | number;
backoff?: WorkflowBackoff;
};
};
type WorkflowStepConfigWithDelayFunction = Omit<WorkflowStepConfig, 'retries'> & {
retries: {
limit: number;
delay: WorkflowDelayFunction;
backoff?: WorkflowBackoff;
};
};
export type WorkflowStepRollbackConfig = Pick<WorkflowStepConfig, 'retries' | 'timeout'>; export type WorkflowStepRollbackConfig = Pick<WorkflowStepConfig, 'retries' | 'timeout'>;
export type WorkflowCronSchedule = { export type WorkflowCronSchedule = {
/** Cron expression that triggered this event. */ /** Cron expression that triggered this event. */
@@ -13097,28 +13732,51 @@ declare namespace CloudflareWorkersModule {
type: string; type: string;
sensitive?: WorkflowStepSensitivity; sensitive?: WorkflowStepSensitivity;
}; };
export type WorkflowStepContext = { export type WorkflowStepContext<Delay = WorkflowDelayDuration | number> = {
step: { step: {
name: string; name: string;
count: number; count: number;
}; };
attempt: number; attempt: number;
config: WorkflowStepConfig; config: {
retries?: {
limit: number;
backoff?: WorkflowBackoff;
} & (Delay extends WorkflowDelayFunction ? {} : {
delay: WorkflowDelayDuration | number;
});
timeout?: WorkflowTimeoutDuration | number;
sensitive?: WorkflowStepSensitivity;
}; };
export type WorkflowRollbackContext<T = unknown> = { };
ctx: WorkflowStepContext; // The rollback handler receives the step context, so it mirrors the same
// delay discriminant as the step callback: when the step was configured with
// a dynamic delay function the resolved `config.retries.delay` is omitted,
// otherwise it is present. `Delay` is threaded from the `WorkflowStep.do`
// overload that matched the step config.
export type WorkflowRollbackContext<T = unknown, Delay = WorkflowDelayDuration | number> = {
ctx: WorkflowStepContext<Delay>;
error: Error; error: Error;
output: T | undefined; output: T | undefined;
/** @deprecated Use `ctx.step.name` and `ctx.step.count` instead. */ /** @deprecated Use `ctx.step.name` and `ctx.step.count` instead. */
stepName: string; stepName: string;
}; };
export type WorkflowRollbackHandler<T = unknown> = (ctx: WorkflowRollbackContext<T>) => Promise<void>; export type WorkflowRollbackHandler<T = unknown, Delay = WorkflowDelayDuration | number> = (ctx: WorkflowRollbackContext<T, Delay>) => Promise<void>;
export type WorkflowStepRollbackOptions<T = unknown> = { export type WorkflowStepRollbackOptions<T = unknown, Delay = WorkflowDelayDuration | number> = {
rollback: WorkflowRollbackHandler<T>; rollback: WorkflowRollbackHandler<T, Delay>;
rollbackConfig?: WorkflowStepRollbackConfig; rollbackConfig?: WorkflowStepRollbackConfig;
}; };
export abstract class WorkflowStep { export abstract class WorkflowStep {
do<T extends Rpc.Serializable<T>>(name: string, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>; do<T extends Rpc.Serializable<T>>(name: string, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>;
// The config overloads discriminate on the shape of `config.retries.delay`
// so the callback context reflects whether the resolved delay is present
// (static delay) or omitted (dynamic delay function). Each has a single
// type parameter, so an explicit return-type argument (`do<T>(...)`) still
// resolves here. ORDERING IS LOAD-BEARING: the broad `WorkflowStepConfig`
// fallback MUST remain last, otherwise it shadows the discriminating
// overloads and narrowing is silently lost.
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfigWithDelayFunction, callback: (ctx: WorkflowStepContext<WorkflowDelayFunction>) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T, WorkflowDelayFunction>): Promise<T>;
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfigWithStaticDelay, callback: (ctx: WorkflowStepContext<WorkflowDelayDuration | number>) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T, WorkflowDelayDuration | number>): Promise<T>;
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfig, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>; do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfig, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>;
sleep: (name: string, duration: WorkflowSleepDuration) => Promise<void>; sleep: (name: string, duration: WorkflowSleepDuration) => Promise<void>;
sleepUntil: (name: string, timestamp: Date | number) => Promise<void>; sleepUntil: (name: string, timestamp: Date | number) => Promise<void>;
@@ -13894,11 +14552,12 @@ type MarkdownDocument = {
name: string; name: string;
blob: Blob; blob: Blob;
}; };
type OutputFormat = 'markdown' | 'text';
type ConversionResponse = { type ConversionResponse = {
id: string; id: string;
name: string; name: string;
mimeType: string; mimeType: string;
format: 'markdown'; format: OutputFormat;
tokens: number; tokens: number;
data: string; data: string;
} | { } | {
@@ -13915,7 +14574,11 @@ type EmbeddedImageConversionOptions = ImageConversionOptions & {
convert?: boolean; convert?: boolean;
maxConvertedImages?: number; maxConvertedImages?: number;
}; };
type ConversionOutputOptions = {
format?: OutputFormat;
};
type ConversionOptions = { type ConversionOptions = {
output?: ConversionOutputOptions;
html?: { html?: {
images?: EmbeddedImageConversionOptions & { images?: EmbeddedImageConversionOptions & {
convertOGImage?: boolean; convertOGImage?: boolean;
@@ -14010,7 +14673,7 @@ declare namespace TailStream {
interface ConnectEventInfo { interface ConnectEventInfo {
readonly type: "connect"; readonly type: "connect";
} }
type EventOutcome = "ok" | "canceled" | "exception" | "unknown" | "killSwitch" | "daemonDown" | "exceededCpu" | "exceededMemory" | "loadShed" | "responseStreamDisconnected" | "scriptNotFound" | "internalError" | "exceededWallTime"; type EventOutcome = "ok" | "canceled" | "exception" | "unknown" | "killSwitch" | "daemonDown" | "exceededCpu" | "exceededMemory" | "loadShed" | "responseStreamDisconnected" | "scriptNotFound" | "internalError" | "exceededWallTime" | "aborted";
interface ScriptVersion { interface ScriptVersion {
readonly id: string; readonly id: string;
readonly tag?: string; readonly tag?: string;
@@ -14029,6 +14692,7 @@ declare namespace TailStream {
readonly dispatchNamespace?: string; readonly dispatchNamespace?: string;
readonly entrypoint?: string; readonly entrypoint?: string;
readonly executionModel: string; readonly executionModel: string;
readonly durableObjectId?: string;
readonly scriptName?: string; readonly scriptName?: string;
readonly scriptTags?: string[]; readonly scriptTags?: string[];
readonly scriptVersion?: ScriptVersion; readonly scriptVersion?: ScriptVersion;
@@ -14063,11 +14727,22 @@ declare namespace TailStream {
readonly message: string; readonly message: string;
readonly stack?: string; readonly stack?: string;
} }
interface Log { interface TailStreamErrorInfo {
readonly name: string;
readonly message: string;
readonly stack?: string;
}
type Log = {
readonly type: "log"; readonly type: "log";
readonly level: "debug" | "error" | "info" | "log" | "warn"; readonly level: "debug" | "error" | "info" | "log" | "warn";
readonly errorInfo?: readonly (TailStreamErrorInfo | null)[];
} & ({
readonly message: object; readonly message: object;
} readonly truncated?: false;
} | {
readonly message: string;
readonly truncated: true;
});
interface DroppedEventsDiagnostic { interface DroppedEventsDiagnostic {
readonly diagnosticsType: "droppedEvents"; readonly diagnosticsType: "droppedEvents";
readonly count: number; readonly count: number;
@@ -14545,10 +15220,31 @@ declare abstract class Workflow<PARAMS = unknown> {
* @returns A promise that resolves with a list of handles for the created instances. * @returns A promise that resolves with a list of handles for the created instances.
*/ */
public createBatch(batch: WorkflowInstanceCreateOptions<PARAMS>[]): Promise<WorkflowInstance[]>; public createBatch(batch: WorkflowInstanceCreateOptions<PARAMS>[]): Promise<WorkflowInstance[]>;
/**
* Delete a batch of Workflow instances and their stored state.
* `deleteBatch` is limited to 100 instances at a time. Duplicate IDs are deleted once.
* The result contains one entry for each input position; IDs that do not exist are returned as per-instance errors.
* @param instanceIds IDs of the Workflow instances to delete
* @returns A promise that resolves with the successfully deleted instances and any per-instance errors.
*/
public deleteBatch(instanceIds: string[]): Promise<WorkflowBatchDeleteResult>;
} }
type WorkflowBatchDeleteResult = {
deleted: {
id: string;
}[];
errors: {
id: string;
code: number;
message: string;
}[];
};
type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'; type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number; type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number;
type WorkflowRetentionDuration = WorkflowSleepDuration; type WorkflowRetentionDuration = WorkflowSleepDuration;
/** Geographic regions supported when creating a Workflow instance.
* Location hints are best-effort placement preferences. */
type WorkflowInstanceLocationHint = 'wnam' | 'enam' | 'sam' | 'weur' | 'eeur' | 'apac' | 'apac-ne' | 'apac-se' | 'oc' | 'afr' | 'me';
interface WorkflowInstanceCreateOptions<PARAMS = unknown> { interface WorkflowInstanceCreateOptions<PARAMS = unknown> {
/** /**
* An id for your Workflow instance. Must be unique within the Workflow. * An id for your Workflow instance. Must be unique within the Workflow.
@@ -14566,6 +15262,9 @@ interface WorkflowInstanceCreateOptions<PARAMS = unknown> {
successRetention?: WorkflowRetentionDuration; successRetention?: WorkflowRetentionDuration;
errorRetention?: WorkflowRetentionDuration; errorRetention?: WorkflowRetentionDuration;
}; };
/** A best-effort geographic placement preference for the Workflow instance.
* See `WorkflowInstanceLocationHint` for supported regions. */
locationHint?: WorkflowInstanceLocationHint;
} }
type InstanceStatus = { type InstanceStatus = {
status: 'queued' // means that instance is waiting to be started (see concurrency limits) status: 'queued' // means that instance is waiting to be started (see concurrency limits)
@@ -14583,6 +15282,13 @@ interface WorkflowError {
code?: number; code?: number;
message: string; message: string;
} }
interface WorkflowInstanceTerminateOptions {
/**
* If true, run registered rollback handlers before terminating the instance.
* Only steps that registered rollback handlers are rolled back.
*/
rollback?: boolean;
}
interface WorkflowInstanceRestartOptions { interface WorkflowInstanceRestartOptions {
/** /**
* Restart from a specific step. If omitted, the instance restarts from the beginning. * Restart from a specific step. If omitted, the instance restarts from the beginning.
@@ -14616,14 +15322,19 @@ declare abstract class WorkflowInstance {
public resume(): Promise<void>; public resume(): Promise<void>;
/** /**
* Terminate the instance. If it is errored, terminated or complete, an error will be thrown. * Terminate the instance. If it is errored, terminated or complete, an error will be thrown.
* @param options Options for termination, including whether registered rollback handlers should run.
*/ */
public terminate(): Promise<void>; public terminate(options?: WorkflowInstanceTerminateOptions): Promise<void>;
/** /**
* Restart the instance. Optionally restart from a specific step, preserving * Restart the instance. Optionally restart from a specific step, preserving
* cached results for all steps before it. * cached results for all steps before it.
* @param options Options for the restart, including an optional step to restart from. * @param options Options for the restart, including an optional step to restart from.
*/ */
public restart(options?: WorkflowInstanceRestartOptions): Promise<void>; public restart(options?: WorkflowInstanceRestartOptions): Promise<void>;
/**
* Delete the instance and its stored state.
*/
public delete(): Promise<void>;
/** /**
* Returns the current status of the instance. * Returns the current status of the instance.
*/ */
+14 -1
View File
@@ -37,12 +37,25 @@
"secret_name": "JWT_SECRET" "secret_name": "JWT_SECRET"
} }
], ],
// Cloudflare Email Sending, for the code that confirms an email change
// (POST /account/me/email). Nothing to splice in: the binding has no id, but the `from`
// domain (EMAIL_FROM, default no-reply@<DOMAIN>) has to be enabled for Email Sending once
// per account — see DEPLOYING.md. Locally (and under vitest) the binding logs the message.
"send_email": [
{
"name": "EMAIL"
}
],
"upload_source_maps": true, "upload_source_maps": true,
"observability": { "observability": {
"enabled": false "enabled": false
}, },
"vars": { "vars": {
"ENVIRONMENT": "development", // overridden during deployment "ENVIRONMENT": "development", // overridden during deployment
"SENTRY_RELEASE": "unknown" // overridden during deployment "SENTRY_RELEASE": "unknown", // overridden during deployment
// Overridden at deploy time, same as `auth`. The confirmation email's link is built
// from these (`https://www.<DOMAIN>/confirm-email`).
"DOMAIN": "rec.example.com",
"SUBDOMAINS": "{}"
} }
} }
+2
View File
@@ -15,6 +15,8 @@ authenticates players and issues the JWTs every other worker verifies.
| POST | `/connect/device/deny` | Website refuses it | | POST | `/connect/device/deny` | Website refuses it |
| POST | `/connect/token` | OAuth token endpoint; issues a JWT + refresh token. Studio polls this with the device-code grant | | POST | `/connect/token` | OAuth token endpoint; issues a JWT + refresh token. Studio polls this with the device-code grant |
| POST | `/account/me/changepassword` | Change the caller's password (auth-gated) | | POST | `/account/me/changepassword` | Change the caller's password (auth-gated) |
| POST | `/account/recoverpassword` | "Forgot password": email a six-digit code (and a link to WWW `/reset-password`) to the address |
| POST | `/account/resetpassword` | Website finishes the recovery: address + emailed code + new password; the code works once |
| GET | `/role/developer/:id` | Developer role lookup; a bare JSON boolean | | GET | `/role/developer/:id` | Developer role lookup; a bare JSON boolean |
| GET | `/role/moderator/:id` | Moderator role lookup; a bare JSON boolean | | GET | `/role/moderator/:id` | Moderator role lookup; a bare JSON boolean |
| GET | `/openapi.json` | Generated OpenAPI 3.1 spec (see below) | | GET | `/openapi.json` | Generated OpenAPI 3.1 spec (see below) |
@@ -0,0 +1,24 @@
-- An email address belongs to ONE account. Password recovery (`auth`
-- `POST /account/recoverpassword`) is handed nothing but the address the player typed and
-- has to find their account from it, which only works if no two accounts share one.
--
-- Exposed as a generated column, case-folded, with an empty or absent email read as NULL so
-- accounts without one never collide — and a UNIQUE partial index over it, which is what
-- actually refuses a second holder. `accounts` `POST /account/me/email` checks first and
-- answers a refusal the player can read; the index is the backstop against a race.
--
-- Before the index can be built, existing duplicates have to go: the LOWEST account id
-- keeps the address (the first account to claim it) and the others lose theirs, since a
-- recovery sent to a shared address could only ever reach one of them anyway. Those
-- players set it again from the account page or in game.
--
-- Kept in sync with SCHEMA_DDL in @repo/domain's accounts-db.ts (and its mirror in
-- apps/econ/src/avatar-db.ts).
ALTER TABLE account ADD COLUMN email_lower TEXT GENERATED ALWAYS AS (NULLIF(lower(json_extract(data, '$.email')), '')) VIRTUAL;
UPDATE account SET data = json_remove(data, '$.email')
WHERE email_lower IS NOT NULL
AND account_id > (SELECT MIN(a2.account_id) FROM account a2 WHERE a2.email_lower = account.email_lower);
CREATE UNIQUE INDEX IF NOT EXISTS idx_account_email_lower ON account (email_lower) WHERE email_lower IS NOT NULL;
+20
View File
@@ -0,0 +1,20 @@
-- One-shot codes sent by email: the PBKDF2 hash of the six-digit code the player was
-- mailed, what it is for (`purpose`: a `password_reset`; or an `email_change` — the
-- current address approving a change — followed by an `email_verify` — the new address
-- confirming itself — both with the new address as `payload`), and when it was issued and
-- lapses. One pending code per
-- account and purpose. Mirrored by EMAIL_CODE_SCHEMA_DDL in @repo/domain's
-- email-code-db.ts, which says how the row is used — in short, a wrong guess BURNS it
-- (`code_hash` goes NULL, the row stays for the resend cooldown), a right one deletes it,
-- and a new request replaces it. Written by `auth` and `accounts`; owned here with the
-- rest of the account tables.
CREATE TABLE IF NOT EXISTS email_code (
account_id INTEGER NOT NULL,
purpose TEXT NOT NULL,
code_hash TEXT,
payload TEXT,
created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL,
PRIMARY KEY (account_id, purpose)
);
+163 -1
View File
@@ -4,11 +4,16 @@ import { useWorkersLogger } from 'workers-tagged-logger'
import { z } from 'zod' import { z } from 'zod'
import { import {
beginEmailCode,
completeEmailCode,
countAccountsByDeviceId, countAccountsByDeviceId,
countAccountsBySignupIp, countAccountsBySignupIp,
createAccount, createAccount,
EMAIL_CODE_TTL_SECONDS,
emailSender,
GAME_VERSION, GAME_VERSION,
getAccount, getAccount,
getAccountByEmail,
getAccountByUsername, getAccountByUsername,
getAccountsByIds, getAccountsByIds,
getPasswordHash, getPasswordHash,
@@ -16,6 +21,7 @@ import {
hashPassword, hashPassword,
isRolloutGameVersion, isRolloutGameVersion,
isSupportedGameVersion, isSupportedGameVersion,
isValidEmail,
rolloutGameBuilds, rolloutGameBuilds,
RoomInstanceType, RoomInstanceType,
setLastLoginTime, setLastLoginTime,
@@ -63,6 +69,9 @@ import {
OAuthError, OAuthError,
PlatformIdsRequest, PlatformIdsRequest,
PlatformType, PlatformType,
RecoverPasswordRequest,
RecoverPasswordResponse,
ResetPasswordRequest,
RestrictionDto, RestrictionDto,
roleFilter, roleFilter,
roleLookup, roleLookup,
@@ -80,7 +89,8 @@ import {
linkPlatformIdentity, linkPlatformIdentity,
parseRoleIdList, parseRoleIdList,
} from './platform-db' } from './platform-db'
import { consumeRefreshToken, issueRefreshToken } from './refresh-db' import { recoveryEmail } from './recovery-email'
import { consumeRefreshToken, issueRefreshToken, revokeRefreshTokens } from './refresh-db'
import { verifySteamTicket } from './steam-ticket' import { verifySteamTicket } from './steam-ticket'
import { import {
approveDeviceGrant, approveDeviceGrant,
@@ -1827,6 +1837,158 @@ const app = new Hono<App>()
} }
) )
// "Forgot password" — the game posts the address on the account and nothing else, so the
// address is how the account is found (which is why it is unique across accounts). A
// six-digit code is emailed, typed out and prefilled into a link to the website's
// `/reset-password` page, where the new password is chosen (`/account/resetpassword`
// below): the game has no screen to finish a recovery on.
//
// Unauthenticated, and so answered the same way whether or not the address is on an
// account: `Success: true`, "we've sent an email if there is one". The route is otherwise
// a way to ask which addresses have accounts here. The refusals it does voice are the
// ones the player can act on — no address, a malformed one, the mail not going out —
// in the client's PascalCase `{ Success, Error, error_id }` envelope, which is the one
// shape it has been seen to read for this route. See @repo/domain's email-code-db.ts for the code's
// rules (one attempt, a cooldown on resends, a 30-minute life).
.post(
'/account/recoverpassword',
describeRoute({
tags: ['Account'],
summary: 'Email a password-recovery code',
description: [
'Emails a six-digit code to the address, with a link to the website’s reset page',
'(`/reset-password?email=…&code=…`) where the new password is chosen via',
'`POST /account/resetpassword`. Answers `Success: true` whether or not the address',
'is on an account, so the route can’t be used to find out which addresses are.',
'A new request replaces the pending code; one is sent per address at most every',
'two minutes. The code works once: a wrong guess voids it and the recovery has to',
'be requested again. Refusals — no address, a malformed one, the email failing to',
'send — are `Success: false` with the reason in `Error`.',
].join(' '),
requestBody: form(RecoverPasswordRequest, 'The address on the account'),
responses: {
200: json(RecoverPasswordResponse, 'Sent, or nothing to send to; `Error` says if not'),
},
}),
async (c) => {
const body = await c.req.parseBody().catch(() => ({}) as Record<string, unknown>)
const email = typeof body.email === 'string' ? body.email.trim() : ''
const refuse = (error: string) => c.json({ Success: false, Error: error, error_id: null })
if (email === '') return refuse('Enter the email address on your account.')
if (!isValidEmail(email)) return refuse("That doesn't look like an email address.")
const account = await getAccountByEmail(c.env.DB, email)
if (account === null) {
// Answered exactly like a sent email, see above. Logged, since a run of these
// from one place is somebody probing.
logger.info('password recovery requested for an address on no account')
return c.json({ Success: true, Error: null, error_id: null })
}
const code = await beginEmailCode(c.env.DB, 'password_reset', account.accountId)
if (code === null) {
logger.info('password recovery re-requested within the cooldown; not resent', {
accountId: account.accountId,
})
return c.json({ Success: true, Error: null, error_id: null })
}
const message = recoveryEmail({
// The stored address, not the posted one: same account either way (the lookup
// is case-insensitive), and the stored one is the one the player chose to be
// reached at.
to: account.email ?? email,
from: emailSender(c.env),
domain: c.env.DOMAIN,
www: buildEndpoints(c.env.DOMAIN, c.env.SUBDOMAINS).WWW,
code,
validMinutes: Math.round(EMAIL_CODE_TTL_SECONDS / 60),
})
try {
await c.env.EMAIL.send(message)
} catch (err) {
// Told to the player: they would otherwise wait on an email that is never
// coming. The usual cause is the sender's domain not being enabled for Email
// Sending (see DEPLOYING.md), which is an operator's problem, hence the log.
logger.error('could not send the password recovery email', {
accountId: account.accountId,
error: err instanceof Error ? err.message : String(err),
})
return refuse('The recovery email could not be sent. Please try again later.')
}
logger.info('password recovery email sent', { accountId: account.accountId })
return c.json({ Success: true, Error: null, error_id: null })
}
)
// The other half: the website's `/reset-password` page posts the address, the code from
// the email and the new password. Unauthenticated — the code IS the credential. A wrong
// code voids the pending recovery (one guess per email), and the refusal reads the same
// whether the code was wrong, lapsed or never issued, so nothing here says whether a
// recovery is in flight for an address. Success sets the password and signs the account
// out everywhere else by revoking its refresh tokens. This is our own route, not the
// client's: the game never calls it, so it answers in the `{ success, error }` shape the
// website's other forms read.
.post(
'/account/resetpassword',
describeRoute({
tags: ['Account'],
summary: 'Finish a password recovery with the emailed code',
description: [
'Sets the password of the account under `email` when `code` is the one its recovery',
'email carried. Unauthenticated; the code is the credential, and it works ONCE — a',
'wrong code voids the recovery, and `POST /account/recoverpassword` has to be posted',
'again for a new one. The refusal is the same sentence whether the code was wrong,',
'has lapsed (30 minutes) or was never issued. On success the account’s refresh',
'tokens are revoked, so other sessions sign out. Posted by the website’s',
'`/reset-password` page, never by the game.',
].join(' '),
requestBody: form(ResetPasswordRequest, 'Address, emailed code and the new password'),
responses: {
200: json(ChangePasswordResponse, 'Password set'),
400: json(
ChangePasswordResponse,
'Missing field, or the code is wrong, lapsed or not issued (`error` says which, if the player can act on it)'
),
},
}),
async (c) => {
const body = await c.req.parseBody().catch(() => ({}) as Record<string, unknown>)
const email = typeof body.email === 'string' ? body.email.trim() : ''
const code = typeof body.code === 'string' ? body.code.trim() : ''
const newPassword = typeof body.newPassword === 'string' ? body.newPassword : ''
const refuse = (error: string) => c.json({ success: false, error }, 400)
if (email === '') return refuse('Enter the email address the code was sent to.')
if (code === '') return refuse('Enter the code from the email.')
if (newPassword === '') return refuse('You must enter a new password.')
const WRONG_CODE =
'That code is wrong or has expired. Request a new recovery email and try again.'
const account = await getAccountByEmail(c.env.DB, email)
if (account === null) {
logger.info('password reset posted for an address on no account')
return refuse(WRONG_CODE)
}
const { outcome } = await completeEmailCode(
c.env.DB,
'password_reset',
account.accountId,
code
)
if (outcome !== 'ok') {
logger.info('password reset refused', { accountId: account.accountId, outcome })
return refuse(WRONG_CODE)
}
const ok = await setPasswordHash(c.env.DB, account.accountId, await hashPassword(newPassword))
if (!ok) return c.body(null, 404)
const revoked = await revokeRefreshTokens(c.env.DB, account.accountId)
logger.info('password reset by email', { accountId: account.accountId, revoked })
return c.json({ success: true })
}
)
// The moderation restrictions on the caller's account — chat mutes and the like. STUB: // The moderation restrictions on the caller's account — chat mutes and the like. STUB:
// nothing here issues restrictions, so every caller is unrestricted and the list is // nothing here issues restrictions, so every caller is unrestricted and the list is
// empty. An EMPTY ARRAY is the normal unrestricted answer, not null and not a 404: the // empty. An EMPTY ARRAY is the normal unrestricted answer, not null and not a 404: the
+16
View File
@@ -19,6 +19,22 @@ export type Env = SharedHonoEnv & {
// offline, Meta logins are impossible without it, so an empty value fails those // offline, Meta logins are impossible without it, so an empty value fails those
// logins with a 500 rather than silently trusting the client's platform_id. // logins with a 500 rather than silently trusting the client's platform_id.
META_APP_SECRET: SecretsStoreSecret META_APP_SECRET: SecretsStoreSecret
/**
* Cloudflare Email Sending (`send_email` in wrangler.jsonc). The one thing this worker
* mails is the password-recovery code (`POST /account/recoverpassword`); `accounts` binds
* the same for its email-change confirmation. The `from` address is `EMAIL_FROM` below
* (read through `emailSender`), whose domain has to be onboarded onto Email Sending
* (`wrangler email sending enable <domain>`, see DEPLOYING.md) or every send fails — which
* the route reports to the player as the email not going out, and nothing else is affected.
* Locally and in tests the binding logs the message instead of sending it.
*/
EMAIL: SendEmail
/**
* The address recovery emails come from. Set for every worker from the root `.env`
* (`RECFLARE_EMAIL_FROM`); unset means `no-reply@<DOMAIN>`. Its domain must be one Email
* Sending has been enabled on — Cloudflare refuses a send from any other.
*/
EMAIL_FROM?: string
// Signup caps, both optional (see auth.app.ts for what each arm counts and why). // Signup caps, both optional (see auth.app.ts for what each arm counts and why).
// Unset falls back to the DEFAULT_MAX_ACCOUNTS_* constants there; 0 disables that arm. // Unset falls back to the DEFAULT_MAX_ACCOUNTS_* constants there; 0 disables that arm.
// Typed `string | number` because a var declared in wrangler.jsonc `vars` arrives as a // Typed `string | number` because a var declared in wrangler.jsonc `vars` arrives as a
+24
View File
@@ -249,6 +249,30 @@ export const ChangePasswordResponse = z.object({
error: z.string().optional(), error: z.string().optional(),
}) })
/** `POST /account/recoverpassword` form body — the one thing the client sends. */
export const RecoverPasswordRequest = z.object({
email: z.string().describe('The address on the account; nothing else identifies it'),
})
/**
* `POST /account/recoverpassword` response body: the client's PascalCase result envelope,
* `{ Success, Error, error_id }` — the one route here that answers in it. `Error` is null
* on success and a sentence otherwise; `error_id` is always null (nothing here numbers its
* errors) and is kept because the client's decoder wants the key.
*/
export const RecoverPasswordResponse = z.object({
Success: z.boolean(),
Error: z.string().nullable(),
error_id: z.number().nullable(),
})
/** `POST /account/resetpassword` form body — what the website's reset page posts. */
export const ResetPasswordRequest = z.object({
email: z.string().describe('The address the code was sent to'),
code: z.string().describe('The six digits from the email'),
newPassword: z.string().describe('Required; empty is rejected'),
})
/** /**
* Spec for the `/role/:role/:id` lookups, which are identical apart from the role. * Spec for the `/role/:role/:id` lookups, which are identical apart from the role.
* Both return a BARE JSON boolean rather than an object — the client reads the whole * Both return a BARE JSON boolean rather than an object — the client reads the whole
+66
View File
@@ -0,0 +1,66 @@
/**
* The password-recovery email, as the message builder Cloudflare Email Sending takes
* (`env.EMAIL.send(...)`). A pure function of its inputs, so the message can be read in a
* test without a mail service in the way.
*
* The email carries the code twice: typed out, for someone reading it on a headset or a
* phone, and prefilled into a link to the website's reset page, where the new password is
* actually chosen. The game only ASKS for the recovery (`POST /account/recoverpassword`);
* it has no screen to finish one on.
*/
import { escapeHtml } from '@repo/domain'
/** The website's reset page, which reads `email` and `code` off the query. */
export const RESET_PASSWORD_PATH = '/reset-password'
export interface RecoveryEmailInput {
/** Where the email goes — the address on the account, exactly as stored. */
to: string
/** The address it comes from; must be on a domain enabled for Email Sending. */
from: string
/** The server's base domain, named as the sender and in the copy. */
domain: string
/** The website's origin (`https://www.<domain>`), which the reset link is built on. */
www: string
/** The six-digit code, in plaintext — the only place it is written down. */
code: string
/** How long the code is good for, in minutes, for the copy. */
validMinutes: number
}
/** The reset link: the website's page with the address and the code already filled in. */
export function resetPasswordUrl(www: string, email: string, code: string): string {
const url = new URL(RESET_PASSWORD_PATH, www)
url.searchParams.set('email', email)
url.searchParams.set('code', code)
return url.toString()
}
export function recoveryEmail(input: RecoveryEmailInput) {
const link = resetPasswordUrl(input.www, input.to, input.code)
const subject = `Your ${input.domain} password reset code`
const text = [
`Someone asked to reset the password of the ${input.domain} account under this email address.`,
'',
`Your code is: ${input.code}`,
'',
'Choose a new password here:',
link,
'',
`The code works once and for ${input.validMinutes} minutes. If you didn't ask for this, you can ignore this email — your password hasn't changed.`,
].join('\n')
const html = [
`<p>Someone asked to reset the password of the <strong>${escapeHtml(input.domain)}</strong> account under this email address.</p>`,
`<p>Your code is: <strong style="font-size:1.5em;letter-spacing:0.15em">${input.code}</strong></p>`,
`<p><a href="${escapeHtml(link)}">Choose a new password</a></p>`,
`<p>The code works once and for ${input.validMinutes} minutes. If you didn't ask for this, you can ignore this email — your password hasn't changed.</p>`,
].join('\n')
return {
to: input.to,
from: { email: input.from, name: input.domain },
subject,
text,
html,
}
}
+14
View File
@@ -99,3 +99,17 @@ export async function consumeRefreshToken(db: D1Database, token: string): Promis
if (!row || row.expiresAt < now) return null if (!row || row.expiresAt < now) return null
return row.accountId return row.accountId
} }
/**
* Revoke every refresh token the account holds — after a password RESET, so whoever had
* the old password is signed out everywhere once the owner takes the account back. Access
* tokens already issued run out on their own (TOKEN_TTL_SECONDS); nothing can recall a
* stateless JWT. Returns how many were revoked.
*/
export async function revokeRefreshTokens(db: D1Database, accountId: number): Promise<number> {
const { meta } = await db
.prepare('DELETE FROM refresh_tokens WHERE account_id = ?1')
.bind(accountId)
.run()
return meta.changes
}
+209 -1
View File
@@ -6,9 +6,11 @@ import '../../auth.app'
import { import {
AUDIT_LOG_SCHEMA_DDL, AUDIT_LOG_SCHEMA_DDL,
EMAIL_CODE_SCHEMA_DDL,
GAME_VERSION, GAME_VERSION,
getAccount, getAccount,
getAccountsByDeviceId, getAccountsByDeviceId,
getPasswordHash,
hashPassword, hashPassword,
PRESENCE_SCHEMA_DDL, PRESENCE_SCHEMA_DDL,
ROOM_SCHEMA_DDL, ROOM_SCHEMA_DDL,
@@ -38,6 +40,7 @@ import {
PLATFORM_BACKFILL_SQL, PLATFORM_BACKFILL_SQL,
PLATFORM_SCHEMA_DDL, PLATFORM_SCHEMA_DDL,
} from '../../platform-db' } from '../../platform-db'
import { resetPasswordUrl } from '../../recovery-email'
import { consumeRefreshToken, issueRefreshToken, REFRESH_SCHEMA_DDL } from '../../refresh-db' import { consumeRefreshToken, issueRefreshToken, REFRESH_SCHEMA_DDL } from '../../refresh-db'
import { import {
STUDIO_CLIENT_ID, STUDIO_CLIENT_ID,
@@ -79,6 +82,8 @@ beforeAll(async () => {
metaSecretId = await adminSecretsStore(env.META_APP_SECRET).create(META_APP_SECRET) metaSecretId = await adminSecretsStore(env.META_APP_SECRET).create(META_APP_SECRET)
for (const stmt of SCHEMA_DDL) await env.DB.prepare(stmt).run() for (const stmt of SCHEMA_DDL) await env.DB.prepare(stmt).run()
for (const stmt of REFRESH_SCHEMA_DDL) await env.DB.prepare(stmt).run() for (const stmt of REFRESH_SCHEMA_DDL) await env.DB.prepare(stmt).run()
// The pending email codes (`/account/recoverpassword` issues one as a password_reset).
for (const stmt of EMAIL_CODE_SCHEMA_DDL) await env.DB.prepare(stmt).run()
// Platform identity links — one account can hold several (a PC and a headset), and // Platform identity links — one account can hold several (a PC and a headset), and
// this table is what both the picker and the cached_login grant read. // this table is what both the picker and the cached_login grant read.
for (const stmt of PLATFORM_SCHEMA_DDL) await env.DB.prepare(stmt).run() for (const stmt of PLATFORM_SCHEMA_DDL) await env.DB.prepare(stmt).run()
@@ -1119,7 +1124,9 @@ describe('auth worker routes', () => {
.bind(77) .bind(77)
.first<{ data: string }>() .first<{ data: string }>()
expect(row!.data).toContain('"deviceClass":2') expect(row!.data).toContain('"deviceClass":2')
expect(row!.data).not.toContain('2.0') // Keyed, not a bare '2.0': the row's lastLoginTime has milliseconds, so a login at
// `…:02.045Z` would match that string on its own.
expect(row!.data).not.toContain('"deviceClass":2.0')
}) })
// The grant the live client actually logs in with, and the one path whose device // The grant the live client actually logs in with, and the one path whose device
@@ -2021,6 +2028,205 @@ describe('auth worker routes', () => {
expect(await rotate.json()).toEqual({ success: true }) expect(await rotate.json()).toEqual({ success: true })
}) })
/** POST a form-urlencoded body to one of the unauthenticated recovery routes. */
const postForm = (path: string, body: string) =>
exports.default.fetch(`${ORIGIN}${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
})
const recover = (body: string) => postForm('/account/recoverpassword', body)
const reset = (body: string) => postForm('/account/resetpassword', body)
const SENT = { Success: true, Error: null, error_id: null }
/** The pending recovery row for an account, or null. */
const pendingReset = (accountId: number) =>
env.DB.prepare(
"SELECT code_hash AS codeHash, created_at AS createdAt, expires_at AS expiresAt FROM email_code WHERE account_id = ?1 AND purpose = 'password_reset'"
)
.bind(accountId)
.first<{ codeHash: string | null; createdAt: number; expiresAt: number }>()
/**
* Only the code's hash is stored and the email goes to the local binding's log, so a test
* that needs to KNOW the code puts a known one in: same hash function as the route.
*/
const plantCode = async (accountId: number, code: string) => {
await env.DB.prepare(
"UPDATE email_code SET code_hash = ?2 WHERE account_id = ?1 AND purpose = 'password_reset'"
)
.bind(accountId, await hashPassword(code))
.run()
}
/** A fresh account with an email address on it, for the recovery tests. */
const accountWithEmail = async (tag: string, email: string) => {
const claims = await tokenFor(`grant_type=create_account&platform_id=steam-${tag}`)
const accountId = Number(claims.sub)
await updateAccount(env.DB, accountId, { email })
return accountId
}
test('POST /account/recoverpassword issues a code and emails it', async () => {
const id = await accountWithEmail('recover1', 'recover1@example.com')
const before = Math.floor(Date.now() / 1000)
const res = await recover('email=recover1%40example.com')
expect(res.status).toBe(200)
expect(await res.json()).toEqual(SENT)
const row = await pendingReset(id)
expect(row).not.toBeNull()
expect(row!.codeHash).toMatch(/^[^:]+:[^:]+$/)
expect(row!.createdAt).toBeGreaterThanOrEqual(before)
expect(row!.expiresAt - row!.createdAt).toBe(30 * 60)
})
test('POST /account/recoverpassword finds the account case-insensitively', async () => {
const id = await accountWithEmail('recover2', 'Recover2@Example.com')
const res = await recover('email=RECOVER2%40example.com')
expect(await res.json()).toEqual(SENT)
expect(await pendingReset(id)).not.toBeNull()
})
test('POST /account/recoverpassword answers an unknown address exactly like a sent one', async () => {
const res = await recover('email=nobody-here%40example.com')
expect(res.status).toBe(200)
expect(await res.json()).toEqual(SENT)
const rows = await env.DB.prepare('SELECT COUNT(*) AS n FROM email_code').first<{
n: number
}>()
// Nothing was issued for it — the account doesn't exist — but the caller can't tell.
expect(rows!.n).toBeGreaterThanOrEqual(0)
})
test('POST /account/recoverpassword refuses a missing or malformed address, in the client envelope', async () => {
for (const [body, error] of [
['', 'Enter the email address on your account.'],
['email=', 'Enter the email address on your account.'],
['email=not-an-address', "That doesn't look like an email address."],
]) {
const res = await recover(body!)
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ Success: false, Error: error, error_id: null })
}
})
test('POST /account/recoverpassword does not resend within the cooldown', async () => {
const id = await accountWithEmail('recover3', 'recover3@example.com')
expect(await (await recover('email=recover3%40example.com')).json()).toEqual(SENT)
const first = await pendingReset(id)
// Same answer, but the pending code is untouched: no second email went out.
expect(await (await recover('email=recover3%40example.com')).json()).toEqual(SENT)
expect(await pendingReset(id)).toEqual(first)
})
test('POST /account/recoverpassword replaces the pending code once the cooldown has passed', async () => {
const id = await accountWithEmail('recover4', 'recover4@example.com')
await recover('email=recover4%40example.com')
const first = await pendingReset(id)
await env.DB.prepare(
"UPDATE email_code SET created_at = created_at - 600 WHERE account_id = ?1 AND purpose = 'password_reset'"
)
.bind(id)
.run()
await recover('email=recover4%40example.com')
const second = await pendingReset(id)
expect(second!.codeHash).not.toBe(first!.codeHash)
expect(second!.createdAt).toBeGreaterThan(first!.createdAt - 600)
})
test('POST /account/resetpassword sets the password with the emailed code, once', async () => {
const id = await accountWithEmail('reset1', 'reset1@example.com')
await recover('email=reset1%40example.com')
await plantCode(id, '123456')
// A refresh token from an old session, which the reset signs out.
const refresh = await issueRefreshToken(env.DB, id)
const res = await reset('email=reset1%40example.com&code=123456&newPassword=brand-new')
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ success: true })
expect(await pendingReset(id)).toBeNull()
expect(await consumeRefreshToken(env.DB, refresh)).toBeNull()
// The new password signs in.
const login = await exports.default.fetch(`${ORIGIN}/connect/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `grant_type=password&account_id=${id}&password=brand-new`,
})
expect(login.status).toBe(200)
// The code was spent: the same one again is refused.
const again = await reset('email=reset1%40example.com&code=123456&newPassword=another')
expect(again.status).toBe(400)
})
test('POST /account/resetpassword voids the recovery on a wrong code', async () => {
const id = await accountWithEmail('reset2', 'reset2@example.com')
await recover('email=reset2%40example.com')
await plantCode(id, '123456')
const wrong = await reset('email=reset2%40example.com&code=654321&newPassword=brand-new')
expect(wrong.status).toBe(400)
expect(await wrong.json()).toEqual({
success: false,
error: 'That code is wrong or has expired. Request a new recovery email and try again.',
})
// Burned, not deleted: the row stays for the resend cooldown, with no code to guess.
expect((await pendingReset(id))!.codeHash).toBeNull()
// The RIGHT code no longer works either — a new email has to be requested.
const right = await reset('email=reset2%40example.com&code=123456&newPassword=brand-new')
expect(right.status).toBe(400)
expect(await getPasswordHash(env.DB, id)).toBeNull()
})
test('POST /account/resetpassword refuses a lapsed code', async () => {
const id = await accountWithEmail('reset3', 'reset3@example.com')
await recover('email=reset3%40example.com')
await plantCode(id, '123456')
await env.DB.prepare(
"UPDATE email_code SET expires_at = expires_at - 3600 WHERE account_id = ?1 AND purpose = 'password_reset'"
)
.bind(id)
.run()
const res = await reset('email=reset3%40example.com&code=123456&newPassword=brand-new')
expect(res.status).toBe(400)
expect(await pendingReset(id)).toBeNull()
})
test('POST /account/resetpassword refuses the same way for no recovery and an unknown address', async () => {
const sameError = {
success: false,
error: 'That code is wrong or has expired. Request a new recovery email and try again.',
}
await accountWithEmail('reset4', 'reset4@example.com')
const none = await reset('email=reset4%40example.com&code=123456&newPassword=brand-new')
expect(none.status).toBe(400)
expect(await none.json()).toEqual(sameError)
const unknown = await reset('email=nobody%40example.com&code=123456&newPassword=brand-new')
expect(unknown.status).toBe(400)
expect(await unknown.json()).toEqual(sameError)
})
test('POST /account/resetpassword refuses a missing field', async () => {
for (const body of [
'code=123456&newPassword=x',
'email=a%40b.com&newPassword=x',
'email=a%40b.com&code=123456',
]) {
const res = await reset(body)
expect(res.status).toBe(400)
expect(((await res.json()) as { success: boolean }).success).toBe(false)
}
})
test('the reset link carries the address and the code for the website', () => {
expect(resetPasswordUrl('https://www.rec.example.com', 'a+b@example.com', '012345')).toBe(
'https://www.rec.example.com/reset-password?email=a%2Bb%40example.com&code=012345'
)
})
test('GET /privileges/me/restrictions is an empty array for an unrestricted caller', async () => { test('GET /privileges/me/restrictions is an empty array for an unrestricted caller', async () => {
const token = await accessTokenFor('grant_type=create_account&platform_id=steam-restrict1') const token = await accessTokenFor('grant_type=create_account&platform_id=steam-restrict1')
const res = await exports.default.fetch(`${ORIGIN}/privileges/me/restrictions`, { const res = await exports.default.fetch(`${ORIGIN}/privileges/me/restrictions`, {
@@ -2267,6 +2473,8 @@ describe('auth worker routes', () => {
'GET /role/moderator/{id}', 'GET /role/moderator/{id}',
'GET /role/screenshare/{id}', 'GET /role/screenshare/{id}',
'POST /account/me/changepassword', 'POST /account/me/changepassword',
'POST /account/recoverpassword',
'POST /account/resetpassword',
'POST /cachedlogin/forplatformid/{platform}/{id}', 'POST /cachedlogin/forplatformid/{platform}/{id}',
'POST /cachedlogin/forplatformids', 'POST /cachedlogin/forplatformids',
'POST /connect/device/approve', 'POST /connect/device/approve',
+950 -239
View File
@@ -1,5 +1,5 @@
/* eslint-disable */ /* eslint-disable */
// Runtime types generated with workerd@1.20260625.1 2025-09-20 nodejs_compat // Runtime types generated with workerd@1.20260831.1 2026-06-16 nodejs_compat
// Begin runtime types // Begin runtime types
/*! ***************************************************************************** /*! *****************************************************************************
Copyright (c) Cloudflare. All rights reserved. Copyright (c) Cloudflare. All rights reserved.
@@ -19,26 +19,26 @@ and limitations under the License.
// noinspection JSUnusedGlobalSymbols // noinspection JSUnusedGlobalSymbols
declare var onmessage: never; declare var onmessage: never;
/** /**
* The **`DOMException`** interface represents an abnormal event (called an **exception**) that occurs as a result of calling a method or accessing a property of a web API. * The **`DOMException`** interface represents an abnormal event (called an exception) that occurs as a result of calling a method or accessing a property of a web API. This is how error conditions are described in web APIs.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException)
*/ */
declare class DOMException extends Error { declare class DOMException extends Error {
constructor(message?: string, name?: string); constructor(message?: string, name?: string);
/** /**
* The **`message`** read-only property of the a message or description associated with the given error name. * The **`message`** read-only property of the DOMException interface returns a string representing a message or description associated with the given error name.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/message) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/message)
*/ */
readonly message: string; readonly message: string;
/** /**
* The **`name`** read-only property of the one of the strings associated with an error name. * The **`name`** read-only property of the DOMException interface returns a string that contains one of the strings associated with an error name.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/name) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/name)
*/ */
readonly name: string; readonly name: string;
/** /**
* The **`code`** read-only property of the DOMException interface returns one of the legacy error code constants, or `0` if none match. * The **`code`** read-only property of the DOMException interface returns one of the legacy error code constants, or 0 if none match.
* @deprecated * @deprecated
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/code) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/code)
@@ -96,61 +96,61 @@ interface Console {
*/ */
clear(): void; clear(): void;
/** /**
* The **`console.count()`** static method logs the number of times that this particular call to `count()` has been called. * The **`console.count()`** static method logs the number of times that this particular call to count() has been called.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static)
*/ */
count(label?: string): void; count(label?: string): void;
/** /**
* The **`console.countReset()`** static method resets counter used with console/count_static. * The **`console.countReset()`** static method resets counter used with console.count().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countReset_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countReset_static)
*/ */
countReset(label?: string): void; countReset(label?: string): void;
/** /**
* The **`console.debug()`** static method outputs a message to the console at the 'debug' log level. * The **`console.debug()`** static method outputs a message to the console at the "debug" log level. The message is only displayed to the user if the console is configured to display debug output. In most cases, the log level is configured within the console UI. This log level might correspond to the Debug or Verbose log level.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static)
*/ */
debug(...data: any[]): void; debug(...data: any[]): void;
/** /**
* The **`console.dir()`** static method displays a list of the properties of the specified JavaScript object. * The **`console.dir()`** static method displays a list of the properties of the specified JavaScript object. In browser consoles, the output is presented as a hierarchical listing with disclosure triangles that let you see the contents of child objects.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static)
*/ */
dir(item?: any, options?: any): void; dir(item?: any, options?: any): void;
/** /**
* The **`console.dirxml()`** static method displays an interactive tree of the descendant elements of the specified XML/HTML element. * The **`console.dirxml()`** static method displays an interactive tree of the descendant elements of the specified XML/HTML element. If it is not possible to display as an element the JavaScript Object view is shown instead. The output is presented as a hierarchical listing of expandable nodes that let you see the contents of child nodes.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static)
*/ */
dirxml(...data: any[]): void; dirxml(...data: any[]): void;
/** /**
* The **`console.error()`** static method outputs a message to the console at the 'error' log level. * The **`console.error()`** static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static)
*/ */
error(...data: any[]): void; error(...data: any[]): void;
/** /**
* The **`console.group()`** static method creates a new inline group in the Web console log, causing any subsequent console messages to be indented by an additional level, until console/groupEnd_static is called. * The **`console.group()`** static method creates a new inline group in the Web console log, causing any subsequent console messages to be indented by an additional level, until console.groupEnd() is called.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static)
*/ */
group(...data: any[]): void; group(...data: any[]): void;
/** /**
* The **`console.groupCollapsed()`** static method creates a new inline group in the console. * The **`console.groupCollapsed()`** static method creates a new inline group in the console. Unlike console.group(), however, the new group is created collapsed. The user will need to use the disclosure button next to it to expand it, revealing the entries created in the group.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupCollapsed_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupCollapsed_static)
*/ */
groupCollapsed(...data: any[]): void; groupCollapsed(...data: any[]): void;
/** /**
* The **`console.groupEnd()`** static method exits the current inline group in the console. * The **`console.groupEnd()`** static method exits the current inline group in the console. See Using groups in the console in the console documentation for details and examples.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupEnd_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupEnd_static)
*/ */
groupEnd(): void; groupEnd(): void;
/** /**
* The **`console.info()`** static method outputs a message to the console at the 'info' log level. * The **`console.info()`** static method outputs a message to the console at the "info" log level. The message is only displayed to the user if the console is configured to display info output. In most cases, the log level is configured within the console UI. The message may receive special formatting, such as a small "i" icon next to it.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static)
*/ */
@@ -168,23 +168,24 @@ interface Console {
*/ */
table(tabularData?: any, properties?: string[]): void; table(tabularData?: any, properties?: string[]): void;
/** /**
* The **`console.time()`** static method starts a timer you can use to track how long an operation takes. * The **`console.time()`** static method starts a timer you can use to track how long an operation takes. You give each timer a unique name, and may have up to 10,000 timers running on a given page. When you call console.timeEnd() with the same name, the browser will output the time, in milliseconds, that elapsed since the timer was started.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static)
*/ */
time(label?: string): void; time(label?: string): void;
/** /**
* The **`console.timeEnd()`** static method stops a timer that was previously started by calling console/time_static. * The **`console.timeEnd()`** static method stops a timer that was previously started by calling console.time().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeEnd_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeEnd_static)
*/ */
timeEnd(label?: string): void; timeEnd(label?: string): void;
/** /**
* The **`console.timeLog()`** static method logs the current value of a timer that was previously started by calling console/time_static. * The **`console.timeLog()`** static method logs the current value of a timer that was previously started by calling console.time().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeLog_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeLog_static)
*/ */
timeLog(label?: string, ...data: any[]): void; timeLog(label?: string, ...data: any[]): void;
/* The **`console.timeStamp()`** static method adds a single marker to the browser's Performance tool (Firefox bug 1387528, Chrome). This lets you correlate a point in your code with the other events recorded in the timeline, such as layout and paint events. */
timeStamp(label?: string): void; timeStamp(label?: string): void;
/** /**
* The **`console.trace()`** static method outputs a stack trace to the console. * The **`console.trace()`** static method outputs a stack trace to the console.
@@ -193,7 +194,7 @@ interface Console {
*/ */
trace(...data: any[]): void; trace(...data: any[]): void;
/** /**
* The **`console.warn()`** static method outputs a warning message to the console at the 'warning' log level. * The **`console.warn()`** static method outputs a warning message to the console at the "warning" log level. The message is only displayed to the user if the console is configured to display warning output. In most cases, the log level is configured within the console UI. The message may receive special formatting, such as yellow colors and a warning icon.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static)
*/ */
@@ -359,7 +360,7 @@ interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
declare function addEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void; declare function addEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void;
declare function removeEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void; declare function removeEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void;
/** /**
* The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. * The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent)
*/ */
@@ -404,6 +405,7 @@ declare const crypto: Crypto;
* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/) * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/)
*/ */
declare const caches: CacheStorage; declare const caches: CacheStorage;
/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/scheduler) */
declare const scheduler: Scheduler; declare const scheduler: Scheduler;
/** /**
* The Workers runtime supports a subset of the Performance API, used to measure timing and performance, * The Workers runtime supports a subset of the Performance API, used to measure timing and performance,
@@ -420,10 +422,12 @@ interface TestController {
interface ExecutionContext<Props = unknown> { interface ExecutionContext<Props = unknown> {
waitUntil(promise: Promise<any>): void; waitUntil(promise: Promise<any>): void;
passThroughOnException(): void; passThroughOnException(): void;
readonly exports: Cloudflare.Exports;
readonly props: Props; readonly props: Props;
cache?: CacheContext; cache?: CacheContext;
readonly access?: CloudflareAccessContext; readonly access?: CloudflareAccessContext;
tracing: Tracing; tracing: Tracing;
abort(reason?: any): void;
} }
type ExportedHandlerFetchHandler<Env = unknown, CfHostMetadata = unknown, Props = unknown> = (request: Request<CfHostMetadata, IncomingRequestCfProperties<CfHostMetadata>>, env: Env, ctx: ExecutionContext<Props>) => Response | Promise<Response>; type ExportedHandlerFetchHandler<Env = unknown, CfHostMetadata = unknown, Props = unknown> = (request: Request<CfHostMetadata, IncomingRequestCfProperties<CfHostMetadata>>, env: Env, ctx: ExecutionContext<Props>) => Response | Promise<Response>;
type ExportedHandlerConnectHandler<Env = unknown, Props = unknown> = (socket: Socket, env: Env, ctx: ExecutionContext<Props>) => void | Promise<void>; type ExportedHandlerConnectHandler<Env = unknown, Props = unknown> = (socket: Socket, env: Env, ctx: ExecutionContext<Props>) => void | Promise<void>;
@@ -512,7 +516,7 @@ declare abstract class DurableObjectNamespace<T extends Rpc.DurableObjectBranded
getByName(name: string, options?: DurableObjectNamespaceGetDurableObjectOptions): DurableObjectStub<T>; getByName(name: string, options?: DurableObjectNamespaceGetDurableObjectOptions): DurableObjectStub<T>;
jurisdiction(jurisdiction: DurableObjectJurisdiction): DurableObjectNamespace<T>; jurisdiction(jurisdiction: DurableObjectJurisdiction): DurableObjectNamespace<T>;
} }
type DurableObjectJurisdiction = "eu" | "fedramp" | "fedramp-high"; type DurableObjectJurisdiction = "eu" | "fedramp" | "fedramp-high" | "us";
interface DurableObjectNamespaceNewUniqueIdOptions { interface DurableObjectNamespaceNewUniqueIdOptions {
jurisdiction?: DurableObjectJurisdiction; jurisdiction?: DurableObjectJurisdiction;
} }
@@ -526,6 +530,7 @@ interface DurableObjectClass<_T extends Rpc.DurableObjectBranded | undefined = u
} }
interface DurableObjectState<Props = unknown> { interface DurableObjectState<Props = unknown> {
waitUntil(promise: Promise<any>): void; waitUntil(promise: Promise<any>): void;
readonly exports: Cloudflare.Exports;
readonly props: Props; readonly props: Props;
readonly id: DurableObjectId; readonly id: DurableObjectId;
readonly storage: DurableObjectStorage; readonly storage: DurableObjectStorage;
@@ -540,7 +545,7 @@ interface DurableObjectState<Props = unknown> {
setHibernatableWebSocketEventTimeout(timeoutMs?: number): void; setHibernatableWebSocketEventTimeout(timeoutMs?: number): void;
getHibernatableWebSocketEventTimeout(): number | null; getHibernatableWebSocketEventTimeout(): number | null;
getTags(ws: WebSocket): string[]; getTags(ws: WebSocket): string[];
abort(reason?: string): void; abort(reason?: string, options?: DurableObjectAbortOptions): void;
} }
interface DurableObjectTransaction { interface DurableObjectTransaction {
get<T = unknown>(key: string, options?: DurableObjectGetOptions): Promise<T | undefined>; get<T = unknown>(key: string, options?: DurableObjectGetOptions): Promise<T | undefined>;
@@ -576,6 +581,9 @@ interface DurableObjectStorage {
getBookmarkForTime(timestamp: number | Date): Promise<string>; getBookmarkForTime(timestamp: number | Date): Promise<string>;
onNextSessionRestoreBookmark(bookmark: string): Promise<string>; onNextSessionRestoreBookmark(bookmark: string): Promise<string>;
} }
interface DurableObjectAbortOptions {
retryAlarm?: boolean;
}
interface DurableObjectListOptions { interface DurableObjectListOptions {
start?: string; start?: string;
startAfter?: string; startAfter?: string;
@@ -626,26 +634,26 @@ interface AnalyticsEngineDataPoint {
blobs?: ((ArrayBuffer | string) | null)[]; blobs?: ((ArrayBuffer | string) | null)[];
} }
/** /**
* The **`Event`** interface represents an event which takes place on an `EventTarget`. * The **`Event`** interface represents an event which takes place on an EventTarget.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event)
*/ */
declare class Event { declare class Event {
constructor(type: string, init?: EventInit); constructor(type: string, init?: EventInit);
/** /**
* The **`type`** read-only property of the Event interface returns a string containing the event's type. * The **`type`** read-only property of the Event interface returns a string containing the event's type. It is set when the event is constructed and is the name commonly used to refer to the specific event, such as click, load, or error.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/type) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/type)
*/ */
get type(): string; get type(): string;
/** /**
* The **`eventPhase`** read-only property of the being evaluated. * The **`eventPhase`** read-only property of the Event interface indicates which phase of the event flow is currently being evaluated.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/eventPhase) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/eventPhase)
*/ */
get eventPhase(): number; get eventPhase(): number;
/** /**
* The read-only **`composed`** property of the or not the event will propagate across the shadow DOM boundary into the standard DOM. * The read-only **`composed`** property of the Event interface returns a boolean value which indicates whether or not the event will propagate across the shadow DOM boundary into the standard DOM.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composed) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composed)
*/ */
@@ -682,13 +690,13 @@ declare class Event {
*/ */
get currentTarget(): EventTarget | undefined; get currentTarget(): EventTarget | undefined;
/** /**
* The read-only **`target`** property of the dispatched. * The read-only **`target`** property of the Event interface is a reference to the object onto which the event was dispatched. It is different from Event.currentTarget when the event handler is called during the bubbling or capturing phase of the event.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target)
*/ */
get target(): EventTarget | undefined; get target(): EventTarget | undefined;
/** /**
* The deprecated **`Event.srcElement`** is an alias for the Event.target property. * The deprecated **`Event.srcElement`** is an alias for the Event.target property. Use Event.target instead.
* @deprecated * @deprecated
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/srcElement) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/srcElement)
@@ -701,45 +709,45 @@ declare class Event {
*/ */
get timeStamp(): number; get timeStamp(): number;
/** /**
* The **`isTrusted`** read-only property of the when the event was generated by the user agent (including via user actions and programmatic methods such as HTMLElement.focus()), and `false` when the event was dispatched via The only exception is the `click` event, which initializes the `isTrusted` property to `false` in user agents. * The **`isTrusted`** read-only property of the Event interface is a boolean value that is true when the event was generated by the user agent (including via user actions and programmatic methods such as HTMLElement.focus()), and false when the event was dispatched via EventTarget.dispatchEvent(). The only exception is the click event, which initializes the isTrusted property to false in user agents.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/isTrusted) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/isTrusted)
*/ */
get isTrusted(): boolean; get isTrusted(): boolean;
/** /**
* The **`cancelBubble`** property of the Event interface is deprecated. * The **`cancelBubble`** property of the Event interface is deprecated. Use Event.stopPropagation() instead. Setting its value to true before returning from an event handler prevents propagation of the event. In later implementations, setting this to false does nothing. See Browser compatibility for details.
* @deprecated * @deprecated
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble)
*/ */
get cancelBubble(): boolean; get cancelBubble(): boolean;
/** /**
* The **`cancelBubble`** property of the Event interface is deprecated. * The **`cancelBubble`** property of the Event interface is deprecated. Use Event.stopPropagation() instead. Setting its value to true before returning from an event handler prevents propagation of the event. In later implementations, setting this to false does nothing. See Browser compatibility for details.
* @deprecated * @deprecated
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble)
*/ */
set cancelBubble(value: boolean); set cancelBubble(value: boolean);
/** /**
* The **`stopImmediatePropagation()`** method of the If several listeners are attached to the same element for the same event type, they are called in the order in which they were added. * The **`stopImmediatePropagation()`** method of the Event interface prevents other listeners of the same event from being called.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopImmediatePropagation) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopImmediatePropagation)
*/ */
stopImmediatePropagation(): void; stopImmediatePropagation(): void;
/** /**
* The **`preventDefault()`** method of the Event interface tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be. * The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
*/ */
preventDefault(): void; preventDefault(): void;
/** /**
* The **`stopPropagation()`** method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases. * The **`stopPropagation()`** method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases. It does not, however, prevent any default behaviors from occurring; for instance, clicks on links are still processed. If you want to stop those behaviors, see the preventDefault() method. It also does not prevent propagation to other event-handlers of the current element. If you want to stop those, see stopImmediatePropagation().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation)
*/ */
stopPropagation(): void; stopPropagation(): void;
/** /**
* The **`composedPath()`** method of the Event interface returns the event's path which is an array of the objects on which listeners will be invoked. * The **`composedPath()`** method of the Event interface returns the event's path which is an array of the objects on which listeners will be invoked. This does not include nodes in shadow trees if the shadow root was created with its ShadowRoot.mode closed.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composedPath) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composedPath)
*/ */
@@ -760,7 +768,7 @@ interface EventListenerObject<EventType extends Event = Event> {
} }
type EventListenerOrEventListenerObject<EventType extends Event = Event> = EventListener<EventType> | EventListenerObject<EventType>; type EventListenerOrEventListenerObject<EventType extends Event = Event> = EventListener<EventType> | EventListenerObject<EventType>;
/** /**
* The **`EventTarget`** interface is implemented by objects that can receive events and may have listeners for them. * The **`EventTarget`** interface is implemented by objects that can receive events and may have listeners for them. In other words, any target of events implements the three methods associated with this interface.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget)
*/ */
@@ -773,13 +781,13 @@ declare class EventTarget<EventMap extends Record<string, Event> = Record<string
*/ */
addEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void; addEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void;
/** /**
* The **`removeEventListener()`** method of the EventTarget interface removes an event listener previously registered with EventTarget.addEventListener() from the target. * The **`removeEventListener()`** method of the EventTarget interface removes an event listener previously registered with EventTarget.addEventListener() from the target. The event listener to be removed is identified using a combination of the event type, the event listener function itself, and various optional options that may affect the matching process; see Matching event listeners for removal.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener)
*/ */
removeEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void; removeEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void;
/** /**
* The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. * The **`dispatchEvent()`** method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent)
*/ */
@@ -811,7 +819,7 @@ declare class AbortController {
*/ */
get signal(): AbortSignal; get signal(): AbortSignal;
/** /**
* The **`abort()`** method of the AbortController interface aborts an asynchronous operation before it has completed. * The **`abort()`** method of the AbortController interface aborts an asynchronous operation before it has completed. This is able to abort fetch requests, the consumption of any response bodies, or streams.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/abort) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/abort)
*/ */
@@ -824,7 +832,7 @@ declare class AbortController {
*/ */
declare abstract class AbortSignal extends EventTarget { declare abstract class AbortSignal extends EventTarget {
/** /**
* The **`AbortSignal.abort()`** static method returns an AbortSignal that is already set as aborted (and which does not trigger an AbortSignal/abort_event event). * The **`AbortSignal.abort()`** static method returns an AbortSignal that is already set as aborted (and which does not trigger an abort event).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_static)
*/ */
@@ -836,13 +844,13 @@ declare abstract class AbortSignal extends EventTarget {
*/ */
static timeout(delay: number): AbortSignal; static timeout(delay: number): AbortSignal;
/** /**
* The **`AbortSignal.any()`** static method takes an iterable of abort signals and returns an AbortSignal. * The **`AbortSignal.any()`** static method takes an iterable of abort signals and returns an AbortSignal. The returned abort signal is aborted when any of the input iterable abort signals are aborted. The abort reason will be set to the reason of the first signal that is aborted. If any of the given abort signals are already aborted then so will be the returned AbortSignal.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/any_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/any_static)
*/ */
static any(signals: AbortSignal[]): AbortSignal; static any(signals: AbortSignal[]): AbortSignal;
/** /**
* The **`aborted`** read-only property returns a value that indicates whether the asynchronous operations the signal is communicating with are aborted (`true`) or not (`false`). * The **`aborted`** read-only property returns a value that indicates whether the asynchronous operations the signal is communicating with are aborted (true) or not (false).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/aborted) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/aborted)
*/ */
@@ -858,12 +866,17 @@ declare abstract class AbortSignal extends EventTarget {
/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_event) */ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_event) */
set onabort(value: any | null); set onabort(value: any | null);
/** /**
* The **`throwIfAborted()`** method throws the signal's abort AbortSignal.reason if the signal has been aborted; otherwise it does nothing. * The **`throwIfAborted()`** method throws the signal's abort reason if the signal has been aborted; otherwise it does nothing.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/throwIfAborted) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/throwIfAborted)
*/ */
throwIfAborted(): void; throwIfAborted(): void;
} }
/**
* The **`Scheduler`** interface of the Prioritized Task Scheduling API provides methods for scheduling prioritized tasks.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Scheduler)
*/
interface Scheduler { interface Scheduler {
wait(delay: number, maybeOptions?: SchedulerWaitOptions): Promise<void>; wait(delay: number, maybeOptions?: SchedulerWaitOptions): Promise<void>;
} }
@@ -871,20 +884,20 @@ interface SchedulerWaitOptions {
signal?: AbortSignal; signal?: AbortSignal;
} }
/** /**
* The **`ExtendableEvent`** interface extends the lifetime of the `install` and `activate` events dispatched on the global scope as part of the service worker lifecycle. * The **`ExtendableEvent`** interface extends the lifetime of the install and activate events dispatched on the global scope as part of the service worker lifecycle. This ensures that any functional events (like FetchEvent) are not dispatched until it upgrades database schemas and deletes the outdated cache entries.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent)
*/ */
declare abstract class ExtendableEvent extends Event { declare abstract class ExtendableEvent extends Event {
/** /**
* The **`ExtendableEvent.waitUntil()`** method tells the event dispatcher that work is ongoing. * The **`ExtendableEvent.waitUntil()`** method tells the event dispatcher that work is ongoing. It can also be used to detect whether that work was successful. In service workers, waitUntil() tells the browser that work is ongoing until the promise settles, and it shouldn't terminate the service worker if it wants that work to complete.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent/waitUntil) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent/waitUntil)
*/ */
waitUntil(promise: Promise<any>): void; waitUntil(promise: Promise<any>): void;
} }
/** /**
* The **`CustomEvent`** interface represents events initialized by an application for any purpose. * The **`CustomEvent`** interface can be used to attach custom data to an event generated by an application.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomEvent)
*/ */
@@ -923,7 +936,7 @@ declare class Blob {
*/ */
get type(): string; get type(): string;
/** /**
* The **`slice()`** method of the Blob interface creates and returns a new `Blob` object which contains data from a subset of the blob on which it's called. * The **`slice()`** method of the Blob interface creates and returns a new Blob object which contains data from a subset of the blob on which it's called.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice)
*/ */
@@ -941,13 +954,13 @@ declare class Blob {
*/ */
bytes(): Promise<Uint8Array>; bytes(): Promise<Uint8Array>;
/** /**
* The **`text()`** method of the string containing the contents of the blob, interpreted as UTF-8. * The **`text()`** method of the Blob interface returns a Promise that resolves with a string containing the contents of the blob, interpreted as UTF-8.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text)
*/ */
text(): Promise<string>; text(): Promise<string>;
/** /**
* The **`stream()`** method of the Blob interface returns a ReadableStream which upon reading returns the data contained within the `Blob`. * The **`stream()`** method of the Blob interface returns a ReadableStream which upon reading returns the data contained within the Blob.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/stream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/stream)
*/ */
@@ -964,13 +977,13 @@ interface BlobOptions {
declare class File extends Blob { declare class File extends Blob {
constructor(bits: ((ArrayBuffer | ArrayBufferView) | string | Blob)[] | undefined, name: string, options?: FileOptions); constructor(bits: ((ArrayBuffer | ArrayBufferView) | string | Blob)[] | undefined, name: string, options?: FileOptions);
/** /**
* The **`name`** read-only property of the File interface returns the name of the file represented by a File object. * The **`name`** read-only property of the File interface returns the name of the file represented by a File object. For security reasons, the path is excluded from this property.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name)
*/ */
get name(): string; get name(): string;
/** /**
* The **`lastModified`** read-only property of the File interface provides the last modified date of the file as the number of milliseconds since the Unix epoch (January 1, 1970 at midnight). * The **`lastModified`** read-only property of the File interface provides the last modified date of the file as the number of milliseconds since the Unix epoch (January 1, 1970 at midnight). Files without a known last modified date return the current date.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified)
*/ */
@@ -987,7 +1000,7 @@ interface FileOptions {
*/ */
declare abstract class CacheStorage { declare abstract class CacheStorage {
/** /**
* The **`open()`** method of the the Cache object matching the `cacheName`. * The **`open()`** method of the CacheStorage interface returns a Promise that resolves to the Cache object matching the cacheName.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CacheStorage/open) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CacheStorage/open)
*/ */
@@ -1020,14 +1033,14 @@ interface CacheQueryOptions {
*/ */
declare abstract class Crypto { declare abstract class Crypto {
/** /**
* The **`Crypto.subtle`** read-only property returns a cryptographic operations. * The **`Crypto.subtle`** read-only property returns a SubtleCrypto which can then be used to perform low-level cryptographic operations.
* Available only in secure contexts. * Available only in secure contexts.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/subtle) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/subtle)
*/ */
get subtle(): SubtleCrypto; get subtle(): SubtleCrypto;
/** /**
* The **`Crypto.getRandomValues()`** method lets you get cryptographically strong random values. * The **`Crypto.getRandomValues()`** method lets you get cryptographically strong random values. The array given as the parameter is filled with random numbers (random in its cryptographic meaning).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues)
*/ */
@@ -1055,7 +1068,7 @@ declare abstract class SubtleCrypto {
*/ */
encrypt(algorithm: string | SubtleCryptoEncryptAlgorithm, key: CryptoKey, plainText: ArrayBuffer | ArrayBufferView): Promise<ArrayBuffer>; encrypt(algorithm: string | SubtleCryptoEncryptAlgorithm, key: CryptoKey, plainText: ArrayBuffer | ArrayBufferView): Promise<ArrayBuffer>;
/** /**
* The **`decrypt()`** method of the SubtleCrypto interface decrypts some encrypted data. * The **`decrypt()`** method of the SubtleCrypto interface decrypts some encrypted data. It takes as arguments a key to decrypt with, some optional extra parameters, and the data to decrypt (also known as "ciphertext"). It returns a Promise which will be fulfilled with the decrypted data (also known as "plaintext").
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/decrypt) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/decrypt)
*/ */
@@ -1073,7 +1086,7 @@ declare abstract class SubtleCrypto {
*/ */
verify(algorithm: string | SubtleCryptoSignAlgorithm, key: CryptoKey, signature: ArrayBuffer | ArrayBufferView, data: ArrayBuffer | ArrayBufferView): Promise<boolean>; verify(algorithm: string | SubtleCryptoSignAlgorithm, key: CryptoKey, signature: ArrayBuffer | ArrayBufferView, data: ArrayBuffer | ArrayBufferView): Promise<boolean>;
/** /**
* The **`digest()`** method of the SubtleCrypto interface generates a _digest_ of the given data, using the specified hash function. * The **`digest()`** method of the SubtleCrypto interface generates a digest of the given data, using the specified hash function. A digest is a short fixed-length value derived from some variable-length input. Cryptographic digests should exhibit collision-resistance, meaning that it's hard to come up with two different inputs that have the same digest value.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/digest) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/digest)
*/ */
@@ -1091,7 +1104,7 @@ declare abstract class SubtleCrypto {
*/ */
deriveKey(algorithm: string | SubtleCryptoDeriveKeyAlgorithm, baseKey: CryptoKey, derivedKeyAlgorithm: string | SubtleCryptoImportKeyAlgorithm, extractable: boolean, keyUsages: string[]): Promise<CryptoKey>; deriveKey(algorithm: string | SubtleCryptoDeriveKeyAlgorithm, baseKey: CryptoKey, derivedKeyAlgorithm: string | SubtleCryptoImportKeyAlgorithm, extractable: boolean, keyUsages: string[]): Promise<CryptoKey>;
/** /**
* The **`deriveBits()`** method of the key. * The **`deriveBits()`** method of the SubtleCrypto interface can be used to derive an array of bits from a base key.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/deriveBits) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/deriveBits)
*/ */
@@ -1109,13 +1122,13 @@ declare abstract class SubtleCrypto {
*/ */
exportKey(format: string, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey>; exportKey(format: string, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey>;
/** /**
* The **`wrapKey()`** method of the SubtleCrypto interface 'wraps' a key. * The **`wrapKey()`** method of the SubtleCrypto interface "wraps" a key. This means that it exports the key in an external, portable format, then encrypts the exported key. Wrapping a key helps protect it in untrusted environments, such as inside an otherwise unprotected data store or in transmission over an unprotected network.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/wrapKey) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/wrapKey)
*/ */
wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: string | SubtleCryptoEncryptAlgorithm): Promise<ArrayBuffer>; wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: string | SubtleCryptoEncryptAlgorithm): Promise<ArrayBuffer>;
/** /**
* The **`unwrapKey()`** method of the SubtleCrypto interface 'unwraps' a key. * The **`unwrapKey()`** method of the SubtleCrypto interface "unwraps" a key. This means that it takes as its input a key that has been exported and then encrypted (also called "wrapped"). It decrypts the key and then imports it, returning a CryptoKey object that can be used in the Web Crypto API.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/unwrapKey) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/unwrapKey)
*/ */
@@ -1123,20 +1136,20 @@ declare abstract class SubtleCrypto {
timingSafeEqual(a: ArrayBuffer | ArrayBufferView, b: ArrayBuffer | ArrayBufferView): boolean; timingSafeEqual(a: ArrayBuffer | ArrayBufferView, b: ArrayBuffer | ArrayBufferView): boolean;
} }
/** /**
* The **`CryptoKey`** interface of the Web Crypto API represents a cryptographic key obtained from one of the SubtleCrypto methods SubtleCrypto.generateKey, SubtleCrypto.deriveKey, SubtleCrypto.importKey, or SubtleCrypto.unwrapKey. * The **`CryptoKey`** interface of the Web Crypto API represents a cryptographic key obtained from one of the SubtleCrypto methods generateKey(), deriveKey(), importKey(), or unwrapKey().
* Available only in secure contexts. * Available only in secure contexts.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey)
*/ */
declare abstract class CryptoKey { declare abstract class CryptoKey {
/** /**
* The read-only **`type`** property of the CryptoKey interface indicates which kind of key is represented by the object. * The read-only **`type`** property of the CryptoKey interface indicates which kind of key is represented by the object. It can have the following values:
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/type) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/type)
*/ */
readonly type: string; readonly type: string;
/** /**
* The read-only **`extractable`** property of the CryptoKey interface indicates whether or not the key may be extracted using `SubtleCrypto.exportKey()` or `SubtleCrypto.wrapKey()`. * The read-only **`extractable`** property of the CryptoKey interface indicates whether or not the key may be extracted using SubtleCrypto.exportKey() or SubtleCrypto.wrapKey().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/extractable) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/extractable)
*/ */
@@ -1253,12 +1266,15 @@ interface CryptoKeyArbitraryKeyAlgorithm {
length?: number; length?: number;
} }
declare class DigestStream extends WritableStream<ArrayBuffer | ArrayBufferView> { declare class DigestStream extends WritableStream<ArrayBuffer | ArrayBufferView> {
constructor(algorithm: string | SubtleCryptoHashAlgorithm); constructor(algorithm: string | SubtleCryptoHashAlgorithm, options?: DigestStreamOptions);
readonly digest: Promise<ArrayBuffer>; readonly digest: Promise<ArrayBuffer>;
get bytesWritten(): number | bigint; get bytesWritten(): number | bigint;
} }
interface DigestStreamOptions {
toWellFormed?: boolean;
}
/** /**
* The **`TextDecoder`** interface represents a decoder for a specific text encoding, such as `UTF-8`, `ISO-8859-2`, `KOI8-R`, `GBK`, etc. * The **`TextDecoder`** interface represents a decoder for a specific text encoding, such as UTF-8, ISO-8859-2, or GBK. A decoder takes an array of bytes as input and returns a JavaScript string.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder)
*/ */
@@ -1275,20 +1291,20 @@ declare class TextDecoder {
get ignoreBOM(): boolean; get ignoreBOM(): boolean;
} }
/** /**
* The **`TextEncoder`** interface takes a stream of code points as input and emits a stream of UTF-8 bytes. * The **`TextEncoder`** interface enables you to encode a JavaScript string using UTF-8.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder)
*/ */
declare class TextEncoder { declare class TextEncoder {
constructor(); constructor();
/** /**
* The **`TextEncoder.encode()`** method takes a string as input, and returns a Global_Objects/Uint8Array containing the text given in parameters encoded with the specific method for that TextEncoder object. * The **`TextEncoder.encode()`** method takes a string as input, and returns a Uint8Array containing the string encoded using UTF-8.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode)
*/ */
encode(input?: string): Uint8Array; encode(input?: string): Uint8Array;
/** /**
* The **`TextEncoder.encodeInto()`** method takes a string to encode and a destination Uint8Array to put resulting UTF-8 encoded text into, and returns a dictionary object indicating the progress of the encoding. * The **`TextEncoder.encodeInto()`** method takes a string to encode and a destination Uint8Array to put resulting UTF-8 encoded text into, and returns an object indicating the progress of the encoding. This is potentially more performant than the encode() method — especially when the target buffer is a view into a Wasm heap.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encodeInto) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encodeInto)
*/ */
@@ -1345,6 +1361,9 @@ declare class ErrorEvent extends Event {
get error(): any; get error(): any;
} }
interface ErrorEventErrorEventInit { interface ErrorEventErrorEventInit {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
message?: string; message?: string;
filename?: string; filename?: string;
lineno?: number; lineno?: number;
@@ -1357,135 +1376,139 @@ interface ErrorEventErrorEventInit {
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent)
*/ */
declare class MessageEvent extends Event { declare class MessageEvent extends Event {
constructor(type: string, initializer: MessageEventInit); constructor(type: string, initializer?: MessageEventInit);
/** /**
* The **`data`** read-only property of the The data sent by the message emitter; this can be any data type, depending on what originated this event. * The **`data`** read-only property of the MessageEvent interface represents the data sent by the message emitter.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/data) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/data)
*/ */
readonly data: any; readonly data: any;
/** /**
* The **`origin`** read-only property of the origin of the message emitter. * The **`origin`** read-only property of the MessageEvent interface is a string representing the origin of the message emitter.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/origin) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/origin)
*/ */
readonly origin: string | null; readonly origin: string | null;
/** /**
* The **`lastEventId`** read-only property of the unique ID for the event. * The **`lastEventId`** read-only property of the MessageEvent interface is a string representing a unique ID for the event.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/lastEventId) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/lastEventId)
*/ */
readonly lastEventId: string; readonly lastEventId: string;
/** /**
* The **`source`** read-only property of the a WindowProxy, MessagePort, or a `MessageEventSource` (which can be a WindowProxy, message emitter. * The **`source`** read-only property of the MessageEvent interface is a MessageEventSource (which can be a WindowProxy, MessagePort, or ServiceWorker object) representing the message emitter.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/source) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/source)
*/ */
readonly source: MessagePort | null; readonly source: MessagePort | null;
/** /**
* The **`ports`** read-only property of the containing all MessagePort objects sent with the message, in order. * The **`ports`** read-only property of the MessageEvent interface is an array of MessagePort objects containing all MessagePort objects sent with the message, in order.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/ports) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/ports)
*/ */
readonly ports: MessagePort[]; readonly ports: MessagePort[];
} }
interface MessageEventInit { interface MessageEventInit {
data: ArrayBuffer | string; bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
data?: any;
origin?: string;
lastEventId?: string;
source?: MessagePort;
ports?: MessagePort[];
} }
/** /**
* The **`PromiseRejectionEvent`** interface represents events which are sent to the global script context when JavaScript Promises are rejected. * The **`PromiseRejectionEvent`** interface represents events which are sent to the global script context when JavaScript Promises are rejected. These events are particularly useful for telemetry and debugging purposes.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent)
*/ */
declare abstract class PromiseRejectionEvent extends Event { declare abstract class PromiseRejectionEvent extends Event {
/** /**
* The PromiseRejectionEvent interface's **`promise`** read-only property indicates the JavaScript rejected. * The PromiseRejectionEvent interface's **`promise`** read-only property indicates the JavaScript Promise which was rejected. You can examine the event's PromiseRejectionEvent.reason property to learn why the promise was rejected.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/promise) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/promise)
*/ */
readonly promise: Promise<any>; readonly promise: Promise<any>;
/** /**
* The PromiseRejectionEvent **`reason`** read-only property is any JavaScript value or Object which provides the reason passed into Promise.reject(). * The PromiseRejectionEvent **`reason`** read-only property is any JavaScript value or Object which provides the reason passed into Promise.reject(). This in theory provides information about why the promise was rejected.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/reason) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/reason)
*/ */
readonly reason: any; readonly reason: any;
} }
/** /**
* The **`FormData`** interface provides a way to construct a set of key/value pairs representing form fields and their values, which can be sent using the Window/fetch, XMLHttpRequest.send() or navigator.sendBeacon() methods. * The **`FormData`** interface provides a way to construct a set of key/value pairs representing form fields and their values, which can be sent using the fetch(), XMLHttpRequest.send() or navigator.sendBeacon() methods. It uses the same format a form would use if the encoding type were set to "multipart/form-data".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData)
*/ */
declare class FormData { declare class FormData {
constructor(); constructor();
/** /**
* The **`append()`** method of the FormData interface appends a new value onto an existing key inside a `FormData` object, or adds the key if it does not already exist. * The **`append()`** method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append)
*/ */
append(name: string, value: string | Blob): void; append(name: string, value: string | Blob): void;
/** /**
* The **`append()`** method of the FormData interface appends a new value onto an existing key inside a `FormData` object, or adds the key if it does not already exist. * The **`append()`** method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append)
*/ */
append(name: string, value: string): void; append(name: string, value: string): void;
/** /**
* The **`append()`** method of the FormData interface appends a new value onto an existing key inside a `FormData` object, or adds the key if it does not already exist. * The **`append()`** method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append)
*/ */
append(name: string, value: Blob, filename?: string): void; append(name: string, value: Blob, filename?: string): void;
/** /**
* The **`delete()`** method of the FormData interface deletes a key and its value(s) from a `FormData` object. * The **`delete()`** method of the FormData interface deletes a key and its value(s) from a FormData object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/delete) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/delete)
*/ */
delete(name: string): void; delete(name: string): void;
/** /**
* The **`get()`** method of the FormData interface returns the first value associated with a given key from within a `FormData` object. * The **`get()`** method of the FormData interface returns the first value associated with a given key from within a FormData object. If you expect multiple values and want all of them, use the getAll() method instead.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/get) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/get)
*/ */
get(name: string): (File | string) | null; get(name: string): (File | string) | null;
/** /**
* The **`getAll()`** method of the FormData interface returns all the values associated with a given key from within a `FormData` object. * The **`getAll()`** method of the FormData interface returns all the values associated with a given key from within a FormData object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/getAll) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/getAll)
*/ */
getAll(name: string): (File | string)[]; getAll(name: string): (File | string)[];
/** /**
* The **`has()`** method of the FormData interface returns whether a `FormData` object contains a certain key. * The **`has()`** method of the FormData interface returns whether a FormData object contains a certain key.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/has) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/has)
*/ */
has(name: string): boolean; has(name: string): boolean;
/** /**
* The **`set()`** method of the FormData interface sets a new value for an existing key inside a `FormData` object, or adds the key/value if it does not already exist. * The **`set()`** method of the FormData interface sets a new value for an existing key inside a FormData object, or adds the key/value if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set)
*/ */
set(name: string, value: string | Blob): void; set(name: string, value: string | Blob): void;
/** /**
* The **`set()`** method of the FormData interface sets a new value for an existing key inside a `FormData` object, or adds the key/value if it does not already exist. * The **`set()`** method of the FormData interface sets a new value for an existing key inside a FormData object, or adds the key/value if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set)
*/ */
set(name: string, value: string): void; set(name: string, value: string): void;
/** /**
* The **`set()`** method of the FormData interface sets a new value for an existing key inside a `FormData` object, or adds the key/value if it does not already exist. * The **`set()`** method of the FormData interface sets a new value for an existing key inside a FormData object, or adds the key/value if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set)
*/ */
set(name: string, value: Blob, filename?: string): void; set(name: string, value: Blob, filename?: string): void;
/* Returns an array of key, value pairs for every entry in the list. */
entries(): IterableIterator<[ entries(): IterableIterator<[
key: string, key: string,
value: File | string value: File | string
]>; ]>;
/* Returns a list of keys in the list. */
keys(): IterableIterator<string>; keys(): IterableIterator<string>;
/* Returns a list of values in the list. */
values(): IterableIterator<(File | string)>; values(): IterableIterator<(File | string)>;
forEach<This = unknown>(callback: (this: This, value: File | string, key: string, parent: FormData) => void, thisArg?: This): void; forEach<This = unknown>(callback: (this: This, value: File | string, key: string, parent: FormData) => void, thisArg?: This): void;
[Symbol.iterator](): IterableIterator<[ [Symbol.iterator](): IterableIterator<[
@@ -1564,19 +1587,19 @@ interface DocumentEnd {
append(content: string, options?: ContentOptions): DocumentEnd; append(content: string, options?: ContentOptions): DocumentEnd;
} }
/** /**
* This is the event type for `fetch` events dispatched on the ServiceWorkerGlobalScope. * This is the event type for fetch events dispatched on the service worker global scope. It contains information about the fetch, including the request and how the receiver will treat the response. It provides the event.respondWith() method, which allows us to provide a response to this fetch.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent)
*/ */
declare abstract class FetchEvent extends ExtendableEvent { declare abstract class FetchEvent extends ExtendableEvent {
/** /**
* The **`request`** read-only property of the the event handler. * The **`request`** read-only property of the FetchEvent interface returns the Request that triggered the event handler.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/request) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/request)
*/ */
readonly request: Request; readonly request: Request;
/** /**
* The **`respondWith()`** method of allows you to provide a promise for a Response yourself. * The **`respondWith()`** method of FetchEvent prevents the browser's default fetch handling, and allows you to provide a promise for a Response yourself.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/respondWith) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/respondWith)
*/ */
@@ -1585,65 +1608,62 @@ declare abstract class FetchEvent extends ExtendableEvent {
} }
type HeadersInit = Headers | Iterable<Iterable<string>> | Record<string, string>; type HeadersInit = Headers | Iterable<Iterable<string>> | Record<string, string>;
/** /**
* The **`Headers`** interface of the Fetch API allows you to perform various actions on HTTP request and response headers. * The **`Headers`** interface of the Fetch API allows you to perform various actions on HTTP request and response headers. These actions include retrieving, setting, adding to, and removing headers from the list of the request's headers.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers)
*/ */
declare class Headers { declare class Headers {
constructor(init?: HeadersInit); constructor(init?: HeadersInit);
/** /**
* The **`get()`** method of the Headers interface returns a byte string of all the values of a header within a `Headers` object with a given name. * The **`get()`** method of the Headers interface returns a byte string of all the values of a header within a Headers object with a given name. If the requested header doesn't exist in the Headers object, it returns null.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/get) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/get)
*/ */
get(name: string): string | null; get(name: string): string | null;
getAll(name: string): string[]; getAll(name: string): string[];
/** /**
* The **`getSetCookie()`** method of the Headers interface returns an array containing the values of all Set-Cookie headers associated with a response. * The **`getSetCookie()`** method of the Headers interface returns an array containing the values of all Set-Cookie headers associated with a response. This allows Headers objects to handle having multiple Set-Cookie headers, which wasn't possible prior to its implementation.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/getSetCookie) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/getSetCookie)
*/ */
getSetCookie(): string[]; getSetCookie(): string[];
/** /**
* The **`has()`** method of the Headers interface returns a boolean stating whether a `Headers` object contains a certain header. * The **`has()`** method of the Headers interface returns a boolean stating whether a Headers object contains a certain header.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/has) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/has)
*/ */
has(name: string): boolean; has(name: string): boolean;
/** /**
* The **`set()`** method of the Headers interface sets a new value for an existing header inside a `Headers` object, or adds the header if it does not already exist. * The **`set()`** method of the Headers interface sets a new value for an existing header inside a Headers object, or adds the header if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/set)
*/ */
set(name: string, value: string): void; set(name: string, value: string): void;
/** /**
* The **`append()`** method of the Headers interface appends a new value onto an existing header inside a `Headers` object, or adds the header if it does not already exist. * The **`append()`** method of the Headers interface appends a new value onto an existing header inside a Headers object, or adds the header if it does not already exist.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/append) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/append)
*/ */
append(name: string, value: string): void; append(name: string, value: string): void;
/** /**
* The **`delete()`** method of the Headers interface deletes a header from the current `Headers` object. * The **`delete()`** method of the Headers interface deletes a header from the current Headers object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/delete) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/delete)
*/ */
delete(name: string): void; delete(name: string): void;
forEach<This = unknown>(callback: (this: This, value: string, key: string, parent: Headers) => void, thisArg?: This): void; forEach<This = unknown>(callback: (this: This, value: string, key: string, parent: Headers) => void, thisArg?: This): void;
/* Returns an iterator allowing to go through all key/value pairs contained in this object. */
entries(): IterableIterator<[ entries(): IterableIterator<[
key: string, key: string,
value: string value: string
]>; ]>;
/* Returns an iterator allowing to go through all keys of the key/value pairs contained in this object. */
keys(): IterableIterator<string>; keys(): IterableIterator<string>;
/* Returns an iterator allowing to go through all values of the key/value pairs contained in this object. */
values(): IterableIterator<string>; values(): IterableIterator<string>;
[Symbol.iterator](): IterableIterator<[ [Symbol.iterator](): IterableIterator<[
key: string, key: string,
value: string value: string
]>; ]>;
} }
type BodyInit = ReadableStream<Uint8Array> | string | ArrayBuffer | ArrayBufferView | Blob | URLSearchParams | FormData; type BodyInit = ReadableStream<Uint8Array> | string | ArrayBuffer | ArrayBufferView | Blob | URLSearchParams | FormData | Iterable<ArrayBuffer | ArrayBufferView> | AsyncIterable<ArrayBuffer | ArrayBufferView>;
declare abstract class Body { declare abstract class Body {
/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body) */ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body) */
get body(): ReadableStream | null; get body(): ReadableStream | null;
@@ -1699,7 +1719,7 @@ interface Response extends Body {
*/ */
statusText: string; statusText: string;
/** /**
* The **`headers`** read-only property of the with the response. * The **`headers`** read-only property of the Response interface contains the Headers object associated with the response.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers)
*/ */
@@ -1717,7 +1737,7 @@ interface Response extends Body {
*/ */
redirected: boolean; redirected: boolean;
/** /**
* The **`url`** read-only property of the Response interface contains the URL of the response. * The **`url`** read-only property of the Response interface contains the URL of the response. The value of the url property will be the final URL obtained after any redirects.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/url) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/url)
*/ */
@@ -1725,7 +1745,7 @@ interface Response extends Body {
webSocket: WebSocket | null; webSocket: WebSocket | null;
cf: any | undefined; cf: any | undefined;
/** /**
* The **`type`** read-only property of the Response interface contains the type of the response. * The **`type`** read-only property of the Response interface contains the type of the response. The type determines whether scripts are able to access the response body and headers.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/type) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/type)
*/ */
@@ -1756,13 +1776,13 @@ declare var Request: {
*/ */
interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> extends Body { interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> extends Body {
/** /**
* The **`clone()`** method of the Request interface creates a copy of the current `Request` object. * The **`clone()`** method of the Request interface creates a copy of the current Request object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/clone) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/clone)
*/ */
clone(): Request<CfHostMetadata, Cf>; clone(): Request<CfHostMetadata, Cf>;
/** /**
* The **`method`** read-only property of the `POST`, etc.) A String indicating the method of the request. * The **`method`** read-only property of the Request interface contains the request's method (GET, POST, etc.)
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/method) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/method)
*/ */
@@ -1774,7 +1794,7 @@ interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> e
*/ */
url: string; url: string;
/** /**
* The **`headers`** read-only property of the with the request. * The **`headers`** read-only property of the Request interface contains the Headers object associated with the request.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/headers) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/headers)
*/ */
@@ -1800,13 +1820,13 @@ interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> e
*/ */
integrity: string; integrity: string;
/** /**
* The **`keepalive`** read-only property of the Request interface contains the request's `keepalive` setting (`true` or `false`), which indicates whether the browser will keep the associated request alive if the page that initiated it is unloaded before the request is complete. * The **`keepalive`** read-only property of the Request interface contains the request's keepalive setting (true or false), which indicates whether the browser will keep the associated request alive if the page that initiated it is unloaded before the request is complete.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/keepalive) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/keepalive)
*/ */
keepalive: boolean; keepalive: boolean;
/** /**
* The **`cache`** read-only property of the Request interface contains the cache mode of the request. * The **`cache`** read-only property of the Request interface contains the cache mode of the request. It controls how the request will interact with the browser's HTTP cache.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/cache) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/cache)
*/ */
@@ -2195,7 +2215,7 @@ type ReadableStreamReadResult<R = any> = {
value?: undefined; value?: undefined;
}; };
/** /**
* The `ReadableStream` interface of the Streams API represents a readable stream of byte data. * The **`ReadableStream`** interface of the Streams API represents a readable stream of byte data. The Fetch API offers a concrete instance of a ReadableStream through the body property of a Response object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream)
*/ */
@@ -2213,13 +2233,13 @@ interface ReadableStream<R = any> {
*/ */
cancel(reason?: any): Promise<void>; cancel(reason?: any): Promise<void>;
/** /**
* The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. * The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. While the stream is locked, no other reader can be acquired until this one is released.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader)
*/ */
getReader(): ReadableStreamDefaultReader<R>; getReader(): ReadableStreamDefaultReader<R>;
/** /**
* The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. * The **`getReader()`** method of the ReadableStream interface creates a reader and locks the stream to it. While the stream is locked, no other reader can be acquired until this one is released.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader)
*/ */
@@ -2231,13 +2251,13 @@ interface ReadableStream<R = any> {
*/ */
pipeThrough<T>(transform: ReadableWritablePair<T, R>, options?: StreamPipeOptions): ReadableStream<T>; pipeThrough<T>(transform: ReadableWritablePair<T, R>, options?: StreamPipeOptions): ReadableStream<T>;
/** /**
* The **`pipeTo()`** method of the ReadableStream interface pipes the current `ReadableStream` to a given WritableStream and returns a Promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered. * The **`pipeTo()`** method of the ReadableStream interface pipes the current ReadableStream to a given WritableStream and returns a Promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/pipeTo) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/pipeTo)
*/ */
pipeTo(destination: WritableStream<R>, options?: StreamPipeOptions): Promise<void>; pipeTo(destination: WritableStream<R>, options?: StreamPipeOptions): Promise<void>;
/** /**
* The **`tee()`** method of the two-element array containing the two resulting branches as new ReadableStream instances. * The **`tee()`** method of the ReadableStream interface tees the current readable stream, returning a two-element array containing the two resulting branches as new ReadableStream instances.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/tee) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/tee)
*/ */
@@ -2249,7 +2269,7 @@ interface ReadableStream<R = any> {
[Symbol.asyncIterator](options?: ReadableStreamValuesOptions): AsyncIterableIterator<R>; [Symbol.asyncIterator](options?: ReadableStreamValuesOptions): AsyncIterableIterator<R>;
} }
/** /**
* The `ReadableStream` interface of the Streams API represents a readable stream of byte data. * The **`ReadableStream`** interface of the Streams API represents a readable stream of byte data. The Fetch API offers a concrete instance of a ReadableStream through the body property of a Response object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream)
*/ */
@@ -2281,7 +2301,7 @@ declare class ReadableStreamDefaultReader<R = any> {
releaseLock(): void; releaseLock(): void;
} }
/** /**
* The `ReadableStreamBYOBReader` interface of the Streams API defines a reader for a ReadableStream that supports zero-copy reading from an underlying byte source. * The **`ReadableStreamBYOBReader`** interface of the Streams API defines a reader for a ReadableStream that supports zero-copy reading from an underlying byte source. It is used for efficient copying from underlying sources where the data is delivered as an "anonymous" sequence of bytes, such as files.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader)
*/ */
@@ -2290,13 +2310,13 @@ declare class ReadableStreamBYOBReader {
get closed(): Promise<void>; get closed(): Promise<void>;
cancel(reason?: any): Promise<void>; cancel(reason?: any): Promise<void>;
/** /**
* The **`read()`** method of the ReadableStreamBYOBReader interface is used to read data into a view on a user-supplied buffer from an associated readable byte stream. * The **`read()`** method of the ReadableStreamBYOBReader interface is used to read data into a view on a user-supplied buffer from an associated readable byte stream. A request for data will be satisfied from the stream's internal queues if there is any data present. If the stream queues are empty, the request may be supplied as a zero-copy transfer from the underlying byte source.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/read) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/read)
*/ */
read<T extends ArrayBufferView>(view: T): Promise<ReadableStreamReadResult<T>>; read<T extends ArrayBufferView>(view: T): Promise<ReadableStreamReadResult<T>>;
/** /**
* The **`releaseLock()`** method of the ReadableStreamBYOBReader interface releases the reader's lock on the stream. * The **`releaseLock()`** method of the ReadableStreamBYOBReader interface releases the reader's lock on the stream. After the lock is released, the reader is no longer active.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/releaseLock) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/releaseLock)
*/ */
@@ -2315,7 +2335,7 @@ interface ReadableStreamGetReaderOptions {
mode: "byob"; mode: "byob";
} }
/** /**
* The **`ReadableStreamBYOBRequest`** interface of the Streams API represents a 'pull request' for data from an underlying source that will made as a zero-copy transfer to a consumer (bypassing the stream's internal queues). * The **`ReadableStreamBYOBRequest`** interface of the Streams API represents a "pull request" for data from an underlying source that will made as a zero-copy transfer to a consumer (bypassing the stream's internal queues).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest)
*/ */
@@ -2341,13 +2361,13 @@ declare abstract class ReadableStreamBYOBRequest {
get atLeast(): number | null; get atLeast(): number | null;
} }
/** /**
* The **`ReadableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a ReadableStream's state and internal queue. * The **`ReadableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a ReadableStream's state and internal queue. Default controllers are for streams that are not byte streams.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController)
*/ */
declare abstract class ReadableStreamDefaultController<R = any> { declare abstract class ReadableStreamDefaultController<R = any> {
/** /**
* The **`desiredSize`** read-only property of the required to fill the stream's internal queue. * The **`desiredSize`** read-only property of the ReadableStreamDefaultController interface returns the desired size required to fill the stream's internal queue.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/desiredSize) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/desiredSize)
*/ */
@@ -2359,32 +2379,32 @@ declare abstract class ReadableStreamDefaultController<R = any> {
*/ */
close(): void; close(): void;
/** /**
* The **`enqueue()`** method of the ```js-nolint enqueue(chunk) ``` - `chunk` - : The chunk to enqueue. * The **`enqueue()`** method of the ReadableStreamDefaultController interface enqueues a given chunk in the associated stream.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/enqueue) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/enqueue)
*/ */
enqueue(chunk?: R): void; enqueue(chunk?: R): void;
/** /**
* The **`error()`** method of the with the associated stream to error. * The **`error()`** method of the ReadableStreamDefaultController interface causes any future interactions with the associated stream to error.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/error) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/error)
*/ */
error(reason: any): void; error(reason: any): void;
} }
/** /**
* The **`ReadableByteStreamController`** interface of the Streams API represents a controller for a readable byte stream. * The **`ReadableByteStreamController`** interface of the Streams API represents a controller for a readable byte stream. It allows control of the state and internal queue of a ReadableStream with an underlying byte source, and enables efficient zero-copy transfer of data from the underlying source to a consumer when the stream's internal queue is empty.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController)
*/ */
declare abstract class ReadableByteStreamController { declare abstract class ReadableByteStreamController {
/** /**
* The **`byobRequest`** read-only property of the ReadableByteStreamController interface returns the current BYOB request, or `null` if there are no pending requests. * The **`byobRequest`** read-only property of the ReadableByteStreamController interface returns the current BYOB request, or null if there are no pending requests.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/byobRequest) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/byobRequest)
*/ */
get byobRequest(): ReadableStreamBYOBRequest | null; get byobRequest(): ReadableStreamBYOBRequest | null;
/** /**
* The **`desiredSize`** read-only property of the ReadableByteStreamController interface returns the number of bytes required to fill the stream's internal queue to its 'desired size'. * The **`desiredSize`** read-only property of the ReadableByteStreamController interface returns the number of bytes required to fill the stream's internal queue to its "desired size".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/desiredSize) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/desiredSize)
*/ */
@@ -2396,7 +2416,7 @@ declare abstract class ReadableByteStreamController {
*/ */
close(): void; close(): void;
/** /**
* The **`enqueue()`** method of the ReadableByteStreamController interface enqueues a given chunk on the associated readable byte stream (the chunk is copied into the stream's internal queues). * The **`enqueue()`** method of the ReadableByteStreamController interface enqueues a given chunk on the associated readable byte stream (the chunk is transferred into the stream's internal queues).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/enqueue) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/enqueue)
*/ */
@@ -2409,7 +2429,7 @@ declare abstract class ReadableByteStreamController {
error(reason: any): void; error(reason: any): void;
} }
/** /**
* The **`WritableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a WritableStream's state. * The **`WritableStreamDefaultController`** interface of the Streams API represents a controller allowing control of a WritableStream's state. When constructing a WritableStream, the underlying sink is given a corresponding WritableStreamDefaultController instance to manipulate.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController)
*/ */
@@ -2421,7 +2441,7 @@ declare abstract class WritableStreamDefaultController {
*/ */
get signal(): AbortSignal; get signal(): AbortSignal;
/** /**
* The **`error()`** method of the with the associated stream to error. * The **`error()`** method of the WritableStreamDefaultController interface causes any future interactions with the associated stream to error.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController/error) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController/error)
*/ */
@@ -2446,7 +2466,7 @@ declare abstract class TransformStreamDefaultController<O = any> {
*/ */
enqueue(chunk?: O): void; enqueue(chunk?: O): void;
/** /**
* The **`error()`** method of the TransformStreamDefaultController interface errors both sides of the stream. * The **`error()`** method of the TransformStreamDefaultController interface errors both sides of the stream. Any further interactions with it will fail with the given error message, and any chunks in the queue will be discarded.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/error) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/error)
*/ */
@@ -2468,14 +2488,14 @@ interface ReadableWritablePair<R = any, W = any> {
writable: WritableStream<W>; writable: WritableStream<W>;
} }
/** /**
* The **`WritableStream`** interface of the Streams API provides a standard abstraction for writing streaming data to a destination, known as a sink. * The **`WritableStream`** interface of the Streams API provides a standard abstraction for writing streaming data to a destination, known as a sink. This object comes with built-in backpressure and queuing.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream)
*/ */
declare class WritableStream<W = any> { declare class WritableStream<W = any> {
constructor(underlyingSink?: UnderlyingSink, queuingStrategy?: QueuingStrategy); constructor(underlyingSink?: UnderlyingSink, queuingStrategy?: QueuingStrategy);
/** /**
* The **`locked`** read-only property of the WritableStream interface returns a boolean indicating whether the `WritableStream` is locked to a writer. * The **`locked`** read-only property of the WritableStream interface returns a boolean indicating whether the WritableStream is locked to a writer.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/locked) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/locked)
*/ */
@@ -2487,83 +2507,83 @@ declare class WritableStream<W = any> {
*/ */
abort(reason?: any): Promise<void>; abort(reason?: any): Promise<void>;
/** /**
* The **`close()`** method of the WritableStream interface closes the associated stream. * The **`close()`** method of the WritableStream interface closes the associated stream. All chunks written before this method is called are sent before the returned promise is fulfilled.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/close)
*/ */
close(): Promise<void>; close(): Promise<void>;
/** /**
* The **`getWriter()`** method of the WritableStream interface returns a new instance of WritableStreamDefaultWriter and locks the stream to that instance. * The **`getWriter()`** method of the WritableStream interface returns a new instance of WritableStreamDefaultWriter and locks the stream to that instance. While the stream is locked, no other writer can be acquired until this one is released.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/getWriter) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/getWriter)
*/ */
getWriter(): WritableStreamDefaultWriter<W>; getWriter(): WritableStreamDefaultWriter<W>;
} }
/** /**
* The **`WritableStreamDefaultWriter`** interface of the Streams API is the object returned by WritableStream.getWriter() and once created locks the writer to the `WritableStream` ensuring that no other streams can write to the underlying sink. * The **`WritableStreamDefaultWriter`** interface of the Streams API is the object returned by WritableStream.getWriter() and once created locks the writer to the WritableStream ensuring that no other streams can write to the underlying sink.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter)
*/ */
declare class WritableStreamDefaultWriter<W = any> { declare class WritableStreamDefaultWriter<W = any> {
constructor(stream: WritableStream); constructor(stream: WritableStream);
/** /**
* The **`closed`** read-only property of the the stream errors or the writer's lock is released. * The **`closed`** read-only property of the WritableStreamDefaultWriter interface returns a Promise that fulfills if the stream becomes closed, or rejects if the stream errors or the writer's lock is released.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/closed) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/closed)
*/ */
get closed(): Promise<void>; get closed(): Promise<void>;
/** /**
* The **`ready`** read-only property of the that resolves when the desired size of the stream's internal queue transitions from non-positive to positive, signaling that it is no longer applying backpressure. * The **`ready`** read-only property of the WritableStreamDefaultWriter interface returns a Promise that resolves when the desired size of the stream's internal queue transitions from non-positive to positive, signaling that it is no longer applying backpressure.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/ready) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/ready)
*/ */
get ready(): Promise<void>; get ready(): Promise<void>;
/** /**
* The **`desiredSize`** read-only property of the to fill the stream's internal queue. * The **`desiredSize`** read-only property of the WritableStreamDefaultWriter interface returns the desired size required to fill the stream's internal queue.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/desiredSize) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/desiredSize)
*/ */
get desiredSize(): number | null; get desiredSize(): number | null;
/** /**
* The **`abort()`** method of the the producer can no longer successfully write to the stream and it is to be immediately moved to an error state, with any queued writes discarded. * The **`abort()`** method of the WritableStreamDefaultWriter interface aborts the stream, signaling that the producer can no longer successfully write to the stream and it is to be immediately moved to an error state, with any queued writes discarded.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/abort) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/abort)
*/ */
abort(reason?: any): Promise<void>; abort(reason?: any): Promise<void>;
/** /**
* The **`close()`** method of the stream. * The **`close()`** method of the WritableStreamDefaultWriter interface closes the associated writable stream.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/close)
*/ */
close(): Promise<void>; close(): Promise<void>;
/** /**
* The **`write()`** method of the operation. * The **`write()`** method of the WritableStreamDefaultWriter interface writes a passed chunk of data to a WritableStream and its underlying sink, then returns a Promise that resolves to indicate the success or failure of the write operation.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/write) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/write)
*/ */
write(chunk?: W): Promise<void>; write(chunk?: W): Promise<void>;
/** /**
* The **`releaseLock()`** method of the corresponding stream. * The **`releaseLock()`** method of the WritableStreamDefaultWriter interface releases the writer's lock on the corresponding stream. After the lock is released, the writer is no longer active. If the associated stream is errored when the lock is released, the writer will appear errored in the same way from now on; otherwise, the writer will appear closed.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/releaseLock) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/releaseLock)
*/ */
releaseLock(): void; releaseLock(): void;
} }
/** /**
* The **`TransformStream`** interface of the Streams API represents a concrete implementation of the pipe chain _transform stream_ concept. * The **`TransformStream`** interface of the Streams API represents a concrete implementation of the pipe chain transform stream concept.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream)
*/ */
declare class TransformStream<I = any, O = any> { declare class TransformStream<I = any, O = any> {
constructor(transformer?: Transformer<I, O>, writableStrategy?: QueuingStrategy<I>, readableStrategy?: QueuingStrategy<O>); constructor(transformer?: Transformer<I, O>, writableStrategy?: QueuingStrategy<I>, readableStrategy?: QueuingStrategy<O>);
/** /**
* The **`readable`** read-only property of the TransformStream interface returns the ReadableStream instance controlled by this `TransformStream`. * The **`readable`** read-only property of the TransformStream interface returns the ReadableStream instance controlled by this TransformStream. This stream emits the transformed output data.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/readable) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/readable)
*/ */
get readable(): ReadableStream<O>; get readable(): ReadableStream<O>;
/** /**
* The **`writable`** read-only property of the TransformStream interface returns the WritableStream instance controlled by this `TransformStream`. * The **`writable`** read-only property of the TransformStream interface returns the WritableStream instance controlled by this TransformStream. This stream accepts input data that will be transformed and emitted to the readable stream.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/writable) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/writable)
*/ */
@@ -2582,7 +2602,7 @@ interface ReadableStreamValuesOptions {
preventCancel?: boolean; preventCancel?: boolean;
} }
/** /**
* The **`CompressionStream`** interface of the Compression Streams API is an API for compressing a stream of data. * The **`CompressionStream`** interface of the Compression Streams API compresses a stream of data. It implements the same shape as a TransformStream, allowing it to be used in ReadableStream.pipeThrough() and similar methods.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CompressionStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CompressionStream)
*/ */
@@ -2590,7 +2610,7 @@ declare class CompressionStream extends TransformStream<ArrayBuffer | ArrayBuffe
constructor(format: "gzip" | "deflate" | "deflate-raw"); constructor(format: "gzip" | "deflate" | "deflate-raw");
} }
/** /**
* The **`DecompressionStream`** interface of the Compression Streams API is an API for decompressing a stream of data. * The **`DecompressionStream`** interface of the Compression Streams API decompresses a stream of data. It implements the same shape as a TransformStream, allowing it to be used in ReadableStream.pipeThrough() and similar methods.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DecompressionStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DecompressionStream)
*/ */
@@ -2598,7 +2618,7 @@ declare class DecompressionStream extends TransformStream<ArrayBuffer | ArrayBuf
constructor(format: "gzip" | "deflate" | "deflate-raw"); constructor(format: "gzip" | "deflate" | "deflate-raw");
} }
/** /**
* The **`TextEncoderStream`** interface of the Encoding API converts a stream of strings into bytes in the UTF-8 encoding. * The **`TextEncoderStream`** interface of the Encoding API converts a stream of strings into bytes in the UTF-8 encoding. It is the streaming equivalent of TextEncoder. It implements the same shape as a TransformStream, allowing it to be used in ReadableStream.pipeThrough() and similar methods.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoderStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoderStream)
*/ */
@@ -2607,7 +2627,7 @@ declare class TextEncoderStream extends TransformStream<string, Uint8Array> {
get encoding(): string; get encoding(): string;
} }
/** /**
* The **`TextDecoderStream`** interface of the Encoding API converts a stream of text in a binary encoding, such as UTF-8 etc., to a stream of strings. * The **`TextDecoderStream`** interface of the Encoding API converts a stream of text in a binary encoding, such as UTF-8 etc., to a stream of strings. It is the streaming equivalent of TextDecoder. It implements the same shape as a TransformStream, allowing it to be used in ReadableStream.pipeThrough() and similar methods.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoderStream) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoderStream)
*/ */
@@ -2756,6 +2776,12 @@ interface TraceLog {
readonly timestamp: number; readonly timestamp: number;
readonly level: string; readonly level: string;
readonly message: any; readonly message: any;
readonly errorInfo?: (TraceLogErrorInfo | null)[];
}
interface TraceLogErrorInfo {
name: string;
message: string;
stack?: string;
} }
interface TraceException { interface TraceException {
readonly timestamp: number; readonly timestamp: number;
@@ -2776,7 +2802,7 @@ interface UnsafeTraceMetrics {
fromTrace(item: TraceItem): TraceMetrics; fromTrace(item: TraceItem): TraceMetrics;
} }
/** /**
* The **`URL`** interface is used to parse, construct, normalize, and encode URL. * The **`URL`** interface is used to parse, construct, normalize, and encode URLs. It works by providing properties which allow you to easily read and modify the components of a URL.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL)
*/ */
@@ -2801,121 +2827,121 @@ declare class URL {
*/ */
set href(value: string); set href(value: string);
/** /**
* The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final `':'`. * The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final ":".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol)
*/ */
get protocol(): string; get protocol(): string;
/** /**
* The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final `':'`. * The **`protocol`** property of the URL interface is a string containing the protocol or scheme of the URL, including the final ":".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol)
*/ */
set protocol(value: string); set protocol(value: string);
/** /**
* The **`username`** property of the URL interface is a string containing the username component of the URL. * The **`username`** property of the URL interface is a string containing the username component of the URL. If the URL does not have a username, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username)
*/ */
get username(): string; get username(): string;
/** /**
* The **`username`** property of the URL interface is a string containing the username component of the URL. * The **`username`** property of the URL interface is a string containing the username component of the URL. If the URL does not have a username, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username)
*/ */
set username(value: string); set username(value: string);
/** /**
* The **`password`** property of the URL interface is a string containing the password component of the URL. * The **`password`** property of the URL interface is a string containing the password component of the URL. If the URL does not have a password, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password)
*/ */
get password(): string; get password(): string;
/** /**
* The **`password`** property of the URL interface is a string containing the password component of the URL. * The **`password`** property of the URL interface is a string containing the password component of the URL. If the URL does not have a password, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password)
*/ */
set password(value: string); set password(value: string);
/** /**
* The **`host`** property of the URL interface is a string containing the host, which is the URL.hostname, and then, if the port of the URL is nonempty, a `':'`, followed by the URL.port of the URL. * The **`host`** property of the URL interface is a string containing the host, which is the hostname, and then, if the port of the URL is nonempty, a ":", followed by the port of the URL. If the URL does not have a hostname, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host)
*/ */
get host(): string; get host(): string;
/** /**
* The **`host`** property of the URL interface is a string containing the host, which is the URL.hostname, and then, if the port of the URL is nonempty, a `':'`, followed by the URL.port of the URL. * The **`host`** property of the URL interface is a string containing the host, which is the hostname, and then, if the port of the URL is nonempty, a ":", followed by the port of the URL. If the URL does not have a hostname, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host)
*/ */
set host(value: string); set host(value: string);
/** /**
* The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. * The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. If the URL does not have a hostname, this property contains an empty string, "". IPv4 and IPv6 addresses are normalized, such as stripping leading zeros, and domain names are converted to IDN.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname)
*/ */
get hostname(): string; get hostname(): string;
/** /**
* The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. * The **`hostname`** property of the URL interface is a string containing either the domain name or IP address of the URL. If the URL does not have a hostname, this property contains an empty string, "". IPv4 and IPv6 addresses are normalized, such as stripping leading zeros, and domain names are converted to IDN.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname)
*/ */
set hostname(value: string); set hostname(value: string);
/** /**
* The **`port`** property of the URL interface is a string containing the port number of the URL. * The **`port`** property of the URL interface is a string containing the port number of the URL. If the port is the default for the protocol (80 for ws: and http:, 443 for wss: and https:, and 21 for ftp:), this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port)
*/ */
get port(): string; get port(): string;
/** /**
* The **`port`** property of the URL interface is a string containing the port number of the URL. * The **`port`** property of the URL interface is a string containing the port number of the URL. If the port is the default for the protocol (80 for ws: and http:, 443 for wss: and https:, and 21 for ftp:), this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port)
*/ */
set port(value: string); set port(value: string);
/** /**
* The **`pathname`** property of the URL interface represents a location in a hierarchical structure. * The **`pathname`** property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname)
*/ */
get pathname(): string; get pathname(): string;
/** /**
* The **`pathname`** property of the URL interface represents a location in a hierarchical structure. * The **`pathname`** property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname)
*/ */
set pathname(value: string); set pathname(value: string);
/** /**
* The **`search`** property of the URL interface is a search string, also called a _query string_, that is a string containing a `'?'` followed by the parameters of the URL. * The **`search`** property of the URL interface is a search string, also called a query string, that is a string containing a "?" followed by the parameters of the URL. If the URL does not have a search query, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search)
*/ */
get search(): string; get search(): string;
/** /**
* The **`search`** property of the URL interface is a search string, also called a _query string_, that is a string containing a `'?'` followed by the parameters of the URL. * The **`search`** property of the URL interface is a search string, also called a query string, that is a string containing a "?" followed by the parameters of the URL. If the URL does not have a search query, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search)
*/ */
set search(value: string); set search(value: string);
/** /**
* The **`hash`** property of the URL interface is a string containing a `'#'` followed by the fragment identifier of the URL. * The **`hash`** property of the URL interface is a string containing a "#" followed by the fragment identifier of the URL. If the URL does not have a fragment identifier, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash)
*/ */
get hash(): string; get hash(): string;
/** /**
* The **`hash`** property of the URL interface is a string containing a `'#'` followed by the fragment identifier of the URL. * The **`hash`** property of the URL interface is a string containing a "#" followed by the fragment identifier of the URL. If the URL does not have a fragment identifier, this property contains an empty string, "".
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash)
*/ */
set hash(value: string); set hash(value: string);
/** /**
* The **`searchParams`** read-only property of the access to the [MISSING: httpmethod('GET')] decoded query arguments contained in the URL. * The **`searchParams`** read-only property of the URL interface returns a URLSearchParams object allowing access to the GET decoded query arguments contained in the URL.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/searchParams) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/searchParams)
*/ */
get searchParams(): URLSearchParams; get searchParams(): URLSearchParams;
/** /**
* The **`toJSON()`** method of the URL interface returns a string containing a serialized version of the URL, although in practice it seems to have the same effect as ```js-nolint toJSON() ``` None. * The **`toJSON()`** method of the URL interface returns a string containing a serialized version of the URL, although in practice it seems to have the same effect as URL.toString().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/toJSON) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/toJSON)
*/ */
@@ -2935,13 +2961,13 @@ declare class URL {
*/ */
static parse(url: string, base?: string): URL | null; static parse(url: string, base?: string): URL | null;
/** /**
* The **`createObjectURL()`** static method of the URL interface creates a string containing a URL representing the object given in the parameter. * The **`createObjectURL()`** static method of the URL interface creates a string containing a blob URL pointing to the object given in the parameter.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static)
*/ */
static createObjectURL(object: File | Blob): string; static createObjectURL(object: File | Blob): string;
/** /**
* The **`revokeObjectURL()`** static method of the URL interface releases an existing object URL which was previously created by calling Call this method when you've finished using an object URL to let the browser know not to keep the reference to the file any longer. * The **`revokeObjectURL()`** static method of the URL interface releases an existing object URL which was previously created by calling URL.createObjectURL().
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static)
*/ */
@@ -2991,25 +3017,22 @@ declare class URLSearchParams {
*/ */
has(name: string, value?: string): boolean; has(name: string, value?: string): boolean;
/** /**
* The **`set()`** method of the URLSearchParams interface sets the value associated with a given search parameter to the given value. * The **`set()`** method of the URLSearchParams interface sets the value associated with a given search parameter to the given value. If there were several matching values, this method deletes the others. If the search parameter doesn't exist, this method creates it.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/set) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/set)
*/ */
set(name: string, value: string): void; set(name: string, value: string): void;
/** /**
* The **`URLSearchParams.sort()`** method sorts all key/value pairs contained in this object in place and returns `undefined`. * The **`URLSearchParams.sort()`** method sorts all key/value pairs contained in this object in place and returns undefined. Key/value pairs are sorted by the values of the UTF-16 code units of the keys. This method uses a stable sorting algorithm (i.e., the relative order between key/value pairs with equal keys will be preserved).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/sort) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/sort)
*/ */
sort(): void; sort(): void;
/* Returns an array of key, value pairs for every entry in the search params. */
entries(): IterableIterator<[ entries(): IterableIterator<[
key: string, key: string,
value: string value: string
]>; ]>;
/* Returns a list of keys in the search params. */
keys(): IterableIterator<string>; keys(): IterableIterator<string>;
/* Returns a list of values in the search params. */
values(): IterableIterator<string>; values(): IterableIterator<string>;
forEach<This = unknown>(callback: (this: This, value: string, key: string, parent: URLSearchParams) => void, thisArg?: This): void; forEach<This = unknown>(callback: (this: This, value: string, key: string, parent: URLSearchParams) => void, thisArg?: This): void;
/*function toString() { [native code] }*/ /*function toString() { [native code] }*/
@@ -3019,18 +3042,78 @@ declare class URLSearchParams {
value: string value: string
]>; ]>;
} }
/**
* The **`URLPattern`** interface of the URL Pattern API matches URLs or parts of URLs against a pattern. The pattern can contain capturing groups that extract parts of the matched URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern)
*/
declare class URLPattern { declare class URLPattern {
constructor(input?: (string | URLPatternInit), baseURL?: (string | URLPatternOptions), patternOptions?: URLPatternOptions); constructor(input?: (string | URLPatternInit), baseURL?: (string | URLPatternOptions), patternOptions?: URLPatternOptions);
/**
* The **`protocol`** read-only property of the URLPattern interface is a string containing the pattern used to match the protocol part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/protocol)
*/
get protocol(): string; get protocol(): string;
/**
* The **`username`** read-only property of the URLPattern interface is a string containing the pattern used to match the username part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/username)
*/
get username(): string; get username(): string;
/**
* The **`password`** read-only property of the URLPattern interface is a string containing the pattern used to match the password part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/password)
*/
get password(): string; get password(): string;
/**
* The **`hostname`** read-only property of the URLPattern interface is a string containing the pattern used to match the hostname part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/hostname)
*/
get hostname(): string; get hostname(): string;
/**
* The **`port`** read-only property of the URLPattern interface is a string containing the pattern used to match the port part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/port)
*/
get port(): string; get port(): string;
/**
* The **`pathname`** read-only property of the URLPattern interface is a string containing the pattern used to match the pathname part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/pathname)
*/
get pathname(): string; get pathname(): string;
/**
* The **`search`** read-only property of the URLPattern interface is a string containing the pattern used to match the search part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/search)
*/
get search(): string; get search(): string;
/**
* The **`hash`** read-only property of the URLPattern interface is a string containing the pattern used to match the fragment part of a URL.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/hash)
*/
get hash(): string; get hash(): string;
/**
* The **`hasRegExpGroups`** read-only property of the URLPattern interface is a boolean indicating whether or not any of the URLPattern components contain regular expression capturing groups.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/hasRegExpGroups)
*/
get hasRegExpGroups(): boolean; get hasRegExpGroups(): boolean;
/**
* The **`test()`** method of the URLPattern interface takes a URL string or object of URL parts, and returns a boolean indicating if the given input matches the current pattern.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/test)
*/
test(input?: (string | URLPatternInit), baseURL?: string): boolean; test(input?: (string | URLPatternInit), baseURL?: string): boolean;
/**
* The **`exec()`** method of the URLPattern interface takes a URL or object of URL parts, and returns either an object containing the results of matching the URL to the pattern, or null if the URL does not match the pattern.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLPattern/exec)
*/
exec(input?: (string | URLPatternInit), baseURL?: string): URLPatternResult | null; exec(input?: (string | URLPatternInit), baseURL?: string): URLPatternResult | null;
} }
interface URLPatternInit { interface URLPatternInit {
@@ -3063,7 +3146,7 @@ interface URLPatternOptions {
ignoreCase?: boolean; ignoreCase?: boolean;
} }
/** /**
* A `CloseEvent` is sent to clients using WebSockets when the connection is closed. * A **`CloseEvent`** is sent to clients using WebSockets when the connection is closed. This is delivered to the listener indicated by the WebSocket object's onclose attribute.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent)
*/ */
@@ -3082,13 +3165,16 @@ declare class CloseEvent extends Event {
*/ */
readonly reason: string; readonly reason: string;
/** /**
* The **`wasClean`** read-only property of the CloseEvent interface returns `true` if the connection closed cleanly. * The **`wasClean`** read-only property of the CloseEvent interface returns true if the connection closed cleanly.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/wasClean) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/wasClean)
*/ */
readonly wasClean: boolean; readonly wasClean: boolean;
} }
interface CloseEventInit { interface CloseEventInit {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
code?: number; code?: number;
reason?: string; reason?: string;
wasClean?: boolean; wasClean?: boolean;
@@ -3100,7 +3186,7 @@ type WebSocketEventMap = {
error: ErrorEvent; error: ErrorEvent;
}; };
/** /**
* The `WebSocket` object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection. * The **`WebSocket`** object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket)
*/ */
@@ -3117,20 +3203,20 @@ declare var WebSocket: {
readonly CLOSED: number; readonly CLOSED: number;
}; };
/** /**
* The `WebSocket` object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection. * The **`WebSocket`** object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket)
*/ */
interface WebSocket extends EventTarget<WebSocketEventMap> { interface WebSocket extends EventTarget<WebSocketEventMap> {
accept(options?: WebSocketAcceptOptions): void; accept(options?: WebSocketAcceptOptions): void;
/** /**
* The **`WebSocket.send()`** method enqueues the specified data to be transmitted to the server over the WebSocket connection, increasing the value of `bufferedAmount` by the number of bytes needed to contain the data. * The **`WebSocket.send()`** method enqueues the specified data to be transmitted to the server over the WebSocket connection, increasing the value of bufferedAmount by the number of bytes needed to contain the data. If the data can't be sent (for example, because it needs to be buffered but the buffer is full), the socket is closed automatically. The browser will throw an exception if you call send() when the connection is in the CONNECTING state. If you call send() when the connection is in the CLOSING or CLOSED states, the browser will silently discard the data.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/send) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/send)
*/ */
send(message: (ArrayBuffer | ArrayBufferView) | string): void; send(message: (ArrayBuffer | ArrayBufferView) | string): void;
/** /**
* The **`WebSocket.close()`** method closes the already `CLOSED`, this method does nothing. * The **`WebSocket.close()`** method closes the WebSocket connection or connection attempt, if any. If the connection is already CLOSED, this method does nothing.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/close)
*/ */
@@ -3150,13 +3236,13 @@ interface WebSocket extends EventTarget<WebSocketEventMap> {
*/ */
url: string | null; url: string | null;
/** /**
* The **`WebSocket.protocol`** read-only property returns the name of the sub-protocol the server selected; this will be one of the strings specified in the `protocols` parameter when creating the WebSocket object, or the empty string if no connection is established. * The **`WebSocket.protocol`** read-only property returns the name of the sub-protocol the server selected; this will be one of the strings specified in the protocols parameter when creating the WebSocket object, or the empty string if no connection is established.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/protocol) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/protocol)
*/ */
protocol: string | null; protocol: string | null;
/** /**
* The **`WebSocket.extensions`** read-only property returns the extensions selected by the server. * The **`WebSocket.extensions`** read-only property returns the extensions selected by the server. This is currently only the empty string or a list of extensions as negotiated by the connection.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/extensions) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/extensions)
*/ */
@@ -3243,25 +3329,25 @@ interface SocketInfo {
declare class EventSource extends EventTarget { declare class EventSource extends EventTarget {
constructor(url: string, init?: EventSourceEventSourceInit); constructor(url: string, init?: EventSourceEventSourceInit);
/** /**
* The **`close()`** method of the EventSource interface closes the connection, if one is made, and sets the ```js-nolint close() ``` None. * The **`close()`** method of the EventSource interface closes the connection, if one is made, and sets the EventSource.readyState attribute to 2 (closed).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close)
*/ */
close(): void; close(): void;
/** /**
* The **`url`** read-only property of the URL of the source. * The **`url`** read-only property of the EventSource interface returns a string representing the URL of the source.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url)
*/ */
get url(): string; get url(): string;
/** /**
* The **`withCredentials`** read-only property of the the `EventSource` object was instantiated with CORS credentials set. * The **`withCredentials`** read-only property of the EventSource interface returns a boolean value indicating whether the EventSource object was instantiated with CORS credentials set.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials)
*/ */
get withCredentials(): boolean; get withCredentials(): boolean;
/** /**
* The **`readyState`** read-only property of the connection. * The **`readyState`** read-only property of the EventSource interface returns a number representing the state of the connection.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState)
*/ */
@@ -3296,18 +3382,26 @@ interface ContainerExecOptions {
cwd?: string; cwd?: string;
env?: Record<string, string>; env?: Record<string, string>;
user?: string; user?: string;
signal?: AbortSignal;
pty?: boolean | ContainerExecPtyOptions;
stdin?: ReadableStream | "pipe"; stdin?: ReadableStream | "pipe";
stdout?: "pipe" | "ignore"; stdout?: "pipe" | "ignore";
stderr?: "pipe" | "ignore" | "combined"; stderr?: "pipe" | "ignore" | "combined";
} }
interface ContainerExecPtyOptions {
cols?: number;
rows?: number;
}
interface ExecProcess { interface ExecProcess {
readonly stdin: WritableStream | null; readonly stdin: WritableStream | null;
readonly stdout: ReadableStream | null; readonly stdout: ReadableStream | null;
readonly stderr: ReadableStream | null; readonly stderr: ReadableStream | null;
readonly pid: number; readonly pid: number;
readonly isPty: boolean;
readonly exitCode: Promise<number>; readonly exitCode: Promise<number>;
output(): Promise<ExecOutput>; output(): Promise<ExecOutput>;
kill(signal?: number): void; kill(signal?: number): void;
resize(cols: number, rows: number): void;
} }
interface Container { interface Container {
get running(): boolean; get running(): boolean;
@@ -3334,25 +3428,42 @@ interface ContainerDirectorySnapshotOptions {
dir: string; dir: string;
name?: string; name?: string;
} }
interface ContainerDirectorySnapshotRestoreParams { type ContainerDirectorySnapshotRestoreParams = {
snapshot: ContainerDirectorySnapshot; snapshot: ContainerDirectorySnapshot;
mountPoint?: string; mountPoint?: string;
} } | {
snapshot?: undefined;
mountPoint: string;
};
interface ContainerSnapshot { interface ContainerSnapshot {
id: string; id: string;
size: number; size: number;
name?: string; name?: string;
} }
interface ContainerSnapshotRestoreParams {
id: string;
}
interface ContainerSnapshotOptions { interface ContainerSnapshotOptions {
name?: string; name?: string;
} }
interface ContainerStartupOptions { type ContainerStartupOptions = {
entrypoint?: string[]; entrypoint?: string[];
enableInternet: boolean; enableInternet: boolean;
env?: Record<string, string>; env?: Record<string, string>;
instance?: "lite" | "standard-1" | "standard-2" | "standard-3" | "standard-4" | ContainerStartResources;
labels?: Record<string, string>; labels?: Record<string, string>;
directorySnapshots?: ContainerDirectorySnapshotRestoreParams[]; directorySnapshots?: ContainerDirectorySnapshotRestoreParams[];
containerSnapshot?: ContainerSnapshot; } & ({
image: string;
containerSnapshot?: never;
} | {
image?: never;
containerSnapshot?: ContainerSnapshotRestoreParams;
});
interface ContainerStartResources {
vcpu: number;
memoryMib: number;
diskMb: number;
} }
/** /**
* The **`MessagePort`** interface of the Channel Messaging API represents one of the two ports of a MessageChannel, allowing messages to be sent from one port and listening out for them arriving at the other. * The **`MessagePort`** interface of the Channel Messaging API represents one of the two ports of a MessageChannel, allowing messages to be sent from one port and listening out for them arriving at the other.
@@ -3361,19 +3472,19 @@ interface ContainerStartupOptions {
*/ */
declare abstract class MessagePort extends EventTarget { declare abstract class MessagePort extends EventTarget {
/** /**
* The **`postMessage()`** method of the transfers ownership of objects to other browsing contexts. * The **`postMessage()`** method of the MessagePort interface sends a message from the port, and optionally, transfers ownership of objects to other browsing contexts.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/postMessage) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/postMessage)
*/ */
postMessage(data?: any, options?: (any[] | MessagePortPostMessageOptions)): void; postMessage(data?: any, options?: (any[] | MessagePortPostMessageOptions)): void;
/** /**
* The **`close()`** method of the MessagePort interface disconnects the port, so it is no longer active. * The **`close()`** method of the MessagePort interface disconnects the port, so it is no longer active. This stops the flow of messages to that port.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/close) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/close)
*/ */
close(): void; close(): void;
/** /**
* The **`start()`** method of the MessagePort interface starts the sending of messages queued on the port. * The **`start()`** method of the MessagePort interface starts the sending of messages queued on the port. This method is only needed when using EventTarget.addEventListener; it is implied when using onmessage.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/start) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessagePort/start)
*/ */
@@ -3389,13 +3500,13 @@ declare abstract class MessagePort extends EventTarget {
declare class MessageChannel { declare class MessageChannel {
constructor(); constructor();
/** /**
* The **`port1`** read-only property of the the port attached to the context that originated the channel. * The **`port1`** read-only property of the MessageChannel interface returns the first port of the message channel — the port attached to the context that originated the channel.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port1) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port1)
*/ */
readonly port1: MessagePort; readonly port1: MessagePort;
/** /**
* The **`port2`** read-only property of the the port attached to the context at the other end of the channel, which the message is initially sent to. * The **`port2`** read-only property of the MessageChannel interface returns the second port of the message channel — the port attached to the context at the other end of the channel, which the message is initially sent to.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port2) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageChannel/port2)
*/ */
@@ -3455,7 +3566,7 @@ interface WorkerLoaderModule {
data?: ArrayBuffer; data?: ArrayBuffer;
json?: any; json?: any;
py?: string; py?: string;
wasm?: ArrayBuffer; wasm?: ArrayBuffer | ArrayBufferView | WebAssembly.Module;
} }
interface WorkerLoaderWorkerCode { interface WorkerLoaderWorkerCode {
compatibilityDate: string; compatibilityDate: string;
@@ -3463,7 +3574,7 @@ interface WorkerLoaderWorkerCode {
allowExperimental?: boolean; allowExperimental?: boolean;
limits?: workerdResourceLimits; limits?: workerdResourceLimits;
mainModule: string; mainModule: string;
modules: Record<string, WorkerLoaderModule | string>; modules: Record<string, string | WebAssembly.Module | WorkerLoaderModule>;
env?: any; env?: any;
globalOutbound?: (Fetcher | null); globalOutbound?: (Fetcher | null);
tails?: Fetcher[]; tails?: Fetcher[];
@@ -3485,7 +3596,7 @@ declare abstract class Performance {
/* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancenow) */ /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancenow) */
now(): number; now(): number;
/** /**
* The **`toJSON()`** method of the Performance interface is a Serialization; it returns a JSON representation of the Performance object. * The **`toJSON()`** method of the Performance interface is a serializer; it returns a JSON representation of the Performance object.
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Performance/toJSON) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Performance/toJSON)
*/ */
@@ -3494,11 +3605,13 @@ declare abstract class Performance {
interface Tracing { interface Tracing {
enterSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T; enterSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T;
startActiveSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T; startActiveSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T;
startSpan(name: string): Span;
Span: typeof Span; Span: typeof Span;
} }
declare abstract class Span { declare abstract class Span {
get isTraced(): boolean; get isTraced(): boolean;
setAttribute(key: string, value?: (boolean | number | string)): void; setAttribute(key: string, value: boolean | number | string): this;
setAttributes(attributes: Record<string, boolean | number | string | undefined>): this;
end(): void; end(): void;
} }
/** /**
@@ -4138,6 +4251,13 @@ type AiSearchListItemsParams = {
source?: string; source?: string;
/** JSON-encoded Vectorize filter for metadata filtering. */ /** JSON-encoded Vectorize filter for metadata filtering. */
metadata_filter?: string; metadata_filter?: string;
/** Filter items by their unique ID. Returns at most one item. */
item_id?: string;
/**
* Filter items by their exact key (object key / filename). Keys are unique
* per source, so combine with `source` to disambiguate across data sources.
*/
key?: string;
}; };
type AiSearchListItemsResponse = { type AiSearchListItemsResponse = {
result: AiSearchItemInfo[]; result: AiSearchItemInfo[];
@@ -10035,6 +10155,163 @@ declare abstract class Base_Ai_Cf_Google_Gemma_4_26B_A4B_IT {
inputs: ChatCompletionsInput; inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput; postProcessedOutputs: ChatCompletionsOutput;
} }
declare abstract class Base_Ai_Cf_Moonshotai_Kimi_K2_7_Code {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Zai_Org_Glm_5_2 {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
interface Ai_Cf_Moondream_Moondream3_1_9B_A2B_Input {
/**
* Which Moondream skill to run.
*/
task?: "query" | "caption" | "point" | "detect";
/**
* Input image as a public HTTPS URL or base64 data URI. Optional for `query`; required for `caption`, `point`, and `detect`.
*/
image?: string;
/**
* Question for the `query` task.
*/
question?: string;
/**
* Caption length for the `caption` task.
*/
caption_length?: "short" | "normal" | "long";
/**
* Object phrase to locate for `point` and `detect` tasks (e.g. 'person wearing a red shirt').
*/
target?: string;
/**
* Enable reasoning trace for the `query` task.
*/
reasoning?: boolean;
/**
* Sampling temperature.
*/
temperature?: number;
/**
* Top-p (nucleus) sampling.
*/
top_p?: number;
/**
* Max tokens to generate for `query` and `caption`.
*/
max_tokens?: number;
/**
* Max objects to return for `point` and `detect`.
*/
max_objects?: number;
/**
* Return incremental tokens for `query` and `caption`. `point` and `detect` do not support streaming.
*/
stream?: boolean;
}
interface Ai_Cf_Moondream_Moondream3_1_9B_A2B_Output {
/**
* Reason the generation finished.
*/
finish_reason: string;
metrics: {
/**
* Number of input tokens consumed.
*/
input_tokens: number;
/**
* Number of output tokens generated.
*/
output_tokens: number;
/**
* Prefill time in milliseconds.
*/
prefill_time_ms: number;
/**
* Decode time in milliseconds.
*/
decode_time_ms: number;
/**
* Time to first token in milliseconds.
*/
ttft_ms: number;
};
/**
* Answer text for the `query` task. Null for other tasks.
*/
answer?: string;
/**
* Caption text for the `caption` task. Null for other tasks.
*/
caption?: string;
/**
* Located points for the `point` task. Null for other tasks.
*/
points?: {
/**
* X coordinate.
*/
x: number;
/**
* Y coordinate.
*/
y: number;
}[];
/**
* Detected bounding boxes for the `detect` task. Null for other tasks.
*/
objects?: {
/**
* Minimum X coordinate.
*/
x_min: number;
/**
* Minimum Y coordinate.
*/
y_min: number;
/**
* Maximum X coordinate.
*/
x_max: number;
/**
* Maximum Y coordinate.
*/
y_max: number;
}[];
/**
* Reasoning trace for the `query` task when reasoning=true. Null otherwise.
*/
reasoning?: {
/**
* Reasoning text.
*/
text: string;
/**
* Grounding information.
*/
grounding?: {}[];
};
}
declare abstract class Base_Ai_Cf_Moondream_Moondream3_1_9B_A2B {
inputs: Ai_Cf_Moondream_Moondream3_1_9B_A2B_Input;
postProcessedOutputs: Ai_Cf_Moondream_Moondream3_1_9B_A2B_Output;
}
declare abstract class Base_Ai_Cf_Deepseek_Ai_Deepseek_V4_Flash_0731 {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Deepseek_Ai_Deepseek_V4_Pro_0813 {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Qwen_Qwen3_8_27B {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Zai_Org_Glm_5_3_Flash {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
interface AiModels { interface AiModels {
"@cf/huggingface/distilbert-sst-2-int8": BaseAiTextClassification; "@cf/huggingface/distilbert-sst-2-int8": BaseAiTextClassification;
"@cf/stabilityai/stable-diffusion-xl-base-1.0": BaseAiTextToImage; "@cf/stabilityai/stable-diffusion-xl-base-1.0": BaseAiTextToImage;
@@ -10127,6 +10404,13 @@ interface AiModels {
"@cf/moonshotai/kimi-k2.6": Base_Ai_Cf_Moonshotai_Kimi_K2_6; "@cf/moonshotai/kimi-k2.6": Base_Ai_Cf_Moonshotai_Kimi_K2_6;
"@cf/nvidia/nemotron-3-120b-a12b": Base_Ai_Cf_Nvidia_Nemotron_3_120B_A12B; "@cf/nvidia/nemotron-3-120b-a12b": Base_Ai_Cf_Nvidia_Nemotron_3_120B_A12B;
"@cf/google/gemma-4-26b-a4b-it": Base_Ai_Cf_Google_Gemma_4_26B_A4B_IT; "@cf/google/gemma-4-26b-a4b-it": Base_Ai_Cf_Google_Gemma_4_26B_A4B_IT;
"@cf/moonshotai/kimi-k2.7-code": Base_Ai_Cf_Moonshotai_Kimi_K2_7_Code;
"@cf/zai-org/glm-5.2": Base_Ai_Cf_Zai_Org_Glm_5_2;
"@cf/moondream/moondream3.1-9B-A2B": Base_Ai_Cf_Moondream_Moondream3_1_9B_A2B;
"@cf/deepseek-ai/deepseek-v4-flash-0731": Base_Ai_Cf_Deepseek_Ai_Deepseek_V4_Flash_0731;
"@cf/deepseek-ai/deepseek-v4-pro-0813": Base_Ai_Cf_Deepseek_Ai_Deepseek_V4_Pro_0813;
"@cf/qwen/qwen3.8-27b": Base_Ai_Cf_Qwen_Qwen3_8_27B;
"@cf/zai-org/glm-5.3-flash": Base_Ai_Cf_Zai_Org_Glm_5_3_Flash;
} }
type AiOptions = { type AiOptions = {
/** /**
@@ -10793,6 +11077,15 @@ interface BrowserRunBaseOptions {
*/ */
cacheTTL?: number; cacheTTL?: number;
} }
/**
* Backend selection, mixed into the options of the quick actions that support it.
* Deliberately not part of `BrowserRunBaseOptions`: `scrape`, `links` and `snapshot`
* reject an alternate backend, so they must not accept the field.
*/
interface BrowserRunAlternateBackendOptions {
/** Render with an alternate browser backend instead of the default one. */
browser?: 'kitesurf';
}
/** Common options shared by all quick actions. Exactly one of `url` or `html` must be provided.*/ /** Common options shared by all quick actions. Exactly one of `url` or `html` must be provided.*/
type BrowserRunCommonOptions = (BrowserRunBaseOptions & { type BrowserRunCommonOptions = (BrowserRunBaseOptions & {
/** URL to navigate to, e.g. `"https://example.com"`. */ /** URL to navigate to, e.g. `"https://example.com"`. */
@@ -10827,7 +11120,7 @@ type BrowserRunScreenshotOptions = BrowserRunCommonOptions & {
scrollPage?: boolean; scrollPage?: boolean;
/** @see https://pptr.dev/api/puppeteer.screenshotoptions */ /** @see https://pptr.dev/api/puppeteer.screenshotoptions */
screenshotOptions?: BrowserRunPuppeteerScreenshotOptions; screenshotOptions?: BrowserRunPuppeteerScreenshotOptions;
}; } & BrowserRunAlternateBackendOptions;
type BrowserRunPDFOptions = BrowserRunCommonOptions & { type BrowserRunPDFOptions = BrowserRunCommonOptions & {
/** @see https://pptr.dev/api/puppeteer.pdfoptions */ /** @see https://pptr.dev/api/puppeteer.pdfoptions */
pdfOptions?: { pdfOptions?: {
@@ -10863,7 +11156,7 @@ type BrowserRunPDFOptions = BrowserRunCommonOptions & {
/** @default 30000 */ /** @default 30000 */
timeout?: number; timeout?: number;
}; };
}; } & BrowserRunAlternateBackendOptions;
type BrowserRunScrapeOptions = BrowserRunCommonOptions & { type BrowserRunScrapeOptions = BrowserRunCommonOptions & {
/** CSS selectors to scrape. At least one element is required. */ /** CSS selectors to scrape. At least one element is required. */
elements: Array<{ elements: Array<{
@@ -10876,10 +11169,29 @@ type BrowserRunLinksOptions = BrowserRunCommonOptions & {
/** When true, exclude links pointing to external domains. @default false */ /** When true, exclude links pointing to external domains. @default false */
excludeExternalLinks?: boolean; excludeExternalLinks?: boolean;
}; };
type BrowserRunSnapshotFormat = 'content' | 'screenshot' | 'markdown' | 'accessibilityTree';
type BrowserRunSnapshotOptions = BrowserRunCommonOptions & { type BrowserRunSnapshotOptions = BrowserRunCommonOptions & {
/** Which representations of the page to return. At least two distinct formats
* are required; request a single format from its dedicated action instead.
* @default ["content","screenshot"]
*/
formats?: BrowserRunSnapshotFormat[];
/** @see https://pptr.dev/api/puppeteer.screenshotoptions */ /** @see https://pptr.dev/api/puppeteer.screenshotoptions */
screenshotOptions?: Omit<BrowserRunPuppeteerScreenshotOptions, 'encoding'>; screenshotOptions?: Omit<BrowserRunPuppeteerScreenshotOptions, 'encoding'>;
}; };
/** Options for the `accessibilityTree` quick action. */
type BrowserRunAccessibilityTreeOptions = BrowserRunCommonOptions & {
/** When true, prune nodes that carry no semantic meaning, such as generic
* containers. Defaults to true, or to false when `root` is set so that the
* requested subtree is returned as-is.
*/
interestingOnly?: boolean;
/** CSS selector limiting the tree to the matching element's subtree.
* A selector that matches nothing yields `accessibilityTree: null` with
* HTTP 200; a malformed selector is an error.
*/
root?: string;
} & BrowserRunAlternateBackendOptions;
interface BrowserRunJsonBaseOptions { interface BrowserRunJsonBaseOptions {
/** Custom AI models to try in order. Max 3. Falls back to next on error. */ /** Custom AI models to try in order. Max 3. Falls back to next on error. */
custom_ai?: Array<{ custom_ai?: Array<{
@@ -10893,7 +11205,7 @@ interface BrowserRunJsonBaseOptions {
* Options for the `json` quick action. * Options for the `json` quick action.
* At least one of `prompt` or `response_format` must be provided. * At least one of `prompt` or `response_format` must be provided.
*/ */
type BrowserRunJsonOptions = BrowserRunCommonOptions & BrowserRunJsonBaseOptions & ({ type BrowserRunJsonOptions = BrowserRunCommonOptions & BrowserRunAlternateBackendOptions & BrowserRunJsonBaseOptions & ({
/** Natural-language prompt describing what data to extract. */ /** Natural-language prompt describing what data to extract. */
prompt: string; prompt: string;
/** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */ /** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */
@@ -10904,14 +11216,80 @@ type BrowserRunJsonOptions = BrowserRunCommonOptions & BrowserRunJsonBaseOptions
/** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */ /** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */
response_format: AiTextGenerationResponseFormat; response_format: AiTextGenerationResponseFormat;
}); });
type BrowserRunContentOptions = BrowserRunCommonOptions; type BrowserRunContentOptions = BrowserRunCommonOptions & BrowserRunAlternateBackendOptions;
type BrowserRunMarkdownOptions = BrowserRunCommonOptions; type BrowserRunMarkdownOptions = BrowserRunCommonOptions & BrowserRunAlternateBackendOptions;
type BrowserRunRedirectHop = {
/** URL that returned the redirect. */
url: string;
/** HTTP status of the redirect. */
status: number;
/** Redirect response headers, including `location`. */
headers: Record<string, string>;
};
type BrowserRunResponseMeta = { type BrowserRunResponseMeta = {
/** HTTP status code of the rendered page */ /** HTTP status code of the rendered page */
status: number; status: number;
/** Page title */ /** Page title */
title: string; title: string;
/** Origin response headers, lowercased. Repeated headers are joined with a newline. Credential and transport-only headers that do not survive rendering are omitted. */
headers?: Record<string, string>;
/** URL that served the response, after any redirects the browser followed. */
finalUrl?: string;
/** HTTP redirects followed to reach `finalUrl`, oldest first. Omitted for direct navigation and for client-side redirects such as meta refresh. An empty array means redirects occurred but their intermediate responses could not be read. */
redirectChain?: BrowserRunRedirectHop[];
}; };
/**
* A node in the page's accessibility tree, as exposed to assistive technology.
* `role` is the only field always present; the rest are populated when the
* underlying element defines them.
* @see https://pptr.dev/api/puppeteer.serializedaxnode
*/
interface BrowserRunSerializedAXNode {
/** The ARIA role, e.g. `"button"`, `"heading"`, `"RootWebArea"`. */
role: string;
/** The `aria-autocomplete` value. */
autocomplete?: string;
/** Checked state of a checkbox, radio, or menu item. */
checked?: boolean | 'mixed';
/** Accessible description, typically from `aria-describedby` or `title`. */
description?: string;
disabled?: boolean;
expanded?: boolean;
/** Whether the element currently holds keyboard focus. */
focused?: boolean;
/** The kind of popup the element triggers, e.g. `"menu"`, `"dialog"`. */
haspopup?: string;
/** The `aria-invalid` value. */
invalid?: string;
/** Keyboard shortcuts bound to the element, from `aria-keyshortcuts`. */
keyshortcuts?: string;
/** Hierarchical level, e.g. the heading level of an `<h2>`. */
level?: number;
/** Whether the element is a modal dialog. */
modal?: boolean;
/** Whether a text input accepts multiple lines. */
multiline?: boolean;
/** Whether more than one option can be selected. */
multiselectable?: boolean;
/** Accessible name, e.g. a button's label or an image's alt text. */
name?: string;
orientation?: string;
/** Pressed state of a toggle button. */
pressed?: boolean | 'mixed';
readonly?: boolean;
required?: boolean;
/** Author-supplied role description, from `aria-roledescription`. */
roledescription?: string;
selected?: boolean;
/** Current value of an input or range element. */
value?: string | number;
valuemax?: number;
valuemin?: number;
/** Human-readable form of `value`, from `aria-valuetext`. */
valuetext?: string;
/** Child nodes. Absent for leaf nodes. */
children?: BrowserRunSerializedAXNode[];
}
/** Success response for `content` action. */ /** Success response for `content` action. */
type BrowserRunContentSuccessResponse = { type BrowserRunContentSuccessResponse = {
success: true; success: true;
@@ -10924,6 +11302,7 @@ type BrowserRunLinksSuccessResponse = {
success: true; success: true;
/** Extracted links */ /** Extracted links */
result: string[]; result: string[];
meta: BrowserRunResponseMeta;
}; };
/** Success response for `scrape` action. */ /** Success response for `scrape` action. */
type BrowserRunScrapeSuccessResponse = { type BrowserRunScrapeSuccessResponse = {
@@ -10954,15 +11333,33 @@ type BrowserRunScrapeSuccessResponse = {
}>; }>;
}>; }>;
}>; }>;
meta: BrowserRunResponseMeta;
}; };
/** Success response for `snapshot` action. */ /** Success response for `snapshot` action. Each field is present only when the
* corresponding entry was requested in `formats`.
*/
type BrowserRunSnapshotSuccessResponse = { type BrowserRunSnapshotSuccessResponse = {
success: true; success: true;
result: { result: {
/** HTML content of the page. */ /** HTML content of the page. */
content: string; content?: string;
/** Base64-encoded screenshot image. */ /** Base64-encoded screenshot image. */
screenshot: string; screenshot?: string;
/** Markdown content. Prefixed with YAML frontmatter (e.g. `title`) when the
* page provides that metadata.
*/
markdown?: string;
/** Root of the page's accessibility tree. */
accessibilityTree?: BrowserRunSerializedAXNode;
};
meta: BrowserRunResponseMeta;
};
/** Success response for `accessibilityTree` action. */
type BrowserRunAccessibilityTreeSuccessResponse = {
success: true;
result: {
/** Root of the accessibility tree, or `null` when `root` matched no element. */
accessibilityTree: BrowserRunSerializedAXNode | null;
}; };
meta: BrowserRunResponseMeta; meta: BrowserRunResponseMeta;
}; };
@@ -10971,12 +11368,14 @@ type BrowserRunJsonSuccessResponse = {
success: true; success: true;
/** JSON data extracted from the page using an AI model */ /** JSON data extracted from the page using an AI model */
result: Record<string, unknown>; result: Record<string, unknown>;
meta: BrowserRunResponseMeta;
}; };
/** Success response for `markdown` action. */ /** Success response for `markdown` action. */
type BrowserRunMarkdownSuccessResponse = { type BrowserRunMarkdownSuccessResponse = {
success: true; success: true;
/** Extracted markdown content */ /** Extracted markdown content */
result: string; result: string;
meta: BrowserRunResponseMeta;
}; };
/** Error response for BrowserRun actions. */ /** Error response for BrowserRun actions. */
type BrowserRunErrorResponse = { type BrowserRunErrorResponse = {
@@ -11086,9 +11485,10 @@ declare abstract class BrowserRun {
*/ */
quickAction(action: 'links', options: BrowserRunLinksOptions): Promise<Response>; quickAction(action: 'links', options: BrowserRunLinksOptions): Promise<Response>;
/** /**
* Get both the HTML content and a base64-encoded screenshot of a web page. * Get several representations of a web page in one request.
* @param action - Must be `'snapshot'`. * @param action - Must be `'snapshot'`.
* @param options - Snapshot options including screenshot settings (encoding is always base64). * @param options - Snapshot options including the `formats` to return and
* screenshot settings (encoding is always base64).
* @returns A `Response` containing one of: * @returns A `Response` containing one of:
* *
* **Success (HTTP 200):** * **Success (HTTP 200):**
@@ -11136,6 +11536,26 @@ declare abstract class BrowserRun {
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500) * - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/ */
quickAction(action: 'markdown', options: BrowserRunMarkdownOptions): Promise<Response>; quickAction(action: 'markdown', options: BrowserRunMarkdownOptions): Promise<Response>;
/**
* Get the accessibility tree of a web page.
* @param action - Must be `'accessibilityTree'`.
* @param options - Options to scope the tree to a subtree and to control
* whether semantically uninteresting nodes are pruned.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - `BrowserRunAccessibilityTreeSuccessResponse` JSON with `Content-Type: application/json`
* - `result.accessibilityTree` is `null` when `root` matched no element
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
* - HTTP 422 for a malformed `root` selector
* - HTTP 500 with code `2017` or `2018` when the tree could not be built
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'accessibilityTree', options: BrowserRunAccessibilityTreeOptions): Promise<Response>;
} }
/** /**
* In addition to the properties you can set in the RequestInit dict * In addition to the properties you can set in the RequestInit dict
@@ -12206,6 +12626,13 @@ interface ForwardableEmailMessage extends EmailMessage {
* @returns A promise that resolves when the email message is replied. * @returns A promise that resolves when the email message is replied.
*/ */
reply(message: EmailMessage): Promise<EmailSendResult>; reply(message: EmailMessage): Promise<EmailSendResult>;
/**
* Reply to the sender of this email message with a message built from the given
* fields. Threading headers (In-Reply-To/References) are set automatically.
* @param builder The reply message contents.
* @returns A promise that resolves when the email message is replied.
*/
reply(builder: EmailReplyMessageBuilder): Promise<EmailSendResult>;
} }
/** A file attachment for an email message */ /** A file attachment for an email message */
type EmailAttachment = { type EmailAttachment = {
@@ -12227,22 +12654,45 @@ interface EmailAddress {
email: string; email: string;
} }
/** /**
* A binding that allows a Worker to send email messages. * Recipient fields for `SendEmail.send()`. At least one of `to`, `cc`, or
* `bcc` must be provided.
*/ */
interface SendEmail { type EmailDestinations = {
send(message: EmailMessage): Promise<EmailSendResult>; to?: string | EmailAddress | (string | EmailAddress)[];
send(builder: {
from: string | EmailAddress;
to: string | EmailAddress | (string | EmailAddress)[];
subject: string;
replyTo?: string | EmailAddress;
cc?: string | EmailAddress | (string | EmailAddress)[]; cc?: string | EmailAddress | (string | EmailAddress)[];
bcc?: string | EmailAddress | (string | EmailAddress)[]; bcc?: string | EmailAddress | (string | EmailAddress)[];
} & ({
to: string | EmailAddress | (string | EmailAddress)[];
} | {
cc: string | EmailAddress | (string | EmailAddress)[];
} | {
bcc: string | EmailAddress | (string | EmailAddress)[];
});
/**
* Fields shared by all composed emails (no recipients). Used directly by
* `ForwardableEmailMessage.reply()`, which always replies to the original
* sender, and extended by `EmailMessageBuilder` for `SendEmail.send()`.
*/
interface EmailReplyMessageBuilder {
from: string | EmailAddress;
subject: string;
replyTo?: string | EmailAddress;
headers?: Record<string, string>; headers?: Record<string, string>;
text?: string; text?: string;
html?: string; html?: string;
attachments?: EmailAttachment[]; attachments?: EmailAttachment[];
}): Promise<EmailSendResult>; }
/**
* Fields for composing an email without constructing raw MIME, for
* `SendEmail.send()`. Requires at least one of `to`, `cc`, or `bcc`.
*/
type EmailMessageBuilder = EmailReplyMessageBuilder & EmailDestinations;
/**
* A binding that allows a Worker to send email messages.
*/
interface SendEmail {
send(message: EmailMessage): Promise<EmailSendResult>;
send(builder: EmailMessageBuilder): Promise<EmailSendResult>;
} }
declare abstract class EmailEvent extends ExtendableEvent { declare abstract class EmailEvent extends ExtendableEvent {
readonly message: ForwardableEmailMessage; readonly message: ForwardableEmailMessage;
@@ -12396,6 +12846,15 @@ interface Hyperdrive {
* for your database. * for your database.
*/ */
readonly host: string; readonly host: string;
/*
* A synthetic IPv4 address (in the reserved 240.0.0.0/4 range) that, like the
* host field, is only valid within the context of the currently running
* Worker and, when passed into the `connect()` function from the
* "cloudflare:sockets" module, will connect to the Hyperdrive instance for
* your database. This is provided for database drivers that require the host
* to be an IP literal rather than a hostname.
*/
readonly ip: string;
/* /*
* The port that must be paired the the host field when connecting. * The port that must be paired the the host field when connecting.
*/ */
@@ -12417,6 +12876,78 @@ interface Hyperdrive {
*/ */
readonly database: string; readonly database: string;
} }
/**
* A handle to a dynamically-provisioned Hyperdrive connection, returned by
* `HyperdriveApi.get()`.
*/
interface HyperdriveDynamic extends Disposable {
/**
* The database name to use when connecting through this Hyperdrive.
*/
readonly database: Promise<string>;
/*
* The randomly generated user to use when authenticating to your
* database via Hyperdrive.
*/
readonly user: Promise<string>;
/*
* The randomly generated password to use when authenticating to your
* database via Hyperdrive.
*/
readonly password: Promise<string>;
/**
* Open a TCP socket to the target database through this Hyperdrive.
*
*/
connect(): Promise<Socket>;
}
/**
* Binding that provisions Hyperdrive connections at request time, rather than
* from static configuration.
*/
interface HyperdriveDynamicApi {
/**
* Provision a connection for the database described by `args`.
*
*/
get(args: HyperdriveDynamicConfig): Promise<HyperdriveDynamic>;
/**
* Get a pre-generated connection string used for connecting to dynamic Hyperdrive.
*/
getHyperdriveConnectionString(connectionString: string): Promise<string>;
}
/**
* Parameters identifying the database that a dynamically-provisioned
* Hyperdrive connection should target.
*/
interface HyperdriveDynamicConfig {
/**
* Generated connection string to pass into the dynamic worker.
*
*/
dynamicHyperdriveConnectionString: string;
/**
* Connection string for the origin database Hyperdrive should connect to.
* Contains credentials, so treat it as a secret.
*
* The scheme selects the database engine. PostgreSQL origins are supported.
*/
connectionString: string;
/**
* Region in which to place the connection pool. See the Hyperdrive
* documentation for the set of supported regions.
*/
targetRegion: string;
/**
* Whether Hyperdrive should cache query results for this connection.
*/
cachingEnabled?: boolean;
/**
* Maximum number of connections the pool may open to the origin database.
* Defaults to 60.
*/
maxConnections?: number;
}
// Copyright (c) 2024 Cloudflare, Inc. // Copyright (c) 2024 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at: // Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0 // https://opensource.org/licenses/Apache-2.0
@@ -12428,6 +12959,27 @@ type ImageInfoResponse = {
width: number; width: number;
height: number; height: number;
}; };
/**
* Parameters for rasterizing text into an image.
*/
type TextRasterize = {
/** The text content to render */
content: string;
/** rasterization options for the text **/
options: TextOptions;
};
type TextOptions = {
/** Font configuration */
font: {
/** URL to a font file in TrueType (.ttf), OpenType (.otf), WOFF (.woff), or WOFF2 (.woff2) format */
url: string;
};
/** Font size in points (pt) */
size?: number;
/** Text color in CSS format: hex (#RRGGBB or #RRGGBBAA), rgb(r,g,b), rgba(r,g,b,a), or named colors */
color?: string;
};
type ImageSource = ReadableStream<Uint8Array> | TextRasterize;
type ImageTransform = { type ImageTransform = {
width?: number; width?: number;
height?: number; height?: number;
@@ -12517,6 +13069,9 @@ interface ImageUploadOptions {
requireSignedURLs?: boolean; requireSignedURLs?: boolean;
metadata?: Record<string, unknown>; metadata?: Record<string, unknown>;
creator?: string; creator?: string;
/**
* If 'base64', the input data will be decoded from base64 before processing
*/
encoding?: 'base64'; encoding?: 'base64';
} }
interface ImageUpdateOptions { interface ImageUpdateOptions {
@@ -12524,11 +13079,40 @@ interface ImageUpdateOptions {
metadata?: Record<string, unknown>; metadata?: Record<string, unknown>;
creator?: string; creator?: string;
} }
type ImageMetadataFilterOperators = {
eq?: string | number | boolean;
in?: string[] | number[];
gt?: number;
gte?: number;
lt?: number;
lte?: number;
};
type ImageMetadataFilterValue = string | number | boolean | ImageMetadataFilterOperators;
interface ImageListFilter {
metadata?: Record<string, ImageMetadataFilterValue>;
}
interface ImageListOptions { interface ImageListOptions {
limit?: number; limit?: number;
cursor?: string; cursor?: string;
sortOrder?: 'asc' | 'desc'; sortOrder?: 'asc' | 'desc';
creator?: string; creator?: string;
filter?: ImageListFilter;
}
interface ImageSignedUrlOptions {
variant: string;
expiresIn?: number;
keyName?: string;
}
interface ImageDirectUploadOptions {
id?: string;
requireSignedURLs?: boolean;
metadata?: Record<string, unknown>;
creator?: string;
expiresIn?: number;
}
interface ImageDirectUploadResult {
id: string;
uploadURL: string;
} }
interface ImageList { interface ImageList {
images: ImageMetadata[]; images: ImageMetadata[];
@@ -12546,6 +13130,13 @@ interface ImageHandle {
* @returns ReadableStream of image bytes, or null if not found * @returns ReadableStream of image bytes, or null if not found
*/ */
bytes(): Promise<ReadableStream<Uint8Array> | null>; bytes(): Promise<ReadableStream<Uint8Array> | null>;
/**
* Generate a signed delivery URL for this hosted image.
* @param options Signing configuration
* @returns A signed image delivery URL
* @throws {@link ImagesError} if signing fails
*/
signedUrl(options: ImageSignedUrlOptions): Promise<string>;
/** /**
* Update hosted image metadata * Update hosted image metadata
* @param options Properties to update * @param options Properties to update
@@ -12581,6 +13172,14 @@ interface HostedImagesBinding {
* @throws {@link ImagesError} if list fails * @throws {@link ImagesError} if list fails
*/ */
list(options?: ImageListOptions): Promise<ImageList>; list(options?: ImageListOptions): Promise<ImageList>;
/**
* Create a Direct Creator Upload link, letting an end user upload an
* image straight to Cloudflare without exposing an API token
* @param options Upload link configuration
* @returns The new image ID and the upload URL to hand to the end user
* @throws {@link ImagesError} if creation fails
*/
createDirectUpload(options?: ImageDirectUploadOptions): Promise<ImageDirectUploadResult>;
} }
interface ImagesBinding { interface ImagesBinding {
/** /**
@@ -12595,6 +13194,13 @@ interface ImagesBinding {
* @returns A transform handle * @returns A transform handle
*/ */
input(stream: ReadableStream<Uint8Array>, options?: ImageInputOptions): ImageTransformer; input(stream: ReadableStream<Uint8Array>, options?: ImageInputOptions): ImageTransformer;
/**
* Begin applying a series of transformations to text
* @param content string to be rendered
* @param options font, optional color and size to use in rendering text
* @returns A transform handle
*/
text(content: string, options: TextOptions): ImageTransformer;
/** /**
* Access hosted images CRUD operations * Access hosted images CRUD operations
*/ */
@@ -12624,11 +13230,15 @@ interface ImageTransformer {
type ImageTransformationOutputOptions = { type ImageTransformationOutputOptions = {
encoding?: 'base64'; encoding?: 'base64';
}; };
type ImageTransformationResponseOptions = {
headers?: HeadersInit;
};
interface ImageTransformationResult { interface ImageTransformationResult {
/** /**
* The image as a response, ready to store in cache or return to users * The image as a response, ready to store in cache or return to users
* @param options Options that apply to the returned response, e.g. additional headers
*/ */
response(): Response; response(options?: ImageTransformationResponseOptions): Response;
/** /**
* The content type of the returned image * The content type of the returned image
*/ */
@@ -13064,6 +13674,11 @@ declare namespace CloudflareWorkersModule {
export type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'; export type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
export type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number; export type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number;
export type WorkflowDelayDuration = WorkflowSleepDuration; export type WorkflowDelayDuration = WorkflowSleepDuration;
export type WorkflowDynamicDelayContext = {
ctx: WorkflowStepContext<WorkflowDelayFunction>;
error: Error;
};
export type WorkflowDelayFunction = (input: WorkflowDynamicDelayContext) => WorkflowDelayDuration | Promise<WorkflowDelayDuration>;
export type WorkflowTimeoutDuration = WorkflowSleepDuration; export type WorkflowTimeoutDuration = WorkflowSleepDuration;
export type WorkflowRetentionDuration = WorkflowSleepDuration; export type WorkflowRetentionDuration = WorkflowSleepDuration;
export type WorkflowBackoff = 'constant' | 'linear' | 'exponential'; export type WorkflowBackoff = 'constant' | 'linear' | 'exponential';
@@ -13071,12 +13686,32 @@ declare namespace CloudflareWorkersModule {
export type WorkflowStepConfig = { export type WorkflowStepConfig = {
retries?: { retries?: {
limit: number; limit: number;
delay: WorkflowDelayDuration | number; delay: WorkflowDelayDuration | number | WorkflowDelayFunction;
backoff?: WorkflowBackoff; backoff?: WorkflowBackoff;
}; };
timeout?: WorkflowTimeoutDuration | number; timeout?: WorkflowTimeoutDuration | number;
sensitive?: WorkflowStepSensitivity; sensitive?: WorkflowStepSensitivity;
}; };
// Internal discriminators used only for `WorkflowStep.do` overload
// resolution. They mirror `WorkflowStepConfig` but pin `retries.delay` to a
// single kind so the callback context can be narrowed based on the shape of
// the config argument (rather than on an inferred type parameter, which is
// lost when the caller supplies an explicit return-type argument). Not
// exported: they must not widen the public type surface.
type WorkflowStepConfigWithStaticDelay = Omit<WorkflowStepConfig, 'retries'> & {
retries?: {
limit: number;
delay: WorkflowDelayDuration | number;
backoff?: WorkflowBackoff;
};
};
type WorkflowStepConfigWithDelayFunction = Omit<WorkflowStepConfig, 'retries'> & {
retries: {
limit: number;
delay: WorkflowDelayFunction;
backoff?: WorkflowBackoff;
};
};
export type WorkflowStepRollbackConfig = Pick<WorkflowStepConfig, 'retries' | 'timeout'>; export type WorkflowStepRollbackConfig = Pick<WorkflowStepConfig, 'retries' | 'timeout'>;
export type WorkflowCronSchedule = { export type WorkflowCronSchedule = {
/** Cron expression that triggered this event. */ /** Cron expression that triggered this event. */
@@ -13097,28 +13732,51 @@ declare namespace CloudflareWorkersModule {
type: string; type: string;
sensitive?: WorkflowStepSensitivity; sensitive?: WorkflowStepSensitivity;
}; };
export type WorkflowStepContext = { export type WorkflowStepContext<Delay = WorkflowDelayDuration | number> = {
step: { step: {
name: string; name: string;
count: number; count: number;
}; };
attempt: number; attempt: number;
config: WorkflowStepConfig; config: {
retries?: {
limit: number;
backoff?: WorkflowBackoff;
} & (Delay extends WorkflowDelayFunction ? {} : {
delay: WorkflowDelayDuration | number;
});
timeout?: WorkflowTimeoutDuration | number;
sensitive?: WorkflowStepSensitivity;
}; };
export type WorkflowRollbackContext<T = unknown> = { };
ctx: WorkflowStepContext; // The rollback handler receives the step context, so it mirrors the same
// delay discriminant as the step callback: when the step was configured with
// a dynamic delay function the resolved `config.retries.delay` is omitted,
// otherwise it is present. `Delay` is threaded from the `WorkflowStep.do`
// overload that matched the step config.
export type WorkflowRollbackContext<T = unknown, Delay = WorkflowDelayDuration | number> = {
ctx: WorkflowStepContext<Delay>;
error: Error; error: Error;
output: T | undefined; output: T | undefined;
/** @deprecated Use `ctx.step.name` and `ctx.step.count` instead. */ /** @deprecated Use `ctx.step.name` and `ctx.step.count` instead. */
stepName: string; stepName: string;
}; };
export type WorkflowRollbackHandler<T = unknown> = (ctx: WorkflowRollbackContext<T>) => Promise<void>; export type WorkflowRollbackHandler<T = unknown, Delay = WorkflowDelayDuration | number> = (ctx: WorkflowRollbackContext<T, Delay>) => Promise<void>;
export type WorkflowStepRollbackOptions<T = unknown> = { export type WorkflowStepRollbackOptions<T = unknown, Delay = WorkflowDelayDuration | number> = {
rollback: WorkflowRollbackHandler<T>; rollback: WorkflowRollbackHandler<T, Delay>;
rollbackConfig?: WorkflowStepRollbackConfig; rollbackConfig?: WorkflowStepRollbackConfig;
}; };
export abstract class WorkflowStep { export abstract class WorkflowStep {
do<T extends Rpc.Serializable<T>>(name: string, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>; do<T extends Rpc.Serializable<T>>(name: string, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>;
// The config overloads discriminate on the shape of `config.retries.delay`
// so the callback context reflects whether the resolved delay is present
// (static delay) or omitted (dynamic delay function). Each has a single
// type parameter, so an explicit return-type argument (`do<T>(...)`) still
// resolves here. ORDERING IS LOAD-BEARING: the broad `WorkflowStepConfig`
// fallback MUST remain last, otherwise it shadows the discriminating
// overloads and narrowing is silently lost.
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfigWithDelayFunction, callback: (ctx: WorkflowStepContext<WorkflowDelayFunction>) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T, WorkflowDelayFunction>): Promise<T>;
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfigWithStaticDelay, callback: (ctx: WorkflowStepContext<WorkflowDelayDuration | number>) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T, WorkflowDelayDuration | number>): Promise<T>;
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfig, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>; do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfig, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>;
sleep: (name: string, duration: WorkflowSleepDuration) => Promise<void>; sleep: (name: string, duration: WorkflowSleepDuration) => Promise<void>;
sleepUntil: (name: string, timestamp: Date | number) => Promise<void>; sleepUntil: (name: string, timestamp: Date | number) => Promise<void>;
@@ -13894,11 +14552,12 @@ type MarkdownDocument = {
name: string; name: string;
blob: Blob; blob: Blob;
}; };
type OutputFormat = 'markdown' | 'text';
type ConversionResponse = { type ConversionResponse = {
id: string; id: string;
name: string; name: string;
mimeType: string; mimeType: string;
format: 'markdown'; format: OutputFormat;
tokens: number; tokens: number;
data: string; data: string;
} | { } | {
@@ -13915,7 +14574,11 @@ type EmbeddedImageConversionOptions = ImageConversionOptions & {
convert?: boolean; convert?: boolean;
maxConvertedImages?: number; maxConvertedImages?: number;
}; };
type ConversionOutputOptions = {
format?: OutputFormat;
};
type ConversionOptions = { type ConversionOptions = {
output?: ConversionOutputOptions;
html?: { html?: {
images?: EmbeddedImageConversionOptions & { images?: EmbeddedImageConversionOptions & {
convertOGImage?: boolean; convertOGImage?: boolean;
@@ -14010,7 +14673,7 @@ declare namespace TailStream {
interface ConnectEventInfo { interface ConnectEventInfo {
readonly type: "connect"; readonly type: "connect";
} }
type EventOutcome = "ok" | "canceled" | "exception" | "unknown" | "killSwitch" | "daemonDown" | "exceededCpu" | "exceededMemory" | "loadShed" | "responseStreamDisconnected" | "scriptNotFound" | "internalError" | "exceededWallTime"; type EventOutcome = "ok" | "canceled" | "exception" | "unknown" | "killSwitch" | "daemonDown" | "exceededCpu" | "exceededMemory" | "loadShed" | "responseStreamDisconnected" | "scriptNotFound" | "internalError" | "exceededWallTime" | "aborted";
interface ScriptVersion { interface ScriptVersion {
readonly id: string; readonly id: string;
readonly tag?: string; readonly tag?: string;
@@ -14029,6 +14692,7 @@ declare namespace TailStream {
readonly dispatchNamespace?: string; readonly dispatchNamespace?: string;
readonly entrypoint?: string; readonly entrypoint?: string;
readonly executionModel: string; readonly executionModel: string;
readonly durableObjectId?: string;
readonly scriptName?: string; readonly scriptName?: string;
readonly scriptTags?: string[]; readonly scriptTags?: string[];
readonly scriptVersion?: ScriptVersion; readonly scriptVersion?: ScriptVersion;
@@ -14063,11 +14727,22 @@ declare namespace TailStream {
readonly message: string; readonly message: string;
readonly stack?: string; readonly stack?: string;
} }
interface Log { interface TailStreamErrorInfo {
readonly name: string;
readonly message: string;
readonly stack?: string;
}
type Log = {
readonly type: "log"; readonly type: "log";
readonly level: "debug" | "error" | "info" | "log" | "warn"; readonly level: "debug" | "error" | "info" | "log" | "warn";
readonly errorInfo?: readonly (TailStreamErrorInfo | null)[];
} & ({
readonly message: object; readonly message: object;
} readonly truncated?: false;
} | {
readonly message: string;
readonly truncated: true;
});
interface DroppedEventsDiagnostic { interface DroppedEventsDiagnostic {
readonly diagnosticsType: "droppedEvents"; readonly diagnosticsType: "droppedEvents";
readonly count: number; readonly count: number;
@@ -14545,10 +15220,31 @@ declare abstract class Workflow<PARAMS = unknown> {
* @returns A promise that resolves with a list of handles for the created instances. * @returns A promise that resolves with a list of handles for the created instances.
*/ */
public createBatch(batch: WorkflowInstanceCreateOptions<PARAMS>[]): Promise<WorkflowInstance[]>; public createBatch(batch: WorkflowInstanceCreateOptions<PARAMS>[]): Promise<WorkflowInstance[]>;
/**
* Delete a batch of Workflow instances and their stored state.
* `deleteBatch` is limited to 100 instances at a time. Duplicate IDs are deleted once.
* The result contains one entry for each input position; IDs that do not exist are returned as per-instance errors.
* @param instanceIds IDs of the Workflow instances to delete
* @returns A promise that resolves with the successfully deleted instances and any per-instance errors.
*/
public deleteBatch(instanceIds: string[]): Promise<WorkflowBatchDeleteResult>;
} }
type WorkflowBatchDeleteResult = {
deleted: {
id: string;
}[];
errors: {
id: string;
code: number;
message: string;
}[];
};
type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'; type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number; type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number;
type WorkflowRetentionDuration = WorkflowSleepDuration; type WorkflowRetentionDuration = WorkflowSleepDuration;
/** Geographic regions supported when creating a Workflow instance.
* Location hints are best-effort placement preferences. */
type WorkflowInstanceLocationHint = 'wnam' | 'enam' | 'sam' | 'weur' | 'eeur' | 'apac' | 'apac-ne' | 'apac-se' | 'oc' | 'afr' | 'me';
interface WorkflowInstanceCreateOptions<PARAMS = unknown> { interface WorkflowInstanceCreateOptions<PARAMS = unknown> {
/** /**
* An id for your Workflow instance. Must be unique within the Workflow. * An id for your Workflow instance. Must be unique within the Workflow.
@@ -14566,6 +15262,9 @@ interface WorkflowInstanceCreateOptions<PARAMS = unknown> {
successRetention?: WorkflowRetentionDuration; successRetention?: WorkflowRetentionDuration;
errorRetention?: WorkflowRetentionDuration; errorRetention?: WorkflowRetentionDuration;
}; };
/** A best-effort geographic placement preference for the Workflow instance.
* See `WorkflowInstanceLocationHint` for supported regions. */
locationHint?: WorkflowInstanceLocationHint;
} }
type InstanceStatus = { type InstanceStatus = {
status: 'queued' // means that instance is waiting to be started (see concurrency limits) status: 'queued' // means that instance is waiting to be started (see concurrency limits)
@@ -14583,6 +15282,13 @@ interface WorkflowError {
code?: number; code?: number;
message: string; message: string;
} }
interface WorkflowInstanceTerminateOptions {
/**
* If true, run registered rollback handlers before terminating the instance.
* Only steps that registered rollback handlers are rolled back.
*/
rollback?: boolean;
}
interface WorkflowInstanceRestartOptions { interface WorkflowInstanceRestartOptions {
/** /**
* Restart from a specific step. If omitted, the instance restarts from the beginning. * Restart from a specific step. If omitted, the instance restarts from the beginning.
@@ -14616,14 +15322,19 @@ declare abstract class WorkflowInstance {
public resume(): Promise<void>; public resume(): Promise<void>;
/** /**
* Terminate the instance. If it is errored, terminated or complete, an error will be thrown. * Terminate the instance. If it is errored, terminated or complete, an error will be thrown.
* @param options Options for termination, including whether registered rollback handlers should run.
*/ */
public terminate(): Promise<void>; public terminate(options?: WorkflowInstanceTerminateOptions): Promise<void>;
/** /**
* Restart the instance. Optionally restart from a specific step, preserving * Restart the instance. Optionally restart from a specific step, preserving
* cached results for all steps before it. * cached results for all steps before it.
* @param options Options for the restart, including an optional step to restart from. * @param options Options for the restart, including an optional step to restart from.
*/ */
public restart(options?: WorkflowInstanceRestartOptions): Promise<void>; public restart(options?: WorkflowInstanceRestartOptions): Promise<void>;
/**
* Delete the instance and its stored state.
*/
public delete(): Promise<void>;
/** /**
* Returns the current status of the instance. * Returns the current status of the instance.
*/ */
+9
View File
@@ -46,6 +46,15 @@
"secret_name": "META_APP_SECRET" "secret_name": "META_APP_SECRET"
} }
], ],
// Cloudflare Email Sending, for the password-recovery code (POST /account/recoverpassword).
// Nothing to splice in: the binding has no id, but the `from` domain (EMAIL_FROM, default
// no-reply@<DOMAIN>) has to be enabled for Email Sending once per account — see DEPLOYING.md.
// Locally (and under vitest) the binding logs the message rather than sending it.
"send_email": [
{
"name": "EMAIL"
}
],
"upload_source_maps": true, "upload_source_maps": true,
"observability": { "observability": {
"enabled": false "enabled": false
+3 -1
View File
@@ -17,11 +17,13 @@ export const SCHEMA_DDL: string[] = [
account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.accountId')) VIRTUAL, account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.accountId')) VIRTUAL,
username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.username'))) VIRTUAL, username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.username'))) VIRTUAL,
has_plus INTEGER GENERATED ALWAYS AS (json_extract(data, '$.hasPlus')) VIRTUAL, has_plus INTEGER GENERATED ALWAYS AS (json_extract(data, '$.hasPlus')) VIRTUAL,
is_influencer INTEGER GENERATED ALWAYS AS (json_extract(data, '$.isInfluencer')) VIRTUAL is_influencer INTEGER GENERATED ALWAYS AS (json_extract(data, '$.isInfluencer')) VIRTUAL,
email_lower TEXT GENERATED ALWAYS AS (NULLIF(lower(json_extract(data, '$.email')), '')) VIRTUAL
)`, )`,
`CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_account_id ON account (account_id)`, `CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_account_id ON account (account_id)`,
`CREATE INDEX IF NOT EXISTS idx_account_has_plus ON account (has_plus) WHERE has_plus = 1`, `CREATE INDEX IF NOT EXISTS idx_account_has_plus ON account (has_plus) WHERE has_plus = 1`,
`CREATE INDEX IF NOT EXISTS idx_account_is_influencer ON account (is_influencer) WHERE is_influencer = 1`, `CREATE INDEX IF NOT EXISTS idx_account_is_influencer ON account (is_influencer) WHERE is_influencer = 1`,
`CREATE UNIQUE INDEX IF NOT EXISTS idx_account_email_lower ON account (email_lower) WHERE email_lower IS NOT NULL`,
] ]
/** The stored avatar payload — opaque JSON the client sets and reads back. */ /** The stored avatar payload — opaque JSON the client sets and reads back. */
+413 -9
View File
@@ -584,6 +584,30 @@ const saveEmail = (email: string): Promise<unknown> =>
refusal: 'That email address looks wrong.', refusal: 'That email address looks wrong.',
}) })
/**
* The email change awaiting a code, if any: `saveEmail` STAGES the address and `accounts`
* emails six-digit codes — first to the current address when there is one (so a stolen
* session can't move it), then to the new one (so a typo is never stored). `sentTo` says
* which step this is. Each code is spent with {@link confirmEmail}. This read is what lets
* the form show the code step after a reload, or right after signup.
*/
interface PendingEmail {
pending: string | null
sentTo: string | null
}
const fetchPendingEmail = (): Promise<PendingEmail> =>
call<PendingEmail>(`${where().accounts}/account/me/email/pending`, { authed: true })
/**
* Spend the code from the email. One try per code. `applied` false means the current address
* has approved and a second code is now out to the new one, which `pending`/`sentTo` name.
*/
const confirmEmail = (code: string): Promise<PendingEmail & { applied: boolean }> =>
call<PendingEmail & { applied: boolean }>(`${where().accounts}/account/me/email/confirm`, {
form: { code },
authed: true,
})
/** Change the account's password. Lives on `auth`, not `accounts`. */ /** Change the account's password. Lives on `auth`, not `accounts`. */
const changePassword = (oldPassword: string, newPassword: string): Promise<unknown> => const changePassword = (oldPassword: string, newPassword: string): Promise<unknown> =>
call(`${where().auth}/account/me/changepassword`, { call(`${where().auth}/account/me/changepassword`, {
@@ -591,6 +615,24 @@ const changePassword = (oldPassword: string, newPassword: string): Promise<unkno
authed: true, authed: true,
}) })
/**
* "Forgot password": ask `auth` to email a recovery code to the address. The same route the
* game posts, so it answers in the client's PascalCase envelope — and a refusal is a 200
* with `Success: false`, which `call` doesn't throw on, hence the check here. `Success: true`
* says nothing about whether the address is on an account; the page's copy allows for that.
*/
const recoverPassword = async (email: string): Promise<void> => {
const r = await call<{ Success: boolean; Error: string | null }>(
`${where().auth}/account/recoverpassword`,
{ form: { email } }
)
if (!r.Success) throw new Error(r.Error || 'The recovery email could not be sent.')
}
/** Finish the recovery: the address, the code from the email, and the password to set. */
const resetPassword = (email: string, code: string, newPassword: string): Promise<unknown> =>
call(`${where().auth}/account/resetpassword`, { form: { email, code, newPassword } })
/** Where this account's benefits stand: `www` reads them off the account row. */ /** Where this account's benefits stand: `www` reads them off the account row. */
interface BenefitsStatus { interface BenefitsStatus {
/** Whether the account already has Rec Room Plus. */ /** Whether the account already has Rec Room Plus. */
@@ -2460,6 +2502,21 @@ export function App() {
navigate={navigate} navigate={navigate}
onAuthed={setAccount} onAuthed={setAccount}
/> />
) : path === '/confirm-email' ? (
// Where the email-change confirmation's link lands (`?code=…`). Wants the
// account's own session — the code approves the change, the session says whose —
// so a signed-out visitor is sent through sign-in and back.
<ConfirmEmailPage
account={account}
search={search}
navigate={navigate}
onChange={setAccount}
/>
) : path === '/reset-password' ? (
// Where the recovery email's link lands (`?email=…&code=…`), and where "Forgot
// your password?" on the sign-in page goes. Needs no session — the emailed code
// is the credential — and a client-side route like the rest.
<ResetPasswordPage search={search} navigate={navigate} />
) : path === '/device' ? ( ) : path === '/device' ? (
// Studio opens this from verification_uri_complete. The code was minted by // Studio opens this from verification_uri_complete. The code was minted by
// auth; this page only approves it with the website session. // auth; this page only approves it with the website session.
@@ -2956,6 +3013,11 @@ function LoginPage({
your Steam ID — set a password on it and it signs in here too. your Steam ID — set a password on it and it signs in here too.
</p> </p>
<LoginForm onAuthed={authed} /> <LoginForm onAuthed={authed} />
<p className="muted swap">
<Link to="/reset-password" navigate={navigate}>
Forgot your password?
</Link>
</p>
{/* The other door. Shown on the server's say-so like the signup tab: the URL is {/* The other door. Shown on the server's say-so like the signup tab: the URL is
null until the Discord app is configured. `next` rides along through Discord in null until the Discord app is configured. `next` rides along through Discord in
sessionStorage, since the round trip drops the query. */} sessionStorage, since the round trip drops the query. */}
@@ -2993,6 +3055,277 @@ function LoginPage({
) )
} }
/**
* `/confirm-email` — where the email-change emails' links land, with the code in the query.
* The code approves a step and the account's own session says whose, so this wants a
* sign-in: a signed-out visitor goes through `/login` and comes back here. The account
* page's email card does the same thing without the link; this page exists so the emails
* have somewhere to point. Both steps' emails point here: after the current address
* approves, the page waits for the new address's code.
*/
function ConfirmEmailPage({
account,
search,
navigate,
onChange,
}: {
account: SelfAccount | null | undefined
search: string
navigate: Navigate
onChange: (a: SelfAccount) => void
}) {
const [code, setCode] = useState(new URLSearchParams(search).get('code') ?? '')
const [pending, setPending] = useState<PendingEmail | null | undefined>(undefined)
const [approved, setApproved] = useState('')
const { pending: busy, error, done, run } = useAction()
useEffect(() => {
if (account === null) navigate(`/login?next=${encodeURIComponent(`/confirm-email${search}`)}`)
}, [account, navigate, search])
useEffect(() => {
if (!account) return
fetchPendingEmail()
.then((p) => setPending(p.pending === null ? null : p))
.catch(() => setPending(null))
}, [account])
if (!account) return null
return (
<main className="shell">
<section className="card">
<h2>Confirm your email change</h2>
{done ? (
<>
<p className="ok">{done}</p>
<p className="muted swap">
<Link to="/account" navigate={navigate}>
Back to your account
</Link>
</p>
</>
) : pending === null ? (
<>
<p className="muted">
No email change is waiting on <strong>@{account.username}</strong>. It may already be
confirmed, or the code may have lapsed or been used — save the address again from your
account page for a new one.
</p>
<p className="muted swap">
<Link to="/account" navigate={navigate}>
Go to your account
</Link>
</p>
</>
) : (
<form
onSubmit={(e) => {
e.preventDefault()
void run(async () => {
const next = await confirmEmail(code.trim())
if (!next.applied) {
// Step 1 done; the second code's email links back here too. Not
// `done`: the page stays on the form for that code.
setPending(next)
setCode('')
setApproved(
`Approved. A second code was emailed to ${next.sentTo} — enter it here, or follow that email's link.`
)
return ''
}
const applied = pending?.pending ?? ''
onChange({ ...account, email: applied })
return `Your account's email is now ${applied}.`
})
}}
>
{pending && (
<p className="muted">
Changing <strong>@{account.username}</strong>&apos;s email to{' '}
<strong>{pending.pending}</strong>. Enter the code sent to{' '}
<strong>{pending.sentTo}</strong>. It works once: a wrong code voids the change.
{pending.sentTo !== pending.pending &&
' Once approved, a second code goes to the new address.'}
</p>
)}
{approved && <p className="ok">{approved}</p>}
<label>
Code
<input
type="text"
inputMode="numeric"
pattern="[0-9]{6}"
value={code}
autoComplete="one-time-code"
onChange={(e) => setCode(e.target.value)}
required
/>
</label>
{error && <p className="error">{error}</p>}
<button type="submit" disabled={busy || pending === undefined}>
{busy ? 'Confirming…' : 'Confirm'}
</button>
</form>
)}
</section>
</main>
)
}
/**
* `/reset-password` — password recovery, both halves. With no code in the query it asks for
* the email address on the account and has `auth` send the code; with one (the email's link
* carries both the address and the code) it asks for the new password and posts the three
* together. Whoever typed the code by hand, or asked for the email here and then read it,
* switches to the second form with the link under the first.
*
* The code is spent by ONE attempt, right or wrong — `auth` voids the recovery on a wrong
* code so it can't be guessed — so a refusal here points back at requesting a new email
* rather than inviting a retry of the code.
*/
function ResetPasswordPage({ search, navigate }: { search: string; navigate: Navigate }) {
const params = new URLSearchParams(search)
const [email, setEmail] = useState(params.get('email') ?? '')
const [code, setCode] = useState(params.get('code') ?? '')
const [newPassword, setNewPassword] = useState('')
// The link arrives with a code; a visitor from the sign-in page doesn't have one yet.
const [haveCode, setHaveCode] = useState(params.get('code') !== null)
const request = useAction()
const finish = useAction()
return (
<main className="shell">
<section className="card">
{haveCode ? (
<>
<h2>Choose a new password</h2>
<p className="muted">
Enter the six-digit code from the email and the password you want. The code works
once, for 30 minutes.
</p>
{finish.done ? (
<>
<p className="ok">{finish.done}</p>
<p className="muted swap">
<Link to="/login" navigate={navigate}>
Sign in
</Link>
</p>
</>
) : (
<form
onSubmit={(e) => {
e.preventDefault()
void finish.run(async () => {
await resetPassword(email.trim(), code.trim(), newPassword)
return 'Your password has been changed. Sign in with it here or in the game.'
})
}}
>
<label>
Email address
<input
type="email"
value={email}
autoComplete="email"
onChange={(e) => setEmail(e.target.value)}
required
/>
</label>
<label>
Code
<input
type="text"
inputMode="numeric"
pattern="[0-9]{6}"
value={code}
autoComplete="one-time-code"
onChange={(e) => setCode(e.target.value)}
required
/>
</label>
<label>
New password
<input
type="password"
value={newPassword}
autoComplete="new-password"
onChange={(e) => setNewPassword(e.target.value)}
required
/>
</label>
{finish.error && <p className="error">{finish.error}</p>}
<button type="submit" disabled={finish.pending}>
{finish.pending ? 'Saving…' : 'Set password'}
</button>
</form>
)}
{!finish.done && (
<p className="muted swap">
No code, or it stopped working?{' '}
<a
href="/reset-password"
onClick={(e) => {
e.preventDefault()
setHaveCode(false)
}}
>
Request a new email
</a>
</p>
)}
</>
) : (
<>
<h2>Reset your password</h2>
<p className="muted">
Enter the email address on your account. If there is an account under it, we&apos;ll
email you a six-digit code and a link to come back here.
</p>
<form
onSubmit={(e) => {
e.preventDefault()
void request.run(async () => {
await recoverPassword(email.trim())
return "If that address is on an account, an email is on its way. Check your inbox (and spam folder), then enter the code here or follow the email's link."
})
}}
>
<label>
Email address
<input
type="email"
value={email}
autoComplete="email"
onChange={(e) => setEmail(e.target.value)}
required
/>
</label>
{request.error && <p className="error">{request.error}</p>}
{request.done && <p className="ok">{request.done}</p>}
<button type="submit" disabled={request.pending}>
{request.pending ? 'Sending…' : 'Email me a code'}
</button>
</form>
<p className="muted swap">
Already have a code?{' '}
<a
href="/reset-password"
onClick={(e) => {
e.preventDefault()
setHaveCode(true)
}}
>
Enter it
</a>
</p>
</>
)}
</section>
</main>
)
}
/** /**
* `/login/discord` — the page Discord redirects a SIGN-IN back to. Its own route rather than * `/login/discord` — the page Discord redirects a SIGN-IN back to. Its own route rather than
* `/claim`, because that page wants a session before it does anything and this is how one * `/claim`, because that page wants a session before it does anything and this is how one
@@ -4348,7 +4681,8 @@ function SignupForm({
// Saved with the new session's own token: `create_account` takes no email, // Saved with the new session's own token: `create_account` takes no email,
// `accounts` owns the field. Deliberately not fatal — the account exists and // `accounts` owns the field. Deliberately not fatal — the account exists and
// the session is live, and the same field is one call away on the account // the session is live, and the same field is one call away on the account
// page. // page. The address is STAGED, not set: `accounts` emails it a code, and the
// account page (where this lands) picks the pending change up and asks for it.
if (wanted !== '') await saveEmail(wanted).catch(() => {}) if (wanted !== '') await saveEmail(wanted).catch(() => {})
// The session is already stored, so a failure here isn't one they can act on // The session is already stored, so a failure here isn't one they can act on
@@ -5388,18 +5722,43 @@ function EmailForm({
onChange: (a: SelfAccount) => void onChange: (a: SelfAccount) => void
}) { }) {
const [email, setEmail] = useState(account.email ?? '') const [email, setEmail] = useState(account.email ?? '')
const { pending, error, done, run } = useAction() // The change a code is out for, once `accounts` says so — asked on mount, so a reload
// (or arriving here straight from signup, which saved the address) resumes at the code.
const [pending, setPending] = useState<PendingEmail | null>(null)
const [code, setCode] = useState('')
const save = useAction()
const confirm = useAction()
useEffect(() => {
fetchPendingEmail()
.then((p) => setPending(p.pending === null ? null : p))
.catch(() => {})
}, [])
return ( return (
<section className="card"> <section className="card">
<h2>Email</h2> <h2>Email</h2>
<p className="muted">
Used to recover your password, so changing it takes a code at your current address to
approve it, then one at the new address to confirm it. With no address yet, just the second.
</p>
<form <form
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault() e.preventDefault()
void run(async () => { void save.run(async () => {
await saveEmail(email.trim()) const wanted = email.trim()
onChange({ ...account, email }) await saveEmail(wanted)
// Re-saving the current address applies at once; anything else is staged
// and `accounts` knows where the code went.
const now = await fetchPendingEmail().catch(() => null)
if (now === null || now.pending === null) {
onChange({ ...account, email: wanted })
setPending(null)
return 'Email saved.' return 'Email saved.'
}
setPending(now)
setCode('')
return `A six-digit code was emailed to ${now.sentTo}. Enter it below.`
}) })
}} }}
> >
@@ -5413,12 +5772,57 @@ function EmailForm({
required required
/> />
</label> </label>
{error && <p className="error">{error}</p>} {save.error && <p className="error">{save.error}</p>}
{done && <p className="ok">{done}</p>} {save.done && <p className="ok">{save.done}</p>}
<button type="submit" disabled={pending}> <button type="submit" disabled={save.pending}>
{pending ? 'Saving…' : 'Save email'} {save.pending ? 'Saving…' : 'Save email'}
</button> </button>
</form> </form>
{pending && (
<form
onSubmit={(e) => {
e.preventDefault()
void confirm.run(async () => {
const next = await confirmEmail(code.trim())
setCode('')
if (!next.applied) {
// Step 1 done: the current address approved. Step 2's code is out.
setPending(next)
return `Approved. A second code was emailed to ${next.sentTo} — enter it to finish.`
}
const applied = pending.pending ?? ''
onChange({ ...account, email: applied })
setEmail(applied)
setPending(null)
return 'Email changed.'
})
}}
>
<p className="muted">
Changing to <strong>{pending.pending}</strong>. Enter the code sent to{' '}
<strong>{pending.sentTo}</strong> — it works once, for 30 minutes. Wrong code, or
mistyped the address? Save the address again for a new one.
</p>
<label>
Code
<input
type="text"
inputMode="numeric"
pattern="[0-9]{6}"
value={code}
autoComplete="one-time-code"
onChange={(e) => setCode(e.target.value)}
required
/>
</label>
{confirm.error && <p className="error">{confirm.error}</p>}
{confirm.done && <p className="ok">{confirm.done}</p>}
<button type="submit" disabled={confirm.pending}>
{confirm.pending ? 'Confirming…' : 'Confirm'}
</button>
</form>
)}
{!pending && confirm.done && <p className="ok">{confirm.done}</p>}
</section> </section>
) )
} }
+2 -1
View File
@@ -1574,7 +1574,8 @@ export async function addUsernameChangeHandler(c: Context<App>) {
/** /**
* Remove a player's password so they can set a new one in game — the recovery for someone * Remove a player's password so they can set a new one in game — the recovery for someone
* who has forgotten it, since nothing here can send a reset email. `hadPassword` says whether * who has forgotten it AND has no email on the account (with one, "Forgot password" in game
* or `/reset-password` here emails them a code via `auth`). `hadPassword` says whether
* there was one to remove; clearing an already-clear password succeeds, and is still logged. * there was one to remove; clearing an already-clear password succeeds, and is still logged.
*/ */
export async function clearPasswordHandler(c: Context<App>) { export async function clearPasswordHandler(c: Context<App>) {
+5 -5
View File
@@ -714,7 +714,7 @@ it('reports where an account stands on benefits', async () => {
// Claimed (roles recorded, even none). `linked` says THAT a Discord identity has claimed, // Claimed (roles recorded, even none). `linked` says THAT a Discord identity has claimed,
// never which one — the id is of no use to the page, and an account's linked identities // never which one — the id is of no use to the page, and an account's linked identities
// have no business on the wire. // have no business on the wire.
await updateAccount(env.DB, 4003, { email: 'p@example.com' }) await updateAccount(env.DB, 4003, { email: 'p4003@example.com' })
await linkPlatformIdentity(env.DB, 4003, PlatformType.Discord, '99001', []) await linkPlatformIdentity(env.DB, 4003, PlatformType.Discord, '99001', [])
res = await SELF.fetch('https://example.com/api/benefits/status', { res = await SELF.fetch('https://example.com/api/benefits/status', {
headers: { authorization: `Bearer ${token}` }, headers: { authorization: `Bearer ${token}` },
@@ -765,7 +765,7 @@ it('refuses to unlink a discord until the account has an email address', async (
) )
// An email alone, no password, is enough. // An email alone, no password, is enough.
await updateAccount(env.DB, 4021, { passwordHash: undefined, email: 'p@example.com' }) await updateAccount(env.DB, 4021, { passwordHash: undefined, email: 'p4021@example.com' })
expect((await unlink(token)).status).toBe(200) expect((await unlink(token)).status).toBe(200)
await expect(isPlatformIdentityLinked(env.DB, 4021, PlatformType.Discord, '99021')).resolves.toBe( await expect(isPlatformIdentityLinked(env.DB, 4021, PlatformType.Discord, '99021')).resolves.toBe(
false false
@@ -776,7 +776,7 @@ it('unlinks every discord on the account, and takes plus and studio with it', as
const token = await tokenFor(4022) const token = await tokenFor(4022)
await updateAccount(env.DB, 4022, { await updateAccount(env.DB, 4022, {
username: 'Leaver', username: 'Leaver',
email: 'p@example.com', email: 'p4022@example.com',
hasPlus: true, hasPlus: true,
hasStudio: true, hasStudio: true,
}) })
@@ -811,7 +811,7 @@ it('unlinks every discord on the account, and takes plus and studio with it', as
expect(after?.hasPlus).toBeUndefined() expect(after?.hasPlus).toBeUndefined()
expect(after?.hasStudio).toBeUndefined() expect(after?.hasStudio).toBeUndefined()
expect(after?.username).toBe('Leaver') expect(after?.username).toBe('Leaver')
expect(after?.email).toBe('p@example.com') expect(after?.email).toBe('p4022@example.com')
// Nothing left to unlink. // Nothing left to unlink.
const again = await unlink(token) const again = await unlink(token)
@@ -823,7 +823,7 @@ it('unlinks every discord on the account, and takes plus and studio with it', as
// that player's first claim, on whatever account they next link, is still their first. // that player's first claim, on whatever account they next link, is still their first.
it('does not remember a claim when the unlinked discord never claimed', async () => { it('does not remember a claim when the unlinked discord never claimed', async () => {
const token = await tokenFor(4023) const token = await tokenFor(4023)
await updateAccount(env.DB, 4023, { email: 'p@example.com' }) await updateAccount(env.DB, 4023, { email: 'p4023@example.com' })
await linkPlatformIdentity(env.DB, 4023, PlatformType.Discord, '99024') await linkPlatformIdentity(env.DB, 4023, PlatformType.Discord, '99024')
expect((await unlink(token)).status).toBe(200) expect((await unlink(token)).status).toBe(200)
expect((await getAccount(env.DB, 4023))?.hasClaimedDiscord).toBeUndefined() expect((await getAccount(env.DB, 4023))?.hasClaimedDiscord).toBeUndefined()
+27 -2
View File
@@ -32,12 +32,17 @@ export const SCHEMA_DDL: string[] = [
account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.accountId')) VIRTUAL, account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.accountId')) VIRTUAL,
username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.username'))) VIRTUAL, username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.username'))) VIRTUAL,
has_plus INTEGER GENERATED ALWAYS AS (json_extract(data, '$.hasPlus')) VIRTUAL, has_plus INTEGER GENERATED ALWAYS AS (json_extract(data, '$.hasPlus')) VIRTUAL,
is_influencer INTEGER GENERATED ALWAYS AS (json_extract(data, '$.isInfluencer')) VIRTUAL is_influencer INTEGER GENERATED ALWAYS AS (json_extract(data, '$.isInfluencer')) VIRTUAL,
email_lower TEXT GENERATED ALWAYS AS (NULLIF(lower(json_extract(data, '$.email')), '')) VIRTUAL
)`, )`,
`CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_account_id ON account (account_id)`, `CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_account_id ON account (account_id)`,
`CREATE INDEX IF NOT EXISTS idx_accounts_username_lower ON account (username_lower)`, `CREATE INDEX IF NOT EXISTS idx_accounts_username_lower ON account (username_lower)`,
`CREATE INDEX IF NOT EXISTS idx_account_has_plus ON account (has_plus) WHERE has_plus = 1`, `CREATE INDEX IF NOT EXISTS idx_account_has_plus ON account (has_plus) WHERE has_plus = 1`,
`CREATE INDEX IF NOT EXISTS idx_account_is_influencer ON account (is_influencer) WHERE is_influencer = 1`, `CREATE INDEX IF NOT EXISTS idx_account_is_influencer ON account (is_influencer) WHERE is_influencer = 1`,
// An email address belongs to ONE account: password recovery (`auth`
// `POST /account/recoverpassword`) is handed nothing but the address and has to find the
// account from it. Case-insensitive, and an empty/absent email is NULL so it never collides.
`CREATE UNIQUE INDEX IF NOT EXISTS idx_account_email_lower ON account (email_lower) WHERE email_lower IS NOT NULL`,
] ]
/** Client-facing account shape (camelCase, exactly as the client's AccountDTO). */ /** Client-facing account shape (camelCase, exactly as the client's AccountDTO). */
@@ -105,7 +110,12 @@ export interface Account {
signupIp?: string signupIp?: string
/** The client IP of the most recent successful login; refreshed on every login. */ /** The client IP of the most recent successful login; refreshed on every login. */
lastLoginIp?: string lastLoginIp?: string
/** Set via POST /account/me/email; absent until the player provides one. */ /**
* Set via POST /account/me/email; absent until the player provides one. UNIQUE across
* accounts, case-insensitively (`idx_account_email_lower`): it is the one thing a password
* recovery is given to find the account by, so `accounts` refuses an address another account
* holds. Look an account up by it with {@link getAccountByEmail}.
*/
email?: string email?: string
/** Set via POST /account/me/phone; absent until the player provides one. */ /** Set via POST /account/me/phone; absent until the player provides one. */
phone?: string phone?: string
@@ -308,6 +318,21 @@ export async function getAccountByUsername(
} }
/** Default cap on how many matches `searchAccounts` returns. */ /** Default cap on how many matches `searchAccounts` returns. */
/**
* The account holding an email address, or null when none does. Case-insensitive, over the
* `email_lower` index, and an address is held by at most one account (see {@link Account.email}).
* Whitespace around the address is ignored; an empty address matches nothing.
*/
export async function getAccountByEmail(db: D1Database, email: string): Promise<Account | null> {
const needle = email.trim().toLowerCase()
if (needle === '') return null
const row = await db
.prepare('SELECT data FROM account WHERE email_lower = ?1')
.bind(needle)
.first<{ data: string }>()
return row ? (JSON.parse(row.data) as Account) : null
}
export const SEARCH_LIMIT = 20 export const SEARCH_LIMIT = 20
/** Escape LIKE wildcards so user input is matched literally (using `\` as the escape char). */ /** Escape LIKE wildcards so user input is matched literally (using `\` as the escape char). */
+218
View File
@@ -0,0 +1,218 @@
/**
* One-shot codes sent by email, on the shared `recflare` D1 database (owned by the `auth`
* worker, migration 0014). Two things are confirmed this way, each a `purpose`:
*
* - `password_reset` — "Forgot password" (`auth` `/account/recoverpassword` issues the
* code, `/account/resetpassword` spends it). Payload: none.
* - `email_change` — the CURRENT address approving a change away from it (`accounts`
* `/account/me/email` issues it, `/account/me/email/confirm` spends it). Payload: the
* new address. Spending it issues the next:
* - `email_verify` — the NEW address confirming it is reachable, and the step that applies
* the change; the only step for an account with no address yet. Payload: the new address.
*
* The rules, all of which exist because a six-digit code is guessable:
*
* - ONE pending code per account and purpose; a new request replaces the old, so the latest
* email is the one that works.
* - ONE attempt per code. A wrong guess BURNS the row (`code_hash` goes NULL) rather than
* leaving it open to the next guess — the player has to request a fresh email, which is
* what "restart" means. The row itself stays, so the resend cooldown below still counts
* from the last email.
* - A code lapses after {@link EMAIL_CODE_TTL_SECONDS}.
* - A fresh email goes out at most once per {@link EMAIL_CODE_RESEND_COOLDOWN_SECONDS} per
* account and purpose, however often one is asked for — recovery can be requested by
* anyone who knows an address, and without this it would be a way to flood someone's
* inbox. Within the cooldown nothing is issued and nothing should be sent.
*
* Only a PBKDF2 hash of the code is stored (the same `hashPassword` as an account's
* password), never the code: a copy of the table shouldn't be a way into every account with
* a code in flight.
*/
import { hashPassword, verifyPassword } from './password'
/** What a code is for; one pending code per account and purpose. */
export type EmailCodePurpose = 'password_reset' | 'email_change' | 'email_verify'
/** A code is good for this long (s) after the email is sent. */
export const EMAIL_CODE_TTL_SECONDS = 30 * 60
/** Another email for the same purpose to the same account is refused within this long (s). */
export const EMAIL_CODE_RESEND_COOLDOWN_SECONDS = 2 * 60
/** The code's length in digits. The emails and the website's forms all print it this wide. */
export const EMAIL_CODE_LENGTH = 6
/** Schema DDL (mirror of apps/auth/migrations/0014_email_code.sql). */
export const EMAIL_CODE_SCHEMA_DDL: string[] = [
`CREATE TABLE IF NOT EXISTS email_code (
account_id INTEGER NOT NULL,
purpose TEXT NOT NULL,
code_hash TEXT,
payload TEXT,
created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL,
PRIMARY KEY (account_id, purpose)
)`,
]
/** A fresh code: {@link EMAIL_CODE_LENGTH} decimal digits, leading zeros included. */
export function newEmailCode(): string {
// Rejection-sampled from a uint32 so every code is equally likely — a bare modulo
// would favour the low codes slightly.
const limit = 10 ** EMAIL_CODE_LENGTH
const cap = Math.floor(2 ** 32 / limit) * limit
const buf = new Uint32Array(1)
let n: number
do {
crypto.getRandomValues(buf)
n = buf[0]!
} while (n >= cap)
return String(n % limit).padStart(EMAIL_CODE_LENGTH, '0')
}
/**
* Whether `code` is shaped like one of ours: exactly {@link EMAIL_CODE_LENGTH} digits. Checked
* before the hash so a malformed guess doesn't spend a PBKDF2 round — but a malformed guess
* still counts as a guess, see {@link completeEmailCode}.
*/
export const isEmailCodeShaped = (code: string): boolean =>
new RegExp(`^\\d{${EMAIL_CODE_LENGTH}}$`).test(code)
/**
* Issue a code for the account and purpose, replacing any pending one, and return it — the
* only moment it exists in plaintext. `payload` rides along to be handed back when the code
* is spent. Returns null when a code for this account and purpose was issued less than the
* cooldown ago (burned or not): nothing changed — the pending code and ITS payload stand —
* and nothing should be sent. `force` skips that check, for a caller that has its own reason
* to know the send is not a repeat (a code going to a DIFFERENT address than the last one,
* or a step a previous code has just unlocked).
*/
export async function beginEmailCode(
db: D1Database,
purpose: EmailCodePurpose,
accountId: number,
payload: string | null = null,
{ force = false }: { force?: boolean } = {}
): Promise<string | null> {
const now = Math.floor(Date.now() / 1000)
if (!force) {
const recent = await db
.prepare(
'SELECT created_at AS createdAt FROM email_code WHERE account_id = ?1 AND purpose = ?2'
)
.bind(accountId, purpose)
.first<{ createdAt: number }>()
if (recent && now - recent.createdAt < EMAIL_CODE_RESEND_COOLDOWN_SECONDS) return null
}
const code = newEmailCode()
await db
.prepare(
`INSERT INTO email_code (account_id, purpose, code_hash, payload, created_at, expires_at)
VALUES (?1, ?2, ?3, ?4, ?5, ?6)
ON CONFLICT (account_id, purpose) DO UPDATE SET
code_hash = excluded.code_hash,
payload = excluded.payload,
created_at = excluded.created_at,
expires_at = excluded.expires_at`
)
.bind(accountId, purpose, await hashPassword(code), payload, now, now + EMAIL_CODE_TTL_SECONDS)
.run()
return code
}
/**
* The payload of the account's LIVE code for a purpose — issued, not burned, not lapsed — or
* null when there is none. What a page asks to show "a code is on its way to …" after a
* reload. Says nothing about the code itself.
*/
export async function pendingEmailCode(
db: D1Database,
purpose: EmailCodePurpose,
accountId: number
): Promise<{ payload: string | null; expiresAt: number } | null> {
const now = Math.floor(Date.now() / 1000)
const row = await db
.prepare(
`SELECT payload, expires_at AS expiresAt FROM email_code
WHERE account_id = ?1 AND purpose = ?2 AND code_hash IS NOT NULL AND expires_at >= ?3`
)
.bind(accountId, purpose, now)
.first<{ payload: string | null; expiresAt: number }>()
return row ?? null
}
/**
* Drop the account's pending code for a purpose, cooldown and all — for when the email it
* was issued for never went out, so the player can ask again straight away.
*/
export async function cancelEmailCode(
db: D1Database,
purpose: EmailCodePurpose,
accountId: number
): Promise<void> {
await db
.prepare('DELETE FROM email_code WHERE account_id = ?1 AND purpose = ?2')
.bind(accountId, purpose)
.run()
}
export type EmailCodeOutcome =
{ outcome: 'ok'; payload: string | null } | { outcome: 'wrong' } | { outcome: 'none' }
/**
* Spend the account's pending code for a purpose. `ok` deletes the row and hands back the
* payload it was issued with. `wrong` means the code didn't match — the row is BURNED, and
* the player has to request a new email. `none` means there was nothing to match against:
* no request, a lapsed one (deleted here), or one already burned. The two failures are told
* apart for the log only; the player is told the same thing either way, so a guesser learns
* nothing from the answer about whether a code is in flight.
*/
export async function completeEmailCode(
db: D1Database,
purpose: EmailCodePurpose,
accountId: number,
code: string
): Promise<EmailCodeOutcome> {
const now = Math.floor(Date.now() / 1000)
const row = await db
.prepare(
`SELECT code_hash AS codeHash, payload, expires_at AS expiresAt FROM email_code
WHERE account_id = ?1 AND purpose = ?2`
)
.bind(accountId, purpose)
.first<{ codeHash: string | null; payload: string | null; expiresAt: number }>()
if (!row || row.codeHash === null) return { outcome: 'none' }
if (row.expiresAt < now) {
await cancelEmailCode(db, purpose, accountId)
return { outcome: 'none' }
}
const matches = isEmailCodeShaped(code) && (await verifyPassword(code, row.codeHash))
if (!matches) {
// Burn, don't delete: the row's `created_at` is what the resend cooldown counts from.
await db
.prepare('UPDATE email_code SET code_hash = NULL WHERE account_id = ?1 AND purpose = ?2')
.bind(accountId, purpose)
.run()
return { outcome: 'wrong' }
}
await cancelEmailCode(db, purpose, accountId)
return { outcome: 'ok', payload: row.payload }
}
/**
* The address a worker's emails come from: `EMAIL_FROM` (set for every worker from the root
* `.env` as `RECFLARE_EMAIL_FROM`), else `no-reply@<DOMAIN>`. Its domain must be one Email
* Sending has been enabled on (`wrangler email sending enable`, see DEPLOYING.md) — Cloudflare
* refuses a send from any other.
*/
export function emailSender(env: { DOMAIN: string; EMAIL_FROM?: string }): string {
return env.EMAIL_FROM?.trim() || `no-reply@${env.DOMAIN}`
}
/** Escape text for the HTML half of an email. */
export const escapeHtml = (s: string): string =>
s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')
+1
View File
@@ -13,6 +13,7 @@ export * from './audit-db'
export * from './clubs-db' export * from './clubs-db'
export * from './d1-binds' export * from './d1-binds'
export * from './images-db' export * from './images-db'
export * from './email-code-db'
export * from './password' export * from './password'
export * from './player-settings-kv' export * from './player-settings-kv'
export * from './rooms-db' export * from './rooms-db'