@adonis-agora/agent-dashboard 0.4.0 → 0.6.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 +42 -0
- package/README.md +15 -1
- package/dist/providers/agent_dashboard_provider.d.ts +10 -0
- package/dist/providers/agent_dashboard_provider.d.ts.map +1 -1
- package/dist/providers/agent_dashboard_provider.js +11 -3
- package/dist/providers/agent_dashboard_provider.js.map +1 -1
- package/dist/spa/assets/index-CkOAJYbh.js +9 -0
- package/dist/spa/index.html +1 -1
- package/dist/src/client/agent-client.d.ts +9 -1
- package/dist/src/client/agent-client.d.ts.map +1 -1
- package/dist/src/client/agent-client.js +13 -0
- package/dist/src/client/agent-client.js.map +1 -1
- package/dist/src/client/types.d.ts +55 -1
- package/dist/src/client/types.d.ts.map +1 -1
- package/package.json +19 -18
- package/dist/spa/assets/index-DR5D-Xzw.js +0 -9
- package/dist/src/server/define_config.d.ts +0 -69
- package/dist/src/server/define_config.d.ts.map +0 -1
- package/dist/src/server/define_config.js +0 -56
- package/dist/src/server/define_config.js.map +0 -1
- package/dist/src/server/gate.d.ts +0 -33
- package/dist/src/server/gate.d.ts.map +0 -1
- package/dist/src/server/gate.js +0 -52
- package/dist/src/server/gate.js.map +0 -1
- package/dist/src/server/paths.d.ts +0 -35
- package/dist/src/server/paths.d.ts.map +0 -1
- package/dist/src/server/paths.js +0 -94
- package/dist/src/server/paths.js.map +0 -1
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { Actor, AgentGovernanceAuthorize } from '@adonis-agora/agent';
|
|
2
|
-
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
|
-
/**
|
|
4
|
-
* An extra authorization gate for the dashboard, run AFTER the agent config's `actorResolver` has
|
|
5
|
-
* resolved the caller. Return `false` (or throw) to deny — the request gets `403`. The governance
|
|
6
|
-
* read-model the SPA serves spans EVERY actor's spend/usage, so most apps restrict the console beyond
|
|
7
|
-
* mere authentication, e.g. `(actor) => actor.roles?.includes('ADMIN') ?? false`.
|
|
8
|
-
*/
|
|
9
|
-
export type AgentDashboardAuthorize = (actor: Actor, ctx: HttpContext) => boolean | Promise<boolean>;
|
|
10
|
-
/**
|
|
11
|
-
* Optional `config('agent').dashboard` block. The dashboard reuses the agent config's `path` and
|
|
12
|
-
* `actorResolver` (so it sits behind the SAME actor gating as the governance routes); this block
|
|
13
|
-
* toggles it on/off, optionally overrides the mount path, and optionally adds an `authorize` gate.
|
|
14
|
-
*/
|
|
15
|
-
export interface AgentDashboardConfig {
|
|
16
|
-
/**
|
|
17
|
-
* Mount the SPA. Default `true` — set `false` to keep the routes off entirely. Note `true` is
|
|
18
|
-
* necessary but not sufficient: the console also needs the agent's `governanceAuthorize` gate, see
|
|
19
|
-
* {@link decideDashboardMount}.
|
|
20
|
-
*/
|
|
21
|
-
enabled?: boolean;
|
|
22
|
-
/** Override the mount path. Default `<agentPath>/dashboard`. */
|
|
23
|
-
path?: string;
|
|
24
|
-
/**
|
|
25
|
-
* Extra authorization run after the actor resolves. Return `false` to deny (`403`). Omit to allow
|
|
26
|
-
* any resolved actor (the default) — note this is only an EXTRA gate on the SPA shell; whether the
|
|
27
|
-
* console mounts at all, and whether its data is readable, is decided by the agent config's
|
|
28
|
-
* `governanceAuthorize`.
|
|
29
|
-
*/
|
|
30
|
-
authorize?: AgentDashboardAuthorize;
|
|
31
|
-
}
|
|
32
|
-
export interface ResolvedAgentDashboardConfig {
|
|
33
|
-
enabled: boolean;
|
|
34
|
-
path?: string;
|
|
35
|
-
authorize?: AgentDashboardAuthorize;
|
|
36
|
-
}
|
|
37
|
-
/** Fill defaults for the optional dashboard config block. */
|
|
38
|
-
export declare function resolveDashboardConfig(config: AgentDashboardConfig | undefined): ResolvedAgentDashboardConfig;
|
|
39
|
-
/** Whether the provider registers the console's routes, and (when it refuses) what to say about it. */
|
|
40
|
-
export type DashboardMountDecision = {
|
|
41
|
-
mount: true;
|
|
42
|
-
} | {
|
|
43
|
-
mount: false;
|
|
44
|
-
reason: 'disabled';
|
|
45
|
-
} | {
|
|
46
|
-
mount: false;
|
|
47
|
-
reason: 'no-governance-gate';
|
|
48
|
-
warning: string;
|
|
49
|
-
} | {
|
|
50
|
-
mount: false;
|
|
51
|
-
reason: 'no-governance-queries';
|
|
52
|
-
warning: string;
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Decide whether to register the console's routes at all — the router-free core of the provider's
|
|
56
|
-
* mount check, extracted so it can be unit tested without booting an app.
|
|
57
|
-
*
|
|
58
|
-
* The console is a pure consumer of the agent's cross-actor `/agent/governance/*` read routes, and
|
|
59
|
-
* those routes are not mounted unless the agent config carries a `governanceAuthorize` gate. Serving
|
|
60
|
-
* a shell that can only 404 its own data is worse than not serving it: the failure shows up as seven
|
|
61
|
-
* dead panels at click time with nothing anywhere explaining why. So the console follows the same
|
|
62
|
-
* fail-closed-by-omission rule one layer down — no gate, no routes — and says so at boot.
|
|
63
|
-
*
|
|
64
|
-
* This costs nothing that still works: every app affected is an app whose console is ALREADY dead in
|
|
65
|
-
* every view but Quota. `dashboard.authorize` is deliberately NOT the trigger; it gates the shell,
|
|
66
|
-
* not the data, and an app can set it and still have a console with nothing to render.
|
|
67
|
-
*/
|
|
68
|
-
export declare function decideDashboardMount(enabled: boolean, governanceAuthorize: AgentGovernanceAuthorize | undefined, governanceQueries?: unknown): DashboardMountDecision;
|
|
69
|
-
//# sourceMappingURL=define_config.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,WAAW,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,6DAA6D;AAC7D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,oBAAoB,GAAG,SAAS,GACvC,4BAA4B,CAK9B;AAED,uGAAuG;AACvG,MAAM,MAAM,sBAAsB,GAC9B;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,uBAAuB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAoBvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,mBAAmB,EAAE,wBAAwB,GAAG,SAAS,EACzD,iBAAiB,CAAC,EAAE,OAAO,GAC1B,sBAAsB,CAgBxB"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/** Fill defaults for the optional dashboard config block. */
|
|
2
|
-
export function resolveDashboardConfig(config) {
|
|
3
|
-
const resolved = { enabled: config?.enabled ?? true };
|
|
4
|
-
if (config?.path !== undefined)
|
|
5
|
-
resolved.path = config.path;
|
|
6
|
-
if (config?.authorize !== undefined)
|
|
7
|
-
resolved.authorize = config.authorize;
|
|
8
|
-
return resolved;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* The exact wording the provider logs when it declines to mount. Mirrors the agent provider's own
|
|
12
|
-
* governance boot warning — same three facts, same vocabulary — so a reader who sees one recognises
|
|
13
|
-
* the other.
|
|
14
|
-
*/
|
|
15
|
-
const NO_GOVERNANCE_GATE_WARNING = '[@adonis-agora/agent-dashboard] the governance console was NOT mounted: every panel but Quota reads the cross-actor `/agent/governance/*` routes, and those are themselves not mounted because no `governanceAuthorize` gate is configured — so the console would load and then fail on every panel. Set `governanceAuthorize` in config/agent.ts (e.g. an ADMIN check) to mount the routes and this console gated, or `governanceAuthorize: () => true` to deliberately restore the old behaviour of letting ANY authenticated actor read them. `GET /agent/approvals/mine` is unaffected — it stays mounted and scoped to the calling actor. To keep the console off on purpose and silence this, set `dashboard: { enabled: false }`.';
|
|
16
|
-
/**
|
|
17
|
-
* The wording logged when the read-model itself was turned off. Deliberately distinct from
|
|
18
|
-
* {@link NO_GOVERNANCE_GATE_WARNING}: both produce the same dead console, and an operator staring at
|
|
19
|
-
* a 404 must be able to tell from the log ALONE which of the two knobs is responsible. A shared
|
|
20
|
-
* "governance is not configured" message would recreate exactly the diagnosability problem this
|
|
21
|
-
* check exists to remove.
|
|
22
|
-
*/
|
|
23
|
-
const NO_GOVERNANCE_QUERIES_WARNING = '[@adonis-agora/agent-dashboard] the governance console was NOT mounted: `governanceQueries` is set to `false` in config/agent.ts, so the cross-actor read-model was never built and the `/agent/governance/*` routes it serves do not exist — the console would load and then fail on every panel but Quota. A `governanceAuthorize` gate is NOT the missing piece here; it is already configured. Remove `governanceQueries: false` (omit it to get the Lucid read-model when the main store is Lucid, or pass a store/factory explicitly) to mount the read-model and this console. To keep the console off on purpose and silence this, set `dashboard: { enabled: false }`.';
|
|
24
|
-
/**
|
|
25
|
-
* Decide whether to register the console's routes at all — the router-free core of the provider's
|
|
26
|
-
* mount check, extracted so it can be unit tested without booting an app.
|
|
27
|
-
*
|
|
28
|
-
* The console is a pure consumer of the agent's cross-actor `/agent/governance/*` read routes, and
|
|
29
|
-
* those routes are not mounted unless the agent config carries a `governanceAuthorize` gate. Serving
|
|
30
|
-
* a shell that can only 404 its own data is worse than not serving it: the failure shows up as seven
|
|
31
|
-
* dead panels at click time with nothing anywhere explaining why. So the console follows the same
|
|
32
|
-
* fail-closed-by-omission rule one layer down — no gate, no routes — and says so at boot.
|
|
33
|
-
*
|
|
34
|
-
* This costs nothing that still works: every app affected is an app whose console is ALREADY dead in
|
|
35
|
-
* every view but Quota. `dashboard.authorize` is deliberately NOT the trigger; it gates the shell,
|
|
36
|
-
* not the data, and an app can set it and still have a console with nothing to render.
|
|
37
|
-
*/
|
|
38
|
-
export function decideDashboardMount(enabled, governanceAuthorize, governanceQueries) {
|
|
39
|
-
if (!enabled)
|
|
40
|
-
return { mount: false, reason: 'disabled' };
|
|
41
|
-
if (governanceAuthorize === undefined) {
|
|
42
|
-
return { mount: false, reason: 'no-governance-gate', warning: NO_GOVERNANCE_GATE_WARNING };
|
|
43
|
-
}
|
|
44
|
-
// ONLY an explicit `false` is decidable here. `undefined` does NOT mean "no read-model": the agent
|
|
45
|
-
// provider's `#resolveGovernance` defaults it to the Lucid read-model whenever the main store is
|
|
46
|
-
// Lucid, and reproducing that resolution would duplicate provider logic in the dashboard.
|
|
47
|
-
if (governanceQueries === false) {
|
|
48
|
-
return {
|
|
49
|
-
mount: false,
|
|
50
|
-
reason: 'no-governance-queries',
|
|
51
|
-
warning: NO_GOVERNANCE_QUERIES_WARNING,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
return { mount: true };
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=define_config.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AA2CA,6DAA6D;AAC7D,MAAM,UAAU,sBAAsB,CACpC,MAAwC;IAExC,MAAM,QAAQ,GAAiC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;IACpF,IAAI,MAAM,EAAE,IAAI,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAC5D,IAAI,MAAM,EAAE,SAAS,KAAK,SAAS;QAAE,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IAC3E,OAAO,QAAQ,CAAC;AAClB,CAAC;AASD;;;;GAIG;AACH,MAAM,0BAA0B,GAC9B,0sBAA0sB,CAAC;AAE7sB;;;;;;GAMG;AACH,MAAM,6BAA6B,GACjC,ipBAAipB,CAAC;AAEppB;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAgB,EAChB,mBAAyD,EACzD,iBAA2B;IAE3B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC1D,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;IAC7F,CAAC;IACD,mGAAmG;IACnG,iGAAiG;IACjG,0FAA0F;IAC1F,IAAI,iBAAiB,KAAK,KAAK,EAAE,CAAC;QAChC,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,uBAAuB;YAC/B,OAAO,EAAE,6BAA6B;SACvC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { ActorResolver } from '@adonis-agora/agent';
|
|
2
|
-
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
|
-
import type { AgentDashboardAuthorize } from './define_config.js';
|
|
4
|
-
/** The outcome of the dashboard access gate: proceed, or deny with an HTTP status + message. */
|
|
5
|
-
export type DashboardGateVerdict = {
|
|
6
|
-
ok: true;
|
|
7
|
-
} | {
|
|
8
|
-
ok: false;
|
|
9
|
-
status: 401 | 403;
|
|
10
|
-
error: string;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Decide whether a request may reach the dashboard, WITHOUT touching the response — so it is unit
|
|
14
|
-
* testable free of the AdonisJS router/app: resolve the actor through the agent config's resolver
|
|
15
|
-
* (missing/failed → `401`), then run the optional `authorize` gate over the resolved actor
|
|
16
|
-
* (denied/threw → `403`).
|
|
17
|
-
*
|
|
18
|
-
* This gates the SPA **shell**, and only the shell. It is NOT what decides whether the console's data
|
|
19
|
-
* is readable, and it is no longer the last line of defence it once had to be:
|
|
20
|
-
*
|
|
21
|
-
* - Whether the console mounts at all is decided earlier, by {@link decideDashboardMount} — the
|
|
22
|
-
* routes are not registered unless the agent config carries a `governanceAuthorize` gate AND its
|
|
23
|
-
* `governanceQueries` read-model exists. So this function never runs for a console that could only
|
|
24
|
-
* 404 its own panels.
|
|
25
|
-
* - Whether the DATA is readable is decided by the agent's own `governanceAuthorize` on the
|
|
26
|
-
* `/agent/governance/*` routes, not here. Omitting `authorize` while a gate is configured leaves
|
|
27
|
-
* the shell open to any resolved actor but exposes no cross-actor data.
|
|
28
|
-
*
|
|
29
|
-
* Omitting BOTH the resolver and `authorize` would expose the shell to any request; the provider is
|
|
30
|
-
* expected to short-circuit on a missing resolver via the `401` here.
|
|
31
|
-
*/
|
|
32
|
-
export declare function evaluateDashboardGate(ctx: HttpContext, actorResolver: ActorResolver | undefined, authorize?: AgentDashboardAuthorize): Promise<DashboardGateVerdict>;
|
|
33
|
-
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../../src/server/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAElE,gGAAgG;AAChG,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,EAChB,aAAa,EAAE,aAAa,GAAG,SAAS,EACxC,SAAS,CAAC,EAAE,uBAAuB,GAClC,OAAO,CAAC,oBAAoB,CAAC,CA4B/B"}
|
package/dist/src/server/gate.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Decide whether a request may reach the dashboard, WITHOUT touching the response — so it is unit
|
|
3
|
-
* testable free of the AdonisJS router/app: resolve the actor through the agent config's resolver
|
|
4
|
-
* (missing/failed → `401`), then run the optional `authorize` gate over the resolved actor
|
|
5
|
-
* (denied/threw → `403`).
|
|
6
|
-
*
|
|
7
|
-
* This gates the SPA **shell**, and only the shell. It is NOT what decides whether the console's data
|
|
8
|
-
* is readable, and it is no longer the last line of defence it once had to be:
|
|
9
|
-
*
|
|
10
|
-
* - Whether the console mounts at all is decided earlier, by {@link decideDashboardMount} — the
|
|
11
|
-
* routes are not registered unless the agent config carries a `governanceAuthorize` gate AND its
|
|
12
|
-
* `governanceQueries` read-model exists. So this function never runs for a console that could only
|
|
13
|
-
* 404 its own panels.
|
|
14
|
-
* - Whether the DATA is readable is decided by the agent's own `governanceAuthorize` on the
|
|
15
|
-
* `/agent/governance/*` routes, not here. Omitting `authorize` while a gate is configured leaves
|
|
16
|
-
* the shell open to any resolved actor but exposes no cross-actor data.
|
|
17
|
-
*
|
|
18
|
-
* Omitting BOTH the resolver and `authorize` would expose the shell to any request; the provider is
|
|
19
|
-
* expected to short-circuit on a missing resolver via the `401` here.
|
|
20
|
-
*/
|
|
21
|
-
export async function evaluateDashboardGate(ctx, actorResolver, authorize) {
|
|
22
|
-
if (actorResolver === undefined) {
|
|
23
|
-
return { ok: false, status: 401, error: 'no actor resolver configured' };
|
|
24
|
-
}
|
|
25
|
-
let actor;
|
|
26
|
-
try {
|
|
27
|
-
actor = await actorResolver.resolve(ctx);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
return {
|
|
31
|
-
ok: false,
|
|
32
|
-
status: 401,
|
|
33
|
-
error: error instanceof Error ? error.message : 'unauthorized',
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
if (authorize !== undefined) {
|
|
37
|
-
try {
|
|
38
|
-
if (!(await authorize(actor, ctx))) {
|
|
39
|
-
return { ok: false, status: 403, error: 'forbidden' };
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
return {
|
|
44
|
-
ok: false,
|
|
45
|
-
status: 403,
|
|
46
|
-
error: error instanceof Error ? error.message : 'forbidden',
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return { ok: true };
|
|
51
|
-
}
|
|
52
|
-
//# sourceMappingURL=gate.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../src/server/gate.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAgB,EAChB,aAAwC,EACxC,SAAmC;IAEnC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC;IAC3E,CAAC;IACD,IAAI,KAAoD,CAAC;IACzD,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc;SAC/D,CAAC;IACJ,CAAC;IACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;gBACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;YACxD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;aAC5D,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure path/asset helpers for the dashboard provider — extracted so they can be unit-tested without
|
|
3
|
-
* booting an AdonisJS app. The provider composes these; it holds only the router wiring + I/O.
|
|
4
|
-
*/
|
|
5
|
-
/** Collapse duplicate slashes and strip leading/trailing ones: `/agent//` → `agent`. */
|
|
6
|
-
export declare function trimSlashes(path: string): string;
|
|
7
|
-
/** The agent API base as an absolute path with a single leading slash: `agent` → `/agent`. */
|
|
8
|
-
export declare function apiBaseFor(agentPath: string): string;
|
|
9
|
-
/**
|
|
10
|
-
* The canonical dashboard mount path (no trailing slash), default `<agentPath>/dashboard`. A caller
|
|
11
|
-
* may override with an explicit `dashboardPath`; both are normalized to a single leading slash.
|
|
12
|
-
*/
|
|
13
|
-
export declare function mountPathFor(agentPath: string, dashboardPath?: string): string;
|
|
14
|
-
/** MIME type for a filename by extension; `application/octet-stream` for anything unknown. */
|
|
15
|
-
export declare function contentTypeFor(filename: string): string;
|
|
16
|
-
/**
|
|
17
|
-
* Reject a wildcard asset request that tries to escape the SPA root via `..` or an absolute path.
|
|
18
|
-
* Returns the safe, normalized relative segments (never starting with `..`), or `null` to deny.
|
|
19
|
-
*/
|
|
20
|
-
export declare function safeAssetSegments(wildcard: string | string[] | undefined): string[] | null;
|
|
21
|
-
/**
|
|
22
|
-
* Inject the resolved agent API base into the served `index.html` as a global the SPA reads before
|
|
23
|
-
* boot, so the client calls the exact base the provider mounted (no build-time coupling). Idempotent
|
|
24
|
-
* per response — inserted right before `</head>`.
|
|
25
|
-
*/
|
|
26
|
-
export declare function injectApiBase(html: string, apiBase: string): string;
|
|
27
|
-
/**
|
|
28
|
-
* Inject a `<base href="${mount}/">` as the FIRST thing inside `<head>`, so the SPA's relative
|
|
29
|
-
* `./assets/*` URLs (Vite `base: './'`) resolve against the mount directory no matter whether the
|
|
30
|
-
* browser's URL carries a trailing slash. This replaces the old trailing-slash redirect, which the
|
|
31
|
-
* AdonisJS router (it normalizes trailing slashes) turned into a duplicate-route crash. `mount` is a
|
|
32
|
-
* leading-slash, no-trailing-slash path (e.g. `/agent/dashboard`).
|
|
33
|
-
*/
|
|
34
|
-
export declare function injectBaseHref(html: string, mount: string): string;
|
|
35
|
-
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/server/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAM9E;AAsBD,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,IAAI,CAU1F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAInE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQlE"}
|
package/dist/src/server/paths.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure path/asset helpers for the dashboard provider — extracted so they can be unit-tested without
|
|
3
|
-
* booting an AdonisJS app. The provider composes these; it holds only the router wiring + I/O.
|
|
4
|
-
*/
|
|
5
|
-
/** Collapse duplicate slashes and strip leading/trailing ones: `/agent//` → `agent`. */
|
|
6
|
-
export function trimSlashes(path) {
|
|
7
|
-
return path.replace(/\/+/g, '/').replace(/^\/+|\/+$/g, '');
|
|
8
|
-
}
|
|
9
|
-
/** The agent API base as an absolute path with a single leading slash: `agent` → `/agent`. */
|
|
10
|
-
export function apiBaseFor(agentPath) {
|
|
11
|
-
const trimmed = trimSlashes(agentPath);
|
|
12
|
-
return trimmed === '' ? '/' : `/${trimmed}`;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* The canonical dashboard mount path (no trailing slash), default `<agentPath>/dashboard`. A caller
|
|
16
|
-
* may override with an explicit `dashboardPath`; both are normalized to a single leading slash.
|
|
17
|
-
*/
|
|
18
|
-
export function mountPathFor(agentPath, dashboardPath) {
|
|
19
|
-
if (dashboardPath !== undefined && trimSlashes(dashboardPath) !== '') {
|
|
20
|
-
return `/${trimSlashes(dashboardPath)}`;
|
|
21
|
-
}
|
|
22
|
-
const trimmed = trimSlashes(agentPath);
|
|
23
|
-
return trimmed === '' ? '/dashboard' : `/${trimmed}/dashboard`;
|
|
24
|
-
}
|
|
25
|
-
const CONTENT_TYPES = {
|
|
26
|
-
html: 'text/html; charset=utf-8',
|
|
27
|
-
js: 'text/javascript; charset=utf-8',
|
|
28
|
-
mjs: 'text/javascript; charset=utf-8',
|
|
29
|
-
css: 'text/css; charset=utf-8',
|
|
30
|
-
json: 'application/json; charset=utf-8',
|
|
31
|
-
svg: 'image/svg+xml',
|
|
32
|
-
png: 'image/png',
|
|
33
|
-
jpg: 'image/jpeg',
|
|
34
|
-
jpeg: 'image/jpeg',
|
|
35
|
-
gif: 'image/gif',
|
|
36
|
-
webp: 'image/webp',
|
|
37
|
-
ico: 'image/x-icon',
|
|
38
|
-
woff: 'font/woff',
|
|
39
|
-
woff2: 'font/woff2',
|
|
40
|
-
ttf: 'font/ttf',
|
|
41
|
-
map: 'application/json; charset=utf-8',
|
|
42
|
-
txt: 'text/plain; charset=utf-8',
|
|
43
|
-
};
|
|
44
|
-
/** MIME type for a filename by extension; `application/octet-stream` for anything unknown. */
|
|
45
|
-
export function contentTypeFor(filename) {
|
|
46
|
-
const dot = filename.lastIndexOf('.');
|
|
47
|
-
const ext = dot === -1 ? '' : filename.slice(dot + 1).toLowerCase();
|
|
48
|
-
return CONTENT_TYPES[ext] ?? 'application/octet-stream';
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Reject a wildcard asset request that tries to escape the SPA root via `..` or an absolute path.
|
|
52
|
-
* Returns the safe, normalized relative segments (never starting with `..`), or `null` to deny.
|
|
53
|
-
*/
|
|
54
|
-
export function safeAssetSegments(wildcard) {
|
|
55
|
-
const parts = Array.isArray(wildcard) ? wildcard : (wildcard ?? '').split('/');
|
|
56
|
-
const segments = [];
|
|
57
|
-
for (const raw of parts) {
|
|
58
|
-
const part = raw.trim();
|
|
59
|
-
if (part === '' || part === '.')
|
|
60
|
-
continue;
|
|
61
|
-
if (part === '..' || part.includes('\0') || part.includes('\\'))
|
|
62
|
-
return null;
|
|
63
|
-
segments.push(part);
|
|
64
|
-
}
|
|
65
|
-
return segments;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Inject the resolved agent API base into the served `index.html` as a global the SPA reads before
|
|
69
|
-
* boot, so the client calls the exact base the provider mounted (no build-time coupling). Idempotent
|
|
70
|
-
* per response — inserted right before `</head>`.
|
|
71
|
-
*/
|
|
72
|
-
export function injectApiBase(html, apiBase) {
|
|
73
|
-
const tag = `<script>window.__AGENT_DASHBOARD_BASE__=${JSON.stringify(apiBase)}</script>`;
|
|
74
|
-
if (html.includes('</head>'))
|
|
75
|
-
return html.replace('</head>', `${tag}</head>`);
|
|
76
|
-
return `${tag}${html}`;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Inject a `<base href="${mount}/">` as the FIRST thing inside `<head>`, so the SPA's relative
|
|
80
|
-
* `./assets/*` URLs (Vite `base: './'`) resolve against the mount directory no matter whether the
|
|
81
|
-
* browser's URL carries a trailing slash. This replaces the old trailing-slash redirect, which the
|
|
82
|
-
* AdonisJS router (it normalizes trailing slashes) turned into a duplicate-route crash. `mount` is a
|
|
83
|
-
* leading-slash, no-trailing-slash path (e.g. `/agent/dashboard`).
|
|
84
|
-
*/
|
|
85
|
-
export function injectBaseHref(html, mount) {
|
|
86
|
-
const tag = `<base href="${mount}/">`;
|
|
87
|
-
const headOpen = html.match(/<head[^>]*>/i);
|
|
88
|
-
if (headOpen?.index !== undefined) {
|
|
89
|
-
const at = headOpen.index + headOpen[0].length;
|
|
90
|
-
return html.slice(0, at) + tag + html.slice(at);
|
|
91
|
-
}
|
|
92
|
-
return `${tag}${html}`;
|
|
93
|
-
}
|
|
94
|
-
//# sourceMappingURL=paths.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/server/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wFAAwF;AACxF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,aAAsB;IACpE,IAAI,aAAa,KAAK,SAAS,IAAI,WAAW,CAAC,aAAa,CAAC,KAAK,EAAE,EAAE,CAAC;QACrE,OAAO,IAAI,WAAW,CAAC,aAAa,CAAC,EAAE,CAAC;IAC1C,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,OAAO,YAAY,CAAC;AACjE,CAAC;AAED,MAAM,aAAa,GAA2B;IAC5C,IAAI,EAAE,0BAA0B;IAChC,EAAE,EAAE,gCAAgC;IACpC,GAAG,EAAE,gCAAgC;IACrC,GAAG,EAAE,yBAAyB;IAC9B,IAAI,EAAE,iCAAiC;IACvC,GAAG,EAAE,eAAe;IACpB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,cAAc;IACnB,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,YAAY;IACnB,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,iCAAiC;IACtC,GAAG,EAAE,2BAA2B;CACjC,CAAC;AAEF,8FAA8F;AAC9F,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACpE,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;AAC1D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAuC;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/E,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,GAAG;YAAE,SAAS;QAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7E,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAAe;IACzD,MAAM,GAAG,GAAG,2CAA2C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC;IAC1F,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;IAC9E,OAAO,GAAG,GAAG,GAAG,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,KAAa;IACxD,MAAM,GAAG,GAAG,eAAe,KAAK,KAAK,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC5C,IAAI,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,GAAG,GAAG,GAAG,IAAI,EAAE,CAAC;AACzB,CAAC"}
|