@xfey/tutti 0.1.33 → 0.1.34
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/README.md +3 -3
- package/dist/server-shell/cli/args.d.ts +6 -0
- package/dist/server-shell/cli/args.js +30 -0
- package/dist/server-shell/cli/cli.js +118 -6
- package/dist/server-shell/cli/errors.d.ts +1 -1
- package/dist/server-shell/cli/host-runtime-endpoint.d.ts +1 -0
- package/dist/server-shell/cli/host-runtime-endpoint.js +10 -5
- package/dist/server-shell/cli/machine-project-inspector.d.ts +1 -0
- package/dist/server-shell/cli/machine-project-inspector.js +1 -0
- package/dist/server-shell/cli/managed-host.d.ts +1 -0
- package/dist/server-shell/cli/managed-host.js +6 -4
- package/dist/server-shell/cli/runtime-commands.d.ts +1 -0
- package/dist/server-shell/cli/runtime-commands.js +5 -1
- package/dist/server-shell/local-console/folder-picker.d.ts +0 -1
- package/dist/server-shell/local-console/folder-picker.js +2 -33
- package/dist/server-shell/local-console/invocation-context.d.ts +21 -0
- package/dist/server-shell/local-console/invocation-context.js +56 -0
- package/dist/server-shell/local-console/lifecycle-lock.d.ts +13 -0
- package/dist/server-shell/local-console/lifecycle-lock.js +135 -0
- package/dist/server-shell/local-console/managed-console.d.ts +38 -0
- package/dist/server-shell/local-console/managed-console.js +254 -36
- package/dist/server-shell/local-console/project-service.d.ts +11 -7
- package/dist/server-shell/local-console/project-service.js +102 -57
- package/dist/server-shell/local-console/runtime-endpoint.d.ts +15 -1
- package/dist/server-shell/local-console/runtime-endpoint.js +21 -5
- package/dist/server-shell/local-console/server.d.ts +12 -0
- package/dist/server-shell/local-console/server.js +152 -45
- package/dist/server-shell/local-console/session.d.ts +10 -15
- package/dist/server-shell/local-console/session.js +69 -17
- package/package.json +1 -1
- package/web/assets/index-B84rQ4YJ.js +29 -0
- package/web/assets/{index-BcZpeSaX.css → index-C7RDpM1L.css} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-DKf4jz_E.js +0 -29
|
@@ -1,33 +1,28 @@
|
|
|
1
|
+
import type { LocalConsoleInvocationContext } from "./invocation-context.js";
|
|
1
2
|
export declare const LOCAL_CONSOLE_SESSION_COOKIE = "tutti_local_console_session";
|
|
2
|
-
type ExpiringValue = {
|
|
3
|
-
hash: string;
|
|
4
|
-
expiresAt: number;
|
|
5
|
-
};
|
|
6
|
-
type LocalConsoleSession = ExpiringValue & {
|
|
7
|
-
csrfToken: string;
|
|
8
|
-
currentDirectory: string;
|
|
9
|
-
};
|
|
10
3
|
export type IssuedLocalConsoleAccessToken = {
|
|
11
4
|
token: string;
|
|
12
5
|
expires_at: string;
|
|
13
6
|
};
|
|
14
7
|
export type ExchangedLocalConsoleSession = {
|
|
15
|
-
sessionToken
|
|
8
|
+
sessionToken?: string;
|
|
9
|
+
contextToken: string;
|
|
16
10
|
csrfToken: string;
|
|
17
11
|
expires_at: string;
|
|
18
12
|
};
|
|
13
|
+
export type ReadLocalConsoleSession = {
|
|
14
|
+
csrfToken: string;
|
|
15
|
+
context: LocalConsoleInvocationContext;
|
|
16
|
+
};
|
|
19
17
|
export declare class LocalConsoleSessionRegistry {
|
|
20
18
|
#private;
|
|
21
19
|
constructor(options?: {
|
|
22
20
|
now?: () => Date;
|
|
23
21
|
});
|
|
24
|
-
issueAccessToken(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
exchangeAccessToken(token: string): ExchangedLocalConsoleSession | null;
|
|
28
|
-
readSession(token: string | undefined): LocalConsoleSession | null;
|
|
22
|
+
issueAccessToken(context: LocalConsoleInvocationContext): IssuedLocalConsoleAccessToken;
|
|
23
|
+
exchangeAccessToken(token: string, existingSessionToken?: string): ExchangedLocalConsoleSession | null;
|
|
24
|
+
readSession(token: string | undefined, contextToken?: string): ReadLocalConsoleSession | null;
|
|
29
25
|
}
|
|
30
26
|
export declare function parseCookieHeader(header: string | undefined): Record<string, string>;
|
|
31
27
|
export declare function localConsoleSessionCookie(token: string, expiresAt: string): string;
|
|
32
|
-
export {};
|
|
33
28
|
//# sourceMappingURL=session.d.ts.map
|
|
@@ -16,22 +16,24 @@ function secretEquals(value, expectedHash) {
|
|
|
16
16
|
export class LocalConsoleSessionRegistry {
|
|
17
17
|
#accessTokens = new Map();
|
|
18
18
|
#sessions = new Map();
|
|
19
|
+
#contexts = new Map();
|
|
19
20
|
#now;
|
|
21
|
+
#browserSessionToken;
|
|
20
22
|
constructor(options = {}) {
|
|
21
23
|
this.#now = options.now ?? (() => new Date());
|
|
22
24
|
}
|
|
23
|
-
issueAccessToken(
|
|
25
|
+
issueAccessToken(context) {
|
|
24
26
|
this.#purgeExpired();
|
|
25
27
|
const token = createSecret();
|
|
26
28
|
const expiresAt = this.#now().getTime() + ACCESS_TOKEN_TTL_MS;
|
|
27
29
|
this.#accessTokens.set(hashSecret(token), {
|
|
28
30
|
hash: hashSecret(token),
|
|
29
31
|
expiresAt,
|
|
30
|
-
|
|
32
|
+
context,
|
|
31
33
|
});
|
|
32
34
|
return { token, expires_at: new Date(expiresAt).toISOString() };
|
|
33
35
|
}
|
|
34
|
-
exchangeAccessToken(token) {
|
|
36
|
+
exchangeAccessToken(token, existingSessionToken) {
|
|
35
37
|
this.#purgeExpired();
|
|
36
38
|
const accessTokenHash = hashSecret(token);
|
|
37
39
|
const accessToken = this.#accessTokens.get(accessTokenHash);
|
|
@@ -41,25 +43,58 @@ export class LocalConsoleSessionRegistry {
|
|
|
41
43
|
return null;
|
|
42
44
|
}
|
|
43
45
|
this.#accessTokens.delete(accessTokenHash);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
let sessionToken;
|
|
47
|
+
let sessionHash = "";
|
|
48
|
+
let session;
|
|
49
|
+
if (existingSessionToken !== undefined) {
|
|
50
|
+
sessionHash = hashSecret(existingSessionToken);
|
|
51
|
+
const existingSession = this.#sessions.get(sessionHash);
|
|
52
|
+
if (existingSession !== undefined &&
|
|
53
|
+
existingSession.expiresAt > this.#now().getTime() &&
|
|
54
|
+
secretEquals(existingSessionToken, existingSession.hash)) {
|
|
55
|
+
session = existingSession;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (session === undefined && this.#browserSessionToken !== undefined) {
|
|
59
|
+
const sharedSessionHash = hashSecret(this.#browserSessionToken);
|
|
60
|
+
const sharedSession = this.#sessions.get(sharedSessionHash);
|
|
61
|
+
if (sharedSession !== undefined &&
|
|
62
|
+
sharedSession.expiresAt > this.#now().getTime() &&
|
|
63
|
+
secretEquals(this.#browserSessionToken, sharedSession.hash)) {
|
|
64
|
+
sessionToken = this.#browserSessionToken;
|
|
65
|
+
sessionHash = sharedSessionHash;
|
|
66
|
+
session = sharedSession;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
53
69
|
if (session === undefined) {
|
|
54
|
-
|
|
70
|
+
sessionToken = createSecret();
|
|
71
|
+
this.#browserSessionToken = sessionToken;
|
|
72
|
+
sessionHash = hashSecret(sessionToken);
|
|
73
|
+
session = {
|
|
74
|
+
hash: sessionHash,
|
|
75
|
+
csrfToken: createSecret(),
|
|
76
|
+
expiresAt: this.#now().getTime() + SESSION_TTL_MS,
|
|
77
|
+
defaultContextHash: "",
|
|
78
|
+
};
|
|
79
|
+
this.#sessions.set(sessionHash, session);
|
|
55
80
|
}
|
|
81
|
+
const contextToken = createSecret();
|
|
82
|
+
const contextHash = hashSecret(contextToken);
|
|
83
|
+
session.defaultContextHash = contextHash;
|
|
84
|
+
this.#contexts.set(contextHash, {
|
|
85
|
+
hash: contextHash,
|
|
86
|
+
expiresAt: session.expiresAt,
|
|
87
|
+
sessionHash,
|
|
88
|
+
context: accessToken.context,
|
|
89
|
+
});
|
|
56
90
|
return {
|
|
57
|
-
sessionToken,
|
|
91
|
+
...(sessionToken === undefined ? {} : { sessionToken }),
|
|
92
|
+
contextToken,
|
|
58
93
|
csrfToken: session.csrfToken,
|
|
59
|
-
expires_at: new Date(expiresAt).toISOString(),
|
|
94
|
+
expires_at: new Date(session.expiresAt).toISOString(),
|
|
60
95
|
};
|
|
61
96
|
}
|
|
62
|
-
readSession(token) {
|
|
97
|
+
readSession(token, contextToken) {
|
|
63
98
|
this.#purgeExpired();
|
|
64
99
|
if (token === undefined || token.trim() === "") {
|
|
65
100
|
return null;
|
|
@@ -70,7 +105,15 @@ export class LocalConsoleSessionRegistry {
|
|
|
70
105
|
!secretEquals(token, session.hash)) {
|
|
71
106
|
return null;
|
|
72
107
|
}
|
|
73
|
-
|
|
108
|
+
const contextHash = contextToken === undefined ? session.defaultContextHash : hashSecret(contextToken);
|
|
109
|
+
const context = this.#contexts.get(contextHash);
|
|
110
|
+
if (context === undefined ||
|
|
111
|
+
context.sessionHash !== hashSecret(token) ||
|
|
112
|
+
context.expiresAt <= this.#now().getTime() ||
|
|
113
|
+
(contextToken !== undefined && !secretEquals(contextToken, context.hash))) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
return { csrfToken: session.csrfToken, context: context.context };
|
|
74
117
|
}
|
|
75
118
|
#purgeExpired() {
|
|
76
119
|
const now = this.#now().getTime();
|
|
@@ -84,6 +127,15 @@ export class LocalConsoleSessionRegistry {
|
|
|
84
127
|
this.#sessions.delete(key);
|
|
85
128
|
}
|
|
86
129
|
}
|
|
130
|
+
if (this.#browserSessionToken !== undefined &&
|
|
131
|
+
!this.#sessions.has(hashSecret(this.#browserSessionToken))) {
|
|
132
|
+
this.#browserSessionToken = undefined;
|
|
133
|
+
}
|
|
134
|
+
for (const [key, value] of this.#contexts) {
|
|
135
|
+
if (value.expiresAt <= now || !this.#sessions.has(value.sessionHash)) {
|
|
136
|
+
this.#contexts.delete(key);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
87
139
|
}
|
|
88
140
|
}
|
|
89
141
|
export function parseCookieHeader(header) {
|