wizards 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/runtime/dist/agents/architect.js +13 -26
- package/apps/runtime/dist/agents/studio-assistant.js +19 -22
- package/apps/runtime/dist/agents/subscription.js +10 -9
- package/apps/runtime/dist/app.js +9 -7
- package/apps/runtime/dist/assistant/knows.js +10 -9
- package/apps/runtime/dist/auth/index.js +7 -0
- package/apps/runtime/dist/connectors/external.js +3 -3
- package/apps/runtime/dist/connectors/index.js +23 -23
- package/apps/runtime/dist/connectors/via-account.js +6 -6
- package/apps/runtime/dist/documents/parse.js +3 -3
- package/apps/runtime/dist/engine/input.js +11 -11
- package/apps/runtime/dist/engine/requirements.js +7 -8
- package/apps/runtime/dist/engine/runner.js +10 -14
- package/apps/runtime/dist/engine/steps.js +6 -6
- package/apps/runtime/dist/engine/surface.js +2 -2
- package/apps/runtime/dist/film/step.js +5 -5
- package/apps/runtime/dist/harness/apple.js +2 -1
- package/apps/runtime/dist/harness/claude.js +2 -2
- package/apps/runtime/dist/harness/codex.js +2 -2
- package/apps/runtime/dist/harness/model.js +4 -5
- package/apps/runtime/dist/harness/terminal.js +4 -4
- package/apps/runtime/dist/media/conversation.js +18 -35
- package/apps/runtime/dist/media/transcribe.js +2 -1
- package/apps/runtime/dist/model-errors.js +1 -1
- package/apps/runtime/dist/models.js +32 -40
- package/apps/runtime/dist/plugins/runs.js +3 -5
- package/apps/runtime/dist/routes/api.js +9 -9
- package/apps/runtime/dist/routes/lang.js +14 -9
- package/apps/runtime/dist/routes/marketplace.js +6 -1
- package/apps/runtime/dist/routes/runs.js +5 -5
- package/apps/runtime/dist/routes/studio.js +38 -37
- package/apps/runtime/dist/services/access.js +4 -4
- package/apps/runtime/dist/services/architect.js +3 -12
- package/apps/runtime/dist/services/assistant-chats.js +2 -2
- package/apps/runtime/dist/services/brand.js +3 -3
- package/apps/runtime/dist/services/cloud.js +5 -5
- package/apps/runtime/dist/services/errors.js +2 -2
- package/apps/runtime/dist/services/knowledge-model.js +3 -3
- package/apps/runtime/dist/services/marketplace.js +18 -8
- package/apps/runtime/dist/services/package-file.js +9 -11
- package/apps/runtime/dist/services/package.js +8 -9
- package/apps/runtime/dist/services/profile.js +2 -1
- package/apps/runtime/dist/services/project-files.js +13 -13
- package/apps/runtime/dist/services/projects.js +7 -11
- package/apps/runtime/dist/services/runners.js +4 -4
- package/apps/runtime/dist/services/runs.js +7 -10
- package/apps/runtime/dist/services/shares.js +2 -2
- package/apps/runtime/dist/services/site.js +8 -11
- package/apps/runtime/dist/services/space-categories.js +7 -7
- package/apps/runtime/dist/services/space-data.js +20 -20
- package/apps/runtime/dist/services/spaces.js +7 -9
- package/apps/runtime/dist/services/wizards.js +11 -13
- package/apps/runtime/dist/store/index.js +2 -2
- package/apps/runtime/dist/texts.js +195 -0
- package/apps/runtime/dist/tools/plugin.js +7 -3
- package/apps/runtime/dist/widgets/step.js +2 -2
- package/apps/web/dist/assets/AboutDialog-BcTtA42P.js +1 -0
- package/apps/web/dist/assets/{ChangelogDialog-sdSC9eZj.js → ChangelogDialog-DMOWV_Iu.js} +1 -1
- package/apps/web/dist/assets/ChatView-CrnrYHjp.js +10 -0
- package/apps/web/dist/assets/EditorPage-DpEw3eOu.js +3 -0
- package/apps/web/dist/assets/{FlowPreview-B4-ipMdE.js → FlowPreview-CzmH4JUQ.js} +1 -1
- package/apps/web/dist/assets/{Harness-DwI4wFqj.js → Harness-DipH0Vec.js} +2 -2
- package/apps/web/dist/assets/{NewWizardChannels-DkI648G-.js → NewWizardChannels-DShu0PP6.js} +1 -1
- package/apps/web/dist/assets/NewWizardPage-HSa6PNJs.js +7 -0
- package/apps/web/dist/assets/OnboardingPage-CPADMs4c.js +1 -0
- package/apps/web/dist/assets/ProjectPage-DMPcrhgt.js +1 -0
- package/apps/web/dist/assets/PublicRunner-DZ5sWmtg.js +1 -0
- package/apps/web/dist/assets/{ReadOnly-Jvzgyelg.js → ReadOnly-B9xaq_M3.js} +1 -1
- package/apps/web/dist/assets/RunDrawer-9nMGhbSm.js +4 -0
- package/apps/web/dist/assets/{RunnerView-DN4sMYS6.js → RunnerView-NSSP3tc6.js} +1 -1
- package/apps/web/dist/assets/SettingsPage-Dy9MbwQh.js +1 -0
- package/apps/web/dist/assets/SetupPage-kemgI7v5.js +1 -0
- package/apps/web/dist/assets/{SharePage-CmowpiJG.js → SharePage-CQfIdcwy.js} +1 -1
- package/apps/web/dist/assets/{changelog-Cz8fZ-jG.js → changelog-BW40vzI6.js} +1 -1
- package/apps/web/dist/assets/{esm-J06O1nN_.js → esm-BF1nonbH.js} +1 -1
- package/apps/web/dist/assets/index-CnJ4Yzkf.css +1 -0
- package/apps/web/dist/assets/index-DQ9qAB4v.js +14 -0
- package/apps/web/dist/assets/{lock-ChDlFFHO.js → lock-DVvM6IsA.js} +1 -1
- package/apps/web/dist/assets/{phone-Cr7jz_kf.js → phone-3fG1okFs.js} +1 -1
- package/apps/web/dist/assets/{settings-menu-BAwHMXCR.js → settings-menu-D9fbi1Z0.js} +1 -1
- package/apps/web/dist/assets/ui-EuR3jezP.js +134 -0
- package/apps/web/dist/assets/{upload-DcAIMe8d.js → upload-BsMUhEfX.js} +1 -1
- package/apps/web/dist/index.html +3 -3
- package/apps/web/dist/mcp/flow.html +78 -78
- package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +26 -9
- package/node_modules/@engenty-wizards/shared/dist/definition.js +125 -3
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.d.ts +1 -1
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +9 -8
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +6 -6
- package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +78 -205
- package/node_modules/@engenty-wizards/shared/dist/marketplace.js +167 -68
- package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +3 -6
- package/node_modules/@engenty-wizards/shared/dist/projects.js +9 -9
- package/node_modules/@engenty-wizards/shared/dist/providers.d.ts +33 -7
- package/node_modules/@engenty-wizards/shared/dist/providers.js +88 -37
- package/node_modules/@engenty-wizards/shared/dist/run.d.ts +298 -365
- package/node_modules/@engenty-wizards/shared/dist/run.js +582 -240
- package/node_modules/@engenty-wizards/shared/dist/texts.d.ts +36 -0
- package/node_modules/@engenty-wizards/shared/dist/texts.js +46 -0
- package/package.json +1 -1
- package/apps/web/dist/assets/AboutDialog-Ck6_TSVJ.js +0 -1
- package/apps/web/dist/assets/ChatView-S1H9Pcih.js +0 -10
- package/apps/web/dist/assets/EditorPage-BSfJXx4W.js +0 -3
- package/apps/web/dist/assets/NewWizardPage-dumNiSqM.js +0 -7
- package/apps/web/dist/assets/OnboardingPage-BAfHLLNT.js +0 -1
- package/apps/web/dist/assets/ProjectPage-fneLQr6R.js +0 -1
- package/apps/web/dist/assets/PublicRunner-CuxDAXK7.js +0 -1
- package/apps/web/dist/assets/RunDrawer-C_T1I77g.js +0 -4
- package/apps/web/dist/assets/SettingsPage-DjFvKMRz.js +0 -1
- package/apps/web/dist/assets/SetupPage-CzYwVUvh.js +0 -1
- package/apps/web/dist/assets/index-CZFfDGHy.css +0 -1
- package/apps/web/dist/assets/index-DZTDv2pA.js +0 -14
- package/apps/web/dist/assets/ui-C5_NcAmG.js +0 -134
|
@@ -8,7 +8,7 @@ import { createOpenAI } from "@ai-sdk/openai";
|
|
|
8
8
|
import { createReplicate } from "@ai-sdk/replicate";
|
|
9
9
|
import { MODEL_CLASSES, TEXT_CLASSES, } from "@engenty-wizards/shared/definition";
|
|
10
10
|
import { creditsModelOf, isCreditsRef, PROVIDER_IDS, providerInfo, providerOfRef, } from "@engenty-wizards/shared/providers";
|
|
11
|
-
import {
|
|
11
|
+
import { note, saidText } from "@engenty-wizards/shared/run";
|
|
12
12
|
import { generateSpeech, generateText, } from "ai";
|
|
13
13
|
import { accountToken, linkedAccount } from "./auth/account.js";
|
|
14
14
|
import { DeviceModel, deviceThinks } from "./engine/device.js";
|
|
@@ -22,6 +22,7 @@ import { seal, unseal } from "./secrets/crypto.js";
|
|
|
22
22
|
import { vaultDelete, vaultGet, vaultSet } from "./secrets/vault.js";
|
|
23
23
|
import { readSetting, writeSetting } from "./settings.js";
|
|
24
24
|
import { currentTenant, currentTenantOrNull } from "./tenants/tenant.js";
|
|
25
|
+
import { serverText } from "./texts.js";
|
|
25
26
|
export { isHarnessVendor } from "./harness/index.js";
|
|
26
27
|
/**
|
|
27
28
|
* A step names a model class, never a model. Where the class runs is decided here, in this order:
|
|
@@ -234,27 +235,26 @@ function ownRef(cfg, cls) {
|
|
|
234
235
|
}
|
|
235
236
|
/** What a class makes, to say that nothing makes it. */
|
|
236
237
|
const MAKES = {
|
|
237
|
-
classifier:
|
|
238
|
-
standard:
|
|
239
|
-
high:
|
|
240
|
-
highest:
|
|
241
|
-
image:
|
|
242
|
-
video:
|
|
243
|
-
speech:
|
|
244
|
-
audio:
|
|
238
|
+
classifier: "makesText",
|
|
239
|
+
standard: "makesText",
|
|
240
|
+
high: "makesText",
|
|
241
|
+
highest: "makesText",
|
|
242
|
+
image: "makesImages",
|
|
243
|
+
video: "makesVideos",
|
|
244
|
+
speech: "makesSpeech",
|
|
245
|
+
audio: "makesVoiceNotes",
|
|
245
246
|
};
|
|
246
247
|
/** Why a class has no way: the provider picked for it lacks its key, or nothing is set up. */
|
|
247
248
|
function missingText(cfg, cls) {
|
|
248
249
|
const bound = cfg.settings.bindings[cls];
|
|
249
250
|
if (isCreditsRef(bound)) {
|
|
250
|
-
return
|
|
251
|
+
return note("creditsNotSignedIn");
|
|
251
252
|
}
|
|
252
|
-
const makes = MAKES[cls];
|
|
253
253
|
const provider = bound ? providerInfo(providerOfRef(bound) ?? "") : null;
|
|
254
254
|
if (provider) {
|
|
255
|
-
return
|
|
255
|
+
return note("providerKeyMissing", { provider: provider.name, makes: note(MAKES[cls]) });
|
|
256
256
|
}
|
|
257
|
-
return
|
|
257
|
+
return note("noModelFor", { makes: note(MAKES[cls]) });
|
|
258
258
|
}
|
|
259
259
|
/**
|
|
260
260
|
* The way to the credits. On a Manage-App's runtime always; alone, through the linked account —
|
|
@@ -274,7 +274,7 @@ async function creditAccess(cfg, chosen) {
|
|
|
274
274
|
const token = await accountToken();
|
|
275
275
|
if (!token) {
|
|
276
276
|
if (chosen) {
|
|
277
|
-
throw new ModelUnavailableError(
|
|
277
|
+
throw new ModelUnavailableError(note("accountNoLongerSigned"));
|
|
278
278
|
}
|
|
279
279
|
return null;
|
|
280
280
|
}
|
|
@@ -301,7 +301,7 @@ async function routeOf(cls) {
|
|
|
301
301
|
function need(cfg, name) {
|
|
302
302
|
const key = cfg.keys[name];
|
|
303
303
|
if (!key) {
|
|
304
|
-
throw new ModelUnavailableError(
|
|
304
|
+
throw new ModelUnavailableError(note("noApiKeyFor", { provider: providerInfo(name)?.name ?? name }));
|
|
305
305
|
}
|
|
306
306
|
return key;
|
|
307
307
|
}
|
|
@@ -412,7 +412,7 @@ async function ownLanguageModel(cfg, ref, meta) {
|
|
|
412
412
|
};
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
|
-
throw new ModelUnavailableError(
|
|
415
|
+
throw new ModelUnavailableError(note("modelNotUsedYet", { ref }));
|
|
416
416
|
}
|
|
417
417
|
/**
|
|
418
418
|
* The language model a text class runs on. A run watched from a device that offers the class
|
|
@@ -492,7 +492,7 @@ export async function imageModel(meta = {}) {
|
|
|
492
492
|
return own(createOpenAI({ apiKey: cfg.keys.openai }).image(aliasOf(id)));
|
|
493
493
|
}
|
|
494
494
|
}
|
|
495
|
-
throw new ModelUnavailableError(
|
|
495
|
+
throw new ModelUnavailableError(note("noModelForImages"));
|
|
496
496
|
}
|
|
497
497
|
export async function videoModel(meta = {}) {
|
|
498
498
|
const route = await routeOf("video");
|
|
@@ -521,7 +521,7 @@ export async function videoModel(meta = {}) {
|
|
|
521
521
|
return own(createGateway({ apiKey: cfg.keys.gateway }).videoModel(id), true);
|
|
522
522
|
}
|
|
523
523
|
}
|
|
524
|
-
throw new ModelUnavailableError(
|
|
524
|
+
throw new ModelUnavailableError(note("noModelForVideos"));
|
|
525
525
|
}
|
|
526
526
|
/** The model that reads a text aloud. */
|
|
527
527
|
export async function speechModel(meta = {}) {
|
|
@@ -529,7 +529,7 @@ export async function speechModel(meta = {}) {
|
|
|
529
529
|
if (route.kind === "credits") {
|
|
530
530
|
const resolved = await viaCredits(route, "speech", meta, (c, id) => c.speechModel(id));
|
|
531
531
|
if (!resolved.ref) {
|
|
532
|
-
throw new ModelUnavailableError(
|
|
532
|
+
throw new ModelUnavailableError(note("noModelForSpeech"));
|
|
533
533
|
}
|
|
534
534
|
return resolved;
|
|
535
535
|
}
|
|
@@ -560,7 +560,7 @@ export async function speechModel(meta = {}) {
|
|
|
560
560
|
return own(createOpenAI({ apiKey: cfg.keys.openai }).speech(aliasOf(id)));
|
|
561
561
|
}
|
|
562
562
|
}
|
|
563
|
-
throw new ModelUnavailableError(
|
|
563
|
+
throw new ModelUnavailableError(note("noModelForSpeech"));
|
|
564
564
|
}
|
|
565
565
|
/**
|
|
566
566
|
* What turns a voice note into text: a transcription model (ElevenLabs Scribe, Whisper), or a
|
|
@@ -711,7 +711,10 @@ export function freeTierRefusal(err) {
|
|
|
711
711
|
}
|
|
712
712
|
/** What the person reads when Vercel's free tier leaves a model out, and how to fix it. */
|
|
713
713
|
export function freeTierText(model) {
|
|
714
|
-
return
|
|
714
|
+
return note("freeTier", {
|
|
715
|
+
model: model ? note("quoted", { text: model }) : note("thisModel"),
|
|
716
|
+
url: GATEWAY_TOP_UP,
|
|
717
|
+
});
|
|
715
718
|
}
|
|
716
719
|
/** What a key was answered for a model: refusals are asked again soon, as a top-up lifts them. */
|
|
717
720
|
const gatewayProbes = new Map();
|
|
@@ -765,7 +768,7 @@ const CONVERSATION_MODEL = env.conversationModel || "gpt-realtime";
|
|
|
765
768
|
export async function conversationAccess() {
|
|
766
769
|
const cfg = await config();
|
|
767
770
|
if (!cfg.keys.openai) {
|
|
768
|
-
throw new ModelUnavailableError(
|
|
771
|
+
throw new ModelUnavailableError(note("noOpenaiApiKey"));
|
|
769
772
|
}
|
|
770
773
|
return { apiKey: cfg.keys.openai, model: CONVERSATION_MODEL };
|
|
771
774
|
}
|
|
@@ -802,12 +805,10 @@ export async function classProblem(cls) {
|
|
|
802
805
|
const named = creditsModelOf((await config()).settings.bindings[cls]);
|
|
803
806
|
if (named) {
|
|
804
807
|
return catalog?.models && !catalog.models.some((m) => m.id === named)
|
|
805
|
-
?
|
|
808
|
+
? note("modelNotAvailableAccount")
|
|
806
809
|
: null;
|
|
807
810
|
}
|
|
808
|
-
return catalog?.classes && !catalog.classes[cls]
|
|
809
|
-
? bilingual("Dafür ist bei deinem Konto kein Modell eingerichtet.", "Your account has no model set up for this.")
|
|
810
|
-
: null;
|
|
811
|
+
return catalog?.classes && !catalog.classes[cls] ? note("accountNoModelSet") : null;
|
|
811
812
|
}
|
|
812
813
|
const client = harness(resolved.vendor);
|
|
813
814
|
if (client && (await detectHarness(client.id))?.auth === "none") {
|
|
@@ -833,7 +834,7 @@ export async function filmClient(cls) {
|
|
|
833
834
|
const client = managed ? null : harness(cfg.settings.source);
|
|
834
835
|
if (!client || !FILM_CLIENTS.has(client.id)) {
|
|
835
836
|
return {
|
|
836
|
-
problem:
|
|
837
|
+
problem: note("claudeCodeMakesFilms"),
|
|
837
838
|
};
|
|
838
839
|
}
|
|
839
840
|
const status = await detectHarness(client.id);
|
|
@@ -918,9 +919,7 @@ async function appleProblem(cls) {
|
|
|
918
919
|
if (!status.supported || status.reason === "missing") {
|
|
919
920
|
return appleUnavailableNote(status);
|
|
920
921
|
}
|
|
921
|
-
return (await hasFfmpeg())
|
|
922
|
-
? null
|
|
923
|
-
: bilingual("Aufnahmen aus Chrome oder Firefox (WebM, Ogg) schreibt dieser Mac erst mit ffmpeg auf. Safari und die App brauchen es nicht. Installiere ffmpeg, z. B. mit „brew install ffmpeg“.", "This Mac needs ffmpeg to transcribe recordings from Chrome or Firefox (WebM, Ogg). Safari and the app don’t. Install ffmpeg, e.g. with “brew install ffmpeg”.");
|
|
922
|
+
return (await hasFfmpeg()) ? null : note("macNeedsFfmpegTranscribe");
|
|
924
923
|
}
|
|
925
924
|
/** At start the ways are asked once, so a model the key cannot reach shows before a run meets it. */
|
|
926
925
|
export async function checkModelsAtStart() {
|
|
@@ -958,7 +957,6 @@ export async function modelSettings(lang = "en") {
|
|
|
958
957
|
// --- Checking a key ------------------------------------------------------------------
|
|
959
958
|
/** A cheap authenticated call: whether the provider takes the key. Nothing is generated. */
|
|
960
959
|
export async function checkKey(name, key, lang = "en") {
|
|
961
|
-
const de = lang === "de";
|
|
962
960
|
const requests = {
|
|
963
961
|
openai: ["https://api.openai.com/v1/models", { authorization: `Bearer ${key}` }],
|
|
964
962
|
anthropic: [
|
|
@@ -991,20 +989,14 @@ export async function checkKey(name, key, lang = "en") {
|
|
|
991
989
|
return {
|
|
992
990
|
ok: false,
|
|
993
991
|
message: res.status === 401
|
|
994
|
-
?
|
|
995
|
-
|
|
996
|
-
: "The provider doesn’t recognise this key."
|
|
997
|
-
: de
|
|
998
|
-
? `Der Anbieter antwortet mit Fehler ${res.status}.`
|
|
999
|
-
: `The provider answered with error ${res.status}.`,
|
|
992
|
+
? serverText(lang, "keyUnknown")
|
|
993
|
+
: serverText(lang, "providerError", { status: String(res.status) }),
|
|
1000
994
|
};
|
|
1001
995
|
}
|
|
1002
996
|
catch {
|
|
1003
997
|
return {
|
|
1004
998
|
ok: false,
|
|
1005
|
-
message:
|
|
1006
|
-
? "Der Anbieter ist gerade nicht erreichbar."
|
|
1007
|
-
: "The provider cannot be reached right now.",
|
|
999
|
+
message: serverText(lang, "providerUnreachable"),
|
|
1008
1000
|
};
|
|
1009
1001
|
}
|
|
1010
1002
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { wizardLang } from "@engenty-wizards/shared/definition";
|
|
2
|
+
import { LANGS, wizardLang } from "@engenty-wizards/shared/definition";
|
|
3
3
|
import { noteText } from "@engenty-wizards/shared/run";
|
|
4
4
|
import { and, asc, eq, inArray, isNotNull } from "drizzle-orm";
|
|
5
5
|
import { db, schema, withTenant } from "../db/client.js";
|
|
@@ -67,9 +67,7 @@ export function runsApiFor(pluginId) {
|
|
|
67
67
|
throw new ServiceError("refused", errorText(err, wizardLang(version.definition)));
|
|
68
68
|
}
|
|
69
69
|
if (err instanceof NoCreditsError) {
|
|
70
|
-
throw new ServiceError("no_credits", wizardLang(version.definition)
|
|
71
|
-
? "Dieser Wizard hat gerade kein Guthaben mehr. Versuch es später noch einmal."
|
|
72
|
-
: "This wizard has run out of credits for now. Try again later.");
|
|
70
|
+
throw new ServiceError("no_credits", noteText({ code: "wizardRunOutCredits" }, wizardLang(version.definition)));
|
|
73
71
|
}
|
|
74
72
|
throw err;
|
|
75
73
|
});
|
|
@@ -157,7 +155,7 @@ export function runsApiFor(pluginId) {
|
|
|
157
155
|
note: event.note
|
|
158
156
|
? {
|
|
159
157
|
code: event.note.code,
|
|
160
|
-
text:
|
|
158
|
+
text: Object.fromEntries(LANGS.map((lang) => [lang, noteText(event.note, lang)])),
|
|
161
159
|
}
|
|
162
160
|
: null,
|
|
163
161
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { note } from "@engenty-wizards/shared/run";
|
|
2
2
|
import { PACKAGE_MIME } from "@engenty-wizards/shared/wizard-package";
|
|
3
3
|
import { Hono } from "hono";
|
|
4
4
|
import { bodyLimit } from "hono/body-limit";
|
|
@@ -20,7 +20,7 @@ import { siteJob, siteSchema, startSiteJob } from "../services/site.js";
|
|
|
20
20
|
import { checkOnServer, checkSchema, listSyncedSpaces, patchSyncedWizard, removeSyncedSpace, removeSyncedWizard, rotateSyncedLink, syncDataSchema, syncSettingsSchema, syncSpaceData, syncWizard, syncWizardSchema, } from "../services/spaces.js";
|
|
21
21
|
import { createWizard, ownedWizard, publishWizard, writeDraft } from "../services/wizards.js";
|
|
22
22
|
import { codeOf, tenantStatus } from "../tenants/control.js";
|
|
23
|
-
import {
|
|
23
|
+
import { notFoundAnswer, say } from "./lang.js";
|
|
24
24
|
import { dispatchAs } from "./plugins.js";
|
|
25
25
|
const importSchema = z.object({
|
|
26
26
|
/** An earlier import's wizard: it is updated instead of a new one being made. */
|
|
@@ -61,7 +61,7 @@ async function caller(c, scopes) {
|
|
|
61
61
|
}
|
|
62
62
|
if ((await tenantStatus(who.tenantId)) === "suspended") {
|
|
63
63
|
return c.json({
|
|
64
|
-
error:
|
|
64
|
+
error: say(c, "accountSuspended"),
|
|
65
65
|
code: "tenant_suspended",
|
|
66
66
|
}, 403);
|
|
67
67
|
}
|
|
@@ -72,7 +72,7 @@ function withinSyncLimit(c, who) {
|
|
|
72
72
|
return allowed(`sync:${who.tenantId}`, 240, HOUR)
|
|
73
73
|
? null
|
|
74
74
|
: c.json({
|
|
75
|
-
error:
|
|
75
|
+
error: say(c, "tooManyTransfersTry"),
|
|
76
76
|
code: "rate_limited",
|
|
77
77
|
}, 429);
|
|
78
78
|
}
|
|
@@ -90,7 +90,7 @@ async function pluginCall(c) {
|
|
|
90
90
|
if (!(await pluginIdsOf(who.tenantId)).has(id)) {
|
|
91
91
|
return loadedPlugin(id) || PRO_PLUGINS.includes(id)
|
|
92
92
|
? c.json({
|
|
93
|
-
error:
|
|
93
|
+
error: say(c, "pluginNotPartPlan"),
|
|
94
94
|
code: "plugin",
|
|
95
95
|
plugin: id,
|
|
96
96
|
}, 403)
|
|
@@ -180,7 +180,7 @@ export const apiRoutes = new Hono()
|
|
|
180
180
|
});
|
|
181
181
|
if (!found) {
|
|
182
182
|
return c.json({
|
|
183
|
-
error:
|
|
183
|
+
error: say(c, "wizardNotPublishedYet"),
|
|
184
184
|
code: "not_found",
|
|
185
185
|
}, 404);
|
|
186
186
|
}
|
|
@@ -290,7 +290,7 @@ export const apiRoutes = new Hono()
|
|
|
290
290
|
}
|
|
291
291
|
if (!allowed(`site:${who.tenantId}`, 20, HOUR)) {
|
|
292
292
|
return c.json({
|
|
293
|
-
error:
|
|
293
|
+
error: say(c, "tooManyTimesRow"),
|
|
294
294
|
code: "rate_limited",
|
|
295
295
|
}, 429);
|
|
296
296
|
}
|
|
@@ -396,7 +396,7 @@ export const apiRoutes = new Hono()
|
|
|
396
396
|
}
|
|
397
397
|
if ((await tenantStatus(who.tenantId)) === "suspended") {
|
|
398
398
|
return c.json({
|
|
399
|
-
error:
|
|
399
|
+
error: say(c, "accountSuspended"),
|
|
400
400
|
code: "tenant_suspended",
|
|
401
401
|
}, 403);
|
|
402
402
|
}
|
|
@@ -427,7 +427,7 @@ export const apiRoutes = new Hono()
|
|
|
427
427
|
return c.json({ wizardId, revision: written.revision, issues: written.issues });
|
|
428
428
|
}
|
|
429
429
|
if (written.issues.length) {
|
|
430
|
-
throw new ServiceError("has_issues",
|
|
430
|
+
throw new ServiceError("has_issues", note("wizardStillErrors"), {
|
|
431
431
|
issues: written.issues,
|
|
432
432
|
wizardId,
|
|
433
433
|
});
|
|
@@ -1,20 +1,25 @@
|
|
|
1
|
+
import { localLang } from "@engenty-wizards/shared/definition";
|
|
2
|
+
import { serverText } from "../texts.js";
|
|
1
3
|
/**
|
|
2
|
-
* The language a visitor's request asks for
|
|
3
|
-
* first
|
|
4
|
-
*
|
|
4
|
+
* The language a visitor's request asks for, as the studio starts in it (`localLang`): the
|
|
5
|
+
* first of the browser's languages engenty speaks other than English, else English. The
|
|
6
|
+
* browser's `Accept-Language` names them in its order; the server has no time zone to go by.
|
|
5
7
|
*/
|
|
6
8
|
export function requestLang(c) {
|
|
7
|
-
const asked = c.req.header("accept-language")
|
|
8
|
-
|
|
9
|
+
const asked = (c.req.header("accept-language") ?? "")
|
|
10
|
+
.split(",")
|
|
11
|
+
.map((part) => part.split(";")[0]?.trim() ?? "")
|
|
12
|
+
.filter(Boolean);
|
|
13
|
+
return localLang(asked) ?? "en";
|
|
9
14
|
}
|
|
10
|
-
/** A line the person reads, in the language their request asks for. */
|
|
11
|
-
export function
|
|
12
|
-
return requestLang(c)
|
|
15
|
+
/** A line of the server's table the person reads, in the language their request asks for. */
|
|
16
|
+
export function say(c, key, params) {
|
|
17
|
+
return serverText(requestLang(c), key, params);
|
|
13
18
|
}
|
|
14
19
|
/** A 404 the person may read: a sentence in their language, the machine code beside it. */
|
|
15
20
|
export function notFoundAnswer(c) {
|
|
16
21
|
return {
|
|
17
|
-
error:
|
|
22
|
+
error: say(c, "notFound"),
|
|
18
23
|
code: "not_found",
|
|
19
24
|
};
|
|
20
25
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CAPABILITY_IDS, INDUSTRY_IDS, ITEM_FORMAT_IDS, MARKETPLACE_PLAN_IDS, USE_CASE_IDS, } from "@engenty-wizards/shared/marketplace";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import { asLang, marketplaceDetail, searchMarketplace, starEntry, } from "../services/marketplace.js";
|
|
4
|
+
import { asLang, marketplaceDetail, searchMarketplace, searchMarketplaceAsGuest, starEntry, } from "../services/marketplace.js";
|
|
5
5
|
import { notFoundAnswer } from "./lang.js";
|
|
6
6
|
const searchSchema = z.object({
|
|
7
7
|
q: z.string().trim().max(200).default(""),
|
|
@@ -36,3 +36,8 @@ export const marketplaceStudio = new Hono()
|
|
|
36
36
|
await starEntry(c.get("user").tenantId, c.req.param("id"), false);
|
|
37
37
|
return c.json({ ok: true });
|
|
38
38
|
});
|
|
39
|
+
/** The gallery for someone not signed in (the studio's start page for guests): only the search. */
|
|
40
|
+
export const marketplaceGuest = new Hono().get("/", async (c) => {
|
|
41
|
+
const { lang, starred: _starred, ...search } = searchSchema.parse(c.req.query());
|
|
42
|
+
return c.json(await searchMarketplaceAsGuest({ ...search, lang: asLang(lang) }));
|
|
43
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FORMATS, LIST_FORMATS, TEXT_CLASSES } from "@engenty-wizards/shared/definition";
|
|
1
|
+
import { FORMATS, LANGS, LIST_FORMATS, TEXT_CLASSES } from "@engenty-wizards/shared/definition";
|
|
2
2
|
import { TableColumnValueError } from "@engenty-wizards/shared/engenty/data-tables";
|
|
3
3
|
import { noteText } from "@engenty-wizards/shared/run";
|
|
4
4
|
import { getConnInfo } from "@hono/node-server/conninfo";
|
|
@@ -39,7 +39,7 @@ import { isIconFile, wizardAvatarSvg, wizardIcon } from "../services/wizard-icon
|
|
|
39
39
|
import { clearStore, deleteRows, listRows, listSecrets, readStoreFile, StoreError, saveRows, scopeOf, storeFiles, updateRow, } from "../store/index.js";
|
|
40
40
|
import { tenantOfLink, tenantOfRun, tenantStatus, tokenOfCode, visitorOverLimit, } from "../tenants/control.js";
|
|
41
41
|
import { bareMime, byteRange, inlineSafe, uploadLimit, uploadMime, wizardManifest, } from "./delivery.js";
|
|
42
|
-
import {
|
|
42
|
+
import { notFoundAnswer, requestLang, say } from "./lang.js";
|
|
43
43
|
const VISITOR_COOKIE = "wz_vid";
|
|
44
44
|
/** Kept files a review shows inline. */
|
|
45
45
|
const INLINE_TYPES = new Set(["application/pdf", "image/png", "image/jpeg", "image/webp"]);
|
|
@@ -205,7 +205,7 @@ export const publicRoutes = new Hono()
|
|
|
205
205
|
const ip = clientIp(c);
|
|
206
206
|
if (codeLookupBlocked(ip)) {
|
|
207
207
|
return c.json({
|
|
208
|
-
error:
|
|
208
|
+
error: say(c, "tooManyTriesWait"),
|
|
209
209
|
code: "too_many_tries",
|
|
210
210
|
}, 429);
|
|
211
211
|
}
|
|
@@ -633,7 +633,7 @@ export const runRoutes = new Hono()
|
|
|
633
633
|
.object({
|
|
634
634
|
lat: z.number().min(-90).max(90),
|
|
635
635
|
lng: z.number().min(-180).max(180),
|
|
636
|
-
language: z.enum(
|
|
636
|
+
language: z.enum(LANGS).default("en"),
|
|
637
637
|
})
|
|
638
638
|
.parse(await c.req.json());
|
|
639
639
|
return c.json({ label: await reverseGeocode(lat, lng, language) });
|
|
@@ -1012,7 +1012,7 @@ export const runRoutes = new Hono()
|
|
|
1012
1012
|
.object({
|
|
1013
1013
|
token: z.string().min(8).max(512),
|
|
1014
1014
|
platform: z.enum(["ios", "android"]),
|
|
1015
|
-
lang: z.enum(
|
|
1015
|
+
lang: z.enum(LANGS).default("en"),
|
|
1016
1016
|
})
|
|
1017
1017
|
.parse(await c.req.json());
|
|
1018
1018
|
await setPushDevice(run.id, body);
|