catalyst-core 0.2.0-beta.3 → 0.3.0-beta.2
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/babel.native.config.cjs +8 -0
- package/bin/catalyst.js +49 -105
- package/changelog.md +8 -0
- package/dist/caching.js +1 -1
- package/dist/globals.d.ts +7 -0
- package/dist/index.jsx +8 -0
- package/dist/logger.js +74 -3
- package/dist/native/androidProject/app/build.gradle.kts +45 -4
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +86 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +8 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +173 -13
- package/dist/native/androidProject/settings.gradle.kts +10 -0
- package/dist/native/androidSetup.js +300 -8
- package/dist/native/bridge/WebBridge.js +481 -59
- package/dist/native/bridge/constants/NativeInterfaces.js +304 -45
- package/dist/native/bridge/errors.js +250 -26
- package/dist/native/bridge/hooks/index.js +132 -1
- package/dist/native/bridge/hooks/useAI.js +94 -0
- package/dist/native/bridge/hooks/useCamera.js +347 -9
- package/dist/native/bridge/hooks/useDataProtection.js +200 -2
- package/dist/native/bridge/hooks/useDeviceInfo.js +71 -2
- package/dist/native/bridge/hooks/useFilePicker.js +429 -2
- package/dist/native/bridge/hooks/useGoogleSignIn.js +81 -1
- package/dist/native/bridge/hooks/useHapticFeedback.js +196 -1
- package/dist/native/bridge/hooks/useIntent.js +95 -1
- package/dist/native/bridge/hooks/useNativeTransition.js +202 -27
- package/dist/native/bridge/hooks/useNetworkStatus.js +84 -3
- package/dist/native/bridge/hooks/useNotification.js +318 -2
- package/dist/native/bridge/hooks/useSafeArea.js +84 -2
- package/dist/native/bridge/hooks/useVideoStream.js +434 -6
- package/dist/native/bridge/hooks/utils.js +27 -1
- package/dist/native/bridge/hooks.js +16 -1
- package/dist/native/bridge/perf/collectors/ApiCollector.js +66 -3
- package/dist/native/bridge/perf/collectors/CacheCollector.js +186 -11
- package/dist/native/bridge/perf/collectors/HookCollector.js +141 -19
- package/dist/native/bridge/perf/collectors/InsightsCollector.js +481 -23
- package/dist/native/bridge/perf/collectors/InteractionCollector.js +245 -10
- package/dist/native/bridge/perf/collectors/KeyboardCollector.js +107 -8
- package/dist/native/bridge/perf/collectors/NavigationCollector.js +273 -32
- package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +178 -2
- package/dist/native/bridge/perf/collectors/RenderCollector.js +258 -14
- package/dist/native/bridge/perf/collectors/ScrollCollector.js +95 -9
- package/dist/native/bridge/perf/collectors/ThreadCollector.js +90 -6
- package/dist/native/bridge/perf/core/constants.js +103 -20
- package/dist/native/bridge/perf/core/measure.js +179 -30
- package/dist/native/bridge/perf/core/session.js +89 -23
- package/dist/native/bridge/perf/core/store.js +554 -1
- package/dist/native/bridge/perf/core/summary.js +174 -1
- package/dist/native/bridge/perf/core/traceExport.js +240 -1
- package/dist/native/bridge/perf/core/waterfalls.js +146 -1
- package/dist/native/bridge/perf/index.js +359 -38
- package/dist/native/bridge/safeArea.js +53 -5
- package/dist/native/bridge/standardizedHooks.js +595 -82
- package/dist/native/bridge/useBaseHook.js +274 -38
- package/dist/native/bridge/utils/CameraUtils.js +201 -56
- package/dist/native/bridge/utils/FileObjectConverter.js +129 -18
- package/dist/native/bridge/utils/NativeBridge.js +425 -141
- package/dist/native/buildAndroid/assets.js +510 -13
- package/dist/native/buildAndroid/build.js +296 -19
- package/dist/native/buildAndroid/config.js +87 -1
- package/dist/native/buildAndroid/index.js +406 -1
- package/dist/native/buildAppAndroid.js +34 -2
- package/dist/native/buildAppIos.js +62 -2
- package/dist/native/buildIos/assets.js +609 -8
- package/dist/native/buildIos/build.js +639 -20
- package/dist/native/buildIos/config.js +294 -12
- package/dist/native/buildIos/index.js +343 -6
- package/dist/native/buildIos/plugins.js +343 -16
- package/dist/native/internal-plugins/device-info-plugin/android/DeviceInfoPlugin.kt +43 -0
- package/dist/native/internal-plugins/device-info-plugin/ios/DeviceInfoPlugin.swift +28 -0
- package/dist/native/internal-plugins/device-info-plugin/manifest.json +19 -0
- package/dist/native/internalPluginUtils.js +232 -7
- package/dist/native/package.json +3 -0
- package/dist/native/plugin-bridge/PluginBridge.js +227 -1
- package/dist/native/pluginComposerAndroid.js +407 -23
- package/dist/native/pluginComposerIos.js +435 -11
- package/dist/native/renameAndroidProject.js +1094 -88
- package/dist/native/setupEmulatorIos.js +289 -22
- package/dist/native/setupServer.js +160 -19
- package/dist/native/terminalProgress.js +199 -11
- package/dist/native/utils.js +193 -15
- package/dist/offline/catalyst-sw.js +145 -1
- package/dist/offline/registerServiceWorker.js +33 -1
- package/dist/otel.js +375 -46
- package/dist/router/ClientRouter.js +14 -2
- package/dist/router/ServerRouter.js +9 -1
- package/dist/router.js +1 -1
- package/dist/scripts/build.js +112 -3
- package/dist/scripts/checkVersion.js +3 -1
- package/dist/scripts/cleanCache.js +30 -1
- package/dist/scripts/generateOfflineManifest.js +116 -1
- package/dist/scripts/loadEnvironmentVariables.js +32 -6
- package/dist/scripts/plugins.js +309 -1
- package/dist/scripts/preServerInit.js +13 -0
- package/dist/scripts/scriptUtils.js +54 -3
- package/dist/scripts/serve.js +51 -4
- package/dist/scripts/start.js +47 -10
- package/dist/scripts/validator.js +149 -1
- package/dist/sentry.cjs +127 -0
- package/dist/sentry.js +125 -5
- package/dist/server/expressServer.js +296 -5
- package/dist/server/manifestCache.js +36 -0
- package/dist/server/renderer/ChunkExtractor.js +144 -0
- package/dist/server/renderer/document/Body.jsx +59 -0
- package/dist/server/renderer/document/FastRefresh.jsx +20 -0
- package/dist/server/renderer/document/Head.jsx +60 -0
- package/dist/server/renderer/document/index.jsx +2 -0
- package/dist/server/renderer/extract.js +149 -31
- package/dist/server/renderer/handler.jsx +450 -0
- package/dist/server/renderer/index.js +8 -1
- package/dist/server/renderer/render.js +47 -0
- package/dist/server/utils/botDetectionMiddleware.js +29 -0
- package/dist/server/utils/cjsRequire.js +10 -0
- package/dist/server/utils/userAgentUtil.js +87 -9
- package/dist/server/utils/validator.js +164 -1
- package/dist/vite/FastRefresh.jsx +20 -0
- package/dist/vite/inject-cache-key-plugin.js +276 -0
- package/dist/vite/loadCustomViteConfig.js +22 -0
- package/dist/vite/manifest-categorization-plugin.js +455 -0
- package/dist/vite/node-loader.mjs +458 -0
- package/dist/vite/scssParams.js +21 -0
- package/dist/vite/vite.config.client.js +130 -0
- package/dist/vite/vite.config.js +498 -0
- package/dist/vite/vite.config.server.js +84 -0
- package/dist/web-router/components/MetaTag.jsx +34 -0
- package/dist/web-router/components/RouterDataProvider.jsx +332 -0
- package/dist/web-router/components/Split.jsx +200 -0
- package/dist/web-router/components/SplitInview.jsx +106 -0
- package/dist/web-router/components/SsrRequestContext.jsx +14 -0
- package/dist/web-router/context.jsx +12 -0
- package/dist/web-router/hooks.jsx +72 -0
- package/dist/web-router/types/components/MetaTag.d.ts +2 -0
- package/dist/web-router/types/components/RouterDataProvider.d.ts +95 -0
- package/dist/web-router/types/context.d.ts +14 -0
- package/dist/web-router/types/hooks.d.ts +1 -0
- package/dist/web-router/types/index.d.ts +3 -0
- package/dist/web-router/types/utils/metaDataUtils.d.ts +24 -0
- package/dist/web-router/utils/metaDataUtils.jsx +119 -0
- package/mcp_v2/conversion-tasks.json +35 -17
- package/mcp_v2/knowledge-base.json +176 -17
- package/mcp_v2/lib/helpers.js +10 -0
- package/mcp_v2/mcp.js +40 -8
- package/mcp_v2/package.json +1 -0
- package/mcp_v2/tools/build.js +161 -37
- package/mcp_v2/tools/conversion.js +106 -5
- package/mcp_v2/tools/tasks.js +18 -14
- package/package.json +35 -68
- package/babel.config.js +0 -32
- package/dist/index.js +0 -1
- package/dist/scripts/devBuild.js +0 -3
- package/dist/scripts/devServe.js +0 -3
- package/dist/scripts/loadScriptsBeforeServerStarts.js +0 -4
- package/dist/scripts/registerAliases.js +0 -6
- package/dist/server/renderer/document/Body.js +0 -11
- package/dist/server/renderer/document/Head.js +0 -9
- package/dist/server/renderer/document/index.js +0 -1
- package/dist/server/renderer/handler.js +0 -47
- package/dist/server/startServer.js +0 -57
- package/dist/webpack/babel-plugins/remove-client.plugin.js +0 -5
- package/dist/webpack/babel-plugins/remove-ssr.plugin.js +0 -5
- package/dist/webpack/babel.config.client.js +0 -1
- package/dist/webpack/babel.config.ssr.js +0 -1
- package/dist/webpack/base.babel.js +0 -7
- package/dist/webpack/development.client.babel.js +0 -10
- package/dist/webpack/production.client.babel.js +0 -4
- package/dist/webpack/production.ssr.babel.js +0 -8
- package/dist/webpack/scssParams.js +0 -9
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Measure = void 0;
|
|
7
|
+
var _constants = require("./constants.js");
|
|
8
|
+
/**
|
|
2
9
|
* measure.js
|
|
3
10
|
*
|
|
4
11
|
* Shared _measure() and _colorFor() logic used by every collector.
|
|
@@ -9,32 +16,174 @@
|
|
|
9
16
|
* - custom data goes in properties[] as [key, value] pairs
|
|
10
17
|
* - start AND end must both be numeric ms timestamps — passing a mark name
|
|
11
18
|
* string as start causes silent fallback to Timings row (confirmed Chrome 145)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const INTERNAL_PROPERTIES = new Set(["simulatorValid"]);
|
|
22
|
+
const PROPERTY_LABELS = {
|
|
23
|
+
interactionId: "Related tap",
|
|
24
|
+
parentOperation: "Parent operation",
|
|
25
|
+
callId: "Call ID",
|
|
26
|
+
requestId: "Request ID",
|
|
27
|
+
memoryId: "Memory sample"
|
|
28
|
+
};
|
|
29
|
+
const PROPERTY_PRIORITY = {
|
|
30
|
+
interactionId: 0,
|
|
31
|
+
parentOperation: 1,
|
|
32
|
+
outcome: 2,
|
|
33
|
+
ok: 3,
|
|
34
|
+
status: 4,
|
|
35
|
+
durationMs: 5,
|
|
36
|
+
roundTripMs: 5,
|
|
37
|
+
responseMs: 5
|
|
38
|
+
};
|
|
39
|
+
class Measure {
|
|
40
|
+
constructor() {
|
|
41
|
+
// Rolling window of recent LoAF entries — shared across all collectors
|
|
42
|
+
// so any collector can check loafOverlap without knowing about others.
|
|
43
|
+
this._recentLoafs = [];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Record a LoAF entry so overlap detection stays current.
|
|
48
|
+
* Called by RenderCollector whenever a long-animation-frame fires.
|
|
49
|
+
*/
|
|
50
|
+
recordLoaf(start, end) {
|
|
51
|
+
this._recentLoafs.push({
|
|
52
|
+
start,
|
|
53
|
+
end
|
|
54
|
+
});
|
|
55
|
+
if (this._recentLoafs.length > _constants.THRESHOLD.LOAF_WINDOW) {
|
|
56
|
+
this._recentLoafs.shift();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
overlapsLoaf(startMs, endMs) {
|
|
60
|
+
return this._recentLoafs.some(loaf => startMs < loaf.end && endMs > loaf.start);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Emit a performance.measure() with Chrome DevTools Extensibility API metadata.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} name - measure name (catalyst:...)
|
|
67
|
+
* @param {string} startMark - name of the opening performance.mark()
|
|
68
|
+
* @param {number} endTime - end time in ms (performance.now()-space)
|
|
69
|
+
* @param {object} detail - arbitrary detail fields added as properties[]
|
|
70
|
+
* @param {string} track - Chrome DevTools track name (from TRACK constant)
|
|
71
|
+
* @param {string} [color] - override color; if omitted, derived from name+detail
|
|
72
|
+
* @param {string} [trackGroup] - Chrome DevTools track group
|
|
73
|
+
*/
|
|
74
|
+
emit(name, startMark, endTime, detail = {}, track, color = null, trackGroup = _constants.TRACK_GROUP) {
|
|
75
|
+
try {
|
|
76
|
+
const startTime = performance.getEntriesByName(startMark, "mark")[0]?.startTime;
|
|
77
|
+
if (startTime == null) {
|
|
78
|
+
console.warn("[CatalystPerf] measure skipped — mark not found:", startMark);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const resolvedColor = color ?? this._colorFor(name, detail, startTime, endTime);
|
|
82
|
+
const properties = this._properties(detail);
|
|
83
|
+
performance.measure(name, {
|
|
84
|
+
start: startTime,
|
|
85
|
+
end: endTime,
|
|
86
|
+
detail: {
|
|
87
|
+
devtools: {
|
|
88
|
+
dataType: "track-entry",
|
|
89
|
+
trackGroup,
|
|
90
|
+
track,
|
|
91
|
+
color: resolvedColor,
|
|
92
|
+
tooltipText: name,
|
|
93
|
+
properties
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
} catch (e) {
|
|
98
|
+
console.warn("[CatalystPerf] measure failed:", name, e.message);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
marker(name, startTime, detail = {}, color = _constants.COLOR.SECONDARY) {
|
|
102
|
+
try {
|
|
103
|
+
performance.mark(name, {
|
|
104
|
+
startTime,
|
|
105
|
+
detail: {
|
|
106
|
+
devtools: {
|
|
107
|
+
dataType: "marker",
|
|
108
|
+
color,
|
|
109
|
+
tooltipText: name,
|
|
110
|
+
properties: this._properties(detail)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
} catch (e) {
|
|
115
|
+
console.warn("[CatalystPerf] marker failed:", name, e.message);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
_properties(detail) {
|
|
119
|
+
return Object.entries(detail).filter(([key, value]) => !INTERNAL_PROPERTIES.has(key) && value != null).sort(([left], [right]) => (PROPERTY_PRIORITY[left] ?? 100) - (PROPERTY_PRIORITY[right] ?? 100)).map(([key, value]) => [this._propertyName(key), this._propertyValue(value)]);
|
|
120
|
+
}
|
|
121
|
+
_propertyName(key) {
|
|
122
|
+
if (PROPERTY_LABELS[key]) return PROPERTY_LABELS[key];
|
|
123
|
+
return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[._-]+/g, " ").replace(/^./, char => char.toUpperCase());
|
|
124
|
+
}
|
|
125
|
+
_propertyValue(value) {
|
|
126
|
+
if (typeof value === "object") {
|
|
127
|
+
try {
|
|
128
|
+
return JSON.stringify(value);
|
|
129
|
+
} catch {
|
|
130
|
+
return String(value);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return String(value);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ─── Color derivation ─────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
_colorFor(name, detail, startTime, endTime) {
|
|
139
|
+
const duration = endTime - startTime;
|
|
140
|
+
|
|
141
|
+
// LoAF — always error (it's a bad frame by definition)
|
|
142
|
+
if (name.startsWith(_constants.PREFIX.LOAF)) return _constants.COLOR.ERROR;
|
|
143
|
+
|
|
144
|
+
// LCP — error if slow
|
|
145
|
+
if (name.startsWith(_constants.PREFIX.LCP)) return detail.renderTime > _constants.THRESHOLD.LCP_BAD_MS ? _constants.COLOR.ERROR : _constants.COLOR.PRIMARY;
|
|
146
|
+
if (name.startsWith(_constants.PREFIX.FCP)) return _constants.COLOR.PRIMARY;
|
|
147
|
+
|
|
148
|
+
// Navigation session
|
|
149
|
+
if (name.startsWith(_constants.PREFIX.SESSION_NAV)) return duration > _constants.THRESHOLD.NAV_SESSION_BAD_MS ? _constants.COLOR.ERROR : _constants.COLOR.PRIMARY;
|
|
150
|
+
|
|
151
|
+
// Route transition
|
|
152
|
+
if (name.startsWith(_constants.PREFIX.ROUTE_TRANSITION)) return _constants.COLOR.SECONDARY;
|
|
153
|
+
|
|
154
|
+
// Scroll session — error if janky
|
|
155
|
+
if (name.startsWith(_constants.PREFIX.SESSION_SCROLL)) return detail.loafCount > 0 ? _constants.COLOR.ERROR : _constants.COLOR.PRIMARY;
|
|
156
|
+
|
|
157
|
+
// Keyboard / viewport — informational
|
|
158
|
+
if (name.startsWith(_constants.PREFIX.SESSION_KEYBOARD)) return _constants.COLOR.SECONDARY;
|
|
159
|
+
if (name.startsWith(_constants.PREFIX.VIEWPORT_RESIZE)) return _constants.COLOR.SECONDARY;
|
|
160
|
+
|
|
161
|
+
// Layout shift
|
|
162
|
+
if (name.startsWith(_constants.PREFIX.LAYOUT_SHIFT)) return detail.value > _constants.THRESHOLD.CLS_BAD ? _constants.COLOR.ERROR : _constants.COLOR.TERTIARY;
|
|
163
|
+
|
|
164
|
+
// Cache spans — color passed explicitly by CacheCollector, this is fallback only
|
|
165
|
+
if (name.startsWith(_constants.PREFIX.CACHE + "/")) {
|
|
166
|
+
if (name.includes("/hit|memory|")) return _constants.COLOR.PRIMARY;
|
|
167
|
+
if (name.includes("/hit|disk|")) return _constants.COLOR.PRIMARY_LIGHT;
|
|
168
|
+
if (name.includes("/miss|")) return _constants.COLOR.ERROR;
|
|
169
|
+
return _constants.COLOR.TERTIARY;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Browser network calls
|
|
173
|
+
if (name.startsWith(_constants.PREFIX.NETWORK_TIMING)) {
|
|
174
|
+
if (detail.ok === false || duration > _constants.THRESHOLD.FETCH_SLOW_MS) return _constants.COLOR.ERROR;
|
|
175
|
+
return _constants.COLOR.SECONDARY;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Hook spans — error if LoAF burst detected during mount
|
|
179
|
+
if (name.startsWith(_constants.PREFIX.HOOK_MOUNT) || name.startsWith(_constants.PREFIX.HOOK_LAZY)) return detail.loafCount > 0 ? _constants.COLOR.ERROR : _constants.COLOR.SECONDARY;
|
|
180
|
+
|
|
181
|
+
// Interaction
|
|
182
|
+
if (name.startsWith(_constants.PREFIX.INTERACTION) || Number.isFinite(detail.responseMs)) return (detail.responseMs ?? duration) > _constants.THRESHOLD.INTERACTION_SLOW_MS ? _constants.COLOR.ERROR : _constants.COLOR.PRIMARY;
|
|
183
|
+
|
|
184
|
+
// Long press — just informational
|
|
185
|
+
if (name.startsWith(_constants.PREFIX.LONG_PRESS)) return _constants.COLOR.TERTIARY;
|
|
186
|
+
return _constants.COLOR.SECONDARY;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
exports.Measure = Measure;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Session = void 0;
|
|
7
|
+
/**
|
|
2
8
|
* session.js
|
|
3
9
|
*
|
|
4
10
|
* Reusable open/close session pattern.
|
|
@@ -10,25 +16,85 @@
|
|
|
10
16
|
* session.close({ loafCount: 3, janky: true })
|
|
11
17
|
*
|
|
12
18
|
* The session owns its own start mark so callers don't track mark names.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
class Session {
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} name - base measure name (catalyst:session/...)
|
|
24
|
+
* @param {Measure} measure - shared Measure instance
|
|
25
|
+
* @param {string} track - Chrome DevTools track name
|
|
26
|
+
*/
|
|
27
|
+
constructor(name, measure, track) {
|
|
28
|
+
this._name = name;
|
|
29
|
+
this._measure = measure;
|
|
30
|
+
this._track = track;
|
|
31
|
+
this._state = null; // { startMark, startTime, ...extra } | null
|
|
32
|
+
}
|
|
33
|
+
get isOpen() {
|
|
34
|
+
return this._state !== null;
|
|
35
|
+
}
|
|
36
|
+
get startTime() {
|
|
37
|
+
return this._state?.startTime ?? null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Open the session.
|
|
42
|
+
* @param {object} extra - any fields to carry in state (e.g. loafCount)
|
|
43
|
+
* @param {number} [atTime] - override start time (default: performance.now())
|
|
44
|
+
*/
|
|
45
|
+
open(extra = {}, atTime = null) {
|
|
46
|
+
if (this._state) return; // already open — ignore double-open
|
|
47
|
+
const startTime = atTime ?? performance.now();
|
|
48
|
+
const startMark = `${this._name}:start:${Math.round(startTime)}`;
|
|
49
|
+
performance.mark(startMark, {
|
|
50
|
+
startTime
|
|
51
|
+
});
|
|
52
|
+
this._state = {
|
|
53
|
+
startMark,
|
|
54
|
+
startTime,
|
|
55
|
+
...extra
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Close the session and emit the measure.
|
|
61
|
+
* @param {object} detail - fields added to properties[] in DevTools
|
|
62
|
+
* @param {number} [atTime] - override end time (default: performance.now())
|
|
63
|
+
* @param {string} [color] - override color
|
|
64
|
+
*/
|
|
65
|
+
close(detail = {}, atTime = null, color = null) {
|
|
66
|
+
if (!this._state) return;
|
|
67
|
+
const {
|
|
68
|
+
startMark,
|
|
69
|
+
startTime
|
|
70
|
+
} = this._state;
|
|
71
|
+
const endTime = atTime ?? performance.now();
|
|
72
|
+
this._state = null;
|
|
73
|
+
this._measure.emit(this._name, startMark, endTime, {
|
|
74
|
+
duration: Math.round(endTime - startTime),
|
|
75
|
+
...detail
|
|
76
|
+
}, this._track, color);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Read a value stored in session state (e.g. loafCount).
|
|
81
|
+
*/
|
|
82
|
+
get(key) {
|
|
83
|
+
return this._state?.[key];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Update a value in session state without closing.
|
|
88
|
+
*/
|
|
89
|
+
set(key, value) {
|
|
90
|
+
if (this._state) this._state[key] = value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Increment a numeric counter in session state.
|
|
95
|
+
*/
|
|
96
|
+
increment(key) {
|
|
97
|
+
if (this._state) this._state[key] = (this._state[key] ?? 0) + 1;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.Session = Session;
|