Marketing Hub: RBAC, i18n (AR/EN), tasks overhaul, team/user merge, tutorial

Features:
- Full RBAC with 3 roles (superadmin/manager/contributor)
- Ownership tracking on posts, tasks, campaigns, projects
- Task system: assign to anyone, filter combobox, visibility scoping
- Team members merged into users table (single source of truth)
- Post thumbnails on kanban cards from attachments
- Publication link validation before publishing
- Interactive onboarding tutorial with Settings restart
- Full Arabic/English i18n with RTL layout support
- Language toggle in sidebar, IBM Plex Sans Arabic font
- Brand-based visibility filtering for non-superadmins
- Manager can only create contributors
- Profile completion flow for new users
- Cookie-based sessions (express-session + SQLite)
This commit is contained in:
fahed
2026-02-08 20:46:58 +03:00
commit 35d84b6bff
2240 changed files with 846749 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReceiveBuffer = void 0;
class ReceiveBuffer {
constructor(size = 4096) {
this.buffer = Buffer.allocUnsafe(size);
this.offset = 0;
this.originalSize = size;
}
get length() {
return this.offset;
}
append(data) {
if (!Buffer.isBuffer(data)) {
throw new Error('Attempted to append a non-buffer instance to ReceiveBuffer.');
}
if (this.offset + data.length >= this.buffer.length) {
const tmp = this.buffer;
this.buffer = Buffer.allocUnsafe(Math.max(this.buffer.length + this.originalSize, this.buffer.length + data.length));
tmp.copy(this.buffer);
}
data.copy(this.buffer, this.offset);
return (this.offset += data.length);
}
peek(length) {
if (length > this.offset) {
throw new Error('Attempted to read beyond the bounds of the managed internal data.');
}
return this.buffer.slice(0, length);
}
get(length) {
if (length > this.offset) {
throw new Error('Attempted to read beyond the bounds of the managed internal data.');
}
const value = Buffer.allocUnsafe(length);
this.buffer.slice(0, length).copy(value);
this.buffer.copyWithin(0, length, length + this.offset - length);
this.offset -= length;
return value;
}
}
exports.ReceiveBuffer = ReceiveBuffer;
//# sourceMappingURL=receivebuffer.js.map