Skip to main content
Deno 2 is finally here πŸŽ‰οΈ
Learn more

Tuner

deno.land/x/tuner

Tuner - ΠΌΠΎΠ΄ΡƒΠ»ΡŒ для управлСния конфигурациями ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. Π”Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ΠΎΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ Π² Π²ΠΈΠ΄Π΅ .ts Ρ„Π°ΠΉΠ»Π°, содСрТащСго ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с полями ΠΈ значСниями. Π€Π°ΠΉΠ»Ρ‹ ΠΌΠΎΠ³ΡƒΡ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒΡΡ ΠΊΠ°ΠΊ Π² самом ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅(local Ρ„Π°ΠΉΠ»Ρ‹), Ρ‚Π°ΠΊ ΠΈ ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎ (remote).

ЀактичСски, ΠΌΠΎΠ΄ΡƒΠ»ΡŒ прСдоставляСт класс для ΠΌΠ΅Π½Π΅Π΄ΠΆΠΌΠ΅Π½Ρ‚Π° Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° ΠΈ нСсколько Ρ„ΡƒΠΊΠ½Ρ†ΠΈΠΉ, ΠΎΠ±Π½ΠΎΠ²Π»ΡΡŽΡ‰ΠΈΠ΅ схСмы ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ для ΡƒΠ΄ΠΎΠ±Π½ΠΎΠΉ ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ.


ОглавлСниС

ИспользованиС

ГСнСрация ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ схСмы

Для Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΠΌΡ„ΠΎΡ€Ρ‚ΠΎΠ³ΠΎ обращСния с ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠ΅ΠΉ интСрфСйсы ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Ρ‹. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° схСма Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ автоматичСски пСрСписана.

ΠŸΡƒΡΡ‚ΡŒ Π² ΠΏΠ°ΠΏΠΊΠ΅ config имССтся Ρ„Π°ΠΉΠ» localSupabaseConfig.ts

Π’Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠΉ ΠΊ названию Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° Π½Π΅Ρ‚.

Π‘Π°ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ обязан ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ΠΏΠΎΠ»Π΅ secrets с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ Π½Π°Π·Π²Π°Π½ΠΈΠΉ сСкрСтных ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ….

secrets : {name: string}[]

// config/localSupabaseConfig.ts
const localSupabase = {
  name: 'local',
  secrets: [
    {
      name: 'API_KEY',
    },
    {
      name: 'URL',
    },
  ],
  timeout: 200,
  mainTable: 'customer',
  otherKey: 'otherValue',
};

export default localSupabase;

Для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ схСмы ΠΈ Ρ‚ΠΈΠΏΠ° этого ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°, Π° Ρ‚Π°ΠΊΠΆΠ΅ отслСТивания ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ этого Ρ„Π°ΠΉΠ»Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ watchConfigFiles:

// config/watcher.ts
import { watchConfigFiles } from 'https://deno.land/x/tuner/mod.ts';

const configFilePaths: ConfigFilePaths = {
  // ΠŸΡƒΡ‚ΠΈ Π΄ΠΎ Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° Ρ‚ΠΈΠΏΠ° supabaseConfig
  filePaths: [
    'config/localSupabaseConfig.ts',
    'config/stageSupabaseConfig.ts',
    'config/prodSupabaseConfig.ts',
  ],
  configType: 'supabaseConfig',
};

await watchConfigFiles(configFilePaths);

ΠŸΡ€ΠΈ запускС deno run –allow-all config/watcher.ts ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠ΅ любого ΠΈΠ· отслСТиваСмых Ρ„Π°ΠΉΠ»ΠΎΠ² измСняСт схСму ΠΊΠΎΠ½Ρ„ΠΈΠ³Π°(ΠΈΠ»ΠΈ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ Π΅Π΅ ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΌ запускС/отсутствии Ρ„Π°ΠΉΠ»Π° схСмы)

Π€Π°ΠΉΠ» схСмы ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° располоТСн Π² Ρ‚ΠΎΠΉ ΠΆΠ΅ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ с Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ${configType}Schema.ts

Π’Ρ‹Π²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ ΠΈ Π΅Π³ΠΎ ΠΈΠΌΠΏΠΎΡ€Ρ‚ автоматичСски Π²ΠΏΠΈΡˆΠ΅Ρ‚ΡΡ Π² config/localSupabaseConfig.ts, …

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΠΎΠ²

// config/manager.ts
import {
  SupabaseConfig,
  SupabaseConfigSchema,
} from '../config/supabaseConfigSchema.ts';
import { ConfigManager } from 'https://deno.land/x/tuner/mod.ts';

const manager = new ConfigManager<
  SupabaseConfig,
  typeof SupabaseConfigSchema
>(
  SupabaseConfigSchema,
);

// Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π°
manager.addRemoteConfigUrl(
  'https://raw.githubusercontent.com/artpani4/configTest/main/configTest.ts',
);

// Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹Ρ… ΠΊΠΎΠ½Ρ„ΠΈΠ³ΠΎΠ²
manager.addRemoteConfigUrls(
  'https://raw.githubusercontent.com/artpani4/configTest/main/configTest.ts',
  'http://example.com/supabaseConfigRu.ts',
  'http://example.com/supabaseConfigEn.ts',
);

// Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠ΄Π½ΠΎΠ³ΠΎ локального ΠΊΠΎΠ½Ρ„ΠΈΠ³Π°
manager.addLocalConfigUrl('config/localSupabaseConfig.ts.ts');

// Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π΅ΡΠΎΠΊΠ»ΡŒΠΊΠΈΡ… Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΊΠΎΠ½Ρ„ΠΈΠ³ΠΎΠ²
manager.addLocalConfigUrls([
  'config/localSupabaseConfig.ts',
  'config/stageSupabaseConfig.ts',
  'config/prodSupabaseConfig.ts',
]);

// Если ΠΏΡ€ΠΎΠΈΠΉΠ·ΠΎΠ΄Π΅Ρ‚ какая-Ρ‚ΠΎ ошибка ΠΏΡ€ΠΈ ΠΏΠΎΠ΄Π³Ρ€ΡƒΠ·ΠΊΠ΅ ΠΊΠ°ΠΊΠΎΠ³ΠΎ-Ρ‚ΠΎ ΠΈΠ· ΠΊΠΎΠ½Ρ„ΠΈΠ³ΠΎΠ², Ρ‚ΠΎ Π΄Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ загрузится ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
// Если ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π²ΠΎΠ·Π½ΠΈΠΊΠ½Π΅Ρ‚ ΠΈ с Π½ΠΈΠΌ(ΠΈΠ»ΠΈ ΠΆΠ΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π½Π΅Ρ‚, Π° Ρ†Π΅Π»Π΅Π²ΠΎΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ нСдоступСн) ΡΡ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅.
await manager.setMainConfig('config/localBotConfig.ts', 'local');
export default manager;

ИспользованиС ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΠΎΠ²

// src/index.ts
import { SupabaseConfig } from '../config/supabaseConfigSchema.ts';
import manager from '../config/manager.ts';

try {
  // АргумСнтом являСтся ΠΏΡ€Π΅Π΄ΠΈΠΊΠ°Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ прСдставляСт собой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΠΎΠ².
  // Π’ Π΄Π°Π½Π½ΠΎΠΌ случаС, функция провСряСт, Ρ€Π°Π²Π½ΠΎ Π»ΠΈ ΠΏΠΎΠ»Π΅ 'name' Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ,  ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠΌΡƒ ΠΈΠ· ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ окруТСния 'name'.
  const config = await manager.loadConfig(
    (config: SupabaseConfig) => config.name === Deno.env.get('name'),
  );
  console.log(config);
  // Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ сикрСтов
  const dbApiKey = manager.getSecret('API_KEY');
  const dbUrl = manager.getSecret('URL');
} catch (e) {
  console.log(e);
}

ΠŸΡ€ΠΈ запускС сикрСты ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ нСпосрСдствСнно

API_KEY=your_key URL=https://your_db_url.supabase.co deno run --allow-all index.ts

Π›ΠΈΠ±ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» .env

API_KEY=your_key
URL=https://your_db_url.supabase.co

Если сикрСт Π½Π΅ находится, гСнСрируСтся ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅.