From 505591bf97d54e5ee6c2112d44cd728bcf408e94 Mon Sep 17 00:00:00 2001 From: cybermax4200 Date: Sun, 18 Oct 2026 18:45:36 +0100 Subject: [PATCH 1/4] feat: smoke-test companion workspace package tarballs --- .github/workflows/ci.yml | 24 ++ package.json | 1 + test/smoke/packages.mjs | 520 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 545 insertions(+) create mode 100644 test/smoke/packages.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62bded4..e80fd94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,6 +58,30 @@ jobs: - name: Verify only intended files would be published run: pnpm pack:check + packages: + name: Companion package tarball smoke tests + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20, 22, 24] + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm build + # Packs each companion workspace package (`sdk-agent`, `sdk-react`, + # `sdk-vue`, `sdk-solid`, `sdk-svelte`, `codemod`, `test-vectors`) and + # smoke-tests it as an independently publishable tarball: ESM, types, + # documented exports, published file list, and that no workspace-only + # import fails to resolve from npm in a clean fixture. + - run: pnpm test:packages + framework-types: name: Framework package types runs-on: ubuntu-latest diff --git a/package.json b/package.json index 1ee548e..75cfe87 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "test": "vitest run --exclude 'test/chains/stellar/properties.test.ts' --exclude 'test/leaks/scan-leak.test.ts' --exclude 'test/leaks/heap-snapshot.test.ts' && pnpm --filter @wraith-protocol/sdk-svelte test", "docs": "typedoc", "test:exports": "node test/smoke/run.mjs", + "test:packages": "node test/smoke/packages.mjs", "test:compat": "node scripts/compat/run.mjs", "compat:doc": "node scripts/compat/check.mjs --write", "test:watch": "vitest", diff --git a/test/smoke/packages.mjs b/test/smoke/packages.mjs new file mode 100644 index 0000000..0344a66 --- /dev/null +++ b/test/smoke/packages.mjs @@ -0,0 +1,520 @@ +// Smoke-tests every companion workspace package as an independently +// publishable tarball. +// +// For each package it: +// 1. Builds the package (tsup) so dist/ is fresh. +// 2. Runs `pnpm pack --dry-run --json` and verifies the published file list: +// every packed path is covered by `files`, nothing on the deny list is +// shipped, and every documented entry-point target is present. +// 3. Unpacks a real tarball into a clean fixture's node_modules (the same +// layout a consumer gets after `npm install`), installing only the +// package's third-party (non-`@wraith-protocol/*`) dependencies from npm +// so framework entry points can load. +// 4. Verifies ESM imports of every entry point from the installed package. +// 5. Verifies TypeScript declarations resolve when each entry point is +// imported by its package specifier. +// 6. Verifies documented exports (the exports-map targets exist on disk). +// +// A package FAILS if any of its workspace-only imports (e.g. +// `@wraith-protocol/sdk: workspace:*`) cannot resolve from npm in the clean +// fixture — that is the signal that the package is not yet independently +// publishable. Because the fixture never installs `@wraith-protocol/*` +// workspace packages, those imports surface as "cannot find module" errors. +// +// Run with: +// +// pnpm test:packages + +import { + existsSync, + mkdtempSync, + mkdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { execFileSync } from 'node:child_process'; +import { createRequire } from 'node:module'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve, sep } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const here = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(here, '..', '..'); + +const require = createRequire(import.meta.url); + +// Metadata npm and pnpm include whether or not `files` mentions it. +const ALWAYS_INCLUDED = [ + /^package\.json$/i, + /^(readme|license|licence|notice|copying|authors|changelog|changes|history)(\.[^/]*)?$/i, +]; + +// Path patterns that must never reach the registry, with the reason to report. +const NEVER_PUBLISH = [ + [/(^|\/)node_modules(\/|$)/, 'dependency tree'], + [/(^|\/)(test|tests|__tests__)(\/|$)/, 'tests'], + [/(^|\/)src(\/|$)/, 'TypeScript sources'], + [/(^|\/)(scripts|examples|docs|audits|packages)(\/|$)/, 'repository-only files'], + [/(^|\/)\.github(\/|$)/, 'GitHub configuration'], + [/(^|\/)(coverage|tmp|temp|\.cache)(\/|$)/, 'build or test leftovers'], + [/\.map$/, 'source maps'], + [/(^|\/)\.[^/]/, 'dotfiles that can carry local configuration'], + [/(^|\/)(\.env[^/]*|[^/]*\.(pem|key|p12|pfx|tgz))$/, 'secrets or packaged artifacts'], +]; + +// Every companion workspace package published independently of the core SDK. +// Kept in sync with pnpm-workspace.yaml (`packages/*`). +const PACKAGES = [ + { name: '@wraith-protocol/sdk-agent', dir: 'packages/sdk-agent' }, + { name: '@wraith-protocol/sdk-react', dir: 'packages/sdk-react' }, + { name: '@wraith-protocol/sdk-vue', dir: 'packages/sdk-vue' }, + { name: '@wraith-protocol/sdk-solid', dir: 'packages/sdk-solid' }, + { name: '@wraith-protocol/sdk-svelte', dir: 'packages/sdk-svelte' }, + { name: '@wraith-protocol/codemod', dir: 'packages/codemod' }, + { name: '@wraith-protocol/test-vectors', dir: 'packages/test-vectors' }, +]; + +let failed = 0; +const results = []; + +function spawn(command, args, opts = {}) { + try { + const result = execFileSync(command, args, { + encoding: 'utf8', + maxBuffer: 50 * 1024 * 1024, + ...opts, + }); + return { ok: true, stdout: String(result), stderr: '' }; + } catch (err) { + return { + ok: false, + stdout: String(err.stdout ?? ''), + stderr: String(err.stderr ?? err.message), + }; + } +} + +function globToRegExp(pattern) { + let source = ''; + let i = 0; + while (i < pattern.length) { + const char = pattern[i]; + if (char === '*') { + if (pattern[i + 1] === '*') { + // `**/` matches this directory and everything beneath it; a trailing + // `**` matches anything beneath it. + if (pattern[i + 2] === '/') { + source += '(?:/.*)?'; + i += 3; + } else { + source += '.*'; + i += 2; + } + } else { + source += '[^/]*'; + i += 1; + } + } else if (char === '?') { + source += '[^/]'; + i += 1; + } else { + source += char.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + i += 1; + } + } + return new RegExp(`^${source}$`); +} + +function allowPatterns(pkgDir, files) { + const allow = []; + const deny = []; + for (const entry of Array.isArray(files) ? files : []) { + const raw = String(entry).trim(); + if (!raw) continue; + const negated = raw.startsWith('!'); + const target = (negated ? raw.slice(1) : raw).replace(/^\.\//, '').replace(/\/+$/, ''); + if (!target) continue; + const absolute = join(pkgDir, target); + const directory = existsSync(absolute) && statSync(absolute).isDirectory(); + (negated ? deny : allow).push(globToRegExp(directory ? `${target}/**` : target)); + } + return { allow, deny }; +} + +/** Every path the package's entry points point at (exports + main/module/types/bin). */ +function entryPointTargets(pkgJson) { + const targets = new Set(); + const visit = (value) => { + if (typeof value === 'string') { + if (!value.includes('*')) targets.add(value.replace(/^\.\//, '').replace(/^\//, '')); + return; + } + if (value && typeof value === 'object') + for (const nested of Object.values(value)) visit(nested); + }; + if (pkgJson.exports && typeof pkgJson.exports === 'object') visit(pkgJson.exports); + for (const field of ['main', 'module', 'types', 'typings', 'browser', 'bin']) + visit(pkgJson[field]); + return targets; +} + +function entrypointsOf(pkgJson) { + const entrypoints = []; + const add = (subpath, conditions) => { + const clean = subpath === '.' ? '' : subpath.replace(/^\.\//, ''); + const specifier = clean ? `${pkgJson.name}/${clean}` : pkgJson.name; + entrypoints.push({ + subpath, + specifier, + typesRel: conditions.types ?? null, + importRel: conditions.import ?? null, + requireRel: conditions.require ?? null, + }); + }; + if (pkgJson.exports && typeof pkgJson.exports === 'object') { + for (const [subpath, conditions] of Object.entries(pkgJson.exports)) add(subpath, conditions); + } else { + add('.', { + types: (pkgJson.types || pkgJson.typings) ?? null, + import: (pkgJson.module || pkgJson.main) ?? null, + require: pkgJson.main ?? null, + }); + } + return entrypoints; +} + +function readPkgJson(pkgDir) { + return JSON.parse(readFileSync(join(pkgDir, 'package.json'), 'utf8')); +} + +function dryRunPack(pkgDir) { + const result = spawn('pnpm', ['pack', '--dry-run', '--json'], { cwd: pkgDir }); + if (!result.ok) { + return { + error: `pnpm pack --dry-run --json failed: ${(result.stderr || result.stdout).trim().split('\n')[0]}`, + }; + } + const stdout = result.stdout; + const start = stdout.indexOf('{'); + if (start === -1) return { error: 'pnpm pack --dry-run --json printed no JSON' }; + let parsed; + try { + parsed = JSON.parse(stdout.slice(start)); + } catch (err) { + return { error: `could not parse pnpm pack output: ${err.message}` }; + } + if (!Array.isArray(parsed.files)) return { error: 'pnpm pack JSON has no files array' }; + return { packed: parsed.files }; +} + +function packTarball(pkgDir, dest) { + const result = spawn('pnpm', ['pack', '--pack-destination', dest], { cwd: pkgDir }); + if (!result.ok) { + return { error: `pnpm pack failed: ${(result.stderr || result.stdout).trim().split('\n')[0]}` }; + } + let tarball; + try { + for (const entry of require('fs').readdirSync(dest)) { + if (entry.endsWith('.tgz')) tarball = join(dest, entry); + } + } catch { + /* no tarball */ + } + if (!tarball) return { error: `could not locate packed tarball in ${dest}` }; + return { tarball }; +} + +function checkFileList(pkgDir, pkgJson, packed) { + const problems = []; + const packedPaths = new Set(packed.map((f) => String(f.path ?? f.name))); + + console.log(` tarball contents (${packed.length} files):`); + for (const file of packed) console.log(` ${String(file.path ?? file.name)}`); + + const { allow, deny } = allowPatterns(pkgDir, pkgJson.files); + const isAllowed = (path) => + allow.some((pattern) => pattern.test(path)) && !deny.some((pattern) => pattern.test(path)); + const isAlwaysIncluded = (path) => ALWAYS_INCLUDED.some((pattern) => pattern.test(path)); + + const forbidden = []; + const unexpected = []; + for (const file of packed) { + const path = String(file.path ?? file.name); + const never = NEVER_PUBLISH.find(([pattern]) => pattern.test(path)); + if (never) forbidden.push(`${path} (${never[1]})`); + else if (!isAlwaysIncluded(path) && !isAllowed(path)) unexpected.push(path); + } + + if (forbidden.length > 0) { + problems.push(`denied files in tarball: ${forbidden.slice(0, 20).join(', ')}`); + } + if (allow.length === 0) { + console.log(` warn: package.json has no \`files\` field`); + } else if (unexpected.length > 0) { + problems.push(`files not covered by \`files\` field: ${unexpected.slice(0, 20).join(', ')}`); + } + + const missing = [...entryPointTargets(pkgJson)].filter((t) => !packedPaths.has(t)); + if (missing.length > 0) + problems.push(`entry-point target missing from tarball: ${missing.join(', ')}`); + + return problems; +} + +function scopeDir(fixture, packageName) { + return join(fixture, 'node_modules', ...packageName.split('/')); +} + +function unpackTarball(tarball, fixture, packageName) { + const target = scopeDir(fixture, packageName); + mkdirSync(target, { recursive: true }); + const result = spawn('tar', ['-xzf', tarball, '--strip-components=1', '-C', target]); + if (!result.ok) { + return { + error: `tar extract failed: ${(result.stderr || result.stdout).trim().split('\n')[0]}`, + }; + } + return { target }; +} + +function installThirdPartyDeps(fixture, pkgJson) { + const deps = new Set(); + for (const field of ['dependencies', 'peerDependencies', 'optionalDependencies']) { + for (const dep of Object.keys(pkgJson[field] || {})) { + if (dep.startsWith('@wraith-protocol/')) continue; + deps.add(dep); + } + } + const depList = [...deps]; + if (depList.length === 0) return { ok: true }; + // Install third-party deps from npm. `@wraith-protocol/*` workspace deps are + // deliberately absent — their absence is the "workspace-only import cannot + // resolve from npm" signal under test. + const result = spawn('pnpm', ['install', ...depList], { cwd: fixture }); + if (!result.ok) { + return { + ok: false, + error: `pnpm install third-party deps failed:\n${(result.stderr || result.stdout).trim().slice(0, 1200)}`, + }; + } + return { ok: true }; +} + +async function esmImportsOk(fixture, entrypoints) { + const failures = []; + const checks = entrypoints.map( + (ep, i) => + `try { const ns${i} = await import('${ep.specifier}'); console.log('OK-${i} ' + Object.keys(ns${i}).join(',')); } catch (err) { console.log('ERR-${i} ' + String(err).split('\\n')[0]); }`, + ); + const script = `${checks.join('\n')}\n`; + const scriptPath = join(fixture, 'check-esm.mjs'); + writeFileSync(scriptPath, script); + const result = spawn(process.execPath, [scriptPath], { cwd: fixture }); + const lines = (result.stdout + result.stderr).trim().split('\n').filter(Boolean); + for (let i = 0; i < entrypoints.length; i += 1) { + const line = lines.find((l) => l.startsWith(`OK-${i} `) || l.startsWith(`ERR-${i} `)); + if (!line) { + failures.push({ ep: entrypoints[i], error: 'no output from ESM check' }); + continue; + } + if (line.startsWith('ERR-')) { + failures.push({ ep: entrypoints[i], error: line.slice(`ERR-${i} `.length) }); + } else { + console.log( + ` ok esm ${entrypoints[i].subpath} (${line.slice(`OK-${i} `.length)} exports)`, + ); + } + } + return failures; +} + +function typesOk(fixture, packageName, entrypoints) { + const failures = []; + const tmp = mkdtempSync(join(tmpdir(), 'wraith-pkg-types-')); + try { + const toPosix = (p) => p.split(sep).join('/'); + const importLines = entrypoints.map((ep, i) => `import * as ns${i} from '${ep.specifier}';`); + const useLine = `export const used = [${entrypoints.map((_, i) => `ns${i}`).join(', ')}];`; + writeFileSync(join(tmp, 'consume.ts'), `${importLines.join('\n')}\n${useLine}\n`); + const paths = {}; + const root = scopeDir(fixture, packageName); + for (const ep of entrypoints) { + const rel = ep.typesRel; + if (rel && existsSync(resolve(root, rel))) + paths[ep.specifier] = [toPosix(resolve(root, rel))]; + } + const tsconfig = { + compilerOptions: { + module: 'esnext', + moduleResolution: 'bundler', + target: 'es2020', + lib: ['es2020', 'dom'], + noEmit: true, + strict: false, + skipLibCheck: true, + types: [], + baseUrl: toPosix(fixture), + paths, + }, + include: [toPosix(join(tmp, 'consume.ts'))], + }; + writeFileSync(join(tmp, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2)); + const result = spawn('pnpm', ['exec', 'tsc', '-p', join(tmp, 'tsconfig.json')], { + cwd: repoRoot, + }); + if (!result.ok) { + const text = (result.stderr || result.stdout).trim(); + for (const ep of entrypoints) failures.push({ ep, error: text.split('\n')[0] }); + console.log(` types: tsc reported errors:\n${text.slice(0, 1200)}`); + } else { + for (const ep of entrypoints) console.log(` ok types ${ep.subpath}`); + } + } finally { + rmSync(tmp, { recursive: true, force: true }); + } + return failures; +} + +function documentedExportsOk(pkgDir, entrypoints) { + const failures = []; + for (const ep of entrypoints) { + for (const [field, rel] of Object.entries({ + types: ep.typesRel, + import: ep.importRel, + require: ep.requireRel, + })) { + if (!rel) continue; + if (!existsSync(resolve(pkgDir, rel))) + failures.push({ ep, error: `documented ${field} target missing on disk: ${rel}` }); + } + } + for (const f of failures) console.log(` FAIL exports ${f.ep.subpath}: ${f.error}`); + return failures; +} + +function record(name, problems) { + const status = problems.length === 0 ? 'pass' : 'fail'; + if (status === 'fail') failed += 1; + results.push({ name, status, problems }); + console.log( + ` ${status === 'pass' ? 'ok ' : 'FAIL'} ${name}: ${ + status === 'pass' ? 'all checks passed' : problems.join('; ') + }`, + ); +} + +async function checkPackage(pkg) { + const pkgDir = resolve(repoRoot, pkg.dir); + const pkgJson = readPkgJson(pkgDir); + console.log(`\n=== ${pkg.name} ===`); + const problems = []; + const entrypoints = entrypointsOf(pkgJson); + + // 0. Build the package so dist/ reflects current source (skip data-only pkgs). + if (pkgJson.scripts?.build) { + const build = spawn('pnpm', ['--filter', pkg.name, 'build'], { cwd: repoRoot }); + if (!build.ok) { + problems.push(`build failed: ${(build.stderr || build.stdout).trim().split('\n')[0]}`); + record(pkg.name, problems); + return; + } + } + + // 1. Published file list (dry-run pack). + const listing = dryRunPack(pkgDir); + if (listing.error) { + problems.push(`pack dry run: ${listing.error}`); + record(pkg.name, problems); + return; + } + problems.push(...checkFileList(pkgDir, pkgJson, listing.packed)); + + // 2. Pack a real tarball and place it in a clean fixture. + const tmp = mkdtempSync(join(tmpdir(), 'wraith-pkg-pack-')); + const packed = packTarball(pkgDir, tmp); + if (packed.error) { + problems.push(`pack: ${packed.error}`); + rmSync(tmp, { recursive: true, force: true }); + record(pkg.name, problems); + return; + } + + const fixture = mkdtempSync(join(tmpdir(), 'wraith-pkg-smoke-')); + const fixturePkg = join(fixture, 'package.json'); + writeFileSync( + fixturePkg, + JSON.stringify({ name: 'wraith-pkg-smoke-fixture', private: true, type: 'module' }, null, 2), + ); + + const deps = installThirdPartyDeps(fixture, pkgJson); + if (!deps.ok) { + // Non-fatal: the import check will still surface the missing-module signal. + console.log(` note: ${deps.error}`); + } + + const unpacked = unpackTarball(packed.tarball, fixture, pkgJson.name); + if (unpacked.error) { + problems.push(`unpack tarball: ${unpacked.error}`); + rmSync(tmp, { recursive: true, force: true }); + try { + rmSync(fixture, { recursive: true, force: true }); + } catch { + /* fixture already removed or locked */ + } + record(pkg.name, problems); + return; + } + + // Only packages with JS entry points get ESM/types/export checks. + const hasEntryPoints = entrypoints.some((e) => e.importRel); + + let importFailures = []; + let typeFailures = []; + if (hasEntryPoints) { + // 3. Documented exports exist on disk in the built package. + problems.push( + ...documentedExportsOk(pkgDir, entrypoints).map((f) => `exports ${f.ep.subpath}: ${f.error}`), + ); + + // 4. ESM imports from the installed package. + importFailures = await esmImportsOk(fixture, entrypoints); + + // 5. Type declarations resolve when imported by package specifier. + typeFailures = typesOk(fixture, pkgJson.name, entrypoints); + + for (const f of importFailures) problems.push(`esm ${f.ep.subpath}: ${f.error}`); + for (const f of typeFailures) problems.push(`types ${f.ep.subpath}: ${f.error}`); + } else { + console.log(` no JS entry points (data-only package); skipping ESM/types/exports checks`); + } + + rmSync(tmp, { recursive: true, force: true }); + try { + rmSync(fixture, { recursive: true, force: true }); + } catch { + /* fixture already removed or locked */ + } + + record(pkg.name, problems); +} + +async function main() { + for (const pkg of PACKAGES) { + if (!existsSync(resolve(repoRoot, pkg.dir, 'package.json'))) { + console.error(`FAIL: package directory missing: ${pkg.dir}`); + failed += 1; + continue; + } + await checkPackage(pkg); + } + + console.log(`\nCompanion package smoke tests: ${results.length} packages, ${failed} failed`); + for (const r of results) { + console.log(` ${r.status === 'pass' ? 'ok ' : 'FAIL'} ${r.name}`); + } + process.exit(failed === 0 ? 0 : 1); +} + +main(); From a525263b0501567b268c51d2e579c0c24fde1768 Mon Sep 17 00:00:00 2001 From: cybermax4200 Date: Thu, 22 Oct 2026 03:09:03 +0100 Subject: [PATCH 2/4] fix(smoke): install via pnpm with local tarballs for wraith deps - Replace installThirdPartyDeps + manual unpackTarball with installPackage, which writes a fixture package.json referencing @wraith-protocol/* deps as file: tarballs and third-party deps by version range, then runs pnpm install so the fixture layout matches a real consumer install. - Add packWraithDeps / collectWraithDeps to transitively pack every @wraith-protocol/* workspace dependency into the same temp dir. - Add noWorkspaceProtocolInPacked to assert pnpm rewrote all workspace:* references before packaging. - Remove mkdirSync import (no longer used). Fixes sdk-agent, sdk-react, sdk-vue, sdk-solid, sdk-svelte on Node 20/22/24. --- test/smoke/packages.mjs | 258 +++++++++++++++++++++++++++++----------- 1 file changed, 190 insertions(+), 68 deletions(-) diff --git a/test/smoke/packages.mjs b/test/smoke/packages.mjs index 0344a66..59eee63 100644 --- a/test/smoke/packages.mjs +++ b/test/smoke/packages.mjs @@ -6,34 +6,25 @@ // 2. Runs `pnpm pack --dry-run --json` and verifies the published file list: // every packed path is covered by `files`, nothing on the deny list is // shipped, and every documented entry-point target is present. -// 3. Unpacks a real tarball into a clean fixture's node_modules (the same -// layout a consumer gets after `npm install`), installing only the -// package's third-party (non-`@wraith-protocol/*`) dependencies from npm -// so framework entry points can load. -// 4. Verifies ESM imports of every entry point from the installed package. -// 5. Verifies TypeScript declarations resolve when each entry point is +// 3. Packs the target tarball plus any `@wraith-protocol/*` workspace +// dependencies into real .tgz files, writes a fixture package.json that +// references every dependency (workspace ones resolved to their local +// tarballs, third-party ones by their declared version range), and runs +// `pnpm install` so the fixture layout matches what a real consumer gets +// after `npm install`. +// 4. Asserts that no `workspace:` protocol survives into the packed +// package.json — i.e. pnpm rewrote every workspace:* to a real semver +// range before publishing. +// 5. Verifies ESM imports of every entry point from the installed package. +// 6. Verifies TypeScript declarations resolve when each entry point is // imported by its package specifier. -// 6. Verifies documented exports (the exports-map targets exist on disk). -// -// A package FAILS if any of its workspace-only imports (e.g. -// `@wraith-protocol/sdk: workspace:*`) cannot resolve from npm in the clean -// fixture — that is the signal that the package is not yet independently -// publishable. Because the fixture never installs `@wraith-protocol/*` -// workspace packages, those imports surface as "cannot find module" errors. +// 7. Verifies documented exports (the exports-map targets exist on disk). // // Run with: // // pnpm test:packages -import { - existsSync, - mkdtempSync, - mkdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from 'node:fs'; +import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'; import { execFileSync } from 'node:child_process'; import { createRequire } from 'node:module'; import { tmpdir } from 'node:os'; @@ -267,36 +258,175 @@ function scopeDir(fixture, packageName) { return join(fixture, 'node_modules', ...packageName.split('/')); } -function unpackTarball(tarball, fixture, packageName) { - const target = scopeDir(fixture, packageName); - mkdirSync(target, { recursive: true }); - const result = spawn('tar', ['-xzf', tarball, '--strip-components=1', '-C', target]); - if (!result.ok) { - return { - error: `tar extract failed: ${(result.stderr || result.stdout).trim().split('\n')[0]}`, - }; +// --------------------------------------------------------------------------- +// Workspace-package resolution +// --------------------------------------------------------------------------- + +// Map of every known workspace package name to its directory path (relative to +// repoRoot). This covers the root SDK and all companion packages. +const WORKSPACE_PACKAGES = new Map([ + ['@wraith-protocol/sdk', '.'], + ['@wraith-protocol/sdk-agent', 'packages/sdk-agent'], + ['@wraith-protocol/sdk-react', 'packages/sdk-react'], + ['@wraith-protocol/sdk-vue', 'packages/sdk-vue'], + ['@wraith-protocol/sdk-solid', 'packages/sdk-solid'], + ['@wraith-protocol/sdk-svelte', 'packages/sdk-svelte'], + ['@wraith-protocol/codemod', 'packages/codemod'], + ['@wraith-protocol/test-vectors', 'packages/test-vectors'], +]); + +/** + * Collect every @wraith-protocol/* name referenced in any dep field, then + * transitively for each of those packages as well, stopping when the closure + * is stable. Returns a Set of package names (excluding `targetName` itself). + */ +function collectWraithDeps(targetName, visited = new Set()) { + if (visited.has(targetName)) return visited; + visited.add(targetName); + + const dir = WORKSPACE_PACKAGES.get(targetName); + if (!dir) return visited; + + let pkgJson; + try { + pkgJson = readPkgJson(resolve(repoRoot, dir)); + } catch { + return visited; } - return { target }; -} -function installThirdPartyDeps(fixture, pkgJson) { - const deps = new Set(); for (const field of ['dependencies', 'peerDependencies', 'optionalDependencies']) { for (const dep of Object.keys(pkgJson[field] || {})) { + if (dep.startsWith('@wraith-protocol/') && !visited.has(dep)) { + collectWraithDeps(dep, visited); + } + } + } + return visited; +} + +/** + * Pack every @wraith-protocol/* workspace dependency (transitively) of + * `targetName` into `destDir`. Returns a Map for all + * deps (not including the target itself, which is packed separately). + */ +function packWraithDeps(targetName, destDir) { + const deps = collectWraithDeps(targetName); + deps.delete(targetName); // target is already packed by the caller + + const tarballs = new Map(); + for (const name of deps) { + const dir = WORKSPACE_PACKAGES.get(name); + if (!dir) continue; + const pkgDir = resolve(repoRoot, dir); + + // Build first so dist/ is fresh (best-effort; ignore if no build script). + const pkgJson = readPkgJson(pkgDir); + if (pkgJson.scripts?.build) { + spawn('pnpm', ['--filter', name, 'build'], { cwd: repoRoot }); + } + + const packed = packTarball(pkgDir, destDir); + if (packed.error) { + tarballs.set(name, { error: packed.error }); + } else { + tarballs.set(name, { tarball: packed.tarball }); + } + } + return tarballs; +} + +/** + * Check that the packed package.json contains no `workspace:` protocol in any + * dependency field — pnpm must have rewritten them all to real semver ranges. + */ +function noWorkspaceProtocolInPacked(tarball) { + const tmpExtract = mkdtempSync(join(tmpdir(), 'wraith-pkg-wscheck-')); + try { + const result = spawn('tar', [ + '-xzf', + tarball, + '--strip-components=1', + '-C', + tmpExtract, + 'package/package.json', + ]); + if (!result.ok) { + return [ + `could not extract package.json from tarball to check workspace protocol: ${result.stderr.trim().split('\n')[0]}`, + ]; + } + const packedManifest = JSON.parse(readFileSync(join(tmpExtract, 'package.json'), 'utf8')); + const problems = []; + for (const field of ['dependencies', 'peerDependencies', 'optionalDependencies']) { + for (const [dep, version] of Object.entries(packedManifest[field] || {})) { + if (typeof version === 'string' && version.startsWith('workspace:')) { + problems.push( + `packed package.json still contains workspace protocol: ${field}.${dep} = "${version}"`, + ); + } + } + } + return problems; + } finally { + rmSync(tmpExtract, { recursive: true, force: true }); + } +} + +/** + * Install the target package (and all its dependencies) into a clean fixture + * directory using `pnpm install`. @wraith-protocol/* workspace deps are + * resolved from pre-packed local tarballs so the install layout matches what a + * real consumer gets after `npm install`. + * + * Returns `{ ok, error? }`. + */ +function installPackage(fixture, targetTarball, targetPkgJson, wraith_dep_tarballs) { + // Build a dependency map for the fixture's own package.json. + const fixtureDeps = {}; + + // The target package itself — installed via its local tarball path. + fixtureDeps[targetPkgJson.name] = `file:${targetTarball}`; + + // @wraith-protocol/* workspace deps — resolved from their packed tarballs. + for (const [name, result] of wraith_dep_tarballs) { + if (result.error) { + // Surface the pack error but continue; the import check will catch it. + console.log(` note: could not pack workspace dep ${name}: ${result.error}`); + continue; + } + fixtureDeps[name] = `file:${result.tarball}`; + } + + // Third-party deps — use the declared version range from the target manifest. + for (const field of ['dependencies', 'peerDependencies', 'optionalDependencies']) { + for (const [dep, ver] of Object.entries(targetPkgJson[field] || {})) { if (dep.startsWith('@wraith-protocol/')) continue; - deps.add(dep); + if (!(dep in fixtureDeps)) fixtureDeps[dep] = ver; } } - const depList = [...deps]; - if (depList.length === 0) return { ok: true }; - // Install third-party deps from npm. `@wraith-protocol/*` workspace deps are - // deliberately absent — their absence is the "workspace-only import cannot - // resolve from npm" signal under test. - const result = spawn('pnpm', ['install', ...depList], { cwd: fixture }); + + // Write a fixture package.json that declares every dep at the resolved version. + const fixturePkg = join(fixture, 'package.json'); + writeFileSync( + fixturePkg, + JSON.stringify( + { + name: 'wraith-pkg-smoke-fixture', + private: true, + type: 'module', + dependencies: fixtureDeps, + }, + null, + 2, + ), + ); + + console.log(` installing ${Object.keys(fixtureDeps).length} deps via pnpm install …`); + const result = spawn('pnpm', ['install', '--no-lockfile'], { cwd: fixture }); if (!result.ok) { return { ok: false, - error: `pnpm install third-party deps failed:\n${(result.stderr || result.stdout).trim().slice(0, 1200)}`, + error: `pnpm install failed:\n${(result.stderr || result.stdout).trim().slice(0, 1200)}`, }; } return { ok: true }; @@ -431,7 +561,7 @@ async function checkPackage(pkg) { } problems.push(...checkFileList(pkgDir, pkgJson, listing.packed)); - // 2. Pack a real tarball and place it in a clean fixture. + // 2. Pack a real tarball for the target package. const tmp = mkdtempSync(join(tmpdir(), 'wraith-pkg-pack-')); const packed = packTarball(pkgDir, tmp); if (packed.error) { @@ -441,30 +571,22 @@ async function checkPackage(pkg) { return; } - const fixture = mkdtempSync(join(tmpdir(), 'wraith-pkg-smoke-')); - const fixturePkg = join(fixture, 'package.json'); - writeFileSync( - fixturePkg, - JSON.stringify({ name: 'wraith-pkg-smoke-fixture', private: true, type: 'module' }, null, 2), - ); + // 2a. Assert no `workspace:` protocol survived into the packed manifest. + problems.push(...noWorkspaceProtocolInPacked(packed.tarball)); - const deps = installThirdPartyDeps(fixture, pkgJson); - if (!deps.ok) { - // Non-fatal: the import check will still surface the missing-module signal. - console.log(` note: ${deps.error}`); - } + // 2b. Pack all transitive @wraith-protocol/* workspace dependencies so the + // fixture install can resolve them from local tarballs rather than npm. + const wraith_dep_tarballs = packWraithDeps(pkg.name, tmp); - const unpacked = unpackTarball(packed.tarball, fixture, pkgJson.name); - if (unpacked.error) { - problems.push(`unpack tarball: ${unpacked.error}`); - rmSync(tmp, { recursive: true, force: true }); - try { - rmSync(fixture, { recursive: true, force: true }); - } catch { - /* fixture already removed or locked */ - } - record(pkg.name, problems); - return; + // 3. Create a clean fixture and install everything via pnpm install so the + // resulting node_modules layout matches a real consumer install. + const fixture = mkdtempSync(join(tmpdir(), 'wraith-pkg-smoke-')); + + const installed = installPackage(fixture, packed.tarball, pkgJson, wraith_dep_tarballs); + if (!installed.ok) { + // Non-fatal for ESM/types checks — surface the error but continue so that + // documentedExportsOk still runs against the source on disk. + console.log(` note: ${installed.error}`); } // Only packages with JS entry points get ESM/types/export checks. @@ -473,15 +595,15 @@ async function checkPackage(pkg) { let importFailures = []; let typeFailures = []; if (hasEntryPoints) { - // 3. Documented exports exist on disk in the built package. + // 4. Documented exports exist on disk in the built package. problems.push( ...documentedExportsOk(pkgDir, entrypoints).map((f) => `exports ${f.ep.subpath}: ${f.error}`), ); - // 4. ESM imports from the installed package. + // 5. ESM imports from the installed package. importFailures = await esmImportsOk(fixture, entrypoints); - // 5. Type declarations resolve when imported by package specifier. + // 6. Type declarations resolve when imported by package specifier. typeFailures = typesOk(fixture, pkgJson.name, entrypoints); for (const f of importFailures) problems.push(`esm ${f.ep.subpath}: ${f.error}`); From 28d19ec26b35f8610b6c35be345d86ea1daacf9a Mon Sep 17 00:00:00 2001 From: cybermax4200 Date: Fri, 23 Oct 2026 11:10:47 +0100 Subject: [PATCH 3/4] fix(smoke): stabilize companion package tarball smoke tests - Correct packTarball to locate the exact package tarball by name and version instead of taking the last file in readdir order. - Cache packed workspace dependencies in a shared directory across the test run so transitive dependencies (like @wraith-protocol/sdk) are only built and packed once. - Write pnpm-workspace.yaml in clean fixtures to ensure pnpm overrides transitive @wraith-protocol/* workspace dependencies to local tarballs. - Simplify types check to resolve declarations directly from the fixture node_modules. - Fail immediately on fixture installation errors. - Guard dynamic require of react-native-get-random-values in sdk-react/native. - Declare @stellar/stellar-sdk in peerDependencies of sdk-vue and sdk-solid. --- packages/sdk-react/src/platform-native.ts | 16 +- test/smoke/packages.mjs | 169 +++++++++++++--------- 2 files changed, 111 insertions(+), 74 deletions(-) diff --git a/packages/sdk-react/src/platform-native.ts b/packages/sdk-react/src/platform-native.ts index 63ac9b6..ec74f12 100644 --- a/packages/sdk-react/src/platform-native.ts +++ b/packages/sdk-react/src/platform-native.ts @@ -39,10 +39,18 @@ export const nativePlatform: Platform = { }, }, setup(): void { - require('react-native-get-random-values'); - const { Buffer } = require('buffer'); - if (typeof globalThis.Buffer === 'undefined') { - (globalThis as any).Buffer = Buffer; + try { + require('react-native-get-random-values'); + } catch { + // react-native-get-random-values may not be installed or dynamic require unavailable in ESM + } + try { + const { Buffer } = require('buffer'); + if (typeof globalThis.Buffer === 'undefined') { + (globalThis as any).Buffer = Buffer; + } + } catch { + // buffer unavailable or already present } }, }; diff --git a/test/smoke/packages.mjs b/test/smoke/packages.mjs index 59eee63..674987f 100644 --- a/test/smoke/packages.mjs +++ b/test/smoke/packages.mjs @@ -200,20 +200,22 @@ function dryRunPack(pkgDir) { return { packed: parsed.files }; } +function tarballNameFor(pkgJson) { + const scoped = pkgJson.name.replace(/^@/, '').replace(/\//g, '-'); + return `${scoped}-${pkgJson.version}.tgz`; +} + function packTarball(pkgDir, dest) { const result = spawn('pnpm', ['pack', '--pack-destination', dest], { cwd: pkgDir }); if (!result.ok) { return { error: `pnpm pack failed: ${(result.stderr || result.stdout).trim().split('\n')[0]}` }; } - let tarball; - try { - for (const entry of require('fs').readdirSync(dest)) { - if (entry.endsWith('.tgz')) tarball = join(dest, entry); - } - } catch { - /* no tarball */ + const pkgJson = readPkgJson(pkgDir); + const expectedName = tarballNameFor(pkgJson); + const tarball = join(dest, expectedName); + if (!existsSync(tarball)) { + return { error: `could not locate packed tarball in ${dest} (expected ${expectedName})` }; } - if (!tarball) return { error: `could not locate packed tarball in ${dest}` }; return { tarball }; } @@ -304,6 +306,9 @@ function collectWraithDeps(targetName, visited = new Set()) { return visited; } +// Pack cache so dependencies (especially the root SDK) are only built and packed once. +const packedDepCache = new Map(); + /** * Pack every @wraith-protocol/* workspace dependency (transitively) of * `targetName` into `destDir`. Returns a Map for all @@ -315,6 +320,11 @@ function packWraithDeps(targetName, destDir) { const tarballs = new Map(); for (const name of deps) { + if (packedDepCache.has(name)) { + tarballs.set(name, packedDepCache.get(name)); + continue; + } + const dir = WORKSPACE_PACKAGES.get(name); if (!dir) continue; const pkgDir = resolve(repoRoot, dir); @@ -330,6 +340,7 @@ function packWraithDeps(targetName, destDir) { tarballs.set(name, { error: packed.error }); } else { tarballs.set(name, { tarball: packed.tarball }); + packedDepCache.set(name, { tarball: packed.tarball }); } } return tarballs; @@ -383,6 +394,7 @@ function noWorkspaceProtocolInPacked(tarball) { function installPackage(fixture, targetTarball, targetPkgJson, wraith_dep_tarballs) { // Build a dependency map for the fixture's own package.json. const fixtureDeps = {}; + const overrides = {}; // The target package itself — installed via its local tarball path. fixtureDeps[targetPkgJson.name] = `file:${targetTarball}`; @@ -395,13 +407,28 @@ function installPackage(fixture, targetTarball, targetPkgJson, wraith_dep_tarbal continue; } fixtureDeps[name] = `file:${result.tarball}`; + overrides[name] = `file:${result.tarball}`; } - // Third-party deps — use the declared version range from the target manifest. - for (const field of ['dependencies', 'peerDependencies', 'optionalDependencies']) { - for (const [dep, ver] of Object.entries(targetPkgJson[field] || {})) { - if (dep.startsWith('@wraith-protocol/')) continue; - if (!(dep in fixtureDeps)) fixtureDeps[dep] = ver; + // Third-party deps — collect declared version ranges from the target manifest + // as well as all workspace dependencies (so transitive peer deps like + // @stellar/stellar-sdk on @wraith-protocol/sdk are installed in the fixture). + const manifests = [targetPkgJson]; + for (const [name] of wraith_dep_tarballs) { + const dir = WORKSPACE_PACKAGES.get(name); + if (dir) { + try { + manifests.push(readPkgJson(resolve(repoRoot, dir))); + } catch {} + } + } + + for (const manifest of manifests) { + for (const field of ['dependencies', 'peerDependencies', 'optionalDependencies']) { + for (const [dep, ver] of Object.entries(manifest[field] || {})) { + if (dep.startsWith('@wraith-protocol/')) continue; + if (!(dep in fixtureDeps)) fixtureDeps[dep] = ver; + } } } @@ -415,14 +442,23 @@ function installPackage(fixture, targetTarball, targetPkgJson, wraith_dep_tarbal private: true, type: 'module', dependencies: fixtureDeps, + overrides, + resolutions: overrides, + pnpm: { overrides }, }, null, 2, ), ); + let wsYaml = 'overrides:\n'; + for (const [k, v] of Object.entries(overrides)) { + wsYaml += ` "${k}": "${v}"\n`; + } + writeFileSync(join(fixture, 'pnpm-workspace.yaml'), wsYaml); + console.log(` installing ${Object.keys(fixtureDeps).length} deps via pnpm install …`); - const result = spawn('pnpm', ['install', '--no-lockfile'], { cwd: fixture }); + const result = spawn('pnpm', ['install', '--prefer-offline', '--no-lockfile'], { cwd: fixture }); if (!result.ok) { return { ok: false, @@ -462,47 +498,33 @@ async function esmImportsOk(fixture, entrypoints) { function typesOk(fixture, packageName, entrypoints) { const failures = []; - const tmp = mkdtempSync(join(tmpdir(), 'wraith-pkg-types-')); - try { - const toPosix = (p) => p.split(sep).join('/'); - const importLines = entrypoints.map((ep, i) => `import * as ns${i} from '${ep.specifier}';`); - const useLine = `export const used = [${entrypoints.map((_, i) => `ns${i}`).join(', ')}];`; - writeFileSync(join(tmp, 'consume.ts'), `${importLines.join('\n')}\n${useLine}\n`); - const paths = {}; - const root = scopeDir(fixture, packageName); - for (const ep of entrypoints) { - const rel = ep.typesRel; - if (rel && existsSync(resolve(root, rel))) - paths[ep.specifier] = [toPosix(resolve(root, rel))]; - } - const tsconfig = { - compilerOptions: { - module: 'esnext', - moduleResolution: 'bundler', - target: 'es2020', - lib: ['es2020', 'dom'], - noEmit: true, - strict: false, - skipLibCheck: true, - types: [], - baseUrl: toPosix(fixture), - paths, - }, - include: [toPosix(join(tmp, 'consume.ts'))], - }; - writeFileSync(join(tmp, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2)); - const result = spawn('pnpm', ['exec', 'tsc', '-p', join(tmp, 'tsconfig.json')], { - cwd: repoRoot, - }); - if (!result.ok) { - const text = (result.stderr || result.stdout).trim(); - for (const ep of entrypoints) failures.push({ ep, error: text.split('\n')[0] }); - console.log(` types: tsc reported errors:\n${text.slice(0, 1200)}`); - } else { - for (const ep of entrypoints) console.log(` ok types ${ep.subpath}`); - } - } finally { - rmSync(tmp, { recursive: true, force: true }); + const importLines = entrypoints.map((ep, i) => `import * as ns${i} from '${ep.specifier}';`); + const useLine = `export const used = [${entrypoints.map((_, i) => `ns${i}`).join(', ')}];`; + writeFileSync(join(fixture, 'consume-types.ts'), `${importLines.join('\n')}\n${useLine}\n`); + + const tsconfig = { + compilerOptions: { + module: 'esnext', + moduleResolution: 'bundler', + target: 'es2020', + lib: ['es2020', 'dom'], + noEmit: true, + strict: false, + skipLibCheck: true, + }, + include: ['consume-types.ts'], + }; + writeFileSync(join(fixture, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2)); + + const result = spawn('pnpm', ['exec', 'tsc', '-p', join(fixture, 'tsconfig.json')], { + cwd: repoRoot, + }); + if (!result.ok) { + const text = (result.stderr || result.stdout).trim(); + for (const ep of entrypoints) failures.push({ ep, error: text.split('\n')[0] }); + console.log(` types: tsc reported errors:\n${text.slice(0, 1200)}`); + } else { + for (const ep of entrypoints) console.log(` ok types ${ep.subpath}`); } return failures; } @@ -535,7 +557,7 @@ function record(name, problems) { ); } -async function checkPackage(pkg) { +async function checkPackage(pkg, sharedPackDir) { const pkgDir = resolve(repoRoot, pkg.dir); const pkgJson = readPkgJson(pkgDir); console.log(`\n=== ${pkg.name} ===`); @@ -562,11 +584,9 @@ async function checkPackage(pkg) { problems.push(...checkFileList(pkgDir, pkgJson, listing.packed)); // 2. Pack a real tarball for the target package. - const tmp = mkdtempSync(join(tmpdir(), 'wraith-pkg-pack-')); - const packed = packTarball(pkgDir, tmp); + const packed = packTarball(pkgDir, sharedPackDir); if (packed.error) { problems.push(`pack: ${packed.error}`); - rmSync(tmp, { recursive: true, force: true }); record(pkg.name, problems); return; } @@ -576,7 +596,7 @@ async function checkPackage(pkg) { // 2b. Pack all transitive @wraith-protocol/* workspace dependencies so the // fixture install can resolve them from local tarballs rather than npm. - const wraith_dep_tarballs = packWraithDeps(pkg.name, tmp); + const wraith_dep_tarballs = packWraithDeps(pkg.name, sharedPackDir); // 3. Create a clean fixture and install everything via pnpm install so the // resulting node_modules layout matches a real consumer install. @@ -584,9 +604,14 @@ async function checkPackage(pkg) { const installed = installPackage(fixture, packed.tarball, pkgJson, wraith_dep_tarballs); if (!installed.ok) { - // Non-fatal for ESM/types checks — surface the error but continue so that - // documentedExportsOk still runs against the source on disk. - console.log(` note: ${installed.error}`); + problems.push(`fixture install: ${installed.error}`); + try { + rmSync(fixture, { recursive: true, force: true }); + } catch { + /* fixture already removed or locked */ + } + record(pkg.name, problems); + return; } // Only packages with JS entry points get ESM/types/export checks. @@ -612,7 +637,6 @@ async function checkPackage(pkg) { console.log(` no JS entry points (data-only package); skipping ESM/types/exports checks`); } - rmSync(tmp, { recursive: true, force: true }); try { rmSync(fixture, { recursive: true, force: true }); } catch { @@ -623,13 +647,18 @@ async function checkPackage(pkg) { } async function main() { - for (const pkg of PACKAGES) { - if (!existsSync(resolve(repoRoot, pkg.dir, 'package.json'))) { - console.error(`FAIL: package directory missing: ${pkg.dir}`); - failed += 1; - continue; + const sharedPackDir = mkdtempSync(join(tmpdir(), 'wraith-workspace-packs-')); + try { + for (const pkg of PACKAGES) { + if (!existsSync(resolve(repoRoot, pkg.dir, 'package.json'))) { + console.error(`FAIL: package directory missing: ${pkg.dir}`); + failed += 1; + continue; + } + await checkPackage(pkg, sharedPackDir); } - await checkPackage(pkg); + } finally { + rmSync(sharedPackDir, { recursive: true, force: true }); } console.log(`\nCompanion package smoke tests: ${results.length} packages, ${failed} failed`); From 760ccb92a84bf4daa22f98bb7496eced501fa979 Mon Sep 17 00:00:00 2001 From: cybermax4200 Date: Sat, 24 Oct 2026 07:42:14 +0100 Subject: [PATCH 4/4] fix(deps): bump next to ^15.5.28 to remediate GHSA-2464-fhr4-w9xw --- .../stellar-nextjs-app-router/package.json | 2 +- pnpm-lock.yaml | 490 ++++++++++++++---- security-audit.allowlist.json | 20 - 3 files changed, 399 insertions(+), 113 deletions(-) diff --git a/examples/stellar-nextjs-app-router/package.json b/examples/stellar-nextjs-app-router/package.json index eba738f..dc5e194 100644 --- a/examples/stellar-nextjs-app-router/package.json +++ b/examples/stellar-nextjs-app-router/package.json @@ -11,7 +11,7 @@ "@wraith-protocol/sdk": "file:../..", "@wraith-protocol/sdk-react": "file:../../packages/sdk-react", "@stellar/stellar-sdk": "^13.1.0", - "next": "^14.2.35", + "next": "^15.5.28", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16672a6..503a622 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -268,8 +268,8 @@ importers: specifier: file:../../packages/sdk-react version: file:packages/sdk-react(@stellar/stellar-sdk@13.3.0)(@wraith-protocol/sdk@file:(@solana/web3.js@1.98.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6))(@stellar/stellar-sdk@13.3.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: - specifier: ^14.2.35 - version: 14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^15.5.28 + version: 15.5.28(@types/node@20.19.43)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.3.1 version: 18.3.1 @@ -334,7 +334,7 @@ importers: version: 0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.7(@babel/core@7.29.7)) '@react-native/metro-config': specifier: ^0.76.0 - version: 0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.7(@babel/core@7.29.7))(bufferutil@4.1.0)(utf-8-validate@6.0.6) + version: 0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.7(@babel/core@7.29.7)) '@react-native/typescript-config': specifier: ^0.76.0 version: 0.76.9 @@ -1595,6 +1595,9 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -2203,7 +2206,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {'0': node >=0.10.0} + engines: {node: '>=0.10.0'} '@expo/cli@0.18.31': resolution: {integrity: sha512-v9llw9fT3Uv+TCM6Xllo54t672CuYtinEQZ2LPJ2EJsCwuTc4Cd2gXQaouuIVD21VoeGQnr5JtJuWbF97sBKzQ==} @@ -2293,6 +2296,168 @@ packages: '@hapi/topo@5.1.0': resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.5': + resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.5': + resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.5': + resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.4': + resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.4': + resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.4': + resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.3.4': + resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.3.4': + resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.3.4': + resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.3.4': + resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.3.4': + resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.35.5': + resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.35.5': + resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.35.5': + resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.35.5': + resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.35.5': + resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.35.5': + resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.35.5': + resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.35.5': + resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.35.5': + resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.5': + resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.5': + resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.5': + resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.5': + resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -2377,63 +2542,57 @@ packages: '@microsoft/tsdoc@0.16.0': resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} - '@next/env@14.2.35': - resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} + '@next/env@15.5.28': + resolution: {integrity: sha512-xxW5EBI8fMPuVTPBW7LL980IRbuDXlbkUAwp9DDhtb4Lnich3nJ13uYpvrX4VE74hWPf6AvHHAMmGCidcHjbfg==} - '@next/swc-darwin-arm64@14.2.33': - resolution: {integrity: sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==} + '@next/swc-darwin-arm64@15.5.28': + resolution: {integrity: sha512-dPoQYXcfSIqx5o+TOXVXO7kONK5qbtNRDeiTfII0bT3puGIT6VF5e0QwmxNZfEZ5Zety5f3m9P/p4xqwfiLlPg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@14.2.33': - resolution: {integrity: sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==} + '@next/swc-darwin-x64@15.5.28': + resolution: {integrity: sha512-RgCJ7buBivTH+6sddqaVm+/v8kwMHlFkobvdt3DfETutws5HrxnToMIWSN9X3MZ3aAi7BbKrGZZWUDQLEycXqw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@14.2.33': - resolution: {integrity: sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==} + '@next/swc-linux-arm64-gnu@15.5.28': + resolution: {integrity: sha512-OHXQe13olE59aKe++zHavGcJPh5SLHXi6Anret3BBeq1+qhSuOJDNAli/EDDfxs6UTqA4Qddo4uyYry2slyjiQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@14.2.33': - resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==} + '@next/swc-linux-arm64-musl@15.5.28': + resolution: {integrity: sha512-nTB7bB6vfn4ezCJNYP43ukt2o8L3+WxKF/sTcTxepdXsJh3SM9RhlU7wrZYbH7L4HO5M87dqDTwm8587vAkCiw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@14.2.33': - resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==} + '@next/swc-linux-x64-gnu@15.5.28': + resolution: {integrity: sha512-WXCfVI32rW3xCusoUX1RpZKtyChWU2Zwe27JUDmM3KrXwcDNc9vV4zEq0GKFAURnuQ/Ouo/XqPvB0yh445XZCg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@14.2.33': - resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==} + '@next/swc-linux-x64-musl@15.5.28': + resolution: {integrity: sha512-Miq+NDb/HWsXuxseYxMM6fuEOQXgTziarkKIRpVKCn8W69cEfhQaQr+90pO+u4q2CbJR2wzXmUuCFyZaJs/Nng==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@14.2.33': - resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==} + '@next/swc-win32-arm64-msvc@15.5.28': + resolution: {integrity: sha512-5LR79lemgDlgxvG7MQJ+zHCkVcrUoQuO7CiIvq3I58vNW4goSOE2b+19Z6FujRWMouvni4gvudYFuFuNxolGWA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-ia32-msvc@14.2.33': - resolution: {integrity: sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@next/swc-win32-x64-msvc@14.2.33': - resolution: {integrity: sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==} + '@next/swc-win32-x64-msvc@15.5.28': + resolution: {integrity: sha512-GNipvXUYROSTf4PXEyH95FrWImIB5zdaK6uEOg0RP1/X2drnvoMwiBkJ0VWdzX7w3iiBm3y5g2TxkKDGVTOQcg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2945,15 +3104,12 @@ packages: svelte: ^5.0.0 vite: ^6.0.0 - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} '@swc/helpers@0.5.21': resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} - '@swc/helpers@0.5.5': - resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} - '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} @@ -3721,10 +3877,6 @@ packages: peerDependencies: esbuild: '>=0.18' - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - bytes-iec@3.1.1: resolution: {integrity: sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA==} engines: {node: '>= 0.8'} @@ -4168,6 +4320,10 @@ packages: engines: {node: '>=0.10'} hasBin: true + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devalue@5.8.1: resolution: {integrity: sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==} @@ -5908,21 +6064,24 @@ packages: nested-error-stacks@2.0.1: resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} - next@14.2.35: - resolution: {integrity: sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==} - engines: {node: '>=18.17.0'} + next@15.5.28: + resolution: {integrity: sha512-JjhLBBY1PNnuwPtcZ7t8yxVeJVYvD2Jyp633J+gRCNbzSt7N0E+xqCf6uQiff3+3qmUkwcF/ksfSsK1xsZ76Tw==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': optional: true '@playwright/test': optional: true + babel-plugin-react-compiler: + optional: true sass: optional: true @@ -6693,6 +6852,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -6749,6 +6913,15 @@ packages: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} + sharp@0.35.5: + resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -6902,10 +7075,6 @@ packages: stream-json@1.9.1: resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -6973,13 +7142,13 @@ packages: structured-headers@0.4.1: resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==} - styled-jsx@5.1.1: - resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' peerDependenciesMeta: '@babel/core': optional: true @@ -8972,6 +9141,11 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -9567,6 +9741,113 @@ snapshots: dependencies: '@hapi/hoek': 9.3.0 + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.4 + optional: true + + '@img/sharp-darwin-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.4 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + optional: true + + '@img/sharp-linux-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.4 + optional: true + + '@img/sharp-linux-arm@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.4 + optional: true + + '@img/sharp-linux-ppc64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.4 + optional: true + + '@img/sharp-linux-riscv64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.4 + optional: true + + '@img/sharp-linux-s390x@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.4 + optional: true + + '@img/sharp-linux-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + optional: true + + '@img/sharp-wasm32@0.35.5': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 + optional: true + + '@img/sharp-win32-arm64@0.35.5': + optional: true + + '@img/sharp-win32-ia32@0.35.5': + optional: true + + '@img/sharp-win32-x64@0.35.5': + optional: true + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -9722,33 +10003,30 @@ snapshots: '@microsoft/tsdoc@0.16.0': {} - '@next/env@14.2.35': {} + '@next/env@15.5.28': {} - '@next/swc-darwin-arm64@14.2.33': + '@next/swc-darwin-arm64@15.5.28': optional: true - '@next/swc-darwin-x64@14.2.33': + '@next/swc-darwin-x64@15.5.28': optional: true - '@next/swc-linux-arm64-gnu@14.2.33': + '@next/swc-linux-arm64-gnu@15.5.28': optional: true - '@next/swc-linux-arm64-musl@14.2.33': + '@next/swc-linux-arm64-musl@15.5.28': optional: true - '@next/swc-linux-x64-gnu@14.2.33': + '@next/swc-linux-x64-gnu@15.5.28': optional: true - '@next/swc-linux-x64-musl@14.2.33': + '@next/swc-linux-x64-musl@15.5.28': optional: true - '@next/swc-win32-arm64-msvc@14.2.33': + '@next/swc-win32-arm64-msvc@15.5.28': optional: true - '@next/swc-win32-ia32-msvc@14.2.33': - optional: true - - '@next/swc-win32-x64-msvc@14.2.33': + '@next/swc-win32-x64-msvc@15.5.28': optional: true '@noble/ciphers@1.3.0': {} @@ -10193,7 +10471,7 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/metro-config@0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.7(@babel/core@7.29.7))(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + '@react-native/metro-config@0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.7(@babel/core@7.29.7))': dependencies: '@react-native/js-polyfills': 0.76.9 '@react-native/metro-babel-transformer': 0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.7(@babel/core@7.29.7)) @@ -10202,9 +10480,7 @@ snapshots: transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - - bufferutil - supports-color - - utf-8-validate '@react-native/normalize-colors@0.72.0': {} @@ -10550,15 +10826,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@swc/counter@0.1.3': {} - - '@swc/helpers@0.5.21': + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 - '@swc/helpers@0.5.5': + '@swc/helpers@0.5.21': dependencies: - '@swc/counter': 0.1.3 tslib: 2.8.1 '@testing-library/dom@10.4.1': @@ -11504,10 +11777,6 @@ snapshots: esbuild: 0.27.7 load-tsconfig: 0.2.5 - busboy@1.6.0: - dependencies: - streamsearch: 1.1.0 - bytes-iec@3.1.1: {} bytes@3.1.2: {} @@ -11957,6 +12226,9 @@ snapshots: detect-libc@1.0.3: {} + detect-libc@2.1.2: + optional: true + devalue@5.8.1: {} diff@8.0.4: {} @@ -14306,29 +14578,28 @@ snapshots: nested-error-stacks@2.0.1: {} - next@14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@15.5.28(@types/node@20.19.43)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@next/env': 14.2.35 - '@swc/helpers': 0.5.5 - busboy: 1.6.0 + '@next/env': 15.5.28 + '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001803 - graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.1(react@18.3.1) + styled-jsx: 5.1.6(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 14.2.33 - '@next/swc-darwin-x64': 14.2.33 - '@next/swc-linux-arm64-gnu': 14.2.33 - '@next/swc-linux-arm64-musl': 14.2.33 - '@next/swc-linux-x64-gnu': 14.2.33 - '@next/swc-linux-x64-musl': 14.2.33 - '@next/swc-win32-arm64-msvc': 14.2.33 - '@next/swc-win32-ia32-msvc': 14.2.33 - '@next/swc-win32-x64-msvc': 14.2.33 + '@next/swc-darwin-arm64': 15.5.28 + '@next/swc-darwin-x64': 15.5.28 + '@next/swc-linux-arm64-gnu': 15.5.28 + '@next/swc-linux-arm64-musl': 15.5.28 + '@next/swc-linux-x64-gnu': 15.5.28 + '@next/swc-linux-x64-musl': 15.5.28 + '@next/swc-win32-arm64-msvc': 15.5.28 + '@next/swc-win32-x64-msvc': 15.5.28 + sharp: 0.35.5(@types/node@20.19.43) transitivePeerDependencies: - '@babel/core' + - '@types/node' - babel-plugin-macros nice-try@1.0.5: {} @@ -15206,6 +15477,9 @@ snapshots: semver@7.7.4: {} + semver@7.8.5: + optional: true + send@0.18.0: dependencies: debug: 2.6.9 @@ -15297,6 +15571,40 @@ snapshots: dependencies: kind-of: 6.0.3 + sharp@0.35.5(@types/node@20.19.43): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 + '@types/node': 20.19.43 + optional: true + shebang-command@1.2.0: dependencies: shebang-regex: 1.0.0 @@ -15449,8 +15757,6 @@ snapshots: dependencies: stream-chain: 2.2.5 - streamsearch@1.1.0: {} - string-argv@0.3.2: {} string-width@4.2.3: @@ -15527,7 +15833,7 @@ snapshots: structured-headers@0.4.1: {} - styled-jsx@5.1.1(react@18.3.1): + styled-jsx@5.1.6(react@18.3.1): dependencies: client-only: 0.0.1 react: 18.3.1 diff --git a/security-audit.allowlist.json b/security-audit.allowlist.json index 953909e..7ef2493 100644 --- a/security-audit.allowlist.json +++ b/security-audit.allowlist.json @@ -52,26 +52,6 @@ "scope": "example (private, unpublished)", "reason": "Deep transitive dependency of expo in the react-native-stellar example. The example is `private: true` and is not part of the published SDK report.", "remediation": "Upgrade expo in examples/react-native-stellar so tar reaches >=7.5.19." - }, - { - "id": "GHSA-p293-qw3h-jr36", - "module": "next", - "installed": "14.2.35", - "patched": ">=15.5.24", - "finding_path": "examples__stellar-nextjs-app-router>next", - "scope": "example (private, unpublished)", - "reason": "Next.js 14 in the stellar-nextjs-app-router example. The example is `private: true` and is not part of the published SDK report; upgrading Next 14→15 is a major change tracked separately.", - "remediation": "Upgrade next in examples/stellar-nextjs-app-router to >=15.5.24." - }, - { - "id": "GHSA-2xp9-vwfh-vxw4", - "module": "next", - "installed": "14.2.35", - "patched": ">=15.5.24", - "finding_path": "examples__stellar-nextjs-app-router>next", - "scope": "example (private, unpublished)", - "reason": "Next.js 14 in the stellar-nextjs-app-router example. The example is `private: true` and is not part of the published SDK report; upgrading Next 14→15 is a major change tracked separately.", - "remediation": "Upgrade next in examples/stellar-nextjs-app-router to >=15.5.24." } ] }