From bfd33ce3af295fc37114f1aa275bcd9949264757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Mon, 19 Aug 2024 18:11:01 +0200 Subject: [PATCH 01/27] Remove depreacted Log hook --- .../architecture/architecture-overview.md | 6 +- docs/docs/architecture/hooks.md | 3 +- docs/docs/common/logging.md | 33 ----- ...setting-up-a-simple-application.feature.ts | 6 +- packages/core/src/common/utils/index.ts | 1 - .../core/src/common/utils/log.hook.spec.ts | 123 ------------------ packages/core/src/common/utils/log.hook.ts | 60 --------- packages/core/src/index.ts | 2 - 8 files changed, 9 insertions(+), 225 deletions(-) delete mode 100644 packages/core/src/common/utils/log.hook.spec.ts delete mode 100644 packages/core/src/common/utils/log.hook.ts diff --git a/docs/docs/architecture/architecture-overview.md b/docs/docs/architecture/architecture-overview.md index 11a2b5fb9b..6d395d3511 100644 --- a/docs/docs/architecture/architecture-overview.md +++ b/docs/docs/architecture/architecture-overview.md @@ -76,7 +76,7 @@ Controllers may have sub-controllers. Hooks can be attached to the controllers o Here's an example of what a FoalTS application may look like. ```typescript -import { Context, controller, Get, HttpResponseNotFound, HttpResponseOK, Log } from '@foal/core'; +import { Context, controller, Get, Hook, HttpResponseNotFound, HttpResponseOK } from '@foal/core'; import { JWTRequired } from '@foal/jwt'; @JWTRequired() @@ -105,7 +105,9 @@ class ApiController { } } -@Log('Receiving a request...') +@Hook(() => { + console.log('Receiving a request...') +}) class AppController { subControllers = [ controller('/api', ApiController) diff --git a/docs/docs/architecture/hooks.md b/docs/docs/architecture/hooks.md index ee868b7d9a..5bea7760a8 100644 --- a/docs/docs/architecture/hooks.md +++ b/docs/docs/architecture/hooks.md @@ -23,7 +23,6 @@ They improve code readability and make unit testing easier. Foal provides a number of hooks to handle the most common scenarios. - `ValidateBody`, `ValidateHeader`, `ValidatePathParam`, `ValidateCookie` and `ValidateQueryParam` validate the format of the incoming HTTP requests (see [Validation](../common/validation-and-sanitization.md)). -- `Log` displays information on the request (see [Logging](../common/logging.md)). - `JWTRequired`, `JWTOptional`, `UseSessions` authenticate the user by filling the `ctx.user` property. - `PermissionRequired` restricts the route access to certain users. @@ -73,7 +72,7 @@ If the user makes a POST request to `/products` whereas she/he is not authentica > If you need to apply a hook globally, you just have to make it decorate the root controller: `AppController`. > > ```typescript -> @Log('Request body:', { body: true }) +> @UseSessions() > export class AppController { > // ... > } diff --git a/docs/docs/common/logging.md b/docs/docs/common/logging.md index 8bbb66ebc2..bb2a61d6a1 100644 --- a/docs/docs/common/logging.md +++ b/docs/docs/common/logging.md @@ -274,36 +274,3 @@ logger.addTransport((level: 'debug'|'warn'|'info'|'error', log: string) => { // Do something }) ``` - -## Logging Hook (deprecated) - -> This hook is deprecated and will be removed in a next release. Use the `Logger` service in a custom hook instead. - -FoalTS provides a convenient hook for logging debug messages: `Log(message: string, options: LogOptions = {})`. - -```typescript -interface LogOptions { - body?: boolean; - params?: boolean; - headers?: string[]|boolean; - query?: boolean; -} -``` - -*Example:* -```typescript -import { Get, HttpResponseOK, Log } from '@foal/core'; - -@Log('AppController', { - body: true, - headers: [ 'X-CSRF-Token' ], - params: true, - query: true -}) -export class AppController { - @Get() - index() { - return new HttpResponseOK(); - } -} -``` diff --git a/packages/acceptance-tests/src/docs/architecture/architecture-overview/setting-up-a-simple-application.feature.ts b/packages/acceptance-tests/src/docs/architecture/architecture-overview/setting-up-a-simple-application.feature.ts index 58ab23456f..2bce691a82 100644 --- a/packages/acceptance-tests/src/docs/architecture/architecture-overview/setting-up-a-simple-application.feature.ts +++ b/packages/acceptance-tests/src/docs/architecture/architecture-overview/setting-up-a-simple-application.feature.ts @@ -9,9 +9,9 @@ import { controller, createApp, Get, + // Hook, HttpResponseNotFound, HttpResponseOK, - // Log, } from '@foal/core'; import { getSecretOrPrivateKey, JWTRequired } from '@foal/jwt'; @@ -58,7 +58,9 @@ describe('Feature: Setting up a simple application', () => { } // Commented in this test to avoid noise in the terminal. - // @Log('Receiving a request...') + // @Hook(() => { + // console.log('Receiving a request...') + // }) class AppController { subControllers = [ controller('/api', ApiController) diff --git a/packages/core/src/common/utils/index.ts b/packages/core/src/common/utils/index.ts index 57c5dcd9f9..8c5c1a7dc2 100644 --- a/packages/core/src/common/utils/index.ts +++ b/packages/core/src/common/utils/index.ts @@ -1,5 +1,4 @@ export { controller } from './controller.util'; export { displayServerURL } from './display-server-url.util'; export { isInFile } from './is-in-file.util'; -export { Log, LogOptions } from './log.hook'; export { streamToBuffer } from './stream-to-buffer'; diff --git a/packages/core/src/common/utils/log.hook.spec.ts b/packages/core/src/common/utils/log.hook.spec.ts deleted file mode 100644 index b428de27ab..0000000000 --- a/packages/core/src/common/utils/log.hook.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -// std -import { strictEqual } from 'assert'; -import { mock } from 'node:test'; - -// FoalTS -import { Context, getHookFunction, ServiceManager, Logger } from '../../core'; -import { Log } from './log.hook'; - -describe('Log', () => { - - let logFn: (message?: any, ...optionalParams: any[]) => void; - let msgs: any[]; - - beforeEach(() => { - msgs = []; - logFn = (...args) => msgs.push(args); - }); - - afterEach(() => { - mock.reset(); - }) - - it('should log a deprecation message.', () => { - const hook = getHookFunction(Log('foo', { logFn })); - - const ctx = new Context({}); - const services = new ServiceManager(); - - const logger = services.get(Logger); - const loggerMock = mock.method(logger, 'warn').mock; - - hook(ctx, services); - - strictEqual(loggerMock.callCount(), 1); - strictEqual( - loggerMock.calls[0].arguments[0], - 'Using the @Log hook is deprecated. Use the Logger service in a custom hook instead.' - ); - }); - - it('should log the message.', () => { - const hook = getHookFunction(Log('foo', { logFn })); - - const ctx = new Context({}); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 1); - strictEqual(msgs[0][0], 'foo'); - }); - - it('should log the request body if options.body = true.', () => { - const hook = getHookFunction(Log('foo', { body: true, logFn })); - - const body = { foo: 'bar' }; - const ctx = new Context({ body }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 2); - strictEqual(msgs[1][0], 'Body: '); - strictEqual(msgs[1][1], body); - }); - - it('should log the request params if options.params = true.', () => { - const hook = getHookFunction(Log('foo', { params: true, logFn })); - - const params = { foo: 'bar' }; - const ctx = new Context({ params }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 2); - strictEqual(msgs[1][0], 'Params: '); - strictEqual(msgs[1][1], params); - }); - - it('should log the request query if options.query = true.', () => { - const hook = getHookFunction(Log('foo', { query: true, logFn })); - - const query = { foo: 'bar' }; - const ctx = new Context({ query }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 2); - strictEqual(msgs[1][0], 'Query: '); - strictEqual(msgs[1][1], query); - }); - - it('should log the request headers if options.headers is a string array.', () => { - const hook = getHookFunction(Log('foo', { headers: [ 'my-header1', 'my-header2' ], logFn })); - - const headers = { - // According to RFC 7230, each header field consists of a case-INsensitive field name. - 'My-header2': 'header 2', - 'my-header1': 'header 1', - 'my-header3': 'header 3' - }; - const ctx = new Context({ headers }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 3); - strictEqual(msgs[1][0], 'my-header1: '); - strictEqual(msgs[1][1], 'header 1'); - strictEqual(msgs[2][0], 'my-header2: '); - // Test the case - strictEqual(msgs[2][1], 'header 2'); - }); - - it('should log all the request headers if options.headers = true.', () => { - const hook = getHookFunction(Log('foo', { headers: true, logFn })); - - const headers = { - 'my-header1': 'header 1', - 'my-header2': 'header 2', - 'my-header3': 'header 3' - }; - const ctx = new Context({ headers }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 2); - strictEqual(msgs[1][0], 'Headers: '); - strictEqual(msgs[1][1], headers); - }); - -}); diff --git a/packages/core/src/common/utils/log.hook.ts b/packages/core/src/common/utils/log.hook.ts deleted file mode 100644 index e414a7925d..0000000000 --- a/packages/core/src/common/utils/log.hook.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Context, Hook, HookDecorator, Logger } from '../../core'; - -/** - * Options of the `Log` hook. - * - * @export - * @interface LogOptions - */ -export interface LogOptions { - body?: boolean; - params?: boolean; - headers?: string[]|boolean; - query?: boolean; - logFn?: (message?: any, ...optionalParams: any[]) => void; -} - -/** - * Hook logging a message with optional information on the HTTP request. - * - * @param message The message to print. - * @param options Options to specify which information on the HTTP request should be printed. - */ - -/** - * Hook factory logging a message with optional information on the HTTP request. - * - * @export - * @deprecated Use the Logger service in a custom hook instead. - * @param {string} message - The message to print on each request. - * @param {LogOptions} [options={}] - Options to specify which information on the HTTP request should be printed. - * @returns {HookDecorator} The hook. - */ -export function Log(message: string, options: LogOptions = {}): HookDecorator { - const logFn = options.logFn || console.log; - return Hook((ctx: Context, services) => { - const logger = services.get(Logger); - logger.warn('Using the @Log hook is deprecated. Use the Logger service in a custom hook instead.'); - - logFn(message); - if (options.body) { - logFn('Body: ', ctx.request.body); - } - if (options.params) { - logFn('Params: ', ctx.request.params); - } - if (options.query) { - logFn('Query: ', ctx.request.query); - } - if (options.headers === true) { - logFn('Headers: ', ctx.request.headers); - } else if (Array.isArray(options.headers)) { - for (const header of options.headers) { - const headerName = Object.keys(ctx.request.headers).find( - head => header.toLowerCase() === head.toLowerCase() // Header names are case insensitive. - ); - logFn(`${header}: `, headerName === undefined ? undefined : ctx.request.headers[headerName]); - } - } - }); -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 346fa2760e..99997606b2 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -17,8 +17,6 @@ export { AsyncService, File, FileList, - Log, - LogOptions, UserRequired, ValidateBody, ValidateCookie, From e8bd827cd2aed529729c83e4f1d92b35b972371c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 14:45:02 +0200 Subject: [PATCH 02/27] [Blog] Remove the deprecated Log hook --- .../assets/version-5.0-is-here/banner.png | Bin 0 -> 16990 bytes docs/blog/version-5.0-release-notes.md | 19 ++++++++++++++++++ .../version-5.0-release-notes.png | Bin 0 -> 34686 bytes 3 files changed, 19 insertions(+) create mode 100644 docs/blog/assets/version-5.0-is-here/banner.png create mode 100644 docs/blog/version-5.0-release-notes.md create mode 100644 docs/static/blog/twitter-banners/version-5.0-release-notes.png diff --git a/docs/blog/assets/version-5.0-is-here/banner.png b/docs/blog/assets/version-5.0-is-here/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..2270aaebc4178fc0595c539181f854793ccb3e4f GIT binary patch literal 16990 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 Wt>f5a{e~jos;;b~RHN|UoBs#q5 literal 0 HcmV?d00001 diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md new file mode 100644 index 0000000000..b3aecf93e8 --- /dev/null +++ b/docs/blog/version-5.0-release-notes.md @@ -0,0 +1,19 @@ +--- +title: Version 5.0 release notes +author: Loïc Poullain +author_title: Creator of FoalTS. Software engineer. +author_url: https://loicpoullain.com +author_image_url: https://avatars1.githubusercontent.com/u/13604533?v=4 +image: blog/twitter-banners/version-5.0-release-notes.png +tags: [release] +--- + +![Banner](./assets/version-5.0-is-here/banner.png) + +Version 5.0 of [Foal](https://foalts.org/) is out! + + + +## Removal of depreacted components + +- The deprecated hook `@Log` has been removed. To replace it, you can use the `Logger` service in a custom `@Hook`. \ No newline at end of file diff --git a/docs/static/blog/twitter-banners/version-5.0-release-notes.png b/docs/static/blog/twitter-banners/version-5.0-release-notes.png new file mode 100644 index 0000000000000000000000000000000000000000..118c134a68a844798a0cd0bb3c11daf0b952d6ef GIT binary patch literal 34686 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 jqNg&d2>QstTlgVw@egS* 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 Date: Mon, 19 Aug 2024 18:15:01 +0200 Subject: [PATCH 03/27] Remove CLI run-script alias --- docs/docs/cli/shell-scripts.md | 2 +- packages/cli/package.json | 6 +++--- packages/cli/src/index.ts | 3 +-- .../get-command-line-arguments.util.spec.ts | 6 +++--- .../get-command-line-arguments.util.ts | 0 packages/cli/src/{run-script => run}/index.ts | 0 .../cli/src/{run-script => run}/run-script.spec.ts | 10 +++++----- packages/cli/src/{run-script => run}/run-script.ts | 0 8 files changed, 13 insertions(+), 14 deletions(-) rename packages/cli/src/{run-script => run}/get-command-line-arguments.util.spec.ts (90%) rename packages/cli/src/{run-script => run}/get-command-line-arguments.util.ts (100%) rename packages/cli/src/{run-script => run}/index.ts (100%) rename packages/cli/src/{run-script => run}/run-script.spec.ts (98%) rename packages/cli/src/{run-script => run}/run-script.ts (100%) diff --git a/docs/docs/cli/shell-scripts.md b/docs/docs/cli/shell-scripts.md index 28f99c7a2d..e139eef109 100644 --- a/docs/docs/cli/shell-scripts.md +++ b/docs/docs/cli/shell-scripts.md @@ -55,7 +55,7 @@ npm run build Then you can execute it with this command: ```shell -npx foal run my-script # or npx foal run-script my-script +npx foal run my-script ``` > You can also provide additionnal arguments to your script (for example: `npx foal run my-script foo=1 bar='[ 3, 4 ]'`). The default template in the generated scripts shows you how to handle such behavior. diff --git a/packages/cli/package.json b/packages/cli/package.json index 91b6cda7ed..98788259f0 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -5,15 +5,15 @@ "main": "./lib/index.js", "types": "./lib/index.d.ts", "scripts": { - "test": "npm run test:generators && npm run test:run-script && npm run test:create-secret && npm run test:rmdir && npm run test:fs", + "test": "npm run test:generators && npm run test:run && npm run test:create-secret && npm run test:rmdir && npm run test:fs", "test:fs": "mocha --file \"./src/test.ts\" --require ts-node/register \"./src/generate/file-system.spec.ts\"", "dev:test:fs": "mocha --file \"./src/test.ts\" --require ts-node/register --watch --extension ts \"./src/generate/file-system.spec.ts\"", "test:generators": "mocha --file \"./src/test.ts\" --require ts-node/register \"./src/generate/generators/**/*.spec.ts\"", "dev:test:generators": "mocha --file \"./src/test.ts\" --require ts-node/register --watch --extension ts \"./src/generate/generators/**/*.spec.ts\"", "test:rmdir": "mocha --file \"./src/test.ts\" --require ts-node/register \"./src/rmdir/**/*.spec.ts\"", "dev:test:rmdir": "mocha --file \"./src/test.ts\" --require ts-node/register --watch --extension ts \"./src/rmdir/**/*.spec.ts\"", - "test:run-script": "mocha --file \"./src/test.ts\" --require ts-node/register \"./src/run-script/**/*.spec.ts\"", - "dev:test:run-script": "mocha --file \"./src/test.ts\" --require ts-node/register --watch --extension ts \"./src/run-script/**/*.spec.ts\"", + "test:run": "mocha --file \"./src/test.ts\" --require ts-node/register \"./src/run/**/*.spec.ts\"", + "dev:test:run": "mocha --file \"./src/test.ts\" --require ts-node/register --watch --extension ts \"./src/run/**/*.spec.ts\"", "test:create-secret": "mocha --file \"./src/test.ts\" --require ts-node/register \"./src/create-secret/**/*.spec.ts\"", "dev:test:create-secret": "mocha --file \"./src/test.ts\" --require ts-node/register --watch --extension ts \"./src/create-secret/**/*.spec.ts\"", "build": "rimraf lib && tsc -p tsconfig-build.json && copyfiles -a -u 3 \"src/generate/templates/**/*\" lib/generate/templates", diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 78b9501130..e60872e7d1 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -26,7 +26,7 @@ import { } from './generate'; import { ClientError } from './generate/file-system'; import { rmdir } from './rmdir'; -import { runScript } from './run-script'; +import { runScript } from './run'; function displayError(...lines: string[]): void { console.error(); @@ -67,7 +67,6 @@ program program .command('run') .argument('', 'Name of the script to run') - .alias('run-script') .description('Run a shell script.') .action((name: string) => { runScript({ name }, process.argv); diff --git a/packages/cli/src/run-script/get-command-line-arguments.util.spec.ts b/packages/cli/src/run/get-command-line-arguments.util.spec.ts similarity index 90% rename from packages/cli/src/run-script/get-command-line-arguments.util.spec.ts rename to packages/cli/src/run/get-command-line-arguments.util.spec.ts index 083948cabd..013a7212dc 100644 --- a/packages/cli/src/run-script/get-command-line-arguments.util.spec.ts +++ b/packages/cli/src/run/get-command-line-arguments.util.spec.ts @@ -6,11 +6,11 @@ import { getCommandLineArguments } from './get-command-line-arguments.util'; describe('getCommandLineArguments', () => { it('should convert the arguments to an object.', () => { - // npx foal run-script foo foo=barfoo bar='hello world' + // npx foal run foo foo=barfoo bar='hello world' const argv = [ '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node', '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal', - 'run-script', + 'run', 'my-script', 'prod', 'foo=barfoo', @@ -28,7 +28,7 @@ describe('getCommandLineArguments', () => { const argv = [ '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node', '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal', - 'run-script', + 'run', 'my-script', 'bar={ "foo": "bar" }', 'foo=3' diff --git a/packages/cli/src/run-script/get-command-line-arguments.util.ts b/packages/cli/src/run/get-command-line-arguments.util.ts similarity index 100% rename from packages/cli/src/run-script/get-command-line-arguments.util.ts rename to packages/cli/src/run/get-command-line-arguments.util.ts diff --git a/packages/cli/src/run-script/index.ts b/packages/cli/src/run/index.ts similarity index 100% rename from packages/cli/src/run-script/index.ts rename to packages/cli/src/run/index.ts diff --git a/packages/cli/src/run-script/run-script.spec.ts b/packages/cli/src/run/run-script.spec.ts similarity index 98% rename from packages/cli/src/run-script/run-script.spec.ts rename to packages/cli/src/run/run-script.spec.ts index e5457f4f10..a135e0574f 100644 --- a/packages/cli/src/run-script/run-script.spec.ts +++ b/packages/cli/src/run/run-script.spec.ts @@ -81,7 +81,7 @@ describe('runScript', () => { await runScript({ name: 'my-script' }, [ '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node', '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal', - 'run-script', + 'run', 'my-script', 'email=bar', 'n=11' @@ -111,7 +111,7 @@ describe('runScript', () => { await runScript({ name: 'my-script' }, [ '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node', '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal', - 'run-script', + 'run', 'my-script', 'foo=bar', ]); @@ -146,7 +146,7 @@ describe('runScript', () => { await runScript({ name: 'my-script' }, [ '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node', '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal', - 'run-script', + 'run', 'my-script', 'foo=bar', ]); @@ -178,7 +178,7 @@ describe('runScript', () => { await runScript({ name: 'my-script' }, [ '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node', '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal', - 'run-script', + 'run', 'my-script', ], log); @@ -201,7 +201,7 @@ describe('runScript', () => { await runScript({ name: 'my-script' }, [ '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node', '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal', - 'run-script', + 'run', 'my-script', ], log); diff --git a/packages/cli/src/run-script/run-script.ts b/packages/cli/src/run/run-script.ts similarity index 100% rename from packages/cli/src/run-script/run-script.ts rename to packages/cli/src/run/run-script.ts From 5c7864ff5c83ce5a5d8eb5ca84d5bb76e6b767b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 14:59:00 +0200 Subject: [PATCH 04/27] [Blog] Remove "npx foal run-script" --- docs/blog/version-5.0-release-notes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index b3aecf93e8..01137a7b8e 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -16,4 +16,5 @@ Version 5.0 of [Foal](https://foalts.org/) is out! ## Removal of depreacted components -- The deprecated hook `@Log` has been removed. To replace it, you can use the `Logger` service in a custom `@Hook`. \ No newline at end of file +- The deprecated hook `@Log` has been removed. To replace it, you can use the `Logger` service in a custom `@Hook`. +- The command alias `npx foal run-script` has been removed. Use `npx foal run` instead. \ No newline at end of file From cad951a653b37fc41e6e327a825fa3b34a5edfd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Tue, 20 Aug 2024 11:42:05 +0200 Subject: [PATCH 05/27] Drop support for Node 18 and add support for Node 20 --- .github/CONTRIBUTING.MD | 3 +- .github/workflows/daily-test.yml | 2 +- .github/workflows/documentation.yml | 4 +- .github/workflows/test.yml | 2 +- .../simple-todo-list/1-installation.md | 2 +- .../simple-todo-list/1-installation.md | 2 +- .../simple-todo-list/1-installation.md | 2 +- .../simple-todo-list/1-installation.md | 2 +- package-lock.json | 274 +++++++++++++++--- packages/acceptance-tests/package.json | 4 +- packages/aws-s3/package.json | 4 +- packages/aws-s3/src/s3-disk.service.spec.ts | 2 +- packages/cli/package.json | 4 +- packages/cli/src/generate/file-system.spec.ts | 18 +- .../cli/src/generate/specs/app/package.json | 4 +- .../generate/specs/app/package.mongodb.json | 4 +- .../specs/app/package.mongodb.yaml.json | 4 +- .../src/generate/specs/app/package.yaml.json | 4 +- .../src/generate/templates/app/package.json | 4 +- .../templates/app/package.mongodb.json | 4 +- packages/core/package.json | 4 +- packages/core/src/express/create-app.spec.ts | 4 +- packages/core/src/index.ts | 2 +- packages/examples/package.json | 4 +- packages/graphiql/package.json | 4 +- packages/graphql/package.json | 6 +- .../graphql/src/graphql.controller.spec.ts | 8 +- packages/internal-test/package.json | 2 +- packages/jwks-rsa/package.json | 4 +- packages/jwt/package.json | 4 +- packages/jwt/src/http/jwt.hook.spec.ts | 34 +-- packages/mongodb/package.json | 2 +- packages/password/package.json | 4 +- packages/redis/package.json | 4 +- packages/social/package.json | 4 +- .../src/google-provider.service.spec.ts | 4 +- packages/socket.io/package.json | 4 +- packages/storage/package.json | 4 +- packages/swagger/package.json | 4 +- packages/typeorm/package.json | 2 +- packages/typestack/package.json | 4 +- 41 files changed, 314 insertions(+), 147 deletions(-) diff --git a/.github/CONTRIBUTING.MD b/.github/CONTRIBUTING.MD index edfdd4c740..ea051a40cb 100644 --- a/.github/CONTRIBUTING.MD +++ b/.github/CONTRIBUTING.MD @@ -136,7 +136,8 @@ All of major releases are supported for at least 18 months. | Release | Status | Active Start | Maintenance Start | End-of-life | Node versions | TS min version | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | -| 4.x | *Active* | 2023-09-06 | | | 18, 20 | 4.9 | +| 5.x | *Active* | TODO | | | 20, 22 | 4.9 | +| 4.x | *Maintenance* | 2023-09-06 | TODO | TODO | 18, 20 | 4.9 | | 3.x | *End-of-Life* | 2022-10-28 | 2023-09-06 | 2024-03-06 | 16, 18 | 4.7 | | 2.x | *End-of-Life* | 2020-12-03 | 2022-10-28 | 2023-04-30 | 10, 12, 14 | 4.0 | | 1.x | *End-of-Life* | 2019-07-11 | 2020-12-03 | 2021-05-31 | 8, 10 | 3.5 | diff --git a/.github/workflows/daily-test.yml b/.github/workflows/daily-test.yml index 2181fa83c3..ce833618dd 100644 --- a/.github/workflows/daily-test.yml +++ b/.github/workflows/daily-test.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node-version: [18, 20] + node-version: [20, 22] services: mongodb: diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index ef1edb3b5c..82ec1825fa 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: - node-version: '18.x' + node-version: '20.x' - name: Test Build run: | cd docs @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: - node-version: '18.x' + node-version: '20.x' - name: Add key to allow access to repository env: SSH_AUTH_SOCK: /tmp/ssh_agent.sock diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 633b4524aa..cd906536d6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - node-version: [18, 20] + node-version: [20, 22] env: SETTINGS_AWS_ACCESS_KEY_ID: ${{ secrets.SETTINGS_AWS_ACCESS_KEY_ID }} diff --git a/docs/docs/tutorials/simple-todo-list/1-installation.md b/docs/docs/tutorials/simple-todo-list/1-installation.md index 71060a412f..c9f0ea91ce 100644 --- a/docs/docs/tutorials/simple-todo-list/1-installation.md +++ b/docs/docs/tutorials/simple-todo-list/1-installation.md @@ -8,7 +8,7 @@ In this tutorial you will learn how to create a basic web application with FoalT > **Requirements:** > -> [Node.js](https://nodejs.org/en/) 18 or greater +> [Node.js](https://nodejs.org/en/) 20 or greater ## Create a New Project diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md index 56e6fd553f..0825150d38 100644 --- a/docs/i18n/es/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md @@ -8,7 +8,7 @@ En este tutorial aprenderá a crear una aplicación web básica con FoalTS. La a > **Requisitos:** > -> [Node.js](https://nodejs.org/en/) 18 o superior +> [Node.js](https://nodejs.org/en/) 20 o superior ## Crear un Nuevo Proyecto diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md index 28937dbdcd..39e9f77e7e 100644 --- a/docs/i18n/fr/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md @@ -8,7 +8,7 @@ Dans ce tutoriel, vous apprendrez comment créer une application web de base ave > **Configuration requise:** > -> [Node.js](https://nodejs.org/en/) 18 ou supérieur +> [Node.js](https://nodejs.org/en/) 20 ou supérieur ## Créer un Nouveau Projet diff --git a/docs/i18n/id/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md b/docs/i18n/id/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md index 4f4dcd0965..7741eaa60e 100644 --- a/docs/i18n/id/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md +++ b/docs/i18n/id/docusaurus-plugin-content-docs/current/tutorials/simple-todo-list/1-installation.md @@ -8,7 +8,7 @@ Pada tutorial kali ini kita akan coba membuat aplikasi web dengan Foal. Aplikasi > **Yang diperlukan:** > -> [Node.js](https://nodejs.org/en/) versi 18 ke atas +> [Node.js](https://nodejs.org/en/) versi 20 ke atas ## Memulai Proyek Baru diff --git a/package-lock.json b/package-lock.json index 594bbf651c..494f5f5ae0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4259,9 +4259,13 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.18.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.6.tgz", - "integrity": "sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w==" + "version": "20.14.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.8.tgz", + "integrity": "sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", @@ -7508,6 +7512,7 @@ "version": "10.3.12", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", @@ -7541,6 +7546,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -7549,6 +7555,7 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -8586,6 +8593,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -9764,9 +9772,10 @@ } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -10935,6 +10944,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "license": "BlueOak-1.0.0" + }, "node_modules/pacote": { "version": "18.0.6", "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", @@ -11122,6 +11137,7 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -11137,6 +11153,7 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, "engines": { "node": "14 || >=16.14" } @@ -14493,6 +14510,12 @@ "node": ">=0.10.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, "node_modules/unique-filename": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", @@ -15191,7 +15214,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "@types/react": "18.2.63", "@types/react-dom": "18.2.20", "@types/supertest": "6.0.2", @@ -15200,7 +15223,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15218,7 +15241,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copy": "~0.3.2", "mocha": "~10.7.0", "rimraf": "~5.0.5", @@ -15226,7 +15249,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15267,7 +15290,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copyfiles": "~2.4.1", "mocha": "~10.7.0", "rimraf": "~5.0.5", @@ -15275,7 +15298,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15352,7 +15375,7 @@ "devDependencies": { "@foal/internal-test": "^4.5.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "@types/supertest": "6.0.2", "ajv-errors": "~3.0.0", "ejs": "~3.1.10", @@ -15366,7 +15389,7 @@ "yamljs": "~0.3.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15412,7 +15435,7 @@ "devDependencies": { "@foal/cli": "^4.5.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "concurrently": "~8.2.2", "copy": "~0.3.2", "mocha": "~10.7.0", @@ -15420,7 +15443,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15435,7 +15458,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "graphiql": "~3.1.1", "mocha": "~10.7.0", "react": "~18.2.0", @@ -15445,7 +15468,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15476,11 +15499,11 @@ "dependencies": { "@foal/core": "^4.5.0", "ajv": "~8.17.0", - "glob": "~10.3.10" + "glob": "~11.0.0" }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "graphql": "~16.9.0", "graphql-request": "~6.1.0", "mocha": "~10.7.0", @@ -15490,7 +15513,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15499,6 +15522,96 @@ "graphql": "^16.9.0" } }, + "packages/graphql/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "packages/graphql/node_modules/glob": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/graphql/node_modules/jackspeak": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "packages/graphql/node_modules/lru-cache": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "packages/graphql/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/graphql/node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "packages/graphql/node_modules/rimraf": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", @@ -15517,6 +15630,83 @@ "url": "https://github.com/sponsors/isaacs" } }, + "packages/graphql/node_modules/rimraf/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/graphql/node_modules/rimraf/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "packages/graphql/node_modules/rimraf/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "packages/graphql/node_modules/rimraf/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/graphql/node_modules/rimraf/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "packages/internal-test": { "name": "@foal/internal-test", "version": "4.5.0", @@ -15527,7 +15717,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15562,14 +15752,14 @@ "@foal/core": "^4.5.0", "@foal/jwt": "^4.5.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15606,14 +15796,14 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15654,7 +15844,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15684,7 +15874,7 @@ "license": "MIT", "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copy": "~0.3.2", "mocha": "~10.7.0", "rimraf": "~5.0.5", @@ -15692,7 +15882,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15726,14 +15916,14 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15767,7 +15957,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copy": "~0.3.2", "jsonwebtoken": "~9.0.2", "mocha": "~10.7.0", @@ -15776,7 +15966,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15850,7 +16040,7 @@ "devDependencies": { "@socket.io/redis-adapter": "~8.3.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "mocha": "~10.7.0", "redis": "~4.6.15", "rimraf": "~5.0.5", @@ -15859,7 +16049,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15895,7 +16085,7 @@ "devDependencies": { "@foal/internal-test": "^4.5.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "@types/supertest": "6.0.2", "copy": "~0.3.2", "mocha": "~10.7.0", @@ -15905,7 +16095,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15939,7 +16129,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copy": "~0.3.2", "mocha": "~10.7.0", "rimraf": "~5.0.5", @@ -15947,7 +16137,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -15991,7 +16181,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" @@ -16027,7 +16217,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "@types/validator": "13.12.0", "class-transformer": "~0.5.1", "class-validator": "~0.14.1", @@ -16038,7 +16228,7 @@ "typescript": "~4.9.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/LoicPoullain" diff --git a/packages/acceptance-tests/package.json b/packages/acceptance-tests/package.json index 989ff8ee17..e2a30cd637 100644 --- a/packages/acceptance-tests/package.json +++ b/packages/acceptance-tests/package.json @@ -11,7 +11,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "dependencies": { "@foal/core": "^4.5.0", @@ -48,7 +48,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "@types/react": "18.2.63", "@types/react-dom": "18.2.20", "@types/supertest": "6.0.2", diff --git a/packages/aws-s3/package.json b/packages/aws-s3/package.json index ca0e974ea8..288f3bdc59 100644 --- a/packages/aws-s3/package.json +++ b/packages/aws-s3/package.json @@ -13,7 +13,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -50,7 +50,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copy": "~0.3.2", "mocha": "~10.7.0", "rimraf": "~5.0.5", diff --git a/packages/aws-s3/src/s3-disk.service.spec.ts b/packages/aws-s3/src/s3-disk.service.spec.ts index 2eca45cbcc..a33a45df53 100644 --- a/packages/aws-s3/src/s3-disk.service.spec.ts +++ b/packages/aws-s3/src/s3-disk.service.spec.ts @@ -11,7 +11,7 @@ import { S3 } from '@aws-sdk/client-s3'; import { S3Disk } from './s3-disk.service'; // Isolate each job with a different S3 bucket. -const bucketName = `foal-test-${process.env.NODE_VERSION?.slice(0,2) || 18}`; +const bucketName = `foal-test-${process.env.NODE_VERSION?.slice(0,2) || 20}`; async function rmObjectsIfExist(s3: S3) { const response = await s3.listObjects({ diff --git a/packages/cli/package.json b/packages/cli/package.json index 98788259f0..8dcdcfbf38 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -23,7 +23,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "bin": { "foal": "./lib/index.js" @@ -66,7 +66,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copyfiles": "~2.4.1", "mocha": "~10.7.0", "rimraf": "~5.0.5", diff --git a/packages/cli/src/generate/file-system.spec.ts b/packages/cli/src/generate/file-system.spec.ts index e6d07d2683..43b2470747 100644 --- a/packages/cli/src/generate/file-system.spec.ts +++ b/packages/cli/src/generate/file-system.spec.ts @@ -117,19 +117,11 @@ describe('FileSystem', () => { if (!(error instanceof ClientError)) { throw new Error('The error thrown should be an instance of ClientError.'); } - try { - // Node 18 - strictEqual( - error.message, - 'The file package.json is not a valid JSON. Unexpected token h in JSON at position 0' - ); - } catch { - // Node 20 - strictEqual( - error.message, - `The file package.json is not a valid JSON. Unexpected token 'h', "hello" is not valid JSON` - ); - } + + strictEqual( + error.message, + `The file package.json is not a valid JSON. Unexpected token 'h', "hello" is not valid JSON` + ); } }); diff --git a/packages/cli/src/generate/specs/app/package.json b/packages/cli/src/generate/specs/app/package.json index 8517831d66..62cfb0471b 100644 --- a/packages/cli/src/generate/specs/app/package.json +++ b/packages/cli/src/generate/specs/app/package.json @@ -21,7 +21,7 @@ "revertmigration": "npx typeorm migration:revert -d build/db" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "dependencies": { "@foal/core": "^4.0.0", @@ -33,7 +33,7 @@ "devDependencies": { "@foal/cli": "^4.0.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "concurrently": "~8.2.2", "mocha": "~10.7.0", "supertest": "~7.0.0", diff --git a/packages/cli/src/generate/specs/app/package.mongodb.json b/packages/cli/src/generate/specs/app/package.mongodb.json index 33c835e238..63596141a8 100644 --- a/packages/cli/src/generate/specs/app/package.mongodb.json +++ b/packages/cli/src/generate/specs/app/package.mongodb.json @@ -18,7 +18,7 @@ "lint:fix": "eslint --ext ts --fix src" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "dependencies": { "@foal/core": "^4.0.0", @@ -29,7 +29,7 @@ "devDependencies": { "@foal/cli": "^4.0.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "concurrently": "~8.2.2", "mocha": "~10.7.0", "supertest": "~7.0.0", diff --git a/packages/cli/src/generate/specs/app/package.mongodb.yaml.json b/packages/cli/src/generate/specs/app/package.mongodb.yaml.json index a3b364bba7..efd530dfbc 100644 --- a/packages/cli/src/generate/specs/app/package.mongodb.yaml.json +++ b/packages/cli/src/generate/specs/app/package.mongodb.yaml.json @@ -18,7 +18,7 @@ "lint:fix": "eslint --ext ts --fix src" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "dependencies": { "@foal/core": "^4.0.0", @@ -30,7 +30,7 @@ "devDependencies": { "@foal/cli": "^4.0.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "concurrently": "~8.2.2", "mocha": "~10.7.0", "supertest": "~7.0.0", diff --git a/packages/cli/src/generate/specs/app/package.yaml.json b/packages/cli/src/generate/specs/app/package.yaml.json index 45ded1138c..b373db5664 100644 --- a/packages/cli/src/generate/specs/app/package.yaml.json +++ b/packages/cli/src/generate/specs/app/package.yaml.json @@ -21,7 +21,7 @@ "revertmigration": "npx typeorm migration:revert -d build/db" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "dependencies": { "@foal/core": "^4.0.0", @@ -34,7 +34,7 @@ "devDependencies": { "@foal/cli": "^4.0.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "concurrently": "~8.2.2", "mocha": "~10.7.0", "supertest": "~7.0.0", diff --git a/packages/cli/src/generate/templates/app/package.json b/packages/cli/src/generate/templates/app/package.json index 0d35074335..6457efd136 100644 --- a/packages/cli/src/generate/templates/app/package.json +++ b/packages/cli/src/generate/templates/app/package.json @@ -21,7 +21,7 @@ "revertmigration": "npx typeorm migration:revert -d build/db" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "dependencies": { "@foal/core": "^4.0.0", @@ -33,7 +33,7 @@ "devDependencies": { "@foal/cli": "^4.0.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "concurrently": "~8.2.2", "mocha": "~10.7.0", "supertest": "~7.0.0", diff --git a/packages/cli/src/generate/templates/app/package.mongodb.json b/packages/cli/src/generate/templates/app/package.mongodb.json index a5a9f03eee..4b2a37edf8 100644 --- a/packages/cli/src/generate/templates/app/package.mongodb.json +++ b/packages/cli/src/generate/templates/app/package.mongodb.json @@ -18,7 +18,7 @@ "lint:fix": "eslint --ext ts --fix src" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "dependencies": { "@foal/core": "^4.0.0", @@ -29,7 +29,7 @@ "devDependencies": { "@foal/cli": "^4.0.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "concurrently": "~8.2.2", "mocha": "~10.7.0", "supertest": "~7.0.0", diff --git a/packages/core/package.json b/packages/core/package.json index 7db9377b20..7842109282 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -18,7 +18,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -69,7 +69,7 @@ "devDependencies": { "@foal/internal-test": "^4.5.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "@types/supertest": "6.0.2", "ajv-errors": "~3.0.0", "ejs": "~3.1.10", diff --git a/packages/core/src/express/create-app.spec.ts b/packages/core/src/express/create-app.spec.ts index c6bd254ca5..3411fdbba4 100644 --- a/packages/core/src/express/create-app.spec.ts +++ b/packages/core/src/express/create-app.spec.ts @@ -581,11 +581,13 @@ describe('createApp', () => { .expect(400) .then(response => { try { + // Node 22 deepStrictEqual(response.body, { body: '{ \"foo\": \"bar\", }', - message: 'Unexpected token } in JSON at position 16' + message: 'Expected double-quoted property name in JSON at position 16 (line 1 column 17)' }); } catch (error) { + // Node 20 deepStrictEqual(response.body, { body: '{ \"foo\": \"bar\", }', message: 'Expected double-quoted property name in JSON at position 16' diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 99997606b2..91071f1915 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -7,7 +7,7 @@ try { const version = process.versions.node; const NODE_CURRENT_MAJOR_VERSION = parseInt(version.split('.')[0], 10); - const NODE_MINIMUM_MAJOR_VERSION = 18; + const NODE_MINIMUM_MAJOR_VERSION = 20; if (NODE_CURRENT_MAJOR_VERSION < NODE_MINIMUM_MAJOR_VERSION) { console.warn(`[Warning] You are using version ${version} of Node. FoalTS requires at least version ${NODE_MINIMUM_MAJOR_VERSION}.`); } diff --git a/packages/examples/package.json b/packages/examples/package.json index 58c162399f..2b146ad048 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -24,7 +24,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -61,7 +61,7 @@ "devDependencies": { "@foal/cli": "^4.5.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "concurrently": "~8.2.2", "copy": "~0.3.2", "mocha": "~10.7.0", diff --git a/packages/graphiql/package.json b/packages/graphiql/package.json index 0be02cfd7a..44ed0cb2e3 100644 --- a/packages/graphiql/package.json +++ b/packages/graphiql/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -44,7 +44,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "graphiql": "~3.1.1", "mocha": "~10.7.0", "react": "~18.2.0", diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 9ca59ceeee..398dcf6302 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -42,11 +42,11 @@ "dependencies": { "@foal/core": "^4.5.0", "ajv": "~8.17.0", - "glob": "~10.3.10" + "glob": "~11.0.0" }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "graphql": "~16.9.0", "graphql-request": "~6.1.0", "mocha": "~10.7.0", diff --git a/packages/graphql/src/graphql.controller.spec.ts b/packages/graphql/src/graphql.controller.spec.ts index 89d67750a5..426d164164 100644 --- a/packages/graphql/src/graphql.controller.spec.ts +++ b/packages/graphql/src/graphql.controller.spec.ts @@ -136,10 +136,10 @@ describe('GraphQLController', () => { } try { - // Node 18 + // Node 22 strictEqual( response.body, - 'The "variables" URL parameter is not a valid JSON-encoded string: Unexpected end of JSON input' + `The "variables" URL parameter is not a valid JSON-encoded string: Expected property name or '}' in JSON at position 1 (line 1 column 2)` ); } catch { // Node 20 @@ -503,10 +503,10 @@ describe('GraphQLController', () => { } try { - // Node 18 + // Node 22 strictEqual( response.body, - 'The "variables" URL parameter is not a valid JSON-encoded string: Unexpected end of JSON input' + `The "variables" URL parameter is not a valid JSON-encoded string: Expected property name or '}' in JSON at position 1 (line 1 column 2)` ); } catch (error) { // Node 20 diff --git a/packages/internal-test/package.json b/packages/internal-test/package.json index d9c6bedbf1..80fcddf14c 100644 --- a/packages/internal-test/package.json +++ b/packages/internal-test/package.json @@ -13,7 +13,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" diff --git a/packages/jwks-rsa/package.json b/packages/jwks-rsa/package.json index d14a801341..4e6a9e0df1 100644 --- a/packages/jwks-rsa/package.json +++ b/packages/jwks-rsa/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -53,7 +53,7 @@ "@foal/core": "^4.5.0", "@foal/jwt": "^4.5.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", diff --git a/packages/jwt/package.json b/packages/jwt/package.json index b22f6237ad..43403ce274 100644 --- a/packages/jwt/package.json +++ b/packages/jwt/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -47,7 +47,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", diff --git a/packages/jwt/src/http/jwt.hook.spec.ts b/packages/jwt/src/http/jwt.hook.spec.ts index cdfa648f78..366668ef0e 100644 --- a/packages/jwt/src/http/jwt.hook.spec.ts +++ b/packages/jwt/src/http/jwt.hook.spec.ts @@ -302,33 +302,15 @@ export function testSuite(JWT: typeof JWTOptional|typeof JWTRequired, required: throw new Error('response should be instance of HttpResponseUnauthorized'); } - try { - // Node 18 - deepStrictEqual(response.body, { - code: 'invalid_token', - description: 'Unexpected token R in JSON at position 27' - }); - } catch { - // Node 20 - deepStrictEqual(response.body, { - code: 'invalid_token', - description: `Unexpected token 'R', ...\"0\",\"name\":RJohn Doe\"\"... is not valid JSON` - }); - } + deepStrictEqual(response.body, { + code: 'invalid_token', + description: `Unexpected token 'R', ...\"0\",\"name\":RJohn Doe\"\"... is not valid JSON` + }); - try { - // Node 18 - strictEqual( - response.getHeader('WWW-Authenticate'), - 'error="invalid_token", error_description="Unexpected token R in JSON at position 27"' - ); - } catch { - // Node 20 - strictEqual( - response.getHeader('WWW-Authenticate'), - `error="invalid_token", error_description="Unexpected token 'R', ...\"0\",\"name\":RJohn Doe\"\"... is not valid JSON"` - ); - } + strictEqual( + response.getHeader('WWW-Authenticate'), + `error="invalid_token", error_description="Unexpected token 'R', ...\"0\",\"name\":RJohn Doe\"\"... is not valid JSON"` + ); }); it('should return an HttpResponseUnauthorized object if options.secretOrPublicKey throws an' diff --git a/packages/mongodb/package.json b/packages/mongodb/package.json index d511fad426..1c5701301d 100644 --- a/packages/mongodb/package.json +++ b/packages/mongodb/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" diff --git a/packages/password/package.json b/packages/password/package.json index 49a56a6596..c071da1354 100644 --- a/packages/password/package.json +++ b/packages/password/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -41,7 +41,7 @@ ], "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copy": "~0.3.2", "mocha": "~10.7.0", "rimraf": "~5.0.5", diff --git a/packages/redis/package.json b/packages/redis/package.json index 44054db9c4..a1171a682c 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -46,7 +46,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", diff --git a/packages/social/package.json b/packages/social/package.json index 0a8d7f1bea..8658c3bcbb 100644 --- a/packages/social/package.json +++ b/packages/social/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -57,7 +57,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copy": "~0.3.2", "jsonwebtoken": "~9.0.2", "mocha": "~10.7.0", diff --git a/packages/social/src/google-provider.service.spec.ts b/packages/social/src/google-provider.service.spec.ts index 09bd6e9ac5..e542c77fca 100644 --- a/packages/social/src/google-provider.service.spec.ts +++ b/packages/social/src/google-provider.service.spec.ts @@ -47,8 +47,8 @@ describe('GoogleProvider', () => { throw error; } try { - // Node 18 - strictEqual(error.message, 'The ID token returned by Google is not a valid JWT: Unexpected end of JSON input.'); + // Node 22 + strictEqual(error.message, `The ID token returned by Google is not a valid JWT: Expected property name or '}' in JSON at position 1 (line 1 column 2).`); } catch { // Node 20 strictEqual(error.message, `The ID token returned by Google is not a valid JWT: Expected property name or '}' in JSON at position 1.`); diff --git a/packages/socket.io/package.json b/packages/socket.io/package.json index 68a35d87c8..23d6ad327f 100644 --- a/packages/socket.io/package.json +++ b/packages/socket.io/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -46,7 +46,7 @@ "devDependencies": { "@socket.io/redis-adapter": "~8.3.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "mocha": "~10.7.0", "redis": "~4.6.15", "rimraf": "~5.0.5", diff --git a/packages/storage/package.json b/packages/storage/package.json index 2542f40c38..14bbb203d0 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -51,7 +51,7 @@ "devDependencies": { "@foal/internal-test": "^4.5.0", "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "@types/supertest": "6.0.2", "copy": "~0.3.2", "mocha": "~10.7.0", diff --git a/packages/swagger/package.json b/packages/swagger/package.json index d296d7d3d4..28cedd93c5 100644 --- a/packages/swagger/package.json +++ b/packages/swagger/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -48,7 +48,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "copy": "~0.3.2", "mocha": "~10.7.0", "rimraf": "~5.0.5", diff --git a/packages/typeorm/package.json b/packages/typeorm/package.json index 46ba64481b..39a04a79d8 100644 --- a/packages/typeorm/package.json +++ b/packages/typeorm/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" diff --git a/packages/typestack/package.json b/packages/typestack/package.json index b4f442fe41..fa550a1601 100644 --- a/packages/typestack/package.json +++ b/packages/typestack/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "publishConfig": { "access": "public" @@ -52,7 +52,7 @@ }, "devDependencies": { "@types/mocha": "10.0.7", - "@types/node": "18.18.6", + "@types/node": "20.14.8", "@types/validator": "13.12.0", "class-transformer": "~0.5.1", "class-validator": "~0.14.1", From 3c46ca7a7a387f3196577d7e992e4bbd19e4a2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 14:49:53 +0200 Subject: [PATCH 06/27] Use latest version of npm --- .github/workflows/test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cd906536d6..466813d15a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,8 +29,6 @@ jobs: uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - - name: Use npm version 9.6 - run: npm install -g npm@9.6 - name: Install project and package dependencies run: npm install - name: Build packages From 06704a2e0d9beae0f112aa03fbdfe35fe396aed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 15:05:34 +0200 Subject: [PATCH 07/27] [Blog] Add support for Node 20 and 22 --- docs/blog/version-5.0-release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 01137a7b8e..b90ed058de 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -14,6 +14,10 @@ Version 5.0 of [Foal](https://foalts.org/) is out! +## Supported versions of Node + +- Support for Node 18 has been dropped and support for Node 22 has been added. + ## Removal of depreacted components - The deprecated hook `@Log` has been removed. To replace it, you can use the `Logger` service in a custom `@Hook`. From ed9541a155d30a8484d71a5916be8d10528e6032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Mon, 19 Aug 2024 18:02:46 +0200 Subject: [PATCH 08/27] Remove node-fetch dependency --- .../15-social-auth.md | 3 +- package-lock.json | 82 +------------------ packages/cli/package.json | 3 +- .../generate/generators/upgrade/upgrade.ts | 3 - packages/cli/typings/node-fetch/index.d.ts | 1 - packages/social/package.json | 3 +- .../social/src/abstract-provider.service.ts | 1 - .../social/src/facebook-provider.service.ts | 3 - .../social/src/github-provider.service.ts | 3 - .../social/src/linkedin-provider.service.ts | 3 - .../social/src/twitter-provider.service.ts | 2 - packages/social/typings/node-fetch/index.d.ts | 1 - 12 files changed, 5 insertions(+), 103 deletions(-) delete mode 100644 packages/cli/typings/node-fetch/index.d.ts delete mode 100644 packages/social/typings/node-fetch/index.d.ts diff --git a/docs/docs/tutorials/real-world-example-with-react/15-social-auth.md b/docs/docs/tutorials/real-world-example-with-react/15-social-auth.md index 9cef3a172d..06f5f83377 100644 --- a/docs/docs/tutorials/real-world-example-with-react/15-social-auth.md +++ b/docs/docs/tutorials/real-world-example-with-react/15-social-auth.md @@ -66,7 +66,7 @@ if (!(await verifyPassword(password, user.password))) { Now that the password problem is solved, you can install the packages and provide your social credentials in the configuration. ```bash -npm install @foal/social node-fetch@2 +npm install @foal/social ``` *config/default.json* @@ -114,7 +114,6 @@ Open the file and add two new routes. import { Context, dependency, Get, HttpResponseRedirect } from '@foal/core'; import { GoogleProvider } from '@foal/social'; import { User } from '../../entities'; -import * as fetch from 'node-fetch'; import { Disk } from '@foal/storage'; interface GoogleUserInfo { diff --git a/package-lock.json b/package-lock.json index 494f5f5ae0..18e4e2d32a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15282,8 +15282,7 @@ "ajv-formats": "~2.1.1", "cli-spinner": "~0.2.10", "colors": "1.4.0", - "commander": "~12.1.0", - "node-fetch": "~2.7.0" + "commander": "~12.1.0" }, "bin": { "foal": "lib/index.js" @@ -15304,25 +15303,6 @@ "url": "https://github.com/sponsors/LoicPoullain" } }, - "packages/cli/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "packages/cli/node_modules/rimraf": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", @@ -15341,25 +15321,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/cli/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "packages/cli/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "packages/cli/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "packages/core": { "name": "@foal/core", "version": "4.5.0", @@ -15952,8 +15913,7 @@ "version": "4.5.0", "license": "MIT", "dependencies": { - "@foal/core": "^4.5.0", - "node-fetch": "~2.7.0" + "@foal/core": "^4.5.0" }, "devDependencies": { "@types/mocha": "10.0.7", @@ -15972,25 +15932,6 @@ "url": "https://github.com/sponsors/LoicPoullain" } }, - "packages/social/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "packages/social/node_modules/rimraf": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", @@ -16009,25 +15950,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/social/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "packages/social/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "packages/social/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "packages/socket.io": { "name": "@foal/socket.io", "version": "4.5.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index 8dcdcfbf38..c3c51cd703 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -61,8 +61,7 @@ "ajv-formats": "~2.1.1", "cli-spinner": "~0.2.10", "colors": "1.4.0", - "commander": "~12.1.0", - "node-fetch": "~2.7.0" + "commander": "~12.1.0" }, "devDependencies": { "@types/mocha": "10.0.7", diff --git a/packages/cli/src/generate/generators/upgrade/upgrade.ts b/packages/cli/src/generate/generators/upgrade/upgrade.ts index 1390ec8f36..a59b8ddfd3 100644 --- a/packages/cli/src/generate/generators/upgrade/upgrade.ts +++ b/packages/cli/src/generate/generators/upgrade/upgrade.ts @@ -1,6 +1,3 @@ -// 3p -import * as fetch from 'node-fetch'; - // FoalTS import { FileSystem } from '../../file-system'; import { installDependencies, logger } from '../../utils'; diff --git a/packages/cli/typings/node-fetch/index.d.ts b/packages/cli/typings/node-fetch/index.d.ts deleted file mode 100644 index c73ed67d18..0000000000 --- a/packages/cli/typings/node-fetch/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'node-fetch'; \ No newline at end of file diff --git a/packages/social/package.json b/packages/social/package.json index 8658c3bcbb..cbc2edd6a0 100644 --- a/packages/social/package.json +++ b/packages/social/package.json @@ -52,8 +52,7 @@ "lib/" ], "dependencies": { - "@foal/core": "^4.5.0", - "node-fetch": "~2.7.0" + "@foal/core": "^4.5.0" }, "devDependencies": { "@types/mocha": "10.0.7", diff --git a/packages/social/src/abstract-provider.service.ts b/packages/social/src/abstract-provider.service.ts index 593c6ce7f1..6297dc5ab5 100644 --- a/packages/social/src/abstract-provider.service.ts +++ b/packages/social/src/abstract-provider.service.ts @@ -4,7 +4,6 @@ import * as crypto from 'crypto'; // 3p import { Config, Context, generateToken, HttpResponseRedirect, convertBase64ToBase64url, CookieOptions, HttpResponseOK } from '@foal/core'; -import * as fetch from 'node-fetch'; /** * Tokens returned by an OAuth2 authorization server. diff --git a/packages/social/src/facebook-provider.service.ts b/packages/social/src/facebook-provider.service.ts index 01947b6f0a..151516d31b 100644 --- a/packages/social/src/facebook-provider.service.ts +++ b/packages/social/src/facebook-provider.service.ts @@ -1,9 +1,6 @@ // std import { URL } from 'url'; -// 3p -import * as fetch from 'node-fetch'; - // FoalTS import { AbstractProvider, SocialTokens } from './abstract-provider.service'; import { UserInfoError } from './user-info.error'; diff --git a/packages/social/src/github-provider.service.ts b/packages/social/src/github-provider.service.ts index 795c129f04..91d1fab011 100644 --- a/packages/social/src/github-provider.service.ts +++ b/packages/social/src/github-provider.service.ts @@ -1,6 +1,3 @@ -// 3p -import * as fetch from 'node-fetch'; - // FoalTS import { AbstractProvider, SocialTokens } from './abstract-provider.service'; import { UserInfoError } from './user-info.error'; diff --git a/packages/social/src/linkedin-provider.service.ts b/packages/social/src/linkedin-provider.service.ts index 350e67c924..b2a294ca6b 100644 --- a/packages/social/src/linkedin-provider.service.ts +++ b/packages/social/src/linkedin-provider.service.ts @@ -1,9 +1,6 @@ // std import { URL } from 'url'; -// 3p -import * as fetch from 'node-fetch'; - // FoalTS import { AbstractProvider, SocialTokens } from './abstract-provider.service'; import { UserInfoError } from './user-info.error'; diff --git a/packages/social/src/twitter-provider.service.ts b/packages/social/src/twitter-provider.service.ts index 1036d21cc5..0c9e1e9ac5 100644 --- a/packages/social/src/twitter-provider.service.ts +++ b/packages/social/src/twitter-provider.service.ts @@ -1,5 +1,3 @@ -// 3p -import * as fetch from 'node-fetch'; // FoalTS import { AbstractProvider, SocialTokens } from './abstract-provider.service'; diff --git a/packages/social/typings/node-fetch/index.d.ts b/packages/social/typings/node-fetch/index.d.ts deleted file mode 100644 index c73ed67d18..0000000000 --- a/packages/social/typings/node-fetch/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'node-fetch'; \ No newline at end of file From 20e8a6dbf5a11c3731c068654ccb5650db52f1d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 16:25:01 +0200 Subject: [PATCH 09/27] Make Context.state type to "{}" by default --- docs/blog/version-5.0-release-notes.md | 37 ++++++++++++++++++- docs/docs/architecture/controllers.md | 2 +- docs/docs/architecture/hooks.md | 4 +- .../forwarding-data-between-hooks.feature.ts | 4 +- packages/core/src/core/http/context.ts | 2 +- .../src/architecture/websocket-context.ts | 2 +- 6 files changed, 42 insertions(+), 9 deletions(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index b90ed058de..5fcc7c2dec 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -18,7 +18,40 @@ Version 5.0 of [Foal](https://foalts.org/) is out! - Support for Node 18 has been dropped and support for Node 22 has been added. -## Removal of depreacted components +## Better typing -- The deprecated hook `@Log` has been removed. To replace it, you can use the `Logger` service in a custom `@Hook`. +- The default type of `Context.state` is now `{}`. This way, you'll get a compilation error if you forget to specify a type for the state. + + ```typescript + // Version 4 + class MyController { + @Get('/foobar') + foobar(ctx: Context) { + // Does not throw. + console.log(ctx.state.shoppingCart); + } + } + + // Version 5 + class MyController { + @Get('/foobar') + foobar(ctx: Context) { + // Throws a compilation error: Property 'shoppingCart' does not exist on type '{}'.ts(2339) + console.log(ctx.state.shoppingCart); + } + } + + // Version 5 (without error) + class MyController { + @Get('/foobar') + foobar(ctx: Context) { + console.log(ctx.state.shoppingCart); + } + } + + ``` + +## Removal of deprecated components + +- The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead. - The command alias `npx foal run-script` has been removed. Use `npx foal run` instead. \ No newline at end of file diff --git a/docs/docs/architecture/controllers.md b/docs/docs/architecture/controllers.md index 2607e8f8e4..6e279ec098 100644 --- a/docs/docs/architecture/controllers.md +++ b/docs/docs/architecture/controllers.md @@ -100,7 +100,7 @@ It has seven properties: | Name | Type | Description | | --- | --- | --- | | `request` | `Request` | Gives information about the HTTP request. | -| `state` | `{ [key: string]: any }` | Object which can be used to forward data accross several hooks (see [Hooks](./hooks.md)). | +| `state` | `{ [key: string]: any } = {}` | Object which can be used to forward data accross several hooks (see [Hooks](./hooks.md)). | | `user` | `{ [key: string]: any }`\|`null` | The current user (see [Authentication](../authentication/quick-start.md)). | | `session`| `Session`\|`null` | The session object if you use sessions. | | `files` | `FileList` | A list of file paths or buffers if you uploaded files (see [Upload and download files](../common/file-storage/upload-and-download-files.md)). | diff --git a/docs/docs/architecture/hooks.md b/docs/docs/architecture/hooks.md index 5bea7760a8..1927e5f5e6 100644 --- a/docs/docs/architecture/hooks.md +++ b/docs/docs/architecture/hooks.md @@ -465,7 +465,7 @@ import { Context, Get, Hook, HttpResponseOK, UserRequired } from '@foal/core'; import { Org } from '../entities'; function AddOrgToContext() { - return Hook(async ctx => { + return Hook(async (ctx: Context) => { if (ctx.user) { ctx.state.org = await Org.findOneByOrFail({ id: ctx.user.orgId }); } @@ -477,7 +477,7 @@ export class ApiController { @Get('/org-name') @UserRequired() @AddOrgToContext() - readOrgName(ctx: Context) { + readOrgName(ctx: Context) { return new HttpResponseOK(ctx.state.org.name); } diff --git a/packages/acceptance-tests/src/docs/architecture/hooks/forwarding-data-between-hooks.feature.ts b/packages/acceptance-tests/src/docs/architecture/hooks/forwarding-data-between-hooks.feature.ts index e862098042..bd92bf967d 100644 --- a/packages/acceptance-tests/src/docs/architecture/hooks/forwarding-data-between-hooks.feature.ts +++ b/packages/acceptance-tests/src/docs/architecture/hooks/forwarding-data-between-hooks.feature.ts @@ -21,7 +21,7 @@ describe('Feature: Forwarding data betweens hooks', () => { /* ======================= DOCUMENTATION BEGIN ======================= */ function AddOrgToContext() { - return Hook(async ctx => { + return Hook(async (ctx: Context) => { if (ctx.user) { ctx.state.org = await Org.findOneByOrFail({ id: ctx.user.orgId }); } @@ -33,7 +33,7 @@ describe('Feature: Forwarding data betweens hooks', () => { @Get('/org-name') @UserRequired() @AddOrgToContext() - readOrgName(ctx: Context) { + readOrgName(ctx: Context) { return new HttpResponseOK(ctx.state.org.name); } diff --git a/packages/core/src/core/http/context.ts b/packages/core/src/core/http/context.ts index f0db4e3c1f..18522ad192 100644 --- a/packages/core/src/core/http/context.ts +++ b/packages/core/src/core/http/context.ts @@ -114,7 +114,7 @@ interface Request extends IncomingMessage { * @class Context * @template User */ -export class Context { +export class Context { readonly request: Request; session: Session | null; diff --git a/packages/socket.io/src/architecture/websocket-context.ts b/packages/socket.io/src/architecture/websocket-context.ts index d6114ed549..ba8156802e 100644 --- a/packages/socket.io/src/architecture/websocket-context.ts +++ b/packages/socket.io/src/architecture/websocket-context.ts @@ -17,7 +17,7 @@ import { Session } from '@foal/core'; * @template ContextSession * @template ContextState */ -export class WebsocketContext { +export class WebsocketContext { readonly socket: Socket; session: Session | null; From 4e80cb83bebde28d20194a0d420ae54737702358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 17:44:42 +0200 Subject: [PATCH 10/27] Upgrade to TS v5 --- .github/CONTRIBUTING.MD | 2 +- package-lock.json | 49 ++++++++++--------- package.json | 2 +- packages/acceptance-tests/package.json | 2 +- packages/aws-s3/package.json | 2 +- packages/cli/package.json | 2 +- .../cli/src/generate/specs/app/package.json | 2 +- .../generate/specs/app/package.mongodb.json | 2 +- .../specs/app/package.mongodb.yaml.json | 2 +- .../src/generate/specs/app/package.yaml.json | 2 +- .../src/generate/templates/app/package.json | 2 +- .../templates/app/package.mongodb.json | 2 +- packages/core/package.json | 2 +- packages/examples/package.json | 2 +- packages/graphiql/package.json | 2 +- packages/graphql/package.json | 2 +- packages/internal-test/package.json | 2 +- packages/jwks-rsa/package.json | 2 +- packages/jwt/package.json | 2 +- packages/mongodb/package.json | 2 +- packages/password/package.json | 2 +- packages/redis/package.json | 2 +- packages/social/package.json | 2 +- packages/socket.io/package.json | 2 +- packages/storage/package.json | 2 +- packages/swagger/package.json | 2 +- packages/typeorm/package.json | 2 +- packages/typestack/package.json | 2 +- 28 files changed, 52 insertions(+), 51 deletions(-) diff --git a/.github/CONTRIBUTING.MD b/.github/CONTRIBUTING.MD index ea051a40cb..b768c5312d 100644 --- a/.github/CONTRIBUTING.MD +++ b/.github/CONTRIBUTING.MD @@ -136,7 +136,7 @@ All of major releases are supported for at least 18 months. | Release | Status | Active Start | Maintenance Start | End-of-life | Node versions | TS min version | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | -| 5.x | *Active* | TODO | | | 20, 22 | 4.9 | +| 5.x | *Active* | TODO | | | 20, 22 | 5.5 | | 4.x | *Maintenance* | 2023-09-06 | TODO | TODO | 18, 20 | 4.9 | | 3.x | *End-of-Life* | 2022-10-28 | 2023-09-06 | 2024-03-06 | 16, 18 | 4.7 | | 2.x | *End-of-Life* | 2020-12-03 | 2022-10-28 | 2023-04-30 | 10, 12, 14 | 4.0 | diff --git a/package-lock.json b/package-lock.json index 18e4e2d32a..ce3b7645f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "lerna": "~8.1.7", "mocha": "~10.7.0", "tslint": "~6.1.3", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } }, "node_modules/@aws-crypto/crc32": { @@ -14462,16 +14462,17 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "devOptional": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/uc.micro": { @@ -15220,7 +15221,7 @@ "@types/supertest": "6.0.2", "mocha": "~10.7.0", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15246,7 +15247,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15294,7 +15295,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15346,7 +15347,7 @@ "supertest": "~7.0.0", "ts-node": "~10.9.2", "twig": "~1.17.1", - "typescript": "~4.9.5", + "typescript": "~5.5.4", "yamljs": "~0.3.0" }, "engines": { @@ -15401,7 +15402,7 @@ "copy": "~0.3.2", "mocha": "~10.7.0", "supervisor": "~0.12.0", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15426,7 +15427,7 @@ "react-dom": "~18.2.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15471,7 +15472,7 @@ "rimraf": "~5.0.5", "ts-node": "~10.9.2", "type-graphql": "2.0.0-beta.3", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15675,7 +15676,7 @@ "devDependencies": { "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15717,7 +15718,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15761,7 +15762,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15802,7 +15803,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15840,7 +15841,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15881,7 +15882,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15923,7 +15924,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -15968,7 +15969,7 @@ "rimraf": "~5.0.5", "socket.io-client": "~4.7.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -16014,7 +16015,7 @@ "rimraf": "~5.0.5", "supertest": "~7.0.0", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -16056,7 +16057,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -16100,7 +16101,7 @@ "sqlite3": "~5.1.7", "ts-node": "~10.9.2", "typeorm": "0.3.17", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" @@ -16147,7 +16148,7 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "engines": { "node": ">=20.0.0" diff --git a/package.json b/package.json index c0c4298ed4..3e0e958f3a 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "lerna": "~8.1.7", "mocha": "~10.7.0", "tslint": "~6.1.3", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/acceptance-tests/package.json b/packages/acceptance-tests/package.json index e2a30cd637..2acf225e84 100644 --- a/packages/acceptance-tests/package.json +++ b/packages/acceptance-tests/package.json @@ -54,6 +54,6 @@ "@types/supertest": "6.0.2", "mocha": "~10.7.0", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/aws-s3/package.json b/packages/aws-s3/package.json index 288f3bdc59..9fb47711e9 100644 --- a/packages/aws-s3/package.json +++ b/packages/aws-s3/package.json @@ -55,6 +55,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/cli/package.json b/packages/cli/package.json index c3c51cd703..99a844e33e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -70,6 +70,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/cli/src/generate/specs/app/package.json b/packages/cli/src/generate/specs/app/package.json index 62cfb0471b..b47f06681e 100644 --- a/packages/cli/src/generate/specs/app/package.json +++ b/packages/cli/src/generate/specs/app/package.json @@ -41,6 +41,6 @@ "eslint": "~8.48.0", "@typescript-eslint/eslint-plugin": "~6.5.0", "@typescript-eslint/parser": "~6.5.0", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } \ No newline at end of file diff --git a/packages/cli/src/generate/specs/app/package.mongodb.json b/packages/cli/src/generate/specs/app/package.mongodb.json index 63596141a8..a4b4a5312e 100644 --- a/packages/cli/src/generate/specs/app/package.mongodb.json +++ b/packages/cli/src/generate/specs/app/package.mongodb.json @@ -37,6 +37,6 @@ "eslint": "~8.48.0", "@typescript-eslint/eslint-plugin": "~6.5.0", "@typescript-eslint/parser": "~6.5.0", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } \ No newline at end of file diff --git a/packages/cli/src/generate/specs/app/package.mongodb.yaml.json b/packages/cli/src/generate/specs/app/package.mongodb.yaml.json index efd530dfbc..8874672d67 100644 --- a/packages/cli/src/generate/specs/app/package.mongodb.yaml.json +++ b/packages/cli/src/generate/specs/app/package.mongodb.yaml.json @@ -38,6 +38,6 @@ "eslint": "~8.48.0", "@typescript-eslint/eslint-plugin": "~6.5.0", "@typescript-eslint/parser": "~6.5.0", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } \ No newline at end of file diff --git a/packages/cli/src/generate/specs/app/package.yaml.json b/packages/cli/src/generate/specs/app/package.yaml.json index b373db5664..7e36eef02f 100644 --- a/packages/cli/src/generate/specs/app/package.yaml.json +++ b/packages/cli/src/generate/specs/app/package.yaml.json @@ -42,6 +42,6 @@ "eslint": "~8.48.0", "@typescript-eslint/eslint-plugin": "~6.5.0", "@typescript-eslint/parser": "~6.5.0", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } \ No newline at end of file diff --git a/packages/cli/src/generate/templates/app/package.json b/packages/cli/src/generate/templates/app/package.json index 6457efd136..a18a0b4ede 100644 --- a/packages/cli/src/generate/templates/app/package.json +++ b/packages/cli/src/generate/templates/app/package.json @@ -41,6 +41,6 @@ "eslint": "~8.48.0", "@typescript-eslint/eslint-plugin": "~6.5.0", "@typescript-eslint/parser": "~6.5.0", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } \ No newline at end of file diff --git a/packages/cli/src/generate/templates/app/package.mongodb.json b/packages/cli/src/generate/templates/app/package.mongodb.json index 4b2a37edf8..7a8aaf182e 100644 --- a/packages/cli/src/generate/templates/app/package.mongodb.json +++ b/packages/cli/src/generate/templates/app/package.mongodb.json @@ -37,6 +37,6 @@ "eslint": "~8.48.0", "@typescript-eslint/eslint-plugin": "~6.5.0", "@typescript-eslint/parser": "~6.5.0", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index 7842109282..fdbc8f1492 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -79,7 +79,7 @@ "supertest": "~7.0.0", "ts-node": "~10.9.2", "twig": "~1.17.1", - "typescript": "~4.9.5", + "typescript": "~5.5.4", "yamljs": "~0.3.0" } } diff --git a/packages/examples/package.json b/packages/examples/package.json index 2b146ad048..5e76d2bc3c 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -66,6 +66,6 @@ "copy": "~0.3.2", "mocha": "~10.7.0", "supervisor": "~0.12.0", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/graphiql/package.json b/packages/graphiql/package.json index 44ed0cb2e3..0999fb3417 100644 --- a/packages/graphiql/package.json +++ b/packages/graphiql/package.json @@ -51,6 +51,6 @@ "react-dom": "~18.2.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 398dcf6302..be060cc552 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -53,7 +53,7 @@ "rimraf": "~5.0.5", "ts-node": "~10.9.2", "type-graphql": "2.0.0-beta.3", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "peerDependencies": { "graphql": "^16.9.0" diff --git a/packages/internal-test/package.json b/packages/internal-test/package.json index 80fcddf14c..fd0379bea3 100644 --- a/packages/internal-test/package.json +++ b/packages/internal-test/package.json @@ -40,6 +40,6 @@ "devDependencies": { "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/jwks-rsa/package.json b/packages/jwks-rsa/package.json index 4e6a9e0df1..e07eb3cea6 100644 --- a/packages/jwks-rsa/package.json +++ b/packages/jwks-rsa/package.json @@ -57,6 +57,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/jwt/package.json b/packages/jwt/package.json index 43403ce274..1371233b3f 100644 --- a/packages/jwt/package.json +++ b/packages/jwt/package.json @@ -51,6 +51,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/mongodb/package.json b/packages/mongodb/package.json index 1c5701301d..bff93979ae 100644 --- a/packages/mongodb/package.json +++ b/packages/mongodb/package.json @@ -54,6 +54,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/password/package.json b/packages/password/package.json index c071da1354..439d42447c 100644 --- a/packages/password/package.json +++ b/packages/password/package.json @@ -46,6 +46,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/redis/package.json b/packages/redis/package.json index a1171a682c..fe58ba2cee 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -50,6 +50,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/social/package.json b/packages/social/package.json index cbc2edd6a0..e9ea2aeba0 100644 --- a/packages/social/package.json +++ b/packages/social/package.json @@ -62,6 +62,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/socket.io/package.json b/packages/socket.io/package.json index 23d6ad327f..49639d5d38 100644 --- a/packages/socket.io/package.json +++ b/packages/socket.io/package.json @@ -52,7 +52,7 @@ "rimraf": "~5.0.5", "socket.io-client": "~4.7.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" }, "dependencies": { "@foal/core": "^4.5.0", diff --git a/packages/storage/package.json b/packages/storage/package.json index 14bbb203d0..041d7d7cdd 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -58,6 +58,6 @@ "rimraf": "~5.0.5", "supertest": "~7.0.0", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/swagger/package.json b/packages/swagger/package.json index 28cedd93c5..3d91f8f540 100644 --- a/packages/swagger/package.json +++ b/packages/swagger/package.json @@ -53,6 +53,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/typeorm/package.json b/packages/typeorm/package.json index 39a04a79d8..f5bfec65f3 100644 --- a/packages/typeorm/package.json +++ b/packages/typeorm/package.json @@ -62,6 +62,6 @@ "sqlite3": "~5.1.7", "ts-node": "~10.9.2", "typeorm": "0.3.17", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } diff --git a/packages/typestack/package.json b/packages/typestack/package.json index fa550a1601..31cd6788e1 100644 --- a/packages/typestack/package.json +++ b/packages/typestack/package.json @@ -60,6 +60,6 @@ "mocha": "~10.7.0", "rimraf": "~5.0.5", "ts-node": "~10.9.2", - "typescript": "~4.9.5" + "typescript": "~5.5.4" } } From fd3683f552be8606ac2dfe0d4f6a2598aa4821ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 17:54:55 +0200 Subject: [PATCH 11/27] [Blog] Support TS v5 --- docs/blog/version-5.0-release-notes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 5fcc7c2dec..701bc0b421 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -14,9 +14,10 @@ Version 5.0 of [Foal](https://foalts.org/) is out! -## Supported versions of Node +## Supported versions of Node and TypeScript - Support for Node 18 has been dropped and support for Node 22 has been added. +- The supported version of TypeScript is version 5. Update your `package.json` file accordingly. ## Better typing From c983483bf7549b7abfb3102d4b44abacec5115c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 17:50:48 +0200 Subject: [PATCH 12/27] Compile to ES2023 --- docs/docs/common/graphql.md | 2 +- packages/acceptance-tests/tsconfig.json | 4 ++-- packages/aws-s3/tsconfig.json | 4 ++-- packages/cli/src/generate/specs/app/tsconfig.json | 4 ++-- packages/cli/src/generate/templates/app/tsconfig.json | 4 ++-- packages/cli/tsconfig.json | 4 ++-- packages/core/tsconfig.json | 4 ++-- packages/examples/src/app/entities/user.entity.ts | 3 --- packages/examples/tsconfig.json | 4 ++-- packages/graphiql/tsconfig.json | 4 ++-- packages/graphql/src/acceptance-test.spec.ts | 6 +++--- packages/graphql/tsconfig.json | 4 ++-- packages/internal-test/tsconfig.json | 4 ++-- packages/jwks-rsa/tsconfig.json | 4 ++-- packages/jwt/tsconfig.json | 4 ++-- packages/mongodb/tsconfig.json | 4 ++-- packages/password/tsconfig.json | 4 ++-- packages/redis/tsconfig.json | 4 ++-- packages/social/tsconfig.json | 4 ++-- packages/socket.io/tsconfig.json | 4 ++-- packages/storage/tsconfig.json | 4 ++-- packages/swagger/tsconfig.json | 4 ++-- packages/typeorm/tsconfig.json | 4 ++-- packages/typestack/tsconfig.json | 4 ++-- tsconfig.json | 4 ++-- 25 files changed, 48 insertions(+), 51 deletions(-) diff --git a/docs/docs/common/graphql.md b/docs/docs/common/graphql.md index b6de5a7128..b7806cd1c6 100644 --- a/docs/docs/common/graphql.md +++ b/docs/docs/common/graphql.md @@ -194,7 +194,7 @@ export class ApiController extends GraphQLController { schema = // ... @dependency - resolvers: RootResolverService; + declare resolvers: RootResolverService; } ``` diff --git a/packages/acceptance-tests/tsconfig.json b/packages/acceptance-tests/tsconfig.json index b3f56375cf..9e17c26a09 100644 --- a/packages/acceptance-tests/tsconfig.json +++ b/packages/acceptance-tests/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ], "jsx": "react" diff --git a/packages/aws-s3/tsconfig.json b/packages/aws-s3/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/aws-s3/tsconfig.json +++ b/packages/aws-s3/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/cli/src/generate/specs/app/tsconfig.json b/packages/cli/src/generate/specs/app/tsconfig.json index 4debd03ca5..37b1c195a3 100644 --- a/packages/cli/src/generate/specs/app/tsconfig.json +++ b/packages/cli/src/generate/specs/app/tsconfig.json @@ -8,10 +8,10 @@ "noImplicitAny": false, "strictPropertyInitialization": false, "module": "commonjs", - "target": "es2021", + "target": "es2023", "rootDir": "src", "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/cli/src/generate/templates/app/tsconfig.json b/packages/cli/src/generate/templates/app/tsconfig.json index 4debd03ca5..37b1c195a3 100644 --- a/packages/cli/src/generate/templates/app/tsconfig.json +++ b/packages/cli/src/generate/templates/app/tsconfig.json @@ -8,10 +8,10 @@ "noImplicitAny": false, "strictPropertyInitialization": false, "module": "commonjs", - "target": "es2021", + "target": "es2023", "rootDir": "src", "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index 51674d2393..249a647247 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/examples/src/app/entities/user.entity.ts b/packages/examples/src/app/entities/user.entity.ts index ecbd75d7fa..0421793bbc 100644 --- a/packages/examples/src/app/entities/user.entity.ts +++ b/packages/examples/src/app/entities/user.entity.ts @@ -6,9 +6,6 @@ import { UserWithPermissions } from '@foal/typeorm'; @Entity() export class User extends UserWithPermissions { - @PrimaryGeneratedColumn() - id: number; - @Column({ unique: true }) email: string; diff --git a/packages/examples/tsconfig.json b/packages/examples/tsconfig.json index d10b194fab..0e8956d45a 100644 --- a/packages/examples/tsconfig.json +++ b/packages/examples/tsconfig.json @@ -3,7 +3,7 @@ "outDir": "build", "sourceMap": true, "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strictNullChecks": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom", "ESNext.AsyncIterable" ] diff --git a/packages/graphiql/tsconfig.json b/packages/graphiql/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/graphiql/tsconfig.json +++ b/packages/graphiql/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/graphql/src/acceptance-test.spec.ts b/packages/graphql/src/acceptance-test.spec.ts index dcc809af5e..dde032fcec 100644 --- a/packages/graphql/src/acceptance-test.spec.ts +++ b/packages/graphql/src/acceptance-test.spec.ts @@ -70,7 +70,7 @@ describe('[Acceptance test] GraphQLController', () => { schema = buildSchema(typeDefs); @dependency - resolvers: AppResolver; + declare resolvers: AppResolver; } class AppController { @@ -109,7 +109,7 @@ describe('[Acceptance test] GraphQLController', () => { schema = schemaFromTypeGlob('./test-dir/*.graphql'); @dependency - resolvers: AppResolver; + declare resolvers: AppResolver; } class AppController { @@ -158,7 +158,7 @@ describe('[Acceptance test] GraphQLController', () => { schema = buildSchema(typeDefs); @dependency - resolvers: Resolvers; + declare resolvers: Resolvers; } class AppController { diff --git a/packages/graphql/tsconfig.json b/packages/graphql/tsconfig.json index 10860f5077..bf9eb7fea0 100644 --- a/packages/graphql/tsconfig.json +++ b/packages/graphql/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom", "ESNext.AsyncIterable" ] diff --git a/packages/internal-test/tsconfig.json b/packages/internal-test/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/internal-test/tsconfig.json +++ b/packages/internal-test/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/jwks-rsa/tsconfig.json b/packages/jwks-rsa/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/jwks-rsa/tsconfig.json +++ b/packages/jwks-rsa/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/jwt/tsconfig.json b/packages/jwt/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/jwt/tsconfig.json +++ b/packages/jwt/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/mongodb/tsconfig.json b/packages/mongodb/tsconfig.json index 282ee38efd..3bbf030a35 100644 --- a/packages/mongodb/tsconfig.json +++ b/packages/mongodb/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ], "types": [ diff --git a/packages/password/tsconfig.json b/packages/password/tsconfig.json index 282ee38efd..3bbf030a35 100644 --- a/packages/password/tsconfig.json +++ b/packages/password/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ], "types": [ diff --git a/packages/redis/tsconfig.json b/packages/redis/tsconfig.json index 282ee38efd..3bbf030a35 100644 --- a/packages/redis/tsconfig.json +++ b/packages/redis/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ], "types": [ diff --git a/packages/social/tsconfig.json b/packages/social/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/social/tsconfig.json +++ b/packages/social/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/socket.io/tsconfig.json b/packages/socket.io/tsconfig.json index 282ee38efd..3bbf030a35 100644 --- a/packages/socket.io/tsconfig.json +++ b/packages/socket.io/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ], "types": [ diff --git a/packages/storage/tsconfig.json b/packages/storage/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/storage/tsconfig.json +++ b/packages/storage/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/swagger/tsconfig.json b/packages/swagger/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/swagger/tsconfig.json +++ b/packages/swagger/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/typeorm/tsconfig.json b/packages/typeorm/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/typeorm/tsconfig.json +++ b/packages/typeorm/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/packages/typestack/tsconfig.json b/packages/typestack/tsconfig.json index dbe86b109b..4be5f16fd3 100644 --- a/packages/typestack/tsconfig.json +++ b/packages/typestack/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "lib/", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -15,7 +15,7 @@ "../../node_modules/@types", ], "lib": [ - "es2021", + "es2023", "dom" ] }, diff --git a/tsconfig.json b/tsconfig.json index 9c91f1d6a3..f317f2ed8d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "outDir": "./lib/", "baseUrl": ".", "module": "commonjs", - "target": "es2021", + "target": "es2023", "emitDecoratorMetadata": true, "experimentalDecorators": true, "strict": true, @@ -11,7 +11,7 @@ "sourceMap": true, "declaration": true, "lib": [ - "es2021", + "es2023", "dom" ] }, From 3cb8f2cf241779e73160ce3b94ba998070ca9f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 19:07:31 +0200 Subject: [PATCH 13/27] Fix linting --- packages/examples/src/app/entities/user.entity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/examples/src/app/entities/user.entity.ts b/packages/examples/src/app/entities/user.entity.ts index 0421793bbc..838ab0d429 100644 --- a/packages/examples/src/app/entities/user.entity.ts +++ b/packages/examples/src/app/entities/user.entity.ts @@ -1,4 +1,4 @@ -import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; +import { Column, Entity } from 'typeorm'; import { hashPassword } from '@foal/core'; import { UserWithPermissions } from '@foal/typeorm'; From 79e40c043c356f7791f4b5125fc876f854946024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 19:11:08 +0200 Subject: [PATCH 14/27] [Blog] Add note on ES2023 --- docs/blog/version-5.0-release-notes.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 701bc0b421..08ca0fdbab 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -16,9 +16,20 @@ Version 5.0 of [Foal](https://foalts.org/) is out! ## Supported versions of Node and TypeScript -- Support for Node 18 has been dropped and support for Node 22 has been added. +- Support for Node 18 has been dropped and support for Node 22 has been added. Foal code is now compiled to ES2023. - The supported version of TypeScript is version 5. Update your `package.json` file accordingly. +> If you're using the `GraphQLController` with the `resolvers` property, you need to add the `declare` keyword before the property name: +> ```typescript +> +> export class ApiController extends GraphQLController { +> schema = // ... +> +> @dependency +> declare resolvers: RootResolverService; +> } +> ``` + ## Better typing - The default type of `Context.state` is now `{}`. This way, you'll get a compilation error if you forget to specify a type for the state. From f22b313139dbdbdb996a1f82ca64c092945d209a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 19:34:08 +0200 Subject: [PATCH 15/27] Improve `AbstractProvider.getUserInfoFromTokens` return type --- docs/docs/authentication/social-auth.md | 8 ++++++-- .../social/src/abstract-provider.service.spec.ts | 15 +++++++++------ packages/social/src/abstract-provider.service.ts | 11 +++++------ packages/social/src/google-provider.service.ts | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/docs/docs/authentication/social-auth.md b/docs/docs/authentication/social-auth.md index 588c1549be..972c3ef8e2 100644 --- a/docs/docs/authentication/social-auth.md +++ b/docs/docs/authentication/social-auth.md @@ -343,7 +343,11 @@ export interface GithubUserInfoParameter { // ... } -export class GithubProvider extends AbstractProvider { +export interface GithubUserInfo { + // ... +} + +export class GithubProvider extends AbstractProvider { protected configPaths = { clientId: 'social.github.clientId', @@ -357,7 +361,7 @@ export class GithubProvider extends AbstractProvider { // ... // In case the server returns an error when requesting diff --git a/packages/social/src/abstract-provider.service.spec.ts b/packages/social/src/abstract-provider.service.spec.ts index 0275a36c35..f8e6d74970 100644 --- a/packages/social/src/abstract-provider.service.spec.ts +++ b/packages/social/src/abstract-provider.service.spec.ts @@ -143,7 +143,7 @@ describe('TokenError', () => { describe('AbstractProvider', () => { - class ConcreteProvider extends AbstractProvider { + class ConcreteProvider extends AbstractProvider { protected configPaths = { clientId: 'settings.social.example.clientId', clientSecret: 'settings.social.example.clientSecret', @@ -151,7 +151,8 @@ describe('AbstractProvider', () => { }; protected authEndpoint = 'https://example2.com/auth'; protected tokenEndpoint = 'http://localhost:3000/token'; - getUserInfoFromTokens(tokens: SocialTokens) { + + async getUserInfoFromTokens(tokens: SocialTokens): Promise { throw new Error('Method not implemented.'); } } @@ -611,7 +612,7 @@ describe('AbstractProvider', () => { }); class ConcreteProvider2 extends ConcreteProvider { - getUserInfoFromTokens(tokens: SocialTokens) { + async getUserInfoFromTokens(tokens: SocialTokens) { // Do not throw an error. } } @@ -656,7 +657,7 @@ describe('AbstractProvider', () => { let calledWithTokens: null|SocialTokens = null; let calledWithParams: null|any = null; class ConcreteProvider2 extends ConcreteProvider { - getUserInfoFromTokens(tokens: SocialTokens, params?: any) { + async getUserInfoFromTokens(tokens: SocialTokens, params?: any) { calledWithTokens = tokens; calledWithParams = params || null; } @@ -718,7 +719,8 @@ describe('Abstract Provider With PKCE', () => { protected usePKCE: boolean = true; protected authEndpoint = 'https://example2.com/auth'; protected tokenEndpoint = 'http://localhost:3000/token'; - getUserInfoFromTokens(tokens: SocialTokens) { + + async getUserInfoFromTokens(tokens: SocialTokens) { throw new Error('Method not implemented.'); } } @@ -917,7 +919,8 @@ describe('Abstract Provider With PKCE and Plain Method', () => { protected useCodeVerifierAsCodeChallenge = true; protected authEndpoint = 'https://example2.com/auth'; protected tokenEndpoint = 'http://localhost:3000/token'; - getUserInfoFromTokens(tokens: SocialTokens) { + + async getUserInfoFromTokens(tokens: SocialTokens) { throw new Error('Method not implemented.'); } } diff --git a/packages/social/src/abstract-provider.service.ts b/packages/social/src/abstract-provider.service.ts index 6297dc5ab5..55008dcf6d 100644 --- a/packages/social/src/abstract-provider.service.ts +++ b/packages/social/src/abstract-provider.service.ts @@ -113,9 +113,9 @@ export interface ObjectType { * @class AbstractProvider * @template AuthParameters - Additional parameters to pass to the auth endpoint. * @template UserInfoParameters - Additional parameters to pass when retrieving user information. - * @template IUserInfo - Type of the user information. + * @template UserInfo - Type of the user information. */ -export abstract class AbstractProvider { +export abstract class AbstractProvider { /** * Configuration paths from which the client ID, client secret and redirect URI must be retrieved. @@ -232,10 +232,10 @@ export abstract class AbstractProvider} The user information. * @memberof AbstractProvider */ - abstract getUserInfoFromTokens(tokens: SocialTokens, params?: UserInfoParameters): any; + abstract getUserInfoFromTokens(tokens: SocialTokens, params?: UserInfoParameters): UserInfo | Promise; /** * Returns an HttpResponseOK or HttpResponseRedirect object to redirect the user to the social provider's authorization page. @@ -393,13 +393,12 @@ export abstract class AbstractProvider>} The access token and the user information * @memberof AbstractProvider */ - async getUserInfo(ctx: Context, params?: UserInfoParameters): Promise> { + async getUserInfo(ctx: Context, params?: UserInfoParameters): Promise> { const tokens = await this.getTokens(ctx); const userInfo = await this.getUserInfoFromTokens(tokens, params); return { userInfo, tokens }; diff --git a/packages/social/src/google-provider.service.ts b/packages/social/src/google-provider.service.ts index faf5c4ead2..bf412898f9 100644 --- a/packages/social/src/google-provider.service.ts +++ b/packages/social/src/google-provider.service.ts @@ -57,7 +57,7 @@ export class GoogleProvider extends AbstractProvider Date: Thu, 22 Aug 2024 19:39:19 +0200 Subject: [PATCH 16/27] [Blog] The return value of `getUserInfoFromTokens` is typed --- docs/blog/version-5.0-release-notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 08ca0fdbab..7b12c8bc95 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -63,6 +63,8 @@ Version 5.0 of [Foal](https://foalts.org/) is out! ``` +- The return value of the social services `getUserInfoFromTokens` method is now typed. + ## Removal of deprecated components - The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead. From b292a5f85a31e9346840b880e801365f8d30a3b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 19:39:58 +0200 Subject: [PATCH 17/27] [Docs] Fix typo --- docs/docs/authentication/social-auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/authentication/social-auth.md b/docs/docs/authentication/social-auth.md index 972c3ef8e2..50382b06d1 100644 --- a/docs/docs/authentication/social-auth.md +++ b/docs/docs/authentication/social-auth.md @@ -361,7 +361,7 @@ export class GithubProvider extends AbstractProvider { + getUserInfoFromTokens(tokens: SocialTokens, params?: GithubUserInfoParameter): GithubUserInfo | Promise { // ... // In case the server returns an error when requesting From d9a79bd6f187a3a0ccd843580b84c12209af4bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 20:38:26 +0200 Subject: [PATCH 18/27] Make addLogContext accept a record with multiple params --- docs/blog/version-5.0-release-notes.md | 4 ++++ docs/docs/common/logging.md | 2 +- packages/core/src/core/logging/logger.spec.ts | 10 ++++++---- packages/core/src/core/logging/logger.ts | 4 ++-- packages/core/src/express/create-app.spec.ts | 7 +++---- packages/core/src/express/create-app.ts | 2 +- .../core/src/sessions/http/use-sessions.hook.spec.ts | 4 ++-- packages/core/src/sessions/http/use-sessions.hook.ts | 2 +- packages/jwt/src/http/jwt.hook.spec.ts | 2 +- packages/jwt/src/http/jwt.hook.ts | 2 +- .../socket.io/src/socketio-controller.service.spec.ts | 10 ++++++---- packages/socket.io/src/socketio-controller.service.ts | 7 +++++-- 12 files changed, 33 insertions(+), 23 deletions(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 7b12c8bc95..f80aeec93d 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -65,6 +65,10 @@ Version 5.0 of [Foal](https://foalts.org/) is out! - The return value of the social services `getUserInfoFromTokens` method is now typed. +## Logging + +- The `Logger.addLogContext(key, value)` method now accepts a record as argument: `Logger.addLogContext(params)`. This makes the function's signature more consistent with other logging methods (`info`, `warn`, etc.) and allows multiple parameters to be passed at once. + ## Removal of deprecated components - The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead. diff --git a/docs/docs/common/logging.md b/docs/docs/common/logging.md index bb2a61d6a1..0f9d08b8db 100644 --- a/docs/docs/common/logging.md +++ b/docs/docs/common/logging.md @@ -260,7 +260,7 @@ This mecanism helps filter logs of a specific request or specific user in a logg If needed, you call also add manually custom parameters to the logger context with this fonction: ```typescript -logger.addLogContext('myKey', 'myValue'); +logger.addLogContext({ myKey: 'myValue' }); ``` ## Transports diff --git a/packages/core/src/core/logging/logger.spec.ts b/packages/core/src/core/logging/logger.spec.ts index bef0ac5cc6..c973a7e2aa 100644 --- a/packages/core/src/core/logging/logger.spec.ts +++ b/packages/core/src/core/logging/logger.spec.ts @@ -22,11 +22,11 @@ describe('Logger', () => { const logger = new Logger(); logger.initLogContext(() => { - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar', jane: 'doe'}); logger.log('error', 'Hello world', {}); }); logger.initLogContext(() => { - logger.addLogContext('foo2', 'bar2'); + logger.addLogContext({ foo2: 'bar2' }); logger.log('error', 'Hello world 2', {}); }); @@ -36,6 +36,7 @@ describe('Logger', () => { strictEqual(loggedMessage.includes('[ERROR]'), true); strictEqual(loggedMessage.includes('foo: "bar"'), true); + strictEqual(loggedMessage.includes('jane: "doe"'), true); notStrictEqual(loggedMessage.includes('foo2: "bar2"'), true); const loggedMessage2 = consoleMock.calls[1].arguments[0]; @@ -43,6 +44,7 @@ describe('Logger', () => { strictEqual(loggedMessage2.includes('[ERROR]'), true); strictEqual(loggedMessage2.includes('foo2: "bar2"'), true); notStrictEqual(loggedMessage2.includes('foo: "bar"'), true); + notStrictEqual(loggedMessage2.includes('jane: "doe"'), true); }); it('should let given params override the context.', () => { @@ -50,7 +52,7 @@ describe('Logger', () => { const logger = new Logger(); logger.initLogContext(() => { - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar' }); logger.log('error', 'Hello world', { foo: 'bar2' }); }); @@ -68,7 +70,7 @@ describe('Logger', () => { const consoleMock = mock.method(console, 'log', () => {}).mock; const logger = new Logger(); - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar' }); strictEqual(consoleMock.callCount(), 1); diff --git a/packages/core/src/core/logging/logger.ts b/packages/core/src/core/logging/logger.ts index 6515dd0a84..d8f8c3830d 100644 --- a/packages/core/src/core/logging/logger.ts +++ b/packages/core/src/core/logging/logger.ts @@ -19,13 +19,13 @@ export class Logger { this.asyncLocalStorage.run({}, callback); } - addLogContext(name: string, value: any): void { + addLogContext(params: Record): void { const store = this.asyncLocalStorage.getStore(); if (!store) { this.log('warn', 'Impossible to add log context information. The logger context has not been initialized.'); return; } - store[name] = value; + Object.assign(store, params); } log( diff --git a/packages/core/src/express/create-app.spec.ts b/packages/core/src/express/create-app.spec.ts index 3411fdbba4..65a91bfb07 100644 --- a/packages/core/src/express/create-app.spec.ts +++ b/packages/core/src/express/create-app.spec.ts @@ -887,7 +887,7 @@ describe('createApp', () => { @Get('/') @Hook((ctx, services) => { const logger = services.get(Logger); - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar' }); }) getA(ctx: Context) { this.logger.info('Hello world'); @@ -995,9 +995,8 @@ describe('createApp', () => { strictEqual(loggerMock.callCount(), 1); - const [key, value] = loggerMock.calls[0].arguments; + const args = loggerMock.calls[0].arguments; - strictEqual(key, 'requestId'); - strictEqual(value, requestId); + deepStrictEqual(args, [{ requestId }]); }); }); diff --git a/packages/core/src/express/create-app.ts b/packages/core/src/express/create-app.ts index aeac0351f4..59f82bb54f 100644 --- a/packages/core/src/express/create-app.ts +++ b/packages/core/src/express/create-app.ts @@ -116,7 +116,7 @@ export async function createApp( const requestId = req.get('x-request-id') || randomUUID(); req.id = requestId; - logger.addLogContext('requestId', requestId); + logger.addLogContext({ requestId }); next(); }); diff --git a/packages/core/src/sessions/http/use-sessions.hook.spec.ts b/packages/core/src/sessions/http/use-sessions.hook.spec.ts index 28f2d937ce..00f48792ad 100644 --- a/packages/core/src/sessions/http/use-sessions.hook.spec.ts +++ b/packages/core/src/sessions/http/use-sessions.hook.spec.ts @@ -615,7 +615,7 @@ describe('UseSessions', () => { strictEqual(loggerMock.callCount(), 1); - deepStrictEqual(loggerMock.calls[0].arguments, ['userId', null]); + deepStrictEqual(loggerMock.calls[0].arguments, [{ userId: null }]); }); }); @@ -632,7 +632,7 @@ describe('UseSessions', () => { strictEqual(loggerMock.callCount(), 1); - deepStrictEqual(loggerMock.calls[0].arguments, ['userId', userId]); + deepStrictEqual(loggerMock.calls[0].arguments, [{ userId }]); }); context('given options.user is not defined', () => { diff --git a/packages/core/src/sessions/http/use-sessions.hook.ts b/packages/core/src/sessions/http/use-sessions.hook.ts index 7e34e74db2..474708f9b4 100644 --- a/packages/core/src/sessions/http/use-sessions.hook.ts +++ b/packages/core/src/sessions/http/use-sessions.hook.ts @@ -144,7 +144,7 @@ export function UseSessions(options: UseSessionOptions = {}): HookDecorator { /* Set ctx.user */ const logger = services.get(Logger); - logger.addLogContext('userId', session.userId); + logger.addLogContext({ userId: session.userId }); if (session.userId !== null && options.user) { const userId = checkUserIdType(session.userId, options.userIdType); diff --git a/packages/jwt/src/http/jwt.hook.spec.ts b/packages/jwt/src/http/jwt.hook.spec.ts index 366668ef0e..2d83436a17 100644 --- a/packages/jwt/src/http/jwt.hook.spec.ts +++ b/packages/jwt/src/http/jwt.hook.spec.ts @@ -632,7 +632,7 @@ export function testSuite(JWT: typeof JWTOptional|typeof JWTRequired, required: strictEqual(loggerMock.callCount(), 1); deepStrictEqual( loggerMock.calls[0].arguments, - ['userId', 123], + [{ userId: 123 }], ); }) diff --git a/packages/jwt/src/http/jwt.hook.ts b/packages/jwt/src/http/jwt.hook.ts index 44d18db238..9292b8991d 100644 --- a/packages/jwt/src/http/jwt.hook.ts +++ b/packages/jwt/src/http/jwt.hook.ts @@ -201,7 +201,7 @@ export function JWT(required: boolean, options: JWTOptions, verifyOptions: Verif const userId = checkAndConvertUserIdType(payload.sub, options.userIdType); const logger = services.get(Logger); - logger.addLogContext('userId', userId); + logger.addLogContext({ userId }); const user = await options.user(userId as never, services); if (!user) { diff --git a/packages/socket.io/src/socketio-controller.service.spec.ts b/packages/socket.io/src/socketio-controller.service.spec.ts index 6a78a77187..c8c426e9a8 100644 --- a/packages/socket.io/src/socketio-controller.service.spec.ts +++ b/packages/socket.io/src/socketio-controller.service.spec.ts @@ -431,7 +431,7 @@ describe('SocketIOController', () => { @EventName('create user') @WebsocketHook((ctx, services) => { const logger = services.get(Logger); - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar' }); }) createUser(ctx: WebsocketContext, payload: any) { this.logger.info('Hello world'); @@ -474,12 +474,14 @@ describe('SocketIOController', () => { const payload = {}; await new Promise(resolve => clientSocket.emit('create user', payload, resolve)); - strictEqual(loggerMock.callCount(), 2); + strictEqual(loggerMock.callCount(), 1); const actualParameters = loggerMock.calls.map(call => call.arguments); const expectedParameters = [ - ['socketId', socketId], - ['messageId', messageId] + [{ + socketId, + messageId, + }] ]; deepStrictEqual(actualParameters, expectedParameters); diff --git a/packages/socket.io/src/socketio-controller.service.ts b/packages/socket.io/src/socketio-controller.service.ts index 085c470125..6063ef3006 100644 --- a/packages/socket.io/src/socketio-controller.service.ts +++ b/packages/socket.io/src/socketio-controller.service.ts @@ -72,8 +72,11 @@ export abstract class SocketIOController implements ISocketIOController { socket.on(route.eventName, async (payload, cb) => { this.logger.initLogContext(async () => { const messageId = randomUUID(); - this.logger.addLogContext('socketId', socket.id); - this.logger.addLogContext('messageId', messageId); + + this.logger.addLogContext({ + socketId: socket.id, + messageId, + }); if (typeof payload === 'function') { cb = payload; From a249f417f7b42df1d2990c5574eb41616e27f22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 20:42:53 +0200 Subject: [PATCH 19/27] Use better param name --- docs/blog/version-5.0-release-notes.md | 2 +- packages/core/src/core/logging/logger.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index f80aeec93d..ac9fd23b03 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -67,7 +67,7 @@ Version 5.0 of [Foal](https://foalts.org/) is out! ## Logging -- The `Logger.addLogContext(key, value)` method now accepts a record as argument: `Logger.addLogContext(params)`. This makes the function's signature more consistent with other logging methods (`info`, `warn`, etc.) and allows multiple parameters to be passed at once. +- The `Logger.addLogContext(key, value)` method now accepts a record as parameter: `Logger.addLogContext(context)`. This makes the function's signature more consistent with other logging methods (`info`, `warn`, etc.) and allows multiple keys/values to be passed at once. ## Removal of deprecated components diff --git a/packages/core/src/core/logging/logger.ts b/packages/core/src/core/logging/logger.ts index d8f8c3830d..4688b4b20a 100644 --- a/packages/core/src/core/logging/logger.ts +++ b/packages/core/src/core/logging/logger.ts @@ -19,13 +19,13 @@ export class Logger { this.asyncLocalStorage.run({}, callback); } - addLogContext(params: Record): void { + addLogContext(context: Record): void { const store = this.asyncLocalStorage.getStore(); if (!store) { this.log('warn', 'Impossible to add log context information. The logger context has not been initialized.'); return; } - Object.assign(store, params); + Object.assign(store, context); } log( From 139e9022f0deee2665f62af4f256dc3bd8939934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 20:56:18 +0200 Subject: [PATCH 20/27] [Docs] Fix typo on error logging --- docs/docs/common/logging.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/common/logging.md b/docs/docs/common/logging.md index 0f9d08b8db..5019f22850 100644 --- a/docs/docs/common/logging.md +++ b/docs/docs/common/logging.md @@ -216,12 +216,12 @@ When an error is thrown (or rejected) in a hook, controller or service and is no ### Disabling Error Logging -In some scenarios, you might want to disable error logging. You can achieve this by setting the `allErrors` configuration option to false. +In some scenarios, you might want to disable error logging. You can achieve this by setting the `logErrors` configuration option to false. ```json { "settings": { - "allErrors": false + "logErrors": false } } ``` From 3e6fb8d34820d96d0a1d61d23af45aa636a6ab1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 20:59:07 +0200 Subject: [PATCH 21/27] Replace loggerFormat with logger.logHttpRequests --- docs/docs/common/logging.md | 29 ++--------- packages/acceptance-tests/config/default.yml | 3 +- .../generate/specs/app/config/default.json | 1 - .../specs/app/config/default.mongodb.json | 3 -- .../specs/app/config/default.mongodb.yml | 3 -- .../src/generate/specs/app/config/default.yml | 1 - .../src/generate/specs/app/config/e2e.json | 4 +- .../specs/app/config/e2e.mongodb.json | 4 +- .../generate/specs/app/config/e2e.mongodb.yml | 3 +- .../cli/src/generate/specs/app/config/e2e.yml | 3 +- .../templates/app/config/default.json | 1 - .../templates/app/config/default.mongodb.json | 3 -- .../templates/app/config/default.mongodb.yml | 3 -- .../generate/templates/app/config/default.yml | 1 - .../generate/templates/app/config/e2e.json | 4 +- .../templates/app/config/e2e.mongodb.json | 4 +- .../templates/app/config/e2e.mongodb.yml | 3 +- .../src/generate/templates/app/config/e2e.yml | 3 +- packages/core/src/express/create-app.spec.ts | 51 +++++++++++++++---- packages/core/src/express/create-app.ts | 11 +--- packages/examples/config/default.yml | 1 - .../src/abstract-provider.service.spec.ts | 9 ++-- .../src/facebook-provider.service.spec.ts | 4 +- .../src/github-provider.service.spec.ts | 4 +- .../src/linkedin-provider.service.spec.ts | 4 +- .../src/twitter-provider.service.spec.ts | 4 +- .../src/parse-and-validate-files.hook.spec.ts | 4 +- 27 files changed, 85 insertions(+), 83 deletions(-) diff --git a/docs/docs/common/logging.md b/docs/docs/common/logging.md index 5019f22850..c2a4d5c1e3 100644 --- a/docs/docs/common/logging.md +++ b/docs/docs/common/logging.md @@ -6,15 +6,6 @@ Foal provides an advanced built-in logger. This page shows how to use it. ## Recommended Configuration -*config/default.json* -```json -{ - "settings": { - "loggerFormat": "foal" - } -} -``` - *config/development.json* ```json { @@ -143,7 +134,7 @@ If you wish to completly mask logs, you can use the `none` format. Each request received by Foal is logged with the INFO level. -With the configuration key `settings.loggerFormat` set to `"foal"`, the messages start with `HTTP request -` and end with the request method and URL. The log parameters include the response status code and content length as well as the response time and the request method and URL. +The messages start with `HTTP request -` and end with the request method and URL. The log parameters include the response status code and content length as well as the response time and the request method and URL. > Note: the query parameters are not logged to avoid logging sensitive data (such as an API key). @@ -162,26 +153,16 @@ const app = await createApp({ }) ``` -### Formatting the log message (deprecated) - -If you wish to customize the HTTP log messages, you can set the value of the `loggerFormat.loggerFormat` configuration to a format supported by [morgan](https://www.npmjs.com/package/morgan). With this technique, no parameters will be logged though. - -```json -{ - "settings": { - "loggerFormat": "tiny" - } -} -``` - ### Disabling HTTP Request Logging -In some scenarios and environments, you might want to disable HTTP request logging. You can achieve this by setting the `loggerFormat` configuration option to `none`. +In some scenarios and environments, you might want to disable HTTP request logging. You can achieve this by setting the `logger.logHttpRequests` configuration option to `false`. ```json { "settings": { - "loggerFormat": "none" + "logger": { + "logHttpRequests": false + } } } ``` diff --git a/packages/acceptance-tests/config/default.yml b/packages/acceptance-tests/config/default.yml index c00cdf3221..07c0485fdc 100644 --- a/packages/acceptance-tests/config/default.yml +++ b/packages/acceptance-tests/config/default.yml @@ -1,2 +1,3 @@ settings: - loggerFormat: none \ No newline at end of file + logger: + logHttpRequests: false \ No newline at end of file diff --git a/packages/cli/src/generate/specs/app/config/default.json b/packages/cli/src/generate/specs/app/config/default.json index 89e6cd04c8..8ada1ddbd5 100644 --- a/packages/cli/src/generate/specs/app/config/default.json +++ b/packages/cli/src/generate/specs/app/config/default.json @@ -1,7 +1,6 @@ { "port": "env(PORT)", "settings": { - "loggerFormat": "foal", "session": { "store": "@foal/typeorm" } diff --git a/packages/cli/src/generate/specs/app/config/default.mongodb.json b/packages/cli/src/generate/specs/app/config/default.mongodb.json index 1e975a3cd8..799d53750c 100644 --- a/packages/cli/src/generate/specs/app/config/default.mongodb.json +++ b/packages/cli/src/generate/specs/app/config/default.mongodb.json @@ -1,8 +1,5 @@ { "port": "env(PORT)", - "settings": { - "loggerFormat": "foal" - }, "database": { "type": "mongodb", "url": "mongodb://localhost:27017/test-foo-bar" diff --git a/packages/cli/src/generate/specs/app/config/default.mongodb.yml b/packages/cli/src/generate/specs/app/config/default.mongodb.yml index 33bd271229..01ccd9ce0f 100644 --- a/packages/cli/src/generate/specs/app/config/default.mongodb.yml +++ b/packages/cli/src/generate/specs/app/config/default.mongodb.yml @@ -1,8 +1,5 @@ port: env(PORT) -settings: - loggerFormat: foal - database: type: mongodb url: mongodb://localhost:27017/test-foo-bar diff --git a/packages/cli/src/generate/specs/app/config/default.yml b/packages/cli/src/generate/specs/app/config/default.yml index b8d452a4a6..ff92e81eeb 100644 --- a/packages/cli/src/generate/specs/app/config/default.yml +++ b/packages/cli/src/generate/specs/app/config/default.yml @@ -1,7 +1,6 @@ port: env(PORT) settings: - loggerFormat: foal session: store: '@foal/typeorm' diff --git a/packages/cli/src/generate/specs/app/config/e2e.json b/packages/cli/src/generate/specs/app/config/e2e.json index 3aa0c9d436..66cd1f4032 100644 --- a/packages/cli/src/generate/specs/app/config/e2e.json +++ b/packages/cli/src/generate/specs/app/config/e2e.json @@ -1,6 +1,8 @@ { "settings": { - "loggerFormat": "none" + "logger": { + "logHttpRequests": false + } }, "database": { "database": "./e2e_db.sqlite3", diff --git a/packages/cli/src/generate/specs/app/config/e2e.mongodb.json b/packages/cli/src/generate/specs/app/config/e2e.mongodb.json index 0557ec9654..9aa6d7d092 100644 --- a/packages/cli/src/generate/specs/app/config/e2e.mongodb.json +++ b/packages/cli/src/generate/specs/app/config/e2e.mongodb.json @@ -1,6 +1,8 @@ { "settings": { - "loggerFormat": "none" + "logger": { + "logHttpRequests": false + } }, "database": { "url": "mongodb://localhost:27017/e2e-test-foo-bar" diff --git a/packages/cli/src/generate/specs/app/config/e2e.mongodb.yml b/packages/cli/src/generate/specs/app/config/e2e.mongodb.yml index 281daa0052..3f1f0a900a 100644 --- a/packages/cli/src/generate/specs/app/config/e2e.mongodb.yml +++ b/packages/cli/src/generate/specs/app/config/e2e.mongodb.yml @@ -1,5 +1,6 @@ settings: - loggerFormat: 'none' + logger: + logHttpRequests: false database: url: mongodb://localhost:27017/e2e-test-foo-bar diff --git a/packages/cli/src/generate/specs/app/config/e2e.yml b/packages/cli/src/generate/specs/app/config/e2e.yml index 06a4add77f..0151d2c5cc 100644 --- a/packages/cli/src/generate/specs/app/config/e2e.yml +++ b/packages/cli/src/generate/specs/app/config/e2e.yml @@ -1,5 +1,6 @@ settings: - loggerFormat: 'none' + logger: + logHttpRequests: false database: database: './e2e_db.sqlite3' diff --git a/packages/cli/src/generate/templates/app/config/default.json b/packages/cli/src/generate/templates/app/config/default.json index 89e6cd04c8..8ada1ddbd5 100644 --- a/packages/cli/src/generate/templates/app/config/default.json +++ b/packages/cli/src/generate/templates/app/config/default.json @@ -1,7 +1,6 @@ { "port": "env(PORT)", "settings": { - "loggerFormat": "foal", "session": { "store": "@foal/typeorm" } diff --git a/packages/cli/src/generate/templates/app/config/default.mongodb.json b/packages/cli/src/generate/templates/app/config/default.mongodb.json index f0e91cf5e5..0393e6fc86 100644 --- a/packages/cli/src/generate/templates/app/config/default.mongodb.json +++ b/packages/cli/src/generate/templates/app/config/default.mongodb.json @@ -1,8 +1,5 @@ { "port": "env(PORT)", - "settings": { - "loggerFormat": "foal" - }, "database": { "type": "mongodb", "url": "mongodb://localhost:27017//* kebabName */" diff --git a/packages/cli/src/generate/templates/app/config/default.mongodb.yml b/packages/cli/src/generate/templates/app/config/default.mongodb.yml index 2afcb89e21..d2b400e060 100644 --- a/packages/cli/src/generate/templates/app/config/default.mongodb.yml +++ b/packages/cli/src/generate/templates/app/config/default.mongodb.yml @@ -1,8 +1,5 @@ port: env(PORT) -settings: - loggerFormat: foal - database: type: mongodb url: mongodb://localhost:27017//* kebabName */ diff --git a/packages/cli/src/generate/templates/app/config/default.yml b/packages/cli/src/generate/templates/app/config/default.yml index b8d452a4a6..ff92e81eeb 100644 --- a/packages/cli/src/generate/templates/app/config/default.yml +++ b/packages/cli/src/generate/templates/app/config/default.yml @@ -1,7 +1,6 @@ port: env(PORT) settings: - loggerFormat: foal session: store: '@foal/typeorm' diff --git a/packages/cli/src/generate/templates/app/config/e2e.json b/packages/cli/src/generate/templates/app/config/e2e.json index 3aa0c9d436..66cd1f4032 100644 --- a/packages/cli/src/generate/templates/app/config/e2e.json +++ b/packages/cli/src/generate/templates/app/config/e2e.json @@ -1,6 +1,8 @@ { "settings": { - "loggerFormat": "none" + "logger": { + "logHttpRequests": false + } }, "database": { "database": "./e2e_db.sqlite3", diff --git a/packages/cli/src/generate/templates/app/config/e2e.mongodb.json b/packages/cli/src/generate/templates/app/config/e2e.mongodb.json index 0526879660..c6b36db3fd 100644 --- a/packages/cli/src/generate/templates/app/config/e2e.mongodb.json +++ b/packages/cli/src/generate/templates/app/config/e2e.mongodb.json @@ -1,6 +1,8 @@ { "settings": { - "loggerFormat": "none" + "logger": { + "logHttpRequests": false + } }, "database": { "url": "mongodb://localhost:27017/e2e-/* kebabName */" diff --git a/packages/cli/src/generate/templates/app/config/e2e.mongodb.yml b/packages/cli/src/generate/templates/app/config/e2e.mongodb.yml index f3ea49f64c..f054ef5607 100644 --- a/packages/cli/src/generate/templates/app/config/e2e.mongodb.yml +++ b/packages/cli/src/generate/templates/app/config/e2e.mongodb.yml @@ -1,5 +1,6 @@ settings: - loggerFormat: 'none' + logger: + logHttpRequests: false database: url: mongodb://localhost:27017/e2e-/* kebabName */ diff --git a/packages/cli/src/generate/templates/app/config/e2e.yml b/packages/cli/src/generate/templates/app/config/e2e.yml index 06a4add77f..0151d2c5cc 100644 --- a/packages/cli/src/generate/templates/app/config/e2e.yml +++ b/packages/cli/src/generate/templates/app/config/e2e.yml @@ -1,5 +1,6 @@ settings: - loggerFormat: 'none' + logger: + logHttpRequests: false database: database: './e2e_db.sqlite3' diff --git a/packages/core/src/express/create-app.spec.ts b/packages/core/src/express/create-app.spec.ts index 65a91bfb07..a1530d6aec 100644 --- a/packages/core/src/express/create-app.spec.ts +++ b/packages/core/src/express/create-app.spec.ts @@ -104,7 +104,7 @@ describe('createApp', () => { Config.remove('settings.debug'); Config.remove('settings.bodyParser.limit'); Config.remove('settings.cookieParser.secret'); - Config.remove('settings.loggerFormat'); + Config.remove('settings.logger.logHttpRequests'); Config.remove('settings.logger.format'); Config.remove('settings.staticFiles.cacheControl'); }); @@ -766,9 +766,37 @@ describe('createApp', () => { } }); - context('given the configuration "settings.loggerFormat" is set to "foal"', () => { + context('given the configuration "settings.logger.logHttpRequests" is set to false', () => { + it('should NOT log the request.', async () => { + Config.set('settings.logger.logHttpRequests', false); + + class AppController { + @Get('/a') + getA(ctx: Context) { + return new HttpResponseOK('a'); + } + } + + const serviceManager = new ServiceManager(); + + const logger = serviceManager.get(Logger); + const loggerMock = mock.method(logger, 'info', () => {}).mock; + + const app = await createApp(AppController, { + serviceManager + }); + + await request(app) + .get('/a') + .expect(200); + + strictEqual(loggerMock.callCount(), 0); + }); + }); + + context('given the configuration "settings.logger.logHttpRequests" is set to true', () => { it('should log the request with a detailed message and detail parameters.', async () => { - Config.set('settings.loggerFormat', 'foal'); + Config.set('settings.logger.logHttpRequests', true); class AppController { @Get('/a') @@ -809,7 +837,7 @@ describe('createApp', () => { }); it('should use the options.getHttpLogParams if provided', async () => { - Config.set('settings.loggerFormat', 'foal'); + Config.set('settings.logger.logHttpRequests', true); class AppController { @Get('/a') @@ -852,10 +880,8 @@ describe('createApp', () => { }); }); - context('given the configuration "settings.loggerFormat" is set to a value different from "none" or "foal"', () => { - it('should log a warning message.', async () => { - Config.set('settings.loggerFormat', 'dev'); - + context('given the configuration "settings.logger.logHttpRequests" is not set', () => { + it('should behave like the configuration is set to true.', async () => { class AppController { @Get('/a') getA(ctx: Context) { @@ -866,14 +892,17 @@ describe('createApp', () => { const serviceManager = new ServiceManager(); const logger = serviceManager.get(Logger); - const loggerMock = mock.method(logger, 'warn', () => {}).mock; + const loggerMock = mock.method(logger, 'info', () => {}).mock; - await createApp(AppController, { + const app = await createApp(AppController, { serviceManager }); + await request(app) + .get('/a') + .expect(200); + strictEqual(loggerMock.callCount(), 1); - strictEqual(loggerMock.calls[0].arguments[0], '[CONFIG] Using another format than "foal" for "settings.loggerFormat" is deprecated.'); }); }); diff --git a/packages/core/src/express/create-app.ts b/packages/core/src/express/create-app.ts index 59f82bb54f..9a4b0440a7 100644 --- a/packages/core/src/express/create-app.ts +++ b/packages/core/src/express/create-app.ts @@ -122,12 +122,8 @@ export async function createApp( }); // Log requests. - const loggerFormat = Config.get( - 'settings.loggerFormat', - 'string', - '[:date] ":method :url HTTP/:http-version" :status - :response-time ms' - ); - if (loggerFormat === 'foal') { + const shouldLogHttpRequests = Config.get('settings.logger.logHttpRequests', 'boolean', true); + if (shouldLogHttpRequests) { const getHttpLogParams = options.getHttpLogParams || getHttpLogParamsDefault; app.use(morgan( (tokens: any, req: any, res: any) => JSON.stringify(getHttpLogParams(tokens, req, res)), @@ -140,9 +136,6 @@ export async function createApp( }, } )) - } else if (loggerFormat !== 'none') { - logger.warn('[CONFIG] Using another format than "foal" for "settings.loggerFormat" is deprecated.'); - app.use(morgan(loggerFormat)); } app.use(protectionHeaders); diff --git a/packages/examples/config/default.yml b/packages/examples/config/default.yml index 2b7a2a1c0f..ee139f9d52 100644 --- a/packages/examples/config/default.yml +++ b/packages/examples/config/default.yml @@ -3,7 +3,6 @@ port: 3001 settings: openapi: useHooks: true - loggerFormat: foal session: secret: 'my secret' staticPath: 'public/' diff --git a/packages/social/src/abstract-provider.service.spec.ts b/packages/social/src/abstract-provider.service.spec.ts index f8e6d74970..9e3321a697 100644 --- a/packages/social/src/abstract-provider.service.spec.ts +++ b/packages/social/src/abstract-provider.service.spec.ts @@ -166,7 +166,7 @@ describe('AbstractProvider', () => { Config.set('settings.social.example.clientId', clientId); Config.set('settings.social.example.clientSecret', clientSecret); Config.set('settings.social.example.redirectUri', redirectUri); - Config.set('settings.loggerFormat', 'none'); + Config.set('settings.logger.logHttpRequests', false); provider = createService(ConcreteProvider); }); @@ -175,6 +175,7 @@ describe('AbstractProvider', () => { Config.remove('settings.social.example.clientId'); Config.remove('settings.social.example.clientSecret'); Config.remove('settings.social.example.redirectUri'); + Config.remove('settings.logger.logHttpRequests'); Config.remove('settings.social.cookie.secure'); Config.remove('settings.social.cookie.domain'); }); @@ -734,7 +735,7 @@ describe('Abstract Provider With PKCE', () => { Config.set('settings.social.example.clientId', clientId); Config.set('settings.social.example.clientSecret', clientSecret); Config.set('settings.social.example.redirectUri', redirectUri); - Config.set('settings.loggerFormat', 'none'); + Config.set('settings.logger.logHttpRequests', false); provider = createService(ConcreteProvider); }); @@ -743,6 +744,7 @@ describe('Abstract Provider With PKCE', () => { Config.remove('settings.social.example.clientId'); Config.remove('settings.social.example.clientSecret'); Config.remove('settings.social.example.redirectUri'); + Config.remove('settings.logger.logHttpRequests'); Config.remove('settings.social.cookie.secure'); Config.remove('settings.social.cookie.domain'); }); @@ -934,7 +936,7 @@ describe('Abstract Provider With PKCE and Plain Method', () => { Config.set('settings.social.example.clientId', clientId); Config.set('settings.social.example.clientSecret', clientSecret); Config.set('settings.social.example.redirectUri', redirectUri); - Config.set('settings.loggerFormat', 'none'); + Config.set('settings.logger.logHttpRequests', false); provider = createService(ConcreteProvider); }); @@ -943,6 +945,7 @@ describe('Abstract Provider With PKCE and Plain Method', () => { Config.remove('settings.social.example.clientId'); Config.remove('settings.social.example.clientSecret'); Config.remove('settings.social.example.redirectUri'); + Config.remove('settings.logger.logHttpRequests'); Config.remove('settings.social.cookie.secure'); Config.remove('settings.social.cookie.domain'); }); diff --git a/packages/social/src/facebook-provider.service.spec.ts b/packages/social/src/facebook-provider.service.spec.ts index 4092419799..d11633b94e 100644 --- a/packages/social/src/facebook-provider.service.spec.ts +++ b/packages/social/src/facebook-provider.service.spec.ts @@ -23,11 +23,11 @@ describe('FacebookProvider', () => { beforeEach(() => { provider = createService(FacebookProvider2); - Config.set('settings.loggerFormat', 'none'); + Config.set('settings.logger.logHttpRequests', false); }); afterEach(() => { - Config.remove('settings.loggerFormat'); + Config.remove('settings.logger.logHttpRequests'); if (server) { server.close(); } diff --git a/packages/social/src/github-provider.service.spec.ts b/packages/social/src/github-provider.service.spec.ts index 2eee26ccd2..427529890c 100644 --- a/packages/social/src/github-provider.service.spec.ts +++ b/packages/social/src/github-provider.service.spec.ts @@ -23,11 +23,11 @@ describe('GithubProvider', () => { beforeEach(() => { provider = createService(GithubProvider2); - Config.set('settings.loggerFormat', 'none'); + Config.set('settings.logger.logHttpRequests', false); }); afterEach(() => { - Config.remove('settings.loggerFormat'); + Config.remove('settings.logger.logHttpRequests'); if (server) { server.close(); } diff --git a/packages/social/src/linkedin-provider.service.spec.ts b/packages/social/src/linkedin-provider.service.spec.ts index 1b3afd077f..a0433159af 100644 --- a/packages/social/src/linkedin-provider.service.spec.ts +++ b/packages/social/src/linkedin-provider.service.spec.ts @@ -21,11 +21,11 @@ describe('LinkedInProvider', () => { beforeEach(() => { provider = createService(LinkedInProvider2); - Config.set('settings.loggerFormat', 'none'); + Config.set('settings.logger.logHttpRequests', false); }); afterEach(() => { - Config.remove('settings.loggerFormat'); + Config.remove('settings.logger.logHttpRequests'); if (server) { server.close(); } diff --git a/packages/social/src/twitter-provider.service.spec.ts b/packages/social/src/twitter-provider.service.spec.ts index cb1086fe06..e575b972e9 100644 --- a/packages/social/src/twitter-provider.service.spec.ts +++ b/packages/social/src/twitter-provider.service.spec.ts @@ -23,11 +23,11 @@ describe('TwitterProvider', () => { beforeEach(() => { provider = createService(TwitterProvider2); - Config.set('settings.loggerFormat', 'none'); + Config.set('settings.logger.logHttpRequests', false); }); afterEach(() => { - Config.remove('settings.loggerFormat'); + Config.remove('settings.logger.logHttpRequests'); if (server) { server.close(); } diff --git a/packages/storage/src/parse-and-validate-files.hook.spec.ts b/packages/storage/src/parse-and-validate-files.hook.spec.ts index cc05958909..e0146012e7 100644 --- a/packages/storage/src/parse-and-validate-files.hook.spec.ts +++ b/packages/storage/src/parse-and-validate-files.hook.spec.ts @@ -21,7 +21,7 @@ interface Actual { describe('ParseAndValidateFiles', () => { beforeEach(() => { - Config.set('settings.loggerFormat', 'none'); + Config.set('settings.logger.logHttpRequests', false); Config.set('settings.disk.driver', 'local'); Config.set('settings.disk.local.directory', 'uploaded'); @@ -31,7 +31,7 @@ describe('ParseAndValidateFiles', () => { }); afterEach(() => { - Config.remove('settings.loggerFormat'); + Config.remove('settings.logger.logHttpRequests'); Config.remove('settings.disk.driver'); Config.remove('settings.disk.local.directory'); From 7218835a81f1fdafacfa629f208fca569313f7c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 21:09:49 +0200 Subject: [PATCH 22/27] [Blog] Replace loggerFormat with logger.logHttpRequests --- docs/blog/version-5.0-release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index ac9fd23b03..5cc9f987fb 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -68,6 +68,7 @@ Version 5.0 of [Foal](https://foalts.org/) is out! ## Logging - The `Logger.addLogContext(key, value)` method now accepts a record as parameter: `Logger.addLogContext(context)`. This makes the function's signature more consistent with other logging methods (`info`, `warn`, etc.) and allows multiple keys/values to be passed at once. +- The deprecated `settings.loggerFormat` configuration has been removed. If you want to disable HTTP logging, set `settings.logger.logHttpRequests` to false instead. ## Removal of deprecated components From a6d98cda61e6bb40470c183be9749ced69922845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 21:42:13 +0200 Subject: [PATCH 23/27] Remove deprecated AbstractProvider.redirect method --- docs/blog/version-5.0-release-notes.md | 3 +- .../src/abstract-provider.service.spec.ts | 56 +++++-------------- .../social/src/abstract-provider.service.ts | 15 ----- 3 files changed, 17 insertions(+), 57 deletions(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 5cc9f987fb..66e681e80b 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -73,4 +73,5 @@ Version 5.0 of [Foal](https://foalts.org/) is out! ## Removal of deprecated components - The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead. -- The command alias `npx foal run-script` has been removed. Use `npx foal run` instead. \ No newline at end of file +- The command alias `npx foal run-script` has been removed. Use `npx foal run` instead. +- The deprecated method `AbstractProvider.redirect` has been removed. Use `AbstractProvider.createHttpResponseWithConsentPageUrl({ isRedirection: true })` instead. \ No newline at end of file diff --git a/packages/social/src/abstract-provider.service.spec.ts b/packages/social/src/abstract-provider.service.spec.ts index 9e3321a697..f4d109371e 100644 --- a/packages/social/src/abstract-provider.service.spec.ts +++ b/packages/social/src/abstract-provider.service.spec.ts @@ -357,32 +357,6 @@ describe('AbstractProvider', () => { }); - describe('has a "redirect" method that', () => { - - it('should behave like the "createHttpResponseWithConsentPageUrl" method with the isRedirection option set to true.', async () => { - const actual = await provider.redirect({ scopes: ['foo'] }); - const expected = await provider.createHttpResponseWithConsentPageUrl({ scopes: ['foo'], isRedirection: true }); - - if (!isHttpResponseRedirect(actual)) { - throw new Error('The response should be an HttpResponseRedirect object.'); - } - - if (!isHttpResponseRedirect(expected)) { - throw new Error('The response should be an HttpResponseRedirect object.'); - } - - const actualConsentPageUrl = new URL(actual.path); - const expectedConsentPageUrl = new URL(expected.path); - - // Remove values generated randomly. - actualConsentPageUrl.searchParams.delete('state'); - expectedConsentPageUrl.searchParams.delete('state'); - - strictEqual(actualConsentPageUrl.href, expectedConsentPageUrl.href); - }); - - }); - describe('has a "getTokens" method that', () => { let server: Server; @@ -749,11 +723,11 @@ describe('Abstract Provider With PKCE', () => { Config.remove('settings.social.cookie.domain'); }); - describe('has a "redirect" method that', () => { + describe('has a "createHttpResponseWithConsentPageUrl" method that', () => { it('should fail if secret is not configured', async () => { try { - await provider.redirect(); + await provider.createHttpResponseWithConsentPageUrl(); } catch(error) { if(!(error instanceof ConfigNotFoundError)){ throw error; @@ -761,7 +735,7 @@ describe('Abstract Provider With PKCE', () => { } }); - describe('should return an HttpResponseRedirect object', () => { + describe('should return an HttpResponse object', () => { beforeEach(() => { Config.set('settings.social.secret.codeVerifierSecret', 'SECRET'); @@ -771,21 +745,21 @@ describe('Abstract Provider With PKCE', () => { Config.remove('settings.social.secret.codeVerifierSecret'); }); - it('with a redirect path which contains a client ID, a response type, a redirect URI, code_challenge and code_challenge_method (S256) if pkce enabled.', async () => { - const response = await provider.redirect(); - ok(response.path.startsWith( + it('with a consentPageUrl which contains a client ID, a response type, a redirect URI, code_challenge and code_challenge_method (S256) if pkce enabled.', async () => { + const response = await provider.createHttpResponseWithConsentPageUrl(); + ok(response.body.consentPageUrl.startsWith( 'https://example2.com/auth?' + 'response_type=code&' + 'client_id=clientIdXXX&' + 'redirect_uri=https%3A%2F%2Fexample.com%2Fcallback' )); - const searchParams = new URLSearchParams(response.path); + const searchParams = new URLSearchParams(response.body.consentPageUrl); ok(searchParams.get('code_challenge')); strictEqual(searchParams.get('code_challenge_method'), 'S256'); }); it('that sets a cookie containing the code verifier encrypted.', async () =>{ - const response = await provider.redirect(); + const response = await provider.createHttpResponseWithConsentPageUrl(); const stateCookieValue = response.getCookie(CODE_VERIFIER_COOKIE_NAME).value; const stateCookieOptions = response.getCookie(CODE_VERIFIER_COOKIE_NAME).options; @@ -804,7 +778,7 @@ describe('Abstract Provider With PKCE', () => { it('that sets a cookie that can have a custom domain.', async () =>{ Config.set('settings.social.cookie.domain', 'foalts.org'); - const response = await provider.redirect(); + const response = await provider.createHttpResponseWithConsentPageUrl(); const { options } = response.getCookie(CODE_VERIFIER_COOKIE_NAME); strictEqual(options.domain, 'foalts.org'); @@ -950,8 +924,8 @@ describe('Abstract Provider With PKCE and Plain Method', () => { Config.remove('settings.social.cookie.domain'); }); - describe('has a "redirect" method that', () => { - describe('should return an HttpResponseRedirect object', () => { + describe('has a "createHttpResponseWithConsentPageUrl" method that', () => { + describe('should return an HttpResponse object', () => { beforeEach(() => { Config.set('settings.social.secret.codeVerifierSecret', 'SECRET'); @@ -961,15 +935,15 @@ describe('Abstract Provider With PKCE and Plain Method', () => { Config.remove('settings.social.secret.codeVerifierSecret'); }); - it('with a redirect path which contains a client ID, a response type, a redirect URI, code_challenge and code_challenge_method (plain) if pkce enabled.', async () => { - const response = await provider.redirect(); - ok(response.path.startsWith( + it('with a consentPageUrl which contains a client ID, a response type, a redirect URI, code_challenge and code_challenge_method (plain) if pkce enabled.', async () => { + const response = await provider.createHttpResponseWithConsentPageUrl(); + ok(response.body.consentPageUrl.startsWith( 'https://example2.com/auth?' + 'response_type=code&' + 'client_id=clientIdXXX&' + 'redirect_uri=https%3A%2F%2Fexample.com%2Fcallback' )); - const searchParams = new URLSearchParams(response.path); + const searchParams = new URLSearchParams(response.body.consentPageUrl); ok(searchParams.get('code_challenge')); strictEqual(searchParams.get('code_challenge_method'), 'plain'); }); diff --git a/packages/social/src/abstract-provider.service.ts b/packages/social/src/abstract-provider.service.ts index 55008dcf6d..af2bbaee13 100644 --- a/packages/social/src/abstract-provider.service.ts +++ b/packages/social/src/abstract-provider.service.ts @@ -308,21 +308,6 @@ export abstract class AbstractProvider} The HttpResponseRedirect object. - * @memberof AbstractProvider - * @deprecated - */ - async redirect({ scopes }: { scopes?: string[] } = {}, params?: AuthParameters): Promise { - return this.createHttpResponseWithConsentPageUrl({ scopes, isRedirection: true }, params) as Promise; - } - /** * Function to use in the controller method that handles the provider redirection. * From 62ebbd4f621fddf514a3638ec40976a687780dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Sat, 24 Aug 2024 20:03:47 +0200 Subject: [PATCH 24/27] Upgrade TypeORM peer dependency to v0.3.20 --- docs/blog/version-5.0-release-notes.md | 4 + docs/docs/authentication/session-tokens.md | 2 +- docs/docs/databases/typeorm/introduction.md | 2 +- package-lock.json | 90 ++++++------------- packages/acceptance-tests/package.json | 2 +- .../cli/src/generate/specs/app/package.json | 2 +- .../generate/specs/app/package.mongodb.json | 2 +- .../specs/app/package.mongodb.yaml.json | 2 +- .../src/generate/specs/app/package.yaml.json | 2 +- .../src/generate/templates/app/package.json | 2 +- .../templates/app/package.mongodb.json | 2 +- packages/examples/package.json | 2 +- packages/typeorm/package.json | 4 +- 13 files changed, 42 insertions(+), 76 deletions(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 66e681e80b..fc2f1cbc8c 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -30,6 +30,10 @@ Version 5.0 of [Foal](https://foalts.org/) is out! > } > ``` +## TypeORM upgrade + +- The minimum required version of TypeORM is v0.3.20. + ## Better typing - The default type of `Context.state` is now `{}`. This way, you'll get a compilation error if you forget to specify a type for the state. diff --git a/docs/docs/authentication/session-tokens.md b/docs/docs/authentication/session-tokens.md index 5d4a588e1a..2f8d0d9e62 100644 --- a/docs/docs/authentication/session-tokens.md +++ b/docs/docs/authentication/session-tokens.md @@ -71,7 +71,7 @@ module.exports = { #### TypeORMStore ``` -npm install typeorm@0.3.17 @foal/typeorm +npm install typeorm@0.3.20 @foal/typeorm ``` This store uses the default TypeORM connection whose configuration is usually specified in `config/default.{json|yml|js}`. diff --git a/docs/docs/databases/typeorm/introduction.md b/docs/docs/databases/typeorm/introduction.md index d2b60c4bb9..772c6be971 100644 --- a/docs/docs/databases/typeorm/introduction.md +++ b/docs/docs/databases/typeorm/introduction.md @@ -59,7 +59,7 @@ When creating a new project, an `SQLite` database is used by default as it does ### Packages ``` -npm install typeorm@0.3.17 @foal/typeorm +npm install typeorm@0.3.20 @foal/typeorm ``` Two packages are required to use TypeORM with FoalTS: diff --git a/package-lock.json b/package-lock.json index ce3b7645f4..ab6a115ab8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1001,6 +1001,7 @@ "version": "7.24.4", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -6144,6 +6145,7 @@ "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -6164,6 +6166,12 @@ "node": "*" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -7512,7 +7520,6 @@ "version": "10.3.12", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", @@ -7546,7 +7553,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -7555,7 +7561,6 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -8593,7 +8598,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -11137,7 +11141,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -11153,7 +11156,6 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "dev": true, "engines": { "node": "14 || >=16.14" } @@ -12096,7 +12098,8 @@ "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true }, "node_modules/replace-ext": { "version": "0.0.1", @@ -14238,21 +14241,22 @@ "dev": true }, "node_modules/typeorm": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.17.tgz", - "integrity": "sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.20.tgz", + "integrity": "sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==", + "license": "MIT", "dependencies": { "@sqltools/formatter": "^1.2.5", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "chalk": "^4.1.2", "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", + "dayjs": "^1.11.9", "debug": "^4.3.4", "dotenv": "^16.0.3", - "glob": "^8.1.0", + "glob": "^10.3.10", "mkdirp": "^2.1.3", - "reflect-metadata": "^0.1.13", + "reflect-metadata": "^0.2.1", "sha.js": "^2.4.11", "tslib": "^2.5.0", "uuid": "^9.0.0", @@ -14264,7 +14268,7 @@ "typeorm-ts-node-esm": "cli-ts-node-esm.js" }, "engines": { - "node": ">= 12.9.0" + "node": ">=16.13.0" }, "funding": { "url": "https://opencollective.com/typeorm" @@ -14272,13 +14276,13 @@ "peerDependencies": { "@google-cloud/spanner": "^5.18.0", "@sap/hana-client": "^2.12.25", - "better-sqlite3": "^7.1.2 || ^8.0.0", + "better-sqlite3": "^7.1.2 || ^8.0.0 || ^9.0.0", "hdb-pool": "^0.1.6", "ioredis": "^5.0.4", - "mongodb": "^5.2.0", - "mssql": "^9.1.1", + "mongodb": "^5.8.0", + "mssql": "^9.1.1 || ^10.0.1", "mysql2": "^2.2.5 || ^3.0.1", - "oracledb": "^5.1.0", + "oracledb": "^6.3.0", "pg": "^8.5.1", "pg-native": "^3.0.0", "pg-query-stream": "^4.0.0", @@ -14342,14 +14346,6 @@ } } }, - "node_modules/typeorm/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/typeorm/node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -14388,35 +14384,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/typeorm/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typeorm/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/typeorm/node_modules/mkdirp": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", @@ -14431,11 +14398,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/typeorm/node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, "node_modules/typeorm/node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -15210,7 +15172,7 @@ "sqlite3": "~5.1.7", "superagent": "~9.0.1", "supertest": "~7.0.0", - "typeorm": "0.3.17", + "typeorm": "0.3.20", "yamljs": "~0.3.0" }, "devDependencies": { @@ -15391,7 +15353,7 @@ "graphql": "~16.9.0", "source-map-support": "~0.5.21", "sqlite3": "~5.1.7", - "typeorm": "0.3.17", + "typeorm": "0.3.20", "yamljs": "~0.3.0" }, "devDependencies": { @@ -16100,7 +16062,7 @@ "rimraf": "~5.0.5", "sqlite3": "~5.1.7", "ts-node": "~10.9.2", - "typeorm": "0.3.17", + "typeorm": "0.3.20", "typescript": "~5.5.4" }, "engines": { @@ -16110,7 +16072,7 @@ "url": "https://github.com/sponsors/LoicPoullain" }, "peerDependencies": { - "typeorm": "^0.3.17" + "typeorm": "^0.3.20" } }, "packages/typeorm/node_modules/rimraf": { diff --git a/packages/acceptance-tests/package.json b/packages/acceptance-tests/package.json index 2acf225e84..b10c6ed164 100644 --- a/packages/acceptance-tests/package.json +++ b/packages/acceptance-tests/package.json @@ -43,7 +43,7 @@ "sqlite3": "~5.1.7", "superagent": "~9.0.1", "supertest": "~7.0.0", - "typeorm": "0.3.17", + "typeorm": "0.3.20", "yamljs": "~0.3.0" }, "devDependencies": { diff --git a/packages/cli/src/generate/specs/app/package.json b/packages/cli/src/generate/specs/app/package.json index b47f06681e..2b63fb4be1 100644 --- a/packages/cli/src/generate/specs/app/package.json +++ b/packages/cli/src/generate/specs/app/package.json @@ -28,7 +28,7 @@ "@foal/typeorm": "^4.0.0", "source-map-support": "~0.5.21", "sqlite3": "~5.1.7", - "typeorm": "0.3.17" + "typeorm": "0.3.20" }, "devDependencies": { "@foal/cli": "^4.0.0", diff --git a/packages/cli/src/generate/specs/app/package.mongodb.json b/packages/cli/src/generate/specs/app/package.mongodb.json index a4b4a5312e..fbafc13a27 100644 --- a/packages/cli/src/generate/specs/app/package.mongodb.json +++ b/packages/cli/src/generate/specs/app/package.mongodb.json @@ -24,7 +24,7 @@ "@foal/core": "^4.0.0", "mongodb": "~5.9.2", "source-map-support": "~0.5.21", - "typeorm": "0.3.17" + "typeorm": "0.3.20" }, "devDependencies": { "@foal/cli": "^4.0.0", diff --git a/packages/cli/src/generate/specs/app/package.mongodb.yaml.json b/packages/cli/src/generate/specs/app/package.mongodb.yaml.json index 8874672d67..5a6840e23f 100644 --- a/packages/cli/src/generate/specs/app/package.mongodb.yaml.json +++ b/packages/cli/src/generate/specs/app/package.mongodb.yaml.json @@ -24,7 +24,7 @@ "@foal/core": "^4.0.0", "mongodb": "~5.9.2", "source-map-support": "~0.5.21", - "typeorm": "0.3.17", + "typeorm": "0.3.20", "yamljs": "~0.3.0" }, "devDependencies": { diff --git a/packages/cli/src/generate/specs/app/package.yaml.json b/packages/cli/src/generate/specs/app/package.yaml.json index 7e36eef02f..e0e2ab0216 100644 --- a/packages/cli/src/generate/specs/app/package.yaml.json +++ b/packages/cli/src/generate/specs/app/package.yaml.json @@ -28,7 +28,7 @@ "@foal/typeorm": "^4.0.0", "source-map-support": "~0.5.21", "sqlite3": "~5.1.7", - "typeorm": "0.3.17", + "typeorm": "0.3.20", "yamljs": "~0.3.0" }, "devDependencies": { diff --git a/packages/cli/src/generate/templates/app/package.json b/packages/cli/src/generate/templates/app/package.json index a18a0b4ede..483d672df9 100644 --- a/packages/cli/src/generate/templates/app/package.json +++ b/packages/cli/src/generate/templates/app/package.json @@ -28,7 +28,7 @@ "@foal/typeorm": "^4.0.0", "source-map-support": "~0.5.21", "sqlite3": "~5.1.7", - "typeorm": "0.3.17" + "typeorm": "0.3.20" }, "devDependencies": { "@foal/cli": "^4.0.0", diff --git a/packages/cli/src/generate/templates/app/package.mongodb.json b/packages/cli/src/generate/templates/app/package.mongodb.json index 7a8aaf182e..74cebcdac6 100644 --- a/packages/cli/src/generate/templates/app/package.mongodb.json +++ b/packages/cli/src/generate/templates/app/package.mongodb.json @@ -24,7 +24,7 @@ "@foal/core": "^4.0.0", "mongodb": "~5.9.2", "source-map-support": "~0.5.21", - "typeorm": "0.3.17" + "typeorm": "0.3.20" }, "devDependencies": { "@foal/cli": "^4.0.0", diff --git a/packages/examples/package.json b/packages/examples/package.json index 5e76d2bc3c..f5978764bb 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -55,7 +55,7 @@ "graphql": "~16.9.0", "source-map-support": "~0.5.21", "sqlite3": "~5.1.7", - "typeorm": "0.3.17", + "typeorm": "0.3.20", "yamljs": "~0.3.0" }, "devDependencies": { diff --git a/packages/typeorm/package.json b/packages/typeorm/package.json index f5bfec65f3..5a6febdcd1 100644 --- a/packages/typeorm/package.json +++ b/packages/typeorm/package.json @@ -50,7 +50,7 @@ "@foal/core": "^4.5.0" }, "peerDependencies": { - "typeorm": "^0.3.17" + "typeorm": "^0.3.20" }, "devDependencies": { "@types/mocha": "10.0.7", @@ -61,7 +61,7 @@ "rimraf": "~5.0.5", "sqlite3": "~5.1.7", "ts-node": "~10.9.2", - "typeorm": "0.3.17", + "typeorm": "0.3.20", "typescript": "~5.5.4" } } From d76a1f24e5437c3d483d73b1498c6d6da320d631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Mon, 26 Aug 2024 14:29:11 +0200 Subject: [PATCH 25/27] Provide a ServiceManager to shell scripts --- docs/docs/authentication/session-tokens.md | 12 +++---- docs/docs/cli/shell-scripts.md | 6 ++-- package-lock.json | 1 + .../revoking-sessions.feature.ts | 20 ++++++------ packages/cli/package.json | 1 + .../src/generate/specs/script/test-foo-bar.ts | 4 ++- .../src/generate/templates/script/script.ts | 4 ++- packages/cli/src/run/run-script.spec.ts | 32 +++++++++++++++++++ packages/cli/src/run/run-script.ts | 13 ++++++-- packages/examples/src/scripts/revoke-token.ts | 6 ++-- 10 files changed, 73 insertions(+), 26 deletions(-) diff --git a/docs/docs/authentication/session-tokens.md b/docs/docs/authentication/session-tokens.md index 2f8d0d9e62..904dcdded8 100644 --- a/docs/docs/authentication/session-tokens.md +++ b/docs/docs/authentication/session-tokens.md @@ -641,7 +641,7 @@ npx foal g script revoke-session Open `scripts/revoke-session.ts` and update its content. ```typescript -import { createService, readSession, Store } from '@foal/core'; +import { readSession, ServiceManager, Store } from '@foal/core'; import { dataSource } from '../db'; @@ -653,10 +653,10 @@ export const schema = { required: [ 'token' ] } -export async function main({ token }: { token: string }) { +export async function main({ token }: { token: string }, services: ServiceManager) { await dataSource.initialize(); - const store = createService(Store); + const store = services.get(Store); await store.boot(); const session = await readSession(store, token); @@ -687,14 +687,14 @@ npx foal g script revoke-all-sessions Open `scripts/revoke-all-sessions.ts` and update its content. ```typescript -import { createService, Store } from '@foal/core'; +import { ServiceManager, Store } from '@foal/core'; import { dataSource } from '../db'; -export async function main() { +export async function main(args: any, services: ServiceManager) { await dataSource.initialize(); - const store = createService(Store); + const store = services.get(Store); await store.boot(); await store.clear(); } diff --git a/docs/docs/cli/shell-scripts.md b/docs/docs/cli/shell-scripts.md index e139eef109..2ea9904374 100644 --- a/docs/docs/cli/shell-scripts.md +++ b/docs/docs/cli/shell-scripts.md @@ -17,19 +17,19 @@ Remove the content of `src/scripts/display-users.ts` and replace it with the cod ```typescript // 3p -import { createService } from '@foal/core'; +import { ServiceManager } from '@foal/core'; // App import { dataSource } from '../db'; import { User } from '../app/entities'; import { Logger } from '../app/services'; -export async function main() { +export async function main(args: any, services: ServiceManager) { await dataSource.initialize(); try { const users = await User.find(); - const logger = createService(Logger); + const logger = services.get(Logger); logger.log(users); } finally { dataSource.destroy(); diff --git a/package-lock.json b/package-lock.json index ab6a115ab8..6ed03b284d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15251,6 +15251,7 @@ "foal": "lib/index.js" }, "devDependencies": { + "@foal/core": "^4.5.0", "@types/mocha": "10.0.7", "@types/node": "20.14.8", "copyfiles": "~2.4.1", diff --git a/packages/acceptance-tests/src/docs/authentication/session-tokens/revoking-sessions.feature.ts b/packages/acceptance-tests/src/docs/authentication/session-tokens/revoking-sessions.feature.ts index a6a8639dac..a15d08ad2a 100644 --- a/packages/acceptance-tests/src/docs/authentication/session-tokens/revoking-sessions.feature.ts +++ b/packages/acceptance-tests/src/docs/authentication/session-tokens/revoking-sessions.feature.ts @@ -5,7 +5,7 @@ import { notStrictEqual, strictEqual } from 'assert'; import { DataSource } from 'typeorm'; // FoalTS -import { Config, createService, createSession, readSession, Store } from '@foal/core'; +import { Config, createSession, readSession, ServiceManager, Store } from '@foal/core'; import { DatabaseSession } from '@foal/typeorm'; import { createAndInitializeDataSource, getTypeORMStorePath } from '../../../common'; @@ -28,10 +28,10 @@ describe('Feature: Revoking sessions', () => { /* ======================= DOCUMENTATION BEGIN ======================= */ - async function main({ token }: { token: string }) { + async function main({ token }: { token: string }, services: ServiceManager) { // await dataSource.initialize(); - const store = createService(Store); + const store = services.get(Store); await store.boot(); const session = await readSession(store, token); @@ -42,7 +42,8 @@ describe('Feature: Revoking sessions', () => { /* ======================= DOCUMENTATION END ========================= */ - const store = createService(Store); + const services = new ServiceManager(); + const store = services.get(Store); dataSource = await createAndInitializeDataSource([ DatabaseSession ]); @@ -51,7 +52,7 @@ describe('Feature: Revoking sessions', () => { notStrictEqual(await readSession(store, session.getToken()), null); - await main({ token: session.getToken() }); + await main({ token: session.getToken() }, services); strictEqual(await readSession(store, session.getToken()), null); @@ -61,17 +62,18 @@ describe('Feature: Revoking sessions', () => { /* ======================= DOCUMENTATION BEGIN ======================= */ - async function main() { + async function main(args: any, services: ServiceManager) { // await dataSource.initialize(); - const store = createService(Store); + const store = services.get(Store); await store.boot(); await store.clear(); } /* ======================= DOCUMENTATION END ========================= */ - const store = createService(Store); + const services = new ServiceManager(); + const store = services.get(Store); dataSource = await createAndInitializeDataSource([ DatabaseSession ]); @@ -83,7 +85,7 @@ describe('Feature: Revoking sessions', () => { notStrictEqual(await readSession(store, session.getToken()), null); notStrictEqual(await readSession(store, session2.getToken()), null); - await main(); + await main(undefined, services); strictEqual(await readSession(store, session.getToken()), null); strictEqual(await readSession(store, session2.getToken()), null); diff --git a/packages/cli/package.json b/packages/cli/package.json index 99a844e33e..d0adc3f67c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -64,6 +64,7 @@ "commander": "~12.1.0" }, "devDependencies": { + "@foal/core": "^4.5.0", "@types/mocha": "10.0.7", "@types/node": "20.14.8", "copyfiles": "~2.4.1", diff --git a/packages/cli/src/generate/specs/script/test-foo-bar.ts b/packages/cli/src/generate/specs/script/test-foo-bar.ts index f9e39a2362..eb9c6fd568 100644 --- a/packages/cli/src/generate/specs/script/test-foo-bar.ts +++ b/packages/cli/src/generate/specs/script/test-foo-bar.ts @@ -1,3 +1,5 @@ +import { ServiceManager } from '@foal/core'; + export const schema = { additionalProperties: false, properties: { @@ -9,6 +11,6 @@ export const schema = { type: 'object', }; -export async function main(args: any) { +export async function main(args: any, services: ServiceManager) { } diff --git a/packages/cli/src/generate/templates/script/script.ts b/packages/cli/src/generate/templates/script/script.ts index f9e39a2362..eb9c6fd568 100644 --- a/packages/cli/src/generate/templates/script/script.ts +++ b/packages/cli/src/generate/templates/script/script.ts @@ -1,3 +1,5 @@ +import { ServiceManager } from '@foal/core'; + export const schema = { additionalProperties: false, properties: { @@ -9,6 +11,6 @@ export const schema = { type: 'object', }; -export async function main(args: any) { +export async function main(args: any, services: ServiceManager) { } diff --git a/packages/cli/src/run/run-script.spec.ts b/packages/cli/src/run/run-script.spec.ts index a135e0574f..48f059d225 100644 --- a/packages/cli/src/run/run-script.spec.ts +++ b/packages/cli/src/run/run-script.spec.ts @@ -162,6 +162,38 @@ describe('runScript', () => { }); }); + it('should call the "main" function of build/scripts/my-script.js with a ServiceManager.', async () => { + mkdirIfDoesNotExist('build/scripts'); + const scriptContent = `const { writeFileSync } = require('fs'); + const { ServiceManager } = require('@foal/core'); + module.exports.main = function main(args, services) { + const isServiceManager = services instanceof ServiceManager; + writeFileSync('my-script-temp', JSON.stringify({ + isServiceManager + }), 'utf8'); + }`; + writeFileSync('build/scripts/my-script.js', scriptContent, 'utf8'); + + delete require.cache[join(process.cwd(), `./build/scripts/my-script.js`)]; + + await runScript({ name: 'my-script' }, [ + '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node', + '/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal', + 'run', + 'my-script', + 'foo=bar', + ]); + + if (!existsSync('my-script-temp')) { + throw new Error('The script was not executed'); + } + const actual = JSON.parse(readFileSync('my-script-temp', 'utf8')); + + deepStrictEqual(actual, { + isServiceManager: true, + }); + }); + it('should catch and log errors thrown in the "main" function.', async () => { mkdirIfDoesNotExist('build/scripts'); const scriptContent = `const { writeFileSync } = require('fs'); diff --git a/packages/cli/src/run/run-script.ts b/packages/cli/src/run/run-script.ts index 61eefef6a5..f78a847b81 100644 --- a/packages/cli/src/run/run-script.ts +++ b/packages/cli/src/run/run-script.ts @@ -1,6 +1,5 @@ // std import { existsSync } from 'fs'; -import { join } from 'path'; // 3p import Ajv from 'ajv'; @@ -10,6 +9,12 @@ import addFormats from 'ajv-formats'; import { getCommandLineArguments } from './get-command-line-arguments.util'; export async function runScript({ name }: { name: string }, argv: string[], log = console.log) { + const { ServiceManager } = require(require.resolve('@foal/core', { + paths: [ process.cwd() ], + })) as typeof import('@foal/core'); + + const services = new ServiceManager(); + if (!existsSync(`build/scripts/${name}.js`)) { if (existsSync(`src/scripts/${name}.ts`)) { log( @@ -22,7 +27,9 @@ export async function runScript({ name }: { name: string }, argv: string[], log return; } - const { main, schema } = require(join(process.cwd(), `./build/scripts/${name}`)); + const { main, schema } = require(require.resolve(`./build/scripts/${name}`, { + paths: [ process.cwd() ], + })); if (!main) { log(`Error: No "main" function was found in build/scripts/${name}.js.`); @@ -47,7 +54,7 @@ export async function runScript({ name }: { name: string }, argv: string[], log } try { - await main(args); + await main(args, services); } catch (error: any) { log(error); } diff --git a/packages/examples/src/scripts/revoke-token.ts b/packages/examples/src/scripts/revoke-token.ts index b51b1715b5..527e3b6175 100644 --- a/packages/examples/src/scripts/revoke-token.ts +++ b/packages/examples/src/scripts/revoke-token.ts @@ -1,5 +1,5 @@ // 3p -import { createService } from '@foal/core'; +import { ServiceManager } from '@foal/core'; import { TypeORMStore } from '@foal/typeorm'; // App @@ -14,8 +14,8 @@ export const schema = { type: 'object', }; -export async function main({ token }: { token: string }) { +export async function main({ token }: { token: string }, services: ServiceManager) { await dataSource.initialize(); - await createService(TypeORMStore).destroy(token); + await services.get(TypeORMStore).destroy(token); } From 7692b0a8e640ec1ff47146041fdef0180fd30530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Mon, 26 Aug 2024 16:52:41 +0200 Subject: [PATCH 26/27] [Blog] Provide a ServiceManager to shell scripts --- docs/blog/version-5.0-release-notes.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index fc2f1cbc8c..50ff8fe179 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -74,6 +74,16 @@ Version 5.0 of [Foal](https://foalts.org/) is out! - The `Logger.addLogContext(key, value)` method now accepts a record as parameter: `Logger.addLogContext(context)`. This makes the function's signature more consistent with other logging methods (`info`, `warn`, etc.) and allows multiple keys/values to be passed at once. - The deprecated `settings.loggerFormat` configuration has been removed. If you want to disable HTTP logging, set `settings.logger.logHttpRequests` to false instead. +## Shell scripts + +- The `main` function of shell scripts now receives an instance of `ServiceManager` as second argument: + ```typescript + export async function main(args: any, services: ServiceManager) { + // ... + } + ``` + + ## Removal of deprecated components - The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead. From ea4fa00181906cc44d48ac49e39cf0d732655988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Mon, 2 Sep 2024 14:35:57 +0200 Subject: [PATCH 27/27] [Website] Use global authors --- docs/blog/version-5.0-release-notes.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 50ff8fe179..27c0138f18 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -1,9 +1,6 @@ --- title: Version 5.0 release notes -author: Loïc Poullain -author_title: Creator of FoalTS. Software engineer. -author_url: https://loicpoullain.com -author_image_url: https://avatars1.githubusercontent.com/u/13604533?v=4 +authors: LoicPoullain image: blog/twitter-banners/version-5.0-release-notes.png tags: [release] ---