Change endpoint from persons to people

This commit is contained in:
xfarrow
2025-03-23 21:00:08 +01:00
parent 4ae263662c
commit d005193f63
7158 changed files with 700476 additions and 735 deletions

View File

@ -0,0 +1,6 @@
import octetstream from './octetstream.js';
import querystring from './querystring.js';
import multipart from './multipart.js';
import json from './json.js';
export { octetstream, querystring, multipart, json };

View File

@ -0,0 +1,39 @@
/* eslint-disable no-underscore-dangle */
import JSONParser from '../parsers/JSON.js';
export const jsonType = 'json';
// the `options` is also available through the `this.options` / `formidable.options`
export default function plugin(formidable, options) {
// the `this` context is always formidable, as the first argument of a plugin
// but this allows us to customize/test each plugin
/* istanbul ignore next */
const self = this || formidable;
if (/json/i.test(self.headers['content-type'])) {
init.call(self, self, options);
}
return self;
};
// Note that it's a good practice (but it's up to you) to use the `this.options` instead
// of the passed `options` (second) param, because when you decide
// to test the plugin you can pass custom `this` context to it (and so `this.options`)
function init(_self, _opts) {
this.type = jsonType;
const parser = new JSONParser(this.options);
parser.on('data', (fields) => {
this.fields = fields;
});
parser.once('end', () => {
this.ended = true;
this._maybeEnd();
});
this._parser = parser;
}

View File

@ -0,0 +1,173 @@
/* eslint-disable no-underscore-dangle */
import { Stream } from 'node:stream';
import MultipartParser from '../parsers/Multipart.js';
import * as errors from '../FormidableError.js';
import FormidableError from '../FormidableError.js';
export const multipartType = 'multipart';
// the `options` is also available through the `options` / `formidable.options`
export default function plugin(formidable, options) {
// the `this` context is always formidable, as the first argument of a plugin
// but this allows us to customize/test each plugin
/* istanbul ignore next */
const self = this || formidable;
// NOTE: we (currently) support both multipart/form-data and multipart/related
const multipart = /multipart/i.test(self.headers['content-type']);
if (multipart) {
const m = self.headers['content-type'].match(
/boundary=(?:"([^"]+)"|([^;]+))/i,
);
if (m) {
const initMultipart = createInitMultipart(m[1] || m[2]);
initMultipart.call(self, self, options); // lgtm [js/superfluous-trailing-arguments]
} else {
const err = new FormidableError(
'bad content-type header, no multipart boundary',
errors.missingMultipartBoundary,
400,
);
self._error(err);
}
}
return self;
}
// Note that it's a good practice (but it's up to you) to use the `this.options` instead
// of the passed `options` (second) param, because when you decide
// to test the plugin you can pass custom `this` context to it (and so `this.options`)
function createInitMultipart(boundary) {
return function initMultipart() {
this.type = multipartType;
const parser = new MultipartParser(this.options);
let headerField;
let headerValue;
let part;
parser.initWithBoundary(boundary);
// eslint-disable-next-line max-statements, consistent-return
parser.on('data', async ({ name, buffer, start, end }) => {
if (name === 'partBegin') {
part = new Stream();
part.readable = true;
part.headers = {};
part.name = null;
part.originalFilename = null;
part.mimetype = null;
part.transferEncoding = this.options.encoding;
part.transferBuffer = '';
headerField = '';
headerValue = '';
} else if (name === 'headerField') {
headerField += buffer.toString(this.options.encoding, start, end);
} else if (name === 'headerValue') {
headerValue += buffer.toString(this.options.encoding, start, end);
} else if (name === 'headerEnd') {
headerField = headerField.toLowerCase();
part.headers[headerField] = headerValue;
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
const m = headerValue.match(
// eslint-disable-next-line no-useless-escape
/\bname=("([^"]*)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))/i,
);
if (headerField === 'content-disposition') {
if (m) {
part.name = m[2] || m[3] || '';
}
part.originalFilename = this._getFileName(headerValue);
} else if (headerField === 'content-type') {
part.mimetype = headerValue;
} else if (headerField === 'content-transfer-encoding') {
part.transferEncoding = headerValue.toLowerCase();
}
headerField = '';
headerValue = '';
} else if (name === 'headersEnd') {
switch (part.transferEncoding) {
case 'binary':
case '7bit':
case '8bit':
case 'utf-8': {
const dataPropagation = (ctx) => {
if (ctx.name === 'partData') {
part.emit('data', ctx.buffer.slice(ctx.start, ctx.end));
}
};
const dataStopPropagation = (ctx) => {
if (ctx.name === 'partEnd') {
part.emit('end');
parser.off('data', dataPropagation);
parser.off('data', dataStopPropagation);
}
};
parser.on('data', dataPropagation);
parser.on('data', dataStopPropagation);
break;
}
case 'base64': {
const dataPropagation = (ctx) => {
if (ctx.name === 'partData') {
part.transferBuffer += ctx.buffer
.slice(ctx.start, ctx.end)
.toString('ascii');
/*
four bytes (chars) in base64 converts to three bytes in binary
encoding. So we should always work with a number of bytes that
can be divided by 4, it will result in a number of bytes that
can be divided vy 3.
*/
const offset = parseInt(part.transferBuffer.length / 4, 10) * 4;
part.emit(
'data',
Buffer.from(
part.transferBuffer.substring(0, offset),
'base64',
),
);
part.transferBuffer = part.transferBuffer.substring(offset);
}
};
const dataStopPropagation = (ctx) => {
if (ctx.name === 'partEnd') {
part.emit('data', Buffer.from(part.transferBuffer, 'base64'));
part.emit('end');
parser.off('data', dataPropagation);
parser.off('data', dataStopPropagation);
}
};
parser.on('data', dataPropagation);
parser.on('data', dataStopPropagation);
break;
}
default:
return this._error(
new FormidableError(
'unknown transfer-encoding',
errors.unknownTransferEncoding,
501,
),
);
}
this._parser.pause();
await this.onPart(part);
this._parser.resume();
} else if (name === 'end') {
this.ended = true;
this._maybeEnd();
}
});
this._parser = parser;
};
}

View File

@ -0,0 +1,84 @@
/* eslint-disable no-underscore-dangle */
import OctetStreamParser from '../parsers/OctetStream.js';
export const octetStreamType = 'octet-stream';
// the `options` is also available through the `options` / `formidable.options`
export default async function plugin(formidable, options) {
// the `this` context is always formidable, as the first argument of a plugin
// but this allows us to customize/test each plugin
/* istanbul ignore next */
const self = this || formidable;
if (/octet-stream/i.test(self.headers['content-type'])) {
await init.call(self, self, options);
}
return self;
}
// Note that it's a good practice (but it's up to you) to use the `this.options` instead
// of the passed `options` (second) param, because when you decide
// to test the plugin you can pass custom `this` context to it (and so `this.options`)
async function init(_self, _opts) {
this.type = octetStreamType;
const originalFilename = this.headers['x-file-name'];
const mimetype = this.headers['content-type'];
const thisPart = {
originalFilename,
mimetype,
};
const newFilename = this._getNewName(thisPart);
const filepath = this._joinDirectoryName(newFilename);
const file = await this._newFile({
newFilename,
filepath,
originalFilename,
mimetype,
});
this.emit('fileBegin', originalFilename, file);
file.open();
this.openedFiles.push(file);
this._flushing += 1;
this._parser = new OctetStreamParser(this.options);
// Keep track of writes that haven't finished so we don't emit the file before it's done being written
let outstandingWrites = 0;
this._parser.on('data', (buffer) => {
this.pause();
outstandingWrites += 1;
file.write(buffer, () => {
outstandingWrites -= 1;
this.resume();
if (this.ended) {
this._parser.emit('doneWritingFile');
}
});
});
this._parser.on('end', () => {
this._flushing -= 1;
this.ended = true;
const done = () => {
file.end(() => {
this.emit('file', 'file', file);
this._maybeEnd();
});
};
if (outstandingWrites === 0) {
done();
} else {
this._parser.once('doneWritingFile', done);
}
});
return this;
}

View File

@ -0,0 +1,41 @@
/* eslint-disable no-underscore-dangle */
import QuerystringParser from '../parsers/Querystring.js';
export const querystringType = 'urlencoded';
// the `options` is also available through the `this.options` / `formidable.options`
export default function plugin(formidable, options) {
// the `this` context is always formidable, as the first argument of a plugin
// but this allows us to customize/test each plugin
/* istanbul ignore next */
const self = this || formidable;
if (/urlencoded/i.test(self.headers['content-type'])) {
init.call(self, self, options);
}
return self;
};
// Note that it's a good practice (but it's up to you) to use the `this.options` instead
// of the passed `options` (second) param, because when you decide
// to test the plugin you can pass custom `this` context to it (and so `this.options`)
function init(_self, _opts) {
this.type = querystringType;
const parser = new QuerystringParser(this.options);
parser.on('data', ({ key, value }) => {
this.emit('field', key, value);
});
parser.once('end', () => {
this.ended = true;
this._maybeEnd();
});
this._parser = parser;
return this;
}