@riddledc/openclaw-riddledc 0.9.1 → 0.9.3

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/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ import {
2
+ configFromOpenClawApi,
3
+ createStaticPreview,
4
+ deleteStaticPreview
5
+ } from "./chunk-LJCZ53PU.js";
6
+
1
7
  // src/index.ts
2
8
  import { Type } from "@sinclair/typebox";
3
9
  import { writeFile, mkdir, readFile, stat, rm } from "fs/promises";
@@ -6,6 +12,11 @@ import { execFile as execFileCb } from "child_process";
6
12
  import { promisify } from "util";
7
13
  var execFile = promisify(execFileCb);
8
14
  var INLINE_CAP = 50 * 1024;
15
+ var PREVIEW_REQUEST_TIMEOUT_MS = 3e4;
16
+ var PREVIEW_UPLOAD_TIMEOUT_MS = 5 * 6e4;
17
+ var PREVIEW_ARTIFACT_TIMEOUT_MS = 6e4;
18
+ var PREVIEW_RETRY_ATTEMPTS = 3;
19
+ var PREVIEW_RETRY_BASE_DELAY_MS = 750;
9
20
  function getCfg(api) {
10
21
  const cfg = api?.config ?? {};
11
22
  const pluginCfg = cfg?.plugins?.entries?.["openclaw-riddledc"]?.config ?? {};
@@ -51,6 +62,76 @@ function abToBase64(ab) {
51
62
  function getWorkspacePath(api) {
52
63
  return api?.workspacePath ?? process.cwd();
53
64
  }
65
+ function describeError(err) {
66
+ const anyErr = err;
67
+ const parts = [];
68
+ if (err instanceof Error) parts.push(err.message);
69
+ else parts.push(String(err));
70
+ const cause = anyErr?.cause;
71
+ if (cause) {
72
+ const causeParts = [
73
+ cause.code ? `code=${cause.code}` : "",
74
+ cause.name ? `name=${cause.name}` : "",
75
+ cause.message ? `message=${cause.message}` : ""
76
+ ].filter(Boolean);
77
+ if (causeParts.length) parts.push(`cause: ${causeParts.join(" ")}`);
78
+ }
79
+ return parts.join("; ");
80
+ }
81
+ async function fetchWithTimeout(url, init, timeoutMs, label) {
82
+ const controller = new AbortController();
83
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
84
+ try {
85
+ return await fetch(url, { ...init, signal: controller.signal });
86
+ } catch (err) {
87
+ if (err?.name === "AbortError") {
88
+ throw new Error(`${label} timed out after ${Math.round(timeoutMs / 1e3)}s`);
89
+ }
90
+ throw err;
91
+ } finally {
92
+ clearTimeout(timer);
93
+ }
94
+ }
95
+ function isTransientFetchError(err) {
96
+ const text = describeError(err).toLowerCase();
97
+ return [
98
+ "fetch failed",
99
+ "timed out",
100
+ "timeout",
101
+ "econnreset",
102
+ "econnrefused",
103
+ "etimedout",
104
+ "eai_again",
105
+ "socket",
106
+ "network",
107
+ "und_err",
108
+ "terminated"
109
+ ].some((needle) => text.includes(needle));
110
+ }
111
+ function sleep(ms) {
112
+ return new Promise((resolve) => setTimeout(resolve, ms));
113
+ }
114
+ async function fetchWithRetry(url, init, timeoutMs, label, opts = {}) {
115
+ const attempts = Math.max(1, opts.attempts ?? PREVIEW_RETRY_ATTEMPTS);
116
+ const baseDelayMs = opts.baseDelayMs ?? PREVIEW_RETRY_BASE_DELAY_MS;
117
+ let lastErr;
118
+ for (let attempt = 1; attempt <= attempts; attempt++) {
119
+ try {
120
+ return await fetchWithTimeout(url, init, timeoutMs, label);
121
+ } catch (err) {
122
+ lastErr = err;
123
+ if (attempt >= attempts || !isTransientFetchError(err)) break;
124
+ const jitterMs = Math.floor(Math.random() * 250);
125
+ const delayMs = Math.min(baseDelayMs * Math.pow(2, attempt - 1) + jitterMs, 5e3);
126
+ console.warn(`[openclaw-riddledc] ${label} attempt ${attempt}/${attempts} failed: ${describeError(err)}; retrying in ${delayMs}ms`);
127
+ await sleep(delayMs);
128
+ }
129
+ }
130
+ throw new Error(`${label} failed after ${attempts} attempts: ${describeError(lastErr)}`);
131
+ }
132
+ function isAlreadyStartedResponse(status, body) {
133
+ return status === 409 && /already in status:\s*(queued|running|complete|completed)/i.test(body);
134
+ }
54
135
  async function writeArtifact(workspace, subdir, filename, content) {
55
136
  const dir = join(workspace, "riddle", subdir);
56
137
  await mkdir(dir, { recursive: true });
@@ -785,70 +866,8 @@ function register(api) {
785
866
  framework: Type.Optional(Type.String({ description: "Framework hint: 'spa' (default) or 'static'" }))
786
867
  }),
787
868
  async execute(_id, params) {
788
- const { apiKey, baseUrl } = getCfg(api);
789
- if (!apiKey) {
790
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: "Missing Riddle API key." }, null, 2) }] };
791
- }
792
- assertAllowedBaseUrl(baseUrl);
793
- const dir = params.directory;
794
- if (!dir || typeof dir !== "string") throw new Error("directory must be an absolute path");
795
- try {
796
- const st = await stat(dir);
797
- if (!st.isDirectory()) throw new Error(`Not a directory: ${dir}`);
798
- } catch (e) {
799
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Cannot access directory: ${e.message}` }, null, 2) }] };
800
- }
801
- const endpoint = baseUrl.replace(/\/$/, "");
802
- const createRes = await fetch(`${endpoint}/v1/preview`, {
803
- method: "POST",
804
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
805
- body: JSON.stringify({ framework: params.framework || "spa" })
806
- });
807
- if (!createRes.ok) {
808
- const err = await createRes.text();
809
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Create failed: HTTP ${createRes.status} ${err}` }, null, 2) }] };
810
- }
811
- const created = await createRes.json();
812
- const tarball = `/tmp/riddle-preview-${created.id}.tar.gz`;
813
- try {
814
- await execFile("tar", ["czf", tarball, "-C", dir, "."], { timeout: 6e4 });
815
- const tarData = await readFile(tarball);
816
- const uploadRes = await fetch(created.upload_url, {
817
- method: "PUT",
818
- headers: { "Content-Type": "application/gzip" },
819
- body: tarData
820
- });
821
- if (!uploadRes.ok) {
822
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, id: created.id, error: `Upload failed: HTTP ${uploadRes.status}` }, null, 2) }] };
823
- }
824
- } finally {
825
- try {
826
- await rm(tarball, { force: true });
827
- } catch {
828
- }
829
- }
830
- const publishRes = await fetch(`${endpoint}/v1/preview/${created.id}/publish`, {
831
- method: "POST",
832
- headers: { Authorization: `Bearer ${apiKey}` }
833
- });
834
- if (!publishRes.ok) {
835
- const err = await publishRes.text();
836
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, id: created.id, error: `Publish failed: HTTP ${publishRes.status} ${err}` }, null, 2) }] };
837
- }
838
- const published = await publishRes.json();
839
- return {
840
- content: [{
841
- type: "text",
842
- text: JSON.stringify({
843
- ok: true,
844
- id: published.id,
845
- preview_url: published.preview_url,
846
- file_count: published.file_count,
847
- total_bytes: published.total_bytes,
848
- expires_at: created.expires_at
849
- }, null, 2)
850
- }]
851
- };
869
+ const result = await createStaticPreview(configFromOpenClawApi(api), params);
870
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
852
871
  }
853
872
  },
854
873
  { optional: true }
@@ -861,21 +880,8 @@ function register(api) {
861
880
  id: Type.String({ description: "Preview ID (e.g. pv_a1b2c3d4)" })
862
881
  }),
863
882
  async execute(_id, params) {
864
- const { apiKey, baseUrl } = getCfg(api);
865
- if (!apiKey) {
866
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: "Missing Riddle API key." }, null, 2) }] };
867
- }
868
- assertAllowedBaseUrl(baseUrl);
869
- const res = await fetch(`${baseUrl.replace(/\/$/, "")}/v1/preview/${params.id}`, {
870
- method: "DELETE",
871
- headers: { Authorization: `Bearer ${apiKey}` }
872
- });
873
- if (!res.ok) {
874
- const err = await res.text();
875
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Delete failed: HTTP ${res.status} ${err}` }, null, 2) }] };
876
- }
877
- const data = await res.json();
878
- return { content: [{ type: "text", text: JSON.stringify({ ok: true, deleted: true, files_removed: data.files_removed }, null, 2) }] };
883
+ const result = await deleteStaticPreview(configFromOpenClawApi(api), params.id);
884
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
879
885
  }
880
886
  },
881
887
  { optional: true }
@@ -927,11 +933,16 @@ function register(api) {
927
933
  const envBody = {};
928
934
  if (hasSensitiveEnv) envBody.env = params.sensitive_env;
929
935
  if (hasLocalStorage) envBody.localStorage = params.localStorage;
930
- const envRes = await fetch(`${endpoint}/v1/server-preview/env`, {
931
- method: "POST",
932
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
933
- body: JSON.stringify(envBody)
934
- });
936
+ let envRes;
937
+ try {
938
+ envRes = await fetchWithTimeout(`${endpoint}/v1/server-preview/env`, {
939
+ method: "POST",
940
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
941
+ body: JSON.stringify(envBody)
942
+ }, PREVIEW_REQUEST_TIMEOUT_MS, "server preview env store");
943
+ } catch (e) {
944
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Store env failed: ${describeError(e)}` }, null, 2) }] };
945
+ }
935
946
  if (!envRes.ok) {
936
947
  const err = await envRes.text();
937
948
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Store env failed: HTTP ${envRes.status} ${err}` }, null, 2) }] };
@@ -957,11 +968,16 @@ function register(api) {
957
968
  if (params.navigation_timeout) createBody.navigation_timeout = params.navigation_timeout;
958
969
  if (params.color_scheme) createBody.color_scheme = params.color_scheme;
959
970
  if (params.viewport) createBody.viewport = params.viewport;
960
- const createRes = await fetch(`${endpoint}/v1/server-preview`, {
961
- method: "POST",
962
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
963
- body: JSON.stringify(createBody)
964
- });
971
+ let createRes;
972
+ try {
973
+ createRes = await fetchWithRetry(`${endpoint}/v1/server-preview`, {
974
+ method: "POST",
975
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
976
+ body: JSON.stringify(createBody)
977
+ }, PREVIEW_REQUEST_TIMEOUT_MS, "server preview create");
978
+ } catch (e) {
979
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Create failed: ${describeError(e)}` }, null, 2) }] };
980
+ }
965
981
  if (!createRes.ok) {
966
982
  const err = await createRes.text();
967
983
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Create failed: HTTP ${createRes.status} ${err}` }, null, 2) }] };
@@ -973,11 +989,16 @@ function register(api) {
973
989
  const excludeArgs = excludes.flatMap((p) => ["--exclude", p]);
974
990
  await execFile("tar", ["czf", tarball, ...excludeArgs, "-C", dir, "."], { timeout: 12e4 });
975
991
  const tarData = await readFile(tarball);
976
- const uploadRes = await fetch(created.upload_url, {
977
- method: "PUT",
978
- headers: { "Content-Type": "application/gzip" },
979
- body: tarData
980
- });
992
+ let uploadRes;
993
+ try {
994
+ uploadRes = await fetchWithRetry(created.upload_url, {
995
+ method: "PUT",
996
+ headers: { "Content-Type": "application/gzip" },
997
+ body: tarData
998
+ }, PREVIEW_UPLOAD_TIMEOUT_MS, "server preview upload");
999
+ } catch (e) {
1000
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Upload failed: ${describeError(e)}` }, null, 2) }] };
1001
+ }
981
1002
  if (!uploadRes.ok) {
982
1003
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Upload failed: HTTP ${uploadRes.status}` }, null, 2) }] };
983
1004
  }
@@ -987,21 +1008,35 @@ function register(api) {
987
1008
  } catch {
988
1009
  }
989
1010
  }
990
- const startRes = await fetch(`${endpoint}/v1/server-preview/${created.job_id}/start`, {
991
- method: "POST",
992
- headers: { Authorization: `Bearer ${apiKey}` }
993
- });
1011
+ let startRes;
1012
+ try {
1013
+ startRes = await fetchWithRetry(`${endpoint}/v1/server-preview/${created.job_id}/start`, {
1014
+ method: "POST",
1015
+ headers: { Authorization: `Bearer ${apiKey}` }
1016
+ }, PREVIEW_REQUEST_TIMEOUT_MS, "server preview start");
1017
+ } catch (e) {
1018
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Start failed: ${describeError(e)}` }, null, 2) }] };
1019
+ }
994
1020
  if (!startRes.ok) {
995
1021
  const err = await startRes.text();
996
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Start failed: HTTP ${startRes.status} ${err}` }, null, 2) }] };
1022
+ if (isAlreadyStartedResponse(startRes.status, err)) {
1023
+ console.warn(`[openclaw-riddledc] server preview start returned ${startRes.status} for ${created.job_id}; continuing to poll`);
1024
+ } else {
1025
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Start failed: HTTP ${startRes.status} ${err}` }, null, 2) }] };
1026
+ }
997
1027
  }
998
1028
  const timeoutMs = ((params.timeout || 120) + 60) * 1e3;
999
1029
  const pollStart = Date.now();
1000
1030
  const POLL_INTERVAL = 3e3;
1001
1031
  while (Date.now() - pollStart < timeoutMs) {
1002
- const statusRes = await fetch(`${endpoint}/v1/server-preview/${created.job_id}`, {
1003
- headers: { Authorization: `Bearer ${apiKey}` }
1004
- });
1032
+ let statusRes;
1033
+ try {
1034
+ statusRes = await fetchWithRetry(`${endpoint}/v1/server-preview/${created.job_id}`, {
1035
+ headers: { Authorization: `Bearer ${apiKey}` }
1036
+ }, PREVIEW_REQUEST_TIMEOUT_MS, "server preview poll", { attempts: 2 });
1037
+ } catch (e) {
1038
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Poll failed: ${describeError(e)}` }, null, 2) }] };
1039
+ }
1005
1040
  if (!statusRes.ok) {
1006
1041
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Poll failed: HTTP ${statusRes.status}` }, null, 2) }] };
1007
1042
  }
@@ -1020,7 +1055,7 @@ function register(api) {
1020
1055
  for (const output of result.outputs) {
1021
1056
  if (output.name && /\.(png|jpg|jpeg)$/i.test(output.name) && output.url) {
1022
1057
  try {
1023
- const imgRes = await fetch(output.url);
1058
+ const imgRes = await fetchWithTimeout(output.url, {}, PREVIEW_ARTIFACT_TIMEOUT_MS, "server preview artifact download");
1024
1059
  if (imgRes.ok) {
1025
1060
  const buf = await imgRes.arrayBuffer();
1026
1061
  const base64 = Buffer.from(buf).toString("base64");
@@ -1096,11 +1131,16 @@ function register(api) {
1096
1131
  const envBody = {};
1097
1132
  if (hasSensitiveEnv) envBody.env = params.sensitive_env;
1098
1133
  if (hasLocalStorage) envBody.localStorage = params.localStorage;
1099
- const envRes = await fetch(`${endpoint}/v1/build-preview/env`, {
1100
- method: "POST",
1101
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
1102
- body: JSON.stringify(envBody)
1103
- });
1134
+ let envRes;
1135
+ try {
1136
+ envRes = await fetchWithTimeout(`${endpoint}/v1/build-preview/env`, {
1137
+ method: "POST",
1138
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
1139
+ body: JSON.stringify(envBody)
1140
+ }, PREVIEW_REQUEST_TIMEOUT_MS, "build preview env store");
1141
+ } catch (e) {
1142
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Store env failed: ${describeError(e)}` }, null, 2) }] };
1143
+ }
1104
1144
  if (!envRes.ok) {
1105
1145
  const err = await envRes.text();
1106
1146
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Store env failed: HTTP ${envRes.status} ${err}` }, null, 2) }] };
@@ -1128,11 +1168,16 @@ function register(api) {
1128
1168
  if (params.color_scheme) createBody.color_scheme = params.color_scheme;
1129
1169
  if (params.viewport) createBody.viewport = params.viewport;
1130
1170
  if (params.audit) createBody.audit = true;
1131
- const createRes = await fetch(`${endpoint}/v1/build-preview`, {
1132
- method: "POST",
1133
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
1134
- body: JSON.stringify(createBody)
1135
- });
1171
+ let createRes;
1172
+ try {
1173
+ createRes = await fetchWithRetry(`${endpoint}/v1/build-preview`, {
1174
+ method: "POST",
1175
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
1176
+ body: JSON.stringify(createBody)
1177
+ }, PREVIEW_REQUEST_TIMEOUT_MS, "build preview create");
1178
+ } catch (e) {
1179
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Create failed: ${describeError(e)}` }, null, 2) }] };
1180
+ }
1136
1181
  if (!createRes.ok) {
1137
1182
  const err = await createRes.text();
1138
1183
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Create failed: HTTP ${createRes.status} ${err}` }, null, 2) }] };
@@ -1144,11 +1189,16 @@ function register(api) {
1144
1189
  const excludeArgs = excludes.flatMap((p) => ["--exclude", p]);
1145
1190
  await execFile("tar", ["czf", tarball, ...excludeArgs, "-C", dir, "."], { timeout: 12e4 });
1146
1191
  const tarData = await readFile(tarball);
1147
- const uploadRes = await fetch(created.upload_url, {
1148
- method: "PUT",
1149
- headers: { "Content-Type": "application/gzip" },
1150
- body: tarData
1151
- });
1192
+ let uploadRes;
1193
+ try {
1194
+ uploadRes = await fetchWithRetry(created.upload_url, {
1195
+ method: "PUT",
1196
+ headers: { "Content-Type": "application/gzip" },
1197
+ body: tarData
1198
+ }, PREVIEW_UPLOAD_TIMEOUT_MS, "build preview upload");
1199
+ } catch (e) {
1200
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Upload failed: ${describeError(e)}` }, null, 2) }] };
1201
+ }
1152
1202
  if (!uploadRes.ok) {
1153
1203
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Upload failed: HTTP ${uploadRes.status}` }, null, 2) }] };
1154
1204
  }
@@ -1158,21 +1208,35 @@ function register(api) {
1158
1208
  } catch {
1159
1209
  }
1160
1210
  }
1161
- const startRes = await fetch(`${endpoint}/v1/build-preview/${created.job_id}/start`, {
1162
- method: "POST",
1163
- headers: { Authorization: `Bearer ${apiKey}` }
1164
- });
1211
+ let startRes;
1212
+ try {
1213
+ startRes = await fetchWithRetry(`${endpoint}/v1/build-preview/${created.job_id}/start`, {
1214
+ method: "POST",
1215
+ headers: { Authorization: `Bearer ${apiKey}` }
1216
+ }, PREVIEW_REQUEST_TIMEOUT_MS, "build preview start");
1217
+ } catch (e) {
1218
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Start failed: ${describeError(e)}` }, null, 2) }] };
1219
+ }
1165
1220
  if (!startRes.ok) {
1166
1221
  const err = await startRes.text();
1167
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Start failed: HTTP ${startRes.status} ${err}` }, null, 2) }] };
1222
+ if (isAlreadyStartedResponse(startRes.status, err)) {
1223
+ console.warn(`[openclaw-riddledc] build preview start returned ${startRes.status} for ${created.job_id}; continuing to poll`);
1224
+ } else {
1225
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Start failed: HTTP ${startRes.status} ${err}` }, null, 2) }] };
1226
+ }
1168
1227
  }
1169
1228
  const timeoutMs = ((params.timeout || 180) + 120) * 1e3;
1170
1229
  const pollStart = Date.now();
1171
1230
  const POLL_INTERVAL = 3e3;
1172
1231
  while (Date.now() - pollStart < timeoutMs) {
1173
- const statusRes = await fetch(`${endpoint}/v1/build-preview/${created.job_id}`, {
1174
- headers: { Authorization: `Bearer ${apiKey}` }
1175
- });
1232
+ let statusRes;
1233
+ try {
1234
+ statusRes = await fetchWithRetry(`${endpoint}/v1/build-preview/${created.job_id}`, {
1235
+ headers: { Authorization: `Bearer ${apiKey}` }
1236
+ }, PREVIEW_REQUEST_TIMEOUT_MS, "build preview poll", { attempts: 2 });
1237
+ } catch (e) {
1238
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Poll failed: ${describeError(e)}` }, null, 2) }] };
1239
+ }
1176
1240
  if (!statusRes.ok) {
1177
1241
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Poll failed: HTTP ${statusRes.status}` }, null, 2) }] };
1178
1242
  }
@@ -1195,7 +1259,7 @@ function register(api) {
1195
1259
  for (const output of result.outputs) {
1196
1260
  if (output.name && /\.(png|jpg|jpeg)$/i.test(output.name) && output.url) {
1197
1261
  try {
1198
- const imgRes = await fetch(output.url);
1262
+ const imgRes = await fetchWithTimeout(output.url, {}, PREVIEW_ARTIFACT_TIMEOUT_MS, "build preview artifact download");
1199
1263
  if (imgRes.ok) {
1200
1264
  const buf = await imgRes.arrayBuffer();
1201
1265
  const base64 = Buffer.from(buf).toString("base64");
@@ -2,7 +2,7 @@
2
2
  "id": "openclaw-riddledc",
3
3
  "name": "Riddle",
4
4
  "description": "Riddle (riddledc.com) hosted browser API tools for OpenClaw agents.",
5
- "version": "0.9.1",
5
+ "version": "0.9.3",
6
6
  "notes": "0.8.0: Added riddle_build_preview for Dockerfile-based builds with image caching.",
7
7
  "type": "plugin",
8
8
  "bundledSkills": [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/openclaw-riddledc",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "OpenClaw integration package for RiddleDC (no secrets).",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",
@@ -18,6 +18,11 @@
18
18
  "types": "./dist/index.d.ts",
19
19
  "import": "./dist/index.js",
20
20
  "require": "./dist/index.cjs"
21
+ },
22
+ "./core": {
23
+ "types": "./dist/core.d.ts",
24
+ "import": "./dist/core.js",
25
+ "require": "./dist/core.cjs"
21
26
  }
22
27
  },
23
28
  "files": [
@@ -45,7 +50,7 @@
45
50
  "typescript": "^5.4.5"
46
51
  },
47
52
  "scripts": {
48
- "build": "npm run sync:openclaw-plugin-version && tsup src/index.ts --format cjs,esm --dts --out-dir dist",
53
+ "build": "npm run sync:openclaw-plugin-version && tsup src/index.ts src/core.ts --format cjs,esm --dts --out-dir dist",
49
54
  "clean": "rm -rf dist",
50
55
  "lint": "echo 'lint: (not configured)'",
51
56
  "test": "echo 'test: (not configured)'",