Update supported Node.js versions and dependencies, implement TypeScript JSDoc types.

This commit is contained in:
Jayden Seric 2022-05-24 00:06:08 +10:00
parent a56972742c
commit 86e5609e60
25 changed files with 626 additions and 249 deletions

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"typescript.disableAutomaticTypeAcquisition": true,
"typescript.enablePromptUseWorkspaceTsdk": true,
"typescript.tsdk": "api/node_modules/typescript/lib"
}

View File

@ -1 +1,3 @@
// @ts-check
export default new URL("../uploads/", import.meta.url); export default new URL("../uploads/", import.meta.url);

11
api/jsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"maxNodeModuleJsDepth": 10,
"module": "nodenext",
"noEmit": true,
"strict": true
},
"typeAcquisition": {
"enable": false
}
}

325
api/package-lock.json generated
View File

@ -10,19 +10,22 @@
"apollo-server-koa": "^3.7.0", "apollo-server-koa": "^3.7.0",
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"graphql": "^16.5.0", "graphql": "^16.5.0",
"graphql-upload": "^13.0.0", "graphql-upload": "^14.0.0",
"koa": "^2.13.4", "koa": "^2.13.4",
"make-dir": "^3.1.0", "make-dir": "^3.1.0",
"shortid": "^2.2.16" "shortid": "^2.2.16"
}, },
"devDependencies": { "devDependencies": {
"@types/koa": "^2.13.4",
"@types/node": "^17.0.35",
"eslint": "^8.16.0", "eslint": "^8.16.0",
"eslint-plugin-simple-import-sort": "^7.0.0", "eslint-plugin-simple-import-sort": "^7.0.0",
"nodemon": "^2.0.16", "nodemon": "^2.0.16",
"prettier": "^2.6.2" "prettier": "^2.6.2",
"typescript": "^4.7.1-rc"
}, },
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >= 16.0.0", "node": "^14.17.0 || ^16.0.0 || >= 18.0.0",
"npm": ">= 7" "npm": ">= 7"
}, },
"funding": { "funding": {
@ -283,6 +286,14 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/busboy": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-0.3.2.tgz",
"integrity": "sha512-iEvdm9Z9KdSs/ozuh1Z7ZsXrOl8F4M/CLMXPZHr3QuJ4d6Bjn+HBMC5EMKpwpAo8oi8iK9GZfFoHaIMrrZgwVw==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/connect": { "node_modules/@types/connect": {
"version": "3.4.35", "version": "3.4.35",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
@ -397,6 +408,11 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz",
"integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==" "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg=="
}, },
"node_modules/@types/object-path": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/@types/object-path/-/object-path-0.11.1.tgz",
"integrity": "sha512-219LSCO9HPcoXcRTC6DbCs0FRhZgBnEMzf16RRqkT40WbkKx3mOeQuz3e2XqbfhOz/AHfbru0kzB1n1RCAsIIg=="
},
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
@ -1018,14 +1034,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/cookies/node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/copy-to": { "node_modules/copy-to": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz",
@ -1119,11 +1127,11 @@
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
}, },
"node_modules/depd": { "node_modules/depd": {
"version": "1.1.2", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.8"
} }
}, },
"node_modules/destroy": { "node_modules/destroy": {
@ -1649,23 +1657,36 @@
} }
}, },
"node_modules/graphql-upload": { "node_modules/graphql-upload": {
"version": "13.0.0", "version": "14.0.0",
"resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-13.0.0.tgz", "resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-14.0.0.tgz",
"integrity": "sha512-YKhx8m/uOtKu4Y1UzBFJhbBGJTlk7k4CydlUUiNrtxnwZv0WigbRHP+DVhRNKt7u7DXOtcKZeYJlGtnMXvreXA==", "integrity": "sha512-l3utaN0p/VLUFFrUAijwEfmsSxEolVri5uuD91yhbOkxRD6q5l0rsy1F4Naq4TKWFSKsGciCjyrc1ZhCT2Ew7A==",
"dependencies": { "dependencies": {
"@types/busboy": "^0.3.2",
"@types/node": "*",
"@types/object-path": "^0.11.1",
"busboy": "^0.3.1", "busboy": "^0.3.1",
"fs-capacitor": "^6.2.0", "fs-capacitor": "^6.2.0",
"http-errors": "^1.8.1", "http-errors": "^2.0.0",
"object-path": "^0.11.8" "object-path": "^0.11.8"
}, },
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >= 16.0.0" "node": "^14.17.0 || ^16.0.0 || >= 18.0.0"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/jaydenseric" "url": "https://github.com/sponsors/jaydenseric"
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "0.13.1 - 16" "@types/express": "^4.0.29",
"@types/koa": "^2.11.4",
"graphql": "^16.3.0"
},
"peerDependenciesMeta": {
"@types/express": {
"optional": true
},
"@types/koa": {
"optional": true
}
} }
}, },
"node_modules/has": { "node_modules/has": {
@ -1734,13 +1755,15 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/http-cache-semantics": { "node_modules/http-assert/node_modules/depd": {
"version": "4.1.0", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
"dev": true "engines": {
"node": ">= 0.6"
}
}, },
"node_modules/http-errors": { "node_modules/http-assert/node_modules/http-errors": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
@ -1755,6 +1778,35 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/http-assert/node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"dev": true
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -2100,12 +2152,35 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/koa/node_modules/depd": { "node_modules/koa/node_modules/http-errors": {
"version": "2.0.0", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"dependencies": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
},
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.6"
}
},
"node_modules/koa/node_modules/http-errors/node_modules/depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/koa/node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
"engines": {
"node": ">= 0.6"
} }
}, },
"node_modules/latest-version": { "node_modules/latest-version": {
@ -2623,37 +2698,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/raw-body/node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/raw-body/node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/raw-body/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/rc": { "node_modules/rc": {
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@ -2883,11 +2927,11 @@
"dev": true "dev": true
}, },
"node_modules/statuses": { "node_modules/statuses": {
"version": "1.5.0", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.8"
} }
}, },
"node_modules/streamsearch": { "node_modules/streamsearch": {
@ -3058,6 +3102,19 @@
"is-typedarray": "^1.0.0" "is-typedarray": "^1.0.0"
} }
}, },
"node_modules/typescript": {
"version": "4.7.1-rc",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.1-rc.tgz",
"integrity": "sha512-EQd2NVelDe6ZVc2sO1CSpuSs+RHzY8c2n/kTNQAHw4um/eAXY+ZY4IKoUpNK0wO6C5hN+XcUXR7yqT8VbwwNIQ==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/undefsafe": { "node_modules/undefsafe": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
@ -3528,6 +3585,14 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/busboy": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-0.3.2.tgz",
"integrity": "sha512-iEvdm9Z9KdSs/ozuh1Z7ZsXrOl8F4M/CLMXPZHr3QuJ4d6Bjn+HBMC5EMKpwpAo8oi8iK9GZfFoHaIMrrZgwVw==",
"requires": {
"@types/node": "*"
}
},
"@types/connect": { "@types/connect": {
"version": "3.4.35", "version": "3.4.35",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
@ -3642,6 +3707,11 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz",
"integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==" "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg=="
}, },
"@types/object-path": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/@types/object-path/-/object-path-0.11.1.tgz",
"integrity": "sha512-219LSCO9HPcoXcRTC6DbCs0FRhZgBnEMzf16RRqkT40WbkKx3mOeQuz3e2XqbfhOz/AHfbru0kzB1n1RCAsIIg=="
},
"@types/qs": { "@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
@ -4109,13 +4179,6 @@
"requires": { "requires": {
"depd": "~2.0.0", "depd": "~2.0.0",
"keygrip": "~1.1.0" "keygrip": "~1.1.0"
},
"dependencies": {
"depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
}
} }
}, },
"copy-to": { "copy-to": {
@ -4191,9 +4254,9 @@
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
}, },
"depd": { "depd": {
"version": "1.1.2", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
}, },
"destroy": { "destroy": {
"version": "1.2.0", "version": "1.2.0",
@ -4587,13 +4650,16 @@
} }
}, },
"graphql-upload": { "graphql-upload": {
"version": "13.0.0", "version": "14.0.0",
"resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-13.0.0.tgz", "resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-14.0.0.tgz",
"integrity": "sha512-YKhx8m/uOtKu4Y1UzBFJhbBGJTlk7k4CydlUUiNrtxnwZv0WigbRHP+DVhRNKt7u7DXOtcKZeYJlGtnMXvreXA==", "integrity": "sha512-l3utaN0p/VLUFFrUAijwEfmsSxEolVri5uuD91yhbOkxRD6q5l0rsy1F4Naq4TKWFSKsGciCjyrc1ZhCT2Ew7A==",
"requires": { "requires": {
"@types/busboy": "^0.3.2",
"@types/node": "*",
"@types/object-path": "^0.11.1",
"busboy": "^0.3.1", "busboy": "^0.3.1",
"fs-capacitor": "^6.2.0", "fs-capacitor": "^6.2.0",
"http-errors": "^1.8.1", "http-errors": "^2.0.0",
"object-path": "^0.11.8" "object-path": "^0.11.8"
} }
}, },
@ -4637,6 +4703,30 @@
"requires": { "requires": {
"deep-equal": "~1.0.1", "deep-equal": "~1.0.1",
"http-errors": "~1.8.0" "http-errors": "~1.8.0"
},
"dependencies": {
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
}
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
}
} }
}, },
"http-cache-semantics": { "http-cache-semantics": {
@ -4646,14 +4736,14 @@
"dev": true "dev": true
}, },
"http-errors": { "http-errors": {
"version": "1.8.1", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"requires": { "requires": {
"depd": "~1.1.2", "depd": "2.0.0",
"inherits": "2.0.4", "inherits": "2.0.4",
"setprototypeof": "1.2.0", "setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2", "statuses": "2.0.1",
"toidentifier": "1.0.1" "toidentifier": "1.0.1"
} }
}, },
@ -4898,10 +4988,29 @@
"vary": "^1.1.2" "vary": "^1.1.2"
}, },
"dependencies": { "dependencies": {
"depd": { "http-errors": {
"version": "2.0.0", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
},
"dependencies": {
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
}
}
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
} }
} }
}, },
@ -5291,30 +5400,6 @@
"http-errors": "2.0.0", "http-errors": "2.0.0",
"iconv-lite": "0.4.24", "iconv-lite": "0.4.24",
"unpipe": "1.0.0" "unpipe": "1.0.0"
},
"dependencies": {
"depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
},
"http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"requires": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
}
},
"statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}
} }
}, },
"rc": { "rc": {
@ -5483,9 +5568,9 @@
"dev": true "dev": true
}, },
"statuses": { "statuses": {
"version": "1.5.0", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}, },
"streamsearch": { "streamsearch": {
"version": "0.1.2", "version": "0.1.2",
@ -5610,6 +5695,12 @@
"is-typedarray": "^1.0.0" "is-typedarray": "^1.0.0"
} }
}, },
"typescript": {
"version": "4.7.1-rc",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.1-rc.tgz",
"integrity": "sha512-EQd2NVelDe6ZVc2sO1CSpuSs+RHzY8c2n/kTNQAHw4um/eAXY+ZY4IKoUpNK0wO6C5hN+XcUXR7yqT8VbwwNIQ==",
"dev": true
},
"undefsafe": { "undefsafe": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",

View File

@ -16,29 +16,33 @@
"bugs": "https://github.com/jaydenseric/apollo-upload-examples/issues", "bugs": "https://github.com/jaydenseric/apollo-upload-examples/issues",
"funding": "https://github.com/sponsors/jaydenseric", "funding": "https://github.com/sponsors/jaydenseric",
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >= 16.0.0", "node": "^14.17.0 || ^16.0.0 || >= 18.0.0",
"npm": ">= 7" "npm": ">= 7"
}, },
"dependencies": { "dependencies": {
"apollo-server-koa": "^3.7.0", "apollo-server-koa": "^3.7.0",
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"graphql": "^16.5.0", "graphql": "^16.5.0",
"graphql-upload": "^13.0.0", "graphql-upload": "^14.0.0",
"koa": "^2.13.4", "koa": "^2.13.4",
"make-dir": "^3.1.0", "make-dir": "^3.1.0",
"shortid": "^2.2.16" "shortid": "^2.2.16"
}, },
"devDependencies": { "devDependencies": {
"@types/koa": "^2.13.4",
"@types/node": "^17.0.35",
"eslint": "^8.16.0", "eslint": "^8.16.0",
"eslint-plugin-simple-import-sort": "^7.0.0", "eslint-plugin-simple-import-sort": "^7.0.0",
"nodemon": "^2.0.16", "nodemon": "^2.0.16",
"prettier": "^2.6.2" "prettier": "^2.6.2",
"typescript": "^4.7.1-rc"
}, },
"scripts": { "scripts": {
"dev": "nodemon", "dev": "nodemon",
"start": "node -r dotenv/config server.mjs", "start": "node -r dotenv/config server.mjs",
"eslint": "eslint .", "eslint": "eslint .",
"prettier": "prettier -c .", "prettier": "prettier -c .",
"test": "npm run eslint && npm run prettier" "types": "tsc -p jsconfig.json",
"test": "npm run eslint && npm run prettier && npm run types"
} }
} }

View File

@ -1,3 +1,5 @@
// @ts-check
import { GraphQLNonNull, GraphQLObjectType, GraphQLString } from "graphql"; import { GraphQLNonNull, GraphQLObjectType, GraphQLString } from "graphql";
import UPLOAD_DIRECTORY_URL from "../config/UPLOAD_DIRECTORY_URL.mjs"; import UPLOAD_DIRECTORY_URL from "../config/UPLOAD_DIRECTORY_URL.mjs";

View File

@ -1,5 +1,7 @@
// @ts-check
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql"; import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import GraphQLUpload from "graphql-upload/public/GraphQLUpload.js"; import GraphQLUpload from "graphql-upload/GraphQLUpload.js";
import storeUpload from "../storeUpload.mjs"; import storeUpload from "../storeUpload.mjs";
import FileType from "./FileType.mjs"; import FileType from "./FileType.mjs";
@ -29,15 +31,25 @@ export default new GraphQLObjectType({
), ),
}, },
}, },
async resolve(parent, { files }) { async resolve(
parent,
/**
* @type {{ files: Array<
* Promise<import("graphql-upload/processRequest.js").FileUpload>
* >}}
*/
{ files }
) {
/** @type {Array<string>} */
const storedFileNames = [];
// Ensure an error storing one upload doesnt prevent storing the rest. // Ensure an error storing one upload doesnt prevent storing the rest.
const results = await Promise.allSettled(files.map(storeUpload)); for (const result of await Promise.allSettled(files.map(storeUpload)))
return results.reduce((storedFiles, { value, reason }) => { if ("value" in result) storedFileNames.push(result.value);
if (value) storedFiles.push(value);
// Realistically you would do more than just log an error. // Realistically you would do more than just log an error.
else console.error(`Failed to store upload: ${reason}`); else console.error(`Failed to store upload: ${result.reason}`);
return storedFiles;
}, []); return storedFileNames;
}, },
}, },
}), }),

View File

@ -1,3 +1,5 @@
// @ts-check
import fs from "fs"; import fs from "fs";
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql"; import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";

View File

@ -1,3 +1,5 @@
// @ts-check
import { GraphQLSchema } from "graphql"; import { GraphQLSchema } from "graphql";
import MutationType from "./MutationType.mjs"; import MutationType from "./MutationType.mjs";

View File

@ -1,5 +1,7 @@
// @ts-check
import { ApolloServer } from "apollo-server-koa"; import { ApolloServer } from "apollo-server-koa";
import graphqlUploadKoa from "graphql-upload/public/graphqlUploadKoa.js"; import graphqlUploadKoa from "graphql-upload/graphqlUploadKoa.js";
import Koa from "koa"; import Koa from "koa";
import makeDir from "make-dir"; import makeDir from "make-dir";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
@ -7,9 +9,7 @@ import { fileURLToPath } from "url";
import UPLOAD_DIRECTORY_URL from "./config/UPLOAD_DIRECTORY_URL.mjs"; import UPLOAD_DIRECTORY_URL from "./config/UPLOAD_DIRECTORY_URL.mjs";
import schema from "./schema/index.mjs"; import schema from "./schema/index.mjs";
/** /** Starts the API server. */
* Starts the API server.
*/
async function startServer() { async function startServer() {
// Ensure the upload directory exists. // Ensure the upload directory exists.
await makeDir(fileURLToPath(UPLOAD_DIRECTORY_URL)); await makeDir(fileURLToPath(UPLOAD_DIRECTORY_URL));

View File

@ -1,3 +1,5 @@
// @ts-check
import { createWriteStream, unlink } from "fs"; import { createWriteStream, unlink } from "fs";
import shortId from "shortid"; import shortId from "shortid";
@ -5,7 +7,9 @@ import UPLOAD_DIRECTORY_URL from "./config/UPLOAD_DIRECTORY_URL.mjs";
/** /**
* Stores a GraphQL file upload in the filesystem. * Stores a GraphQL file upload in the filesystem.
* @param {Promise<object>} upload GraphQL file upload. * @param {Promise<
* import("graphql-upload/processRequest.js").FileUpload
* >} upload GraphQL file upload.
* @returns {Promise<string>} Resolves the stored file name. * @returns {Promise<string>} Resolves the stored file name.
*/ */
export default async function storeUpload(upload) { export default async function storeUpload(upload) {

View File

@ -1,6 +1,14 @@
// @ts-check
import { createElement as h } from "react"; import { createElement as h } from "react";
import styles from "./Header.module.css"; import styles from "./Header.module.css";
export const Header = (props) => /**
h("header", { ...props, className: styles.header }); * React component for a header.
* @param {object} props Props.
* @param {import("react").ReactNode} [props.children] Children.
*/
export default function Header({ children }) {
return h("header", { className: styles.header }, children);
}

View File

@ -1,11 +1,19 @@
import Head from "next/head"; // @ts-check
import PropTypes from "prop-types";
import nextHead from "next/head.js";
import { createElement as h, Fragment } from "react"; import { createElement as h, Fragment } from "react";
export const Page = ({ title, children }) => /**
h(Fragment, null, h(Head, null, h("title", null, title)), children); * React component for a page.
* @param {object} props Props.
Page.propTypes = { * @param {string} props.title Title.
title: PropTypes.string.isRequired, * @param {import("react").ReactNode} [props.children] Children.
children: PropTypes.node.isRequired, */
}; export default function Page({ title, children }) {
return h(
Fragment,
null,
h(nextHead.default, null, h("title", null, title)),
children
);
}

View File

@ -1,6 +1,14 @@
// @ts-check
import { createElement as h } from "react"; import { createElement as h } from "react";
import styles from "./Section.module.css"; import styles from "./Section.module.css";
export const Section = (props) => /**
h("section", { ...props, className: styles.section }); * React component for a section.
* @param {object} props Props.
* @param {import("react").ReactNode} [props.children] Children.
*/
export default function Section({ children }) {
return h("section", { className: styles.section }, children);
}

View File

@ -1,4 +1,8 @@
import { gql, useApolloClient, useMutation } from "@apollo/client"; // @ts-check
import { gql } from "@apollo/client/core";
import { useApolloClient } from "@apollo/client/react/hooks/useApolloClient.js";
import { useMutation } from "@apollo/client/react/hooks/useMutation.js";
import ButtonSubmit from "device-agnostic-ui/ButtonSubmit.mjs"; import ButtonSubmit from "device-agnostic-ui/ButtonSubmit.mjs";
import Code from "device-agnostic-ui/Code.mjs"; import Code from "device-agnostic-ui/Code.mjs";
import Fieldset from "device-agnostic-ui/Fieldset.mjs"; import Fieldset from "device-agnostic-ui/Fieldset.mjs";
@ -13,7 +17,8 @@ const SINGLE_UPLOAD_MUTATION = gql`
} }
`; `;
export function UploadBlob() { /** React component for a uploading a blob. */
export default function UploadBlob() {
const [name, setName] = useState(""); const [name, setName] = useState("");
const [content, setContent] = useState(""); const [content, setContent] = useState("");
const [singleUploadMutation, { loading }] = useMutation( const [singleUploadMutation, { loading }] = useMutation(
@ -21,18 +26,36 @@ export function UploadBlob() {
); );
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const onNameChange = ({ target: { value } }) => setName(value); /**
const onContentChange = ({ target: { value } }) => setContent(value); * @type {import("react").ChangeEventHandler<
const onSubmit = (event) => { * HTMLInputElement | HTMLTextAreaElement
* >}
*/
function onNameChange({ target: { value } }) {
setName(value);
}
/**
* @type {import("react").ChangeEventHandler<
* HTMLInputElement | HTMLTextAreaElement
* >}
*/
function onContentChange({ target: { value } }) {
setContent(value);
}
/** @type {import("react").FormEventHandler<HTMLFormElement>} */
function onSubmit(event) {
event.preventDefault(); event.preventDefault();
const file = new Blob([content], { type: "text/plain" }); singleUploadMutation({
file.name = `${name}.txt`; variables: {
file: new File([content], `${name}.txt`, { type: "text/plain" }),
singleUploadMutation({ variables: { file } }).then(() => { },
}).then(() => {
apolloClient.resetStore(); apolloClient.resetStore();
}); });
}; }
return h( return h(
"form", "form",

View File

@ -1,4 +1,8 @@
import { gql, useApolloClient, useMutation } from "@apollo/client"; // @ts-check
import { gql } from "@apollo/client/core";
import { useApolloClient } from "@apollo/client/react/hooks/useApolloClient.js";
import { useMutation } from "@apollo/client/react/hooks/useMutation.js";
import { createElement as h } from "react"; import { createElement as h } from "react";
const SINGLE_UPLOAD_MUTATION = gql` const SINGLE_UPLOAD_MUTATION = gql`
@ -9,20 +13,18 @@ const SINGLE_UPLOAD_MUTATION = gql`
} }
`; `;
export function UploadFile() { /** React component for a uploading a single file. */
export default function UploadFile() {
const [uploadFileMutation] = useMutation(SINGLE_UPLOAD_MUTATION); const [uploadFileMutation] = useMutation(SINGLE_UPLOAD_MUTATION);
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const onChange = ({ /** @type {import("react").ChangeEventHandler<HTMLInputElement>} */
target: { function onChange({ target: { validity, files } }) {
validity, if (validity.valid && files && files[0])
files: [file], uploadFileMutation({ variables: { file: files[0] } }).then(() => {
}, apolloClient.resetStore();
}) => });
validity.valid && }
uploadFileMutation({ variables: { file } }).then(() => {
apolloClient.resetStore();
});
return h("input", { type: "file", required: true, onChange }); return h("input", { type: "file", required: true, onChange });
} }

View File

@ -1,4 +1,8 @@
import { gql, useApolloClient, useMutation } from "@apollo/client"; // @ts-check
import { gql } from "@apollo/client/core";
import { useApolloClient } from "@apollo/client/react/hooks/useApolloClient.js";
import { useMutation } from "@apollo/client/react/hooks/useMutation.js";
import { createElement as h } from "react"; import { createElement as h } from "react";
const MULTIPLE_UPLOAD_MUTATION = gql` const MULTIPLE_UPLOAD_MUTATION = gql`
@ -9,15 +13,33 @@ const MULTIPLE_UPLOAD_MUTATION = gql`
} }
`; `;
export function UploadFileList() { /**
const [multipleUploadMutation] = useMutation(MULTIPLE_UPLOAD_MUTATION); * @typedef {{
* multipleUpload: {
* id: string,
* },
* }} MultipleUploadMutationData
*/
/** React component for a uploading a file list. */
export default function UploadFileList() {
const [multipleUploadMutation] =
/**
* @type {import("@apollo/client/react/types/types.js").MutationTuple<
* MultipleUploadMutationData,
* { files: FileList }
* >}
*/
(useMutation(MULTIPLE_UPLOAD_MUTATION));
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const onChange = ({ target: { validity, files } }) => /** @type {import("react").ChangeEventHandler<HTMLInputElement>} */
validity.valid && function onChange({ target: { validity, files } }) {
multipleUploadMutation({ variables: { files } }).then(() => { if (validity.valid && files && files[0])
apolloClient.resetStore(); multipleUploadMutation({ variables: { files } }).then(() => {
}); apolloClient.resetStore();
});
}
return h("input", { type: "file", multiple: true, required: true, onChange }); return h("input", { type: "file", multiple: true, required: true, onChange });
} }

View File

@ -1,4 +1,7 @@
import { gql, useQuery } from "@apollo/client"; // @ts-check
import { gql } from "@apollo/client/core";
import { useQuery } from "@apollo/client/react/hooks/useQuery.js";
import Scroll from "device-agnostic-ui/Scroll.mjs"; import Scroll from "device-agnostic-ui/Scroll.mjs";
import Table from "device-agnostic-ui/Table.mjs"; import Table from "device-agnostic-ui/Table.mjs";
import { createElement as h } from "react"; import { createElement as h } from "react";
@ -12,8 +15,24 @@ const UPLOADS_QUERY = gql`
} }
`; `;
export function Uploads() { /**
const { data: { uploads = [] } = {} } = useQuery(UPLOADS_QUERY); * @typedef {{
* uploads: Array<{
* id: string,
* url: string
* }>,
* }} UploadsQueryData
*/
/** React component for displaying uploads. */
export default function Uploads() {
const { data: { uploads = [] } = {} } =
/**
* @type {import("@apollo/client/react/types/types.js").QueryResult<
* UploadsQueryData
* >}
*/
(useQuery(UPLOADS_QUERY));
return h( return h(
Scroll, Scroll,

11
app/jsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"maxNodeModuleJsDepth": 10,
"module": "nodenext",
"noEmit": true,
"strict": true
},
"typeAcquisition": {
"enable": false
}
}

View File

@ -1,3 +1,5 @@
// @ts-check
export default { export default {
env: { env: {
API_URI: process.env.API_URI, API_URI: process.env.API_URI,

116
app/package-lock.json generated
View File

@ -12,12 +12,14 @@
"device-agnostic-ui": "~10.0.0", "device-agnostic-ui": "~10.0.0",
"graphql": "^16.5.0", "graphql": "^16.5.0",
"next": "^12.1.6", "next": "^12.1.6",
"prop-types": "^15.8.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2" "react-dom": "^17.0.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.17.0", "@babel/eslint-parser": "^7.17.0",
"@types/node": "^17.0.35",
"@types/react": "^17.0.45",
"@types/react-dom": "^17.0.17",
"babel-plugin-graphql-tag": "^3.3.0", "babel-plugin-graphql-tag": "^3.3.0",
"eslint": "^8.16.0", "eslint": "^8.16.0",
"eslint-plugin-react-hooks": "^4.5.0", "eslint-plugin-react-hooks": "^4.5.0",
@ -25,10 +27,11 @@
"prettier": "^2.6.2", "prettier": "^2.6.2",
"stylelint": "^14.8.3", "stylelint": "^14.8.3",
"stylelint-config-recommended": "^7.0.0", "stylelint-config-recommended": "^7.0.0",
"stylelint-prettier": "^2.0.0" "stylelint-prettier": "^2.0.0",
"typescript": "^4.7.1-rc"
}, },
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >= 16.0.0", "node": "^14.17.0 || ^16.0.0 || >= 18.0.0",
"npm": ">= 7" "npm": ">= 7"
}, },
"funding": { "funding": {
@ -764,6 +767,12 @@
"integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
"dev": true "dev": true
}, },
"node_modules/@types/node": {
"version": "17.0.35",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz",
"integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==",
"dev": true
},
"node_modules/@types/normalize-package-data": { "node_modules/@types/normalize-package-data": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
@ -776,6 +785,38 @@
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
"dev": true "dev": true
}, },
"node_modules/@types/prop-types": {
"version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
"dev": true
},
"node_modules/@types/react": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.45.tgz",
"integrity": "sha512-YfhQ22Lah2e3CHPsb93tRwIGNiSwkuz1/blk4e6QrWS0jQzCSNbGLtOEYhPg02W0yGTTmpajp7dCTbBAMN3qsg==",
"dev": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
"version": "17.0.17",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz",
"integrity": "sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==",
"dev": true,
"dependencies": {
"@types/react": "^17"
}
},
"node_modules/@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
"dev": true
},
"node_modules/@wry/context": { "node_modules/@wry/context": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz", "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz",
@ -1181,6 +1222,12 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/csstype": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==",
"dev": true
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -3637,6 +3684,19 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/typescript": {
"version": "4.7.1-rc",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.1-rc.tgz",
"integrity": "sha512-EQd2NVelDe6ZVc2sO1CSpuSs+RHzY8c2n/kTNQAHw4um/eAXY+ZY4IKoUpNK0wO6C5hN+XcUXR7yqT8VbwwNIQ==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/uri-js": { "node_modules/uri-js": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@ -4234,6 +4294,12 @@
"integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
"dev": true "dev": true
}, },
"@types/node": {
"version": "17.0.35",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz",
"integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==",
"dev": true
},
"@types/normalize-package-data": { "@types/normalize-package-data": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
@ -4246,6 +4312,38 @@
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
"dev": true "dev": true
}, },
"@types/prop-types": {
"version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
"dev": true
},
"@types/react": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.45.tgz",
"integrity": "sha512-YfhQ22Lah2e3CHPsb93tRwIGNiSwkuz1/blk4e6QrWS0jQzCSNbGLtOEYhPg02W0yGTTmpajp7dCTbBAMN3qsg==",
"dev": true,
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"@types/react-dom": {
"version": "17.0.17",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz",
"integrity": "sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==",
"dev": true,
"requires": {
"@types/react": "^17"
}
},
"@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
"dev": true
},
"@wry/context": { "@wry/context": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz", "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz",
@ -4530,6 +4628,12 @@
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true "dev": true
}, },
"csstype": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==",
"dev": true
},
"debug": { "debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -6316,6 +6420,12 @@
"integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
"dev": true "dev": true
}, },
"typescript": {
"version": "4.7.1-rc",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.1-rc.tgz",
"integrity": "sha512-EQd2NVelDe6ZVc2sO1CSpuSs+RHzY8c2n/kTNQAHw4um/eAXY+ZY4IKoUpNK0wO6C5hN+XcUXR7yqT8VbwwNIQ==",
"dev": true
},
"uri-js": { "uri-js": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",

View File

@ -16,22 +16,24 @@
"bugs": "https://github.com/jaydenseric/apollo-upload-examples/issues", "bugs": "https://github.com/jaydenseric/apollo-upload-examples/issues",
"funding": "https://github.com/sponsors/jaydenseric", "funding": "https://github.com/sponsors/jaydenseric",
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >= 16.0.0", "node": "^14.17.0 || ^16.0.0 || >= 18.0.0",
"npm": ">= 7" "npm": ">= 7"
}, },
"browserslist": "Node 12.22 - 13 and Node < 13, Node 14.17 - 15 and Node < 15, Node >= 16, > 0.5%, not OperaMini all, not IE > 0, not dead", "browserslist": "Node 14.17 - 15 and Node < 15, Node 16 - 17 and Node < 17, Node >= 18, > 0.5%, not OperaMini all, not IE > 0, not dead",
"dependencies": { "dependencies": {
"@apollo/client": "^3.6.4", "@apollo/client": "^3.6.4",
"apollo-upload-client": "^17.0.0", "apollo-upload-client": "^17.0.0",
"device-agnostic-ui": "~10.0.0", "device-agnostic-ui": "~10.0.0",
"graphql": "^16.5.0", "graphql": "^16.5.0",
"next": "^12.1.6", "next": "^12.1.6",
"prop-types": "^15.8.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2" "react-dom": "^17.0.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.17.0", "@babel/eslint-parser": "^7.17.0",
"@types/node": "^17.0.35",
"@types/react": "^17.0.45",
"@types/react-dom": "^17.0.17",
"babel-plugin-graphql-tag": "^3.3.0", "babel-plugin-graphql-tag": "^3.3.0",
"eslint": "^8.16.0", "eslint": "^8.16.0",
"eslint-plugin-react-hooks": "^4.5.0", "eslint-plugin-react-hooks": "^4.5.0",
@ -39,7 +41,8 @@
"prettier": "^2.6.2", "prettier": "^2.6.2",
"stylelint": "^14.8.3", "stylelint": "^14.8.3",
"stylelint-config-recommended": "^7.0.0", "stylelint-config-recommended": "^7.0.0",
"stylelint-prettier": "^2.0.0" "stylelint-prettier": "^2.0.0",
"typescript": "^4.7.1-rc"
}, },
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@ -48,6 +51,7 @@
"eslint": "eslint .", "eslint": "eslint .",
"stylelint": "stylelint '**/*.css'", "stylelint": "stylelint '**/*.css'",
"prettier": "prettier -c .", "prettier": "prettier -c .",
"test": "npm run eslint && npm run stylelint && npm run prettier" "types": "tsc -p jsconfig.json",
"test": "npm run eslint && npm run stylelint && npm run prettier && npm run types"
} }
} }

View File

@ -1,3 +1,5 @@
// @ts-check
import "device-agnostic-ui/theme.css"; import "device-agnostic-ui/theme.css";
import "device-agnostic-ui/global.css"; import "device-agnostic-ui/global.css";
import "device-agnostic-ui/Button.css"; import "device-agnostic-ui/Button.css";
@ -11,12 +13,18 @@ import "device-agnostic-ui/Scroll.css";
import "device-agnostic-ui/Table.css"; import "device-agnostic-ui/Table.css";
import "device-agnostic-ui/Textbox.css"; import "device-agnostic-ui/Textbox.css";
import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client"; import { InMemoryCache } from "@apollo/client/cache/inmemory/inMemoryCache.js";
import { ApolloClient } from "@apollo/client/core/ApolloClient.js";
import { ApolloProvider } from "@apollo/client/react/context/ApolloProvider.js";
import { createUploadLink } from "apollo-upload-client"; import { createUploadLink } from "apollo-upload-client";
import Head from "next/head"; import nextApp from "next/app.js";
import PropTypes from "prop-types"; import nextHead from "next/head.js";
import { createElement as h } from "react"; import { createElement as h, Fragment } from "react";
/**
* Creates an Apollo Client instance.
* @param {{ [key: string]: unknown }} [cache] Apollo Client initial cache.
*/
const createApolloClient = (cache = {}) => const createApolloClient = (cache = {}) =>
new ApolloClient({ new ApolloClient({
ssrMode: typeof window === "undefined", ssrMode: typeof window === "undefined",
@ -24,64 +32,75 @@ const createApolloClient = (cache = {}) =>
link: createUploadLink({ uri: process.env.API_URI }), link: createUploadLink({ uri: process.env.API_URI }),
}); });
const App = ({ /**
* React component for the Next.js app.
* @param {import("next/app.js").AppProps & AppCustomProps} props Props.
*/
function App({
Component, Component,
pageProps, pageProps,
apolloCache, apolloCache,
apolloClient = createApolloClient(apolloCache), apolloClient = createApolloClient(apolloCache),
}) => }) {
h( return h(ApolloProvider, {
ApolloProvider, client: apolloClient,
{ client: apolloClient }, children: h(
h( Fragment,
Head,
null, null,
h("meta", { h(
name: "viewport", nextHead.default,
content: "width=device-width, initial-scale=1", null,
}), h("meta", {
h("meta", { name: "color-scheme", content: "light dark" }), name: "viewport",
h("meta", { name: "theme-color", content: "white" }), content: "width=device-width, initial-scale=1",
h("link", { rel: "manifest", href: "/manifest.webmanifest" }) }),
h("meta", { name: "color-scheme", content: "light dark" }),
h("meta", { name: "theme-color", content: "white" }),
h("link", { rel: "manifest", href: "/manifest.webmanifest" })
),
h(Component, pageProps)
), ),
h(Component, pageProps) });
); }
App.getInitialProps = async (context) => { if (typeof window === "undefined")
const props = { App.getInitialProps =
pageProps: context.Component.getInitialProps /** @param {import("next/app.js").AppContext} context */
? await context.Component.getInitialProps(context) async function getInitialProps(context) {
: {}, const apolloClient = createApolloClient();
}; const [props, { default: ReactDOMServer }, { getMarkupFromTree }] =
await Promise.all([
nextApp.default.getInitialProps(context),
import("react-dom/server.js"),
import("@apollo/client/react/ssr/getDataFromTree.js"),
]);
if (context.ctx.req) { try {
const apolloClient = createApolloClient(); await getMarkupFromTree({
try { tree: h(App, {
const { getDataFromTree } = await import("@apollo/client/react/ssr"); ...props,
await getDataFromTree( apolloClient,
h(App, { router: context.router,
...props, Component: context.Component,
apolloClient, }),
router: context.router, renderFunction: ReactDOMServer.renderToStaticMarkup,
Component: context.Component, });
}) } catch (error) {
); // Prevent crash from GraphQL errors.
} catch (error) { console.error(error);
// Prevent crash from GraphQL errors. }
console.error(error);
}
props.apolloCache = apolloClient.cache.extract(); return {
} ...props,
apolloCache: apolloClient.cache.extract(),
return props; };
}; };
App.propTypes = {
Component: PropTypes.elementType.isRequired,
pageProps: PropTypes.object,
apolloCache: PropTypes.object,
apolloClient: PropTypes.instanceOf(ApolloClient),
};
export default App; export default App;
/**
* Next.js app custom props.
* @typedef {object} AppCustomProps
* @prop {{ [key: string]: unknown }} [apolloCache] Apollo Client initial cache.
* @prop {ApolloClient<any>} apolloClient Apollo Client.
*/

View File

@ -1,15 +1,17 @@
// @ts-check
import Code from "device-agnostic-ui/Code.mjs"; import Code from "device-agnostic-ui/Code.mjs";
import Heading from "device-agnostic-ui/Heading.mjs"; import Heading from "device-agnostic-ui/Heading.mjs";
import Margin from "device-agnostic-ui/Margin.mjs"; import Margin from "device-agnostic-ui/Margin.mjs";
import { createElement as h } from "react"; import { createElement as h } from "react";
import { Header } from "../components/Header.mjs"; import Header from "../components/Header.mjs";
import { Page } from "../components/Page.mjs"; import Page from "../components/Page.mjs";
import { Section } from "../components/Section.mjs"; import Section from "../components/Section.mjs";
import { UploadBlob } from "../components/UploadBlob.mjs"; import UploadBlob from "../components/UploadBlob.mjs";
import { UploadFile } from "../components/UploadFile.mjs"; import UploadFile from "../components/UploadFile.mjs";
import { UploadFileList } from "../components/UploadFileList.mjs"; import UploadFileList from "../components/UploadFileList.mjs";
import { Uploads } from "../components/Uploads.mjs"; import Uploads from "../components/Uploads.mjs";
export default function IndexPage() { export default function IndexPage() {
return h( return h(

4
app/typings.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module "*.module.css" {
const classes: { [key: string]: string };
export default classes;
}