mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 03:19:46 +00:00
Merge remote-tracking branch 'origin/main' into rewrite
This commit is contained in:
commit
84a5e1318b
22 changed files with 79 additions and 77 deletions
|
|
@ -139,7 +139,11 @@ import { metricsController } from '@/controllers/metrics.ts';
|
||||||
import { manifestController } from '@/controllers/manifest.ts';
|
import { manifestController } from '@/controllers/manifest.ts';
|
||||||
import { nodeInfoController, nodeInfoSchemaController } from '@/controllers/well-known/nodeinfo.ts';
|
import { nodeInfoController, nodeInfoSchemaController } from '@/controllers/well-known/nodeinfo.ts';
|
||||||
import { nostrController } from '@/controllers/well-known/nostr.ts';
|
import { nostrController } from '@/controllers/well-known/nostr.ts';
|
||||||
|
<<<<<<< HEAD
|
||||||
import { requireProof, requireRole } from '@/middleware/auth98Middleware.ts';
|
import { requireProof, requireRole } from '@/middleware/auth98Middleware.ts';
|
||||||
|
=======
|
||||||
|
import { auth98Middleware, requireProof, requireRole } from '@/middleware/auth98Middleware.ts';
|
||||||
|
>>>>>>> origin/main
|
||||||
import { cacheControlMiddleware } from '@/middleware/cacheControlMiddleware.ts';
|
import { cacheControlMiddleware } from '@/middleware/cacheControlMiddleware.ts';
|
||||||
import { cspMiddleware } from '@/middleware/cspMiddleware.ts';
|
import { cspMiddleware } from '@/middleware/cspMiddleware.ts';
|
||||||
import { metricsMiddleware } from '@/middleware/metricsMiddleware.ts';
|
import { metricsMiddleware } from '@/middleware/metricsMiddleware.ts';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { DittoTables } from '@ditto/db';
|
import { DittoTables } from '@ditto/db';
|
||||||
|
import { MuteListPolicy } from '@ditto/policies';
|
||||||
import {
|
import {
|
||||||
streamingClientMessagesCounter,
|
streamingClientMessagesCounter,
|
||||||
streamingConnectionsGauge,
|
streamingConnectionsGauge,
|
||||||
|
|
@ -11,7 +12,6 @@ import { Kysely } from 'kysely';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { type AppController } from '@/app.ts';
|
import { type AppController } from '@/app.ts';
|
||||||
import { MuteListPolicy } from '../../../policies/MuteListPolicy.ts';
|
|
||||||
import { getFeedPubkeys } from '@/queries.ts';
|
import { getFeedPubkeys } from '@/queries.ts';
|
||||||
import { AdminStore } from '@/storages/AdminStore.ts';
|
import { AdminStore } from '@/storages/AdminStore.ts';
|
||||||
import { hydrateEvents } from '@/storages/hydrate.ts';
|
import { hydrateEvents } from '@/storages/hydrate.ts';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { type DittoConf } from '@ditto/conf';
|
import { type DittoConf } from '@ditto/conf';
|
||||||
import { relayConnectionsGauge, relayEventsCounter, relayMessagesCounter } from '@ditto/metrics';
|
import { relayConnectionsGauge, relayEventsCounter, relayMessagesCounter } from '@ditto/metrics';
|
||||||
|
import { MemoryRateLimiter, MultiRateLimiter, type RateLimiter } from '@ditto/ratelimiter';
|
||||||
import { logi } from '@soapbox/logi';
|
import { logi } from '@soapbox/logi';
|
||||||
import { JsonValue } from '@std/json';
|
import { JsonValue } from '@std/json';
|
||||||
import {
|
import {
|
||||||
|
|
@ -19,9 +20,6 @@ import { relayInfoController } from '@/controllers/nostr/relay-info.ts';
|
||||||
import { RelayError } from '@/RelayError.ts';
|
import { RelayError } from '@/RelayError.ts';
|
||||||
import { errorJson } from '../../../utils/log.ts';
|
import { errorJson } from '../../../utils/log.ts';
|
||||||
import { purifyEvent } from '../../../utils/purify.ts';
|
import { purifyEvent } from '../../../utils/purify.ts';
|
||||||
import { MemoryRateLimiter } from '../../../utils/ratelimiter/MemoryRateLimiter.ts';
|
|
||||||
import { MultiRateLimiter } from '../../../utils/ratelimiter/MultiRateLimiter.ts';
|
|
||||||
import { RateLimiter } from '../../../utils/ratelimiter/types.ts';
|
|
||||||
import { Time } from '../../../utils/time.ts';
|
import { Time } from '../../../utils/time.ts';
|
||||||
import { DittoPipeline } from '@/DittoPipeline.ts';
|
import { DittoPipeline } from '@/DittoPipeline.ts';
|
||||||
import { EventsDB } from '@/storages/EventsDB.ts';
|
import { EventsDB } from '@/storages/EventsDB.ts';
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
|
import { DeepLTranslator, LibreTranslateTranslator } from '@ditto/translators';
|
||||||
import { safeFetch } from '@soapbox/safe-fetch';
|
import { safeFetch } from '@soapbox/safe-fetch';
|
||||||
|
|
||||||
import { AppMiddleware } from '@/app.ts';
|
import { AppMiddleware } from '@/app.ts';
|
||||||
import { DeepLTranslator } from '@/translators/DeepLTranslator.ts';
|
|
||||||
import { LibreTranslateTranslator } from '@/translators/LibreTranslateTranslator.ts';
|
|
||||||
|
|
||||||
/** Set the translator used for translating posts. */
|
/** Set the translator used for translating posts. */
|
||||||
export const translatorMiddleware: AppMiddleware = async (c, next) => {
|
export const translatorMiddleware: AppMiddleware = async (c, next) => {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
|
import { DenoUploader, IPFSUploader, S3Uploader } from '@ditto/uploaders';
|
||||||
import { BlossomUploader, NostrBuildUploader } from '@nostrify/nostrify/uploaders';
|
import { BlossomUploader, NostrBuildUploader } from '@nostrify/nostrify/uploaders';
|
||||||
import { safeFetch } from '@soapbox/safe-fetch';
|
import { safeFetch } from '@soapbox/safe-fetch';
|
||||||
|
|
||||||
import { AppMiddleware } from '@/app.ts';
|
import { AppMiddleware } from '@/app.ts';
|
||||||
import { DenoUploader } from '../../uploaders/DenoUploader.ts';
|
|
||||||
import { IPFSUploader } from '../../uploaders/IPFSUploader.ts';
|
|
||||||
import { S3Uploader } from '../../uploaders/S3Uploader.ts';
|
|
||||||
|
|
||||||
/** Set an uploader for the user. */
|
/** Set an uploader for the user. */
|
||||||
export const uploaderMiddleware: AppMiddleware = async (c, next) => {
|
export const uploaderMiddleware: AppMiddleware = async (c, next) => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { DittoConf } from '@ditto/conf';
|
import { DittoConf } from '@ditto/conf';
|
||||||
import { DittoDB } from '@ditto/db';
|
import { DittoDB } from '@ditto/db';
|
||||||
import ISO6391, { LanguageCode } from 'iso-639-1';
|
|
||||||
import lande from 'lande';
|
|
||||||
import { NostrEvent } from '@nostrify/nostrify';
|
import { NostrEvent } from '@nostrify/nostrify';
|
||||||
import { generateSecretKey, nip19 } from 'nostr-tools';
|
import { generateSecretKey, nip19 } from 'nostr-tools';
|
||||||
|
|
||||||
|
|
@ -65,15 +63,3 @@ export function testConf(): DittoConf {
|
||||||
export function sleep(ms: number): Promise<void> {
|
export function sleep(ms: number): Promise<void> {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLanguage(text: string): LanguageCode | undefined {
|
|
||||||
const [topResult] = lande(text);
|
|
||||||
if (topResult) {
|
|
||||||
const [iso6393] = topResult;
|
|
||||||
const locale = new Intl.Locale(iso6393);
|
|
||||||
if (ISO6391.validate(locale.language)) {
|
|
||||||
return locale.language;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@ditto/lang",
|
"name": "@ditto/lang",
|
||||||
|
"version": "1.1.0",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./language.ts"
|
".": "./language.ts"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { detectLanguage } from './language.ts';
|
|
||||||
import { assertEquals } from '@std/assert';
|
import { assertEquals } from '@std/assert';
|
||||||
|
|
||||||
|
import { detectLanguage } from './language.ts';
|
||||||
|
|
||||||
Deno.test('Detect English language', () => {
|
Deno.test('Detect English language', () => {
|
||||||
assertEquals(detectLanguage(``, 0.90), undefined);
|
assertEquals(detectLanguage(``, 0.90), undefined);
|
||||||
assertEquals(detectLanguage(`Good morning my fellow friends`, 0.90), 'en');
|
assertEquals(detectLanguage(`Good morning my fellow friends`, 0.90), 'en');
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,12 @@ Deno.test('block event: muted user cannot post', async () => {
|
||||||
const blockEventCopy = structuredClone(blockEvent);
|
const blockEventCopy = structuredClone(blockEvent);
|
||||||
const event1authorUserMeCopy = structuredClone(event1authorUserMe);
|
const event1authorUserMeCopy = structuredClone(event1authorUserMe);
|
||||||
|
|
||||||
const db = new MockRelay();
|
const relay = new MockRelay();
|
||||||
|
const policy = new MuteListPolicy(userBlack.pubkey, relay);
|
||||||
|
|
||||||
const store = new UserStore(userBlackCopy.pubkey, db);
|
await relay.event(blockEventCopy);
|
||||||
const policy = new MuteListPolicy(userBlack.pubkey, db);
|
await relay.event(userBlackCopy);
|
||||||
|
await relay.event(userMeCopy);
|
||||||
await store.event(blockEventCopy);
|
|
||||||
await store.event(userBlackCopy);
|
|
||||||
await store.event(userMeCopy);
|
|
||||||
|
|
||||||
const ok = await policy.call(event1authorUserMeCopy);
|
const ok = await policy.call(event1authorUserMeCopy);
|
||||||
|
|
||||||
|
|
@ -35,13 +33,11 @@ Deno.test('allow event: user is NOT muted because there is no muted event', asyn
|
||||||
const userMeCopy = structuredClone(userMe);
|
const userMeCopy = structuredClone(userMe);
|
||||||
const event1authorUserMeCopy = structuredClone(event1authorUserMe);
|
const event1authorUserMeCopy = structuredClone(event1authorUserMe);
|
||||||
|
|
||||||
const db = new MockRelay();
|
const relay = new MockRelay();
|
||||||
|
const policy = new MuteListPolicy(userBlack.pubkey, relay);
|
||||||
|
|
||||||
const store = new UserStore(userBlackCopy.pubkey, db);
|
await relay.event(userBlackCopy);
|
||||||
const policy = new MuteListPolicy(userBlack.pubkey, db);
|
await relay.event(userMeCopy);
|
||||||
|
|
||||||
await store.event(userBlackCopy);
|
|
||||||
await store.event(userMeCopy);
|
|
||||||
|
|
||||||
const ok = await policy.call(event1authorUserMeCopy);
|
const ok = await policy.call(event1authorUserMeCopy);
|
||||||
|
|
||||||
|
|
@ -55,16 +51,15 @@ Deno.test('allow event: user is NOT muted because he is not in mute event', asyn
|
||||||
const blockEventCopy = structuredClone(blockEvent);
|
const blockEventCopy = structuredClone(blockEvent);
|
||||||
const event1copy = structuredClone(event1);
|
const event1copy = structuredClone(event1);
|
||||||
|
|
||||||
const db = new MockRelay();
|
const relay = new MockRelay();
|
||||||
|
|
||||||
const store = new UserStore(userBlackCopy.pubkey, db);
|
const policy = new MuteListPolicy(userBlack.pubkey, relay);
|
||||||
const policy = new MuteListPolicy(userBlack.pubkey, db);
|
|
||||||
|
|
||||||
await store.event(userBlackCopy);
|
await relay.event(userBlackCopy);
|
||||||
await store.event(blockEventCopy);
|
await relay.event(blockEventCopy);
|
||||||
await store.event(userMeCopy);
|
await relay.event(userMeCopy);
|
||||||
await store.event(event1copy);
|
await relay.event(event1copy);
|
||||||
await store.event(event1authorUserMeCopy);
|
await relay.event(event1authorUserMeCopy);
|
||||||
|
|
||||||
const ok = await policy.call(event1copy);
|
const ok = await policy.call(event1copy);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,18 @@
|
||||||
import { NostrEvent, NostrRelayOK, NPolicy, NStore } from '@nostrify/nostrify';
|
import type { NostrEvent, NostrRelayOK, NPolicy, NStore } from '@nostrify/nostrify';
|
||||||
|
|
||||||
import { getTagSet } from '@ditto/utils/tags';
|
|
||||||
|
|
||||||
export class MuteListPolicy implements NPolicy {
|
export class MuteListPolicy implements NPolicy {
|
||||||
constructor(private pubkey: string, private store: NStore) {}
|
constructor(private pubkey: string, private store: NStore) {}
|
||||||
|
|
||||||
async call(event: NostrEvent): Promise<NostrRelayOK> {
|
async call(event: NostrEvent): Promise<NostrRelayOK> {
|
||||||
|
const pubkeys = new Set<string>();
|
||||||
|
|
||||||
const [muteList] = await this.store.query([{ authors: [this.pubkey], kinds: [10000], limit: 1 }]);
|
const [muteList] = await this.store.query([{ authors: [this.pubkey], kinds: [10000], limit: 1 }]);
|
||||||
const pubkeys = getTagSet(muteList?.tags ?? [], 'p');
|
|
||||||
|
for (const [name, value] of muteList?.tags ?? []) {
|
||||||
|
if (name === 'p') {
|
||||||
|
pubkeys.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pubkeys.has(event.pubkey)) {
|
if (pubkeys.has(event.pubkey)) {
|
||||||
return ['OK', event.id, false, 'blocked: Your account has been deactivated.'];
|
return ['OK', event.id, false, 'blocked: Your account has been deactivated.'];
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@ditto/policies",
|
"name": "@ditto/policies",
|
||||||
|
"version": "1.1.0",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./mod.ts"
|
".": "./mod.ts"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@ditto/ratelimiter",
|
"name": "@ditto/ratelimiter",
|
||||||
|
"version": "1.1.0",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./mod.ts"
|
".": "./mod.ts"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { DittoConf } from '@ditto/conf';
|
import { DittoConf } from '@ditto/conf';
|
||||||
|
import { detectLanguage } from '@ditto/lang';
|
||||||
import { assert, assertEquals } from '@std/assert';
|
import { assert, assertEquals } from '@std/assert';
|
||||||
|
|
||||||
import { DeepLTranslator } from '@/translators/DeepLTranslator.ts';
|
import { DeepLTranslator } from './DeepLTranslator.ts';
|
||||||
import { getLanguage } from '@/test.ts';
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
deeplBaseUrl: baseUrl,
|
deeplBaseUrl: baseUrl,
|
||||||
|
|
@ -28,9 +28,9 @@ Deno.test('DeepL translation with source language omitted', {
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(data.source_lang, 'pt');
|
assertEquals(data.source_lang, 'pt');
|
||||||
assertEquals(getLanguage(data.results[0]), 'en');
|
assertEquals(detectLanguage(data.results[0], 0), 'en');
|
||||||
assertEquals(getLanguage(data.results[1]), 'en');
|
assertEquals(detectLanguage(data.results[1], 0), 'en');
|
||||||
assertEquals(getLanguage(data.results[2]), 'en');
|
assertEquals(detectLanguage(data.results[2], 0), 'en');
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test('DeepL translation with source language set', {
|
Deno.test('DeepL translation with source language set', {
|
||||||
|
|
@ -49,9 +49,9 @@ Deno.test('DeepL translation with source language set', {
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(data.source_lang, 'pt');
|
assertEquals(data.source_lang, 'pt');
|
||||||
assertEquals(getLanguage(data.results[0]), 'en');
|
assertEquals(detectLanguage(data.results[0], 0), 'en');
|
||||||
assertEquals(getLanguage(data.results[1]), 'en');
|
assertEquals(detectLanguage(data.results[1], 0), 'en');
|
||||||
assertEquals(getLanguage(data.results[2]), 'en');
|
assertEquals(detectLanguage(data.results[2], 0), 'en');
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("DeepL translation doesn't alter Nostr URIs", {
|
Deno.test("DeepL translation doesn't alter Nostr URIs", {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { LanguageCode } from 'iso-639-1';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { DittoTranslator } from '@/interfaces/DittoTranslator.ts';
|
import { languageSchema } from './schema.ts';
|
||||||
import { languageSchema } from '@/schema.ts';
|
|
||||||
|
import type { LanguageCode } from 'iso-639-1';
|
||||||
|
import type { DittoTranslator } from './DittoTranslator.ts';
|
||||||
|
|
||||||
interface DeepLTranslatorOpts {
|
interface DeepLTranslatorOpts {
|
||||||
/** DeepL base URL to use. Default: 'https://api.deepl.com' */
|
/** DeepL base URL to use. Default: 'https://api.deepl.com' */
|
||||||
|
|
@ -31,7 +32,7 @@ export class DeepLTranslator implements DittoTranslator {
|
||||||
source: LanguageCode | undefined,
|
source: LanguageCode | undefined,
|
||||||
dest: LanguageCode,
|
dest: LanguageCode,
|
||||||
opts?: { signal?: AbortSignal },
|
opts?: { signal?: AbortSignal },
|
||||||
) {
|
): Promise<{ results: string[]; source_lang: LanguageCode }> {
|
||||||
const { translations } = await this.translateMany(texts, source, dest, opts);
|
const { translations } = await this.translateMany(texts, source, dest, opts);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { DittoConf } from '@ditto/conf';
|
import { DittoConf } from '@ditto/conf';
|
||||||
|
import { detectLanguage } from '@ditto/lang';
|
||||||
import { assertEquals } from '@std/assert';
|
import { assertEquals } from '@std/assert';
|
||||||
|
|
||||||
import { LibreTranslateTranslator } from '@/translators/LibreTranslateTranslator.ts';
|
import { LibreTranslateTranslator } from './LibreTranslateTranslator.ts';
|
||||||
import { getLanguage } from '@/test.ts';
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
libretranslateBaseUrl: baseUrl,
|
libretranslateBaseUrl: baseUrl,
|
||||||
|
|
@ -28,9 +28,9 @@ Deno.test('LibreTranslate translation with source language omitted', {
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(data.source_lang, 'pt');
|
assertEquals(data.source_lang, 'pt');
|
||||||
assertEquals(getLanguage(data.results[0]), 'ca');
|
assertEquals(detectLanguage(data.results[0], 0), 'ca');
|
||||||
assertEquals(getLanguage(data.results[1]), 'ca');
|
assertEquals(detectLanguage(data.results[1], 0), 'ca');
|
||||||
assertEquals(getLanguage(data.results[2]), 'ca');
|
assertEquals(detectLanguage(data.results[2], 0), 'ca');
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test('LibreTranslate translation with source language set', {
|
Deno.test('LibreTranslate translation with source language set', {
|
||||||
|
|
@ -49,7 +49,7 @@ Deno.test('LibreTranslate translation with source language set', {
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(data.source_lang, 'pt');
|
assertEquals(data.source_lang, 'pt');
|
||||||
assertEquals(getLanguage(data.results[0]), 'ca');
|
assertEquals(detectLanguage(data.results[0], 0), 'ca');
|
||||||
assertEquals(getLanguage(data.results[1]), 'ca');
|
assertEquals(detectLanguage(data.results[1], 0), 'ca');
|
||||||
assertEquals(getLanguage(data.results[2]), 'ca');
|
assertEquals(detectLanguage(data.results[2], 0), 'ca');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { LanguageCode } from 'iso-639-1';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { DittoTranslator } from '@/interfaces/DittoTranslator.ts';
|
import { languageSchema } from './schema.ts';
|
||||||
import { languageSchema } from '@/schema.ts';
|
|
||||||
|
import type { LanguageCode } from 'iso-639-1';
|
||||||
|
import type { DittoTranslator } from './DittoTranslator.ts';
|
||||||
|
|
||||||
interface LibreTranslateTranslatorOpts {
|
interface LibreTranslateTranslatorOpts {
|
||||||
/** Libretranslate endpoint to use. Default: 'https://libretranslate.com' */
|
/** Libretranslate endpoint to use. Default: 'https://libretranslate.com' */
|
||||||
|
|
@ -31,7 +32,7 @@ export class LibreTranslateTranslator implements DittoTranslator {
|
||||||
source: LanguageCode | undefined,
|
source: LanguageCode | undefined,
|
||||||
dest: LanguageCode,
|
dest: LanguageCode,
|
||||||
opts?: { signal?: AbortSignal },
|
opts?: { signal?: AbortSignal },
|
||||||
) {
|
): Promise<{ results: string[]; source_lang: LanguageCode }> {
|
||||||
const translations = await Promise.all(
|
const translations = await Promise.all(
|
||||||
texts.map((text) => this.translateOne(text, source, dest, 'html', { signal: opts?.signal })),
|
texts.map((text) => this.translateOne(text, source, dest, 'html', { signal: opts?.signal })),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
export { DeepLTranslator } from './DeepLTranslator.ts';
|
export { DeepLTranslator } from './DeepLTranslator.ts';
|
||||||
export { LibreTranslateTranslator } from './LibreTranslateTranslator.ts';
|
export { LibreTranslateTranslator } from './LibreTranslateTranslator.ts';
|
||||||
|
|
||||||
export type { LanguageCode } from 'iso-639-1';
|
|
||||||
export type { DittoTranslator } from './DittoTranslator.ts';
|
export type { DittoTranslator } from './DittoTranslator.ts';
|
||||||
|
|
|
||||||
8
packages/translators/schema.ts
Normal file
8
packages/translators/schema.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import ISO6391 from 'iso-639-1';
|
||||||
|
import z from 'zod';
|
||||||
|
|
||||||
|
/** Value is a ISO-639-1 language code. */
|
||||||
|
export const languageSchema = z.string().refine(
|
||||||
|
(val) => ISO6391.validate(val),
|
||||||
|
{ message: 'Not a valid language in ISO-639-1 format' },
|
||||||
|
);
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
|
||||||
import { NUploader } from '@nostrify/nostrify';
|
|
||||||
import { crypto } from '@std/crypto';
|
import { crypto } from '@std/crypto';
|
||||||
import { encodeHex } from '@std/encoding/hex';
|
import { encodeHex } from '@std/encoding/hex';
|
||||||
import { extensionsByType } from '@std/media-types';
|
import { extensionsByType } from '@std/media-types';
|
||||||
|
|
||||||
|
import type { NUploader } from '@nostrify/nostrify';
|
||||||
|
|
||||||
export interface DenoUploaderOpts {
|
export interface DenoUploaderOpts {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
dir: string;
|
dir: string;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { NUploader } from '@nostrify/nostrify';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import type { NUploader } from '@nostrify/nostrify';
|
||||||
|
|
||||||
export interface IPFSUploaderOpts {
|
export interface IPFSUploaderOpts {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
apiUrl?: string;
|
apiUrl?: string;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
|
||||||
import { S3Client } from '@bradenmacdonald/s3-lite-client';
|
import { S3Client } from '@bradenmacdonald/s3-lite-client';
|
||||||
import { NUploader } from '@nostrify/nostrify';
|
|
||||||
import { crypto } from '@std/crypto';
|
import { crypto } from '@std/crypto';
|
||||||
import { encodeHex } from '@std/encoding/hex';
|
import { encodeHex } from '@std/encoding/hex';
|
||||||
import { extensionsByType } from '@std/media-types';
|
import { extensionsByType } from '@std/media-types';
|
||||||
|
|
||||||
|
import type { NUploader } from '@nostrify/nostrify';
|
||||||
|
|
||||||
export interface S3UploaderOpts {
|
export interface S3UploaderOpts {
|
||||||
endPoint: string;
|
endPoint: string;
|
||||||
region: string;
|
region: string;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@ditto/uploaders",
|
"name": "@ditto/uploaders",
|
||||||
|
"version": "1.1.0",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./mod.ts"
|
".": "./mod.ts"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue