webspresso 0.0.110 → 0.0.112
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/core/client/adapter/datastar.js +190 -51
- package/core/client/api.js +23 -21
- package/core/client/controller.js +407 -40
- package/core/client/debug.js +12 -12
- package/core/client/devtool.js +124 -19
- package/core/client/forms.js +163 -29
- package/core/client/fragments.js +616 -118
- package/core/client/host.js +369 -0
- package/core/client/index.d.ts +18 -0
- package/core/client/index.js +154 -23
- package/core/client/lite.js +101 -4
- package/core/client/server-fragments.js +142 -22
- package/core/client/services.js +588 -0
- package/core/client/utils.js +188 -2
- package/index.d.ts +334 -29
- package/index.js +3 -0
- package/package.json +1 -1
- package/src/bundle/index.js +175 -14
- package/src/dev/banner.js +4 -1
- package/src/dev-reload/index.js +29 -1
- package/src/server.js +28 -0
package/core/client/debug.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* and lifecycle cleanup errors without logging raw form values or sensitive payloads.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const { NOOP_DEBUGGER } = require('./utils');
|
|
11
|
+
const { isArray, isNumber, NOOP_DEBUGGER, uid } = require('./utils');
|
|
12
12
|
|
|
13
13
|
const SENSITIVE_KEY_PATTERN = /password|passwd|secret|token|authorization|cookie|credit|card|cvv|ssn|api[-_]?key/i;
|
|
14
14
|
|
|
@@ -32,7 +32,7 @@ function summarizePayloadSafely(payload, includeSafePrimitives = false) {
|
|
|
32
32
|
if (typeof Blob !== 'undefined' && payload instanceof Blob) {
|
|
33
33
|
return { type: 'Blob', size: payload.size, mimeType: payload.type || 'application/octet-stream' };
|
|
34
34
|
}
|
|
35
|
-
if (
|
|
35
|
+
if (isArray(payload)) {
|
|
36
36
|
return { type: 'Array', length: payload.length };
|
|
37
37
|
}
|
|
38
38
|
if (typeof payload === 'object') {
|
|
@@ -58,7 +58,7 @@ function summarizePayloadSafely(payload, includeSafePrimitives = false) {
|
|
|
58
58
|
*/
|
|
59
59
|
function createActiveDebugger(options = {}) {
|
|
60
60
|
let enabled = Boolean(options.enabled);
|
|
61
|
-
const maxEvents =
|
|
61
|
+
const maxEvents = isNumber(options.maxEvents) && options.maxEvents > 0 ? options.maxEvents : 200;
|
|
62
62
|
const customLogger = typeof options.logger === 'function' ? options.logger : null;
|
|
63
63
|
|
|
64
64
|
const events = [];
|
|
@@ -73,7 +73,7 @@ function createActiveDebugger(options = {}) {
|
|
|
73
73
|
|
|
74
74
|
function pushEvent(type, detail = {}) {
|
|
75
75
|
const entry = {
|
|
76
|
-
id:
|
|
76
|
+
id: uid('evt'),
|
|
77
77
|
type,
|
|
78
78
|
timestamp: Date.now(),
|
|
79
79
|
...detail,
|
|
@@ -192,7 +192,7 @@ function createActiveDebugger(options = {}) {
|
|
|
192
192
|
completedAt: Date.now(),
|
|
193
193
|
},
|
|
194
194
|
invalidation: {
|
|
195
|
-
tags:
|
|
195
|
+
tags: isArray(tags) ? [...tags] : [],
|
|
196
196
|
triggeredAt: Date.now(),
|
|
197
197
|
},
|
|
198
198
|
refresh: null,
|
|
@@ -215,11 +215,11 @@ function createActiveDebugger(options = {}) {
|
|
|
215
215
|
recordChainRefresh(chainId, { fragmentIds, status, loadMs, renderMs, totalServerMs, error }) {
|
|
216
216
|
const chain = chainId ? causalChains.get(chainId) : null;
|
|
217
217
|
const refreshData = {
|
|
218
|
-
fragmentIds:
|
|
218
|
+
fragmentIds: isArray(fragmentIds) ? [...fragmentIds] : [],
|
|
219
219
|
status: status || 'ok',
|
|
220
|
-
loadMs:
|
|
221
|
-
renderMs:
|
|
222
|
-
totalServerMs:
|
|
220
|
+
loadMs: isNumber(loadMs) ? loadMs : null,
|
|
221
|
+
renderMs: isNumber(renderMs) ? renderMs : null,
|
|
222
|
+
totalServerMs: isNumber(totalServerMs) ? totalServerMs : null,
|
|
223
223
|
error: error ? String(error.message || error) : null,
|
|
224
224
|
completedAt: Date.now(),
|
|
225
225
|
};
|
|
@@ -234,9 +234,9 @@ function createActiveDebugger(options = {}) {
|
|
|
234
234
|
const patchData = {
|
|
235
235
|
instanceId,
|
|
236
236
|
fragmentName: fragmentName || null,
|
|
237
|
-
patchMs:
|
|
238
|
-
loadMs:
|
|
239
|
-
renderMs:
|
|
237
|
+
patchMs: isNumber(patchMs) ? patchMs : 0,
|
|
238
|
+
loadMs: isNumber(loadMs) ? loadMs : null,
|
|
239
|
+
renderMs: isNumber(renderMs) ? renderMs : null,
|
|
240
240
|
completedAt: Date.now(),
|
|
241
241
|
};
|
|
242
242
|
if (chain) {
|
package/core/client/devtool.js
CHANGED
|
@@ -15,16 +15,15 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
const { defaultStorage } = require('./storage');
|
|
18
|
+
const { isArray, isNumber } = require('./utils');
|
|
18
19
|
|
|
19
20
|
const DEVTOOL_HOST_ID = 'webspresso-client-devtools-host';
|
|
20
21
|
|
|
21
|
-
const PKG_VERSION =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
})();
|
|
22
|
+
const PKG_VERSION =
|
|
23
|
+
(typeof window !== 'undefined' &&
|
|
24
|
+
window.__WEBSPRESSO_DEV_META__ &&
|
|
25
|
+
window.__WEBSPRESSO_DEV_META__.version) ||
|
|
26
|
+
'0.0.110';
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* Connect to Redux DevTools browser extension if installed.
|
|
@@ -176,10 +175,61 @@ function mountDevtool(runtime, options = {}) {
|
|
|
176
175
|
const position = options.position || 'bottom-right';
|
|
177
176
|
const isRight = position.includes('right');
|
|
178
177
|
const studioUrl = options.studioUrl || 'http://localhost:4567';
|
|
178
|
+
let metaOverrides =
|
|
179
|
+
options.meta && typeof options.meta === 'object' ? { ...options.meta } : {};
|
|
179
180
|
let isOpen = Boolean(options.open);
|
|
180
181
|
let activeTab = 'controllers'; // 'controllers' | 'fragments' | 'network' | 'storage' | 'studio'
|
|
181
182
|
let selectedControllerId = null;
|
|
182
183
|
|
|
184
|
+
function resolveDevFeatures() {
|
|
185
|
+
const winMeta =
|
|
186
|
+
typeof window !== 'undefined' &&
|
|
187
|
+
window.__WEBSPRESSO_DEV_META__ &&
|
|
188
|
+
typeof window.__WEBSPRESSO_DEV_META__ === 'object'
|
|
189
|
+
? window.__WEBSPRESSO_DEV_META__
|
|
190
|
+
: {};
|
|
191
|
+
const merged = { ...winMeta, ...metaOverrides };
|
|
192
|
+
const pluginsList = isArray(merged.plugins)
|
|
193
|
+
? merged.plugins
|
|
194
|
+
: isArray(options.plugins)
|
|
195
|
+
? options.plugins
|
|
196
|
+
: [];
|
|
197
|
+
|
|
198
|
+
const hasStudio =
|
|
199
|
+
options.hasStudio !== undefined
|
|
200
|
+
? Boolean(options.hasStudio)
|
|
201
|
+
: merged.hasStudio !== undefined
|
|
202
|
+
? Boolean(merged.hasStudio)
|
|
203
|
+
: merged.hasDb !== undefined
|
|
204
|
+
? Boolean(merged.hasDb)
|
|
205
|
+
: Boolean(
|
|
206
|
+
options.studioUrl ||
|
|
207
|
+
pluginsList.includes('studio') ||
|
|
208
|
+
pluginsList.includes('db-studio')
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const hasAdmin =
|
|
212
|
+
options.hasAdmin !== undefined
|
|
213
|
+
? Boolean(options.hasAdmin)
|
|
214
|
+
: merged.hasAdmin !== undefined
|
|
215
|
+
? Boolean(merged.hasAdmin)
|
|
216
|
+
: Boolean(
|
|
217
|
+
options.adminPath ||
|
|
218
|
+
options.adminUrl ||
|
|
219
|
+
pluginsList.includes('admin-panel') ||
|
|
220
|
+
pluginsList.includes('adminPanel') ||
|
|
221
|
+
pluginsList.includes('admin')
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const adminPath = merged.adminPath || options.adminPath || options.adminUrl || '/_admin';
|
|
225
|
+
return {
|
|
226
|
+
hasStudio,
|
|
227
|
+
hasAdmin,
|
|
228
|
+
adminPath,
|
|
229
|
+
plugins: pluginsList,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
183
233
|
// Initialize Redux DevTools extension bridge if available
|
|
184
234
|
const reduxBridge = setupReduxDevToolsBridge(runtime);
|
|
185
235
|
|
|
@@ -257,6 +307,8 @@ function mountDevtool(runtime, options = {}) {
|
|
|
257
307
|
flex-direction: column;
|
|
258
308
|
overflow: hidden;
|
|
259
309
|
z-index: 999999;
|
|
310
|
+
}
|
|
311
|
+
.ws-drawer.ws-drawer-enter {
|
|
260
312
|
animation: wsFadeIn 0.15s ease-out;
|
|
261
313
|
}
|
|
262
314
|
@keyframes wsFadeIn {
|
|
@@ -753,33 +805,46 @@ function mountDevtool(runtime, options = {}) {
|
|
|
753
805
|
}
|
|
754
806
|
|
|
755
807
|
function renderStudioTab() {
|
|
756
|
-
|
|
757
|
-
<div>
|
|
758
|
-
<div style="margin-bottom:16px;">
|
|
759
|
-
<strong style="font-size:13px;color:#fff;">Developer Tools & Studio Integrations</strong>
|
|
760
|
-
<p style="font-size:10px;color:#71717a;">Direct shortcuts to Webspresso's integrated developer productivity tools.</p>
|
|
761
|
-
</div>
|
|
808
|
+
const features = resolveDevFeatures();
|
|
762
809
|
|
|
810
|
+
const studioCardHtml = features.hasStudio
|
|
811
|
+
? `
|
|
763
812
|
<div class="ws-card" style="margin-bottom:12px;display:flex;align-items:center;justify-content:space-between;">
|
|
764
813
|
<div>
|
|
765
814
|
<div style="font-weight:700;color:#fbbf24;font-size:13px;">🗄️ Webspresso DB Studio</div>
|
|
766
815
|
<div style="font-size:10px;color:#a1a1aa;margin-top:2px;">Visual database browser, query runner, and table inspector.</div>
|
|
767
816
|
<div style="font-size:9px;color:#71717a;margin-top:4px;">Run in terminal: <code>npx webspresso studio</code> (port 4567)</div>
|
|
768
817
|
</div>
|
|
769
|
-
<a href="${studioUrl}" target="_blank" rel="noopener noreferrer" class="ws-btn ws-btn-primary" style="text-decoration:none;">
|
|
818
|
+
<a href="${studioUrl}" target="_blank" rel="noopener noreferrer" class="ws-btn ws-btn-primary" id="ws-btn-open-studio" style="text-decoration:none;">
|
|
770
819
|
Open DB Studio ↗
|
|
771
820
|
</a>
|
|
772
821
|
</div>
|
|
822
|
+
`
|
|
823
|
+
: '';
|
|
773
824
|
|
|
825
|
+
const adminCardHtml = features.hasAdmin
|
|
826
|
+
? `
|
|
774
827
|
<div class="ws-card" style="margin-bottom:12px;display:flex;align-items:center;justify-content:space-between;">
|
|
775
828
|
<div>
|
|
776
829
|
<div style="font-weight:700;color:#38bdf8;font-size:13px;">⚙️ Admin Panel SPA</div>
|
|
777
830
|
<div style="font-size:10px;color:#a1a1aa;margin-top:2px;">Mithril.js model CRUD and staff administration cockpit.</div>
|
|
778
831
|
</div>
|
|
779
|
-
<a href="
|
|
780
|
-
Open
|
|
832
|
+
<a href="${features.adminPath}" target="_blank" rel="noopener noreferrer" class="ws-btn" id="ws-btn-open-admin" style="text-decoration:none;">
|
|
833
|
+
Open ${features.adminPath} ↗
|
|
781
834
|
</a>
|
|
782
835
|
</div>
|
|
836
|
+
`
|
|
837
|
+
: '';
|
|
838
|
+
|
|
839
|
+
return `
|
|
840
|
+
<div>
|
|
841
|
+
<div style="margin-bottom:16px;">
|
|
842
|
+
<strong style="font-size:13px;color:#fff;">Developer Tools & Studio Integrations</strong>
|
|
843
|
+
<p style="font-size:10px;color:#71717a;">Direct shortcuts to Webspresso's integrated developer productivity tools.</p>
|
|
844
|
+
</div>
|
|
845
|
+
|
|
846
|
+
${studioCardHtml}
|
|
847
|
+
${adminCardHtml}
|
|
783
848
|
|
|
784
849
|
<div class="ws-card" style="display:flex;align-items:center;justify-content:space-between;">
|
|
785
850
|
<div>
|
|
@@ -859,6 +924,9 @@ function mountDevtool(runtime, options = {}) {
|
|
|
859
924
|
`;
|
|
860
925
|
}
|
|
861
926
|
|
|
927
|
+
let lastRenderedHtml = '';
|
|
928
|
+
let wasOpen = false;
|
|
929
|
+
|
|
862
930
|
function findInShadow(id) {
|
|
863
931
|
if (shadow && typeof shadow.getElementById === 'function') {
|
|
864
932
|
return shadow.getElementById(id);
|
|
@@ -866,8 +934,39 @@ function mountDevtool(runtime, options = {}) {
|
|
|
866
934
|
return shadow && typeof shadow.querySelector === 'function' ? shadow.querySelector(`#${id}`) : null;
|
|
867
935
|
}
|
|
868
936
|
|
|
869
|
-
function updateDom() {
|
|
870
|
-
|
|
937
|
+
function updateDom(force = false) {
|
|
938
|
+
const nextHtml = isOpen ? renderDrawer() : renderPill();
|
|
939
|
+
if (!force && nextHtml === lastRenderedHtml && isOpen === wasOpen) {
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// Preserve scroll positions inside drawer before updating DOM
|
|
944
|
+
let prevContentScrollTop = 0;
|
|
945
|
+
const prevContentEl =
|
|
946
|
+
isOpen && wasOpen && shadow && typeof shadow.querySelector === 'function'
|
|
947
|
+
? shadow.querySelector('.ws-content')
|
|
948
|
+
: null;
|
|
949
|
+
if (prevContentEl) {
|
|
950
|
+
prevContentScrollTop = prevContentEl.scrollTop || 0;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
lastRenderedHtml = nextHtml;
|
|
954
|
+
const openingTransition = isOpen && !wasOpen;
|
|
955
|
+
wasOpen = isOpen;
|
|
956
|
+
|
|
957
|
+
container.innerHTML = nextHtml;
|
|
958
|
+
if (openingTransition) {
|
|
959
|
+
const drawerEl = findInShadow('ws-devtool-drawer');
|
|
960
|
+
if (drawerEl && drawerEl.classList) {
|
|
961
|
+
drawerEl.classList.add('ws-drawer-enter');
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
if (prevContentScrollTop > 0 && shadow && typeof shadow.querySelector === 'function') {
|
|
965
|
+
const nextContentEl = shadow.querySelector('.ws-content');
|
|
966
|
+
if (nextContentEl) {
|
|
967
|
+
nextContentEl.scrollTop = prevContentScrollTop;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
871
970
|
bindEvents();
|
|
872
971
|
}
|
|
873
972
|
|
|
@@ -1043,7 +1142,7 @@ function mountDevtool(runtime, options = {}) {
|
|
|
1043
1142
|
document.addEventListener('keydown', onKeyDown);
|
|
1044
1143
|
|
|
1045
1144
|
// Periodic polling to keep snapshots live
|
|
1046
|
-
const pollIntervalMs =
|
|
1145
|
+
const pollIntervalMs = isNumber(options.pollInterval) ? options.pollInterval : 2000;
|
|
1047
1146
|
let pollTimer = null;
|
|
1048
1147
|
if (pollIntervalMs > 0) {
|
|
1049
1148
|
pollTimer = setInterval(() => {
|
|
@@ -1076,6 +1175,12 @@ function mountDevtool(runtime, options = {}) {
|
|
|
1076
1175
|
isOpen() {
|
|
1077
1176
|
return isOpen;
|
|
1078
1177
|
},
|
|
1178
|
+
setMeta(nextMeta = {}) {
|
|
1179
|
+
if (nextMeta && typeof nextMeta === 'object') {
|
|
1180
|
+
metaOverrides = { ...metaOverrides, ...nextMeta };
|
|
1181
|
+
updateDom();
|
|
1182
|
+
}
|
|
1183
|
+
},
|
|
1079
1184
|
getSnapshot() {
|
|
1080
1185
|
return {
|
|
1081
1186
|
controllers: getControllersSnapshot(),
|