humanish 0.20.5 → 0.21.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/comms-email-catch.d.ts +53 -0
- package/dist/comms-email-catch.js +209 -0
- package/dist/comms-email-catch.js.map +1 -0
- package/dist/comms-faux-inbox.js +12 -2
- package/dist/comms-faux-inbox.js.map +1 -1
- package/dist/comms-types.d.ts +2 -2
- package/dist/concurrent-shared-world-lab.js +9 -2
- package/dist/concurrent-shared-world-lab.js.map +1 -1
- package/dist/cua-actor-lab.d.ts +14 -0
- package/dist/cua-actor-lab.js +24 -2
- package/dist/cua-actor-lab.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/init-templates.js +7 -4
- package/dist/init-templates.js.map +1 -1
- package/dist/run.d.ts +15 -0
- package/dist/run.js +9 -0
- package/dist/run.js.map +1 -1
- package/docs/architecture/external-public-shared-world.md +8 -5
- package/docs/contracts/run-bundle.md +7 -1
- package/docs/contracts/schemas.md +1 -1
- package/docs/goals/current.md +1 -1
- package/docs/product/cineguessr-3player-external-public.md +14 -5
- package/docs/ramp/README.md +1 -1
- package/package.json +1 -1
- package/dist/comms-resend-catch.d.ts +0 -30
- package/dist/comms-resend-catch.js +0 -120
- package/dist/comms-resend-catch.js.map +0 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type ServerResponse } from "node:http";
|
|
2
|
+
import type { CommsChannel } from "./comms-types.js";
|
|
3
|
+
/** One send, normalized across providers. `body` is html-preferred, else text. */
|
|
4
|
+
export interface NormalizedSend {
|
|
5
|
+
from: string;
|
|
6
|
+
to: string[];
|
|
7
|
+
subject?: string;
|
|
8
|
+
body: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A provider wire-shape adapter. Vendor-neutral seam: the server owns the HTTP + routing + bus
|
|
12
|
+
* delivery; a profile only knows how ONE provider (or a custom app) shapes its send request.
|
|
13
|
+
*/
|
|
14
|
+
export interface EmailSendProfile {
|
|
15
|
+
/** Descriptive name (e.g. "generic", "sendgrid"). Not a dependency — just a label. */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Request paths (method POST) this profile accepts a send on. */
|
|
18
|
+
sendPaths: string[];
|
|
19
|
+
/** Parse a POST body (already JSON-parsed) into zero+ normalized sends (a batch yields many). */
|
|
20
|
+
parse(path: string, body: unknown): NormalizedSend[];
|
|
21
|
+
/** Optional provider-faithful success response. Default: 200 `{ id }` (single) / `{ data:[{id}] }`. */
|
|
22
|
+
respond?: (res: ServerResponse, ids: string[], batch: boolean) => void;
|
|
23
|
+
}
|
|
24
|
+
export interface EmailCatchServer {
|
|
25
|
+
/** Point the app's email-API base URL here (loopback only). */
|
|
26
|
+
readonly url: string;
|
|
27
|
+
readonly port: number;
|
|
28
|
+
/** Every normalized send accepted this run (runtime-only; for inspection/tests). */
|
|
29
|
+
readonly received: NormalizedSend[];
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export interface EmailCatchOptions {
|
|
33
|
+
/** Bind host. Default 127.0.0.1 (loopback ONLY). */
|
|
34
|
+
host?: string;
|
|
35
|
+
/** Port. Default 0 (ephemeral). */
|
|
36
|
+
port?: number;
|
|
37
|
+
/** Wire-shape profiles, tried in order by path. Default [genericEmailProfile, sendgridEmailProfile]. */
|
|
38
|
+
profiles?: EmailSendProfile[];
|
|
39
|
+
/** Deterministic id for responses (tests). Default a zero-padded counter. */
|
|
40
|
+
idFor?: (n: number) => string;
|
|
41
|
+
}
|
|
42
|
+
/** The flat-JSON shape: `{ from, to, subject, html, text }`. Matches Resend (POST /emails) AND a
|
|
43
|
+
* custom app that sends the common shape AND Postmark's TitleCase keys (From/To/HtmlBody/…). */
|
|
44
|
+
export declare const genericEmailProfile: EmailSendProfile;
|
|
45
|
+
/** SendGrid's nested shape: `from.email`, `personalizations[].to[].email`, `content[].value`. Proves
|
|
46
|
+
* the seam handles a structurally different vendor, not just a field-name rename. */
|
|
47
|
+
export declare const sendgridEmailProfile: EmailSendProfile;
|
|
48
|
+
export declare const DEFAULT_EMAIL_PROFILES: EmailSendProfile[];
|
|
49
|
+
/**
|
|
50
|
+
* Start the vendor-neutral email catch, routing accepted sends into `channel`. Returns the loopback
|
|
51
|
+
* URL to hand the app as its email-API base URL. `close()` in a finally (mirror by-id teardown).
|
|
52
|
+
*/
|
|
53
|
+
export declare function startEmailCatchServer(channel: CommsChannel, options?: EmailCatchOptions): Promise<EmailCatchServer>;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// A VENDOR-NEUTRAL loopback catch server for email-send APIs (#297). An app hardwired to a hosted
|
|
2
|
+
// email provider is redirected into the faux bus with ONE env var and no code change: point the app's
|
|
3
|
+
// API base URL at this server. The catch does not depend on, or name itself after, any one vendor —
|
|
4
|
+
// it normalizes each provider's distinct wire shape (Resend's flat body, SendGrid's nested
|
|
5
|
+
// personalizations, Postmark's TitleCase, a custom app's own JSON) to one shape via pluggable
|
|
6
|
+
// PROFILES, and routes the result into a CommsChannel. Resend-compatible and SendGrid-compatible out
|
|
7
|
+
// of the box; extend with a custom profile for anything else. (There is no standardized email-send
|
|
8
|
+
// request shape across vendors, so normalization is by design, not a shortcut.)
|
|
9
|
+
//
|
|
10
|
+
// 127.0.0.1 only; request bodies are never logged; request size is capped.
|
|
11
|
+
import { createServer } from "node:http";
|
|
12
|
+
// ---------------------------------------------------------------- shared parse helpers
|
|
13
|
+
function str(value) {
|
|
14
|
+
return typeof value === "string" ? value : "";
|
|
15
|
+
}
|
|
16
|
+
function optStr(value) {
|
|
17
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
18
|
+
}
|
|
19
|
+
/** "Name <email@host>" → "email@host"; a bare address passes through. */
|
|
20
|
+
function bareEmail(value) {
|
|
21
|
+
const angle = value.match(/<([^>]+)>/);
|
|
22
|
+
return (angle ? angle[1] ?? value : value).trim();
|
|
23
|
+
}
|
|
24
|
+
/** A recipient field → address strings: an array, a single, or a comma-separated string (Postmark). */
|
|
25
|
+
function toAddresses(value) {
|
|
26
|
+
if (Array.isArray(value))
|
|
27
|
+
return value.map((entry) => bareEmail(String(entry)));
|
|
28
|
+
if (typeof value === "string")
|
|
29
|
+
return value.split(",").map((part) => bareEmail(part)).filter((part) => part.length > 0);
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
// ---------------------------------------------------------------- built-in profiles
|
|
33
|
+
/** The flat-JSON shape: `{ from, to, subject, html, text }`. Matches Resend (POST /emails) AND a
|
|
34
|
+
* custom app that sends the common shape AND Postmark's TitleCase keys (From/To/HtmlBody/…). */
|
|
35
|
+
export const genericEmailProfile = {
|
|
36
|
+
name: "generic",
|
|
37
|
+
sendPaths: ["/emails", "/emails/batch", "/email", "/email/batch", "/send"],
|
|
38
|
+
parse(_path, body) {
|
|
39
|
+
const items = Array.isArray(body) ? body : [body];
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const item of items) {
|
|
42
|
+
if (typeof item !== "object" || item === null)
|
|
43
|
+
continue;
|
|
44
|
+
const rec = item;
|
|
45
|
+
const from = str(rec.from ?? rec.From);
|
|
46
|
+
const to = toAddresses(rec.to ?? rec.To);
|
|
47
|
+
const subject = optStr(rec.subject ?? rec.Subject);
|
|
48
|
+
const bodyValue = str(rec.html ?? rec.HtmlBody ?? rec.text ?? rec.TextBody);
|
|
49
|
+
if (to.length === 0 && from === "" && bodyValue === "")
|
|
50
|
+
continue;
|
|
51
|
+
out.push({ from, to, ...(subject === undefined ? {} : { subject }), body: bodyValue });
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
/** SendGrid's nested shape: `from.email`, `personalizations[].to[].email`, `content[].value`. Proves
|
|
57
|
+
* the seam handles a structurally different vendor, not just a field-name rename. */
|
|
58
|
+
export const sendgridEmailProfile = {
|
|
59
|
+
name: "sendgrid",
|
|
60
|
+
sendPaths: ["/v3/mail/send"],
|
|
61
|
+
parse(_path, body) {
|
|
62
|
+
if (typeof body !== "object" || body === null)
|
|
63
|
+
return [];
|
|
64
|
+
const rec = body;
|
|
65
|
+
const fromObj = rec.from;
|
|
66
|
+
const from = typeof fromObj === "object" && fromObj !== null ? str(fromObj.email) : str(fromObj);
|
|
67
|
+
const subject = optStr(rec.subject);
|
|
68
|
+
const content = Array.isArray(rec.content) ? rec.content : [];
|
|
69
|
+
const isPart = (part) => typeof part === "object" && part !== null;
|
|
70
|
+
const chosen = content.find((part) => isPart(part) && part.type === "text/html") ??
|
|
71
|
+
content.find((part) => isPart(part) && part.type === "text/plain");
|
|
72
|
+
const bodyValue = isPart(chosen) ? str(chosen.value) : "";
|
|
73
|
+
const personalizations = Array.isArray(rec.personalizations) ? rec.personalizations : [];
|
|
74
|
+
const to = [];
|
|
75
|
+
for (const personalization of personalizations) {
|
|
76
|
+
if (!isPart(personalization))
|
|
77
|
+
continue;
|
|
78
|
+
const recipients = Array.isArray(personalization.to) ? personalization.to : [];
|
|
79
|
+
for (const recipient of recipients) {
|
|
80
|
+
if (!isPart(recipient))
|
|
81
|
+
continue;
|
|
82
|
+
const email = str(recipient.email);
|
|
83
|
+
if (email.length > 0)
|
|
84
|
+
to.push(email);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (to.length === 0)
|
|
88
|
+
return [];
|
|
89
|
+
return [{ from, to, ...(subject === undefined ? {} : { subject }), body: bodyValue }];
|
|
90
|
+
},
|
|
91
|
+
respond(res, ids, _batch) {
|
|
92
|
+
// SendGrid answers 202 with the id in a header and an empty body.
|
|
93
|
+
res.statusCode = 202;
|
|
94
|
+
if (ids[0] !== undefined)
|
|
95
|
+
res.setHeader("x-message-id", ids[0]);
|
|
96
|
+
res.end();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
export const DEFAULT_EMAIL_PROFILES = [genericEmailProfile, sendgridEmailProfile];
|
|
100
|
+
// ---------------------------------------------------------------- server
|
|
101
|
+
class BodyTooLargeError extends Error {
|
|
102
|
+
}
|
|
103
|
+
function readBody(req, limit) {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
let size = 0;
|
|
106
|
+
const chunks = [];
|
|
107
|
+
req.on("data", (chunk) => {
|
|
108
|
+
size += chunk.length;
|
|
109
|
+
if (size > limit) {
|
|
110
|
+
// Reject WITHOUT destroying the socket here: the handler responds 413 cleanly first (a
|
|
111
|
+
// write-after-destroy would otherwise reset the connection), then tears the request down.
|
|
112
|
+
reject(new BodyTooLargeError("request body too large"));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
chunks.push(chunk);
|
|
116
|
+
});
|
|
117
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
118
|
+
req.on("error", reject);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const MAX_BODY_BYTES = 5 * 1024 * 1024;
|
|
122
|
+
/**
|
|
123
|
+
* Start the vendor-neutral email catch, routing accepted sends into `channel`. Returns the loopback
|
|
124
|
+
* URL to hand the app as its email-API base URL. `close()` in a finally (mirror by-id teardown).
|
|
125
|
+
*/
|
|
126
|
+
export async function startEmailCatchServer(channel, options = {}) {
|
|
127
|
+
const host = options.host ?? "127.0.0.1";
|
|
128
|
+
const profiles = options.profiles ?? DEFAULT_EMAIL_PROFILES;
|
|
129
|
+
const received = [];
|
|
130
|
+
let idCounter = 0;
|
|
131
|
+
const idFor = options.idFor ?? ((n) => `humanish-catch-${n.toString().padStart(6, "0")}`);
|
|
132
|
+
const respondJson = (res, status, value) => {
|
|
133
|
+
res.statusCode = status;
|
|
134
|
+
res.setHeader("content-type", "application/json");
|
|
135
|
+
res.end(JSON.stringify(value));
|
|
136
|
+
};
|
|
137
|
+
const handle = async (req, res) => {
|
|
138
|
+
const path = (req.url ?? "/").split("?")[0] ?? "/";
|
|
139
|
+
if (req.method === "GET" && (path === "/" || path === "/health")) {
|
|
140
|
+
respondJson(res, 200, { ok: true, service: "humanish-email-catch", channel: channel.channel, profiles: profiles.map((p) => p.name) });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const profile = req.method === "POST" ? profiles.find((candidate) => candidate.sendPaths.includes(path)) : undefined;
|
|
144
|
+
if (profile === undefined) {
|
|
145
|
+
respondJson(res, 404, { error: "not found" });
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
let raw;
|
|
149
|
+
try {
|
|
150
|
+
raw = await readBody(req, MAX_BODY_BYTES);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (!res.headersSent)
|
|
154
|
+
respondJson(res, error instanceof BodyTooLargeError ? 413 : 400, { error: "request body could not be read" });
|
|
155
|
+
req.destroy();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
let parsed;
|
|
159
|
+
try {
|
|
160
|
+
parsed = JSON.parse(raw.length > 0 ? raw : "{}");
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
respondJson(res, 422, { error: "invalid JSON body" });
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const sends = profile.parse(path, parsed);
|
|
167
|
+
if (sends.length === 0) {
|
|
168
|
+
// A well-formed request that names no deliverable recipient (empty body, or a shape the profile
|
|
169
|
+
// could not resolve to a send) — return a bad-request rather than a fabricated success id.
|
|
170
|
+
respondJson(res, 422, { error: "no deliverable message in request" });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const ids = [];
|
|
174
|
+
for (const send of sends) {
|
|
175
|
+
received.push(send);
|
|
176
|
+
const inbound = {
|
|
177
|
+
from: send.from,
|
|
178
|
+
to: send.to,
|
|
179
|
+
...(send.subject === undefined ? {} : { subject: send.subject }),
|
|
180
|
+
body: send.body
|
|
181
|
+
};
|
|
182
|
+
await channel.deliverRaw(inbound);
|
|
183
|
+
idCounter += 1;
|
|
184
|
+
ids.push(idFor(idCounter));
|
|
185
|
+
}
|
|
186
|
+
const batch = Array.isArray(parsed) || path.endsWith("/batch");
|
|
187
|
+
if (profile.respond)
|
|
188
|
+
profile.respond(res, ids, batch);
|
|
189
|
+
else if (batch)
|
|
190
|
+
respondJson(res, 200, { data: ids.map((id) => ({ id })) });
|
|
191
|
+
else
|
|
192
|
+
respondJson(res, 200, { id: ids[0] ?? idFor(idCounter) });
|
|
193
|
+
};
|
|
194
|
+
const server = createServer((req, res) => {
|
|
195
|
+
void handle(req, res).catch(() => {
|
|
196
|
+
if (!res.headersSent)
|
|
197
|
+
respondJson(res, 500, { error: "catch server error" });
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
await new Promise((resolve) => server.listen(options.port ?? 0, host, () => resolve()));
|
|
201
|
+
const port = server.address().port;
|
|
202
|
+
return {
|
|
203
|
+
url: `http://${host}:${port}`,
|
|
204
|
+
port,
|
|
205
|
+
received,
|
|
206
|
+
close: () => new Promise((resolve) => server.close(() => resolve()))
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=comms-email-catch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comms-email-catch.js","sourceRoot":"","sources":["../src/comms-email-catch.ts"],"names":[],"mappings":"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"}
|
package/dist/comms-faux-inbox.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// The FAUX in-process email/SMS bus (#297 Stage 2). Deterministic, $0, offline, public-safe: a
|
|
2
|
-
// message an app-under-test "sends" (via an ingress like the
|
|
2
|
+
// message an app-under-test "sends" (via an ingress like the vendor-neutral email catch) is routed to the
|
|
3
3
|
// addressed actor inbox and read back through the same CommsChannel port a real provider adapter
|
|
4
4
|
// would implement. Nothing leaves the process. See comms-types.ts for the port + public-safety notes.
|
|
5
5
|
import { digestText } from "./redaction.js";
|
|
@@ -51,7 +51,9 @@ export function extractOtpCodes(body) {
|
|
|
51
51
|
list.push(c);
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
|
-
|
|
54
|
+
// The alphanumeric alternative requires at least one DIGIT (lookahead) so a labeled prose word like
|
|
55
|
+
// "your code is INVALID" isn't captured as a code; pure-digit codes (4–8) match directly.
|
|
56
|
+
const labeledRe = /(?:one[-\s]?time\s+(?:pass)?code|verification\s+code|security\s+code|access\s+code|login\s+code|confirmation\s+code|passcode|\bOTP\b|\bPIN\b|\bcode\b)\D{0,15}\b([0-9]{4,8}|(?=[A-Za-z0-9]*[0-9])[A-Z0-9]{6,8})\b/gi;
|
|
55
57
|
let m;
|
|
56
58
|
while ((m = labeledRe.exec(text)) !== null)
|
|
57
59
|
push(labeled, m[1] ?? "");
|
|
@@ -91,6 +93,14 @@ export class FauxInbox {
|
|
|
91
93
|
if (existing)
|
|
92
94
|
return existing;
|
|
93
95
|
const value = this.channel === "sms" ? smsAddressFor(actorId) : `${sanitizeLocalPart(actorId)}@${this.domain}`;
|
|
96
|
+
// Address collision guard: two distinct actor ids can sanitize to the same local part. Reuse the
|
|
97
|
+
// existing inbox rather than resetting its queue (which would drop already-delivered mail). Both
|
|
98
|
+
// actors then share it — a faux-world edge; declare distinct addresses to avoid it.
|
|
99
|
+
const prior = this.byValue.get(value.toLowerCase());
|
|
100
|
+
if (prior) {
|
|
101
|
+
this.byActor.set(actorId, prior);
|
|
102
|
+
return prior;
|
|
103
|
+
}
|
|
94
104
|
const address = { channel: this.channel, actorId, value, digest: digestText(value, 16) };
|
|
95
105
|
this.byActor.set(actorId, address);
|
|
96
106
|
this.byValue.set(value.toLowerCase(), address);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comms-faux-inbox.js","sourceRoot":"","sources":["../src/comms-faux-inbox.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,
|
|
1
|
+
{"version":3,"file":"comms-faux-inbox.js","sourceRoot":"","sources":["../src/comms-faux-inbox.ts"],"names":[],"mappings":"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"}
|
package/dist/comms-types.d.ts
CHANGED
|
@@ -34,8 +34,8 @@ export interface OutboundMessage {
|
|
|
34
34
|
subject?: string;
|
|
35
35
|
body: string;
|
|
36
36
|
}
|
|
37
|
-
/** A raw inbound from an INGRESS (the
|
|
38
|
-
* strings the bus resolves against its provisioned inboxes. */
|
|
37
|
+
/** A raw inbound from an INGRESS (the vendor-neutral email catch, an SMTP sink, …): recipients are
|
|
38
|
+
* raw address strings the bus resolves against its provisioned inboxes. */
|
|
39
39
|
export interface InboundRaw {
|
|
40
40
|
from: string;
|
|
41
41
|
to: string[];
|
|
@@ -39,7 +39,7 @@ import { adapterScoreFailureMessage, applyBrowserAdapterHooks } from "./adapter-
|
|
|
39
39
|
import { actorRegistry, isCuaActorDescriptor } from "./actor-registry.js";
|
|
40
40
|
import { toErrorMessage } from "./command-failure.js";
|
|
41
41
|
import { mapWithConcurrency } from "./concurrency.js";
|
|
42
|
-
import { commandDigestOf, composeLaneInstructions, defaultPackLocalTree, provisionCloneSubject, provisionLocalTreeSubject, resolveLaneDevice, resolveSubjectState, runCuaLane } from "./cua-actor-lab.js";
|
|
42
|
+
import { commandDigestOf, composeLaneInstructions, defaultPackLocalTree, provisionCloneSubject, provisionLocalTreeSubject, declaredScreenForRender, resolveLaneDevice, resolveSubjectState, runCuaLane } from "./cua-actor-lab.js";
|
|
43
43
|
import { createDesktopSandbox, loadE2BDesktopModule } from "./e2b-desktop-launch.js";
|
|
44
44
|
import { concurrentSharedWorldValidationReason, externalPublicSharedWorldValidationReason } from "./lab-config.js";
|
|
45
45
|
import { buildObserverData } from "./observer-data.js";
|
|
@@ -1379,8 +1379,15 @@ export function buildConcurrentSharedWorldBundle(args) {
|
|
|
1379
1379
|
? "Actor desktop is running; the attached Observer hydrates the runtime stream URL without persisting it."
|
|
1380
1380
|
: "Contract actor only: dry-run produced the evidence shape without launching a desktop or spending provider tokens.");
|
|
1381
1381
|
const traceScreenshotMode = session?.trace.redaction.screenshots;
|
|
1382
|
+
// Include `declared` on the no-outcome fallback too (dry-run, skipped lane): otherwise an
|
|
1383
|
+
// ABSENT declared means either "the preset rendered faithfully" or "there was no live
|
|
1384
|
+
// outcome", and a dry-run bundle keeps the self-confirming shape this field exists to kill.
|
|
1385
|
+
const fallbackDeclared = declaredScreenForRender(spec.devicePreset, spec.deviceName, spec.resolution);
|
|
1382
1386
|
const desktopGeometry = outcome?.desktopGeometry ?? {
|
|
1383
|
-
screen: {
|
|
1387
|
+
screen: {
|
|
1388
|
+
requested: { width: spec.resolution[0], height: spec.resolution[1] },
|
|
1389
|
+
...(fallbackDeclared ? { declared: fallbackDeclared } : {})
|
|
1390
|
+
}
|
|
1384
1391
|
};
|
|
1385
1392
|
const screenshotMode = traceScreenshotMode === "raw" || traceScreenshotMode === "blurred"
|
|
1386
1393
|
? traceScreenshotMode
|