@n24q02m/hull 0.0.0-stage → 0.4.0-beta.9

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.
Files changed (231) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +166 -2
  3. package/build/auth/credential-form.d.ts +163 -0
  4. package/build/auth/credential-form.d.ts.map +1 -0
  5. package/build/auth/credential-form.js +1869 -0
  6. package/build/auth/credential-form.js.map +1 -0
  7. package/build/auth/delegated-oauth-app.d.ts +90 -0
  8. package/build/auth/delegated-oauth-app.d.ts.map +1 -0
  9. package/build/auth/delegated-oauth-app.js +881 -0
  10. package/build/auth/delegated-oauth-app.js.map +1 -0
  11. package/build/auth/index.d.ts +12 -0
  12. package/build/auth/index.d.ts.map +1 -0
  13. package/build/auth/index.js +12 -0
  14. package/build/auth/index.js.map +1 -0
  15. package/build/auth/local-oauth-app.d.ts +152 -0
  16. package/build/auth/local-oauth-app.d.ts.map +1 -0
  17. package/build/auth/local-oauth-app.js +975 -0
  18. package/build/auth/local-oauth-app.js.map +1 -0
  19. package/build/auth/relay-login.d.ts +46 -0
  20. package/build/auth/relay-login.d.ts.map +1 -0
  21. package/build/auth/relay-login.js +197 -0
  22. package/build/auth/relay-login.js.map +1 -0
  23. package/build/auth/router.d.ts +18 -0
  24. package/build/auth/router.d.ts.map +1 -0
  25. package/build/auth/router.js +62 -0
  26. package/build/auth/router.js.map +1 -0
  27. package/build/auth/session-store.d.ts +49 -0
  28. package/build/auth/session-store.d.ts.map +1 -0
  29. package/build/auth/session-store.js +94 -0
  30. package/build/auth/session-store.js.map +1 -0
  31. package/build/auth/stable-sub.d.ts +27 -0
  32. package/build/auth/stable-sub.d.ts.map +1 -0
  33. package/build/auth/stable-sub.js +38 -0
  34. package/build/auth/stable-sub.js.map +1 -0
  35. package/build/auth/well-known.d.ts +4 -0
  36. package/build/auth/well-known.d.ts.map +1 -0
  37. package/build/auth/well-known.js +26 -0
  38. package/build/auth/well-known.js.map +1 -0
  39. package/build/cli/build-cli.d.ts +97 -0
  40. package/build/cli/build-cli.d.ts.map +1 -0
  41. package/build/cli/build-cli.js +309 -0
  42. package/build/cli/build-cli.js.map +1 -0
  43. package/build/cli/index.d.ts +2 -0
  44. package/build/cli/index.d.ts.map +1 -0
  45. package/build/cli/index.js +2 -0
  46. package/build/cli/index.js.map +1 -0
  47. package/build/crypto/aes.d.ts +8 -0
  48. package/build/crypto/aes.d.ts.map +1 -0
  49. package/build/crypto/aes.js +27 -0
  50. package/build/crypto/aes.js.map +1 -0
  51. package/build/crypto/ecdh.d.ts +5 -0
  52. package/build/crypto/ecdh.d.ts.map +1 -0
  53. package/build/crypto/ecdh.js +16 -0
  54. package/build/crypto/ecdh.js.map +1 -0
  55. package/build/crypto/index.d.ts +4 -0
  56. package/build/crypto/index.d.ts.map +1 -0
  57. package/build/crypto/index.js +4 -0
  58. package/build/crypto/index.js.map +1 -0
  59. package/build/crypto/kdf.d.ts +15 -0
  60. package/build/crypto/kdf.d.ts.map +1 -0
  61. package/build/crypto/kdf.js +26 -0
  62. package/build/crypto/kdf.js.map +1 -0
  63. package/build/index.d.ts +19 -0
  64. package/build/index.d.ts.map +1 -0
  65. package/build/index.js +28 -0
  66. package/build/index.js.map +1 -0
  67. package/build/lifecycle/lock.d.ts +68 -0
  68. package/build/lifecycle/lock.d.ts.map +1 -0
  69. package/build/lifecycle/lock.js +173 -0
  70. package/build/lifecycle/lock.js.map +1 -0
  71. package/build/oauth/cache.d.ts +22 -0
  72. package/build/oauth/cache.d.ts.map +1 -0
  73. package/build/oauth/cache.js +24 -0
  74. package/build/oauth/cache.js.map +1 -0
  75. package/build/oauth/index.d.ts +6 -0
  76. package/build/oauth/index.d.ts.map +1 -0
  77. package/build/oauth/index.js +6 -0
  78. package/build/oauth/index.js.map +1 -0
  79. package/build/oauth/jwt-issuer.d.ts +87 -0
  80. package/build/oauth/jwt-issuer.d.ts.map +1 -0
  81. package/build/oauth/jwt-issuer.js +205 -0
  82. package/build/oauth/jwt-issuer.js.map +1 -0
  83. package/build/oauth/pkce.d.ts +10 -0
  84. package/build/oauth/pkce.d.ts.map +1 -0
  85. package/build/oauth/pkce.js +34 -0
  86. package/build/oauth/pkce.js.map +1 -0
  87. package/build/oauth/provider.d.ts +52 -0
  88. package/build/oauth/provider.d.ts.map +1 -0
  89. package/build/oauth/provider.js +98 -0
  90. package/build/oauth/provider.js.map +1 -0
  91. package/build/oauth/user-store.d.ts +25 -0
  92. package/build/oauth/user-store.d.ts.map +1 -0
  93. package/build/oauth/user-store.js +85 -0
  94. package/build/oauth/user-store.js.map +1 -0
  95. package/build/relay/browser.d.ts +15 -0
  96. package/build/relay/browser.d.ts.map +1 -0
  97. package/build/relay/browser.js +121 -0
  98. package/build/relay/browser.js.map +1 -0
  99. package/build/relay/client.d.ts +36 -0
  100. package/build/relay/client.d.ts.map +1 -0
  101. package/build/relay/client.js +135 -0
  102. package/build/relay/client.js.map +1 -0
  103. package/build/relay/session.d.ts +12 -0
  104. package/build/relay/session.d.ts.map +1 -0
  105. package/build/relay/session.js +55 -0
  106. package/build/relay/session.js.map +1 -0
  107. package/build/relay/tool-helpers.d.ts +85 -0
  108. package/build/relay/tool-helpers.d.ts.map +1 -0
  109. package/build/relay/tool-helpers.js +103 -0
  110. package/build/relay/tool-helpers.js.map +1 -0
  111. package/build/relay/wordlist.d.ts +2 -0
  112. package/build/relay/wordlist.d.ts.map +1 -0
  113. package/build/relay/wordlist.js +7782 -0
  114. package/build/relay/wordlist.js.map +1 -0
  115. package/build/schema/types.d.ts +67 -0
  116. package/build/schema/types.d.ts.map +1 -0
  117. package/build/schema/types.js +2 -0
  118. package/build/schema/types.js.map +1 -0
  119. package/build/storage/atomic-write.d.ts +8 -0
  120. package/build/storage/atomic-write.d.ts.map +1 -0
  121. package/build/storage/atomic-write.js +26 -0
  122. package/build/storage/atomic-write.js.map +1 -0
  123. package/build/storage/backends.d.ts +74 -0
  124. package/build/storage/backends.d.ts.map +1 -0
  125. package/build/storage/backends.js +193 -0
  126. package/build/storage/backends.js.map +1 -0
  127. package/build/storage/config-file.d.ts +35 -0
  128. package/build/storage/config-file.d.ts.map +1 -0
  129. package/build/storage/config-file.js +259 -0
  130. package/build/storage/config-file.js.map +1 -0
  131. package/build/storage/credential-store.d.ts +71 -0
  132. package/build/storage/credential-store.d.ts.map +1 -0
  133. package/build/storage/credential-store.js +91 -0
  134. package/build/storage/credential-store.js.map +1 -0
  135. package/build/storage/data-dir.d.ts +58 -0
  136. package/build/storage/data-dir.d.ts.map +1 -0
  137. package/build/storage/data-dir.js +79 -0
  138. package/build/storage/data-dir.js.map +1 -0
  139. package/build/storage/encryption.d.ts +9 -0
  140. package/build/storage/encryption.d.ts.map +1 -0
  141. package/build/storage/encryption.js +27 -0
  142. package/build/storage/encryption.js.map +1 -0
  143. package/build/storage/home-dir.d.ts +11 -0
  144. package/build/storage/home-dir.d.ts.map +1 -0
  145. package/build/storage/home-dir.js +18 -0
  146. package/build/storage/home-dir.js.map +1 -0
  147. package/build/storage/index.d.ts +12 -0
  148. package/build/storage/index.d.ts.map +1 -0
  149. package/build/storage/index.js +15 -0
  150. package/build/storage/index.js.map +1 -0
  151. package/build/storage/machine-id.d.ts +4 -0
  152. package/build/storage/machine-id.d.ts.map +1 -0
  153. package/build/storage/machine-id.js +73 -0
  154. package/build/storage/machine-id.js.map +1 -0
  155. package/build/storage/mode.d.ts +23 -0
  156. package/build/storage/mode.d.ts.map +1 -0
  157. package/build/storage/mode.js +46 -0
  158. package/build/storage/mode.js.map +1 -0
  159. package/build/storage/per-plugin-store.d.ts +65 -0
  160. package/build/storage/per-plugin-store.d.ts.map +1 -0
  161. package/build/storage/per-plugin-store.js +194 -0
  162. package/build/storage/per-plugin-store.js.map +1 -0
  163. package/build/storage/resolver.d.ts +7 -0
  164. package/build/storage/resolver.d.ts.map +1 -0
  165. package/build/storage/resolver.js +38 -0
  166. package/build/storage/resolver.js.map +1 -0
  167. package/build/storage/session-lock.d.ts +19 -0
  168. package/build/storage/session-lock.d.ts.map +1 -0
  169. package/build/storage/session-lock.js +105 -0
  170. package/build/storage/session-lock.js.map +1 -0
  171. package/build/token-auth/authenticator.d.ts +70 -0
  172. package/build/token-auth/authenticator.d.ts.map +1 -0
  173. package/build/token-auth/authenticator.js +146 -0
  174. package/build/token-auth/authenticator.js.map +1 -0
  175. package/build/token-auth/cli.d.ts +38 -0
  176. package/build/token-auth/cli.d.ts.map +1 -0
  177. package/build/token-auth/cli.js +192 -0
  178. package/build/token-auth/cli.js.map +1 -0
  179. package/build/token-auth/context.d.ts +30 -0
  180. package/build/token-auth/context.d.ts.map +1 -0
  181. package/build/token-auth/context.js +32 -0
  182. package/build/token-auth/context.js.map +1 -0
  183. package/build/token-auth/http-guard.d.ts +26 -0
  184. package/build/token-auth/http-guard.d.ts.map +1 -0
  185. package/build/token-auth/http-guard.js +51 -0
  186. package/build/token-auth/http-guard.js.map +1 -0
  187. package/build/token-auth/index.d.ts +14 -0
  188. package/build/token-auth/index.d.ts.map +1 -0
  189. package/build/token-auth/index.js +14 -0
  190. package/build/token-auth/index.js.map +1 -0
  191. package/build/token-auth/limiter.d.ts +20 -0
  192. package/build/token-auth/limiter.d.ts.map +1 -0
  193. package/build/token-auth/limiter.js +41 -0
  194. package/build/token-auth/limiter.js.map +1 -0
  195. package/build/token-auth/loopback.d.ts +17 -0
  196. package/build/token-auth/loopback.d.ts.map +1 -0
  197. package/build/token-auth/loopback.js +62 -0
  198. package/build/token-auth/loopback.js.map +1 -0
  199. package/build/token-auth/py-compat.d.ts +24 -0
  200. package/build/token-auth/py-compat.d.ts.map +1 -0
  201. package/build/token-auth/py-compat.js +76 -0
  202. package/build/token-auth/py-compat.js.map +1 -0
  203. package/build/token-auth/tokens.d.ts +36 -0
  204. package/build/token-auth/tokens.d.ts.map +1 -0
  205. package/build/token-auth/tokens.js +115 -0
  206. package/build/token-auth/tokens.js.map +1 -0
  207. package/build/token-auth/users.d.ts +62 -0
  208. package/build/token-auth/users.d.ts.map +1 -0
  209. package/build/token-auth/users.js +174 -0
  210. package/build/token-auth/users.js.map +1 -0
  211. package/build/transport/cache.d.ts +19 -0
  212. package/build/transport/cache.d.ts.map +1 -0
  213. package/build/transport/cache.js +76 -0
  214. package/build/transport/cache.js.map +1 -0
  215. package/build/transport/index.d.ts +5 -0
  216. package/build/transport/index.d.ts.map +1 -0
  217. package/build/transport/index.js +4 -0
  218. package/build/transport/index.js.map +1 -0
  219. package/build/transport/local-server.d.ts +173 -0
  220. package/build/transport/local-server.d.ts.map +1 -0
  221. package/build/transport/local-server.js +457 -0
  222. package/build/transport/local-server.js.map +1 -0
  223. package/build/transport/oauth-middleware.d.ts +45 -0
  224. package/build/transport/oauth-middleware.d.ts.map +1 -0
  225. package/build/transport/oauth-middleware.js +86 -0
  226. package/build/transport/oauth-middleware.js.map +1 -0
  227. package/build/transport/streamable-http.d.ts +54 -0
  228. package/build/transport/streamable-http.d.ts.map +1 -0
  229. package/build/transport/streamable-http.js +57 -0
  230. package/build/transport/streamable-http.js.map +1 -0
  231. package/package.json +107 -4
@@ -0,0 +1,15 @@
1
+ export declare function deriveAesKey(sharedSecret: ArrayBuffer, passphrase: string): Promise<CryptoKey>;
2
+ /**
3
+ * Derive a deterministic 32-byte Ed25519 seed for OAuth JWT signing.
4
+ *
5
+ * Used in HTTP multi-user mode (CREDENTIAL_SECRET set) so every container
6
+ * replica converges on the SAME signing key without a shared volume or
7
+ * external secret store. Domain-separated per server via the HKDF info label.
8
+ *
9
+ * HKDF-SHA256 with IKM = secret, empty salt, info =
10
+ * `mcp-jwt-signing-key-v1:<serverName>`. Byte-identical to core-py's
11
+ * `derive_jwt_signing_seed` for the same inputs (enforced by the shared
12
+ * crypto-vectors fixture).
13
+ */
14
+ export declare function deriveJwtSigningSeed(secret: string, serverName: string): Buffer;
15
+ //# sourceMappingURL=kdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kdf.d.ts","sourceRoot":"","sources":["../../src/crypto/kdf.ts"],"names":[],"mappings":"AAOA,wBAAsB,YAAY,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAWpG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAG/E"}
@@ -0,0 +1,26 @@
1
+ import { hkdfSync } from 'node:crypto';
2
+ const encoder = new TextEncoder();
3
+ const INFO = encoder.encode('mcp-relay');
4
+ const JWT_SIGNING_INFO_PREFIX = 'mcp-jwt-signing-key-v1:';
5
+ export async function deriveAesKey(sharedSecret, passphrase) {
6
+ const salt = encoder.encode(passphrase);
7
+ const keyMaterial = await crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false, ['deriveKey']);
8
+ return crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-256', salt, info: INFO }, keyMaterial, { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
9
+ }
10
+ /**
11
+ * Derive a deterministic 32-byte Ed25519 seed for OAuth JWT signing.
12
+ *
13
+ * Used in HTTP multi-user mode (CREDENTIAL_SECRET set) so every container
14
+ * replica converges on the SAME signing key without a shared volume or
15
+ * external secret store. Domain-separated per server via the HKDF info label.
16
+ *
17
+ * HKDF-SHA256 with IKM = secret, empty salt, info =
18
+ * `mcp-jwt-signing-key-v1:<serverName>`. Byte-identical to core-py's
19
+ * `derive_jwt_signing_seed` for the same inputs (enforced by the shared
20
+ * crypto-vectors fixture).
21
+ */
22
+ export function deriveJwtSigningSeed(secret, serverName) {
23
+ const info = encoder.encode(`${JWT_SIGNING_INFO_PREFIX}${serverName}`);
24
+ return Buffer.from(hkdfSync('sha256', Buffer.from(secret, 'utf-8'), Buffer.alloc(0), info, 32));
25
+ }
26
+ //# sourceMappingURL=kdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kdf.js","sourceRoot":"","sources":["../../src/crypto/kdf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;AAEjC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;AACxC,MAAM,uBAAuB,GAAG,yBAAyB,CAAA;AAEzD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,YAAyB,EAAE,UAAkB;IAC9E,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACvC,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAEpG,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EACnD,WAAW,EACX,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,EAChC,IAAI,EACJ,CAAC,SAAS,EAAE,SAAS,CAAC,CACvB,CAAA;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,UAAkB;IACrE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,uBAAuB,GAAG,UAAU,EAAE,CAAC,CAAA;IACtE,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;AACjG,CAAC"}
@@ -0,0 +1,19 @@
1
+ export { authorizationServerMetadata, type CapabilityInfo, type ConfigField, type CredentialsCallback, createDelegatedOAuthApp, createLocalOAuthApp, type DelegatedOAuthAppOptions, type DelegatedOAuthAppResult, type FlowType, type LocalOAuthAppOptions, type LocalOAuthAppResult, type NextStep, type OAuthTokens, protectedResourceMetadata, type RelayConfigSchema, type RenderOptions, renderCredentialForm, type StepCallback, type SubjectContext, type TokenCallback, type UpstreamOAuthConfig } from './auth/index.js';
2
+ export { type BuildCliOptions, buildCli, type CliHandler, type ServeFn } from './cli/build-cli.js';
3
+ export * from './crypto/index.js';
4
+ export { JWTIssuer } from './oauth/jwt-issuer.js';
5
+ export { verifyPKCE } from './oauth/pkce.js';
6
+ export { InMemoryAuthCache, type IOAuthSessionCache, OAuthProvider, type OAuthProviderOptions, type PreAuthSession } from './oauth/provider.js';
7
+ export { type IUserCredentialStore, SqliteUserStore } from './oauth/user-store.js';
8
+ export { tryOpenBrowser } from './relay/browser.js';
9
+ export { createSession, generatePassphrase, notifyComplete, pollForResponses, pollForResult, type RelaySession, sendMessage } from './relay/client.js';
10
+ export { buildOpenRelayHandler, type ElicitationServer, type OpenRelayHandlerOptions, type OpenRelayResult, registerOpenRelayTool, type ToolRegistrar } from './relay/tool-helpers.js';
11
+ export type * from './schema/types.js';
12
+ export { exportConfig, importConfig, listConfigs, scheduleReloadExit } from './storage/config-file.js';
13
+ export { deleteStoredConfig as deleteConfig, readStoredConfig as readConfig, writeStoredConfig as writeConfig } from './storage/credential-store.js';
14
+ export { clearMode, getMode, type ServerMode, setLocalMode } from './storage/mode.js';
15
+ export * from './storage/resolver.js';
16
+ export { acquireSessionLock, releaseSessionLock, type SessionInfo, writeSessionLock } from './storage/session-lock.js';
17
+ export * from './token-auth/index.js';
18
+ export { type HttpRoute, type HttpServerHandle, type RunHttpServerOptions, runHttpServer } from './transport/local-server.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,2BAA2B,EAC3B,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,yBAAyB,EACzB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,oBAAoB,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAClG,cAAc,mBAAmB,CAAA;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,KAAK,oBAAoB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,KAAK,YAAY,EACjB,WAAW,EACZ,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,aAAa,EACnB,MAAM,yBAAyB,CAAA;AAChC,mBAAmB,mBAAmB,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAGtG,OAAO,EACL,kBAAkB,IAAI,YAAY,EAClC,gBAAgB,IAAI,UAAU,EAC9B,iBAAiB,IAAI,WAAW,EACjC,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrF,cAAc,uBAAuB,CAAA;AACrC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,WAAW,EAChB,gBAAgB,EACjB,MAAM,2BAA2B,CAAA;AAGlC,cAAc,uBAAuB,CAAA;AAErC,OAAO,EACL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,aAAa,EACd,MAAM,6BAA6B,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,28 @@
1
+ // Local OAuth 2.1 Authorization Server (single-user, 127.0.0.1) +
2
+ // Delegated OAuth (upstream redirect / device code) for remote multi-user.
3
+ export { authorizationServerMetadata, createDelegatedOAuthApp, createLocalOAuthApp, protectedResourceMetadata, renderCredentialForm } from './auth/index.js';
4
+ // Console-script CLI builder shared by every TS MCP server (config/relay/doctor
5
+ // built-ins + version + help; parity with core-py's build_cli).
6
+ export { buildCli } from './cli/build-cli.js';
7
+ export * from './crypto/index.js';
8
+ // OAuth 2.1 multi-user infrastructure (HTTP mode)
9
+ export { JWTIssuer } from './oauth/jwt-issuer.js';
10
+ export { verifyPKCE } from './oauth/pkce.js';
11
+ export { InMemoryAuthCache, OAuthProvider } from './oauth/provider.js';
12
+ export { SqliteUserStore } from './oauth/user-store.js';
13
+ export { tryOpenBrowser } from './relay/browser.js';
14
+ export { createSession, generatePassphrase, notifyComplete, pollForResponses, pollForResult, sendMessage } from './relay/client.js';
15
+ export { buildOpenRelayHandler, registerOpenRelayTool } from './relay/tool-helpers.js';
16
+ export { exportConfig, importConfig, listConfigs, scheduleReloadExit } from './storage/config-file.js';
17
+ // Single-user credential read/write/delete route through the unified
18
+ // per-plugin store (with legacy config.enc read fallback).
19
+ export { deleteStoredConfig as deleteConfig, readStoredConfig as readConfig, writeStoredConfig as writeConfig } from './storage/credential-store.js';
20
+ export { clearMode, getMode, setLocalMode } from './storage/mode.js';
21
+ export * from './storage/resolver.js';
22
+ export { acquireSessionLock, releaseSessionLock, writeSessionLock } from './storage/session-lock.js';
23
+ // HTTP token-table auth (no-auth / token / multi users.toml), the TS port of
24
+ // core-py hull_core.auth; wired into runHttpServer via its `auth` option.
25
+ export * from './token-auth/index.js';
26
+ // HTTP MCP server entry point (OAuth AS + /mcp transport on 127.0.0.1)
27
+ export { runHttpServer } from './transport/local-server.js';
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,2EAA2E;AAC3E,OAAO,EACL,2BAA2B,EAI3B,uBAAuB,EACvB,mBAAmB,EAQnB,yBAAyB,EAGzB,oBAAoB,EAKrB,MAAM,iBAAiB,CAAA;AACxB,gFAAgF;AAChF,gEAAgE;AAChE,OAAO,EAAwB,QAAQ,EAAiC,MAAM,oBAAoB,CAAA;AAClG,cAAc,mBAAmB,CAAA;AACjC,kDAAkD;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EACL,iBAAiB,EAEjB,aAAa,EAGd,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAA6B,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,aAAa,EAEb,WAAW,EACZ,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,qBAAqB,EAIrB,qBAAqB,EAEtB,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AACtG,qEAAqE;AACrE,2DAA2D;AAC3D,OAAO,EACL,kBAAkB,IAAI,YAAY,EAClC,gBAAgB,IAAI,UAAU,EAC9B,iBAAiB,IAAI,WAAW,EACjC,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAmB,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrF,cAAc,uBAAuB,CAAA;AACrC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAElB,gBAAgB,EACjB,MAAM,2BAA2B,CAAA;AAClC,6EAA6E;AAC7E,0EAA0E;AAC1E,cAAc,uBAAuB,CAAA;AACrC,uEAAuE;AACvE,OAAO,EAIL,aAAa,EACd,MAAM,6BAA6B,CAAA"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Lock-file lifecycle helpers for HTTP server mode.
3
+ *
4
+ * After the stdio-pure + http-multi-user split, lock files are used solely
5
+ * by `runHttpServer` to prevent two HTTP servers binding the same port for
6
+ * the same `serverName`. They are no longer used to discover or steer
7
+ * daemon-bridge processes; per-credState TTLs and PID liveness checks have
8
+ * been removed along with the daemon model.
9
+ *
10
+ * On-disk format (4 lines + trailing newline, padded to 512 bytes):
11
+ *
12
+ * ```
13
+ * {pid}
14
+ * {port}
15
+ * {token}
16
+ * {spawnedAt_iso8601_utc}
17
+ * ```
18
+ *
19
+ * `sweepStaleLocks` removes lock files whose `spawnedAt` is older than the
20
+ * configured TTL. There is no daemon to terminate — the HTTP server owns
21
+ * its own lifecycle and exits when its parent process exits.
22
+ *
23
+ * TypeScript port of core-py's `mcp_core.lifecycle.lock`. Behaviour kept
24
+ * identical for cross-language parity.
25
+ */
26
+ export declare const DEFAULT_LOCK_TTL_HOURS = 24;
27
+ /** Parsed lock metadata — shared by sweep and refresh helpers. */
28
+ export interface LockMetadata {
29
+ pid: number;
30
+ port: number;
31
+ token: string;
32
+ spawnedAt: Date;
33
+ }
34
+ export declare function locksDir(root?: string): string;
35
+ /**
36
+ * No-arg lock-dir resolver — sweep tests `vi.spyOn(lockModule, 'lockDir')`
37
+ * to redirect into a temp directory without threading a `root` arg.
38
+ */
39
+ export declare function lockDir(): string;
40
+ /**
41
+ * Refresh `spawnedAt` of an existing lock file. Silent no-op on legacy /
42
+ * malformed files so callers don't need try/except.
43
+ *
44
+ * Padded to 512 bytes so on-disk size stays stable while a Windows
45
+ * byte-range lock is held past the metadata region (parity with core-py).
46
+ */
47
+ export declare function refreshLockTimestamp(path: string): void;
48
+ /**
49
+ * Remove stale lock files for `serverName`. Returns count removed.
50
+ *
51
+ * Called by `runHttpServer` at startup before writing its own lock,
52
+ * preventing pile-up of dozens of `<server>-<port>.lock` files when HTTP
53
+ * servers exit abnormally (Windows OOM, taskkill, signal).
54
+ *
55
+ * A lock is stale when:
56
+ * - file is unreadable or has malformed payload (legacy / corrupt)
57
+ * - `spawnedAt` is older than the TTL
58
+ */
59
+ export declare function sweepStaleLocks(serverName: string, ttlHours?: number, root?: string): number;
60
+ /**
61
+ * Write the 4-line lock payload (pid, port, token, ISO timestamp) padded
62
+ * to 512 bytes. Used by `runHttpServer` after the OS file lock is
63
+ * acquired.
64
+ *
65
+ * Returns the absolute path to the lock file.
66
+ */
67
+ export declare function writeLockFile(serverName: string, port: number, token: string, root?: string): string;
68
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/lifecycle/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAcH,eAAO,MAAM,sBAAsB,KAAK,CAAA;AAExC,kEAAkE;AAClE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,IAAI,CAAA;CAChB;AAED,wBAAgB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;GAGG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAeD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiBvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAoD5F;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAMpG"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Lock-file lifecycle helpers for HTTP server mode.
3
+ *
4
+ * After the stdio-pure + http-multi-user split, lock files are used solely
5
+ * by `runHttpServer` to prevent two HTTP servers binding the same port for
6
+ * the same `serverName`. They are no longer used to discover or steer
7
+ * daemon-bridge processes; per-credState TTLs and PID liveness checks have
8
+ * been removed along with the daemon model.
9
+ *
10
+ * On-disk format (4 lines + trailing newline, padded to 512 bytes):
11
+ *
12
+ * ```
13
+ * {pid}
14
+ * {port}
15
+ * {token}
16
+ * {spawnedAt_iso8601_utc}
17
+ * ```
18
+ *
19
+ * `sweepStaleLocks` removes lock files whose `spawnedAt` is older than the
20
+ * configured TTL. There is no daemon to terminate — the HTTP server owns
21
+ * its own lifecycle and exits when its parent process exits.
22
+ *
23
+ * TypeScript port of core-py's `mcp_core.lifecycle.lock`. Behaviour kept
24
+ * identical for cross-language parity.
25
+ */
26
+ import { existsSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
27
+ import { homedir } from 'node:os';
28
+ import { join } from 'node:path';
29
+ // Self-import so `sweepStaleLocks` can resolve `lockDir` through the
30
+ // module namespace at call time. This makes
31
+ // `vi.spyOn(lockModule, 'lockDir').mockReturnValue(...)` actually
32
+ // intercept the helper from inside the sweep loop — without this
33
+ // indirection, the closure-captured local binding ignores spies and
34
+ // test mocks become silent no-ops.
35
+ import * as self from './lock.js';
36
+ export const DEFAULT_LOCK_TTL_HOURS = 24;
37
+ export function locksDir(root) {
38
+ return root ?? join(homedir(), '.config', 'mcp', 'locks');
39
+ }
40
+ /**
41
+ * No-arg lock-dir resolver — sweep tests `vi.spyOn(lockModule, 'lockDir')`
42
+ * to redirect into a temp directory without threading a `root` arg.
43
+ */
44
+ export function lockDir() {
45
+ return locksDir();
46
+ }
47
+ /** Internal helper: parse the textual lock payload into `LockMetadata`. */
48
+ function parseLockText(raw) {
49
+ const lines = raw.replace(/\n+$/, '').split('\n');
50
+ if (lines.length < 4)
51
+ return null;
52
+ const pid = Number(lines[0]);
53
+ const port = Number(lines[1]);
54
+ if (!Number.isInteger(pid) || !Number.isInteger(port))
55
+ return null;
56
+ const token = lines[2];
57
+ const spawnedAt = new Date(lines[3]);
58
+ if (Number.isNaN(spawnedAt.getTime()))
59
+ return null;
60
+ return { pid, port, token, spawnedAt };
61
+ }
62
+ /**
63
+ * Refresh `spawnedAt` of an existing lock file. Silent no-op on legacy /
64
+ * malformed files so callers don't need try/except.
65
+ *
66
+ * Padded to 512 bytes so on-disk size stays stable while a Windows
67
+ * byte-range lock is held past the metadata region (parity with core-py).
68
+ */
69
+ export function refreshLockTimestamp(path) {
70
+ if (!existsSync(path))
71
+ return;
72
+ let raw;
73
+ try {
74
+ raw = readFileSync(path, { encoding: 'utf-8' });
75
+ }
76
+ catch {
77
+ return;
78
+ }
79
+ const md = parseLockText(raw);
80
+ if (md === null)
81
+ return;
82
+ const now = new Date().toISOString();
83
+ const payload = `${md.pid}\n${md.port}\n${md.token}\n${now}\n`;
84
+ try {
85
+ writeFileSync(path, payload.padEnd(512, ' '), { encoding: 'utf-8' });
86
+ }
87
+ catch {
88
+ // Best-effort
89
+ }
90
+ }
91
+ /**
92
+ * Remove stale lock files for `serverName`. Returns count removed.
93
+ *
94
+ * Called by `runHttpServer` at startup before writing its own lock,
95
+ * preventing pile-up of dozens of `<server>-<port>.lock` files when HTTP
96
+ * servers exit abnormally (Windows OOM, taskkill, signal).
97
+ *
98
+ * A lock is stale when:
99
+ * - file is unreadable or has malformed payload (legacy / corrupt)
100
+ * - `spawnedAt` is older than the TTL
101
+ */
102
+ export function sweepStaleLocks(serverName, ttlHours, root) {
103
+ const dir = root !== undefined ? root : self.lockDir();
104
+ if (!existsSync(dir))
105
+ return 0;
106
+ let removed = 0;
107
+ let entries;
108
+ try {
109
+ entries = readdirSync(dir);
110
+ }
111
+ catch {
112
+ return 0;
113
+ }
114
+ const prefix = `${serverName}-`;
115
+ const suffix = '.lock';
116
+ const now = Date.now();
117
+ const ttlMs = (ttlHours ?? DEFAULT_LOCK_TTL_HOURS) * 3600 * 1000;
118
+ for (const entry of entries) {
119
+ if (!entry.startsWith(prefix) || !entry.endsWith(suffix))
120
+ continue;
121
+ const full = join(dir, entry);
122
+ let raw;
123
+ try {
124
+ raw = readFileSync(full, { encoding: 'utf-8' });
125
+ }
126
+ catch {
127
+ try {
128
+ unlinkSync(full);
129
+ removed += 1;
130
+ }
131
+ catch {
132
+ /* ignore */
133
+ }
134
+ continue;
135
+ }
136
+ const meta = parseLockText(raw);
137
+ if (meta === null) {
138
+ try {
139
+ unlinkSync(full);
140
+ removed += 1;
141
+ }
142
+ catch {
143
+ /* ignore */
144
+ }
145
+ continue;
146
+ }
147
+ if (now - meta.spawnedAt.getTime() > ttlMs) {
148
+ try {
149
+ unlinkSync(full);
150
+ removed += 1;
151
+ }
152
+ catch {
153
+ /* ignore */
154
+ }
155
+ }
156
+ }
157
+ return removed;
158
+ }
159
+ /**
160
+ * Write the 4-line lock payload (pid, port, token, ISO timestamp) padded
161
+ * to 512 bytes. Used by `runHttpServer` after the OS file lock is
162
+ * acquired.
163
+ *
164
+ * Returns the absolute path to the lock file.
165
+ */
166
+ export function writeLockFile(serverName, port, token, root) {
167
+ const dir = locksDir(root);
168
+ const path = join(dir, `${serverName}-${port}.lock`);
169
+ const payload = `${process.pid}\n${port}\n${token}\n${new Date().toISOString()}\n`;
170
+ writeFileSync(path, payload.padEnd(512, ' '), { encoding: 'utf-8', mode: 0o600 });
171
+ return path;
172
+ }
173
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/lifecycle/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC1F,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,qEAAqE;AACrE,4CAA4C;AAC5C,kEAAkE;AAClE,iEAAiE;AACjE,oEAAoE;AACpE,mCAAmC;AACnC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAEjC,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAA;AAUxC,MAAM,UAAU,QAAQ,CAAC,IAAa;IACpC,OAAO,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO;IACrB,OAAO,QAAQ,EAAE,CAAA;AACnB,CAAC;AAED,2EAA2E;AAC3E,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACjC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAClE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;IACtB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IACpC,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,IAAI,CAAA;IAClD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAA;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAM;IAC7B,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAM;IACR,CAAC;IACD,MAAM,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;IAC7B,IAAI,EAAE,KAAK,IAAI;QAAE,OAAM;IACvB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACpC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,KAAK,KAAK,GAAG,IAAI,CAAA;IAC9D,IAAI,CAAC;QACH,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB,EAAE,QAAiB,EAAE,IAAa;IAClF,MAAM,GAAG,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAA;IACtD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,CAAA;IAE9B,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,IAAI,OAAiB,CAAA;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAA;IACV,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,UAAU,GAAG,CAAA;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAA;IACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACtB,MAAM,KAAK,GAAG,CAAC,QAAQ,IAAI,sBAAsB,CAAC,GAAG,IAAI,GAAG,IAAI,CAAA;IAEhE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,SAAQ;QAClE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC7B,IAAI,GAAW,CAAA;QACf,IAAI,CAAC;YACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,CAAA;gBAChB,OAAO,IAAI,CAAC,CAAA;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;YACD,SAAQ;QACV,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;QAC/B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,CAAA;gBAChB,OAAO,IAAI,CAAC,CAAA;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;YACD,SAAQ;QACV,CAAC;QACD,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,CAAA;gBAChB,OAAO,IAAI,CAAC,CAAA;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,IAAY,EAAE,KAAa,EAAE,IAAa;IAC1F,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,IAAI,IAAI,OAAO,CAAC,CAAA;IACpD,MAAM,OAAO,GAAG,GAAG,OAAO,CAAC,GAAG,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,CAAA;IAClF,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACjF,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,22 @@
1
+ export interface PreAuthSession {
2
+ sessionId: string;
3
+ clientId: string;
4
+ redirectUri: string;
5
+ state: string;
6
+ codeChallenge: string;
7
+ codeChallengeMethod: string;
8
+ /** Serialized CryptoKeyPair for later credential retrieval */
9
+ keyPairJwk: JsonWebKey;
10
+ passphrase: string;
11
+ expiresAt: number;
12
+ }
13
+ export interface IOAuthSessionCache {
14
+ save(session: PreAuthSession): void;
15
+ getAndDelete(sessionId: string): PreAuthSession | null;
16
+ }
17
+ export declare class InMemoryAuthCache implements IOAuthSessionCache {
18
+ private cache;
19
+ save(session: PreAuthSession): void;
20
+ getAndDelete(sessionId: string): PreAuthSession | null;
21
+ }
22
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/oauth/cache.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;IACrB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,8DAA8D;IAC9D,UAAU,EAAE,UAAU,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IACnC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAA;CACvD;AAED,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,KAAK,CAAoC;IAEjD,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAOlC;IAED,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMrD;CACF"}
@@ -0,0 +1,24 @@
1
+ export class InMemoryAuthCache {
2
+ constructor() {
3
+ this.cache = new Map();
4
+ }
5
+ save(session) {
6
+ this.cache.set(session.sessionId, session);
7
+ // Cleanup expired entries
8
+ const now = Math.floor(Date.now() / 1000);
9
+ for (const [id, sess] of this.cache) {
10
+ if (sess.expiresAt < now)
11
+ this.cache.delete(id);
12
+ }
13
+ }
14
+ getAndDelete(sessionId) {
15
+ const sess = this.cache.get(sessionId);
16
+ if (!sess)
17
+ return null;
18
+ this.cache.delete(sessionId);
19
+ if (sess.expiresAt < Math.floor(Date.now() / 1000))
20
+ return null;
21
+ return sess;
22
+ }
23
+ }
24
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/oauth/cache.ts"],"names":[],"mappings":"AAkBA,MAAM,OAAO,iBAAiB;IAA9B;QACU,UAAK,GAAG,IAAI,GAAG,EAA0B,CAAA;IAkBnD,CAAC;IAhBC,IAAI,CAAC,OAAuB;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAC1C,0BAA0B;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QACzC,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,SAAS,GAAG,GAAG;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACjD,CAAC;IACH,CAAC;IAED,YAAY,CAAC,SAAiB;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACtC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QACtB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAC5B,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QAC/D,OAAO,IAAI,CAAA;IACb,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ export { InMemoryAuthCache, type IOAuthSessionCache, type PreAuthSession } from './cache.js';
2
+ export { JWTIssuer } from './jwt-issuer.js';
3
+ export { verifyPKCE } from './pkce.js';
4
+ export { OAuthProvider, type OAuthProviderOptions } from './provider.js';
5
+ export { type IUserCredentialStore, SqliteUserStore } from './user-store.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,KAAK,oBAAoB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { InMemoryAuthCache } from './cache.js';
2
+ export { JWTIssuer } from './jwt-issuer.js';
3
+ export { verifyPKCE } from './pkce.js';
4
+ export { OAuthProvider } from './provider.js';
5
+ export { SqliteUserStore } from './user-store.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAGlB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EACL,aAAa,EAEd,MAAM,eAAe,CAAA;AACtB,OAAO,EAA6B,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * JWT Issuer and JWKS generation for TypeScript MCP servers.
3
+ * Uses jose (industry-standard, zero-dep, Web Crypto compatible).
4
+ *
5
+ * Two signing modes, selected at construction:
6
+ *
7
+ * - LOCAL single-user (credentialSecret unset): RSA-2048, RS256, kid="key-1",
8
+ * keys generated on first run and persisted to disk so they survive restarts
9
+ * on a real machine. Behavior is unchanged from the pre-stability-fix code.
10
+ *
11
+ * - HTTP multi-user (credentialSecret set): Ed25519, EdDSA, signing key DERIVED
12
+ * deterministically from CREDENTIAL_SECRET via HKDF-SHA256. No disk I/O. Every
13
+ * container replica converges on the same key without a shared volume or
14
+ * external secret store, so OAuth tokens survive container recreation
15
+ * (Watchtower :latest redeploys). kid is the base64url SHA-256 thumbprint of
16
+ * the raw public key.
17
+ *
18
+ * The two modes are different deployments that never exchange tokens
19
+ * (iss/aud are server-scoped); the per-mode algorithm split is permanent and
20
+ * intentional. Each process runs exactly one algorithm; the verify path uses
21
+ * that single alg, never a {RS256, EdDSA} union.
22
+ */
23
+ import * as jose from 'jose';
24
+ export declare class JWTIssuer {
25
+ private serverName;
26
+ private keysDir;
27
+ private privateKeyPath;
28
+ private publicKeyPath;
29
+ private credentialSecret;
30
+ alg: 'RS256' | 'EdDSA';
31
+ private kid;
32
+ private privateKey;
33
+ private publicKey;
34
+ private okpX;
35
+ private _initialized;
36
+ constructor(serverName: string, keysDir?: string, credentialSecret?: string | null);
37
+ /** Must call before using issuer — loads/generates (RSA) or derives (EdDSA) keys. */
38
+ init(): Promise<void>;
39
+ private deriveEddsaKeys;
40
+ private loadOrGenerateRsaKeys;
41
+ /**
42
+ * Return JWKS payload for /.well-known/jwks.json. Always a `keys` array
43
+ * (multi-key-aware for future rotation). RSA mode emits an RSA JWK; EdDSA
44
+ * mode emits an OKP JWK.
45
+ */
46
+ getJwks(): Promise<jose.JSONWebKeySet>;
47
+ /** Issue a JWT access token (typ="access") signed with the active alg. */
48
+ issueAccessToken(sub: string, expiresInSeconds?: number): Promise<string>;
49
+ /**
50
+ * Issue a JWT refresh token (typ="refresh") signed with the active alg.
51
+ *
52
+ * Defaults to a 1-year (31536000s) lifetime so long-running MCP clients can
53
+ * mint fresh access tokens without forcing the user back through the browser
54
+ * PKCE flow. The access token stays short-lived (1h); the refresh token is the
55
+ * renewal credential and is rotated on every use (the /token refresh handler
56
+ * issues a new refresh token each time), so the security control is rotation,
57
+ * not a short TTL. A short refresh TTL was the residual re-auth driver: a
58
+ * self-hosted server a user touches only intermittently (less than once a
59
+ * month) would silently expire its refresh token between sessions, forcing a
60
+ * fresh browser OAuth tab on the next use. With a 1-year floor, only a
61
+ * genuinely long idle gap re-prompts. Same key / iss / aud as access tokens;
62
+ * the typ claim is the only thing distinguishing them, and verifyAccessToken
63
+ * rejects typ="refresh" so a refresh token can never be used as an access
64
+ * token at the /mcp resource.
65
+ */
66
+ issueRefreshToken(sub: string, expiresInSeconds?: number): Promise<string>;
67
+ /**
68
+ * Verify a JWT access token and return its payload. Throws on failure (bad
69
+ * signature, wrong issuer/audience, expired) — the same jose errors existing
70
+ * callers already catch. The verify path uses the single active algorithm,
71
+ * never a union. Additionally rejects tokens whose typ claim is "refresh"
72
+ * (throwing jose.errors.JWTClaimValidationFailed) so a refresh token cannot
73
+ * be replayed as an access token. Tokens with typ="access" OR a missing typ
74
+ * claim are accepted (the latter keeps already-issued pre-refresh-support
75
+ * tokens valid).
76
+ */
77
+ verifyAccessToken(token: string): Promise<jose.JWTPayload>;
78
+ /**
79
+ * Verify a JWT refresh token and return its payload. Same key / audience /
80
+ * issuer checks as verifyAccessToken and throws the same jose errors on
81
+ * failure; uses the single active algorithm. Additionally asserts
82
+ * typ=="refresh" (throwing jose.errors.JWTClaimValidationFailed otherwise) so
83
+ * an access token can never be exchanged at the refresh grant.
84
+ */
85
+ verifyRefreshToken(token: string): Promise<jose.JWTPayload>;
86
+ }
87
+ //# sourceMappingURL=jwt-issuer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-issuer.d.ts","sourceRoot":"","sources":["../../src/oauth/jwt-issuer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAU5B,qBAAa,SAAS;IACpB,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,gBAAgB,CAAe;IACvC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;IACtB,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,YAAY,CAAQ;IAE5B,YAAY,UAAU,EAAE,MAAM,EAAE,OAAO,SAAmB,EAAE,gBAAgB,GAAE,MAAM,GAAG,IAAW,EAOjG;IAED,qFAAqF;IAC/E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1B;YAEa,eAAe;YAYf,qBAAqB;IA6BnC;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAY3C;IAED,0EAA0E;IACpE,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,gBAAgB,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAS5E;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,gBAAgB,SAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CASjF;IAED;;;;;;;;;OASG;IACG,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAW/D;IAED;;;;;;OAMG;IACG,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAWhE;CACF"}