diff --git a/apps/bot/package.json b/apps/bot/package.json index 9763490..f4ffe0c 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -5,6 +5,8 @@ "main": "index.js", "license": "MIT", "dependencies": { + "@apollo/client": "^3.12.3", + "jsonwebtoken": "^9.0.2", "telegraf": "catalog:", "zod": "catalog:" }, @@ -12,14 +14,18 @@ "build": "rimraf ./build & tsc -p tsconfig.json", "build:watch": "tsc -w -p tsconfig.json", "start": "node dist/src/index.js", - "dev": "tsx watch src/index.ts", + "dev": "dotenv -e ../../.env.local tsx watch src/index.ts", "lint": "eslint", "lint-staged": "lint-staged" }, "devDependencies": { "@repo/eslint-config": "workspace:*", + "@repo/graphql": "workspace:*", "@repo/lint-staged-config": "workspace:*", "@repo/typescript-config": "workspace:*", + "@types/jsonwebtoken": "^9.0.7", + "@types/node": "catalog:", + "dotenv-cli": "catalog:", "lint-staged": "catalog:", "rimraf": "catalog:", "tsx": "catalog:", diff --git a/apps/bot/src/api/query.ts b/apps/bot/src/api/query.ts new file mode 100644 index 0000000..9ca47ed --- /dev/null +++ b/apps/bot/src/api/query.ts @@ -0,0 +1,13 @@ +import { createApolloClient } from '../apollo/client'; +import { getToken } from '../utils/jwt'; +import * as GQL from '@repo/graphql/types'; + +export async function createCustomer(variables: GQL.CreateCustomerMutationVariables) { + const token = await getToken(); + const { mutate } = createApolloClient({ token }); + + return mutate({ + mutation: GQL.CreateCustomerDocument, + variables, + }); +} diff --git a/apps/bot/src/apollo/client.ts b/apps/bot/src/apollo/client.ts new file mode 100644 index 0000000..0de2834 --- /dev/null +++ b/apps/bot/src/apollo/client.ts @@ -0,0 +1,16 @@ +import { env as environment } from '../config/env'; +import { ApolloClient, InMemoryCache } from '@apollo/client/core'; + +type Parameters_ = { token: null | string | undefined }; + +export function createApolloClient(parameters?: Parameters_) { + return new ApolloClient({ + cache: new InMemoryCache(), + headers: parameters?.token + ? { + Authorization: `Bearer ${parameters.token}`, + } + : undefined, + uri: environment.URL_GRAPHQL, + }); +} diff --git a/apps/bot/src/config/env.ts b/apps/bot/src/config/env.ts new file mode 100644 index 0000000..688f1e8 --- /dev/null +++ b/apps/bot/src/config/env.ts @@ -0,0 +1,11 @@ +/* eslint-disable unicorn/prevent-abbreviations */ +import { z } from 'zod'; + +export const envSchema = z.object({ + BOT_TOKEN: z.string(), + LOGIN_GRAPHQL: z.string(), + PASSWORD_GRAPHQL: z.string(), + URL_GRAPHQL: z.string(), +}); + +export const env = envSchema.parse(process.env); diff --git a/apps/bot/src/index.ts b/apps/bot/src/index.ts index 5253e18..04e3c81 100644 --- a/apps/bot/src/index.ts +++ b/apps/bot/src/index.ts @@ -1,6 +1,39 @@ -/* eslint-disable no-console */ -function init() { - console.log('hello'); -} +/* eslint-disable promise/prefer-await-to-then */ +import { createCustomer } from './api/query'; +import { env as environment } from './config/env'; +import { Telegraf } from 'telegraf'; +import { message } from 'telegraf/filters'; -init(); +const bot = new Telegraf(environment.BOT_TOKEN); + +bot.start((context) => { + return context.reply('Добро пожаловать! Пожалуйста, поделитесь своим номером телефона.', { + reply_markup: { + keyboard: [ + [ + { + request_contact: true, + text: 'Отправить номер телефона', + }, + ], + ], + one_time_keyboard: true, + }, + }); +}); + +bot.on(message('contact'), async (context) => { + createCustomer({ + name: context.from.first_name, + phone: context.message.contact.phone_number, + telegramId: context.from.id, + }) + .then((response) => context.reply(JSON.stringify(response))) + .catch((error) => context.reply(JSON.stringify(error))); +}); + +bot.launch(); + +// Enable graceful stop +process.once('SIGINT', () => bot.stop('SIGINT')); +process.once('SIGTERM', () => bot.stop('SIGTERM')); diff --git a/apps/bot/src/utils/jwt.ts b/apps/bot/src/utils/jwt.ts new file mode 100644 index 0000000..f5d784c --- /dev/null +++ b/apps/bot/src/utils/jwt.ts @@ -0,0 +1,48 @@ +import { createApolloClient } from '../apollo/client'; +import { env as environment } from '../config/env'; +import * as GQL from '@repo/graphql/types'; +import * as jwt from 'jsonwebtoken'; + +const token: null | string = null; + +export async function getToken() { + if (!token || isTokenExpired()) { + const response = await login(); + return response?.data?.login.jwt; + } + + return token; +} + +function isTokenExpired(threshold: number = 300) { + if (!token) throw new Error('Token is missing'); + + try { + const decoded = jwt.decode(token); + + if (!decoded || typeof decoded === 'string' || !decoded.exp) { + throw new Error("Invalid token or missing 'exp' field."); + } + + const currentTime = Math.floor(Date.now() / 1_000); + const tokenExpirationTime = decoded.exp; + + return tokenExpirationTime < currentTime + threshold; + } catch { + return true; + } +} + +async function login() { + const { mutate } = createApolloClient(); + + const response = await mutate({ + mutation: GQL.LoginDocument, + variables: { + identifier: environment.LOGIN_GRAPHQL, + password: environment.PASSWORD_GRAPHQL, + }, + }); + + return response; +} diff --git a/apps/bot/tsconfig.json b/apps/bot/tsconfig.json index 87c6fad..bb656f2 100644 --- a/apps/bot/tsconfig.json +++ b/apps/bot/tsconfig.json @@ -5,6 +5,8 @@ "outDir": "dist", "alwaysStrict": true, "strict": true, + "moduleResolution": "bundler", + "module": "ES2020", "paths": { "@/*": ["./*"] } diff --git a/packages/graphql/query.graphql b/packages/graphql/query.graphql index c15b400..f74e637 100644 --- a/packages/graphql/query.graphql +++ b/packages/graphql/query.graphql @@ -1,5 +1,28 @@ -query Test { - customers { - name +mutation Register($identifier: String!, $password: String!, $email: String!) { + register(input: { username: $identifier, password: $password, email: $email }) { + jwt + user { + username + } + } +} + +mutation Login($identifier: String!, $password: String!) { + login(input: { identifier: $identifier, password: $password }) { + jwt + } +} + +mutation CreateCustomer($name: String!, $telegramId: Long!, $phone: String!) { + createCustomer(data: { name: $name, telegramId: $telegramId, phone: $phone, role: client }) { + documentId + name + telegramId + phone + role + active + createdAt + updatedAt + publishedAt } } diff --git a/packages/graphql/types.ts b/packages/graphql/types.ts index ec37076..9608337 100644 --- a/packages/graphql/types.ts +++ b/packages/graphql/types.ts @@ -548,10 +548,33 @@ export type UsersPermissionsUserInput = { username: InputMaybe; }; -export type TestQueryVariables = Exact<{ [key: string]: never; }>; +export type RegisterMutationVariables = Exact<{ + identifier: Scalars['String']['input']; + password: Scalars['String']['input']; + email: Scalars['String']['input']; +}>; -export type TestQuery = { __typename?: 'Query', customers: Array<{ __typename?: 'Customer', name: string } | null> }; +export type RegisterMutation = { __typename?: 'Mutation', register: { __typename?: 'UsersPermissionsLoginPayload', jwt: string | null, user: { __typename?: 'UsersPermissionsMe', username: string } } }; + +export type LoginMutationVariables = Exact<{ + identifier: Scalars['String']['input']; + password: Scalars['String']['input']; +}>; -export const TestDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Test"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"customers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export type LoginMutation = { __typename?: 'Mutation', login: { __typename?: 'UsersPermissionsLoginPayload', jwt: string | null } }; + +export type CreateCustomerMutationVariables = Exact<{ + name: Scalars['String']['input']; + telegramId: Scalars['Long']['input']; + phone: Scalars['String']['input']; +}>; + + +export type CreateCustomerMutation = { __typename?: 'Mutation', createCustomer: { __typename?: 'Customer', documentId: string, name: string, telegramId: any | null, phone: string, role: Enum_Customer_Role, active: boolean | null, createdAt: any | null, updatedAt: any | null, publishedAt: any | null } | null }; + + +export const RegisterDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Register"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"password"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"register"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"username"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identifier"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"password"},"value":{"kind":"Variable","name":{"kind":"Name","value":"password"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"jwt"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]}}]}}]} as unknown as DocumentNode; +export const LoginDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Login"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"password"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"login"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"identifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identifier"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"password"},"value":{"kind":"Variable","name":{"kind":"Name","value":"password"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"jwt"}}]}}]}}]} as unknown as DocumentNode; +export const CreateCustomerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateCustomer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"telegramId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Long"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"phone"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createCustomer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"telegramId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"telegramId"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"phone"},"value":{"kind":"Variable","name":{"kind":"Name","value":"phone"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"role"},"value":{"kind":"EnumValue","value":"client"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"telegramId"}},{"kind":"Field","name":{"kind":"Name","value":"phone"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"active"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"publishedAt"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index adf4c04..0e23d32 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,7 +32,7 @@ catalogs: version: 1.1.2 '@radix-ui/react-slot': specifier: ^1.1.0 - version: 1.1.0 + version: 1.1.1 '@telegram-apps/sdk-react': specifier: ^2.0.19 version: 2.0.19 @@ -63,6 +63,9 @@ catalogs: clsx: specifier: ^2.1.1 version: 2.1.1 + dotenv-cli: + specifier: ^7.4.4 + version: 7.4.4 eruda: specifier: ^3.4.1 version: 3.4.1 @@ -164,6 +167,12 @@ importers: apps/bot: dependencies: + '@apollo/client': + specifier: ^3.12.3 + version: 3.12.3(@types/react@19.0.1)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + jsonwebtoken: + specifier: ^9.0.2 + version: 9.0.2 telegraf: specifier: 'catalog:' version: 4.16.3 @@ -174,12 +183,24 @@ importers: '@repo/eslint-config': specifier: workspace:* version: link:../../packages/eslint-config + '@repo/graphql': + specifier: workspace:* + version: link:../../packages/graphql '@repo/lint-staged-config': specifier: workspace:* version: link:../../packages/lint-staged-config '@repo/typescript-config': specifier: workspace:* version: link:../../packages/typescript-config + '@types/jsonwebtoken': + specifier: ^9.0.7 + version: 9.0.7 + '@types/node': + specifier: 'catalog:' + version: 20.17.8 + dotenv-cli: + specifier: 'catalog:' + version: 7.4.4 lint-staged: specifier: 'catalog:' version: 15.2.10 @@ -338,7 +359,7 @@ importers: devDependencies: '@radix-ui/react-slot': specifier: 'catalog:' - version: 1.1.0(@types/react@19.0.1)(react@19.0.0) + version: 1.1.1(@types/react@19.0.1)(react@19.0.0) '@repo/eslint-config': specifier: workspace:* version: link:../eslint-config @@ -413,6 +434,24 @@ packages: subscriptions-transport-ws: optional: true + '@apollo/client@3.12.3': + resolution: {integrity: sha512-KZ5zymRdb8bMbGUb1wP2U04ff7qIGgaC1BCdCVC+IPFiXkxEhHBc5fDEQOwAUT+vUo9KbBh3g7QK/JCOswn59w==} + peerDependencies: + graphql: ^15.0.0 || ^16.0.0 + graphql-ws: ^5.5.5 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + subscriptions-transport-ws: ^0.9.0 || ^0.11.0 + peerDependenciesMeta: + graphql-ws: + optional: true + react: + optional: true + react-dom: + optional: true + subscriptions-transport-ws: + optional: true + '@ardatan/relay-compiler@12.0.0': resolution: {integrity: sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==} hasBin: true @@ -1938,15 +1977,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-compose-refs@1.1.0': - resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-compose-refs@1.1.1': resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} peerDependencies: @@ -1978,15 +2008,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-slot@1.1.0': - resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-slot@1.1.1': resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==} peerDependencies: @@ -2206,6 +2227,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/jsonwebtoken@9.0.7': + resolution: {integrity: sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==} + '@types/node@20.17.8': resolution: {integrity: sha512-ahz2g6/oqbKalW9sPv6L2iRbhLnojxjYWspAqhjvqSWBgGebEJT5GvRmk0QXPj3sbC6rU0GTQjPLQkmR8CObvA==} @@ -2652,6 +2676,9 @@ packages: buffer-alloc@1.2.0: resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-fill@1.0.0: resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} @@ -2899,9 +2926,6 @@ packages: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} - dataloader@2.2.2: - resolution: {integrity: sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==} - dataloader@2.2.3: resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} @@ -3003,10 +3027,22 @@ packages: dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dotenv-cli@7.4.4: + resolution: {integrity: sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==} + hasBin: true + + dotenv-expand@10.0.0: + resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} + engines: {node: '>=12'} + dotenv@16.0.3: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + dset@3.1.4: resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} engines: {node: '>=4'} @@ -3014,6 +3050,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + electron-to-chromium@1.5.65: resolution: {integrity: sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==} @@ -4107,10 +4146,20 @@ packages: resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} + + jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -4129,10 +4178,6 @@ packages: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} - lilconfig@3.1.2: - resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} - engines: {node: '>=14'} - lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -4172,12 +4217,33 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.lowercase@4.3.0: resolution: {integrity: sha512-UcvP1IZYyDKyEL64mmrwoA1AbFu5ahojhTtkOUr1K9dbuxzS9ev8i4TxMMGCqRC9TE8uDaSoufNAXxRPNTseVA==} lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} @@ -5775,6 +5841,30 @@ snapshots: transitivePeerDependencies: - '@types/react' + '@apollo/client@3.12.3(@types/react@19.0.1)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) + '@wry/caches': 1.0.1 + '@wry/equality': 0.5.7 + '@wry/trie': 0.5.0 + graphql: 16.9.0 + graphql-tag: 2.12.6(graphql@16.9.0) + hoist-non-react-statics: 3.3.2 + optimism: 0.18.1 + prop-types: 15.8.1 + rehackt: 0.1.0(@types/react@19.0.1)(react@19.0.0) + response-iterator: 0.2.6 + symbol-observable: 4.0.0 + ts-invariant: 0.10.3 + tslib: 2.8.1 + zen-observable-ts: 1.2.5 + optionalDependencies: + graphql-ws: 5.16.0(graphql@16.9.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + transitivePeerDependencies: + - '@types/react' + '@ardatan/relay-compiler@12.0.0(graphql@16.9.0)': dependencies: '@babel/core': 7.26.0 @@ -7007,7 +7097,7 @@ snapshots: '@graphql-tools/batch-execute@8.5.22(graphql@16.9.0)': dependencies: '@graphql-tools/utils': 9.2.1(graphql@16.9.0) - dataloader: 2.2.2 + dataloader: 2.2.3 graphql: 16.9.0 tslib: 2.8.1 value-or-promise: 1.0.12 @@ -7060,7 +7150,7 @@ snapshots: '@graphql-tools/executor': 0.0.20(graphql@16.9.0) '@graphql-tools/schema': 9.0.19(graphql@16.9.0) '@graphql-tools/utils': 9.2.1(graphql@16.9.0) - dataloader: 2.2.2 + dataloader: 2.2.3 graphql: 16.9.0 tslib: 2.8.1 value-or-promise: 1.0.12 @@ -7310,7 +7400,7 @@ snapshots: '@whatwg-node/fetch': 0.10.1 chalk: 4.1.2 debug: 4.4.0 - dotenv: 16.0.3 + dotenv: 16.4.7 graphql: 16.9.0 graphql-request: 6.1.0(graphql@16.9.0) http-proxy-agent: 7.0.2 @@ -7639,12 +7729,6 @@ snapshots: '@types/react': 19.0.1 '@types/react-dom': 19.0.1 - '@radix-ui/react-compose-refs@1.1.0(@types/react@19.0.1)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.1 - '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.1)(react@19.0.0)': dependencies: react: 19.0.0 @@ -7666,13 +7750,6 @@ snapshots: '@types/react': 19.0.1 '@types/react-dom': 19.0.1 - '@radix-ui/react-slot@1.1.0(@types/react@19.0.1)(react@19.0.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.1 - '@radix-ui/react-slot@1.1.1(@types/react@19.0.1)(react@19.0.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) @@ -7864,6 +7941,10 @@ snapshots: '@types/json5@0.0.29': {} + '@types/jsonwebtoken@9.0.7': + dependencies: + '@types/node': 20.17.8 + '@types/node@20.17.8': dependencies: undici-types: 6.19.8 @@ -8446,6 +8527,8 @@ snapshots: buffer-alloc-unsafe: 1.1.0 buffer-fill: 1.0.0 + buffer-equal-constant-time@1.0.1: {} + buffer-fill@1.0.0: {} buffer@5.7.1: @@ -8720,8 +8803,6 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 - dataloader@2.2.2: {} - dataloader@2.2.3: {} debounce@1.2.1: {} @@ -8796,12 +8877,27 @@ snapshots: no-case: 3.0.4 tslib: 2.8.1 + dotenv-cli@7.4.4: + dependencies: + cross-spawn: 7.0.6 + dotenv: 16.4.7 + dotenv-expand: 10.0.0 + minimist: 1.2.8 + + dotenv-expand@10.0.0: {} + dotenv@16.0.3: {} + dotenv@16.4.7: {} + dset@3.1.4: {} eastasianwidth@0.2.0: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + electron-to-chromium@1.5.65: {} emoji-regex@10.4.0: {} @@ -9450,7 +9546,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.3.7 + debug: 4.4.0 escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -10219,6 +10315,19 @@ snapshots: espree: 9.6.1 semver: 7.6.3 + jsonwebtoken@9.0.2: + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.6.3 + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 @@ -10226,6 +10335,17 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 + jwa@1.4.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@3.2.2: + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -10243,8 +10363,6 @@ snapshots: lilconfig@2.1.0: {} - lilconfig@3.1.2: {} - lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -10296,10 +10414,24 @@ snapshots: lodash.get@4.4.2: {} + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.lowercase@4.3.0: {} lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} + lodash.sortby@4.7.0: {} lodash.zip@4.2.0: {} @@ -10724,14 +10856,14 @@ snapshots: postcss-load-config@4.0.2(postcss@8.4.49): dependencies: - lilconfig: 3.1.2 + lilconfig: 3.1.3 yaml: 2.6.1 optionalDependencies: postcss: 8.4.49 postcss-load-config@6.0.1(jiti@2.4.1)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.6.1): dependencies: - lilconfig: 3.1.2 + lilconfig: 3.1.3 optionalDependencies: jiti: 2.4.1 postcss: 8.4.49 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2a6d79b..71adaee 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -21,6 +21,7 @@ catalog: autoprefixer: ^10.4.20 class-variance-authority: ^0.7.1 clsx: ^2.1.1 + dotenv-cli: ^7.4.4 eruda: ^3.4.1 eslint: ^9.15.0 eslint-plugin-tailwindcss: ^3.17.5