diff --git a/apps/backend/assets/ejs-templates/mail/account-created.ejs b/apps/backend/assets/ejs-templates/mail/account-created.ejs index 86f3550..7c67c4f 100644 --- a/apps/backend/assets/ejs-templates/mail/account-created.ejs +++ b/apps/backend/assets/ejs-templates/mail/account-created.ejs @@ -81,7 +81,7 @@

{ + async addNewResetToken( + userId: string, + ): Promise<{ token: string; user_id: string }> { return this.authRegistry.addResetToken({ token: generateSecureToken(), userId, diff --git a/apps/backend/src/app/auth/auth-registry.spec.ts b/apps/backend/src/app/auth/auth-core/auth-registry.spec.ts similarity index 100% rename from apps/backend/src/app/auth/auth-registry.spec.ts rename to apps/backend/src/app/auth/auth-core/auth-registry.spec.ts diff --git a/apps/backend/src/app/auth/auth-registry.ts b/apps/backend/src/app/auth/auth-core/auth-registry.ts similarity index 67% rename from apps/backend/src/app/auth/auth-registry.ts rename to apps/backend/src/app/auth/auth-core/auth-registry.ts index 60375b0..cfc45ba 100644 --- a/apps/backend/src/app/auth/auth-registry.ts +++ b/apps/backend/src/app/auth/auth-core/auth-registry.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { DatabaseService } from '../../services/core/database/database.service'; +import { DatabaseService } from '../../../services/core/database/database.service'; import * as dayjs from 'dayjs'; export interface CreateResetToken { @@ -15,7 +15,9 @@ export class AuthRegistry { } constructor(private databaseService: DatabaseService) {} - async addResetToken(resetAuth: CreateResetToken): Promise { + async addResetToken( + resetAuth: CreateResetToken, + ): Promise<{ token: string; user_id: string }> { return this.database .insertInto('reset_tokens') .values({ @@ -23,7 +25,7 @@ export class AuthRegistry { token: resetAuth.token, valid_until: resetAuth.validUntil.toDate(), }) - .execute() - .then(() => {}); + .returning(['user_id', 'token']) + .executeTakeFirstOrThrow(); } } diff --git a/apps/backend/src/app/auth/auth-controller.service.spec.ts b/apps/backend/src/app/auth/auth-feature/auth-controller.service.spec.ts similarity index 100% rename from apps/backend/src/app/auth/auth-controller.service.spec.ts rename to apps/backend/src/app/auth/auth-feature/auth-controller.service.spec.ts diff --git a/apps/backend/src/app/auth/auth-controller.service.ts b/apps/backend/src/app/auth/auth-feature/auth-controller.service.ts similarity index 83% rename from apps/backend/src/app/auth/auth-controller.service.ts rename to apps/backend/src/app/auth/auth-feature/auth-controller.service.ts index e002a0a..eabc3b7 100644 --- a/apps/backend/src/app/auth/auth-controller.service.ts +++ b/apps/backend/src/app/auth/auth-feature/auth-controller.service.ts @@ -1,5 +1,5 @@ import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { UsersCoreService } from '../users/users-core.service'; +import { UsersCoreService } from '../../users/users-core/users-core.service'; @Injectable() export class AuthControllerService { diff --git a/apps/backend/src/app/auth/auth.controller.spec.ts b/apps/backend/src/app/auth/auth-feature/auth.controller.spec.ts similarity index 100% rename from apps/backend/src/app/auth/auth.controller.spec.ts rename to apps/backend/src/app/auth/auth-feature/auth.controller.spec.ts diff --git a/apps/backend/src/app/auth/auth.controller.ts b/apps/backend/src/app/auth/auth-feature/auth.controller.ts similarity index 87% rename from apps/backend/src/app/auth/auth.controller.ts rename to apps/backend/src/app/auth/auth-feature/auth.controller.ts index e65aec8..d05c42c 100644 --- a/apps/backend/src/app/auth/auth.controller.ts +++ b/apps/backend/src/app/auth/auth-feature/auth.controller.ts @@ -5,7 +5,7 @@ import { Post, } from '@nestjs/common'; import { AuthControllerService } from './auth-controller.service'; -import { ZodValidationPipe } from '../../lib/nestjs/zod-validation/zod-validation.pipe'; +import { ZodValidationPipe } from '../../../lib/nestjs/zod-validation/zod-validation.pipe'; import { ResetAuth, resetAuthParser } from '@my-monorepo/common'; @Controller('auth') diff --git a/apps/backend/src/app/auth/auth-feature/auth.module.ts b/apps/backend/src/app/auth/auth-feature/auth.module.ts new file mode 100644 index 0000000..e73ec13 --- /dev/null +++ b/apps/backend/src/app/auth/auth-feature/auth.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { UsersCoreModule } from '../../users/users-core/users-core.module'; +import { AuthControllerService } from './auth-controller.service'; +import { AuthController } from './auth.controller'; +import { AuthCoreModule } from '../auth-core/auth-core.module'; + +@Module({ + imports: [UsersCoreModule, AuthCoreModule], + controllers: [AuthController], + providers: [AuthControllerService], +}) +export class AuthFeatureModule {} diff --git a/apps/backend/src/app/auth/auth.module.ts b/apps/backend/src/app/auth/auth.module.ts deleted file mode 100644 index e5668b0..0000000 --- a/apps/backend/src/app/auth/auth.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Module } from '@nestjs/common'; -import { AuthController } from './auth.controller'; -import { AuthRegistry } from './auth-registry'; -import { AuthControllerService } from './auth-controller.service'; -import { AuthCoreService } from './auth-core.service'; -import { UsersModule } from '../users/users.module'; - -@Module({ - controllers: [AuthController], - providers: [AuthRegistry, AuthControllerService, AuthCoreService], - imports: [UsersModule], - exports: [AuthCoreService, AuthRegistry], -}) -export class AuthModule {} diff --git a/apps/backend/src/app/users/users-controller.service.spec.ts b/apps/backend/src/app/users/user-feature/users-controller.service.spec.ts similarity index 100% rename from apps/backend/src/app/users/users-controller.service.spec.ts rename to apps/backend/src/app/users/user-feature/users-controller.service.spec.ts diff --git a/apps/backend/src/app/users/users-controller.service.ts b/apps/backend/src/app/users/user-feature/users-controller.service.ts similarity index 55% rename from apps/backend/src/app/users/users-controller.service.ts rename to apps/backend/src/app/users/user-feature/users-controller.service.ts index 927c471..cb89738 100644 --- a/apps/backend/src/app/users/users-controller.service.ts +++ b/apps/backend/src/app/users/user-feature/users-controller.service.ts @@ -3,12 +3,13 @@ import { Inject, Injectable } from '@nestjs/common'; import { LOCALIZATION_SERVICE, LocalizationService, -} from '../../services/core/localization/localization.service'; -import { MailerService } from '../../services/core/mailer/mailer.service'; -import { MailTemplateEnum } from '../../services/core/template-renderer/mail-template-data'; -import { TemplateRendererService } from '../../services/core/template-renderer/template-renderer.service'; -import { AuthCoreService } from '../auth/auth-core.service'; -import { UsersCoreService } from './users-core.service'; +} from '../../../services/core/localization/localization.service'; +import { MailerService } from '../../../services/core/mailer/mailer.service'; +import { MailTemplateEnum } from '../../../services/core/template-renderer/mail-template-data'; +import { TemplateRendererService } from '../../../services/core/template-renderer/template-renderer.service'; +import { AuthCoreService } from '../../auth/auth-core/auth-core.service'; +import { UsersCoreService } from '../users-core/users-core.service'; +import { LinkBuilderService } from '../../../services/core/link-builder/link-builder.service'; @Injectable() export class UsersControllerService { @@ -19,16 +20,25 @@ export class UsersControllerService { private localizationService: LocalizationService, private templateRendererService: TemplateRendererService, private authCoreService: AuthCoreService, + private linkBuilderService: LinkBuilderService, ) {} async createUser(newUser: CreateUser): Promise { // FIXME : return result once auth is done const createUserResult = await this.userCoreService.addUser(newUser); - if (createUserResult.ok) { - const createdUser = createUserResult.data; - await this.authCoreService.addNewResetToken(createdUser.id); + if (!createUserResult.ok) { + return; } + const createdUser = createUserResult.data; + const resetToken = await this.authCoreService.addNewResetToken( + createdUser.id, + ); + const resetLink = this.linkBuilderService.buildLinkToFrontend(['reset'], { + userId: resetToken.user_id, + token: resetToken.token, + }); + // build mail const mailTitle = this.localizationService.translate( 'mail.create-user.title', ); @@ -41,6 +51,7 @@ export class UsersControllerService { { title: mailTitle, bodyTitle: mailBodyTitle, + resetLink: resetLink, }, ); void this.mailerService.sendEmail({ diff --git a/apps/backend/src/app/users/user-feature/users-feature.module.ts b/apps/backend/src/app/users/user-feature/users-feature.module.ts new file mode 100644 index 0000000..eba3085 --- /dev/null +++ b/apps/backend/src/app/users/user-feature/users-feature.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { UsersControllerService } from './users-controller.service'; +import { UsersController } from './users.controller'; +import { UsersCoreModule } from '../users-core/users-core.module'; +import { AuthCoreModule } from '../../auth/auth-core/auth-core.module'; + +@Module({ + imports: [UsersCoreModule, AuthCoreModule], + providers: [UsersControllerService], + controllers: [UsersController], +}) +export class UsersFeatureModule {} diff --git a/apps/backend/src/app/users/users.controller.spec.ts b/apps/backend/src/app/users/user-feature/users.controller.spec.ts similarity index 100% rename from apps/backend/src/app/users/users.controller.spec.ts rename to apps/backend/src/app/users/user-feature/users.controller.spec.ts diff --git a/apps/backend/src/app/users/users.controller.ts b/apps/backend/src/app/users/user-feature/users.controller.ts similarity index 83% rename from apps/backend/src/app/users/users.controller.ts rename to apps/backend/src/app/users/user-feature/users.controller.ts index a975b83..fdf6e30 100644 --- a/apps/backend/src/app/users/users.controller.ts +++ b/apps/backend/src/app/users/user-feature/users.controller.ts @@ -1,6 +1,6 @@ import { CreateUser, createUserParser } from '@my-monorepo/common'; import { Body, Controller, Post } from '@nestjs/common'; -import { ZodValidationPipe } from '../../lib/nestjs/zod-validation/zod-validation.pipe'; +import { ZodValidationPipe } from '../../../lib/nestjs/zod-validation/zod-validation.pipe'; import { UsersControllerService } from './users-controller.service'; @Controller('users') diff --git a/apps/backend/src/app/users/users-core/users-core.module.ts b/apps/backend/src/app/users/users-core/users-core.module.ts new file mode 100644 index 0000000..7f9a219 --- /dev/null +++ b/apps/backend/src/app/users/users-core/users-core.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { UsersCoreService } from './users-core.service'; +import { UsersRegistry } from './users-registry'; + +const PROVIDERS = [UsersCoreService, UsersRegistry]; +@Module({ + providers: PROVIDERS, + exports: PROVIDERS, +}) +export class UsersCoreModule {} diff --git a/apps/backend/src/app/users/users-core.service.spec.ts b/apps/backend/src/app/users/users-core/users-core.service.spec.ts similarity index 100% rename from apps/backend/src/app/users/users-core.service.spec.ts rename to apps/backend/src/app/users/users-core/users-core.service.spec.ts diff --git a/apps/backend/src/app/users/users-core.service.ts b/apps/backend/src/app/users/users-core/users-core.service.ts similarity index 100% rename from apps/backend/src/app/users/users-core.service.ts rename to apps/backend/src/app/users/users-core/users-core.service.ts diff --git a/apps/backend/src/app/users/users-error.ts b/apps/backend/src/app/users/users-core/users-error.ts similarity index 81% rename from apps/backend/src/app/users/users-error.ts rename to apps/backend/src/app/users/users-core/users-error.ts index b670d77..d00062e 100644 --- a/apps/backend/src/app/users/users-error.ts +++ b/apps/backend/src/app/users/users-core/users-error.ts @@ -1,4 +1,4 @@ -import { AppError } from '../../lib/app-error'; +import { AppError } from '../../../lib/app-error'; import { HttpStatus } from '@nestjs/common'; export class UserEmailAlreadyExistError extends AppError { diff --git a/apps/backend/src/app/users/users-registry.spec.ts b/apps/backend/src/app/users/users-core/users-registry.spec.ts similarity index 100% rename from apps/backend/src/app/users/users-registry.spec.ts rename to apps/backend/src/app/users/users-core/users-registry.spec.ts diff --git a/apps/backend/src/app/users/users-registry.ts b/apps/backend/src/app/users/users-core/users-registry.ts similarity index 95% rename from apps/backend/src/app/users/users-registry.ts rename to apps/backend/src/app/users/users-core/users-registry.ts index 935fb40..a093628 100644 --- a/apps/backend/src/app/users/users-registry.ts +++ b/apps/backend/src/app/users/users-core/users-registry.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { DatabaseService } from '../../services/core/database/database.service'; +import { DatabaseService } from '../../../services/core/database/database.service'; import { CreateUser, isDefined, Result, User } from '@my-monorepo/common'; import { UserEmailAlreadyExistError } from './users-error'; diff --git a/apps/backend/src/app/users/users.module.ts b/apps/backend/src/app/users/users.module.ts deleted file mode 100644 index b57cd41..0000000 --- a/apps/backend/src/app/users/users.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { forwardRef, Module } from '@nestjs/common'; -import { UsersRegistry } from './users-registry'; -import { UsersController } from './users.controller'; -import { UsersControllerService } from './users-controller.service'; -import { UsersCoreService } from './users-core.service'; -import { AuthModule } from '../auth/auth.module'; - -@Module({ - providers: [UsersRegistry, UsersControllerService, UsersCoreService], - controllers: [UsersController], - imports: [forwardRef(() => AuthModule)], - exports: [UsersCoreService, UsersRegistry], -}) -export class UsersModule {} diff --git a/apps/backend/src/services/core/core.module.ts b/apps/backend/src/services/core/core.module.ts index 9a69d31..b7767f1 100644 --- a/apps/backend/src/services/core/core.module.ts +++ b/apps/backend/src/services/core/core.module.ts @@ -5,6 +5,7 @@ import { LOCALIZATION_SERVICE_PROVIDER } from './localization/localization.servi import { LoggerService } from './logger/logger.service'; import { MailerService } from './mailer/mailer.service'; import { TemplateRendererService } from './template-renderer/template-renderer.service'; +import { LinkBuilderService } from './link-builder/link-builder.service'; const DECLARATIONS = [ DatabaseService, @@ -13,6 +14,7 @@ const DECLARATIONS = [ LoggerService, MailerService, TemplateRendererService, + LinkBuilderService, ]; @Global() diff --git a/apps/backend/src/services/core/env/env.service.ts b/apps/backend/src/services/core/env/env.service.ts index 71c51f7..b49a8ad 100644 --- a/apps/backend/src/services/core/env/env.service.ts +++ b/apps/backend/src/services/core/env/env.service.ts @@ -13,6 +13,7 @@ const envParser = z MAIL_PORT: z.coerce.number(), MAIL_USER: z.string().email(), MAIL_PASSWORD: z.string(), + APP_FRONTEND_URL: z.string(), }) .transform((parsed) => ({ database: { @@ -28,6 +29,9 @@ const envParser = z user: parsed.MAIL_USER, password: parsed.MAIL_PASSWORD, }, + app: { + frontendUrl: parsed.APP_FRONTEND_URL, + }, })); export type EnvConfig = Readonly>; diff --git a/apps/backend/src/services/core/link-builder/link-builder.service.spec.ts b/apps/backend/src/services/core/link-builder/link-builder.service.spec.ts new file mode 100644 index 0000000..2528432 --- /dev/null +++ b/apps/backend/src/services/core/link-builder/link-builder.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { LinkBuilderService } from './link-builder.service'; + +describe('LinkBuilderService', () => { + let service: LinkBuilderService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [LinkBuilderService], + }).compile(); + + service = module.get(LinkBuilderService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/apps/backend/src/services/core/link-builder/link-builder.service.ts b/apps/backend/src/services/core/link-builder/link-builder.service.ts new file mode 100644 index 0000000..bc5c376 --- /dev/null +++ b/apps/backend/src/services/core/link-builder/link-builder.service.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@nestjs/common'; +import { EnvService } from '../env/env.service'; + +@Injectable() +export class LinkBuilderService { + constructor(private envService: EnvService) {} + + buildLinkToFrontend( + path: string[], + queryParams: Record = {}, + ) { + const base = this.envService.config.app.frontendUrl; + const segments = path.join('/'); + const queryParamsList = Object.entries(queryParams); + const joinedQueryParam = queryParamsList + .map(([k, v]) => `${k}=${v}`) + .join('&'); + const queryParamsStr = + queryParamsList.length > 0 ? `?${joinedQueryParam}` : ''; + return `${base}/${segments}${queryParamsStr}`; + } +} diff --git a/apps/backend/src/services/core/template-renderer/mail-template-data.ts b/apps/backend/src/services/core/template-renderer/mail-template-data.ts index c946b20..676900c 100644 --- a/apps/backend/src/services/core/template-renderer/mail-template-data.ts +++ b/apps/backend/src/services/core/template-renderer/mail-template-data.ts @@ -19,6 +19,7 @@ const MAIL_TEMPLATE_PATH_MAP = { export interface CreateAccountMailTemplateData { title: string; bodyTitle: string; + resetLink: string; } export function getMailTemplatePath(template: MailTemplateEnum): string { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53c564a..a2fc8c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,6 +28,9 @@ importers: '@types/passport-local': specifier: ^1.0.38 version: 1.0.38 + argon2: + specifier: ^0.44.0 + version: 0.44.0 dayjs: specifier: ^1.11.13 version: 1.11.13 @@ -384,6 +387,9 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@epic-web/invariant@1.0.0': + resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + '@eslint-community/eslint-utils@4.7.0': resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -879,6 +885,10 @@ packages: '@paralleldrive/cuid2@2.2.2': resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} + '@phc/format@1.0.0': + resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} + engines: {node: '>=10'} + '@pkgr/core@0.2.7': resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1371,6 +1381,10 @@ packages: arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + argon2@0.44.0: + resolution: {integrity: sha512-zHPGN3S55sihSQo0dBbK0A5qpi2R31z7HZDZnry3ifOyj8bZZnpZND2gpmhnRGO1V/d555RwBqIK5W4Mrmv3ig==} + engines: {node: '>=16.17.0'} + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -1681,6 +1695,11 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-env@10.0.0: + resolution: {integrity: sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q==} + engines: {node: '>=20'} + hasBin: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2773,9 +2792,17 @@ packages: node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + node-addon-api@8.5.0: + resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} + engines: {node: ^18 || ^20 || >= 21} + node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -4056,6 +4083,8 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@epic-web/invariant@1.0.0': {} + '@eslint-community/eslint-utils@4.7.0(eslint@9.31.0(jiti@1.21.7))': dependencies: eslint: 9.31.0(jiti@1.21.7) @@ -4650,6 +4679,8 @@ snapshots: dependencies: '@noble/hashes': 1.8.0 + '@phc/format@1.0.0': {} + '@pkgr/core@0.2.7': {} '@sec-ant/readable-stream@0.4.1': {} @@ -5228,6 +5259,13 @@ snapshots: arg@4.1.3: {} + argon2@0.44.0: + dependencies: + '@phc/format': 1.0.0 + cross-env: 10.0.0 + node-addon-api: 8.5.0 + node-gyp-build: 4.8.4 + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -5607,6 +5645,11 @@ snapshots: create-require@1.1.1: {} + cross-env@10.0.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -6828,10 +6871,14 @@ snapshots: node-abort-controller@3.1.1: {} + node-addon-api@8.5.0: {} + node-emoji@1.11.0: dependencies: lodash: 4.17.21 + node-gyp-build@4.8.4: {} + node-int64@0.4.0: {} node-releases@2.0.19: {}