Repo cleanup and updates
This commit is contained in:
parent
3a1063e40e
commit
99f8d7e2eb
72 changed files with 11857 additions and 16439 deletions
|
|
@ -9,3 +9,12 @@ export type {
|
|||
User,
|
||||
} from "./lib/database.js";
|
||||
export { getWorkerUtils } from "./lib/utils.js";
|
||||
export {
|
||||
getMaxAttachmentSize,
|
||||
getMaxTotalAttachmentSize,
|
||||
MAX_ATTACHMENTS,
|
||||
} from "./lib/config/attachments.js";
|
||||
export {
|
||||
getSignalAutoGroupNameTemplate,
|
||||
buildSignalGroupName,
|
||||
} from "./lib/config/signal.js";
|
||||
|
|
|
|||
36
packages/bridge-common/lib/config/attachments.ts
Normal file
36
packages/bridge-common/lib/config/attachments.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* Attachment size configuration for messaging channels
|
||||
*
|
||||
* Environment variables:
|
||||
* - BRIDGE_MAX_ATTACHMENT_SIZE_MB: Maximum size for a single attachment in MB (default: 50)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the maximum attachment size in bytes from environment variable
|
||||
* Defaults to 50MB if not set
|
||||
*/
|
||||
export function getMaxAttachmentSize(): number {
|
||||
const envValue = process.env.BRIDGE_MAX_ATTACHMENT_SIZE_MB;
|
||||
const sizeInMB = envValue ? parseInt(envValue, 10) : 50;
|
||||
|
||||
// Validate the value
|
||||
if (isNaN(sizeInMB) || sizeInMB <= 0) {
|
||||
console.warn(`Invalid BRIDGE_MAX_ATTACHMENT_SIZE_MB value: ${envValue}, using default 50MB`);
|
||||
return 50 * 1024 * 1024;
|
||||
}
|
||||
|
||||
return sizeInMB * 1024 * 1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum total size for all attachments in a message
|
||||
* This is 4x the single attachment size
|
||||
*/
|
||||
export function getMaxTotalAttachmentSize(): number {
|
||||
return getMaxAttachmentSize() * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum number of attachments per message
|
||||
*/
|
||||
export const MAX_ATTACHMENTS = 10;
|
||||
29
packages/bridge-common/lib/config/signal.ts
Normal file
29
packages/bridge-common/lib/config/signal.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Signal configuration
|
||||
*
|
||||
* Environment variables:
|
||||
* - SIGNAL_AUTO_GROUP_NAME_TEMPLATE: Template for auto-created group names (default: "Support Request: {conversationId}")
|
||||
* Available placeholders: {conversationId}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the Signal auto-group name template from environment variable
|
||||
* Defaults to "Support Request: {conversationId}" if not set
|
||||
*/
|
||||
export function getSignalAutoGroupNameTemplate(): string {
|
||||
const template = process.env.SIGNAL_AUTO_GROUP_NAME_TEMPLATE;
|
||||
|
||||
if (!template) {
|
||||
return "Support Request: {conversationId}";
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Signal group name from the template and conversation ID
|
||||
*/
|
||||
export function buildSignalGroupName(conversationId: string): string {
|
||||
const template = getSignalAutoGroupNameTemplate();
|
||||
return template.replace('{conversationId}', conversationId);
|
||||
}
|
||||
|
|
@ -138,15 +138,57 @@ export type VoiceLine = Selectable<Database["VoiceLine"]>;
|
|||
export type Webhook = Selectable<Database["Webhook"]>;
|
||||
export type User = Selectable<Database["User"]>;
|
||||
|
||||
export const db = new KyselyAuth<Database>({
|
||||
dialect: new PostgresDialect({
|
||||
pool: new Pool({
|
||||
host: process.env.DATABASE_HOST,
|
||||
database: process.env.DATABASE_NAME,
|
||||
port: parseInt(process.env.DATABASE_PORT!),
|
||||
user: process.env.DATABASE_USER,
|
||||
password: process.env.DATABASE_PASSWORD,
|
||||
}),
|
||||
}) as any,
|
||||
plugins: [new CamelCasePlugin() as any],
|
||||
// Lazy database initialization to avoid errors during build time
|
||||
let _db: KyselyAuth<Database> | undefined;
|
||||
|
||||
function getDb(): KyselyAuth<Database> {
|
||||
if (_db) {
|
||||
return _db;
|
||||
}
|
||||
|
||||
// Validate environment variables
|
||||
const DATABASE_HOST = process.env.DATABASE_HOST;
|
||||
const DATABASE_NAME = process.env.DATABASE_NAME;
|
||||
const DATABASE_PORT = process.env.DATABASE_PORT;
|
||||
const DATABASE_USER = process.env.DATABASE_USER;
|
||||
const DATABASE_PASSWORD = process.env.DATABASE_PASSWORD;
|
||||
|
||||
if (!DATABASE_HOST || !DATABASE_NAME || !DATABASE_PORT || !DATABASE_USER || !DATABASE_PASSWORD) {
|
||||
throw new Error('Missing required database environment variables: DATABASE_HOST, DATABASE_NAME, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD');
|
||||
}
|
||||
|
||||
const port = parseInt(DATABASE_PORT, 10);
|
||||
if (isNaN(port) || port < 1 || port > 65535) {
|
||||
throw new Error(`Invalid DATABASE_PORT: ${DATABASE_PORT}. Must be a number between 1 and 65535.`);
|
||||
}
|
||||
|
||||
_db = new KyselyAuth<Database>({
|
||||
dialect: new PostgresDialect({
|
||||
pool: new Pool({
|
||||
host: DATABASE_HOST,
|
||||
database: DATABASE_NAME,
|
||||
port,
|
||||
user: DATABASE_USER,
|
||||
password: DATABASE_PASSWORD,
|
||||
}),
|
||||
}) as any,
|
||||
plugins: [new CamelCasePlugin() as any],
|
||||
});
|
||||
|
||||
return _db;
|
||||
}
|
||||
|
||||
// Export db as a getter that lazily initializes the database
|
||||
export const db = new Proxy({} as KyselyAuth<Database>, {
|
||||
get(_target, prop) {
|
||||
const instance = getDb();
|
||||
const value = (instance as any)[prop];
|
||||
|
||||
// If it's a function, bind it to the actual instance to preserve 'this' context
|
||||
if (typeof value === 'function') {
|
||||
return value.bind(instance);
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@link-stack/bridge-common",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"main": "build/main/index.js",
|
||||
"type": "module",
|
||||
"author": "Darren Clarke <darren@redaranj.com>",
|
||||
|
|
@ -15,8 +15,9 @@
|
|||
"pg": "^8.16.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@link-stack/eslint-config": "*",
|
||||
"@link-stack/typescript-config": "*",
|
||||
"@link-stack/eslint-config": "workspace:*",
|
||||
"@link-stack/typescript-config": "workspace:*",
|
||||
"@types/pg": "^8.15.5",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "@link-stack/bridge-ui",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@link-stack/bridge-common": "*",
|
||||
"@link-stack/signal-api": "*",
|
||||
"@link-stack/ui": "*",
|
||||
"@link-stack/bridge-common": "workspace:*",
|
||||
"@link-stack/signal-api": "workspace:*",
|
||||
"@link-stack/ui": "workspace:*",
|
||||
"@mui/material": "^6",
|
||||
"@mui/x-data-grid-pro": "^7",
|
||||
"kysely": "0.27.5",
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ export const colors: any = {
|
|||
helpYellow: "#fff4d5",
|
||||
dwcDarkBlue: "#191847",
|
||||
hazyMint: "#ecf7f8",
|
||||
leafcutterElectricBlue: "#4d6aff",
|
||||
leafcutterLightBlue: "#fafbfd",
|
||||
waterbearElectricPurple: "#332c83",
|
||||
waterbearLightSmokePurple: "#eff3f8",
|
||||
bumpedPurple: "#212058",
|
||||
|
|
|
|||
2
packages/eslint-config/index.js
Normal file
2
packages/eslint-config/index.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Placeholder entry point for eslint-config package
|
||||
module.exports = {};
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"name": "@link-stack/eslint-config",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"description": "amigo's eslint config",
|
||||
"main": "index.js",
|
||||
"author": "Abel Luck <abel@guardianproject.info>",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"private": false,
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"fmt": "prettier \"profile/**/*.js\" --write"
|
||||
},
|
||||
|
|
|
|||
2
packages/jest-config/index.js
Normal file
2
packages/jest-config/index.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Placeholder entry point for jest-config package
|
||||
module.exports = {};
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"name": "@link-stack/jest-config",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"author": "Abel Luck <abel@guardianproject.info>",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"private": false,
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@link-stack/logger",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"description": "Shared logging utility for Link Stack monorepo",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
|
|
@ -23,8 +23,8 @@
|
|||
"pino-pretty": "^13.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@link-stack/eslint-config": "*",
|
||||
"@link-stack/typescript-config": "*",
|
||||
"@link-stack/eslint-config": "workspace:*",
|
||||
"@link-stack/typescript-config": "workspace:*",
|
||||
"@types/node": "^24.7.0",
|
||||
"eslint": "^9.37.0",
|
||||
"tsup": "^8.5.0",
|
||||
|
|
@ -33,4 +33,4 @@
|
|||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export const getPinoConfig = (): LoggerOptions => {
|
|||
timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`,
|
||||
redact: {
|
||||
paths: [
|
||||
// Top-level sensitive fields
|
||||
'password',
|
||||
'token',
|
||||
'secret',
|
||||
|
|
@ -24,11 +25,35 @@ export const getPinoConfig = (): LoggerOptions => {
|
|||
'apiKey',
|
||||
'authorization',
|
||||
'cookie',
|
||||
'HandshakeKey',
|
||||
'receivedSecret',
|
||||
'access_token',
|
||||
'refresh_token',
|
||||
'zammadCsrfToken',
|
||||
'clientSecret',
|
||||
// Nested sensitive fields (one level)
|
||||
'*.password',
|
||||
'*.token',
|
||||
'*.secret',
|
||||
'*.api_key',
|
||||
'*.apiKey',
|
||||
'*.authorization',
|
||||
'*.cookie',
|
||||
'*.access_token',
|
||||
'*.refresh_token',
|
||||
'*.zammadCsrfToken',
|
||||
'*.HandshakeKey',
|
||||
'*.receivedSecret',
|
||||
'*.clientSecret',
|
||||
// Common nested patterns
|
||||
'payload.HandshakeKey',
|
||||
'headers.authorization',
|
||||
'headers.cookie',
|
||||
'headers.Authorization',
|
||||
'headers.Cookie',
|
||||
'credentials.password',
|
||||
'credentials.secret',
|
||||
'credentials.token',
|
||||
],
|
||||
censor: '[REDACTED]',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@link-stack/signal-api",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"type": "module",
|
||||
"main": "build/index.js",
|
||||
"exports": {
|
||||
|
|
@ -13,8 +13,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@openapitools/openapi-generator-cli": "^2.24.0",
|
||||
"@link-stack/typescript-config": "*",
|
||||
"@link-stack/eslint-config": "*",
|
||||
"@link-stack/typescript-config": "workspace:*",
|
||||
"@link-stack/eslint-config": "workspace:*",
|
||||
"@types/node": "^24",
|
||||
"typescript": "^5"
|
||||
}
|
||||
|
|
|
|||
2
packages/typescript-config/index.js
Normal file
2
packages/typescript-config/index.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Placeholder entry point for typescript-config package
|
||||
module.exports = {};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@link-stack/typescript-config",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"description": "Shared TypeScript config",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Abel Luck <abel@guardianproject.info>",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@link-stack/ui",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json"
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@ export const colors: any = {
|
|||
helpYellow: "#fff4d5",
|
||||
dwcDarkBlue: "#191847",
|
||||
hazyMint: "#ecf7f8",
|
||||
leafcutterElectricBlue: "#4d6aff",
|
||||
leafcutterLightBlue: "#fafbfd",
|
||||
waterbearElectricPurple: "#332c83",
|
||||
waterbearLightSmokePurple: "#eff3f8",
|
||||
bumpedPurple: "#212058",
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "@link-stack/zammad-addon-bridge",
|
||||
"displayName": "Bridge",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"description": "An addon that adds CDR Bridge channels to Zammad.",
|
||||
"scripts": {
|
||||
"build": "node '../../node_modules/@link-stack/zammad-addon-common/dist/build.js'",
|
||||
"migrate": "node '../../node_modules/@link-stack/zammad-addon-common/dist/migrate.js'"
|
||||
"build": "node '../zammad-addon-common/dist/build.js'",
|
||||
"migrate": "node '../zammad-addon-common/dist/migrate.js'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@link-stack/zammad-addon-common": "*"
|
||||
"@link-stack/zammad-addon-common": "workspace:*"
|
||||
},
|
||||
"author": "",
|
||||
"license": "AGPL-3.0-or-later"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@link-stack/zammad-addon-common",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"description": "",
|
||||
"bin": {
|
||||
"zpm-build": "./dist/build.js",
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
"author": "",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@link-stack/logger": "*",
|
||||
"@link-stack/logger": "workspace:*",
|
||||
"glob": "^11.0.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "@link-stack/zammad-addon-hardening",
|
||||
"displayName": "Hardening",
|
||||
"version": "3.2.0b3",
|
||||
"version": "3.3.0-beta.1",
|
||||
"description": "A Zammad addon that hardens a Zammad instance according to CDR's needs.",
|
||||
"scripts": {
|
||||
"build": "node '../../node_modules/@link-stack/zammad-addon-common/dist/build.js'",
|
||||
"migrate": "node '../../node_modules/@link-stack/zammad-addon-common/dist/migrate.js'"
|
||||
"build": "node '../zammad-addon-common/dist/build.js'",
|
||||
"migrate": "node '../zammad-addon-common/dist/migrate.js'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@link-stack/zammad-addon-common": "*"
|
||||
"@link-stack/zammad-addon-common": "workspace:*"
|
||||
},
|
||||
"author": "",
|
||||
"license": "AGPL-3.0-or-later"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue