@lovelybunch/api 1.0.76 → 1.0.77-alpha.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/dist/config/oauth.d.ts +33 -0
- package/dist/config/oauth.js +43 -0
- package/dist/lib/auth/auth-manager.d.ts +21 -1
- package/dist/lib/auth/auth-manager.js +57 -3
- package/dist/lib/auth/clerk-verifier.d.ts +22 -0
- package/dist/lib/auth/clerk-verifier.js +30 -0
- package/dist/lib/terminal/terminal-manager.js +2 -1
- package/dist/middleware/auth.js +40 -3
- package/dist/routes/api/v1/auth/route.js +90 -0
- package/dist/routes/api/v1/auth-settings/route.js +83 -2
- package/dist/routes/api/v1/events/status/route.d.ts +1 -1
- package/dist/routes/api/v1/jobs/[id]/route.d.ts +8 -8
- package/dist/routes/api/v1/jobs/[id]/run/route.d.ts +2 -2
- package/dist/routes/api/v1/jobs/[id]/runs/[runId]/route.d.ts +2 -2
- package/dist/routes/api/v1/jobs/route.d.ts +8 -8
- package/dist/routes/api/v1/jobs/status/route.d.ts +1 -1
- package/dist/routes/api/v1/mail/route.d.ts +3 -3
- package/dist/routes/api/v1/tasks/[id]/route.d.ts +4 -4
- package/dist/routes/api/v1/tasks/[id]/steps/[stepId]/route.d.ts +2 -2
- package/dist/routes/api/v1/tasks/route.d.ts +1 -1
- package/dist/server-with-static.js +36 -17
- package/dist/server.js +12 -0
- package/package.json +25 -23
- package/static/assets/{ActivityPage-sJEQn6DK.js → ActivityPage-DqSj7XDx.js} +1 -1
- package/static/assets/{AgentsContextEditPage-DU3qIXk9.js → AgentsContextEditPage-C5afMo09.js} +1 -1
- package/static/assets/AgentsContextPage-IrZGdiYt.js +1 -0
- package/static/assets/{ApiKeysSettingsPage-Bg84BQHV.js → ApiKeysSettingsPage-CFBTIYNp.js} +2 -2
- package/static/assets/AuthSettingsPage-LU7DFMG6.js +11 -0
- package/static/assets/{CallbackPage-BFn0Np2S.js → CallbackPage-Beg0ZLv4.js} +1 -1
- package/static/assets/CoconutCallbackPage-BuBYbeY-.js +1 -0
- package/static/assets/CodePage-C9auBWu3.js +2 -0
- package/static/assets/{CollapsibleSection-CNs1mvsZ.js → CollapsibleSection-C3uaXDrK.js} +1 -1
- package/static/assets/{DashboardPage-DMJSzzgD.js → DashboardPage-DK2uEtcQ.js} +2 -2
- package/static/assets/{GitPage-uqene8zj.js → GitPage-BgfZ5rXn.js} +2 -2
- package/static/assets/{GitSettingsPage-CLswbZsT.js → GitSettingsPage-DIhaZgDD.js} +2 -2
- package/static/assets/{IdentityPage-BDTPXEo7.js → IdentityPage-6_IEyGmH.js} +2 -2
- package/static/assets/{ImplementationStepsEditor-D4cvhPhz.js → ImplementationStepsEditor-BXjs77nI.js} +1 -1
- package/static/assets/IntegrationsSettingsPage-Cu-C86-i.js +1 -0
- package/static/assets/JobDetailPage-BWd0sz7w.js +1 -0
- package/static/assets/KnowledgeDetailPage-Cx0NiVN5.js +1 -0
- package/static/assets/KnowledgeEditPage-Dtp9Ceyp.js +1 -0
- package/static/assets/{KnowledgePage-B2zI3xwW.js → KnowledgePage-DRavibOT.js} +2 -2
- package/static/assets/LoginPage-Bn-55dqi.js +1 -0
- package/static/assets/MailInboxPage-B-mzoocZ.js +1 -0
- package/static/assets/MailProcessingModal-B5HFIwxh.js +1 -0
- package/static/assets/MailReadPage-DVVICNmn.js +1 -0
- package/static/assets/MailSentPage-BmqXLEIF.js +1 -0
- package/static/assets/McpSettingsPage-D6hW-2uy.js +1 -0
- package/static/assets/{MemoryEditPage-DXSQoCT4.js → MemoryEditPage-Cw2oWAW2.js} +1 -1
- package/static/assets/MemoryPage-BKNQlp0x.js +1 -0
- package/static/assets/{NewKnowledgePage-deMsezK8.js → NewKnowledgePage-zWnjfGF1.js} +1 -1
- package/static/assets/{NewSkillPage-DRYWdrlV.js → NewSkillPage-eqK5nwnk.js} +1 -1
- package/static/assets/{NewTaskPage-B6xdic5_.js → NewTaskPage-BcOmFrza.js} +2 -2
- package/static/assets/{NotFoundPage-Bxu9uKFO.js → NotFoundPage-CKcBMXOQ.js} +1 -1
- package/static/assets/{NotificationsSettingsPage-CLgtsCVM.js → NotificationsSettingsPage-DETz35D7.js} +1 -1
- package/static/assets/PromptsSettingsPage-8--L7lw4.js +1 -0
- package/static/assets/{ResourceDetailPage-CMPDRdVM.js → ResourceDetailPage-BH-A0yn7.js} +1 -1
- package/static/assets/{ResourcesPage-DspYILfG.js → ResourcesPage-CfdKptfd.js} +1 -1
- package/static/assets/{RoleEditPage-DXtzicVZ.js → RoleEditPage-DfqF4tLW.js} +1 -1
- package/static/assets/RolePage-CCwufp_f.js +1 -0
- package/static/assets/{RulesSettingsPage-E8V9cexV.js → RulesSettingsPage-dzUPGors.js} +4 -4
- package/static/assets/{RunDetailPage-DsxkqFst.js → RunDetailPage-B9I5nrOb.js} +1 -1
- package/static/assets/SchedulePage-7Ufvzd34.js +4 -0
- package/static/assets/SkillDetailPage-DCjWVhUE.js +1 -0
- package/static/assets/{SkillEditPage-DwyebzFV.js → SkillEditPage-BA-ebFGI.js} +1 -1
- package/static/assets/{SkillsPage-CauK65X_.js → SkillsPage-QqNzKzhn.js} +2 -2
- package/static/assets/{SkillsSettingsPage-DXMRv3jR.js → SkillsSettingsPage-DPXiPnWO.js} +1 -1
- package/static/assets/SourceInput-0S84iX2C.js +1 -0
- package/static/assets/{TagInput-Ct-WRvTs.js → TagInput-C_2MLj_1.js} +1 -1
- package/static/assets/{TaskDetailPage-CApk2iBh.js → TaskDetailPage-6E7isObV.js} +2 -2
- package/static/assets/{TaskEditPage-NgOVShfK.js → TaskEditPage-Bd1DFoK3.js} +1 -1
- package/static/assets/{TasksPage-BoPrP_Rl.js → TasksPage-CeWPVVwj.js} +1 -1
- package/static/assets/{TeamEditPage-ChY6mYm8.js → TeamEditPage-CgYsqeq9.js} +1 -1
- package/static/assets/TeamPage-CEojyLvc.js +1 -0
- package/static/assets/{TerminalPage-CRhcscF2.js → TerminalPage-D-LJMND7.js} +1 -1
- package/static/assets/{TerminalSessionPage-CSCQg2sn.js → TerminalSessionPage-BGHgOQhV.js} +2 -2
- package/static/assets/{UserPreferencesPage-DxCSWJnS.js → UserPreferencesPage-D5nGgztl.js} +1 -1
- package/static/assets/{UserSettingsPage-DKkOLNPV.js → UserSettingsPage-Dv6fSWWx.js} +1 -1
- package/static/assets/UtilitiesPage-hCM0KDs8.js +1 -0
- package/static/assets/{alert-Dw_RSroN.js → alert-DxBTp_In.js} +1 -1
- package/static/assets/{arrow-down-UClxXzT-.js → arrow-down-Be4lZFzF.js} +1 -1
- package/static/assets/{arrow-left-DWmf9YJp.js → arrow-left-DzGSl0dC.js} +1 -1
- package/static/assets/{arrow-up-fLCh7Hvh.js → arrow-up-6HVzdiIw.js} +1 -1
- package/static/assets/{arrow-up-down-Btc3okb3.js → arrow-up-down-C9lUuyDO.js} +1 -1
- package/static/assets/{badge-vIqE5SOP.js → badge-DyF_7_dv.js} +1 -1
- package/static/assets/{browser-modal-DgMJTsMd.js → browser-modal-DKHn0FAC.js} +2 -2
- package/static/assets/{card-DPLdBoa5.js → card-DW9yx9FC.js} +1 -1
- package/static/assets/{chevron-left-CiNaLX-v.js → chevron-left-CJjrbO2y.js} +1 -1
- package/static/assets/{chevron-up-DFd-7wxW.js → chevron-up-BrSqNhfU.js} +1 -1
- package/static/assets/{chevrons-up-BfU70OcQ.js → chevrons-up-wQrNHZqU.js} +1 -1
- package/static/assets/{circle-alert-Mv00T-P2.js → circle-alert-ByPjREVD.js} +1 -1
- package/static/assets/{circle-check-xMiP6SLO.js → circle-check-D7peX4CI.js} +1 -1
- package/static/assets/{circle-check-big-BEY1IoIP.js → circle-check-big--yqXPZzU.js} +1 -1
- package/static/assets/{circle-play-iZZwaGbV.js → circle-play-C2th8mzN.js} +1 -1
- package/static/assets/{circle-x-z3iynaE7.js → circle-x-Oj6Gai3s.js} +1 -1
- package/static/assets/{clipboard-C8wZRPDH.js → clipboard-qigxJPlJ.js} +1 -1
- package/static/assets/{clock-C_9shc08.js → clock-JhtahL2B.js} +1 -1
- package/static/assets/{code-DH-sRhus.js → code-DcBDG3ah.js} +1 -1
- package/static/assets/{download-CE8b59ER.js → download-BBjLPrfj.js} +1 -1
- package/static/assets/{external-link-DPyKt8NE.js → external-link-DDneC3kx.js} +1 -1
- package/static/assets/{eye-BpGD-yoS.js → eye-Bl23BbY6.js} +1 -1
- package/static/assets/{folder-git-2-BIw4zbmy.js → folder-git-2-BBe22u2y.js} +1 -1
- package/static/assets/{globe-CUo7eHKN.js → globe-C3j3aWiD.js} +1 -1
- package/static/assets/{index-UXL5-kaP.js → index-0zkOcODK.js} +105 -105
- package/static/assets/{index-ClO9-JVh.js → index-B-9XKFgb.js} +1 -1
- package/static/assets/{index-Cdwx6Zps.js → index-CWt3zgDI.js} +1 -1
- package/static/assets/{index-Bkt1rQVV.js → index-Cbo5QxHl.js} +1 -1
- package/static/assets/{index-iB8oed57.js → index-D2rSjJPF.js} +1 -1
- package/static/assets/{index-Bfb3OTwj.js → index-DFfxOZw8.js} +1 -1
- package/static/assets/{index-B07hel4U.js → index-DUwRskPW.js} +1 -1
- package/static/assets/index-DVMcu9sQ.css +1 -0
- package/static/assets/{index-CpJ0uBf3.js → index-DaAZbWZV.js} +1 -1
- package/static/assets/{index-BCwmQxLC.js → index-DdDCTC_d.js} +1 -1
- package/static/assets/{index-jaRIZ6SY.js → index-DdSybLsG.js} +1 -1
- package/static/assets/{index-BaR4iUzg.js → index-DgFdrtDt.js} +1 -1
- package/static/assets/{index-CTouvf2d.js → index-DkobSVA-.js} +1 -1
- package/static/assets/{index-CsBxEWw5.js → index-DuWsaYa4.js} +1 -1
- package/static/assets/{index-CGbmjmEy.js → index-DukcrMyC.js} +1 -1
- package/static/assets/{index-BOKaM9K-.js → index-I6ZfnFaA.js} +1 -1
- package/static/assets/{index-Dkr9CBL7.js → index-QZn_aaqg.js} +1 -1
- package/static/assets/{index-C65b3D5_.js → index-UM1qitEs.js} +1 -1
- package/static/assets/{index-DZAYfTI2.js → index-r07pPAcM.js} +1 -1
- package/static/assets/{index-DnZKG-_7.js → index-xBQb0rMo.js} +1 -1
- package/static/assets/{info-D-UNBNx2.js → info-DWORrO-s.js} +1 -1
- package/static/assets/{label-8VKluf9w.js → label-DyhnItJm.js} +1 -1
- package/static/assets/{markdown-editor-DBdRsbP2.js → markdown-editor-C8LFQE7K.js} +38 -38
- package/static/assets/{message-square-CO8kDUed.js → message-square-CiISW36v.js} +1 -1
- package/static/assets/{paperclip-DlLXZbru.js → paperclip-DRufaOtA.js} +1 -1
- package/static/assets/{pause-zSiaxJBu.js → pause-GqIUdKFa.js} +1 -1
- package/static/assets/{pipeline-builders-Bkf0wt_O.js → pipeline-builders-DrEjlsbH.js} +1 -1
- package/static/assets/{play-DVBhRokt.js → play-CkuTY54l.js} +1 -1
- package/static/assets/{radio-group-CThYUcA4.js → radio-group-ClpV676y.js} +1 -1
- package/static/assets/{refresh-cw-tXYl1ePu.js → refresh-cw-CYBx0C_n.js} +1 -1
- package/static/assets/{search-BxF7Wwex.js → search-DxiQuWo1.js} +1 -1
- package/static/assets/{select-CyHFRA1Y.js → select-D_L7OXwN.js} +1 -1
- package/static/assets/{server-lRxThHjr.js → server-CgjJESGe.js} +1 -1
- package/static/assets/{switch-BUpDbrux.js → switch-DXojpqQ8.js} +1 -1
- package/static/assets/{tabs-DkvCmQEX.js → tabs-zdz4RlY5.js} +1 -1
- package/static/assets/{tag-CkcZNLnh.js → tag-CeaYtqPJ.js} +1 -1
- package/static/assets/terminal-preview-CspSfoko.js +1 -0
- package/static/assets/{triangle-alert-CmjG_mbF.js → triangle-alert-DTdlIh6V.js} +1 -1
- package/static/assets/{use-terminal-D3iV7-iC.js → use-terminal-DkVoTttR.js} +1 -1
- package/static/assets/{video-CY_dOujm.js → video-5zJ0jcFw.js} +1 -1
- package/static/index.html +2 -2
- package/dist/routes/api/v1/context/architecture/route.d.ts +0 -3
- package/dist/routes/api/v1/context/architecture/route.js +0 -245
- package/dist/routes/api/v1/context/project/route.d.ts +0 -3
- package/dist/routes/api/v1/context/project/route.js +0 -200
- package/static/assets/AgentsContextPage-tJ-LhFYb.js +0 -1
- package/static/assets/AuthSettingsPage-Bwr7uP3z.js +0 -11
- package/static/assets/CodePage-kp4s3wCJ.js +0 -2
- package/static/assets/IntegrationsSettingsPage-o7NXZGt9.js +0 -1
- package/static/assets/JobDetailPage-DuEiPz6X.js +0 -1
- package/static/assets/KnowledgeDetailPage-DFVud_VC.js +0 -1
- package/static/assets/KnowledgeEditPage-XG6HKK7E.js +0 -1
- package/static/assets/LoginPage-CUJRxwXy.js +0 -1
- package/static/assets/MailInboxPage-BlCG-tba.js +0 -1
- package/static/assets/MailProcessingModal-BJIdHOqK.js +0 -1
- package/static/assets/MailReadPage-MoNo_gmW.js +0 -1
- package/static/assets/MailSentPage-QzpuIJmT.js +0 -1
- package/static/assets/McpSettingsPage-BZcCGkGM.js +0 -1
- package/static/assets/MemoryPage-oBnyuvSf.js +0 -1
- package/static/assets/PromptsSettingsPage-BWaELCjG.js +0 -1
- package/static/assets/RolePage-DafGURGp.js +0 -1
- package/static/assets/SchedulePage-B2YvNDHr.js +0 -4
- package/static/assets/SkillDetailPage-CWkqSfuT.js +0 -1
- package/static/assets/SourceInput-C0iKqbQ1.js +0 -1
- package/static/assets/TeamPage-DH-dJhFG.js +0 -1
- package/static/assets/UtilitiesPage-CBNSvixW.js +0 -1
- package/static/assets/index-BcCuKdbf.css +0 -1
- package/static/assets/terminal-preview-CLWDhoOZ.js +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clerk OAuth configuration.
|
|
3
|
+
*
|
|
4
|
+
* Coconut currently has a single control plane, so these values are public
|
|
5
|
+
* (non-secret) constants. If a second control plane is ever introduced, move
|
|
6
|
+
* these to environment variables.
|
|
7
|
+
*
|
|
8
|
+
* Kept in sync with packages/cli/src/commands/serve.ts (startup banner).
|
|
9
|
+
*/
|
|
10
|
+
import type { AuthConfig } from '@lovelybunch/types';
|
|
11
|
+
export declare const CLERK_JWKS_URL = "https://clerk.coconut.dev/.well-known/jwks.json";
|
|
12
|
+
export declare const CLERK_ISSUER = "https://clerk.coconut.dev";
|
|
13
|
+
export interface OAuthRuntimeConfig {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
clientId?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function setOAuthRuntimeConfig(config: OAuthRuntimeConfig): void;
|
|
18
|
+
export declare function getOAuthRuntimeConfig(): OAuthRuntimeConfig;
|
|
19
|
+
/**
|
|
20
|
+
* OAuth is active for this coconut iff auth.json has a Coconut OAuth provider
|
|
21
|
+
* entry that is explicitly enabled AND has a non-empty clientId. Missing entry,
|
|
22
|
+
* `enabled: false`, or missing clientId all disable OAuth.
|
|
23
|
+
*
|
|
24
|
+
* This is the single source of truth for "should we offer Continue with
|
|
25
|
+
* Coconut" — startup, middleware, /status, and the admin settings toggle all
|
|
26
|
+
* go through it.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isCoconutOAuthActive(config: AuthConfig): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Convert an AuthConfig into the runtime OAuth cache shape. Safe to call even
|
|
31
|
+
* when OAuth isn't active — returns `{ enabled: false }` in that case.
|
|
32
|
+
*/
|
|
33
|
+
export declare function oauthRuntimeFromAuthConfig(config: AuthConfig): OAuthRuntimeConfig;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clerk OAuth configuration.
|
|
3
|
+
*
|
|
4
|
+
* Coconut currently has a single control plane, so these values are public
|
|
5
|
+
* (non-secret) constants. If a second control plane is ever introduced, move
|
|
6
|
+
* these to environment variables.
|
|
7
|
+
*
|
|
8
|
+
* Kept in sync with packages/cli/src/commands/serve.ts (startup banner).
|
|
9
|
+
*/
|
|
10
|
+
export const CLERK_JWKS_URL = 'https://clerk.coconut.dev/.well-known/jwks.json';
|
|
11
|
+
export const CLERK_ISSUER = 'https://clerk.coconut.dev';
|
|
12
|
+
let runtimeConfig = { enabled: false };
|
|
13
|
+
export function setOAuthRuntimeConfig(config) {
|
|
14
|
+
runtimeConfig = config;
|
|
15
|
+
}
|
|
16
|
+
export function getOAuthRuntimeConfig() {
|
|
17
|
+
return runtimeConfig;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* OAuth is active for this coconut iff auth.json has a Coconut OAuth provider
|
|
21
|
+
* entry that is explicitly enabled AND has a non-empty clientId. Missing entry,
|
|
22
|
+
* `enabled: false`, or missing clientId all disable OAuth.
|
|
23
|
+
*
|
|
24
|
+
* This is the single source of truth for "should we offer Continue with
|
|
25
|
+
* Coconut" — startup, middleware, /status, and the admin settings toggle all
|
|
26
|
+
* go through it.
|
|
27
|
+
*/
|
|
28
|
+
export function isCoconutOAuthActive(config) {
|
|
29
|
+
const coconut = config.providers.oauth?.coconut;
|
|
30
|
+
return !!(coconut && coconut.enabled && coconut.clientId);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Convert an AuthConfig into the runtime OAuth cache shape. Safe to call even
|
|
34
|
+
* when OAuth isn't active — returns `{ enabled: false }` in that case.
|
|
35
|
+
*/
|
|
36
|
+
export function oauthRuntimeFromAuthConfig(config) {
|
|
37
|
+
if (!isCoconutOAuthActive(config))
|
|
38
|
+
return { enabled: false };
|
|
39
|
+
return {
|
|
40
|
+
enabled: true,
|
|
41
|
+
clientId: config.providers.oauth.coconut.clientId,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -23,6 +23,23 @@ export declare class AuthManager {
|
|
|
23
23
|
* Initialize auth config with defaults
|
|
24
24
|
*/
|
|
25
25
|
initializeAuthConfig(adminEmail: string, adminName: string): Promise<AuthConfig>;
|
|
26
|
+
/**
|
|
27
|
+
* Upsert the Coconut OAuth provider entry in auth.json. Creates a minimal
|
|
28
|
+
* OAuth-only auth config on first run (auth.json missing), or merges the
|
|
29
|
+
* new Coconut OAuth settings into an existing config without touching other
|
|
30
|
+
* providers, users, or session state.
|
|
31
|
+
*
|
|
32
|
+
* Used by:
|
|
33
|
+
* - `nut init --oauth-client-id <id>` (provisioning automation)
|
|
34
|
+
* - `PUT /api/v1/auth-settings/oauth/coconut` (admin toggle)
|
|
35
|
+
*
|
|
36
|
+
* Callers are responsible for validating that `clientId` is present when
|
|
37
|
+
* `enabled: true` — this method stores what it's given.
|
|
38
|
+
*/
|
|
39
|
+
upsertCoconutOAuth(options: {
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
clientId?: string;
|
|
42
|
+
}): Promise<AuthConfig>;
|
|
26
43
|
/**
|
|
27
44
|
* Find user by email
|
|
28
45
|
*/
|
|
@@ -72,7 +89,10 @@ export declare class AuthManager {
|
|
|
72
89
|
*/
|
|
73
90
|
generateToken(user: LocalAuthUser, provider?: string): Promise<string>;
|
|
74
91
|
/**
|
|
75
|
-
* Verify JWT token
|
|
92
|
+
* Verify JWT token (local HS256 session token)
|
|
93
|
+
*
|
|
94
|
+
* Algorithms are pinned to HS256 to prevent algorithm-confusion attacks
|
|
95
|
+
* when the middleware also accepts externally-issued RS256 JWTs (OAuth).
|
|
76
96
|
*/
|
|
77
97
|
verifyToken(token: string): Promise<AuthSession | null>;
|
|
78
98
|
/**
|
|
@@ -92,6 +92,55 @@ export class AuthManager {
|
|
|
92
92
|
await this.saveAuthConfig(config);
|
|
93
93
|
return config;
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Upsert the Coconut OAuth provider entry in auth.json. Creates a minimal
|
|
97
|
+
* OAuth-only auth config on first run (auth.json missing), or merges the
|
|
98
|
+
* new Coconut OAuth settings into an existing config without touching other
|
|
99
|
+
* providers, users, or session state.
|
|
100
|
+
*
|
|
101
|
+
* Used by:
|
|
102
|
+
* - `nut init --oauth-client-id <id>` (provisioning automation)
|
|
103
|
+
* - `PUT /api/v1/auth-settings/oauth/coconut` (admin toggle)
|
|
104
|
+
*
|
|
105
|
+
* Callers are responsible for validating that `clientId` is present when
|
|
106
|
+
* `enabled: true` — this method stores what it's given.
|
|
107
|
+
*/
|
|
108
|
+
async upsertCoconutOAuth(options) {
|
|
109
|
+
let config = null;
|
|
110
|
+
try {
|
|
111
|
+
config = await this.loadAuthConfig();
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// auth.json missing; fall through and bootstrap a minimal shape below.
|
|
115
|
+
}
|
|
116
|
+
if (!config) {
|
|
117
|
+
config = {
|
|
118
|
+
version: '1.0',
|
|
119
|
+
enabled: true,
|
|
120
|
+
allowRegistration: false,
|
|
121
|
+
providers: {
|
|
122
|
+
local: { enabled: false, users: [] },
|
|
123
|
+
oauth: {},
|
|
124
|
+
},
|
|
125
|
+
session: {
|
|
126
|
+
secret: this.generateSecret(),
|
|
127
|
+
expiresIn: DEFAULT_SESSION_EXPIRY,
|
|
128
|
+
cookieName: DEFAULT_COOKIE_NAME,
|
|
129
|
+
secure: process.env.NODE_ENV === 'production',
|
|
130
|
+
},
|
|
131
|
+
apiKeys: [],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (!config.providers.oauth) {
|
|
135
|
+
config.providers.oauth = {};
|
|
136
|
+
}
|
|
137
|
+
config.providers.oauth.coconut = {
|
|
138
|
+
enabled: options.enabled,
|
|
139
|
+
clientId: options.clientId,
|
|
140
|
+
};
|
|
141
|
+
await this.saveAuthConfig(config);
|
|
142
|
+
return config;
|
|
143
|
+
}
|
|
95
144
|
/**
|
|
96
145
|
* Find user by email
|
|
97
146
|
*/
|
|
@@ -268,15 +317,20 @@ export class AuthManager {
|
|
|
268
317
|
iat: Math.floor(Date.now() / 1000),
|
|
269
318
|
exp: Math.floor(Date.now() / 1000) + this.parseExpiry(config.session.expiresIn),
|
|
270
319
|
};
|
|
271
|
-
return jwt.sign(payload, config.session.secret);
|
|
320
|
+
return jwt.sign(payload, config.session.secret, { algorithm: 'HS256' });
|
|
272
321
|
}
|
|
273
322
|
/**
|
|
274
|
-
* Verify JWT token
|
|
323
|
+
* Verify JWT token (local HS256 session token)
|
|
324
|
+
*
|
|
325
|
+
* Algorithms are pinned to HS256 to prevent algorithm-confusion attacks
|
|
326
|
+
* when the middleware also accepts externally-issued RS256 JWTs (OAuth).
|
|
275
327
|
*/
|
|
276
328
|
async verifyToken(token) {
|
|
277
329
|
try {
|
|
278
330
|
const config = await this.loadAuthConfig();
|
|
279
|
-
const decoded = jwt.verify(token, config.session.secret
|
|
331
|
+
const decoded = jwt.verify(token, config.session.secret, {
|
|
332
|
+
algorithms: ['HS256'],
|
|
333
|
+
});
|
|
280
334
|
return decoded;
|
|
281
335
|
}
|
|
282
336
|
catch (error) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jwtVerify, type JWTPayload } from 'jose';
|
|
2
|
+
/**
|
|
3
|
+
* Clerk JWT verification.
|
|
4
|
+
*
|
|
5
|
+
* - JWKS keys are fetched once and cached in memory by `jose`.
|
|
6
|
+
* - `issuer` is enforced so tokens from other Identity Providers cannot pass.
|
|
7
|
+
* - `audience` (the coconut's OAuth client_id) is enforced so a token issued
|
|
8
|
+
* for one coconut's client cannot be replayed against another coconut.
|
|
9
|
+
*/
|
|
10
|
+
type JwksKeyFn = Parameters<typeof jwtVerify>[1];
|
|
11
|
+
export interface ClerkVerifyResult {
|
|
12
|
+
payload: JWTPayload;
|
|
13
|
+
}
|
|
14
|
+
export declare function verifyClerkToken(token: string, options: {
|
|
15
|
+
audience: string;
|
|
16
|
+
}): Promise<ClerkVerifyResult | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Test-only: inject a custom JWKS key function (e.g. `jose.createLocalJWKSet`
|
|
19
|
+
* backed by a generated keypair) so middleware tests don't hit the network.
|
|
20
|
+
*/
|
|
21
|
+
export declare function __setClerkJwksForTests(jwks: JwksKeyFn | null): void;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createRemoteJWKSet, jwtVerify } from 'jose';
|
|
2
|
+
import { CLERK_ISSUER, CLERK_JWKS_URL } from '../../config/oauth.js';
|
|
3
|
+
let jwksInstance = null;
|
|
4
|
+
function getJwks() {
|
|
5
|
+
if (!jwksInstance) {
|
|
6
|
+
jwksInstance = createRemoteJWKSet(new URL(CLERK_JWKS_URL));
|
|
7
|
+
}
|
|
8
|
+
return jwksInstance;
|
|
9
|
+
}
|
|
10
|
+
export async function verifyClerkToken(token, options) {
|
|
11
|
+
try {
|
|
12
|
+
const jwks = getJwks();
|
|
13
|
+
const verifyOptions = {
|
|
14
|
+
issuer: CLERK_ISSUER,
|
|
15
|
+
audience: options.audience,
|
|
16
|
+
};
|
|
17
|
+
const { payload } = await jwtVerify(token, jwks, verifyOptions);
|
|
18
|
+
return { payload };
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Test-only: inject a custom JWKS key function (e.g. `jose.createLocalJWKSet`
|
|
26
|
+
* backed by a generated keypair) so middleware tests don't hit the network.
|
|
27
|
+
*/
|
|
28
|
+
export function __setClerkJwksForTests(jwks) {
|
|
29
|
+
jwksInstance = jwks;
|
|
30
|
+
}
|
|
@@ -2,6 +2,7 @@ import * as pty from 'node-pty';
|
|
|
2
2
|
import { WebSocket } from 'ws';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import fs from 'fs';
|
|
5
|
+
import { randomBytes } from 'crypto';
|
|
5
6
|
import { fileURLToPath } from 'url';
|
|
6
7
|
import { createInitScript } from './context-helper.js';
|
|
7
8
|
import { getShellPath, getShellArgs, prepareShellInit } from './shell-utils.js';
|
|
@@ -48,7 +49,7 @@ export class TerminalManager {
|
|
|
48
49
|
ensureSpawnHelperPermissions();
|
|
49
50
|
spawnHelperFixed = true;
|
|
50
51
|
}
|
|
51
|
-
const sessionId = `${taskId}-${Date.now()}-${
|
|
52
|
+
const sessionId = `${taskId}-${Date.now()}-${randomBytes(9).toString('base64url')}`;
|
|
52
53
|
// Get the project root directory
|
|
53
54
|
let projectRoot;
|
|
54
55
|
if (process.env.NODE_ENV === 'development' && process.env.GAIT_DEV_ROOT) {
|
package/dist/middleware/auth.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getCookie } from 'hono/cookie';
|
|
2
2
|
import { getConnInfo } from '@hono/node-server/conninfo';
|
|
3
3
|
import { getAuthManager } from '../lib/auth/auth-manager.js';
|
|
4
|
+
import { getOAuthRuntimeConfig } from '../config/oauth.js';
|
|
5
|
+
import { verifyClerkToken } from '../lib/auth/clerk-verifier.js';
|
|
4
6
|
const LOOPBACK_ADDRESSES = new Set(['127.0.0.1', '::1', '::ffff:127.0.0.1']);
|
|
5
7
|
/**
|
|
6
8
|
* Check if a request is a direct localhost connection (not proxied).
|
|
@@ -33,6 +35,7 @@ const PUBLIC_ROUTES = [
|
|
|
33
35
|
'/api/v1/auth/logout',
|
|
34
36
|
'/api/v1/auth/oauth',
|
|
35
37
|
'/api/v1/auth/callback',
|
|
38
|
+
'/api/v1/auth/oauth/exchange',
|
|
36
39
|
];
|
|
37
40
|
// Routes that require specific roles
|
|
38
41
|
const ADMIN_ROUTES = [
|
|
@@ -110,8 +113,35 @@ export async function authMiddleware(c, next) {
|
|
|
110
113
|
if (!token) {
|
|
111
114
|
return c.json({ error: 'Unauthorized', message: 'No authentication token provided' }, 401);
|
|
112
115
|
}
|
|
113
|
-
// Verify token
|
|
114
|
-
|
|
116
|
+
// Verify token: try local HS256 session JWT first (fast, no network),
|
|
117
|
+
// then fall back to Clerk JWKS verification when --oauth is enabled.
|
|
118
|
+
let session = await authManager.verifyToken(token);
|
|
119
|
+
let authType = 'session';
|
|
120
|
+
if (!session) {
|
|
121
|
+
const oauth = getOAuthRuntimeConfig();
|
|
122
|
+
if (oauth.enabled && oauth.clientId) {
|
|
123
|
+
const result = await verifyClerkToken(token, { audience: oauth.clientId });
|
|
124
|
+
if (result) {
|
|
125
|
+
const { payload } = result;
|
|
126
|
+
// Map Clerk claims to the AuthSession shape expected downstream.
|
|
127
|
+
// OAuth sessions never receive the 'admin' role - admin-gated routes
|
|
128
|
+
// remain reachable only via locally-minted session tokens.
|
|
129
|
+
session = {
|
|
130
|
+
userId: typeof payload.sub === 'string' ? payload.sub : '',
|
|
131
|
+
email: typeof payload.email === 'string' ? payload.email : '',
|
|
132
|
+
name: typeof payload.name === 'string' ? payload.name : '',
|
|
133
|
+
// OAuth sessions get the most restricted role; admin is reachable
|
|
134
|
+
// only via locally-minted tokens.
|
|
135
|
+
role: 'viewer',
|
|
136
|
+
provider: 'oauth',
|
|
137
|
+
iat: typeof payload.iat === 'number' ? payload.iat : Math.floor(Date.now() / 1000),
|
|
138
|
+
exp: typeof payload.exp === 'number' ? payload.exp : Math.floor(Date.now() / 1000) + 3600,
|
|
139
|
+
};
|
|
140
|
+
authType = 'oauth';
|
|
141
|
+
c.set('oauthClaims', payload);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
115
145
|
if (!session) {
|
|
116
146
|
return c.json({ error: 'Unauthorized', message: 'Invalid or expired token' }, 401);
|
|
117
147
|
}
|
|
@@ -121,7 +151,7 @@ export async function authMiddleware(c, next) {
|
|
|
121
151
|
}
|
|
122
152
|
// Store session in context
|
|
123
153
|
c.set('session', session);
|
|
124
|
-
c.set('authType',
|
|
154
|
+
c.set('authType', authType);
|
|
125
155
|
return next();
|
|
126
156
|
}
|
|
127
157
|
/**
|
|
@@ -177,6 +207,13 @@ export function requireAdmin(c) {
|
|
|
177
207
|
if (authEnabled === false) {
|
|
178
208
|
return null;
|
|
179
209
|
}
|
|
210
|
+
// Trusted non-session authenticators (direct localhost connection, valid API
|
|
211
|
+
// key) are authoritative: they've already passed auth at the middleware
|
|
212
|
+
// layer, so admin-gated routes accept them without a session.role check.
|
|
213
|
+
const authType = c.get('authType');
|
|
214
|
+
if (authType === 'localhost' || authType === 'apikey') {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
180
217
|
const session = requireAuth(c);
|
|
181
218
|
if (!session) {
|
|
182
219
|
throw new Error('Authentication required');
|
|
@@ -2,6 +2,8 @@ import { Hono } from 'hono';
|
|
|
2
2
|
import { setCookie, deleteCookie } from 'hono/cookie';
|
|
3
3
|
import { getAuthManager } from '../../../../lib/auth/auth-manager.js';
|
|
4
4
|
import { getSession } from '../../../../middleware/auth.js';
|
|
5
|
+
import { CLERK_ISSUER, CLERK_JWKS_URL, getOAuthRuntimeConfig, } from '../../../../config/oauth.js';
|
|
6
|
+
import { verifyClerkToken } from '../../../../lib/auth/clerk-verifier.js';
|
|
5
7
|
const auth = new Hono();
|
|
6
8
|
/**
|
|
7
9
|
* POST /api/v1/auth/login
|
|
@@ -209,11 +211,21 @@ auth.get('/status', async (c) => {
|
|
|
209
211
|
},
|
|
210
212
|
};
|
|
211
213
|
}
|
|
214
|
+
const oauth = getOAuthRuntimeConfig();
|
|
215
|
+
const oauthInfo = oauth.enabled && oauth.clientId
|
|
216
|
+
? {
|
|
217
|
+
enabled: true,
|
|
218
|
+
clientId: oauth.clientId,
|
|
219
|
+
issuer: CLERK_ISSUER,
|
|
220
|
+
jwksUrl: CLERK_JWKS_URL,
|
|
221
|
+
}
|
|
222
|
+
: { enabled: false };
|
|
212
223
|
return c.json({
|
|
213
224
|
success: true,
|
|
214
225
|
data: {
|
|
215
226
|
enabled: authEnabled,
|
|
216
227
|
config,
|
|
228
|
+
oauth: oauthInfo,
|
|
217
229
|
},
|
|
218
230
|
});
|
|
219
231
|
}
|
|
@@ -223,8 +235,86 @@ auth.get('/status', async (c) => {
|
|
|
223
235
|
success: true,
|
|
224
236
|
data: {
|
|
225
237
|
enabled: false,
|
|
238
|
+
oauth: { enabled: false },
|
|
226
239
|
},
|
|
227
240
|
});
|
|
228
241
|
}
|
|
229
242
|
});
|
|
243
|
+
/**
|
|
244
|
+
* POST /api/v1/auth/oauth/exchange
|
|
245
|
+
* Exchange a verified Clerk access token for a local nut-session cookie.
|
|
246
|
+
*
|
|
247
|
+
* The SPA handles the PKCE token exchange against Clerk directly, then POSTs
|
|
248
|
+
* the resulting access_token here. We verify it via Clerk's JWKS (issuer +
|
|
249
|
+
* this coconut's client_id as audience), then mint a local HS256 session JWT
|
|
250
|
+
* and set it as the standard session cookie. Downstream auth flows are
|
|
251
|
+
* unchanged from this point on.
|
|
252
|
+
*/
|
|
253
|
+
auth.post('/oauth/exchange', async (c) => {
|
|
254
|
+
try {
|
|
255
|
+
const oauth = getOAuthRuntimeConfig();
|
|
256
|
+
if (!oauth.enabled || !oauth.clientId) {
|
|
257
|
+
return c.json({ success: false, error: 'OAuth is not enabled on this coconut' }, 400);
|
|
258
|
+
}
|
|
259
|
+
const body = await c.req
|
|
260
|
+
.json()
|
|
261
|
+
.catch(() => ({}));
|
|
262
|
+
const accessToken = body.accessToken;
|
|
263
|
+
if (!accessToken || typeof accessToken !== 'string') {
|
|
264
|
+
return c.json({ success: false, error: 'accessToken is required' }, 400);
|
|
265
|
+
}
|
|
266
|
+
const verified = await verifyClerkToken(accessToken, {
|
|
267
|
+
audience: oauth.clientId,
|
|
268
|
+
});
|
|
269
|
+
if (!verified) {
|
|
270
|
+
return c.json({ success: false, error: 'Invalid or expired OAuth token' }, 401);
|
|
271
|
+
}
|
|
272
|
+
const { payload } = verified;
|
|
273
|
+
const sub = typeof payload.sub === 'string' ? payload.sub : '';
|
|
274
|
+
const email = typeof payload.email === 'string' ? payload.email : '';
|
|
275
|
+
const name = typeof payload.name === 'string'
|
|
276
|
+
? payload.name
|
|
277
|
+
: (email ? email.split('@')[0] : 'Coconut User');
|
|
278
|
+
if (!sub || !email) {
|
|
279
|
+
return c.json({ success: false, error: 'OAuth token missing required claims (sub/email)' }, 401);
|
|
280
|
+
}
|
|
281
|
+
const authManager = getAuthManager();
|
|
282
|
+
const config = await authManager.loadAuthConfig();
|
|
283
|
+
// Mint a local session JWT so the existing cookie path remains unchanged.
|
|
284
|
+
// OAuth sessions are always 'viewer' - admin role is reserved for
|
|
285
|
+
// locally-managed users.
|
|
286
|
+
const localUserShape = {
|
|
287
|
+
id: sub,
|
|
288
|
+
email,
|
|
289
|
+
name,
|
|
290
|
+
role: 'viewer',
|
|
291
|
+
registered: true,
|
|
292
|
+
createdAt: new Date(),
|
|
293
|
+
updatedAt: new Date(),
|
|
294
|
+
};
|
|
295
|
+
const token = await authManager.generateToken(localUserShape, 'oauth');
|
|
296
|
+
setCookie(c, config.session.cookieName, token, {
|
|
297
|
+
httpOnly: true,
|
|
298
|
+
secure: config.session.secure || false,
|
|
299
|
+
sameSite: 'Lax',
|
|
300
|
+
maxAge: authManager['parseExpiry'](config.session.expiresIn),
|
|
301
|
+
path: '/',
|
|
302
|
+
});
|
|
303
|
+
return c.json({
|
|
304
|
+
success: true,
|
|
305
|
+
data: {
|
|
306
|
+
user: {
|
|
307
|
+
id: sub,
|
|
308
|
+
email,
|
|
309
|
+
name,
|
|
310
|
+
role: 'viewer',
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
console.error('OAuth exchange error:', error);
|
|
317
|
+
return c.json({ success: false, error: 'OAuth exchange failed' }, 500);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
230
320
|
export default auth;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { getAuthManager } from '../../../../lib/auth/auth-manager.js';
|
|
3
3
|
import { requireAdmin } from '../../../../middleware/auth.js';
|
|
4
|
+
import { CLERK_ISSUER, CLERK_JWKS_URL, oauthRuntimeFromAuthConfig, setOAuthRuntimeConfig, } from '../../../../config/oauth.js';
|
|
4
5
|
const authSettings = new Hono();
|
|
5
6
|
/**
|
|
6
7
|
* GET /api/v1/auth-settings
|
|
@@ -52,6 +53,17 @@ authSettings.get('/', async (c) => {
|
|
|
52
53
|
callbackUrl: config.providers.oauth.github.callbackUrl,
|
|
53
54
|
}
|
|
54
55
|
: undefined,
|
|
56
|
+
// Coconut OAuth: clientId is not a secret (it's the public
|
|
57
|
+
// OAuth client_id used in the authorize URL), so we return it in
|
|
58
|
+
// full so admins can verify it in the UI.
|
|
59
|
+
coconut: config.providers.oauth.coconut
|
|
60
|
+
? {
|
|
61
|
+
enabled: config.providers.oauth.coconut.enabled,
|
|
62
|
+
clientId: config.providers.oauth.coconut.clientId,
|
|
63
|
+
issuer: CLERK_ISSUER,
|
|
64
|
+
jwksUrl: CLERK_JWKS_URL,
|
|
65
|
+
}
|
|
66
|
+
: undefined,
|
|
55
67
|
},
|
|
56
68
|
},
|
|
57
69
|
session: {
|
|
@@ -220,15 +232,84 @@ authSettings.delete('/users/:id', async (c) => {
|
|
|
220
232
|
return c.json({ success: false, error: error.message || 'Failed to remove user' }, error.message === 'Admin access required' ? 403 : 400);
|
|
221
233
|
}
|
|
222
234
|
});
|
|
235
|
+
/**
|
|
236
|
+
* PUT /api/v1/auth-settings/oauth/coconut
|
|
237
|
+
* Admin-only: toggle Coconut OAuth and/or update its client ID. Persists to
|
|
238
|
+
* auth.json and immediately refreshes the OAuth runtime cache so the change
|
|
239
|
+
* takes effect on the very next request (no server restart required).
|
|
240
|
+
*
|
|
241
|
+
* Request body:
|
|
242
|
+
* { enabled: boolean, clientId?: string }
|
|
243
|
+
*
|
|
244
|
+
* Rules:
|
|
245
|
+
* - If `enabled: true` and no clientId is supplied AND none is already
|
|
246
|
+
* persisted, responds 400 with an actionable message.
|
|
247
|
+
* - If `enabled: false`, clientId (if any) is preserved so the admin can
|
|
248
|
+
* toggle back on later without re-entering it.
|
|
249
|
+
*/
|
|
250
|
+
authSettings.put('/oauth/coconut', async (c) => {
|
|
251
|
+
try {
|
|
252
|
+
requireAdmin(c);
|
|
253
|
+
const authManager = getAuthManager();
|
|
254
|
+
const body = await c.req
|
|
255
|
+
.json()
|
|
256
|
+
.catch(() => ({}));
|
|
257
|
+
if (typeof body.enabled !== 'boolean') {
|
|
258
|
+
return c.json({ success: false, error: '`enabled` (boolean) is required' }, 400);
|
|
259
|
+
}
|
|
260
|
+
// Resolve the effective clientId: explicit > previously-persisted.
|
|
261
|
+
let clientId = typeof body.clientId === 'string' ? body.clientId.trim() : undefined;
|
|
262
|
+
if (!clientId) {
|
|
263
|
+
const existing = await authManager.loadAuthConfig().catch(() => null);
|
|
264
|
+
clientId = existing?.providers.oauth.coconut?.clientId;
|
|
265
|
+
}
|
|
266
|
+
if (body.enabled && !clientId) {
|
|
267
|
+
return c.json({
|
|
268
|
+
success: false,
|
|
269
|
+
error: 'Coconut OAuth cannot be enabled without a client ID. Provide `clientId` in the request body, ' +
|
|
270
|
+
'or run `nut init --oauth-client-id <id>` to seed it.',
|
|
271
|
+
}, 400);
|
|
272
|
+
}
|
|
273
|
+
const updated = await authManager.upsertCoconutOAuth({
|
|
274
|
+
enabled: body.enabled,
|
|
275
|
+
clientId,
|
|
276
|
+
});
|
|
277
|
+
// Live-apply so the next request hits the new state.
|
|
278
|
+
setOAuthRuntimeConfig(oauthRuntimeFromAuthConfig(updated));
|
|
279
|
+
return c.json({
|
|
280
|
+
success: true,
|
|
281
|
+
data: {
|
|
282
|
+
coconut: {
|
|
283
|
+
enabled: updated.providers.oauth.coconut?.enabled ?? false,
|
|
284
|
+
clientId: updated.providers.oauth.coconut?.clientId,
|
|
285
|
+
issuer: CLERK_ISSUER,
|
|
286
|
+
jwksUrl: CLERK_JWKS_URL,
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
console.error('Update Coconut OAuth error:', error);
|
|
293
|
+
return c.json({ success: false, error: error.message || 'Failed to update Coconut OAuth' }, error.message === 'Admin access required' ? 403 : 500);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
223
296
|
/**
|
|
224
297
|
* PUT /api/v1/auth-settings/oauth/:provider
|
|
225
|
-
* Configure OAuth provider (admin only)
|
|
298
|
+
* Configure a third-party OAuth provider (admin only). Coconut OAuth has its
|
|
299
|
+
* own dedicated route (above) with stricter validation and live runtime
|
|
300
|
+
* reload, so this handler refuses `coconut` to avoid ambiguity.
|
|
226
301
|
*/
|
|
227
302
|
authSettings.put('/oauth/:provider', async (c) => {
|
|
228
303
|
try {
|
|
229
304
|
requireAdmin(c);
|
|
230
|
-
const authManager = getAuthManager();
|
|
231
305
|
const provider = c.req.param('provider');
|
|
306
|
+
if (provider === 'coconut') {
|
|
307
|
+
return c.json({
|
|
308
|
+
success: false,
|
|
309
|
+
error: 'Use PUT /auth-settings/oauth/coconut for Coconut OAuth',
|
|
310
|
+
}, 400);
|
|
311
|
+
}
|
|
312
|
+
const authManager = getAuthManager();
|
|
232
313
|
const body = await c.req.json();
|
|
233
314
|
const config = await authManager.loadAuthConfig();
|
|
234
315
|
if (!config.providers.oauth) {
|
|
@@ -7,9 +7,9 @@ import { Context } from "hono";
|
|
|
7
7
|
* Get logging system status and configuration
|
|
8
8
|
*/
|
|
9
9
|
export declare function GET(c: Context): Promise<(Response & import("hono").TypedResponse<{
|
|
10
|
-
[x: string]: any;
|
|
11
10
|
currentFile: string;
|
|
12
11
|
sizeBytes: number;
|
|
12
|
+
lastSeq: number;
|
|
13
13
|
rotateBytes: number;
|
|
14
14
|
logsDir: string;
|
|
15
15
|
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
@@ -9,6 +9,9 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
9
9
|
}, 404, "json">) | (Response & import("hono").TypedResponse<{
|
|
10
10
|
success: true;
|
|
11
11
|
data: {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
status: ScheduledJobStatus;
|
|
12
15
|
schedule: {
|
|
13
16
|
type: "cron";
|
|
14
17
|
expression: string;
|
|
@@ -22,11 +25,8 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
22
25
|
anchorHour?: number;
|
|
23
26
|
};
|
|
24
27
|
description?: string;
|
|
25
|
-
id: string;
|
|
26
|
-
name: string;
|
|
27
28
|
prompt: string;
|
|
28
29
|
model: string;
|
|
29
|
-
status: ScheduledJobStatus;
|
|
30
30
|
metadata: {
|
|
31
31
|
createdAt: string;
|
|
32
32
|
updatedAt: string;
|
|
@@ -39,8 +39,8 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
39
39
|
agentIds?: string[];
|
|
40
40
|
mcpServers?: string[];
|
|
41
41
|
runs: {
|
|
42
|
-
error?: string;
|
|
43
42
|
id: string;
|
|
43
|
+
error?: string;
|
|
44
44
|
status: import("@lovelybunch/types").ScheduledJobRunStatus;
|
|
45
45
|
jobId: string;
|
|
46
46
|
trigger: import("@lovelybunch/types").ScheduledJobTrigger;
|
|
@@ -70,6 +70,9 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
70
70
|
}, 400, "json">) | (Response & import("hono").TypedResponse<{
|
|
71
71
|
success: true;
|
|
72
72
|
data: {
|
|
73
|
+
id: string;
|
|
74
|
+
name: string;
|
|
75
|
+
status: ScheduledJobStatus;
|
|
73
76
|
schedule: {
|
|
74
77
|
type: "cron";
|
|
75
78
|
expression: string;
|
|
@@ -83,11 +86,8 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
83
86
|
anchorHour?: number;
|
|
84
87
|
};
|
|
85
88
|
description?: string;
|
|
86
|
-
id: string;
|
|
87
|
-
name: string;
|
|
88
89
|
prompt: string;
|
|
89
90
|
model: string;
|
|
90
|
-
status: ScheduledJobStatus;
|
|
91
91
|
metadata: {
|
|
92
92
|
createdAt: string;
|
|
93
93
|
updatedAt: string;
|
|
@@ -100,8 +100,8 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
100
100
|
agentIds?: string[];
|
|
101
101
|
mcpServers?: string[];
|
|
102
102
|
runs: {
|
|
103
|
-
error?: string;
|
|
104
103
|
id: string;
|
|
104
|
+
error?: string;
|
|
105
105
|
status: import("@lovelybunch/types").ScheduledJobRunStatus;
|
|
106
106
|
jobId: string;
|
|
107
107
|
trigger: import("@lovelybunch/types").ScheduledJobTrigger;
|
|
@@ -12,8 +12,8 @@ export declare function POST(c: Context): Promise<(Response & import("hono").Typ
|
|
|
12
12
|
run: {
|
|
13
13
|
id: string;
|
|
14
14
|
jobId: string;
|
|
15
|
-
trigger: import("
|
|
16
|
-
status: import("
|
|
15
|
+
trigger: import("node_modules/@lovelybunch/types/src/index.js").ScheduledJobTrigger;
|
|
16
|
+
status: import("node_modules/@lovelybunch/types/src/index.js").ScheduledJobRunStatus;
|
|
17
17
|
startedAt: string;
|
|
18
18
|
finishedAt?: string;
|
|
19
19
|
outputPath?: string;
|
|
@@ -10,8 +10,8 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
10
10
|
data: {
|
|
11
11
|
id: string;
|
|
12
12
|
jobId: string;
|
|
13
|
-
trigger: import("
|
|
14
|
-
status: import("
|
|
13
|
+
trigger: import("node_modules/@lovelybunch/types/src/index.js").ScheduledJobTrigger;
|
|
14
|
+
status: import("node_modules/@lovelybunch/types/src/index.js").ScheduledJobRunStatus;
|
|
15
15
|
startedAt: string;
|
|
16
16
|
finishedAt?: string;
|
|
17
17
|
outputPath?: string;
|