@pajh/buldng 0.0.3 → 0.0.4
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/package.json +14 -10
- package/src/buldng-dev-errors.js +84 -0
- package/{dist → src}/buldng-lib.js +59 -2
- package/{dist → src}/buldng-ops.js +8 -8
- package/src/buldng-web.ts +267 -0
- /package/{dist → src}/buldng-validate.js +0 -0
- /package/{dist → src}/buldng.css +0 -0
- /package/{dist → src}/clean.sh +0 -0
- /package/{dist → src}/init.js +0 -0
- /package/{dist → src}/layout.ts +0 -0
- /package/{dist → src}/types/global.d.ts +0 -0
- /package/{dist → src}/workfile.js +0 -0
- /package/{dist → src}/wrapper.html +0 -0
package/package.json
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pajh/buldng",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "
|
|
6
|
-
"files": [
|
|
5
|
+
"main": "./src/buldng-lib.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"src"
|
|
8
|
+
],
|
|
7
9
|
"scripts": {
|
|
8
|
-
"
|
|
10
|
+
"check": "tsc --noEmit",
|
|
11
|
+
"build": "npm run check"
|
|
9
12
|
},
|
|
10
13
|
"dependencies": {
|
|
11
|
-
|
|
12
|
-
"typescript": "^7.0.2"
|
|
14
|
+
"esbuild": "^0.28.2"
|
|
13
15
|
},
|
|
14
16
|
"devDependencies": {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
"typescript": "^6.0.3"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": "./src/buldng-lib.js",
|
|
21
|
+
"./web": "./src/buldng-web.ts"
|
|
22
|
+
}
|
|
19
23
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Development-only error overlay installed by the local preview server.
|
|
2
|
+
// The production build never references this file from its HTML.
|
|
3
|
+
|
|
4
|
+
window.__buldngErrorOverlay = true;
|
|
5
|
+
|
|
6
|
+
let shown = false;
|
|
7
|
+
|
|
8
|
+
window.addEventListener("error", (event) => {
|
|
9
|
+
showError(event.error ?? event.message, "error");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
13
|
+
showError(event.reason, "unhandledrejection");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
function showError(reason, type) {
|
|
17
|
+
if (shown) return;
|
|
18
|
+
shown = true;
|
|
19
|
+
|
|
20
|
+
const message = getMessage(reason);
|
|
21
|
+
const stack = getStack(reason);
|
|
22
|
+
const overlay = document.createElement("aside");
|
|
23
|
+
overlay.id = "buldng-dev-error-overlay";
|
|
24
|
+
overlay.style.cssText = [
|
|
25
|
+
"position: fixed",
|
|
26
|
+
"z-index: 2147483647",
|
|
27
|
+
"left: 1rem",
|
|
28
|
+
"right: 1rem",
|
|
29
|
+
"bottom: 1rem",
|
|
30
|
+
"max-height: 70vh",
|
|
31
|
+
"overflow: auto",
|
|
32
|
+
"padding: 1rem 1.25rem",
|
|
33
|
+
"border: 2px solid #d33",
|
|
34
|
+
"border-radius: 8px",
|
|
35
|
+
"background: #240b0b",
|
|
36
|
+
"color: #fff",
|
|
37
|
+
"font: 16px/1.4 monospace",
|
|
38
|
+
"box-shadow: 0 4px 24px #0008",
|
|
39
|
+
].join(";");
|
|
40
|
+
|
|
41
|
+
const close = document.createElement("button");
|
|
42
|
+
close.type = "button";
|
|
43
|
+
close.textContent = "Close";
|
|
44
|
+
close.style.cssText = "float:right; padding:.35rem .6rem; cursor:pointer";
|
|
45
|
+
close.addEventListener("click", () => overlay.remove());
|
|
46
|
+
|
|
47
|
+
const title = document.createElement("strong");
|
|
48
|
+
title.textContent = "BULDR preview: something broke";
|
|
49
|
+
|
|
50
|
+
const hint = document.createElement("p");
|
|
51
|
+
hint.textContent = `(${type}) Check the DevTools console for the full mapped stack.`;
|
|
52
|
+
|
|
53
|
+
const text = document.createElement("p");
|
|
54
|
+
text.textContent = message;
|
|
55
|
+
|
|
56
|
+
overlay.append(close, title, hint, text);
|
|
57
|
+
if (stack) {
|
|
58
|
+
const details = document.createElement("details");
|
|
59
|
+
const summary = document.createElement("summary");
|
|
60
|
+
summary.textContent = "Raw stack";
|
|
61
|
+
const pre = document.createElement("pre");
|
|
62
|
+
pre.textContent = stack;
|
|
63
|
+
pre.style.cssText = "white-space:pre-wrap; overflow-wrap:anywhere";
|
|
64
|
+
details.append(summary, pre);
|
|
65
|
+
overlay.appendChild(details);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
document.body?.appendChild(overlay);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getMessage(reason) {
|
|
72
|
+
if (reason instanceof Error && reason.message) return reason.message;
|
|
73
|
+
if (typeof reason === "string" && reason) return reason;
|
|
74
|
+
try {
|
|
75
|
+
const text = JSON.stringify(reason);
|
|
76
|
+
return text || "Unknown error";
|
|
77
|
+
} catch {
|
|
78
|
+
return String(reason) || "Unknown error";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getStack(reason) {
|
|
83
|
+
return reason && typeof reason.stack === "string" ? reason.stack : "";
|
|
84
|
+
}
|
|
@@ -7,7 +7,7 @@ import esbuild from "esbuild";
|
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { dirname, join } from "node:path";
|
|
9
9
|
import { readFileSync } from "node:fs";
|
|
10
|
-
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
11
|
import { WorkFile } from "./workfile.js";
|
|
12
12
|
import { getDest, setSource, setDest, assertDestWrite, assertSourceRead, getInputs, looksLikeFilename, looksLikeHTML,
|
|
13
13
|
looksLikeCSS, looksLikeJS, ensureLeadingSlash, ensureWorkFile } from "./buldng-validate.js";
|
|
@@ -35,7 +35,8 @@ export default {
|
|
|
35
35
|
pageHTML,
|
|
36
36
|
buldngHTMLWrapper,
|
|
37
37
|
reg,
|
|
38
|
-
printHeader
|
|
38
|
+
printHeader,
|
|
39
|
+
typescriptCheck
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
@@ -57,6 +58,59 @@ export function reg(key, value) {
|
|
|
57
58
|
return wf;
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
function findTSC() {
|
|
62
|
+
const localTSC = path.resolve("node_modules/.bin/tsc");
|
|
63
|
+
|
|
64
|
+
if (fs.existsSync(localTSC)) {
|
|
65
|
+
return localTSC; // Local compiler — correct
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const globalTSC = execSync("which tsc").toString().trim();
|
|
70
|
+
return globalTSC; // Global compiler — acceptable
|
|
71
|
+
} catch {
|
|
72
|
+
return null; // No compiler found
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function typescriptCheck() {
|
|
77
|
+
let hasTS = false;
|
|
78
|
+
const require = createRequire(import.meta.url);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
// Detect ANY installed TypeScript (local or global)
|
|
82
|
+
require.resolve("typescript");
|
|
83
|
+
|
|
84
|
+
hasTS = true;
|
|
85
|
+
} catch {
|
|
86
|
+
hasTS = false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!hasTS) {
|
|
90
|
+
console.log("TypeScript not found — skipping TS checks");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const { execSync } = require("node:child_process");
|
|
95
|
+
const tscPath = findTSC();
|
|
96
|
+
|
|
97
|
+
if (!tscPath) {
|
|
98
|
+
console.error("TypeScript compiler not found (local or global)");
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
console.log("Using TypeScript compiler:", tscPath);
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
// npx will run local tsc if present, otherwise global tsc
|
|
107
|
+
execSync(`${tscPath} --noEmit`, { stdio: "inherit" });
|
|
108
|
+
} catch (err) {
|
|
109
|
+
throw new Error("TypeScript check failed");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
60
114
|
let headerPrinted = false;
|
|
61
115
|
export function printHeader(importMeta) {
|
|
62
116
|
if (headerPrinted) return;
|
|
@@ -221,6 +275,9 @@ export function deepCopy(from, to) {
|
|
|
221
275
|
// 2.5 Save camera.css to the site root (this triggers execution)
|
|
222
276
|
const buldngCSS = new WorkFile("file", { absPath: packageFileAbs("buldng.css") }, []);
|
|
223
277
|
buldngCSS.save("buldng.css");
|
|
278
|
+
|
|
279
|
+
const devErrors = new WorkFile("file", { absPath: packageFileAbs("buldng-dev-errors.js") }, []);
|
|
280
|
+
devErrors.save("buldng-dev-errors.js");
|
|
224
281
|
|
|
225
282
|
// 3. Wrap project shell in buldng's wrapper.html
|
|
226
283
|
const wrapperWF = new WorkFile("file", { absPath: packageFileAbs("wrapper.html") }, []);
|
|
@@ -93,6 +93,12 @@ export function op_compile(config, children) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
const child = children[0];
|
|
96
|
+
const compileOptions = {
|
|
97
|
+
minify: config.flags?.minify ?? true,
|
|
98
|
+
sourcemap: config.flags?.sourcemap ?? true,
|
|
99
|
+
format: config.flags?.format ?? "esm",
|
|
100
|
+
target: config.flags?.target ?? "esnext",
|
|
101
|
+
};
|
|
96
102
|
|
|
97
103
|
// If child is a file WorkFile, use its absolute path directly
|
|
98
104
|
if (child.op === "file" && child.config.absPath) {
|
|
@@ -101,10 +107,7 @@ export function op_compile(config, children) {
|
|
|
101
107
|
const result = esbuild.buildSync({
|
|
102
108
|
entryPoints: [entry],
|
|
103
109
|
bundle: true,
|
|
104
|
-
|
|
105
|
-
sourcemap: true,
|
|
106
|
-
format: "esm",
|
|
107
|
-
target: "esnext",
|
|
110
|
+
...compileOptions,
|
|
108
111
|
write: false
|
|
109
112
|
});
|
|
110
113
|
|
|
@@ -125,10 +128,7 @@ export function op_compile(config, children) {
|
|
|
125
128
|
sourcefile: "input.ts"
|
|
126
129
|
},
|
|
127
130
|
bundle: true,
|
|
128
|
-
|
|
129
|
-
sourcemap: true,
|
|
130
|
-
format: "esm",
|
|
131
|
-
target: "esnext",
|
|
131
|
+
...compileOptions,
|
|
132
132
|
write: false
|
|
133
133
|
});
|
|
134
134
|
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// buldng-web.ts
|
|
2
|
+
// Pure runtime API for buldng. The optional renderer only writes text into a caller-owned element.
|
|
3
|
+
|
|
4
|
+
let errorPage: string | null = null;
|
|
5
|
+
let listenersInstalled = false;
|
|
6
|
+
let redirectStarted = false;
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface Window {
|
|
10
|
+
__buldngErrorOverlay?: boolean;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ERROR_STORAGE_PREFIX = "buldng:error:";
|
|
15
|
+
|
|
16
|
+
export type ErrorPayload = {
|
|
17
|
+
id: string;
|
|
18
|
+
type: "error" | "unhandledrejection";
|
|
19
|
+
message: string;
|
|
20
|
+
stack: string;
|
|
21
|
+
time: string;
|
|
22
|
+
url: string;
|
|
23
|
+
userAgent: string;
|
|
24
|
+
platform: string;
|
|
25
|
+
language: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Configure the global error handler.
|
|
30
|
+
* @param url A full URL path like "/error/" or "/fatal/".
|
|
31
|
+
*/
|
|
32
|
+
export function setErrorPage(url: string) {
|
|
33
|
+
if (typeof url !== "string" || !url.length) {
|
|
34
|
+
throw new Error("setErrorPage: URL must be a non-empty string");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Normalize: ensure no accidental double slashes
|
|
38
|
+
errorPage = url.endsWith("/") ? url.slice(0, -1) : url;
|
|
39
|
+
|
|
40
|
+
// Install global listeners once. Calling setErrorPage again only changes the destination.
|
|
41
|
+
installGlobalErrorHandler();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Internal: installs global error + unhandled rejection handlers.
|
|
46
|
+
*/
|
|
47
|
+
function installGlobalErrorHandler() {
|
|
48
|
+
if (!errorPage || listenersInstalled || isErrorPage() || window.__buldngErrorOverlay) return;
|
|
49
|
+
|
|
50
|
+
listenersInstalled = true;
|
|
51
|
+
|
|
52
|
+
window.addEventListener("error", (event) => {
|
|
53
|
+
handleError({
|
|
54
|
+
type: "error",
|
|
55
|
+
reason: event.error ?? event.message,
|
|
56
|
+
fallbackMessage: event.message,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
61
|
+
handleError({
|
|
62
|
+
type: "unhandledrejection",
|
|
63
|
+
reason: event.reason,
|
|
64
|
+
fallbackMessage: "Unhandled promise rejection",
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Read an error payload previously saved by the global handler.
|
|
71
|
+
* Defaults to the errorId query parameter on the current page.
|
|
72
|
+
*/
|
|
73
|
+
export function readErrorPayload(id = getErrorId()): ErrorPayload | null {
|
|
74
|
+
if (!id) return null;
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const raw = localStorage.getItem(storageKey(id));
|
|
78
|
+
if (!raw) return null;
|
|
79
|
+
|
|
80
|
+
const payload: unknown = JSON.parse(raw);
|
|
81
|
+
return isErrorPayload(payload) ? payload : null;
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Read and remove an error payload. Useful for one-shot error pages.
|
|
89
|
+
*/
|
|
90
|
+
export function consumeErrorPayload(id = getErrorId()): ErrorPayload | null {
|
|
91
|
+
const payload = readErrorPayload(id);
|
|
92
|
+
if (id) {
|
|
93
|
+
try {
|
|
94
|
+
localStorage.removeItem(storageKey(id));
|
|
95
|
+
} catch {
|
|
96
|
+
// Storage may be unavailable or blocked; the payload was still safely read if possible.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return payload;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Render a payload as safe text inside a caller-owned element.
|
|
104
|
+
* Returns the payload that was rendered, or null when it was unavailable.
|
|
105
|
+
*/
|
|
106
|
+
export function renderErrorPayload(
|
|
107
|
+
elementId: string,
|
|
108
|
+
payload = readErrorPayload()
|
|
109
|
+
): ErrorPayload | null {
|
|
110
|
+
const container = document.getElementById(elementId);
|
|
111
|
+
if (!container) return null;
|
|
112
|
+
|
|
113
|
+
container.replaceChildren();
|
|
114
|
+
if (!payload) {
|
|
115
|
+
const empty = document.createElement("p");
|
|
116
|
+
empty.textContent = "Error details are no longer available.";
|
|
117
|
+
container.appendChild(empty);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const details: Array<[string, string]> = [
|
|
122
|
+
["Type", payload.type],
|
|
123
|
+
["Message", payload.message],
|
|
124
|
+
["Time", payload.time],
|
|
125
|
+
["Page", payload.url],
|
|
126
|
+
["User agent", payload.userAgent],
|
|
127
|
+
["Platform", payload.platform],
|
|
128
|
+
["Language", payload.language],
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
const list = document.createElement("dl");
|
|
132
|
+
for (const [label, value] of details) {
|
|
133
|
+
const term = document.createElement("dt");
|
|
134
|
+
term.textContent = label;
|
|
135
|
+
const description = document.createElement("dd");
|
|
136
|
+
description.textContent = value;
|
|
137
|
+
list.append(term, description);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (payload.stack) {
|
|
141
|
+
const stackLabel = document.createElement("h3");
|
|
142
|
+
stackLabel.textContent = "Stack";
|
|
143
|
+
const stack = document.createElement("pre");
|
|
144
|
+
stack.textContent = payload.stack;
|
|
145
|
+
list.append(stackLabel, stack);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
container.appendChild(list);
|
|
149
|
+
return payload;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Return the error record ID from the current URL.
|
|
154
|
+
*/
|
|
155
|
+
export function getErrorId(): string | null {
|
|
156
|
+
return new URLSearchParams(location.search).get("errorId");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function handleError(info: {
|
|
160
|
+
type: ErrorPayload["type"];
|
|
161
|
+
reason: unknown;
|
|
162
|
+
fallbackMessage: string;
|
|
163
|
+
}) {
|
|
164
|
+
if (redirectStarted || !errorPage) return;
|
|
165
|
+
redirectStarted = true;
|
|
166
|
+
|
|
167
|
+
const payload = buildPayload(info);
|
|
168
|
+
const stored = saveErrorPayload(payload);
|
|
169
|
+
redirect(payload, stored);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function buildPayload(info: {
|
|
173
|
+
type: ErrorPayload["type"];
|
|
174
|
+
reason: unknown;
|
|
175
|
+
fallbackMessage: string;
|
|
176
|
+
}): ErrorPayload {
|
|
177
|
+
const id = createId();
|
|
178
|
+
const error = info.reason instanceof Error ? info.reason : null;
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
id,
|
|
182
|
+
type: info.type,
|
|
183
|
+
message: getErrorMessage(info.reason, info.fallbackMessage),
|
|
184
|
+
stack: error?.stack ?? getErrorStack(info.reason),
|
|
185
|
+
time: new Date().toISOString(),
|
|
186
|
+
url: location.href,
|
|
187
|
+
userAgent: navigator.userAgent,
|
|
188
|
+
platform: navigator.platform,
|
|
189
|
+
language: navigator.language,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Redirect to the configured error page with a storage key, plus a small fallback.
|
|
195
|
+
*/
|
|
196
|
+
function redirect(payload: ErrorPayload, stored: boolean) {
|
|
197
|
+
if (!errorPage) return;
|
|
198
|
+
|
|
199
|
+
const destination = new URL(errorPage, location.href);
|
|
200
|
+
if (stored) {
|
|
201
|
+
destination.searchParams.set("errorId", payload.id);
|
|
202
|
+
} else {
|
|
203
|
+
destination.searchParams.set("type", payload.type);
|
|
204
|
+
destination.searchParams.set("message", payload.message.slice(0, 500));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
window.location.href = destination.href;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function saveErrorPayload(payload: ErrorPayload): boolean {
|
|
211
|
+
try {
|
|
212
|
+
localStorage.setItem(storageKey(payload.id), JSON.stringify(payload));
|
|
213
|
+
return true;
|
|
214
|
+
} catch {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function storageKey(id: string) {
|
|
220
|
+
return `${ERROR_STORAGE_PREFIX}${id}`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function createId() {
|
|
224
|
+
if (typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
225
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function isErrorPage() {
|
|
229
|
+
const destination = new URL(errorPage!, location.href);
|
|
230
|
+
const destinationPath = destination.pathname.replace(/\/$/, "") || "/";
|
|
231
|
+
const currentPath = location.pathname.replace(/\/$/, "") || "/";
|
|
232
|
+
return destination.origin === location.origin && destinationPath === currentPath;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function getErrorMessage(reason: unknown, fallback: string) {
|
|
236
|
+
if (reason instanceof Error && reason.message) return reason.message;
|
|
237
|
+
if (typeof reason === "string" && reason) return reason;
|
|
238
|
+
if (reason !== null && reason !== undefined) {
|
|
239
|
+
try {
|
|
240
|
+
const text = JSON.stringify(reason);
|
|
241
|
+
if (text) return text;
|
|
242
|
+
} catch {
|
|
243
|
+
// Fall through to the stable message below.
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return fallback;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function getErrorStack(reason: unknown) {
|
|
250
|
+
if (!reason || typeof reason !== "object") return "";
|
|
251
|
+
const stack = (reason as { stack?: unknown }).stack;
|
|
252
|
+
return typeof stack === "string" ? stack : "";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function isErrorPayload(value: unknown): value is ErrorPayload {
|
|
256
|
+
if (!value || typeof value !== "object") return false;
|
|
257
|
+
const payload = value as Partial<ErrorPayload>;
|
|
258
|
+
return typeof payload.id === "string"
|
|
259
|
+
&& (payload.type === "error" || payload.type === "unhandledrejection")
|
|
260
|
+
&& typeof payload.message === "string"
|
|
261
|
+
&& typeof payload.stack === "string"
|
|
262
|
+
&& typeof payload.time === "string"
|
|
263
|
+
&& typeof payload.url === "string"
|
|
264
|
+
&& typeof payload.userAgent === "string"
|
|
265
|
+
&& typeof payload.platform === "string"
|
|
266
|
+
&& typeof payload.language === "string";
|
|
267
|
+
}
|
|
File without changes
|
/package/{dist → src}/buldng.css
RENAMED
|
File without changes
|
/package/{dist → src}/clean.sh
RENAMED
|
File without changes
|
/package/{dist → src}/init.js
RENAMED
|
File without changes
|
/package/{dist → src}/layout.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|