diff --git a/packages/parse-email-address/.eslintrc.js b/packages/parse-email-address/.eslintrc.js new file mode 100644 index 000000000..ecc28524e --- /dev/null +++ b/packages/parse-email-address/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + parser: '@typescript-eslint/parser', + plugins: ['ghost'], + extends: [ + 'plugin:ghost/node' + ] +}; diff --git a/packages/parse-email-address/LICENSE b/packages/parse-email-address/LICENSE new file mode 100644 index 000000000..efad547e8 --- /dev/null +++ b/packages/parse-email-address/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2013-2026 Ghost Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/parse-email-address/README.md b/packages/parse-email-address/README.md new file mode 100644 index 000000000..8c50cfa55 --- /dev/null +++ b/packages/parse-email-address/README.md @@ -0,0 +1,49 @@ +# Parse Email Address + +Extract the local and domain parts of email address strings. + +## Install + +`npm install @tryghost/parse-email-address --save` + +or + +`yarn add @tryghost/parse-email-address` + +## Usage + +```javascript +import { parseEmailAddress } from '@tryghost/parse-email-address'; + +parseEmailAddress('foo@example.com'); +// => {local: 'foo', domain: 'example.com'} + +parseEmailAddress('invalid'); +// => null + +parseEmailAddress('foo@中文.example'); +// => {local: 'foo', domain: 'xn--fiq228c.example'} +``` + +- Domain names must have at least two labels. `example.com` is okay, `example` is not. +- The top level domain must have at least two octets. `example.com` is okay, `example.x` is not. +- There are various length limits: + - The whole email is limited to 986 octets, per SMTP. + - Domain names are limited to 253 octets, per SMTP. + - Domain labels are limited to 63 octets, per DNS. + +## Develop + +This is a monorepo package. + +Follow the instructions for the top-level repo. +1. `git clone` this repo & `cd` into it as usual +2. Run `yarn` to install top-level dependencies. + + + +## Test + +- `yarn lint` run just eslint +- `yarn test` run lint and tests + diff --git a/packages/parse-email-address/package.json b/packages/parse-email-address/package.json new file mode 100644 index 000000000..fb3da8a3a --- /dev/null +++ b/packages/parse-email-address/package.json @@ -0,0 +1,37 @@ +{ + "name": "@tryghost/parse-email-address", + "version": "0.0.0", + "repository": "https://github.com/TryGhost/framework/tree/main/packages/parse-email-address", + "author": "Ghost Foundation", + "license": "MIT", + "main": "build/index.js", + "types": "build/index.d.ts", + "scripts": { + "dev": "tsc --watch --preserveWatchOutput --sourceMap", + "build": "yarn build:ts", + "build:ts": "tsc", + "prepare": "tsc", + "test:unit": "NODE_ENV=testing c8 --src src --all --check-coverage --100 --reporter text --reporter cobertura mocha -r ts-node/register './test/**/*.test.ts'", + "test": "yarn test:types && yarn test:unit", + "test:types": "tsc --noEmit", + "lint:code": "eslint src/ --ext .ts --cache", + "lint": "yarn lint:code && yarn lint:test", + "lint:test": "eslint -c test/.eslintrc.js test/ --ext .ts --cache" + }, + "files": [ + "build" + ], + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "c8": "10.1.3", + "mocha": "11.7.5", + "sinon": "21.0.1", + "ts-node": "10.9.2", + "typescript": "5.9.3" + }, + "dependencies": { + "parse-email-address": "^0.0.2" + } +} diff --git a/packages/parse-email-address/src/index.ts b/packages/parse-email-address/src/index.ts new file mode 100644 index 000000000..e8c42ab76 --- /dev/null +++ b/packages/parse-email-address/src/index.ts @@ -0,0 +1,20 @@ +import {parseEmailAddress as upstreamParseEmailAddress} from 'parse-email-address'; +import {domainToASCII} from 'node:url'; + +export const parseEmailAddress = ( + emailAddress: string +): null | { local: string; domain: string } => { + const upstreamParsed = upstreamParseEmailAddress(emailAddress); + if (!upstreamParsed) { + return null; + } + + const {user: local, domain: rawDomain} = upstreamParsed; + + const domain = domainToASCII(rawDomain); + if (!domain) { + return null; + } + + return {local, domain}; +}; diff --git a/packages/parse-email-address/test/.eslintrc.js b/packages/parse-email-address/test/.eslintrc.js new file mode 100644 index 000000000..6fe6dc150 --- /dev/null +++ b/packages/parse-email-address/test/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + parser: '@typescript-eslint/parser', + plugins: ['ghost'], + extends: [ + 'plugin:ghost/test' + ] +}; diff --git a/packages/parse-email-address/test/index.test.ts b/packages/parse-email-address/test/index.test.ts new file mode 100644 index 000000000..fee310be0 --- /dev/null +++ b/packages/parse-email-address/test/index.test.ts @@ -0,0 +1,63 @@ +import assert from 'node:assert/strict'; +import {parseEmailAddress} from '../src'; + +describe('parseEmailAddress', function () { + it('returns null for invalid email addresses', function () { + const invalid = [ + // These aren't email addresses + '', + 'foo', + 'example.com', + '@example.com', + // Bad spacing + ' foo@example.com', + 'foo@example.com ', + 'foo @example.com', + 'foo@example .com', + // Too many @s + 'foo@bar@example.com', + // Invalid user + 'a"b(c)d,e:f;gi[j\\k]l@example.com', + 'just"not"right@example.com', + 'this is"not\\allowed@example.com', + 'x'.repeat(975) + '@example.com', + // Invalid domains + 'foo@example', + 'foo@no_underscores.example', + 'foo@xn--iñvalid.com', + 'foo@' + 'x'.repeat(253) + '.yz', + // IP domains + 'foo@[127.0.0.1]', + 'foo@[IPv6:::1]', + 'foo@[ipv6:::1]', + // Tag domains + 'foo@[bar:Baz]' + ]; + for (const input of invalid) { + assert.equal(parseEmailAddress(input), null, input); + } + }); + + it('returns the local and domain part of domains', function () { + const testCases: [string, string, string][] = [ + // Basic cases + ['foo@example.com', 'foo', 'example.com'], + ['foo.bar@example.com', 'foo.bar', 'example.com'], + ['foo.bar+baz@example.com', 'foo.bar+baz', 'example.com'], + // Unusual usernames + ['" "@example.com', '" "', 'example.com'], + ['"foo..bar"@example.com', '"foo..bar"', 'example.com'], + ['""@example.com', '""', 'example.com'], + ['"\\"@example.com', '"\\"', 'example.com'], + ['"foo@bar.example"@example.com', '"foo@bar.example"', 'example.com'], + // Lowercasing + ['Foo@Example.COM', 'Foo', 'example.com'], + // Non-ASCII + ['foo@中文.example', 'foo', 'xn--fiq228c.example'], + ['中文@example.com', '中文', 'example.com'] + ]; + for (const [input, local, domain] of testCases) { + assert.deepEqual(parseEmailAddress(input), {local, domain}, input); + } + }); +}); diff --git a/packages/parse-email-address/tsconfig.json b/packages/parse-email-address/tsconfig.json new file mode 100644 index 000000000..ed34382bc --- /dev/null +++ b/packages/parse-email-address/tsconfig.json @@ -0,0 +1,110 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": ["es2019"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + "rootDir": "src", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "build", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": ["src/**/*"] +} diff --git a/yarn.lock b/yarn.lock index 4babeae2a..c8397678b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1295,7 +1295,14 @@ dependencies: "@sinonjs/commons" "^3.0.1" -"@sinonjs/samsam@^8.0.0", "@sinonjs/samsam@^8.0.1": +"@sinonjs/fake-timers@^15.1.0": + version "15.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-15.1.0.tgz#f42e713425d4eb1a7bc88ef5d7f76c4546586c25" + integrity sha512-cqfapCxwTGsrR80FEgOoPsTonoefMBY7dnUEbQ+GRcved0jvkJLzvX6F4WtN+HBqbPX/SiFsIRUp+IrCW/2I2w== + dependencies: + "@sinonjs/commons" "^3.0.1" + +"@sinonjs/samsam@^8.0.0", "@sinonjs/samsam@^8.0.1", "@sinonjs/samsam@^8.0.3": version "8.0.3" resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-8.0.3.tgz#eb6ffaef421e1e27783cc9b52567de20cb28072d" integrity sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ== @@ -3856,6 +3863,13 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chokidar@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -4346,6 +4360,11 @@ diff@^7.0.0: resolved "https://registry.yarnpkg.com/diff/-/diff-7.0.0.tgz#3fb34d387cd76d803f6eebea67b921dab0182a9a" integrity sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw== +diff@^8.0.2: + version "8.0.3" + resolved "https://registry.yarnpkg.com/diff/-/diff-8.0.3.tgz#c7da3d9e0e8c283bb548681f8d7174653720c2d5" + integrity sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -5641,7 +5660,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^10.3.7, glob@^10.4.1: +glob@^10.3.7, glob@^10.4.1, glob@^10.4.5: version "10.5.0" resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c" integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg== @@ -7257,7 +7276,7 @@ minimatch@^5.0.1, minimatch@^5.1.0, minimatch@^5.1.6, minimatch@~5.1.2: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: +minimatch@^9.0.4, minimatch@^9.0.5: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== @@ -7407,6 +7426,33 @@ mocha@10.8.2: yargs-parser "^20.2.9" yargs-unparser "^2.0.0" +mocha@11.7.5: + version "11.7.5" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-11.7.5.tgz#58f5bbfa5e0211ce7e5ee6128107cefc2515a627" + integrity sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig== + dependencies: + browser-stdout "^1.3.1" + chokidar "^4.0.1" + debug "^4.3.5" + diff "^7.0.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^10.4.5" + he "^1.2.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^9.0.5" + ms "^2.1.3" + picocolors "^1.1.1" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^9.2.0" + yargs "^17.7.2" + yargs-parser "^21.1.1" + yargs-unparser "^2.0.0" + moment-timezone@^0.5.23, moment-timezone@^0.5.33: version "0.5.48" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.48.tgz#111727bb274734a518ae154b5ca589283f058967" @@ -7872,6 +7918,11 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-email-address@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/parse-email-address/-/parse-email-address-0.0.2.tgz#1fc9f86cad5e703aeb04554904f5f5a6e4ac0884" + integrity sha512-Ul8NS2MQ6PG7xdaa2SCNbkUjKcm0TTySXWquqDT8u+vldPVHZNhhrwfhG0KqN8caA96ul34Ptu6JtX7JYtK8CA== + parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -8286,6 +8337,11 @@ readdir-glob@^1.1.2: dependencies: minimatch "^5.1.0" +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -8869,6 +8925,17 @@ sinon@19.0.5: nise "^6.1.1" supports-color "^7.2.0" +sinon@21.0.1: + version "21.0.1" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-21.0.1.tgz#36b9126065a44906f7ba4a47b723b99315a8c356" + integrity sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw== + dependencies: + "@sinonjs/commons" "^3.0.1" + "@sinonjs/fake-timers" "^15.1.0" + "@sinonjs/samsam" "^8.0.3" + diff "^8.0.2" + supports-color "^7.2.0" + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -9567,6 +9634,11 @@ typescript@5.8.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== +typescript@5.9.3: + version "5.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + uid-safe@~2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" @@ -9852,7 +9924,7 @@ word-wrap@^1.2.5, word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -workerpool@9.3.4: +workerpool@9.3.4, workerpool@^9.2.0: version "9.3.4" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-9.3.4.tgz#f6c92395b2141afd78e2a889e80cb338fe9fca41" integrity sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==