@adonis-agora/telescope 0.10.0 → 0.12.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/CHANGELOG.md +68 -0
- package/dist/providers/telescope_ui_provider.d.ts.map +1 -1
- package/dist/providers/telescope_ui_provider.js +46 -3
- package/dist/providers/telescope_ui_provider.js.map +1 -1
- package/dist/src/ai/index.d.ts +1 -1
- package/dist/src/ai/index.js +1 -1
- package/dist/src/alerts/exception_source.d.ts.map +1 -1
- package/dist/src/alerts/exception_source.js +2 -4
- package/dist/src/alerts/exception_source.js.map +1 -1
- package/dist/src/alerts/index.d.ts +1 -1
- package/dist/src/alerts/index.js +1 -1
- package/dist/src/context_accessor.d.ts +13 -0
- package/dist/src/context_accessor.d.ts.map +1 -1
- package/dist/src/context_accessor.js +20 -0
- package/dist/src/context_accessor.js.map +1 -1
- package/dist/src/entry.d.ts +13 -0
- package/dist/src/entry.d.ts.map +1 -1
- package/dist/src/entry.js +15 -0
- package/dist/src/entry.js.map +1 -1
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/index.d.ts +1 -1
- package/dist/src/mcp/index.js +1 -1
- package/dist/src/metrics/metrics_service.d.ts +13 -0
- package/dist/src/metrics/metrics_service.d.ts.map +1 -1
- package/dist/src/metrics/metrics_service.js +23 -4
- package/dist/src/metrics/metrics_service.js.map +1 -1
- package/dist/src/metrics/pulse.d.ts.map +1 -1
- package/dist/src/metrics/pulse.js +5 -2
- package/dist/src/metrics/pulse.js.map +1 -1
- package/dist/src/metrics/stats.d.ts.map +1 -1
- package/dist/src/metrics/stats.js +6 -2
- package/dist/src/metrics/stats.js.map +1 -1
- package/dist/src/profiling/index.d.ts +1 -1
- package/dist/src/profiling/index.js +1 -1
- package/dist/src/request_watcher.d.ts +46 -8
- package/dist/src/request_watcher.d.ts.map +1 -1
- package/dist/src/request_watcher.js +63 -16
- package/dist/src/request_watcher.js.map +1 -1
- package/dist/src/ui/access_denied_page.d.ts +102 -0
- package/dist/src/ui/access_denied_page.d.ts.map +1 -0
- package/dist/src/ui/access_denied_page.js +266 -0
- package/dist/src/ui/access_denied_page.js.map +1 -0
- package/dist/src/ui/define_config.d.ts +27 -0
- package/dist/src/ui/define_config.d.ts.map +1 -1
- package/dist/src/ui/define_config.js +1 -0
- package/dist/src/ui/define_config.js.map +1 -1
- package/dist/src/ui/guard.d.ts +29 -0
- package/dist/src/ui/guard.d.ts.map +1 -1
- package/dist/src/ui/guard.js +49 -0
- package/dist/src/ui/guard.js.map +1 -1
- package/dist/src/ui/index.d.ts +6 -4
- package/dist/src/ui/index.d.ts.map +1 -1
- package/dist/src/ui/index.js +4 -2
- package/dist/src/ui/index.js.map +1 -1
- package/dist/src/ui/login_page.d.ts +24 -11
- package/dist/src/ui/login_page.d.ts.map +1 -1
- package/dist/src/ui/login_page.js +29 -41
- package/dist/src/ui/login_page.js.map +1 -1
- package/dist/src/watchers/index.d.ts +1 -1
- package/dist/src/watchers/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,27 +1,26 @@
|
|
|
1
|
+
import { escapeHtml } from './access_denied_page.js';
|
|
2
|
+
import { sanitizeReturnTo } from './auth.js';
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `
|
|
7
|
-
* into the HTML), so this function's only per-request-ish input is `basePath` — a developer-
|
|
8
|
-
* controlled config value, not user input — and the page body is otherwise a static template.
|
|
9
|
-
* This sidesteps HTML-escaping entirely: there is no reflected query-param interpolation surface
|
|
10
|
-
* to get wrong.
|
|
11
|
-
*
|
|
12
|
-
* The visual language (dark zinc card, mono type, emerald accent) mirrors the Agora consoles so
|
|
13
|
-
* they feel like one family. The submit flow POSTs JSON via `fetch` and follows the JSON
|
|
14
|
-
* `redirectTo` it gets back (rather than a classic form POST + server redirect), which is why the
|
|
15
|
-
* markup keeps its own `<script>`.
|
|
16
|
-
*
|
|
17
|
-
* The password input has NO `required` attribute and the value is forwarded AS-IS (empty string
|
|
18
|
-
* when blank): the host's `login` hook — not this page — decides whether a password matters, so an
|
|
19
|
-
* email-only host (gate on username, ignore password) works with the same page as a host with real
|
|
20
|
-
* passwords.
|
|
4
|
+
* JSON for embedding INSIDE an inline `<script>`: `JSON.stringify` alone leaves `</script>` (and
|
|
5
|
+
* `<!--`) untouched, and the HTML parser ends the script element on the first `</script>` it sees
|
|
6
|
+
* regardless of JavaScript string boundaries — so a `returnTo` of `/x</script><script>…` would run.
|
|
7
|
+
* Escaping the angle brackets (and `&`, plus the two line terminators JSON allows but JS doesn't)
|
|
8
|
+
* as `\uXXXX` keeps the value byte-identical once parsed and inert to the HTML parser.
|
|
21
9
|
*/
|
|
22
|
-
|
|
10
|
+
function jsonForScript(value) {
|
|
11
|
+
return JSON.stringify(value)
|
|
12
|
+
.replaceAll('<', '\\u003c')
|
|
13
|
+
.replaceAll('>', '\\u003e')
|
|
14
|
+
.replaceAll('&', '\\u0026')
|
|
15
|
+
.replaceAll('\u2028', '\\u2028')
|
|
16
|
+
.replaceAll('\u2029', '\\u2029');
|
|
17
|
+
}
|
|
18
|
+
export function renderLoginPage(basePath, options = {}) {
|
|
23
19
|
const loginAction = `${basePath}/login`;
|
|
24
20
|
const defaultReturnTo = basePath === '' ? '/' : basePath;
|
|
21
|
+
const returnTo = sanitizeReturnTo(options.returnTo, defaultReturnTo);
|
|
22
|
+
const nonceAttr = options.nonce !== undefined ? ` nonce="${escapeHtml(options.nonce)}"` : '';
|
|
23
|
+
const errorStyle = options.error ? ' style="display:block"' : '';
|
|
25
24
|
return `<!doctype html>
|
|
26
25
|
<html lang="en">
|
|
27
26
|
<head>
|
|
@@ -29,7 +28,7 @@ export function renderLoginPage(basePath) {
|
|
|
29
28
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
30
29
|
<meta name="robots" content="noindex, nofollow" />
|
|
31
30
|
<title>Sign in — Telescope</title>
|
|
32
|
-
<style>
|
|
31
|
+
<style${nonceAttr}>
|
|
33
32
|
:root { color-scheme: dark; }
|
|
34
33
|
* { box-sizing: border-box; }
|
|
35
34
|
body {
|
|
@@ -104,7 +103,8 @@ export function renderLoginPage(basePath) {
|
|
|
104
103
|
<body>
|
|
105
104
|
<div class="card">
|
|
106
105
|
<p class="brand">Telescope</p>
|
|
107
|
-
<form id="login-form" autocomplete="on">
|
|
106
|
+
<form id="login-form" method="post" action="${escapeHtml(loginAction)}" autocomplete="on">
|
|
107
|
+
<input type="hidden" name="returnTo" value="${escapeHtml(returnTo)}" />
|
|
108
108
|
<label>
|
|
109
109
|
<span class="field-label">Username</span>
|
|
110
110
|
<input id="username" name="username" type="text" autocomplete="username" required autofocus />
|
|
@@ -113,41 +113,29 @@ export function renderLoginPage(basePath) {
|
|
|
113
113
|
<span class="field-label">Password</span>
|
|
114
114
|
<input id="password" name="password" type="password" autocomplete="current-password" />
|
|
115
115
|
</label>
|
|
116
|
-
<p id="error" role="alert">Invalid username or password.</p>
|
|
116
|
+
<p id="error" role="alert"${errorStyle}>Invalid username or password.</p>
|
|
117
117
|
<button id="submit" type="submit">Sign in</button>
|
|
118
118
|
</form>
|
|
119
119
|
</div>
|
|
120
|
-
<script>
|
|
120
|
+
<script${nonceAttr}>
|
|
121
121
|
(function () {
|
|
122
|
-
var LOGIN_ACTION = ${
|
|
123
|
-
var
|
|
124
|
-
var params = new URLSearchParams(window.location.search);
|
|
122
|
+
var LOGIN_ACTION = ${jsonForScript(loginAction)};
|
|
123
|
+
var RETURN_TO = ${jsonForScript(returnTo)};
|
|
125
124
|
var errorBox = document.getElementById('error');
|
|
126
|
-
if (params.get('error')) errorBox.style.display = 'block';
|
|
127
|
-
|
|
128
|
-
function sameOriginReturnTo(value) {
|
|
129
|
-
if (typeof value !== 'string' || value === '') return DEFAULT_RETURN_TO;
|
|
130
|
-
if (value.charAt(0) !== '/' || value.charAt(1) === '/' || value.indexOf('://') !== -1) {
|
|
131
|
-
return DEFAULT_RETURN_TO;
|
|
132
|
-
}
|
|
133
|
-
return value;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
125
|
var form = document.getElementById('login-form');
|
|
137
126
|
var submitButton = document.getElementById('submit');
|
|
138
127
|
form.addEventListener('submit', function (event) {
|
|
139
128
|
event.preventDefault();
|
|
140
129
|
submitButton.disabled = true;
|
|
141
130
|
errorBox.style.display = 'none';
|
|
142
|
-
var returnTo = sameOriginReturnTo(params.get('returnTo'));
|
|
143
131
|
fetch(LOGIN_ACTION, {
|
|
144
132
|
method: 'POST',
|
|
145
|
-
headers: { 'content-type': 'application/json' },
|
|
133
|
+
headers: { 'content-type': 'application/json', accept: 'application/json' },
|
|
146
134
|
credentials: 'same-origin',
|
|
147
135
|
body: JSON.stringify({
|
|
148
136
|
username: document.getElementById('username').value,
|
|
149
137
|
password: document.getElementById('password').value,
|
|
150
|
-
returnTo:
|
|
138
|
+
returnTo: RETURN_TO,
|
|
151
139
|
}),
|
|
152
140
|
})
|
|
153
141
|
.then(function (response) {
|
|
@@ -155,7 +143,7 @@ export function renderLoginPage(basePath) {
|
|
|
155
143
|
return response.json();
|
|
156
144
|
})
|
|
157
145
|
.then(function (data) {
|
|
158
|
-
window.location.href = data.redirectTo ||
|
|
146
|
+
window.location.href = data.redirectTo || RETURN_TO;
|
|
159
147
|
})
|
|
160
148
|
.catch(function () {
|
|
161
149
|
errorBox.style.display = 'block';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login_page.js","sourceRoot":"","sources":["../../../src/ui/login_page.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"login_page.js","sourceRoot":"","sources":["../../../src/ui/login_page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAqC7C;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC;SAC/B,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAO,GAAqB,EAAE;IAC9E,MAAM,WAAW,GAAG,GAAG,QAAQ,QAAQ,CAAC;IACxC,MAAM,eAAe,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;IACzD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7F,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO;;;;;;;QAOD,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDA2EiC,UAAU,CAAC,WAAW,CAAC;oDACrB,UAAU,CAAC,QAAQ,CAAC;;;;;;;;;kCAStC,UAAU;;;;SAInC,SAAS;;uBAEK,aAAa,CAAC,WAAW,CAAC;oBAC7B,aAAa,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiCnC,CAAC;AACT,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Keep in sync with this package's `version` in package.json. */
|
|
2
|
-
export declare const VERSION = "0.
|
|
2
|
+
export declare const VERSION = "0.12.0";
|
|
3
3
|
export type { CacheEntryContent, CacheEventLike, CacheOperation } from './cache_watcher.js';
|
|
4
4
|
export { buildCacheEntry, CACHE_EVENTS, CacheWatcher } from './cache_watcher.js';
|
|
5
5
|
export { nextCronRunMs } from './cron_next_run.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Keep in sync with this package's `version` in package.json. */
|
|
2
|
-
export const VERSION = '0.
|
|
2
|
+
export const VERSION = '0.12.0';
|
|
3
3
|
// — cache watcher —
|
|
4
4
|
export { buildCacheEntry, CACHE_EVENTS, CacheWatcher } from './cache_watcher.js';
|
|
5
5
|
export { nextCronRunMs } from './cron_next_run.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/telescope",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Laravel Telescope-style headless observability for AdonisJS — records HTTP requests and every Agora diagnostics event as queryable entries, plus opt-in subpaths for per-technology watchers, a web dashboard, AI exception diagnosis, and alerting.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|