PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
← All changes | includes/devtools.php +47 -61 0.9.51.1.10 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode — DevTools / debug bus.
3 + * OpenStation — DevTools / debug bus.
4 4 *
5 5 * Provides a generic per-session pub/sub channel that plugins use to
6 6 * stream debug data (SQL queries, HTTP timings, hook traces, custom
7 7 * events) from a server-side capture into a client-side inspector
@@ -9,27 +9,27 @@
9 9 *
10 10 * Architecture:
11 11 *
12 12 * 1. Inspector plugin allocates a session id with
13 - * `wp.desktop.devtools.debug.startSession()` and decides which
13 + * `wp.os.devtools.debug.startSession()` and decides which
14 14 * channels it cares about (`'query'`, `'log'`, …).
15 15 * 2. Inspector contributes `X-WP-Debug-Session: <id>` to the
16 16 * target window via
17 - * `wp.desktop.devtools.addRequestHeader( windowId, 'X-WP-Debug-Session', sessionId )`.
17 + * `wp.os.devtools.addRequestHeader( windowId, 'X-WP-Debug-Session', sessionId )`.
18 18 * 3. The target window's iframe attaches that header to every
19 19 * fetch / XHR / sendBeacon (the chromeless inline bridge merges
20 20 * contributed headers into outgoing requests).
21 21 * 4. Server-side capture hooks read the header via
22 - * {@see desktop_mode_debug_session_for_request()}, run their
22 + * {@see openstation_debug_session_for_request()}, run their
23 23 * capture (SAVEQUERIES, output buffering, etc.), and publish via
24 - * {@see desktop_mode_debug_publish()}.
24 + * {@see openstation_debug_publish()}.
25 25 * 5. Inspector subscribes via
26 - * `wp.desktop.devtools.debug.subscribe( sessionId, channel, cb )`.
26 + * `wp.os.devtools.debug.subscribe( sessionId, channel, cb )`.
27 27 * The shell polls `GET /desktop-mode/v1/debug` every second and
28 28 * replays new events to subscribers.
29 29 *
30 30 * Storage: a per-session ring buffer in a transient. Bounded by
31 - * {@see DESKTOP_MODE_DEBUG_RING_SIZE} so a misconfigured capture
31 + * {@see OPENSTATION_DEBUG_RING_SIZE} so a misconfigured capture
32 32 * loop can't fill the database. TTL is 1 hour — long enough for an
33 33 * inspector session to span a few page loads, short enough that
34 34 * abandoned sessions don't squat indefinitely.
35 35 *
@@ -37,11 +37,9 @@
37 37 * logged-in AND hold `manage_options`. Debug data leaks request /
38 38 * response details (query parameters, internal IDs) — locking it to
39 39 * site admins matches the cost of getting that wrong.
40 40 *
41 - * @since 0.6.0
42 - *
43 - * @package WPDesktopMode
41 + * @package OpenStation
44 42 */
45 43
46 44 defined( 'ABSPATH' ) || exit;
47 45
@@ -52,9 +50,9 @@
52 50 * page loads) survives on the buffer without truncation. Anything
53 51 * higher and a single transient row starts to push the row-size
54 52 * sanity threshold for typical wp_options storage.
55 53 */
56 -const DESKTOP_MODE_DEBUG_RING_SIZE = 500;
54 +const OPENSTATION_DEBUG_RING_SIZE = 500;
57 55
58 56 /**
59 57 * Transient TTL for a session ring buffer, in seconds.
60 58 *
@@ -60,21 +58,19 @@
60 58 *
61 59 * One hour. Inspector windows that stay open longer than that should
62 60 * heartbeat by republishing — at which point the TTL extends.
63 61 */
64 -const DESKTOP_MODE_DEBUG_SESSION_TTL = 3600;
62 +const OPENSTATION_DEBUG_SESSION_TTL = 3600;
65 63
66 64 /**
67 65 * Build the transient key for a (session, channel) pair.
68 66 *
69 - * @since 0.6.0
70 - *
71 67 * @param string $session_id Session id (as supplied by the client).
72 68 * @param string $channel Channel name (`'query'`, `'log'`, …).
73 69 * @return string Transient key safe for `set_transient`.
74 70 */
75 -function desktop_mode_debug_transient_key( $session_id, $channel ) {
76 - return 'desktop_mode_dbg_' . md5( (string) $session_id . '|' . (string) $channel );
71 +function openstation_debug_transient_key( $session_id, $channel ) {
72 + return 'openstation_dbg_' . md5( (string) $session_id . '|' . (string) $channel );
77 73 }
78 74
79 75 /**
80 76 * Read the debug session id from the current request's headers.
@@ -88,13 +84,11 @@
88 84 * filter (`sanitize_key()` would lowercase, breaking UUID v4
89 85 * round-trips); values longer than 64 characters are rejected —
90 86 * a tight gate for `crypto.randomUUID()`-shaped ids.
91 87 *
92 - * @since 0.6.0
93 - *
94 88 * @return string Session id, or '' when absent / invalid.
95 89 */
96 -function desktop_mode_debug_session_for_request() {
90 +function openstation_debug_session_for_request() {
97 91 $raw = '';
98 92 if ( isset( $_SERVER['HTTP_X_WP_DEBUG_SESSION'] ) ) {
99 93 $raw = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_WP_DEBUG_SESSION'] ) );
100 94 }
@@ -115,13 +109,11 @@
115 109 * Publish a payload onto a (session, channel).
116 110 *
117 111 * The newest event is appended to the ring buffer; once the cap is
118 112 * reached, the oldest events are dropped FIFO. Fires the
119 - * `desktop_mode_debug_publish` action so observability widgets can
113 + * `openstation_debug_publish` action so observability widgets can
120 114 * tail the stream synchronously without going through the REST poll.
121 115 *
122 - * @since 0.6.0
123 - *
124 116 * @param string $session_id Session id from the client.
125 117 * @param string $channel Channel name. Free-form; convention is
126 118 * lowercase ASCII (e.g. `'query'`,
127 119 * `'log'`, `'rest_timing'`).
@@ -129,15 +121,15 @@
129 121 * @return bool True when the event was appended (queued for storage);
130 122 * false only when `$session_id` or `$channel` is empty.
131 123 * `set_transient()` failures are not detected.
132 124 */
133 -function desktop_mode_debug_publish( $session_id, $channel, $payload ) {
125 +function openstation_debug_publish( $session_id, $channel, $payload ) {
134 126 $session_id = (string) $session_id;
135 127 $channel = (string) $channel;
136 128 if ( '' === $session_id || '' === $channel ) {
137 129 return false;
138 130 }
139 - $key = desktop_mode_debug_transient_key( $session_id, $channel );
131 + $key = openstation_debug_transient_key( $session_id, $channel );
140 132 $existing = get_transient( $key );
141 133 if ( ! is_array( $existing ) ) {
142 134 $existing = array(
143 135 'next_id' => 0,
@@ -143,11 +135,11 @@
143 135 'next_id' => 0,
144 136 'events' => array(),
145 137 );
146 138 }
147 - $next_id = isset( $existing['next_id'] ) ? (int) $existing['next_id'] : 0;
148 - $next_id++;
149 - $existing['next_id'] = $next_id;
139 + $next_id = isset( $existing['next_id'] ) ? (int) $existing['next_id'] : 0;
140 + ++$next_id;
141 + $existing['next_id'] = $next_id;
150 142 $existing['events'][] = array(
151 143 'id' => $next_id,
152 144 't' => (int) round( microtime( true ) * 1000 ),
153 145 'channel' => $channel,
@@ -152,16 +144,16 @@
152 144 't' => (int) round( microtime( true ) * 1000 ),
153 145 'channel' => $channel,
154 146 'payload' => $payload,
155 147 );
156 - $max = (int) apply_filters( 'desktop_mode_debug_ring_size', DESKTOP_MODE_DEBUG_RING_SIZE );
148 + $max = (int) apply_filters( 'openstation_debug_ring_size', OPENSTATION_DEBUG_RING_SIZE );
157 149 if ( $max < 1 ) {
158 - $max = DESKTOP_MODE_DEBUG_RING_SIZE;
150 + $max = OPENSTATION_DEBUG_RING_SIZE;
159 151 }
160 152 if ( count( $existing['events'] ) > $max ) {
161 153 $existing['events'] = array_slice( $existing['events'], -$max );
162 154 }
163 - set_transient( $key, $existing, DESKTOP_MODE_DEBUG_SESSION_TTL );
155 + set_transient( $key, $existing, OPENSTATION_DEBUG_SESSION_TTL );
164 156
165 157 /**
166 158 * Fires after a debug event is appended to the ring buffer.
167 159 *
@@ -168,15 +160,13 @@
168 160 * Lets observability hooks tail the stream synchronously instead
169 161 * of polling the REST endpoint. The arguments mirror the JS-side
170 162 * `DebugEvent` shape minus the auto-assigned id / timestamp.
171 163 *
172 - * @since 0.6.0
173 - *
174 164 * @param string $session_id Session id from the publishing call.
175 165 * @param string $channel Channel name.
176 166 * @param mixed $payload Published payload.
177 167 */
178 - do_action( 'desktop_mode_debug_publish', $session_id, $channel, $payload );
168 + do_action( 'openstation_debug_publish', $session_id, $channel, $payload );
179 169 return true;
180 170 }
181 171
182 172 /**
@@ -186,19 +176,20 @@
186 176 * Returns `array( 'events' => [], 'cursor' => N )`. The cursor is the
187 177 * highest event id seen across all returned events; clients pass it
188 178 * back as `since` on the next poll.
189 179 *
190 - * @since 0.6.0
191 - *
192 180 * @param string $session_id Session id.
193 181 * @param int $since Highest id the client has seen.
194 182 * @param string|null $channel Optional channel filter.
195 183 * @return array
196 184 */
197 -function desktop_mode_debug_drain( $session_id, $since = 0, $channel = null ) {
185 +function openstation_debug_drain( $session_id, $since = 0, $channel = null ) {
198 186 $session_id = (string) $session_id;
199 187 if ( '' === $session_id ) {
200 - return array( 'events' => array(), 'cursor' => (int) $since );
188 + return array(
189 + 'events' => array(),
190 + 'cursor' => (int) $since,
191 + );
201 192 }
202 193
203 194 $channels = array();
204 195 if ( null !== $channel && '' !== (string) $channel ) {
@@ -207,11 +198,11 @@
207 198 // Without a channel filter the client wants every channel for
208 199 // this session. We don't keep an index of channels per session
209 200 // (would double-write on every publish); instead we let the
210 201 // caller pass a list, OR fan out via the
211 - // `desktop_mode_debug_channels` filter for plugins that know
202 + // `openstation_debug_channels` filter for plugins that know
212 203 // their full set up-front.
213 - $declared = apply_filters( 'desktop_mode_debug_channels', array(), $session_id );
204 + $declared = apply_filters( 'openstation_debug_channels', array(), $session_id );
214 205 if ( is_array( $declared ) ) {
215 206 foreach ( $declared as $ch ) {
216 207 if ( is_string( $ch ) && '' !== $ch ) {
217 208 $channels[] = $ch;
@@ -222,9 +213,9 @@
222 213
223 214 $cursor = (int) $since;
224 215 $out = array();
225 216 foreach ( $channels as $ch ) {
226 - $key = desktop_mode_debug_transient_key( $session_id, $ch );
217 + $key = openstation_debug_transient_key( $session_id, $ch );
227 218 $data = get_transient( $key );
228 219 if ( ! is_array( $data ) || empty( $data['events'] ) ) {
229 220 continue;
230 221 }
@@ -250,9 +241,12 @@
250 241 static function ( $a, $b ) {
251 242 return ( (int) $a['id'] ) - ( (int) $b['id'] );
252 243 }
253 244 );
254 - return array( 'events' => $out, 'cursor' => $cursor );
245 + return array(
246 + 'events' => $out,
247 + 'cursor' => $cursor,
248 + );
255 249 }
256 250
257 251 /**
258 252 * REST: GET /desktop-mode/v1/debug
@@ -258,17 +252,15 @@
258 252 * REST: GET /desktop-mode/v1/debug
259 253 *
260 254 * Returns events newer than `since` for the given session id.
261 255 * Supports both `channel=foo` (single) and `channels[]=foo&channels[]=bar`
262 - * (list); falls back to the `desktop_mode_debug_channels` filter
256 + * (list); falls back to the `openstation_debug_channels` filter
263 257 * when no channel param is supplied.
264 258 *
265 - * @since 0.6.0
266 - *
267 259 * @param WP_REST_Request $request REST request.
268 260 * @return WP_REST_Response
269 261 */
270 -function desktop_mode_rest_debug_drain( WP_REST_Request $request ) {
262 +function openstation_rest_debug_drain( WP_REST_Request $request ) {
271 263 $session_id = (string) $request->get_param( 'sessionId' );
272 264 $since = (int) $request->get_param( 'since' );
273 265 $channel = $request->get_param( 'channel' );
274 266 $channels = $request->get_param( 'channels' );
@@ -274,12 +266,12 @@
274 266 $channels = $request->get_param( 'channels' );
275 267
276 268 if ( is_array( $channels ) && count( $channels ) > 0 ) {
277 269 // Multi-channel drain — concatenate the per-channel results.
278 - $cursor = $since;
270 + $cursor = $since;
279 271 $all_events = array();
280 272 foreach ( $channels as $ch ) {
281 - $result = desktop_mode_debug_drain( $session_id, $since, (string) $ch );
273 + $result = openstation_debug_drain( $session_id, $since, (string) $ch );
282 274 foreach ( $result['events'] as $ev ) {
283 275 $all_events[] = $ev;
284 276 }
285 277 if ( $result['cursor'] > $cursor ) {
@@ -299,9 +291,9 @@
299 291 )
300 292 );
301 293 }
302 294
303 - $result = desktop_mode_debug_drain(
295 + $result = openstation_debug_drain(
304 296 $session_id,
305 297 $since,
306 298 is_string( $channel ) ? $channel : null
307 299 );
@@ -313,32 +305,26 @@
313 305 *
314 306 * Logged-in admins only — debug data exposes internal request shapes
315 307 * that should never leak to lower-privileged users. Plugins that need
316 308 * to relax this for a specific session can hook the
317 - * `desktop_mode_debug_rest_permission` filter (filters TRUE/FALSE).
309 + * `openstation_debug_rest_permission` filter (filters TRUE/FALSE).
318 310 *
319 - * @since 0.6.0
320 - *
321 311 * @return bool
322 312 */
323 -function desktop_mode_rest_debug_permission() {
313 +function openstation_rest_debug_permission() {
324 314 $allowed = is_user_logged_in() && current_user_can( 'manage_options' );
325 315 /**
326 316 * Filter the permission decision for the debug REST endpoint.
327 317 *
328 - * @since 0.6.0
329 - *
330 318 * @param bool $allowed Default: caller is a logged-in admin.
331 319 */
332 - return (bool) apply_filters( 'desktop_mode_debug_rest_permission', $allowed );
320 + return (bool) apply_filters( 'openstation_debug_rest_permission', $allowed );
333 321 }
334 322
335 323 /**
336 324 * Register the debug REST routes.
337 - *
338 - * @since 0.6.0
339 325 */
340 -function desktop_mode_register_debug_rest_routes() {
326 +function openstation_register_debug_rest_routes() {
341 327 register_rest_route(
342 328 'desktop-mode/v1',
343 329 '/debug',
344 330 array(
@@ -343,10 +329,10 @@
343 329 '/debug',
344 330 array(
345 331 array(
346 332 'methods' => WP_REST_Server::READABLE,
347 - 'callback' => 'desktop_mode_rest_debug_drain',
348 - 'permission_callback' => 'desktop_mode_rest_debug_permission',
333 + 'callback' => 'openstation_rest_debug_drain',
334 + 'permission_callback' => 'openstation_rest_debug_permission',
349 335 'args' => array(
350 336 'sessionId' => array(
351 337 'required' => true,
352 338 'type' => 'string',
@@ -366,5 +352,5 @@
366 352 ),
367 353 )
368 354 );
369 355 }
370 -add_action( 'rest_api_init', 'desktop_mode_register_debug_rest_routes' );
356 +add_action( 'rest_api_init', 'openstation_register_debug_rest_routes' );