create qr-codes by tg bot
This commit is contained in:
@@ -0,0 +1 @@
|
||||
dist
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@hereconnect/constants",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": ["dist/**/*"],
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "tsc --noEmit src/index.ts",
|
||||
"build": "tsc",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hereconnect/types": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "~5.6.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export const EPOCH = 1731661630981;
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./qrCodePlacements";
|
||||
export * from "./EPOCH";
|
||||
@@ -0,0 +1,12 @@
|
||||
import { type QRCodeDocument } from '@hereconnect/types'
|
||||
|
||||
export type QrCodePlacement = QRCodeDocument['placement']
|
||||
|
||||
export const qrCodePlacements = [
|
||||
{ type: 'car', label: 'Автомобиль' },
|
||||
{ type: 'pet', label: 'Питомец' },
|
||||
{ type: 'door', label: 'Входная дверь дома или квартиры' },
|
||||
{ type: 'store', label: 'Магазин' },
|
||||
{ type: 'restaurant_table', label: 'Стол в кафе или ресторане' },
|
||||
{ type: 'other', label: 'Другое' },
|
||||
] as const satisfies { type: QrCodePlacement; label: string }[]
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
"types": [],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/index.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
@@ -42,11 +42,7 @@
|
||||
"eslint": "^9.16.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"fast-check": "^3.23.1",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.4.2",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.2",
|
||||
"vitest": "^2.1.8"
|
||||
"prettier": "^3.4.1",
|
||||
"typescript": "^5.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "@hereconnect/lib-service-health-checkserver",
|
||||
"version": "1.0.0",
|
||||
"main": "src/health-server.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./src/health-server.ts",
|
||||
"default": "./src/health-server.ts"
|
||||
}
|
||||
},
|
||||
"files": ["src/**/*"],
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "tsc --noEmit src/health-server.ts",
|
||||
"build": "pnpm run lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.17.6",
|
||||
"typescript": "~5.6.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import http from "http";
|
||||
|
||||
/**
|
||||
* Запускает HTTP-сервер для проверки здоровья.
|
||||
* @param controller - AbortController для управления состоянием здоровья.
|
||||
* @param defaultPort - Порт для сервера по умолчанию (если не указан в ENV HEALTH_PORT).
|
||||
* @param defaultHostName - Имя хоста для сервера по умолчанию (если не указан в ENV HEALTH_HOST).
|
||||
*/
|
||||
export function startHealthServer(
|
||||
controller: AbortController,
|
||||
defaultPort: number = 8000,
|
||||
defaultHostName: string = "127.0.0.1",
|
||||
) {
|
||||
const port = parseInt(process.env.HEALTH_PORT || `${defaultPort}`, 10);
|
||||
const hostname = process.env.HEALTH_HOST || defaultHostName;
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
if (req.url === "/health") {
|
||||
const signal = controller.signal;
|
||||
|
||||
// Если сигнал отмены активирован, сервер помечается как "unhealthy"
|
||||
if (signal.aborted) {
|
||||
res.writeHead(500, { "Content-Type": "application/json" });
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
status: "unhealthy",
|
||||
reason: "Service aborted",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Возвращаем стандартный статус "ok", если всё нормально
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
status: "ok",
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
res.writeHead(404, { "Content-Type": "text/plain" });
|
||||
res.end("Not Found");
|
||||
}
|
||||
});
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers<void>();
|
||||
server.once("error", reject);
|
||||
server.listen(port, hostname, resolve);
|
||||
|
||||
promise.then(() => {
|
||||
console.log(
|
||||
`Healthcheck server running on http://${hostname}:${port}/health`,
|
||||
);
|
||||
});
|
||||
|
||||
// Закрываем сервер при активации AbortController
|
||||
controller.signal.addEventListener("abort", () => {
|
||||
console.log("Healthcheck server shutting down due to abort signal.");
|
||||
reject();
|
||||
server.close();
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["index.ts"]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
dist
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@hereconnect/lib-service-seq-tracker",
|
||||
"version": "1.0.0",
|
||||
"main": "src/serviceSeqTracker.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./src/serviceSeqTracker.ts",
|
||||
"default": "./src/serviceSeqTracker.ts"
|
||||
}
|
||||
},
|
||||
"files": ["src/**/*"],
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "tsc --noEmit src/serviceSeqTracker.ts",
|
||||
"build": "pnpm run lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~5.6.3",
|
||||
"@types/node": "^20.17.6",
|
||||
"@types/pouchdb-core": "^7.0.15"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { type defaults as PouchDB } from "pouchdb-core";
|
||||
|
||||
export interface ServiceSeqTrackerDocument {
|
||||
lastSeq: string | number;
|
||||
}
|
||||
|
||||
export type ServiceSeqTrackerDatabase =
|
||||
PouchDB.Database<ServiceSeqTrackerDocument>;
|
||||
|
||||
export class ServiceSeqTracker {
|
||||
/**
|
||||
* @param _id
|
||||
* @param serviceSeqTrackerDb
|
||||
* @constructor
|
||||
*/
|
||||
static async Init(
|
||||
_id: string,
|
||||
serviceSeqTrackerDb: ServiceSeqTrackerDatabase,
|
||||
) {
|
||||
const doc = await serviceSeqTrackerDb.get(_id).catch((error) => {
|
||||
if (error.name === "not_found") {
|
||||
return {
|
||||
_id,
|
||||
lastSeq: "0",
|
||||
};
|
||||
}
|
||||
throw error; // Re-throw other errors
|
||||
});
|
||||
return new ServiceSeqTracker(doc, serviceSeqTrackerDb);
|
||||
}
|
||||
|
||||
private constructor(
|
||||
private doc: ServiceSeqTrackerDocument,
|
||||
private serviceSeqTrackerDb: ServiceSeqTrackerDatabase,
|
||||
) {}
|
||||
|
||||
get lastSeq() {
|
||||
return this.doc.lastSeq;
|
||||
}
|
||||
|
||||
checkNextSeq(seq: number | string) {
|
||||
if (!this.doc) {
|
||||
}
|
||||
const next = parseInt(seq as string, 10);
|
||||
const current = parseInt(this.doc.lastSeq as string, 10);
|
||||
if (next < current) {
|
||||
throw new Error(
|
||||
`Sequence number is too old: ${seq} (${next} < ${current})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
saveSeq(seq: number | string) {
|
||||
this.doc.lastSeq = seq;
|
||||
return this.serviceSeqTrackerDb.put(this.doc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["index.ts"]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./updates/saveUpdate";
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./updates/saveUpdate"), exports);
|
||||
//# sourceMappingURL=index.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC"}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import type { BaseDocument } from "@hereconnect/types";
|
||||
export interface TelegramWebhookDesignDocument extends BaseDocument {
|
||||
_id: "_design/webhook";
|
||||
type: "_design/webhook";
|
||||
updated_at: BaseDocument["created_at"];
|
||||
updates: {
|
||||
saveUpdate: string;
|
||||
};
|
||||
constants: {
|
||||
telegram_secret_token: string;
|
||||
telegram_webhook_url?: string;
|
||||
};
|
||||
}
|
||||
export interface TgUpdateDocument extends BaseDocument {
|
||||
data: unknown;
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=types.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { TelegramWebhookDesignDocument, TgUpdateDocument } from "../types";
|
||||
export type { TelegramWebhookDesignDocument };
|
||||
type CouchRequest = {
|
||||
body: string;
|
||||
headers: Record<string, string>;
|
||||
method: string;
|
||||
query: Record<string, string>;
|
||||
userCtx: {
|
||||
name: string | null;
|
||||
roles: string[];
|
||||
};
|
||||
};
|
||||
type CouchResponse = [
|
||||
TgUpdateDocument | null,
|
||||
{
|
||||
code: number;
|
||||
body: string;
|
||||
} | string
|
||||
];
|
||||
type UpdateFunction = (doc: TgUpdateDocument | null, req: CouchRequest) => CouchResponse;
|
||||
export declare const saveUpdate: UpdateFunction;
|
||||
export declare const saveUpdateString: string;
|
||||
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.saveUpdateString = exports.saveUpdate = void 0;
|
||||
var saveUpdate = function (doc, req) {
|
||||
var token = req.headers["X-Telegram-Bot-Api-Secret-Token"];
|
||||
if (token !== this.constants.telegram_secret_token) {
|
||||
return [null, { code: 403, body: "Forbidden: Invalid token" }];
|
||||
}
|
||||
var data = JSON.parse(req.body);
|
||||
if (doc) {
|
||||
return [null, { code: 304, body: "Update already exists" }];
|
||||
}
|
||||
doc = {
|
||||
_id: "tg_update:" + data.update_id.toString(),
|
||||
type: "tg_update",
|
||||
data: data,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
return [doc, "Message saved"];
|
||||
};
|
||||
exports.saveUpdate = saveUpdate;
|
||||
exports.saveUpdateString = exports.saveUpdate.toString();
|
||||
//# sourceMappingURL=saveUpdate.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"saveUpdate.js","sourceRoot":"","sources":["../../src/updates/saveUpdate.ts"],"names":[],"mappings":";;;AAyBO,IAAM,UAAU,GAAmB,UAExC,GAA4B,EAC5B,GAAiB;IAEjB,IAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;IAC7D,IAAI,KAAK,KAAK,IAAI,CAAC,SAAS,CAAC,qBAAqB,EAAE,CAAC;QACnD,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,IAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAElC,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,GAAG,GAAG;QACJ,GAAG,EAAE,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE;QAC7C,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;IAEF,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;AAChC,CAAC,CAAC;AAxBW,QAAA,UAAU,cAwBrB;AAEW,QAAA,gBAAgB,GAAG,kBAAU,CAAC,QAAQ,EAAE,CAAC"}
|
||||
@@ -0,0 +1,25 @@
|
||||
// eslint.config.mjs
|
||||
import typescriptPlugin from "@typescript-eslint/eslint-plugin";
|
||||
import parser from "@typescript-eslint/parser";
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: ["dist", "node_modules"], // Исключаем папки из проверки
|
||||
},
|
||||
{
|
||||
files: ["src/**/*.ts"], // Проверяем только TypeScript файлы
|
||||
languageOptions: {
|
||||
parser, // Используем парсер TypeScript
|
||||
ecmaVersion: "latest", // Последняя версия ECMAScript
|
||||
sourceType: "module", // Модули ES
|
||||
},
|
||||
plugins: {
|
||||
"@typescript-eslint": typescriptPlugin, // Используем плагин TypeScript
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": ["error"], // Ошибка для неиспользуемых переменных
|
||||
semi: ["error", "always"], // Всегда требовать точку с запятой
|
||||
quotes: ["error", "double"], // Использовать двойные кавычки
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "@hereconnect/tg-bot-webhook-ddoc",
|
||||
"version": "1.0.1",
|
||||
"license": "@hereconnect/license",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=v20.10.0",
|
||||
"pnpm": ">=8.15.0"
|
||||
},
|
||||
"contributors": [],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"type-check": "tsc --noEmit",
|
||||
"clean": "rm -rf dist",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"validate": "npm run type-check && npm run lint"
|
||||
},
|
||||
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": ["dist/**/*"],
|
||||
"devDependencies": {
|
||||
"@hereconnect/types": "workspace:^",
|
||||
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
||||
"@typescript-eslint/parser": "^8.18.0",
|
||||
"eslint": "^9.16.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./updates/saveUpdate";
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { BaseDocument } from "@hereconnect/types";
|
||||
|
||||
export interface TelegramWebhookDesignDocument extends BaseDocument {
|
||||
_id: "_design/webhook";
|
||||
type: "_design/webhook";
|
||||
updated_at: BaseDocument["created_at"];
|
||||
|
||||
updates: {
|
||||
saveUpdate: string;
|
||||
};
|
||||
constants: {
|
||||
telegram_secret_token: string;
|
||||
telegram_webhook_url?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface TgUpdateDocument extends BaseDocument {
|
||||
data: unknown;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { TelegramWebhookDesignDocument, TgUpdateDocument } from "../types";
|
||||
|
||||
export type { TelegramWebhookDesignDocument };
|
||||
|
||||
type CouchRequest = {
|
||||
body: string; // JSON-строка
|
||||
headers: Record<string, string>; // Заголовки запроса
|
||||
method: string; // HTTP-метод (обычно POST для update handlers)
|
||||
query: Record<string, string>; // Параметры запроса (например, ?key=value)
|
||||
userCtx: {
|
||||
name: string | null; // Имя пользователя, если используется аутентификация
|
||||
roles: string[]; // Роли пользователя
|
||||
};
|
||||
};
|
||||
|
||||
type CouchResponse = [
|
||||
TgUpdateDocument | null,
|
||||
{ code: number; body: string } | string,
|
||||
];
|
||||
|
||||
type UpdateFunction = (
|
||||
doc: TgUpdateDocument | null,
|
||||
req: CouchRequest,
|
||||
) => CouchResponse;
|
||||
|
||||
export const saveUpdate: UpdateFunction = function (
|
||||
this: TelegramWebhookDesignDocument,
|
||||
doc: TgUpdateDocument | null,
|
||||
req: CouchRequest,
|
||||
): CouchResponse {
|
||||
const token = req.headers["X-Telegram-Bot-Api-Secret-Token"];
|
||||
if (token !== this.constants.telegram_secret_token) {
|
||||
return [null, { code: 403, body: "Forbidden: Invalid token" }];
|
||||
}
|
||||
|
||||
const data = JSON.parse(req.body);
|
||||
|
||||
if (doc) {
|
||||
return [null, { code: 304, body: "Update already exists" }];
|
||||
}
|
||||
|
||||
doc = {
|
||||
_id: "tg_update:" + data.update_id.toString(),
|
||||
type: "tg_update",
|
||||
data: data,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
return [doc, "Message saved"];
|
||||
};
|
||||
|
||||
export const saveUpdateString = saveUpdate.toString();
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES5",
|
||||
"module": "CommonJS",
|
||||
"outDir": "dist",
|
||||
"strict": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"files": ["src/index.ts"],
|
||||
}
|
||||
@@ -1,19 +1,21 @@
|
||||
{
|
||||
"name": "@hereconnect/types",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./src/index.ts",
|
||||
"default": "./src/index.ts"
|
||||
"import": "./dist/index.d.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": ["src/**/*"],
|
||||
"files": ["dist/**/*"],
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "tsc --noEmit src/index.ts",
|
||||
"build": "pnpm run lint"
|
||||
"build": "tsc",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "~5.6.3",
|
||||
|
||||
@@ -27,7 +27,10 @@ export interface QRCodeDocument extends BaseDocument {
|
||||
user_uuid: string;
|
||||
|
||||
/** Идентификатор браузера, через который был создан QR-код */
|
||||
browser_uuid: string;
|
||||
browser_uuid?: string;
|
||||
|
||||
/** Идентификатор телеграм-аккаунта, через который был создан QR-код */
|
||||
telegram_id?: string;
|
||||
|
||||
/** Название объекта, для которого создан QR‑код, например "Мой автомобиль" */
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { BaseDocument } from './BaseDocument'
|
||||
import type { BaseDocument } from "./BaseDocument";
|
||||
|
||||
/**
|
||||
* Интерфейс для документа пользователя.
|
||||
@@ -6,20 +6,23 @@ import type { BaseDocument } from './BaseDocument'
|
||||
*/
|
||||
export interface UserDocument extends BaseDocument {
|
||||
/** Тип документа, всегда 'user' */
|
||||
type: 'user'
|
||||
type: "user";
|
||||
|
||||
/** Telegram ID пользователя */
|
||||
telegram_id?: number;
|
||||
|
||||
/** Имя пользователя */
|
||||
name: string
|
||||
name: string;
|
||||
|
||||
/** Уникальный UUID пользователя, не связанный с _id */
|
||||
user_uuid: string
|
||||
user_uuid: string;
|
||||
|
||||
/** Email пользователя */
|
||||
email: string
|
||||
email?: string;
|
||||
|
||||
/** Роли пользователя (например, ['admin', 'user']) */
|
||||
roles: string[]
|
||||
roles: string[];
|
||||
|
||||
/** Пароль пользователя (должен храниться в зашифрованном виде) */
|
||||
password: string
|
||||
password: string;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "./dist",
|
||||
"strict": true
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"types": ["web-push"],
|
||||
},
|
||||
"include": ["index.ts"]
|
||||
"include": ["src/index.ts"],
|
||||
"exclude": ["node_modules", "dist"],
|
||||
}
|
||||
Reference in New Issue
Block a user