@selvajs/server 1.5.0-beta.1 → 1.5.0-beta.11

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 (132) hide show
  1. package/README.md +17 -17
  2. package/dist/access/guards.d.ts.map +1 -1
  3. package/dist/access/guards.js +2 -6
  4. package/dist/access/guards.js.map +1 -1
  5. package/dist/api/bodies.d.ts +0 -2
  6. package/dist/api/bodies.d.ts.map +1 -1
  7. package/dist/api/deps.d.ts +16 -1
  8. package/dist/api/deps.d.ts.map +1 -1
  9. package/dist/api/deps.js +3 -1
  10. package/dist/api/deps.js.map +1 -1
  11. package/dist/api/errors.d.ts +11 -0
  12. package/dist/api/errors.d.ts.map +1 -1
  13. package/dist/api/errors.js +15 -1
  14. package/dist/api/errors.js.map +1 -1
  15. package/dist/api/idempotency-http.d.ts.map +1 -0
  16. package/dist/api/idempotency-http.js.map +1 -0
  17. package/dist/api/idempotency.d.ts +58 -0
  18. package/dist/api/idempotency.d.ts.map +1 -0
  19. package/dist/api/idempotency.js +130 -0
  20. package/dist/api/idempotency.js.map +1 -0
  21. package/dist/api/index.d.ts +3 -0
  22. package/dist/api/index.d.ts.map +1 -1
  23. package/dist/api/index.js +3 -0
  24. package/dist/api/index.js.map +1 -1
  25. package/dist/api/openapi.d.ts +84 -0
  26. package/dist/api/openapi.d.ts.map +1 -0
  27. package/dist/api/openapi.js +247 -0
  28. package/dist/api/openapi.js.map +1 -0
  29. package/dist/api/rate-limit.d.ts +57 -0
  30. package/dist/api/rate-limit.d.ts.map +1 -0
  31. package/dist/api/rate-limit.js +108 -0
  32. package/dist/api/rate-limit.js.map +1 -0
  33. package/dist/api/respond.d.ts +14 -9
  34. package/dist/api/respond.d.ts.map +1 -1
  35. package/dist/api/respond.js +49 -17
  36. package/dist/api/respond.js.map +1 -1
  37. package/dist/api/scope.d.ts +3 -0
  38. package/dist/api/scope.d.ts.map +1 -1
  39. package/dist/api/scope.js +8 -2
  40. package/dist/api/scope.js.map +1 -1
  41. package/dist/compute/index.d.ts +0 -1
  42. package/dist/compute/index.d.ts.map +1 -1
  43. package/dist/compute/index.js +0 -1
  44. package/dist/compute/index.js.map +1 -1
  45. package/dist/definitions/definition-service.d.ts.map +1 -1
  46. package/dist/definitions/definition-service.js +7 -1
  47. package/dist/definitions/definition-service.js.map +1 -1
  48. package/dist/definitions/index.d.ts +1 -1
  49. package/dist/definitions/index.d.ts.map +1 -1
  50. package/dist/definitions/index.js +1 -1
  51. package/dist/definitions/index.js.map +1 -1
  52. package/dist/definitions/visibility.d.ts +35 -1
  53. package/dist/definitions/visibility.d.ts.map +1 -1
  54. package/dist/definitions/visibility.js +91 -5
  55. package/dist/definitions/visibility.js.map +1 -1
  56. package/dist/handlers/apiTokens.d.ts +46 -5
  57. package/dist/handlers/apiTokens.d.ts.map +1 -1
  58. package/dist/handlers/apiTokens.js +70 -20
  59. package/dist/handlers/apiTokens.js.map +1 -1
  60. package/dist/handlers/definitions.d.ts +7 -1
  61. package/dist/handlers/definitions.d.ts.map +1 -1
  62. package/dist/handlers/definitions.js +28 -9
  63. package/dist/handlers/definitions.js.map +1 -1
  64. package/dist/handlers/index.d.ts +2 -1
  65. package/dist/handlers/index.d.ts.map +1 -1
  66. package/dist/handlers/index.js +2 -1
  67. package/dist/handlers/index.js.map +1 -1
  68. package/dist/handlers/me.d.ts.map +1 -1
  69. package/dist/handlers/me.js +9 -1
  70. package/dist/handlers/me.js.map +1 -1
  71. package/dist/handlers/oauthConsent.d.ts +49 -0
  72. package/dist/handlers/oauthConsent.d.ts.map +1 -0
  73. package/dist/handlers/oauthConsent.js +76 -0
  74. package/dist/handlers/oauthConsent.js.map +1 -0
  75. package/dist/handlers/projects.d.ts +5 -0
  76. package/dist/handlers/projects.d.ts.map +1 -1
  77. package/dist/handlers/projects.js +19 -3
  78. package/dist/handlers/projects.js.map +1 -1
  79. package/dist/handlers/services.d.ts +1 -1
  80. package/dist/handlers/services.d.ts.map +1 -1
  81. package/dist/handlers/services.js.map +1 -1
  82. package/dist/http/api-token.d.ts +27 -3
  83. package/dist/http/api-token.d.ts.map +1 -1
  84. package/dist/http/api-token.js +62 -6
  85. package/dist/http/api-token.js.map +1 -1
  86. package/dist/http/csrf.d.ts +18 -0
  87. package/dist/http/csrf.d.ts.map +1 -0
  88. package/dist/http/csrf.js +37 -0
  89. package/dist/http/csrf.js.map +1 -0
  90. package/dist/http/index.d.ts +2 -1
  91. package/dist/http/index.d.ts.map +1 -1
  92. package/dist/http/index.js +2 -1
  93. package/dist/http/index.js.map +1 -1
  94. package/dist/oauth/index.d.ts +163 -0
  95. package/dist/oauth/index.d.ts.map +1 -0
  96. package/dist/oauth/index.js +466 -0
  97. package/dist/oauth/index.js.map +1 -0
  98. package/dist/organizations/index.d.ts +1 -0
  99. package/dist/organizations/index.d.ts.map +1 -1
  100. package/dist/organizations/index.js +1 -0
  101. package/dist/organizations/index.js.map +1 -1
  102. package/dist/organizations/user-memberships.d.ts +11 -0
  103. package/dist/organizations/user-memberships.d.ts.map +1 -0
  104. package/dist/organizations/user-memberships.js +23 -0
  105. package/dist/organizations/user-memberships.js.map +1 -0
  106. package/dist/testing/harness.d.ts +3 -1
  107. package/dist/testing/harness.d.ts.map +1 -1
  108. package/dist/testing/harness.js +6 -1
  109. package/dist/testing/harness.js.map +1 -1
  110. package/dist/testing/index.d.ts +1 -1
  111. package/dist/testing/index.d.ts.map +1 -1
  112. package/dist/testing/index.js +1 -1
  113. package/dist/testing/index.js.map +1 -1
  114. package/dist/testing/scenarios.d.ts +6 -0
  115. package/dist/testing/scenarios.d.ts.map +1 -1
  116. package/dist/testing/scenarios.js +12 -1
  117. package/dist/testing/scenarios.js.map +1 -1
  118. package/dist/tokens/api-token-codec.d.ts +2 -2
  119. package/dist/tokens/api-token-codec.js +2 -2
  120. package/dist/tokens/api-token-holder.d.ts +30 -0
  121. package/dist/tokens/api-token-holder.d.ts.map +1 -0
  122. package/dist/tokens/api-token-holder.js +27 -0
  123. package/dist/tokens/api-token-holder.js.map +1 -0
  124. package/dist/tokens/index.d.ts +1 -0
  125. package/dist/tokens/index.d.ts.map +1 -1
  126. package/dist/tokens/index.js +1 -0
  127. package/dist/tokens/index.js.map +1 -1
  128. package/package.json +15 -10
  129. package/dist/compute/idempotency-http.d.ts.map +0 -1
  130. package/dist/compute/idempotency-http.js.map +0 -1
  131. /package/dist/{compute → api}/idempotency-http.d.ts +0 -0
  132. /package/dist/{compute → api}/idempotency-http.js +0 -0
@@ -8,13 +8,19 @@
8
8
  */
9
9
  import { randomUUID } from 'node:crypto';
10
10
  import { apiError, ApiErrorCode, collection, created, noContent, parseBody, parseListOptions, requireCaller, requireParams, CreateProjectBodySchema, UpdateProjectBodySchema } from '../api/index.js';
11
- import { canChangeVisibilityToPublic, canEdit, canSolve, canView, hasPermission, slugify, SYSTEM_CONTEXT, outsideTokenOrg, validateProjectFlags, withAdminBypass } from '@selvajs/platform';
11
+ import { canChangeVisibilityToPublic, canCreateDefinition, canEdit, canSolve, canView, hasPermission, slugify, SYSTEM_CONTEXT, outsideTokenOrg, scopeAllows, validateProjectFlags, withAdminBypass } from '@selvajs/platform';
12
12
  import { resolveAccessibleProjects } from '../definitions/index.js';
13
13
  import { projectAccessInputFromRowsWith, requireCanCreateProject, requireCanEditProjectSettings, requireCanManage } from '../access/index.js';
14
14
  import { createProjectWithUniqueSlug } from '../projects/index.js';
15
+ /**
16
+ * Projects the caller can view. `canCreateDefinitions` says whether
17
+ * `POST /definitions` would take this project from this caller: the same rule
18
+ * as the route, and for an API token its `upload` scope there.
19
+ */
15
20
  export const listProjects = async (req) => {
16
21
  const { ctx } = requireCaller(req);
17
- const { projects } = await resolveAccessibleProjects(ctx, req.deps);
22
+ const set = await resolveAccessibleProjects(ctx, req.deps);
23
+ const { projects } = set;
18
24
  const { limit, cursor } = parseListOptions(req.url);
19
25
  // The accessible set is resolved in-process rather than by the store, so the
20
26
  // cursor is an index into it. Opaque to callers either way.
@@ -24,8 +30,18 @@ export const listProjects = async (req) => {
24
30
  }
25
31
  const items = projects.slice(start, start + (limit ?? projects.length));
26
32
  const nextIndex = start + items.length;
33
+ // The create route names its project in the body, so it checks scope org-wide.
34
+ const tokenMayUpload = scopeAllows(ctx, 'upload');
27
35
  return collection({
28
- items,
36
+ items: items.map((project) => ({
37
+ ...project,
38
+ canCreateDefinitions: tokenMayUpload &&
39
+ canCreateDefinition(projectAccessInputFromRowsWith(req, ctx, project, {
40
+ member: set.memberByProjectId.get(project.id) ?? null,
41
+ orgMember: set.orgMemberByOrgId.get(project.orgId) ?? null,
42
+ platformGrants: set.grantsByProjectId.get(project.id) ?? []
43
+ }))
44
+ })),
29
45
  nextCursor: nextIndex < projects.length ? String(nextIndex) : undefined
30
46
  });
31
47
  };
@@ -1 +1 @@
1
- {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"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"}
@@ -18,5 +18,5 @@ export declare function orgAssetService(deps: SelvaDeps): OrgAssetService;
18
18
  * about: a handler that quietly skipped hashing would persist a row whose token
19
19
  * can never be verified, and nothing downstream would report it.
20
20
  */
21
- export declare function tokenCodec(deps: SelvaDeps, family: keyof SelvaDeps['tokens']): TokenCodec;
21
+ export declare function tokenCodec(deps: SelvaDeps, family: Exclude<keyof SelvaDeps['tokens'], 'mayHoldApiTokens'>): TokenCodec;
22
22
  //# sourceMappingURL=services.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/handlers/services.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,oEAMhD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe,CAMhE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC,QAAQ,CAAC,GAAG,UAAU,CAMzF"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/handlers/services.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,oEAMhD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe,CAMhE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC,GAC5D,UAAU,CAMZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/handlers/services.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,UAAU,iBAAiB,CAAC,IAAe;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAe;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,IAAe,EAAE,MAAiC;IAC5E,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,oCAAoC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/handlers/services.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,UAAU,iBAAiB,CAAC,IAAe;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAe;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACzB,IAAe,EACf,MAA8D;IAE9D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,oCAAoC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC"}
@@ -1,6 +1,7 @@
1
- import type { ApiToken, AuthUser, IAuthProvider, IDataProvider, ILogger, RequestContext } from '@selvajs/platform';
1
+ import type { ApiToken, AuthUser, IAuthProvider, IDataProvider, ILogger, RequestContext, SelvaFlags } from '@selvajs/platform';
2
2
  import { ApiErrorCode } from '../api/errors.js';
3
3
  import { type ApiTokenCodec } from '../tokens/api-token-codec.js';
4
+ import { type ApiTokenHolderPolicy } from '../tokens/api-token-holder.js';
4
5
  export type ApiTokenResolution =
5
6
  /** No API token on the request. Carry on with the cookie or proxy path. */
6
7
  {
@@ -22,7 +23,19 @@ export interface ResolveApiTokenDeps {
22
23
  /** Absent when the host hasn't configured API tokens: a sent key gets 503. */
23
24
  codec?: ApiTokenCodec;
24
25
  auth: Pick<IAuthProvider, 'getUser' | 'delegatedSession'>;
25
- data: Pick<IDataProvider, 'apiTokens' | 'orgs'>;
26
+ data: Pick<IDataProvider, 'apiTokens' | 'orgs' | 'permissions' | 'projects' | 'platformProjectGrants' | 'definitions'>;
27
+ /** The same policy passed as `SelvaDeps.tokens.mayHoldApiTokens`. Absent: the default rule in `canHoldApiTokens`. */
28
+ mayHoldApiTokens?: ApiTokenHolderPolicy;
29
+ /**
30
+ * The host's feature flags, which decide project visibility in the holder
31
+ * rule's project scan. Absent: every flag off, which only ever refuses more.
32
+ */
33
+ flag?: (name: keyof SelvaFlags) => boolean;
34
+ /**
35
+ * Skips the holder check for a token that passed it within the cache's TTL.
36
+ * Absent: checked on every request.
37
+ */
38
+ holderVerdicts?: HolderVerdictCache;
26
39
  /** Receives background failures (the `lastUsedAt` write). Logs the token id only. */
27
40
  log?: ILogger;
28
41
  now?: () => number;
@@ -40,7 +53,18 @@ export interface ResolveApiTokenOptions {
40
53
  * broken key and act as someone else.
41
54
  *
42
55
  * The owner is re-checked on every request (disabled, still a member of the
43
- * token's org), then their live context is narrowed to the token's scopes.
56
+ * token's org, still allowed to hold keys), then their live context is
57
+ * narrowed to the token's scopes.
44
58
  */
45
59
  export declare function resolveApiToken(request: Request, deps: ResolveApiTokenDeps, { pathPrefix }?: ResolveApiTokenOptions): Promise<ApiTokenResolution>;
60
+ export interface HolderVerdictCache {
61
+ passed(tokenId: string, now: number): boolean;
62
+ remember(tokenId: string, now: number): void;
63
+ }
64
+ /**
65
+ * Remembers passed holder checks for `ttlMs`, so a busy upload key doesn't
66
+ * re-scan its org's projects on every request. A withdrawn right takes effect
67
+ * within the TTL; a disabled owner or a removed member is still refused at once.
68
+ */
69
+ export declare function createHolderVerdictCache(ttlMs?: number, maxEntries?: number): HolderVerdictCache;
46
70
  //# sourceMappingURL=api-token.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-token.d.ts","sourceRoot":"","sources":["../../src/http/api-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,aAAa,EACb,OAAO,EACP,cAAc,EACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAGN,KAAK,aAAa,EAClB,MAAM,8BAA8B,CAAC;AAGtC,MAAM,MAAM,kBAAkB;AAC7B,2EAA2E;AACzE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE;AACtE,0EAA0E;GACxE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7E,MAAM,WAAW,mBAAmB;IACnC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,kBAAkB,CAAC,CAAC;IAC1D,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,MAAM,CAAC,CAAC;IAChD,qFAAqF;IACrF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAmBD;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,mBAAmB,EACzB,EAAE,UAAuB,EAAE,GAAE,sBAA2B,GACtD,OAAO,CAAC,kBAAkB,CAAC,CAuE7B"}
1
+ {"version":3,"file":"api-token.d.ts","sourceRoot":"","sources":["../../src/http/api-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,aAAa,EACb,OAAO,EACP,cAAc,EACd,UAAU,EACV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAGN,KAAK,aAAa,EAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAoB,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAG5F,MAAM,MAAM,kBAAkB;AAC7B,2EAA2E;AACzE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE;AACtE,0EAA0E;GACxE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7E,MAAM,WAAW,mBAAmB;IACnC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,kBAAkB,CAAC,CAAC;IAC1D,IAAI,EAAE,IAAI,CACT,aAAa,EACb,WAAW,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,uBAAuB,GAAG,aAAa,CAC3F,CAAC;IACF,qHAAqH;IACrH,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,UAAU,KAAK,OAAO,CAAC;IAC3C;;;OAGG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,qFAAqF;IACrF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,mBAAmB,EACzB,EAAE,UAAuB,EAAE,GAAE,sBAA2B,GACtD,OAAO,CAAC,kBAAkB,CAAC,CAoF7B;AAED,MAAM,WAAW,kBAAkB;IAClC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,EAAE,UAAU,SAAS,GAAG,kBAAkB,CAoBhG"}
@@ -1,6 +1,7 @@
1
1
  import { SYSTEM_CONTEXT, narrowApiTokenContext } from '@selvajs/platform';
2
2
  import { ApiErrorCode } from '../api/errors.js';
3
3
  import { API_TOKEN_PREFIX, looksLikeApiToken } from '../tokens/api-token-codec.js';
4
+ import { canHoldApiTokens } from '../tokens/api-token-holder.js';
4
5
  import { buildRequestContext } from './request-context.js';
5
6
  /** `lastUsedAt` is written at most this often per token, so a busy key isn't a write per request. */
6
7
  const LAST_USED_WRITE_INTERVAL_MS = 5 * 60 * 1000;
@@ -16,6 +17,12 @@ const UNAVAILABLE = {
16
17
  code: ApiErrorCode.API_TOKENS_UNAVAILABLE,
17
18
  message: 'API tokens are not available on this server.'
18
19
  };
20
+ const HOLDER_REFUSED = {
21
+ kind: 'rejected',
22
+ status: 403,
23
+ code: ApiErrorCode.API_TOKEN_HOLDER_REFUSED,
24
+ message: 'This API token’s owner may no longer use API tokens in this org.'
25
+ };
19
26
  /**
20
27
  * Authenticate a request by its `Authorization: Bearer selva_…` header.
21
28
  *
@@ -25,7 +32,8 @@ const UNAVAILABLE = {
25
32
  * broken key and act as someone else.
26
33
  *
27
34
  * The owner is re-checked on every request (disabled, still a member of the
28
- * token's org), then their live context is narrowed to the token's scopes.
35
+ * token's org, still allowed to hold keys), then their live context is
36
+ * narrowed to the token's scopes.
29
37
  */
30
38
  export async function resolveApiToken(request, deps, { pathPrefix = '/api/v1/' } = {}) {
31
39
  const url = new URL(request.url);
@@ -62,21 +70,38 @@ export async function resolveApiToken(request, deps, { pathPrefix = '/api/v1/' }
62
70
  const token = await store.getByTokenHash(SYSTEM_CONTEXT, deps.codec.hashToken(raw));
63
71
  if (!token)
64
72
  return UNAUTHORIZED;
65
- const [user, member] = await Promise.all([
73
+ const [user, member, platformPermissions] = await Promise.all([
66
74
  deps.auth.getUser(token.userId),
67
- deps.data.orgs.getOrgMember(SYSTEM_CONTEXT, token.orgId, token.userId)
75
+ deps.data.orgs.getOrgMember(SYSTEM_CONTEXT, token.orgId, token.userId),
76
+ // Read only for the holder check: narrowing drops platform permissions anyway.
77
+ deps.data.permissions.getFor(SYSTEM_CONTEXT, token.userId)
68
78
  ]);
69
79
  if (!user || user.disabled || !member)
70
80
  return UNAUTHORIZED;
71
- // Platform permissions aren't read: narrowing drops them anyway.
72
- let ctx = narrowApiTokenContext(await buildRequestContext({ user, platformPermissions: [], membership: member, pinOrg: true }, { orgs: deps.data.orgs }), token);
81
+ const live = await buildRequestContext({ user, platformPermissions, membership: member, pinOrg: true }, { orgs: deps.data.orgs });
82
+ const now = deps.now?.() ?? Date.now();
83
+ if (!deps.holderVerdicts?.passed(token.id, now)) {
84
+ const holds = await canHoldApiTokens(live, token.scopes, {
85
+ policy: deps.mayHoldApiTokens,
86
+ deps: {
87
+ orgs: deps.data.orgs,
88
+ projects: deps.data.projects,
89
+ platformProjectGrants: deps.data.platformProjectGrants,
90
+ definitionMeta: deps.data.definitions,
91
+ flag: deps.flag ?? (() => false)
92
+ }
93
+ });
94
+ if (!holds)
95
+ return HOLDER_REFUSED;
96
+ deps.holderVerdicts?.remember(token.id, now);
97
+ }
98
+ let ctx = narrowApiTokenContext(live, token);
73
99
  // Signed only after the user check above: a minted session can't be
74
100
  // revoked, and row security doesn't look at bans.
75
101
  if (delegated) {
76
102
  const sessionToken = await delegated.mint(user.id, { orgId: token.orgId });
77
103
  ctx = { ...ctx, adapterContext: { sessionToken } };
78
104
  }
79
- const now = deps.now?.() ?? Date.now();
80
105
  if (!token.lastUsedAt || now - Date.parse(token.lastUsedAt) >= LAST_USED_WRITE_INTERVAL_MS) {
81
106
  store.touchLastUsed(SYSTEM_CONTEXT, token.id, new Date(now).toISOString()).catch((err) => {
82
107
  deps.log?.warn('Failed to record API token use', {
@@ -88,6 +113,37 @@ export async function resolveApiToken(request, deps, { pathPrefix = '/api/v1/' }
88
113
  }
89
114
  return { kind: 'ok', user, ctx, token };
90
115
  }
116
+ /**
117
+ * Remembers passed holder checks for `ttlMs`, so a busy upload key doesn't
118
+ * re-scan its org's projects on every request. A withdrawn right takes effect
119
+ * within the TTL; a disabled owner or a removed member is still refused at once.
120
+ */
121
+ export function createHolderVerdictCache(ttlMs = 30_000, maxEntries = 10_000) {
122
+ const until = new Map();
123
+ return {
124
+ passed(tokenId, now) {
125
+ const expiry = until.get(tokenId);
126
+ if (expiry === undefined)
127
+ return false;
128
+ if (expiry > now)
129
+ return true;
130
+ until.delete(tokenId);
131
+ return false;
132
+ },
133
+ remember(tokenId, now) {
134
+ if (until.size >= maxEntries) {
135
+ for (const [id, expiry] of until)
136
+ if (expiry <= now)
137
+ until.delete(id);
138
+ // Still full of live entries: drop the oldest insert.
139
+ if (until.size >= maxEntries)
140
+ until.delete(until.keys().next().value);
141
+ }
142
+ until.delete(tokenId);
143
+ until.set(tokenId, now + ttlMs);
144
+ }
145
+ };
146
+ }
91
147
  function bearerOf(request) {
92
148
  const header = request.headers.get('authorization');
93
149
  if (!header)
@@ -1 +1 @@
1
- {"version":3,"file":"api-token.js","sourceRoot":"","sources":["../../src/http/api-token.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api-token.js","sourceRoot":"","sources":["../../src/http/api-token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * SvelteKit's form-submission CSRF check, with the two exemptions it can't
3
+ * express. A host turns the framework's own check off and calls this first.
4
+ *
5
+ * - A Selva API key in `Authorization`: a cross-site form can't set the header,
6
+ * and a `selva_` bearer never falls back to the cookie. API-token uploads are
7
+ * multipart with no `Origin`, which the framework check refuses. Any other
8
+ * `Authorization` (a proxy's id token) still gets checked: the request may run
9
+ * as the cookie session.
10
+ * - `exemptPaths`: endpoints that take a form body from servers, which send no
11
+ * `Origin` (the OAuth token endpoint, per RFC 6749).
12
+ */
13
+ export interface CsrfOptions {
14
+ /** Exact paths that accept cross-site form bodies. */
15
+ exemptPaths?: readonly string[];
16
+ }
17
+ export declare function isCrossSiteFormSubmission(request: Request, options?: CsrfOptions): boolean;
18
+ //# sourceMappingURL=csrf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/http/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAcH,MAAM,WAAW,WAAW;IAC3B,sDAAsD;IACtD,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAS9F"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * SvelteKit's form-submission CSRF check, with the two exemptions it can't
3
+ * express. A host turns the framework's own check off and calls this first.
4
+ *
5
+ * - A Selva API key in `Authorization`: a cross-site form can't set the header,
6
+ * and a `selva_` bearer never falls back to the cookie. API-token uploads are
7
+ * multipart with no `Origin`, which the framework check refuses. Any other
8
+ * `Authorization` (a proxy's id token) still gets checked: the request may run
9
+ * as the cookie session.
10
+ * - `exemptPaths`: endpoints that take a form body from servers, which send no
11
+ * `Origin` (the OAuth token endpoint, per RFC 6749).
12
+ */
13
+ import { API_TOKEN_PREFIX } from '../tokens/index.js';
14
+ const UNSAFE_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
15
+ // The content types a browser form can send without a CORS preflight, plus
16
+ // SvelteKit's own binary form encoding.
17
+ const FORM_TYPES = [
18
+ 'application/x-www-form-urlencoded',
19
+ 'multipart/form-data',
20
+ 'text/plain',
21
+ 'application/x-sveltekit-formdata'
22
+ ];
23
+ export function isCrossSiteFormSubmission(request, options = {}) {
24
+ if (!UNSAFE_METHODS.has(request.method))
25
+ return false;
26
+ const type = (request.headers.get('content-type') ?? '').split(';')[0].trim().toLowerCase();
27
+ if (!FORM_TYPES.includes(type))
28
+ return false;
29
+ const bearer = /^Bearer\s+(\S+)/i.exec(request.headers.get('authorization') ?? '')?.[1];
30
+ if (bearer?.startsWith(API_TOKEN_PREFIX))
31
+ return false;
32
+ const url = new URL(request.url);
33
+ if (options.exemptPaths?.includes(url.pathname))
34
+ return false;
35
+ return request.headers.get('origin') !== url.origin;
36
+ }
37
+ //# sourceMappingURL=csrf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/http/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACnE,2EAA2E;AAC3E,wCAAwC;AACxC,MAAM,UAAU,GAAG;IAClB,mCAAmC;IACnC,qBAAqB;IACrB,YAAY;IACZ,kCAAkC;CAClC,CAAC;AAOF,MAAM,UAAU,yBAAyB,CAAC,OAAgB,EAAE,UAAuB,EAAE;IACpF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5F,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxF,IAAI,MAAM,EAAE,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,KAAK,CAAC;IACvD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9D,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC;AACrD,CAAC"}
@@ -1,8 +1,9 @@
1
1
  export { safeRedirectTarget } from './redirect.js';
2
+ export { isCrossSiteFormSubmission, type CsrfOptions } from './csrf.js';
2
3
  export { declaredBodySizeExceeds, type HeadersLike } from './body-size.js';
3
4
  export { applySecurityHeaders, type SecurityHeaderOptions } from './security-headers.js';
4
5
  export { createRouteClassifier, type RouteClassifier, type RouteClassifierConfig } from './route-classifier.js';
5
6
  export { createLoginRateLimiter, addressKeysCollapsed, type LoginRateLimiter, type LoginRateLimiterConfig } from './login-rate-limit.js';
6
7
  export { buildRequestContext, type BuildRequestContextInput } from './request-context.js';
7
- export { resolveApiToken, type ApiTokenResolution, type ResolveApiTokenDeps, type ResolveApiTokenOptions } from './api-token.js';
8
+ export { createHolderVerdictCache, resolveApiToken, type ApiTokenResolution, type HolderVerdictCache, type ResolveApiTokenDeps, type ResolveApiTokenOptions } from './api-token.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,EACN,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,sBAAsB,EACtB,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EACN,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,yBAAyB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,EACN,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,sBAAsB,EACtB,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EACN,wBAAwB,EACxB,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,MAAM,gBAAgB,CAAC"}
@@ -1,9 +1,10 @@
1
1
  // HTTP hardening helpers — transport-agnostic request/response guards.
2
2
  export { safeRedirectTarget } from './redirect.js';
3
+ export { isCrossSiteFormSubmission } from './csrf.js';
3
4
  export { declaredBodySizeExceeds } from './body-size.js';
4
5
  export { applySecurityHeaders } from './security-headers.js';
5
6
  export { createRouteClassifier } from './route-classifier.js';
6
7
  export { createLoginRateLimiter, addressKeysCollapsed } from './login-rate-limit.js';
7
8
  export { buildRequestContext } from './request-context.js';
8
- export { resolveApiToken } from './api-token.js';
9
+ export { createHolderVerdictCache, resolveApiToken } from './api-token.js';
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAoB,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAA8B,MAAM,uBAAuB,CAAC;AACzF,OAAO,EACN,qBAAqB,EAGrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,sBAAsB,EACtB,oBAAoB,EAGpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAiC,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EACN,eAAe,EAIf,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,yBAAyB,EAAoB,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAoB,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAA8B,MAAM,uBAAuB,CAAC;AACzF,OAAO,EACN,qBAAqB,EAGrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,sBAAsB,EACtB,oBAAoB,EAGpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAiC,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EACN,wBAAwB,EACxB,eAAe,EAKf,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * OAuth 2.1 for MCP clients and the Grasshopper plugin, with this instance as
3
+ * its own authorization server.
4
+ *
5
+ * The access token is an ordinary API token. The host mints it while the user is
6
+ * signed in, at consent, through the same path as Team → API tokens; this
7
+ * module seals the raw key into the authorization code and hands it over at the
8
+ * token endpoint. So `/mcp` and `/api/v1` keep one credential type.
9
+ *
10
+ * Nothing here is stored. A registered client's id is its own signed metadata,
11
+ * and a code is its own encrypted grant, bound to the issuing origin. The only
12
+ * state is the set of redeemed codes, in the host's memory, so on several
13
+ * replicas a code could be redeemed once per replica within its minute, and only
14
+ * by whoever holds the PKCE verifier.
15
+ */
16
+ /** The scopes a grant can carry. Each maps to one org-wide API scope. */
17
+ export declare const OAUTH_SCOPES: readonly ["read", "solve", "upload"];
18
+ export type OAuthScope = (typeof OAUTH_SCOPES)[number];
19
+ /**
20
+ * All a registered (DCR or CIMD) client can be granted. Its name and redirects
21
+ * are whatever the registrant chose, so `upload`, which puts code on the org's
22
+ * Compute server, stays with the built-in client and a look-alike can't phish for it.
23
+ */
24
+ export declare const REGISTERED_CLIENT_SCOPES: readonly ["read", "solve"];
25
+ /** The Grasshopper plugin's client id. Built in, so it needs no registration and works air-gapped. */
26
+ export declare const GRASSHOPPER_CLIENT_ID = "selva-grasshopper";
27
+ export declare const MCP_PATH = "/mcp";
28
+ export declare const CODE_TTL_MS = 60000;
29
+ export declare class OAuthError extends Error {
30
+ /** RFC 6749 / 7591 error code. */
31
+ readonly error: string;
32
+ readonly status: number;
33
+ constructor(
34
+ /** RFC 6749 / 7591 error code. */
35
+ error: string, description: string, status?: number);
36
+ toBody(): {
37
+ error: string;
38
+ error_description: string;
39
+ };
40
+ }
41
+ export interface OAuthClient {
42
+ clientId: string;
43
+ /** Shown on the consent page. Unverified for a registered client: whatever it claimed. */
44
+ name: string;
45
+ redirectUris: string[];
46
+ /** Shipped with this server, so its name can be trusted. */
47
+ builtIn: boolean;
48
+ /** All this client can be granted, whatever it asks for. */
49
+ scopes: readonly OAuthScope[];
50
+ }
51
+ /** A validated `/oauth/authorize` request, ready for the consent page. */
52
+ export interface AuthorizeRequest {
53
+ client: OAuthClient;
54
+ redirectUri: string;
55
+ state?: string;
56
+ codeChallenge: string;
57
+ scopes: OAuthScope[];
58
+ resource: string;
59
+ }
60
+ /** What the host minted at consent. `secret` is the raw API key. */
61
+ export interface Grant {
62
+ tokenId: string;
63
+ secret: string;
64
+ scopes: OAuthScope[];
65
+ expiresAt: string;
66
+ }
67
+ export interface OAuthServerOptions {
68
+ /** This instance's origin, e.g. `https://selva.example.com`. */
69
+ origin: string;
70
+ /** `SELVA_HMAC_KEY`. Rotating it invalidates registered clients and live codes. */
71
+ secret: string;
72
+ /**
73
+ * Fetches a Client ID Metadata Document. The URL comes from an unknown client,
74
+ * so the host must guard it against SSRF. Without it, URL client ids are refused.
75
+ */
76
+ fetchClientMetadata?: (url: string) => Promise<unknown>;
77
+ /**
78
+ * Redeemed code hashes and their expiry. Pass one map for the process so a
79
+ * rebuilt server (a new origin, a rotated secret) still refuses a replay.
80
+ */
81
+ redeemedCodes?: Map<string, number>;
82
+ /** Called once a code is exchanged, with the token its grant carries. */
83
+ onRedeemed?: (tokenId: string) => void;
84
+ now?: () => number;
85
+ }
86
+ interface HttpResult {
87
+ status: number;
88
+ body: Record<string, unknown>;
89
+ }
90
+ export declare function mcpResourceUrl(origin: string): string;
91
+ export declare function resourceMetadataUrl(origin: string): string;
92
+ /** RFC 9728. Claude uses only the first authorization server. */
93
+ export declare function protectedResourceMetadata(origin: string): {
94
+ resource: string;
95
+ authorization_servers: string[];
96
+ scopes_supported: ("read" | "solve")[];
97
+ bearer_methods_supported: string[];
98
+ };
99
+ /**
100
+ * RFC 8414. Claude picks Client ID Metadata Documents only when both
101
+ * `client_id_metadata_document_supported` and the `none` auth method appear.
102
+ */
103
+ export declare function authorizationServerMetadata(origin: string): {
104
+ issuer: string;
105
+ authorization_endpoint: string;
106
+ token_endpoint: string;
107
+ registration_endpoint: string;
108
+ response_types_supported: string[];
109
+ grant_types_supported: string[];
110
+ code_challenge_methods_supported: string[];
111
+ token_endpoint_auth_methods_supported: string[];
112
+ scopes_supported: ("read" | "solve" | "upload")[];
113
+ client_id_metadata_document_supported: boolean;
114
+ authorization_response_iss_parameter_supported: boolean;
115
+ };
116
+ export declare function createOAuthServer(options: OAuthServerOptions): {
117
+ register: (input: unknown) => HttpResult;
118
+ resolveClient: (clientId: string) => Promise<OAuthClient>;
119
+ parseAuthorizeRequest: (query: URLSearchParams) => Promise<AuthorizeRequest>;
120
+ approve: (request: AuthorizeRequest, grant: Grant) => string;
121
+ deny: (request: AuthorizeRequest) => string;
122
+ exchange: (form: URLSearchParams) => HttpResult;
123
+ protectedResourceMetadata: () => {
124
+ resource: string;
125
+ authorization_servers: string[];
126
+ scopes_supported: ("read" | "solve")[];
127
+ bearer_methods_supported: string[];
128
+ };
129
+ authorizationServerMetadata: () => {
130
+ issuer: string;
131
+ authorization_endpoint: string;
132
+ token_endpoint: string;
133
+ registration_endpoint: string;
134
+ response_types_supported: string[];
135
+ grant_types_supported: string[];
136
+ code_challenge_methods_supported: string[];
137
+ token_endpoint_auth_methods_supported: string[];
138
+ scopes_supported: ("read" | "solve" | "upload")[];
139
+ client_id_metadata_document_supported: boolean;
140
+ authorization_response_iss_parameter_supported: boolean;
141
+ };
142
+ };
143
+ export type OAuthServer = ReturnType<typeof createOAuthServer>;
144
+ /** OAuth scopes to the API scopes a minted token gets. */
145
+ export declare function apiScopesFor(scopes: readonly OAuthScope[]): string[];
146
+ /** One access level a consent page offers, and the scopes approving it grants. */
147
+ export interface ConsentChoice {
148
+ access: 'read' | 'solve' | 'upload';
149
+ scopes: OAuthScope[];
150
+ }
151
+ /**
152
+ * The access levels a consent page offers for a request, narrowest first. The
153
+ * user may narrow what the client asked for, never widen it. An upload request
154
+ * is offered as asked: narrowing it to read would leave the client unable to
155
+ * do the one thing it signed in for.
156
+ */
157
+ export declare function consentChoices(scopes: readonly OAuthScope[]): ConsentChoice[];
158
+ /** A redirect to a program on the user's own machine, which any local process can claim. */
159
+ export declare function isLoopbackRedirect(uri: string): boolean;
160
+ /** Exact, except a loopback redirect matches on any port (RFC 8252 §7.3). */
161
+ export declare function redirectMatches(registered: string, requested: string): boolean;
162
+ export {};
163
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"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"}