46 lines
2.4 KiB
JavaScript
46 lines
2.4 KiB
JavaScript
import { renderPrompt, ACTION_GROUPS } from './actions.js';
|
|
import { normalizeLanguage } from './settings.js';
|
|
import { serializePrompt, MAX_URL_CHARS } from './build-url.js';
|
|
|
|
const IDS = new Set([...Object.values(ACTION_GROUPS).flat(), 'translate']);
|
|
const error = message => ({ kind: 'error', message });
|
|
|
|
export function prepareAction(request) {
|
|
if (!IDS.has(request.actionId)) return error('This action is no longer available. Please try again.');
|
|
const source = String(request.source ?? '').trim();
|
|
if (!source && request.actionId !== 'ask') return error('There is no text or URL to send. Please select it again.');
|
|
const isUrl = request.actionId.includes('-');
|
|
if (isUrl) {
|
|
try {
|
|
const parsed = new URL(source);
|
|
if (!['http:', 'https:'].includes(parsed.protocol) || parsed.username || parsed.password) throw new Error();
|
|
} catch {
|
|
return error('This action supports only HTTP or HTTPS links without embedded login credentials.');
|
|
}
|
|
}
|
|
let language = normalizeLanguage(request.language);
|
|
if (request.actionId === 'translate') {
|
|
if (!language && request.settings.translationMode === 'preferred') language = normalizeLanguage(request.settings.translationLanguage);
|
|
if (!language) return { kind: 'language' };
|
|
}
|
|
const resolved = { ...request, language };
|
|
const serialize = text => serializePrompt(request.settings, renderPrompt(resolved, text));
|
|
const url = serialize(source);
|
|
if (url.length <= MAX_URL_CHARS) return { kind: 'ready', url };
|
|
if (isUrl) return error('This URL is too long to send intact. No part of it has been sent.');
|
|
const marker = '\n[Selected text shortened]';
|
|
if (serialize(marker).length >= MAX_URL_CHARS) return error('The prompt instructions are too long. Shorten your prompt template and try again.');
|
|
const points = Array.from(source);
|
|
let low = 0, high = points.length;
|
|
while (low < high) {
|
|
const mid = Math.ceil((low + high) / 2);
|
|
if (serialize(points.slice(0, mid).join('') + marker).length <= MAX_URL_CHARS) low = mid;
|
|
else high = mid - 1;
|
|
}
|
|
let kept = points.slice(0, low).join('');
|
|
const boundary = kept.search(/\s+\S*$/u);
|
|
if (boundary > kept.length * 0.9) kept = kept.slice(0, boundary);
|
|
if (!kept.trim()) return error('The prompt leaves no room for the selected text. Shorten the prompt template and try again.');
|
|
return { kind: 'shortened', url: serialize(kept + marker) };
|
|
}
|