diff --git a/GRAPHQL_MULTIPART_REQUEST_SPEC_URL.js b/GRAPHQL_MULTIPART_REQUEST_SPEC_URL.mjs similarity index 80% rename from GRAPHQL_MULTIPART_REQUEST_SPEC_URL.js rename to GRAPHQL_MULTIPART_REQUEST_SPEC_URL.mjs index f5730ff..316ef14 100644 --- a/GRAPHQL_MULTIPART_REQUEST_SPEC_URL.js +++ b/GRAPHQL_MULTIPART_REQUEST_SPEC_URL.mjs @@ -1,7 +1,5 @@ // @ts-check -"use strict"; - /** * [GraphQL multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec) * URL. Useful for error messages, etc. @@ -9,4 +7,4 @@ const GRAPHQL_MULTIPART_REQUEST_SPEC_URL = "https://github.com/jaydenseric/graphql-multipart-request-spec"; -module.exports = GRAPHQL_MULTIPART_REQUEST_SPEC_URL; +export default GRAPHQL_MULTIPART_REQUEST_SPEC_URL; diff --git a/GraphQLUpload.js b/GraphQLUpload.mjs similarity index 78% rename from GraphQLUpload.js rename to GraphQLUpload.mjs index 2b85a7b..d241c60 100644 --- a/GraphQLUpload.js +++ b/GraphQLUpload.mjs @@ -1,11 +1,10 @@ // @ts-check -"use strict"; +import { GraphQLError, GraphQLScalarType } from "graphql"; -const { GraphQLScalarType, GraphQLError } = require("graphql"); -const Upload = require("./Upload.js"); +import Upload from "./Upload.mjs"; -/** @typedef {import("./processRequest").FileUpload} FileUpload */ +/** @typedef {import("./processRequest.mjs").FileUpload} FileUpload */ /** * A GraphQL `Upload` scalar that can be used in a @@ -18,8 +17,8 @@ const Upload = require("./Upload.js"); * from [`@graphql-tools/schema`](https://npm.im/@graphql-tools/schema): * * ```js - * const { makeExecutableSchema } = require("@graphql-tools/schema"); - * const GraphQLUpload = require("graphql-upload/GraphQLUpload.js"); + * import { makeExecutableSchema } from "@graphql-tools/schema/makeExecutableSchema"; + * import GraphQLUpload from "graphql-upload/GraphQLUpload.mjs"; * * const schema = makeExecutableSchema({ * typeDefs: ` @@ -34,8 +33,8 @@ const Upload = require("./Upload.js"); * A manually constructed schema with an image upload mutation: * * ```js - * const { GraphQLSchema, GraphQLObjectType, GraphQLBoolean } = require("graphql"); - * const GraphQLUpload = require("graphql-upload/GraphQLUpload.js"); + * import { GraphQLBoolean, GraphQLObjectType, GraphQLSchema } from "graphql"; + * import GraphQLUpload from "graphql-upload/GraphQLUpload.mjs"; * * const schema = new GraphQLSchema({ * mutation: new GraphQLObjectType({ @@ -77,4 +76,4 @@ const GraphQLUpload = new GraphQLScalarType({ }, }); -module.exports = GraphQLUpload; +export default GraphQLUpload; diff --git a/GraphQLUpload.test.mjs b/GraphQLUpload.test.mjs index 17b51b2..e738bc2 100644 --- a/GraphQLUpload.test.mjs +++ b/GraphQLUpload.test.mjs @@ -3,8 +3,8 @@ import { doesNotThrow, throws } from "assert"; import { parseValue } from "graphql"; -import GraphQLUpload from "./GraphQLUpload.js"; -import Upload from "./Upload.js"; +import GraphQLUpload from "./GraphQLUpload.mjs"; +import Upload from "./Upload.mjs"; /** * Adds `GraphQLUpload` tests. diff --git a/Upload.js b/Upload.mjs similarity index 78% rename from Upload.js rename to Upload.mjs index 3c577a9..c2a1bec 100644 --- a/Upload.js +++ b/Upload.mjs @@ -1,9 +1,7 @@ // @ts-check -"use strict"; - -/** @typedef {import("./GraphQLUpload.js")} GraphQLUpload */ -/** @typedef {import("./processRequest.js")} processRequest */ +/** @typedef {import("./GraphQLUpload.mjs").default} GraphQLUpload */ +/** @typedef {import("./processRequest.mjs").default} processRequest */ /** * A file expected to be uploaded as it was declared in the `map` field of a @@ -12,18 +10,18 @@ * this class wherever the file is expected in the GraphQL operation. The scalar * {@linkcode GraphQLUpload} derives it’s value from {@linkcode Upload.promise}. */ -class Upload { +export default class Upload { constructor() { /** * Promise that resolves file upload details. This should only be utilized * by {@linkcode GraphQLUpload}. - * @type {Promise} + * @type {Promise} */ this.promise = new Promise((resolve, reject) => { /** * Resolves the upload promise with the file upload details. This should * only be utilized by {@linkcode processRequest}. - * @param {import("./processRequest.js").FileUpload} file File upload + * @param {import("./processRequest.mjs").FileUpload} file File upload * details. */ this.resolve = (file) => { @@ -31,7 +29,7 @@ class Upload { * The file upload details, available when the * {@linkcode Upload.promise} resolves. This should only be utilized by * {@linkcode processRequest}. - * @type {import("./processRequest.js").FileUpload | undefined} + * @type {import("./processRequest.mjs").FileUpload | undefined} */ this.file = file; @@ -51,5 +49,3 @@ class Upload { this.promise.catch(() => {}); } } - -module.exports = Upload; diff --git a/Upload.test.mjs b/Upload.test.mjs index ed3c938..083f684 100644 --- a/Upload.test.mjs +++ b/Upload.test.mjs @@ -2,7 +2,7 @@ import { ok, rejects, strictEqual } from "assert"; -import Upload from "./Upload.js"; +import Upload from "./Upload.mjs"; /** * Adds `Upload` tests. diff --git a/changelog.md b/changelog.md index 435335d..2a4a8ca 100644 --- a/changelog.md +++ b/changelog.md @@ -2,9 +2,41 @@ ## Next +### Major + +- Updated the [`fs-capacitor`](https://npm.im/fs-capacitor) dependency to v8, fixing [#318](https://github.com/jaydenseric/graphql-upload/issues/318). +- The type `FileUploadCreateReadStreamOptions` from the `processRequest.mjs` module now uses types from [`fs-capacitor`](https://npm.im/fs-capacitor) that are slightly more specific. +- The API is now ESM in `.mjs` files instead of CJS in `.js` files, [accessible via `import` but not `require`](https://nodejs.org/dist/latest/docs/api/esm.html#require). To migrate imports: + + ```diff + - import GraphQLUpload from "graphql-upload/GraphQLUpload.js"; + + import GraphQLUpload from "graphql-upload/GraphQLUpload.mjs"; + ``` + + ```diff + - import graphqlUploadExpress from "graphql-upload/graphqlUploadExpress.js"; + + import graphqlUploadExpress from "graphql-upload/graphqlUploadExpress.mjs"; + ``` + + ```diff + - import graphqlUploadKoa from "graphql-upload/graphqlUploadKoa.js"; + + import graphqlUploadKoa from "graphql-upload/graphqlUploadKoa.mjs"; + ``` + + ```diff + - import processRequest from "graphql-upload/processRequest.js"; + + import processRequest from "graphql-upload/processRequest.mjs"; + ``` + + ```diff + - import Upload from "graphql-upload/Upload.js"; + + import Upload from "graphql-upload/Upload.mjs"; + ``` + ### Patch - Updated dev dependencies. +- Updated examples in JSDoc comments. - Updated the changelog entry for v14.0.0 to show how to migrate imports. ## 15.0.2 diff --git a/graphqlUploadExpress.js b/graphqlUploadExpress.mjs similarity index 80% rename from graphqlUploadExpress.js rename to graphqlUploadExpress.mjs index 01a512b..299c098 100644 --- a/graphqlUploadExpress.js +++ b/graphqlUploadExpress.mjs @@ -1,8 +1,6 @@ // @ts-check -"use strict"; - -const defaultProcessRequest = require("./processRequest.js"); +import defaultProcessRequest from "./processRequest.mjs"; /** * Creates [Express](https://expressjs.com) middleware that processes incoming @@ -10,29 +8,30 @@ const defaultProcessRequest = require("./processRequest.js"); * using {@linkcode processRequest}, ignoring non multipart requests. It sets * the request `body` to be similar to a conventional GraphQL POST request for * following GraphQL middleware to consume. - * @param {import("./processRequest.js").ProcessRequestOptions & { - * processRequest?: import("./processRequest.js").ProcessRequestFunction + * @param {import("./processRequest.mjs").ProcessRequestOptions & { + * processRequest?: import("./processRequest.mjs").ProcessRequestFunction * }} options Options. * @returns Express middleware. * @example * Basic [`express-graphql`](https://npm.im/express-graphql) setup: * * ```js - * const express = require("express"); - * const graphqlHTTP = require("express-graphql"); - * const graphqlUploadExpress = require("graphql-upload/graphqlUploadExpress.js"); - * const schema = require("./schema.js"); + * import express from "express"; + * import expressGraphQL from "express-graphql"; + * import graphqlUploadExpress from "graphql-upload/graphqlUploadExpress.mjs"; + * + * import schema from "./schema.mjs"; * * express() * .use( * "/graphql", * graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }), - * graphqlHTTP({ schema }) + * expressGraphQL.graphqlHTTP({ schema }) * ) * .listen(3000); * ``` */ -function graphqlUploadExpress({ +export default function graphqlUploadExpress({ processRequest = defaultProcessRequest, ...processRequestOptions } = {}) { @@ -76,5 +75,3 @@ function graphqlUploadExpress({ return graphqlUploadExpressMiddleware; } - -module.exports = graphqlUploadExpress; diff --git a/graphqlUploadExpress.test.mjs b/graphqlUploadExpress.test.mjs index 3be23ea..544cdd2 100644 --- a/graphqlUploadExpress.test.mjs +++ b/graphqlUploadExpress.test.mjs @@ -6,8 +6,8 @@ import { createServer } from "http"; import createError from "http-errors"; import fetch, { File, FormData } from "node-fetch"; -import graphqlUploadExpress from "./graphqlUploadExpress.js"; -import processRequest from "./processRequest.js"; +import graphqlUploadExpress from "./graphqlUploadExpress.mjs"; +import processRequest from "./processRequest.mjs"; import listen from "./test/listen.mjs"; /** @@ -44,7 +44,7 @@ export default (tests) => { /** * @type {{ * variables: { - * file: import("./Upload.js"), + * file: import("./Upload.mjs").default, * }, * } | undefined} */ @@ -84,7 +84,7 @@ export default (tests) => { /** * @type {{ * variables: { - * file: import("./Upload.js"), + * file: import("./Upload.mjs").default, * }, * } | undefined} */ diff --git a/graphqlUploadKoa.js b/graphqlUploadKoa.mjs similarity index 76% rename from graphqlUploadKoa.js rename to graphqlUploadKoa.mjs index fbb2839..27772f0 100644 --- a/graphqlUploadKoa.js +++ b/graphqlUploadKoa.mjs @@ -1,8 +1,6 @@ // @ts-check -"use strict"; - -const defaultProcessRequest = require("./processRequest.js"); +import defaultProcessRequest from "./processRequest.mjs"; /** * Creates [Koa](https://koajs.com) middleware that processes incoming @@ -10,19 +8,21 @@ const defaultProcessRequest = require("./processRequest.js"); * using {@linkcode processRequest}, ignoring non multipart requests. It sets * the request `body` to be similar to a conventional GraphQL POST request for * following GraphQL middleware to consume. - * @param {import("./processRequest.js").ProcessRequestOptions & { - * processRequest?: import("./processRequest.js").ProcessRequestFunction + * @param {import("./processRequest.mjs").ProcessRequestOptions & { + * processRequest?: import("./processRequest.mjs").ProcessRequestFunction * }} options Options. * @returns Koa middleware. * @example * Basic [`graphql-api-koa`](https://npm.im/graphql-api-koa) setup: * * ```js - * const Koa = require("koa"); - * const bodyParser = require("koa-bodyparser"); - * const { errorHandler, execute } = require("graphql-api-koa"); - * const graphqlUploadKoa = require("graphql-upload/graphqlUploadKoa.js"); - * const schema = require("./schema.js"); + * import errorHandler from "graphql-api-koa/errorHandler.mjs"; + * import execute from "graphql-api-koa/execute.mjs"; + * import graphqlUploadKoa from "graphql-upload/graphqlUploadKoa.mjs"; + * import Koa from "koa"; + * import bodyParser from "koa-bodyparser"; + * + * import schema from "./schema.mjs"; * * new Koa() * .use(errorHandler()) @@ -32,7 +32,7 @@ const defaultProcessRequest = require("./processRequest.js"); * .listen(3000); * ``` */ -function graphqlUploadKoa({ +export default function graphqlUploadKoa({ processRequest = defaultProcessRequest, ...processRequestOptions } = {}) { @@ -65,5 +65,3 @@ function graphqlUploadKoa({ return graphqlUploadKoaMiddleware; } - -module.exports = graphqlUploadKoa; diff --git a/graphqlUploadKoa.test.mjs b/graphqlUploadKoa.test.mjs index 1d6f694..1bd9f51 100644 --- a/graphqlUploadKoa.test.mjs +++ b/graphqlUploadKoa.test.mjs @@ -5,8 +5,8 @@ import { createServer } from "http"; import Koa from "koa"; import fetch, { File, FormData } from "node-fetch"; -import graphqlUploadKoa from "./graphqlUploadKoa.js"; -import processRequest from "./processRequest.js"; +import graphqlUploadKoa from "./graphqlUploadKoa.mjs"; +import processRequest from "./processRequest.mjs"; import listen from "./test/listen.mjs"; /** @@ -40,7 +40,7 @@ export default (tests) => { /** * @type {{ * variables: { - * file: import("./Upload.js"), + * file: import("./Upload.mjs").default, * }, * } | undefined} */ @@ -80,7 +80,7 @@ export default (tests) => { /** * @type {{ * variables: { - * file: import("./Upload.js"), + * file: import("./Upload.mjs").default, * }, * } | undefined} */ diff --git a/ignoreStream.js b/ignoreStream.mjs similarity index 77% rename from ignoreStream.js rename to ignoreStream.mjs index 1454925..81604d0 100644 --- a/ignoreStream.js +++ b/ignoreStream.mjs @@ -1,17 +1,13 @@ // @ts-check -"use strict"; - /** * Safely ignores a Node.js readable stream. * @param {import("stream").Readable} stream Node.js readable stream. */ -function ignoreStream(stream) { +export default function ignoreStream(stream) { // Prevent an unhandled error from crashing the process. stream.on("error", () => {}); // Waste the stream. stream.resume(); } - -module.exports = ignoreStream; diff --git a/ignoreStream.test.mjs b/ignoreStream.test.mjs index 1837445..2321ed4 100644 --- a/ignoreStream.test.mjs +++ b/ignoreStream.test.mjs @@ -2,7 +2,7 @@ import { doesNotThrow, strictEqual } from "assert"; -import ignoreStream from "./ignoreStream.js"; +import ignoreStream from "./ignoreStream.mjs"; import CountReadableStream from "./test/CountReadableStream.mjs"; /** diff --git a/package.json b/package.json index 3fd2cf1..3e8fab1 100644 --- a/package.json +++ b/package.json @@ -27,22 +27,22 @@ "mjs" ], "files": [ - "GRAPHQL_MULTIPART_REQUEST_SPEC_URL.js", - "GraphQLUpload.js", - "graphqlUploadExpress.js", - "graphqlUploadKoa.js", - "ignoreStream.js", - "processRequest.js", - "Upload.js" + "GRAPHQL_MULTIPART_REQUEST_SPEC_URL.mjs", + "GraphQLUpload.mjs", + "graphqlUploadExpress.mjs", + "graphqlUploadKoa.mjs", + "ignoreStream.mjs", + "processRequest.mjs", + "Upload.mjs" ], "sideEffects": false, "exports": { - "./GraphQLUpload.js": "./GraphQLUpload.js", - "./graphqlUploadExpress.js": "./graphqlUploadExpress.js", - "./graphqlUploadKoa.js": "./graphqlUploadKoa.js", + "./GraphQLUpload.mjs": "./GraphQLUpload.mjs", + "./graphqlUploadExpress.mjs": "./graphqlUploadExpress.mjs", + "./graphqlUploadKoa.mjs": "./graphqlUploadKoa.mjs", "./package.json": "./package.json", - "./processRequest.js": "./processRequest.js", - "./Upload.js": "./Upload.js" + "./processRequest.mjs": "./processRequest.mjs", + "./Upload.mjs": "./Upload.mjs" }, "engines": { "node": "^14.17.0 || ^16.0.0 || >= 18.0.0" @@ -65,7 +65,7 @@ "@types/node": "*", "@types/object-path": "^0.11.1", "busboy": "^1.6.0", - "fs-capacitor": "^6.2.0", + "fs-capacitor": "^8.0.0", "http-errors": "^2.0.0", "object-path": "^0.11.8" }, diff --git a/processRequest.js b/processRequest.mjs similarity index 93% rename from processRequest.js rename to processRequest.mjs index a3f785c..98ae1a4 100644 --- a/processRequest.js +++ b/processRequest.mjs @@ -1,16 +1,15 @@ // @ts-check -"use strict"; +import busboy from "busboy"; +import { WriteStream } from "fs-capacitor"; +import createError from "http-errors"; +import objectPath from "object-path"; -const busboy = require("busboy"); -const { WriteStream } = require("fs-capacitor"); -const createError = require("http-errors"); -const objectPath = require("object-path"); -const GRAPHQL_MULTIPART_REQUEST_SPEC_URL = require("./GRAPHQL_MULTIPART_REQUEST_SPEC_URL.js"); -const ignoreStream = require("./ignoreStream.js"); -const Upload = require("./Upload.js"); +import GRAPHQL_MULTIPART_REQUEST_SPEC_URL from "./GRAPHQL_MULTIPART_REQUEST_SPEC_URL.mjs"; +import ignoreStream from "./ignoreStream.mjs"; +import Upload from "./Upload.mjs"; -/** @typedef {import("./GraphQLUpload.js")} GraphQLUpload */ +/** @typedef {import("./GraphQLUpload.mjs").default} GraphQLUpload */ /** * Processes an incoming @@ -23,7 +22,7 @@ const Upload = require("./Upload.js"); * with appropriate HTTP status codes. Used to create custom middleware. * @type {ProcessRequestFunction} */ -function processRequest( +export default function processRequest( request, response, { @@ -346,8 +345,6 @@ function processRequest( }); } -module.exports = processRequest; - /** * File upload details that are only available after the file’s field in the * [GraphQL multipart request](https://github.com/jaydenseric/graphql-multipart-request-spec) @@ -383,17 +380,19 @@ module.exports = processRequest; /** * {@linkcode FileUploadCreateReadStream} options. * @typedef {object} FileUploadCreateReadStreamOptions - * @prop {string} [options.encoding] Specify an encoding for the - * [`data`](https://nodejs.org/api/stream.html#event-data) chunks to be + * @prop {import("fs-capacitor") + * .ReadStreamOptions["encoding"]} [options.encoding] Specify an encoding for + * the [`data`](https://nodejs.org/api/stream.html#event-data) chunks to be * strings (without splitting multi-byte characters across chunks) instead of * Node.js [`Buffer`](https://nodejs.org/api/buffer.html#buffer) instances. * Supported values depend on the * [`Buffer` implementation](https://github.com/nodejs/node/blob/v18.1.0/lib/buffer.js#L590-L680) * and include `utf8`, `ucs2`, `utf16le`, `latin1`, `ascii`, `base64`, * `base64url`, or `hex`. Defaults to `utf8`. - * @prop {number} [options.highWaterMark] Maximum number of bytes to store in - * the internal buffer before ceasing to read from the underlying resource. - * Defaults to `16384`. + * @prop {import("fs-capacitor") + * .ReadStreamOptions["highWaterMark"]} [options.highWaterMark] Maximum number + * of bytes to store in the internal buffer before ceasing to read from the + * underlying resource. Defaults to `16384`. */ /** diff --git a/processRequest.test.mjs b/processRequest.test.mjs index 5d5a854..46d1e24 100644 --- a/processRequest.test.mjs +++ b/processRequest.test.mjs @@ -12,12 +12,12 @@ import { ReadStream } from "fs-capacitor"; import { createServer } from "http"; import fetch, { File, FormData } from "node-fetch"; -import processRequest from "./processRequest.js"; +import processRequest from "./processRequest.mjs"; import abortingMultipartRequest from "./test/abortingMultipartRequest.mjs"; import Deferred from "./test/Deferred.mjs"; import listen from "./test/listen.mjs"; import streamToString from "./test/streamToString.mjs"; -import Upload from "./Upload.js"; +import Upload from "./Upload.mjs"; /** * Adds `processRequest` tests. @@ -65,7 +65,7 @@ export default (tests) => { /** * @type {{ * variables: { - * file: import("./Upload.js"), + * file: Upload, * }, * }} */ @@ -124,7 +124,7 @@ export default (tests) => { /** * @type {{ * variables: { - * file: import("./Upload.js"), + * file: Upload, * }, * }} */ @@ -186,7 +186,7 @@ export default (tests) => { /** * @type {Array<{ * variables: { - * file: import("./Upload.js"), + * file: Upload, * }, * }>} */ @@ -260,7 +260,7 @@ export default (tests) => { /** * @type {{ * variables: { - * files: Array, + * files: Array, * }, * }} */ @@ -333,8 +333,8 @@ export default (tests) => { /** * @type {{ * variables: { - * fileA: import("./Upload.js"), - * fileB: import("./Upload.js"), + * fileA: Upload, + * fileB: Upload, * }, * }} */ @@ -388,7 +388,7 @@ export default (tests) => { /** * @type {{ * variables: { - * file: import("./Upload.js"), + * file: Upload, * }, * }} */ @@ -446,7 +446,7 @@ export default (tests) => { /** * @type {{ * variables: { - * file: import("./Upload.js"), + * file: Upload, * }, * }} */ @@ -542,7 +542,7 @@ export default (tests) => { /** * @type {{ * variables: { - * files: Array, + * files: Array, * }, * }} */ @@ -615,7 +615,7 @@ export default (tests) => { /** * @type {{ * variables: { - * files: Array, + * files: Array, * }, * }} */ @@ -749,9 +749,9 @@ export default (tests) => { /** * @type {{ * variables: { - * fileA: import("./Upload.js"), - * fileB: import("./Upload.js"), - * fileC: import("./Upload.js"), + * fileA: Upload, + * fileB: Upload, + * fileC: Upload, * }, * }} */ @@ -894,9 +894,9 @@ export default (tests) => { /** * @type {{ * variables: { - * fileA: import("./Upload.js"), - * fileB: import("./Upload.js"), - * fileC: import("./Upload.js"), + * fileA: Upload, + * fileB: Upload, + * fileC: Upload, * }, * }} */ diff --git a/readme.md b/readme.md index 762b68c..5baa16c 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ [![npm version](https://badgen.net/npm/v/graphql-upload)](https://npm.im/graphql-upload) [![CI status](https://github.com/jaydenseric/graphql-upload/workflows/CI/badge.svg)](https://github.com/jaydenseric/graphql-upload/actions) -Middleware and an [`Upload`](./GraphQLUpload.js) scalar to add support for [GraphQL multipart requests](https://github.com/jaydenseric/graphql-multipart-request-spec) (file uploads via queries and mutations) to various Node.js GraphQL servers. +Middleware and an [`Upload`](./GraphQLUpload.mjs) scalar to add support for [GraphQL multipart requests](https://github.com/jaydenseric/graphql-multipart-request-spec) (file uploads via queries and mutations) to various Node.js GraphQL servers. ## Installation @@ -16,13 +16,13 @@ To install [`graphql-upload`](https://npm.im/graphql-upload) and the [`graphql`] npm install graphql-upload graphql ``` -Use the [`graphqlUploadKoa`](./graphqlUploadKoa.js) or [`graphqlUploadExpress`](./graphqlUploadExpress.js) middleware just before GraphQL middleware. Alternatively, use [`processRequest`](./processRequest.js) to create custom middleware. +Use the [`graphqlUploadKoa`](./graphqlUploadKoa.mjs) or [`graphqlUploadExpress`](./graphqlUploadExpress.mjs) middleware just before GraphQL middleware. Alternatively, use [`processRequest`](./processRequest.mjs) to create custom middleware. -A schema built with separate SDL and resolvers (e.g. using [`makeExecutableSchema`](https://www.graphql-tools.com/docs/api/modules/schema_src#makeexecutableschema) from [`@graphql-tools/schema`](https://npm.im/@graphql-tools/schema)) requires the [`Upload`](./GraphQLUpload.js) scalar to be setup. +A schema built with separate SDL and resolvers (e.g. using [`makeExecutableSchema`](https://www.graphql-tools.com/docs/api/modules/schema_src#makeexecutableschema) from [`@graphql-tools/schema`](https://npm.im/@graphql-tools/schema)) requires the [`Upload`](./GraphQLUpload.mjs) scalar to be setup. ## Usage -[Clients implementing the GraphQL multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec#client) upload files as [`Upload`](./GraphQLUpload.js) scalar query or mutation variables. Their resolver values are promises that resolve file upload details for processing and storage. Files are typically streamed into cloud storage but may also be stored in the filesystem. +[Clients implementing the GraphQL multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec#client) upload files as [`Upload`](./GraphQLUpload.mjs) scalar query or mutation variables. Their resolver values are promises that resolve file upload details for processing and storage. Files are typically streamed into cloud storage but may also be stored in the filesystem. See the [example API and client](https://github.com/jaydenseric/apollo-upload-examples). @@ -40,7 +40,7 @@ See the [example API and client](https://github.com/jaydenseric/apollo-upload-ex The [GraphQL multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec) allows a file to be used for multiple query or mutation variables (file deduplication), and for variables to be used in multiple places. GraphQL resolvers need to be able to manage independent file streams. As resolvers are executed asynchronously, it’s possible they will try to process files in a different order than received in the multipart request. -[`busboy`](https://npm.im/busboy) parses multipart request streams. Once the `operations` and `map` fields have been parsed, [`Upload`](./GraphQLUpload.js) scalar values in the GraphQL operations are populated with promises, and the operations are passed down the middleware chain to GraphQL resolvers. +[`busboy`](https://npm.im/busboy) parses multipart request streams. Once the `operations` and `map` fields have been parsed, [`Upload`](./GraphQLUpload.mjs) scalar values in the GraphQL operations are populated with promises, and the operations are passed down the middleware chain to GraphQL resolvers. [`fs-capacitor`](https://npm.im/fs-capacitor) is used to buffer file uploads to the filesystem and coordinate simultaneous reading and writing. As soon as a file upload’s contents begins streaming, its data begins buffering to the filesystem and its associated promise resolves. GraphQL resolvers can then create new streams from the buffer by calling the function `createReadStream`. The buffer is destroyed once all streams have ended or closed and the server has responded to the request. Any remaining buffer files will be cleaned when the process exits. @@ -50,10 +50,10 @@ The [GraphQL multipart request spec](https://github.com/jaydenseric/graphql-mult ## Exports -These CommonJS modules are published to [npm](https://npmjs.com) and exported via the [`package.json`](./package.json) `exports` field: +These ECMAScript modules are published to [npm](https://npmjs.com) and exported via the [`package.json`](./package.json) `exports` field: -- [`GraphQLUpload.js`](./GraphQLUpload.js) -- [`graphqlUploadExpress.js`](./graphqlUploadExpress.js) -- [`graphqlUploadKoa.js`](./graphqlUploadKoa.js) -- [`processRequest.js`](./processRequest.js) -- [`Upload.js`](./Upload.js) +- [`GraphQLUpload.mjs`](./GraphQLUpload.mjs) +- [`graphqlUploadExpress.mjs`](./graphqlUploadExpress.mjs) +- [`graphqlUploadKoa.mjs`](./graphqlUploadKoa.mjs) +- [`processRequest.mjs`](./processRequest.mjs) +- [`Upload.mjs`](./Upload.mjs)