création du serveur

This commit is contained in:
Didictateur 2025-11-07 20:19:34 +01:00
parent db6f3ebc51
commit 8d1d718f5f
1122 changed files with 21290 additions and 3402 deletions

3
.dockerignore Normal file
View file

@ -0,0 +1,3 @@
node_modules
npm-debug.log
.DS_Store

41
.gitignore vendored
View file

@ -1,41 +0,0 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Linker files
*.ilk
# Debugger Files
*.pdb
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# debug information files
*.dwo

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "frontend/public/assets/chess-pieces"]
path = frontend/public/assets/chess-pieces
url = git@github.com:Kadagaden/chess-pieces.git

12
Dockerfile Normal file
View file

@ -0,0 +1,12 @@
FROM node:18-alpine
WORKDIR /app
# Install deps first (cache)
COPY package.json package-lock.json* ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

View file

@ -1,29 +0,0 @@
.PHONY: sync-frontend dev-sync
all: docker sync-frontend dev-sync
docker:
docker-compose -f deploy/docker-compose.dev.yml up --build -d
@echo "Frontend is running at http://localhost:3000"
@echo "Backend is running at http://localhost:4000"
stop:
docker-compose -f deploy/docker-compose.dev.yml down
@echo "Stopped."
restart: stop docker
sync-frontend:
@echo "Syncing frontend source -> public for dev..."
@rsync -av --exclude node_modules --exclude .git --delete frontend/src/ frontend/public/src/
dev-sync: sync-frontend
@echo "Done. You can run 'make dev-sync' whenever you changed frontend/src files."
.PHONY: dev-watch
dev-watch:
@echo "Watching frontend/src for changes (requires inotifywait). Press Ctrl-C to stop."
@which inotifywait > /dev/null || (echo "Please install inotify-tools (apt install inotify-tools)" && exit 1)
while inotifywait -e modify,create,delete -r frontend/src; do \
$(MAKE) dev-sync; \
done

View file

@ -1,25 +0,0 @@
Dev quickstart (mock backend + static frontend)
From repo root run:
cd deploy
docker-compose -f docker-compose.dev.yml up --build -d
Then open http://localhost:3000 for the frontend. Backend API listens on http://localhost:4000
If you edit files under `frontend/src/` during development, run:
make dev-sync
This will copy changed files into `frontend/public/src/` so the static server (http://localhost:3000) serves the latest JS/CSS without rebuilding containers.
Development workflow note
-------------------------
Two strategies are supported during development to ensure the static server serves the latest frontend sources:
- Symlink (used in this repo): `frontend/public/src/game.js` is a symbolic link to `../../src/game.js` so there's one source of truth. This avoids accidental drift between `src/` and `public/src/` when editing locally. Symlinks are convenient for local development but may not be appropriate for all deployment or CI environments.
- Rsync / dev-sync: Run `make dev-sync` to copy files from `frontend/src/` into `frontend/public/src/`. This works in environments where symlinks are undesirable or when preparing files for containers.
Choose the approach that fits your workflow. This repository currently keeps a regular copy of `game.js` in `frontend/public/src/` (to avoid symlink issues in containers/CI), and `make dev-sync` remains available as the recommended way to update the public copy during development.

View file

@ -1,7 +0,0 @@
FROM node:22-alpine
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci --only=production || npm install --only=production
COPY . .
EXPOSE 4000
CMD ["node","index.js"]

View file

@ -1,16 +0,0 @@
Backend mock for ChessNut (Express + Socket.IO)
API endpoints:
- POST /api/create { name, pass }
- GET /api/list
- POST /api/join { id, pass }
Socket.IO events:
- join-game (room name)
- move (payload includes gameId)
Run locally:
cd backend
npm install
node index.js

View file

@ -1,29 +0,0 @@
// Small ESM helper run by backend to instantiate engine GameState and print a minimal serialized view.
import fs from 'fs';
import path from 'path';
async function main(){
try{
const enginePath = 'file:///app/engine/core/game_state.js';
const mod = await import(enginePath);
const GameState = mod && (mod.default || mod.GameState);
if(typeof GameState !== 'function'){
console.error(JSON.stringify({ ok:false, error: 'GameState not found in module', keys: Object.keys(mod||{}) }));
process.exit(2);
}
const gs = new GameState();
// attempt a minimal serialization similar to server's serializeEngineState
let boardObj = (typeof gs.getBoard === 'function') ? gs.getBoard() : gs.board;
const w = (typeof boardObj.getWidth === 'function') ? boardObj.getWidth() : (boardObj.width || 8);
const h = (typeof boardObj.getHeight === 'function') ? boardObj.getHeight() : (boardObj.height || 8);
const board = Array.from({ length: h }, () => Array.from({ length: w }, () => null));
// best-effort: leave board nulls—engine may have complex pieces
const out = { ok:true, width: w, height: h };
console.log(JSON.stringify(out));
}catch(e){
console.error(JSON.stringify({ ok:false, error: (e && e.stack) || String(e) }));
process.exit(1);
}
}
main();

View file

@ -1,511 +0,0 @@
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(bodyParser.json());
const fs = require('fs');
const path = require('path');
const LOGFILE = process.env.CHESSNUT_LOG || '/tmp/chessnut.log';
function appendLogLine(line){
try{ fs.appendFileSync(LOGFILE, line + '\n'); }catch(e){}
}
function log(){
const ts = new Date().toISOString();
const msg = Array.prototype.slice.call(arguments).map(x => (typeof x === 'string' ? x : JSON.stringify(x))).join(' ');
const line = `${ts} ${msg}`;
console.log(line);
appendLogLine(line);
}
// Request logging middleware: logs method, path, small subset of headers and body
app.use((req, res, next) => {
try{
const { method, path } = req;
const info = { method, path, headers: { origin: req.headers.origin, host: req.headers.host }, body: req.body };
log('HTTP', info);
}catch(e){}
next();
});
const server = http.createServer(app);
const io = new Server(server, { cors: { origin: '*' } });
const PORT = process.env.PORT || 4000;
// simple in-memory storage (not persisted)
const games = [];
// map socket.id -> { gameId, playerId }
const socketMap = new Map();
// map `${gameId}:${playerId}` -> timeoutId for pending disconnects
const pendingDisconnects = new Map();
function pdKey(gameId, playerId){ return `${gameId}:${playerId}`; }
// Diagnostic helper: attempt to dynamically import the engine GameState module
async function tryImportEngine(){
const candidates = [];
// common possibilities inside container /app
candidates.push(path.join(__dirname, 'engine', 'core', 'game_state.js'));
candidates.push(path.resolve(__dirname, '../engine/core/game_state.js'));
candidates.push('/app/engine/core/game_state.js');
candidates.push('/engine/core/game_state.js');
const attemptErrors = {};
for (const candidate of candidates) {
try {
const urlStr = 'file://' + candidate;
const mod = await import(urlStr);
log('tryImportEngine: import OK', { tried: candidate, keys: Object.keys(mod) });
return { ok: true, mod, tried: candidate };
} catch (e) {
attemptErrors[candidate] = (e && e.stack) || String(e);
}
}
// if we get here, all attempts failed — gather snippets from likely engine dir(s)
const files = ['game_state.js','board.js','piece.js','cell.js'];
const snippets = {};
const probeDirs = [path.join(__dirname, 'engine', 'core'), path.resolve(__dirname, '../engine/core'), '/app/engine/core', '/engine/core'];
for (const d of probeDirs) {
for (const f of files) {
const p = path.join(d, f);
try { const txt = fs.readFileSync(p, 'utf8'); snippets[p] = txt.slice(0, 2000); } catch(err) { snippets[p] = `read-failed: ${err && err.message}`; }
}
}
log('tryImportEngine: all attempts failed', { attempts: Object.keys(attemptErrors).length, attemptErrors: Object.keys(attemptErrors).reduce((acc,k)=>{acc[k]=attemptErrors[k].split('\n')[0];return acc;},{}) });
try{ fs.writeFileSync('/tmp/chessnut-engine-import-error.log', JSON.stringify({ time: new Date().toISOString(), attemptErrors, snippets }, null, 2)); }catch(err){}
// try fallback by running engine-loader.mjs (ESM) via node
try{
const loaderRes = await runEngineLoader();
log('tryImportEngine: runEngineLoader result', { loaderRes });
if(loaderRes && loaderRes.ok) return { ok: true, loader: loaderRes };
}catch(e){ log('tryImportEngine: runEngineLoader failed', { err: e && e.stack || e }); }
return { ok: false, error: attemptErrors, snippets };
}
// Fallback: try to run engine-loader.mjs via node (spawn) to let node use ESM loader
const { spawnSync } = require('child_process');
async function runEngineLoader(){
try{
const loaderPath = path.join(__dirname, 'engine-loader.mjs');
const res = spawnSync('node', [loaderPath], { encoding: 'utf8', maxBuffer: 200000 });
if(res.error){ return { ok:false, error: res.error.message }; }
if(res.status !== 0){
return { ok:false, stdout: res.stdout, stderr: res.stderr, status: res.status };
}
try{ const j = JSON.parse(res.stdout || '{}'); return { ok:true, result: j, raw: res.stdout }; }catch(e){ return { ok:true, raw: res.stdout }; }
}catch(e){ return { ok:false, error: e && e.stack }; }
}
app.post('/api/create', (req, res) => {
console.log('[backend] POST /api/create received', req.body && { name: req.body.name, owner: req.body.ownerNickname });
const id = 'game-' + Math.random().toString(36).slice(2,9);
const { name, pass, ownerNickname, ownerColorChoice } = req.body || {};
const g = {
id,
name: name || id,
pass: pass || null,
created: Date.now(),
players: [],
started: false,
options: { startWhenTwo: true }
};
// add owner as first player if provided
let ownerPlayer = null;
if(ownerNickname){
ownerPlayer = { id: 'p-' + Math.random().toString(36).slice(2,6), nickname: ownerNickname, colorChoice: ownerColorChoice || 'random', colorAssigned: null };
g.players.push(ownerPlayer);
// explicit owner id for robust ownership checks
g.ownerId = ownerPlayer.id;
}
games.push(g);
io.emit('games-list', games);
// return game and owner player if present so frontend can persist player id
if(ownerPlayer) return res.json({ ok: true, game: g, player: ownerPlayer });
res.json({ ok: true, game: g });
});
app.get('/api/list', (req, res) => {
// remove any orphan games (no players)
for (let i = games.length - 1; i >= 0; i--) {
const g = games[i];
if(!g.players || g.players.length === 0){
games.splice(i, 1);
}
}
res.json(games);
});
// remove previously created test games (names used during local testing)
app.post('/api/cleanup-tests', (req, res) => {
const patterns = [/^test$/i, /^curl-test$/i, /^start-test$/i];
const before = games.length;
for (let i = games.length - 1; i >= 0; i--) {
const g = games[i];
if (patterns.some(p => p.test(g.name))) {
games.splice(i, 1);
}
}
const removed = before - games.length;
io.emit('games-list', games);
res.json({ ok: true, removed });
});
function pruneOrphans(){
let removed = 0;
for (let i = games.length - 1; i >= 0; i--) {
const g = games[i];
if(!g.players || g.players.length === 0){ games.splice(i,1); removed++; }
}
if(removed) io.emit('games-list', games);
return removed;
}
// allow manual prune via api for dev
app.post('/api/prune-orphans', (req, res) => {
const removed = pruneOrphans();
res.json({ ok: true, removed });
});
// dev helper: delete game(s) by exact name
app.post('/api/delete-by-name', (req, res) => {
const { name } = req.body || {};
if(!name) return res.status(400).json({ error: 'name required' });
const before = games.length;
for (let i = games.length - 1; i >= 0; i--) {
if (games[i].name === name) games.splice(i,1);
}
const removed = before - games.length;
if(removed) io.emit('games-list', games);
res.json({ ok: true, removed });
});
// dev helper: delete a game by id
app.post('/api/delete-by-id', (req, res) => {
const { id } = req.body || {};
if(!id) return res.status(400).json({ error: 'id required' });
const idx = games.findIndex(g => g.id === id);
if(idx === -1) return res.status(404).json({ error: 'not found' });
games.splice(idx, 1);
io.emit('games-list', games);
res.json({ ok: true, removed: 1 });
});
// periodic prune every minute
setInterval(() => { pruneOrphans(); }, 60 * 1000);
app.post('/api/join', (req, res) => {
const { id, pass, nickname, colorChoice } = req.body || {};
const g = games.find(x => x.id === id);
if(!g) {
// log current games snapshot to help debugging
try{
const snapshot = games.map(x => ({ id: x.id, name: x.name, players: (x.players||[]).length, started: !!x.started }));
log('start failed - game not found', { requestedId: id, gamesSnapshot: snapshot });
}catch(e){ log('start failed - game not found (and failed to snapshot)'); }
return res.status(404).json({ error: 'not found' });
}
if(g.pass && g.pass !== pass) return res.status(403).json({ error: 'bad password' });
if(g.players.length >= 2) return res.status(403).json({ error: 'full' });
const player = { id: 'p-' + Math.random().toString(36).slice(2,6), nickname: nickname || 'Anon', colorChoice: colorChoice || 'random', colorAssigned: null };
player.connected = true;
g.players.push(player);
io.to(g.id).emit('player-update', g);
io.emit('games-list', games);
res.json({ ok: true, game: g, player });
});
// leave a game: payload { gameId, playerId }
app.post('/api/leave', (req, res) => {
const { gameId, playerId } = req.body || {};
const gIndex = games.findIndex(x => x.id === gameId);
if(gIndex === -1) return res.status(404).json({ error: 'not found' });
const g = games[gIndex];
const pIndex = g.players.findIndex(p => p.id === playerId);
if(pIndex === -1) return res.status(404).json({ error: 'player not in game' });
// do not allow leaving once game started
if (g.started) return res.status(403).json({ error: 'game in progress' });
// remove player (allowed only if game not started)
const leaving = g.players.splice(pIndex, 1)[0];
// clear any pending disconnect timer for this player
const key = pdKey(gameId, playerId);
if(pendingDisconnects.has(key)){ clearTimeout(pendingDisconnects.get(key)); pendingDisconnects.delete(key); }
// if the leaving player was the owner, remove the entire game
if(g.ownerId && leaving.id === g.ownerId){
games.splice(gIndex, 1);
io.emit('games-list', games);
io.to(gameId).emit('game-deleted', { gameId });
return res.json({ ok: true, deleted: true });
}
io.to(gameId).emit('player-update', g);
io.emit('games-list', games);
res.json({ ok: true, game: g });
});
app.get('/api/game/:id', (req, res) => {
const id = req.params.id;
const g = games.find(x => x.id === id);
if(!g) return res.status(404).json({ error: 'not found' });
// if game exists but has no players, treat as not found and remove it
if(!g.players || g.players.length === 0){
// only prune if game has not started
if (!g.started) {
const idx = games.findIndex(x => x.id === id);
if(idx !== -1) games.splice(idx, 1);
return res.status(404).json({ error: 'not found' });
}
}
res.json(g);
});
app.post('/api/start', async (req, res) => {
const { id } = req.body || {};
log('POST /api/start', { id, body: req.body });
const g = games.find(x => x.id === id);
if(!g) return res.status(404).json({ error: 'not found' });
if(g.players.length < 2) {
log('start rejected: need 2 players', { gameId: id, players: g.players.map(p=>p.id) });
return res.status(400).json({ error: 'need 2 players' });
}
// assign colors
const p0 = g.players[0];
const p1 = g.players[1];
function assign(){
// if one chose white and other chose black, honor
if(p0.colorChoice === 'white' && p1.colorChoice === 'black'){ p0.colorAssigned = 'white'; p1.colorAssigned = 'black'; return; }
if(p0.colorChoice === 'black' && p1.colorChoice === 'white'){ p0.colorAssigned = 'black'; p1.colorAssigned = 'white'; return; }
// if one fixed and other random, honor fixed
if(p0.colorChoice === 'white' || p0.colorChoice === 'black'){ p0.colorAssigned = p0.colorChoice; p1.colorAssigned = (p0.colorChoice === 'white' ? 'black' : 'white'); return; }
if(p1.colorChoice === 'white' || p1.colorChoice === 'black'){ p1.colorAssigned = p1.colorChoice; p0.colorAssigned = (p1.colorChoice === 'white' ? 'black' : 'white'); return; }
// otherwise random
if(Math.random() < 0.5){ p0.colorAssigned = 'white'; p1.colorAssigned = 'black'; } else { p0.colorAssigned = 'black'; p1.colorAssigned = 'white'; }
}
assign();
// Safety: if both players somehow received the same color (bug/regression), force distinct colors
try{
if (p0.colorAssigned && p1.colorAssigned && p0.colorAssigned === p1.colorAssigned) {
log('api/start: duplicate colorAssigned detected, forcing distinct assignment', { gameId: g.id, p0: p0.id, p1: p1.id, current: p0.colorAssigned });
p0.colorAssigned = 'white';
p1.colorAssigned = 'black';
}
}catch(e){ log('api/start: safety assignment check failed', { err: e && e.stack }); }
// Notify clients about players/colors immediately
try{ io.to(g.id).emit('player-update', g); }catch(e){ log('failed to emit player-update after assign', { err: e && e.stack }); }
g.started = true;
// Initialize a minimal game.state to be consumed by frontend.
// We avoid importing engine/ here: state is a plain JS structure describing the board.
// Board is an 8x8 array of cells; each cell is either null or { color: 'white'|'black', type: 'PAWN'|'ROOK'|... }
function initialState() {
const w = 8, h = 8;
const board = Array.from({ length: h }, () => Array.from({ length: w }, () => null));
// pawns
for (let x = 0; x < w; x++) {
board[1][x] = { color: 'white', type: 'PAWN' };
board[6][x] = { color: 'black', type: 'PAWN' };
}
// rooks
board[0][0] = { color: 'white', type: 'ROOK' };
board[0][7] = { color: 'white', type: 'ROOK' };
board[7][0] = { color: 'black', type: 'ROOK' };
board[7][7] = { color: 'black', type: 'ROOK' };
// knights
board[0][1] = { color: 'white', type: 'KNIGHT' };
board[0][6] = { color: 'white', type: 'KNIGHT' };
board[7][1] = { color: 'black', type: 'KNIGHT' };
board[7][6] = { color: 'black', type: 'KNIGHT' };
// bishops
board[0][2] = { color: 'white', type: 'BISHOP' };
board[0][5] = { color: 'white', type: 'BISHOP' };
board[7][2] = { color: 'black', type: 'BISHOP' };
board[7][5] = { color: 'black', type: 'BISHOP' };
// queen/king
board[0][3] = { color: 'white', type: 'QUEEN' };
board[0][4] = { color: 'white', type: 'KING' };
board[7][3] = { color: 'black', type: 'QUEEN' };
board[7][4] = { color: 'black', type: 'KING' };
return { board, width: w, height: h };
}
// only initialize if not already present
if (!g.state) {
// attempt to import engine GameState for richer state; on failure we log diagnostics
const importResult = await tryImportEngine();
if (importResult.ok) {
try {
const GameState = importResult.mod && (importResult.mod.default || importResult.mod.GameState);
if (typeof GameState === 'function') {
const gs = new GameState();
g._engineState = gs;
// best-effort serialize engine board into plain structure
try{
const serialized = (typeof gs.getBoard === 'function') ? (function(){
const boardObj = gs.getBoard();
const w = (typeof boardObj.getWidth === 'function') ? boardObj.getWidth() : (boardObj.width || 8);
const h = (typeof boardObj.getHeight === 'function') ? boardObj.getHeight() : (boardObj.height || 8);
const board = Array.from({ length: h }, (v, y) => Array.from({ length: w }, (v2, x) => {
try {
const cell = (typeof boardObj.getCell === 'function') ? boardObj.getCell(x, y) : (boardObj.grid && boardObj.grid[y] && boardObj.grid[y][x]);
if (!cell || !cell.piece) return null;
const p = cell.piece;
const color = (typeof p.getColor === 'function' ? p.getColor() : p.color) || p.color;
const type = (typeof p.getType === 'function' ? p.getType() : p.type) || p.type;
return { color: String(color).toLowerCase(), type: String(type).toUpperCase() };
} catch (e) { return null; }
}));
return { board, width: w, height: h };
})() : null;
g.state = serialized || initialState();
}catch(e){ log('engine serialization failed, falling back', { err: e && e.stack }); g.state = initialState(); }
} else {
log('imported engine module does not expose GameState constructor, falling back to plain state');
g.state = initialState();
}
} catch(e){ log('failed to instantiate GameState, falling back', { err: e && e.stack }); g.state = initialState(); }
} else {
// engine import failed: do NOT abort. Use the plain initial state so server continues to work
log('api/start: engine import failed, falling back to plain initialState', { gameId: g.id, diagnostic: importResult });
g.state = initialState();
}
}
// set initial turn: white starts
g.turn = 'white';
log('start succeeded', { gameId: g.id, players: g.players.map(p => ({ id: p.id, nickname: p.nickname, colorAssigned: p.colorAssigned })) });
io.to(g.id).emit('game-start', g);
io.emit('games-list', games);
res.json({ ok: true, game: g });
});
io.on('connection', (socket) => {
log('socket connected', { socketId: socket.id, remote: socket.handshake && socket.handshake.address });
socket.on('join-game', (gameId) => {
const room = gameId;
socket.join(room);
log('join-game', { socketId: socket.id, room });
});
// client can identify which player it is in a game so server can map socket -> player
socket.on('identify', (payload) => {
try {
const { gameId, playerId } = payload || {};
if(gameId && playerId){
socketMap.set(socket.id, { gameId, playerId });
log('identify', { socketId: socket.id, gameId, playerId });
// if this player had a pending disconnect timer, cancel it and mark reconnected
const key = pdKey(gameId, playerId);
if(pendingDisconnects.has(key)){
clearTimeout(pendingDisconnects.get(key));
pendingDisconnects.delete(key);
// mark player as connected again and notify others
const g = games.find(x => x.id === gameId);
if(g){
const p = g.players.find(p => p.id === playerId);
if(p){ p.connected = true; io.to(gameId).emit('player-update', g); io.emit('games-list', games); }
}
}
}
}catch(e){ }
});
socket.on('move', (payload) => {
try {
log('socket move', { socketId: socket.id, payload });
const { gameId, playerId, from, to } = payload || {};
const g = games.find(x => x.id === gameId);
if (!g) return;
// basic validation: must be started and it must be the player's turn
if (!g.started) return;
const player = g.players.find(p => p.id === playerId);
if (!player) return;
// determine player's color
const color = player.colorAssigned || (player.colorChoice === 'white' ? 'white' : (player.colorChoice === 'black' ? 'black' : null));
// if no assigned color (random choice), try to infer from players array
if (!color) {
if (g.players[0] && g.players[1]) {
// if not assigned, assume assignment as in /api/start logic
// fallback: first player white
}
}
// ensure it is this player's turn (simple toggle 'white'/'black')
if (g.turn && color && g.turn !== color) {
// not this player's turn
socket.emit('error', { error: 'not your turn' });
return;
}
// bounds check and cell existence
const h = g.state.height || g.state.board.length;
const w = g.state.width || (g.state.board[0] && g.state.board[0].length) || 8;
if (!from || !to) return;
if (from.x < 0 || from.x >= w || from.y < 0 || from.y >= h) return;
if (to.x < 0 || to.x >= w || to.y < 0 || to.y >= h) return;
const src = g.state.board[from.y][from.x];
if (!src) return; // no piece at source
if (src.color !== color) { socket.emit('error', { error: 'not your piece' }); return; }
// naive move apply: move piece from src to dest (no legality checks beyond ownership)
const dst = g.state.board[to.y][to.x];
// apply
g.state.board[to.y][to.x] = src;
g.state.board[from.y][from.x] = null;
// toggle turn
g.turn = g.turn === 'white' ? 'black' : 'white';
io.to(gameId).emit('move', { gameId, playerId, from, to });
io.to(gameId).emit('game-state', g.state);
} catch (e) {
console.error('move handler error', e && e.stack);
}
});
socket.on('disconnect', (reason) => {
const meta = socketMap.get(socket.id);
log('socket disconnect', { socketId: socket.id, reason, meta });
if(!meta) return;
const { gameId, playerId } = meta;
// remove mapping for this socket immediately
socketMap.delete(socket.id);
// schedule a delayed removal: if the player doesn't reconnect within 3s, consider them left
const key = pdKey(gameId, playerId);
if(pendingDisconnects.has(key)){
clearTimeout(pendingDisconnects.get(key));
pendingDisconnects.delete(key);
}
const t = setTimeout(() => {
// perform removal after grace period
const gIndex = games.findIndex(x => x.id === gameId);
if(gIndex === -1){ pendingDisconnects.delete(key); return; }
const g = games[gIndex];
const pIndex = g.players.findIndex(p => p.id === playerId);
if(pIndex === -1){ pendingDisconnects.delete(key); return; }
const player = g.players[pIndex];
// remove player regardless of started state (user asked players away >3s are considered left)
const leaving = g.players.splice(pIndex, 1)[0];
log('delayed remove player', { gameId, playerId: leaving.id, owner: g.ownerId });
// if owner left, remove entire game immediately
if(g.ownerId && leaving.id === g.ownerId){
games.splice(gIndex, 1);
io.emit('games-list', games);
io.to(gameId).emit('game-deleted', { gameId });
pendingDisconnects.delete(key);
return;
}
io.to(gameId).emit('player-update', g);
io.emit('games-list', games);
pendingDisconnects.delete(key);
}, 3000);
pendingDisconnects.set(key, t);
});
});
server.listen(PORT, () => console.log(`backend listening ${PORT}`));

View file

@ -1,22 +0,0 @@
export {}; // Make this a module
declare global {
namespace NodeJS {
type TypedArray<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike> =
| Uint8Array<TArrayBuffer>
| Uint8ClampedArray<TArrayBuffer>
| Uint16Array<TArrayBuffer>
| Uint32Array<TArrayBuffer>
| Int8Array<TArrayBuffer>
| Int16Array<TArrayBuffer>
| Int32Array<TArrayBuffer>
| BigUint64Array<TArrayBuffer>
| BigInt64Array<TArrayBuffer>
| Float16Array<TArrayBuffer>
| Float32Array<TArrayBuffer>
| Float64Array<TArrayBuffer>;
type ArrayBufferView<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike> =
| TypedArray<TArrayBuffer>
| DataView<TArrayBuffer>;
}
}

View file

@ -1,20 +0,0 @@
export {}; // Make this a module
declare global {
namespace NodeJS {
type TypedArray =
| Uint8Array
| Uint8ClampedArray
| Uint16Array
| Uint32Array
| Int8Array
| Int16Array
| Int32Array
| BigUint64Array
| BigInt64Array
| Float16Array
| Float32Array
| Float64Array;
type ArrayBufferView = TypedArray | DataView;
}
}

View file

@ -1,15 +0,0 @@
{
"name": "chessnut-backend",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "node index.js",
"dev": "NODE_ENV=development node index.js"
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.2",
"socket.io": "^4.7.1",
"body-parser": "^1.20.2"
}
}

View file

@ -1,33 +0,0 @@
import fs from 'fs';
import path from 'path';
import url from 'url';
(async function(){
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
const p = path.resolve(__dirname, '../engine/core/game_state.js');
console.log('Trying to load:', p);
try{
const content = fs.readFileSync(p, 'utf8');
console.log('File exists, first 200 chars:\n', content.slice(0,200));
}catch(e){ console.error('Cannot read file', e && e.message); }
try{
console.log('\nAttempting dynamic import() with file:// path...');
const mod = await import('file://' + p);
console.log('Imported module keys:', Object.keys(mod));
console.log('Default export type:', typeof mod.default);
}catch(e){
console.error('import(file://) failed:');
console.error(e && e.stack || e);
}
try{
console.log('\nAttempting import with relative path from backend:');
const mod2 = await import('../engine/core/game_state.js');
console.log('Imported module keys (rel):', Object.keys(mod2));
console.log('Default export type (rel):', typeof mod2.default);
}catch(e){
console.error('relative import failed:');
console.error(e && e.stack || e);
}
})();

View file

@ -1,16 +0,0 @@
version: '3.8'
services:
backend:
build: ../backend
ports:
- '4000:4000'
volumes:
- ../backend:/app
- ../engine:/app/engine
frontend:
image: nginx:stable-alpine
ports:
- '3000:80'
volumes:
- ../frontend/public:/usr/share/nginx/html:ro

View file

@ -1,67 +0,0 @@
import Cell from './cell.js';
import * as Movement from './movement/index.js';
import Piece, { PieceColor, PieceType } from './piece.js';
/**
* Represents the game board.
*/
class Board {
/**
* @param {number} width
* @param {number} height
*/
constructor(width, height) {
/** @type {number} */
this.width = width;
/** @type {number} */
this.height = height;
/** @type {Cell[][]} */
this.grid = Array.from({ length: height }, () => Array.from({ length: width }, () => new Cell()));
this.setupInitialPieces();
}
/**
* @param {number} x
* @param {number} y
* @param {Piece|null} piece
*/
setPiece(x, y, piece) {
this.grid[y][x].piece = piece;
}
setupInitialPieces() {
// Pawns
for (let x = 0; x < this.width; x++) {
this.setPiece(x, 1, new Piece(PieceColor.WHITE, PieceType.PAWN, [Movement.PawnMove], x, 1));
this.setPiece(x, 6, new Piece(PieceColor.BLACK, PieceType.PAWN, [Movement.PawnMove], x, 6));
}
// Rooks
this.setPiece(0, 0, new Piece(PieceColor.WHITE, PieceType.ROOK, [Movement.RookMove], 0, 0));
this.setPiece(7, 0, new Piece(PieceColor.WHITE, PieceType.ROOK, [Movement.RookMove], 7, 0));
this.setPiece(0, 7, new Piece(PieceColor.BLACK, PieceType.ROOK, [Movement.RookMove], 0, 7));
this.setPiece(7, 7, new Piece(PieceColor.BLACK, PieceType.ROOK, [Movement.RookMove], 7, 7));
// Knights
this.setPiece(1, 0, new Piece(PieceColor.WHITE, PieceType.KNIGHT, [Movement.KnightMove], 1, 0));
this.setPiece(6, 0, new Piece(PieceColor.WHITE, PieceType.KNIGHT, [Movement.KnightMove], 6, 0));
this.setPiece(1, 7, new Piece(PieceColor.BLACK, PieceType.KNIGHT, [Movement.KnightMove], 1, 7));
this.setPiece(6, 7, new Piece(PieceColor.BLACK, PieceType.KNIGHT, [Movement.KnightMove], 6, 7));
// Bishops
this.setPiece(2, 0, new Piece(PieceColor.WHITE, PieceType.BISHOP, [Movement.BishopMove], 2, 0));
this.setPiece(5, 0, new Piece(PieceColor.WHITE, PieceType.BISHOP, [Movement.BishopMove], 5, 0));
this.setPiece(2, 7, new Piece(PieceColor.BLACK, PieceType.BISHOP, [Movement.BishopMove], 2, 7));
this.setPiece(5, 7, new Piece(PieceColor.BLACK, PieceType.BISHOP, [Movement.BishopMove], 5, 7));
// Queens and Kings
this.setPiece(3, 0, new Piece(PieceColor.WHITE, PieceType.QUEEN, [Movement.QueenMove], 3, 0));
this.setPiece(4, 0, new Piece(PieceColor.WHITE, PieceType.KING, [Movement.KingMove], 4, 0));
this.setPiece(3, 7, new Piece(PieceColor.BLACK, PieceType.QUEEN, [Movement.QueenMove], 3, 7));
this.setPiece(4, 7, new Piece(PieceColor.BLACK, PieceType.KING, [Movement.KingMove], 4, 7));
}
}
export { Cell, Movement, Piece, PieceColor, PieceType };
export default Board;

View file

@ -1,14 +0,0 @@
import Effect from './effect.js';
class Card {
constructor() {
/** @type {string} */
this.name;
/** @type {string} */
this.description;
/** @type {Effect} */
this.effect;
}
}
export default Card;

View file

@ -1,11 +0,0 @@
class Cell {
/**
* @param {Piece|null} piece
*/
constructor(piece = null) {
/** @type {Piece|null} */
this.piece = piece;
}
}
export default Cell;

View file

@ -1,5 +0,0 @@
class Effect {
constructor() {}
}
export default Effect;

View file

@ -1,133 +0,0 @@
import Board, { Piece } from './board.js';
import Team from './team.js';
import Stack from './stack.js';
import PieceColor from './board.js';
import Piece from './board.js';
class GameState {
constructor() {
/** @type {Board} */
this.board = new Board(8, 8);
/** @type {Stack} */
this.stack = new Stack();
/** @type {Team} */
this.whiteTeam = new Team("white");
/** @type {Team} */
this.blackTeam = new Team("black");
/** @type {number} */
this.turn = 0;
/** @type {Piece|null} */
this.whiteSelectedPiece = null;
/** @type {Piece|null} */
this.blackSelectedPiece = null;
}
/**
* @returns {void}
*/
nextTurn() {
this.turn = 1 - this.turn;
}
/**
* @param {PieceColor} color
* @returns {boolean}
*/
hasHisKing(color) {
const team = color === PieceColor.WHITE ? this.whiteTeam : this.blackTeam;
return team.hasKing();
}
/**
* @param {PieceColor}
* @returns {Array<>}
*/
getMoves(team) {
if (team == WHITE && this.whiteSelectedPiece != null) {
if (this.whiteSelectedPiece.priorityMovements.length > 0) {
return this.whiteSelectedPiece.priorityMovements.flatmap((m) => m.moves());
} else {
return this.whiteSelectedPiece.movements.flatMap((m) => m.moves());
}
} else if (team == BLACK && this.blackSelectedPiece != null) {
if (this.blackSelectedPiece.priorityMovements.length > 0) {
return this.blackSelectedPiece.priorityMovements.flatmap((m) => m.moves());
} else {
return this.blackSelectedPiece.movements.flatMap((m) => m.moves());
}
} else {
return [];
}
}
/**
* @param {number}
* @param {number}
* @param {PieceColor}
* @returns {boolean}
*/
click(x, y, team) {
selectedPiece = this.board.grid[x][y];
// White team
if (team == WHITE) {
// one empty cell
if (this.whiteSelectedPiece == null) {
this.whiteSelectedPiece = this.board.grid[x][y].piece;
// previous one was black
} else if (this.whiteSelectedPiece.color == BLACK) {
this.whiteSelectedPiece = this.board.grid[x][y].piece;
// select a white piece
} else if (selectedPiece.color == WHITE) {
this.whiteSelectedPiece = this.board.grid[x][y].piece;
// possible move
} else {
// authorized move
if (this.getMoves(team).filter(({x_, y_, _}) => x == x_ && y == y_).length > 0) {
if (selectedPiece != null) {
this.whiteTeam.capture.push(selectedPiece);
}
this.board.grid[x][y] = this.whiteSelectedPiece;
this.board.grid[this.whiteSelectedPiece.x][this.whiteSelectedPiece.y] = null;
this.whiteSelectedPiece.x = x;
this.whiteSelectedPiece.y = y;
return true;
} else {
this.whiteSelectedPiece = this.board.grid[x][y].piece;
}
}
// black team
} else {
// one empty cell
if (this.blackSelectedPiece == null) {
this.blackSelectedPiece = this.board.grid[x][y].piece;
// previous one was white
} else if (this.blackSelectedPiece.color == WHITE) {
this.blackSelectedPiece = this.board.grid[x][y].piece;
// select a black piece
} else if (selectedPiece.color == BLACK) {
this.blackSelectedPiece = this.board.grid[x][y].piece;
// possible move
} else {
// authorized move
if (this.getMoves(team).filter(({x_, y_, _}) => x == x_ && y == y_).length > 0) {
if (selectedPiece != null) {
this.blackTeam.capture.push(selectedPiece);
}
this.board.grid[x][y] = this.blackSelectedPiece;
this.board.grid[this.blackSelectedPiece.x][this.blackSelectedPiece.y] = null;
this.blackSelectedPiece.x = x;
this.blackSelectedPiece.y = y;
return true;
} else {
this.blackSelectedPiece = this.board.grid[x][y].piece;
}
}
}
// no move done
return false;
}
}
export default GameState;

View file

@ -1,31 +0,0 @@
import Card from './card.js';
class Hand {
constructor() {
/** @type {Array(Card)} */
this.cards = [];
}
/**
* @param {Card} card
*/
pushCard(card) {
this.cards.push(card);
}
/**
* @param {number} index
* @returns {Card|null}
*/
popCard(index) {
if (index < 0 || index >= this.cards.length) {
return null;
} else {
let c = this.cards.at(index);
this.cards.splice(index, 1);
return c;
}
}
}
export default Hand;

View file

@ -1,59 +0,0 @@
// Utilities for movement generation
// The movement modules receive a context object with at least:
// - board: instance exposing getWidth(), getHeight(), getCell(x,y) and setPiece(x,y,piece)
// - from: { x, y }
// - piece: the moving piece (with getColor())
/**
* Walk in linear directions (array of dx,dy) until blocked.
* Returns an array of move objects: { x, y, capture: boolean }
*
* Options:
* - maxSteps (default: Infinity)
* - allowCapture=true
* - allowEmpty=true
*/
export function generateLinearMoves({
board,
from,
piece,
directions,
maxSteps = Infinity,
allowCapture = true,
allowEmpty = true,
allowRing = false
}) {
const moves = [];
const w = board.getWidth();
const h = board.getHeight();
const color = piece.getColor();
for (const [dx, dy] of directions) {
let steps = 0;
let x = from.x + dx;
let y = from.y + dy;
while (x >= 0 && x < w && y >= 0 && y < h && steps < maxSteps) {
const cell = board.getCell(x, y);
const target = cell?.piece ?? null;
if (target == null) {
if (allowEmpty) moves.push({ x, y, capture: false });
// continue along this direction
} else {
// occupied
if (target.getColor() !== color) {
if (allowCapture) moves.push({ x, y, capture: true });
}
// stop after encountering any piece
break;
}
steps++;
x += dx;
y += dy;
}
}
return moves;
}

View file

@ -1,13 +0,0 @@
// Central export for movement modules
import {RookMove, BishopMove, KnightMove, QueenMove, KingMove, PawnMove} from './moves.js';
import { generateLinearMoves } from './generateMoves.js';
export default {
RookMove,
BishopMove,
KnightMove,
QueenMove,
KingMove,
PawnMove,
generateLinearMoves,
};

View file

@ -1,178 +0,0 @@
import { generateLinearMoves } from './generateMoves.js';
// basic moves
class RookMove {
/**
* Return possible moves for a rook-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece, allowRing }
*/
static moves(ctx) {
const orthogonals = [
[1, 0],
[-1, 0],
[0, 1],
[0, -1],
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: orthogonals,
allowRing: ctx.allowRing
});
}
}
class BishopMove {
/**
* Return possible moves for a bishop-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const diagonals = [
[1, 1],
[1, -1],
[-1, 1],
[-1, -1],
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: diagonals,
allowRing: ctx.allowRing
});
}
}
class KnightMove {
/**
* Return possible moves for a knight-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const knightMoves = [
[2, 1], [2, -1], [-2, 1], [-2, -1],
[1, 2], [1, -2], [-1, 2], [-1, -2],
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: knightMoves,
maxSteps: 1,
allowEmpty: true,
allowCapture: true,
allowRing: ctx.allowRing
});
}
}
class QueenMove {
/**
* Return possible moves for a queen-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const directions = [
[1, 0], [-1, 0], [0, 1], [0, -1], // orthogonals
[1, 1], [1, -1], [-1, 1], [-1, -1], // diagonals
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: directions,
allowRing: ctx.allowRing
});
}
}
class KingMove {
/**
* Return possible moves for a king-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const directions = [
[1, 0], [-1, 0], [0, 1], [0, -1], // orthogonals
[1, 1], [1, -1], [-1, 1], [-1, -1], // diagonals
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: directions,
maxSteps: 1,
allowRing: ctx.allowRing
});
}
}
class PawnMove {
/**
* Return possible moves for a pawn-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const color = ctx.piece.getColor();
const forward = (color === 'white') ? -1 : 1; // assuming y=0 is top
const moves = [];
const w = ctx.board.getWidth();
const h = ctx.board.getHeight();
const x = ctx.from.x;
const y = ctx.from.y;
// Forward move
if (y + forward >= 0 && y + forward < h) {
const forwardCell = ctx.board.getCell(x, y + forward);
if (forwardCell?.piece == null) {
moves.push({ x: x, y: y + forward, capture: false });
// Double step from starting position
const startingRow = (color === 'white') ? h - 2 : 1;
if (!ctx.piece.hasMoved) {
const doubleForwardCell = ctx.board.getCell(x, y + 2 * forward);
if (doubleForwardCell?.piece == null) {
moves.push({ x: x, y: y + 2 * forward, capture: false });
}
}
}
}
// Captures
for (const dx of [-1, 1]) {
if (x + dx >= 0 && x + dx < w && y + forward >= 0 && y + forward < h) {
const diagCell = ctx.board.getCell(x + dx, y + forward);
const target = diagCell?.piece ?? null;
if (target != null && target.getColor() !== color) {
moves.push({ x: x + dx, y: y + forward, capture: true });
}
}
}
return moves;
}
}
export { RookMove, BishopMove, KnightMove, QueenMove, KingMove, PawnMove };

View file

@ -1,42 +0,0 @@
const PieceColor = {
WHITE: 'WHITE',
BLACK: 'BLACK'
};
const PieceType = {
PAWN: 'PAWN',
KNIGHT: 'KNIGHT',
BISHOP: 'BISHOP',
ROOK: 'ROOK',
QUEEN: 'QUEEN',
KING: 'KING'
};
class Piece {
/**
* @param {PieceColor} color
* @param {PieceType} type
* @param {Array<import('./movement/index.js').default>} movements
* @param {number} x
* @param {number} y
*/
constructor(color, type, movements, x, y) {
/** @type {PieceColor} */
this.color = color;
/** @type {PieceType} */
this.type = type;
/** @type {boolean} */
this.hasMoved = false;
/** @type {Array<import('./movement/index.js').default>} */
this.movements = movements;
/** @type {Array<import('./movement/index.js').default>} */
this.priorityMovements = [];
/** @type {number} */
this.x = x;
/** @type {number} */
this.y = y;
}
}
export default Piece;
export { PieceColor, PieceType };

View file

@ -1,50 +0,0 @@
import Card from './card.js';
class Stack {
constructor() {
/** @type {Array(Card)} */
this.stack;
/** @type {Array{Card}} */
this.discard;
}
/**
* @returns {Card|null}
*/
drawACard() {
if (this.stack.length > 0) {
return this.stack.pop();
} else {
if (this.discard.length == 0) {
return null;
}
while (this.discard.length > 0) {
let randomIndex = Math.floor(Math.random() * this.discard.length);
this.stack.push(this.discard.at(randomIndex));
this.stack.splice(randomIndex, 1);
}
return this.stack.pop();
}
}
/**
*
* @param {card} card
*/
discardACard(card) {
this.discard.push(card);
}
/**
* @description Shuffle the stack
*/
shuffle() {
let index = this.stack.length - 1;
while (index > 0) {
let randomIndex = Math.floor(Math.random() * index);
[this.stack[index], this.stack[randomIndex]] = [this.stack[randomIndex], this.stack[index]];
}
}
}
export default Stack;

View file

@ -1,30 +0,0 @@
import Piece, { PieceColor } from './piece.js';
import Hand from './hand.js';
class Team {
/**
* @param {PieceColor} color
* @param {Piece} king
*/
constructor(color, king) {
/** @type {PieceColor} */
this.color = color;
/** @type {Piece} */
this.king = king;
/** @type {Hand} */
this.hand = new Hand();
/** @type {boolean} */
this.hasMadeAction = false;
/** @type {Array<Piece>} */
this.capture = [];
}
/**
* @returns {boolean}
*/
hasKing() {
return this.king !== null;
}
}
export default Team;

View file

@ -1,8 +0,0 @@
Frontend demo: simple static lobby + board renderer
Contents:
- `public/index.html` : entry page
- `src/main.js` : minimal JS for lobby and board rendering
- `src/styles.css` : styles
How to run (dev): serve the `public` folder with a static server (e.g. `npx serve public` or `python3 -m http.server` from `frontend/public`)

@ -1 +0,0 @@
Subproject commit 978d74002e90598eb2f952460e37552a4ec2dace

View file

@ -1,131 +0,0 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>ChessNut 1 Partie</title>
<link rel="stylesheet" href="src/styles.css">
<style>
/* Minimal board CSS: keep responsive wrapper but delegate main layout to linked stylesheet */
.game-page{max-width:1000px;margin:12px auto;padding:8px}
#board-wrapper{width:100%;max-width:900px;margin:0 auto}
/* keep a wrapper that forces a square area; the actual .board/.cell layout lives in src/styles.css */
#board-wrapper .board{width:100%;aspect-ratio:1/1;box-sizing:border-box}
.cell .piece{width:100%;height:100%;object-fit:contain;display:block}
.cell.selected{outline:3px solid rgba(0,128,255,0.6);}
/* grid cells will be created dynamically via JS using grid-template */
/* checkerboard colors handled by .cell.light/.cell.dark in src/styles.css */
#meta{margin-top:8px}
</style>
</head>
<body>
<div class="game-page">
<header><h1>Partie</h1></header>
<div id="meta">Chargement...</div>
<div id="player-color" style="margin-top:6px;font-weight:600">Couleur: —</div>
<div id="players-panel" style="margin-top:8px;font-size:14px">
<strong>Joueurs:</strong>
<ul id="players-list" style="list-style:none;padding-left:0;margin-top:6px"></ul>
</div>
<div id="server-load-indicator" style="margin-top:6px;color:#666">Chargement de l'état du serveur...</div>
<div id="board-wrapper"><div id="board-container"></div></div>
<div style="margin-top:8px">
</div>
</div>
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<script src="src/game.js?v=4"></script>
<script>
// small bootstrap: fetch initial game state and wire socket updates
(function(){
const qs = new URLSearchParams(window.location.search);
const gid = qs.get('game');
const meta = document.getElementById('meta');
if(!gid){ meta.textContent = 'Game ID manquant'; return; }
meta.textContent = 'Affichage du plateau...';
// render an empty board immediately so user always sees a board even if backend is slow/unavailable
try { if(typeof renderBoardFromState === 'function') renderBoardFromState(null); } catch(e){ console.warn('initial empty board render failed', e); }
// fetch initial state: prefer explicit backend host then fallback to same-origin
(function(){
function handleGameObj(g){
// set globals expected by src/game.js so socket handlers attach correctly
try {
currentGameId = gid;
// prefer a session-scoped stored player id for this game (persisted at join/create)
try{
// support multiple possible sessionStorage key formats used across the app
const candidateKeys = [
'chessnut:game:' + gid + ':playerId', // older/other modules
'playerId:' + gid // newer lightweight key used elsewhere
];
let stored = null;
for (const k of candidateKeys) {
stored = sessionStorage.getItem(k);
if (stored) { myPlayerId = stored; break; }
}
// if still not found, fall back to first player from server and persist under both keys
if (!stored && g && g.players && g.players[0]) {
myPlayerId = g.players[0].id;
try{
sessionStorage.setItem('chessnut:game:' + gid + ':playerId', myPlayerId);
sessionStorage.setItem('playerId:' + gid, myPlayerId);
}catch(e){}
}
}catch(e){}
// remember the last received game object and compute this client's assigned color (if any)
window.lastGameObj = g;
if (g && g.players && myPlayerId) {
const me = g.players.find(p => p.id === myPlayerId);
window.myColor = me && me.colorAssigned ? me.colorAssigned : null;
const pc = document.getElementById('player-color'); if(pc) pc.textContent = 'Couleur: ' + (window.myColor || 'non assignée');
}
// render board from state or empty board (after computing myColor so render can honor orientation)
if(g && g.state && typeof renderBoardFromState === 'function') renderBoardFromState(g.state);
else if(typeof renderBoardFromState === 'function') renderBoardFromState(null);
const sli = document.getElementById('server-load-indicator'); if(sli) sli.style.display = 'none';
if(typeof socket === 'undefined' || !socket){
socket = io();
socket.on('connect', () => { socket.emit('join-game', gid); socket.emit('identify', { gameId: gid, playerId: myPlayerId }); });
socket.on('game-state', (s) => { if(typeof renderBoardFromState === 'function') renderBoardFromState(s); if(typeof setMeta === 'function') setMeta('game-state updated'); });
socket.on('move', (m) => { if(typeof setMeta === 'function') setMeta('remote move ' + JSON.stringify(m)); });
socket.on('player-update', (g) => {
// update local cached game object, render players list and recompute myColor when players list changes
try{
window.lastGameObj = g;
if (g) { try{ renderPlayersList(g); }catch(e){} }
if (g && g.players && myPlayerId) {
const me = g.players.find(p => p.id === myPlayerId);
window.myColor = me && me.colorAssigned ? me.colorAssigned : window.myColor;
const pc = document.getElementById('player-color'); if(pc) pc.textContent = 'Couleur: ' + (window.myColor || 'non assignée');
}
// re-render board to apply orientation change if colorAssigned arrived late
if (typeof renderBoardFromState === 'function' && g && g.state) renderBoardFromState(g.state);
}catch(e){}
if(typeof setMeta === 'function') setMeta('players updated');
});
}
// ensure players list is rendered on initial load
try{ if(window.lastGameObj) renderPlayersList(window.lastGameObj); }catch(e){}
} catch(e){ console.warn('socket init failed', e); }
}
fetch('http://localhost:4000/api/game/' + gid).then(r => r.ok ? r.json() : null).then(g => {
if(g) { handleGameObj(g); }
else {
// try same-origin
fetch('/api/game/' + gid).then(r => r.ok ? r.json() : null).then(handleGameObj).catch(()=>{ handleGameObj(null); const sli = document.getElementById('server-load-indicator'); if(sli) sli.textContent = 'Serveur injoignable'; });
}
}).catch(()=>{
fetch('/api/game/' + gid).then(r => r.ok ? r.json() : null).then(handleGameObj).catch(()=>{ handleGameObj(null); const sli = document.getElementById('server-load-indicator'); if(sli) sli.textContent = 'Serveur injoignable'; });
});
})();
const leaveBtn = document.getElementById('leave');
if (leaveBtn) {
leaveBtn.addEventListener('click', ()=>{ window.location.href = 'waiting.html?game=' + encodeURIComponent(gid); });
}
})();
</script>
</body>
</html>

View file

@ -1,50 +0,0 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>ChessNut — Lobby</title>
<link rel="stylesheet" href="src/styles.css">
</head>
<body>
<div id="app">
<header>
<h1>ChessNut — Lobby</h1>
</header>
<main>
<section id="lobby">
<div class="card">
<h2>Créer une partie</h2>
<label>Nom de la partie <input id="create-name" placeholder="Mon match"></label>
<label>Mot de passe (optionnel) <input id="create-pass" type="password" placeholder="motdepasse"></label>
<button id="create-btn">Créer</button>
</div>
<div class="card">
<h2>Rejoindre une partie</h2>
<button id="show-list-btn">Afficher les parties disponibles</button>
<div id="games-list" class="hidden">
<ul id="games-ul"></ul>
</div>
</div>
</section>
<section id="board-section" class="hidden">
<div class="card">
<h2>Partie <span id="game-id"></span></h2>
<div>Rôle: <span id="player-role"></span></div>
<div id="board-container" style="margin-top:12px;"></div>
<div style="margin-top:12px;">
<button id="flip-btn">Retourner</button>
<button id="back-to-lobby">Retour au lobby</button>
</div>
</div>
</section>
<!-- waiting room is a separate page: waiting.html -->
</main>
</div>
<script src="src/main.js?v=2"></script>
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
</body>
</html>

View file

@ -1,192 +0,0 @@
const q = s => document.querySelector(s);
// socket variable will be initialized on first load/join
let socket = null;
let myPlayerId = null;
let currentGameId = null;
let selected = null; // {x,y}
function renderBoardFromState(state, asWhite = null) {
const container = q('#board-container');
if(!container){ console.error('renderBoardFromState: #board-container not found'); return; }
console.log('renderBoardFromState called, state present?', !!state);
container.innerHTML = '';
const boardEl = document.createElement('div');
boardEl.className = 'board';
// if no state provided, create an empty 8x8 board
if(!state || !state.board){
const w = 8, h = 8;
const board = Array.from({ length: h }, () => Array.from({ length: w }, () => null));
state = { board, width: w, height: h };
}
const h = state.height || state.board.length;
const w = state.width || (state.board[0] && state.board[0].length) || 8;
// Use CSS grid so cells distribute evenly and keep the board square via wrapper's aspect-ratio
boardEl.style.display = 'grid';
boardEl.style.gridTemplateColumns = `repeat(${w}, 1fr)`;
boardEl.style.gridTemplateRows = `repeat(${h}, 1fr)`;
// Keep cells square regardless of board dimensions by setting an aspect-ratio on the board element.
// We want height / width ratio so each grid cell becomes square: aspect-ratio = h / w
boardEl.style.aspectRatio = `${w} / ${h}`; // CSS aspect-ratio uses width/height, but grid tracks make squares when width/height ratio is set accordingly
// Make the board responsive: max size will be limited by container width
boardEl.style.maxWidth = 'min(90vmin, 80vw)';
boardEl.style.width = '100%';
// determine orientation: explicit asWhite param > window.myColor > default true
try{
let useWhite = true;
if (asWhite === null) {
if (window && window.myColor) useWhite = (String(window.myColor).toLowerCase() === 'white');
} else {
useWhite = !!asWhite;
}
console.log('[renderBoardFromState] myPlayerId=', myPlayerId, 'window.myColor=', window && window.myColor, 'asWhite param=', asWhite, 'computed useWhite=', useWhite);
// set dataset for easier inspection in DevTools
try { boardEl.dataset.orientation = useWhite ? 'white' : 'black'; container.dataset.myPlayerId = myPlayerId || ''; } catch(e) {}
if (!useWhite) boardEl.classList.add('flipped');
}catch(e){}
// Render cells in visual order depending on orientation. We do not rotate the element; instead we map
// visual coordinates -> state coordinates so piece images remain upright.
const useWhite = (boardEl.dataset.orientation || 'white') === 'white' || (window && window.myColor && String(window.myColor).toLowerCase() === 'white');
for (let vr = 0; vr < h; vr++) {
for (let vc = 0; vc < w; vc++) {
// Map visual row/col to state row/col depending on orientation
// For white perspective we want white pieces at the bottom (state row 0 -> visual bottom),
// so state row = h-1 - vr. For black perspective, state row = vr.
const r = useWhite ? (h - 1 - vr) : vr;
// For white perspective, file order is left->right = state col 0..w-1; for black it's mirrored.
const c = useWhite ? vc : (w - 1 - vc);
const cell = document.createElement('div');
cell.className = 'cell';
// alternate light/dark based on visual coordinates so checkerboard looks proper
const isLight = ((vr + vc) % 2) === 0;
cell.classList.add(isLight ? 'light' : 'dark');
// store state coordinates so click handlers send correct moves
cell.dataset.x = c;
cell.dataset.y = r;
const piece = document.createElement('img');
piece.className = 'piece';
const cellObj = state.board[r] && state.board[r][c];
if (cellObj) {
const t = cellObj.type || 'PAWN';
const color = (cellObj.color || 'white').toLowerCase();
const lookup = {
PAWN: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wP' : 'bP'}.svg`,
ROOK: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wR' : 'bR'}.svg`,
KNIGHT: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wN' : 'bN'}.svg`,
BISHOP: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wB' : 'bB'}.svg`,
QUEEN: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wQ' : 'bQ'}.svg`,
KING: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wK' : 'bK'}.svg`,
};
piece.src = lookup[t] || lookup.PAWN;
} else {
piece.style.display = 'none';
}
cell.appendChild(piece);
boardEl.appendChild(cell);
// clicks on cells should do absolutely nothing (display-only mode)
cell.addEventListener('click', () => {
// intentionally empty - no selection, no move, no UI changes
});
}
}
container.appendChild(boardEl);
// (previously: overlay/drawing code removed per user request)
// ensure player color display is in sync
try{ const pc = document.getElementById('player-color'); if(pc && window && window.myColor) pc.textContent = 'Couleur: ' + window.myColor; }catch(e){}
console.log('renderBoardFromState: board appended (w=' + w + ', h=' + h + ')');
}
function setMeta(text) { q('#meta').textContent = text; }
function renderPlayersList(gameObj){
try{
const ul = document.getElementById('players-list'); if(!ul) return;
ul.innerHTML = '';
const players = (gameObj && gameObj.players) ? gameObj.players : [];
players.forEach(p => {
const li = document.createElement('li');
li.textContent = (p.nickname || p.id) + ' — ' + (p.colorAssigned || 'non assignée');
if(window && myPlayerId && p.id === myPlayerId) li.textContent += ' (vous)';
ul.appendChild(li);
});
}catch(e){}
}
q('#create-only')?.addEventListener('click', async () => {
const name = q('#game-name').value || 'game-from-ui';
const res = await fetch('/api/create', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ name, ownerNickname: 'ui-host' }) });
const j = await res.json();
setMeta('Created: ' + j.game.id);
q('#game-id-input').value = j.game.id;
// store owner player id in session so host remembers which player they are
try{ if (j.player && j.game && j.player.id) { sessionStorage.setItem('chessnut:game:' + j.game.id + ':playerId', j.player.id); sessionStorage.setItem('playerId:' + j.game.id, j.player.id); } }catch(e){}
});
q('#create-start')?.addEventListener('click', async () => {
const name = q('#game-name').value || 'game-from-ui';
// create
const createResp = await fetch('/api/create', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ name, ownerNickname: 'ui-host' }) });
const createJson = await createResp.json();
const id = createJson.game.id;
setMeta('Created: ' + id + ' — joining as second player...');
// join as second player
const joinResp = await fetch('/api/join', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id, nickname: 'ui-guest' }) });
const joinJson = await joinResp.json();
// if join returned a player object, use it as this client's player id (we're acting as the guest here)
if (joinJson && joinJson.player && joinJson.player.id) {
myPlayerId = joinJson.player.id;
try{ sessionStorage.setItem('chessnut:game:' + id + ':playerId', myPlayerId); sessionStorage.setItem('playerId:' + id, myPlayerId); }catch(e){}
}
setMeta('Joined — starting...');
const startResp = await fetch('/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id }) });
const startJson = await startResp.json();
setMeta('Started: ' + id);
if (startJson.game && startJson.game.state) renderBoardFromState(startJson.game.state);
// connect socket and join room as the guest player we created earlier
currentGameId = id;
// try to capture the second player id from server game.players
const players = startJson.game.players || [];
if (players[1]) myPlayerId = players[1].id; else if (players[0]) myPlayerId = players[0].id;
// persist player id in sessionStorage (per-tab) so reloads can identify this client without colliding across tabs
try{ if(myPlayerId && id) { sessionStorage.setItem('chessnut:game:' + id + ':playerId', myPlayerId); sessionStorage.setItem('playerId:' + id, myPlayerId); } }catch(e){}
if (!socket) {
socket = io();
socket.on('connect', () => { socket.emit('join-game', currentGameId); socket.emit('identify', { gameId: currentGameId, playerId: myPlayerId }); });
socket.on('game-state', (s) => { renderBoardFromState(s); setMeta('game-state updated'); });
socket.on('move', (m) => { setMeta('remote move ' + JSON.stringify(m)); });
socket.on('player-update', (g) => { setMeta('players updated'); });
socket.on('error', (e) => { console.warn('socket error', e); setMeta('Socket error: ' + (e && e.error)); });
}
});
q('#load')?.addEventListener('click', async () => {
const id = q('#game-id-input').value;
if(!id) return setMeta('Enter a game id');
const res = await fetch('/api/game/' + id).catch(e => null);
if(!res || !res.ok) return setMeta('Game not found or backend unreachable');
const j = await res.json();
setMeta('Loaded: ' + id + ' (started=' + !!j.started + ')');
if (j.state && j.state.board) renderBoardFromState(j.state);
// wire socket to listen to updates in this game
currentGameId = id;
// choose a player id if any exists (by default pick first)
if (j.players && j.players.length > 0) myPlayerId = j.players[0].id;
// prefer stored player id if present (sessionStorage is per-tab so two tabs won't collide)
try{ const stored = sessionStorage.getItem('chessnut:game:' + id + ':playerId') || sessionStorage.getItem('playerId:' + id); if(stored) myPlayerId = stored; else if(myPlayerId && id) { sessionStorage.setItem('chessnut:game:' + id + ':playerId', myPlayerId); sessionStorage.setItem('playerId:' + id, myPlayerId); } }catch(e){}
if (!socket) {
socket = io();
socket.on('connect', () => { socket.emit('join-game', currentGameId); socket.emit('identify', { gameId: currentGameId, playerId: myPlayerId }); });
socket.on('game-state', (s) => { renderBoardFromState(s); setMeta('game-state updated'); });
socket.on('move', (m) => { setMeta('remote move ' + JSON.stringify(m)); });
socket.on('player-update', (g) => { setMeta('players updated'); });
socket.on('error', (e) => { console.warn('socket error', e); setMeta('Socket error: ' + (e && e.error)); });
}
});

View file

@ -1,234 +0,0 @@
// Minimal frontend to create/join a game and render a static board using chess_maestro pieces
const q = s => document.querySelector(s);
function showLobby() {
q('#lobby').classList.remove('hidden');
q('#board-section')?.classList?.add('hidden');
}
function showBoard(gameId, role) {
q('#lobby').classList.add('hidden');
q('#board-section')?.classList?.remove('hidden');
q('#game-id').textContent = gameId;
q('#player-role').textContent = role;
// determine this client's assigned color (if any) so we can render board from that perspective
(function(){
const stored = sessionStorage.getItem(`playerId:${gameId}`) || sessionStorage.getItem('chessnut:game:' + gameId + ':playerId');
// prefer server-provided state to compute orientation when available
fetch(`/api/game/${gameId}`).then(r => { if(!r.ok) throw new Error('no api'); return r.json(); }).then(g => {
try{
let asWhite = true;
if (stored && g && g.players) {
const me = g.players.find(p => p.id === stored);
if (me && me.colorAssigned) asWhite = (String(me.colorAssigned).toLowerCase() === 'white');
} else if (role) {
// fall back to role passed by caller
asWhite = (role === 'white');
}
if (g && g.state && typeof renderBoardFromState === 'function') renderBoardFromState(g.state, asWhite);
else renderBoard(asWhite);
}catch(e){ renderBoard(role === 'white'); }
}).catch(() => {
// backend not reachable: fall back to role param
renderBoard(role === 'white');
});
})();
}
q('#create-btn').addEventListener('click', () => {
console.log('[frontend] create-btn clicked');
const id = 'game-' + Math.random().toString(36).slice(2,9);
const pass = q('#create-pass').value;
const name = q('#create-name').value || id;
const nick = 'player';
const colorChoice = 'random';
const game = { id, name, pass: pass || null, owner: 'you', created: Date.now(), players: [{ id: 'p-' + Math.random().toString(36).slice(2,6), nickname: nick, colorChoice, colorAssigned: null }], started: false };
// try backend first (explicit host). If it fails, save locally and redirect to waiting page.
// include a neutral ownerNickname so backend creates the owner player, but we do not surface any pseudo in the UI
fetch('http://localhost:4000/api/create', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({name, pass, ownerNickname: nick, ownerColorChoice: colorChoice}) })
.then(r => { console.log('[frontend] backend /api/create response', r.status); if(!r.ok) throw new Error('no api'); return r.json(); })
.then(resp => { console.log('[frontend] created (backend)', resp); /* backend now returns { ok: true, game, player } for the owner */
if(resp.player && resp.player.id){ sessionStorage.setItem(`playerId:${resp.game.id}`, resp.player.id); }
alert('Partie créée: ' + (resp.game.name || 'Partie')); window.location.href = `waiting.html?game=${resp.game.id}`; })
.catch((err) => {
console.warn('[frontend] backend create failed, saving locally and redirecting', err && err.message);
// save to localStorage so waiting page can pick it up
const all = JSON.parse(localStorage.getItem('games') || '[]');
all.push(game);
localStorage.setItem('games', JSON.stringify(all));
alert('Partie créée localement: ' + (game.name || 'Partie'));
window.location.href = `waiting.html?game=${game.id}`;
});
});
q('#show-list-btn').addEventListener('click', () => {
const list = q('#games-list');
list.classList.toggle('hidden');
renderGameList();
});
function saveGame(game){
const all = JSON.parse(localStorage.getItem('games') || '[]');
all.push(game);
localStorage.setItem('games', JSON.stringify(all));
}
function renderGameList(){
const ul = q('#games-ul');
ul.innerHTML = '';
console.log('[frontend] renderGameList called');
// prefer backend host in dev
fetch('http://localhost:4000/api/list')
.then(r => { if(!r.ok) throw new Error('no remote api'); return r.json(); })
.then(all => { if(!all || all.length === 0){ ul.innerHTML = '<li>Aucune partie disponible</li>'; return; } all.forEach(g => renderGameListItem(ul, g)); })
.catch(() => {
// try same-origin then localStorage
fetch('/api/list')
.then(r => { if(!r.ok) throw new Error('no local api'); return r.json(); })
.then(all => { if(!all || all.length === 0){ ul.innerHTML = '<li>Aucune partie disponible</li>'; return; } all.forEach(g => renderGameListItem(ul, g)); })
.catch(() => {
const all = JSON.parse(localStorage.getItem('games') || '[]');
if(all.length === 0){ ul.innerHTML = '<li>Aucune partie disponible</li>'; return; }
all.forEach(g => renderGameListItem(ul, g));
});
});
}
// Socket: listen for global games-list updates from backend to refresh lobby list live
if(typeof io !== 'undefined'){
try{
const sock = io('http://localhost:4000', { transports: ['websocket', 'polling'] });
sock.on('connect', () => { console.log('lobby socket connected', sock.id); });
sock.on('games-list', (list) => { console.log('games-list event received', list); try { renderGameList(); } catch(e){} });
sock.on('connect_error', (e) => { console.warn('lobby socket connect error', e); });
}catch(e){ console.warn('failed to init lobby socket', e); }
}
function renderGameListItem(ul, g){
const li = document.createElement('li');
// display only human-friendly name; avoid showing internal ids
li.textContent = g.name || 'Partie';
// detect if this client already joined this game (we store playerId in sessionStorage)
const storedPlayerId = sessionStorage.getItem(`playerId:${g.id}`);
// If we have a stored player id but the server-side game no longer contains that player,
// cleanup the sessionStorage entry (it means the player was removed / left).
let alreadyJoined = false;
if (storedPlayerId) {
const playerStillInGame = (g.players || []).some(p => p.id === storedPlayerId);
if (!playerStillInGame) {
// stale stored id: remove it
sessionStorage.removeItem(`playerId:${g.id}`);
} else {
alreadyJoined = true;
}
}
if(alreadyJoined){
const span = document.createElement('span');
span.textContent = ' — Vous êtes dans cette partie';
span.style.marginLeft = '8px';
li.appendChild(span);
} else {
const btn = document.createElement('button');
btn.textContent = 'Rejoindre';
btn.addEventListener('click', () => {
console.log('[frontend] join clicked for', g.id);
if(g.pass){ const entered = prompt('Mot de passe pour rejoindre la partie'); if(entered !== g.pass){ alert('Mot de passe incorrect'); return; } }
const payload = { id: g.id, pass: g.pass, nickname: 'player' };
// prefer backend host first
fetch('http://localhost:4000/api/join', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) })
.then(r => { if(!r.ok) throw new Error('join failed'); return r.json(); })
.then(resp => { if(resp && resp.player && resp.player.id){ sessionStorage.setItem(`playerId:${g.id}`, resp.player.id); } window.location.href = `waiting.html?game=${g.id}`; })
.catch(() => {
fetch('/api/join', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) })
.then(r => { if(!r.ok) throw new Error('join failed'); return r.json(); })
.then(() => { window.location.href = `waiting.html?game=${g.id}`; })
.catch(() => { saveGame(g); window.location.href = `waiting.html?game=${g.id}`; });
});
});
li.appendChild(btn);
}
ul.appendChild(li);
}
q('#leave-btn')?.addEventListener('click', () => showLobby());
q('#flip-btn')?.addEventListener('click', () => { const board = q('#board-container'); board.classList.toggle('flipped'); });
function renderBoard(asWhite=true) {
const container = q('#board-container');
if(!container) return;
container.innerHTML = '';
const board = document.createElement('div');
board.className = 'board';
// render without CSS rotation: draw ranks/files in visual order
for (let vr = 0; vr < 8; vr++) {
const row = document.createElement('div');
row.className = 'row';
for (let vc = 0; vc < 8; vc++) {
// For white perspective we want white at bottom -> state row = 7 - vr
const r = asWhite ? (7 - vr) : vr;
const c = asWhite ? vc : (7 - vc);
const cell = document.createElement('div');
cell.className = 'cell';
const piece = document.createElement('img');
piece.className = 'piece';
if (r === 1) piece.src = 'assets/chess-pieces/chess_maestro_bw/wP.svg';
else if (r === 6) piece.src = 'assets/chess-pieces/chess_maestro_bw/bP.svg';
else piece.style.display = 'none';
cell.appendChild(piece);
row.appendChild(cell);
}
board.appendChild(row);
}
container.appendChild(board);
}
// initial view
showLobby();
// waiting room helpers
let pollInterval = null;
function showWaiting(game){
q('#lobby').classList.add('hidden');
q('#board-section')?.classList?.add('hidden');
q('#lobby-waiting').classList.remove('hidden');
// show the game name instead of internal id
q('#wait-game-id').textContent = game.name || '';
renderWaitingPlayers(game.players || []);
}
function renderWaitingPlayers(players){
const ul = q('#wait-players'); ul.innerHTML = '';
if(!players || players.length === 0) ul.innerHTML = '<li>Aucun joueur</li>';
(players||[]).forEach(p => { const li = document.createElement('li'); li.textContent = `${p.nickname} (${p.colorAssigned || p.colorChoice})`; ul.appendChild(li); });
}
function startPolling(gameId){
if(pollInterval) clearInterval(pollInterval);
pollInterval = setInterval(() => {
fetch(`/api/game/${gameId}`).then(r => { if(!r.ok) throw new Error('no api'); return r.json(); }).then(g => {
renderWaitingPlayers(g.players || []);
if(g.started){ clearInterval(pollInterval); q('#lobby-waiting').classList.add('hidden'); showBoard(g.id, 'white'); }
}).catch(() => {
fetch(`http://localhost:4000/api/game/${gameId}`).then(r => r.json()).then(g => { renderWaitingPlayers(g.players || []); if(g.started){ clearInterval(pollInterval); q('#lobby-waiting').classList.add('hidden'); showBoard(g.id, 'white'); } }).catch(()=>{});
});
}, 1000);
}
q('#start-btn')?.addEventListener('click', () => {
const id = q('#wait-game-id').textContent;
fetch('/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id }) })
.then(r => { if(!r.ok) throw new Error('start failed'); return r.json(); })
.then(() => alert('Partie démarrée'))
.catch(() => { fetch('http://localhost:4000/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id }) }).then(()=>alert('Partie démarrée')).catch(()=>alert('Impossible de démarrer la partie')); });
});
q('#back-to-lobby')?.addEventListener('click', () => { if(pollInterval) clearInterval(pollInterval); q('#lobby-waiting').classList.add('hidden'); showLobby(); });

View file

@ -1,22 +0,0 @@
:root{
--cell-size: 60px;
}
body{font-family: Arial, Helvetica, sans-serif; margin:0; padding:0;}
.hidden{display:none}
header{background:#222;color:#fff;padding:10px}
main{padding:16px}
.card{border:1px solid #ddd;padding:12px;margin:8px;border-radius:6px}
/* The board will be a CSS grid with an aspect-ratio set by JS to keep cells square regardless of board dimensions. */
.board{display:grid; gap:0; margin:0 auto;}
.row{display:flex;gap:0 /* no gap between cells */}
.row .cell { width:var(--cell-size); height:var(--cell-size); }
/* Make sizing include borders so borders don't add extra space */
*, *::before, *::after { box-sizing: border-box; }
/* For grid-rendered boards (JS sets display:grid on .board), let cells stretch to the grid track size.
For row-based rendering, `.row .cell` provides fixed sizing. */
.board > .cell { width:100%; height:100%; display:flex; align-items:center; justify-content:center; background:#f0d9b5; border:1px solid #b58863; margin:0; }
.cell.light { background: #f0d9b5; }
.cell.dark { background: #b58863; }
.piece{width:70%;height:70%;object-fit:contain}
.game-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
.controls button{margin-left:8px}

View file

@ -1,170 +0,0 @@
const q = s => document.querySelector(s);
function qsParam(name){
const p = new URLSearchParams(window.location.search);
return p.get(name);
}
const gameId = qsParam('game');
console.log('[waiting.js] loaded - build: v2 -', { gameId, url: window.location.href });
if(!gameId){ document.body.innerHTML = '<p>Game ID missing in URL</p>'; }
else {
// Query explicit backend first to avoid interpreting same-origin static 404 as game-deleted
fetch(`http://localhost:4000/api/game/${gameId}`).then(r => {
if(r.status === 404){
// game deleted — eject user to lobby and clear session state
sessionStorage.removeItem(`playerId:${gameId}`);
alert('La partie a été supprimée par l\'hôte. Retour au lobby.');
window.location.href = 'index.html';
throw new Error('game deleted');
}
if(!r.ok) throw new Error('no api');
return r.json();
}).then(g => {
q('#wait-game-id').textContent = g.name || '';
renderWaitingPlayers(g.players||[]);
// if game already started, redirect immediately to the game page
if (g.started) { window.location.href = `game.html?game=${g.id}`; return; }
// display current player nick and color if we have a playerId
const stored = sessionStorage.getItem(`playerId:${gameId}`);
if(stored){
const me = (g.players||[]).find(p=>p.id===stored);
if(me){ q('#player-nick').textContent = 'Vous'; q('#player-color').textContent = me.colorChoice || '-'; }
}
// owner-only start button
const ownerId = g.players && g.players[0] && g.players[0].id;
if(ownerId && stored && ownerId === stored){ q('#start-btn')?.classList.remove('hidden'); } else { q('#start-btn')?.classList.add('hidden'); }
// disable start button unless there are at least 2 players
const startBtn = q('#start-btn');
if(startBtn){ if((g.players||[]).length < 2){ startBtn.disabled = true; } else { startBtn.disabled = false; } }
if(!g.started) startPolling(gameId);
// try to connect socket.io for instant updates and identification
tryConnectSocket(gameId);
}).catch(()=>{
// fallback: attempt same-origin server, then localStorage
fetch(`/api/game/${gameId}`).then(r=>{
if(r.status === 404){ sessionStorage.removeItem(`playerId:${gameId}`); alert('La partie a été supprimée par l\'hôte. Retour au lobby.'); window.location.href = 'index.html'; throw new Error('game deleted'); }
if(!r.ok) throw new Error('no api');
return r.json();
}).then(g=>{
q('#wait-game-id').textContent = g.name || '';
renderWaitingPlayers(g.players||[]);
// if game already started, redirect immediately to the game page
if (g.started) { window.location.href = `game.html?game=${g.id}`; return; }
const stored = sessionStorage.getItem(`playerId:${gameId}`);
if(stored){ const me = (g.players||[]).find(p=>p.id===stored); if(me){ q('#player-nick').textContent = 'Vous'; q('#player-color').textContent = me.colorChoice || '-'; } }
const ownerId = g.players && g.players[0] && g.players[0].id;
if(ownerId && stored && ownerId === stored){ q('#start-btn')?.classList.remove('hidden'); } else { q('#start-btn')?.classList.add('hidden'); }
// disable start button unless there are at least 2 players
const startBtn = q('#start-btn');
if(startBtn){ if((g.players||[]).length < 2){ startBtn.disabled = true; } else { startBtn.disabled = false; } }
if(!g.started) startPolling(gameId);
tryConnectSocket(gameId);
}).catch(()=>{
const all = JSON.parse(localStorage.getItem('games') || '[]');
const g = all.find(x=>x.id === gameId);
if(g){ q('#wait-game-id').textContent = g.name || ''; renderWaitingPlayers(g.players || []); } else { startPolling(gameId); }
});
});
}
// Socket.IO wiring: connect to backend explicitly and join game room; send identify so server can map socket->player
function tryConnectSocket(gameId){
if(typeof io === 'undefined') return; // socket lib not loaded
// connect explicitly to backend to avoid same-origin static server 404
const sock = io('http://localhost:4000', { transports: ['websocket', 'polling'] });
sock.on('connect', () => {
console.log('socket connected from waiting page', sock.id);
sock.emit('join-game', gameId);
const stored = sessionStorage.getItem(`playerId:${gameId}`) || (()=>{ const all = JSON.parse(localStorage.getItem('games') || '[]'); const g = all.find(x=>x.id===gameId); return g && g.players && g.players[0] && g.players[0].id; })();
if(stored) sock.emit('identify', { gameId, playerId: stored });
});
sock.on('reconnect', (attempt) => { console.log('waiting socket reconnected', attempt); });
sock.on('game-deleted', (payload) => {
if(payload && payload.gameId === gameId){
sessionStorage.removeItem(`playerId:${gameId}`);
alert('La partie a été supprimée par l\'hôte. Retour au lobby.');
window.location.href = 'index.html';
}
});
sock.on('player-update', (g) => {
if(!g) return;
console.log('[waiting.js] player-update received', g);
renderWaitingPlayers(g.players||[]);
// update start button visibility/disabled state live
try { console.log('[waiting.js] updating start button'); updateStartButton(g); } catch(e){ console.error('updateStartButton error', e); }
});
sock.on('game-start', (g) => {
if(!g) return;
// redirect to game view when started
window.location.href = `game.html?game=${g.id}`;
});
sock.on('connect_error', (err) => {
console.warn('socket connect error', err);
// leave polling as fallback
});
}
function updateStartButton(g){
const stored = sessionStorage.getItem(`playerId:${gameId}`);
const ownerId = g.players && g.players[0] && g.players[0].id;
const startBtn = q('#start-btn');
console.log('[waiting.js] updateStartButton values', { ownerId, stored, playersLength: (g.players||[]).length, startBtnExists: !!startBtn });
if(ownerId && stored && ownerId === stored){ startBtn?.classList.remove('hidden'); } else { startBtn?.classList.add('hidden'); }
if(startBtn){ startBtn.disabled = ((g.players||[]).length < 2); }
}
function renderWaitingPlayers(players){
const ul = q('#wait-players'); ul.innerHTML = '';
if(!players || players.length === 0) ul.innerHTML = '<li>Aucun joueur</li>';
(players||[]).forEach((p, i) => { const li = document.createElement('li'); li.textContent = `Joueur ${i+1} (${p.colorAssigned || p.colorChoice})`; ul.appendChild(li); });
}
let poll = null;
function startPolling(id){
if(poll) clearInterval(poll);
poll = setInterval(()=>{
// Prefer explicit backend host to avoid same-origin 404 from static server
fetch(`http://localhost:4000/api/game/${id}`).then(r=>{ if(!r.ok) throw new Error('no api'); return r.json(); }).then(g=>{ renderWaitingPlayers(g.players||[]); if(g.started){ clearInterval(poll); window.location.href = `game.html?game=${g.id}`; } }).catch(()=>{
// fallback to same-origin if backend not reachable
fetch(`/api/game/${id}`).then(r=>{ if(!r.ok) throw new Error('no api'); return r.json(); }).then(g=>{ renderWaitingPlayers(g.players||[]); if(g.started){ clearInterval(poll); window.location.href = `game.html?game=${g.id}`; } }).catch(()=>{});
});
}, 1000);
}
// Join handled from lobby; waiting room doesn't provide a join button
q('#start-btn')?.addEventListener('click', () => {
// force explicit backend host (no fallback) so request always goes to :4000
console.log('[waiting] start click - POST to http://localhost:4000/api/start', { gameId });
fetch('http://localhost:4000/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id: gameId }) })
.then(async (r) => {
const body = await r.json().catch(()=>({}));
if(!r.ok) throw body;
return body;
})
.then((resp)=>{ try { window.location.href = `game.html?game=${resp.game.id}`; } catch(e) { alert('Partie démarrée'); } })
.catch((err)=>{ const msg = (err && err.error) ? err.error : (typeof err === 'string' ? err : JSON.stringify(err)); alert('Impossible de démarrer: ' + msg); console.error('start error', err); });
});
q('#leave-btn')?.addEventListener('click', () => {
const stored = sessionStorage.getItem(`playerId:${gameId}`) || null;
const playerId = stored || (() => { const all = JSON.parse(localStorage.getItem('games') || '[]'); const g = all.find(x=>x.id===gameId); return g && g.players && g.players[0] && g.players[0].id; })();
if(!playerId){ alert('Impossible de déterminer votre identifiant de joueur pour quitter'); return; }
// prefer explicit backend host to avoid same-origin static server 404s
fetch(`http://localhost:4000/api/leave`, { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ gameId, playerId }) })
.then(r=>{ if(!r.ok) throw new Error('leave failed'); return r.json(); }).then(resp=>{
if(resp.deleted){ alert('Vous étiez l\'hôte — la partie a été supprimée'); window.location.href = 'index.html'; }
else { alert('Vous avez quitté la partie'); window.location.href = 'index.html'; }
}).catch(()=>{
// fallback to same-origin in case backend is proxied
fetch('/api/leave', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ gameId, playerId }) })
.then(r=>{ if(!r.ok) throw new Error('leave failed'); return r.json(); }).then(resp=>{
if(resp.deleted){ alert('Vous étiez l\'hôte — la partie a été supprimée'); window.location.href = 'index.html'; }
else { alert('Vous avez quitté la partie'); window.location.href = 'index.html'; }
}).catch(err=>{
console.error('leave failed', err);
alert('Impossible de quitter la partie — le serveur est injoignable. Si le problème persiste, vérifiez que le backend tourne sur :4000.');
});
});
});

View file

@ -1,33 +0,0 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>ChessNut — Salle d'attente</title>
<link rel="stylesheet" href="src/styles.css">
<style>
.waiting-page{max-width:900px;margin:20px auto}
</style>
</head>
<body>
<div class="waiting-page">
<header><h1>Salle d'attente</h1></header>
<div class="card">
<div>Partie: <span id="wait-game-id"></span></div>
<div>Joueurs:</div>
<ul id="wait-players"></ul>
<div>
<div>Votre pseudo: <strong id="player-nick">-</strong></div>
<div>Couleur choisie: <strong id="player-color">-</strong></div>
</div>
<div>
<button id="start-btn">Commencer la partie</button>
<button id="leave-btn">Quitter</button>
</div>
</div>
</div>
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<script src="src/waiting.js?v=3"></script>
</body>
</html>

View file

@ -1,136 +0,0 @@
const q = s => document.querySelector(s);
// socket variable will be initialized on first load/join
let socket = null;
let myPlayerId = null;
let currentGameId = null;
let selected = null; // {x,y}
function renderBoardFromState(state) {
const container = q('#board-container');
if(!container){ console.error('renderBoardFromState: #board-container not found'); return; }
console.log('renderBoardFromState called, state present?', !!state);
// clear previous board and overlays
container.innerHTML = '';
removeExistingOverlay(container);
const boardEl = document.createElement('div');
boardEl.className = 'board';
// if no state provided, create an empty 8x8 board
if(!state || !state.board){
const w = 8, h = 8;
const board = Array.from({ length: h }, () => Array.from({ length: w }, () => null));
state = { board, width: w, height: h };
}
const h = state.height || state.board.length;
const w = state.width || (state.board[0] && state.board[0].length) || 8;
// Use CSS grid so cells distribute evenly and keep the board square via wrapper's aspect-ratio
boardEl.style.display = 'grid';
boardEl.style.gridTemplateColumns = `repeat(${w}, 1fr)`;
boardEl.style.gridTemplateRows = `repeat(${h}, 1fr)`;
for (let r = 0; r < h; r++) {
for (let c = 0; c < w; c++) {
const cell = document.createElement('div');
cell.className = 'cell';
// alternate light/dark based on coordinates (classic checkerboard)
const isLight = ((r + c) % 2) === 1;
cell.classList.add(isLight ? 'light' : 'dark');
cell.dataset.x = c;
cell.dataset.y = r;
const piece = document.createElement('img');
piece.className = 'piece';
const cellObj = state.board[r] && state.board[r][c];
if (cellObj) {
const t = cellObj.type || 'PAWN';
const color = (cellObj.color || 'white').toLowerCase();
const lookup = {
PAWN: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wP' : 'bP'}.svg`,
ROOK: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wR' : 'bR'}.svg`,
KNIGHT: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wN' : 'bN'}.svg`,
BISHOP: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wB' : 'bB'}.svg`,
QUEEN: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wQ' : 'bQ'}.svg`,
KING: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wK' : 'bK'}.svg`,
};
piece.src = lookup[t] || lookup.PAWN;
} else {
piece.style.display = 'none';
}
cell.appendChild(piece);
boardEl.appendChild(cell);
// clicks on cells should do absolutely nothing (display-only mode)
cell.addEventListener('click', () => {
// intentionally empty — do not select, do not emit moves, do not change UI
});
}
}
container.appendChild(boardEl);
// (previously: overlay/drawing code removed per user request)
console.log('renderBoardFromState: board appended (w=' + w + ', h=' + h + ')');
}
function setMeta(text) { q('#meta').textContent = text; }
q('#create-only')?.addEventListener('click', async () => {
const name = q('#game-name').value || 'game-from-ui';
const res = await fetch('/api/create', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ name, ownerNickname: 'ui-host' }) });
const j = await res.json();
setMeta('Created: ' + j.game.id);
q('#game-id-input').value = j.game.id;
});
q('#create-start')?.addEventListener('click', async () => {
const name = q('#game-name').value || 'game-from-ui';
// create
const createResp = await fetch('/api/create', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ name, ownerNickname: 'ui-host' }) });
const createJson = await createResp.json();
const id = createJson.game.id;
setMeta('Created: ' + id + ' — joining as second player...');
// join as second player
await fetch('/api/join', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id, nickname: 'ui-guest' }) });
setMeta('Joined — starting...');
const startResp = await fetch('/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id }) });
const startJson = await startResp.json();
setMeta('Started: ' + id);
if (startJson.game && startJson.game.state) renderBoardFromState(startJson.game.state);
// connect socket and join room as the guest player we created earlier
currentGameId = id;
// try to capture the second player id from server game.players
const players = startJson.game.players || [];
if (players[1]) myPlayerId = players[1].id; else if (players[0]) myPlayerId = players[0].id;
if (!socket) {
socket = io();
socket.on('connect', () => { socket.emit('join-game', currentGameId); socket.emit('identify', { gameId: currentGameId, playerId: myPlayerId }); });
socket.on('game-state', (s) => { renderBoardFromState(s); setMeta('game-state updated'); });
socket.on('move', (m) => { setMeta('remote move ' + JSON.stringify(m)); });
socket.on('player-update', (g) => { setMeta('players updated'); });
socket.on('error', (e) => { console.warn('socket error', e); setMeta('Socket error: ' + (e && e.error)); });
}
});
q('#load')?.addEventListener('click', async () => {
const id = q('#game-id-input').value;
if(!id) return setMeta('Enter a game id');
const res = await fetch('/api/game/' + id).catch(e => null);
if(!res || !res.ok) return setMeta('Game not found or backend unreachable');
const j = await res.json();
setMeta('Loaded: ' + id + ' (started=' + !!j.started + ')');
if (j.state && j.state.board) renderBoardFromState(j.state);
// wire socket to listen to updates in this game
currentGameId = id;
// choose a player id if any exists (by default pick first)
if (j.players && j.players.length > 0) myPlayerId = j.players[0].id;
if (!socket) {
socket = io();
socket.on('connect', () => { socket.emit('join-game', currentGameId); socket.emit('identify', { gameId: currentGameId, playerId: myPlayerId }); });
socket.on('game-state', (s) => { renderBoardFromState(s); setMeta('game-state updated'); });
socket.on('move', (m) => { setMeta('remote move ' + JSON.stringify(m)); });
socket.on('player-update', (g) => { setMeta('players updated'); });
socket.on('error', (e) => { console.warn('socket error', e); setMeta('Socket error: ' + (e && e.error)); });
}
});

View file

@ -1,242 +0,0 @@
// Minimal frontend to create/join a game and render a static board using chess_maestro pieces
const q = s => document.querySelector(s);
function showLobby() {
q('#lobby').classList.remove('hidden');
q('#board-section')?.classList?.add('hidden');
}
function showBoard(gameId, role) {
q('#lobby').classList.add('hidden');
q('#board-section')?.classList?.remove('hidden');
q('#game-id').textContent = gameId;
q('#player-role').textContent = role;
// Try to fetch the server-provided game.state. If present, render from state.board.
fetch(`/api/game/${gameId}`).then(r => { if(!r.ok) throw new Error('no api'); return r.json(); }).then(g => {
if (g && g.state && g.state.board) {
renderBoardFromState(g.state, role === 'white');
} else {
renderBoard(role === 'white');
}
}).catch(() => {
// fallback to static local render
renderBoard(role === 'white');
});
}
q('#create-btn').addEventListener('click', () => {
console.log('[frontend] create-btn clicked');
const id = 'game-' + Math.random().toString(36).slice(2,9);
const pass = q('#create-pass').value;
const name = q('#create-name').value || id;
// minimal create: no prompts, use default host nickname
const nick = 'Host';
const colorChoice = 'random';
const game = { id, name, pass: pass || null, owner: 'you', created: Date.now(), players: [{ id: 'p-' + Math.random().toString(36).slice(2,6), nickname: nick, colorChoice, colorAssigned: null }], started: false };
// try backend first (explicit host). If it fails, save locally and redirect to waiting page.
fetch('http://localhost:4000/api/create', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({name, pass, ownerNickname: nick, ownerColorChoice: colorChoice}) })
.then(r => { console.log('[frontend] backend /api/create response', r.status); if(!r.ok) throw new Error('no api'); return r.json(); })
.then(g => { console.log('[frontend] created (backend)', g); alert('Partie créée: ' + g.id); window.location.href = `waiting.html?game=${g.id}`; })
.catch((err) => {
console.warn('[frontend] backend create failed, saving locally and redirecting', err && err.message);
// save to localStorage so waiting page can pick it up
const all = JSON.parse(localStorage.getItem('games') || '[]');
all.push(game);
localStorage.setItem('games', JSON.stringify(all));
alert('Partie créée localement: ' + game.id);
window.location.href = `waiting.html?game=${game.id}`;
});
});
q('#show-list-btn').addEventListener('click', () => {
const list = q('#games-list');
list.classList.toggle('hidden');
renderGameList();
});
function saveGame(game){
const all = JSON.parse(localStorage.getItem('games') || '[]');
all.push(game);
localStorage.setItem('games', JSON.stringify(all));
}
function renderGameList(){
const ul = q('#games-ul');
ul.innerHTML = '';
console.log('[frontend] renderGameList called');
// prefer backend host in dev
fetch('http://localhost:4000/api/list')
.then(r => { if(!r.ok) throw new Error('no remote api'); return r.json(); })
.then(all => { if(!all || all.length === 0){ ul.innerHTML = '<li>Aucune partie disponible</li>'; return; } all.forEach(g => renderGameListItem(ul, g)); })
.catch(() => {
// try same-origin then localStorage
fetch('/api/list')
.then(r => { if(!r.ok) throw new Error('no local api'); return r.json(); })
.then(all => { if(!all || all.length === 0){ ul.innerHTML = '<li>Aucune partie disponible</li>'; return; } all.forEach(g => renderGameListItem(ul, g)); })
.catch(() => {
const all = JSON.parse(localStorage.getItem('games') || '[]');
if(all.length === 0){ ul.innerHTML = '<li>Aucune partie disponible</li>'; return; }
all.forEach(g => renderGameListItem(ul, g));
});
});
}
function renderGameListItem(ul, g){
const li = document.createElement('li');
li.textContent = `${g.name} (${g.id})`;
const btn = document.createElement('button');
btn.textContent = 'Rejoindre';
btn.addEventListener('click', () => {
console.log('[frontend] join clicked for', g.id);
if(g.pass){ const entered = prompt('Mot de passe pour rejoindre la partie'); if(entered !== g.pass){ alert('Mot de passe incorrect'); return; } }
const nick = prompt('Ton pseudo') || 'Player';
const payload = { id: g.id, pass: g.pass, nickname: nick };
// prefer backend host first
fetch('http://localhost:4000/api/join', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) })
.then(r => { if(!r.ok) throw new Error('join failed'); return r.json(); })
.then(() => { window.location.href = `waiting.html?game=${g.id}`; })
.catch(() => {
fetch('/api/join', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) })
.then(r => { if(!r.ok) throw new Error('join failed'); return r.json(); })
.then(() => { window.location.href = `waiting.html?game=${g.id}`; })
.catch(() => { saveGame(g); window.location.href = `waiting.html?game=${g.id}`; });
});
});
li.appendChild(btn);
ul.appendChild(li);
}
q('#leave-btn')?.addEventListener('click', () => showLobby());
q('#flip-btn')?.addEventListener('click', () => { const board = q('#board-container'); board.classList.toggle('flipped'); });
function renderBoard(asWhite=true) {
// legacy static render (used as fallback)
const container = q('#board-container');
if(!container) return;
container.innerHTML = '';
const board = document.createElement('div');
board.className = 'board';
if (!asWhite) board.classList.add('flipped');
for (let r = 0; r < 8; r++) {
const row = document.createElement('div');
row.className = 'row';
for (let c = 0; c < 8; c++) {
const cell = document.createElement('div');
cell.className = 'cell';
const piece = document.createElement('img');
piece.className = 'piece';
if (r === 1) piece.src = 'assets/chess-pieces/chess_maestro_bw/wP.svg';
else if (r === 6) piece.src = 'assets/chess-pieces/chess_maestro_bw/bP.svg';
else piece.style.display = 'none';
cell.appendChild(piece);
row.appendChild(cell);
}
board.appendChild(row);
}
container.appendChild(board);
}
function renderBoardFromState(state, asWhite = true) {
const container = q('#board-container');
if(!container) return;
container.innerHTML = '';
const boardEl = document.createElement('div');
boardEl.className = 'board';
if (!asWhite) boardEl.classList.add('flipped');
const h = state.height || state.board.length;
const w = state.width || (state.board[0] && state.board[0].length) || 8;
for (let r = 0; r < h; r++) {
const row = document.createElement('div');
row.className = 'row';
for (let c = 0; c < w; c++) {
const cell = document.createElement('div');
cell.className = 'cell';
const piece = document.createElement('img');
piece.className = 'piece';
const cellObj = state.board[r] && state.board[r][c];
if (cellObj) {
// map type/color to an asset - minimal mapping for common pieces
const t = cellObj.type || 'PAWN';
const color = (cellObj.color || 'white').toLowerCase();
const lookup = {
PAWN: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wP' : 'bP'}.svg`,
ROOK: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wR' : 'bR'}.svg`,
KNIGHT: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wN' : 'bN'}.svg`,
BISHOP: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wB' : 'bB'}.svg`,
QUEEN: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wQ' : 'bQ'}.svg`,
KING: `assets/chess-pieces/chess_maestro_bw/${color[0] === 'w' ? 'wK' : 'bK'}.svg`,
};
piece.src = lookup[t] || lookup.PAWN;
} else {
piece.style.display = 'none';
}
cell.appendChild(piece);
row.appendChild(cell);
}
boardEl.appendChild(row);
}
container.appendChild(boardEl);
}
// initial view
// initial view
// If URL contains ?game=..., directly open the board view
const params = new URLSearchParams(window.location.search);
const initialGame = params.get('game');
if (initialGame) {
// assign a default role (will be refreshed when fetching game state)
showBoard(initialGame, 'white');
} else {
showLobby();
}
// waiting room helpers
let pollInterval = null;
function showWaiting(game){
q('#lobby').classList.add('hidden');
q('#board-section')?.classList?.add('hidden');
q('#lobby-waiting').classList.remove('hidden');
q('#wait-game-id').textContent = game.id || '';
renderWaitingPlayers(game.players || []);
}
function renderWaitingPlayers(players){
const ul = q('#wait-players'); ul.innerHTML = '';
if(!players || players.length === 0) ul.innerHTML = '<li>Aucun joueur</li>';
(players||[]).forEach(p => { const li = document.createElement('li'); li.textContent = `${p.nickname} (${p.colorAssigned || p.colorChoice})`; ul.appendChild(li); });
}
function startPolling(gameId){
if(pollInterval) clearInterval(pollInterval);
pollInterval = setInterval(() => {
fetch(`/api/game/${gameId}`).then(r => { if(!r.ok) throw new Error('no api'); return r.json(); }).then(g => {
renderWaitingPlayers(g.players || []);
if(g.started){ clearInterval(pollInterval); q('#lobby-waiting').classList.add('hidden'); showBoard(g.id, 'white'); }
}).catch(() => {
fetch(`http://localhost:4000/api/game/${gameId}`).then(r => r.json()).then(g => { renderWaitingPlayers(g.players || []); if(g.started){ clearInterval(pollInterval); q('#lobby-waiting').classList.add('hidden'); showBoard(g.id, 'white'); } }).catch(()=>{});
});
}, 1000);
}
q('#start-btn')?.addEventListener('click', () => {
const id = q('#wait-game-id').textContent;
fetch('/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id }) })
.then(r => { if(!r.ok) throw new Error('start failed'); return r.json(); })
.then(() => alert('Partie démarrée'))
.catch(() => { fetch('http://localhost:4000/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id }) }).then(()=>alert('Partie démarrée')).catch(()=>alert('Impossible de démarrer la partie')); });
});
q('#back-to-lobby')?.addEventListener('click', () => { if(pollInterval) clearInterval(pollInterval); q('#lobby-waiting').classList.add('hidden'); showLobby(); });

View file

@ -1,30 +0,0 @@
:root{
--cell-size: 60px;
}
body{font-family: Arial, Helvetica, sans-serif; margin:0; padding:0;}
.hidden{display:none}
header{background:#222;color:#fff;padding:10px}
main{padding:16px}
.card{border:1px solid #ddd;padding:12px;margin:8px;border-radius:6px}
.board{display:flex;flex-direction:column;gap:0 /* no gap between rows */; /* remove outer border so cell borders touch */ width:calc(var(--cell-size)*8);}
.row{display:flex;gap:0 /* no gap between cells */}
.row .cell { width:var(--cell-size); height:var(--cell-size); }
/* Make sizing include borders so borders don't add extra space */
*, *::before, *::after { box-sizing: border-box; }
/* For grid-rendered boards (JS sets display:grid on .board), let cells stretch to the grid track size.
For row-based rendering, `.row .cell` provides fixed sizing. */
.board > .cell { width:100%; height:100%; display:flex; align-items:center; justify-content:center; background:#f0d9b5; border:1px solid #b58863; margin:0; }
.cell.light { background: #f0d9b5; }
.cell.dark { background: #b58863; }
.piece{width:48px;height:48px}
.game-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
.controls button{margin-left:8px}
/* Ensure selected cells have no visual effect (display-only mode) */
.cell.selected{outline: none !important; box-shadow: none !important; border-color: inherit !important; background: inherit !important}
/* Overlay for drawings (arrows/circles) */
.board-overlay-wrapper{position:relative;width:100%;height:100%;}
.board-overlay{position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:auto;z-index:30}
.overlay-controls button{background:rgba(255,255,255,0.9);border:1px solid #ccc;padding:6px 8px;border-radius:4px;cursor:pointer}
.overlay-controls button:hover{filter:brightness(0.95)}

View file

@ -1,56 +0,0 @@
const q = s => document.querySelector(s);
function qsParam(name){
const p = new URLSearchParams(window.location.search);
return p.get(name);
}
const gameId = qsParam('game');
if(!gameId){ document.body.innerHTML = '<p>Game ID missing in URL</p>'; }
else {
q('#wait-game-id').textContent = gameId;
// try backend first, if fails read from localStorage (fallback created locally)
fetch(`/api/game/${gameId}`).then(r => { if(!r.ok) throw new Error('no api'); return r.json(); }).then(g => {
renderWaitingPlayers(g.players||[]);
if(!g.started) startPolling(gameId);
}).catch(()=>{
// fallback: look in localStorage
const all = JSON.parse(localStorage.getItem('games') || '[]');
const g = all.find(x=>x.id === gameId);
if(g){ renderWaitingPlayers(g.players || []); } else { startPolling(gameId); }
});
}
function renderWaitingPlayers(players){
const ul = q('#wait-players'); ul.innerHTML = '';
if(!players || players.length === 0) ul.innerHTML = '<li>Aucun joueur</li>';
(players||[]).forEach(p => { const li = document.createElement('li'); li.textContent = `${p.nickname} (${p.colorAssigned || p.colorChoice})`; ul.appendChild(li); });
}
let poll = null;
function startPolling(id){
if(poll) clearInterval(poll);
poll = setInterval(()=>{
fetch(`/api/game/${id}`).then(r=>{ if(!r.ok) throw new Error('no api'); return r.json(); }).then(g=>{ renderWaitingPlayers(g.players||[]); if(g.started){ clearInterval(poll); window.location.href = `game.html?game=${g.id}`; } }).catch(()=>{
fetch(`http://localhost:4000/api/game/${id}`).then(r=>r.json()).then(g=>{ renderWaitingPlayers(g.players||[]); if(g.started){ clearInterval(poll); window.location.href = `game.html?game=${g.id}`; } }).catch(()=>{});
});
}, 1000);
}
q('#join-btn')?.addEventListener('click', () => {
const nick = q('#nick-input').value || 'Guest';
const colorChoice = q('#color-choice').value || 'random';
fetch('/api/join', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id: gameId, nickname: nick, colorChoice }) })
.then(r=>{ if(!r.ok) throw new Error('join failed'); return r.json(); }).then(resp=>{ renderWaitingPlayers(resp.game.players || []); }).catch(()=>{ alert('Impossible de rejoindre (backend absent)'); });
});
q('#start-btn')?.addEventListener('click', () => {
fetch('/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id: gameId }) })
.then(r=>{ if(!r.ok) throw new Error('start failed'); return r.json(); }).then((res)=>{
// If backend confirms, go to game page
window.location.href = `game.html?game=${gameId}`;
}).catch(()=>{
// If backend absent, still attempt to open the game page — polling may still load state from localStorage/backends
window.location.href = `game.html?game=${gameId}`;
});
});

1
node_modules/.bin/uuid generated vendored Symbolic link
View file

@ -0,0 +1 @@
../uuid/dist/bin/uuid

View file

@ -1,5 +1,5 @@
{ {
"name": "chessnut-backend", "name": "chessnut-server",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
@ -20,12 +20,12 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "24.7.2", "version": "24.10.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz",
"integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==", "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~7.14.0" "undici-types": "~7.16.0"
} }
}, },
"node_modules/accepts": { "node_modules/accepts": {
@ -118,6 +118,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/chess.js": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/chess.js/-/chess.js-1.4.0.tgz",
"integrity": "sha512-BBJgrrtKQOzFLonR0l+k64A98NLemPwNsCskwb+29bRwobUa4iTm51E1kwGPbWXAcfdDa18nad6vpPPKPWarqw==",
"license": "BSD-2-Clause"
},
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "0.5.4", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@ -1021,9 +1027,9 @@
} }
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "7.14.0", "version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/unpipe": { "node_modules/unpipe": {
@ -1044,6 +1050,19 @@
"node": ">= 0.4.0" "node": ">= 0.4.0"
} }
}, },
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View file

@ -8,7 +8,7 @@ This package contains type definitions for node (https://nodejs.org/).
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node. Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node.
### Additional Details ### Additional Details
* Last updated: Sat, 11 Oct 2025 14:02:18 GMT * Last updated: Mon, 03 Nov 2025 01:29:59 GMT
* Dependencies: [undici-types](https://npmjs.com/package/undici-types) * Dependencies: [undici-types](https://npmjs.com/package/undici-types)
# Credits # Credits

View file

@ -44,6 +44,13 @@ declare module "assert" {
* @default true * @default true
*/ */
strict?: boolean | undefined; strict?: boolean | undefined;
/**
* If set to `true`, skips prototype and constructor
* comparison in deep equality checks.
* @since v24.9.0
* @default false
*/
skipPrototype?: boolean | undefined;
} }
interface Assert extends Pick<typeof assert, AssertMethodNames> { interface Assert extends Pick<typeof assert, AssertMethodNames> {
readonly [kOptions]: AssertOptions & { strict: false }; readonly [kOptions]: AssertOptions & { strict: false };
@ -67,7 +74,8 @@ declare module "assert" {
* ``` * ```
* *
* **Important**: When destructuring assertion methods from an `Assert` instance, * **Important**: When destructuring assertion methods from an `Assert` instance,
* the methods lose their connection to the instance's configuration options (such as `diff` and `strict` settings). * the methods lose their connection to the instance's configuration options (such
* as `diff`, `strict`, and `skipPrototype` settings).
* The destructured methods will fall back to default behavior instead. * The destructured methods will fall back to default behavior instead.
* *
* ```js * ```js
@ -81,6 +89,33 @@ declare module "assert" {
* strictEqual({ a: 1 }, { b: { c: 1 } }); * strictEqual({ a: 1 }, { b: { c: 1 } });
* ``` * ```
* *
* The `skipPrototype` option affects all deep equality methods:
*
* ```js
* class Foo {
* constructor(a) {
* this.a = a;
* }
* }
*
* class Bar {
* constructor(a) {
* this.a = a;
* }
* }
*
* const foo = new Foo(1);
* const bar = new Bar(1);
*
* // Default behavior - fails due to different constructors
* const assert1 = new Assert();
* assert1.deepStrictEqual(foo, bar); // AssertionError
*
* // Skip prototype comparison - passes if properties are equal
* const assert2 = new Assert({ skipPrototype: true });
* assert2.deepStrictEqual(foo, bar); // OK
* ```
*
* When destructured, methods lose access to the instance's `this` context and revert to default assertion behavior * When destructured, methods lose access to the instance's `this` context and revert to default assertion behavior
* (diff: 'simple', non-strict mode). * (diff: 'simple', non-strict mode).
* To maintain custom options when using destructured methods, avoid * To maintain custom options when using destructured methods, avoid

View file

@ -451,7 +451,16 @@ declare module "buffer" {
*/ */
subarray(start?: number, end?: number): Buffer<TArrayBuffer>; subarray(start?: number, end?: number): Buffer<TArrayBuffer>;
} }
// TODO: remove globals in future version
/**
* @deprecated This is intended for internal use, and will be removed once `@types/node` no longer supports
* TypeScript versions earlier than 5.7.
*/
type NonSharedBuffer = Buffer<ArrayBuffer>; type NonSharedBuffer = Buffer<ArrayBuffer>;
/**
* @deprecated This is intended for internal use, and will be removed once `@types/node` no longer supports
* TypeScript versions earlier than 5.7.
*/
type AllowSharedBuffer = Buffer<ArrayBufferLike>; type AllowSharedBuffer = Buffer<ArrayBufferLike>;
} }
/** @deprecated Use `Buffer.allocUnsafeSlow()` instead. */ /** @deprecated Use `Buffer.allocUnsafeSlow()` instead. */

View file

@ -59,7 +59,7 @@ declare module "buffer" {
* @since v19.4.0, v18.14.0 * @since v19.4.0, v18.14.0
* @param input The input to validate. * @param input The input to validate.
*/ */
export function isUtf8(input: Buffer | ArrayBuffer | NodeJS.TypedArray): boolean; export function isUtf8(input: ArrayBuffer | NodeJS.TypedArray): boolean;
/** /**
* This function returns `true` if `input` contains only valid ASCII-encoded data, * This function returns `true` if `input` contains only valid ASCII-encoded data,
* including the case in which `input` is empty. * including the case in which `input` is empty.
@ -68,7 +68,7 @@ declare module "buffer" {
* @since v19.6.0, v18.15.0 * @since v19.6.0, v18.15.0
* @param input The input to validate. * @param input The input to validate.
*/ */
export function isAscii(input: Buffer | ArrayBuffer | NodeJS.TypedArray): boolean; export function isAscii(input: ArrayBuffer | NodeJS.TypedArray): boolean;
export let INSPECT_MAX_BYTES: number; export let INSPECT_MAX_BYTES: number;
export const kMaxLength: number; export const kMaxLength: number;
export const kStringMaxLength: number; export const kStringMaxLength: number;
@ -113,7 +113,11 @@ declare module "buffer" {
* @param fromEnc The current encoding. * @param fromEnc The current encoding.
* @param toEnc To target encoding. * @param toEnc To target encoding.
*/ */
export function transcode(source: Uint8Array, fromEnc: TranscodeEncoding, toEnc: TranscodeEncoding): Buffer; export function transcode(
source: Uint8Array,
fromEnc: TranscodeEncoding,
toEnc: TranscodeEncoding,
): NonSharedBuffer;
/** /**
* Resolves a `'blob:nodedata:...'` an associated `Blob` object registered using * Resolves a `'blob:nodedata:...'` an associated `Blob` object registered using
* a prior call to `URL.createObjectURL()`. * a prior call to `URL.createObjectURL()`.
@ -330,7 +334,7 @@ declare module "buffer" {
* @return The number of bytes contained within `string`. * @return The number of bytes contained within `string`.
*/ */
byteLength( byteLength(
string: string | Buffer | NodeJS.ArrayBufferView | ArrayBuffer | SharedArrayBuffer, string: string | NodeJS.ArrayBufferView | ArrayBufferLike,
encoding?: BufferEncoding, encoding?: BufferEncoding,
): number; ): number;
/** /**

View file

@ -66,6 +66,7 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/child_process.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/child_process.js)
*/ */
declare module "child_process" { declare module "child_process" {
import { NonSharedBuffer } from "node:buffer";
import { Abortable, EventEmitter } from "node:events"; import { Abortable, EventEmitter } from "node:events";
import * as dgram from "node:dgram"; import * as dgram from "node:dgram";
import * as net from "node:net"; import * as net from "node:net";
@ -1001,7 +1002,7 @@ declare module "child_process" {
function exec( function exec(
command: string, command: string,
options: ExecOptionsWithBufferEncoding, options: ExecOptionsWithBufferEncoding,
callback?: (error: ExecException | null, stdout: Buffer, stderr: Buffer) => void, callback?: (error: ExecException | null, stdout: NonSharedBuffer, stderr: NonSharedBuffer) => void,
): ChildProcess; ): ChildProcess;
// `options` with well-known or absent `encoding` means stdout/stderr are definitely `string`. // `options` with well-known or absent `encoding` means stdout/stderr are definitely `string`.
function exec( function exec(
@ -1013,7 +1014,11 @@ declare module "child_process" {
function exec( function exec(
command: string, command: string,
options: ExecOptions | undefined | null, options: ExecOptions | undefined | null,
callback?: (error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void, callback?: (
error: ExecException | null,
stdout: string | NonSharedBuffer,
stderr: string | NonSharedBuffer,
) => void,
): ChildProcess; ): ChildProcess;
interface PromiseWithChild<T> extends Promise<T> { interface PromiseWithChild<T> extends Promise<T> {
child: ChildProcess; child: ChildProcess;
@ -1027,8 +1032,8 @@ declare module "child_process" {
command: string, command: string,
options: ExecOptionsWithBufferEncoding, options: ExecOptionsWithBufferEncoding,
): PromiseWithChild<{ ): PromiseWithChild<{
stdout: Buffer; stdout: NonSharedBuffer;
stderr: Buffer; stderr: NonSharedBuffer;
}>; }>;
function __promisify__( function __promisify__(
command: string, command: string,
@ -1041,8 +1046,8 @@ declare module "child_process" {
command: string, command: string,
options: ExecOptions | undefined | null, options: ExecOptions | undefined | null,
): PromiseWithChild<{ ): PromiseWithChild<{
stdout: string | Buffer; stdout: string | NonSharedBuffer;
stderr: string | Buffer; stderr: string | NonSharedBuffer;
}>; }>;
} }
interface ExecFileOptions extends CommonOptions, Abortable { interface ExecFileOptions extends CommonOptions, Abortable {
@ -1144,13 +1149,13 @@ declare module "child_process" {
function execFile( function execFile(
file: string, file: string,
options: ExecFileOptionsWithBufferEncoding, options: ExecFileOptionsWithBufferEncoding,
callback?: (error: ExecFileException | null, stdout: Buffer, stderr: Buffer) => void, callback?: (error: ExecFileException | null, stdout: NonSharedBuffer, stderr: NonSharedBuffer) => void,
): ChildProcess; ): ChildProcess;
function execFile( function execFile(
file: string, file: string,
args: readonly string[] | undefined | null, args: readonly string[] | undefined | null,
options: ExecFileOptionsWithBufferEncoding, options: ExecFileOptionsWithBufferEncoding,
callback?: (error: ExecFileException | null, stdout: Buffer, stderr: Buffer) => void, callback?: (error: ExecFileException | null, stdout: NonSharedBuffer, stderr: NonSharedBuffer) => void,
): ChildProcess; ): ChildProcess;
// `options` with well-known or absent `encoding` means stdout/stderr are definitely `string`. // `options` with well-known or absent `encoding` means stdout/stderr are definitely `string`.
function execFile( function execFile(
@ -1169,7 +1174,11 @@ declare module "child_process" {
file: string, file: string,
options: ExecFileOptions | undefined | null, options: ExecFileOptions | undefined | null,
callback: callback:
| ((error: ExecFileException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | ((
error: ExecFileException | null,
stdout: string | NonSharedBuffer,
stderr: string | NonSharedBuffer,
) => void)
| undefined | undefined
| null, | null,
): ChildProcess; ): ChildProcess;
@ -1178,7 +1187,11 @@ declare module "child_process" {
args: readonly string[] | undefined | null, args: readonly string[] | undefined | null,
options: ExecFileOptions | undefined | null, options: ExecFileOptions | undefined | null,
callback: callback:
| ((error: ExecFileException | null, stdout: string | Buffer, stderr: string | Buffer) => void) | ((
error: ExecFileException | null,
stdout: string | NonSharedBuffer,
stderr: string | NonSharedBuffer,
) => void)
| undefined | undefined
| null, | null,
): ChildProcess; ): ChildProcess;
@ -1198,16 +1211,16 @@ declare module "child_process" {
file: string, file: string,
options: ExecFileOptionsWithBufferEncoding, options: ExecFileOptionsWithBufferEncoding,
): PromiseWithChild<{ ): PromiseWithChild<{
stdout: Buffer; stdout: NonSharedBuffer;
stderr: Buffer; stderr: NonSharedBuffer;
}>; }>;
function __promisify__( function __promisify__(
file: string, file: string,
args: readonly string[] | undefined | null, args: readonly string[] | undefined | null,
options: ExecFileOptionsWithBufferEncoding, options: ExecFileOptionsWithBufferEncoding,
): PromiseWithChild<{ ): PromiseWithChild<{
stdout: Buffer; stdout: NonSharedBuffer;
stderr: Buffer; stderr: NonSharedBuffer;
}>; }>;
function __promisify__( function __promisify__(
file: string, file: string,
@ -1228,16 +1241,16 @@ declare module "child_process" {
file: string, file: string,
options: ExecFileOptions | undefined | null, options: ExecFileOptions | undefined | null,
): PromiseWithChild<{ ): PromiseWithChild<{
stdout: string | Buffer; stdout: string | NonSharedBuffer;
stderr: string | Buffer; stderr: string | NonSharedBuffer;
}>; }>;
function __promisify__( function __promisify__(
file: string, file: string,
args: readonly string[] | undefined | null, args: readonly string[] | undefined | null,
options: ExecFileOptions | undefined | null, options: ExecFileOptions | undefined | null,
): PromiseWithChild<{ ): PromiseWithChild<{
stdout: string | Buffer; stdout: string | NonSharedBuffer;
stderr: string | Buffer; stderr: string | NonSharedBuffer;
}>; }>;
} }
interface ForkOptions extends ProcessEnvOptions, MessagingOptions, Abortable { interface ForkOptions extends ProcessEnvOptions, MessagingOptions, Abortable {
@ -1343,11 +1356,11 @@ declare module "child_process" {
* @param command The command to run. * @param command The command to run.
* @param args List of string arguments. * @param args List of string arguments.
*/ */
function spawnSync(command: string): SpawnSyncReturns<Buffer>; function spawnSync(command: string): SpawnSyncReturns<NonSharedBuffer>;
function spawnSync(command: string, options: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns<string>; function spawnSync(command: string, options: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns<string>;
function spawnSync(command: string, options: SpawnSyncOptionsWithBufferEncoding): SpawnSyncReturns<Buffer>; function spawnSync(command: string, options: SpawnSyncOptionsWithBufferEncoding): SpawnSyncReturns<NonSharedBuffer>;
function spawnSync(command: string, options?: SpawnSyncOptions): SpawnSyncReturns<string | Buffer>; function spawnSync(command: string, options?: SpawnSyncOptions): SpawnSyncReturns<string | NonSharedBuffer>;
function spawnSync(command: string, args: readonly string[]): SpawnSyncReturns<Buffer>; function spawnSync(command: string, args: readonly string[]): SpawnSyncReturns<NonSharedBuffer>;
function spawnSync( function spawnSync(
command: string, command: string,
args: readonly string[], args: readonly string[],
@ -1357,12 +1370,12 @@ declare module "child_process" {
command: string, command: string,
args: readonly string[], args: readonly string[],
options: SpawnSyncOptionsWithBufferEncoding, options: SpawnSyncOptionsWithBufferEncoding,
): SpawnSyncReturns<Buffer>; ): SpawnSyncReturns<NonSharedBuffer>;
function spawnSync( function spawnSync(
command: string, command: string,
args?: readonly string[], args?: readonly string[],
options?: SpawnSyncOptions, options?: SpawnSyncOptions,
): SpawnSyncReturns<string | Buffer>; ): SpawnSyncReturns<string | NonSharedBuffer>;
interface CommonExecOptions extends CommonOptions { interface CommonExecOptions extends CommonOptions {
input?: string | NodeJS.ArrayBufferView | undefined; input?: string | NodeJS.ArrayBufferView | undefined;
/** /**
@ -1404,10 +1417,10 @@ declare module "child_process" {
* @param command The command to run. * @param command The command to run.
* @return The stdout from the command. * @return The stdout from the command.
*/ */
function execSync(command: string): Buffer; function execSync(command: string): NonSharedBuffer;
function execSync(command: string, options: ExecSyncOptionsWithStringEncoding): string; function execSync(command: string, options: ExecSyncOptionsWithStringEncoding): string;
function execSync(command: string, options: ExecSyncOptionsWithBufferEncoding): Buffer; function execSync(command: string, options: ExecSyncOptionsWithBufferEncoding): NonSharedBuffer;
function execSync(command: string, options?: ExecSyncOptions): string | Buffer; function execSync(command: string, options?: ExecSyncOptions): string | NonSharedBuffer;
interface ExecFileSyncOptions extends CommonExecOptions { interface ExecFileSyncOptions extends CommonExecOptions {
shell?: boolean | string | undefined; shell?: boolean | string | undefined;
} }
@ -1437,11 +1450,11 @@ declare module "child_process" {
* @param args List of string arguments. * @param args List of string arguments.
* @return The stdout from the command. * @return The stdout from the command.
*/ */
function execFileSync(file: string): Buffer; function execFileSync(file: string): NonSharedBuffer;
function execFileSync(file: string, options: ExecFileSyncOptionsWithStringEncoding): string; function execFileSync(file: string, options: ExecFileSyncOptionsWithStringEncoding): string;
function execFileSync(file: string, options: ExecFileSyncOptionsWithBufferEncoding): Buffer; function execFileSync(file: string, options: ExecFileSyncOptionsWithBufferEncoding): NonSharedBuffer;
function execFileSync(file: string, options?: ExecFileSyncOptions): string | Buffer; function execFileSync(file: string, options?: ExecFileSyncOptions): string | NonSharedBuffer;
function execFileSync(file: string, args: readonly string[]): Buffer; function execFileSync(file: string, args: readonly string[]): NonSharedBuffer;
function execFileSync( function execFileSync(
file: string, file: string,
args: readonly string[], args: readonly string[],
@ -1451,8 +1464,12 @@ declare module "child_process" {
file: string, file: string,
args: readonly string[], args: readonly string[],
options: ExecFileSyncOptionsWithBufferEncoding, options: ExecFileSyncOptionsWithBufferEncoding,
): Buffer; ): NonSharedBuffer;
function execFileSync(file: string, args?: readonly string[], options?: ExecFileSyncOptions): string | Buffer; function execFileSync(
file: string,
args?: readonly string[],
options?: ExecFileSyncOptions,
): string | NonSharedBuffer;
} }
declare module "node:child_process" { declare module "node:child_process" {
export * from "child_process"; export * from "child_process";

View file

@ -72,7 +72,7 @@ declare module "cluster" {
* String arguments passed to worker. * String arguments passed to worker.
* @default process.argv.slice(2) * @default process.argv.slice(2)
*/ */
args?: string[] | undefined; args?: readonly string[] | undefined;
/** /**
* Whether or not to send output to parent's stdio. * Whether or not to send output to parent's stdio.
* @default false * @default false

View file

@ -431,9 +431,10 @@ declare module "node:console" {
colorMode?: boolean | "auto" | undefined; colorMode?: boolean | "auto" | undefined;
/** /**
* Specifies options that are passed along to * Specifies options that are passed along to
* [`util.inspect()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilinspectobject-options). * `util.inspect()`. Can be an options object or, if different options
* for stdout and stderr are desired, a `Map` from stream objects to options.
*/ */
inspectOptions?: InspectOptions | undefined; inspectOptions?: InspectOptions | ReadonlyMap<NodeJS.WritableStream, InspectOptions> | undefined;
/** /**
* Set group indentation. * Set group indentation.
* @default 2 * @default 2

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/dgram.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/dgram.js)
*/ */
declare module "dgram" { declare module "dgram" {
import { NonSharedBuffer } from "node:buffer";
import { AddressInfo, BlockList } from "node:net"; import { AddressInfo, BlockList } from "node:net";
import * as dns from "node:dns"; import * as dns from "node:dns";
import { Abortable, EventEmitter } from "node:events"; import { Abortable, EventEmitter } from "node:events";
@ -85,8 +86,8 @@ declare module "dgram" {
* @param options Available options are: * @param options Available options are:
* @param callback Attached as a listener for `'message'` events. Optional. * @param callback Attached as a listener for `'message'` events. Optional.
*/ */
function createSocket(type: SocketType, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; function createSocket(type: SocketType, callback?: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): Socket;
function createSocket(options: SocketOptions, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; function createSocket(options: SocketOptions, callback?: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): Socket;
/** /**
* Encapsulates the datagram functionality. * Encapsulates the datagram functionality.
* *
@ -556,37 +557,37 @@ declare module "dgram" {
addListener(event: "connect", listener: () => void): this; addListener(event: "connect", listener: () => void): this;
addListener(event: "error", listener: (err: Error) => void): this; addListener(event: "error", listener: (err: Error) => void): this;
addListener(event: "listening", listener: () => void): this; addListener(event: "listening", listener: () => void): this;
addListener(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this; addListener(event: "message", listener: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): this;
emit(event: string | symbol, ...args: any[]): boolean; emit(event: string | symbol, ...args: any[]): boolean;
emit(event: "close"): boolean; emit(event: "close"): boolean;
emit(event: "connect"): boolean; emit(event: "connect"): boolean;
emit(event: "error", err: Error): boolean; emit(event: "error", err: Error): boolean;
emit(event: "listening"): boolean; emit(event: "listening"): boolean;
emit(event: "message", msg: Buffer, rinfo: RemoteInfo): boolean; emit(event: "message", msg: NonSharedBuffer, rinfo: RemoteInfo): boolean;
on(event: string, listener: (...args: any[]) => void): this; on(event: string, listener: (...args: any[]) => void): this;
on(event: "close", listener: () => void): this; on(event: "close", listener: () => void): this;
on(event: "connect", listener: () => void): this; on(event: "connect", listener: () => void): this;
on(event: "error", listener: (err: Error) => void): this; on(event: "error", listener: (err: Error) => void): this;
on(event: "listening", listener: () => void): this; on(event: "listening", listener: () => void): this;
on(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this; on(event: "message", listener: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): this;
once(event: string, listener: (...args: any[]) => void): this; once(event: string, listener: (...args: any[]) => void): this;
once(event: "close", listener: () => void): this; once(event: "close", listener: () => void): this;
once(event: "connect", listener: () => void): this; once(event: "connect", listener: () => void): this;
once(event: "error", listener: (err: Error) => void): this; once(event: "error", listener: (err: Error) => void): this;
once(event: "listening", listener: () => void): this; once(event: "listening", listener: () => void): this;
once(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this; once(event: "message", listener: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): this;
prependListener(event: string, listener: (...args: any[]) => void): this; prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(event: "close", listener: () => void): this; prependListener(event: "close", listener: () => void): this;
prependListener(event: "connect", listener: () => void): this; prependListener(event: "connect", listener: () => void): this;
prependListener(event: "error", listener: (err: Error) => void): this; prependListener(event: "error", listener: (err: Error) => void): this;
prependListener(event: "listening", listener: () => void): this; prependListener(event: "listening", listener: () => void): this;
prependListener(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this; prependListener(event: "message", listener: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): this;
prependOnceListener(event: string, listener: (...args: any[]) => void): this; prependOnceListener(event: string, listener: (...args: any[]) => void): this;
prependOnceListener(event: "close", listener: () => void): this; prependOnceListener(event: "close", listener: () => void): this;
prependOnceListener(event: "connect", listener: () => void): this; prependOnceListener(event: "connect", listener: () => void): this;
prependOnceListener(event: "error", listener: (err: Error) => void): this; prependOnceListener(event: "error", listener: (err: Error) => void): this;
prependOnceListener(event: "listening", listener: () => void): this; prependOnceListener(event: "listening", listener: () => void): this;
prependOnceListener(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this; prependOnceListener(event: "message", listener: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): this;
/** /**
* Calls `socket.close()` and returns a promise that fulfills when the socket has closed. * Calls `socket.close()` and returns a promise that fulfills when the socket has closed.
* @since v20.5.0 * @since v20.5.0

View file

@ -189,7 +189,6 @@ declare module "diagnostics_channel" {
* }); * });
* ``` * ```
* @since v15.1.0, v14.17.0 * @since v15.1.0, v14.17.0
* @deprecated Since v18.7.0,v16.17.0 - Use {@link subscribe(name, onMessage)}
* @param onMessage The handler to receive channel messages * @param onMessage The handler to receive channel messages
*/ */
subscribe(onMessage: ChannelListener): void; subscribe(onMessage: ChannelListener): void;
@ -210,7 +209,6 @@ declare module "diagnostics_channel" {
* channel.unsubscribe(onMessage); * channel.unsubscribe(onMessage);
* ``` * ```
* @since v15.1.0, v14.17.0 * @since v15.1.0, v14.17.0
* @deprecated Since v18.7.0,v16.17.0 - Use {@link unsubscribe(name, onMessage)}
* @param onMessage The previous subscribed handler to remove * @param onMessage The previous subscribed handler to remove
* @return `true` if the handler was found, `false` otherwise. * @return `true` if the handler was found, `false` otherwise.
*/ */

View file

@ -19,6 +19,7 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/fs.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/fs.js)
*/ */
declare module "fs" { declare module "fs" {
import { NonSharedBuffer } from "node:buffer";
import * as stream from "node:stream"; import * as stream from "node:stream";
import { Abortable, EventEmitter } from "node:events"; import { Abortable, EventEmitter } from "node:events";
import { URL } from "node:url"; import { URL } from "node:url";
@ -394,23 +395,29 @@ declare module "fs" {
* 3. error * 3. error
*/ */
addListener(event: string, listener: (...args: any[]) => void): this; addListener(event: string, listener: (...args: any[]) => void): this;
addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; addListener(event: "change", listener: (eventType: string, filename: string | NonSharedBuffer) => void): this;
addListener(event: "close", listener: () => void): this; addListener(event: "close", listener: () => void): this;
addListener(event: "error", listener: (error: Error) => void): this; addListener(event: "error", listener: (error: Error) => void): this;
on(event: string, listener: (...args: any[]) => void): this; on(event: string, listener: (...args: any[]) => void): this;
on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; on(event: "change", listener: (eventType: string, filename: string | NonSharedBuffer) => void): this;
on(event: "close", listener: () => void): this; on(event: "close", listener: () => void): this;
on(event: "error", listener: (error: Error) => void): this; on(event: "error", listener: (error: Error) => void): this;
once(event: string, listener: (...args: any[]) => void): this; once(event: string, listener: (...args: any[]) => void): this;
once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; once(event: "change", listener: (eventType: string, filename: string | NonSharedBuffer) => void): this;
once(event: "close", listener: () => void): this; once(event: "close", listener: () => void): this;
once(event: "error", listener: (error: Error) => void): this; once(event: "error", listener: (error: Error) => void): this;
prependListener(event: string, listener: (...args: any[]) => void): this; prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; prependListener(
event: "change",
listener: (eventType: string, filename: string | NonSharedBuffer) => void,
): this;
prependListener(event: "close", listener: () => void): this; prependListener(event: "close", listener: () => void): this;
prependListener(event: "error", listener: (error: Error) => void): this; prependListener(event: "error", listener: (error: Error) => void): this;
prependOnceListener(event: string, listener: (...args: any[]) => void): this; prependOnceListener(event: string, listener: (...args: any[]) => void): this;
prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; prependOnceListener(
event: "change",
listener: (eventType: string, filename: string | NonSharedBuffer) => void,
): this;
prependOnceListener(event: "close", listener: () => void): this; prependOnceListener(event: "close", listener: () => void): this;
prependOnceListener(event: "error", listener: (error: Error) => void): this; prependOnceListener(event: "error", listener: (error: Error) => void): this;
} }
@ -1550,7 +1557,7 @@ declare module "fs" {
export function readlink( export function readlink(
path: PathLike, path: PathLike,
options: BufferEncodingOption, options: BufferEncodingOption,
callback: (err: NodeJS.ErrnoException | null, linkString: Buffer) => void, callback: (err: NodeJS.ErrnoException | null, linkString: NonSharedBuffer) => void,
): void; ): void;
/** /**
* Asynchronous readlink(2) - read value of a symbolic link. * Asynchronous readlink(2) - read value of a symbolic link.
@ -1560,7 +1567,7 @@ declare module "fs" {
export function readlink( export function readlink(
path: PathLike, path: PathLike,
options: EncodingOption, options: EncodingOption,
callback: (err: NodeJS.ErrnoException | null, linkString: string | Buffer) => void, callback: (err: NodeJS.ErrnoException | null, linkString: string | NonSharedBuffer) => void,
): void; ): void;
/** /**
* Asynchronous readlink(2) - read value of a symbolic link. * Asynchronous readlink(2) - read value of a symbolic link.
@ -1582,13 +1589,13 @@ declare module "fs" {
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function __promisify__(path: PathLike, options: BufferEncodingOption): Promise<Buffer>; function __promisify__(path: PathLike, options: BufferEncodingOption): Promise<NonSharedBuffer>;
/** /**
* Asynchronous readlink(2) - read value of a symbolic link. * Asynchronous readlink(2) - read value of a symbolic link.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function __promisify__(path: PathLike, options?: EncodingOption): Promise<string | Buffer>; function __promisify__(path: PathLike, options?: EncodingOption): Promise<string | NonSharedBuffer>;
} }
/** /**
* Returns the symbolic link's string value. * Returns the symbolic link's string value.
@ -1607,13 +1614,13 @@ declare module "fs" {
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
export function readlinkSync(path: PathLike, options: BufferEncodingOption): Buffer; export function readlinkSync(path: PathLike, options: BufferEncodingOption): NonSharedBuffer;
/** /**
* Synchronous readlink(2) - read value of a symbolic link. * Synchronous readlink(2) - read value of a symbolic link.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
export function readlinkSync(path: PathLike, options?: EncodingOption): string | Buffer; export function readlinkSync(path: PathLike, options?: EncodingOption): string | NonSharedBuffer;
/** /**
* Asynchronously computes the canonical pathname by resolving `.`, `..`, and * Asynchronously computes the canonical pathname by resolving `.`, `..`, and
* symbolic links. * symbolic links.
@ -1653,7 +1660,7 @@ declare module "fs" {
export function realpath( export function realpath(
path: PathLike, path: PathLike,
options: BufferEncodingOption, options: BufferEncodingOption,
callback: (err: NodeJS.ErrnoException | null, resolvedPath: Buffer) => void, callback: (err: NodeJS.ErrnoException | null, resolvedPath: NonSharedBuffer) => void,
): void; ): void;
/** /**
* Asynchronous realpath(3) - return the canonicalized absolute pathname. * Asynchronous realpath(3) - return the canonicalized absolute pathname.
@ -1663,7 +1670,7 @@ declare module "fs" {
export function realpath( export function realpath(
path: PathLike, path: PathLike,
options: EncodingOption, options: EncodingOption,
callback: (err: NodeJS.ErrnoException | null, resolvedPath: string | Buffer) => void, callback: (err: NodeJS.ErrnoException | null, resolvedPath: string | NonSharedBuffer) => void,
): void; ): void;
/** /**
* Asynchronous realpath(3) - return the canonicalized absolute pathname. * Asynchronous realpath(3) - return the canonicalized absolute pathname.
@ -1685,13 +1692,13 @@ declare module "fs" {
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function __promisify__(path: PathLike, options: BufferEncodingOption): Promise<Buffer>; function __promisify__(path: PathLike, options: BufferEncodingOption): Promise<NonSharedBuffer>;
/** /**
* Asynchronous realpath(3) - return the canonicalized absolute pathname. * Asynchronous realpath(3) - return the canonicalized absolute pathname.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function __promisify__(path: PathLike, options?: EncodingOption): Promise<string | Buffer>; function __promisify__(path: PathLike, options?: EncodingOption): Promise<string | NonSharedBuffer>;
/** /**
* Asynchronous [`realpath(3)`](http://man7.org/linux/man-pages/man3/realpath.3.html). * Asynchronous [`realpath(3)`](http://man7.org/linux/man-pages/man3/realpath.3.html).
* *
@ -1717,12 +1724,12 @@ declare module "fs" {
function native( function native(
path: PathLike, path: PathLike,
options: BufferEncodingOption, options: BufferEncodingOption,
callback: (err: NodeJS.ErrnoException | null, resolvedPath: Buffer) => void, callback: (err: NodeJS.ErrnoException | null, resolvedPath: NonSharedBuffer) => void,
): void; ): void;
function native( function native(
path: PathLike, path: PathLike,
options: EncodingOption, options: EncodingOption,
callback: (err: NodeJS.ErrnoException | null, resolvedPath: string | Buffer) => void, callback: (err: NodeJS.ErrnoException | null, resolvedPath: string | NonSharedBuffer) => void,
): void; ): void;
function native( function native(
path: PathLike, path: PathLike,
@ -1742,17 +1749,17 @@ declare module "fs" {
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
export function realpathSync(path: PathLike, options: BufferEncodingOption): Buffer; export function realpathSync(path: PathLike, options: BufferEncodingOption): NonSharedBuffer;
/** /**
* Synchronous realpath(3) - return the canonicalized absolute pathname. * Synchronous realpath(3) - return the canonicalized absolute pathname.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
export function realpathSync(path: PathLike, options?: EncodingOption): string | Buffer; export function realpathSync(path: PathLike, options?: EncodingOption): string | NonSharedBuffer;
export namespace realpathSync { export namespace realpathSync {
function native(path: PathLike, options?: EncodingOption): string; function native(path: PathLike, options?: EncodingOption): string;
function native(path: PathLike, options: BufferEncodingOption): Buffer; function native(path: PathLike, options: BufferEncodingOption): NonSharedBuffer;
function native(path: PathLike, options?: EncodingOption): string | Buffer; function native(path: PathLike, options?: EncodingOption): string | NonSharedBuffer;
} }
/** /**
* Asynchronously removes a file or symbolic link. No arguments other than a * Asynchronously removes a file or symbolic link. No arguments other than a
@ -2122,12 +2129,8 @@ declare module "fs" {
*/ */
export function mkdtemp( export function mkdtemp(
prefix: string, prefix: string,
options: options: BufferEncodingOption,
| "buffer" callback: (err: NodeJS.ErrnoException | null, folder: NonSharedBuffer) => void,
| {
encoding: "buffer";
},
callback: (err: NodeJS.ErrnoException | null, folder: Buffer) => void,
): void; ): void;
/** /**
* Asynchronously creates a unique temporary directory. * Asynchronously creates a unique temporary directory.
@ -2137,7 +2140,7 @@ declare module "fs" {
export function mkdtemp( export function mkdtemp(
prefix: string, prefix: string,
options: EncodingOption, options: EncodingOption,
callback: (err: NodeJS.ErrnoException | null, folder: string | Buffer) => void, callback: (err: NodeJS.ErrnoException | null, folder: string | NonSharedBuffer) => void,
): void; ): void;
/** /**
* Asynchronously creates a unique temporary directory. * Asynchronously creates a unique temporary directory.
@ -2159,13 +2162,13 @@ declare module "fs" {
* Generates six random characters to be appended behind a required prefix to create a unique temporary directory. * Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function __promisify__(prefix: string, options: BufferEncodingOption): Promise<Buffer>; function __promisify__(prefix: string, options: BufferEncodingOption): Promise<NonSharedBuffer>;
/** /**
* Asynchronously creates a unique temporary directory. * Asynchronously creates a unique temporary directory.
* Generates six random characters to be appended behind a required prefix to create a unique temporary directory. * Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function __promisify__(prefix: string, options?: EncodingOption): Promise<string | Buffer>; function __promisify__(prefix: string, options?: EncodingOption): Promise<string | NonSharedBuffer>;
} }
/** /**
* Returns the created directory path. * Returns the created directory path.
@ -2183,13 +2186,13 @@ declare module "fs" {
* Generates six random characters to be appended behind a required prefix to create a unique temporary directory. * Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
export function mkdtempSync(prefix: string, options: BufferEncodingOption): Buffer; export function mkdtempSync(prefix: string, options: BufferEncodingOption): NonSharedBuffer;
/** /**
* Synchronously creates a unique temporary directory. * Synchronously creates a unique temporary directory.
* Generates six random characters to be appended behind a required prefix to create a unique temporary directory. * Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
export function mkdtempSync(prefix: string, options?: EncodingOption): string | Buffer; export function mkdtempSync(prefix: string, options?: EncodingOption): string | NonSharedBuffer;
export interface DisposableTempDir extends AsyncDisposable { export interface DisposableTempDir extends AsyncDisposable {
/** /**
* The path of the created directory. * The path of the created directory.
@ -2263,7 +2266,7 @@ declare module "fs" {
recursive?: boolean | undefined; recursive?: boolean | undefined;
} }
| "buffer", | "buffer",
callback: (err: NodeJS.ErrnoException | null, files: Buffer[]) => void, callback: (err: NodeJS.ErrnoException | null, files: NonSharedBuffer[]) => void,
): void; ): void;
/** /**
* Asynchronous readdir(3) - read a directory. * Asynchronous readdir(3) - read a directory.
@ -2280,7 +2283,7 @@ declare module "fs" {
| BufferEncoding | BufferEncoding
| undefined | undefined
| null, | null,
callback: (err: NodeJS.ErrnoException | null, files: string[] | Buffer[]) => void, callback: (err: NodeJS.ErrnoException | null, files: string[] | NonSharedBuffer[]) => void,
): void; ): void;
/** /**
* Asynchronous readdir(3) - read a directory. * Asynchronous readdir(3) - read a directory.
@ -2315,7 +2318,7 @@ declare module "fs" {
withFileTypes: true; withFileTypes: true;
recursive?: boolean | undefined; recursive?: boolean | undefined;
}, },
callback: (err: NodeJS.ErrnoException | null, files: Dirent<Buffer>[]) => void, callback: (err: NodeJS.ErrnoException | null, files: Dirent<NonSharedBuffer>[]) => void,
): void; ): void;
export namespace readdir { export namespace readdir {
/** /**
@ -2348,7 +2351,7 @@ declare module "fs" {
withFileTypes?: false | undefined; withFileTypes?: false | undefined;
recursive?: boolean | undefined; recursive?: boolean | undefined;
}, },
): Promise<Buffer[]>; ): Promise<NonSharedBuffer[]>;
/** /**
* Asynchronous readdir(3) - read a directory. * Asynchronous readdir(3) - read a directory.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
@ -2363,7 +2366,7 @@ declare module "fs" {
}) })
| BufferEncoding | BufferEncoding
| null, | null,
): Promise<string[] | Buffer[]>; ): Promise<string[] | NonSharedBuffer[]>;
/** /**
* Asynchronous readdir(3) - read a directory. * Asynchronous readdir(3) - read a directory.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
@ -2388,7 +2391,7 @@ declare module "fs" {
withFileTypes: true; withFileTypes: true;
recursive?: boolean | undefined; recursive?: boolean | undefined;
}, },
): Promise<Dirent<Buffer>[]>; ): Promise<Dirent<NonSharedBuffer>[]>;
} }
/** /**
* Reads the contents of the directory. * Reads the contents of the directory.
@ -2428,7 +2431,7 @@ declare module "fs" {
recursive?: boolean | undefined; recursive?: boolean | undefined;
} }
| "buffer", | "buffer",
): Buffer[]; ): NonSharedBuffer[];
/** /**
* Synchronous readdir(3) - read a directory. * Synchronous readdir(3) - read a directory.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
@ -2443,7 +2446,7 @@ declare module "fs" {
}) })
| BufferEncoding | BufferEncoding
| null, | null,
): string[] | Buffer[]; ): string[] | NonSharedBuffer[];
/** /**
* Synchronous readdir(3) - read a directory. * Synchronous readdir(3) - read a directory.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
@ -2468,7 +2471,7 @@ declare module "fs" {
withFileTypes: true; withFileTypes: true;
recursive?: boolean | undefined; recursive?: boolean | undefined;
}, },
): Dirent<Buffer>[]; ): Dirent<NonSharedBuffer>[];
/** /**
* Closes the file descriptor. No arguments other than a possible exception are * Closes the file descriptor. No arguments other than a possible exception are
* given to the completion callback. * given to the completion callback.
@ -2835,7 +2838,7 @@ declare module "fs" {
encoding?: BufferEncoding | null, encoding?: BufferEncoding | null,
): number; ): number;
export type ReadPosition = number | bigint; export type ReadPosition = number | bigint;
export interface ReadSyncOptions { export interface ReadOptions {
/** /**
* @default 0 * @default 0
*/ */
@ -2849,9 +2852,15 @@ declare module "fs" {
*/ */
position?: ReadPosition | null | undefined; position?: ReadPosition | null | undefined;
} }
export interface ReadAsyncOptions<TBuffer extends NodeJS.ArrayBufferView> extends ReadSyncOptions { export interface ReadOptionsWithBuffer<T extends NodeJS.ArrayBufferView> extends ReadOptions {
buffer?: TBuffer; buffer?: T | undefined;
} }
/** @deprecated Use `ReadOptions` instead. */
// TODO: remove in future major
export interface ReadSyncOptions extends ReadOptions {}
/** @deprecated Use `ReadOptionsWithBuffer` instead. */
// TODO: remove in future major
export interface ReadAsyncOptions<T extends NodeJS.ArrayBufferView> extends ReadOptionsWithBuffer<T> {}
/** /**
* Read data from the file specified by `fd`. * Read data from the file specified by `fd`.
* *
@ -2886,15 +2895,15 @@ declare module "fs" {
* `position` defaults to `null` * `position` defaults to `null`
* @since v12.17.0, 13.11.0 * @since v12.17.0, 13.11.0
*/ */
export function read<TBuffer extends NodeJS.ArrayBufferView>( export function read<TBuffer extends NodeJS.ArrayBufferView = NonSharedBuffer>(
fd: number, fd: number,
options: ReadAsyncOptions<TBuffer>, options: ReadOptionsWithBuffer<TBuffer>,
callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void,
): void; ): void;
export function read<TBuffer extends NodeJS.ArrayBufferView>( export function read<TBuffer extends NodeJS.ArrayBufferView>(
fd: number, fd: number,
buffer: TBuffer, buffer: TBuffer,
options: ReadSyncOptions, options: ReadOptions,
callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void,
): void; ): void;
export function read<TBuffer extends NodeJS.ArrayBufferView>( export function read<TBuffer extends NodeJS.ArrayBufferView>(
@ -2904,7 +2913,7 @@ declare module "fs" {
): void; ): void;
export function read( export function read(
fd: number, fd: number,
callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: NodeJS.ArrayBufferView) => void, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: NonSharedBuffer) => void,
): void; ): void;
export namespace read { export namespace read {
/** /**
@ -2924,16 +2933,16 @@ declare module "fs" {
bytesRead: number; bytesRead: number;
buffer: TBuffer; buffer: TBuffer;
}>; }>;
function __promisify__<TBuffer extends NodeJS.ArrayBufferView>( function __promisify__<TBuffer extends NodeJS.ArrayBufferView = NonSharedBuffer>(
fd: number, fd: number,
options: ReadAsyncOptions<TBuffer>, options: ReadOptionsWithBuffer<TBuffer>,
): Promise<{ ): Promise<{
bytesRead: number; bytesRead: number;
buffer: TBuffer; buffer: TBuffer;
}>; }>;
function __promisify__(fd: number): Promise<{ function __promisify__(fd: number): Promise<{
bytesRead: number; bytesRead: number;
buffer: NodeJS.ArrayBufferView; buffer: NonSharedBuffer;
}>; }>;
} }
/** /**
@ -2955,7 +2964,7 @@ declare module "fs" {
* Similar to the above `fs.readSync` function, this version takes an optional `options` object. * Similar to the above `fs.readSync` function, this version takes an optional `options` object.
* If no `options` object is specified, it will default with the above values. * If no `options` object is specified, it will default with the above values.
*/ */
export function readSync(fd: number, buffer: NodeJS.ArrayBufferView, opts?: ReadSyncOptions): number; export function readSync(fd: number, buffer: NodeJS.ArrayBufferView, opts?: ReadOptions): number;
/** /**
* Asynchronously reads the entire contents of a file. * Asynchronously reads the entire contents of a file.
* *
@ -3628,12 +3637,12 @@ declare module "fs" {
export function watch( export function watch(
filename: PathLike, filename: PathLike,
options: WatchOptionsWithBufferEncoding | "buffer", options: WatchOptionsWithBufferEncoding | "buffer",
listener: WatchListener<Buffer>, listener: WatchListener<NonSharedBuffer>,
): FSWatcher; ): FSWatcher;
export function watch( export function watch(
filename: PathLike, filename: PathLike,
options: WatchOptions | BufferEncoding | "buffer" | null, options: WatchOptions | BufferEncoding | "buffer" | null,
listener: WatchListener<string | Buffer>, listener: WatchListener<string | NonSharedBuffer>,
): FSWatcher; ): FSWatcher;
export function watch(filename: PathLike, listener: WatchListener<string>): FSWatcher; export function watch(filename: PathLike, listener: WatchListener<string>): FSWatcher;
/** /**
@ -4344,27 +4353,29 @@ declare module "fs" {
* @since v12.9.0 * @since v12.9.0
* @param [position='null'] * @param [position='null']
*/ */
export function writev( export function writev<TBuffers extends readonly NodeJS.ArrayBufferView[]>(
fd: number, fd: number,
buffers: readonly NodeJS.ArrayBufferView[], buffers: TBuffers,
cb: (err: NodeJS.ErrnoException | null, bytesWritten: number, buffers: NodeJS.ArrayBufferView[]) => void, cb: (err: NodeJS.ErrnoException | null, bytesWritten: number, buffers: TBuffers) => void,
): void; ): void;
export function writev( export function writev<TBuffers extends readonly NodeJS.ArrayBufferView[]>(
fd: number, fd: number,
buffers: readonly NodeJS.ArrayBufferView[], buffers: TBuffers,
position: number | null, position: number | null,
cb: (err: NodeJS.ErrnoException | null, bytesWritten: number, buffers: NodeJS.ArrayBufferView[]) => void, cb: (err: NodeJS.ErrnoException | null, bytesWritten: number, buffers: TBuffers) => void,
): void; ): void;
export interface WriteVResult { // Providing a default type parameter doesn't provide true BC for userland consumers, but at least suppresses TS2314
// TODO: remove default in future major version
export interface WriteVResult<T extends readonly NodeJS.ArrayBufferView[] = NodeJS.ArrayBufferView[]> {
bytesWritten: number; bytesWritten: number;
buffers: NodeJS.ArrayBufferView[]; buffers: T;
} }
export namespace writev { export namespace writev {
function __promisify__( function __promisify__<TBuffers extends readonly NodeJS.ArrayBufferView[]>(
fd: number, fd: number,
buffers: readonly NodeJS.ArrayBufferView[], buffers: TBuffers,
position?: number, position?: number,
): Promise<WriteVResult>; ): Promise<WriteVResult<TBuffers>>;
} }
/** /**
* For detailed information, see the documentation of the asynchronous version of * For detailed information, see the documentation of the asynchronous version of
@ -4389,27 +4400,29 @@ declare module "fs" {
* @since v13.13.0, v12.17.0 * @since v13.13.0, v12.17.0
* @param [position='null'] * @param [position='null']
*/ */
export function readv( export function readv<TBuffers extends readonly NodeJS.ArrayBufferView[]>(
fd: number, fd: number,
buffers: readonly NodeJS.ArrayBufferView[], buffers: TBuffers,
cb: (err: NodeJS.ErrnoException | null, bytesRead: number, buffers: NodeJS.ArrayBufferView[]) => void, cb: (err: NodeJS.ErrnoException | null, bytesRead: number, buffers: TBuffers) => void,
): void; ): void;
export function readv( export function readv<TBuffers extends readonly NodeJS.ArrayBufferView[]>(
fd: number, fd: number,
buffers: readonly NodeJS.ArrayBufferView[], buffers: TBuffers,
position: number | null, position: number | null,
cb: (err: NodeJS.ErrnoException | null, bytesRead: number, buffers: NodeJS.ArrayBufferView[]) => void, cb: (err: NodeJS.ErrnoException | null, bytesRead: number, buffers: TBuffers) => void,
): void; ): void;
export interface ReadVResult { // Providing a default type parameter doesn't provide true BC for userland consumers, but at least suppresses TS2314
// TODO: remove default in future major version
export interface ReadVResult<T extends readonly NodeJS.ArrayBufferView[] = NodeJS.ArrayBufferView[]> {
bytesRead: number; bytesRead: number;
buffers: NodeJS.ArrayBufferView[]; buffers: T;
} }
export namespace readv { export namespace readv {
function __promisify__( function __promisify__<TBuffers extends readonly NodeJS.ArrayBufferView[]>(
fd: number, fd: number,
buffers: readonly NodeJS.ArrayBufferView[], buffers: TBuffers,
position?: number, position?: number,
): Promise<ReadVResult>; ): Promise<ReadVResult<TBuffers>>;
} }
/** /**
* For detailed information, see the documentation of the asynchronous version of * For detailed information, see the documentation of the asynchronous version of

View file

@ -9,6 +9,7 @@
* @since v10.0.0 * @since v10.0.0
*/ */
declare module "fs/promises" { declare module "fs/promises" {
import { NonSharedBuffer } from "node:buffer";
import { Abortable } from "node:events"; import { Abortable } from "node:events";
import { Stream } from "node:stream"; import { Stream } from "node:stream";
import { ReadableStream } from "node:stream/web"; import { ReadableStream } from "node:stream/web";
@ -31,6 +32,8 @@ declare module "fs/promises" {
OpenDirOptions, OpenDirOptions,
OpenMode, OpenMode,
PathLike, PathLike,
ReadOptions,
ReadOptionsWithBuffer,
ReadPosition, ReadPosition,
ReadStream, ReadStream,
ReadVResult, ReadVResult,
@ -59,6 +62,7 @@ declare module "fs/promises" {
bytesRead: number; bytesRead: number;
buffer: T; buffer: T;
} }
/** @deprecated This interface will be removed in a future version. Use `import { ReadOptionsWithBuffer } from "node:fs"` instead. */
interface FileReadOptions<T extends NodeJS.ArrayBufferView = Buffer> { interface FileReadOptions<T extends NodeJS.ArrayBufferView = Buffer> {
/** /**
* @default `Buffer.alloc(0xffff)` * @default `Buffer.alloc(0xffff)`
@ -237,11 +241,13 @@ declare module "fs/promises" {
length?: number | null, length?: number | null,
position?: ReadPosition | null, position?: ReadPosition | null,
): Promise<FileReadResult<T>>; ): Promise<FileReadResult<T>>;
read<T extends NodeJS.ArrayBufferView = Buffer>( read<T extends NodeJS.ArrayBufferView>(
buffer: T, buffer: T,
options?: FileReadOptions<T>, options?: ReadOptions,
): Promise<FileReadResult<T>>;
read<T extends NodeJS.ArrayBufferView = NonSharedBuffer>(
options?: ReadOptionsWithBuffer<T>,
): Promise<FileReadResult<T>>; ): Promise<FileReadResult<T>>;
read<T extends NodeJS.ArrayBufferView = Buffer>(options?: FileReadOptions<T>): Promise<FileReadResult<T>>;
/** /**
* Returns a byte-oriented `ReadableStream` that may be used to read the file's * Returns a byte-oriented `ReadableStream` that may be used to read the file's
* contents. * contents.
@ -285,7 +291,7 @@ declare module "fs/promises" {
options?: options?:
| ({ encoding?: null | undefined } & Abortable) | ({ encoding?: null | undefined } & Abortable)
| null, | null,
): Promise<Buffer>; ): Promise<NonSharedBuffer>;
/** /**
* Asynchronously reads the entire contents of a file. The underlying file will _not_ be closed automatically. * Asynchronously reads the entire contents of a file. The underlying file will _not_ be closed automatically.
* The `FileHandle` must have been opened for reading. * The `FileHandle` must have been opened for reading.
@ -304,7 +310,7 @@ declare module "fs/promises" {
| (ObjectEncodingOptions & Abortable) | (ObjectEncodingOptions & Abortable)
| BufferEncoding | BufferEncoding
| null, | null,
): Promise<string | Buffer>; ): Promise<string | NonSharedBuffer>;
/** /**
* Convenience method to create a `readline` interface and stream over the file. * Convenience method to create a `readline` interface and stream over the file.
* See `filehandle.createReadStream()` for the options. * See `filehandle.createReadStream()` for the options.
@ -413,7 +419,7 @@ declare module "fs/promises" {
* @param [position='null'] The offset from the beginning of the file where the data from `buffer` should be written. If `position` is not a `number`, the data will be written at the current * @param [position='null'] The offset from the beginning of the file where the data from `buffer` should be written. If `position` is not a `number`, the data will be written at the current
* position. See the POSIX pwrite(2) documentation for more detail. * position. See the POSIX pwrite(2) documentation for more detail.
*/ */
write<TBuffer extends Uint8Array>( write<TBuffer extends NodeJS.ArrayBufferView>(
buffer: TBuffer, buffer: TBuffer,
offset?: number | null, offset?: number | null,
length?: number | null, length?: number | null,
@ -452,14 +458,20 @@ declare module "fs/promises" {
* @param [position='null'] The offset from the beginning of the file where the data from `buffers` should be written. If `position` is not a `number`, the data will be written at the current * @param [position='null'] The offset from the beginning of the file where the data from `buffers` should be written. If `position` is not a `number`, the data will be written at the current
* position. * position.
*/ */
writev(buffers: readonly NodeJS.ArrayBufferView[], position?: number): Promise<WriteVResult>; writev<TBuffers extends readonly NodeJS.ArrayBufferView[]>(
buffers: TBuffers,
position?: number,
): Promise<WriteVResult<TBuffers>>;
/** /**
* Read from a file and write to an array of [ArrayBufferView](https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView) s * Read from a file and write to an array of [ArrayBufferView](https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView) s
* @since v13.13.0, v12.17.0 * @since v13.13.0, v12.17.0
* @param [position='null'] The offset from the beginning of the file where the data should be read from. If `position` is not a `number`, the data will be read from the current position. * @param [position='null'] The offset from the beginning of the file where the data should be read from. If `position` is not a `number`, the data will be read from the current position.
* @return Fulfills upon success an object containing two properties: * @return Fulfills upon success an object containing two properties:
*/ */
readv(buffers: readonly NodeJS.ArrayBufferView[], position?: number): Promise<ReadVResult>; readv<TBuffers extends readonly NodeJS.ArrayBufferView[]>(
buffers: TBuffers,
position?: number,
): Promise<ReadVResult<TBuffers>>;
/** /**
* Closes the file handle after waiting for any pending operation on the handle to * Closes the file handle after waiting for any pending operation on the handle to
* complete. * complete.
@ -696,7 +708,7 @@ declare module "fs/promises" {
recursive?: boolean | undefined; recursive?: boolean | undefined;
} }
| "buffer", | "buffer",
): Promise<Buffer[]>; ): Promise<NonSharedBuffer[]>;
/** /**
* Asynchronous readdir(3) - read a directory. * Asynchronous readdir(3) - read a directory.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
@ -711,7 +723,7 @@ declare module "fs/promises" {
}) })
| BufferEncoding | BufferEncoding
| null, | null,
): Promise<string[] | Buffer[]>; ): Promise<string[] | NonSharedBuffer[]>;
/** /**
* Asynchronous readdir(3) - read a directory. * Asynchronous readdir(3) - read a directory.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
@ -736,7 +748,7 @@ declare module "fs/promises" {
withFileTypes: true; withFileTypes: true;
recursive?: boolean | undefined; recursive?: boolean | undefined;
}, },
): Promise<Dirent<Buffer>[]>; ): Promise<Dirent<NonSharedBuffer>[]>;
/** /**
* Reads the contents of the symbolic link referred to by `path`. See the POSIX [`readlink(2)`](http://man7.org/linux/man-pages/man2/readlink.2.html) documentation for more detail. The promise is * Reads the contents of the symbolic link referred to by `path`. See the POSIX [`readlink(2)`](http://man7.org/linux/man-pages/man2/readlink.2.html) documentation for more detail. The promise is
* fulfilled with the`linkString` upon success. * fulfilled with the`linkString` upon success.
@ -754,13 +766,16 @@ declare module "fs/promises" {
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function readlink(path: PathLike, options: BufferEncodingOption): Promise<Buffer>; function readlink(path: PathLike, options: BufferEncodingOption): Promise<NonSharedBuffer>;
/** /**
* Asynchronous readlink(2) - read value of a symbolic link. * Asynchronous readlink(2) - read value of a symbolic link.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function readlink(path: PathLike, options?: ObjectEncodingOptions | string | null): Promise<string | Buffer>; function readlink(
path: PathLike,
options?: ObjectEncodingOptions | string | null,
): Promise<string | NonSharedBuffer>;
/** /**
* Creates a symbolic link. * Creates a symbolic link.
* *
@ -911,7 +926,7 @@ declare module "fs/promises" {
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function realpath(path: PathLike, options: BufferEncodingOption): Promise<Buffer>; function realpath(path: PathLike, options: BufferEncodingOption): Promise<NonSharedBuffer>;
/** /**
* Asynchronous realpath(3) - return the canonicalized absolute pathname. * Asynchronous realpath(3) - return the canonicalized absolute pathname.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
@ -920,7 +935,7 @@ declare module "fs/promises" {
function realpath( function realpath(
path: PathLike, path: PathLike,
options?: ObjectEncodingOptions | BufferEncoding | null, options?: ObjectEncodingOptions | BufferEncoding | null,
): Promise<string | Buffer>; ): Promise<string | NonSharedBuffer>;
/** /**
* Creates a unique temporary directory. A unique directory name is generated by * Creates a unique temporary directory. A unique directory name is generated by
* appending six random characters to the end of the provided `prefix`. Due to * appending six random characters to the end of the provided `prefix`. Due to
@ -956,13 +971,16 @@ declare module "fs/promises" {
* Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory. * Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function mkdtemp(prefix: string, options: BufferEncodingOption): Promise<Buffer>; function mkdtemp(prefix: string, options: BufferEncodingOption): Promise<NonSharedBuffer>;
/** /**
* Asynchronously creates a unique temporary directory. * Asynchronously creates a unique temporary directory.
* Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory. * Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
*/ */
function mkdtemp(prefix: string, options?: ObjectEncodingOptions | BufferEncoding | null): Promise<string | Buffer>; function mkdtemp(
prefix: string,
options?: ObjectEncodingOptions | BufferEncoding | null,
): Promise<string | NonSharedBuffer>;
/** /**
* The resulting Promise holds an async-disposable object whose `path` property * The resulting Promise holds an async-disposable object whose `path` property
* holds the created directory path. When the object is disposed, the directory * holds the created directory path. When the object is disposed, the directory
@ -1138,7 +1156,7 @@ declare module "fs/promises" {
flag?: OpenMode | undefined; flag?: OpenMode | undefined;
} & Abortable) } & Abortable)
| null, | null,
): Promise<Buffer>; ): Promise<NonSharedBuffer>;
/** /**
* Asynchronously reads the entire contents of a file. * Asynchronously reads the entire contents of a file.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol. * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
@ -1174,7 +1192,7 @@ declare module "fs/promises" {
) )
| BufferEncoding | BufferEncoding
| null, | null,
): Promise<string | Buffer>; ): Promise<string | NonSharedBuffer>;
/** /**
* Asynchronously open a directory for iterative scanning. See the POSIX [`opendir(3)`](http://man7.org/linux/man-pages/man3/opendir.3.html) documentation for more detail. * Asynchronously open a directory for iterative scanning. See the POSIX [`opendir(3)`](http://man7.org/linux/man-pages/man3/opendir.3.html) documentation for more detail.
* *
@ -1251,11 +1269,11 @@ declare module "fs/promises" {
function watch( function watch(
filename: PathLike, filename: PathLike,
options: WatchOptionsWithBufferEncoding | "buffer", options: WatchOptionsWithBufferEncoding | "buffer",
): NodeJS.AsyncIterator<FileChangeInfo<Buffer>>; ): NodeJS.AsyncIterator<FileChangeInfo<NonSharedBuffer>>;
function watch( function watch(
filename: PathLike, filename: PathLike,
options: WatchOptions | BufferEncoding | "buffer", options: WatchOptions | BufferEncoding | "buffer",
): NodeJS.AsyncIterator<FileChangeInfo<string | Buffer>>; ): NodeJS.AsyncIterator<FileChangeInfo<string | NonSharedBuffer>>;
/** /**
* Asynchronously copies the entire directory structure from `src` to `dest`, * Asynchronously copies the entire directory structure from `src` to `dest`,
* including subdirectories and files. * including subdirectories and files.

41
node_modules/@types/node/globals.typedarray.d.ts generated vendored Normal file
View file

@ -0,0 +1,41 @@
export {}; // Make this a module
declare global {
namespace NodeJS {
type TypedArray<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike> =
| Uint8Array<TArrayBuffer>
| Uint8ClampedArray<TArrayBuffer>
| Uint16Array<TArrayBuffer>
| Uint32Array<TArrayBuffer>
| Int8Array<TArrayBuffer>
| Int16Array<TArrayBuffer>
| Int32Array<TArrayBuffer>
| BigUint64Array<TArrayBuffer>
| BigInt64Array<TArrayBuffer>
| Float16Array<TArrayBuffer>
| Float32Array<TArrayBuffer>
| Float64Array<TArrayBuffer>;
type ArrayBufferView<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike> =
| TypedArray<TArrayBuffer>
| DataView<TArrayBuffer>;
// The following aliases are required to allow use of non-shared ArrayBufferViews in @types/node
// while maintaining compatibility with TS <=5.6.
// TODO: remove once @types/node no longer supports TS 5.6, and replace with native types.
type NonSharedUint8Array = Uint8Array<ArrayBuffer>;
type NonSharedUint8ClampedArray = Uint8ClampedArray<ArrayBuffer>;
type NonSharedUint16Array = Uint16Array<ArrayBuffer>;
type NonSharedUint32Array = Uint32Array<ArrayBuffer>;
type NonSharedInt8Array = Int8Array<ArrayBuffer>;
type NonSharedInt16Array = Int16Array<ArrayBuffer>;
type NonSharedInt32Array = Int32Array<ArrayBuffer>;
type NonSharedBigUint64Array = BigUint64Array<ArrayBuffer>;
type NonSharedBigInt64Array = BigInt64Array<ArrayBuffer>;
type NonSharedFloat16Array = Float16Array<ArrayBuffer>;
type NonSharedFloat32Array = Float32Array<ArrayBuffer>;
type NonSharedFloat64Array = Float64Array<ArrayBuffer>;
type NonSharedDataView = DataView<ArrayBuffer>;
type NonSharedTypedArray = TypedArray<ArrayBuffer>;
type NonSharedArrayBufferView = ArrayBufferView<ArrayBuffer>;
}
}

View file

@ -40,6 +40,7 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/http.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/http.js)
*/ */
declare module "http" { declare module "http" {
import { NonSharedBuffer } from "node:buffer";
import * as stream from "node:stream"; import * as stream from "node:stream";
import { URL } from "node:url"; import { URL } from "node:url";
import { LookupOptions } from "node:dns"; import { LookupOptions } from "node:dns";
@ -339,6 +340,17 @@ declare module "http" {
* If the header's value is an array, the items will be joined using `; `. * If the header's value is an array, the items will be joined using `; `.
*/ */
uniqueHeaders?: Array<string | string[]> | undefined; uniqueHeaders?: Array<string | string[]> | undefined;
/**
* A callback which receives an
* incoming request and returns a boolean, to control which upgrade attempts
* should be accepted. Accepted upgrades will fire an `'upgrade'` event (or
* their sockets will be destroyed, if no listener is registered) while
* rejected upgrades will fire a `'request'` event like any non-upgrade
* request.
* @since v24.9.0
* @default () => server.listenerCount('upgrade') > 0
*/
shouldUpgradeCallback?: ((request: InstanceType<Request>) => boolean) | undefined;
/** /**
* If set to `true`, an error is thrown when writing to an HTTP response which does not have a body. * If set to `true`, an error is thrown when writing to an HTTP response which does not have a body.
* @default false * @default false
@ -484,13 +496,13 @@ declare module "http" {
addListener(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this; addListener(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this;
addListener( addListener(
event: "connect", event: "connect",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this; ): this;
addListener(event: "dropRequest", listener: (req: InstanceType<Request>, socket: stream.Duplex) => void): this; addListener(event: "dropRequest", listener: (req: InstanceType<Request>, socket: stream.Duplex) => void): this;
addListener(event: "request", listener: RequestListener<Request, Response>): this; addListener(event: "request", listener: RequestListener<Request, Response>): this;
addListener( addListener(
event: "upgrade", event: "upgrade",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this; ): this;
emit(event: string, ...args: any[]): boolean; emit(event: string, ...args: any[]): boolean;
emit(event: "close"): boolean; emit(event: "close"): boolean;
@ -508,14 +520,14 @@ declare module "http" {
res: InstanceType<Response> & { req: InstanceType<Request> }, res: InstanceType<Response> & { req: InstanceType<Request> },
): boolean; ): boolean;
emit(event: "clientError", err: Error, socket: stream.Duplex): boolean; emit(event: "clientError", err: Error, socket: stream.Duplex): boolean;
emit(event: "connect", req: InstanceType<Request>, socket: stream.Duplex, head: Buffer): boolean; emit(event: "connect", req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer): boolean;
emit(event: "dropRequest", req: InstanceType<Request>, socket: stream.Duplex): boolean; emit(event: "dropRequest", req: InstanceType<Request>, socket: stream.Duplex): boolean;
emit( emit(
event: "request", event: "request",
req: InstanceType<Request>, req: InstanceType<Request>,
res: InstanceType<Response> & { req: InstanceType<Request> }, res: InstanceType<Response> & { req: InstanceType<Request> },
): boolean; ): boolean;
emit(event: "upgrade", req: InstanceType<Request>, socket: stream.Duplex, head: Buffer): boolean; emit(event: "upgrade", req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer): boolean;
on(event: string, listener: (...args: any[]) => void): this; on(event: string, listener: (...args: any[]) => void): this;
on(event: "close", listener: () => void): this; on(event: "close", listener: () => void): this;
on(event: "connection", listener: (socket: Socket) => void): this; on(event: "connection", listener: (socket: Socket) => void): this;
@ -524,10 +536,16 @@ declare module "http" {
on(event: "checkContinue", listener: RequestListener<Request, Response>): this; on(event: "checkContinue", listener: RequestListener<Request, Response>): this;
on(event: "checkExpectation", listener: RequestListener<Request, Response>): this; on(event: "checkExpectation", listener: RequestListener<Request, Response>): this;
on(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this; on(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this;
on(event: "connect", listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void): this; on(
event: "connect",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this;
on(event: "dropRequest", listener: (req: InstanceType<Request>, socket: stream.Duplex) => void): this; on(event: "dropRequest", listener: (req: InstanceType<Request>, socket: stream.Duplex) => void): this;
on(event: "request", listener: RequestListener<Request, Response>): this; on(event: "request", listener: RequestListener<Request, Response>): this;
on(event: "upgrade", listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void): this; on(
event: "upgrade",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this;
once(event: string, listener: (...args: any[]) => void): this; once(event: string, listener: (...args: any[]) => void): this;
once(event: "close", listener: () => void): this; once(event: "close", listener: () => void): this;
once(event: "connection", listener: (socket: Socket) => void): this; once(event: "connection", listener: (socket: Socket) => void): this;
@ -538,13 +556,13 @@ declare module "http" {
once(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this; once(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this;
once( once(
event: "connect", event: "connect",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this; ): this;
once(event: "dropRequest", listener: (req: InstanceType<Request>, socket: stream.Duplex) => void): this; once(event: "dropRequest", listener: (req: InstanceType<Request>, socket: stream.Duplex) => void): this;
once(event: "request", listener: RequestListener<Request, Response>): this; once(event: "request", listener: RequestListener<Request, Response>): this;
once( once(
event: "upgrade", event: "upgrade",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this; ): this;
prependListener(event: string, listener: (...args: any[]) => void): this; prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(event: "close", listener: () => void): this; prependListener(event: "close", listener: () => void): this;
@ -556,7 +574,7 @@ declare module "http" {
prependListener(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this; prependListener(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this;
prependListener( prependListener(
event: "connect", event: "connect",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this; ): this;
prependListener( prependListener(
event: "dropRequest", event: "dropRequest",
@ -565,7 +583,7 @@ declare module "http" {
prependListener(event: "request", listener: RequestListener<Request, Response>): this; prependListener(event: "request", listener: RequestListener<Request, Response>): this;
prependListener( prependListener(
event: "upgrade", event: "upgrade",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this; ): this;
prependOnceListener(event: string, listener: (...args: any[]) => void): this; prependOnceListener(event: string, listener: (...args: any[]) => void): this;
prependOnceListener(event: "close", listener: () => void): this; prependOnceListener(event: "close", listener: () => void): this;
@ -577,7 +595,7 @@ declare module "http" {
prependOnceListener(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this; prependOnceListener(event: "clientError", listener: (err: Error, socket: stream.Duplex) => void): this;
prependOnceListener( prependOnceListener(
event: "connect", event: "connect",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this; ): this;
prependOnceListener( prependOnceListener(
event: "dropRequest", event: "dropRequest",
@ -586,7 +604,7 @@ declare module "http" {
prependOnceListener(event: "request", listener: RequestListener<Request, Response>): this; prependOnceListener(event: "request", listener: RequestListener<Request, Response>): this;
prependOnceListener( prependOnceListener(
event: "upgrade", event: "upgrade",
listener: (req: InstanceType<Request>, socket: stream.Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: stream.Duplex, head: NonSharedBuffer) => void,
): this; ): this;
} }
/** /**
@ -1106,7 +1124,7 @@ declare module "http" {
addListener(event: "abort", listener: () => void): this; addListener(event: "abort", listener: () => void): this;
addListener( addListener(
event: "connect", event: "connect",
listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void, listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this; ): this;
addListener(event: "continue", listener: () => void): this; addListener(event: "continue", listener: () => void): this;
addListener(event: "information", listener: (info: InformationEvent) => void): this; addListener(event: "information", listener: (info: InformationEvent) => void): this;
@ -1115,7 +1133,7 @@ declare module "http" {
addListener(event: "timeout", listener: () => void): this; addListener(event: "timeout", listener: () => void): this;
addListener( addListener(
event: "upgrade", event: "upgrade",
listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void, listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this; ): this;
addListener(event: "close", listener: () => void): this; addListener(event: "close", listener: () => void): this;
addListener(event: "drain", listener: () => void): this; addListener(event: "drain", listener: () => void): this;
@ -1128,13 +1146,19 @@ declare module "http" {
* @deprecated * @deprecated
*/ */
on(event: "abort", listener: () => void): this; on(event: "abort", listener: () => void): this;
on(event: "connect", listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void): this; on(
event: "connect",
listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this;
on(event: "continue", listener: () => void): this; on(event: "continue", listener: () => void): this;
on(event: "information", listener: (info: InformationEvent) => void): this; on(event: "information", listener: (info: InformationEvent) => void): this;
on(event: "response", listener: (response: IncomingMessage) => void): this; on(event: "response", listener: (response: IncomingMessage) => void): this;
on(event: "socket", listener: (socket: Socket) => void): this; on(event: "socket", listener: (socket: Socket) => void): this;
on(event: "timeout", listener: () => void): this; on(event: "timeout", listener: () => void): this;
on(event: "upgrade", listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void): this; on(
event: "upgrade",
listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this;
on(event: "close", listener: () => void): this; on(event: "close", listener: () => void): this;
on(event: "drain", listener: () => void): this; on(event: "drain", listener: () => void): this;
on(event: "error", listener: (err: Error) => void): this; on(event: "error", listener: (err: Error) => void): this;
@ -1146,13 +1170,19 @@ declare module "http" {
* @deprecated * @deprecated
*/ */
once(event: "abort", listener: () => void): this; once(event: "abort", listener: () => void): this;
once(event: "connect", listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void): this; once(
event: "connect",
listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this;
once(event: "continue", listener: () => void): this; once(event: "continue", listener: () => void): this;
once(event: "information", listener: (info: InformationEvent) => void): this; once(event: "information", listener: (info: InformationEvent) => void): this;
once(event: "response", listener: (response: IncomingMessage) => void): this; once(event: "response", listener: (response: IncomingMessage) => void): this;
once(event: "socket", listener: (socket: Socket) => void): this; once(event: "socket", listener: (socket: Socket) => void): this;
once(event: "timeout", listener: () => void): this; once(event: "timeout", listener: () => void): this;
once(event: "upgrade", listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void): this; once(
event: "upgrade",
listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this;
once(event: "close", listener: () => void): this; once(event: "close", listener: () => void): this;
once(event: "drain", listener: () => void): this; once(event: "drain", listener: () => void): this;
once(event: "error", listener: (err: Error) => void): this; once(event: "error", listener: (err: Error) => void): this;
@ -1166,7 +1196,7 @@ declare module "http" {
prependListener(event: "abort", listener: () => void): this; prependListener(event: "abort", listener: () => void): this;
prependListener( prependListener(
event: "connect", event: "connect",
listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void, listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this; ): this;
prependListener(event: "continue", listener: () => void): this; prependListener(event: "continue", listener: () => void): this;
prependListener(event: "information", listener: (info: InformationEvent) => void): this; prependListener(event: "information", listener: (info: InformationEvent) => void): this;
@ -1175,7 +1205,7 @@ declare module "http" {
prependListener(event: "timeout", listener: () => void): this; prependListener(event: "timeout", listener: () => void): this;
prependListener( prependListener(
event: "upgrade", event: "upgrade",
listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void, listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this; ): this;
prependListener(event: "close", listener: () => void): this; prependListener(event: "close", listener: () => void): this;
prependListener(event: "drain", listener: () => void): this; prependListener(event: "drain", listener: () => void): this;
@ -1190,7 +1220,7 @@ declare module "http" {
prependOnceListener(event: "abort", listener: () => void): this; prependOnceListener(event: "abort", listener: () => void): this;
prependOnceListener( prependOnceListener(
event: "connect", event: "connect",
listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void, listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this; ): this;
prependOnceListener(event: "continue", listener: () => void): this; prependOnceListener(event: "continue", listener: () => void): this;
prependOnceListener(event: "information", listener: (info: InformationEvent) => void): this; prependOnceListener(event: "information", listener: (info: InformationEvent) => void): this;
@ -1199,7 +1229,7 @@ declare module "http" {
prependOnceListener(event: "timeout", listener: () => void): this; prependOnceListener(event: "timeout", listener: () => void): this;
prependOnceListener( prependOnceListener(
event: "upgrade", event: "upgrade",
listener: (response: IncomingMessage, socket: Socket, head: Buffer) => void, listener: (response: IncomingMessage, socket: Socket, head: NonSharedBuffer) => void,
): this; ): this;
prependOnceListener(event: "close", listener: () => void): this; prependOnceListener(event: "close", listener: () => void): this;
prependOnceListener(event: "drain", listener: () => void): this; prependOnceListener(event: "drain", listener: () => void): this;

View file

@ -9,6 +9,7 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/http2.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/http2.js)
*/ */
declare module "http2" { declare module "http2" {
import { NonSharedBuffer } from "node:buffer";
import EventEmitter = require("node:events"); import EventEmitter = require("node:events");
import * as fs from "node:fs"; import * as fs from "node:fs";
import * as net from "node:net"; import * as net from "node:net";
@ -191,7 +192,7 @@ declare module "http2" {
sendTrailers(headers: OutgoingHttpHeaders): void; sendTrailers(headers: OutgoingHttpHeaders): void;
addListener(event: "aborted", listener: () => void): this; addListener(event: "aborted", listener: () => void): this;
addListener(event: "close", listener: () => void): this; addListener(event: "close", listener: () => void): this;
addListener(event: "data", listener: (chunk: Buffer | string) => void): this; addListener(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
addListener(event: "drain", listener: () => void): this; addListener(event: "drain", listener: () => void): this;
addListener(event: "end", listener: () => void): this; addListener(event: "end", listener: () => void): this;
addListener(event: "error", listener: (err: Error) => void): this; addListener(event: "error", listener: (err: Error) => void): this;
@ -206,7 +207,7 @@ declare module "http2" {
addListener(event: string | symbol, listener: (...args: any[]) => void): this; addListener(event: string | symbol, listener: (...args: any[]) => void): this;
emit(event: "aborted"): boolean; emit(event: "aborted"): boolean;
emit(event: "close"): boolean; emit(event: "close"): boolean;
emit(event: "data", chunk: Buffer | string): boolean; emit(event: "data", chunk: NonSharedBuffer | string): boolean;
emit(event: "drain"): boolean; emit(event: "drain"): boolean;
emit(event: "end"): boolean; emit(event: "end"): boolean;
emit(event: "error", err: Error): boolean; emit(event: "error", err: Error): boolean;
@ -221,7 +222,7 @@ declare module "http2" {
emit(event: string | symbol, ...args: any[]): boolean; emit(event: string | symbol, ...args: any[]): boolean;
on(event: "aborted", listener: () => void): this; on(event: "aborted", listener: () => void): this;
on(event: "close", listener: () => void): this; on(event: "close", listener: () => void): this;
on(event: "data", listener: (chunk: Buffer | string) => void): this; on(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
on(event: "drain", listener: () => void): this; on(event: "drain", listener: () => void): this;
on(event: "end", listener: () => void): this; on(event: "end", listener: () => void): this;
on(event: "error", listener: (err: Error) => void): this; on(event: "error", listener: (err: Error) => void): this;
@ -236,7 +237,7 @@ declare module "http2" {
on(event: string | symbol, listener: (...args: any[]) => void): this; on(event: string | symbol, listener: (...args: any[]) => void): this;
once(event: "aborted", listener: () => void): this; once(event: "aborted", listener: () => void): this;
once(event: "close", listener: () => void): this; once(event: "close", listener: () => void): this;
once(event: "data", listener: (chunk: Buffer | string) => void): this; once(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
once(event: "drain", listener: () => void): this; once(event: "drain", listener: () => void): this;
once(event: "end", listener: () => void): this; once(event: "end", listener: () => void): this;
once(event: "error", listener: (err: Error) => void): this; once(event: "error", listener: (err: Error) => void): this;
@ -251,7 +252,7 @@ declare module "http2" {
once(event: string | symbol, listener: (...args: any[]) => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this;
prependListener(event: "aborted", listener: () => void): this; prependListener(event: "aborted", listener: () => void): this;
prependListener(event: "close", listener: () => void): this; prependListener(event: "close", listener: () => void): this;
prependListener(event: "data", listener: (chunk: Buffer | string) => void): this; prependListener(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
prependListener(event: "drain", listener: () => void): this; prependListener(event: "drain", listener: () => void): this;
prependListener(event: "end", listener: () => void): this; prependListener(event: "end", listener: () => void): this;
prependListener(event: "error", listener: (err: Error) => void): this; prependListener(event: "error", listener: (err: Error) => void): this;
@ -266,7 +267,7 @@ declare module "http2" {
prependListener(event: string | symbol, listener: (...args: any[]) => void): this; prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
prependOnceListener(event: "aborted", listener: () => void): this; prependOnceListener(event: "aborted", listener: () => void): this;
prependOnceListener(event: "close", listener: () => void): this; prependOnceListener(event: "close", listener: () => void): this;
prependOnceListener(event: "data", listener: (chunk: Buffer | string) => void): this; prependOnceListener(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
prependOnceListener(event: "drain", listener: () => void): this; prependOnceListener(event: "drain", listener: () => void): this;
prependOnceListener(event: "end", listener: () => void): this; prependOnceListener(event: "end", listener: () => void): this;
prependOnceListener(event: "error", listener: (err: Error) => void): this; prependOnceListener(event: "error", listener: (err: Error) => void): this;
@ -284,61 +285,111 @@ declare module "http2" {
addListener(event: "continue", listener: () => {}): this; addListener(event: "continue", listener: () => {}): this;
addListener( addListener(
event: "headers", event: "headers",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
addListener(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this; addListener(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this;
addListener( addListener(
event: "response", event: "response",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
addListener(event: string | symbol, listener: (...args: any[]) => void): this; addListener(event: string | symbol, listener: (...args: any[]) => void): this;
emit(event: "continue"): boolean; emit(event: "continue"): boolean;
emit(event: "headers", headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number): boolean; emit(
event: "headers",
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
): boolean;
emit(event: "push", headers: IncomingHttpHeaders, flags: number): boolean; emit(event: "push", headers: IncomingHttpHeaders, flags: number): boolean;
emit(event: "response", headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number): boolean; emit(
event: "response",
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
): boolean;
emit(event: string | symbol, ...args: any[]): boolean; emit(event: string | symbol, ...args: any[]): boolean;
on(event: "continue", listener: () => {}): this; on(event: "continue", listener: () => {}): this;
on( on(
event: "headers", event: "headers",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
on(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this; on(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this;
on( on(
event: "response", event: "response",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
on(event: string | symbol, listener: (...args: any[]) => void): this; on(event: string | symbol, listener: (...args: any[]) => void): this;
once(event: "continue", listener: () => {}): this; once(event: "continue", listener: () => {}): this;
once( once(
event: "headers", event: "headers",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
once(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this; once(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this;
once( once(
event: "response", event: "response",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
once(event: string | symbol, listener: (...args: any[]) => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this;
prependListener(event: "continue", listener: () => {}): this; prependListener(event: "continue", listener: () => {}): this;
prependListener( prependListener(
event: "headers", event: "headers",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
prependListener(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this; prependListener(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this;
prependListener( prependListener(
event: "response", event: "response",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
prependListener(event: string | symbol, listener: (...args: any[]) => void): this; prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
prependOnceListener(event: "continue", listener: () => {}): this; prependOnceListener(event: "continue", listener: () => {}): this;
prependOnceListener( prependOnceListener(
event: "headers", event: "headers",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
prependOnceListener(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this; prependOnceListener(event: "push", listener: (headers: IncomingHttpHeaders, flags: number) => void): this;
prependOnceListener( prependOnceListener(
event: "response", event: "response",
listener: (headers: IncomingHttpHeaders & IncomingHttpStatusHeader, flags: number) => void, listener: (
headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this; prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
} }
@ -784,10 +835,10 @@ declare module "http2" {
* @since v8.9.3 * @since v8.9.3
* @param payload Optional ping payload. * @param payload Optional ping payload.
*/ */
ping(callback: (err: Error | null, duration: number, payload: Buffer) => void): boolean; ping(callback: (err: Error | null, duration: number, payload: NonSharedBuffer) => void): boolean;
ping( ping(
payload: NodeJS.ArrayBufferView, payload: NodeJS.ArrayBufferView,
callback: (err: Error | null, duration: number, payload: Buffer) => void, callback: (err: Error | null, duration: number, payload: NonSharedBuffer) => void,
): boolean; ): boolean;
/** /**
* Calls `ref()` on this `Http2Session` instance's underlying `net.Socket`. * Calls `ref()` on this `Http2Session` instance's underlying `net.Socket`.
@ -849,7 +900,7 @@ declare module "http2" {
): this; ): this;
addListener( addListener(
event: "goaway", event: "goaway",
listener: (errorCode: number, lastStreamID: number, opaqueData?: Buffer) => void, listener: (errorCode: number, lastStreamID: number, opaqueData?: NonSharedBuffer) => void,
): this; ): this;
addListener(event: "localSettings", listener: (settings: Settings) => void): this; addListener(event: "localSettings", listener: (settings: Settings) => void): this;
addListener(event: "ping", listener: () => void): this; addListener(event: "ping", listener: () => void): this;
@ -859,7 +910,7 @@ declare module "http2" {
emit(event: "close"): boolean; emit(event: "close"): boolean;
emit(event: "error", err: Error): boolean; emit(event: "error", err: Error): boolean;
emit(event: "frameError", frameType: number, errorCode: number, streamID: number): boolean; emit(event: "frameError", frameType: number, errorCode: number, streamID: number): boolean;
emit(event: "goaway", errorCode: number, lastStreamID: number, opaqueData?: Buffer): boolean; emit(event: "goaway", errorCode: number, lastStreamID: number, opaqueData?: NonSharedBuffer): boolean;
emit(event: "localSettings", settings: Settings): boolean; emit(event: "localSettings", settings: Settings): boolean;
emit(event: "ping"): boolean; emit(event: "ping"): boolean;
emit(event: "remoteSettings", settings: Settings): boolean; emit(event: "remoteSettings", settings: Settings): boolean;
@ -868,7 +919,10 @@ declare module "http2" {
on(event: "close", listener: () => void): this; on(event: "close", listener: () => void): this;
on(event: "error", listener: (err: Error) => void): this; on(event: "error", listener: (err: Error) => void): this;
on(event: "frameError", listener: (frameType: number, errorCode: number, streamID: number) => void): this; on(event: "frameError", listener: (frameType: number, errorCode: number, streamID: number) => void): this;
on(event: "goaway", listener: (errorCode: number, lastStreamID: number, opaqueData?: Buffer) => void): this; on(
event: "goaway",
listener: (errorCode: number, lastStreamID: number, opaqueData?: NonSharedBuffer) => void,
): this;
on(event: "localSettings", listener: (settings: Settings) => void): this; on(event: "localSettings", listener: (settings: Settings) => void): this;
on(event: "ping", listener: () => void): this; on(event: "ping", listener: () => void): this;
on(event: "remoteSettings", listener: (settings: Settings) => void): this; on(event: "remoteSettings", listener: (settings: Settings) => void): this;
@ -877,7 +931,10 @@ declare module "http2" {
once(event: "close", listener: () => void): this; once(event: "close", listener: () => void): this;
once(event: "error", listener: (err: Error) => void): this; once(event: "error", listener: (err: Error) => void): this;
once(event: "frameError", listener: (frameType: number, errorCode: number, streamID: number) => void): this; once(event: "frameError", listener: (frameType: number, errorCode: number, streamID: number) => void): this;
once(event: "goaway", listener: (errorCode: number, lastStreamID: number, opaqueData?: Buffer) => void): this; once(
event: "goaway",
listener: (errorCode: number, lastStreamID: number, opaqueData?: NonSharedBuffer) => void,
): this;
once(event: "localSettings", listener: (settings: Settings) => void): this; once(event: "localSettings", listener: (settings: Settings) => void): this;
once(event: "ping", listener: () => void): this; once(event: "ping", listener: () => void): this;
once(event: "remoteSettings", listener: (settings: Settings) => void): this; once(event: "remoteSettings", listener: (settings: Settings) => void): this;
@ -891,7 +948,7 @@ declare module "http2" {
): this; ): this;
prependListener( prependListener(
event: "goaway", event: "goaway",
listener: (errorCode: number, lastStreamID: number, opaqueData?: Buffer) => void, listener: (errorCode: number, lastStreamID: number, opaqueData?: NonSharedBuffer) => void,
): this; ): this;
prependListener(event: "localSettings", listener: (settings: Settings) => void): this; prependListener(event: "localSettings", listener: (settings: Settings) => void): this;
prependListener(event: "ping", listener: () => void): this; prependListener(event: "ping", listener: () => void): this;
@ -906,7 +963,7 @@ declare module "http2" {
): this; ): this;
prependOnceListener( prependOnceListener(
event: "goaway", event: "goaway",
listener: (errorCode: number, lastStreamID: number, opaqueData?: Buffer) => void, listener: (errorCode: number, lastStreamID: number, opaqueData?: NonSharedBuffer) => void,
): this; ): this;
prependOnceListener(event: "localSettings", listener: (settings: Settings) => void): this; prependOnceListener(event: "localSettings", listener: (settings: Settings) => void): this;
prependOnceListener(event: "ping", listener: () => void): this; prependOnceListener(event: "ping", listener: () => void): this;
@ -976,6 +1033,7 @@ declare module "http2" {
stream: ClientHttp2Stream, stream: ClientHttp2Stream,
headers: IncomingHttpHeaders & IncomingHttpStatusHeader, headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number, flags: number,
rawHeaders: string[],
) => void, ) => void,
): this; ): this;
addListener(event: string | symbol, listener: (...args: any[]) => void): this; addListener(event: string | symbol, listener: (...args: any[]) => void): this;
@ -987,6 +1045,7 @@ declare module "http2" {
stream: ClientHttp2Stream, stream: ClientHttp2Stream,
headers: IncomingHttpHeaders & IncomingHttpStatusHeader, headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number, flags: number,
rawHeaders: string[],
): boolean; ): boolean;
emit(event: string | symbol, ...args: any[]): boolean; emit(event: string | symbol, ...args: any[]): boolean;
on(event: "altsvc", listener: (alt: string, origin: string, stream: number) => void): this; on(event: "altsvc", listener: (alt: string, origin: string, stream: number) => void): this;
@ -998,6 +1057,7 @@ declare module "http2" {
stream: ClientHttp2Stream, stream: ClientHttp2Stream,
headers: IncomingHttpHeaders & IncomingHttpStatusHeader, headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number, flags: number,
rawHeaders: string[],
) => void, ) => void,
): this; ): this;
on(event: string | symbol, listener: (...args: any[]) => void): this; on(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1013,6 +1073,7 @@ declare module "http2" {
stream: ClientHttp2Stream, stream: ClientHttp2Stream,
headers: IncomingHttpHeaders & IncomingHttpStatusHeader, headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number, flags: number,
rawHeaders: string[],
) => void, ) => void,
): this; ): this;
once(event: string | symbol, listener: (...args: any[]) => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1028,6 +1089,7 @@ declare module "http2" {
stream: ClientHttp2Stream, stream: ClientHttp2Stream,
headers: IncomingHttpHeaders & IncomingHttpStatusHeader, headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number, flags: number,
rawHeaders: string[],
) => void, ) => void,
): this; ): this;
prependListener(event: string | symbol, listener: (...args: any[]) => void): this; prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1043,6 +1105,7 @@ declare module "http2" {
stream: ClientHttp2Stream, stream: ClientHttp2Stream,
headers: IncomingHttpHeaders & IncomingHttpStatusHeader, headers: IncomingHttpHeaders & IncomingHttpStatusHeader,
flags: number, flags: number,
rawHeaders: string[],
) => void, ) => void,
): this; ): this;
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this; prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1160,7 +1223,12 @@ declare module "http2" {
): this; ): this;
addListener( addListener(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
addListener(event: string | symbol, listener: (...args: any[]) => void): this; addListener(event: string | symbol, listener: (...args: any[]) => void): this;
emit( emit(
@ -1168,7 +1236,13 @@ declare module "http2" {
session: ServerHttp2Session<Http1Request, Http1Response, Http2Request, Http2Response>, session: ServerHttp2Session<Http1Request, Http1Response, Http2Request, Http2Response>,
socket: net.Socket | tls.TLSSocket, socket: net.Socket | tls.TLSSocket,
): boolean; ): boolean;
emit(event: "stream", stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number): boolean; emit(
event: "stream",
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
): boolean;
emit(event: string | symbol, ...args: any[]): boolean; emit(event: string | symbol, ...args: any[]): boolean;
on( on(
event: "connect", event: "connect",
@ -1179,7 +1253,12 @@ declare module "http2" {
): this; ): this;
on( on(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
on(event: string | symbol, listener: (...args: any[]) => void): this; on(event: string | symbol, listener: (...args: any[]) => void): this;
once( once(
@ -1191,7 +1270,12 @@ declare module "http2" {
): this; ): this;
once( once(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
once(event: string | symbol, listener: (...args: any[]) => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this;
prependListener( prependListener(
@ -1203,7 +1287,12 @@ declare module "http2" {
): this; ): this;
prependListener( prependListener(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
prependListener(event: string | symbol, listener: (...args: any[]) => void): this; prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
prependOnceListener( prependOnceListener(
@ -1215,7 +1304,12 @@ declare module "http2" {
): this; ): this;
prependOnceListener( prependOnceListener(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this; prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
} }
@ -1384,7 +1478,12 @@ declare module "http2" {
addListener(event: "sessionError", listener: (err: Error) => void): this; addListener(event: "sessionError", listener: (err: Error) => void): this;
addListener( addListener(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
addListener(event: "timeout", listener: () => void): this; addListener(event: "timeout", listener: () => void): this;
addListener(event: string | symbol, listener: (...args: any[]) => void): this; addListener(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1399,7 +1498,13 @@ declare module "http2" {
session: ServerHttp2Session<Http1Request, Http1Response, Http2Request, Http2Response>, session: ServerHttp2Session<Http1Request, Http1Response, Http2Request, Http2Response>,
): boolean; ): boolean;
emit(event: "sessionError", err: Error): boolean; emit(event: "sessionError", err: Error): boolean;
emit(event: "stream", stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number): boolean; emit(
event: "stream",
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
): boolean;
emit(event: "timeout"): boolean; emit(event: "timeout"): boolean;
emit(event: string | symbol, ...args: any[]): boolean; emit(event: string | symbol, ...args: any[]): boolean;
on( on(
@ -1417,7 +1522,12 @@ declare module "http2" {
on(event: "sessionError", listener: (err: Error) => void): this; on(event: "sessionError", listener: (err: Error) => void): this;
on( on(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
on(event: "timeout", listener: () => void): this; on(event: "timeout", listener: () => void): this;
on(event: string | symbol, listener: (...args: any[]) => void): this; on(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1436,7 +1546,12 @@ declare module "http2" {
once(event: "sessionError", listener: (err: Error) => void): this; once(event: "sessionError", listener: (err: Error) => void): this;
once( once(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
once(event: "timeout", listener: () => void): this; once(event: "timeout", listener: () => void): this;
once(event: string | symbol, listener: (...args: any[]) => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1455,7 +1570,12 @@ declare module "http2" {
prependListener(event: "sessionError", listener: (err: Error) => void): this; prependListener(event: "sessionError", listener: (err: Error) => void): this;
prependListener( prependListener(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
prependListener(event: "timeout", listener: () => void): this; prependListener(event: "timeout", listener: () => void): this;
prependListener(event: string | symbol, listener: (...args: any[]) => void): this; prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1474,7 +1594,12 @@ declare module "http2" {
prependOnceListener(event: "sessionError", listener: (err: Error) => void): this; prependOnceListener(event: "sessionError", listener: (err: Error) => void): this;
prependOnceListener( prependOnceListener(
event: "stream", event: "stream",
listener: (stream: ServerHttp2Stream, headers: IncomingHttpHeaders, flags: number) => void, listener: (
stream: ServerHttp2Stream,
headers: IncomingHttpHeaders,
flags: number,
rawHeaders: string[],
) => void,
): this; ): this;
prependOnceListener(event: "timeout", listener: () => void): this; prependOnceListener(event: "timeout", listener: () => void): this;
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this; prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
@ -1798,45 +1923,45 @@ declare module "http2" {
* @since v8.4.0 * @since v8.4.0
*/ */
setTimeout(msecs: number, callback?: () => void): void; setTimeout(msecs: number, callback?: () => void): void;
read(size?: number): Buffer | string | null; read(size?: number): NonSharedBuffer | string | null;
addListener(event: "aborted", listener: (hadError: boolean, code: number) => void): this; addListener(event: "aborted", listener: (hadError: boolean, code: number) => void): this;
addListener(event: "close", listener: () => void): this; addListener(event: "close", listener: () => void): this;
addListener(event: "data", listener: (chunk: Buffer | string) => void): this; addListener(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
addListener(event: "end", listener: () => void): this; addListener(event: "end", listener: () => void): this;
addListener(event: "readable", listener: () => void): this; addListener(event: "readable", listener: () => void): this;
addListener(event: "error", listener: (err: Error) => void): this; addListener(event: "error", listener: (err: Error) => void): this;
addListener(event: string | symbol, listener: (...args: any[]) => void): this; addListener(event: string | symbol, listener: (...args: any[]) => void): this;
emit(event: "aborted", hadError: boolean, code: number): boolean; emit(event: "aborted", hadError: boolean, code: number): boolean;
emit(event: "close"): boolean; emit(event: "close"): boolean;
emit(event: "data", chunk: Buffer | string): boolean; emit(event: "data", chunk: NonSharedBuffer | string): boolean;
emit(event: "end"): boolean; emit(event: "end"): boolean;
emit(event: "readable"): boolean; emit(event: "readable"): boolean;
emit(event: "error", err: Error): boolean; emit(event: "error", err: Error): boolean;
emit(event: string | symbol, ...args: any[]): boolean; emit(event: string | symbol, ...args: any[]): boolean;
on(event: "aborted", listener: (hadError: boolean, code: number) => void): this; on(event: "aborted", listener: (hadError: boolean, code: number) => void): this;
on(event: "close", listener: () => void): this; on(event: "close", listener: () => void): this;
on(event: "data", listener: (chunk: Buffer | string) => void): this; on(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
on(event: "end", listener: () => void): this; on(event: "end", listener: () => void): this;
on(event: "readable", listener: () => void): this; on(event: "readable", listener: () => void): this;
on(event: "error", listener: (err: Error) => void): this; on(event: "error", listener: (err: Error) => void): this;
on(event: string | symbol, listener: (...args: any[]) => void): this; on(event: string | symbol, listener: (...args: any[]) => void): this;
once(event: "aborted", listener: (hadError: boolean, code: number) => void): this; once(event: "aborted", listener: (hadError: boolean, code: number) => void): this;
once(event: "close", listener: () => void): this; once(event: "close", listener: () => void): this;
once(event: "data", listener: (chunk: Buffer | string) => void): this; once(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
once(event: "end", listener: () => void): this; once(event: "end", listener: () => void): this;
once(event: "readable", listener: () => void): this; once(event: "readable", listener: () => void): this;
once(event: "error", listener: (err: Error) => void): this; once(event: "error", listener: (err: Error) => void): this;
once(event: string | symbol, listener: (...args: any[]) => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this;
prependListener(event: "aborted", listener: (hadError: boolean, code: number) => void): this; prependListener(event: "aborted", listener: (hadError: boolean, code: number) => void): this;
prependListener(event: "close", listener: () => void): this; prependListener(event: "close", listener: () => void): this;
prependListener(event: "data", listener: (chunk: Buffer | string) => void): this; prependListener(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
prependListener(event: "end", listener: () => void): this; prependListener(event: "end", listener: () => void): this;
prependListener(event: "readable", listener: () => void): this; prependListener(event: "readable", listener: () => void): this;
prependListener(event: "error", listener: (err: Error) => void): this; prependListener(event: "error", listener: (err: Error) => void): this;
prependListener(event: string | symbol, listener: (...args: any[]) => void): this; prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
prependOnceListener(event: "aborted", listener: (hadError: boolean, code: number) => void): this; prependOnceListener(event: "aborted", listener: (hadError: boolean, code: number) => void): this;
prependOnceListener(event: "close", listener: () => void): this; prependOnceListener(event: "close", listener: () => void): this;
prependOnceListener(event: "data", listener: (chunk: Buffer | string) => void): this; prependOnceListener(event: "data", listener: (chunk: NonSharedBuffer | string) => void): this;
prependOnceListener(event: "end", listener: () => void): this; prependOnceListener(event: "end", listener: () => void): this;
prependOnceListener(event: "readable", listener: () => void): this; prependOnceListener(event: "readable", listener: () => void): this;
prependOnceListener(event: "error", listener: (err: Error) => void): this; prependOnceListener(event: "error", listener: (err: Error) => void): this;
@ -2195,8 +2320,8 @@ declare module "http2" {
* will result in a `TypeError` being thrown. * will result in a `TypeError` being thrown.
* @since v8.4.0 * @since v8.4.0
*/ */
writeHead(statusCode: number, headers?: OutgoingHttpHeaders): this; writeHead(statusCode: number, headers?: OutgoingHttpHeaders | readonly string[]): this;
writeHead(statusCode: number, statusMessage: string, headers?: OutgoingHttpHeaders): this; writeHead(statusCode: number, statusMessage: string, headers?: OutgoingHttpHeaders | readonly string[]): this;
/** /**
* Call `http2stream.pushStream()` with the given headers, and wrap the * Call `http2stream.pushStream()` with the given headers, and wrap the
* given `Http2Stream` on a newly created `Http2ServerResponse` as the callback * given `Http2Stream` on a newly created `Http2ServerResponse` as the callback
@ -2496,7 +2621,7 @@ declare module "http2" {
* ``` * ```
* @since v8.4.0 * @since v8.4.0
*/ */
export function getPackedSettings(settings: Settings): Buffer; export function getPackedSettings(settings: Settings): NonSharedBuffer;
/** /**
* Returns a `HTTP/2 Settings Object` containing the deserialized settings from * Returns a `HTTP/2 Settings Object` containing the deserialized settings from
* the given `Buffer` as generated by `http2.getPackedSettings()`. * the given `Buffer` as generated by `http2.getPackedSettings()`.

View file

@ -4,6 +4,7 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/https.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/https.js)
*/ */
declare module "https" { declare module "https" {
import { NonSharedBuffer } from "node:buffer";
import { Duplex } from "node:stream"; import { Duplex } from "node:stream";
import * as tls from "node:tls"; import * as tls from "node:tls";
import * as http from "node:http"; import * as http from "node:http";
@ -63,22 +64,25 @@ declare module "https" {
*/ */
closeIdleConnections(): void; closeIdleConnections(): void;
addListener(event: string, listener: (...args: any[]) => void): this; addListener(event: string, listener: (...args: any[]) => void): this;
addListener(event: "keylog", listener: (line: Buffer, tlsSocket: tls.TLSSocket) => void): this; addListener(event: "keylog", listener: (line: NonSharedBuffer, tlsSocket: tls.TLSSocket) => void): this;
addListener( addListener(
event: "newSession", event: "newSession",
listener: (sessionId: Buffer, sessionData: Buffer, callback: (err: Error, resp: Buffer) => void) => void, listener: (sessionId: NonSharedBuffer, sessionData: NonSharedBuffer, callback: () => void) => void,
): this; ): this;
addListener( addListener(
event: "OCSPRequest", event: "OCSPRequest",
listener: ( listener: (
certificate: Buffer, certificate: NonSharedBuffer,
issuer: Buffer, issuer: NonSharedBuffer,
callback: (err: Error | null, resp: Buffer) => void, callback: (err: Error | null, resp: Buffer | null) => void,
) => void, ) => void,
): this; ): this;
addListener( addListener(
event: "resumeSession", event: "resumeSession",
listener: (sessionId: Buffer, callback: (err: Error, sessionData: Buffer) => void) => void, listener: (
sessionId: NonSharedBuffer,
callback: (err: Error | null, sessionData: Buffer | null) => void,
) => void,
): this; ): this;
addListener(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this; addListener(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this;
addListener(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this; addListener(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this;
@ -91,28 +95,32 @@ declare module "https" {
addListener(event: "clientError", listener: (err: Error, socket: Duplex) => void): this; addListener(event: "clientError", listener: (err: Error, socket: Duplex) => void): this;
addListener( addListener(
event: "connect", event: "connect",
listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this; ): this;
addListener(event: "request", listener: http.RequestListener<Request, Response>): this; addListener(event: "request", listener: http.RequestListener<Request, Response>): this;
addListener( addListener(
event: "upgrade", event: "upgrade",
listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this; ): this;
emit(event: string, ...args: any[]): boolean; emit(event: string, ...args: any[]): boolean;
emit(event: "keylog", line: Buffer, tlsSocket: tls.TLSSocket): boolean; emit(event: "keylog", line: NonSharedBuffer, tlsSocket: tls.TLSSocket): boolean;
emit( emit(
event: "newSession", event: "newSession",
sessionId: Buffer, sessionId: NonSharedBuffer,
sessionData: Buffer, sessionData: NonSharedBuffer,
callback: (err: Error, resp: Buffer) => void, callback: () => void,
): boolean; ): boolean;
emit( emit(
event: "OCSPRequest", event: "OCSPRequest",
certificate: Buffer, certificate: NonSharedBuffer,
issuer: Buffer, issuer: NonSharedBuffer,
callback: (err: Error | null, resp: Buffer) => void, callback: (err: Error | null, resp: Buffer | null) => void,
): boolean;
emit(
event: "resumeSession",
sessionId: NonSharedBuffer,
callback: (err: Error | null, sessionData: Buffer | null) => void,
): boolean; ): boolean;
emit(event: "resumeSession", sessionId: Buffer, callback: (err: Error, sessionData: Buffer) => void): boolean;
emit(event: "secureConnection", tlsSocket: tls.TLSSocket): boolean; emit(event: "secureConnection", tlsSocket: tls.TLSSocket): boolean;
emit(event: "tlsClientError", err: Error, tlsSocket: tls.TLSSocket): boolean; emit(event: "tlsClientError", err: Error, tlsSocket: tls.TLSSocket): boolean;
emit(event: "close"): boolean; emit(event: "close"): boolean;
@ -130,30 +138,33 @@ declare module "https" {
res: InstanceType<Response>, res: InstanceType<Response>,
): boolean; ): boolean;
emit(event: "clientError", err: Error, socket: Duplex): boolean; emit(event: "clientError", err: Error, socket: Duplex): boolean;
emit(event: "connect", req: InstanceType<Request>, socket: Duplex, head: Buffer): boolean; emit(event: "connect", req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer): boolean;
emit( emit(
event: "request", event: "request",
req: InstanceType<Request>, req: InstanceType<Request>,
res: InstanceType<Response>, res: InstanceType<Response>,
): boolean; ): boolean;
emit(event: "upgrade", req: InstanceType<Request>, socket: Duplex, head: Buffer): boolean; emit(event: "upgrade", req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer): boolean;
on(event: string, listener: (...args: any[]) => void): this; on(event: string, listener: (...args: any[]) => void): this;
on(event: "keylog", listener: (line: Buffer, tlsSocket: tls.TLSSocket) => void): this; on(event: "keylog", listener: (line: NonSharedBuffer, tlsSocket: tls.TLSSocket) => void): this;
on( on(
event: "newSession", event: "newSession",
listener: (sessionId: Buffer, sessionData: Buffer, callback: (err: Error, resp: Buffer) => void) => void, listener: (sessionId: NonSharedBuffer, sessionData: NonSharedBuffer, callback: () => void) => void,
): this; ): this;
on( on(
event: "OCSPRequest", event: "OCSPRequest",
listener: ( listener: (
certificate: Buffer, certificate: NonSharedBuffer,
issuer: Buffer, issuer: NonSharedBuffer,
callback: (err: Error | null, resp: Buffer) => void, callback: (err: Error | null, resp: Buffer | null) => void,
) => void, ) => void,
): this; ): this;
on( on(
event: "resumeSession", event: "resumeSession",
listener: (sessionId: Buffer, callback: (err: Error, sessionData: Buffer) => void) => void, listener: (
sessionId: NonSharedBuffer,
callback: (err: Error | null, sessionData: Buffer | null) => void,
) => void,
): this; ): this;
on(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this; on(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this;
on(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this; on(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this;
@ -164,26 +175,35 @@ declare module "https" {
on(event: "checkContinue", listener: http.RequestListener<Request, Response>): this; on(event: "checkContinue", listener: http.RequestListener<Request, Response>): this;
on(event: "checkExpectation", listener: http.RequestListener<Request, Response>): this; on(event: "checkExpectation", listener: http.RequestListener<Request, Response>): this;
on(event: "clientError", listener: (err: Error, socket: Duplex) => void): this; on(event: "clientError", listener: (err: Error, socket: Duplex) => void): this;
on(event: "connect", listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void): this; on(
event: "connect",
listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this;
on(event: "request", listener: http.RequestListener<Request, Response>): this; on(event: "request", listener: http.RequestListener<Request, Response>): this;
on(event: "upgrade", listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void): this; on(
event: "upgrade",
listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this;
once(event: string, listener: (...args: any[]) => void): this; once(event: string, listener: (...args: any[]) => void): this;
once(event: "keylog", listener: (line: Buffer, tlsSocket: tls.TLSSocket) => void): this; once(event: "keylog", listener: (line: NonSharedBuffer, tlsSocket: tls.TLSSocket) => void): this;
once( once(
event: "newSession", event: "newSession",
listener: (sessionId: Buffer, sessionData: Buffer, callback: (err: Error, resp: Buffer) => void) => void, listener: (sessionId: NonSharedBuffer, sessionData: NonSharedBuffer, callback: () => void) => void,
): this; ): this;
once( once(
event: "OCSPRequest", event: "OCSPRequest",
listener: ( listener: (
certificate: Buffer, certificate: NonSharedBuffer,
issuer: Buffer, issuer: NonSharedBuffer,
callback: (err: Error | null, resp: Buffer) => void, callback: (err: Error | null, resp: Buffer | null) => void,
) => void, ) => void,
): this; ): this;
once( once(
event: "resumeSession", event: "resumeSession",
listener: (sessionId: Buffer, callback: (err: Error, sessionData: Buffer) => void) => void, listener: (
sessionId: NonSharedBuffer,
callback: (err: Error | null, sessionData: Buffer | null) => void,
) => void,
): this; ): this;
once(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this; once(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this;
once(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this; once(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this;
@ -194,26 +214,35 @@ declare module "https" {
once(event: "checkContinue", listener: http.RequestListener<Request, Response>): this; once(event: "checkContinue", listener: http.RequestListener<Request, Response>): this;
once(event: "checkExpectation", listener: http.RequestListener<Request, Response>): this; once(event: "checkExpectation", listener: http.RequestListener<Request, Response>): this;
once(event: "clientError", listener: (err: Error, socket: Duplex) => void): this; once(event: "clientError", listener: (err: Error, socket: Duplex) => void): this;
once(event: "connect", listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void): this; once(
event: "connect",
listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this;
once(event: "request", listener: http.RequestListener<Request, Response>): this; once(event: "request", listener: http.RequestListener<Request, Response>): this;
once(event: "upgrade", listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void): this; once(
event: "upgrade",
listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this;
prependListener(event: string, listener: (...args: any[]) => void): this; prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(event: "keylog", listener: (line: Buffer, tlsSocket: tls.TLSSocket) => void): this; prependListener(event: "keylog", listener: (line: NonSharedBuffer, tlsSocket: tls.TLSSocket) => void): this;
prependListener( prependListener(
event: "newSession", event: "newSession",
listener: (sessionId: Buffer, sessionData: Buffer, callback: (err: Error, resp: Buffer) => void) => void, listener: (sessionId: NonSharedBuffer, sessionData: NonSharedBuffer, callback: () => void) => void,
): this; ): this;
prependListener( prependListener(
event: "OCSPRequest", event: "OCSPRequest",
listener: ( listener: (
certificate: Buffer, certificate: NonSharedBuffer,
issuer: Buffer, issuer: NonSharedBuffer,
callback: (err: Error | null, resp: Buffer) => void, callback: (err: Error | null, resp: Buffer | null) => void,
) => void, ) => void,
): this; ): this;
prependListener( prependListener(
event: "resumeSession", event: "resumeSession",
listener: (sessionId: Buffer, callback: (err: Error, sessionData: Buffer) => void) => void, listener: (
sessionId: NonSharedBuffer,
callback: (err: Error | null, sessionData: Buffer | null) => void,
) => void,
): this; ): this;
prependListener(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this; prependListener(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this;
prependListener(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this; prependListener(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this;
@ -226,30 +255,33 @@ declare module "https" {
prependListener(event: "clientError", listener: (err: Error, socket: Duplex) => void): this; prependListener(event: "clientError", listener: (err: Error, socket: Duplex) => void): this;
prependListener( prependListener(
event: "connect", event: "connect",
listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this; ): this;
prependListener(event: "request", listener: http.RequestListener<Request, Response>): this; prependListener(event: "request", listener: http.RequestListener<Request, Response>): this;
prependListener( prependListener(
event: "upgrade", event: "upgrade",
listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this; ): this;
prependOnceListener(event: string, listener: (...args: any[]) => void): this; prependOnceListener(event: string, listener: (...args: any[]) => void): this;
prependOnceListener(event: "keylog", listener: (line: Buffer, tlsSocket: tls.TLSSocket) => void): this; prependOnceListener(event: "keylog", listener: (line: NonSharedBuffer, tlsSocket: tls.TLSSocket) => void): this;
prependOnceListener( prependOnceListener(
event: "newSession", event: "newSession",
listener: (sessionId: Buffer, sessionData: Buffer, callback: (err: Error, resp: Buffer) => void) => void, listener: (sessionId: NonSharedBuffer, sessionData: NonSharedBuffer, callback: () => void) => void,
): this; ): this;
prependOnceListener( prependOnceListener(
event: "OCSPRequest", event: "OCSPRequest",
listener: ( listener: (
certificate: Buffer, certificate: NonSharedBuffer,
issuer: Buffer, issuer: NonSharedBuffer,
callback: (err: Error | null, resp: Buffer) => void, callback: (err: Error | null, resp: Buffer | null) => void,
) => void, ) => void,
): this; ): this;
prependOnceListener( prependOnceListener(
event: "resumeSession", event: "resumeSession",
listener: (sessionId: Buffer, callback: (err: Error, sessionData: Buffer) => void) => void, listener: (
sessionId: NonSharedBuffer,
callback: (err: Error | null, sessionData: Buffer | null) => void,
) => void,
): this; ): this;
prependOnceListener(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this; prependOnceListener(event: "secureConnection", listener: (tlsSocket: tls.TLSSocket) => void): this;
prependOnceListener(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this; prependOnceListener(event: "tlsClientError", listener: (err: Error, tlsSocket: tls.TLSSocket) => void): this;
@ -262,12 +294,12 @@ declare module "https" {
prependOnceListener(event: "clientError", listener: (err: Error, socket: Duplex) => void): this; prependOnceListener(event: "clientError", listener: (err: Error, socket: Duplex) => void): this;
prependOnceListener( prependOnceListener(
event: "connect", event: "connect",
listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this; ): this;
prependOnceListener(event: "request", listener: http.RequestListener<Request, Response>): this; prependOnceListener(event: "request", listener: http.RequestListener<Request, Response>): this;
prependOnceListener( prependOnceListener(
event: "upgrade", event: "upgrade",
listener: (req: InstanceType<Request>, socket: Duplex, head: Buffer) => void, listener: (req: InstanceType<Request>, socket: Duplex, head: NonSharedBuffer) => void,
): this; ): this;
} }
/** /**

View file

@ -13,6 +13,7 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/net.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/net.js)
*/ */
declare module "net" { declare module "net" {
import { NonSharedBuffer } from "node:buffer";
import * as stream from "node:stream"; import * as stream from "node:stream";
import { Abortable, EventEmitter } from "node:events"; import { Abortable, EventEmitter } from "node:events";
import * as dns from "node:dns"; import * as dns from "node:dns";
@ -380,7 +381,7 @@ declare module "net" {
event: "connectionAttemptTimeout", event: "connectionAttemptTimeout",
listener: (ip: string, port: number, family: number) => void, listener: (ip: string, port: number, family: number) => void,
): this; ): this;
addListener(event: "data", listener: (data: Buffer) => void): this; addListener(event: "data", listener: (data: NonSharedBuffer) => void): this;
addListener(event: "drain", listener: () => void): this; addListener(event: "drain", listener: () => void): this;
addListener(event: "end", listener: () => void): this; addListener(event: "end", listener: () => void): this;
addListener(event: "error", listener: (err: Error) => void): this; addListener(event: "error", listener: (err: Error) => void): this;
@ -396,7 +397,7 @@ declare module "net" {
emit(event: "connectionAttempt", ip: string, port: number, family: number): boolean; emit(event: "connectionAttempt", ip: string, port: number, family: number): boolean;
emit(event: "connectionAttemptFailed", ip: string, port: number, family: number, error: Error): boolean; emit(event: "connectionAttemptFailed", ip: string, port: number, family: number, error: Error): boolean;
emit(event: "connectionAttemptTimeout", ip: string, port: number, family: number): boolean; emit(event: "connectionAttemptTimeout", ip: string, port: number, family: number): boolean;
emit(event: "data", data: Buffer): boolean; emit(event: "data", data: NonSharedBuffer): boolean;
emit(event: "drain"): boolean; emit(event: "drain"): boolean;
emit(event: "end"): boolean; emit(event: "end"): boolean;
emit(event: "error", err: Error): boolean; emit(event: "error", err: Error): boolean;
@ -412,7 +413,7 @@ declare module "net" {
listener: (ip: string, port: number, family: number, error: Error) => void, listener: (ip: string, port: number, family: number, error: Error) => void,
): this; ): this;
on(event: "connectionAttemptTimeout", listener: (ip: string, port: number, family: number) => void): this; on(event: "connectionAttemptTimeout", listener: (ip: string, port: number, family: number) => void): this;
on(event: "data", listener: (data: Buffer) => void): this; on(event: "data", listener: (data: NonSharedBuffer) => void): this;
on(event: "drain", listener: () => void): this; on(event: "drain", listener: () => void): this;
on(event: "end", listener: () => void): this; on(event: "end", listener: () => void): this;
on(event: "error", listener: (err: Error) => void): this; on(event: "error", listener: (err: Error) => void): this;
@ -431,7 +432,7 @@ declare module "net" {
): this; ): this;
once(event: "connectionAttemptTimeout", listener: (ip: string, port: number, family: number) => void): this; once(event: "connectionAttemptTimeout", listener: (ip: string, port: number, family: number) => void): this;
once(event: "connect", listener: () => void): this; once(event: "connect", listener: () => void): this;
once(event: "data", listener: (data: Buffer) => void): this; once(event: "data", listener: (data: NonSharedBuffer) => void): this;
once(event: "drain", listener: () => void): this; once(event: "drain", listener: () => void): this;
once(event: "end", listener: () => void): this; once(event: "end", listener: () => void): this;
once(event: "error", listener: (err: Error) => void): this; once(event: "error", listener: (err: Error) => void): this;
@ -453,7 +454,7 @@ declare module "net" {
event: "connectionAttemptTimeout", event: "connectionAttemptTimeout",
listener: (ip: string, port: number, family: number) => void, listener: (ip: string, port: number, family: number) => void,
): this; ): this;
prependListener(event: "data", listener: (data: Buffer) => void): this; prependListener(event: "data", listener: (data: NonSharedBuffer) => void): this;
prependListener(event: "drain", listener: () => void): this; prependListener(event: "drain", listener: () => void): this;
prependListener(event: "end", listener: () => void): this; prependListener(event: "end", listener: () => void): this;
prependListener(event: "error", listener: (err: Error) => void): this; prependListener(event: "error", listener: (err: Error) => void): this;
@ -478,7 +479,7 @@ declare module "net" {
event: "connectionAttemptTimeout", event: "connectionAttemptTimeout",
listener: (ip: string, port: number, family: number) => void, listener: (ip: string, port: number, family: number) => void,
): this; ): this;
prependOnceListener(event: "data", listener: (data: Buffer) => void): this; prependOnceListener(event: "data", listener: (data: NonSharedBuffer) => void): this;
prependOnceListener(event: "drain", listener: () => void): this; prependOnceListener(event: "drain", listener: () => void): this;
prependOnceListener(event: "end", listener: () => void): this; prependOnceListener(event: "end", listener: () => void): this;
prependOnceListener(event: "error", listener: (err: Error) => void): this; prependOnceListener(event: "error", listener: (err: Error) => void): this;

View file

@ -8,6 +8,7 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/os.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/os.js)
*/ */
declare module "os" { declare module "os" {
import { NonSharedBuffer } from "buffer";
interface CpuInfo { interface CpuInfo {
model: string; model: string;
speed: number; speed: number;
@ -253,9 +254,9 @@ declare module "os" {
* Throws a [`SystemError`](https://nodejs.org/docs/latest-v24.x/api/errors.html#class-systemerror) if a user has no `username` or `homedir`. * Throws a [`SystemError`](https://nodejs.org/docs/latest-v24.x/api/errors.html#class-systemerror) if a user has no `username` or `homedir`.
* @since v6.0.0 * @since v6.0.0
*/ */
function userInfo(options: UserInfoOptionsWithBufferEncoding): UserInfo<Buffer>;
function userInfo(options?: UserInfoOptionsWithStringEncoding): UserInfo<string>; function userInfo(options?: UserInfoOptionsWithStringEncoding): UserInfo<string>;
function userInfo(options: UserInfoOptions): UserInfo<string | Buffer>; function userInfo(options: UserInfoOptionsWithBufferEncoding): UserInfo<NonSharedBuffer>;
function userInfo(options: UserInfoOptions): UserInfo<string | NonSharedBuffer>;
type SignalConstants = { type SignalConstants = {
[key in NodeJS.Signals]: number; [key in NodeJS.Signals]: number;
}; };

View file

@ -1,6 +1,6 @@
{ {
"name": "@types/node", "name": "@types/node",
"version": "24.7.2", "version": "24.10.0",
"description": "TypeScript definitions for node", "description": "TypeScript definitions for node",
"homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node", "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node",
"license": "MIT", "license": "MIT",
@ -147,9 +147,9 @@
}, },
"scripts": {}, "scripts": {},
"dependencies": { "dependencies": {
"undici-types": "~7.14.0" "undici-types": "~7.16.0"
}, },
"peerDependencies": {}, "peerDependencies": {},
"typesPublisherContentHash": "4bf36d2d52de2aa8898ee24d026198a784567fa5a42adcae5e37b826951ff66d", "typesPublisherContentHash": "520eb7d36290a7656940213fbf34026408b9af9ff538455bf669b4ea7a21d5bf",
"typeScriptVersion": "5.2" "typeScriptVersion": "5.2"
} }

View file

@ -1,5 +1,6 @@
declare module "process" { declare module "process" {
import { Control, MessageOptions } from "node:child_process"; import { Control, MessageOptions, SendHandle } from "node:child_process";
import { PathLike } from "node:fs";
import * as tty from "node:tty"; import * as tty from "node:tty";
import { Worker } from "node:worker_threads"; import { Worker } from "node:worker_threads";
@ -331,7 +332,7 @@ declare module "process" {
*/ */
type UnhandledRejectionListener = (reason: unknown, promise: Promise<unknown>) => void; type UnhandledRejectionListener = (reason: unknown, promise: Promise<unknown>) => void;
type WarningListener = (warning: Error) => void; type WarningListener = (warning: Error) => void;
type MessageListener = (message: unknown, sendHandle: unknown) => void; type MessageListener = (message: unknown, sendHandle: SendHandle) => void;
type SignalsListener = (signal: Signals) => void; type SignalsListener = (signal: Signals) => void;
type MultipleResolveListener = ( type MultipleResolveListener = (
type: MultipleResolveType, type: MultipleResolveType,
@ -1466,7 +1467,7 @@ declare module "process" {
* @since v20.12.0 * @since v20.12.0
* @param path The path to the .env file * @param path The path to the .env file
*/ */
loadEnvFile(path?: string | URL | Buffer): void; loadEnvFile(path?: PathLike): void;
/** /**
* The `process.pid` property returns the PID of the process. * The `process.pid` property returns the PID of the process.
* *
@ -1775,7 +1776,7 @@ declare module "process" {
*/ */
send?( send?(
message: any, message: any,
sendHandle?: any, sendHandle?: SendHandle,
options?: MessageOptions, options?: MessageOptions,
callback?: (error: Error | null) => void, callback?: (error: Error | null) => void,
): boolean; ): boolean;
@ -1979,7 +1980,7 @@ declare module "process" {
emit(event: "uncaughtExceptionMonitor", error: Error): boolean; emit(event: "uncaughtExceptionMonitor", error: Error): boolean;
emit(event: "unhandledRejection", reason: unknown, promise: Promise<unknown>): boolean; emit(event: "unhandledRejection", reason: unknown, promise: Promise<unknown>): boolean;
emit(event: "warning", warning: Error): boolean; emit(event: "warning", warning: Error): boolean;
emit(event: "message", message: unknown, sendHandle: unknown): this; emit(event: "message", message: unknown, sendHandle: SendHandle): this;
emit(event: Signals, signal?: Signals): boolean; emit(event: Signals, signal?: Signals): boolean;
emit( emit(
event: "multipleResolves", event: "multipleResolves",

View file

@ -150,4 +150,13 @@ declare module "node:sea" {
* @since v20.12.0 * @since v20.12.0
*/ */
function getRawAsset(key: AssetKey): ArrayBuffer; function getRawAsset(key: AssetKey): ArrayBuffer;
/**
* This method can be used to retrieve an array of all the keys of assets
* embedded into the single-executable application.
* An error is thrown when not running inside a single-executable application.
* @since v24.8.0
* @returns An array containing all the keys of the assets
* embedded in the executable. If no assets are embedded, returns an empty array.
*/
function getAssetKeys(): string[];
} }

View file

@ -43,10 +43,9 @@
* @see [source](https://github.com/nodejs/node/blob/v24.x/lib/sqlite.js) * @see [source](https://github.com/nodejs/node/blob/v24.x/lib/sqlite.js)
*/ */
declare module "node:sqlite" { declare module "node:sqlite" {
import { PathLike } from "node:fs";
type SQLInputValue = null | number | bigint | string | NodeJS.ArrayBufferView; type SQLInputValue = null | number | bigint | string | NodeJS.ArrayBufferView;
type SQLOutputValue = null | number | bigint | string | Uint8Array; type SQLOutputValue = null | number | bigint | string | NodeJS.NonSharedUint8Array;
/** @deprecated Use `SQLInputValue` or `SQLOutputValue` instead. */
type SupportedValueType = SQLOutputValue;
interface DatabaseSyncOptions { interface DatabaseSyncOptions {
/** /**
* If `true`, the database is opened by the constructor. When * If `true`, the database is opened by the constructor. When
@ -240,7 +239,7 @@ declare module "node:sqlite" {
* To use an in-memory database, the path should be the special name `':memory:'`. * To use an in-memory database, the path should be the special name `':memory:'`.
* @param options Configuration options for the database connection. * @param options Configuration options for the database connection.
*/ */
constructor(path: string | Buffer | URL, options?: DatabaseSyncOptions); constructor(path: PathLike, options?: DatabaseSyncOptions);
/** /**
* Registers a new aggregate function with the SQLite database. This method is a wrapper around * Registers a new aggregate function with the SQLite database. This method is a wrapper around
* [`sqlite3_create_window_function()`](https://www.sqlite.org/c3ref/create_function.html). * [`sqlite3_create_window_function()`](https://www.sqlite.org/c3ref/create_function.html).
@ -330,6 +329,64 @@ declare module "node:sqlite" {
func: (...args: SQLOutputValue[]) => SQLInputValue, func: (...args: SQLOutputValue[]) => SQLInputValue,
): void; ): void;
function(name: string, func: (...args: SQLOutputValue[]) => SQLInputValue): void; function(name: string, func: (...args: SQLOutputValue[]) => SQLInputValue): void;
/**
* Sets an authorizer callback that SQLite will invoke whenever it attempts to
* access data or modify the database schema through prepared statements.
* This can be used to implement security policies, audit access, or restrict certain operations.
* This method is a wrapper around [`sqlite3_set_authorizer()`](https://sqlite.org/c3ref/set_authorizer.html).
*
* When invoked, the callback receives five arguments:
*
* * `actionCode` {number} The type of operation being performed (e.g.,
* `SQLITE_INSERT`, `SQLITE_UPDATE`, `SQLITE_SELECT`).
* * `arg1` {string|null} The first argument (context-dependent, often a table name).
* * `arg2` {string|null} The second argument (context-dependent, often a column name).
* * `dbName` {string|null} The name of the database.
* * `triggerOrView` {string|null} The name of the trigger or view causing the access.
*
* The callback must return one of the following constants:
*
* * `SQLITE_OK` - Allow the operation.
* * `SQLITE_DENY` - Deny the operation (causes an error).
* * `SQLITE_IGNORE` - Ignore the operation (silently skip).
*
* ```js
* import { DatabaseSync, constants } from 'node:sqlite';
* const db = new DatabaseSync(':memory:');
*
* // Set up an authorizer that denies all table creation
* db.setAuthorizer((actionCode) => {
* if (actionCode === constants.SQLITE_CREATE_TABLE) {
* return constants.SQLITE_DENY;
* }
* return constants.SQLITE_OK;
* });
*
* // This will work
* db.prepare('SELECT 1').get();
*
* // This will throw an error due to authorization denial
* try {
* db.exec('CREATE TABLE blocked (id INTEGER)');
* } catch (err) {
* console.log('Operation blocked:', err.message);
* }
* ```
* @since v24.10.0
* @param callback The authorizer function to set, or `null` to
* clear the current authorizer.
*/
setAuthorizer(
callback:
| ((
actionCode: number,
arg1: string | null,
arg2: string | null,
dbName: string | null,
triggerOrView: string | null,
) => number)
| null,
): void;
/** /**
* Whether the database is currently open or not. * Whether the database is currently open or not.
* @since v22.15.0 * @since v22.15.0
@ -355,6 +412,47 @@ declare module "node:sqlite" {
* @return The prepared statement. * @return The prepared statement.
*/ */
prepare(sql: string): StatementSync; prepare(sql: string): StatementSync;
/**
* Creates a new `SQLTagStore`, which is an LRU (Least Recently Used) cache for
* storing prepared statements. This allows for the efficient reuse of prepared
* statements by tagging them with a unique identifier.
*
* When a tagged SQL literal is executed, the `SQLTagStore` checks if a prepared
* statement for that specific SQL string already exists in the cache. If it does,
* the cached statement is used. If not, a new prepared statement is created,
* executed, and then stored in the cache for future use. This mechanism helps to
* avoid the overhead of repeatedly parsing and preparing the same SQL statements.
*
* ```js
* import { DatabaseSync } from 'node:sqlite';
*
* const db = new DatabaseSync(':memory:');
* const sql = db.createSQLTagStore();
*
* db.exec('CREATE TABLE users (id INT, name TEXT)');
*
* // Using the 'run' method to insert data.
* // The tagged literal is used to identify the prepared statement.
* sql.run`INSERT INTO users VALUES (1, 'Alice')`;
* sql.run`INSERT INTO users VALUES (2, 'Bob')`;
*
* // Using the 'get' method to retrieve a single row.
* const id = 1;
* const user = sql.get`SELECT * FROM users WHERE id = ${id}`;
* console.log(user); // { id: 1, name: 'Alice' }
*
* // Using the 'all' method to retrieve all rows.
* const allUsers = sql.all`SELECT * FROM users ORDER BY id`;
* console.log(allUsers);
* // [
* // { id: 1, name: 'Alice' },
* // { id: 2, name: 'Bob' }
* // ]
* ```
* @since v24.9.0
* @returns A new SQL tag store for caching prepared statements.
*/
createTagStore(maxSize?: number): SQLTagStore;
/** /**
* Creates and attaches a session to the database. This method is a wrapper around * Creates and attaches a session to the database. This method is a wrapper around
* [`sqlite3session_create()`](https://www.sqlite.org/session/sqlite3session_create.html) and * [`sqlite3session_create()`](https://www.sqlite.org/session/sqlite3session_create.html) and
@ -410,7 +508,7 @@ declare module "node:sqlite" {
* @returns Binary changeset that can be applied to other databases. * @returns Binary changeset that can be applied to other databases.
* @since v22.12.0 * @since v22.12.0
*/ */
changeset(): Uint8Array; changeset(): NodeJS.NonSharedUint8Array;
/** /**
* Similar to the method above, but generates a more compact patchset. See * Similar to the method above, but generates a more compact patchset. See
* [Changesets and Patchsets](https://www.sqlite.org/sessionintro.html#changesets_and_patchsets) * [Changesets and Patchsets](https://www.sqlite.org/sessionintro.html#changesets_and_patchsets)
@ -420,7 +518,7 @@ declare module "node:sqlite" {
* @returns Binary patchset that can be applied to other databases. * @returns Binary patchset that can be applied to other databases.
* @since v22.12.0 * @since v22.12.0
*/ */
patchset(): Uint8Array; patchset(): NodeJS.NonSharedUint8Array;
/** /**
* Closes the session. An exception is thrown if the database or the session is not open. This method is a * Closes the session. An exception is thrown if the database or the session is not open. This method is a
* wrapper around * wrapper around
@ -428,6 +526,73 @@ declare module "node:sqlite" {
*/ */
close(): void; close(): void;
} }
/**
* This class represents a single LRU (Least Recently Used) cache for storing
* prepared statements.
*
* Instances of this class are created via the database.createSQLTagStore() method,
* not by using a constructor. The store caches prepared statements based on the
* provided SQL query string. When the same query is seen again, the store
* retrieves the cached statement and safely applies the new values through
* parameter binding, thereby preventing attacks like SQL injection.
*
* The cache has a maxSize that defaults to 1000 statements, but a custom size can
* be provided (e.g., database.createSQLTagStore(100)). All APIs exposed by this
* class execute synchronously.
* @since v24.9.0
*/
interface SQLTagStore {
/**
* Executes the given SQL query and returns all resulting rows as an array of objects.
* @since v24.9.0
*/
all(
stringElements: TemplateStringsArray,
...boundParameters: SQLInputValue[]
): Record<string, SQLOutputValue>[];
/**
* Executes the given SQL query and returns the first resulting row as an object.
* @since v24.9.0
*/
get(
stringElements: TemplateStringsArray,
...boundParameters: SQLInputValue[]
): Record<string, SQLOutputValue> | undefined;
/**
* Executes the given SQL query and returns an iterator over the resulting rows.
* @since v24.9.0
*/
iterate(
stringElements: TemplateStringsArray,
...boundParameters: SQLInputValue[]
): NodeJS.Iterator<Record<string, SQLOutputValue>>;
/**
* Executes the given SQL query, which is expected to not return any rows (e.g., INSERT, UPDATE, DELETE).
* @since v24.9.0
*/
run(stringElements: TemplateStringsArray, ...boundParameters: SQLInputValue[]): StatementResultingChanges;
/**
* A read-only property that returns the number of prepared statements currently in the cache.
* @since v24.9.0
* @returns The maximum number of prepared statements the cache can hold.
*/
size(): number;
/**
* A read-only property that returns the maximum number of prepared statements the cache can hold.
* @since v24.9.0
*/
readonly capacity: number;
/**
* A read-only property that returns the `DatabaseSync` object associated with this `SQLTagStore`.
* @since v24.9.0
*/
readonly db: DatabaseSync;
/**
* Resets the LRU cache, clearing all stored prepared statements.
* @since v24.9.0
*/
clear(): void;
}
interface StatementColumnMetadata { interface StatementColumnMetadata {
/** /**
* The unaliased name of the column in the origin * The unaliased name of the column in the origin
@ -679,7 +844,7 @@ declare module "node:sqlite" {
* @returns A promise that fulfills with the total number of backed-up pages upon completion, or rejects if an * @returns A promise that fulfills with the total number of backed-up pages upon completion, or rejects if an
* error occurs. * error occurs.
*/ */
function backup(sourceDb: DatabaseSync, path: string | Buffer | URL, options?: BackupOptions): Promise<number>; function backup(sourceDb: DatabaseSync, path: PathLike, options?: BackupOptions): Promise<number>;
/** /**
* @since v22.13.0 * @since v22.13.0
*/ */
@ -719,5 +884,54 @@ declare module "node:sqlite" {
* @since v22.12.0 * @since v22.12.0
*/ */
const SQLITE_CHANGESET_ABORT: number; const SQLITE_CHANGESET_ABORT: number;
/**
* Deny the operation and cause an error to be returned.
* @since v24.10.0
*/
const SQLITE_DENY: number;
/**
* Ignore the operation and continue as if it had never been requested.
* @since 24.10.0
*/
const SQLITE_IGNORE: number;
/**
* Allow the operation to proceed normally.
* @since v24.10.0
*/
const SQLITE_OK: number;
const SQLITE_CREATE_INDEX: number;
const SQLITE_CREATE_TABLE: number;
const SQLITE_CREATE_TEMP_INDEX: number;
const SQLITE_CREATE_TEMP_TABLE: number;
const SQLITE_CREATE_TEMP_TRIGGER: number;
const SQLITE_CREATE_TEMP_VIEW: number;
const SQLITE_CREATE_TRIGGER: number;
const SQLITE_CREATE_VIEW: number;
const SQLITE_DELETE: number;
const SQLITE_DROP_INDEX: number;
const SQLITE_DROP_TABLE: number;
const SQLITE_DROP_TEMP_INDEX: number;
const SQLITE_DROP_TEMP_TABLE: number;
const SQLITE_DROP_TEMP_TRIGGER: number;
const SQLITE_DROP_TEMP_VIEW: number;
const SQLITE_DROP_TRIGGER: number;
const SQLITE_DROP_VIEW: number;
const SQLITE_INSERT: number;
const SQLITE_PRAGMA: number;
const SQLITE_READ: number;
const SQLITE_SELECT: number;
const SQLITE_TRANSACTION: number;
const SQLITE_UPDATE: number;
const SQLITE_ATTACH: number;
const SQLITE_DETACH: number;
const SQLITE_ALTER_TABLE: number;
const SQLITE_REINDEX: number;
const SQLITE_ANALYZE: number;
const SQLITE_CREATE_VTABLE: number;
const SQLITE_DROP_VTABLE: number;
const SQLITE_FUNCTION: number;
const SQLITE_SAVEPOINT: number;
const SQLITE_COPY: number;
const SQLITE_RECURSIVE: number;
} }
} }

View file

@ -1656,6 +1656,7 @@ declare module "stream" {
ref(): void; ref(): void;
unref(): void; unref(): void;
} }
// TODO: these should all take webstream arguments
/** /**
* Returns whether the stream has encountered an error. * Returns whether the stream has encountered an error.
* @since v17.3.0, v16.14.0 * @since v17.3.0, v16.14.0
@ -1664,8 +1665,15 @@ declare module "stream" {
/** /**
* Returns whether the stream is readable. * Returns whether the stream is readable.
* @since v17.4.0, v16.14.0 * @since v17.4.0, v16.14.0
* @returns Only returns `null` if `stream` is not a valid `Readable`, `Duplex` or `ReadableStream`.
*/ */
function isReadable(stream: Readable | NodeJS.ReadableStream): boolean; function isReadable(stream: Readable | NodeJS.ReadableStream): boolean | null;
/**
* Returns whether the stream is writable.
* @since v20.0.0
* @returns Only returns `null` if `stream` is not a valid `Writable`, `Duplex` or `WritableStream`.
*/
function isWritable(stream: Writable | NodeJS.WritableStream): boolean | null;
} }
export = Stream; export = Stream;
} }

Some files were not shown because too many files have changed in this diff Show more