@adminide-stack/yantra-mobile 12.0.142-alpha.0 → 12.0.144

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 (118) hide show
  1. package/lib/features/attachments/displayUserMessageText.js +2 -2
  2. package/lib/features/attachments/displayUserMessageText.js.map +1 -1
  3. package/lib/features/devices/bodyComposition.js +116 -0
  4. package/lib/features/devices/bodyComposition.js.map +1 -0
  5. package/lib/features/devices/readings.js.map +1 -1
  6. package/lib/features/devices/session.js +22 -2
  7. package/lib/features/devices/session.js.map +1 -1
  8. package/lib/features/notion/NotionAgentPanel.js +987 -0
  9. package/lib/features/notion/NotionAgentPanel.js.map +1 -0
  10. package/lib/features/notion/NotionAskAiSheet.js +362 -0
  11. package/lib/features/notion/NotionAskAiSheet.js.map +1 -0
  12. package/lib/features/notion/NotionBlockView.js +4 -3
  13. package/lib/features/notion/NotionBlockView.js.map +1 -1
  14. package/lib/features/notion/NotionConnectionsSheet.js +47 -13
  15. package/lib/features/notion/NotionConnectionsSheet.js.map +1 -1
  16. package/lib/features/notion/NotionPageView.js +68 -8
  17. package/lib/features/notion/NotionPageView.js.map +1 -1
  18. package/lib/features/notion/NotionSidebarSections.js +1 -1
  19. package/lib/features/notion/NotionSidebarSections.js.map +1 -1
  20. package/lib/features/notion/NotionWorkspaceView.js +14 -9
  21. package/lib/features/notion/NotionWorkspaceView.js.map +1 -1
  22. package/lib/features/notion/database/DatabaseCells.js +3 -1
  23. package/lib/features/notion/database/DatabaseCells.js.map +1 -1
  24. package/lib/features/notion/database/DatabaseDateLayouts.js +1 -1
  25. package/lib/features/notion/database/DatabaseDateLayouts.js.map +1 -1
  26. package/lib/features/notion/database/NotionDatabaseView.js +1 -1
  27. package/lib/features/notion/database/NotionDatabaseView.js.map +1 -1
  28. package/lib/features/notion/notionAgentRunStatus.js +2 -2
  29. package/lib/features/notion/notionAgentRunStatus.js.map +1 -1
  30. package/lib/features/notion/notionAgentRuns.js +57 -0
  31. package/lib/features/notion/notionAgentRuns.js.map +1 -0
  32. package/lib/features/notion/notionAiContext.js +91 -0
  33. package/lib/features/notion/notionAiContext.js.map +1 -0
  34. package/lib/features/notion/notionConnections.js +42 -4
  35. package/lib/features/notion/notionConnections.js.map +1 -1
  36. package/lib/features/notion/notionDocuments.js +61 -1
  37. package/lib/features/notion/notionDocuments.js.map +1 -1
  38. package/lib/features/notion/notionNotesAgent.js +173 -3
  39. package/lib/features/notion/notionNotesAgent.js.map +1 -1
  40. package/lib/features/notion/notionPageKinds.js +1 -1
  41. package/lib/features/webbuilder/WebBuilderExperience.js +229 -97
  42. package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
  43. package/lib/features/webbuilder/buildFragments.js +33 -7
  44. package/lib/features/webbuilder/buildFragments.js.map +1 -1
  45. package/lib/features/webbuilder/buildJob.js +2 -2
  46. package/lib/features/webbuilder/buildJob.js.map +1 -1
  47. package/lib/features/webbuilder/codeFiles.js +18 -1
  48. package/lib/features/webbuilder/codeFiles.js.map +1 -1
  49. package/lib/features/webbuilder/components/BottomTabs.js.map +1 -1
  50. package/lib/features/webbuilder/components/CodeView.js +134 -56
  51. package/lib/features/webbuilder/components/CodeView.js.map +1 -1
  52. package/lib/features/webbuilder/components/Composer.js +2 -2
  53. package/lib/features/webbuilder/components/Composer.js.map +1 -1
  54. package/lib/features/webbuilder/components/PreviewFrame.js +19 -3
  55. package/lib/features/webbuilder/components/PreviewFrame.js.map +1 -1
  56. package/lib/features/webbuilder/components/PreviewScreen.js +310 -46
  57. package/lib/features/webbuilder/components/PreviewScreen.js.map +1 -1
  58. package/lib/features/webbuilder/components/ProjectChat.js +141 -12
  59. package/lib/features/webbuilder/components/ProjectChat.js.map +1 -1
  60. package/lib/features/webbuilder/components/ProjectSheets.js +792 -0
  61. package/lib/features/webbuilder/components/ProjectSheets.js.map +1 -0
  62. package/lib/features/webbuilder/components/ProjectsScreen.js +14 -2
  63. package/lib/features/webbuilder/components/ProjectsScreen.js.map +1 -1
  64. package/lib/features/webbuilder/components/PublishSheet.js +914 -58
  65. package/lib/features/webbuilder/components/PublishSheet.js.map +1 -1
  66. package/lib/features/webbuilder/components/TemplateCard.js +9 -6
  67. package/lib/features/webbuilder/components/TemplateCard.js.map +1 -1
  68. package/lib/features/webbuilder/components/TemplatesSheet.js +5 -17
  69. package/lib/features/webbuilder/components/TemplatesSheet.js.map +1 -1
  70. package/lib/features/webbuilder/connectorTemplates.js +171 -0
  71. package/lib/features/webbuilder/connectorTemplates.js.map +1 -0
  72. package/lib/features/webbuilder/fileTree.js +163 -0
  73. package/lib/features/webbuilder/fileTree.js.map +1 -0
  74. package/lib/features/webbuilder/followUps.js +67 -0
  75. package/lib/features/webbuilder/followUps.js.map +1 -0
  76. package/lib/features/webbuilder/previewProbe.js +49 -0
  77. package/lib/features/webbuilder/previewProbe.js.map +1 -0
  78. package/lib/features/webbuilder/previewRoutes.js +156 -0
  79. package/lib/features/webbuilder/previewRoutes.js.map +1 -0
  80. package/lib/features/webbuilder/projectTools.js +341 -0
  81. package/lib/features/webbuilder/projectTools.js.map +1 -0
  82. package/lib/features/webbuilder/publishTools.js +475 -0
  83. package/lib/features/webbuilder/publishTools.js.map +1 -0
  84. package/lib/features/webbuilder/sleepNotice.js +13 -0
  85. package/lib/features/webbuilder/sleepNotice.js.map +1 -0
  86. package/lib/features/webbuilder/stepLabels.js +37 -7
  87. package/lib/features/webbuilder/stepLabels.js.map +1 -1
  88. package/lib/features/webbuilder/studioCatalog.js +5 -1
  89. package/lib/features/webbuilder/studioCatalog.js.map +1 -1
  90. package/lib/features/webbuilder/templateCatalog.js +140 -0
  91. package/lib/features/webbuilder/templateCatalog.js.map +1 -0
  92. package/lib/features/webbuilder/webbuilderPrompts.js +31 -5
  93. package/lib/features/webbuilder/webbuilderPrompts.js.map +1 -1
  94. package/lib/features/webbuilder/workflow.js +8 -4
  95. package/lib/features/webbuilder/workflow.js.map +1 -1
  96. package/lib/screens/Devices/index.js +205 -3
  97. package/lib/screens/Devices/index.js.map +1 -1
  98. package/lib/screens/WebBuilderNative/codeWorkspaceApi.js +9 -6
  99. package/lib/screens/WebBuilderNative/codeWorkspaceApi.js.map +1 -1
  100. package/lib/screens/WebBuilderNative/index.js +1 -1
  101. package/lib/screens/WebBuilderNative/index.js.map +1 -1
  102. package/lib/screens/WebBuilderNative/keepAlive.js +53 -3
  103. package/lib/screens/WebBuilderNative/keepAlive.js.map +1 -1
  104. package/lib/screens/WebBuilderNative/unreachableRetry.js +23 -0
  105. package/lib/screens/WebBuilderNative/unreachableRetry.js.map +1 -0
  106. package/lib/screens/WebBuilderNative/useConnectorTemplates.js +37 -0
  107. package/lib/screens/WebBuilderNative/useConnectorTemplates.js.map +1 -0
  108. package/lib/screens/WebBuilderNative/useSandboxKeepAlive.js +6 -0
  109. package/lib/screens/WebBuilderNative/useSandboxKeepAlive.js.map +1 -1
  110. package/lib/screens/WebBuilderNative/useWebBuilderHost.js +302 -40
  111. package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
  112. package/lib/screens/WebBuilderNative/useWebBuilderJobs.js +2 -2
  113. package/lib/screens/WebBuilderNative/useWebBuilderJobs.js.map +1 -1
  114. package/lib/screens/WebBuilderNative/versionUndo.js +1 -1
  115. package/lib/screens/WebBuilderNative/versionUndo.js.map +1 -1
  116. package/lib/screens/WebBuilderNative/webbuilderTransport.js +147 -77
  117. package/lib/screens/WebBuilderNative/webbuilderTransport.js.map +1 -1
  118. package/package.json +4 -4
@@ -0,0 +1,475 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ function publishKind(input) {
21
+ if (!input.liveUrl) return "never";
22
+ return input.buildLive ? "published" : "changes";
23
+ }
24
+ function publishStatusLine(kind, publishing) {
25
+ if (publishing) return {
26
+ tone: "info",
27
+ text: "Publishing\u2026"
28
+ };
29
+ if (kind === "never") return {
30
+ tone: "neutral",
31
+ text: "Not published yet"
32
+ };
33
+ if (kind === "changes") return {
34
+ tone: "warning",
35
+ text: "Changes not live yet"
36
+ };
37
+ return {
38
+ tone: "success",
39
+ text: "Live"
40
+ };
41
+ }
42
+ function publishPrimaryLabel(kind) {
43
+ if (kind === "never") return "Publish";
44
+ return kind === "changes" ? "Update site" : "Publish again";
45
+ }
46
+ function projectNameOfLiveUrl(liveUrl) {
47
+ const host = String(liveUrl || "").replace(/^https?:\/\//i, "").split(/[/?#]/)[0].toLowerCase();
48
+ const m = /^([a-z0-9-]+)\.(?:yarntra\.com|pages\.dev)$/.exec(host);
49
+ return m ? m[1] : "";
50
+ }
51
+ const AI_BUSY_TEXT = "Wait for the AI to finish";
52
+ function ownCloudflareTurn(title) {
53
+ return `Publish "${title.trim() || "this site"}" to my own Cloudflare account.`;
54
+ }
55
+ function rec(v) {
56
+ return v && typeof v === "object" && !Array.isArray(v) ? v : {};
57
+ }
58
+ function str(v) {
59
+ return typeof v === "string" ? v.trim() : "";
60
+ }
61
+ function actionFields(data) {
62
+ const r = rec(data);
63
+ const inner = rec(r.data);
64
+ return Object.keys(inner).length ? inner : r;
65
+ }
66
+ function plainActionError(error, fallback) {
67
+ const first = String(error != null ? error : "").split("\n")[0].replace(/\s*\[[A-Z][A-Z0-9_]*(?:;[^\]]*)?\]\s*$/, "").replace(/[;,]?\s*the user (?:cannot|can't|can not) fix this\.?/i, ".").replace(/\.\.$/, ".").trim();
68
+ if (!first || /^at\s|\bError:\s*$/.test(first) || /^cdecli-agent\b/i.test(first)) return fallback;
69
+ return first.length > 240 ? `${first.slice(0, 239)}\u2026` : first;
70
+ }
71
+ const CUSTOM_DOMAIN_ACTION = "WEBBUILDER_CUSTOM_DOMAIN";
72
+ const UNPUBLISH_ACTION = "WEBBUILDER_UNPUBLISH";
73
+ const PLATFORM_DOMAIN_SUFFIX = "yarntra.com";
74
+ const REGISTRAR_GUIDES = [{
75
+ id: "namecheap",
76
+ label: "Namecheap",
77
+ steps: ["Open Domain List and click Manage next to your domain.", "Go to Advanced DNS and click Add New Record.", "Pick the type, paste the host and value from above, then save."]
78
+ }, {
79
+ id: "godaddy",
80
+ label: "GoDaddy",
81
+ steps: ["Open My Products and click DNS next to your domain.", "Click Add New Record.", "Pick the type, paste the name and value from above, then save."]
82
+ }, {
83
+ id: "cloudflare",
84
+ label: "Cloudflare",
85
+ steps: ["Open your domain, then DNS > Records.", "Click Add record and paste the name and target from above.", "Set Proxy status to DNS only (grey cloud), then save."]
86
+ }, {
87
+ id: "other",
88
+ label: "Other",
89
+ steps: ["Sign in where you bought the domain and open its DNS settings.", "Add each record above: same type, host and value.", "Save. Changes can take up to a few hours to reach everyone."]
90
+ }];
91
+ function domainSteps(input) {
92
+ const add = {
93
+ id: "add",
94
+ label: "Add your domain"
95
+ };
96
+ const dns = {
97
+ id: "dns",
98
+ label: input.autoConfigured ? "DNS set up for you" : "Add the DNS record"
99
+ };
100
+ const verify = {
101
+ id: "verify",
102
+ label: "Verify and turn on HTTPS"
103
+ };
104
+ if (!input.attached) {
105
+ return [__spreadProps(__spreadValues({}, add), {
106
+ status: "active"
107
+ }), __spreadProps(__spreadValues({}, dns), {
108
+ status: "pending"
109
+ }), __spreadProps(__spreadValues({}, verify), {
110
+ status: "pending"
111
+ })];
112
+ }
113
+ if (input.state === "active") {
114
+ return [__spreadProps(__spreadValues({}, add), {
115
+ status: "done"
116
+ }), __spreadProps(__spreadValues({}, dns), {
117
+ status: "done"
118
+ }), __spreadProps(__spreadValues({}, verify), {
119
+ status: "done"
120
+ })];
121
+ }
122
+ if (input.state === "error") {
123
+ return [__spreadProps(__spreadValues({}, add), {
124
+ status: "done"
125
+ }), __spreadProps(__spreadValues({}, dns), {
126
+ status: input.autoConfigured ? "done" : "failed"
127
+ }), __spreadProps(__spreadValues({}, verify), {
128
+ status: "pending"
129
+ })];
130
+ }
131
+ return [__spreadProps(__spreadValues({}, add), {
132
+ status: "done"
133
+ }), __spreadProps(__spreadValues({}, dns), {
134
+ status: input.autoConfigured ? "done" : "active"
135
+ }), __spreadProps(__spreadValues({}, verify), {
136
+ status: input.autoConfigured ? "active" : "pending"
137
+ })];
138
+ }
139
+ function normalizeDomain(raw) {
140
+ return String(raw || "").trim().replace(/^https?:\/\//i, "").split("/")[0].toLowerCase().replace(/\.$/, "");
141
+ }
142
+ function isValidDomain(raw) {
143
+ const d = normalizeDomain(raw);
144
+ return /^(?=.{4,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/.test(d);
145
+ }
146
+ function isPlatformDomain(domain) {
147
+ const d = normalizeDomain(domain);
148
+ return d === PLATFORM_DOMAIN_SUFFIX || d.endsWith(`.${PLATFORM_DOMAIN_SUFFIX}`);
149
+ }
150
+ function dnsStateOf(status) {
151
+ const s = str(status).toLowerCase();
152
+ if (s === "active") return "active";
153
+ if (s === "error" || s === "blocked" || s === "deactivated" || s === "failed") return "error";
154
+ return "pending";
155
+ }
156
+ function dnsStateText(state) {
157
+ if (state === "active") return "Connected - your domain is live with HTTPS.";
158
+ if (state === "error") return "Something is wrong with the DNS setup. Check the records below, then check again.";
159
+ return "Waiting for DNS - this can take up to a few hours.";
160
+ }
161
+ function dnsStateLabel(state) {
162
+ if (state === "active") return "Active";
163
+ return state === "error" ? "Error" : "Pending";
164
+ }
165
+ function recordValueLabel(type) {
166
+ const t = type.toUpperCase();
167
+ if (t === "CNAME") return "Value: your site's address";
168
+ if (t === "TXT") return "Value: ownership code";
169
+ if (t === "A" || t === "AAAA") return "Value: server address";
170
+ return "Value";
171
+ }
172
+ function recordHostLabel(name, domain) {
173
+ return name === "@" ? `Host: @ (${normalizeDomain(domain) || "the bare domain"})` : "Host";
174
+ }
175
+ function formatTtl(ttl) {
176
+ if (ttl == null || !Number.isFinite(ttl) || ttl <= 0) return "";
177
+ if (ttl === 1) return "Auto";
178
+ if (ttl % 3600 === 0) return `${ttl / 3600} hr`;
179
+ if (ttl % 60 === 0) return `${ttl / 60} min`;
180
+ return `${ttl} s`;
181
+ }
182
+ function zoneOf(domain, host) {
183
+ const d = normalizeDomain(domain);
184
+ if (!host || host === "@") return d;
185
+ return d.startsWith(`${host}.`) ? d.slice(host.length + 1) : d;
186
+ }
187
+ function hostLabel(fqdn, zone) {
188
+ const name = normalizeDomain(fqdn);
189
+ const z = normalizeDomain(zone);
190
+ if (!z) return name;
191
+ if (name === z) return "@";
192
+ return name.endsWith(`.${z}`) ? name.slice(0, -(z.length + 1)) : name;
193
+ }
194
+ function recordRows(manualDns) {
195
+ const list = Array.isArray(manualDns) ? manualDns : rec(manualDns).records;
196
+ if (!Array.isArray(list)) return [];
197
+ return list.map((item) => {
198
+ const r = rec(item);
199
+ const type = str(r.type).toUpperCase();
200
+ const value = str(r.value) || str(r.content) || str(r.target);
201
+ const ttl = Number(r.ttl);
202
+ const note = str(r.note);
203
+ return __spreadValues(__spreadValues({
204
+ type,
205
+ name: str(r.name) || str(r.host) || "@",
206
+ value
207
+ }, Number.isFinite(ttl) && ttl > 0 ? {
208
+ ttl
209
+ } : {}), note && note !== "Subdomain CNAME." ? {
210
+ note
211
+ } : {});
212
+ }).filter((r) => r.type && r.value);
213
+ }
214
+ function parseDomainDns(input, fallbackDomain = "") {
215
+ const data = actionFields(input);
216
+ const domain = normalizeDomain(str(data.domain) || fallbackDomain);
217
+ const verification = rec(data.verification);
218
+ const validation = rec(data.validation);
219
+ const live = data.live === true || dnsStateOf(data.status) === "active";
220
+ const state = live ? "active" : dnsStateOf(data.status || verification.status);
221
+ const autoConfigured = data.dnsConfigured === true || isPlatformDomain(domain);
222
+ let records = [];
223
+ if (!live && !autoConfigured) {
224
+ const recordState = dnsStateOf(verification.status || data.status);
225
+ records = recordRows(data.manualDns).map((r) => __spreadProps(__spreadValues({}, r), {
226
+ state: recordState
227
+ }));
228
+ const zone = records.length ? zoneOf(domain, records[0].name) : "";
229
+ const txtName = str(validation.txt_name) || str(validation.txtName);
230
+ const txtValue = str(validation.txt_value) || str(validation.txtValue);
231
+ if (txtName && txtValue && !records.some((r) => r.type === "TXT" && r.value === txtValue)) {
232
+ records.push({
233
+ type: "TXT",
234
+ name: hostLabel(txtName, zone),
235
+ value: txtValue,
236
+ state: dnsStateOf(validation.status)
237
+ });
238
+ }
239
+ }
240
+ const sug = rec(rec(data.manualDns).suggestion);
241
+ const suggestion = !live && str(sug.domain) ? {
242
+ domain: normalizeDomain(str(sug.domain)),
243
+ why: str(sug.why)
244
+ } : void 0;
245
+ const errorMessage = state === "error" ? str(verification.error_message) || str(verification.errorMessage) || str(validation.error_message) || str(validation.errorMessage) || str(data.dnsError) || void 0 : void 0;
246
+ return __spreadValues(__spreadValues({
247
+ domain,
248
+ state,
249
+ records,
250
+ autoConfigured
251
+ }, suggestion ? {
252
+ suggestion
253
+ } : {}), errorMessage ? {
254
+ errorMessage
255
+ } : {});
256
+ }
257
+ function isNotAttachedError(error, data) {
258
+ const blob = [error || "", str(actionFields(data).hint)].join("\n");
259
+ return /not attached|attach it with operation|could not read the domain status|not found/i.test(blob);
260
+ }
261
+ function attachDomainParams(projectName, domain) {
262
+ return {
263
+ projectName,
264
+ domain: normalizeDomain(domain),
265
+ operation: "attach",
266
+ configureDns: true,
267
+ proxied: false
268
+ };
269
+ }
270
+ function domainStatusParams(projectName, domain, retry = false) {
271
+ return __spreadValues({
272
+ projectName,
273
+ domain: normalizeDomain(domain),
274
+ operation: "status"
275
+ }, retry ? {
276
+ retry: true
277
+ } : {});
278
+ }
279
+ function removeDomainParams(projectName, domain) {
280
+ return {
281
+ projectName,
282
+ domain: normalizeDomain(domain),
283
+ operation: "remove"
284
+ };
285
+ }
286
+ function unpublishParams(projectName, customDomain) {
287
+ return __spreadValues({
288
+ projectName
289
+ }, customDomain ? {
290
+ customDomain: normalizeDomain(customDomain)
291
+ } : {});
292
+ }
293
+ const LEVELS = /* @__PURE__ */ new Set(["pass", "warn", "fail", "skip"]);
294
+ const CATEGORIES = /* @__PURE__ */ new Set(["security", "seo", "performance", "quality"]);
295
+ const SEVERITIES = /* @__PURE__ */ new Set(["critical", "warning", "info"]);
296
+ const clip = (v, max) => str(v).slice(0, max);
297
+ function parsePrePublishReport(raw) {
298
+ let value = raw;
299
+ if (typeof value === "string") {
300
+ try {
301
+ value = JSON.parse(value);
302
+ } catch (e) {
303
+ return null;
304
+ }
305
+ }
306
+ const top = rec(value);
307
+ const r0 = Array.isArray(top.items) ? top : rec(top.report);
308
+ if (!Array.isArray(r0.items)) return null;
309
+ const items = [];
310
+ for (const it of r0.items.slice(0, 60)) {
311
+ const r = rec(it);
312
+ const level = String(r.level || "");
313
+ const title = clip(r.title, 200);
314
+ if (LEVELS.has(level) && title) {
315
+ items.push(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadProps(__spreadValues({
316
+ id: clip(r.id, 64) || title.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
317
+ level
318
+ }, r.critical === true ? {
319
+ critical: true
320
+ } : {}), {
321
+ title
322
+ }), clip(r.detail, 1e3) ? {
323
+ detail: clip(r.detail, 1e3)
324
+ } : {}), clip(r.fix, 1e3) ? {
325
+ fix: clip(r.fix, 1e3)
326
+ } : {}), CATEGORIES.has(String(r.category)) ? {
327
+ category: r.category
328
+ } : {}), SEVERITIES.has(String(r.severity)) ? {
329
+ severity: r.severity
330
+ } : {}), clip(r.why, 400) ? {
331
+ why: clip(r.why, 400)
332
+ } : {}));
333
+ }
334
+ }
335
+ const scoresRec = rec(r0.scores);
336
+ const scores = {};
337
+ for (const key of ["performance", "accessibility", "seo", "bestPractices"]) {
338
+ const n = Number(scoresRec[key]);
339
+ if (scoresRec[key] != null && Number.isFinite(n)) scores[key] = Math.max(0, Math.min(100, Math.round(n)));
340
+ }
341
+ if (!items.length && !Object.keys(scores).length) return null;
342
+ return __spreadValues({
343
+ ranAt: str(r0.ranAt),
344
+ blocking: r0.blocking === true,
345
+ items
346
+ }, Object.keys(scores).length ? {
347
+ scores
348
+ } : {});
349
+ }
350
+ const CATEGORY_BY_ID = {
351
+ secrets: "security",
352
+ "npm-audit": "security",
353
+ "meta-title": "seo",
354
+ "meta-description": "seo",
355
+ "og-image": "seo",
356
+ favicon: "seo",
357
+ "lighthouse-seo": "seo",
358
+ "lighthouse-perf": "performance",
359
+ "lighthouse-a11y": "performance",
360
+ "broken-images": "quality"
361
+ };
362
+ const WHY_BY_ID = {
363
+ secrets: "Anything in your site's code can be read by every visitor. A leaked key lets others spend your money or reach your data.",
364
+ "npm-audit": "Known security holes in the packages your site uses can be used to attack your visitors or your site.",
365
+ "broken-images": "Broken images make the site look unfinished."
366
+ };
367
+ function categoryOf(item) {
368
+ if (item.category) return item.category;
369
+ if (CATEGORY_BY_ID[item.id]) return CATEGORY_BY_ID[item.id];
370
+ return item.id.startsWith("db-") ? "security" : "quality";
371
+ }
372
+ function severityOf(item) {
373
+ if (item.level === "pass" || item.level === "skip") return null;
374
+ if (item.severity) return item.severity;
375
+ if (item.level === "fail" && item.critical) return "critical";
376
+ return "warning";
377
+ }
378
+ function fixTurnText(item) {
379
+ const fix = (item.fix || "").trim();
380
+ const detail = (item.detail || "").trim();
381
+ const parts = [`Fix this before I publish: ${item.title}.`];
382
+ if (detail && item.id !== "secrets") parts.push(`Details: ${detail}`);
383
+ if (fix) parts.push(fix);
384
+ if (item.id === "secrets") {
385
+ parts.push("Never put secret keys in client code - move them to server-side environment variables.");
386
+ }
387
+ return parts.join("\n").slice(0, 2e3);
388
+ }
389
+ const RANK = {
390
+ problem: 0,
391
+ skipped: 1,
392
+ ok: 2
393
+ };
394
+ const SEVERITY_RANK = {
395
+ critical: 0,
396
+ warning: 1,
397
+ info: 2
398
+ };
399
+ function reviewFindings(report) {
400
+ var _a;
401
+ return ((_a = report == null ? void 0 : report.items) != null ? _a : []).map((item, i) => {
402
+ const severity = severityOf(item);
403
+ let status = "problem";
404
+ if (item.level === "pass") status = "ok";
405
+ else if (item.level === "skip") status = "skipped";
406
+ const why = item.why || WHY_BY_ID[item.id];
407
+ const finding = __spreadProps(__spreadValues(__spreadValues({
408
+ key: `report:${item.id}`,
409
+ category: categoryOf(item),
410
+ status,
411
+ severity,
412
+ title: item.title
413
+ }, item.detail ? {
414
+ detail: item.detail
415
+ } : {}), why ? {
416
+ why
417
+ } : {}), {
418
+ fixText: status === "problem" && item.fix ? fixTurnText(item) : null,
419
+ blocks: severity === "critical"
420
+ });
421
+ return {
422
+ finding,
423
+ i
424
+ };
425
+ }).sort((a, b) => {
426
+ var _a2, _b;
427
+ return RANK[a.finding.status] - RANK[b.finding.status] || SEVERITY_RANK[(_a2 = a.finding.severity) != null ? _a2 : "info"] - SEVERITY_RANK[(_b = b.finding.severity) != null ? _b : "info"] || a.i - b.i;
428
+ }).map(({
429
+ finding
430
+ }) => finding);
431
+ }
432
+ function findingsForTab(findings, tab) {
433
+ if (tab === "security") return findings.filter((f) => f.category === "security" || f.category === "quality");
434
+ if (tab === "seo") return findings.filter((f) => f.category === "seo");
435
+ return findings.filter((f) => f.category === "performance");
436
+ }
437
+ const SEVERITY_LABEL = {
438
+ critical: "Critical",
439
+ warning: "Warning",
440
+ info: "Tip"
441
+ };
442
+ const TAB_EMPTY = {
443
+ security: {
444
+ title: "Checks run when you publish: secret keys, dependencies and database rules",
445
+ body: "A critical problem stops the publish, and you can fix it with AI."
446
+ },
447
+ seo: {
448
+ title: "Checks run when you publish: page title, description, share image and icon",
449
+ body: "Fix anything missing with AI so the site reads well in search and in shared links."
450
+ },
451
+ speed: {
452
+ title: "Speed is measured when you publish (Google PageSpeed, mobile)",
453
+ body: "Scores for speed, accessibility, SEO and best practices appear here."
454
+ }
455
+ };
456
+ function scoreBadges(report) {
457
+ var _a;
458
+ const labels = [["performance", "Speed"], ["accessibility", "Accessibility"], ["seo", "SEO"], ["bestPractices", "Best practices"]];
459
+ const out = [];
460
+ for (const [key, label] of labels) {
461
+ const v = (_a = report == null ? void 0 : report.scores) == null ? void 0 : _a[key];
462
+ if (typeof v === "number") {
463
+ let tone = "poor";
464
+ if (v >= 90) tone = "good";
465
+ else if (v >= 50) tone = "ok";
466
+ out.push({
467
+ key,
468
+ label,
469
+ value: v,
470
+ tone
471
+ });
472
+ }
473
+ }
474
+ return out;
475
+ }export{AI_BUSY_TEXT,CUSTOM_DOMAIN_ACTION,PLATFORM_DOMAIN_SUFFIX,REGISTRAR_GUIDES,SEVERITY_LABEL,TAB_EMPTY,UNPUBLISH_ACTION,actionFields,attachDomainParams,categoryOf,dnsStateLabel,dnsStateOf,dnsStateText,domainStatusParams,domainSteps,findingsForTab,fixTurnText,formatTtl,hostLabel,isNotAttachedError,isPlatformDomain,isValidDomain,normalizeDomain,ownCloudflareTurn,parseDomainDns,parsePrePublishReport,plainActionError,projectNameOfLiveUrl,publishKind,publishPrimaryLabel,publishStatusLine,recordHostLabel,recordValueLabel,removeDomainParams,reviewFindings,scoreBadges,severityOf,unpublishParams,zoneOf};//# sourceMappingURL=publishTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publishTools.js","sources":["../../../src/features/webbuilder/publishTools.ts"],"sourcesContent":["/**\n * The Publish menu's logic (web `publish/PublishMenu`, `publishState`, `customDomain`,\n * `prePublishReport`, `review/security`, `review/performance`): the status line and the\n * primary label, your-domain setup (WEBBUILDER_CUSTOM_DOMAIN attach / status / remove,\n * the three steps, the registrar records), Unpublish, and the Review site findings\n * (the server's pre-publish checks: security, SEO and speed). Pure.\n */\n\n// ── Status ───────────────────────────────────────────────────────────────\n\n/** `never`: not on the internet; `changes`: live, the newest build is not; `published`: live and current. */\nexport type PublishKind = 'never' | 'changes' | 'published';\n\nexport function publishKind(input: { liveUrl: string | null | undefined; buildLive: boolean }): PublishKind {\n if (!input.liveUrl) return 'never';\n return input.buildLive ? 'published' : 'changes';\n}\n\nexport type StatusTone = 'neutral' | 'info' | 'warning' | 'success';\n\nexport function publishStatusLine(kind: PublishKind, publishing: boolean): { tone: StatusTone; text: string } {\n if (publishing) return { tone: 'info', text: 'Publishing…' };\n if (kind === 'never') return { tone: 'neutral', text: 'Not published yet' };\n if (kind === 'changes') return { tone: 'warning', text: 'Changes not live yet' };\n return { tone: 'success', text: 'Live' };\n}\n\nexport function publishPrimaryLabel(kind: PublishKind): string {\n if (kind === 'never') return 'Publish';\n return kind === 'changes' ? 'Update site' : 'Publish again';\n}\n\n/** The project name a live address was published under (`<name>.yarntra.com`), or ''. */\nexport function projectNameOfLiveUrl(liveUrl: string | null | undefined): string {\n const host = String(liveUrl || '')\n .replace(/^https?:\\/\\//i, '')\n .split(/[/?#]/)[0]\n .toLowerCase();\n const m = /^([a-z0-9-]+)\\.(?:yarntra\\.com|pages\\.dev)$/.exec(host);\n return m ? m[1] : '';\n}\n\nexport const AI_BUSY_TEXT = 'Wait for the AI to finish';\n\n/** The own-Cloudflare export: an agent turn, as the web menu sends it. */\nexport function ownCloudflareTurn(title: string): string {\n return `Publish \"${title.trim() || 'this site'}\" to my own Cloudflare account.`;\n}\n\n// ── Connector results ────────────────────────────────────────────────────\n\nfunction rec(v: unknown): Record<string, unknown> {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : {};\n}\n\nfunction str(v: unknown): string {\n return typeof v === 'string' ? v.trim() : '';\n}\n\n/** The action's fields (the transport unwraps `{ data }`; a second layer is tolerated). */\nexport function actionFields(data: unknown): Record<string, unknown> {\n const r = rec(data);\n const inner = rec(r.data);\n return Object.keys(inner).length ? inner : r;\n}\n\n/** A connector error as one plain sentence: no `[CODE]` tags, notes for the AI or stack frames. */\nexport function plainActionError(error: string | null | undefined, fallback: string): string {\n const first = String(error ?? '')\n .split('\\n')[0]\n .replace(/\\s*\\[[A-Z][A-Z0-9_]*(?:;[^\\]]*)?\\]\\s*$/, '')\n .replace(/[;,]?\\s*the user (?:cannot|can't|can not) fix this\\.?/i, '.')\n .replace(/\\.\\.$/, '.')\n .trim();\n if (!first || /^at\\s|\\bError:\\s*$/.test(first) || /^cdecli-agent\\b/i.test(first)) return fallback;\n return first.length > 240 ? `${first.slice(0, 239)}…` : first;\n}\n\n// ── Your domain ──────────────────────────────────────────────────────────\n\nexport const CUSTOM_DOMAIN_ACTION = 'WEBBUILDER_CUSTOM_DOMAIN';\nexport const UNPUBLISH_ACTION = 'WEBBUILDER_UNPUBLISH';\nexport const PLATFORM_DOMAIN_SUFFIX = 'yarntra.com';\n\nexport type DnsState = 'pending' | 'active' | 'error';\n\nexport interface DnsRecordRow {\n type: string;\n /** Host as registrars ask for it: \"@\" for the root, else the labels left of the zone. */\n name: string;\n value: string;\n ttl?: number;\n note?: string;\n state?: DnsState;\n}\n\nexport interface DomainDnsView {\n domain: string;\n state: DnsState;\n records: DnsRecordRow[];\n /** DNS was written on our side (platform address or a zone on the same account). */\n autoConfigured: boolean;\n /** Root domain at another registrar: connect this subdomain instead. */\n suggestion?: { domain: string; why: string };\n errorMessage?: string;\n}\n\nexport type RegistrarId = 'namecheap' | 'godaddy' | 'cloudflare' | 'other';\n\nexport const REGISTRAR_GUIDES: ReadonlyArray<{ id: RegistrarId; label: string; steps: readonly string[] }> = [\n {\n id: 'namecheap',\n label: 'Namecheap',\n steps: [\n 'Open Domain List and click Manage next to your domain.',\n 'Go to Advanced DNS and click Add New Record.',\n 'Pick the type, paste the host and value from above, then save.',\n ],\n },\n {\n id: 'godaddy',\n label: 'GoDaddy',\n steps: [\n 'Open My Products and click DNS next to your domain.',\n 'Click Add New Record.',\n 'Pick the type, paste the name and value from above, then save.',\n ],\n },\n {\n id: 'cloudflare',\n label: 'Cloudflare',\n steps: [\n 'Open your domain, then DNS > Records.',\n 'Click Add record and paste the name and target from above.',\n 'Set Proxy status to DNS only (grey cloud), then save.',\n ],\n },\n {\n id: 'other',\n label: 'Other',\n steps: [\n 'Sign in where you bought the domain and open its DNS settings.',\n 'Add each record above: same type, host and value.',\n 'Save. Changes can take up to a few hours to reach everyone.',\n ],\n },\n];\n\nexport type DomainStepStatus = 'done' | 'active' | 'pending' | 'failed';\nexport interface DomainStep {\n id: 'add' | 'dns' | 'verify';\n label: string;\n status: DomainStepStatus;\n}\n\n/** The three-step setup list: add the domain, add the DNS record, verify. */\nexport function domainSteps(input: { attached: boolean; state?: DnsState; autoConfigured?: boolean }): DomainStep[] {\n const add = { id: 'add' as const, label: 'Add your domain' };\n const dns = { id: 'dns' as const, label: input.autoConfigured ? 'DNS set up for you' : 'Add the DNS record' };\n const verify = { id: 'verify' as const, label: 'Verify and turn on HTTPS' };\n if (!input.attached) {\n return [\n { ...add, status: 'active' },\n { ...dns, status: 'pending' },\n { ...verify, status: 'pending' },\n ];\n }\n if (input.state === 'active') {\n return [\n { ...add, status: 'done' },\n { ...dns, status: 'done' },\n { ...verify, status: 'done' },\n ];\n }\n if (input.state === 'error') {\n return [\n { ...add, status: 'done' },\n { ...dns, status: input.autoConfigured ? 'done' : 'failed' },\n { ...verify, status: 'pending' },\n ];\n }\n return [\n { ...add, status: 'done' },\n { ...dns, status: input.autoConfigured ? 'done' : 'active' },\n { ...verify, status: input.autoConfigured ? 'active' : 'pending' },\n ];\n}\n\nexport function normalizeDomain(raw: string): string {\n return String(raw || '')\n .trim()\n .replace(/^https?:\\/\\//i, '')\n .split('/')[0]\n .toLowerCase()\n .replace(/\\.$/, '');\n}\n\n/** Something that can be a domain: labels of letters, digits and dashes, and a TLD. */\nexport function isValidDomain(raw: string): boolean {\n const d = normalizeDomain(raw);\n return /^(?=.{4,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$/.test(d);\n}\n\nexport function isPlatformDomain(domain: string): boolean {\n const d = normalizeDomain(domain);\n return d === PLATFORM_DOMAIN_SUFFIX || d.endsWith(`.${PLATFORM_DOMAIN_SUFFIX}`);\n}\n\n/** Cloudflare's domain / verification / validation status words to our three states. */\nexport function dnsStateOf(status: unknown): DnsState {\n const s = str(status).toLowerCase();\n if (s === 'active') return 'active';\n if (s === 'error' || s === 'blocked' || s === 'deactivated' || s === 'failed') return 'error';\n return 'pending';\n}\n\nexport function dnsStateText(state: DnsState): string {\n if (state === 'active') return 'Connected - your domain is live with HTTPS.';\n if (state === 'error') return 'Something is wrong with the DNS setup. Check the records below, then check again.';\n return 'Waiting for DNS - this can take up to a few hours.';\n}\n\nexport function dnsStateLabel(state: DnsState): string {\n if (state === 'active') return 'Active';\n return state === 'error' ? 'Error' : 'Pending';\n}\n\n/** What the record's value is, in words: the CNAME target is the site's own address. */\nexport function recordValueLabel(type: string): string {\n const t = type.toUpperCase();\n if (t === 'CNAME') return \"Value: your site's address\";\n if (t === 'TXT') return 'Value: ownership code';\n if (t === 'A' || t === 'AAAA') return 'Value: server address';\n return 'Value';\n}\n\n/** The host field in words: \"@\" is the bare domain. */\nexport function recordHostLabel(name: string, domain: string): string {\n return name === '@' ? `Host: @ (${normalizeDomain(domain) || 'the bare domain'})` : 'Host';\n}\n\nexport function formatTtl(ttl: number | undefined): string {\n if (ttl == null || !Number.isFinite(ttl) || ttl <= 0) return '';\n if (ttl === 1) return 'Auto';\n if (ttl % 3600 === 0) return `${ttl / 3600} hr`;\n if (ttl % 60 === 0) return `${ttl / 60} min`;\n return `${ttl} s`;\n}\n\n/** The zone a record row lives in: the domain minus the host the connector gave (\"www\" or \"@\"). */\nexport function zoneOf(domain: string, host: string): string {\n const d = normalizeDomain(domain);\n if (!host || host === '@') return d;\n return d.startsWith(`${host}.`) ? d.slice(host.length + 1) : d;\n}\n\n/** `_cf-custom-hostname.www.example.com` in zone `example.com` -> `_cf-custom-hostname.www`. */\nexport function hostLabel(fqdn: string, zone: string): string {\n const name = normalizeDomain(fqdn);\n const z = normalizeDomain(zone);\n if (!z) return name;\n if (name === z) return '@';\n return name.endsWith(`.${z}`) ? name.slice(0, -(z.length + 1)) : name;\n}\n\nfunction recordRows(manualDns: unknown): DnsRecordRow[] {\n const list = Array.isArray(manualDns) ? manualDns : rec(manualDns).records;\n if (!Array.isArray(list)) return [];\n return list\n .map((item) => {\n const r = rec(item);\n const type = str(r.type).toUpperCase();\n const value = str(r.value) || str(r.content) || str(r.target);\n const ttl = Number(r.ttl);\n const note = str(r.note);\n return {\n type,\n name: str(r.name) || str(r.host) || '@',\n value,\n ...(Number.isFinite(ttl) && ttl > 0 ? { ttl } : {}),\n ...(note && note !== 'Subdomain CNAME.' ? { note } : {}),\n };\n })\n .filter((r) => r.type && r.value);\n}\n\n/** WEBBUILDER_CUSTOM_DOMAIN attach / status data -> the panel view. */\nexport function parseDomainDns(input: unknown, fallbackDomain = ''): DomainDnsView {\n const data = actionFields(input);\n const domain = normalizeDomain(str(data.domain) || fallbackDomain);\n const verification = rec(data.verification);\n const validation = rec(data.validation);\n const live = data.live === true || dnsStateOf(data.status) === 'active';\n const state: DnsState = live ? 'active' : dnsStateOf(data.status || verification.status);\n const autoConfigured = data.dnsConfigured === true || isPlatformDomain(domain);\n\n let records: DnsRecordRow[] = [];\n if (!live && !autoConfigured) {\n const recordState = dnsStateOf(verification.status || data.status);\n records = recordRows(data.manualDns).map((r) => ({ ...r, state: recordState }));\n const zone = records.length ? zoneOf(domain, records[0].name) : '';\n const txtName = str(validation.txt_name) || str(validation.txtName);\n const txtValue = str(validation.txt_value) || str(validation.txtValue);\n if (txtName && txtValue && !records.some((r) => r.type === 'TXT' && r.value === txtValue)) {\n records.push({\n type: 'TXT',\n name: hostLabel(txtName, zone),\n value: txtValue,\n state: dnsStateOf(validation.status),\n });\n }\n }\n\n const sug = rec(rec(data.manualDns).suggestion);\n const suggestion =\n !live && str(sug.domain) ? { domain: normalizeDomain(str(sug.domain)), why: str(sug.why) } : undefined;\n const errorMessage =\n state === 'error'\n ? str(verification.error_message) ||\n str(verification.errorMessage) ||\n str(validation.error_message) ||\n str(validation.errorMessage) ||\n str(data.dnsError) ||\n undefined\n : undefined;\n\n return {\n domain,\n state,\n records,\n autoConfigured,\n ...(suggestion ? { suggestion } : {}),\n ...(errorMessage ? { errorMessage } : {}),\n };\n}\n\n/** A status call that failed because the domain isn't on the project: offer to connect it. */\nexport function isNotAttachedError(error: string | null | undefined, data?: unknown): boolean {\n const blob = [error || '', str(actionFields(data).hint)].join('\\n');\n return /not attached|attach it with operation|could not read the domain status|not found/i.test(blob);\n}\n\nexport function attachDomainParams(projectName: string, domain: string): Record<string, unknown> {\n // proxied:false matches the deploy path: a proxied cross-account CNAME is Cloudflare error 1014.\n return { projectName, domain: normalizeDomain(domain), operation: 'attach', configureDns: true, proxied: false };\n}\n\nexport function domainStatusParams(projectName: string, domain: string, retry = false): Record<string, unknown> {\n return { projectName, domain: normalizeDomain(domain), operation: 'status', ...(retry ? { retry: true } : {}) };\n}\n\nexport function removeDomainParams(projectName: string, domain: string): Record<string, unknown> {\n return { projectName, domain: normalizeDomain(domain), operation: 'remove' };\n}\n\nexport function unpublishParams(projectName: string, customDomain?: string | null): Record<string, unknown> {\n return { projectName, ...(customDomain ? { customDomain: normalizeDomain(customDomain) } : {}) };\n}\n\n// ── Review site ──────────────────────────────────────────────────────────\n\nexport type ReviewCategory = 'security' | 'seo' | 'performance' | 'quality';\nexport type ReviewSeverity = 'critical' | 'warning' | 'info';\n\nexport interface PrePublishItem {\n id: string;\n level: 'pass' | 'warn' | 'fail' | 'skip';\n critical?: boolean;\n title: string;\n detail?: string;\n fix?: string;\n category?: ReviewCategory;\n severity?: ReviewSeverity;\n why?: string;\n}\n\nexport interface PrePublishReport {\n ranAt: string;\n blocking: boolean;\n items: PrePublishItem[];\n scores?: { performance?: number; accessibility?: number; seo?: number; bestPractices?: number };\n}\n\nconst LEVELS = new Set(['pass', 'warn', 'fail', 'skip']);\nconst CATEGORIES = new Set(['security', 'seo', 'performance', 'quality']);\nconst SEVERITIES = new Set(['critical', 'warning', 'info']);\n\nconst clip = (v: unknown, max: number) => str(v).slice(0, max);\n\n/** The `aiCodePrePublishReview` JSON (or a publish's `checks`) as a report, or null. */\nexport function parsePrePublishReport(raw: unknown): PrePublishReport | null {\n let value = raw;\n if (typeof value === 'string') {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n const top = rec(value);\n const r0 = Array.isArray(top.items) ? top : rec(top.report);\n if (!Array.isArray(r0.items)) return null;\n const items: PrePublishItem[] = [];\n for (const it of r0.items.slice(0, 60)) {\n const r = rec(it);\n const level = String(r.level || '');\n const title = clip(r.title, 200);\n if (LEVELS.has(level) && title) {\n items.push({\n id: clip(r.id, 64) || title.toLowerCase().replace(/[^a-z0-9]+/g, '-'),\n level: level as PrePublishItem['level'],\n ...(r.critical === true ? { critical: true } : {}),\n title,\n ...(clip(r.detail, 1000) ? { detail: clip(r.detail, 1000) } : {}),\n ...(clip(r.fix, 1000) ? { fix: clip(r.fix, 1000) } : {}),\n ...(CATEGORIES.has(String(r.category)) ? { category: r.category as ReviewCategory } : {}),\n ...(SEVERITIES.has(String(r.severity)) ? { severity: r.severity as ReviewSeverity } : {}),\n ...(clip(r.why, 400) ? { why: clip(r.why, 400) } : {}),\n });\n }\n }\n const scoresRec = rec(r0.scores);\n const scores: NonNullable<PrePublishReport['scores']> = {};\n for (const key of ['performance', 'accessibility', 'seo', 'bestPractices'] as const) {\n const n = Number(scoresRec[key]);\n if (scoresRec[key] != null && Number.isFinite(n)) scores[key] = Math.max(0, Math.min(100, Math.round(n)));\n }\n if (!items.length && !Object.keys(scores).length) return null;\n return {\n ranAt: str(r0.ranAt),\n blocking: r0.blocking === true,\n items,\n ...(Object.keys(scores).length ? { scores } : {}),\n };\n}\n\nconst CATEGORY_BY_ID: Record<string, ReviewCategory> = {\n secrets: 'security',\n 'npm-audit': 'security',\n 'meta-title': 'seo',\n 'meta-description': 'seo',\n 'og-image': 'seo',\n favicon: 'seo',\n 'lighthouse-seo': 'seo',\n 'lighthouse-perf': 'performance',\n 'lighthouse-a11y': 'performance',\n 'broken-images': 'quality',\n};\n\n/** Same reasons the server sends, for reports from servers that do not send them yet. */\nconst WHY_BY_ID: Record<string, string> = {\n secrets:\n \"Anything in your site's code can be read by every visitor. A leaked key lets others spend your money or reach your data.\",\n 'npm-audit':\n 'Known security holes in the packages your site uses can be used to attack your visitors or your site.',\n 'broken-images': 'Broken images make the site look unfinished.',\n};\n\nexport function categoryOf(item: PrePublishItem): ReviewCategory {\n if (item.category) return item.category;\n if (CATEGORY_BY_ID[item.id]) return CATEGORY_BY_ID[item.id];\n return item.id.startsWith('db-') ? 'security' : 'quality';\n}\n\nexport function severityOf(item: PrePublishItem): ReviewSeverity | null {\n if (item.level === 'pass' || item.level === 'skip') return null;\n if (item.severity) return item.severity;\n if (item.level === 'fail' && item.critical) return 'critical';\n return 'warning';\n}\n\n/** The edit-turn text \"Fix with AI\" sends (an edit of this build). */\nexport function fixTurnText(item: PrePublishItem): string {\n const fix = (item.fix || '').trim();\n const detail = (item.detail || '').trim();\n const parts = [`Fix this before I publish: ${item.title}.`];\n if (detail && item.id !== 'secrets') parts.push(`Details: ${detail}`);\n if (fix) parts.push(fix);\n if (item.id === 'secrets') {\n parts.push('Never put secret keys in client code - move them to server-side environment variables.');\n }\n return parts.join('\\n').slice(0, 2000);\n}\n\nexport interface ReviewFinding {\n key: string;\n category: ReviewCategory;\n status: 'problem' | 'ok' | 'skipped';\n severity: ReviewSeverity | null;\n title: string;\n detail?: string;\n why?: string;\n fixText: string | null;\n blocks: boolean;\n}\n\nconst RANK: Record<ReviewFinding['status'], number> = { problem: 0, skipped: 1, ok: 2 };\nconst SEVERITY_RANK: Record<ReviewSeverity, number> = { critical: 0, warning: 1, info: 2 };\n\nexport function reviewFindings(report: PrePublishReport | null): ReviewFinding[] {\n return (report?.items ?? [])\n .map((item, i) => {\n const severity = severityOf(item);\n let status: ReviewFinding['status'] = 'problem';\n if (item.level === 'pass') status = 'ok';\n else if (item.level === 'skip') status = 'skipped';\n const why = item.why || WHY_BY_ID[item.id];\n const finding: ReviewFinding = {\n key: `report:${item.id}`,\n category: categoryOf(item),\n status,\n severity,\n title: item.title,\n ...(item.detail ? { detail: item.detail } : {}),\n ...(why ? { why } : {}),\n fixText: status === 'problem' && item.fix ? fixTurnText(item) : null,\n blocks: severity === 'critical',\n };\n return { finding, i };\n })\n .sort(\n (a, b) =>\n RANK[a.finding.status] - RANK[b.finding.status] ||\n SEVERITY_RANK[a.finding.severity ?? 'info'] - SEVERITY_RANK[b.finding.severity ?? 'info'] ||\n a.i - b.i,\n )\n .map(({ finding }) => finding);\n}\n\nexport type ReviewTab = 'security' | 'seo' | 'speed';\n\n/** A tab's findings: Security holds security and quality, SEO its own, Speed the performance ones. */\nexport function findingsForTab(findings: ReviewFinding[], tab: ReviewTab): ReviewFinding[] {\n if (tab === 'security') return findings.filter((f) => f.category === 'security' || f.category === 'quality');\n if (tab === 'seo') return findings.filter((f) => f.category === 'seo');\n return findings.filter((f) => f.category === 'performance');\n}\n\nexport const SEVERITY_LABEL: Record<ReviewSeverity, string> = {\n critical: 'Critical',\n warning: 'Warning',\n info: 'Tip',\n};\n\nexport const TAB_EMPTY: Record<ReviewTab, { title: string; body: string }> = {\n security: {\n title: 'Checks run when you publish: secret keys, dependencies and database rules',\n body: 'A critical problem stops the publish, and you can fix it with AI.',\n },\n seo: {\n title: 'Checks run when you publish: page title, description, share image and icon',\n body: 'Fix anything missing with AI so the site reads well in search and in shared links.',\n },\n speed: {\n title: 'Speed is measured when you publish (Google PageSpeed, mobile)',\n body: 'Scores for speed, accessibility, SEO and best practices appear here.',\n },\n};\n\nexport interface ScoreBadge {\n key: 'performance' | 'accessibility' | 'seo' | 'bestPractices';\n label: string;\n value: number;\n tone: 'good' | 'ok' | 'poor';\n}\n\nexport function scoreBadges(report: PrePublishReport | null): ScoreBadge[] {\n const labels: Array<[ScoreBadge['key'], string]> = [\n ['performance', 'Speed'],\n ['accessibility', 'Accessibility'],\n ['seo', 'SEO'],\n ['bestPractices', 'Best practices'],\n ];\n const out: ScoreBadge[] = [];\n for (const [key, label] of labels) {\n const v = report?.scores?.[key];\n if (typeof v === 'number') {\n let tone: ScoreBadge['tone'] = 'poor';\n if (v >= 90) tone = 'good';\n else if (v >= 50) tone = 'ok';\n out.push({ key, label, value: v, tone });\n }\n }\n return out;\n}\n"],"names":["_a"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ const PREVIEW_SLEEPS_AFTER_MS = 60 * 6e4;
2
+ const SLEEP_NOTICE_IDLE_MS = 40 * 6e4;
3
+ function sleepNoticeDue(opts) {
4
+ if (opts.busy) return false;
5
+ const at = Number(opts.lastChangeAt);
6
+ if (!Number.isFinite(at) || at <= 0) return false;
7
+ return opts.now - at >= SLEEP_NOTICE_IDLE_MS;
8
+ }
9
+ function minutesUntilSleep(lastChangeAt, now) {
10
+ const at = Number(lastChangeAt);
11
+ if (!Number.isFinite(at) || at <= 0) return Math.round(PREVIEW_SLEEPS_AFTER_MS / 6e4);
12
+ return Math.max(0, Math.ceil((at + PREVIEW_SLEEPS_AFTER_MS - now) / 6e4));
13
+ }export{PREVIEW_SLEEPS_AFTER_MS,SLEEP_NOTICE_IDLE_MS,minutesUntilSleep,sleepNoticeDue};//# sourceMappingURL=sleepNotice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleepNotice.js","sources":["../../../src/features/webbuilder/sleepNotice.ts"],"sourcesContent":["/** When to say an unpublished agent build's preview is about to sleep - the web `preview/sleepNotice.ts`. Pure. */\n\n/** An agent build's sandbox sleeps this long after its last change. */\nexport const PREVIEW_SLEEPS_AFTER_MS = 60 * 60_000;\n/** The notice shows once the build has been idle this long (20 minutes or less left). */\nexport const SLEEP_NOTICE_IDLE_MS = 40 * 60_000;\n\n/** True once the preview has 20 minutes or less left, never while the AI works on it or before it has a change time. */\nexport function sleepNoticeDue(opts: { lastChangeAt: number | null | undefined; now: number; busy: boolean }): boolean {\n if (opts.busy) return false;\n const at = Number(opts.lastChangeAt);\n if (!Number.isFinite(at) || at <= 0) return false;\n return opts.now - at >= SLEEP_NOTICE_IDLE_MS;\n}\n\n/** Minutes until it sleeps (0 when it should be asleep already). */\nexport function minutesUntilSleep(lastChangeAt: number | null | undefined, now: number): number {\n const at = Number(lastChangeAt);\n if (!Number.isFinite(at) || at <= 0) return Math.round(PREVIEW_SLEEPS_AFTER_MS / 60_000);\n return Math.max(0, Math.ceil((at + PREVIEW_SLEEPS_AFTER_MS - now) / 60_000));\n}\n"],"names":[],"mappings":"AAGO,MAAM,0BAA0B,EAAK,GAAA;AAErC,MAAM,uBAAuB,EAAK,GAAA;AAGlC,SAAS,eAAe,IAInB,EAAA;AACV,EAAI,IAAA,IAAA,CAAK,MAAa,OAAA,KAAA;AACtB,EAAM,MAAA,EAAA,GAAK,MAAO,CAAA,IAAA,CAAK,YAAY,CAAA;AACnC,EAAA,IAAI,CAAC,MAAO,CAAA,QAAA,CAAS,EAAE,CAAK,IAAA,EAAA,IAAM,GAAU,OAAA,KAAA;AAC5C,EAAO,OAAA,IAAA,CAAK,MAAM,EAAM,IAAA,oBAAA;AAC1B;AAGgB,SAAA,iBAAA,CAAkB,cAAyC,GAAqB,EAAA;AAC9F,EAAM,MAAA,EAAA,GAAK,OAAO,YAAY,CAAA;AAC9B,EAAI,IAAA,CAAC,MAAO,CAAA,QAAA,CAAS,EAAE,CAAA,IAAK,EAAM,IAAA,CAAA,EAAU,OAAA,IAAA,CAAK,KAAM,CAAA,uBAAA,GAA0B,GAAM,CAAA;AACvF,EAAO,OAAA,IAAA,CAAK,IAAI,CAAG,EAAA,IAAA,CAAK,MAAM,EAAK,GAAA,uBAAA,GAA0B,GAAO,IAAA,GAAM,CAAC,CAAA;AAC7E"}