wizards 0.2.29 → 0.2.31
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/auth/account.js +8 -0
- package/apps/runtime/dist/auth/index.js +3 -0
- package/apps/runtime/dist/authoring/guide.js +1 -0
- package/apps/runtime/dist/engine/steps.js +3 -1
- package/apps/runtime/dist/env.js +5 -0
- package/apps/runtime/dist/files/storage.js +3 -0
- package/apps/runtime/dist/files/web-images.js +101 -0
- package/apps/runtime/dist/index.js +4 -0
- package/apps/runtime/dist/manage.js +6 -1
- package/apps/runtime/dist/plugins/loader.js +9 -2
- package/apps/runtime/dist/plugins/pro-keys.js +34 -0
- package/apps/runtime/dist/plugins/pro-state.js +83 -0
- package/apps/runtime/dist/plugins/pro.js +316 -0
- package/apps/runtime/dist/render/downloads.js +5 -3
- package/apps/runtime/dist/routes/plugins.js +49 -0
- package/apps/runtime/dist/routes/studio.js +3 -0
- package/apps/runtime/dist/widgets/step.js +10 -4
- package/apps/web/dist/assets/{Account-BaOouMw9.js → Account-v7Iqkep5.js} +1 -1
- package/apps/web/dist/assets/{ChangelogDialog-3t_EKUPH.js → ChangelogDialog-CnYW-DMa.js} +1 -1
- package/apps/web/dist/assets/{CreditsDialog-BW-RETl-.js → CreditsDialog-BtID6slV.js} +1 -1
- package/apps/web/dist/assets/{EditorPage-DrJhgEHO.js → EditorPage-UqOALINq.js} +1 -1
- package/apps/web/dist/assets/{FlowPreview-Wu5ovKrU.js → FlowPreview-CxBGhnMi.js} +1 -1
- package/apps/web/dist/assets/{Harness-Oh4MEjiK.js → Harness-BBUVWLMx.js} +1 -1
- package/apps/web/dist/assets/{HomePage-eYqUUwzG.js → HomePage-E2kbDAWI.js} +1 -1
- package/apps/web/dist/assets/{ImportWizard-BSjp83g0.js → ImportWizard-DBxxe467.js} +1 -1
- package/apps/web/dist/assets/{LocalRuntime-CqBfKp8q.js → LocalRuntime-DMU_dzV1.js} +1 -1
- package/apps/web/dist/assets/{NewWizardPage-Bpqk-BwW.js → NewWizardPage-B9rqko-D.js} +2 -2
- package/apps/web/dist/assets/{ProjectPage-SK7e8kxV.js → ProjectPage-cqeSCfvy.js} +1 -1
- package/apps/web/dist/assets/{PublicRunner-Cu056QMy.js → PublicRunner-CrRc-QgY.js} +1 -1
- package/apps/web/dist/assets/{RunDrawer-BdcgNjPZ.js → RunDrawer-DRKc8Bm5.js} +1 -1
- package/apps/web/dist/assets/{RunnerView-JOMD-e27.js → RunnerView-BH2sXBlx.js} +1 -1
- package/apps/web/dist/assets/SettingsPage-DeehkMtv.js +1 -0
- package/apps/web/dist/assets/{SetupPage-DdWIlUCF.js → SetupPage-D13qI_dd.js} +1 -1
- package/apps/web/dist/assets/{SharePage-C5JlCg9u.js → SharePage-8ji9ACWJ.js} +1 -1
- package/apps/web/dist/assets/arrow-right-CzoY677S.js +1 -0
- package/apps/web/dist/assets/changelog-D536XAHL.js +1 -0
- package/apps/web/dist/assets/{circle-alert-BG9P3ewL.js → circle-alert-CN6dFS0d.js} +1 -1
- package/apps/web/dist/assets/{definition-CwX2olVF.js → definition-Cx9uG0KU.js} +1 -1
- package/apps/web/dist/assets/{esm-MDvpTvd_.js → esm-CSQNLh1s.js} +1 -1
- package/apps/web/dist/assets/{external-link-BwCtn1nW.js → external-link-DvkH63pi.js} +1 -1
- package/apps/web/dist/assets/{image-DG4q2P1H.js → image-BUbtvL1h.js} +1 -1
- package/apps/web/dist/assets/{index-knnf98Fv.js → index-CYZmm7HU.js} +4 -4
- package/apps/web/dist/assets/{lock-DH_BntP_.js → lock-COAprdab.js} +1 -1
- package/apps/web/dist/assets/{meta-cFJejpIa.js → meta-Daw62MfH.js} +1 -1
- package/apps/web/dist/assets/{pen-line-B1dsy3Sr.js → pen-line-JsP-r_aH.js} +1 -1
- package/apps/web/dist/assets/{refresh-cw-B9M1g3SH.js → refresh-cw-DLXaS3Ri.js} +1 -1
- package/apps/web/dist/assets/{settings-menu-DC825gd1.js → settings-menu-br026gwt.js} +1 -1
- package/apps/web/dist/assets/{star-axQV_3EC.js → star-CpnGQZXD.js} +1 -1
- package/apps/web/dist/assets/{surface-D7bnQtqR.js → surface-BFwNWkx9.js} +1 -1
- package/apps/web/dist/assets/{trash-3S1_XpVa.js → trash-CQZuqdcu.js} +1 -1
- package/apps/web/dist/assets/{ui-BZ01zr3i.js → ui-BTkH_7CG.js} +1 -1
- package/apps/web/dist/assets/{upload-U0i8fAW3.js → upload-Dok4YeXQ.js} +1 -1
- package/apps/web/dist/assets/{video-Db4o719f.js → video-BjQoPIsn.js} +1 -1
- package/apps/web/dist/assets/{volume-2-6f7qN_LM.js → volume-2-D-Bn77h4.js} +1 -1
- package/apps/web/dist/assets/{wand-sparkles-MelvBtiK.js → wand-sparkles-D3sDsFFG.js} +1 -1
- package/apps/web/dist/index.html +3 -3
- package/apps/web/dist/mcp/flow.html +1 -1
- package/package.json +1 -1
- package/apps/web/dist/assets/SettingsPage-BSu-2gL5.js +0 -1
- package/apps/web/dist/assets/arrow-right-hy38IBRU.js +0 -1
- package/apps/web/dist/assets/changelog-C2q3P5lJ.js +0 -1
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { unzipSync } from "fflate";
|
|
6
|
+
import { accountToken, linkedAccount } from "../auth/account.js";
|
|
7
|
+
import { env } from "../env.js";
|
|
8
|
+
import { managed, verifySigned } from "../manage.js";
|
|
9
|
+
import { deleteSetting, readSetting, writeSetting } from "../settings.js";
|
|
10
|
+
import { MANIFEST_FILE } from "./discovery.js";
|
|
11
|
+
import { findNewPlugins, reloadPlugin } from "./loader.js";
|
|
12
|
+
import { signedByUs } from "./pro-keys.js";
|
|
13
|
+
import { currentEntitlement, ENTITLEMENT_SETTING, heldBackModules, INSTALLED_FILE, installedModule, proModulesDir, runtimeTag, setEntitlement, } from "./pro-state.js";
|
|
14
|
+
import { loadedPlugin } from "./registry.js";
|
|
15
|
+
/*
|
|
16
|
+
* Pro modules on a runtime that runs alone (docs/content/dev/plugins/pro-modules): the closed
|
|
17
|
+
* plugins the linked account's plan includes, fetched from its Manage-App.
|
|
18
|
+
*
|
|
19
|
+
* GET /v1/modules?runtime=<release> what is built for this release, the plan's
|
|
20
|
+
* part of it, and the signed entitlement
|
|
21
|
+
* GET /v1/modules/:id/package?runtime=<release> one module's zip
|
|
22
|
+
*
|
|
23
|
+
* A package is taken only when its SHA-256 and the signature over id, version, release and that
|
|
24
|
+
* hash check out against a key this runtime carries (pro-keys.ts): neither the Manage-App nor
|
|
25
|
+
* the way there can hand over code of their own.
|
|
26
|
+
*/
|
|
27
|
+
/** The audience of an entitlement, as the Manage-App signs it. */
|
|
28
|
+
const AUDIENCE = "urn:engenty:wizards:modules";
|
|
29
|
+
/** Larger packages are refused before they are read. */
|
|
30
|
+
const MAX_PACKAGE = 30 * 1024 * 1024;
|
|
31
|
+
/** What a package may hold, besides its manifest. */
|
|
32
|
+
const PARTS = ["dist/", "migrations/"];
|
|
33
|
+
const base = () => `${env.local.accountUrl}/v1/modules`;
|
|
34
|
+
/** Something the person can mend or retry; the message is for them. */
|
|
35
|
+
export class ProModuleError extends Error {
|
|
36
|
+
status;
|
|
37
|
+
code;
|
|
38
|
+
constructor(message, status = 400, code = "pro_module") {
|
|
39
|
+
super(message);
|
|
40
|
+
this.status = status;
|
|
41
|
+
this.code = code;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
let listing = null;
|
|
45
|
+
let lastError = null;
|
|
46
|
+
// --- the entitlement -------------------------------------------------------------------
|
|
47
|
+
/**
|
|
48
|
+
* At start, before the plugins load: what the last check said, while it lasts and belongs to the
|
|
49
|
+
* account that is linked now.
|
|
50
|
+
*/
|
|
51
|
+
export async function loadEntitlement() {
|
|
52
|
+
if (managed) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const [stored, account] = await Promise.all([
|
|
56
|
+
readSetting(ENTITLEMENT_SETTING),
|
|
57
|
+
linkedAccount(),
|
|
58
|
+
]);
|
|
59
|
+
setEntitlement(stored && account && stored.tenantId === account.tenantId ? stored : null);
|
|
60
|
+
}
|
|
61
|
+
async function keep(value) {
|
|
62
|
+
setEntitlement(value);
|
|
63
|
+
if (value) {
|
|
64
|
+
await writeSetting(ENTITLEMENT_SETTING, value);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
await deleteSetting(ENTITLEMENT_SETTING);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Loads and unloads Pro modules after the entitlement changed. */
|
|
71
|
+
async function apply(before) {
|
|
72
|
+
const after = currentEntitlement();
|
|
73
|
+
const same = before?.modules.join() === after?.modules.join() &&
|
|
74
|
+
(before?.expiresAt ?? 0) > Date.now() === (after?.expiresAt ?? 0) > Date.now();
|
|
75
|
+
if (!same) {
|
|
76
|
+
await findNewPlugins();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function call(path, token) {
|
|
80
|
+
const url = new URL(`${base()}${path}`);
|
|
81
|
+
url.searchParams.set("runtime", runtimeTag());
|
|
82
|
+
const res = await fetch(url, {
|
|
83
|
+
headers: { authorization: `Bearer ${token}` },
|
|
84
|
+
signal: AbortSignal.timeout(60_000),
|
|
85
|
+
}).catch(() => null);
|
|
86
|
+
if (!res) {
|
|
87
|
+
throw new ProModuleError("Dein engenty-Konto ist gerade nicht erreichbar.", 502, "offline");
|
|
88
|
+
}
|
|
89
|
+
return res;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Asks the account what its plan includes now, keeps the signed answer and fetches what an
|
|
93
|
+
* installed module needs (a new release, a new build). Unreachable: what was confirmed lasts
|
|
94
|
+
* until it ends.
|
|
95
|
+
*/
|
|
96
|
+
export async function refreshPro() {
|
|
97
|
+
if (managed) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const before = currentEntitlement();
|
|
101
|
+
const account = await linkedAccount();
|
|
102
|
+
if (!account) {
|
|
103
|
+
listing = null;
|
|
104
|
+
lastError = null;
|
|
105
|
+
await keep(null);
|
|
106
|
+
await apply(before);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const token = await accountToken();
|
|
111
|
+
if (!token) {
|
|
112
|
+
throw new ProModuleError("Dein engenty-Konto ist gerade nicht erreichbar.", 502, "offline");
|
|
113
|
+
}
|
|
114
|
+
const res = await call("", token);
|
|
115
|
+
if (res.status === 401) {
|
|
116
|
+
throw new ProModuleError("Das engenty-Konto nimmt diese Anmeldung nicht mehr an.", 403);
|
|
117
|
+
}
|
|
118
|
+
if (!res.ok) {
|
|
119
|
+
throw new ProModuleError(`Das Konto antwortet nicht wie erwartet (${res.status}).`, 502);
|
|
120
|
+
}
|
|
121
|
+
const answer = (await res.json());
|
|
122
|
+
const claims = await verifySigned(answer.entitlement?.token ?? "", [AUDIENCE], env.local.accountUrl);
|
|
123
|
+
if (!claims || claims.sub !== account.tenantId || !Array.isArray(claims.modules)) {
|
|
124
|
+
throw new ProModuleError("Die Bestätigung des Pakets ließ sich nicht prüfen.", 502);
|
|
125
|
+
}
|
|
126
|
+
listing = answer;
|
|
127
|
+
lastError = null;
|
|
128
|
+
await keep({
|
|
129
|
+
tenantId: account.tenantId,
|
|
130
|
+
modules: claims.modules.map(String),
|
|
131
|
+
plan: answer.plan ?? null,
|
|
132
|
+
expiresAt: (claims.exp ?? 0) * 1000,
|
|
133
|
+
checkedAt: Date.now(),
|
|
134
|
+
});
|
|
135
|
+
await apply(before);
|
|
136
|
+
await updateInstalled();
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
lastError = err.message;
|
|
140
|
+
console.error("[pro modules]", lastError);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
let timer = null;
|
|
144
|
+
/** Checks at start, then once a day while the runtime runs; a check that failed, within the hour. */
|
|
145
|
+
export function startProChecks() {
|
|
146
|
+
if (managed || timer) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
void refreshPro();
|
|
150
|
+
timer = setInterval(() => {
|
|
151
|
+
const checkedAt = currentEntitlement()?.checkedAt ?? 0;
|
|
152
|
+
if (lastError || Date.now() - checkedAt > 23 * 3600_000) {
|
|
153
|
+
void refreshPro();
|
|
154
|
+
}
|
|
155
|
+
}, 3600_000);
|
|
156
|
+
timer.unref();
|
|
157
|
+
}
|
|
158
|
+
// --- installing ------------------------------------------------------------------------
|
|
159
|
+
async function installedIds() {
|
|
160
|
+
const entries = await readdir(proModulesDir(), { withFileTypes: true }).catch(() => []);
|
|
161
|
+
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
|
|
162
|
+
}
|
|
163
|
+
/** Installed modules built for another release or from another build are fetched anew. */
|
|
164
|
+
async function updateInstalled() {
|
|
165
|
+
for (const id of await installedIds()) {
|
|
166
|
+
const entry = listing?.modules.find((m) => m.id === id);
|
|
167
|
+
const installed = installedModule(join(proModulesDir(), id));
|
|
168
|
+
if (entry?.included && installed?.sha256 !== entry.sha256) {
|
|
169
|
+
await installPro(id).catch((err) => console.error(`[pro modules] ${id}: update failed:`, err.message));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** The files of a zip, refusing any that would land outside the module's folder. */
|
|
174
|
+
function filesOf(zip) {
|
|
175
|
+
let files;
|
|
176
|
+
try {
|
|
177
|
+
files = unzipSync(zip);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
throw new ProModuleError("Das Paket ist beschädigt.", 502);
|
|
181
|
+
}
|
|
182
|
+
const out = {};
|
|
183
|
+
for (const [name, data] of Object.entries(files)) {
|
|
184
|
+
if (name.endsWith("/")) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const parts = name.split("/");
|
|
188
|
+
const safe = parts.every((p) => p && p !== "." && p !== ".." && !p.includes("\\"));
|
|
189
|
+
const allowed = name === MANIFEST_FILE || PARTS.some((part) => name.startsWith(part));
|
|
190
|
+
if (!(safe && allowed)) {
|
|
191
|
+
throw new ProModuleError(`Das Paket enthält eine unerlaubte Datei: ${name}`, 502);
|
|
192
|
+
}
|
|
193
|
+
out[name] = data;
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
/** Fetches one module of the plan, checks it and puts it in place; then it loads. */
|
|
198
|
+
export async function installPro(id) {
|
|
199
|
+
if (managed) {
|
|
200
|
+
throw new ProModuleError("Hier nicht verfügbar.", 404, "not_found");
|
|
201
|
+
}
|
|
202
|
+
const token = await accountToken();
|
|
203
|
+
if (!token) {
|
|
204
|
+
throw new ProModuleError("Verbinde zuerst dein engenty-Konto (Einstellungen → Konto).", 409);
|
|
205
|
+
}
|
|
206
|
+
if (!listing) {
|
|
207
|
+
await refreshPro();
|
|
208
|
+
}
|
|
209
|
+
const entry = listing?.modules.find((m) => m.id === id);
|
|
210
|
+
if (!entry) {
|
|
211
|
+
throw new ProModuleError(`Für ${runtimeTag()} gibt es dieses Modul nicht.`, 404, "not_found");
|
|
212
|
+
}
|
|
213
|
+
if (!entry.included) {
|
|
214
|
+
throw new ProModuleError("Dieses Modul ist nicht Teil deines Pakets.", 403, "plan");
|
|
215
|
+
}
|
|
216
|
+
const res = await call(`/${encodeURIComponent(id)}/package`, token);
|
|
217
|
+
if (!res.ok) {
|
|
218
|
+
throw new ProModuleError(`Das Modul ließ sich nicht laden (${res.status}).`, 502);
|
|
219
|
+
}
|
|
220
|
+
if (Number(res.headers.get("content-length") ?? 0) > MAX_PACKAGE) {
|
|
221
|
+
throw new ProModuleError("Das Paket ist zu groß.", 502);
|
|
222
|
+
}
|
|
223
|
+
const zip = new Uint8Array(await res.arrayBuffer());
|
|
224
|
+
const sha256 = createHash("sha256").update(zip).digest("hex");
|
|
225
|
+
const genuine = sha256 === entry.sha256 &&
|
|
226
|
+
signedByUs({
|
|
227
|
+
id,
|
|
228
|
+
version: entry.version,
|
|
229
|
+
runtime: runtimeTag(),
|
|
230
|
+
sha256,
|
|
231
|
+
signature: entry.signature,
|
|
232
|
+
});
|
|
233
|
+
if (zip.length > MAX_PACKAGE || !genuine) {
|
|
234
|
+
throw new ProModuleError("Das Paket ist nicht von engenty signiert und wurde verworfen.", 502);
|
|
235
|
+
}
|
|
236
|
+
const files = filesOf(zip);
|
|
237
|
+
const manifest = JSON.parse(new TextDecoder().decode(files[MANIFEST_FILE] ?? new Uint8Array()));
|
|
238
|
+
if (manifest?.id !== id) {
|
|
239
|
+
throw new ProModuleError("Das Paket passt nicht zu diesem Modul.", 502);
|
|
240
|
+
}
|
|
241
|
+
const dir = proModulesDir();
|
|
242
|
+
const target = join(dir, id);
|
|
243
|
+
const fresh = join(dir, `.new-${id}-${randomBytes(4).toString("hex")}`);
|
|
244
|
+
const old = join(dir, `.old-${id}-${randomBytes(4).toString("hex")}`);
|
|
245
|
+
await mkdir(fresh, { recursive: true });
|
|
246
|
+
try {
|
|
247
|
+
for (const [path, data] of Object.entries(files)) {
|
|
248
|
+
await mkdir(dirname(join(fresh, path)), { recursive: true });
|
|
249
|
+
await writeFile(join(fresh, path), data);
|
|
250
|
+
}
|
|
251
|
+
const installed = {
|
|
252
|
+
id,
|
|
253
|
+
version: entry.version,
|
|
254
|
+
runtime: runtimeTag(),
|
|
255
|
+
sha256,
|
|
256
|
+
installedAt: new Date().toISOString(),
|
|
257
|
+
};
|
|
258
|
+
await writeFile(join(fresh, INSTALLED_FILE), `${JSON.stringify(installed, null, 2)}\n`);
|
|
259
|
+
if (existsSync(target)) {
|
|
260
|
+
await rename(target, old);
|
|
261
|
+
}
|
|
262
|
+
await rename(fresh, target);
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
await rm(fresh, { recursive: true, force: true });
|
|
266
|
+
await rm(old, { recursive: true, force: true });
|
|
267
|
+
}
|
|
268
|
+
await reloadPlugin(id);
|
|
269
|
+
}
|
|
270
|
+
/** Removes an installed module; its tables and what is in them stay. */
|
|
271
|
+
export async function removePro(id) {
|
|
272
|
+
if (managed || !(await installedIds()).includes(id)) {
|
|
273
|
+
throw new ProModuleError("Dieses Modul ist nicht installiert.", 404, "not_found");
|
|
274
|
+
}
|
|
275
|
+
await rm(join(proModulesDir(), id), { recursive: true, force: true });
|
|
276
|
+
await findNewPlugins();
|
|
277
|
+
}
|
|
278
|
+
export async function proState() {
|
|
279
|
+
const entitlement = currentEntitlement();
|
|
280
|
+
const account = await linkedAccount();
|
|
281
|
+
const ids = new Set([...(listing?.modules.map((m) => m.id) ?? []), ...(await installedIds())]);
|
|
282
|
+
const modules = [...ids].sort().map((id) => {
|
|
283
|
+
const entry = listing?.modules.find((m) => m.id === id);
|
|
284
|
+
const installed = installedModule(join(proModulesDir(), id));
|
|
285
|
+
const plugin = loadedPlugin(id);
|
|
286
|
+
return {
|
|
287
|
+
id,
|
|
288
|
+
name: entry?.name ?? plugin?.source.manifest.name ?? id,
|
|
289
|
+
version: entry?.version ?? installed?.version ?? "",
|
|
290
|
+
description: entry?.description ?? plugin?.source.manifest.description ?? "",
|
|
291
|
+
size: entry?.size ?? null,
|
|
292
|
+
included: entitlement?.modules.includes(id) ?? false,
|
|
293
|
+
installed: installed ? { version: installed.version, runtime: installed.runtime } : null,
|
|
294
|
+
loaded: Boolean(plugin?.source.pro),
|
|
295
|
+
heldBack: heldBackModules().get(id) ?? null,
|
|
296
|
+
update: Boolean(entry?.included && installed && installed.sha256 !== entry.sha256),
|
|
297
|
+
};
|
|
298
|
+
});
|
|
299
|
+
return {
|
|
300
|
+
linked: Boolean(account),
|
|
301
|
+
/** Where the plans are: `<accountUrl>/billing`. */
|
|
302
|
+
accountUrl: env.local.accountUrl,
|
|
303
|
+
runtime: runtimeTag(),
|
|
304
|
+
plan: entitlement?.plan ?? listing?.plan ?? null,
|
|
305
|
+
expiresAt: entitlement ? new Date(entitlement.expiresAt).toISOString() : null,
|
|
306
|
+
checkedAt: entitlement ? new Date(entitlement.checkedAt).toISOString() : null,
|
|
307
|
+
error: lastError,
|
|
308
|
+
modules,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/** For tests: forget what the account said. */
|
|
312
|
+
export function resetProForTests() {
|
|
313
|
+
listing = null;
|
|
314
|
+
lastError = null;
|
|
315
|
+
setEntitlement(null);
|
|
316
|
+
}
|
|
@@ -93,13 +93,15 @@ export async function renderDownload(step, output, format, baseName) {
|
|
|
93
93
|
const data = format === "html"
|
|
94
94
|
? html
|
|
95
95
|
: await cachedRender(source, format, async () => {
|
|
96
|
+
// Pictures the widget took from the web are assets: the renderer gets them inline.
|
|
97
|
+
const inlined = await inlineAssetRefs(html);
|
|
96
98
|
switch (format) {
|
|
97
99
|
case "png":
|
|
98
|
-
return widgetPng(
|
|
100
|
+
return widgetPng(inlined, size);
|
|
99
101
|
case "pdf":
|
|
100
|
-
return widgetPdf(
|
|
102
|
+
return widgetPdf(inlined, size);
|
|
101
103
|
case "mp4":
|
|
102
|
-
return output.widget?.duration ? widgetMp4(
|
|
104
|
+
return output.widget?.duration ? widgetMp4(inlined, size) : null;
|
|
103
105
|
default:
|
|
104
106
|
return null;
|
|
105
107
|
}
|
|
@@ -3,6 +3,7 @@ import { Hono } from "hono";
|
|
|
3
3
|
import { streamSSE } from "hono/streaming";
|
|
4
4
|
import { managed } from "../manage.js";
|
|
5
5
|
import { pluginProblems, reloadPlugin, rescanPlugins } from "../plugins/loader.js";
|
|
6
|
+
import { installPro, proState, refreshPro, removePro } from "../plugins/pro.js";
|
|
6
7
|
import { loadedPlugin, onPluginChange, pluginAsset, pluginIdsOf, pluginsOf, } from "../plugins/registry.js";
|
|
7
8
|
const admin = (user) => user.role === "owner" || user.role === "admin";
|
|
8
9
|
/** Plugins change while the app runs only where it runs alone: a reload would hit every tenant. */
|
|
@@ -18,6 +19,8 @@ function view(plugin) {
|
|
|
18
19
|
version,
|
|
19
20
|
description: description ?? "",
|
|
20
21
|
generation: plugin.generation,
|
|
22
|
+
/** Installed from the linked account's plan (Settings → Plugins → Pro modules). */
|
|
23
|
+
pro: Boolean(plugin.source.pro),
|
|
21
24
|
/** Why the server half did not load; the plugin then adds nothing on the server. */
|
|
22
25
|
error: plugin.error,
|
|
23
26
|
script: script ? address("client.js", script.rev) : null,
|
|
@@ -155,6 +158,52 @@ export const pluginRoutes = new Hono()
|
|
|
155
158
|
return plugin
|
|
156
159
|
? c.json({ plugin: view(plugin) })
|
|
157
160
|
: c.json({ error: "not found", code: "not_found" }, 404);
|
|
161
|
+
})
|
|
162
|
+
// Pro modules: the closed plugins the linked account's plan includes (plugins/pro.ts).
|
|
163
|
+
.get("/-/pro", async (c) => {
|
|
164
|
+
if (!canReload(c.get("user"))) {
|
|
165
|
+
return c.json({ error: "not found", code: "not_found" }, 404);
|
|
166
|
+
}
|
|
167
|
+
return c.json(await proState());
|
|
168
|
+
})
|
|
169
|
+
.post("/-/pro/refresh", async (c) => {
|
|
170
|
+
if (!canReload(c.get("user"))) {
|
|
171
|
+
return c.json({ error: "forbidden", code: "forbidden" }, 403);
|
|
172
|
+
}
|
|
173
|
+
await refreshPro();
|
|
174
|
+
return c.json(await proState());
|
|
175
|
+
})
|
|
176
|
+
.post("/-/pro/:id", async (c) => {
|
|
177
|
+
if (!canReload(c.get("user"))) {
|
|
178
|
+
return c.json({ error: "forbidden", code: "forbidden" }, 403);
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
await installPro(c.req.param("id"));
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
const answer = answerOf(err);
|
|
185
|
+
if (answer) {
|
|
186
|
+
return c.json(answer.body, answer.status);
|
|
187
|
+
}
|
|
188
|
+
throw err;
|
|
189
|
+
}
|
|
190
|
+
return c.json(await proState());
|
|
191
|
+
})
|
|
192
|
+
.delete("/-/pro/:id", async (c) => {
|
|
193
|
+
if (!canReload(c.get("user"))) {
|
|
194
|
+
return c.json({ error: "forbidden", code: "forbidden" }, 403);
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
await removePro(c.req.param("id"));
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
const answer = answerOf(err);
|
|
201
|
+
if (answer) {
|
|
202
|
+
return c.json(answer.body, answer.status);
|
|
203
|
+
}
|
|
204
|
+
throw err;
|
|
205
|
+
}
|
|
206
|
+
return c.json(await proState());
|
|
158
207
|
})
|
|
159
208
|
.all("/:id", dispatch)
|
|
160
209
|
.all("/:id/*", dispatch);
|
|
@@ -27,6 +27,7 @@ import { seenApps } from "../mcp/seen.js";
|
|
|
27
27
|
import { generateImageMedia, generateSpeechMedia, generateVideoMedia } from "../media/generate.js";
|
|
28
28
|
import { transcribeAudio } from "../media/transcribe.js";
|
|
29
29
|
import { checkKey, classProblem, embeddingModel, hasTextModel, LOCAL_KEYS, localModelSettings, ModelUnavailableError, modelSettings, saveLocalModels, saveModels, storedKey, textModel, } from "../models.js";
|
|
30
|
+
import { refreshPro } from "../plugins/pro.js";
|
|
30
31
|
import { HTML_RESPONSE_CSP } from "../render/guard.js";
|
|
31
32
|
import { isAdminRole, mayBuild, mayCreate, projectWritable, requireWritable, } from "../services/access.js";
|
|
32
33
|
import { architectTurn } from "../services/architect.js";
|
|
@@ -1214,6 +1215,8 @@ export const studio = new Hono()
|
|
|
1214
1215
|
}
|
|
1215
1216
|
await unlink();
|
|
1216
1217
|
await forgetCloud();
|
|
1218
|
+
// Pro modules went with the account's plan; installed ones stay on disk.
|
|
1219
|
+
await refreshPro();
|
|
1217
1220
|
// Models that ran on the account's credits have nothing to run on now; another source stays.
|
|
1218
1221
|
if (localModelSettings().source === "account") {
|
|
1219
1222
|
await saveLocalModels({ source: "own" });
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { allFields, dataRef, widgetSize, } from "@engenty-wizards/shared/definition";
|
|
2
2
|
import { resolveRef } from "../engine/template.js";
|
|
3
3
|
import { StepError } from "../engine/types.js";
|
|
4
|
-
import { extFor, loadAsset } from "../files/storage.js";
|
|
4
|
+
import { extFor, inlineAssetRefs, loadAsset } from "../files/storage.js";
|
|
5
|
+
import { snapshotDataImages } from "../files/web-images.js";
|
|
5
6
|
import { markMedia } from "../media/marking.js";
|
|
6
7
|
import { mainLogoId } from "../services/brand.js";
|
|
7
8
|
import { snapshotFile } from "../services/files.js";
|
|
@@ -141,7 +142,10 @@ async function runFilmStep(step, ctx, html, data, media, origin) {
|
|
|
141
142
|
}
|
|
142
143
|
/** A widget step makes no model call: it binds this run's data into the widget and keeps the file. */
|
|
143
144
|
export async function runWidgetStep(step, ctx) {
|
|
144
|
-
const { data, media, origin } = await widgetData(step, ctx);
|
|
145
|
+
const { data: raw, media, origin } = await widgetData(step, ctx);
|
|
146
|
+
// Photos the data points to on the web (a listing, a product) are kept with the run: the
|
|
147
|
+
// page may load none itself.
|
|
148
|
+
const data = await snapshotDataImages(raw, ctx.saveAsset, step.id, ctx.signal);
|
|
145
149
|
const html = await bundleWidget({
|
|
146
150
|
entry: step.entry,
|
|
147
151
|
files: ctx.files,
|
|
@@ -150,12 +154,14 @@ export async function runWidgetStep(step, ctx) {
|
|
|
150
154
|
media: step.video ? FILM_MEDIA_ORIGIN : undefined,
|
|
151
155
|
ai: origin,
|
|
152
156
|
});
|
|
157
|
+
// What is shown and rendered carries those pictures inline; the kept page keeps the asset refs.
|
|
158
|
+
const shown = await inlineAssetRefs(html);
|
|
153
159
|
if (step.video) {
|
|
154
|
-
return runFilmStep(step, ctx,
|
|
160
|
+
return runFilmStep(step, ctx, shown, data, media, origin);
|
|
155
161
|
}
|
|
156
162
|
let probe = null;
|
|
157
163
|
try {
|
|
158
|
-
probe = await probeWidget(
|
|
164
|
+
probe = await probeWidget(shown, widgetSize(step));
|
|
159
165
|
}
|
|
160
166
|
catch (err) {
|
|
161
167
|
console.error(`[widget ${step.id}]`, err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{D as r,Q as i}from"./surface-D7bnQtqR.js";import{D as a,G as o,H as s,c,f as l,g as u,h as d,j as f,k as p,n as ee,o as m,r as h,s as g,t as _,x as v}from"./ui-BZ01zr3i.js";import{n as y,r as b}from"./upload-U0i8fAW3.js";import{t as x}from"./external-link-BwCtn1nW.js";import{B as te,H as S,I as C,U as w,W as T,_t as E,at as D,ft as O}from"./index-knnf98Fv.js";import{n as k}from"./LocalRuntime-CqBfKp8q.js";var A={name:`hard-drive`,size:24,node:[[`path`,{d:`M10 16h.01`,key:`1bzywj`}],[`path`,{d:`M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z`,key:`18tbho`}],[`path`,{d:`M21.946 12.013H2.054`,key:`zqlbp7`}],[`path`,{d:`M6 16h.01`,key:`1pmjb7`}]]};A.node;var j=o(A),M={name:`layout-grid`,size:24,node:[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]};M.node;var N=o(M),P={name:`list`,size:24,node:[[`path`,{d:`M3 5h.01`,key:`18ugdj`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M3 19h.01`,key:`noohij`}],[`path`,{d:`M8 5h13`,key:`1pao27`}],[`path`,{d:`M8 12h13`,key:`1za7za`}],[`path`,{d:`M8 19h13`,key:`m83p4d`}]]};P.node;var F=o(P),I=e(t(),1),L=e=>[`project-files`,e];function R(e){return r({queryKey:L(e),queryFn:()=>v.get(`/api/studio/projects/${e}/files`),refetchInterval:e=>e.state.data?.files.some(e=>e.status===`pending`)?2e3:!1})}function z(e,t){return a(`/api/studio/projects/${e}/files/${t}/content`)}function B(e,t=!1){let n=i(),[r,a]=(0,I.useState)(!1),[o,s]=(0,I.useState)(null),c=()=>n.invalidateQueries({queryKey:L(e)}),l=async e=>{s(null);try{await e()}catch(e){s(e.message)}finally{await c()}};return{busy:r,error:o,readOnly:t,upload:async(t,n)=>{a(!0),await l(async()=>{for(let r of n)await v.upload(`/api/studio/projects/${e}/files?kind=${t}`,r),await c()}),a(!1)},describe:(t,n)=>l(()=>v.patch(`/api/studio/projects/${e}/files/${t}`,{description:n})),remove:t=>l(()=>v.del(`/api/studio/projects/${e}/files/${t}`)),reindex:t=>l(()=>v.post(`/api/studio/projects/${e}/files/${t}/reindex`)),order:(t,n)=>l(()=>v.put(`/api/studio/projects/${e}/files/order`,{kind:t,ids:n}))}}function V(e,t){let n=`wz.layout.${e}`,[r,i]=(0,I.useState)(()=>{try{let e=localStorage.getItem(n);return e===`list`||e===`cards`?e:t}catch{return t}});return[r,()=>i(e=>{let t=e===`list`?`cards`:`list`;try{localStorage.setItem(n,t)}catch{}return t})]}function H(e,t,n=700){let[r,i]=(0,I.useState)(`idle`),[a,o]=(0,I.useState)(null),s=JSON.stringify(e),c=(0,I.useRef)(s),l=(0,I.useRef)({value:e,json:s,save:t});l.current={value:e,json:s,save:t};let u=(0,I.useRef)(Promise.resolve()),d=(0,I.useCallback)(()=>{let e=l.current;e.json!==c.current&&(c.current=e.json,i(`saving`),u.current=u.current.then(async()=>{try{await e.save(e.value),o(null),i(`saved`)}catch(e){c.current=``,o(e.message),i(`error`)}}))},[]);return(0,I.useEffect)(()=>{if(s===c.current)return;let e=setTimeout(d,n);return()=>clearTimeout(e)},[s,n,d]),(0,I.useEffect)(()=>d,[d]),{state:r,error:a}}function U(e){return e<1e6?`${Math.max(1,Math.round(e/1e3))} KB`:`${(e/1e6).toFixed(1)} MB`}var W=e(n(),1);function G({id:e,children:t}){return(0,W.jsx)(`div`,{id:e,className:`scroll-mt-24 max-md:scroll-mt-36`,children:t})}function K({title:e,hint:t,save:n,action:r,locked:i,plain:a,children:o}){return(0,W.jsxs)(`section`,{className:`flex flex-col gap-2.5`,children:[(0,W.jsxs)(`div`,{className:`flex items-start justify-between gap-4 px-1`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,W.jsx)(`h2`,{className:`font-display font-semibold text-lg leading-tight`,children:e}),n?.state===`saving`?(0,W.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 text-[0.75rem] text-ink-3`,children:[(0,W.jsx)(l,{className:`size-3`}),` `,f(`project.saving`)]}):n?.state===`saved`?(0,W.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-[0.75rem] text-moss`,children:[(0,W.jsx)(s,{className:`size-3.5`}),` `,f(`settings.saved`)]}):null]}),t?(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-snug`,children:t}):null]}),r?(0,W.jsx)(`div`,{className:`shrink-0`,children:r}):null]}),a?o:(0,W.jsxs)(ee,{className:`p-3.5 sm:p-5`,children:[i?(0,W.jsx)(`fieldset`,{disabled:!0,className:`min-w-0`,children:o}):o,n?.state===`error`&&n.error?(0,W.jsx)(`p`,{className:`mt-4 text-[0.875rem] text-rose`,children:n.error}):null]})]})}function q({children:e,layout:t,onToggle:n}){return(0,W.jsxs)(`div`,{className:`mb-3 flex items-start gap-2`,children:[(0,W.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,W.jsx)(`div`,{className:`w-56 max-w-full transition-[width] duration-200 focus-within:w-full has-[input:not(:placeholder-shown)]:w-full`,children:e})}),(0,W.jsx)(m,{label:f(t===`list`?`project.viewCards`:`project.viewList`),onClick:n,children:t===`list`?(0,W.jsx)(N,{className:`size-4`}):(0,W.jsx)(F,{className:`size-4`})})]})}function J({value:e,onChange:t,onEnter:n,placeholder:r,busy:i}){return(0,W.jsxs)(`div`,{className:`relative`,children:[(0,W.jsx)(y,{className:`-translate-y-1/2 pointer-events-none absolute top-1/2 left-3 size-4 text-ink-4`}),(0,W.jsx)(`input`,{type:`search`,value:e,placeholder:r,onChange:e=>t(e.target.value),onKeyDown:e=>e.key===`Enter`&&n?.(),className:`h-9 w-full rounded-lg border border-input bg-card pr-3 pl-9 text-[0.875rem] text-ink outline-none transition placeholder:text-ink-4 focus:border-focus focus:ring-4 focus:ring-focus-glow`}),i?(0,W.jsx)(l,{className:`-translate-y-1/2 absolute top-1/2 right-3 size-4 text-ink-3`}):null]})}function Y({onFiles:e,accept:t,multiple:n=!0,className:r,children:i}){return(0,W.jsxs)(`label`,{onDragOver:e=>{e.preventDefault(),e.currentTarget.dataset.over=`1`},onDragLeave:e=>{delete e.currentTarget.dataset.over},onDrop:t=>{t.preventDefault(),delete t.currentTarget.dataset.over;let r=Array.from(t.dataTransfer.files);r.length&&e(n?r:r.slice(0,1))},className:u(`flex cursor-pointer items-center justify-center gap-2 rounded-lg border border-input border-dashed text-[0.875rem] text-ink-3 transition focus-within:border-focus focus-within:ring-4 focus-within:ring-focus-glow hover:border-ink-4 hover:text-ink data-[over]:border-focus data-[over]:bg-paper-2 data-[over]:text-ink`,r),children:[i,(0,W.jsx)(`input`,{className:`sr-only`,type:`file`,accept:t,multiple:n,onChange:t=>{let n=Array.from(t.target.files??[]);t.target.value=``,n.length&&e(n)}})]})}var X=`mt-1.5 text-[0.8125rem] text-ink-3`;function Z(e){let t=i(),[n,r]=(0,I.useState)(!1),a=E({mutationFn:e=>v.post(`/api/studio/account/link`,e),onSuccess:({url:e})=>{k(e),r(!0)}});return(0,I.useEffect)(()=>{if(!n)return;let e=setInterval(()=>void t.invalidateQueries({queryKey:[`me`]}),2e3),i=setTimeout(()=>r(!1),3e5);return()=>{clearInterval(e),clearTimeout(i)}},[n,t]),(0,I.useEffect)(()=>{e&&r(!1)},[e]),{link:a,waiting:n}}function Q({link:e,waiting:t}){return e.isError?(0,W.jsx)(`p`,{className:`text-[0.8125rem] text-rose`,children:f(`local.accountFailed`)}):t?(0,W.jsxs)(`p`,{className:`flex items-center gap-2 text-[0.8125rem] text-ink-3`,children:[(0,W.jsx)(l,{className:`size-3.5`}),` `,f(`local.accountWaiting`)]}):null}function ne(){let e=Z(!1),{link:t}=e,[n,r]=(0,I.useState)(``);return(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex items-start gap-4 py-5 first:pt-0 last:pb-0`,children:[(0,W.jsx)(`div`,{className:`flex size-11 shrink-0 items-center justify-center rounded-full bg-paper-2 text-ink-2`,children:(0,W.jsx)(j,{className:`size-5`})}),(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:f(`account.local`)}),(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-relaxed`,children:f(`account.localText`)})]})]}),w.account?(0,W.jsxs)(`div`,{className:`flex flex-col gap-4 py-5 last:pb-0`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:f(`account.with`)}),(0,W.jsxs)(`ul`,{className:`mt-2 flex flex-col gap-2 text-[0.875rem] text-ink-2 leading-snug`,children:[(0,W.jsxs)(`li`,{className:`flex items-start gap-2.5`,children:[(0,W.jsx)(b,{className:`mt-0.5 size-4 shrink-0 text-amber`}),f(`account.withCredits`)]}),(0,W.jsxs)(`li`,{className:`flex items-start gap-2.5`,children:[(0,W.jsx)(O,{className:`mt-0.5 size-4 shrink-0 text-cobalt`}),f(`account.withCloud`)]})]})]}),(0,W.jsx)(`div`,{children:(0,W.jsx)(_,{busy:t.isPending&&!t.variables?.signup,onClick:()=>t.mutate({}),children:f(`account.signIn`)})})]}):null,w.account?(0,W.jsxs)(`form`,{className:`flex flex-col gap-3 py-5 last:pb-0`,onSubmit:e=>{e.preventDefault(),t.mutate({signup:!0,code:n.trim()||void 0})},children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:f(`account.new`)}),(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-relaxed`,children:f(`account.newHint`)})]}),(0,W.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,W.jsx)(g,{value:n,maxLength:64,autoComplete:`off`,spellCheck:!1,placeholder:f(`account.code`),"aria-label":f(`account.code`),onChange:e=>r(e.target.value),className:`w-56 font-mono text-[0.875rem]`}),(0,W.jsx)(_,{type:`submit`,variant:`secondary`,className:`h-11`,busy:t.isPending&&!!t.variables?.signup,children:f(`account.create`)})]}),(0,W.jsx)(Q,{...e})]}):null]})}var $={start:`account.kind.start`,monthly:`account.kind.monthly`,gift:`account.kind.gift`};function re({account:e}){let t=i(),n=Z(e.signedIn),r=E({mutationFn:()=>v.del(`/api/studio/account`),onSuccess:()=>t.invalidateQueries({queryKey:[`me`]})}),a=new Intl.DateTimeFormat(p,{dateStyle:`medium`});return(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-4 gap-y-3 py-5 first:pt-0`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,W.jsx)(`span`,{className:`truncate font-medium text-[0.9375rem]`,children:e.name||e.email}),e.signedIn?(0,W.jsx)(h,{tone:`live`,children:f(`account.linked`)}):null]}),(0,W.jsx)(`div`,{className:`truncate text-[0.875rem] text-ink-3`,children:e.email})]}),(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,W.jsxs)(_,{variant:`secondary`,onClick:()=>k(e.url),children:[f(`setup.openAccount`),` `,(0,W.jsx)(x,{className:`size-4`})]}),(0,W.jsxs)(_,{variant:`ghost`,busy:r.isPending,onClick:()=>r.mutate(),children:[(0,W.jsx)(D,{className:`size-4`}),` `,f(`nav.logout`)]})]})]}),e.signedIn?null:(0,W.jsxs)(`div`,{className:`flex flex-col gap-3 py-5`,children:[(0,W.jsx)(`p`,{className:`text-[0.875rem] text-ink-2`,children:f(`local.accountExpired`)}),(0,W.jsx)(`div`,{children:(0,W.jsx)(_,{busy:n.link.isPending,onClick:()=>n.link.mutate({}),children:f(`account.signInAgain`)})}),(0,W.jsx)(Q,{...n})]}),e.credits===null?null:(0,W.jsxs)(`div`,{className:`py-5`,children:[(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-4 gap-y-3`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsx)(`div`,{className:`text-[0.8125rem] text-ink-3`,children:f(`account.credits`)}),(0,W.jsx)(`div`,{className:`font-display font-semibold text-[1.375rem] tabular-nums leading-tight`,children:f(`nav.credits`,{n:Math.floor(e.credits).toLocaleString()})})]}),(0,W.jsxs)(_,{variant:`secondary`,onClick:()=>k(`${e.url}/billing`),children:[f(`account.topUp`),` `,(0,W.jsx)(x,{className:`size-4`})]})]}),e.expiring.length?(0,W.jsx)(`ul`,{className:`mt-3 flex flex-col gap-1 text-[0.8125rem] text-ink-3 tabular-nums`,children:e.expiring.map(e=>(0,W.jsxs)(`li`,{children:[f(`account.expires`,{n:Math.floor(e.credits).toLocaleString(),date:a.format(new Date(e.expiresAt))}),$[e.kind]?(0,W.jsxs)(`span`,{className:`text-ink-4`,children:[` · `,f($[e.kind])]}):null]},`${e.kind}:${e.expiresAt}`))}):null]}),(0,W.jsxs)(`div`,{className:`flex items-start gap-2.5 py-5 text-[0.875rem] text-ink-2 leading-snug last:pb-0`,children:[(0,W.jsx)(O,{className:`mt-0.5 size-4 shrink-0 text-cobalt`}),(0,W.jsx)(`p`,{children:f(`account.cloud`,{host:C(e.cloudUrl)})})]})]})}function ie({me:e,fromAccount:t}){let n=i(),[r,a]=(0,I.useState)(e.profile),o=e=>a(t=>({...t,...e})),s=H(r,async e=>{await v.put(`/api/studio/profile`,e),await n.invalidateQueries({queryKey:[`me`]})});return(0,W.jsx)(K,{title:f(`account.profile`),hint:f(`account.hint`),save:s,children:(0,W.jsxs)(`div`,{className:`flex flex-col gap-6 sm:flex-row sm:gap-8`,children:[(0,W.jsxs)(`div`,{className:`flex shrink-0 flex-col items-center gap-2 sm:w-32`,children:[(0,W.jsx)(`div`,{className:`flex size-20 items-center justify-center overflow-hidden rounded-full bg-ember-tint font-semibold text-[1.75rem] text-ember-strong ring-1 ring-border-soft`,children:e.user.image?(0,W.jsx)(`img`,{src:e.user.image,alt:``,className:`size-full object-cover`}):T(r.name)||`?`}),(0,W.jsx)(`p`,{className:`text-center text-[0.75rem] text-ink-3 leading-snug`,children:f(`account.initials`)})]}),(0,W.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-5`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.name`)}),(0,W.jsx)(g,{value:r.name,maxLength:80,disabled:t,onChange:e=>o({name:e.target.value})}),(0,W.jsx)(`p`,{className:X,children:f(t?`account.fromAccount`:`account.nameHint`)})]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.about`)}),(0,W.jsx)(d,{minRows:3,maxLength:2e3,value:r.about,onChange:e=>o({about:e.target.value})}),(0,W.jsx)(`p`,{className:X,children:f(`account.aboutHint`)})]}),(0,W.jsxs)(`div`,{className:`grid gap-5 sm:grid-cols-2`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.email`)}),(0,W.jsx)(g,{type:`email`,value:r.email,maxLength:200,disabled:t,onChange:e=>o({email:e.target.value})})]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.phone`)}),(0,W.jsx)(g,{type:`tel`,value:r.phone,maxLength:40,onChange:e=>o({phone:e.target.value})})]})]})]})]})})}function ae({me:e}){let t=e.mode===`managed`,n=t||!!e.account;return(0,W.jsxs)(`div`,{className:`flex flex-col gap-9`,children:[(0,W.jsx)(K,{title:f(`account.connection`),hint:f(`account.connectionHint`),children:t?(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,W.jsx)(`span`,{className:`truncate font-medium text-[0.9375rem]`,children:e.user.name}),(0,W.jsx)(h,{tone:`live`,children:f(`account.linked`)})]}),(0,W.jsx)(`div`,{className:`truncate text-[0.875rem] text-ink-3`,children:e.user.email})]}),e.manageUrl?(0,W.jsxs)(_,{variant:`secondary`,onClick:()=>k(`${e.manageUrl}/account`),children:[f(`setup.openAccount`),` `,(0,W.jsx)(x,{className:`size-4`})]}):null]}):e.account?(0,W.jsx)(re,{account:e.account}):(0,W.jsx)(ne,{})}),(0,W.jsx)(ie,{me:e,fromAccount:n},n?`account`:`own`),(0,W.jsx)(K,{title:f(`account.look`),hint:f(`account.lookHint`),children:(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between gap-4 pb-4`,children:[(0,W.jsx)(`span`,{className:`font-medium text-[0.875rem]`,children:f(`nav.language`)}),(0,W.jsx)(S,{tone:`surface`})]}),(0,W.jsxs)(`div`,{className:`flex items-center justify-between gap-4 pt-4`,children:[(0,W.jsx)(`span`,{className:`font-medium text-[0.875rem]`,children:f(`nav.theme`)}),(0,W.jsx)(te,{})]})]})})]})}export{Y as a,K as c,H as d,B as f,N as h,G as i,U as l,R as m,Q as n,q as o,V as p,Z as r,J as s,ae as t,z as u};
|
|
1
|
+
import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{D as r,Q as i}from"./surface-BFwNWkx9.js";import{D as a,G as o,H as s,c,f as l,g as u,h as d,j as f,k as p,n as ee,o as m,r as h,s as g,t as _,x as v}from"./ui-BTkH_7CG.js";import{n as y,r as b}from"./upload-Dok4YeXQ.js";import{t as x}from"./external-link-DvkH63pi.js";import{B as te,H as S,I as C,U as w,W as T,_t as E,at as D,ft as O}from"./index-CYZmm7HU.js";import{n as k}from"./LocalRuntime-DMU_dzV1.js";var A={name:`hard-drive`,size:24,node:[[`path`,{d:`M10 16h.01`,key:`1bzywj`}],[`path`,{d:`M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z`,key:`18tbho`}],[`path`,{d:`M21.946 12.013H2.054`,key:`zqlbp7`}],[`path`,{d:`M6 16h.01`,key:`1pmjb7`}]]};A.node;var j=o(A),M={name:`layout-grid`,size:24,node:[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]};M.node;var N=o(M),P={name:`list`,size:24,node:[[`path`,{d:`M3 5h.01`,key:`18ugdj`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M3 19h.01`,key:`noohij`}],[`path`,{d:`M8 5h13`,key:`1pao27`}],[`path`,{d:`M8 12h13`,key:`1za7za`}],[`path`,{d:`M8 19h13`,key:`m83p4d`}]]};P.node;var F=o(P),I=e(t(),1),L=e=>[`project-files`,e];function R(e){return r({queryKey:L(e),queryFn:()=>v.get(`/api/studio/projects/${e}/files`),refetchInterval:e=>e.state.data?.files.some(e=>e.status===`pending`)?2e3:!1})}function z(e,t){return a(`/api/studio/projects/${e}/files/${t}/content`)}function B(e,t=!1){let n=i(),[r,a]=(0,I.useState)(!1),[o,s]=(0,I.useState)(null),c=()=>n.invalidateQueries({queryKey:L(e)}),l=async e=>{s(null);try{await e()}catch(e){s(e.message)}finally{await c()}};return{busy:r,error:o,readOnly:t,upload:async(t,n)=>{a(!0),await l(async()=>{for(let r of n)await v.upload(`/api/studio/projects/${e}/files?kind=${t}`,r),await c()}),a(!1)},describe:(t,n)=>l(()=>v.patch(`/api/studio/projects/${e}/files/${t}`,{description:n})),remove:t=>l(()=>v.del(`/api/studio/projects/${e}/files/${t}`)),reindex:t=>l(()=>v.post(`/api/studio/projects/${e}/files/${t}/reindex`)),order:(t,n)=>l(()=>v.put(`/api/studio/projects/${e}/files/order`,{kind:t,ids:n}))}}function V(e,t){let n=`wz.layout.${e}`,[r,i]=(0,I.useState)(()=>{try{let e=localStorage.getItem(n);return e===`list`||e===`cards`?e:t}catch{return t}});return[r,()=>i(e=>{let t=e===`list`?`cards`:`list`;try{localStorage.setItem(n,t)}catch{}return t})]}function H(e,t,n=700){let[r,i]=(0,I.useState)(`idle`),[a,o]=(0,I.useState)(null),s=JSON.stringify(e),c=(0,I.useRef)(s),l=(0,I.useRef)({value:e,json:s,save:t});l.current={value:e,json:s,save:t};let u=(0,I.useRef)(Promise.resolve()),d=(0,I.useCallback)(()=>{let e=l.current;e.json!==c.current&&(c.current=e.json,i(`saving`),u.current=u.current.then(async()=>{try{await e.save(e.value),o(null),i(`saved`)}catch(e){c.current=``,o(e.message),i(`error`)}}))},[]);return(0,I.useEffect)(()=>{if(s===c.current)return;let e=setTimeout(d,n);return()=>clearTimeout(e)},[s,n,d]),(0,I.useEffect)(()=>d,[d]),{state:r,error:a}}function U(e){return e<1e6?`${Math.max(1,Math.round(e/1e3))} KB`:`${(e/1e6).toFixed(1)} MB`}var W=e(n(),1);function G({id:e,children:t}){return(0,W.jsx)(`div`,{id:e,className:`scroll-mt-24 max-md:scroll-mt-36`,children:t})}function K({title:e,hint:t,save:n,action:r,locked:i,plain:a,children:o}){return(0,W.jsxs)(`section`,{className:`flex flex-col gap-2.5`,children:[(0,W.jsxs)(`div`,{className:`flex items-start justify-between gap-4 px-1`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,W.jsx)(`h2`,{className:`font-display font-semibold text-lg leading-tight`,children:e}),n?.state===`saving`?(0,W.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 text-[0.75rem] text-ink-3`,children:[(0,W.jsx)(l,{className:`size-3`}),` `,f(`project.saving`)]}):n?.state===`saved`?(0,W.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-[0.75rem] text-moss`,children:[(0,W.jsx)(s,{className:`size-3.5`}),` `,f(`settings.saved`)]}):null]}),t?(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-snug`,children:t}):null]}),r?(0,W.jsx)(`div`,{className:`shrink-0`,children:r}):null]}),a?o:(0,W.jsxs)(ee,{className:`p-3.5 sm:p-5`,children:[i?(0,W.jsx)(`fieldset`,{disabled:!0,className:`min-w-0`,children:o}):o,n?.state===`error`&&n.error?(0,W.jsx)(`p`,{className:`mt-4 text-[0.875rem] text-rose`,children:n.error}):null]})]})}function q({children:e,layout:t,onToggle:n}){return(0,W.jsxs)(`div`,{className:`mb-3 flex items-start gap-2`,children:[(0,W.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,W.jsx)(`div`,{className:`w-56 max-w-full transition-[width] duration-200 focus-within:w-full has-[input:not(:placeholder-shown)]:w-full`,children:e})}),(0,W.jsx)(m,{label:f(t===`list`?`project.viewCards`:`project.viewList`),onClick:n,children:t===`list`?(0,W.jsx)(N,{className:`size-4`}):(0,W.jsx)(F,{className:`size-4`})})]})}function J({value:e,onChange:t,onEnter:n,placeholder:r,busy:i}){return(0,W.jsxs)(`div`,{className:`relative`,children:[(0,W.jsx)(y,{className:`-translate-y-1/2 pointer-events-none absolute top-1/2 left-3 size-4 text-ink-4`}),(0,W.jsx)(`input`,{type:`search`,value:e,placeholder:r,onChange:e=>t(e.target.value),onKeyDown:e=>e.key===`Enter`&&n?.(),className:`h-9 w-full rounded-lg border border-input bg-card pr-3 pl-9 text-[0.875rem] text-ink outline-none transition placeholder:text-ink-4 focus:border-focus focus:ring-4 focus:ring-focus-glow`}),i?(0,W.jsx)(l,{className:`-translate-y-1/2 absolute top-1/2 right-3 size-4 text-ink-3`}):null]})}function Y({onFiles:e,accept:t,multiple:n=!0,className:r,children:i}){return(0,W.jsxs)(`label`,{onDragOver:e=>{e.preventDefault(),e.currentTarget.dataset.over=`1`},onDragLeave:e=>{delete e.currentTarget.dataset.over},onDrop:t=>{t.preventDefault(),delete t.currentTarget.dataset.over;let r=Array.from(t.dataTransfer.files);r.length&&e(n?r:r.slice(0,1))},className:u(`flex cursor-pointer items-center justify-center gap-2 rounded-lg border border-input border-dashed text-[0.875rem] text-ink-3 transition focus-within:border-focus focus-within:ring-4 focus-within:ring-focus-glow hover:border-ink-4 hover:text-ink data-[over]:border-focus data-[over]:bg-paper-2 data-[over]:text-ink`,r),children:[i,(0,W.jsx)(`input`,{className:`sr-only`,type:`file`,accept:t,multiple:n,onChange:t=>{let n=Array.from(t.target.files??[]);t.target.value=``,n.length&&e(n)}})]})}var X=`mt-1.5 text-[0.8125rem] text-ink-3`;function Z(e){let t=i(),[n,r]=(0,I.useState)(!1),a=E({mutationFn:e=>v.post(`/api/studio/account/link`,e),onSuccess:({url:e})=>{k(e),r(!0)}});return(0,I.useEffect)(()=>{if(!n)return;let e=setInterval(()=>void t.invalidateQueries({queryKey:[`me`]}),2e3),i=setTimeout(()=>r(!1),3e5);return()=>{clearInterval(e),clearTimeout(i)}},[n,t]),(0,I.useEffect)(()=>{e&&r(!1)},[e]),{link:a,waiting:n}}function Q({link:e,waiting:t}){return e.isError?(0,W.jsx)(`p`,{className:`text-[0.8125rem] text-rose`,children:f(`local.accountFailed`)}):t?(0,W.jsxs)(`p`,{className:`flex items-center gap-2 text-[0.8125rem] text-ink-3`,children:[(0,W.jsx)(l,{className:`size-3.5`}),` `,f(`local.accountWaiting`)]}):null}function ne(){let e=Z(!1),{link:t}=e,[n,r]=(0,I.useState)(``);return(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex items-start gap-4 py-5 first:pt-0 last:pb-0`,children:[(0,W.jsx)(`div`,{className:`flex size-11 shrink-0 items-center justify-center rounded-full bg-paper-2 text-ink-2`,children:(0,W.jsx)(j,{className:`size-5`})}),(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:f(`account.local`)}),(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-relaxed`,children:f(`account.localText`)})]})]}),w.account?(0,W.jsxs)(`div`,{className:`flex flex-col gap-4 py-5 last:pb-0`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:f(`account.with`)}),(0,W.jsxs)(`ul`,{className:`mt-2 flex flex-col gap-2 text-[0.875rem] text-ink-2 leading-snug`,children:[(0,W.jsxs)(`li`,{className:`flex items-start gap-2.5`,children:[(0,W.jsx)(b,{className:`mt-0.5 size-4 shrink-0 text-amber`}),f(`account.withCredits`)]}),(0,W.jsxs)(`li`,{className:`flex items-start gap-2.5`,children:[(0,W.jsx)(O,{className:`mt-0.5 size-4 shrink-0 text-cobalt`}),f(`account.withCloud`)]})]})]}),(0,W.jsx)(`div`,{children:(0,W.jsx)(_,{busy:t.isPending&&!t.variables?.signup,onClick:()=>t.mutate({}),children:f(`account.signIn`)})})]}):null,w.account?(0,W.jsxs)(`form`,{className:`flex flex-col gap-3 py-5 last:pb-0`,onSubmit:e=>{e.preventDefault(),t.mutate({signup:!0,code:n.trim()||void 0})},children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:f(`account.new`)}),(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-relaxed`,children:f(`account.newHint`)})]}),(0,W.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,W.jsx)(g,{value:n,maxLength:64,autoComplete:`off`,spellCheck:!1,placeholder:f(`account.code`),"aria-label":f(`account.code`),onChange:e=>r(e.target.value),className:`w-56 font-mono text-[0.875rem]`}),(0,W.jsx)(_,{type:`submit`,variant:`secondary`,className:`h-11`,busy:t.isPending&&!!t.variables?.signup,children:f(`account.create`)})]}),(0,W.jsx)(Q,{...e})]}):null]})}var $={start:`account.kind.start`,monthly:`account.kind.monthly`,gift:`account.kind.gift`};function re({account:e}){let t=i(),n=Z(e.signedIn),r=E({mutationFn:()=>v.del(`/api/studio/account`),onSuccess:()=>t.invalidateQueries({queryKey:[`me`]})}),a=new Intl.DateTimeFormat(p,{dateStyle:`medium`});return(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-4 gap-y-3 py-5 first:pt-0`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,W.jsx)(`span`,{className:`truncate font-medium text-[0.9375rem]`,children:e.name||e.email}),e.signedIn?(0,W.jsx)(h,{tone:`live`,children:f(`account.linked`)}):null]}),(0,W.jsx)(`div`,{className:`truncate text-[0.875rem] text-ink-3`,children:e.email})]}),(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,W.jsxs)(_,{variant:`secondary`,onClick:()=>k(e.url),children:[f(`setup.openAccount`),` `,(0,W.jsx)(x,{className:`size-4`})]}),(0,W.jsxs)(_,{variant:`ghost`,busy:r.isPending,onClick:()=>r.mutate(),children:[(0,W.jsx)(D,{className:`size-4`}),` `,f(`nav.logout`)]})]})]}),e.signedIn?null:(0,W.jsxs)(`div`,{className:`flex flex-col gap-3 py-5`,children:[(0,W.jsx)(`p`,{className:`text-[0.875rem] text-ink-2`,children:f(`local.accountExpired`)}),(0,W.jsx)(`div`,{children:(0,W.jsx)(_,{busy:n.link.isPending,onClick:()=>n.link.mutate({}),children:f(`account.signInAgain`)})}),(0,W.jsx)(Q,{...n})]}),e.credits===null?null:(0,W.jsxs)(`div`,{className:`py-5`,children:[(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-4 gap-y-3`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsx)(`div`,{className:`text-[0.8125rem] text-ink-3`,children:f(`account.credits`)}),(0,W.jsx)(`div`,{className:`font-display font-semibold text-[1.375rem] tabular-nums leading-tight`,children:f(`nav.credits`,{n:Math.floor(e.credits).toLocaleString()})})]}),(0,W.jsxs)(_,{variant:`secondary`,onClick:()=>k(`${e.url}/billing`),children:[f(`account.topUp`),` `,(0,W.jsx)(x,{className:`size-4`})]})]}),e.expiring.length?(0,W.jsx)(`ul`,{className:`mt-3 flex flex-col gap-1 text-[0.8125rem] text-ink-3 tabular-nums`,children:e.expiring.map(e=>(0,W.jsxs)(`li`,{children:[f(`account.expires`,{n:Math.floor(e.credits).toLocaleString(),date:a.format(new Date(e.expiresAt))}),$[e.kind]?(0,W.jsxs)(`span`,{className:`text-ink-4`,children:[` · `,f($[e.kind])]}):null]},`${e.kind}:${e.expiresAt}`))}):null]}),(0,W.jsxs)(`div`,{className:`flex items-start gap-2.5 py-5 text-[0.875rem] text-ink-2 leading-snug last:pb-0`,children:[(0,W.jsx)(O,{className:`mt-0.5 size-4 shrink-0 text-cobalt`}),(0,W.jsx)(`p`,{children:f(`account.cloud`,{host:C(e.cloudUrl)})})]})]})}function ie({me:e,fromAccount:t}){let n=i(),[r,a]=(0,I.useState)(e.profile),o=e=>a(t=>({...t,...e})),s=H(r,async e=>{await v.put(`/api/studio/profile`,e),await n.invalidateQueries({queryKey:[`me`]})});return(0,W.jsx)(K,{title:f(`account.profile`),hint:f(`account.hint`),save:s,children:(0,W.jsxs)(`div`,{className:`flex flex-col gap-6 sm:flex-row sm:gap-8`,children:[(0,W.jsxs)(`div`,{className:`flex shrink-0 flex-col items-center gap-2 sm:w-32`,children:[(0,W.jsx)(`div`,{className:`flex size-20 items-center justify-center overflow-hidden rounded-full bg-ember-tint font-semibold text-[1.75rem] text-ember-strong ring-1 ring-border-soft`,children:e.user.image?(0,W.jsx)(`img`,{src:e.user.image,alt:``,className:`size-full object-cover`}):T(r.name)||`?`}),(0,W.jsx)(`p`,{className:`text-center text-[0.75rem] text-ink-3 leading-snug`,children:f(`account.initials`)})]}),(0,W.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-5`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.name`)}),(0,W.jsx)(g,{value:r.name,maxLength:80,disabled:t,onChange:e=>o({name:e.target.value})}),(0,W.jsx)(`p`,{className:X,children:f(t?`account.fromAccount`:`account.nameHint`)})]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.about`)}),(0,W.jsx)(d,{minRows:3,maxLength:2e3,value:r.about,onChange:e=>o({about:e.target.value})}),(0,W.jsx)(`p`,{className:X,children:f(`account.aboutHint`)})]}),(0,W.jsxs)(`div`,{className:`grid gap-5 sm:grid-cols-2`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.email`)}),(0,W.jsx)(g,{type:`email`,value:r.email,maxLength:200,disabled:t,onChange:e=>o({email:e.target.value})})]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.phone`)}),(0,W.jsx)(g,{type:`tel`,value:r.phone,maxLength:40,onChange:e=>o({phone:e.target.value})})]})]})]})]})})}function ae({me:e}){let t=e.mode===`managed`,n=t||!!e.account;return(0,W.jsxs)(`div`,{className:`flex flex-col gap-9`,children:[(0,W.jsx)(K,{title:f(`account.connection`),hint:f(`account.connectionHint`),children:t?(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,W.jsx)(`span`,{className:`truncate font-medium text-[0.9375rem]`,children:e.user.name}),(0,W.jsx)(h,{tone:`live`,children:f(`account.linked`)})]}),(0,W.jsx)(`div`,{className:`truncate text-[0.875rem] text-ink-3`,children:e.user.email})]}),e.manageUrl?(0,W.jsxs)(_,{variant:`secondary`,onClick:()=>k(`${e.manageUrl}/account`),children:[f(`setup.openAccount`),` `,(0,W.jsx)(x,{className:`size-4`})]}):null]}):e.account?(0,W.jsx)(re,{account:e.account}):(0,W.jsx)(ne,{})}),(0,W.jsx)(ie,{me:e,fromAccount:n},n?`account`:`own`),(0,W.jsx)(K,{title:f(`account.look`),hint:f(`account.lookHint`),children:(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between gap-4 pb-4`,children:[(0,W.jsx)(`span`,{className:`font-medium text-[0.875rem]`,children:f(`nav.language`)}),(0,W.jsx)(S,{tone:`surface`})]}),(0,W.jsxs)(`div`,{className:`flex items-center justify-between gap-4 pt-4`,children:[(0,W.jsx)(`span`,{className:`font-medium text-[0.875rem]`,children:f(`nav.theme`)}),(0,W.jsx)(te,{})]})]})})]})}export{Y as a,K as c,H as d,B as f,N as h,G as i,U as l,R as m,Q as n,q as o,V as p,Z as r,J as s,ae as t,z as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{t as r}from"./preload-helper-CNEI7N0N.js";import{a as i,f as a,g as o,i as s,j as c,s as l}from"./ui-
|
|
1
|
+
import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{t as r}from"./preload-helper-CNEI7N0N.js";import{a as i,f as a,g as o,i as s,j as c,s as l}from"./ui-BTkH_7CG.js";var u=e(t(),1),d=e(n(),1);function f(e){switch(e.group){case`Added`:return{label:`NEW`,dot:`bg-moss`};case`Fixed`:return{label:`FIXED`,dot:`bg-amber`};case`Changed`:return{label:`CHANGED`,dot:`bg-cobalt`};case`Performance`:return{label:`PERFORMANCE`,dot:`bg-ember`};case`Deploy`:return{label:`DEPLOY`,dot:`bg-ink-4`};case`Docs`:return{label:`DOCS`,dot:`bg-ink-4`};default:return{label:`OTHER`,dot:`bg-ink-4`}}}var p=e=>e.version?e.version.replace(/^v/,``):c(`about.unreleased`),m=e=>e.timestamp?new Date(e.timestamp*1e3).toISOString().slice(0,10):``,h=e=>e.charAt(0).toUpperCase()+e.slice(1);function g(e,t){let n=t.trim().toLowerCase();if(!n)return e;let r=[];for(let t of e){if(`${p(t)} ${m(t)}`.toLowerCase().includes(n)){r.push(t);continue}let e=t.commits.filter(e=>`${f(e).label} ${e.scope??``} ${e.message}`.toLowerCase().includes(n));e.length>0&&r.push({...t,commits:e})}return r}async function _(e){if(e)try{let t=await fetch(`https://raw.githubusercontent.com/engenty/engenty-wizards/v${e}/apps/web/src/about/changelog.json`,{signal:AbortSignal.timeout(5e3)});if(t.ok)return await t.json()}catch{}return(await r(async()=>{let{default:e}=await import(`./changelog-D536XAHL.js`);return{default:e}},[])).default}function v({open:e,onClose:t,version:n}){let[r,v]=(0,u.useState)(null),[y,b]=(0,u.useState)(``);(0,u.useEffect)(()=>{if(!e||r)return;let t=!1;return _(n).then(e=>{t||v(e)}),()=>{t=!0}},[e,r,n]),(0,u.useEffect)(()=>{e||b(``)},[e]);let x=r?g(r,y):[];return(0,d.jsxs)(s,{open:e,onClose:t,title:c(`about.changelog`),wide:!0,children:[(0,d.jsx)(`p`,{className:`-mt-3 mb-4 text-[0.875rem] text-ink-3`,children:c(`about.changelogHint`)}),r===null?(0,d.jsx)(`div`,{className:`flex justify-center py-10 text-ink-3`,children:(0,d.jsx)(a,{})}):r.length===0?(0,d.jsx)(i,{children:c(`about.changelogEmpty`)}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(l,{type:`search`,value:y,placeholder:c(`about.search`),onChange:e=>b(e.target.value)}),x.length===0?(0,d.jsx)(i,{children:c(`about.noMatches`)}):null,x.map(e=>(0,d.jsxs)(`section`,{className:`mt-6`,children:[(0,d.jsxs)(`h3`,{className:`flex items-baseline gap-3 border-border-soft border-b pb-2 font-display font-semibold text-[1rem]`,children:[p(e),(0,d.jsx)(`span`,{className:`font-normal font-sans text-[0.8125rem] text-ink-3 tabular-nums`,children:m(e)})]}),(0,d.jsx)(`ul`,{className:`mt-3 flex flex-col gap-2`,children:e.commits.map(e=>{let t=f(e);return(0,d.jsxs)(`li`,{className:`flex items-start gap-2.5 text-[0.875rem]`,children:[(0,d.jsx)(`span`,{className:o(`mt-[7px] size-1.5 shrink-0 rounded-full`,t.dot)}),(0,d.jsxs)(`span`,{className:`min-w-0 text-ink-2`,children:[(0,d.jsxs)(`span`,{className:`font-semibold text-[0.75rem] text-ink tracking-wide`,children:[t.label,e.scope?` [${e.scope}]`:``]}),` `,h(e.message),e.breaking?(0,d.jsx)(`span`,{className:`ml-1.5 rounded-full bg-rose-tint px-1.5 py-0.5 font-medium text-[0.75rem] text-rose`,children:c(`about.breaking`)}):null]})]},e.id)})})]},e.version??`unreleased`))]})]})}export{v as ChangelogDialog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{t as r}from"./preload-helper-CNEI7N0N.js";import{a as i,f as a,i as o,j as s,k as c,s as l}from"./ui-
|
|
1
|
+
import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{t as r}from"./preload-helper-CNEI7N0N.js";import{a as i,f as a,i as o,j as s,k as c,s as l}from"./ui-BTkH_7CG.js";import{t as u}from"./external-link-DvkH63pi.js";var d=e(t(),1),f=[{name:`engenty wizards`,description:{de:`KI-Wizards aus einer Beschreibung, mit einem Link geteilt.`,en:`AI wizards built from a description, shared with a link.`},homepage:`https://github.com/engenty/engenty-wizards`,license:`FSL-1.1-MIT`},{name:`engenty`,description:{de:`Konnektoren, Datentabellen, Suche und die Engenties stammen aus dem engenty-Framework.`,en:`Connectors, data tables, search and the engenties come from the engenty framework.`},homepage:`https://github.com/engenty/engenty`,license:`FSL-1.1-MIT`}],p=[{name:`Mastra`,description:{de:`Agent-Framework hinter den KI-Schritten.`,en:`Agent framework behind the AI steps.`},homepage:`https://github.com/mastra-ai/mastra`,license:`Apache-2.0`},{name:`AI SDK`,description:{de:`Modell-Aufrufe für Text, Bild, Video und Sprache.`,en:`Model calls for text, image, video and speech.`},homepage:`https://github.com/vercel/ai`,license:`Apache-2.0`},{name:`Model Context Protocol`,description:{de:`MCP-Server zum Bauen von Wizards, MCP-Client für Werkzeuge der Schritte.`,en:`MCP server for building wizards, MCP client for the steps' tools.`},homepage:`https://github.com/modelcontextprotocol/typescript-sdk`,license:`MIT`},{name:`Hono`,description:{de:`HTTP-API der Runtime.`,en:`The runtime's HTTP API.`},homepage:`https://github.com/honojs/hono`,license:`MIT`},{name:`Drizzle ORM`,description:{de:`Schema und Migrationen der Datenbanken.`,en:`Schema and migrations of the databases.`},homepage:`https://github.com/drizzle-team/drizzle-orm`,license:`Apache-2.0`},{name:`libSQL`,description:{de:`Eine Datenbank je Mandant, lokal als Datei oder bei Turso.`,en:`One database per tenant, a local file or at Turso.`},homepage:`https://github.com/tursodatabase/libsql`,license:`MIT`},{name:`Playwright`,description:{de:`Browser-Schritte sowie PDF- und PNG-Export.`,en:`Browser steps and the PDF and PNG export.`},homepage:`https://github.com/microsoft/playwright`,license:`Apache-2.0`},{name:`agentOS`,description:{de:`Sandbox für Code-Schritte ohne Docker.`,en:`Sandbox for code steps without Docker.`},homepage:`https://github.com/rivet-dev/agentos`,license:`Apache-2.0`},{name:`React`,description:{de:`UI-Bibliothek der Web-App.`,en:`UI library of the web app.`},homepage:`https://github.com/facebook/react`,license:`MIT`},{name:`Vite`,description:{de:`Build-Werkzeug der Web-App.`,en:`Build tool of the web app.`},homepage:`https://github.com/vitejs/vite`,license:`MIT`},{name:`Tailwind CSS`,description:{de:`Styling der Oberfläche.`,en:`Styling of the interface.`},homepage:`https://github.com/tailwindlabs/tailwindcss`,license:`MIT`},{name:`React Flow`,description:{de:`Das Diagramm der Schritte im Editor.`,en:`The diagram of steps in the editor.`},homepage:`https://github.com/xyflow/xyflow`,license:`MIT`},{name:`TanStack Query`,description:{de:`Server-Daten in der Web-App.`,en:`Server data in the web app.`},homepage:`https://github.com/TanStack/query`,license:`MIT`},{name:`xterm.js`,description:{de:`Das Terminal auf der Seite, in dem sich KI-Clients anmelden.`,en:`The terminal on the page where AI clients sign in.`},homepage:`https://github.com/xtermjs/xterm.js`,license:`MIT`},{name:`Lucide`,description:{de:`Icons.`,en:`Icons.`},homepage:`https://github.com/lucide-icons/lucide`,license:`ISC`},{name:`Geist & Geist Mono`,description:{de:`Schrift der Oberfläche.`,en:`Typeface of the interface.`},homepage:`https://github.com/vercel/geist-font`,license:`OFL-1.1`},{name:`Space Grotesk`,description:{de:`Schrift der Überschriften.`,en:`Typeface of the headings.`},homepage:`https://github.com/floriankarsten/space-grotesk`,license:`OFL-1.1`},{name:`git-cliff`,description:{de:`Erzeugt den Changelog aus den Commits.`,en:`Generates the changelog from the commits.`},homepage:`https://github.com/orhun/git-cliff`,license:`MIT OR Apache-2.0`}],m=e(n(),1),h=(e,...t)=>t.some(t=>t?.toLowerCase().includes(e));function g({name:e,homepage:t,version:n,license:r,description:i}){return(0,m.jsxs)(`li`,{className:`py-2.5`,children:[(0,m.jsxs)(`div`,{className:`flex flex-wrap items-baseline gap-x-2.5 gap-y-0.5`,children:[t?(0,m.jsxs)(`a`,{href:t,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 font-medium text-[0.875rem] text-ink underline-offset-4 hover:underline`,children:[e,(0,m.jsx)(u,{"aria-hidden":!0,className:`size-3 text-ink-4`})]}):(0,m.jsx)(`span`,{className:`font-medium text-[0.875rem] text-ink`,children:e}),n?(0,m.jsx)(`span`,{className:`text-[0.75rem] text-ink-3 tabular-nums`,children:n}):null,(0,m.jsx)(`span`,{className:`text-[0.75rem] text-ink-3`,children:r})]}),i?(0,m.jsx)(`p`,{className:`mt-0.5 text-[0.8125rem] text-ink-3`,children:i}):null]})}function _({title:e,hint:t,children:n}){return(0,m.jsxs)(`section`,{className:`mt-6`,children:[(0,m.jsx)(`h3`,{className:`border-border-soft border-b pb-2 font-display font-semibold text-[1rem]`,children:e}),t?(0,m.jsx)(`p`,{className:`mt-2 text-[0.8125rem] text-ink-3`,children:t}):null,n]})}function v({credits:e}){return(0,m.jsx)(`ul`,{className:`divide-y divide-border-soft`,children:e.map(e=>(0,m.jsx)(g,{name:e.name,homepage:e.homepage,license:e.license,description:e.description[c]},e.name))})}function y({label:e,packages:t}){return(0,m.jsxs)(`div`,{className:`mt-4`,children:[(0,m.jsx)(`h4`,{className:`font-medium text-[0.75rem] text-ink-3 tracking-wide`,children:e}),(0,m.jsx)(`ul`,{className:`divide-y divide-border-soft`,children:t.map(e=>(0,m.jsx)(g,{...e},e.name))})]})}function b({open:e,onClose:t}){let[n,c]=(0,d.useState)(null),[u,g]=(0,d.useState)(``);(0,d.useEffect)(()=>{if(!e||n)return;let t=!1;return r(()=>import(`./oss-credits-CIxnNZor.js`).then(e=>{t||c(e.default)}),[]),()=>{t=!0}},[e,n]),(0,d.useEffect)(()=>{e||g(``)},[e]);let b=u.trim().toLowerCase(),x=e=>b?e.filter(e=>h(b,e.name,e.license,e.description.de,e.description.en)):e,S=e=>b?e.filter(e=>h(b,e.name,e.license,e.version)):e,C=x(f),w=x(p),T=n?[{id:`shared`,label:s(`about.creditsShared`),packages:S(n.shared)},...n.groups.map(e=>({id:e.id,label:e.label,packages:S(e.packages)}))].filter(e=>e.packages.length>0):[],E=C.length===0&&w.length===0&&T.length===0;return(0,m.jsxs)(o,{open:e,onClose:t,title:s(`about.credits`),wide:!0,children:[(0,m.jsx)(`p`,{className:`-mt-3 mb-4 text-[0.875rem] text-ink-3`,children:s(`about.creditsHint`)}),(0,m.jsx)(l,{type:`search`,value:u,placeholder:s(`about.search`),onChange:e=>g(e.target.value)}),C.length>0?(0,m.jsx)(_,{title:s(`about.creditsProduct`),children:(0,m.jsx)(v,{credits:C})}):null,w.length>0?(0,m.jsx)(_,{title:s(`about.creditsBuiltWith`),children:(0,m.jsx)(v,{credits:w})}):null,n===null?(0,m.jsx)(`div`,{className:`flex justify-center py-10 text-ink-3`,children:(0,m.jsx)(a,{})}):T.length>0?(0,m.jsx)(_,{title:s(`about.creditsDeps`),hint:b?void 0:s(`about.creditsDepsHint`),children:T.map(e=>(0,m.jsx)(y,{label:e.label,packages:e.packages},e.id))}):null,n!==null&&E?(0,m.jsx)(i,{children:s(`about.noMatches`)}):null]})}export{b as CreditsDialog};
|