fix: resolve obsidian community review issues for 0.1.1

- tsconfig: drop deprecated baseUrl and moduleResolution=node10 (node->bundler)
  that failed build verification on newer TypeScript
- esbuild: replace builtin-modules dependency with node:module builtinModules
- settings-tab: use createDiv/createSpan instead of createEl("div"/"span")
- main: avoid globalThis; reference crypto.randomUUID directly
- type Supabase rpc/select responses and loadData to remove unsafe-any flows
  (destructuring, assignment, member access, arguments)
- template-engine: annotate replace() callback params to drop unsafe arguments
- styles: drop !important; override via selector specificity
- bump version to 0.1.1 (manifest, package, versions)
This commit is contained in:
tmlnv 2026-06-29 23:06:08 +03:00
parent b70131db90
commit 0351218fff
11 changed files with 64 additions and 76 deletions

View file

@ -1,6 +1,8 @@
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
import { builtinModules } from "node:module";
const builtins = [...builtinModules, ...builtinModules.map((name) => `node:${name}`)];
const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD

View file

@ -1,7 +1,7 @@
{
"id": "telegram-bridge",
"name": "Telegram Bridge",
"version": "0.1.0",
"version": "0.1.1",
"minAppVersion": "1.5.0",
"description": "Sync messages from Telegram into your vault through a self-hosted Supabase backend.",
"author": "tmlnv",

18
package-lock.json generated
View file

@ -1,18 +1,17 @@
{
"name": "telegram-bridge",
"version": "0.1.0",
"version": "0.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "telegram-bridge",
"version": "0.1.0",
"version": "0.1.1",
"dependencies": {
"@supabase/supabase-js": "^2.49.8"
},
"devDependencies": {
"@types/node": "^20.17.30",
"builtin-modules": "^3.3.0",
"esbuild": "^0.25.1",
"obsidian": "latest",
"typescript": "^5.8.2",
@ -1128,19 +1127,6 @@
"node": ">=12"
}
},
"node_modules/builtin-modules": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cac": {
"version": "6.7.14",
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",

View file

@ -1,6 +1,6 @@
{
"name": "telegram-bridge",
"version": "0.1.0",
"version": "0.1.1",
"description": "Sync messages from Telegram into your vault through a self-hosted Supabase backend.",
"main": "main.js",
"scripts": {
@ -16,7 +16,6 @@
},
"devDependencies": {
"@types/node": "^20.17.30",
"builtin-modules": "^3.3.0",
"esbuild": "^0.25.1",
"obsidian": "latest",
"typescript": "^5.8.2",

View file

@ -29,8 +29,8 @@ import { findMatchingRule } from "./distribution-rules";
import { expandTemplate } from "./template-engine";
function createClientId(): string {
if (globalThis.crypto?.randomUUID) {
return globalThis.crypto.randomUUID();
if (typeof crypto !== "undefined" && crypto.randomUUID) {
return crypto.randomUUID();
}
return `client-${Date.now()}`;
@ -114,7 +114,7 @@ export default class ObsidianTelegramPlugin extends Plugin {
}
async loadSettings(): Promise<void> {
const loaded = await this.loadData();
const loaded = (await this.loadData()) as Partial<PluginSettings> | null;
this.settings = {
...DEFAULT_SETTINGS,
...loaded,
@ -294,13 +294,13 @@ export default class ObsidianTelegramPlugin extends Plugin {
return null;
}
const { data, error } = await getClient().rpc("get_usage_estimate");
if (error) {
throw new Error(`Failed to load usage estimate: ${error.message}`);
const response = await getClient().rpc("get_usage_estimate");
if (response.error) {
throw new Error(`Failed to load usage estimate: ${response.error.message}`);
}
const row = Array.isArray(data) ? data[0] : data;
this.latestUsageEstimate = (row ?? null) as UsageEstimateRow | null;
const rows = (response.data ?? []) as UsageEstimateRow[];
this.latestUsageEstimate = rows[0] ?? null;
this.updateStatusIndicator();
return this.latestUsageEstimate;
}
@ -311,21 +311,22 @@ export default class ObsidianTelegramPlugin extends Plugin {
return null;
}
const { data, error } = await getClient()
const response = await getClient()
.from("user_preferences")
.select("*")
.eq("user_id", getSession()!.user.id)
.maybeSingle();
if (error) {
throw new Error(`Failed to load usage settings: ${error.message}`);
if (response.error) {
throw new Error(`Failed to load usage settings: ${response.error.message}`);
}
if (!data) {
const preferences = response.data as UserPreferencesRow | null;
if (!preferences) {
return await this.pushUserPreferencesToServer();
}
this.latestUserPreferences = data as UserPreferencesRow;
this.latestUserPreferences = preferences;
this.settings.estimated_storage_limit_mb = Math.max(
1,
Math.round(this.latestUserPreferences.estimated_storage_limit_bytes / (1024 * 1024)),
@ -353,17 +354,17 @@ export default class ObsidianTelegramPlugin extends Plugin {
updated_at: new Date().toISOString(),
};
const { data, error } = await getClient()
const response = await getClient()
.from("user_preferences")
.upsert(payload)
.select("*")
.single();
if (error) {
throw new Error(`Failed to save usage settings: ${error.message}`);
if (response.error) {
throw new Error(`Failed to save usage settings: ${response.error.message}`);
}
this.latestUserPreferences = data as UserPreferencesRow;
this.latestUserPreferences = response.data as UserPreferencesRow;
this.settings.estimated_storage_limit_mb = Math.max(
1,
Math.round(this.latestUserPreferences.estimated_storage_limit_bytes / (1024 * 1024)),

View file

@ -34,11 +34,11 @@ export class ObsidianTelegramSettingTab extends PluginSettingTab {
}
const intro = containerEl.createDiv({ cls: "obsidian-telegram-intro" });
intro.createEl("div", {
intro.createDiv({
cls: "obsidian-telegram-intro-title",
text: "Requires a self-hosted Supabase project",
});
intro.createEl("div", {
intro.createDiv({
cls: "obsidian-telegram-intro-body",
text: "This plugin reads Telegram messages from your own Supabase backend. Follow the README to provision a free Supabase project, deploy the edge functions, and create a Telegram bot before connecting below.",
});
@ -58,7 +58,7 @@ export class ObsidianTelegramSettingTab extends PluginSettingTab {
const summary = details.createEl("summary", {
cls: "obsidian-telegram-section-summary",
});
summary.createEl("span", {
summary.createSpan({
cls: "obsidian-telegram-section-title",
text: title,
});
@ -585,11 +585,11 @@ export class ObsidianTelegramSettingTab extends PluginSettingTab {
description: string,
): void {
const row = containerEl.createDiv({ cls: "obsidian-telegram-connection-row" });
row.createEl("div", { cls: "obsidian-telegram-connection-label", text: label });
row.createDiv({ cls: "obsidian-telegram-connection-label", text: label });
const body = row.createDiv({ cls: "obsidian-telegram-connection-body" });
body.createEl("div", { cls: "obsidian-telegram-connection-value", text: value });
body.createEl("div", { cls: "obsidian-telegram-connection-description", text: description });
body.createDiv({ cls: "obsidian-telegram-connection-value", text: value });
body.createDiv({ cls: "obsidian-telegram-connection-description", text: description });
}
private usageSummaryEl: HTMLElement | null = null;
@ -618,16 +618,16 @@ export class ObsidianTelegramSettingTab extends PluginSettingTab {
const headerEl = summaryEl.createDiv({ cls: "obsidian-telegram-usage-header" });
const headerCopyEl = headerEl.createDiv();
headerCopyEl.createEl("div", { cls: "obsidian-telegram-usage-eyebrow", text: "Estimated usage" });
headerCopyEl.createEl("div", {
headerCopyEl.createDiv({ cls: "obsidian-telegram-usage-eyebrow", text: "Estimated usage" });
headerCopyEl.createDiv({
cls: "obsidian-telegram-usage-title obsidian-telegram-skeleton-text",
text: "—",
});
headerCopyEl.createEl("div", {
headerCopyEl.createDiv({
cls: "obsidian-telegram-usage-subtitle obsidian-telegram-skeleton-text",
text: "Loading estimated storage usage…",
});
headerEl.createEl("div", {
headerEl.createDiv({
cls: "obsidian-telegram-usage-badge obsidian-telegram-skeleton-badge",
text: "—",
});
@ -650,11 +650,11 @@ export class ObsidianTelegramSettingTab extends PluginSettingTab {
this.createUsageStat(statsEl, "Files", "—", "— of estimate");
const footerEl = summaryEl.createDiv({ cls: "obsidian-telegram-usage-footer" });
footerEl.createEl("div", {
footerEl.createDiv({
cls: "obsidian-telegram-usage-note obsidian-telegram-skeleton-text",
text: "Fetching notification status…",
});
footerEl.createEl("div", {
footerEl.createDiv({
cls: "obsidian-telegram-usage-note obsidian-telegram-skeleton-text",
text: "Fetching warning state…",
});
@ -696,22 +696,22 @@ export class ObsidianTelegramSettingTab extends PluginSettingTab {
const headerEl = summaryEl.createDiv({ cls: "obsidian-telegram-usage-header" });
const headerCopyEl = headerEl.createDiv();
headerCopyEl.createEl("div", { cls: "obsidian-telegram-usage-eyebrow", text: "Estimated usage" });
headerCopyEl.createEl("div", {
headerCopyEl.createDiv({ cls: "obsidian-telegram-usage-eyebrow", text: "Estimated usage" });
headerCopyEl.createDiv({
cls: "obsidian-telegram-usage-title",
text:
usage === null
? "No synced data yet"
: `${this.formatBytes(usageBytes)} of ${this.formatBytes(limitBytes)}`,
});
headerCopyEl.createEl("div", {
headerCopyEl.createDiv({
cls: "obsidian-telegram-usage-subtitle",
text:
usage === null
? "The chart will appear after your first synced messages."
: `${usage.message_count} messages and ${usage.file_count} files tracked by the estimate.`,
});
headerEl.createEl("div", {
headerEl.createDiv({
cls: "obsidian-telegram-usage-badge",
text: `${usagePercent}%`,
});
@ -752,11 +752,11 @@ export class ObsidianTelegramSettingTab extends PluginSettingTab {
);
const footerEl = summaryEl.createDiv({ cls: "obsidian-telegram-usage-footer" });
footerEl.createEl("div", {
footerEl.createDiv({
cls: "obsidian-telegram-usage-note",
text: notificationStatus,
});
footerEl.createEl("div", {
footerEl.createDiv({
cls: "obsidian-telegram-usage-note",
text: preferences?.telegram_warnings_enabled
? "Telegram warnings are enabled."
@ -766,10 +766,10 @@ export class ObsidianTelegramSettingTab extends PluginSettingTab {
private createUsageStat(containerEl: HTMLElement, label: string, value: string, meta?: string): void {
const statEl = containerEl.createDiv({ cls: "obsidian-telegram-usage-stat" });
statEl.createEl("div", { cls: "obsidian-telegram-usage-stat-label", text: label });
statEl.createEl("div", { cls: "obsidian-telegram-usage-stat-value", text: value });
statEl.createDiv({ cls: "obsidian-telegram-usage-stat-label", text: label });
statEl.createDiv({ cls: "obsidian-telegram-usage-stat-value", text: value });
if (meta) {
statEl.createEl("div", { cls: "obsidian-telegram-usage-stat-meta", text: meta });
statEl.createDiv({ cls: "obsidian-telegram-usage-stat-meta", text: meta });
}
}

View file

@ -107,18 +107,18 @@ export class SyncEngine {
throw new Error("Cannot start sync without an authenticated session.");
}
const { data, error } = await getClient()
const response = await getClient()
.from("sync_clients")
.select("*")
.eq("id", this.clientId)
.maybeSingle();
if (error) {
throw new Error(`Failed to load sync client: ${error.message}`);
if (response.error) {
throw new Error(`Failed to load sync client: ${response.error.message}`);
}
if (data) {
const row = data as SyncClientRow;
const row = response.data as SyncClientRow | null;
if (row) {
this.cursor = {
last_processed_message_updated_at: row.last_processed_message_updated_at,
last_processed_message_id: row.last_processed_message_id,
@ -177,17 +177,17 @@ export class SyncEngine {
}
private async fetchMessagesAfterCursor(): Promise<MessageRow[]> {
const { data, error } = await getClient().rpc("fetch_messages_after_cursor", {
const response = await getClient().rpc("fetch_messages_after_cursor", {
p_last_processed_message_updated_at: this.cursor.last_processed_message_updated_at,
p_last_processed_message_id: this.cursor.last_processed_message_id,
p_limit: 50,
});
if (error) {
throw new Error(`Failed to fetch messages: ${error.message}`);
if (response.error) {
throw new Error(`Failed to fetch messages: ${response.error.message}`);
}
return (data ?? []) as MessageRow[];
return (response.data ?? []) as MessageRow[];
}
private subscribeRealtime(): void {

View file

@ -98,10 +98,10 @@ export function expandTemplate(
const content = getContent(message);
let result = template;
result = result.replace(/\{\{messageDate:([^}]+)\}\}/g, (_match, format) =>
result = result.replace(/\{\{messageDate:([^}]+)\}\}/g, (_match: string, format: string) =>
formatDate(message.telegram_date, format),
);
result = result.replace(/\{\{content(?::(\d+))?\}\}/g, (_match, length) =>
result = result.replace(/\{\{content(?::(\d+))?\}\}/g, (_match: string, length?: string) =>
sliceContent(content, length),
);
result = result.replace(/\{\{chatId\}\}/g, String(message.telegram_chat_id));

View file

@ -267,10 +267,10 @@
border-top: 0;
}
.obsidian-telegram-section-note {
border-top: 0 !important;
padding-top: 4px !important;
padding-bottom: 4px !important;
.obsidian-telegram-section-body .obsidian-telegram-section-note {
border-top: 0;
padding-top: 4px;
padding-bottom: 4px;
}
.obsidian-telegram-section-note .setting-item-control {

View file

@ -1,13 +1,12 @@
{
"compilerOptions": {
"outDir": "./dist",
"baseUrl": ".",
"allowSyntheticDefaultImports": true,
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES2020",
"moduleResolution": "node",
"moduleResolution": "bundler",
"strict": true,
"isolatedModules": true,
"lib": ["DOM", "ES2020"],

View file

@ -1,3 +1,4 @@
{
"0.1.0": "1.5.0"
"0.1.0": "1.5.0",
"0.1.1": "1.5.0"
}