refactor: Remove hardcoded values
All checks were successful
Queue Release Build / prepare (push) Successful in 2m28s
Deploy Web Apps / deploy (push) Successful in 7m58s
Queue Release Build / build-linux (push) Successful in 46m59s
Queue Release Build / build-windows (push) Successful in 26m2s
Queue Release Build / finalize (push) Successful in 23s
All checks were successful
Queue Release Build / prepare (push) Successful in 2m28s
Deploy Web Apps / deploy (push) Successful in 7m58s
Queue Release Build / build-linux (push) Successful in 46m59s
Queue Release Build / build-windows (push) Successful in 26m2s
Queue Release Build / finalize (push) Successful in 23s
This commit is contained in:
@@ -5,9 +5,10 @@ import {
|
||||
input
|
||||
} from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { environment } from '../../../../../../../../environments/environment';
|
||||
import { extractYoutubeVideoId } from '../../../../../domain/rules/link-embed.rules';
|
||||
|
||||
const YOUTUBE_EMBED_FALLBACK_ORIGIN = 'https://toju.app';
|
||||
const YOUTUBE_EMBED_FALLBACK_ORIGIN = environment.publicOrigin;
|
||||
|
||||
function resolveYoutubeClientOrigin(): string {
|
||||
if (typeof window === 'undefined') {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { environment } from '../../../../../environments/environment';
|
||||
|
||||
export interface ExperimentalVlcPlayerOptions {
|
||||
container: HTMLElement;
|
||||
@@ -23,7 +24,7 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
const VLC_RUNTIME_SCRIPT_URL = '/vlcjs/metoyou-vlc-player.js';
|
||||
const VLC_RUNTIME_SCRIPT_URL = environment.experimentalMedia.vlcRuntimeScriptUrl;
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ExperimentalVlcRuntimeService {
|
||||
@@ -60,6 +61,7 @@ export class ExperimentalVlcRuntimeService {
|
||||
|
||||
script.src = VLC_RUNTIME_SCRIPT_URL;
|
||||
script.async = true;
|
||||
|
||||
script.onload = () => {
|
||||
const runtime = this.document.defaultView?.MetoYouVlcJs;
|
||||
|
||||
@@ -70,6 +72,7 @@ export class ExperimentalVlcRuntimeService {
|
||||
|
||||
resolve(runtime);
|
||||
};
|
||||
|
||||
script.onerror = () => reject(new Error(`The experimental VLC.js runtime was not found at ${VLC_RUNTIME_SCRIPT_URL}.`));
|
||||
|
||||
this.document.head.appendChild(script);
|
||||
|
||||
@@ -10,7 +10,7 @@ The standalone plugin store is available from the title bar Plugins button, the
|
||||
|
||||
The plugin manager UI is split between Settings -> Client plugins for global client plugins and Settings -> Server -> Server plugins for chat-server plugins. The two pages filter by manifest `scope` and include installed plugins, capability grant toggles, per-plugin activate/reload/unload actions, runtime logs, extension-point counts, server requirements, generated settings, and docs.
|
||||
|
||||
The Store tab consumes user-managed HTTP(S), `file://`, or absolute local-path source manifests. Local-path sources and entrypoints are read through the Electron desktop file bridge. A source manifest can expose a `plugins` array whose entries include `id`, `title`, `description`, `version`, `scope`, `author`/`authors`, `image`/`imageUrl`, `github`/`githubUrl`, `install`/`installUrl`/`manifestUrl`, `bundle`/`bundleUrl`, and `readme`/`readmeUrl`. Installing a `scope: "server"` plugin fetches the linked plugin manifest, validates it, registers it with the client registry, and persists the basic install metadata as a server plugin requirement. When a different user joins that server, required plugins block the join until the user accepts the download; optional and recommended plugins are offered as selectable downloads and can be skipped. Once a server has local server-scoped plugins installed, the title bar shows a compact Server plugins button for that server. Installing a `scope: "client"` plugin persists it locally for the current desktop/browser client.
|
||||
The Store tab consumes user-managed HTTP(S), `file://`, or absolute local-path source manifests. New users and legacy source lists are seeded with the official Toju plugin repository at `https://raw.githubusercontent.com/Myxelium/official-toju-plugin-repository/refs/heads/master/plugin-source.json`, while source removal remains persisted after migration. Local-path sources and entrypoints are read through the Electron desktop file bridge. A source manifest can expose a `plugins` array whose entries include `id`, `title`, `description`, `version`, `scope`, `author`/`authors`, `image`/`imageUrl`, `github`/`githubUrl`, `install`/`installUrl`/`manifestUrl`, `bundle`/`bundleUrl`, and `readme`/`readmeUrl`. Installing a `scope: "server"` plugin fetches the linked plugin manifest, validates it, registers it with the client registry, and persists the basic install metadata as a server plugin requirement. When a different user joins that server, required plugins block the join until the user accepts the download; optional and recommended plugins are offered as selectable downloads and can be skipped. Once a server has local server-scoped plugins installed, the title bar shows a compact Server plugins button for that server. Installing a `scope: "client"` plugin persists it locally for the current desktop/browser client.
|
||||
|
||||
Store plugins can be published as cached browser bundles by adding `bundle` or `bundleUrl` to the source manifest entry. The bundle is a browser-safe ESM JavaScript file. During install, Electron downloads the bundle into app data under `plugin-bundles/<plugin-id>/<version>/main.js`, writes a cached manifest next to it, and registers the plugin from that local cached manifest path. If no bundle URL is provided and the manifest entrypoint is a relative browser module, Electron caches that entrypoint path instead. Browser-only clients still load directly from the source URL; the renderer CSP allows HTTP(S), `file://` via local cache, and blob-backed plugin entrypoints. Saved store sources refresh during app bootstrap; when a source advertises a higher version for an installed plugin, the store attempts to update the local cached bundle and persisted install metadata automatically.
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Injector } from '@angular/core';
|
||||
import { environment } from '../../../../../environments/environment';
|
||||
import type { TojuPluginManifest } from '../../../../shared-kernel';
|
||||
import { ElectronBridgeService } from '../../../../core/platform/electron/electron-bridge.service';
|
||||
import { PluginStoreService } from './plugin-store.service';
|
||||
@@ -6,8 +7,11 @@ import { PluginHostService } from './plugin-host.service';
|
||||
import { PluginDesktopStateService } from './plugin-desktop-state.service';
|
||||
import { PluginRequirementService } from './plugin-requirement.service';
|
||||
import { PluginRegistryService } from './plugin-registry.service';
|
||||
import { PluginCapabilityService } from './plugin-capability.service';
|
||||
import type { PluginStoreEntry } from '../../domain/models/plugin-store.models';
|
||||
|
||||
const OFFICIAL_PLUGIN_SOURCE_URL = environment.pluginStore.defaultSourceUrls[0];
|
||||
|
||||
describe('PluginStoreService', () => {
|
||||
let fetchMock: ReturnType<typeof vi.fn>;
|
||||
let registerLocalManifest: ReturnType<typeof vi.fn>;
|
||||
@@ -36,42 +40,79 @@ describe('PluginStoreService', () => {
|
||||
});
|
||||
|
||||
it('loads plugin entries from source manifests and resolves relative links', async () => {
|
||||
fetchMock.mockResolvedValueOnce(jsonResponse({
|
||||
plugins: [
|
||||
{
|
||||
author: 'Ada Example',
|
||||
description: 'Adds better channel tools.',
|
||||
github: 'https://github.com/example/better-channels',
|
||||
id: 'example.better-channels',
|
||||
image: './images/better.png',
|
||||
install: './better/toju-plugin.json',
|
||||
readme: './better/README.md',
|
||||
title: 'Better Channels',
|
||||
version: '1.2.0'
|
||||
}
|
||||
],
|
||||
title: 'Example Plugins'
|
||||
}));
|
||||
mockFetchResponses(fetchMock, {
|
||||
'https://plugins.example.test/index.json': jsonResponse({
|
||||
plugins: [
|
||||
{
|
||||
author: 'Ada Example',
|
||||
description: 'Adds better channel tools.',
|
||||
github: 'https://github.com/example/better-channels',
|
||||
id: 'example.better-channels',
|
||||
image: './images/better.png',
|
||||
install: './better/toju-plugin.json',
|
||||
readme: './better/README.md',
|
||||
title: 'Better Channels',
|
||||
version: '1.2.0'
|
||||
}
|
||||
],
|
||||
title: 'Example Plugins'
|
||||
})
|
||||
});
|
||||
|
||||
const service = createService(registerLocalManifest, unregister);
|
||||
|
||||
await service.addSourceUrl('https://plugins.example.test/index.json#latest');
|
||||
|
||||
expect(service.sourceUrls()).toEqual(['https://plugins.example.test/index.json']);
|
||||
expect(service.sources()[0]?.title).toBe('Example Plugins');
|
||||
expect(service.availablePlugins()).toEqual([
|
||||
expect(service.sourceUrls()).toEqual([OFFICIAL_PLUGIN_SOURCE_URL, 'https://plugins.example.test/index.json']);
|
||||
|
||||
expect(service.sources().some((source) => source.title === 'Example Plugins')).toBe(true);
|
||||
expect(service.availablePlugins()).toContainEqual(expect.objectContaining({
|
||||
author: 'Ada Example',
|
||||
githubUrl: 'https://github.com/example/better-channels',
|
||||
id: 'example.better-channels',
|
||||
imageUrl: 'https://plugins.example.test/images/better.png',
|
||||
installUrl: 'https://plugins.example.test/better/toju-plugin.json',
|
||||
readmeUrl: 'https://plugins.example.test/better/README.md',
|
||||
sourceTitle: 'Example Plugins',
|
||||
title: 'Better Channels',
|
||||
version: '1.2.0'
|
||||
}));
|
||||
});
|
||||
|
||||
it('seeds the official plugin repository for new users', () => {
|
||||
const service = createService(registerLocalManifest, unregister);
|
||||
|
||||
expect(service.sourceUrls()).toEqual([OFFICIAL_PLUGIN_SOURCE_URL]);
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
OFFICIAL_PLUGIN_SOURCE_URL,
|
||||
expect.objectContaining({
|
||||
author: 'Ada Example',
|
||||
githubUrl: 'https://github.com/example/better-channels',
|
||||
id: 'example.better-channels',
|
||||
imageUrl: 'https://plugins.example.test/images/better.png',
|
||||
installUrl: 'https://plugins.example.test/better/toju-plugin.json',
|
||||
readmeUrl: 'https://plugins.example.test/better/README.md',
|
||||
sourceTitle: 'Example Plugins',
|
||||
title: 'Better Channels',
|
||||
version: '1.2.0'
|
||||
headers: { Accept: 'application/json' }
|
||||
})
|
||||
]);
|
||||
);
|
||||
});
|
||||
|
||||
it('adds the official plugin repository when loading legacy source lists', () => {
|
||||
storage.setItem('metoyou_plugin_store', JSON.stringify({
|
||||
installedPlugins: [],
|
||||
schemaVersion: 1,
|
||||
sourceUrls: ['https://plugins.example.test/index.json']
|
||||
}));
|
||||
|
||||
const service = createService(registerLocalManifest, unregister);
|
||||
|
||||
expect(service.sourceUrls()).toEqual([OFFICIAL_PLUGIN_SOURCE_URL, 'https://plugins.example.test/index.json']);
|
||||
});
|
||||
|
||||
it('keeps user-removed default sources removed after schema migration', () => {
|
||||
storage.setItem('metoyou_plugin_store', JSON.stringify({
|
||||
installedPlugins: [],
|
||||
schemaVersion: 2,
|
||||
sourceUrls: ['https://plugins.example.test/index.json']
|
||||
}));
|
||||
|
||||
const service = createService(registerLocalManifest, unregister);
|
||||
|
||||
expect(service.sourceUrls()).toEqual(['https://plugins.example.test/index.json']);
|
||||
});
|
||||
|
||||
it('accepts local source manifest paths and resolves relative file links', async () => {
|
||||
@@ -94,9 +135,10 @@ describe('PluginStoreService', () => {
|
||||
|
||||
await service.addSourceUrl('/home/ludde/Desktop/TestPlugin/plugin-source.json');
|
||||
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
expect(fetchMock).not.toHaveBeenCalledWith('/home/ludde/Desktop/TestPlugin/plugin-source.json', expect.anything());
|
||||
expect(readFile).toHaveBeenCalledWith('/home/ludde/Desktop/TestPlugin/plugin-source.json');
|
||||
expect(service.sourceUrls()).toEqual(['file:///home/ludde/Desktop/TestPlugin/plugin-source.json']);
|
||||
expect(service.sourceUrls()).toEqual([OFFICIAL_PLUGIN_SOURCE_URL, 'file:///home/ludde/Desktop/TestPlugin/plugin-source.json']);
|
||||
|
||||
expect(service.availablePlugins()).toEqual([
|
||||
expect.objectContaining({
|
||||
id: 'example.local-plugin',
|
||||
@@ -112,7 +154,9 @@ describe('PluginStoreService', () => {
|
||||
const manifest = createManifest({ version: '1.0.0' });
|
||||
const plugin = createStoreEntry({ version: '1.0.0' });
|
||||
|
||||
fetchMock.mockResolvedValueOnce(jsonResponse(manifest));
|
||||
mockFetchResponses(fetchMock, {
|
||||
[plugin.installUrl ?? '']: jsonResponse(manifest)
|
||||
});
|
||||
|
||||
const service = createService(registerLocalManifest, unregister);
|
||||
|
||||
@@ -141,9 +185,10 @@ describe('PluginStoreService', () => {
|
||||
writeFile: vi.fn(async () => true)
|
||||
};
|
||||
|
||||
fetchMock
|
||||
.mockResolvedValueOnce(jsonResponse(manifest))
|
||||
.mockResolvedValueOnce(textResponse('export function activate() {}'));
|
||||
mockFetchResponses(fetchMock, {
|
||||
[plugin.bundleUrl ?? '']: textResponse('export function activate() {}'),
|
||||
[plugin.installUrl ?? '']: jsonResponse(manifest)
|
||||
});
|
||||
|
||||
const service = createService(registerLocalManifest, unregister, electronApi);
|
||||
|
||||
@@ -171,7 +216,9 @@ describe('PluginStoreService', () => {
|
||||
it('loads plugin readmes as markdown text', async () => {
|
||||
const plugin = createStoreEntry({ readmeUrl: 'https://plugins.example.test/better/README.md' });
|
||||
|
||||
fetchMock.mockResolvedValueOnce(textResponse('# Better Channels'));
|
||||
mockFetchResponses(fetchMock, {
|
||||
[plugin.readmeUrl ?? '']: textResponse('# Better Channels')
|
||||
});
|
||||
|
||||
const service = createService(registerLocalManifest, unregister);
|
||||
const readme = await service.loadReadme(plugin);
|
||||
@@ -185,6 +232,21 @@ describe('PluginStoreService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
function mockFetchResponses(fetchMock: ReturnType<typeof vi.fn>, responses: Record<string, Response>): void {
|
||||
fetchMock.mockImplementation(async (url: RequestInfo | URL) => {
|
||||
const requestUrl = typeof url === 'string'
|
||||
? url
|
||||
: url instanceof URL
|
||||
? url.toString()
|
||||
: url.url;
|
||||
|
||||
return responses[requestUrl]
|
||||
?? (requestUrl === OFFICIAL_PLUGIN_SOURCE_URL
|
||||
? jsonResponse({ plugins: [], title: 'Official Toju Plugins' })
|
||||
: textResponse(''));
|
||||
});
|
||||
}
|
||||
|
||||
function createService(
|
||||
registerLocalManifest: ReturnType<typeof vi.fn>,
|
||||
unregister: ReturnType<typeof vi.fn>,
|
||||
@@ -220,6 +282,12 @@ function createService(
|
||||
writeJson: vi.fn(async () => undefined)
|
||||
}
|
||||
},
|
||||
{
|
||||
provide: PluginCapabilityService,
|
||||
useValue: {
|
||||
grantAll: vi.fn()
|
||||
}
|
||||
},
|
||||
{
|
||||
provide: PluginRegistryService,
|
||||
useValue: { unregister }
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { environment } from '../../../../../environments/environment';
|
||||
import { RealtimeSessionFacade } from '../../../../core/realtime';
|
||||
import { getUserScopedStorageKey } from '../../../../core/storage/current-user-storage';
|
||||
import { ElectronBridgeService } from '../../../../core/platform/electron/electron-bridge.service';
|
||||
@@ -44,14 +45,11 @@ import { PluginDesktopStateService } from './plugin-desktop-state.service';
|
||||
import { PluginRequirementService } from './plugin-requirement.service';
|
||||
import { PluginRegistryService } from './plugin-registry.service';
|
||||
|
||||
const STORE_SCHEMA_VERSION = 1;
|
||||
const STORE_SCHEMA_VERSION = 2;
|
||||
const STORAGE_KEY_PLUGIN_STORE = 'metoyou_plugin_store';
|
||||
const STORAGE_KEY_SERVER_PLUGIN_INSTALLS = 'metoyou_server_plugin_installs';
|
||||
const PLUGIN_CACHE_DIR = 'plugin-bundles';
|
||||
const DEFAULT_STORE_STATE: PersistedPluginStoreState = {
|
||||
installedPlugins: [],
|
||||
sourceUrls: []
|
||||
};
|
||||
const DEFAULT_PLUGIN_SOURCE_URLS = [...environment.pluginStore.defaultSourceUrls];
|
||||
|
||||
export interface PluginStoreInstallOptions {
|
||||
activate?: boolean;
|
||||
@@ -953,12 +951,12 @@ export class PluginStoreService {
|
||||
const raw = localStorage.getItem(getUserScopedStorageKey(STORAGE_KEY_PLUGIN_STORE));
|
||||
|
||||
if (!raw) {
|
||||
return { ...DEFAULT_STORE_STATE };
|
||||
return createDefaultStoreState();
|
||||
}
|
||||
|
||||
return normalizePersistedState(JSON.parse(raw) as unknown);
|
||||
} catch {
|
||||
return { ...DEFAULT_STORE_STATE };
|
||||
return createDefaultStoreState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1132,22 +1130,63 @@ function readPluginInstallScope(record: Record<string, unknown>): TojuPluginInst
|
||||
|
||||
function normalizePersistedState(value: unknown): PersistedPluginStoreState {
|
||||
if (!isRecord(value)) {
|
||||
return { ...DEFAULT_STORE_STATE };
|
||||
return createDefaultStoreState();
|
||||
}
|
||||
|
||||
const schemaVersion = typeof value['schemaVersion'] === 'number' ? value['schemaVersion'] : 0;
|
||||
const sourceUrls = Array.isArray(value['sourceUrls'])
|
||||
? normalizePluginSourceUrls(value['sourceUrls'])
|
||||
: [];
|
||||
|
||||
return {
|
||||
installedPlugins: Array.isArray(value['installedPlugins'])
|
||||
? value['installedPlugins'].filter(isInstalledStorePlugin)
|
||||
: [],
|
||||
sourceUrls: Array.isArray(value['sourceUrls'])
|
||||
? value['sourceUrls']
|
||||
.filter((entry): entry is string => typeof entry === 'string')
|
||||
.map((entry) => normalizeOptionalSourceUrl(entry))
|
||||
.filter((entry): entry is string => !!entry)
|
||||
: []
|
||||
schemaVersion: STORE_SCHEMA_VERSION,
|
||||
sourceUrls: schemaVersion < STORE_SCHEMA_VERSION
|
||||
? mergePluginSourceUrls(DEFAULT_PLUGIN_SOURCE_URLS, sourceUrls)
|
||||
: sourceUrls
|
||||
};
|
||||
}
|
||||
|
||||
function createDefaultStoreState(): PersistedPluginStoreState {
|
||||
return {
|
||||
installedPlugins: [],
|
||||
schemaVersion: STORE_SCHEMA_VERSION,
|
||||
sourceUrls: [...DEFAULT_PLUGIN_SOURCE_URLS]
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePluginSourceUrls(sourceUrls: unknown[]): string[] {
|
||||
const normalizedSourceUrls: string[] = [];
|
||||
|
||||
for (const entry of sourceUrls) {
|
||||
if (typeof entry !== 'string') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sourceUrl = normalizeOptionalSourceUrl(entry);
|
||||
|
||||
if (sourceUrl && !normalizedSourceUrls.includes(sourceUrl)) {
|
||||
normalizedSourceUrls.push(sourceUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return normalizedSourceUrls;
|
||||
}
|
||||
|
||||
function mergePluginSourceUrls(defaultSourceUrls: string[], sourceUrls: string[]): string[] {
|
||||
const mergedSourceUrls: string[] = [];
|
||||
|
||||
for (const sourceUrl of defaultSourceUrls.concat(sourceUrls)) {
|
||||
if (!mergedSourceUrls.includes(sourceUrl)) {
|
||||
mergedSourceUrls.push(sourceUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return mergedSourceUrls;
|
||||
}
|
||||
|
||||
function normalizePersistedServerPluginInstallState(value: unknown): { servers: Record<string, InstalledStorePlugin[]> } {
|
||||
if (!isRecord(value) || !isRecord(value['servers'])) {
|
||||
return { servers: {} };
|
||||
|
||||
@@ -48,6 +48,7 @@ export interface PluginStoreReadme {
|
||||
|
||||
export interface PersistedPluginStoreState {
|
||||
installedPlugins: InstalledStorePlugin[];
|
||||
schemaVersion?: number;
|
||||
sourceUrls: string[];
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
computed,
|
||||
type Signal
|
||||
} from '@angular/core';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { STORAGE_KEY_ICE_SERVERS } from '../../core/constants';
|
||||
import { ICE_SERVERS } from './realtime.constants';
|
||||
|
||||
export interface IceServerEntry {
|
||||
id: string;
|
||||
@@ -15,7 +15,7 @@ export interface IceServerEntry {
|
||||
credential?: string;
|
||||
}
|
||||
|
||||
const DEFAULT_ENTRIES: IceServerEntry[] = ICE_SERVERS.map((server, index) => ({
|
||||
const DEFAULT_ENTRIES: IceServerEntry[] = environment.realtime.defaultIceServers.map((server, index) => ({
|
||||
id: `default-stun-${index}`,
|
||||
type: 'stun' as const,
|
||||
urls: Array.isArray(server.urls) ? server.urls[0] : server.urls
|
||||
|
||||
@@ -5,14 +5,6 @@ import type { LatencyProfile } from '../../shared-kernel';
|
||||
* Centralised here so nothing is hard-coded inline.
|
||||
*/
|
||||
|
||||
export const ICE_SERVERS: RTCIceServer[] = [
|
||||
{ urls: 'stun:stun.l.google.com:19302' },
|
||||
{ urls: 'stun:stun1.l.google.com:19302' },
|
||||
{ urls: 'stun:stun2.l.google.com:19302' },
|
||||
{ urls: 'stun:stun3.l.google.com:19302' },
|
||||
{ urls: 'stun:stun4.l.google.com:19302' }
|
||||
];
|
||||
|
||||
/** Base delay (ms) for exponential backoff on signaling reconnect */
|
||||
export const SIGNALING_RECONNECT_BASE_DELAY_MS = 1_000;
|
||||
/** Maximum delay (ms) between signaling reconnect attempts */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
publicOrigin: 'https://toju.app',
|
||||
defaultServers: [
|
||||
{
|
||||
key: 'toju-primary',
|
||||
@@ -12,5 +13,20 @@ export const environment = {
|
||||
url: 'https://signal-sweden.toju.app'
|
||||
}
|
||||
],
|
||||
defaultServerUrl: 'https://signal.toju.app'
|
||||
defaultServerUrl: 'https://signal.toju.app',
|
||||
experimentalMedia: {
|
||||
vlcRuntimeScriptUrl: '/vlcjs/metoyou-vlc-player.js'
|
||||
},
|
||||
pluginStore: {
|
||||
defaultSourceUrls: ['https://raw.githubusercontent.com/Myxelium/official-toju-plugin-repository/refs/heads/master/plugin-source.json']
|
||||
},
|
||||
realtime: {
|
||||
defaultIceServers: [
|
||||
{ urls: 'stun:stun.l.google.com:19302' },
|
||||
{ urls: 'stun:stun1.l.google.com:19302' },
|
||||
{ urls: 'stun:stun2.l.google.com:19302' },
|
||||
{ urls: 'stun:stun3.l.google.com:19302' },
|
||||
{ urls: 'stun:stun4.l.google.com:19302' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export const environment = {
|
||||
production: false,
|
||||
publicOrigin: 'https://toju.app',
|
||||
defaultServers: [
|
||||
{
|
||||
key: 'default',
|
||||
@@ -17,5 +18,20 @@ export const environment = {
|
||||
url: 'https://signal-sweden.toju.app'
|
||||
}
|
||||
],
|
||||
defaultServerUrl: 'https://46.59.68.77:3001'
|
||||
defaultServerUrl: 'https://46.59.68.77:3001',
|
||||
experimentalMedia: {
|
||||
vlcRuntimeScriptUrl: '/vlcjs/metoyou-vlc-player.js'
|
||||
},
|
||||
pluginStore: {
|
||||
defaultSourceUrls: ['https://raw.githubusercontent.com/Myxelium/official-toju-plugin-repository/refs/heads/master/plugin-source.json']
|
||||
},
|
||||
realtime: {
|
||||
defaultIceServers: [
|
||||
{ urls: 'stun:stun.l.google.com:19302' },
|
||||
{ urls: 'stun:stun1.l.google.com:19302' },
|
||||
{ urls: 'stun:stun2.l.google.com:19302' },
|
||||
{ urls: 'stun:stun3.l.google.com:19302' },
|
||||
{ urls: 'stun:stun4.l.google.com:19302' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user