@astrale-os/shell 0.1.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/dist/adapters/iframe.shell-adapter.d.ts +10 -0
- package/dist/adapters/iframe.shell-adapter.d.ts.map +1 -0
- package/dist/adapters/iframe.shell-adapter.js +55 -0
- package/dist/adapters/kernel-client.adapter.d.ts +53 -0
- package/dist/adapters/kernel-client.adapter.d.ts.map +1 -0
- package/dist/adapters/kernel-client.adapter.js +69 -0
- package/dist/adapters/message-port.transport.d.ts +7 -0
- package/dist/adapters/message-port.transport.d.ts.map +1 -0
- package/dist/adapters/message-port.transport.js +42 -0
- package/dist/application/channels/children-channel.d.ts +21 -0
- package/dist/application/channels/children-channel.d.ts.map +1 -0
- package/dist/application/channels/children-channel.js +82 -0
- package/dist/application/channels/observer.d.ts +9 -0
- package/dist/application/channels/observer.d.ts.map +1 -0
- package/dist/application/channels/observer.js +23 -0
- package/dist/application/channels/parent-channel.d.ts +17 -0
- package/dist/application/channels/parent-channel.d.ts.map +1 -0
- package/dist/application/channels/parent-channel.js +21 -0
- package/dist/application/channels/types.d.ts +12 -0
- package/dist/application/channels/types.d.ts.map +1 -0
- package/dist/application/channels/types.js +29 -0
- package/dist/application/intent/pipeline-runner.d.ts +12 -0
- package/dist/application/intent/pipeline-runner.d.ts.map +1 -0
- package/dist/application/intent/pipeline-runner.js +27 -0
- package/dist/application/intent/request.d.ts +34 -0
- package/dist/application/intent/request.d.ts.map +1 -0
- package/dist/application/intent/request.js +70 -0
- package/dist/application/intent/router.d.ts +56 -0
- package/dist/application/intent/router.d.ts.map +1 -0
- package/dist/application/intent/router.js +94 -0
- package/dist/application/kernel-facade.d.ts +33 -0
- package/dist/application/kernel-facade.d.ts.map +1 -0
- package/dist/application/kernel-facade.js +77 -0
- package/dist/application/shell.d.ts +100 -0
- package/dist/application/shell.d.ts.map +1 -0
- package/dist/application/shell.js +256 -0
- package/dist/application/windowing/child-init.d.ts +23 -0
- package/dist/application/windowing/child-init.d.ts.map +1 -0
- package/dist/application/windowing/child-init.js +101 -0
- package/dist/application/windowing/handshake.d.ts +30 -0
- package/dist/application/windowing/handshake.d.ts.map +1 -0
- package/dist/application/windowing/handshake.js +63 -0
- package/dist/application/windowing/lifecycle-controller.d.ts +10 -0
- package/dist/application/windowing/lifecycle-controller.d.ts.map +1 -0
- package/dist/application/windowing/lifecycle-controller.js +30 -0
- package/dist/application/windowing/mount-controller.d.ts +25 -0
- package/dist/application/windowing/mount-controller.d.ts.map +1 -0
- package/dist/application/windowing/mount-controller.js +277 -0
- package/dist/application/windowing/protocol.d.ts +21 -0
- package/dist/application/windowing/protocol.d.ts.map +1 -0
- package/dist/application/windowing/protocol.js +19 -0
- package/dist/application/windowing/token-refresh.d.ts +19 -0
- package/dist/application/windowing/token-refresh.d.ts.map +1 -0
- package/dist/application/windowing/token-refresh.js +60 -0
- package/dist/domain/identity/delegation.d.ts +15 -0
- package/dist/domain/identity/delegation.d.ts.map +1 -0
- package/dist/domain/identity/delegation.js +12 -0
- package/dist/domain/identity/path.d.ts +11 -0
- package/dist/domain/identity/path.d.ts.map +1 -0
- package/dist/domain/identity/path.js +13 -0
- package/dist/domain/identity/resolve-self.d.ts +21 -0
- package/dist/domain/identity/resolve-self.d.ts.map +1 -0
- package/dist/domain/identity/resolve-self.js +36 -0
- package/dist/domain/intent/middleware/capabilities.d.ts +28 -0
- package/dist/domain/intent/middleware/capabilities.d.ts.map +1 -0
- package/dist/domain/intent/middleware/capabilities.js +18 -0
- package/dist/domain/intent/middleware/logging.d.ts +14 -0
- package/dist/domain/intent/middleware/logging.d.ts.map +1 -0
- package/dist/domain/intent/middleware/logging.js +21 -0
- package/dist/domain/intent/middleware/rate-limit.d.ts +20 -0
- package/dist/domain/intent/middleware/rate-limit.d.ts.map +1 -0
- package/dist/domain/intent/middleware/rate-limit.js +33 -0
- package/dist/domain/intent/pipeline.d.ts +3 -0
- package/dist/domain/intent/pipeline.d.ts.map +1 -0
- package/dist/domain/intent/pipeline.js +1 -0
- package/dist/domain/intent/router.d.ts +6 -0
- package/dist/domain/intent/router.d.ts.map +1 -0
- package/dist/domain/intent/router.js +1 -0
- package/dist/domain/message/errors.d.ts +2 -0
- package/dist/domain/message/errors.d.ts.map +1 -0
- package/dist/domain/message/errors.js +1 -0
- package/dist/domain/message/registries.d.ts +145 -0
- package/dist/domain/message/registries.d.ts.map +1 -0
- package/dist/domain/message/registries.js +1 -0
- package/dist/domain/message/types.d.ts +30 -0
- package/dist/domain/message/types.d.ts.map +1 -0
- package/dist/domain/message/types.js +1 -0
- package/dist/domain/window/config.d.ts +26 -0
- package/dist/domain/window/config.d.ts.map +1 -0
- package/dist/domain/window/config.js +1 -0
- package/dist/domain/window/lifecycle.d.ts +27 -0
- package/dist/domain/window/lifecycle.d.ts.map +1 -0
- package/dist/domain/window/lifecycle.js +36 -0
- package/dist/domain/window/window.d.ts +12 -0
- package/dist/domain/window/window.d.ts.map +1 -0
- package/dist/domain/window/window.js +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/ports/kernel-client.d.ts +33 -0
- package/dist/ports/kernel-client.d.ts.map +1 -0
- package/dist/ports/kernel-client.js +1 -0
- package/dist/ports/shell-adapter.d.ts +13 -0
- package/dist/ports/shell-adapter.d.ts.map +1 -0
- package/dist/ports/shell-adapter.js +1 -0
- package/dist/ports/transport.d.ts +7 -0
- package/dist/ports/transport.d.ts.map +1 -0
- package/dist/ports/transport.js +1 -0
- package/package.json +41 -0
- package/src/adapters/iframe.shell-adapter.ts +68 -0
- package/src/adapters/kernel-client.adapter.ts +138 -0
- package/src/adapters/message-port.transport.ts +50 -0
- package/src/application/channels/children-channel.ts +112 -0
- package/src/application/channels/observer.ts +33 -0
- package/src/application/channels/parent-channel.ts +43 -0
- package/src/application/channels/types.ts +41 -0
- package/src/application/intent/pipeline-runner.ts +36 -0
- package/src/application/intent/request.ts +87 -0
- package/src/application/intent/router.ts +161 -0
- package/src/application/kernel-facade.ts +143 -0
- package/src/application/shell.ts +433 -0
- package/src/application/windowing/child-init.ts +137 -0
- package/src/application/windowing/handshake.ts +98 -0
- package/src/application/windowing/lifecycle-controller.ts +40 -0
- package/src/application/windowing/mount-controller.ts +335 -0
- package/src/application/windowing/protocol.ts +37 -0
- package/src/application/windowing/token-refresh.ts +78 -0
- package/src/domain/identity/delegation.ts +25 -0
- package/src/domain/identity/path.ts +14 -0
- package/src/domain/identity/resolve-self.ts +38 -0
- package/src/domain/intent/middleware/capabilities.ts +53 -0
- package/src/domain/intent/middleware/logging.ts +45 -0
- package/src/domain/intent/middleware/rate-limit.ts +54 -0
- package/src/domain/intent/pipeline.ts +3 -0
- package/src/domain/intent/router.ts +6 -0
- package/src/domain/message/errors.ts +9 -0
- package/src/domain/message/registries.ts +76 -0
- package/src/domain/message/types.ts +32 -0
- package/src/domain/window/config.ts +28 -0
- package/src/domain/window/lifecycle.ts +39 -0
- package/src/domain/window/window.ts +13 -0
- package/src/index.ts +103 -0
- package/src/ports/kernel-client.ts +32 -0
- package/src/ports/shell-adapter.ts +11 -0
- package/src/ports/transport.ts +7 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { REFRESH_WINDOW_MS } from '../../domain/identity/delegation';
|
|
2
|
+
const BACKOFF_DELAYS_MS = [1_000, 2_000, 4_000];
|
|
3
|
+
export function createTokenRefresher(config) {
|
|
4
|
+
const now = config.now ?? Date.now;
|
|
5
|
+
let timer = null;
|
|
6
|
+
let stopped = false;
|
|
7
|
+
function schedule() {
|
|
8
|
+
if (stopped)
|
|
9
|
+
return;
|
|
10
|
+
if (timer)
|
|
11
|
+
clearTimeout(timer);
|
|
12
|
+
const token = config.token();
|
|
13
|
+
const leadTimeMs = Math.max(token.expiresAt - now() - REFRESH_WINDOW_MS, 0);
|
|
14
|
+
timer = setTimeout(() => {
|
|
15
|
+
void runRefresh();
|
|
16
|
+
}, leadTimeMs);
|
|
17
|
+
}
|
|
18
|
+
async function runRefresh() {
|
|
19
|
+
for (let attempt = 0; attempt <= BACKOFF_DELAYS_MS.length; attempt += 1) {
|
|
20
|
+
if (stopped)
|
|
21
|
+
return;
|
|
22
|
+
try {
|
|
23
|
+
const next = await config.mint();
|
|
24
|
+
config.setToken({
|
|
25
|
+
credential: next.credential,
|
|
26
|
+
expiresAt: next.expiresAt,
|
|
27
|
+
issuedAt: now(),
|
|
28
|
+
scope: { functionId: config.functionId },
|
|
29
|
+
});
|
|
30
|
+
schedule();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
if (attempt === BACKOFF_DELAYS_MS.length) {
|
|
35
|
+
config.onFailure?.(err);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await delay(BACKOFF_DELAYS_MS[attempt]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
start() {
|
|
44
|
+
stopped = false;
|
|
45
|
+
schedule();
|
|
46
|
+
},
|
|
47
|
+
stop() {
|
|
48
|
+
stopped = true;
|
|
49
|
+
if (timer)
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
timer = null;
|
|
52
|
+
},
|
|
53
|
+
async forceRefreshNow() {
|
|
54
|
+
await runRefresh();
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function delay(ms) {
|
|
59
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
60
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type DelegationScope = {
|
|
2
|
+
readonly functionId: string;
|
|
3
|
+
};
|
|
4
|
+
export type DelegationToken = {
|
|
5
|
+
readonly credential: string;
|
|
6
|
+
readonly scope: DelegationScope;
|
|
7
|
+
readonly issuedAt: number;
|
|
8
|
+
readonly expiresAt: number;
|
|
9
|
+
};
|
|
10
|
+
export type TokenState = 'fresh' | 'expiring' | 'expired' | 'refreshing' | 'failed';
|
|
11
|
+
/** How long before expiration we start proactively refreshing. */
|
|
12
|
+
export declare const REFRESH_WINDOW_MS = 120000;
|
|
13
|
+
export declare function stateOf(token: DelegationToken, now?: number): TokenState;
|
|
14
|
+
export declare function isExpired(token: DelegationToken, now?: number): boolean;
|
|
15
|
+
//# sourceMappingURL=delegation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation.d.ts","sourceRoot":"","sources":["../../../src/domain/identity/delegation.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAA;AAEnF,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,SAAU,CAAA;AAExC,wBAAgB,OAAO,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,SAAa,GAAG,UAAU,CAI5E;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,SAAa,GAAG,OAAO,CAE3E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** How long before expiration we start proactively refreshing. */
|
|
2
|
+
export const REFRESH_WINDOW_MS = 120_000;
|
|
3
|
+
export function stateOf(token, now = Date.now()) {
|
|
4
|
+
if (token.expiresAt <= now)
|
|
5
|
+
return 'expired';
|
|
6
|
+
if (token.expiresAt - now <= REFRESH_WINDOW_MS)
|
|
7
|
+
return 'expiring';
|
|
8
|
+
return 'fresh';
|
|
9
|
+
}
|
|
10
|
+
export function isExpired(token, now = Date.now()) {
|
|
11
|
+
return token.expiresAt <= now;
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in kernel root identity, used as the default mint subject when no
|
|
3
|
+
* explicit `mintIdentity` is configured.
|
|
4
|
+
*/
|
|
5
|
+
export declare const SYSTEM_IDENTITY = "__system__";
|
|
6
|
+
/**
|
|
7
|
+
* Address a method on an identity or path: `@<id>::method` for a bare node id,
|
|
8
|
+
* `<path>::method` for an absolute path (one starting with `/`).
|
|
9
|
+
*/
|
|
10
|
+
export declare function identityMethod(identity: string, method: string): string;
|
|
11
|
+
//# sourceMappingURL=path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/domain/identity/path.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,eAAe,eAAe,CAAA;AAE3C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGvE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in kernel root identity, used as the default mint subject when no
|
|
3
|
+
* explicit `mintIdentity` is configured.
|
|
4
|
+
*/
|
|
5
|
+
export const SYSTEM_IDENTITY = '__system__';
|
|
6
|
+
/**
|
|
7
|
+
* Address a method on an identity or path: `@<id>::method` for a bare node id,
|
|
8
|
+
* `<path>::method` for an absolute path (one starting with `/`).
|
|
9
|
+
*/
|
|
10
|
+
export function identityMethod(identity, method) {
|
|
11
|
+
const target = identity.startsWith('/') ? identity : `@${identity}`;
|
|
12
|
+
return `${target}::${method}`;
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Kernel path that returns the AUTHENTICATED caller's own identity node. */
|
|
2
|
+
export declare const WHOAMI_PATH = "/:kernel.astrale.ai:interface.Identity:whoami";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the mint SUBJECT — the identity node a delegation/credential should be
|
|
5
|
+
* minted for. It MUST be the principal the kernel actually authenticates this
|
|
6
|
+
* caller as, otherwise the minted token impersonates someone else.
|
|
7
|
+
*
|
|
8
|
+
* Why a kernel round-trip and not the local credential: a cookie-fronted SPA
|
|
9
|
+
* holds an EMPTY credential string (the session token lives in an httpOnly
|
|
10
|
+
* cookie it can't read), so the subject cannot be derived locally. We ask the
|
|
11
|
+
* kernel via `whoami`; that request carries the cookie, so the router unseals it
|
|
12
|
+
* and the kernel answers with the logged-in user's node. Without this the shell
|
|
13
|
+
* defaulted every mint to `__system__`, so a View iframe mounted by a logged-in
|
|
14
|
+
* user acted as the kernel ROOT instead of as that user.
|
|
15
|
+
*
|
|
16
|
+
* `fallback` (the configured `mintIdentity`, default `__system__`) is used when
|
|
17
|
+
* whoami can't be resolved — a genuinely system/dev caller, or an unauthenticated
|
|
18
|
+
* boot. The result is cached: the principal is stable for a session.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createSelfResolver(fallback?: string): (whoami: () => Promise<unknown>) => Promise<string>;
|
|
21
|
+
//# sourceMappingURL=resolve-self.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-self.d.ts","sourceRoot":"","sources":["../../../src/domain/identity/resolve-self.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,eAAO,MAAM,WAAW,kDAAkD,CAAA;AAE1E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,GAAE,MAAwB,GACjC,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAarD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { SYSTEM_IDENTITY } from './path';
|
|
2
|
+
/** Kernel path that returns the AUTHENTICATED caller's own identity node. */
|
|
3
|
+
export const WHOAMI_PATH = '/:kernel.astrale.ai:interface.Identity:whoami';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the mint SUBJECT — the identity node a delegation/credential should be
|
|
6
|
+
* minted for. It MUST be the principal the kernel actually authenticates this
|
|
7
|
+
* caller as, otherwise the minted token impersonates someone else.
|
|
8
|
+
*
|
|
9
|
+
* Why a kernel round-trip and not the local credential: a cookie-fronted SPA
|
|
10
|
+
* holds an EMPTY credential string (the session token lives in an httpOnly
|
|
11
|
+
* cookie it can't read), so the subject cannot be derived locally. We ask the
|
|
12
|
+
* kernel via `whoami`; that request carries the cookie, so the router unseals it
|
|
13
|
+
* and the kernel answers with the logged-in user's node. Without this the shell
|
|
14
|
+
* defaulted every mint to `__system__`, so a View iframe mounted by a logged-in
|
|
15
|
+
* user acted as the kernel ROOT instead of as that user.
|
|
16
|
+
*
|
|
17
|
+
* `fallback` (the configured `mintIdentity`, default `__system__`) is used when
|
|
18
|
+
* whoami can't be resolved — a genuinely system/dev caller, or an unauthenticated
|
|
19
|
+
* boot. The result is cached: the principal is stable for a session.
|
|
20
|
+
*/
|
|
21
|
+
export function createSelfResolver(fallback = SYSTEM_IDENTITY) {
|
|
22
|
+
let cached;
|
|
23
|
+
return async (whoami) => {
|
|
24
|
+
if (cached !== undefined)
|
|
25
|
+
return cached;
|
|
26
|
+
try {
|
|
27
|
+
const me = (await whoami());
|
|
28
|
+
const id = me && typeof me.id === 'string' && me.id.length > 0 ? me.id : undefined;
|
|
29
|
+
cached = id ?? fallback;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
cached = fallback;
|
|
33
|
+
}
|
|
34
|
+
return cached;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { IntentRegistry } from '../../message/registries';
|
|
2
|
+
import type { WindowCapabilities } from '../../window/config';
|
|
3
|
+
import type { IntentMiddleware } from '../pipeline';
|
|
4
|
+
export type CapabilityLookup = (sender: string) => WindowCapabilities | undefined;
|
|
5
|
+
export type CapabilityViolation = {
|
|
6
|
+
readonly sender: string;
|
|
7
|
+
readonly intent: keyof IntentRegistry;
|
|
8
|
+
};
|
|
9
|
+
export type CapabilitiesConfig = {
|
|
10
|
+
/**
|
|
11
|
+
* Map each sender windowId to its declared capabilities. Intents whose
|
|
12
|
+
* name is absent from the sender's capability list are blocked.
|
|
13
|
+
*/
|
|
14
|
+
readonly lookup: CapabilityLookup;
|
|
15
|
+
/**
|
|
16
|
+
* Called when an intent is blocked. The violation can be used to emit
|
|
17
|
+
* an ErrorMessage back to the sender (shell wiring does that separately).
|
|
18
|
+
*/
|
|
19
|
+
readonly onViolation?: (violation: CapabilityViolation) => void;
|
|
20
|
+
/**
|
|
21
|
+
* If true, intents originated by the shell itself (sender === selfWindowId)
|
|
22
|
+
* are never filtered. Default: true.
|
|
23
|
+
*/
|
|
24
|
+
readonly allowSelf?: boolean;
|
|
25
|
+
readonly selfWindowId?: string;
|
|
26
|
+
};
|
|
27
|
+
export declare function capabilitiesMiddleware(config: CapabilitiesConfig): IntentMiddleware;
|
|
28
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../../../src/domain/intent/middleware/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAE9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEnD,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAA;AAEjF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,cAAc,CAAA;CACtC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;IAEjC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAE/D;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAE5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B,CAAA;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,kBAAkB,GAAG,gBAAgB,CAkBnF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function capabilitiesMiddleware(config) {
|
|
2
|
+
const { lookup, onViolation, selfWindowId } = config;
|
|
3
|
+
const allowSelf = config.allowSelf ?? true;
|
|
4
|
+
return async (message, next) => {
|
|
5
|
+
const sender = message.envelope.sender.windowId;
|
|
6
|
+
if (allowSelf && selfWindowId !== undefined && sender === selfWindowId) {
|
|
7
|
+
await next();
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const caps = lookup(sender);
|
|
11
|
+
const intentName = message.envelope.name;
|
|
12
|
+
if (!caps || !caps.intents.includes(intentName)) {
|
|
13
|
+
onViolation?.({ sender, intent: intentName });
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
await next();
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IntentMiddleware } from '../pipeline';
|
|
2
|
+
export type LoggingSink = (entry: LoggingEntry) => void;
|
|
3
|
+
export type LoggingEntry = {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly sender: string;
|
|
6
|
+
readonly correlationId?: string;
|
|
7
|
+
readonly phase: 'in' | 'out';
|
|
8
|
+
readonly timestamp: number;
|
|
9
|
+
};
|
|
10
|
+
export type LoggingConfig = {
|
|
11
|
+
readonly sink?: LoggingSink;
|
|
12
|
+
};
|
|
13
|
+
export declare function loggingMiddleware(config?: LoggingConfig): IntentMiddleware;
|
|
14
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../../src/domain/intent/middleware/logging.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEnD,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAA;AAEvD,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,KAAK,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAA;CAC5B,CAAA;AAED,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,aAAkB,GAAG,gBAAgB,CAQ9E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function loggingMiddleware(config = {}) {
|
|
2
|
+
const sink = config.sink ?? defaultSink;
|
|
3
|
+
return async (message, next) => {
|
|
4
|
+
sink(toEntry(message, 'in'));
|
|
5
|
+
await next();
|
|
6
|
+
sink(toEntry(message, 'out'));
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function toEntry(message, phase) {
|
|
10
|
+
return {
|
|
11
|
+
name: message.envelope.name,
|
|
12
|
+
sender: message.envelope.sender.windowId,
|
|
13
|
+
correlationId: message.envelope.correlationId,
|
|
14
|
+
phase,
|
|
15
|
+
timestamp: Date.now(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function defaultSink(entry) {
|
|
19
|
+
// eslint-disable-next-line no-console -- built-in sink; opt-in via wiring.
|
|
20
|
+
console.debug(`[shell.intent] ${entry.phase} ${entry.name} from=${entry.sender}${entry.correlationId ? ` corr=${entry.correlationId}` : ''}`);
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IntentMessage } from '../../message/types';
|
|
2
|
+
import type { IntentMiddleware } from '../pipeline';
|
|
3
|
+
export type RateLimitKey = (message: IntentMessage) => string;
|
|
4
|
+
export type RateLimitViolation = {
|
|
5
|
+
readonly key: string;
|
|
6
|
+
readonly intent: string;
|
|
7
|
+
};
|
|
8
|
+
export type RateLimitConfig = {
|
|
9
|
+
readonly windowMs: number;
|
|
10
|
+
readonly max: number;
|
|
11
|
+
readonly key?: RateLimitKey;
|
|
12
|
+
readonly onViolation?: (violation: RateLimitViolation) => void;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Fixed-window rate limiter. An amortized sweep evicts expired buckets on
|
|
16
|
+
* every `windowMs` interval of activity so the map stays bounded by the
|
|
17
|
+
* number of active keys, not the total ever seen.
|
|
18
|
+
*/
|
|
19
|
+
export declare function rateLimitMiddleware(config: RateLimitConfig): IntentMiddleware;
|
|
20
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../../src/domain/intent/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEnD,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,aAAa,KAAK,MAAM,CAAA;AAE7D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,YAAY,CAAA;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,kBAAkB,KAAK,IAAI,CAAA;CAC/D,CAAA;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,gBAAgB,CA+B7E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixed-window rate limiter. An amortized sweep evicts expired buckets on
|
|
3
|
+
* every `windowMs` interval of activity so the map stays bounded by the
|
|
4
|
+
* number of active keys, not the total ever seen.
|
|
5
|
+
*/
|
|
6
|
+
export function rateLimitMiddleware(config) {
|
|
7
|
+
const { windowMs, max, onViolation } = config;
|
|
8
|
+
const key = config.key ?? ((m) => `${m.envelope.sender.windowId}|${m.envelope.name}`);
|
|
9
|
+
const buckets = new Map();
|
|
10
|
+
let nextSweepAt = 0;
|
|
11
|
+
return async (message, next) => {
|
|
12
|
+
const k = key(message);
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
if (now >= nextSweepAt) {
|
|
15
|
+
for (const [bucketKey, bucket] of buckets) {
|
|
16
|
+
if (bucket.resetAt <= now)
|
|
17
|
+
buckets.delete(bucketKey);
|
|
18
|
+
}
|
|
19
|
+
nextSweepAt = now + windowMs;
|
|
20
|
+
}
|
|
21
|
+
let bucket = buckets.get(k);
|
|
22
|
+
if (!bucket || bucket.resetAt <= now) {
|
|
23
|
+
bucket = { count: 0, resetAt: now + windowMs };
|
|
24
|
+
buckets.set(k, bucket);
|
|
25
|
+
}
|
|
26
|
+
bucket.count += 1;
|
|
27
|
+
if (bucket.count > max) {
|
|
28
|
+
onViolation?.({ key: k, intent: message.envelope.name });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
await next();
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../../src/domain/intent/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IntentRegistry } from '../message/registries';
|
|
2
|
+
import type { IntentMessage } from '../message/types';
|
|
3
|
+
export interface IntentRouter {
|
|
4
|
+
dispatch<K extends keyof IntentRegistry>(message: IntentMessage<K>): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/domain/intent/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/domain/message/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,mBAAmB,GACnB,iBAAiB,GACjB,oBAAoB,GACpB,qBAAqB,GACrB,oBAAoB,GACpB,iBAAiB,GACjB,sBAAsB,GACtB,mBAAmB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
export interface ViewRef {
|
|
2
|
+
readonly viewId: string;
|
|
3
|
+
readonly functionId: string;
|
|
4
|
+
readonly label?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Intent registry — extensible via declaration merging.
|
|
8
|
+
*
|
|
9
|
+
* Consumers extend via:
|
|
10
|
+
* declare module '@astrale-os/shell' {
|
|
11
|
+
* interface IntentRegistry { ... }
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
export interface IntentRegistry {
|
|
15
|
+
open: {
|
|
16
|
+
payload: {
|
|
17
|
+
nodeId: string;
|
|
18
|
+
viewId?: string;
|
|
19
|
+
};
|
|
20
|
+
response: {
|
|
21
|
+
windowId: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
close: {
|
|
25
|
+
payload: {
|
|
26
|
+
windowId: string;
|
|
27
|
+
};
|
|
28
|
+
response: void;
|
|
29
|
+
};
|
|
30
|
+
focus: {
|
|
31
|
+
payload: {
|
|
32
|
+
nodeId: string;
|
|
33
|
+
};
|
|
34
|
+
response: void;
|
|
35
|
+
};
|
|
36
|
+
willClose: {
|
|
37
|
+
payload: Record<string, never>;
|
|
38
|
+
response: void;
|
|
39
|
+
};
|
|
40
|
+
closeAck: {
|
|
41
|
+
payload: Record<string, never>;
|
|
42
|
+
response: void;
|
|
43
|
+
};
|
|
44
|
+
closeRefuse: {
|
|
45
|
+
payload: {
|
|
46
|
+
reason: string;
|
|
47
|
+
};
|
|
48
|
+
response: void;
|
|
49
|
+
};
|
|
50
|
+
pickView: {
|
|
51
|
+
payload: {
|
|
52
|
+
views: ViewRef[];
|
|
53
|
+
};
|
|
54
|
+
response: {
|
|
55
|
+
viewId: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
receive: {
|
|
59
|
+
payload: {
|
|
60
|
+
data: unknown;
|
|
61
|
+
sourceIntent: string;
|
|
62
|
+
};
|
|
63
|
+
response: void;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Hot-swap — parent pushes a new target node to an already-mounted view
|
|
67
|
+
* without remounting. The child reads `targetNodeId` at handshake time
|
|
68
|
+
* for the initial value; `setTarget` replaces it for the lifetime of the
|
|
69
|
+
* window.
|
|
70
|
+
*/
|
|
71
|
+
setTarget: {
|
|
72
|
+
payload: {
|
|
73
|
+
nodeId: string;
|
|
74
|
+
};
|
|
75
|
+
response: void;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Child → parent: a view asks the user to grant `perms` (a permission
|
|
79
|
+
* bitmask) on `node` to `identity` (the beneficiary subject). Both `node`
|
|
80
|
+
* and `identity` are bare node ids (e.g. the view's `targetNodeId`, or
|
|
81
|
+
* `whoami().id` for "grant to myself") — the root shell addresses them as
|
|
82
|
+
* `@<id>`. The root shell (GUI) surfaces a modal, computes the delta vs.
|
|
83
|
+
* what the subject already holds, and — on approval — grants only the
|
|
84
|
+
* missing bits under the GUI user's own credential. `reason` is shown to
|
|
85
|
+
* the user. `response.perms` is the bitmask actually granted (0 if
|
|
86
|
+
* declined / nothing was missing).
|
|
87
|
+
*
|
|
88
|
+
* Reaches a handler only from a view mounted as a DIRECT child of the root
|
|
89
|
+
* shell — the default intent policy does not bubble past one hop.
|
|
90
|
+
*/
|
|
91
|
+
requestAccess: {
|
|
92
|
+
payload: {
|
|
93
|
+
node: string;
|
|
94
|
+
identity: string;
|
|
95
|
+
perms: number;
|
|
96
|
+
reason?: string;
|
|
97
|
+
};
|
|
98
|
+
response: {
|
|
99
|
+
granted: boolean;
|
|
100
|
+
perms: number;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Generic correlated reply channel. The default intent transport is
|
|
105
|
+
* fire-and-forget; `requestIntent()` sends an intent carrying a
|
|
106
|
+
* `correlationId` and awaits an `intentReply` whose payload echoes it back
|
|
107
|
+
* with the handler's `result`. Routed to the resolver purely by
|
|
108
|
+
* `correlationId` — it intentionally matches no local handler.
|
|
109
|
+
*/
|
|
110
|
+
intentReply: {
|
|
111
|
+
payload: {
|
|
112
|
+
correlationId: string;
|
|
113
|
+
result: unknown;
|
|
114
|
+
};
|
|
115
|
+
response: void;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Control message registry — extensible via declaration merging.
|
|
120
|
+
*/
|
|
121
|
+
export interface CtrlRegistry {
|
|
122
|
+
handshake: {
|
|
123
|
+
data: {
|
|
124
|
+
delegationToken: string;
|
|
125
|
+
tokenExpiresAt: number;
|
|
126
|
+
windowId: string;
|
|
127
|
+
kernelUrl: string;
|
|
128
|
+
functionId: string;
|
|
129
|
+
targetNodeId?: string;
|
|
130
|
+
mintIdentity?: string;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
handshakeAck: {
|
|
134
|
+
data: {
|
|
135
|
+
windowId: string;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
tokenRefresh: {
|
|
139
|
+
data: {
|
|
140
|
+
delegationToken: string;
|
|
141
|
+
tokenExpiresAt: number;
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=registries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registries.d.ts","sourceRoot":"","sources":["../../../src/domain/message/registries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ErrorCode } from './errors';
|
|
2
|
+
import type { CtrlRegistry, IntentRegistry } from './registries';
|
|
3
|
+
export type IntentEnvelope<K extends keyof IntentRegistry = keyof IntentRegistry> = {
|
|
4
|
+
readonly name: K;
|
|
5
|
+
readonly payload: IntentRegistry[K]['payload'];
|
|
6
|
+
readonly sender: {
|
|
7
|
+
readonly windowId: string;
|
|
8
|
+
};
|
|
9
|
+
readonly correlationId?: string;
|
|
10
|
+
};
|
|
11
|
+
export type IntentMessage<K extends keyof IntentRegistry = keyof IntentRegistry> = {
|
|
12
|
+
readonly type: 'intent';
|
|
13
|
+
readonly version: 1;
|
|
14
|
+
readonly envelope: IntentEnvelope<K>;
|
|
15
|
+
};
|
|
16
|
+
export type CtrlMessage<K extends keyof CtrlRegistry = keyof CtrlRegistry> = {
|
|
17
|
+
readonly type: 'ctrl';
|
|
18
|
+
readonly version: 1;
|
|
19
|
+
readonly action: K;
|
|
20
|
+
readonly data: CtrlRegistry[K]['data'];
|
|
21
|
+
};
|
|
22
|
+
export type ErrorMessage = {
|
|
23
|
+
readonly type: 'error';
|
|
24
|
+
readonly version: 1;
|
|
25
|
+
readonly code: ErrorCode;
|
|
26
|
+
readonly message: string;
|
|
27
|
+
readonly context?: unknown;
|
|
28
|
+
};
|
|
29
|
+
export type ShellMessage = IntentMessage | CtrlMessage | ErrorMessage;
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/domain/message/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAEhE,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,cAAc,GAAG,MAAM,cAAc,IAAI;IAClF,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC9C,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,cAAc,GAAG,MAAM,cAAc,IAAI;IACjF,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;IACnB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,YAAY,GAAG,MAAM,YAAY,IAAI;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;IAClB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,WAAW,GAAG,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { IntentRegistry } from '../message/registries';
|
|
2
|
+
export interface SandboxProfile {
|
|
3
|
+
readonly allowScripts: boolean;
|
|
4
|
+
readonly allowForms: boolean;
|
|
5
|
+
readonly allowPopups: boolean;
|
|
6
|
+
readonly allowSameOrigin: boolean;
|
|
7
|
+
readonly allowModals: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface WindowCapabilities {
|
|
10
|
+
readonly intents: ReadonlyArray<keyof IntentRegistry>;
|
|
11
|
+
}
|
|
12
|
+
export interface WindowConfig {
|
|
13
|
+
readonly functionId: string;
|
|
14
|
+
readonly isolation: 'sandboxed' | 'shared';
|
|
15
|
+
readonly capabilities: WindowCapabilities;
|
|
16
|
+
/**
|
|
17
|
+
* Sandbox profile for the iframe.
|
|
18
|
+
* - `undefined` → adapter default (`DEFAULT_SANDBOX` in iframe.shell-adapter).
|
|
19
|
+
* - `SandboxProfile` → explicit flag set, becomes the `sandbox=…` attribute.
|
|
20
|
+
* - `null` → opt out: no `sandbox` attribute on the iframe at all (the
|
|
21
|
+
* browser's cross-origin policy is the only remaining isolation). Used
|
|
22
|
+
* for first-party trusted views per the GUI allowlist.
|
|
23
|
+
*/
|
|
24
|
+
readonly sandbox?: SandboxProfile | null;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/domain/window/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,cAAc,CAAC,CAAA;CACtD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,QAAQ,CAAA;IAC1C,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAA;IACzC;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;CACzC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { WindowState } from './window';
|
|
2
|
+
export type LifecycleEvent = {
|
|
3
|
+
kind: 'hide';
|
|
4
|
+
} | {
|
|
5
|
+
kind: 'restore';
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'requestClose';
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'closeAck';
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'closeRefuse';
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'forceClose';
|
|
14
|
+
};
|
|
15
|
+
export type TransitionResult = {
|
|
16
|
+
ok: true;
|
|
17
|
+
next: WindowState;
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
reason: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Pure state-machine transition. Used by the lifecycle controller —
|
|
24
|
+
* no timers, no side effects here.
|
|
25
|
+
*/
|
|
26
|
+
export declare function transition(state: WindowState, event: LifecycleEvent): TransitionResult;
|
|
27
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/domain/window/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAA;AAE1B,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9F;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,cAAc,GAAG,gBAAgB,CAsBtF"}
|