@braidhq/server 0.0.1
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/LICENSE +21 -0
- package/dist/app.d.ts +7 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +71 -0
- package/dist/app.js.map +1 -0
- package/dist/composeFs.d.ts +20 -0
- package/dist/composeFs.d.ts.map +1 -0
- package/dist/composeFs.js +134 -0
- package/dist/composeFs.js.map +1 -0
- package/dist/composition.d.ts +49 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +43 -0
- package/dist/composition.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/agent/ClaudeCodeAgentBinding.d.ts +8 -0
- package/dist/infrastructure/agent/ClaudeCodeAgentBinding.d.ts.map +1 -0
- package/dist/infrastructure/agent/ClaudeCodeAgentBinding.js +62 -0
- package/dist/infrastructure/agent/ClaudeCodeAgentBinding.js.map +1 -0
- package/dist/infrastructure/agent/SubprocessSkillRunner.d.ts +54 -0
- package/dist/infrastructure/agent/SubprocessSkillRunner.d.ts.map +1 -0
- package/dist/infrastructure/agent/SubprocessSkillRunner.js +240 -0
- package/dist/infrastructure/agent/SubprocessSkillRunner.js.map +1 -0
- package/dist/infrastructure/agent/asyncQueue.d.ts +22 -0
- package/dist/infrastructure/agent/asyncQueue.d.ts.map +1 -0
- package/dist/infrastructure/agent/asyncQueue.js +43 -0
- package/dist/infrastructure/agent/asyncQueue.js.map +1 -0
- package/dist/infrastructure/agent/mcpConfig.d.ts +18 -0
- package/dist/infrastructure/agent/mcpConfig.d.ts.map +1 -0
- package/dist/infrastructure/agent/mcpConfig.js +47 -0
- package/dist/infrastructure/agent/mcpConfig.js.map +1 -0
- package/dist/infrastructure/agent/streamJsonParser.d.ts +20 -0
- package/dist/infrastructure/agent/streamJsonParser.d.ts.map +1 -0
- package/dist/infrastructure/agent/streamJsonParser.js +44 -0
- package/dist/infrastructure/agent/streamJsonParser.js.map +1 -0
- package/dist/infrastructure/agent/subprocessEventStream.d.ts +26 -0
- package/dist/infrastructure/agent/subprocessEventStream.d.ts.map +1 -0
- package/dist/infrastructure/agent/subprocessEventStream.js +112 -0
- package/dist/infrastructure/agent/subprocessEventStream.js.map +1 -0
- package/dist/infrastructure/fs/FsClarifyTicketRepository.d.ts +13 -0
- package/dist/infrastructure/fs/FsClarifyTicketRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsClarifyTicketRepository.js +33 -0
- package/dist/infrastructure/fs/FsClarifyTicketRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsDecisionRepository.d.ts +13 -0
- package/dist/infrastructure/fs/FsDecisionRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsDecisionRepository.js +56 -0
- package/dist/infrastructure/fs/FsDecisionRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsProposalRepository.d.ts +14 -0
- package/dist/infrastructure/fs/FsProposalRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsProposalRepository.js +40 -0
- package/dist/infrastructure/fs/FsProposalRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsRunRepository.d.ts +21 -0
- package/dist/infrastructure/fs/FsRunRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsRunRepository.js +88 -0
- package/dist/infrastructure/fs/FsRunRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsSkillRegistry.d.ts +34 -0
- package/dist/infrastructure/fs/FsSkillRegistry.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsSkillRegistry.js +143 -0
- package/dist/infrastructure/fs/FsSkillRegistry.js.map +1 -0
- package/dist/infrastructure/fs/FsStatusedJsonRepository.d.ts +35 -0
- package/dist/infrastructure/fs/FsStatusedJsonRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsStatusedJsonRepository.js +79 -0
- package/dist/infrastructure/fs/FsStatusedJsonRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsWorkspaceRepository.d.ts +21 -0
- package/dist/infrastructure/fs/FsWorkspaceRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsWorkspaceRepository.js +87 -0
- package/dist/infrastructure/fs/FsWorkspaceRepository.js.map +1 -0
- package/dist/infrastructure/fs/WorkspaceRegistryFile.d.ts +17 -0
- package/dist/infrastructure/fs/WorkspaceRegistryFile.d.ts.map +1 -0
- package/dist/infrastructure/fs/WorkspaceRegistryFile.js +58 -0
- package/dist/infrastructure/fs/WorkspaceRegistryFile.js.map +1 -0
- package/dist/infrastructure/fs/frontmatter.d.ts +13 -0
- package/dist/infrastructure/fs/frontmatter.d.ts.map +1 -0
- package/dist/infrastructure/fs/frontmatter.js +46 -0
- package/dist/infrastructure/fs/frontmatter.js.map +1 -0
- package/dist/infrastructure/fs/jsonFileStore.d.ts +5 -0
- package/dist/infrastructure/fs/jsonFileStore.d.ts.map +1 -0
- package/dist/infrastructure/fs/jsonFileStore.js +29 -0
- package/dist/infrastructure/fs/jsonFileStore.js.map +1 -0
- package/dist/infrastructure/fs/paths.d.ts +22 -0
- package/dist/infrastructure/fs/paths.d.ts.map +1 -0
- package/dist/infrastructure/fs/paths.js +46 -0
- package/dist/infrastructure/fs/paths.js.map +1 -0
- package/dist/infrastructure/fs/productManifestWriter.d.ts +22 -0
- package/dist/infrastructure/fs/productManifestWriter.d.ts.map +1 -0
- package/dist/infrastructure/fs/productManifestWriter.js +75 -0
- package/dist/infrastructure/fs/productManifestWriter.js.map +1 -0
- package/dist/infrastructure/oauth/GoogleOAuth.d.ts +60 -0
- package/dist/infrastructure/oauth/GoogleOAuth.d.ts.map +1 -0
- package/dist/infrastructure/oauth/GoogleOAuth.js +114 -0
- package/dist/infrastructure/oauth/GoogleOAuth.js.map +1 -0
- package/dist/infrastructure/orphanReaper.d.ts +18 -0
- package/dist/infrastructure/orphanReaper.d.ts.map +1 -0
- package/dist/infrastructure/orphanReaper.js +42 -0
- package/dist/infrastructure/orphanReaper.js.map +1 -0
- package/dist/infrastructure/secrets/SecretStore.d.ts +36 -0
- package/dist/infrastructure/secrets/SecretStore.d.ts.map +1 -0
- package/dist/infrastructure/secrets/SecretStore.js +44 -0
- package/dist/infrastructure/secrets/SecretStore.js.map +1 -0
- package/dist/middleware/cors.d.ts +11 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +30 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/error.d.ts +3 -0
- package/dist/middleware/error.d.ts.map +1 -0
- package/dist/middleware/error.js +52 -0
- package/dist/middleware/error.js.map +1 -0
- package/dist/middleware/workspaceId.d.ts +10 -0
- package/dist/middleware/workspaceId.d.ts.map +1 -0
- package/dist/middleware/workspaceId.js +9 -0
- package/dist/middleware/workspaceId.js.map +1 -0
- package/dist/routes/clarify.d.ts +8 -0
- package/dist/routes/clarify.d.ts.map +1 -0
- package/dist/routes/clarify.js +84 -0
- package/dist/routes/clarify.js.map +1 -0
- package/dist/routes/decisions.d.ts +7 -0
- package/dist/routes/decisions.d.ts.map +1 -0
- package/dist/routes/decisions.js +30 -0
- package/dist/routes/decisions.js.map +1 -0
- package/dist/routes/edges.d.ts +7 -0
- package/dist/routes/edges.d.ts.map +1 -0
- package/dist/routes/edges.js +30 -0
- package/dist/routes/edges.js.map +1 -0
- package/dist/routes/health.d.ts +3 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +10 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/helpers.d.ts +5 -0
- package/dist/routes/helpers.d.ts.map +1 -0
- package/dist/routes/helpers.js +14 -0
- package/dist/routes/helpers.js.map +1 -0
- package/dist/routes/model.d.ts +7 -0
- package/dist/routes/model.d.ts.map +1 -0
- package/dist/routes/model.js +12 -0
- package/dist/routes/model.js.map +1 -0
- package/dist/routes/nodes.d.ts +7 -0
- package/dist/routes/nodes.d.ts.map +1 -0
- package/dist/routes/nodes.js +47 -0
- package/dist/routes/nodes.js.map +1 -0
- package/dist/routes/oauth.d.ts +20 -0
- package/dist/routes/oauth.d.ts.map +1 -0
- package/dist/routes/oauth.js +107 -0
- package/dist/routes/oauth.js.map +1 -0
- package/dist/routes/ontology.d.ts +8 -0
- package/dist/routes/ontology.d.ts.map +1 -0
- package/dist/routes/ontology.js +21 -0
- package/dist/routes/ontology.js.map +1 -0
- package/dist/routes/proposals.d.ts +10 -0
- package/dist/routes/proposals.d.ts.map +1 -0
- package/dist/routes/proposals.js +80 -0
- package/dist/routes/proposals.js.map +1 -0
- package/dist/routes/runs.d.ts +9 -0
- package/dist/routes/runs.d.ts.map +1 -0
- package/dist/routes/runs.js +73 -0
- package/dist/routes/runs.js.map +1 -0
- package/dist/routes/skills.d.ts +9 -0
- package/dist/routes/skills.d.ts.map +1 -0
- package/dist/routes/skills.js +42 -0
- package/dist/routes/skills.js.map +1 -0
- package/dist/routes/workspaceEvents.d.ts +14 -0
- package/dist/routes/workspaceEvents.d.ts.map +1 -0
- package/dist/routes/workspaceEvents.js +37 -0
- package/dist/routes/workspaceEvents.js.map +1 -0
- package/dist/routes/workspaces.d.ts +8 -0
- package/dist/routes/workspaces.d.ts.map +1 -0
- package/dist/routes/workspaces.js +167 -0
- package/dist/routes/workspaces.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +33 -0
- package/dist/server.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface GoogleOAuthConfig {
|
|
2
|
+
/** OAuth client id from the user's GCP project. */
|
|
3
|
+
readonly clientId: string;
|
|
4
|
+
/** OAuth client secret. */
|
|
5
|
+
readonly clientSecret: string;
|
|
6
|
+
/** Absolute redirect URI registered in the GCP OAuth client. */
|
|
7
|
+
readonly redirectUri: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AuthorizationUrlInput {
|
|
10
|
+
/** OAuth scope(s) requested. Braid passes Drive read-only. */
|
|
11
|
+
readonly scopes: readonly string[];
|
|
12
|
+
/** State token (CSRF + flow-restore). */
|
|
13
|
+
readonly state: string;
|
|
14
|
+
/** PKCE verifier; the URL embeds its SHA-256 challenge. */
|
|
15
|
+
readonly codeVerifier: string;
|
|
16
|
+
}
|
|
17
|
+
export interface TokenSet {
|
|
18
|
+
readonly accessToken: string;
|
|
19
|
+
readonly refreshToken: string;
|
|
20
|
+
readonly expiresAt: string;
|
|
21
|
+
readonly scope: string;
|
|
22
|
+
readonly tokenType: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RefreshedAccessToken {
|
|
25
|
+
readonly accessToken: string;
|
|
26
|
+
readonly expiresAt: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Minimal Google OAuth 2.0 client for installed-app / web flow.
|
|
30
|
+
*
|
|
31
|
+
* Why not `openid-client` or `google-auth-library`: we only need 4 calls
|
|
32
|
+
* (build URL, exchange code, refresh, revoke); avoiding a heavyweight
|
|
33
|
+
* dependency keeps the server's install footprint small and the auth
|
|
34
|
+
* surface auditable.
|
|
35
|
+
*/
|
|
36
|
+
export declare class GoogleOAuth {
|
|
37
|
+
private readonly config;
|
|
38
|
+
constructor(config: GoogleOAuthConfig);
|
|
39
|
+
/**
|
|
40
|
+
* Build the URL the user's browser is sent to. `state` and `codeVerifier`
|
|
41
|
+
* MUST be unique per flow; the caller stores them in pending-state until
|
|
42
|
+
* the callback arrives.
|
|
43
|
+
*/
|
|
44
|
+
buildAuthorizationUrl(input: AuthorizationUrlInput): string;
|
|
45
|
+
exchangeCode(input: {
|
|
46
|
+
code: string;
|
|
47
|
+
codeVerifier: string;
|
|
48
|
+
}): Promise<TokenSet>;
|
|
49
|
+
refreshAccessToken(refreshToken: string): Promise<RefreshedAccessToken>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Helper for callers: produce a fresh PKCE verifier (32 bytes, base64url).
|
|
53
|
+
* Caller stashes alongside the `state` token until the callback returns.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createPkceVerifier(): string;
|
|
56
|
+
/**
|
|
57
|
+
* CSRF state token. Random 16 bytes, opaque to Google.
|
|
58
|
+
*/
|
|
59
|
+
export declare function createOAuthState(): string;
|
|
60
|
+
//# sourceMappingURL=GoogleOAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GoogleOAuth.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/oauth/GoogleOAuth.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,2BAA2B;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;;;GAOG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,iBAAiB;IAEtD;;;;OAIG;IACH,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM;IAgBrD,YAAY,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;IA2B9E,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAsB9E;AA4BD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
const AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/v2/auth';
|
|
3
|
+
const TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token';
|
|
4
|
+
/**
|
|
5
|
+
* Minimal Google OAuth 2.0 client for installed-app / web flow.
|
|
6
|
+
*
|
|
7
|
+
* Why not `openid-client` or `google-auth-library`: we only need 4 calls
|
|
8
|
+
* (build URL, exchange code, refresh, revoke); avoiding a heavyweight
|
|
9
|
+
* dependency keeps the server's install footprint small and the auth
|
|
10
|
+
* surface auditable.
|
|
11
|
+
*/
|
|
12
|
+
export class GoogleOAuth {
|
|
13
|
+
config;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Build the URL the user's browser is sent to. `state` and `codeVerifier`
|
|
19
|
+
* MUST be unique per flow; the caller stores them in pending-state until
|
|
20
|
+
* the callback arrives.
|
|
21
|
+
*/
|
|
22
|
+
buildAuthorizationUrl(input) {
|
|
23
|
+
const params = new URLSearchParams({
|
|
24
|
+
client_id: this.config.clientId,
|
|
25
|
+
redirect_uri: this.config.redirectUri,
|
|
26
|
+
response_type: 'code',
|
|
27
|
+
scope: input.scopes.join(' '),
|
|
28
|
+
access_type: 'offline', // → refresh_token in response
|
|
29
|
+
prompt: 'consent', // ensure refresh_token even on re-auth
|
|
30
|
+
include_granted_scopes: 'true',
|
|
31
|
+
state: input.state,
|
|
32
|
+
code_challenge: pkceChallenge(input.codeVerifier),
|
|
33
|
+
code_challenge_method: 'S256',
|
|
34
|
+
});
|
|
35
|
+
return `${AUTH_ENDPOINT}?${params.toString()}`;
|
|
36
|
+
}
|
|
37
|
+
async exchangeCode(input) {
|
|
38
|
+
const body = new URLSearchParams({
|
|
39
|
+
client_id: this.config.clientId,
|
|
40
|
+
client_secret: this.config.clientSecret,
|
|
41
|
+
redirect_uri: this.config.redirectUri,
|
|
42
|
+
grant_type: 'authorization_code',
|
|
43
|
+
code: input.code,
|
|
44
|
+
code_verifier: input.codeVerifier,
|
|
45
|
+
});
|
|
46
|
+
const response = await fetch(TOKEN_ENDPOINT, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
49
|
+
body,
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
const text = await response.text().catch(() => '');
|
|
53
|
+
throw new Error(`Google token exchange failed: ${response.status} ${response.statusText} ${text}`);
|
|
54
|
+
}
|
|
55
|
+
const payload = await response.json();
|
|
56
|
+
if (!payload.refresh_token) {
|
|
57
|
+
// Google only returns refresh_token on first consent. If we don't have
|
|
58
|
+
// one, the caller can't store anything useful for next time.
|
|
59
|
+
throw new Error('Google did not return a refresh_token. Add prompt=consent and ensure access_type=offline.');
|
|
60
|
+
}
|
|
61
|
+
return tokenSetFromPayload(payload);
|
|
62
|
+
}
|
|
63
|
+
async refreshAccessToken(refreshToken) {
|
|
64
|
+
const body = new URLSearchParams({
|
|
65
|
+
client_id: this.config.clientId,
|
|
66
|
+
client_secret: this.config.clientSecret,
|
|
67
|
+
grant_type: 'refresh_token',
|
|
68
|
+
refresh_token: refreshToken,
|
|
69
|
+
});
|
|
70
|
+
const response = await fetch(TOKEN_ENDPOINT, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
73
|
+
body,
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
const text = await response.text().catch(() => '');
|
|
77
|
+
throw new Error(`Google token refresh failed: ${response.status} ${response.statusText} ${text}`);
|
|
78
|
+
}
|
|
79
|
+
const payload = await response.json();
|
|
80
|
+
return {
|
|
81
|
+
accessToken: payload.access_token,
|
|
82
|
+
expiresAt: secondsFromNow(payload.expires_in).toISOString(),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function tokenSetFromPayload(p) {
|
|
87
|
+
return {
|
|
88
|
+
accessToken: p.access_token,
|
|
89
|
+
refreshToken: p.refresh_token,
|
|
90
|
+
expiresAt: secondsFromNow(p.expires_in).toISOString(),
|
|
91
|
+
scope: p.scope,
|
|
92
|
+
tokenType: p.token_type,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function secondsFromNow(seconds) {
|
|
96
|
+
return new Date(Date.now() + seconds * 1000);
|
|
97
|
+
}
|
|
98
|
+
function pkceChallenge(verifier) {
|
|
99
|
+
return createHash('sha256').update(verifier).digest('base64url');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Helper for callers: produce a fresh PKCE verifier (32 bytes, base64url).
|
|
103
|
+
* Caller stashes alongside the `state` token until the callback returns.
|
|
104
|
+
*/
|
|
105
|
+
export function createPkceVerifier() {
|
|
106
|
+
return randomBytes(32).toString('base64url');
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* CSRF state token. Random 16 bytes, opaque to Google.
|
|
110
|
+
*/
|
|
111
|
+
export function createOAuthState() {
|
|
112
|
+
return randomBytes(16).toString('base64url');
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=GoogleOAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GoogleOAuth.js","sourceRoot":"","sources":["../../../src/infrastructure/oauth/GoogleOAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Clock, RunRepository, WorkspaceRepository } from '@braidhq/core';
|
|
2
|
+
/**
|
|
3
|
+
* Run records survive across server restarts, but the subprocess that was
|
|
4
|
+
* driving each run does not. On startup any run without a `completedAt`
|
|
5
|
+
* timestamp is an orphan: nobody is going to drain its events. We tag those
|
|
6
|
+
* with a synthetic `error` event so the UI can show why the transcript is
|
|
7
|
+
* truncated, and a `completed` event so the run leaves the active list.
|
|
8
|
+
*
|
|
9
|
+
* Idempotent: runs that are already marked completed are skipped.
|
|
10
|
+
*/
|
|
11
|
+
export declare function reapOrphanRuns(deps: {
|
|
12
|
+
workspaceRepository: WorkspaceRepository;
|
|
13
|
+
runRepository: RunRepository;
|
|
14
|
+
clock: Clock;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
reaped: number;
|
|
17
|
+
}>;
|
|
18
|
+
//# sourceMappingURL=orphanReaper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orphanReaper.d.ts","sourceRoot":"","sources":["../../src/infrastructure/orphanReaper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAG9E;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,aAAa,EAAE,aAAa,CAAA;IAC5B,KAAK,EAAE,KAAK,CAAA;CACb,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA+B9B"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run records survive across server restarts, but the subprocess that was
|
|
3
|
+
* driving each run does not. On startup any run without a `completedAt`
|
|
4
|
+
* timestamp is an orphan: nobody is going to drain its events. We tag those
|
|
5
|
+
* with a synthetic `error` event so the UI can show why the transcript is
|
|
6
|
+
* truncated, and a `completed` event so the run leaves the active list.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent: runs that are already marked completed are skipped.
|
|
9
|
+
*/
|
|
10
|
+
export async function reapOrphanRuns(deps) {
|
|
11
|
+
const workspaces = await deps.workspaceRepository.list();
|
|
12
|
+
let reaped = 0;
|
|
13
|
+
for (const workspace of workspaces) {
|
|
14
|
+
const records = await deps.runRepository.listRecords(workspace);
|
|
15
|
+
for (const record of records) {
|
|
16
|
+
if (record.completedAt !== undefined)
|
|
17
|
+
continue;
|
|
18
|
+
const at = deps.clock.now();
|
|
19
|
+
const error = {
|
|
20
|
+
type: 'error',
|
|
21
|
+
message: 'Run aborted: server restarted before the subprocess finished.',
|
|
22
|
+
at,
|
|
23
|
+
};
|
|
24
|
+
const completed = {
|
|
25
|
+
type: 'completed',
|
|
26
|
+
runId: record.runId,
|
|
27
|
+
exitCode: -1,
|
|
28
|
+
at,
|
|
29
|
+
};
|
|
30
|
+
await deps.runRepository.appendEvent(workspace, record.runId, error);
|
|
31
|
+
await deps.runRepository.appendEvent(workspace, record.runId, completed);
|
|
32
|
+
await deps.runRepository.saveRecord(workspace, {
|
|
33
|
+
...record,
|
|
34
|
+
completedAt: at,
|
|
35
|
+
exitCode: -1,
|
|
36
|
+
});
|
|
37
|
+
reaped++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { reaped };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=orphanReaper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orphanReaper.js","sourceRoot":"","sources":["../../src/infrastructure/orphanReaper.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAIpC;IACC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAA;IACxD,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;QAC/D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS;gBAClC,SAAQ;YACV,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;YAC3B,MAAM,KAAK,GAAe;gBACxB,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,+DAA+D;gBACxE,EAAE;aACH,CAAA;YACD,MAAM,SAAS,GAAe;gBAC5B,IAAI,EAAE,WAAW;gBACjB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,CAAC,CAAC;gBACZ,EAAE;aACH,CAAA;YACD,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YACpE,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;YACxE,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,EAAE;gBAC7C,GAAG,MAAM;gBACT,WAAW,EAAE,EAAE;gBACf,QAAQ,EAAE,CAAC,CAAC;aACb,CAAC,CAAA;YACF,MAAM,EAAE,CAAA;QACV,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-scope JSON secret storage on the local filesystem. One file per
|
|
3
|
+
* `(namespace, key)` under `<root>/<namespace>/<key>.json`. Files are
|
|
4
|
+
* written with mode 0600 so only the running user can read them; the
|
|
5
|
+
* containing directory is mode 0700.
|
|
6
|
+
*
|
|
7
|
+
* This is NOT an encrypted-at-rest store. It's appropriate for local /
|
|
8
|
+
* single-user Braid installs (the OSS target). A hosted SaaS deployment
|
|
9
|
+
* would swap this for a vault adapter (AWS Secrets Manager, Vault, …)
|
|
10
|
+
* by implementing the same interface.
|
|
11
|
+
*
|
|
12
|
+
* Layout:
|
|
13
|
+
* <root>/
|
|
14
|
+
* oauth-google/
|
|
15
|
+
* <workspaceId>--<sourceId>.json # one set of tokens per source
|
|
16
|
+
* oauth-github/
|
|
17
|
+
* <workspaceId>--<sourceId>.json
|
|
18
|
+
*/
|
|
19
|
+
export interface SecretRecord {
|
|
20
|
+
readonly value: unknown;
|
|
21
|
+
readonly updatedAt: string;
|
|
22
|
+
}
|
|
23
|
+
export interface SecretStore {
|
|
24
|
+
read: <T>(namespace: string, key: string) => Promise<T | undefined>;
|
|
25
|
+
write: (namespace: string, key: string, value: unknown) => Promise<void>;
|
|
26
|
+
delete: (namespace: string, key: string) => Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export declare class FsSecretStore implements SecretStore {
|
|
29
|
+
private readonly root;
|
|
30
|
+
constructor(root: string);
|
|
31
|
+
read<T>(namespace: string, key: string): Promise<T | undefined>;
|
|
32
|
+
write(namespace: string, key: string, value: unknown): Promise<void>;
|
|
33
|
+
delete(namespace: string, key: string): Promise<void>;
|
|
34
|
+
private pathFor;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=SecretStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SecretStore.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/secrets/SecretStore.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAA;IACnE,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxE,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1D;AAED,qBAAa,aAAc,YAAW,WAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,MAAM;IAEnC,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAc/D,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3D,OAAO,CAAC,OAAO;CAGhB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { chmod, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
export class FsSecretStore {
|
|
4
|
+
root;
|
|
5
|
+
constructor(root) {
|
|
6
|
+
this.root = root;
|
|
7
|
+
}
|
|
8
|
+
async read(namespace, key) {
|
|
9
|
+
const path = this.pathFor(namespace, key);
|
|
10
|
+
try {
|
|
11
|
+
const raw = await readFile(path, 'utf-8');
|
|
12
|
+
const record = JSON.parse(raw);
|
|
13
|
+
return record.value;
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error.code === 'ENOENT')
|
|
17
|
+
return undefined;
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async write(namespace, key, value) {
|
|
22
|
+
const path = this.pathFor(namespace, key);
|
|
23
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
24
|
+
const record = { value, updatedAt: new Date().toISOString() };
|
|
25
|
+
await writeFile(path, JSON.stringify(record, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
26
|
+
// mkdir's mode arg is ignored on some platforms; explicitly chmod the
|
|
27
|
+
// dir + file to keep the perms stable across reboots / restores.
|
|
28
|
+
await chmod(dirname(path), 0o700);
|
|
29
|
+
await chmod(path, 0o600);
|
|
30
|
+
}
|
|
31
|
+
async delete(namespace, key) {
|
|
32
|
+
const path = this.pathFor(namespace, key);
|
|
33
|
+
await rm(path, { force: true });
|
|
34
|
+
}
|
|
35
|
+
pathFor(namespace, key) {
|
|
36
|
+
return join(this.root, sanitize(namespace), `${sanitize(key)}.json`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Conservative: only ASCII letters / digits / `-`, `_`, `.`. Anything else
|
|
40
|
+
// is replaced with `_` so a hostile workspaceId can't escape the dir.
|
|
41
|
+
function sanitize(input) {
|
|
42
|
+
return input.replace(/[^\w.-]/g, '_');
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=SecretStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SecretStore.js","sourceRoot":"","sources":["../../../src/infrastructure/secrets/SecretStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACxE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AA+BzC,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAE7C,KAAK,CAAC,IAAI,CAAI,SAAiB,EAAE,GAAW;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QACzC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAA;YAC9C,OAAO,MAAM,CAAC,KAAU,CAAA;QAC1B,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACb,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBACpD,OAAO,SAAS,CAAA;YAClB,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,SAAiB,EAAE,GAAW,EAAE,KAAc;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QACzC,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC5D,MAAM,MAAM,GAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAA;QAC3E,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC1F,sEAAsE;QACtE,iEAAiE;QACjE,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAA;QACjC,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,GAAW;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QACzC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACjC,CAAC;IAEO,OAAO,CAAC,SAAiB,EAAE,GAAW;QAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACtE,CAAC;CACF;AAED,2EAA2E;AAC3E,sEAAsE;AACtE,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;AACvC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
export interface CorsOptions {
|
|
3
|
+
readonly allowedOrigins?: readonly string[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Permissive CORS for Studio dev / Tier 1 (Tauri embedded server).
|
|
7
|
+
* Origins default to Vite dev server ports. In production deployments,
|
|
8
|
+
* pass the actual studio origin list explicitly.
|
|
9
|
+
*/
|
|
10
|
+
export declare function corsMiddleware(options?: CorsOptions): MiddlewareHandler;
|
|
11
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAQ7C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,WAAgB,GAAG,iBAAiB,CAkB3E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const DEFAULT_DEV_ORIGINS = [
|
|
2
|
+
'http://localhost:5173',
|
|
3
|
+
'http://localhost:4173',
|
|
4
|
+
'http://127.0.0.1:5173',
|
|
5
|
+
];
|
|
6
|
+
/**
|
|
7
|
+
* Permissive CORS for Studio dev / Tier 1 (Tauri embedded server).
|
|
8
|
+
* Origins default to Vite dev server ports. In production deployments,
|
|
9
|
+
* pass the actual studio origin list explicitly.
|
|
10
|
+
*/
|
|
11
|
+
export function corsMiddleware(options = {}) {
|
|
12
|
+
const allowed = new Set(options.allowedOrigins ?? DEFAULT_DEV_ORIGINS);
|
|
13
|
+
return async (context, next) => {
|
|
14
|
+
const origin = context.req.header('Origin');
|
|
15
|
+
if (origin && allowed.has(origin)) {
|
|
16
|
+
context.header('Access-Control-Allow-Origin', origin);
|
|
17
|
+
context.header('Access-Control-Allow-Credentials', 'true');
|
|
18
|
+
context.header('Vary', 'Origin');
|
|
19
|
+
}
|
|
20
|
+
if (context.req.method === 'OPTIONS') {
|
|
21
|
+
context.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
|
22
|
+
context.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
23
|
+
context.header('Access-Control-Max-Age', '86400');
|
|
24
|
+
return context.body(null, 204);
|
|
25
|
+
}
|
|
26
|
+
await next();
|
|
27
|
+
return undefined;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAEA,MAAM,mBAAmB,GAAG;IAC1B,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;CACxB,CAAA;AAMD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,UAAuB,EAAE;IACtD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,mBAAmB,CAAC,CAAA;IACtE,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAC3C,IAAI,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,MAAM,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAA;YACrD,OAAO,CAAC,MAAM,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAA;YAC1D,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QAClC,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACrC,OAAO,CAAC,MAAM,CAAC,8BAA8B,EAAE,wCAAwC,CAAC,CAAA;YACxF,OAAO,CAAC,MAAM,CAAC,8BAA8B,EAAE,6BAA6B,CAAC,CAAA;YAC7E,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAA;YACjD,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QAChC,CAAC;QACD,MAAM,IAAI,EAAE,CAAA;QACZ,OAAO,SAAS,CAAA;IAClB,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/middleware/error.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AA+CxC,eAAO,MAAM,YAAY,EAAE,YAkB1B,CAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BraidError, ConflictError, NotFoundError, ValidationError, } from '@braidhq/core';
|
|
2
|
+
import { ZodError } from 'zod';
|
|
3
|
+
const PROBLEM_BASE_URL = 'https://braid.dev/errors';
|
|
4
|
+
function statusFor(error) {
|
|
5
|
+
if (error instanceof ValidationError)
|
|
6
|
+
return 400;
|
|
7
|
+
if (error instanceof NotFoundError)
|
|
8
|
+
return 404;
|
|
9
|
+
if (error instanceof ConflictError)
|
|
10
|
+
return 409;
|
|
11
|
+
return 500;
|
|
12
|
+
}
|
|
13
|
+
function problemFromBraidError(error) {
|
|
14
|
+
const problem = {
|
|
15
|
+
type: `${PROBLEM_BASE_URL}/${error.code.toLowerCase()}`,
|
|
16
|
+
title: error.name,
|
|
17
|
+
status: statusFor(error),
|
|
18
|
+
code: error.code,
|
|
19
|
+
detail: error.message,
|
|
20
|
+
};
|
|
21
|
+
if (error instanceof ValidationError && error.issues)
|
|
22
|
+
problem.issues = [...error.issues];
|
|
23
|
+
return problem;
|
|
24
|
+
}
|
|
25
|
+
function problemFromZodError(error) {
|
|
26
|
+
return {
|
|
27
|
+
type: `${PROBLEM_BASE_URL}/braid-val`,
|
|
28
|
+
title: 'ValidationError',
|
|
29
|
+
status: 400,
|
|
30
|
+
code: 'BRAID-VAL',
|
|
31
|
+
detail: error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}`).join('; '),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const PROBLEM_JSON_HEADERS = { 'Content-Type': 'application/problem+json' };
|
|
35
|
+
export const errorHandler = (error, context) => {
|
|
36
|
+
if (error instanceof BraidError) {
|
|
37
|
+
const problem = problemFromBraidError(error);
|
|
38
|
+
return context.json(problem, problem.status, PROBLEM_JSON_HEADERS);
|
|
39
|
+
}
|
|
40
|
+
if (error instanceof ZodError) {
|
|
41
|
+
const problem = problemFromZodError(error);
|
|
42
|
+
return context.json(problem, problem.status, PROBLEM_JSON_HEADERS);
|
|
43
|
+
}
|
|
44
|
+
return context.json({
|
|
45
|
+
type: `${PROBLEM_BASE_URL}/internal`,
|
|
46
|
+
title: 'InternalError',
|
|
47
|
+
status: 500,
|
|
48
|
+
code: 'BRAID-INTERNAL',
|
|
49
|
+
detail: error instanceof Error ? error.message : 'unknown error',
|
|
50
|
+
}, 500, PROBLEM_JSON_HEADERS);
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/middleware/error.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAA;AAE9B,MAAM,gBAAgB,GAAG,0BAA0B,CAAA;AAEnD,SAAS,SAAS,CAAC,KAAiB;IAClC,IAAI,KAAK,YAAY,eAAe;QAClC,OAAO,GAAG,CAAA;IACZ,IAAI,KAAK,YAAY,aAAa;QAChC,OAAO,GAAG,CAAA;IACZ,IAAI,KAAK,YAAY,aAAa;QAChC,OAAO,GAAG,CAAA;IACZ,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAiB;IAC9C,MAAM,OAAO,GAAqB;QAChC,IAAI,EAAE,GAAG,gBAAgB,IAAI,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,EAA8B;QACnF,KAAK,EAAE,KAAK,CAAC,IAAI;QACjB,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC;QACxB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,OAAO;KACtB,CAAA;IACD,IAAI,KAAK,YAAY,eAAe,IAAI,KAAK,CAAC,MAAM;QAClD,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAA;IACpC,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAe;IAC1C,OAAO;QACL,IAAI,EAAE,GAAG,gBAAgB,YAAwC;QACjE,KAAK,EAAE,iBAAiB;QACxB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;KAC1F,CAAA;AACH,CAAC;AAED,MAAM,oBAAoB,GAAG,EAAE,cAAc,EAAE,0BAA0B,EAAW,CAAA;AAEpF,MAAM,CAAC,MAAM,YAAY,GAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IAC3D,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAA;QAC5C,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,MAA8B,EAAE,oBAAoB,CAAC,CAAA;IAC5F,CAAC;IAED,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAA;QAC1C,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,MAA8B,EAAE,oBAAoB,CAAC,CAAA;IAC5F,CAAC;IAED,OAAO,OAAO,CAAC,IAAI,CAAC;QAClB,IAAI,EAAE,GAAG,gBAAgB,WAAW;QACpC,KAAK,EAAE,eAAe;QACtB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;KACjE,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAA;AAC/B,CAAC,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WorkspaceId as WorkspaceIdType } from '@braidhq/schema';
|
|
2
|
+
import type { Context, MiddlewareHandler } from 'hono';
|
|
3
|
+
declare module 'hono' {
|
|
4
|
+
interface ContextVariableMap {
|
|
5
|
+
workspaceId: WorkspaceIdType;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export declare const workspaceIdMiddleware: MiddlewareHandler;
|
|
9
|
+
export declare function getWorkspaceId(context: Context): WorkspaceIdType;
|
|
10
|
+
//# sourceMappingURL=workspaceId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceId.d.ts","sourceRoot":"","sources":["../../src/middleware/workspaceId.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAGtD,OAAO,QAAQ,MAAM,CAAC;IACpB,UAAU,kBAAkB;QAC1B,WAAW,EAAE,eAAe,CAAA;KAC7B;CACF;AAED,eAAO,MAAM,qBAAqB,EAAE,iBAGnC,CAAA;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,CAEhE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { WorkspaceId } from '@braidhq/schema';
|
|
2
|
+
export const workspaceIdMiddleware = async (context, next) => {
|
|
3
|
+
context.set('workspaceId', WorkspaceId.parse(context.req.param('workspaceId')));
|
|
4
|
+
await next();
|
|
5
|
+
};
|
|
6
|
+
export function getWorkspaceId(context) {
|
|
7
|
+
return context.get('workspaceId');
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=workspaceId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceId.js","sourceRoot":"","sources":["../../src/middleware/workspaceId.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAQ7C,MAAM,CAAC,MAAM,qBAAqB,GAAsB,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAC9E,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAA;IAC/E,MAAM,IAAI,EAAE,CAAA;AACd,CAAC,CAAA;AAED,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;AACnC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ClarifyTicketRepository, HITLService } from '@braidhq/core';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
export interface ClarifyRouterDeps {
|
|
4
|
+
hitlService: HITLService;
|
|
5
|
+
clarifyRepository: ClarifyTicketRepository;
|
|
6
|
+
}
|
|
7
|
+
export declare function createClarifyRouter(deps: ClarifyRouterDeps): Hono;
|
|
8
|
+
//# sourceMappingURL=clarify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clarify.d.ts","sourceRoot":"","sources":["../../src/routes/clarify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAGzE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AA4B3B,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,WAAW,CAAA;IACxB,iBAAiB,EAAE,uBAAuB,CAAA;CAC3C;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CA6EjE"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ClarifyCandidateId, ClarifyDraft, ClarifyStatus, ClarifyTicketId, ProposalId, UserId } from '@braidhq/schema';
|
|
2
|
+
import { zValidator } from '@hono/zod-validator';
|
|
3
|
+
import { Hono } from 'hono';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { getWorkspaceId } from '../middleware/workspaceId.js';
|
|
6
|
+
import { assertEntityInWorkspace } from './helpers.js';
|
|
7
|
+
const ListQuerySchema = z.object({
|
|
8
|
+
status: z.union([ClarifyStatus, z.array(ClarifyStatus)]).optional(),
|
|
9
|
+
limit: z.coerce.number().int().positive().optional(),
|
|
10
|
+
offset: z.coerce.number().int().nonnegative().optional(),
|
|
11
|
+
});
|
|
12
|
+
const AnswerBodySchema = z.object({
|
|
13
|
+
candidateId: ClarifyCandidateId,
|
|
14
|
+
userId: UserId,
|
|
15
|
+
});
|
|
16
|
+
const SkipBodySchema = z.object({
|
|
17
|
+
reason: z.string().min(1),
|
|
18
|
+
userId: UserId,
|
|
19
|
+
});
|
|
20
|
+
const LinkProposalBodySchema = z.object({
|
|
21
|
+
proposalId: ProposalId,
|
|
22
|
+
userId: UserId,
|
|
23
|
+
});
|
|
24
|
+
const CreateBodySchema = ClarifyDraft.omit({ workspaceId: true });
|
|
25
|
+
export function createClarifyRouter(deps) {
|
|
26
|
+
const router = new Hono();
|
|
27
|
+
// Skill-facing create. Body is the ClarifyDraft minus workspaceId (taken
|
|
28
|
+
// from the URL). Candidates' proposedOperations are NOT validated here;
|
|
29
|
+
// they are validated when a user picks one via answerClarifyTicket.
|
|
30
|
+
router.post('/', zValidator('json', CreateBodySchema), async (context) => {
|
|
31
|
+
const workspaceId = getWorkspaceId(context);
|
|
32
|
+
const body = context.req.valid('json');
|
|
33
|
+
const ticket = await deps.hitlService.submitClarifyTicket({ workspaceId, ...body });
|
|
34
|
+
return context.json(ticket.toData(), 201);
|
|
35
|
+
});
|
|
36
|
+
router.get('/', zValidator('query', ListQuerySchema), async (context) => {
|
|
37
|
+
const workspaceId = getWorkspaceId(context);
|
|
38
|
+
const { status, limit, offset } = context.req.valid('query');
|
|
39
|
+
const statuses = status === undefined ? undefined : Array.isArray(status) ? status : [status];
|
|
40
|
+
const tickets = await deps.clarifyRepository.list({ workspaceId, statuses, limit, offset });
|
|
41
|
+
return context.json({ items: tickets.map(ticket => ticket.toData()) });
|
|
42
|
+
});
|
|
43
|
+
router.get('/:clarifyTicketId', async (context) => {
|
|
44
|
+
const workspaceId = getWorkspaceId(context);
|
|
45
|
+
const ticketId = ClarifyTicketId.parse(context.req.param('clarifyTicketId'));
|
|
46
|
+
const ticket = await deps.clarifyRepository.load(ticketId);
|
|
47
|
+
assertEntityInWorkspace(workspaceId, ticket.workspaceId, 'ClarifyTicket', ticketId);
|
|
48
|
+
return context.json(ticket.toData());
|
|
49
|
+
});
|
|
50
|
+
router.post('/:clarifyTicketId/answer', zValidator('json', AnswerBodySchema), async (context) => {
|
|
51
|
+
const workspaceId = getWorkspaceId(context);
|
|
52
|
+
const ticketId = ClarifyTicketId.parse(context.req.param('clarifyTicketId'));
|
|
53
|
+
const { candidateId, userId } = context.req.valid('json');
|
|
54
|
+
const ticket = await deps.clarifyRepository.load(ticketId);
|
|
55
|
+
assertEntityInWorkspace(workspaceId, ticket.workspaceId, 'ClarifyTicket', ticketId);
|
|
56
|
+
const decision = await deps.hitlService.answerClarifyTicket(ticketId, candidateId, userId);
|
|
57
|
+
return context.json(decision);
|
|
58
|
+
});
|
|
59
|
+
// Skill-facing: the braid-clarify skill calls this once it has wrapped
|
|
60
|
+
// an `answered` ticket's resolution into a Proposal. Transitions the
|
|
61
|
+
// ticket `answered → applied` and stamps the linking proposalId so the
|
|
62
|
+
// UI can navigate from a ticket back to its Proposal. No graph
|
|
63
|
+
// mutation happens here; the Proposal apply already covered that.
|
|
64
|
+
router.patch('/:clarifyTicketId', zValidator('json', LinkProposalBodySchema), async (context) => {
|
|
65
|
+
const workspaceId = getWorkspaceId(context);
|
|
66
|
+
const ticketId = ClarifyTicketId.parse(context.req.param('clarifyTicketId'));
|
|
67
|
+
const { proposalId, userId } = context.req.valid('json');
|
|
68
|
+
const ticket = await deps.clarifyRepository.load(ticketId);
|
|
69
|
+
assertEntityInWorkspace(workspaceId, ticket.workspaceId, 'ClarifyTicket', ticketId);
|
|
70
|
+
const decision = await deps.hitlService.linkClarifyTicketToProposal(ticketId, proposalId, userId);
|
|
71
|
+
return context.json(decision);
|
|
72
|
+
});
|
|
73
|
+
router.post('/:clarifyTicketId/skip', zValidator('json', SkipBodySchema), async (context) => {
|
|
74
|
+
const workspaceId = getWorkspaceId(context);
|
|
75
|
+
const ticketId = ClarifyTicketId.parse(context.req.param('clarifyTicketId'));
|
|
76
|
+
const { reason, userId } = context.req.valid('json');
|
|
77
|
+
const ticket = await deps.clarifyRepository.load(ticketId);
|
|
78
|
+
assertEntityInWorkspace(workspaceId, ticket.workspaceId, 'ClarifyTicket', ticketId);
|
|
79
|
+
const decision = await deps.hitlService.skipClarifyTicket(ticketId, reason, userId);
|
|
80
|
+
return context.json(decision);
|
|
81
|
+
});
|
|
82
|
+
return router;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=clarify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clarify.js","sourceRoot":"","sources":["../../src/routes/clarify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DecisionRepository } from '@braidhq/core';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
export interface DecisionsRouterDeps {
|
|
4
|
+
decisionRepository: DecisionRepository;
|
|
5
|
+
}
|
|
6
|
+
export declare function createDecisionsRouter(deps: DecisionsRouterDeps): Hono;
|
|
7
|
+
//# sourceMappingURL=decisions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decisions.d.ts","sourceRoot":"","sources":["../../src/routes/decisions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAGvD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAW3B,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,kBAAkB,CAAA;CACvC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAoBrE"}
|