From 350878c94530a2ff6c512bb664607ea272549298 Mon Sep 17 00:00:00 2001 From: James Cook Date: Thu, 4 May 2023 11:55:55 +0100 Subject: [PATCH 01/15] fix: response typing typo --- .changeset/green-lies-push.md | 5 +++++ src/types.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/green-lies-push.md diff --git a/.changeset/green-lies-push.md b/.changeset/green-lies-push.md new file mode 100644 index 0000000..d186d9b --- /dev/null +++ b/.changeset/green-lies-push.md @@ -0,0 +1,5 @@ +--- +"classcharts-api": patch +--- + +Fixed internal typing typo diff --git a/src/types.ts b/src/types.ts index b424369..53cd230 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,9 +4,9 @@ * Helper type to define response from ClassCharts * @internal */ -export type ClassChartsResponse = { +export type ClassChartsResponse = { data: Data; - meta: Error; + meta: Meta; error?: string; success: number; }; From d3ba7bdcecfa45707b28beacd68e4d148774e5a4 Mon Sep 17 00:00:00 2001 From: James Cook Date: Thu, 4 May 2023 20:14:55 +0100 Subject: [PATCH 02/15] chore: fix readme examples --- readme.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/readme.md b/readme.md index 522b4fe..cb65470 100644 --- a/readme.md +++ b/readme.md @@ -23,8 +23,6 @@ async function main() { ); console.log(await client.getActivity()); console.log(await client.getStudentInfo()); - console.log(await client.getActivity()); - console.log(await client.getActivity()); } main(); From c3315ad05469e1fc17ed1ed9ffaaae9a6ccb3840 Mon Sep 17 00:00:00 2001 From: James Cook Date: Thu, 4 May 2023 20:15:37 +0100 Subject: [PATCH 03/15] chore: fix readme examples --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index cb65470..c8fa0c2 100644 --- a/readme.md +++ b/readme.md @@ -17,8 +17,8 @@ async function main() { await client.login(); console.log( await client.getBehaviour({ - fromDate: "20/01/2000", - toDate: "01/02/2000", + from: "20/01/2000", + to: "01/02/2000", }) ); console.log(await client.getActivity()); From 9382479ab6cd6d735a3497cc9f3575d8d332eb6e Mon Sep 17 00:00:00 2001 From: James Date: Thu, 4 May 2023 21:56:19 +0100 Subject: [PATCH 04/15] feat: New docs! (#28) --- .gitignore | 4 +- .prettierignore | 1 - docs/.nojekyll | 0 docs/README.md | 285 +++++++++++++++++++++++++++++++++++++++++++++ docs/index.html | 38 ++++++ readme.md | 36 +++--- typedoc.config.cjs | 2 +- 7 files changed, 340 insertions(+), 26 deletions(-) create mode 100644 docs/.nojekyll create mode 100644 docs/README.md create mode 100644 docs/index.html diff --git a/.gitignore b/.gitignore index d09bd88..815af20 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,4 @@ dist .pnp.* tests/config.json -tests/sandbox.js - -docs/ \ No newline at end of file +tests/sandbox.js \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 2c98acd..78ac5b6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,4 @@ dist -docs node_modules pnpm-lock.yaml .prettierrc.json diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..868b1c3 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,285 @@ +

+

ClassCharts API JS

+

+ A typescript wrapper for getting information from the Classcharts API +

+

+

+ Source +   •   + Issues +   •   + NPM +   •   + Discord +   •   + TypeDoc +   •   + API Docs +

+ +# Introduction + +The ClassCharts API is a typescript wrapper around the ClassCharts API. It allows you to easily make requests to the ClassCharts API without having to worry about the underlying implementation of making requests. + +## Help + +For any help with the library, please join the [discord](https://discord.gg/DTcwugcgZ2) where you can ask questions and get help from the community. + +# Installation + +## Requirements + +- Node.js 16 or newer + +## NPM + +```bash +npm install classcharts-api # npm +yarn add classcharts-api # yarn +pnpm add classcharts-api # pnpm +``` + +# Logging In + +Before making any requests, you must login to the client. This will get you a session ID which will be used for all requests. + +## Student Client + +```typescript +import { StudentClient } from "classcharts-api"; + +// Date of birth MUST in the format DD/MM/YYYY +const client = new StudentClient("classchartsCode", "01/1/2000"); +await client.login(); +``` + +## Parent Client + +```typescript +import { ParentClient } from "classcharts-api"; + +const client = new ParentClient("username", "password"); +await client.login(); +``` + +# Universal Methods + +All the following methods can be used on both the student and parent client. Each example expects the client to be already logged in. + +## `.getStudentInfo` + +```typescript +const studentInfo = await client.getStudentInfo(); +console.log(studentInfo); +/** +{ + success: 1, + data: { + user: { + id: 2339528, + ... + } + }, + meta: { + session_id: '5vf2v7n5uk9jftrxaarrik39vk6yjm48', + ... + } +} +*/ +``` + +## `.getActivity` + +```typescript +// Dates must be in format YYYY-MM-DD +const activity = await client.getActivity({ + from: "2023-04-01", + to: "2023-05-10", + last_id: "12", +}); +console.log(activity); +``` + +## `.getFullActivity` + +```typescript +// Dates must be in format YYYY-MM-DD +const activity = await client.getFullActivity({ + from: "2023-04-01", + to: "2023-05-10", +}); +console.log(activity); +``` + +## `.getBehaviour` + +Gets behaviour for a given date range. + +```typescript +// Dates must be in format YYYY-MM-DD +const behaviour = await client.getBehaviour({ + from: "2023-04-01", + to: "2023-05-10", +}); +console.log(behaviour); + +/** +{ + "success": 1, + "data": { + "timeline": [ + { + "positive": 426, + ... + }, + ], + ... + "meta": { + "start_date": "2023-04-01T00:00:00+00:00", + ... + } +} +*/ +``` + +## `.getHomeworks` + +Gets homeworks for a given date range. + +```typescript +// Dates must be in format YYYY-MM-DD +const homeworks = await client.getHomeworks({ + from: "2023-04-01", + to: "2023-05-10", + displayDate: 'issue_date' // Can be 'due_date' or 'issue_date' +}); +console.log(homeworks); + +/** +{ + success: 1, + data: [ + { + lesson: '7A/Pe1', + ... + }, + ], + meta: { + start_date: '2023-04-01T00:00:00+00:00', + ... + } +} + +``` + +## `.getLessons` + +Gets lessons for a specific date. + +```typescript +// Dates must be in format YYYY-MM-DD +const lessons = await client.getLessons({ + date: "2023-04-01", +}); +console.log(lessons); + +/** +{ + "success": 1, + "data": [ + { + "teacher_name": "Mr J Doe", + ... + } + ... + ], + "meta": { + "dates": [ + "2023-05-04" + ], + ... + } +} +*/ +``` + +## `.getBadges` + +Gets all earned badges. + +```typescript +const badges = await client.getBadges(); +console.log(badges); + +/** +{ + success: 1, + data: [ + { + id: 123, + name: 'Big Badge', + ... + }, + ... + ], + meta: [] +} +*/ +``` + +## `.getAnnouncements` + +Gets all announcements. + +```typescript +const announcements = await client.getAnnouncements(); +console.log(announcements); +``` + +## `.getDetentions` + +Gets all detentions. + +```typescript +const detentions = await client.getDetentions(); +console.log(detentions); +``` + +## `.getAttendance` + +Gets attendance. + +```typescript +const attendance = await client.getAttendance(); +console.log(attendance); +``` + +# Parent Specific Methods + +## `.getPupils` + +Gets a list of all pupils the parent has access to. + +```typescript +const pupils = await client.getPupils(); +console.log(pupils); +/** +[ + { + id: 123, + name: 'John Doe', + ... + }, + ... +] +*/ +``` + +## `.selectPupil` + +Selects a pupil to make subsequent requests for. + +```typescript +await client.selectPupil(123); +``` diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..5d950b1 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,38 @@ + + + + + Classcharts-API + + + + + + + +
+ + + + + + + diff --git a/readme.md b/readme.md index c8fa0c2..5395263 100644 --- a/readme.md +++ b/readme.md @@ -1,29 +1,23 @@ -# Classcharts API +

Classcharts API

+
+Discord + npm + NPM + npm + node-current +
-A client for the classcharts API +

A typescript wrapper for getting information from the Classcharts API.

+ +# Links - [Documentation](https://classchartsapi.github.io/classcharts-api-js/) -- [API Documentation (with library examples)](https://classchartsapi.github.io/api-docs/#introduction) - [Discord](https://discord.gg/DTcwugcgZ2) -# Examples +# Contributing -Docs are very much a WIP, for any help with the library, please join the discord above +Contributions are welcome! There are lots of API endpoints which we simply do not have access to to implement, so if you have access to them, please consider contributing! If you have any questions, feel free to ask in the [discord](https://discord.gg/DTcwugcgZ2). -```typescript -import { StudentClient } from "classcharts-api"; -async function main() { - const client = new StudentClient("classchartsCode", "01/1/2000"); - await client.login(); - console.log( - await client.getBehaviour({ - from: "20/01/2000", - to: "01/02/2000", - }) - ); - console.log(await client.getActivity()); - console.log(await client.getStudentInfo()); -} +# Help -main(); -``` +For any help with the library, please join the [discord](https://discord.gg/DTcwugcgZ2) where you can ask questions and get help from the community. diff --git a/typedoc.config.cjs b/typedoc.config.cjs index f1cac71..9ecd167 100644 --- a/typedoc.config.cjs +++ b/typedoc.config.cjs @@ -13,7 +13,7 @@ module.exports = { Github: "https://github.com/classchartsapi/classcharts-api-js", }, includeVersion: true, - out: "docs", + out: "docs/typedoc", sort: "required-first", umamiOptions: { src: "https://umami.jaminit.co.uk/script.js", From 06300ec95a2a14533d4934dbc9f72cab0f0ca12f Mon Sep 17 00:00:00 2001 From: James Cook Date: Thu, 4 May 2023 21:56:56 +0100 Subject: [PATCH 05/15] chore: update readme name --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 5395263..53c505e 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -

Classcharts API

+

Classcharts API JS

Discord npm From 451f80062cff0b27d91b49b18b57ac8d3833ccd0 Mon Sep 17 00:00:00 2001 From: James Cook Date: Thu, 4 May 2023 22:18:40 +0100 Subject: [PATCH 06/15] chore: add required node version to package.json --- .changeset/lucky-horses-guess.md | 5 +++++ package.json | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .changeset/lucky-horses-guess.md diff --git a/.changeset/lucky-horses-guess.md b/.changeset/lucky-horses-guess.md new file mode 100644 index 0000000..5b79a87 --- /dev/null +++ b/.changeset/lucky-horses-guess.md @@ -0,0 +1,5 @@ +--- +"classcharts-api": patch +--- + +Specify the required node version diff --git a/package.json b/package.json index 28ce8a6..5f1dd83 100644 --- a/package.json +++ b/package.json @@ -60,5 +60,8 @@ }, "files": [ "dist/**" - ] + ], + "engines": { + "node": ">=16" + } } From 86df2e09279770ec21ed80698df797e8f1e1adfd Mon Sep 17 00:00:00 2001 From: James Date: Thu, 4 May 2023 22:39:55 +0100 Subject: [PATCH 07/15] feat: Small docs improvements (#29) --- .gitignore | 3 ++- docs/README.md | 12 ++++++++++++ docs/index.html | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 815af20..2b61141 100644 --- a/.gitignore +++ b/.gitignore @@ -118,4 +118,5 @@ dist .pnp.* tests/config.json -tests/sandbox.js \ No newline at end of file + +docs/typedoc \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 868b1c3..18817b4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -36,7 +36,13 @@ For any help with the library, please join the [discord](https://discord.gg/DTcw ```bash npm install classcharts-api # npm +``` + +```bash yarn add classcharts-api # yarn +``` + +```bash pnpm add classcharts-api # pnpm ``` @@ -230,6 +236,8 @@ console.log(badges); ## `.getAnnouncements` +?> This method does not include `meta` in the response, since I do not have access to this endpoint to test it. If you have access to this endpoint, please open a PR to add the `meta` response. Thanks! + Gets all announcements. ```typescript @@ -239,6 +247,8 @@ console.log(announcements); ## `.getDetentions` +?> This method does not include `meta` in the response, since I do not have access to this endpoint to test it. If you have access to this endpoint, please open a PR to add the `meta` response. Thanks! + Gets all detentions. ```typescript @@ -248,6 +258,8 @@ console.log(detentions); ## `.getAttendance` +?> This method does not include `meta` in the response, since I do not have access to this endpoint to test it. If you have access to this endpoint, please open a PR to add the `meta` response. Thanks! + Gets attendance. ```typescript diff --git a/docs/index.html b/docs/index.html index 5d950b1..7d11319 100644 --- a/docs/index.html +++ b/docs/index.html @@ -34,5 +34,7 @@ + + From a3e078b0b755d38883aa978f2ef1ab1198e743cb Mon Sep 17 00:00:00 2001 From: James Cook Date: Tue, 9 May 2023 19:24:03 +0100 Subject: [PATCH 08/15] fix: handle parsing json errors --- .changeset/modern-rabbits-film.md | 5 +++++ src/core/baseClient.ts | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 .changeset/modern-rabbits-film.md diff --git a/.changeset/modern-rabbits-film.md b/.changeset/modern-rabbits-film.md new file mode 100644 index 0000000..98493e4 --- /dev/null +++ b/.changeset/modern-rabbits-film.md @@ -0,0 +1,5 @@ +--- +"classcharts-api": minor +--- + +Throw more description JSON parsing errors diff --git a/src/core/baseClient.ts b/src/core/baseClient.ts index ca6f2fa..f17ce26 100644 --- a/src/core/baseClient.ts +++ b/src/core/baseClient.ts @@ -112,10 +112,14 @@ export class BaseClient { } } const request = await ky(path, requestOptions); - const responseJSON = (await request.json()) as ClassChartsResponse< - unknown, - unknown - >; + let responseJSON: ClassChartsResponse; + try { + responseJSON = await request.json(); + } catch (err) { + throw new Error( + "Error parsing JSON. Returned response: " + (await request.text()) + ); + } if (responseJSON.success == 0) { throw new Error(responseJSON.error); } From f11c7c564d5a671a026a33074f6ea8ffd5f27f7a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 19:27:01 +0100 Subject: [PATCH 09/15] Version Packages (#27) Co-authored-by: github-actions[bot] --- .changeset/green-lies-push.md | 5 ----- .changeset/lucky-horses-guess.md | 5 ----- .changeset/modern-rabbits-film.md | 5 ----- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- 5 files changed, 12 insertions(+), 16 deletions(-) delete mode 100644 .changeset/green-lies-push.md delete mode 100644 .changeset/lucky-horses-guess.md delete mode 100644 .changeset/modern-rabbits-film.md diff --git a/.changeset/green-lies-push.md b/.changeset/green-lies-push.md deleted file mode 100644 index d186d9b..0000000 --- a/.changeset/green-lies-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"classcharts-api": patch ---- - -Fixed internal typing typo diff --git a/.changeset/lucky-horses-guess.md b/.changeset/lucky-horses-guess.md deleted file mode 100644 index 5b79a87..0000000 --- a/.changeset/lucky-horses-guess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"classcharts-api": patch ---- - -Specify the required node version diff --git a/.changeset/modern-rabbits-film.md b/.changeset/modern-rabbits-film.md deleted file mode 100644 index 98493e4..0000000 --- a/.changeset/modern-rabbits-film.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"classcharts-api": minor ---- - -Throw more description JSON parsing errors diff --git a/CHANGELOG.md b/CHANGELOG.md index 721936f..3b6eb55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # classcharts-api +## 2.2.0 + +### Minor Changes + +- a3e078b: Throw more description JSON parsing errors + +### Patch Changes + +- 350878c: Fixed internal typing typo +- 451f800: Specify the required node version + ## 2.1.3 ### Patch Changes diff --git a/package.json b/package.json index 5f1dd83..557d45f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "classcharts-api", "type": "module", - "version": "2.1.3", + "version": "2.2.0", "license": "ISC", "author": { "name": "James Cook", From 00e3a13821c2899f1c5fe534d4ffbec7d88b7431 Mon Sep 17 00:00:00 2001 From: James Cook Date: Sun, 14 May 2023 00:59:21 +0100 Subject: [PATCH 10/15] chore: typo fixes + config files --- .eslintignore | 2 +- .eslintrc.js => .eslintrc.cjs | 0 .idea/.gitignore | 5 ++ .idea/classcharts-api-js.iml | 12 ++++ .idea/codeStyles/Project.xml | 58 ++++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 ++ .idea/inspectionProfiles/Project_Default.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/prettier.xml | 6 ++ .idea/vcs.xml | 6 ++ docs/index.html | 2 +- package.json | 2 +- src/core/baseClient.ts | 8 +-- src/core/parentClient.ts | 6 +- src/core/studentClient.ts | 10 ++-- tests/baseClient.test.ts | 2 + tsconfig.json | 2 +- 17 files changed, 124 insertions(+), 16 deletions(-) rename .eslintrc.js => .eslintrc.cjs (100%) create mode 100644 .idea/.gitignore create mode 100644 .idea/classcharts-api-js.iml create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/prettier.xml create mode 100644 .idea/vcs.xml diff --git a/.eslintignore b/.eslintignore index 4462152..2e37f93 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,5 @@ dist/ docs/ node_modules/ -.eslintrc.js +.eslintrc.cjs tsconfig.json \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 100% rename from .eslintrc.js rename to .eslintrc.cjs diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/classcharts-api-js.iml b/.idea/classcharts-api-js.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/classcharts-api-js.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..f986f2f --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ac983d9 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000..b0c1c68 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 7d11319..e005a08 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,7 +2,7 @@ - Classcharts-API + ClassCharts-API { if (!this.email) throw new Error("Email not inputted"); @@ -33,7 +33,7 @@ export class ParentClient extends BaseClient { formData.append("email", this.email); formData.append("logintype", "existing"); formData.append("password", this.password); - formData.append("recaptcha-token", "no-token-avaliable"); + formData.append("recaptcha-token", "no-token-available"); const headers = new Headers({ "Content-Type": "application/x-www-form-urlencoded", }); @@ -45,7 +45,7 @@ export class ParentClient extends BaseClient { }); if (response.status != 302 || !response.headers.get("set-cookie")) throw new Error( - "Unauthenticated: Classcharts returned an error: " + + "Unauthenticated: ClassCharts returned an error: " + response.status + " " + response.statusText diff --git a/src/core/studentClient.ts b/src/core/studentClient.ts index 750c9b9..0ab9fc9 100644 --- a/src/core/studentClient.ts +++ b/src/core/studentClient.ts @@ -8,7 +8,7 @@ import ky from "ky-universal"; */ export class StudentClient extends BaseClient { /** - * @property studentCode Classcharts student code + * @property studentCode ClassCharts student code * @internal */ private studentCode = ""; @@ -20,7 +20,7 @@ export class StudentClient extends BaseClient { /** * - * @param studentCode Classcharts student code + * @param studentCode ClassCharts student code * @param dateOfBirth Student's date of birth */ constructor(studentCode: string, dateOfBirth?: string) { @@ -30,7 +30,7 @@ export class StudentClient extends BaseClient { } /** - * Authenticates with classcharts + * Authenticates with ClassCharts */ async login(): Promise { if (!this.studentCode) throw new Error("Student Code not inputted"); @@ -39,7 +39,7 @@ export class StudentClient extends BaseClient { formData.append("code", this.studentCode.toUpperCase()); formData.append("dob", this.dateOfBirth); formData.append("remember_me", "1"); - formData.append("recaptcha-token", "no-token-avaliable"); + formData.append("recaptcha-token", "no-token-available"); const request = await ky(BASE_URL + "/student/login", { method: "POST", body: formData, @@ -49,7 +49,7 @@ export class StudentClient extends BaseClient { }); if (request.status != 302 || !request.headers.get("set-cookie")) { throw new Error( - "Unauthenticated: Classcharts returned an error: " + + "Unauthenticated: ClassCharts returned an error: " + request.status + " " + request.statusText diff --git a/tests/baseClient.test.ts b/tests/baseClient.test.ts index 0a0b145..189cb24 100644 --- a/tests/baseClient.test.ts +++ b/tests/baseClient.test.ts @@ -1,4 +1,6 @@ import { StudentClient } from "../src"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore import { code, dob } from "./config.json"; import "jest-extended"; const client = new StudentClient(code, dob); diff --git a/tsconfig.json b/tsconfig.json index 346da08..8bc8621 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,7 @@ "noUnusedLocals": true, "noUnusedParameters": true, "skipLibCheck": true, - "isolatedModules": true + "isolatedModules": true, }, "include": ["./src/**/*"] } From 6552c282d5e8045bbb11fa980f39ede55db4017f Mon Sep 17 00:00:00 2001 From: James Cook Date: Tue, 30 May 2023 18:37:24 +0100 Subject: [PATCH 11/15] feat: use native fetch --- .changeset/small-papayas-live.md | 5 +++ package.json | 5 +-- pnpm-lock.yaml | 76 -------------------------------- src/core/baseClient.ts | 12 +++-- src/core/parentClient.ts | 3 +- src/core/studentClient.ts | 4 +- 6 files changed, 13 insertions(+), 92 deletions(-) create mode 100644 .changeset/small-papayas-live.md diff --git a/.changeset/small-papayas-live.md b/.changeset/small-papayas-live.md new file mode 100644 index 0000000..69114d3 --- /dev/null +++ b/.changeset/small-papayas-live.md @@ -0,0 +1,5 @@ +--- +"classcharts-api": minor +--- + +Migrate to native fetch diff --git a/package.json b/package.json index b813e2f..70bed7e 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,6 @@ "test": "jest", "release": "pnpm run build && changeset publish" }, - "dependencies": { - "ky-universal": "^0.11.0" - }, "devDependencies": { "@changesets/cli": "^2.26.1", "@types/jest": "^29.5.1", @@ -62,6 +59,6 @@ "dist/**" ], "engines": { - "node": ">=16" + "node": ">=18" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3d9f67..577c3d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,10 +1,5 @@ lockfileVersion: '6.0' -dependencies: - ky-universal: - specifier: ^0.11.0 - version: 0.11.0(ky@0.33.3) - devDependencies: '@changesets/cli': specifier: ^2.26.1 @@ -1200,13 +1195,6 @@ packages: eslint-visitor-keys: 3.4.0 dev: true - /abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - dependencies: - event-target-shim: 5.0.1 - dev: false - /acorn-jsx@5.3.2(acorn@8.8.2): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1630,11 +1618,6 @@ packages: stream-transform: 2.1.3 dev: true - /data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - dev: false - /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -1949,11 +1932,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - dev: false - /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -2033,14 +2011,6 @@ packages: bser: 2.1.1 dev: true - /fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.2.1 - dev: false - /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -2096,13 +2066,6 @@ packages: is-callable: 1.2.7 dev: true - /formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - dependencies: - fetch-blob: 3.2.0 - dev: false - /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -3089,26 +3052,6 @@ packages: engines: {node: '>=6'} dev: true - /ky-universal@0.11.0(ky@0.33.3): - resolution: {integrity: sha512-65KyweaWvk+uKKkCrfAf+xqN2/epw1IJDtlyCPxYffFCMR8u1sp2U65NtWpnozYfZxQ6IUzIlvUcw+hQ82U2Xw==} - engines: {node: '>=14.16'} - peerDependencies: - ky: '>=0.31.4' - web-streams-polyfill: '>=3.2.1' - peerDependenciesMeta: - web-streams-polyfill: - optional: true - dependencies: - abort-controller: 3.0.0 - ky: 0.33.3 - node-fetch: 3.3.1 - dev: false - - /ky@0.33.3: - resolution: {integrity: sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==} - engines: {node: '>=14.16'} - dev: false - /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -3302,20 +3245,6 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - dev: false - - /node-fetch@3.3.1: - resolution: {integrity: sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - dev: false - /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true @@ -4191,11 +4120,6 @@ packages: defaults: 1.0.4 dev: true - /web-streams-polyfill@3.2.1: - resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} - engines: {node: '>= 8'} - dev: false - /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: diff --git a/src/core/baseClient.ts b/src/core/baseClient.ts index d2531d7..f89ccd3 100644 --- a/src/core/baseClient.ts +++ b/src/core/baseClient.ts @@ -1,4 +1,3 @@ -import ky, { type Options as KyOptions } from "ky-universal"; import type { ActivityResponse, AnnouncementsResponse, @@ -87,7 +86,7 @@ export class BaseClient { */ public async makeAuthedRequest( path: string, - kyOptions: KyOptions, + fetchOptions: RequestInit, options?: { revalidateToken?: boolean } ) { if (!this.sessionId) throw new Error("No session ID"); @@ -98,20 +97,19 @@ export class BaseClient { options.revalidateToken = true; } const requestOptions = { - ...kyOptions, + ...fetchOptions, headers: { Cookie: this?.authCookies?.join(";") ?? [], Authorization: "Basic " + this.sessionId, - ...kyOptions.headers, + ...fetchOptions.headers, }, - credentials: undefined, - } satisfies KyOptions; + } satisfies RequestInit; if (options?.revalidateToken === true && this.lastPing) { if (Date.now() - this.lastPing + 5000 > PING_INTERVAL) { await this.getNewSessionId(); } } - const request = await ky(path, requestOptions); + const request = await fetch(path, requestOptions); let responseJSON: ClassChartsResponse; try { responseJSON = await request.json(); diff --git a/src/core/parentClient.ts b/src/core/parentClient.ts index 93f9c17..dad9fa5 100644 --- a/src/core/parentClient.ts +++ b/src/core/parentClient.ts @@ -1,4 +1,3 @@ -import ky from "ky-universal"; import type { GetPupilsResponse } from "../types.js"; import { BaseClient } from "./baseClient.js"; @@ -37,7 +36,7 @@ export class ParentClient extends BaseClient { const headers = new Headers({ "Content-Type": "application/x-www-form-urlencoded", }); - const response = await ky(BASE_URL + "/parent/login", { + const response = await fetch(BASE_URL + "/parent/login", { method: "POST", body: formData, headers: headers, diff --git a/src/core/studentClient.ts b/src/core/studentClient.ts index 0ab9fc9..d8d6747 100644 --- a/src/core/studentClient.ts +++ b/src/core/studentClient.ts @@ -1,7 +1,6 @@ import { API_BASE_STUDENT, BASE_URL } from "../utils/consts.js"; import { BaseClient } from "./baseClient.js"; import { parseCookies } from "../utils/utils.js"; -import ky from "ky-universal"; /** * Student Client @@ -40,11 +39,10 @@ export class StudentClient extends BaseClient { formData.append("dob", this.dateOfBirth); formData.append("remember_me", "1"); formData.append("recaptcha-token", "no-token-available"); - const request = await ky(BASE_URL + "/student/login", { + const request = await fetch(BASE_URL + "/student/login", { method: "POST", body: formData, redirect: "manual", - throwHttpErrors: false, credentials: undefined, }); if (request.status != 302 || !request.headers.get("set-cookie")) { From 3fe6a7e493d09dcb2baf6d1dd4f8ae65b64f0b7c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 18:38:32 +0100 Subject: [PATCH 12/15] chore: Version Packages (#30) Co-authored-by: github-actions[bot] --- .changeset/small-papayas-live.md | 5 ----- CHANGELOG.md | 6 ++++++ package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/small-papayas-live.md diff --git a/.changeset/small-papayas-live.md b/.changeset/small-papayas-live.md deleted file mode 100644 index 69114d3..0000000 --- a/.changeset/small-papayas-live.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"classcharts-api": minor ---- - -Migrate to native fetch diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b6eb55..1d7abb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # classcharts-api +## 2.3.0 + +### Minor Changes + +- 6552c28: Migrate to native fetch + ## 2.2.0 ### Minor Changes diff --git a/package.json b/package.json index 70bed7e..96db6a7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "classcharts-api", "type": "module", - "version": "2.2.0", + "version": "2.3.0", "license": "ISC", "author": { "name": "James Cook", From 2184c86f3c1418bb5d557019b523668c69b87148 Mon Sep 17 00:00:00 2001 From: James Cook Date: Tue, 30 May 2023 20:53:54 +0100 Subject: [PATCH 13/15] docs: update nodejs version requirement --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 18817b4..4af083e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -30,7 +30,7 @@ For any help with the library, please join the [discord](https://discord.gg/DTcw ## Requirements -- Node.js 16 or newer +- Node.js 18 or newer ## NPM From 40b1683d94a1e5425a07bbec8ebd4ce4d28a39c4 Mon Sep 17 00:00:00 2001 From: James Cook Date: Thu, 1 Jun 2023 19:45:40 +0100 Subject: [PATCH 14/15] fix: export types first see: https://publint.dev/rules#exports_types_should_be_first --- .changeset/red-lobsters-destroy.md | 5 +++++ package.json | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/red-lobsters-destroy.md diff --git a/.changeset/red-lobsters-destroy.md b/.changeset/red-lobsters-destroy.md new file mode 100644 index 0000000..9bf5e97 --- /dev/null +++ b/.changeset/red-lobsters-destroy.md @@ -0,0 +1,5 @@ +--- +"classcharts-api": patch +--- + +Export types first diff --git a/package.json b/package.json index 96db6a7..f956301 100644 --- a/package.json +++ b/package.json @@ -48,9 +48,9 @@ "types": "./dist/index.d.ts", "exports": { ".": { + "types": "./dist/index.d.ts", "import": "./dist/index.js", - "require": "./dist/index.js", - "types": "./dist/index.d.ts" + "require": "./dist/index.js" }, "./types": "./dist/index.d.ts", "./package.json": "./package.json" From 0cabed9778ce432a787d473d466479787035b2e5 Mon Sep 17 00:00:00 2001 From: James Cook Date: Thu, 1 Jun 2023 19:54:26 +0100 Subject: [PATCH 15/15] chore: repo cleanup --- .devcontainer/Dockerfile | 16 ------ .devcontainer/devcontainer.json | 24 -------- .github/workflows/{typedoc.yml => docs.yml} | 10 ++-- .idea/.gitignore | 5 -- .idea/classcharts-api-js.iml | 12 ---- .idea/codeStyles/Project.xml | 58 -------------------- .idea/codeStyles/codeStyleConfig.xml | 5 -- .idea/inspectionProfiles/Project_Default.xml | 6 -- .idea/modules.xml | 8 --- .idea/prettier.xml | 6 -- .idea/vcs.xml | 6 -- .prettierignore | 7 ++- .vscode/extensions.json | 6 +- 13 files changed, 10 insertions(+), 159 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .devcontainer/devcontainer.json rename .github/workflows/{typedoc.yml => docs.yml} (75%) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/classcharts-api-js.iml delete mode 100644 .idea/codeStyles/Project.xml delete mode 100644 .idea/codeStyles/codeStyleConfig.xml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/prettier.xml delete mode 100644 .idea/vcs.xml diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 7f0043e..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/javascript-node/.devcontainer/base.Dockerfile - -# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 16, 14, 12, 16-bullseye, 14-bullseye, 12-bullseye, 16-buster, 14-buster, 12-buster -ARG VARIANT="16-bullseye" -FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT} - -# [Optional] Uncomment this section to install additional OS packages. -# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends - -# [Optional] Uncomment if you want to install an additional version of node using nvm -# ARG EXTRA_NODE_VERSION=10 -# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" - -# [Optional] Uncomment if you want to install more global node modules -RUN su node -c "npm install -g pnpm np" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index af46c9e..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,24 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: -// https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/javascript-node -{ - "name": "Node.js", - "build": { - "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick a Node version: 16, 14, 12. - // Append -bullseye or -buster to pin to an OS version. - // Use -bullseye variants on local arm64/Apple Silicon. - "args": { - "VARIANT": "16-bullseye" - } - }, - // Set *default* container specific settings.json values on container create. - "settings": {}, - // Add the IDs of extensions you want installed when the container is created. - "extensions": ["dbaeumer.vscode-eslint"], - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "pnpm install", - // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - "remoteUser": "node" -} diff --git a/.github/workflows/typedoc.yml b/.github/workflows/docs.yml similarity index 75% rename from .github/workflows/typedoc.yml rename to .github/workflows/docs.yml index eab1064..dc0f84e 100644 --- a/.github/workflows/typedoc.yml +++ b/.github/workflows/docs.yml @@ -1,4 +1,4 @@ -name: Typedoc +name: Docs on: push: @@ -19,21 +19,21 @@ jobs: - uses: pnpm/action-setup@v2 with: version: 8.2.0 - - name: Retrieve the cached "node_modules" directory (if present) + - name: Retrieve the cache uses: actions/cache@v3 id: node-cache with: path: node_modules key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - - name: Install dependencies (if the cached directory was not found) + - name: Install dependencies if: steps.node-cache.outputs.cache-hit != 'true' run: pnpm install - - name: Test to see if the project compiles + - name: Build run: pnpm run build - - name: Create the docs directory locally in CI + - name: Generate typedoc run: pnpm generateDocs - name: Deploy 🚀 diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index b58b603..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/classcharts-api-js.iml b/.idea/classcharts-api-js.iml deleted file mode 100644 index 24643cc..0000000 --- a/.idea/classcharts-api-js.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index f986f2f..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 03d9549..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index ac983d9..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml deleted file mode 100644 index b0c1c68..0000000 --- a/.idea/prettier.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 78ac5b6..16ac6bc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,6 @@ -dist -node_modules +dist/ +node_modules/ pnpm-lock.yaml .prettierrc.json -.eslint.js \ No newline at end of file +.eslint.js +CHANGELOG.md \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json index e7cd390..1d7ac85 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,3 @@ { - "recommendations": [ - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "EditorConfig.EditorConfig" - ] + "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] }