@valbuild/server 0.95.0 → 0.96.0
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/dist/valbuild-server.cjs.dev.js +404 -10
- package/dist/valbuild-server.cjs.prod.js +404 -10
- package/dist/valbuild-server.esm.js +404 -10
- package/package.json +4 -4
|
@@ -2579,6 +2579,76 @@ class ValOpsFS extends ValOps {
|
|
|
2579
2579
|
async onInit() {
|
|
2580
2580
|
// do nothing
|
|
2581
2581
|
}
|
|
2582
|
+
async getPresignedAuthNonce(project, corsOrigin, auth) {
|
|
2583
|
+
const authHeader = "pat" in auth ? {
|
|
2584
|
+
"x-val-pat": auth.pat
|
|
2585
|
+
} : {
|
|
2586
|
+
Authorization: `Bearer ${auth.apiKey}`
|
|
2587
|
+
};
|
|
2588
|
+
try {
|
|
2589
|
+
const res = await fetch(`${this.contentUrl}/v1/${project}/presigned-auth-nonce`, {
|
|
2590
|
+
method: "POST",
|
|
2591
|
+
headers: {
|
|
2592
|
+
...authHeader,
|
|
2593
|
+
"Content-Type": "application/json"
|
|
2594
|
+
},
|
|
2595
|
+
body: JSON.stringify({
|
|
2596
|
+
corsOrigin
|
|
2597
|
+
})
|
|
2598
|
+
});
|
|
2599
|
+
if (res.ok) {
|
|
2600
|
+
const json = await res.json();
|
|
2601
|
+
const parsed = z.object({
|
|
2602
|
+
nonce: z.string(),
|
|
2603
|
+
expiresAt: z.string()
|
|
2604
|
+
}).safeParse(json);
|
|
2605
|
+
if (parsed.success) {
|
|
2606
|
+
return {
|
|
2607
|
+
status: "success",
|
|
2608
|
+
data: {
|
|
2609
|
+
nonce: parsed.data.nonce,
|
|
2610
|
+
baseUrl: `${this.contentUrl}/v1/${project}`
|
|
2611
|
+
}
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
console.error("Could not parse presigned auth nonce response. Error: " + fromError(parsed.error));
|
|
2615
|
+
return {
|
|
2616
|
+
status: "error",
|
|
2617
|
+
statusCode: 500,
|
|
2618
|
+
error: {
|
|
2619
|
+
message: "Could not get presigned auth nonce. The response from the content host was not in the expected format."
|
|
2620
|
+
}
|
|
2621
|
+
};
|
|
2622
|
+
}
|
|
2623
|
+
if (res.status === 401) {
|
|
2624
|
+
return {
|
|
2625
|
+
status: "error",
|
|
2626
|
+
statusCode: 401,
|
|
2627
|
+
error: {
|
|
2628
|
+
message: "Could not get presigned auth nonce. The local PAT was rejected by the content host. Try re-running `val login`."
|
|
2629
|
+
}
|
|
2630
|
+
};
|
|
2631
|
+
}
|
|
2632
|
+
const unknownErrorMessage = `Could not get presigned auth nonce. HTTP error: ${res.status} ${res.statusText}`;
|
|
2633
|
+
console.error(unknownErrorMessage);
|
|
2634
|
+
return {
|
|
2635
|
+
status: "error",
|
|
2636
|
+
statusCode: 500,
|
|
2637
|
+
error: {
|
|
2638
|
+
message: unknownErrorMessage
|
|
2639
|
+
}
|
|
2640
|
+
};
|
|
2641
|
+
} catch (e) {
|
|
2642
|
+
console.error("Could not get presigned auth nonce (connection error?):", e);
|
|
2643
|
+
return {
|
|
2644
|
+
status: "error",
|
|
2645
|
+
statusCode: 500,
|
|
2646
|
+
error: {
|
|
2647
|
+
message: `Could not get presigned auth nonce. Error: ${e instanceof Error ? e.message : JSON.stringify(e)}`
|
|
2648
|
+
}
|
|
2649
|
+
};
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2582
2652
|
async getCommitSummary() {
|
|
2583
2653
|
return {
|
|
2584
2654
|
error: {
|
|
@@ -3900,7 +3970,7 @@ class ValOpsHttp extends ValOps {
|
|
|
3900
3970
|
return {
|
|
3901
3971
|
status: "error",
|
|
3902
3972
|
error: {
|
|
3903
|
-
message: "Could not get nonce." + message
|
|
3973
|
+
message: "Could not get nonce. " + message
|
|
3904
3974
|
}
|
|
3905
3975
|
};
|
|
3906
3976
|
}
|
|
@@ -4647,6 +4717,14 @@ function hasRemoteFileSchema(schema) {
|
|
|
4647
4717
|
|
|
4648
4718
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
4649
4719
|
const ValServer = (valModules, options, callbacks) => {
|
|
4720
|
+
const AIContentBlock = z.union([z.object({
|
|
4721
|
+
type: z.literal("text"),
|
|
4722
|
+
text: z.string()
|
|
4723
|
+
}), z.object({
|
|
4724
|
+
type: z.literal("image_url"),
|
|
4725
|
+
url: z.string()
|
|
4726
|
+
})]);
|
|
4727
|
+
const AIMessageContent = z.union([z.string(), z.array(AIContentBlock)]);
|
|
4650
4728
|
const ProfilesResponse = z.object({
|
|
4651
4729
|
profiles: z.array(z.object({
|
|
4652
4730
|
profileId: z.string(),
|
|
@@ -5444,15 +5522,38 @@ const ValServer = (valModules, options, callbacks) => {
|
|
|
5444
5522
|
};
|
|
5445
5523
|
}
|
|
5446
5524
|
if (serverOps instanceof ValOpsFS) {
|
|
5447
|
-
// In FS mode
|
|
5448
|
-
//
|
|
5449
|
-
//
|
|
5525
|
+
// In FS mode patch-file uploads are buffered through this server (no remote round-trip),
|
|
5526
|
+
// so baseUrl points at /api/val/upload. AI image uploads, however, go straight to the
|
|
5527
|
+
// content host — we resolve a contentBaseUrl + a PAT-issued nonce here so the browser
|
|
5528
|
+
// can POST directly without exposing the PAT.
|
|
5450
5529
|
const host = `/api/val`;
|
|
5530
|
+
let contentBaseUrl = null;
|
|
5531
|
+
let contentAuthNonce = null;
|
|
5532
|
+
if (!options.project) {
|
|
5533
|
+
console.warn("Direct content-host uploads (AI images) disabled: no `project` set in val.config (and VAL_PROJECT env var is not set).");
|
|
5534
|
+
} else {
|
|
5535
|
+
const authDataRes = await getRemoteFileAuth();
|
|
5536
|
+
if (authDataRes.status !== 200) {
|
|
5537
|
+
console.warn("Direct content-host uploads (AI images) disabled: " + authDataRes.json.message);
|
|
5538
|
+
} else {
|
|
5539
|
+
const corsOrigin = "*"; // TODO: add cors origin
|
|
5540
|
+
const presignedAuthNonce = await serverOps.getPresignedAuthNonce(options.project, corsOrigin, authDataRes.json.remoteFileAuth);
|
|
5541
|
+
if (presignedAuthNonce.status === "success") {
|
|
5542
|
+
contentBaseUrl = presignedAuthNonce.data.baseUrl;
|
|
5543
|
+
contentAuthNonce = presignedAuthNonce.data.nonce;
|
|
5544
|
+
} else {
|
|
5545
|
+
console.warn("Direct content-host uploads (AI images) disabled: " + presignedAuthNonce.error.message);
|
|
5546
|
+
}
|
|
5547
|
+
}
|
|
5548
|
+
}
|
|
5451
5549
|
return {
|
|
5452
5550
|
status: 200,
|
|
5453
5551
|
json: {
|
|
5454
5552
|
nonce: null,
|
|
5455
|
-
baseUrl: `${host}/upload
|
|
5553
|
+
baseUrl: `${host}/upload`,
|
|
5554
|
+
// NOTE: this is the /upload/patches endpoint - the client will add /patches/:patchId/files to this and post to it
|
|
5555
|
+
contentBaseUrl,
|
|
5556
|
+
contentAuthNonce
|
|
5456
5557
|
}
|
|
5457
5558
|
};
|
|
5458
5559
|
}
|
|
@@ -5478,7 +5579,9 @@ const ValServer = (valModules, options, callbacks) => {
|
|
|
5478
5579
|
status: 200,
|
|
5479
5580
|
json: {
|
|
5480
5581
|
nonce: presignedAuthNonce.data.nonce,
|
|
5481
|
-
baseUrl: presignedAuthNonce.data.baseUrl
|
|
5582
|
+
baseUrl: presignedAuthNonce.data.baseUrl,
|
|
5583
|
+
contentBaseUrl: presignedAuthNonce.data.baseUrl,
|
|
5584
|
+
contentAuthNonce: presignedAuthNonce.data.nonce
|
|
5482
5585
|
}
|
|
5483
5586
|
};
|
|
5484
5587
|
}
|
|
@@ -6148,7 +6251,7 @@ const ValServer = (valModules, options, callbacks) => {
|
|
|
6148
6251
|
}
|
|
6149
6252
|
if (!options.project) {
|
|
6150
6253
|
return {
|
|
6151
|
-
status:
|
|
6254
|
+
status: 401,
|
|
6152
6255
|
json: {
|
|
6153
6256
|
message: "Project is not configured"
|
|
6154
6257
|
}
|
|
@@ -6157,7 +6260,7 @@ const ValServer = (valModules, options, callbacks) => {
|
|
|
6157
6260
|
const authDataRes = await getRemoteFileAuth();
|
|
6158
6261
|
if (authDataRes.status !== 200) {
|
|
6159
6262
|
return {
|
|
6160
|
-
status:
|
|
6263
|
+
status: 401,
|
|
6161
6264
|
json: {
|
|
6162
6265
|
message: authDataRes.json.message
|
|
6163
6266
|
}
|
|
@@ -6450,14 +6553,19 @@ const ValServer = (valModules, options, callbacks) => {
|
|
|
6450
6553
|
const SessionMessagesResponse = z.object({
|
|
6451
6554
|
messages: z.array(z.object({
|
|
6452
6555
|
role: z.string(),
|
|
6453
|
-
content:
|
|
6556
|
+
content: AIMessageContent
|
|
6454
6557
|
})),
|
|
6455
6558
|
nextCursor: z.object({
|
|
6456
6559
|
updatedAt: z.string(),
|
|
6457
6560
|
id: z.string()
|
|
6458
6561
|
}).nullable().optional()
|
|
6459
6562
|
});
|
|
6460
|
-
const
|
|
6563
|
+
const params = new URLSearchParams();
|
|
6564
|
+
if (req.query.limit) params.set("limit", req.query.limit);
|
|
6565
|
+
if (req.query.cursor_updatedAt) params.set("cursor_updatedAt", req.query.cursor_updatedAt);
|
|
6566
|
+
if (req.query.cursor_id) params.set("cursor_id", req.query.cursor_id);
|
|
6567
|
+
const qs = params.toString();
|
|
6568
|
+
const upstreamUrl = `${options.valContentUrl}/v1/${options.project}/ai/sessions/${encodeURIComponent(sessionId)}/messages` + (qs ? `?${qs}` : "");
|
|
6461
6569
|
const upstreamRes = await fetch(upstreamUrl, {
|
|
6462
6570
|
headers
|
|
6463
6571
|
});
|
|
@@ -6508,6 +6616,292 @@ const ValServer = (valModules, options, callbacks) => {
|
|
|
6508
6616
|
});
|
|
6509
6617
|
}
|
|
6510
6618
|
},
|
|
6619
|
+
"/ai/session-image-to-patch-file": {
|
|
6620
|
+
POST: async req => {
|
|
6621
|
+
const cookies = req.cookies;
|
|
6622
|
+
const auth = getAuth(cookies);
|
|
6623
|
+
if (auth.error) {
|
|
6624
|
+
return {
|
|
6625
|
+
status: 401,
|
|
6626
|
+
json: {
|
|
6627
|
+
message: auth.error
|
|
6628
|
+
}
|
|
6629
|
+
};
|
|
6630
|
+
}
|
|
6631
|
+
if (!options.project) {
|
|
6632
|
+
return {
|
|
6633
|
+
status: 500,
|
|
6634
|
+
json: {
|
|
6635
|
+
message: "Project is not configured"
|
|
6636
|
+
}
|
|
6637
|
+
};
|
|
6638
|
+
}
|
|
6639
|
+
const authDataRes = await getRemoteFileAuth();
|
|
6640
|
+
if (authDataRes.status !== 200) {
|
|
6641
|
+
return {
|
|
6642
|
+
status: 500,
|
|
6643
|
+
json: {
|
|
6644
|
+
message: authDataRes.json.message
|
|
6645
|
+
}
|
|
6646
|
+
};
|
|
6647
|
+
}
|
|
6648
|
+
const authData = authDataRes.json.remoteFileAuth;
|
|
6649
|
+
let headers;
|
|
6650
|
+
if (serverOps instanceof ValOpsFS) {
|
|
6651
|
+
headers = getProfileAuthHeaders(authData, null, "application/json");
|
|
6652
|
+
} else {
|
|
6653
|
+
if (!("id" in auth) || !auth.id) {
|
|
6654
|
+
return {
|
|
6655
|
+
status: 401,
|
|
6656
|
+
json: {
|
|
6657
|
+
message: "Unauthorized"
|
|
6658
|
+
}
|
|
6659
|
+
};
|
|
6660
|
+
}
|
|
6661
|
+
headers = getProfileAuthHeaders(authData, {
|
|
6662
|
+
sub: auth.id
|
|
6663
|
+
}, "application/json");
|
|
6664
|
+
}
|
|
6665
|
+
const execFetch = async () => {
|
|
6666
|
+
try {
|
|
6667
|
+
const upstreamUrl = `${options.valContentUrl}/v1/${options.project}/patches/${encodeURIComponent(req.body.patchId)}/files/from-session-file`;
|
|
6668
|
+
const upstreamRes = await fetch(upstreamUrl, {
|
|
6669
|
+
method: "POST",
|
|
6670
|
+
headers,
|
|
6671
|
+
body: JSON.stringify({
|
|
6672
|
+
files: req.body.files.map(f => ({
|
|
6673
|
+
filePath: f.filePath,
|
|
6674
|
+
key: f.key,
|
|
6675
|
+
...(f.isRemote !== undefined ? {
|
|
6676
|
+
isRemote: f.isRemote
|
|
6677
|
+
} : {})
|
|
6678
|
+
}))
|
|
6679
|
+
})
|
|
6680
|
+
});
|
|
6681
|
+
if (!upstreamRes.ok) {
|
|
6682
|
+
var _upstreamJson;
|
|
6683
|
+
const text = await upstreamRes.text();
|
|
6684
|
+
let upstreamJson = null;
|
|
6685
|
+
try {
|
|
6686
|
+
upstreamJson = JSON.parse(text);
|
|
6687
|
+
} catch {
|
|
6688
|
+
upstreamJson = null;
|
|
6689
|
+
}
|
|
6690
|
+
if (upstreamRes.status === 400 && upstreamJson) {
|
|
6691
|
+
return {
|
|
6692
|
+
status: 400,
|
|
6693
|
+
json: {
|
|
6694
|
+
message: upstreamJson.message ?? `AI session image to patch failed: ${text}`,
|
|
6695
|
+
...(upstreamJson.details ? {
|
|
6696
|
+
details: upstreamJson.details
|
|
6697
|
+
} : {})
|
|
6698
|
+
}
|
|
6699
|
+
};
|
|
6700
|
+
}
|
|
6701
|
+
return {
|
|
6702
|
+
status: 500,
|
|
6703
|
+
json: {
|
|
6704
|
+
message: `AI session image to patch failed: ${upstreamRes.status} ${((_upstreamJson = upstreamJson) === null || _upstreamJson === void 0 ? void 0 : _upstreamJson.message) ?? text}`
|
|
6705
|
+
}
|
|
6706
|
+
};
|
|
6707
|
+
}
|
|
6708
|
+
const rawUpstreamJson = await upstreamRes.json();
|
|
6709
|
+
const UpstreamResponse = z.object({
|
|
6710
|
+
patchId: z.string(),
|
|
6711
|
+
files: z.array(z.object({
|
|
6712
|
+
filePath: z.string(),
|
|
6713
|
+
metadata: z.object({
|
|
6714
|
+
width: z.number(),
|
|
6715
|
+
height: z.number(),
|
|
6716
|
+
mimeType: z.string()
|
|
6717
|
+
})
|
|
6718
|
+
}))
|
|
6719
|
+
});
|
|
6720
|
+
const json = UpstreamResponse.safeParse(rawUpstreamJson);
|
|
6721
|
+
if (!json.success) {
|
|
6722
|
+
return {
|
|
6723
|
+
status: 500,
|
|
6724
|
+
json: {
|
|
6725
|
+
message: "Could not parse AI session image patch response: " + fromError(json.error).toString()
|
|
6726
|
+
}
|
|
6727
|
+
};
|
|
6728
|
+
}
|
|
6729
|
+
if (json.data.patchId !== req.body.patchId) {
|
|
6730
|
+
return {
|
|
6731
|
+
status: 500,
|
|
6732
|
+
json: {
|
|
6733
|
+
message: `AI session image to patch upstream returned mismatched patchId: expected '${req.body.patchId}', got '${json.data.patchId}'`
|
|
6734
|
+
}
|
|
6735
|
+
};
|
|
6736
|
+
}
|
|
6737
|
+
if (serverOps instanceof ValOpsFS) {
|
|
6738
|
+
// Mirror the binaries from the content host into local patch
|
|
6739
|
+
// storage so /files?patch_id=... can serve them. Match upstream
|
|
6740
|
+
// entries to client-provided keys by filePath.
|
|
6741
|
+
const keysByFilePath = new Map(req.body.files.map(f => [f.filePath, f.key]));
|
|
6742
|
+
for (const file of json.data.files) {
|
|
6743
|
+
const sessionKey = keysByFilePath.get(file.filePath);
|
|
6744
|
+
if (!sessionKey) {
|
|
6745
|
+
return {
|
|
6746
|
+
status: 500,
|
|
6747
|
+
json: {
|
|
6748
|
+
message: `AI session image to patch: upstream returned file '${file.filePath}' which was not in the request`
|
|
6749
|
+
}
|
|
6750
|
+
};
|
|
6751
|
+
}
|
|
6752
|
+
const downloadUrl = `${options.valContentUrl}/v1/${options.project}/ai/images?key=${encodeURIComponent(sessionKey)}`;
|
|
6753
|
+
let binaryRes;
|
|
6754
|
+
try {
|
|
6755
|
+
binaryRes = await fetch(downloadUrl, {
|
|
6756
|
+
headers
|
|
6757
|
+
});
|
|
6758
|
+
} catch (err) {
|
|
6759
|
+
return {
|
|
6760
|
+
status: 500,
|
|
6761
|
+
json: {
|
|
6762
|
+
message: `Could not download AI session image '${file.filePath}' from content host: ${err instanceof Error ? err.message : String(err)}`
|
|
6763
|
+
}
|
|
6764
|
+
};
|
|
6765
|
+
}
|
|
6766
|
+
if (!binaryRes.ok) {
|
|
6767
|
+
return {
|
|
6768
|
+
status: 500,
|
|
6769
|
+
json: {
|
|
6770
|
+
message: `Could not download AI session image '${file.filePath}' from content host: ${binaryRes.status} ${binaryRes.statusText}`
|
|
6771
|
+
}
|
|
6772
|
+
};
|
|
6773
|
+
}
|
|
6774
|
+
const arrayBuffer = await binaryRes.arrayBuffer();
|
|
6775
|
+
const base64 = Buffer.from(arrayBuffer).toString("base64");
|
|
6776
|
+
const dataUrl = `data:${file.metadata.mimeType};base64,${base64}`;
|
|
6777
|
+
const type = file.metadata.mimeType.startsWith("image/") ? "image" : "file";
|
|
6778
|
+
const saveRes = await serverOps.saveBase64EncodedBinaryFileFromPatch(file.filePath, req.body.parentRef, req.body.patchId, dataUrl, type, file.metadata);
|
|
6779
|
+
if (saveRes.error) {
|
|
6780
|
+
return {
|
|
6781
|
+
status: 500,
|
|
6782
|
+
json: {
|
|
6783
|
+
message: `Could not save AI session image '${file.filePath}' to local patch storage: ${saveRes.error.message}`
|
|
6784
|
+
}
|
|
6785
|
+
};
|
|
6786
|
+
}
|
|
6787
|
+
}
|
|
6788
|
+
}
|
|
6789
|
+
return {
|
|
6790
|
+
status: 200,
|
|
6791
|
+
json: {
|
|
6792
|
+
patchId: req.body.patchId,
|
|
6793
|
+
files: json.data.files
|
|
6794
|
+
}
|
|
6795
|
+
};
|
|
6796
|
+
} catch (err) {
|
|
6797
|
+
return {
|
|
6798
|
+
status: 500,
|
|
6799
|
+
json: {
|
|
6800
|
+
message: err instanceof Error ? err.message : "AI session image to patch error"
|
|
6801
|
+
}
|
|
6802
|
+
};
|
|
6803
|
+
}
|
|
6804
|
+
};
|
|
6805
|
+
return execFetch();
|
|
6806
|
+
}
|
|
6807
|
+
},
|
|
6808
|
+
"/ai/images": {
|
|
6809
|
+
PATCH: async req => {
|
|
6810
|
+
const cookies = req.cookies;
|
|
6811
|
+
const auth = getAuth(cookies);
|
|
6812
|
+
if (auth.error) {
|
|
6813
|
+
return {
|
|
6814
|
+
status: 401,
|
|
6815
|
+
json: {
|
|
6816
|
+
message: auth.error
|
|
6817
|
+
}
|
|
6818
|
+
};
|
|
6819
|
+
}
|
|
6820
|
+
if (!options.project) {
|
|
6821
|
+
return {
|
|
6822
|
+
status: 500,
|
|
6823
|
+
json: {
|
|
6824
|
+
message: "Project is not configured"
|
|
6825
|
+
}
|
|
6826
|
+
};
|
|
6827
|
+
}
|
|
6828
|
+
const authDataRes = await getRemoteFileAuth();
|
|
6829
|
+
if (authDataRes.status !== 200) {
|
|
6830
|
+
return {
|
|
6831
|
+
status: 500,
|
|
6832
|
+
json: {
|
|
6833
|
+
message: authDataRes.json.message
|
|
6834
|
+
}
|
|
6835
|
+
};
|
|
6836
|
+
}
|
|
6837
|
+
const authData = authDataRes.json.remoteFileAuth;
|
|
6838
|
+
let headers;
|
|
6839
|
+
if (serverOps instanceof ValOpsFS) {
|
|
6840
|
+
headers = getProfileAuthHeaders(authData, null, "application/json");
|
|
6841
|
+
} else {
|
|
6842
|
+
if (!("id" in auth) || !auth.id) {
|
|
6843
|
+
return {
|
|
6844
|
+
status: 401,
|
|
6845
|
+
json: {
|
|
6846
|
+
message: "Unauthorized"
|
|
6847
|
+
}
|
|
6848
|
+
};
|
|
6849
|
+
}
|
|
6850
|
+
headers = getProfileAuthHeaders(authData, {
|
|
6851
|
+
sub: auth.id
|
|
6852
|
+
}, "application/json");
|
|
6853
|
+
}
|
|
6854
|
+
const execFetch = async () => {
|
|
6855
|
+
try {
|
|
6856
|
+
const upstreamUrl = `${options.valContentUrl}/v1/${options.project}/ai/images`;
|
|
6857
|
+
const upstreamRes = await fetch(upstreamUrl, {
|
|
6858
|
+
method: "PATCH",
|
|
6859
|
+
headers,
|
|
6860
|
+
body: JSON.stringify({
|
|
6861
|
+
key: req.body.key,
|
|
6862
|
+
metadata: req.body.metadata,
|
|
6863
|
+
contentType: req.body.contentType
|
|
6864
|
+
})
|
|
6865
|
+
});
|
|
6866
|
+
if (!upstreamRes.ok) {
|
|
6867
|
+
const text = await upstreamRes.text();
|
|
6868
|
+
return {
|
|
6869
|
+
status: 500,
|
|
6870
|
+
json: {
|
|
6871
|
+
message: `AI images patch failed: ${upstreamRes.status} ${text}`
|
|
6872
|
+
}
|
|
6873
|
+
};
|
|
6874
|
+
}
|
|
6875
|
+
const UpstreamResponse = z.object({
|
|
6876
|
+
key: z.string()
|
|
6877
|
+
});
|
|
6878
|
+
const json = UpstreamResponse.safeParse(await upstreamRes.json());
|
|
6879
|
+
if (!json.success) {
|
|
6880
|
+
return {
|
|
6881
|
+
status: 500,
|
|
6882
|
+
json: {
|
|
6883
|
+
message: "Could not parse AI images patch response: " + fromError(json.error).toString()
|
|
6884
|
+
}
|
|
6885
|
+
};
|
|
6886
|
+
}
|
|
6887
|
+
return {
|
|
6888
|
+
status: 200,
|
|
6889
|
+
json: {
|
|
6890
|
+
key: json.data.key
|
|
6891
|
+
}
|
|
6892
|
+
};
|
|
6893
|
+
} catch (err) {
|
|
6894
|
+
return {
|
|
6895
|
+
status: 500,
|
|
6896
|
+
json: {
|
|
6897
|
+
message: err instanceof Error ? err.message : "AI images patch error"
|
|
6898
|
+
}
|
|
6899
|
+
};
|
|
6900
|
+
}
|
|
6901
|
+
};
|
|
6902
|
+
return execFetch();
|
|
6903
|
+
}
|
|
6904
|
+
},
|
|
6511
6905
|
//#region files
|
|
6512
6906
|
"/files": {
|
|
6513
6907
|
GET: async req => {
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"./package.json": "./package.json"
|
|
17
17
|
},
|
|
18
18
|
"types": "dist/valbuild-server.cjs.d.ts",
|
|
19
|
-
"version": "0.
|
|
19
|
+
"version": "0.96.0",
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@prettier/sync": "^0.6.1",
|
|
22
22
|
"@types/jest": "^30.0.0"
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"typescript": "^5.9.3",
|
|
31
31
|
"zod": "^4.3.5",
|
|
32
32
|
"zod-validation-error": "^5.0.0",
|
|
33
|
-
"@valbuild/core": "0.
|
|
34
|
-
"@valbuild/
|
|
35
|
-
"@valbuild/
|
|
33
|
+
"@valbuild/core": "0.96.0",
|
|
34
|
+
"@valbuild/ui": "0.96.0",
|
|
35
|
+
"@valbuild/shared": "0.96.0"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
38
|
"node": ">=18.17.0"
|