apps/bot: add create-customer functional

This commit is contained in:
vchikalkin 2024-12-22 17:24:32 +03:00
parent ab65579ccc
commit 1d4584bd6f
11 changed files with 370 additions and 62 deletions

View File

@ -5,6 +5,8 @@
"main": "index.js", "main": "index.js",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@apollo/client": "^3.12.3",
"jsonwebtoken": "^9.0.2",
"telegraf": "catalog:", "telegraf": "catalog:",
"zod": "catalog:" "zod": "catalog:"
}, },
@ -12,14 +14,18 @@
"build": "rimraf ./build & tsc -p tsconfig.json", "build": "rimraf ./build & tsc -p tsconfig.json",
"build:watch": "tsc -w -p tsconfig.json", "build:watch": "tsc -w -p tsconfig.json",
"start": "node dist/src/index.js", "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": "eslint",
"lint-staged": "lint-staged" "lint-staged": "lint-staged"
}, },
"devDependencies": { "devDependencies": {
"@repo/eslint-config": "workspace:*", "@repo/eslint-config": "workspace:*",
"@repo/graphql": "workspace:*",
"@repo/lint-staged-config": "workspace:*", "@repo/lint-staged-config": "workspace:*",
"@repo/typescript-config": "workspace:*", "@repo/typescript-config": "workspace:*",
"@types/jsonwebtoken": "^9.0.7",
"@types/node": "catalog:",
"dotenv-cli": "catalog:",
"lint-staged": "catalog:", "lint-staged": "catalog:",
"rimraf": "catalog:", "rimraf": "catalog:",
"tsx": "catalog:", "tsx": "catalog:",

13
apps/bot/src/api/query.ts Normal file
View File

@ -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,
});
}

View File

@ -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,
});
}

View File

@ -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);

View File

@ -1,6 +1,39 @@
/* eslint-disable no-console */ /* eslint-disable promise/prefer-await-to-then */
function init() { import { createCustomer } from './api/query';
console.log('hello'); 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'));

48
apps/bot/src/utils/jwt.ts Normal file
View File

@ -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;
}

View File

@ -5,6 +5,8 @@
"outDir": "dist", "outDir": "dist",
"alwaysStrict": true, "alwaysStrict": true,
"strict": true, "strict": true,
"moduleResolution": "bundler",
"module": "ES2020",
"paths": { "paths": {
"@/*": ["./*"] "@/*": ["./*"]
} }

View File

@ -1,5 +1,28 @@
query Test { mutation Register($identifier: String!, $password: String!, $email: String!) {
customers { register(input: { username: $identifier, password: $password, email: $email }) {
name 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
} }
} }

View File

@ -548,10 +548,33 @@ export type UsersPermissionsUserInput = {
username: InputMaybe<Scalars['String']['input']>; username: InputMaybe<Scalars['String']['input']>;
}; };
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<TestQuery, TestQueryVariables>; 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<RegisterMutation, RegisterMutationVariables>;
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<LoginMutation, LoginMutationVariables>;
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<CreateCustomerMutation, CreateCustomerMutationVariables>;

232
pnpm-lock.yaml generated
View File

@ -32,7 +32,7 @@ catalogs:
version: 1.1.2 version: 1.1.2
'@radix-ui/react-slot': '@radix-ui/react-slot':
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0 version: 1.1.1
'@telegram-apps/sdk-react': '@telegram-apps/sdk-react':
specifier: ^2.0.19 specifier: ^2.0.19
version: 2.0.19 version: 2.0.19
@ -63,6 +63,9 @@ catalogs:
clsx: clsx:
specifier: ^2.1.1 specifier: ^2.1.1
version: 2.1.1 version: 2.1.1
dotenv-cli:
specifier: ^7.4.4
version: 7.4.4
eruda: eruda:
specifier: ^3.4.1 specifier: ^3.4.1
version: 3.4.1 version: 3.4.1
@ -164,6 +167,12 @@ importers:
apps/bot: apps/bot:
dependencies: 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: telegraf:
specifier: 'catalog:' specifier: 'catalog:'
version: 4.16.3 version: 4.16.3
@ -174,12 +183,24 @@ importers:
'@repo/eslint-config': '@repo/eslint-config':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/eslint-config version: link:../../packages/eslint-config
'@repo/graphql':
specifier: workspace:*
version: link:../../packages/graphql
'@repo/lint-staged-config': '@repo/lint-staged-config':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/lint-staged-config version: link:../../packages/lint-staged-config
'@repo/typescript-config': '@repo/typescript-config':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/typescript-config 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: lint-staged:
specifier: 'catalog:' specifier: 'catalog:'
version: 15.2.10 version: 15.2.10
@ -338,7 +359,7 @@ importers:
devDependencies: devDependencies:
'@radix-ui/react-slot': '@radix-ui/react-slot':
specifier: 'catalog:' 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': '@repo/eslint-config':
specifier: workspace:* specifier: workspace:*
version: link:../eslint-config version: link:../eslint-config
@ -413,6 +434,24 @@ packages:
subscriptions-transport-ws: subscriptions-transport-ws:
optional: true 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': '@ardatan/relay-compiler@12.0.0':
resolution: {integrity: sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==} resolution: {integrity: sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==}
hasBin: true hasBin: true
@ -1938,15 +1977,6 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true 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': '@radix-ui/react-compose-refs@1.1.1':
resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==}
peerDependencies: peerDependencies:
@ -1978,15 +2008,6 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true 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': '@radix-ui/react-slot@1.1.1':
resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==} resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==}
peerDependencies: peerDependencies:
@ -2206,6 +2227,9 @@ packages:
'@types/json5@0.0.29': '@types/json5@0.0.29':
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
'@types/jsonwebtoken@9.0.7':
resolution: {integrity: sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==}
'@types/node@20.17.8': '@types/node@20.17.8':
resolution: {integrity: sha512-ahz2g6/oqbKalW9sPv6L2iRbhLnojxjYWspAqhjvqSWBgGebEJT5GvRmk0QXPj3sbC6rU0GTQjPLQkmR8CObvA==} resolution: {integrity: sha512-ahz2g6/oqbKalW9sPv6L2iRbhLnojxjYWspAqhjvqSWBgGebEJT5GvRmk0QXPj3sbC6rU0GTQjPLQkmR8CObvA==}
@ -2652,6 +2676,9 @@ packages:
buffer-alloc@1.2.0: buffer-alloc@1.2.0:
resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==}
buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
buffer-fill@1.0.0: buffer-fill@1.0.0:
resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==}
@ -2899,9 +2926,6 @@ packages:
resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dataloader@2.2.2:
resolution: {integrity: sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==}
dataloader@2.2.3: dataloader@2.2.3:
resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==}
@ -3003,10 +3027,22 @@ packages:
dot-case@3.0.4: dot-case@3.0.4:
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} 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: dotenv@16.0.3:
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
dotenv@16.4.7:
resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
engines: {node: '>=12'}
dset@3.1.4: dset@3.1.4:
resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -3014,6 +3050,9 @@ packages:
eastasianwidth@0.2.0: eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
ecdsa-sig-formatter@1.0.11:
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
electron-to-chromium@1.5.65: electron-to-chromium@1.5.65:
resolution: {integrity: sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==} resolution: {integrity: sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==}
@ -4107,10 +4146,20 @@ packages:
resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 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: jsx-ast-utils@3.3.5:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'} 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: keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
@ -4129,10 +4178,6 @@ packages:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
lilconfig@3.1.2:
resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
engines: {node: '>=14'}
lilconfig@3.1.3: lilconfig@3.1.3:
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
engines: {node: '>=14'} engines: {node: '>=14'}
@ -4172,12 +4217,33 @@ packages:
lodash.get@4.4.2: lodash.get@4.4.2:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} 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: lodash.lowercase@4.3.0:
resolution: {integrity: sha512-UcvP1IZYyDKyEL64mmrwoA1AbFu5ahojhTtkOUr1K9dbuxzS9ev8i4TxMMGCqRC9TE8uDaSoufNAXxRPNTseVA==} resolution: {integrity: sha512-UcvP1IZYyDKyEL64mmrwoA1AbFu5ahojhTtkOUr1K9dbuxzS9ev8i4TxMMGCqRC9TE8uDaSoufNAXxRPNTseVA==}
lodash.merge@4.6.2: lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
lodash.once@4.1.1:
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
lodash.sortby@4.7.0: lodash.sortby@4.7.0:
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
@ -5775,6 +5841,30 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- '@types/react' - '@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)': '@ardatan/relay-compiler@12.0.0(graphql@16.9.0)':
dependencies: dependencies:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
@ -7007,7 +7097,7 @@ snapshots:
'@graphql-tools/batch-execute@8.5.22(graphql@16.9.0)': '@graphql-tools/batch-execute@8.5.22(graphql@16.9.0)':
dependencies: dependencies:
'@graphql-tools/utils': 9.2.1(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 graphql: 16.9.0
tslib: 2.8.1 tslib: 2.8.1
value-or-promise: 1.0.12 value-or-promise: 1.0.12
@ -7060,7 +7150,7 @@ snapshots:
'@graphql-tools/executor': 0.0.20(graphql@16.9.0) '@graphql-tools/executor': 0.0.20(graphql@16.9.0)
'@graphql-tools/schema': 9.0.19(graphql@16.9.0) '@graphql-tools/schema': 9.0.19(graphql@16.9.0)
'@graphql-tools/utils': 9.2.1(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 graphql: 16.9.0
tslib: 2.8.1 tslib: 2.8.1
value-or-promise: 1.0.12 value-or-promise: 1.0.12
@ -7310,7 +7400,7 @@ snapshots:
'@whatwg-node/fetch': 0.10.1 '@whatwg-node/fetch': 0.10.1
chalk: 4.1.2 chalk: 4.1.2
debug: 4.4.0 debug: 4.4.0
dotenv: 16.0.3 dotenv: 16.4.7
graphql: 16.9.0 graphql: 16.9.0
graphql-request: 6.1.0(graphql@16.9.0) graphql-request: 6.1.0(graphql@16.9.0)
http-proxy-agent: 7.0.2 http-proxy-agent: 7.0.2
@ -7639,12 +7729,6 @@ snapshots:
'@types/react': 19.0.1 '@types/react': 19.0.1
'@types/react-dom': 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)': '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.1)(react@19.0.0)':
dependencies: dependencies:
react: 19.0.0 react: 19.0.0
@ -7666,13 +7750,6 @@ snapshots:
'@types/react': 19.0.1 '@types/react': 19.0.1
'@types/react-dom': 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)': '@radix-ui/react-slot@1.1.1(@types/react@19.0.1)(react@19.0.0)':
dependencies: dependencies:
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) '@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/json5@0.0.29': {}
'@types/jsonwebtoken@9.0.7':
dependencies:
'@types/node': 20.17.8
'@types/node@20.17.8': '@types/node@20.17.8':
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
@ -8446,6 +8527,8 @@ snapshots:
buffer-alloc-unsafe: 1.1.0 buffer-alloc-unsafe: 1.1.0
buffer-fill: 1.0.0 buffer-fill: 1.0.0
buffer-equal-constant-time@1.0.1: {}
buffer-fill@1.0.0: {} buffer-fill@1.0.0: {}
buffer@5.7.1: buffer@5.7.1:
@ -8720,8 +8803,6 @@ snapshots:
es-errors: 1.3.0 es-errors: 1.3.0
is-data-view: 1.0.1 is-data-view: 1.0.1
dataloader@2.2.2: {}
dataloader@2.2.3: {} dataloader@2.2.3: {}
debounce@1.2.1: {} debounce@1.2.1: {}
@ -8796,12 +8877,27 @@ snapshots:
no-case: 3.0.4 no-case: 3.0.4
tslib: 2.8.1 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.0.3: {}
dotenv@16.4.7: {}
dset@3.1.4: {} dset@3.1.4: {}
eastasianwidth@0.2.0: {} eastasianwidth@0.2.0: {}
ecdsa-sig-formatter@1.0.11:
dependencies:
safe-buffer: 5.2.1
electron-to-chromium@1.5.65: {} electron-to-chromium@1.5.65: {}
emoji-regex@10.4.0: {} emoji-regex@10.4.0: {}
@ -9450,7 +9546,7 @@ snapshots:
ajv: 6.12.6 ajv: 6.12.6
chalk: 4.1.2 chalk: 4.1.2
cross-spawn: 7.0.6 cross-spawn: 7.0.6
debug: 4.3.7 debug: 4.4.0
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
eslint-scope: 8.2.0 eslint-scope: 8.2.0
eslint-visitor-keys: 4.2.0 eslint-visitor-keys: 4.2.0
@ -10219,6 +10315,19 @@ snapshots:
espree: 9.6.1 espree: 9.6.1
semver: 7.6.3 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: jsx-ast-utils@3.3.5:
dependencies: dependencies:
array-includes: 3.1.8 array-includes: 3.1.8
@ -10226,6 +10335,17 @@ snapshots:
object.assign: 4.1.5 object.assign: 4.1.5
object.values: 1.2.0 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: keyv@4.5.4:
dependencies: dependencies:
json-buffer: 3.0.1 json-buffer: 3.0.1
@ -10243,8 +10363,6 @@ snapshots:
lilconfig@2.1.0: {} lilconfig@2.1.0: {}
lilconfig@3.1.2: {}
lilconfig@3.1.3: {} lilconfig@3.1.3: {}
lines-and-columns@1.2.4: {} lines-and-columns@1.2.4: {}
@ -10296,10 +10414,24 @@ snapshots:
lodash.get@4.4.2: {} 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.lowercase@4.3.0: {}
lodash.merge@4.6.2: {} lodash.merge@4.6.2: {}
lodash.once@4.1.1: {}
lodash.sortby@4.7.0: {} lodash.sortby@4.7.0: {}
lodash.zip@4.2.0: {} lodash.zip@4.2.0: {}
@ -10724,14 +10856,14 @@ snapshots:
postcss-load-config@4.0.2(postcss@8.4.49): postcss-load-config@4.0.2(postcss@8.4.49):
dependencies: dependencies:
lilconfig: 3.1.2 lilconfig: 3.1.3
yaml: 2.6.1 yaml: 2.6.1
optionalDependencies: optionalDependencies:
postcss: 8.4.49 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): postcss-load-config@6.0.1(jiti@2.4.1)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.6.1):
dependencies: dependencies:
lilconfig: 3.1.2 lilconfig: 3.1.3
optionalDependencies: optionalDependencies:
jiti: 2.4.1 jiti: 2.4.1
postcss: 8.4.49 postcss: 8.4.49

View File

@ -21,6 +21,7 @@ catalog:
autoprefixer: ^10.4.20 autoprefixer: ^10.4.20
class-variance-authority: ^0.7.1 class-variance-authority: ^0.7.1
clsx: ^2.1.1 clsx: ^2.1.1
dotenv-cli: ^7.4.4
eruda: ^3.4.1 eruda: ^3.4.1
eslint: ^9.15.0 eslint: ^9.15.0
eslint-plugin-tailwindcss: ^3.17.5 eslint-plugin-tailwindcss: ^3.17.5