fastify-txstate 3.6.6 → 3.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -190,3 +190,4 @@ export default class Server {
190
190
  export * from './analytics';
191
191
  export * from './error';
192
192
  export * from './unified-auth';
193
+ export * from './postformdata';
package/lib/index.js CHANGED
@@ -418,3 +418,4 @@ exports.default = Server;
418
418
  __exportStar(require("./analytics"), exports);
419
419
  __exportStar(require("./error"), exports);
420
420
  __exportStar(require("./unified-auth"), exports);
421
+ __exportStar(require("./postformdata"), exports);
@@ -0,0 +1,15 @@
1
+ import { Readable } from 'node:stream';
2
+ import { ReadableStream } from 'node:stream/web';
3
+ export interface FormDataTextField {
4
+ name: string;
5
+ value: string;
6
+ }
7
+ export interface FormDataFileField {
8
+ name: string;
9
+ value: ReadableStream | Readable;
10
+ filename?: string;
11
+ filetype?: string;
12
+ filesize?: number;
13
+ }
14
+ export type FormDataField = FormDataTextField | FormDataFileField;
15
+ export declare function postFormData(url: string, fields: FormDataField[], headers?: Record<string, any>): Promise<Response>;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.postFormData = postFormData;
4
+ const node_stream_1 = require("node:stream");
5
+ const web_1 = require("node:stream/web");
6
+ async function postFormData(url, fields, headers = {}) {
7
+ const encoder = new TextEncoder();
8
+ const boundary = `${Math.random().toString(36).substring(2, 15)}${Math.random().toString(36).substring(2, 15)}`;
9
+ const footer = `--${boundary}--\r\n`;
10
+ const chunks = fields.map(field => new FormDataChunk(boundary, encoder, field));
11
+ const totalSize = chunks.some(chunk => chunk.contentsize == null) ? undefined : chunks.reduce((sum, chunk) => sum + chunk.extrasize + chunk.contentsize, 0);
12
+ headers = {
13
+ ...headers,
14
+ 'Content-Type': `multipart/form-data; boundary=${boundary}`
15
+ };
16
+ if (totalSize) {
17
+ headers['Content-Length'] = totalSize.toString();
18
+ }
19
+ let i = 0;
20
+ let part = 'header';
21
+ const stream = new web_1.ReadableStream({
22
+ async pull(controller) {
23
+ if (i === chunks.length) {
24
+ controller.enqueue(encoder.encode(footer));
25
+ controller.close();
26
+ }
27
+ else {
28
+ const chunk = chunks[i];
29
+ if (part === 'header') {
30
+ controller.enqueue(encoder.encode(chunk.header));
31
+ part = 'content';
32
+ }
33
+ else if (part === 'content') {
34
+ const { value, done } = await chunk.contentReader.read();
35
+ if (done)
36
+ part = 'footer';
37
+ else
38
+ controller.enqueue(value);
39
+ }
40
+ else if (part === 'footer') {
41
+ controller.enqueue(encoder.encode(chunk.footer));
42
+ i++;
43
+ part = 'header';
44
+ }
45
+ }
46
+ },
47
+ cancel() {
48
+ for (const chunk of chunks) {
49
+ if (chunk.contentReader.cancel) {
50
+ chunk.contentReader.cancel();
51
+ }
52
+ }
53
+ }
54
+ });
55
+ return await fetch(url, {
56
+ method: 'POST',
57
+ headers,
58
+ duplex: 'half',
59
+ body: stream
60
+ });
61
+ }
62
+ function isFileField(field) {
63
+ return 'filename' in field || 'filetype' in field || 'filesize' in field || (typeof field.value === 'object' && 'getReader' in field.value);
64
+ }
65
+ class FormDataChunk {
66
+ header;
67
+ footer;
68
+ extrasize;
69
+ contentsize;
70
+ contentReader;
71
+ constructor(boundary, encoder, field) {
72
+ this.header = `--${boundary}\r\nContent-Disposition: form-data; name="${field.name}"`;
73
+ this.footer = '\r\n';
74
+ if (isFileField(field)) {
75
+ this.header += `; filename="${field.filename ?? field.name}"\r\nContent-Type: ${field.filetype ?? 'application/octet-stream'}`;
76
+ this.contentsize = field.filesize;
77
+ this.contentReader = (field.value instanceof node_stream_1.Readable ? web_1.ReadableStream.from(field.value) : field.value).getReader();
78
+ }
79
+ else {
80
+ const encoded = encoder.encode(field.value);
81
+ this.contentsize = encoded.length;
82
+ this.contentReader = new web_1.ReadableStream({
83
+ start: controller => {
84
+ controller.enqueue(encoded);
85
+ controller.close();
86
+ }
87
+ }).getReader();
88
+ }
89
+ this.header += '\r\n\r\n';
90
+ this.extrasize = Buffer.byteLength(this.header) + Buffer.byteLength(this.footer);
91
+ }
92
+ }
package/lib-esm/index.js CHANGED
@@ -13,4 +13,6 @@ export const analyticsPlugin = ftxst.analyticsPlugin
13
13
  export const AnalyticsClient = ftxst.AnalyticsClient
14
14
  export const LoggingAnalyticsClient = ftxst.LoggingAnalyticsClient
15
15
  export const ElasticAnalyticsClient = ftxst.ElasticAnalyticsClient
16
+ export const postFormData = ftxst.postFormData
17
+ export const readableToWebReadable = ftxst.readableToWebReadable
16
18
  export default ftxst.default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify-txstate",
3
- "version": "3.6.6",
3
+ "version": "3.6.7",
4
4
  "description": "A small wrapper for fastify providing a set of common conventions & utility functions we use.",
5
5
  "exports": {
6
6
  ".": {
@@ -34,6 +34,7 @@
34
34
  "ua-parser-js": "^1.0.37"
35
35
  },
36
36
  "devDependencies": {
37
+ "@fastify/multipart": "^8.0.0",
37
38
  "@types/chai": "^4.2.14",
38
39
  "@types/mocha": "^10.0.0",
39
40
  "@types/node": "^22.0.0",