@aethervtt/shard-platform-web 0.0.1 → 0.2.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/audio-cache.d.ts +44 -0
- package/dist/audio-cache.js +215 -0
- package/dist/audio-compat.d.ts +4 -0
- package/dist/audio-compat.js +34 -0
- package/dist/audio-graph.d.ts +35 -0
- package/dist/audio-graph.js +365 -0
- package/dist/audio-preview.d.ts +59 -0
- package/dist/audio-preview.js +142 -0
- package/dist/audio.d.ts +8 -12
- package/dist/audio.js +835 -245
- package/dist/index.d.ts +3 -1
- package/dist/index.js +26 -1
- package/dist/input.d.ts +17 -4
- package/dist/input.js +103 -11
- package/dist/performance.d.ts +7 -0
- package/dist/performance.js +116 -0
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface WebPlatformOptions {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function createWebPlatform(options?: WebPlatformOptions): Platform;
|
|
11
11
|
export { createWebAudioBackend, type WebAudioBackend } from './audio.js';
|
|
12
|
-
export {
|
|
12
|
+
export { type AudioRenderPlan, audioBufferWav, measureAudioBuffer, renderAudioPreview, } from './audio-preview.js';
|
|
13
|
+
export { createDomInputSource, type DomInputOptions } from './input.js';
|
|
14
|
+
export { createWebPerformance } from './performance.js';
|
|
13
15
|
export { createIndexedDbStorage } from './storage.js';
|
|
14
16
|
export { createWebWorkers } from './workers.js';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ShardError } from "@aethervtt/shard-core";
|
|
2
2
|
import { createWebAudioBackend } from "./audio.js";
|
|
3
|
+
import { createWebPerformance } from "./performance.js";
|
|
3
4
|
import { createIndexedDbStorage } from "./storage.js";
|
|
4
5
|
import { createWebWorkers } from "./workers.js";
|
|
5
6
|
function createWebPlatform(options = {}) {
|
|
@@ -20,9 +21,22 @@ function createWebPlatform(options = {}) {
|
|
|
20
21
|
return res;
|
|
21
22
|
};
|
|
22
23
|
const fs = {
|
|
24
|
+
resolveUrl: (path) => new URL(path, baseUrl).href,
|
|
23
25
|
writable: false,
|
|
24
26
|
readText: async (path) => (await fetchOk(path)).text(),
|
|
25
27
|
readBytes: async (path) => new Uint8Array(await (await fetchOk(path)).arrayBuffer()),
|
|
28
|
+
readRange: async (path, offset, length) => {
|
|
29
|
+
const res = await fetch(new URL(path, baseUrl), {
|
|
30
|
+
headers: { Range: `bytes=${offset}-${offset + length - 1}` }
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
throw new ShardError("platform/fs-not-found", `Failed to fetch "${path}" (${res.status})`, {
|
|
34
|
+
path
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
38
|
+
return res.status === 206 ? bytes : bytes.subarray(offset, offset + length);
|
|
39
|
+
},
|
|
26
40
|
writeText: async (path) => readOnly(path),
|
|
27
41
|
writeBytes: async (path) => readOnly(path),
|
|
28
42
|
exists: async (path) => (await fetch(new URL(path, baseUrl), { method: "HEAD" })).ok
|
|
@@ -42,6 +56,7 @@ function createWebPlatform(options = {}) {
|
|
|
42
56
|
},
|
|
43
57
|
fs,
|
|
44
58
|
storage: createIndexedDbStorage(options.storageName),
|
|
59
|
+
performance: createWebPerformance(),
|
|
45
60
|
clock: { now: () => performance.now() },
|
|
46
61
|
log: {
|
|
47
62
|
log: (level, message, data) => console[level](`[shard] ${message}`, data ?? "")
|
|
@@ -49,13 +64,23 @@ function createWebPlatform(options = {}) {
|
|
|
49
64
|
};
|
|
50
65
|
}
|
|
51
66
|
import { createWebAudioBackend as createWebAudioBackend2 } from "./audio.js";
|
|
67
|
+
import {
|
|
68
|
+
audioBufferWav,
|
|
69
|
+
measureAudioBuffer,
|
|
70
|
+
renderAudioPreview
|
|
71
|
+
} from "./audio-preview.js";
|
|
52
72
|
import { createDomInputSource } from "./input.js";
|
|
73
|
+
import { createWebPerformance as createWebPerformance2 } from "./performance.js";
|
|
53
74
|
import { createIndexedDbStorage as createIndexedDbStorage2 } from "./storage.js";
|
|
54
75
|
import { createWebWorkers as createWebWorkers2 } from "./workers.js";
|
|
55
76
|
export {
|
|
77
|
+
audioBufferWav,
|
|
56
78
|
createDomInputSource,
|
|
57
79
|
createIndexedDbStorage2 as createIndexedDbStorage,
|
|
58
80
|
createWebAudioBackend2 as createWebAudioBackend,
|
|
81
|
+
createWebPerformance2 as createWebPerformance,
|
|
59
82
|
createWebPlatform,
|
|
60
|
-
createWebWorkers2 as createWebWorkers
|
|
83
|
+
createWebWorkers2 as createWebWorkers,
|
|
84
|
+
measureAudioBuffer,
|
|
85
|
+
renderAudioPreview
|
|
61
86
|
};
|
package/dist/input.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type InputSource } from '@aethervtt/shard-platform';
|
|
2
|
+
export interface DomInputOptions {
|
|
3
|
+
/**
|
|
4
|
+
* The element's context menu. 'block' (default): never shown, for a game that owns its page.
|
|
5
|
+
* 'pass': shown unless a control drags with the right button, for a host with menus of its own
|
|
6
|
+
* (0060).
|
|
7
|
+
*/
|
|
8
|
+
contextMenu?: 'block' | 'pass';
|
|
9
|
+
}
|
|
2
10
|
/**
|
|
3
|
-
* DOM input: pointer and wheel events on `element` (positions in its backing pixels
|
|
4
|
-
* focus on the window, gamepads polled on drain. Works in
|
|
11
|
+
* DOM input: pointer and wheel events on `element` (positions in its backing pixels, and in CSS
|
|
12
|
+
* pixels for `pointer` events), keys and focus on the window, gamepads polled on drain. Works in
|
|
13
|
+
* browsers and Tauri webviews alike.
|
|
14
|
+
*
|
|
15
|
+
* Events pass through to the page unless the scene takes them (0060): a press with a button an
|
|
16
|
+
* enabled control drags with, a claimed pointer's later events, and the wheel while a control
|
|
17
|
+
* zooms with it are `preventDefault`ed; so is the context menu, unless `contextMenu` is 'pass'.
|
|
5
18
|
*/
|
|
6
|
-
export declare function createDomInputSource(element: HTMLElement): InputSource;
|
|
19
|
+
export declare function createDomInputSource(element: HTMLElement, options?: DomInputOptions): InputSource;
|
package/dist/input.js
CHANGED
|
@@ -1,14 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MODIFIERS
|
|
3
|
+
} from "@aethervtt/shard-platform";
|
|
1
4
|
const BUTTONS = ["left", "middle", "right", "back", "forward"];
|
|
2
|
-
function
|
|
3
|
-
|
|
5
|
+
function modifiersOf(e) {
|
|
6
|
+
return (e.shiftKey ? MODIFIERS.shift : 0) | (e.ctrlKey ? MODIFIERS.ctrl : 0) | (e.altKey ? MODIFIERS.alt : 0) | (e.metaKey ? MODIFIERS.meta : 0);
|
|
7
|
+
}
|
|
8
|
+
function kindOf(e) {
|
|
9
|
+
return e.pointerType === "touch" ? "touch" : e.pointerType === "pen" ? "pen" : "mouse";
|
|
10
|
+
}
|
|
11
|
+
function createDomInputSource(element, options = {}) {
|
|
12
|
+
const blockMenu = (options.contextMenu ?? "block") === "block";
|
|
13
|
+
const events = [];
|
|
14
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
15
|
+
const queue = {
|
|
16
|
+
push(e) {
|
|
17
|
+
events.push(e);
|
|
18
|
+
for (const listener of listeners) listener();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
4
21
|
const target = globalThis.window;
|
|
5
22
|
const toPixels = (e) => {
|
|
6
23
|
const rect = element.getBoundingClientRect();
|
|
7
24
|
const sx = element instanceof HTMLCanvasElement ? element.width / Math.max(1, rect.width) : 1;
|
|
8
25
|
const sy = element instanceof HTMLCanvasElement ? element.height / Math.max(1, rect.height) : 1;
|
|
9
|
-
|
|
26
|
+
const cx = e.clientX - rect.left;
|
|
27
|
+
const cy = e.clientY - rect.top;
|
|
28
|
+
return { x: cx * sx, y: cy * sy, cx, cy, sx, sy };
|
|
10
29
|
};
|
|
11
30
|
const knownPads = /* @__PURE__ */ new Set();
|
|
31
|
+
let policy = { buttons: [], wheel: false, touch: false };
|
|
32
|
+
const down = /* @__PURE__ */ new Map();
|
|
33
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
34
|
+
const touchAction = element.style.touchAction;
|
|
35
|
+
const capture = (id) => {
|
|
36
|
+
try {
|
|
37
|
+
element.setPointerCapture?.(id);
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const pointer = (e, phase, cx, cy) => {
|
|
42
|
+
const button = phase === "move" ? down.get(e.pointerId) ?? "left" : BUTTONS[e.button] ?? "left";
|
|
43
|
+
queue.push({
|
|
44
|
+
type: "pointer",
|
|
45
|
+
id: e.pointerId,
|
|
46
|
+
phase,
|
|
47
|
+
pointer: kindOf(e),
|
|
48
|
+
button,
|
|
49
|
+
x: cx,
|
|
50
|
+
y: cy,
|
|
51
|
+
modifiers: modifiersOf(e)
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
const takes = (e) => e.pointerType === "touch" ? policy.touch : policy.buttons.includes(BUTTONS[e.button] ?? "left");
|
|
12
55
|
const onKeyDown = (e) => {
|
|
13
56
|
if (!e.ctrlKey && !e.metaKey) {
|
|
14
57
|
if (e.key.length === 1) queue.push({ type: "text", text: e.key });
|
|
@@ -21,43 +64,76 @@ function createDomInputSource(element) {
|
|
|
21
64
|
queue.push({ type: "key", code: e.code, pressed: false });
|
|
22
65
|
};
|
|
23
66
|
const onPointerDown = (e) => {
|
|
24
|
-
const { x, y } = toPixels(e);
|
|
67
|
+
const { x, y, cx, cy } = toPixels(e);
|
|
68
|
+
down.set(e.pointerId, BUTTONS[e.button] ?? "left");
|
|
69
|
+
if (takes(e)) {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
capture(e.pointerId);
|
|
72
|
+
}
|
|
25
73
|
if (e.pointerType === "touch")
|
|
26
74
|
queue.push({ type: "touch", id: e.pointerId, phase: "start", x, y });
|
|
27
75
|
else queue.push({ type: "mouse-button", button: BUTTONS[e.button] ?? "left", pressed: true });
|
|
76
|
+
pointer(e, "down", cx, cy);
|
|
28
77
|
};
|
|
29
78
|
const onPointerUp = (e) => {
|
|
30
|
-
const { x, y } = toPixels(e);
|
|
79
|
+
const { x, y, cx, cy } = toPixels(e);
|
|
80
|
+
if (claimed.has(e.pointerId)) e.preventDefault();
|
|
31
81
|
if (e.pointerType === "touch")
|
|
32
82
|
queue.push({ type: "touch", id: e.pointerId, phase: "end", x, y });
|
|
33
83
|
else queue.push({ type: "mouse-button", button: BUTTONS[e.button] ?? "left", pressed: false });
|
|
84
|
+
if (down.has(e.pointerId)) pointer(e, "up", cx, cy);
|
|
85
|
+
down.delete(e.pointerId);
|
|
86
|
+
claimed.delete(e.pointerId);
|
|
87
|
+
};
|
|
88
|
+
const onPointerCancel = (e) => {
|
|
89
|
+
if (!down.has(e.pointerId)) return;
|
|
90
|
+
const { x, y, cx, cy } = toPixels(e);
|
|
91
|
+
if (e.pointerType === "touch")
|
|
92
|
+
queue.push({ type: "touch", id: e.pointerId, phase: "end", x, y });
|
|
93
|
+
pointer(e, "cancel", cx, cy);
|
|
94
|
+
down.delete(e.pointerId);
|
|
95
|
+
claimed.delete(e.pointerId);
|
|
34
96
|
};
|
|
35
97
|
const onPointerMove = (e) => {
|
|
36
|
-
const { x, y, sx, sy } = toPixels(e);
|
|
98
|
+
const { x, y, cx, cy, sx, sy } = toPixels(e);
|
|
99
|
+
if (claimed.has(e.pointerId)) e.preventDefault();
|
|
37
100
|
if (e.pointerType === "touch")
|
|
38
101
|
queue.push({ type: "touch", id: e.pointerId, phase: "move", x, y });
|
|
39
102
|
else queue.push({ type: "mouse-move", x, y, dx: e.movementX * sx, dy: e.movementY * sy });
|
|
103
|
+
pointer(e, "move", cx, cy);
|
|
40
104
|
};
|
|
41
105
|
const onWheel = (e) => {
|
|
106
|
+
if (policy.wheel) e.preventDefault();
|
|
42
107
|
const scale = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? 400 : 1;
|
|
43
|
-
|
|
108
|
+
const { cx, cy } = toPixels(e);
|
|
109
|
+
queue.push({
|
|
110
|
+
type: "wheel",
|
|
111
|
+
dx: e.deltaX * scale,
|
|
112
|
+
dy: e.deltaY * scale,
|
|
113
|
+
x: cx,
|
|
114
|
+
y: cy,
|
|
115
|
+
modifiers: modifiersOf(e)
|
|
116
|
+
});
|
|
44
117
|
};
|
|
45
118
|
const onBlur = () => queue.push({ type: "focus", focused: false });
|
|
46
119
|
const onFocus = () => queue.push({ type: "focus", focused: true });
|
|
47
|
-
const onContextMenu = (e) =>
|
|
120
|
+
const onContextMenu = (e) => {
|
|
121
|
+
if (blockMenu || policy.buttons.includes("right")) e.preventDefault();
|
|
122
|
+
};
|
|
48
123
|
target.addEventListener("keydown", onKeyDown);
|
|
49
124
|
target.addEventListener("keyup", onKeyUp);
|
|
50
125
|
target.addEventListener("blur", onBlur);
|
|
51
126
|
target.addEventListener("focus", onFocus);
|
|
52
127
|
element.addEventListener("pointerdown", onPointerDown);
|
|
53
128
|
target.addEventListener("pointerup", onPointerUp);
|
|
129
|
+
element.addEventListener("pointercancel", onPointerCancel);
|
|
54
130
|
element.addEventListener("pointermove", onPointerMove);
|
|
55
|
-
element.addEventListener("wheel", onWheel, { passive:
|
|
131
|
+
element.addEventListener("wheel", onWheel, { passive: false });
|
|
56
132
|
element.addEventListener("contextmenu", onContextMenu);
|
|
57
133
|
return {
|
|
58
134
|
drain(out) {
|
|
59
|
-
for (const e of
|
|
60
|
-
|
|
135
|
+
for (const e of events) out.push(e);
|
|
136
|
+
events.length = 0;
|
|
61
137
|
const pads = globalThis.navigator?.getGamepads?.() ?? [];
|
|
62
138
|
for (let i = 0; i < pads.length; i++) {
|
|
63
139
|
const pad = pads[i];
|
|
@@ -76,13 +152,29 @@ function createDomInputSource(element) {
|
|
|
76
152
|
}
|
|
77
153
|
}
|
|
78
154
|
},
|
|
155
|
+
onInput(listener) {
|
|
156
|
+
listeners.add(listener);
|
|
157
|
+
return () => listeners.delete(listener);
|
|
158
|
+
},
|
|
159
|
+
claimPointer(id) {
|
|
160
|
+
if (!down.has(id) || claimed.has(id)) return;
|
|
161
|
+
claimed.add(id);
|
|
162
|
+
capture(id);
|
|
163
|
+
},
|
|
164
|
+
setPointerPolicy(next) {
|
|
165
|
+
policy = { buttons: [...next.buttons], wheel: next.wheel, touch: next.touch };
|
|
166
|
+
element.style.touchAction = next.touch ? "none" : touchAction;
|
|
167
|
+
},
|
|
79
168
|
dispose() {
|
|
169
|
+
listeners.clear();
|
|
170
|
+
element.style.touchAction = touchAction;
|
|
80
171
|
target.removeEventListener("keydown", onKeyDown);
|
|
81
172
|
target.removeEventListener("keyup", onKeyUp);
|
|
82
173
|
target.removeEventListener("blur", onBlur);
|
|
83
174
|
target.removeEventListener("focus", onFocus);
|
|
84
175
|
element.removeEventListener("pointerdown", onPointerDown);
|
|
85
176
|
target.removeEventListener("pointerup", onPointerUp);
|
|
177
|
+
element.removeEventListener("pointercancel", onPointerCancel);
|
|
86
178
|
element.removeEventListener("pointermove", onPointerMove);
|
|
87
179
|
element.removeEventListener("wheel", onWheel);
|
|
88
180
|
element.removeEventListener("contextmenu", onContextMenu);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HostPerformance } from '@aethervtt/shard-platform';
|
|
2
|
+
/**
|
|
3
|
+
* The page's own instruments (0062): a `longtask` observer, and resource timing for downloads.
|
|
4
|
+
* One per page: the observer starts on the first call and keeps every long task since, buffered
|
|
5
|
+
* ones from before it included. Three.js pages can use it too, so both renderers measure alike.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createWebPerformance(): HostPerformance;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const RESOURCE_BUFFER = 1e4;
|
|
2
|
+
const TASK_HISTORY = 1e3;
|
|
3
|
+
let shared;
|
|
4
|
+
function createWebPerformance() {
|
|
5
|
+
if (shared) return shared;
|
|
6
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
7
|
+
const tasks = [];
|
|
8
|
+
const observes = typeof PerformanceObserver !== "undefined" && PerformanceObserver.supportedEntryTypes?.includes("longtask");
|
|
9
|
+
if (observes) {
|
|
10
|
+
new PerformanceObserver((list) => {
|
|
11
|
+
for (const entry of list.getEntries()) {
|
|
12
|
+
tasks.push([entry.startTime, entry.duration]);
|
|
13
|
+
if (tasks.length > TASK_HISTORY) tasks.shift();
|
|
14
|
+
for (const listener of listeners) listener(entry.startTime, entry.duration);
|
|
15
|
+
}
|
|
16
|
+
}).observe({ type: "longtask", buffered: true });
|
|
17
|
+
}
|
|
18
|
+
const timing = typeof performance !== "undefined" && "getEntriesByType" in performance;
|
|
19
|
+
if (timing && performance.setResourceTimingBufferSize) {
|
|
20
|
+
performance.setResourceTimingBufferSize(RESOURCE_BUFFER);
|
|
21
|
+
}
|
|
22
|
+
shared = {
|
|
23
|
+
userAgent: typeof navigator === "undefined" ? "unknown" : navigator.userAgent,
|
|
24
|
+
...observes && {
|
|
25
|
+
onLongTask(listener) {
|
|
26
|
+
for (const [start, duration] of tasks) listener(start, duration);
|
|
27
|
+
listeners.add(listener);
|
|
28
|
+
return () => void listeners.delete(listener);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
...timing && { downloads },
|
|
32
|
+
heap,
|
|
33
|
+
startSampler,
|
|
34
|
+
measure
|
|
35
|
+
};
|
|
36
|
+
return shared;
|
|
37
|
+
}
|
|
38
|
+
const MEMORY_EVERY_MS = 5e3;
|
|
39
|
+
let measured;
|
|
40
|
+
let measuring = false;
|
|
41
|
+
let measuredAt = Number.NEGATIVE_INFINITY;
|
|
42
|
+
function heap() {
|
|
43
|
+
const page = performance;
|
|
44
|
+
if (globalThis.crossOriginIsolated && page.measureUserAgentSpecificMemory) {
|
|
45
|
+
const now = performance.now();
|
|
46
|
+
if (!measuring && now - measuredAt >= MEMORY_EVERY_MS) {
|
|
47
|
+
measuring = true;
|
|
48
|
+
measuredAt = now;
|
|
49
|
+
page.measureUserAgentSpecificMemory().then((r) => {
|
|
50
|
+
measured = { usedBytes: r.bytes, source: "measureUserAgentSpecificMemory" };
|
|
51
|
+
}).catch(() => {
|
|
52
|
+
}).finally(() => {
|
|
53
|
+
measuring = false;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (measured) return measured;
|
|
57
|
+
}
|
|
58
|
+
const memory = page.memory;
|
|
59
|
+
if (!memory) return void 0;
|
|
60
|
+
return {
|
|
61
|
+
usedBytes: memory.usedJSHeapSize,
|
|
62
|
+
totalBytes: memory.totalJSHeapSize,
|
|
63
|
+
limitBytes: memory.jsHeapSizeLimit,
|
|
64
|
+
source: "performance.memory"
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const SAMPLE_INTERVAL_MS = 1;
|
|
68
|
+
async function startSampler() {
|
|
69
|
+
const Ctor = globalThis.Profiler;
|
|
70
|
+
if (!Ctor) return void 0;
|
|
71
|
+
let profiler;
|
|
72
|
+
try {
|
|
73
|
+
profiler = new Ctor({ sampleInterval: SAMPLE_INTERVAL_MS, maxBufferSize: 1e5 });
|
|
74
|
+
} catch {
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
stop: async () => {
|
|
79
|
+
const trace = await profiler.stop();
|
|
80
|
+
const { hottestFromSelfProfile, samplesFromSelfProfile } = await import("@aethervtt/shard-core/capture");
|
|
81
|
+
return {
|
|
82
|
+
hottest: hottestFromSelfProfile(trace, SAMPLE_INTERVAL_MS),
|
|
83
|
+
samples: samplesFromSelfProfile(trace, SAMPLE_INTERVAL_MS)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function measure(name, track, start, ms) {
|
|
89
|
+
try {
|
|
90
|
+
performance.measure(name, {
|
|
91
|
+
start,
|
|
92
|
+
end: start + ms,
|
|
93
|
+
detail: {
|
|
94
|
+
devtools: { dataType: "track-entry", track: `shard ${track}`, trackGroup: "Shard" }
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function downloads() {
|
|
101
|
+
const result = { transferred: 0, decoded: 0 };
|
|
102
|
+
const add = (entry) => {
|
|
103
|
+
result.transferred += entry.transferSize;
|
|
104
|
+
result.decoded += entry.decodedBodySize;
|
|
105
|
+
};
|
|
106
|
+
for (const entry of performance.getEntriesByType("navigation")) {
|
|
107
|
+
add(entry);
|
|
108
|
+
}
|
|
109
|
+
for (const entry of performance.getEntriesByType("resource")) {
|
|
110
|
+
add(entry);
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
export {
|
|
115
|
+
createWebPerformance
|
|
116
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aethervtt/shard-platform-web",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"README.md"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@aethervtt/shard-core": "0.0
|
|
20
|
-
"@aethervtt/shard-platform": "0.0
|
|
19
|
+
"@aethervtt/shard-core": "0.2.0",
|
|
20
|
+
"@aethervtt/shard-platform": "0.2.0"
|
|
21
21
|
},
|
|
22
22
|
"repository": {
|
|
23
23
|
"type": "git",
|
|
@@ -29,6 +29,6 @@
|
|
|
29
29
|
"provenance": true
|
|
30
30
|
},
|
|
31
31
|
"shard": {
|
|
32
|
-
"buildSha": "
|
|
32
|
+
"buildSha": "32c22a3944ed23f5d1baa90bf7cc9fae724f5fd8"
|
|
33
33
|
}
|
|
34
34
|
}
|