| @@ -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' ); | |