@riddledc/riddle-proof 0.8.84 → 0.8.85

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.
Files changed (67) hide show
  1. package/README.md +193 -0
  2. package/capabilities.json +17 -0
  3. package/dist/advanced/engine-harness.js +2 -2
  4. package/dist/advanced/index.js +4 -4
  5. package/dist/advanced/runner.js +2 -2
  6. package/dist/change-proof.cjs +22 -260
  7. package/dist/change-proof.d.cts +1 -1
  8. package/dist/change-proof.d.ts +1 -1
  9. package/dist/change-proof.js +2 -2
  10. package/dist/checked-meaning.cjs +67 -0
  11. package/dist/checked-meaning.d.cts +2 -0
  12. package/dist/checked-meaning.d.ts +2 -0
  13. package/dist/checked-meaning.js +41 -0
  14. package/dist/{chunk-QYZ3GKCP.js → chunk-AFARUBE4.js} +12 -11
  15. package/dist/chunk-J2SIQGQI.js +71 -0
  16. package/dist/{chunk-7OAETQU3.js → chunk-JZKLCY5G.js} +1 -1
  17. package/dist/chunk-KB7FYRBG.js +46 -0
  18. package/dist/chunk-NWLKJ2WI.js +31 -0
  19. package/dist/{chunk-LR4UYJDY.js → chunk-O2AO726C.js} +1 -1
  20. package/dist/chunk-ODLGSEP2.js +43 -0
  21. package/dist/chunk-OHDNCXRM.js +17 -0
  22. package/dist/cli/index.js +7 -7
  23. package/dist/cli.cjs +265 -1122
  24. package/dist/cli.d.cts +0 -1
  25. package/dist/cli.d.ts +0 -1
  26. package/dist/cli.js +7 -7
  27. package/dist/engine-harness.js +2 -2
  28. package/dist/grounded-evidence.cjs +95 -0
  29. package/dist/grounded-evidence.d.cts +2 -0
  30. package/dist/grounded-evidence.d.ts +2 -0
  31. package/dist/grounded-evidence.js +69 -0
  32. package/dist/index.cjs +314 -2042
  33. package/dist/index.d.cts +9 -3
  34. package/dist/index.d.ts +9 -3
  35. package/dist/index.js +126 -18
  36. package/dist/pr-comment.cjs +17 -107
  37. package/dist/pr-comment.d.cts +1 -1
  38. package/dist/pr-comment.d.ts +1 -1
  39. package/dist/pr-comment.js +3 -3
  40. package/dist/receipts.cjs +10 -255
  41. package/dist/receipts.d.cts +7 -115
  42. package/dist/receipts.d.ts +7 -115
  43. package/dist/receipts.js +1 -1
  44. package/dist/riddle-client.cjs +23 -695
  45. package/dist/riddle-client.d.cts +1 -188
  46. package/dist/riddle-client.d.ts +1 -188
  47. package/dist/riddle-client.js +5 -2
  48. package/dist/runner.js +2 -2
  49. package/dist/runtime/index.cjs +23 -695
  50. package/dist/runtime/index.d.cts +1 -5
  51. package/dist/runtime/index.d.ts +1 -5
  52. package/dist/runtime/index.js +5 -2
  53. package/dist/runtime/riddle-client.cjs +23 -695
  54. package/dist/runtime/riddle-client.d.cts +1 -5
  55. package/dist/runtime/riddle-client.d.ts +1 -5
  56. package/dist/runtime/riddle-client.js +5 -2
  57. package/dist/semantic-certificate.cjs +17 -1083
  58. package/dist/semantic-certificate.d.cts +2 -310
  59. package/dist/semantic-certificate.d.ts +2 -310
  60. package/dist/semantic-certificate.js +1 -1
  61. package/package.json +28 -5
  62. package/runtime/lib/riddle_core_call.mjs +3 -806
  63. package/dist/chunk-5IFZSUPF.js +0 -644
  64. package/dist/chunk-AQTCU6W5.js +0 -1086
  65. package/dist/chunk-MEVVL4TI.js +0 -258
  66. package/dist/{chunk-WLUMLHII.js → chunk-BID7CKMM.js} +9 -9
  67. package/dist/{chunk-YH7ADFY4.js → chunk-IVSP24XI.js} +3 -3
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,712 +15,41 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/runtime/index.ts
31
21
  var runtime_exports = {};
32
22
  __export(runtime_exports, {
33
- DEFAULT_RIDDLE_API_BASE_URL: () => DEFAULT_RIDDLE_API_BASE_URL,
34
- DEFAULT_RIDDLE_API_KEY_FILE: () => DEFAULT_RIDDLE_API_KEY_FILE,
35
- RIDDLE_UNSUBMITTED_WAKE_HINT: () => RIDDLE_UNSUBMITTED_WAKE_HINT,
36
- RiddleApiError: () => RiddleApiError,
37
- collectRiddlePreviewDeployWarnings: () => collectRiddlePreviewDeployWarnings,
38
- createRiddleApiClient: () => createRiddleApiClient,
39
- deployRiddlePreview: () => deployRiddlePreview,
40
- deployRiddleStaticPreview: () => deployRiddleStaticPreview,
41
- detectRiddlePreviewSource: () => detectRiddlePreviewSource,
42
- getRiddleBalance: () => getRiddleBalance,
43
- isTerminalRiddleJobStatus: () => isTerminalRiddleJobStatus,
44
- parseRiddleViewport: () => parseRiddleViewport,
45
- pollRiddleJob: () => pollRiddleJob,
46
- resolveRiddleApiKey: () => resolveRiddleApiKey,
47
- resolveRiddleApiKeySource: () => resolveRiddleApiKeySource,
48
- riddleRequestJson: () => riddleRequestJson,
49
- runRiddleScript: () => runRiddleScript,
50
- runRiddleServerPreview: () => runRiddleServerPreview
23
+ DEFAULT_RIDDLE_API_BASE_URL: () => import_client.DEFAULT_RIDDLE_API_BASE_URL,
24
+ DEFAULT_RIDDLE_API_KEY_FILE: () => import_client.DEFAULT_RIDDLE_API_KEY_FILE,
25
+ RIDDLE_BALANCE_ENDPOINT_PATH: () => import_client.RIDDLE_BALANCE_ENDPOINT_PATH,
26
+ RIDDLE_UNSUBMITTED_WAKE_HINT: () => import_client.RIDDLE_UNSUBMITTED_WAKE_HINT,
27
+ RiddleApiError: () => import_client.RiddleApiError,
28
+ collectRiddlePreviewDeployWarnings: () => import_client.collectRiddlePreviewDeployWarnings,
29
+ createRiddleApiClient: () => import_client.createRiddleApiClient,
30
+ deployRiddlePreview: () => import_client.deployRiddlePreview,
31
+ deployRiddleStaticPreview: () => import_client.deployRiddleStaticPreview,
32
+ detectRiddlePreviewSource: () => import_client.detectRiddlePreviewSource,
33
+ getRiddleBalance: () => import_client.getRiddleBalance,
34
+ getRiddleJobArtifacts: () => import_client.getRiddleJobArtifacts,
35
+ isTerminalRiddleJobStatus: () => import_client.isTerminalRiddleJobStatus,
36
+ parseRiddleViewport: () => import_client.parseRiddleViewport,
37
+ pollRiddleJob: () => import_client.pollRiddleJob,
38
+ resolveRiddleApiKey: () => import_client.resolveRiddleApiKey,
39
+ resolveRiddleApiKeySource: () => import_client.resolveRiddleApiKeySource,
40
+ riddleRequestJson: () => import_client.riddleRequestJson,
41
+ runRiddleScript: () => import_client.runRiddleScript,
42
+ runRiddleServerPreview: () => import_client.runRiddleServerPreview
51
43
  });
52
44
  module.exports = __toCommonJS(runtime_exports);
53
45
 
54
46
  // src/riddle-client.ts
55
- var import_node_child_process = require("child_process");
56
- var import_node_fs = require("fs");
57
- var import_node_os = require("os");
58
- var import_node_path = __toESM(require("path"), 1);
59
-
60
- // src/receipts.ts
61
- var RIDDLE_PREVIEW_RECEIPT_VERSION = "riddle.preview-receipt.v1";
62
- function isRecord(value) {
63
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
64
- }
65
- function requiredString(record, key, context) {
66
- const value = record[key];
67
- if (typeof value !== "string" || !value.trim()) {
68
- throw new Error(`${context}.${key} must be a non-empty string.`);
69
- }
70
- return value.trim();
71
- }
72
- function normalizedSourceIdentity(value) {
73
- if (!isRecord(value)) return {};
74
- return {
75
- git_revision: typeof value.git_revision === "string" && value.git_revision.trim() ? value.git_revision.trim() : void 0,
76
- repository: typeof value.repository === "string" && value.repository.trim() ? value.repository.trim() : void 0,
77
- dirty: typeof value.dirty === "boolean" ? value.dirty : void 0,
78
- label: typeof value.label === "string" && value.label.trim() ? value.label.trim() : void 0
79
- };
80
- }
81
- function parseRiddlePreviewReceipt(value) {
82
- if (!isRecord(value)) throw new Error("Preview receipt must be an object.");
83
- if (value.version !== RIDDLE_PREVIEW_RECEIPT_VERSION) {
84
- throw new Error(`Unsupported Preview receipt version ${String(value.version || "missing")}.`);
85
- }
86
- if (!isRecord(value.source)) throw new Error("Preview receipt source must be an object.");
87
- const expiresAt = requiredString(value, "expires_at", "preview receipt");
88
- const publishedAt = requiredString(value, "published_at", "preview receipt");
89
- const contentDigest = requiredString(value, "content_digest", "preview receipt");
90
- if (!contentDigest.startsWith("sha256:") || contentDigest.length <= "sha256:".length) {
91
- throw new Error("preview receipt.content_digest must be a sha256 digest.");
92
- }
93
- if (!Number.isFinite(Date.parse(expiresAt)) || !Number.isFinite(Date.parse(publishedAt))) {
94
- throw new Error("Preview receipt timestamps must be valid ISO date strings.");
95
- }
96
- return {
97
- version: RIDDLE_PREVIEW_RECEIPT_VERSION,
98
- preview_id: requiredString(value, "preview_id", "preview receipt"),
99
- url: requiredString(value, "url", "preview receipt"),
100
- expires_at: expiresAt,
101
- content_digest: contentDigest,
102
- source: normalizedSourceIdentity(value.source),
103
- published_at: publishedAt
104
- };
105
- }
106
-
107
- // src/riddle-client.ts
108
- var DEFAULT_RIDDLE_API_BASE_URL = "https://api.riddledc.com";
109
- var DEFAULT_RIDDLE_API_KEY_FILE = "/tmp/riddle-api-key";
110
- var RIDDLE_UNSUBMITTED_WAKE_HINT = "hosted worker may still be waking or waiting for a lease";
111
- var RiddleApiError = class extends Error {
112
- constructor(pathname, status, body) {
113
- super(`Riddle API ${pathname} failed HTTP ${status}: ${body}`);
114
- this.name = "RiddleApiError";
115
- this.status = status;
116
- this.body = body;
117
- this.path = pathname;
118
- }
119
- };
120
- var PREVIEW_PUBLISH_RECOVERY_STATUSES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
121
- var PREVIEW_PUBLISH_RECOVERY_ATTEMPTS = 30;
122
- var PREVIEW_PUBLISH_RECOVERY_INTERVAL_MS = 2e3;
123
- function normalizeBaseUrl(value) {
124
- return (value || DEFAULT_RIDDLE_API_BASE_URL).replace(/\/$/, "");
125
- }
126
- function fetchFor(config = {}) {
127
- return config.fetchImpl || fetch;
128
- }
129
- function resolveRiddleApiKeyWithSource(config = {}) {
130
- if (config.apiKey?.trim()) return { apiKey: config.apiKey.trim(), source: "option" };
131
- if (process.env.RIDDLE_API_KEY?.trim()) return { apiKey: process.env.RIDDLE_API_KEY.trim(), source: "env" };
132
- const keyFile = config.apiKeyFile || process.env.RIDDLE_API_KEY_FILE || DEFAULT_RIDDLE_API_KEY_FILE;
133
- if ((0, import_node_fs.existsSync)(keyFile)) {
134
- const key = (0, import_node_fs.readFileSync)(keyFile, "utf8").trim();
135
- if (key) return { apiKey: key, source: "file", file: keyFile };
136
- }
137
- throw new Error(`Riddle API key missing. Set RIDDLE_API_KEY or write ${DEFAULT_RIDDLE_API_KEY_FILE}.`);
138
- }
139
- function resolveRiddleApiKeySource(config = {}) {
140
- const { apiKey: _apiKey, ...source } = resolveRiddleApiKeyWithSource(config);
141
- return source;
142
- }
143
- function resolveRiddleApiKey(config = {}) {
144
- return resolveRiddleApiKeyWithSource(config).apiKey;
145
- }
146
- async function riddleRequestJson(config, pathname, init = {}) {
147
- const response = await fetchFor(config)(`${normalizeBaseUrl(config.apiBaseUrl)}${pathname}`, {
148
- ...init,
149
- headers: {
150
- Authorization: `Bearer ${resolveRiddleApiKey(config)}`,
151
- "Content-Type": "application/json",
152
- ...init.headers || {}
153
- }
154
- });
155
- const text = await response.text();
156
- let json = null;
157
- try {
158
- json = JSON.parse(text);
159
- } catch {
160
- }
161
- if (!response.ok) throw new RiddleApiError(pathname, response.status, text);
162
- return json ?? text;
163
- }
164
- async function getRiddleBalance(config = {}) {
165
- return riddleRequestJson(config, "/v1/balance", { method: "GET" });
166
- }
167
- function previewDeployResultFromRecord(input) {
168
- const { record, id, label, framework, expiresAt, publishRecovered, publishError } = input;
169
- const receipt = record.receipt && typeof record.receipt === "object" ? parseRiddlePreviewReceipt(record.receipt) : void 0;
170
- return {
171
- ok: true,
172
- id: String(record.id || record.preview_id || id),
173
- label,
174
- framework,
175
- preview_url: String(record.preview_url || ""),
176
- file_count: typeof record.file_count === "number" ? record.file_count : void 0,
177
- total_bytes: typeof record.total_bytes === "number" ? record.total_bytes : void 0,
178
- expires_at: receipt?.expires_at || expiresAt,
179
- receipt,
180
- publish_recovered: publishRecovered || void 0,
181
- publish_error: publishError,
182
- warnings: input.warnings?.length ? input.warnings : void 0,
183
- raw: record
184
- };
185
- }
186
- function gitOutput(directory, args) {
187
- try {
188
- return (0, import_node_child_process.execFileSync)("git", ["-C", directory, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
189
- } catch {
190
- return "";
191
- }
192
- }
193
- function detectRiddlePreviewSource(directory) {
194
- const gitRevision = gitOutput(directory, ["rev-parse", "HEAD"]);
195
- if (!gitRevision) return {};
196
- const repository = gitOutput(directory, ["config", "--get", "remote.origin.url"]);
197
- const status = gitOutput(directory, ["status", "--porcelain", "--untracked-files=normal"]);
198
- return {
199
- git_revision: gitRevision,
200
- repository: repository || void 0,
201
- dirty: Boolean(status)
202
- };
203
- }
204
- function canRecoverPreviewPublish(error) {
205
- return error instanceof RiddleApiError && PREVIEW_PUBLISH_RECOVERY_STATUSES.has(error.status);
206
- }
207
- function summarizePreviewDirectory(directory) {
208
- const stack = [directory];
209
- let fileCount = 0;
210
- let totalBytes = 0;
211
- while (stack.length) {
212
- const current = stack.pop();
213
- for (const entry of (0, import_node_fs.readdirSync)(current, { withFileTypes: true })) {
214
- const fullPath = import_node_path.default.join(current, entry.name);
215
- if (entry.isDirectory()) {
216
- stack.push(fullPath);
217
- continue;
218
- }
219
- if (!entry.isFile()) continue;
220
- const stat = (0, import_node_fs.statSync)(fullPath);
221
- fileCount += 1;
222
- totalBytes += stat.size;
223
- }
224
- }
225
- return { file_count: fileCount, total_bytes: totalBytes };
226
- }
227
- function previewProgressEmitter(config, base) {
228
- return async (snapshot) => {
229
- if (!config.onPreviewProgress) return;
230
- await config.onPreviewProgress({
231
- label: base.label,
232
- framework: base.framework,
233
- directory: base.directory,
234
- elapsed_ms: Math.max(0, Date.now() - base.startedAt),
235
- warnings: base.warnings?.length ? base.warnings : void 0,
236
- ...snapshot
237
- });
238
- };
239
- }
240
- async function waitForPublishedPreview(config, input) {
241
- await input.emitProgress?.({
242
- stage: "publish_recovering",
243
- id: input.id,
244
- file_count: input.localSummary?.file_count,
245
- total_bytes: input.localSummary?.total_bytes,
246
- publish_error: input.publishError.message,
247
- message: `publish returned ${input.publishError.status}; polling preview status`
248
- });
249
- for (let attempt = 1; attempt <= PREVIEW_PUBLISH_RECOVERY_ATTEMPTS; attempt += 1) {
250
- const status = await riddleRequestJson(config, `/v1/preview/${input.id}`);
251
- await input.emitProgress?.({
252
- stage: "checking_status",
253
- id: input.id,
254
- attempt,
255
- attempts: PREVIEW_PUBLISH_RECOVERY_ATTEMPTS,
256
- status: typeof status.status === "string" ? status.status : null,
257
- preview_url: typeof status.preview_url === "string" ? status.preview_url : void 0,
258
- file_count: typeof status.file_count === "number" ? status.file_count : input.localSummary?.file_count,
259
- total_bytes: typeof status.total_bytes === "number" ? status.total_bytes : input.localSummary?.total_bytes
260
- });
261
- if (String(status.status || "") === "ready" && String(status.preview_url || "").trim()) {
262
- await input.emitProgress?.({
263
- stage: "ready",
264
- id: input.id,
265
- preview_url: String(status.preview_url),
266
- file_count: typeof status.file_count === "number" ? status.file_count : input.localSummary?.file_count,
267
- total_bytes: typeof status.total_bytes === "number" ? status.total_bytes : input.localSummary?.total_bytes
268
- });
269
- return previewDeployResultFromRecord({
270
- record: status,
271
- id: input.id,
272
- label: input.label,
273
- framework: input.framework,
274
- expiresAt: input.expiresAt,
275
- publishRecovered: true,
276
- publishError: input.publishError.message,
277
- warnings: input.warnings
278
- });
279
- }
280
- if (attempt < PREVIEW_PUBLISH_RECOVERY_ATTEMPTS) {
281
- await new Promise((resolve) => setTimeout(resolve, PREVIEW_PUBLISH_RECOVERY_INTERVAL_MS));
282
- }
283
- }
284
- throw input.publishError;
285
- }
286
- async function deployRiddlePreview(config, directory, label, framework = "static", options = {}) {
287
- if (!directory?.trim()) throw new Error("directory is required");
288
- if (!label?.trim()) throw new Error("label is required");
289
- if (framework !== "spa" && framework !== "static") throw new Error("framework must be spa or static");
290
- const startedAt = Date.now();
291
- const warnings = collectRiddlePreviewDeployWarnings(directory, framework);
292
- const source = options.source || detectRiddlePreviewSource(directory);
293
- const emitProgress = previewProgressEmitter(config, { label, framework, directory, startedAt, warnings });
294
- await emitProgress({ stage: "validating", message: "checking preview input directory" });
295
- const localSummary = summarizePreviewDirectory(directory);
296
- await emitProgress({
297
- stage: "creating",
298
- file_count: localSummary.file_count,
299
- total_bytes: localSummary.total_bytes,
300
- message: "creating preview upload target"
301
- });
302
- const created = await riddleRequestJson(config, "/v1/preview", {
303
- method: "POST",
304
- body: JSON.stringify({ framework, label, source })
305
- });
306
- const id = String(created.id || "");
307
- const uploadUrl = String(created.upload_url || "");
308
- if (!id || !uploadUrl) throw new Error("Riddle preview create response was missing id or upload_url.");
309
- await emitProgress({
310
- stage: "created",
311
- id,
312
- file_count: localSummary.file_count,
313
- total_bytes: localSummary.total_bytes,
314
- message: "preview upload target created"
315
- });
316
- const scratch = (0, import_node_fs.mkdtempSync)(import_node_path.default.join((0, import_node_os.tmpdir)(), "riddle-preview-upload-"));
317
- const tarball = import_node_path.default.join(scratch, `${id}.tar.gz`);
318
- let tarballBytes = 0;
319
- try {
320
- await emitProgress({
321
- stage: "archiving",
322
- id,
323
- file_count: localSummary.file_count,
324
- total_bytes: localSummary.total_bytes,
325
- message: "creating preview archive"
326
- });
327
- (0, import_node_child_process.execFileSync)("tar", ["czf", tarball, "-C", directory, "."], { stdio: "pipe" });
328
- tarballBytes = (0, import_node_fs.statSync)(tarball).size;
329
- await emitProgress({
330
- stage: "archived",
331
- id,
332
- file_count: localSummary.file_count,
333
- total_bytes: localSummary.total_bytes,
334
- tarball_bytes: tarballBytes,
335
- message: "preview archive created"
336
- });
337
- await emitProgress({
338
- stage: "uploading",
339
- id,
340
- file_count: localSummary.file_count,
341
- total_bytes: localSummary.total_bytes,
342
- tarball_bytes: tarballBytes,
343
- message: "uploading preview archive"
344
- });
345
- const upload = await fetchFor(config)(uploadUrl, {
346
- method: "PUT",
347
- headers: { "Content-Type": "application/gzip" },
348
- body: (0, import_node_fs.readFileSync)(tarball)
349
- });
350
- if (!upload.ok) {
351
- throw new RiddleApiError(uploadUrl, upload.status, await upload.text());
352
- }
353
- await emitProgress({
354
- stage: "uploaded",
355
- id,
356
- file_count: localSummary.file_count,
357
- total_bytes: localSummary.total_bytes,
358
- tarball_bytes: tarballBytes,
359
- message: "preview archive uploaded"
360
- });
361
- } finally {
362
- (0, import_node_fs.rmSync)(scratch, { recursive: true, force: true });
363
- }
364
- const expiresAt = typeof created.expires_at === "string" ? created.expires_at : void 0;
365
- try {
366
- await emitProgress({
367
- stage: "publishing",
368
- id,
369
- file_count: localSummary.file_count,
370
- total_bytes: localSummary.total_bytes,
371
- tarball_bytes: tarballBytes || void 0,
372
- message: "publishing preview"
373
- });
374
- const published = await riddleRequestJson(config, `/v1/preview/${id}/publish`, {
375
- method: "POST"
376
- });
377
- await emitProgress({
378
- stage: "ready",
379
- id,
380
- preview_url: String(published.preview_url || ""),
381
- file_count: typeof published.file_count === "number" ? published.file_count : localSummary.file_count,
382
- total_bytes: typeof published.total_bytes === "number" ? published.total_bytes : localSummary.total_bytes
383
- });
384
- return previewDeployResultFromRecord({ record: published, id, label, framework, expiresAt, warnings });
385
- } catch (error) {
386
- if (!canRecoverPreviewPublish(error)) throw error;
387
- return waitForPublishedPreview(config, {
388
- id,
389
- label,
390
- framework,
391
- expiresAt,
392
- publishError: error,
393
- warnings,
394
- localSummary,
395
- emitProgress
396
- });
397
- }
398
- }
399
- function latestMatchingMtimeMs(directory, predicate) {
400
- let latest = 0;
401
- const stack = [directory];
402
- let visited = 0;
403
- while (stack.length) {
404
- const current = stack.pop();
405
- for (const entry of (0, import_node_fs.readdirSync)(current, { withFileTypes: true })) {
406
- const fullPath = import_node_path.default.join(current, entry.name);
407
- if (entry.isDirectory()) {
408
- stack.push(fullPath);
409
- continue;
410
- }
411
- if (!entry.isFile() || !predicate(fullPath)) continue;
412
- const stat = (0, import_node_fs.statSync)(fullPath);
413
- latest = Math.max(latest, stat.mtimeMs);
414
- visited += 1;
415
- if (visited >= 1e4) return latest;
416
- }
417
- }
418
- return latest;
419
- }
420
- function collectRiddlePreviewDeployWarnings(directory, framework = "static") {
421
- try {
422
- if (framework !== "static") return [];
423
- const resolvedDirectory = import_node_path.default.resolve(directory);
424
- if (import_node_path.default.basename(resolvedDirectory) !== "out") return [];
425
- const repoRoot = import_node_path.default.dirname(resolvedDirectory);
426
- const nextAppDir = import_node_path.default.join(repoRoot, ".next", "server", "app");
427
- if (!(0, import_node_fs.existsSync)(nextAppDir)) return [];
428
- const nextRenderedMtimeMs = latestMatchingMtimeMs(nextAppDir, (filePath) => /\.(?:html|rsc)$/i.test(filePath));
429
- if (!nextRenderedMtimeMs) return [];
430
- const outRenderedMtimeMs = (0, import_node_fs.existsSync)(resolvedDirectory) ? latestMatchingMtimeMs(resolvedDirectory, (filePath) => /\.(?:html|txt|rsc)$/i.test(filePath)) : 0;
431
- if (!outRenderedMtimeMs) {
432
- return [
433
- "Riddle Preview static deploy target is an out/ directory with newer Next render output in .next/server/app, but no rendered HTML/RSC files were found in out/. Run the project static bundle/export step before deploying."
434
- ];
435
- }
436
- if (nextRenderedMtimeMs > outRenderedMtimeMs + 1e3) {
437
- return [
438
- "Riddle Preview static deploy target out/ appears older than the Next render output in .next/server/app. Run the project static bundle/export step, such as npm run build:static-deploy or next export, before deploying to avoid a stale Preview."
439
- ];
440
- }
441
- return [];
442
- } catch {
443
- return [];
444
- }
445
- }
446
- async function deployRiddleStaticPreview(config, directory, label, options = {}) {
447
- return deployRiddlePreview(config, directory, label, "static", options);
448
- }
449
- function createTarball(directory, label, exclude = []) {
450
- const scratch = (0, import_node_fs.mkdtempSync)(import_node_path.default.join((0, import_node_os.tmpdir)(), "riddle-upload-"));
451
- const tarball = import_node_path.default.join(scratch, `${label}.tar.gz`);
452
- const excludeArgs = exclude.flatMap((item) => ["--exclude", item]);
453
- try {
454
- (0, import_node_child_process.execFileSync)("tar", ["czf", tarball, ...excludeArgs, "-C", directory, "."], { stdio: "pipe" });
455
- return { scratch, tarball };
456
- } catch (error) {
457
- (0, import_node_fs.rmSync)(scratch, { recursive: true, force: true });
458
- throw error;
459
- }
460
- }
461
- function parseRiddleViewport(value) {
462
- if (!value) return void 0;
463
- const match = /^(\d+)x(\d+)$/.exec(value.trim());
464
- if (!match) throw new Error("viewport must look like 1280x720");
465
- return { width: Number(match[1]), height: Number(match[2]) };
466
- }
467
- function scriptErrorFrom(job) {
468
- const nested = job?.proof_of_execution && typeof job.proof_of_execution === "object" && !Array.isArray(job.proof_of_execution) ? job.proof_of_execution : null;
469
- return typeof job?.script_error === "string" && job.script_error.trim() ? job.script_error : typeof nested?.script_error === "string" && nested.script_error.trim() ? nested.script_error : null;
470
- }
471
- async function runRiddleServerPreview(config, input) {
472
- if (!input.directory?.trim()) throw new Error("directory is required");
473
- if (!input.script?.trim()) throw new Error("script is required");
474
- const port = input.port || 3e3;
475
- const routePath = input.path || "/";
476
- const timeoutSec = input.timeoutSec || 180;
477
- const created = await riddleRequestJson(config, "/v1/server-preview", {
478
- method: "POST",
479
- body: JSON.stringify({
480
- image: input.image || "node:22-slim",
481
- command: input.command || "node scripts/riddleSpaPreviewServer.mjs build 3000",
482
- port,
483
- path: routePath,
484
- readiness_path: input.readinessPath || routePath,
485
- readiness_timeout: input.readinessTimeoutSec || 90,
486
- wait_until: input.waitUntil || "domcontentloaded",
487
- wait_for_selector: input.waitForSelector || "body",
488
- navigation_timeout: input.navigationTimeoutSec || 60,
489
- viewport: input.viewport,
490
- timeout: timeoutSec,
491
- script: input.script
492
- })
493
- });
494
- const jobId = String(created.job_id || "");
495
- const uploadUrl = String(created.upload_url || "");
496
- if (!jobId || !uploadUrl) {
497
- throw new Error(`Riddle server preview create response was missing job_id or upload_url.`);
498
- }
499
- const { scratch, tarball } = createTarball(input.directory, jobId, [
500
- ".git",
501
- "node_modules",
502
- "test-results",
503
- ...input.exclude || []
504
- ]);
505
- try {
506
- const upload = await fetchFor(config)(uploadUrl, {
507
- method: "PUT",
508
- headers: { "Content-Type": "application/gzip" },
509
- body: (0, import_node_fs.readFileSync)(tarball)
510
- });
511
- if (!upload.ok) throw new RiddleApiError(uploadUrl, upload.status, await upload.text());
512
- } finally {
513
- (0, import_node_fs.rmSync)(scratch, { recursive: true, force: true });
514
- }
515
- await riddleRequestJson(config, `/v1/server-preview/${jobId}/start`, {
516
- method: "POST"
517
- });
518
- let job = null;
519
- const attempts = input.pollAttempts || Math.ceil((timeoutSec + 90) / 2);
520
- const intervalMs = input.pollIntervalMs || 2e3;
521
- for (let index = 0; index < attempts; index += 1) {
522
- job = await riddleRequestJson(config, `/v1/server-preview/${jobId}`);
523
- if (isTerminalRiddleJobStatus(job.status)) break;
524
- if (index + 1 < attempts) await new Promise((resolve) => setTimeout(resolve, intervalMs));
525
- }
526
- const status = job?.status ? String(job.status) : null;
527
- const scriptError = scriptErrorFrom(job);
528
- return {
529
- ok: (status === "completed" || status === "complete") && !scriptError,
530
- job_id: jobId,
531
- status,
532
- terminal: isTerminalRiddleJobStatus(status),
533
- script_error: scriptError,
534
- job
535
- };
536
- }
537
- async function runRiddleScript(config, input) {
538
- if (!input.url?.trim()) throw new Error("url is required");
539
- if (!input.script?.trim()) throw new Error("script is required");
540
- const payload = {
541
- url: input.url,
542
- script: input.script,
543
- sync: input.sync ?? false,
544
- timeout_sec: input.timeoutSec || 120
545
- };
546
- if (input.viewport) payload.viewport = input.viewport;
547
- if (input.include) payload.include = input.include;
548
- if (typeof input.strict === "boolean") payload.strict = input.strict;
549
- if (input.options) payload.options = input.options;
550
- return riddleRequestJson(config, "/v1/run", {
551
- method: "POST",
552
- body: JSON.stringify(payload)
553
- });
554
- }
555
- function isTerminalRiddleJobStatus(status) {
556
- return ["completed", "complete", "completed_error", "completed_timeout", "failed"].includes(String(status || ""));
557
- }
558
- function stringField(record, key) {
559
- const value = record?.[key];
560
- return typeof value === "string" && value.trim() ? value.trim() : null;
561
- }
562
- function parseTimestampMs(value) {
563
- if (!value) return null;
564
- const parsed = Date.parse(value);
565
- return Number.isFinite(parsed) ? parsed : null;
566
- }
567
- function buildPollSnapshot(jobId, job, input) {
568
- const status = job?.status ? String(job.status) : null;
569
- const phase = job?.phase ? String(job.phase) : null;
570
- const terminal = isTerminalRiddleJobStatus(status);
571
- const createdAt = stringField(job, "created_at");
572
- const submittedAt = stringField(job, "submitted_at");
573
- const completedAt = stringField(job, "completed_at");
574
- const createdMs = parseTimestampMs(createdAt);
575
- const submittedMs = parseTimestampMs(submittedAt);
576
- const rawExecution = job?.execution && typeof job.execution === "object" && !Array.isArray(job.execution) ? job.execution : null;
577
- const enqueuedAt = rawExecution ? stringField(rawExecution, "enqueued_at") : null;
578
- const enqueuedMs = parseTimestampMs(enqueuedAt);
579
- const queueStartedMs = enqueuedMs ?? createdMs;
580
- const claimedAt = rawExecution ? stringField(rawExecution, "claimed_at") : null;
581
- const claimedMs = parseTimestampMs(claimedAt);
582
- let queueElapsedMs = null;
583
- if (queueStartedMs !== null && claimedMs !== null) {
584
- queueElapsedMs = Math.max(0, claimedMs - queueStartedMs);
585
- } else if (queueStartedMs !== null && submittedMs !== null) {
586
- queueElapsedMs = Math.max(0, submittedMs - queueStartedMs);
587
- } else if (queueStartedMs !== null && !submittedAt && !terminal) {
588
- queueElapsedMs = Math.max(0, input.observedAt - queueStartedMs);
589
- }
590
- return {
591
- job_id: jobId,
592
- status,
593
- phase,
594
- terminal,
595
- attempt: input.attempt,
596
- attempts: input.attempts,
597
- elapsed_ms: Math.max(0, input.observedAt - input.startedAt),
598
- created_at: createdAt,
599
- submitted_at: submittedAt,
600
- completed_at: completedAt,
601
- queue_elapsed_ms: queueElapsedMs,
602
- pre_submission_elapsed_ms: Math.max(0, Math.floor(input.preSubmissionElapsedMs ?? 0)),
603
- running_without_submission: Boolean(status && !terminal && !submittedAt),
604
- active_execution: Boolean(status === "running" && phase && phase !== "queued"),
605
- execution: rawExecution ? rawExecution : void 0
606
- };
607
- }
608
- function pollMessage(snapshot, timedOut) {
609
- if (!timedOut) return void 0;
610
- const submitted = snapshot.submitted_at || "not submitted";
611
- const wakeHint = snapshot.running_without_submission && !snapshot.created_at && !snapshot.submitted_at ? ` ${RIDDLE_UNSUBMITTED_WAKE_HINT}.` : "";
612
- const queue = snapshot.queue_elapsed_ms !== null ? ` queue_elapsed_ms=${snapshot.queue_elapsed_ms}` : "";
613
- const preSubmit = snapshot.pre_submission_elapsed_ms > 0 ? ` pre_submission_elapsed_ms=${snapshot.pre_submission_elapsed_ms}` : "";
614
- return `Riddle job ${snapshot.job_id} did not reach a terminal status after ${snapshot.attempt} poll attempts; status=${snapshot.status || "unknown"} phase=${snapshot.phase || "unknown"} submitted_at=${submitted}.${wakeHint}${queue}${preSubmit}`;
615
- }
616
- async function pollRiddleJob(config, jobId, options = {}) {
617
- if (!jobId?.trim()) throw new Error("jobId is required");
618
- const attempts = Math.max(1, Math.floor(options.attempts ?? (options.wait ? 300 : 1)));
619
- const intervalMs = Math.max(0, Math.floor(options.intervalMs ?? 2e3));
620
- const progressEveryMs = Math.max(0, Math.floor(options.progressEveryMs ?? 1e4));
621
- const unsubmittedTimeoutMs = Math.max(0, Math.floor(options.unsubmittedTimeoutMs ?? 0));
622
- const startedAt = Date.now();
623
- let job = null;
624
- let lastSnapshot = null;
625
- let lastProgressAt = 0;
626
- let lastProgressKey = "";
627
- let preSubmissionElapsedMs = 0;
628
- let unsubmittedTimedOut = false;
629
- for (let index = 0; index < attempts; index += 1) {
630
- job = await riddleRequestJson(config, `/v1/jobs/${jobId}`);
631
- const observedAt = Date.now();
632
- const nextSnapshot = buildPollSnapshot(jobId, job, {
633
- attempt: index + 1,
634
- attempts,
635
- startedAt,
636
- observedAt,
637
- preSubmissionElapsedMs
638
- });
639
- if (nextSnapshot.running_without_submission) {
640
- preSubmissionElapsedMs = Math.max(preSubmissionElapsedMs, nextSnapshot.elapsed_ms);
641
- }
642
- lastSnapshot = {
643
- ...nextSnapshot,
644
- pre_submission_elapsed_ms: preSubmissionElapsedMs
645
- };
646
- const progressKey = [
647
- lastSnapshot.status || "unknown",
648
- lastSnapshot.phase || "unknown",
649
- lastSnapshot.terminal ? "terminal" : "nonterminal",
650
- lastSnapshot.submitted_at ? "submitted" : "unsubmitted"
651
- ].join(":");
652
- if (options.onProgress) {
653
- const shouldReport = index === 0 || lastSnapshot.terminal || progressKey !== lastProgressKey || observedAt - lastProgressAt >= progressEveryMs;
654
- if (shouldReport) {
655
- lastProgressAt = observedAt;
656
- lastProgressKey = progressKey;
657
- await options.onProgress(lastSnapshot);
658
- }
659
- }
660
- unsubmittedTimedOut = Boolean(
661
- options.wait && unsubmittedTimeoutMs > 0 && lastSnapshot.running_without_submission && !lastSnapshot.created_at && !lastSnapshot.submitted_at && preSubmissionElapsedMs >= unsubmittedTimeoutMs
662
- );
663
- if (lastSnapshot.terminal) break;
664
- if (unsubmittedTimedOut) break;
665
- if (index + 1 < attempts) {
666
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
667
- }
668
- }
669
- const status = job?.status ? String(job.status) : null;
670
- const fallbackObservedAt = Date.now();
671
- const snapshot = lastSnapshot || buildPollSnapshot(jobId, job, {
672
- attempt: 0,
673
- attempts,
674
- startedAt,
675
- observedAt: fallbackObservedAt
676
- });
677
- if (!isTerminalRiddleJobStatus(status)) {
678
- const timedOut = Boolean(options.wait);
679
- return {
680
- ok: !timedOut,
681
- job_id: jobId,
682
- status,
683
- terminal: false,
684
- job,
685
- poll: {
686
- ...snapshot,
687
- timed_out: timedOut,
688
- interval_ms: intervalMs,
689
- unsubmitted_timeout: unsubmittedTimedOut || void 0,
690
- unsubmitted_timeout_ms: unsubmittedTimedOut ? unsubmittedTimeoutMs : void 0,
691
- message: pollMessage(snapshot, timedOut)
692
- }
693
- };
694
- }
695
- const artifacts = await riddleRequestJson(config, `/v1/jobs/${jobId}/artifacts`);
696
- return {
697
- ok: status === "completed" || status === "complete",
698
- job_id: jobId,
699
- status,
700
- terminal: true,
701
- job,
702
- artifacts,
703
- poll: {
704
- ...snapshot,
705
- timed_out: false,
706
- interval_ms: intervalMs
707
- }
708
- };
709
- }
710
- function createRiddleApiClient(config = {}) {
711
- return {
712
- apiKeySource: () => resolveRiddleApiKeySource(config),
713
- requestJson: (pathname, init) => riddleRequestJson(config, pathname, init),
714
- getBalance: () => getRiddleBalance(config),
715
- deployPreview: (directory, label, framework = "static", options) => deployRiddlePreview(config, directory, label, framework, options),
716
- deployStaticPreview: (directory, label, options) => deployRiddleStaticPreview(config, directory, label, options),
717
- runScript: (input) => runRiddleScript(config, input),
718
- runServerPreview: (input) => runRiddleServerPreview(config, input),
719
- pollJob: (jobId, options) => pollRiddleJob(config, jobId, options)
720
- };
721
- }
47
+ var import_client = require("@riddledc/riddle-proof-riddle-client/client");
722
48
  // Annotate the CommonJS export names for ESM import in node:
723
49
  0 && (module.exports = {
724
50
  DEFAULT_RIDDLE_API_BASE_URL,
725
51
  DEFAULT_RIDDLE_API_KEY_FILE,
52
+ RIDDLE_BALANCE_ENDPOINT_PATH,
726
53
  RIDDLE_UNSUBMITTED_WAKE_HINT,
727
54
  RiddleApiError,
728
55
  collectRiddlePreviewDeployWarnings,
@@ -731,6 +58,7 @@ function createRiddleApiClient(config = {}) {
731
58
  deployRiddleStaticPreview,
732
59
  detectRiddlePreviewSource,
733
60
  getRiddleBalance,
61
+ getRiddleJobArtifacts,
734
62
  isTerminalRiddleJobStatus,
735
63
  parseRiddleViewport,
736
64
  pollRiddleJob,