@selvajs/server 1.1.0 → 1.3.0

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 (233) hide show
  1. package/dist/access/guards.d.ts +213 -0
  2. package/dist/access/guards.d.ts.map +1 -0
  3. package/dist/access/guards.js +417 -0
  4. package/dist/access/guards.js.map +1 -0
  5. package/dist/access/index.d.ts +2 -0
  6. package/dist/access/index.d.ts.map +1 -1
  7. package/dist/access/index.js +6 -0
  8. package/dist/access/index.js.map +1 -1
  9. package/dist/access/permissions-scope.d.ts +15 -0
  10. package/dist/access/permissions-scope.d.ts.map +1 -0
  11. package/dist/access/permissions-scope.js +23 -0
  12. package/dist/access/permissions-scope.js.map +1 -0
  13. package/dist/api/bodies.d.ts +104 -0
  14. package/dist/api/bodies.d.ts.map +1 -0
  15. package/dist/api/bodies.js +87 -0
  16. package/dist/api/bodies.js.map +1 -0
  17. package/dist/api/deps.d.ts +135 -0
  18. package/dist/api/deps.d.ts.map +1 -0
  19. package/dist/api/deps.js +55 -0
  20. package/dist/api/deps.js.map +1 -0
  21. package/dist/api/errors.d.ts +35 -0
  22. package/dist/api/errors.d.ts.map +1 -0
  23. package/dist/api/errors.js +63 -0
  24. package/dist/api/errors.js.map +1 -0
  25. package/dist/api/index.d.ts +12 -0
  26. package/dist/api/index.d.ts.map +1 -0
  27. package/dist/api/index.js +15 -0
  28. package/dist/api/index.js.map +1 -0
  29. package/dist/api/map-core-error.d.ts +19 -0
  30. package/dist/api/map-core-error.d.ts.map +1 -0
  31. package/dist/api/map-core-error.js +49 -0
  32. package/dist/api/map-core-error.js.map +1 -0
  33. package/dist/api/pagination.d.ts +19 -0
  34. package/dist/api/pagination.d.ts.map +1 -0
  35. package/dist/api/pagination.js +40 -0
  36. package/dist/api/pagination.js.map +1 -0
  37. package/dist/api/request.d.ts +93 -0
  38. package/dist/api/request.d.ts.map +1 -0
  39. package/dist/api/request.js +150 -0
  40. package/dist/api/request.js.map +1 -0
  41. package/dist/api/respond.d.ts +29 -0
  42. package/dist/api/respond.d.ts.map +1 -0
  43. package/dist/api/respond.js +59 -0
  44. package/dist/api/respond.js.map +1 -0
  45. package/dist/api/responses-schema.d.ts +158 -0
  46. package/dist/api/responses-schema.d.ts.map +1 -0
  47. package/dist/api/responses-schema.js +104 -0
  48. package/dist/api/responses-schema.js.map +1 -0
  49. package/dist/api/responses.d.ts +19 -0
  50. package/dist/api/responses.d.ts.map +1 -0
  51. package/dist/api/responses.js +21 -0
  52. package/dist/api/responses.js.map +1 -0
  53. package/dist/api/shaped.d.ts +23 -0
  54. package/dist/api/shaped.d.ts.map +1 -0
  55. package/dist/api/shaped.js +29 -0
  56. package/dist/api/shaped.js.map +1 -0
  57. package/dist/api/types.d.ts +41 -0
  58. package/dist/api/types.d.ts.map +1 -0
  59. package/dist/api/types.js +12 -0
  60. package/dist/api/types.js.map +1 -0
  61. package/dist/compute/errors.d.ts +18 -0
  62. package/dist/compute/errors.d.ts.map +1 -0
  63. package/dist/compute/errors.js +21 -0
  64. package/dist/compute/errors.js.map +1 -0
  65. package/dist/compute/evict-changed-servers.d.ts +22 -0
  66. package/dist/compute/evict-changed-servers.d.ts.map +1 -0
  67. package/dist/compute/evict-changed-servers.js +31 -0
  68. package/dist/compute/evict-changed-servers.js.map +1 -0
  69. package/dist/compute/idempotency-http.d.ts +47 -0
  70. package/dist/compute/idempotency-http.d.ts.map +1 -0
  71. package/dist/compute/idempotency-http.js +51 -0
  72. package/dist/compute/idempotency-http.js.map +1 -0
  73. package/dist/compute/index.d.ts +5 -0
  74. package/dist/compute/index.d.ts.map +1 -1
  75. package/dist/compute/index.js +5 -0
  76. package/dist/compute/index.js.map +1 -1
  77. package/dist/compute/resolve-server.d.ts +25 -0
  78. package/dist/compute/resolve-server.d.ts.map +1 -0
  79. package/dist/compute/resolve-server.js +35 -0
  80. package/dist/compute/resolve-server.js.map +1 -0
  81. package/dist/compute/server-config-write.d.ts +52 -0
  82. package/dist/compute/server-config-write.d.ts.map +1 -0
  83. package/dist/compute/server-config-write.js +100 -0
  84. package/dist/compute/server-config-write.js.map +1 -0
  85. package/dist/definitions/index.d.ts +1 -0
  86. package/dist/definitions/index.d.ts.map +1 -1
  87. package/dist/definitions/index.js +1 -0
  88. package/dist/definitions/index.js.map +1 -1
  89. package/dist/definitions/visibility.d.ts +74 -0
  90. package/dist/definitions/visibility.d.ts.map +1 -0
  91. package/dist/definitions/visibility.js +117 -0
  92. package/dist/definitions/visibility.js.map +1 -0
  93. package/dist/handlers/definitionVersions.d.ts +30 -0
  94. package/dist/handlers/definitionVersions.d.ts.map +1 -0
  95. package/dist/handlers/definitionVersions.js +93 -0
  96. package/dist/handlers/definitionVersions.js.map +1 -0
  97. package/dist/handlers/definitions.d.ts +35 -0
  98. package/dist/handlers/definitions.d.ts.map +1 -0
  99. package/dist/handlers/definitions.js +207 -0
  100. package/dist/handlers/definitions.js.map +1 -0
  101. package/dist/handlers/index.d.ts +27 -0
  102. package/dist/handlers/index.d.ts.map +1 -0
  103. package/dist/handlers/index.js +29 -0
  104. package/dist/handlers/index.js.map +1 -0
  105. package/dist/handlers/invite-lookup.d.ts +11 -0
  106. package/dist/handlers/invite-lookup.d.ts.map +1 -0
  107. package/dist/handlers/invite-lookup.js +20 -0
  108. package/dist/handlers/invite-lookup.js.map +1 -0
  109. package/dist/handlers/invites.d.ts +31 -0
  110. package/dist/handlers/invites.d.ts.map +1 -0
  111. package/dist/handlers/invites.js +148 -0
  112. package/dist/handlers/invites.js.map +1 -0
  113. package/dist/handlers/me.d.ts +8 -0
  114. package/dist/handlers/me.d.ts.map +1 -0
  115. package/dist/handlers/me.js +21 -0
  116. package/dist/handlers/me.js.map +1 -0
  117. package/dist/handlers/me.starred.d.ts +11 -0
  118. package/dist/handlers/me.starred.d.ts.map +1 -0
  119. package/dist/handlers/me.starred.js +21 -0
  120. package/dist/handlers/me.starred.js.map +1 -0
  121. package/dist/handlers/orgAssets.d.ts +13 -0
  122. package/dist/handlers/orgAssets.d.ts.map +1 -0
  123. package/dist/handlers/orgAssets.js +54 -0
  124. package/dist/handlers/orgAssets.js.map +1 -0
  125. package/dist/handlers/orgCompute.d.ts +16 -0
  126. package/dist/handlers/orgCompute.d.ts.map +1 -0
  127. package/dist/handlers/orgCompute.js +96 -0
  128. package/dist/handlers/orgCompute.js.map +1 -0
  129. package/dist/handlers/orgMembers.d.ts +29 -0
  130. package/dist/handlers/orgMembers.d.ts.map +1 -0
  131. package/dist/handlers/orgMembers.js +200 -0
  132. package/dist/handlers/orgMembers.js.map +1 -0
  133. package/dist/handlers/orgs.d.ts +16 -0
  134. package/dist/handlers/orgs.d.ts.map +1 -0
  135. package/dist/handlers/orgs.js +26 -0
  136. package/dist/handlers/orgs.js.map +1 -0
  137. package/dist/handlers/projectMembers.d.ts +15 -0
  138. package/dist/handlers/projectMembers.d.ts.map +1 -0
  139. package/dist/handlers/projectMembers.js +95 -0
  140. package/dist/handlers/projectMembers.js.map +1 -0
  141. package/dist/handlers/projects.d.ts +21 -0
  142. package/dist/handlers/projects.d.ts.map +1 -0
  143. package/dist/handlers/projects.js +164 -0
  144. package/dist/handlers/projects.js.map +1 -0
  145. package/dist/handlers/reclaim.d.ts +10 -0
  146. package/dist/handlers/reclaim.d.ts.map +1 -0
  147. package/dist/handlers/reclaim.js +38 -0
  148. package/dist/handlers/reclaim.js.map +1 -0
  149. package/dist/handlers/services.d.ts +22 -0
  150. package/dist/handlers/services.d.ts.map +1 -0
  151. package/dist/handlers/services.js +37 -0
  152. package/dist/handlers/services.js.map +1 -0
  153. package/dist/handlers/shareLinks.d.ts +23 -0
  154. package/dist/handlers/shareLinks.d.ts.map +1 -0
  155. package/dist/handlers/shareLinks.js +85 -0
  156. package/dist/handlers/shareLinks.js.map +1 -0
  157. package/dist/http/index.d.ts +1 -0
  158. package/dist/http/index.d.ts.map +1 -1
  159. package/dist/http/index.js +1 -0
  160. package/dist/http/index.js.map +1 -1
  161. package/dist/http/login-rate-limit.d.ts +72 -0
  162. package/dist/http/login-rate-limit.d.ts.map +1 -0
  163. package/dist/http/login-rate-limit.js +84 -0
  164. package/dist/http/login-rate-limit.js.map +1 -0
  165. package/dist/notifications/deliver-invite.d.ts +27 -0
  166. package/dist/notifications/deliver-invite.d.ts.map +1 -0
  167. package/dist/notifications/deliver-invite.js +32 -0
  168. package/dist/notifications/deliver-invite.js.map +1 -0
  169. package/dist/notifications/index.d.ts +4 -0
  170. package/dist/notifications/index.d.ts.map +1 -0
  171. package/dist/notifications/index.js +4 -0
  172. package/dist/notifications/index.js.map +1 -0
  173. package/dist/notifications/smtp-config.d.ts +37 -0
  174. package/dist/notifications/smtp-config.d.ts.map +1 -0
  175. package/dist/notifications/smtp-config.js +41 -0
  176. package/dist/notifications/smtp-config.js.map +1 -0
  177. package/dist/notifications/smtp-provider.d.ts +18 -0
  178. package/dist/notifications/smtp-provider.d.ts.map +1 -0
  179. package/dist/notifications/smtp-provider.js +71 -0
  180. package/dist/notifications/smtp-provider.js.map +1 -0
  181. package/dist/ops/deploymentConfig.d.ts +73 -0
  182. package/dist/ops/deploymentConfig.d.ts.map +1 -0
  183. package/dist/ops/deploymentConfig.js +154 -0
  184. package/dist/ops/deploymentConfig.js.map +1 -0
  185. package/dist/ops/index.d.ts +1 -0
  186. package/dist/ops/index.d.ts.map +1 -1
  187. package/dist/ops/index.js +3 -2
  188. package/dist/ops/index.js.map +1 -1
  189. package/dist/organizations/index.d.ts +3 -0
  190. package/dist/organizations/index.d.ts.map +1 -0
  191. package/dist/organizations/index.js +5 -0
  192. package/dist/organizations/index.js.map +1 -0
  193. package/dist/organizations/list-all-members.d.ts +10 -0
  194. package/dist/organizations/list-all-members.d.ts.map +1 -0
  195. package/dist/organizations/list-all-members.js +36 -0
  196. package/dist/organizations/list-all-members.js.map +1 -0
  197. package/dist/organizations/org-asset-service.d.ts +39 -0
  198. package/dist/organizations/org-asset-service.d.ts.map +1 -0
  199. package/dist/organizations/org-asset-service.js +71 -0
  200. package/dist/organizations/org-asset-service.js.map +1 -0
  201. package/dist/projects/create-project.d.ts +30 -0
  202. package/dist/projects/create-project.d.ts.map +1 -0
  203. package/dist/projects/create-project.js +56 -0
  204. package/dist/projects/create-project.js.map +1 -0
  205. package/dist/projects/index.d.ts +2 -0
  206. package/dist/projects/index.d.ts.map +1 -0
  207. package/dist/projects/index.js +3 -0
  208. package/dist/projects/index.js.map +1 -0
  209. package/dist/providers/auth-lookup.d.ts +14 -0
  210. package/dist/providers/auth-lookup.d.ts.map +1 -0
  211. package/dist/providers/auth-lookup.js +34 -0
  212. package/dist/providers/auth-lookup.js.map +1 -0
  213. package/dist/providers/index.d.ts +1 -0
  214. package/dist/providers/index.d.ts.map +1 -1
  215. package/dist/providers/index.js +1 -0
  216. package/dist/providers/index.js.map +1 -1
  217. package/dist/testing/harness.d.ts +168 -0
  218. package/dist/testing/harness.d.ts.map +1 -0
  219. package/dist/testing/harness.js +314 -0
  220. package/dist/testing/harness.js.map +1 -0
  221. package/dist/testing/index.d.ts +18 -0
  222. package/dist/testing/index.d.ts.map +1 -0
  223. package/dist/testing/index.js +15 -0
  224. package/dist/testing/index.js.map +1 -0
  225. package/dist/testing/scenarios.d.ts +67 -0
  226. package/dist/testing/scenarios.d.ts.map +1 -0
  227. package/dist/testing/scenarios.js +104 -0
  228. package/dist/testing/scenarios.js.map +1 -0
  229. package/dist/testing/seed-adapter.d.ts +31 -0
  230. package/dist/testing/seed-adapter.d.ts.map +1 -0
  231. package/dist/testing/seed-adapter.js +19 -0
  232. package/dist/testing/seed-adapter.js.map +1 -0
  233. package/package.json +42 -3
@@ -0,0 +1,213 @@
1
+ /**
2
+ * The permission guards every API handler runs before touching a store.
3
+ *
4
+ * These name no framework. A guard raises `ApiError`, which `runHandler` folds
5
+ * into the response envelope — so the same guard protects a SvelteKit route, a
6
+ * Next route handler, or a Hono route behind that host's own adapter.
7
+ *
8
+ * **Guards that redirect stay with the host.** A redirect is a browser-page
9
+ * concept, not an API one, and a framework implements it by throwing a value
10
+ * only that framework understands.
11
+ *
12
+ * A caller outside an API route — a page load, or a route that builds its own
13
+ * `Response` — has to convert the `ApiError` at its boundary, since a framework
14
+ * will not recognize it. Selva does that with `asHttpError` in
15
+ * `access.server.ts`; SvelteKit gives anything that is not its own `HttpError` a
16
+ * 500, so an unconverted guard denial reads as a crash.
17
+ *
18
+ * Providers arrive through {@link AccessDeps} rather than being resolved here.
19
+ * That is what keeps this module importable without booting an app: a guard
20
+ * that reached for a module global would drag the whole composition root — and
21
+ * its top-level `await createSelvaProviders()` — into every consumer.
22
+ */
23
+ import type { AuthUser, DefinitionRecord, OrgPermission, OrgRole, PlatformPermission, Project, RequestContext, SelvaConfig } from '@selvajs/platform';
24
+ import { type ProjectAccessInputBuilder } from './project-access-input.js';
25
+ import type { SelvaDeps } from '../api/deps.js';
26
+ export type AnyPermission = PlatformPermission | OrgPermission;
27
+ /**
28
+ * What the permission-only guards read.
29
+ *
30
+ * `deps` is absent here on purpose: `requirePermission` and friends check
31
+ * `ctx.platformPermissions` and touch no store, so demanding providers from
32
+ * their callers — the ~20 admin routes and page loads that only ever ask "may
33
+ * this user do X?" — would be a cost with nothing behind it. The guards that do
34
+ * read stores take `HasDeps` instead, which requires them.
35
+ */
36
+ export interface Locals {
37
+ user?: AuthUser;
38
+ ctx?: RequestContext;
39
+ }
40
+ /**
41
+ * What a store-reading guard takes: identity plus the providers to read with.
42
+ *
43
+ * `ApiRequest` satisfies this structurally, so a mounted handler passes itself.
44
+ * Everyone else passes `scoped(locals)`.
45
+ */
46
+ type ScopedLocals = Locals & HasDeps;
47
+ /**
48
+ * The stores a guard reads, injected rather than resolved.
49
+ *
50
+ * `ApiRequest` satisfies this structurally, so a mounted handler passes itself
51
+ * and the guard runs against that request's providers.
52
+ *
53
+ * **Required, not optional.** These guards used to fall back to a host's module
54
+ * globals when no `deps` arrived, which meant importing this file pulled in that
55
+ * host's composition root — in Selva a module running a top-level
56
+ * `await createSelvaProviders()`, so any handler importing a guard booted the
57
+ * whole provider stack. That is what kept these guards in the app; a caller with
58
+ * no `deps` in hand builds them with `accessDepsFromConfig`.
59
+ */
60
+ export type AccessDeps = Pick<SelvaDeps, 'orgs' | 'projects' | 'definitionMeta' | 'platformProjectGrants' | 'flag'>;
61
+ interface HasDeps {
62
+ deps: AccessDeps;
63
+ }
64
+ /**
65
+ * Derive the stores a guard needs from a resolved config.
66
+ *
67
+ * Pure — it reads the config it is handed and nothing else, which is what keeps
68
+ * this module free of any import that boots the app. Page loads pass
69
+ * `locals.providers`; `hooks.server.ts` sets it on every request.
70
+ */
71
+ export declare function accessDepsFromConfig(config: SelvaConfig): AccessDeps;
72
+ /** `locals` as a store-reading guard wants it. */
73
+ export declare function scoped<L extends Locals & {
74
+ providers: SelvaConfig;
75
+ }>(locals: L): L & {
76
+ deps: AccessDeps;
77
+ };
78
+ export declare function requireAuthed(locals: Locals): {
79
+ user: AuthUser;
80
+ ctx: RequestContext;
81
+ };
82
+ /** Throws 403 — use in API routes. */
83
+ export declare function requirePermission(locals: Locals, permission: AnyPermission): AuthUser;
84
+ export declare const requireManageInstanceUsers: (locals: Locals) => AuthUser;
85
+ export declare const requireManageCompute: (locals: Locals) => AuthUser;
86
+ export declare const requireManageOrgMembers: (locals: Locals) => AuthUser;
87
+ export declare const requireManageOrgCompute: (locals: Locals) => AuthUser;
88
+ export declare const requireInstanceAdmin: (locals: Locals) => AuthUser;
89
+ /**
90
+ * Platform scope is not delegable: `manage_instance_users` runs the user-admin
91
+ * surface but must not be able to mint an `instance_admin`, or an org admin
92
+ * holding it self-elevates. Three routes write platform permissions — the two
93
+ * `/api/admin/users` handlers and the invite mint route — and each carried its
94
+ * own copy of this check.
95
+ *
96
+ * Pass `current` on an update. Revoking is a platform-scope change too, so a
97
+ * PATCH that drops `instance_admin` is refused for the same reason granting it
98
+ * is; without `current` the caller is creating (a user, an invite) and there is
99
+ * nothing to compare against.
100
+ *
101
+ * Requesting nothing on a create is always allowed — that is a
102
+ * `manage_instance_users` operation, not a platform-scope one.
103
+ */
104
+ export declare function assertCanGrantPlatformPermissions(ctx: RequestContext, requested: readonly PlatformPermission[], current?: readonly PlatformPermission[]): void;
105
+ /**
106
+ * Tenancy gate for `/api/v1/orgs/{orgId}/…`. The URL id is never trusted alone
107
+ * — the acting context decides which tenant a request applies to, so a
108
+ * mismatch is 403 rather than a silent read of the caller's own org.
109
+ */
110
+ export declare function requireActingOrg(locals: Locals, orgId: string | undefined): {
111
+ ctx: RequestContext;
112
+ orgId: string;
113
+ };
114
+ /**
115
+ * Assemble a rule input from rows the caller already loaded.
116
+ *
117
+ * Unlike the other builders this one issues no reads — the caller batched them.
118
+ * It still needs `deps` for the flag lookups, which decide whether a
119
+ * cross-org-public or platform project is visible at all.
120
+ */
121
+ export declare function projectAccessInputFromRowsWith(src: HasDeps, ...args: Parameters<ProjectAccessInputBuilder['projectAccessInputFromRows']>): import("@selvajs/platform").ProjectAccessInput;
122
+ /**
123
+ * Gates creation of a *new* definition. Container projects require project
124
+ * owner/editor (canEdit). Commons projects (`autoJoinOnUpload=true`) accept
125
+ * any authenticated user — the handler stamps `ownerId = user.id` so the
126
+ * uploader becomes the owner.
127
+ */
128
+ export declare function requireCanCreateDefinition(locals: ScopedLocals, projectId: string): Promise<{
129
+ user: AuthUser;
130
+ ctx: RequestContext;
131
+ project: Project;
132
+ }>;
133
+ /**
134
+ * Org-content gate — the caller must be a member of `orgId`. Used by the
135
+ * file-serving proxy for org-private assets (e.g. pricing sheets under
136
+ * `orgs/{id}/private/*`). Org membership is the only rule; runs through
137
+ * `contentCheck` (no `instance_admin` bypass) — platform staff use Reclaim
138
+ * if they need access without membership.
139
+ *
140
+ * Throws 401 unauthenticated, 403 when not a member.
141
+ */
142
+ export declare function requireCanViewOrg(locals: ScopedLocals, orgId: string): Promise<AuthUser>;
143
+ /**
144
+ * Project members must belong to the project's parent org. Enforced at the
145
+ * rule layer, not as a DB constraint, to leave room for cross-org guests
146
+ * later without a schema migration.
147
+ */
148
+ export declare function requireTargetIsOrgMember(locals: ScopedLocals, orgId: string, targetUserId: string): Promise<void>;
149
+ /**
150
+ * `canChangeOrgRole` with the actor's membership row loaded — whether the
151
+ * caller may grant or revoke org `owner`/`admin` standing (§3).
152
+ *
153
+ * Returns rather than throws: the three callers each phrase the refusal for
154
+ * what they were doing ("invite someone as owner", "change roles", "remove
155
+ * another owner") and raise it through `apiError`. What must not diverge is the
156
+ * decision, which is why that half lives in `rules.ts` and this loads its input.
157
+ */
158
+ export declare function canActorChangeOrgRole(ctx: RequestContext, orgId: string, role: OrgRole, src: HasDeps): Promise<boolean>;
159
+ /**
160
+ * `canReclaim` — org owner/admin escape hatch. Returns the project so the
161
+ * handler can use its `orgId` without re-fetching.
162
+ */
163
+ export declare function requireCanReclaim(locals: ScopedLocals, projectId: string): Promise<{
164
+ user: AuthUser;
165
+ ctx: RequestContext;
166
+ project: Project;
167
+ }>;
168
+ /**
169
+ * `canCreateProject` — owner/admin always; member needs `manage_projects`.
170
+ * Tenancy is enforced via `actingOrgId`.
171
+ */
172
+ export declare function requireCanCreateProject(locals: ScopedLocals, targetOrgId: string): Promise<{
173
+ user: AuthUser;
174
+ ctx: RequestContext;
175
+ }>;
176
+ /**
177
+ * Project-management gate (`canManage` — owner, or `instance_admin` via the
178
+ * bypass). Managing members is the same authority as managing the project, so
179
+ * both callers share this; `action` only shapes the 403 message.
180
+ */
181
+ export declare function requireCanManage(locals: ScopedLocals, projectId: string, action?: 'project' | 'members'): Promise<AuthUser>;
182
+ export declare function requireCanEditProjectSettings(locals: ScopedLocals, projectId: string): Promise<{
183
+ user: AuthUser;
184
+ ctx: RequestContext;
185
+ project: Project;
186
+ }>;
187
+ export declare function requireCanViewProject(locals: ScopedLocals, projectId: string): Promise<AuthUser>;
188
+ /**
189
+ * Solve gating. Today `canSolve === canView` for non-platform projects, but
190
+ * the rule lives in its own function so future cost-gating (quotas, rate
191
+ * limits) lands without touching view semantics. `viewer` project role
192
+ * passes; platform projects narrow to grants with `canSolve=true`.
193
+ */
194
+ export declare function requireCanSolve(locals: ScopedLocals, projectId: string, preloadedProject?: Project): Promise<{
195
+ user: AuthUser;
196
+ ctx: RequestContext;
197
+ project: Project;
198
+ }>;
199
+ /**
200
+ * Loads the record and gates editing. Returns the record AND the project it
201
+ * loads for the gate, so callers skip a re-fetch of either.
202
+ */
203
+ export declare function requireEditableDefinition(locals: ScopedLocals, guid: string): Promise<{
204
+ record: DefinitionRecord;
205
+ ctx: RequestContext;
206
+ project: Project | null;
207
+ }>;
208
+ export declare function requireCanEditDefinition(locals: ScopedLocals, projectId: string, definitionGuid: string, preloaded?: {
209
+ project?: Project | null;
210
+ definition?: DefinitionRecord | null;
211
+ }): Promise<AuthUser>;
212
+ export {};
213
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/access/guards.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,417 @@
1
+ /**
2
+ * The permission guards every API handler runs before touching a store.
3
+ *
4
+ * These name no framework. A guard raises `ApiError`, which `runHandler` folds
5
+ * into the response envelope — so the same guard protects a SvelteKit route, a
6
+ * Next route handler, or a Hono route behind that host's own adapter.
7
+ *
8
+ * **Guards that redirect stay with the host.** A redirect is a browser-page
9
+ * concept, not an API one, and a framework implements it by throwing a value
10
+ * only that framework understands.
11
+ *
12
+ * A caller outside an API route — a page load, or a route that builds its own
13
+ * `Response` — has to convert the `ApiError` at its boundary, since a framework
14
+ * will not recognize it. Selva does that with `asHttpError` in
15
+ * `access.server.ts`; SvelteKit gives anything that is not its own `HttpError` a
16
+ * 500, so an unconverted guard denial reads as a crash.
17
+ *
18
+ * Providers arrive through {@link AccessDeps} rather than being resolved here.
19
+ * That is what keeps this module importable without booting an app: a guard
20
+ * that reached for a module global would drag the whole composition root — and
21
+ * its top-level `await createSelvaProviders()` — into every consumer.
22
+ */
23
+ import { isFlagEnabled, hasPermission, canReclaim, canCreateProject, canChangeOrgRole, canView, canSolve, canEdit, canManage, canEditProjectSettings, canEditDefinition } from '@selvajs/platform';
24
+ import { createProjectAccessInputBuilder } from './project-access-input.js';
25
+ import { apiError, ApiErrorCode } from '../api/errors.js';
26
+ /**
27
+ * Derive the stores a guard needs from a resolved config.
28
+ *
29
+ * Pure — it reads the config it is handed and nothing else, which is what keeps
30
+ * this module free of any import that boots the app. Page loads pass
31
+ * `locals.providers`; `hooks.server.ts` sets it on every request.
32
+ */
33
+ export function accessDepsFromConfig(config) {
34
+ return {
35
+ orgs: config.data.orgs,
36
+ projects: config.data.projects,
37
+ definitionMeta: config.data.definitions,
38
+ platformProjectGrants: config.data.platformProjectGrants,
39
+ flag: (name) => isFlagEnabled(config, name)
40
+ };
41
+ }
42
+ /** `locals` as a store-reading guard wants it. */
43
+ export function scoped(locals) {
44
+ return { ...locals, deps: accessDepsFromConfig(locals.providers) };
45
+ }
46
+ // Accessors rather than `src.deps.orgs` inline: they keep the 17 call sites
47
+ // below reading the same as before, and they are the single place that would
48
+ // change if `AccessDeps` grew a store.
49
+ const orgsOf = (src) => src.deps.orgs;
50
+ const projectsOf = (src) => src.deps.projects;
51
+ const definitionMetaOf = (src) => src.deps.definitionMeta;
52
+ const flagOf = (src) => src.deps.flag;
53
+ export function requireAuthed(locals) {
54
+ const { user, ctx } = locals;
55
+ if (!user || !ctx)
56
+ apiError(401, ApiErrorCode.UNAUTHORIZED, 'Unauthorized');
57
+ return { user, ctx };
58
+ }
59
+ /** Throws 403 — use in API routes. */
60
+ export function requirePermission(locals, permission) {
61
+ const { user, ctx } = requireAuthed(locals);
62
+ if (!hasPermission(ctx, permission)) {
63
+ apiError(403, ApiErrorCode.FORBIDDEN, `You don't have permission to do this.`);
64
+ }
65
+ return user;
66
+ }
67
+ // Named aliases exist only for permissions with real call sites. Routes gating
68
+ // on anything else call `requirePermission(locals, '…')` directly rather than
69
+ // growing an alias per permission — `manage_definitions` and `manage_projects`
70
+ // had wrappers that nothing ever called.
71
+ export const requireManageInstanceUsers = (locals) => requirePermission(locals, 'manage_instance_users');
72
+ export const requireManageCompute = (locals) => requirePermission(locals, 'manage_compute');
73
+ export const requireManageOrgMembers = (locals) => requirePermission(locals, 'manage_org_members');
74
+ export const requireManageOrgCompute = (locals) => requirePermission(locals, 'manage_org_compute');
75
+ export const requireInstanceAdmin = (locals) => requirePermission(locals, 'instance_admin');
76
+ /**
77
+ * Platform scope is not delegable: `manage_instance_users` runs the user-admin
78
+ * surface but must not be able to mint an `instance_admin`, or an org admin
79
+ * holding it self-elevates. Three routes write platform permissions — the two
80
+ * `/api/admin/users` handlers and the invite mint route — and each carried its
81
+ * own copy of this check.
82
+ *
83
+ * Pass `current` on an update. Revoking is a platform-scope change too, so a
84
+ * PATCH that drops `instance_admin` is refused for the same reason granting it
85
+ * is; without `current` the caller is creating (a user, an invite) and there is
86
+ * nothing to compare against.
87
+ *
88
+ * Requesting nothing on a create is always allowed — that is a
89
+ * `manage_instance_users` operation, not a platform-scope one.
90
+ */
91
+ export function assertCanGrantPlatformPermissions(ctx, requested, current) {
92
+ const changed = current
93
+ ? requested.length !== current.length ||
94
+ requested.some((p) => !current.includes(p)) ||
95
+ current.some((p) => !requested.includes(p))
96
+ : requested.length > 0;
97
+ if (!changed)
98
+ return;
99
+ if (hasPermission(ctx, 'instance_admin'))
100
+ return;
101
+ apiError(403, ApiErrorCode.FORBIDDEN, current
102
+ ? 'Only a platform admin can change platform-scope permissions'
103
+ : 'Only a platform admin can grant platform-scope permissions');
104
+ }
105
+ /**
106
+ * Tenancy gate for `/api/v1/orgs/{orgId}/…`. The URL id is never trusted alone
107
+ * — the acting context decides which tenant a request applies to, so a
108
+ * mismatch is 403 rather than a silent read of the caller's own org.
109
+ */
110
+ export function requireActingOrg(locals, orgId) {
111
+ const ctx = locals.ctx;
112
+ if (!ctx)
113
+ apiError(401, ApiErrorCode.UNAUTHORIZED, 'Unauthorized');
114
+ if (!orgId)
115
+ apiError(400, ApiErrorCode.VALIDATION_FAILED, 'Missing org ID');
116
+ if (!ctx.actingOrgId)
117
+ apiError(400, ApiErrorCode.VALIDATION_FAILED, 'No active organization');
118
+ if (ctx.actingOrgId !== orgId) {
119
+ apiError(403, ApiErrorCode.FORBIDDEN, 'Acting org does not match the target org.');
120
+ }
121
+ return { ctx, orgId };
122
+ }
123
+ /**
124
+ * Gate for pages reachable by any platform-class permission holder (the
125
+
126
+ /**
127
+ * Management-scope bypass — used for org governance and project management
128
+ * actions (Reclaim, create project, delete project, manage members, edit
129
+ * settings). `instance_admin` bypasses these so platform staff can administer
130
+ * the instance without being a member of every org.
131
+ *
132
+ * NOT used for content access (view, solve, edit definitions):
133
+ * `instance_admin` follows the same `canView`/`canEdit` rules as any other
134
+ * user there, keeping blast radius small and forcing content escalation
135
+ * through Reclaim, which leaves an audit trail.
136
+ */
137
+ async function managementBypassOrRun(ctx, check) {
138
+ if (hasPermission(ctx, 'instance_admin'))
139
+ return true;
140
+ return await check();
141
+ }
142
+ // Content-scope check — NO `instance_admin` bypass. `canView`, `canSolve`,
143
+ // `canEdit`, and `canEditDefinition` run as-is regardless of platform role;
144
+ // platform staff use Reclaim first if they need content access.
145
+ async function contentCheck(check) {
146
+ return await check();
147
+ }
148
+ async function loadProjectOr404(ctx, projectId, src) {
149
+ const project = await projectsOf(src).getProject(ctx, projectId);
150
+ if (!project)
151
+ apiError(404, ApiErrorCode.NOT_FOUND, 'Project not found');
152
+ return project;
153
+ }
154
+ // Rule-input assembly (the "which rows does each visibility need" knowledge)
155
+ // lives in `@selvajs/server/access`; this binding wires it to the provider set
156
+ // the caller carries.
157
+ function accessInputsFor(src) {
158
+ const readFlag = flagOf(src);
159
+ return createProjectAccessInputBuilder({
160
+ getProjectMember: (ctx, projectId, userId) => projectsOf(src).getProjectMember(ctx, projectId, userId),
161
+ getOrgMember: (ctx, orgId, userId) => orgsOf(src).getOrgMember(ctx, orgId, userId),
162
+ listPlatformGrants: (ctx, projectId) => src.deps.platformProjectGrants.listByProject(ctx, projectId),
163
+ flags: () => ({
164
+ allowCrossOrgPublic: readFlag('ALLOW_CROSS_ORG_PUBLIC'),
165
+ enablePlatformProjects: readFlag('ENABLE_PLATFORM_PROJECTS')
166
+ })
167
+ });
168
+ }
169
+ function buildProjectAccessInput(ctx, project, src, overrides) {
170
+ return accessInputsFor(src).buildProjectAccessInput(ctx, project, overrides);
171
+ }
172
+ /**
173
+ * Assemble a rule input from rows the caller already loaded.
174
+ *
175
+ * Unlike the other builders this one issues no reads — the caller batched them.
176
+ * It still needs `deps` for the flag lookups, which decide whether a
177
+ * cross-org-public or platform project is visible at all.
178
+ */
179
+ export function projectAccessInputFromRowsWith(src, ...args) {
180
+ return accessInputsFor(src).projectAccessInputFromRows(...args);
181
+ }
182
+ /**
183
+ * Gates creation of a *new* definition. Container projects require project
184
+ * owner/editor (canEdit). Commons projects (`autoJoinOnUpload=true`) accept
185
+ * any authenticated user — the handler stamps `ownerId = user.id` so the
186
+ * uploader becomes the owner.
187
+ */
188
+ export async function requireCanCreateDefinition(locals, projectId) {
189
+ const { user, ctx } = requireAuthed(locals);
190
+ const project = await loadProjectOr404(ctx, projectId, locals);
191
+ const allowed = await contentCheck(async () => {
192
+ if (project.autoJoinOnUpload)
193
+ return true;
194
+ return canEdit(await buildProjectAccessInput(ctx, project, locals));
195
+ });
196
+ if (!allowed) {
197
+ apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have permission to upload definitions to this project.');
198
+ }
199
+ return { user, ctx, project };
200
+ }
201
+ /**
202
+ * Org-content gate — the caller must be a member of `orgId`. Used by the
203
+ * file-serving proxy for org-private assets (e.g. pricing sheets under
204
+ * `orgs/{id}/private/*`). Org membership is the only rule; runs through
205
+ * `contentCheck` (no `instance_admin` bypass) — platform staff use Reclaim
206
+ * if they need access without membership.
207
+ *
208
+ * Throws 401 unauthenticated, 403 when not a member.
209
+ */
210
+ export async function requireCanViewOrg(locals, orgId) {
211
+ const { user, ctx } = requireAuthed(locals);
212
+ const allowed = await contentCheck(async () => {
213
+ const member = await orgsOf(locals).getOrgMember(ctx, orgId, ctx.userId);
214
+ return member !== null;
215
+ });
216
+ if (!allowed)
217
+ apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have access to this organization.');
218
+ return user;
219
+ }
220
+ /**
221
+ * Project members must belong to the project's parent org. Enforced at the
222
+ * rule layer, not as a DB constraint, to leave room for cross-org guests
223
+ * later without a schema migration.
224
+ */
225
+ export async function requireTargetIsOrgMember(locals, orgId, targetUserId) {
226
+ const { ctx } = requireAuthed(locals);
227
+ const member = await orgsOf(locals).getOrgMember(ctx, orgId, targetUserId);
228
+ if (!member) {
229
+ apiError(400, ApiErrorCode.VALIDATION_FAILED, 'User must be a member of this organization to be added to a project.');
230
+ }
231
+ }
232
+ /**
233
+ * `canChangeOrgRole` with the actor's membership row loaded — whether the
234
+ * caller may grant or revoke org `owner`/`admin` standing (§3).
235
+ *
236
+ * Returns rather than throws: the three callers each phrase the refusal for
237
+ * what they were doing ("invite someone as owner", "change roles", "remove
238
+ * another owner") and raise it through `apiError`. What must not diverge is the
239
+ * decision, which is why that half lives in `rules.ts` and this loads its input.
240
+ */
241
+ export async function canActorChangeOrgRole(ctx, orgId, role, src) {
242
+ if (role === 'member')
243
+ return true;
244
+ const actorMember = await orgsOf(src).getOrgMember(ctx, orgId, ctx.userId);
245
+ return canChangeOrgRole({ actorMember, role });
246
+ }
247
+ /**
248
+ * `canReclaim` — org owner/admin escape hatch. Returns the project so the
249
+ * handler can use its `orgId` without re-fetching.
250
+ */
251
+ export async function requireCanReclaim(locals, projectId) {
252
+ const { user, ctx } = requireAuthed(locals);
253
+ const project = await loadProjectOr404(ctx, projectId, locals);
254
+ // Ahead of the bypass, not inside the check: `instance_admin` short-circuits
255
+ // `managementBypassOrRun`, so `canReclaim`'s platform-project refusal (§4a)
256
+ // never ran for the one role that could reach it. Reclaim is content
257
+ // escalation wearing management clothing — the management bypass is not its
258
+ // to inherit.
259
+ if (project.visibility === 'platform') {
260
+ apiError(403, ApiErrorCode.FORBIDDEN, 'Platform projects cannot be reclaimed.');
261
+ }
262
+ const allowed = await managementBypassOrRun(ctx, async () => {
263
+ const orgMember = await orgsOf(locals).getOrgMember(ctx, project.orgId, ctx.userId);
264
+ return canReclaim({
265
+ project,
266
+ orgMember,
267
+ actingOrgId: ctx.actingOrgId ?? null
268
+ });
269
+ });
270
+ if (!allowed) {
271
+ apiError(403, ApiErrorCode.FORBIDDEN, 'Only org owners or admins of this project’s org can reclaim it.');
272
+ }
273
+ return { user, ctx, project };
274
+ }
275
+ /**
276
+ * `canCreateProject` — owner/admin always; member needs `manage_projects`.
277
+ * Tenancy is enforced via `actingOrgId`.
278
+ */
279
+ export async function requireCanCreateProject(locals, targetOrgId) {
280
+ const { user, ctx } = requireAuthed(locals);
281
+ const allowed = await managementBypassOrRun(ctx, async () => {
282
+ const orgMember = await orgsOf(locals).getOrgMember(ctx, targetOrgId, ctx.userId);
283
+ return canCreateProject({
284
+ orgPermissions: ctx.orgPermissions,
285
+ orgMember,
286
+ actingOrgId: ctx.actingOrgId ?? null,
287
+ targetOrgId
288
+ });
289
+ });
290
+ if (!allowed)
291
+ apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have permission to create projects in this org.');
292
+ return { user, ctx };
293
+ }
294
+ /**
295
+ * Project-management gate (`canManage` — owner, or `instance_admin` via the
296
+ * bypass). Managing members is the same authority as managing the project, so
297
+ * both callers share this; `action` only shapes the 403 message.
298
+ */
299
+ export async function requireCanManage(locals, projectId, action = 'project') {
300
+ const { user, ctx } = requireAuthed(locals);
301
+ const allowed = await managementBypassOrRun(ctx, async () => {
302
+ const project = await loadProjectOr404(ctx, projectId, locals);
303
+ return canManage(await buildProjectAccessInput(ctx, project, locals));
304
+ });
305
+ if (!allowed) {
306
+ apiError(403, ApiErrorCode.FORBIDDEN, action === 'members'
307
+ ? 'Only project owners can manage members.'
308
+ : 'Only project owners can manage this project.');
309
+ }
310
+ return user;
311
+ }
312
+ // Owner-only gate for project settings, centralized so PATCH
313
+ // /api/projects/[id] matches the rest of the access layer.
314
+ export async function requireCanEditProjectSettings(locals, projectId) {
315
+ const { user, ctx } = requireAuthed(locals);
316
+ const project = await loadProjectOr404(ctx, projectId, locals);
317
+ const allowed = await managementBypassOrRun(ctx, async () => canEditProjectSettings(await buildProjectAccessInput(ctx, project, locals)));
318
+ if (!allowed)
319
+ apiError(403, ApiErrorCode.FORBIDDEN, 'Only project owners can edit project settings.');
320
+ return { user, ctx, project };
321
+ }
322
+ export async function requireCanViewProject(locals, projectId) {
323
+ const { user, ctx } = requireAuthed(locals);
324
+ const allowed = await contentCheck(async () => {
325
+ const project = await loadProjectOr404(ctx, projectId, locals);
326
+ return canView(await buildProjectAccessInput(ctx, project, locals));
327
+ });
328
+ if (!allowed)
329
+ apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have access to this project.');
330
+ return user;
331
+ }
332
+ /**
333
+ * Solve gating. Today `canSolve === canView` for non-platform projects, but
334
+ * the rule lives in its own function so future cost-gating (quotas, rate
335
+ * limits) lands without touching view semantics. `viewer` project role
336
+ * passes; platform projects narrow to grants with `canSolve=true`.
337
+ */
338
+ export async function requireCanSolve(locals, projectId,
339
+ // Callers that already loaded the project (e.g. the solve endpoint, which
340
+ // reads orgId/pin off it) pass it to skip a redundant `getProject` here.
341
+ preloadedProject) {
342
+ const { user, ctx } = requireAuthed(locals);
343
+ const project = preloadedProject ?? (await loadProjectOr404(ctx, projectId, locals));
344
+ const allowed = await contentCheck(async () => canSolve(await buildProjectAccessInput(ctx, project, locals)));
345
+ if (!allowed)
346
+ apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have access to this project.');
347
+ return { user, ctx, project };
348
+ }
349
+ /**
350
+ * Org membership for the commons branch of `canEditDefinition`, or `null` when
351
+ * that branch cannot fire. Skipping the round-trip on container projects keeps
352
+ * the common edit path at the same two reads it had before commons gained the
353
+ * membership test.
354
+ */
355
+ async function loadCommonsOrgMember(ctx, project, src) {
356
+ if (!project?.autoJoinOnUpload)
357
+ return null;
358
+ return await orgsOf(src).getOrgMember(ctx, project.orgId, ctx.userId);
359
+ }
360
+ /**
361
+ * Loads the record and gates editing. Returns the record AND the project it
362
+ * loads for the gate, so callers skip a re-fetch of either.
363
+ */
364
+ export async function requireEditableDefinition(locals, guid) {
365
+ const { ctx } = requireAuthed(locals);
366
+ const record = await definitionMetaOf(locals).get(ctx, guid);
367
+ if (!record)
368
+ apiError(404, ApiErrorCode.NOT_FOUND, 'Definition not found');
369
+ // Load project + member once up front; `project` is returned for reuse.
370
+ const [project, member] = await Promise.all([
371
+ projectsOf(locals).getProject(ctx, record.projectId),
372
+ projectsOf(locals).getProjectMember(ctx, record.projectId, ctx.userId)
373
+ ]);
374
+ const allowed = await contentCheck(async () => canEditDefinition({
375
+ project,
376
+ definition: record,
377
+ member,
378
+ orgMember: await loadCommonsOrgMember(ctx, project, locals),
379
+ userId: ctx.userId,
380
+ platformPermissions: ctx.platformPermissions,
381
+ enablePlatformProjects: flagOf(locals)('ENABLE_PLATFORM_PROJECTS')
382
+ }));
383
+ if (!allowed)
384
+ apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have permission to edit this definition.');
385
+ return { record, ctx, project };
386
+ }
387
+ export async function requireCanEditDefinition(locals, projectId, definitionGuid,
388
+ // Callers that already loaded the project and/or definition (e.g. the solve
389
+ // endpoint) pass them to skip the redundant fetches inside the gate. The
390
+ // member row still loads here (the caller doesn't have it).
391
+ preloaded) {
392
+ const { user, ctx } = requireAuthed(locals);
393
+ const allowed = await contentCheck(async () => {
394
+ const [project, definition, member] = await Promise.all([
395
+ preloaded?.project !== undefined
396
+ ? Promise.resolve(preloaded.project)
397
+ : projectsOf(locals).getProject(ctx, projectId),
398
+ preloaded?.definition !== undefined
399
+ ? Promise.resolve(preloaded.definition)
400
+ : definitionMetaOf(locals).get(ctx, definitionGuid),
401
+ projectsOf(locals).getProjectMember(ctx, projectId, ctx.userId)
402
+ ]);
403
+ return canEditDefinition({
404
+ project,
405
+ definition,
406
+ member,
407
+ orgMember: await loadCommonsOrgMember(ctx, project, locals),
408
+ userId: ctx.userId,
409
+ platformPermissions: ctx.platformPermissions,
410
+ enablePlatformProjects: flagOf(locals)('ENABLE_PLATFORM_PROJECTS')
411
+ });
412
+ });
413
+ if (!allowed)
414
+ apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have permission to edit this definition.');
415
+ return user;
416
+ }
417
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/access/guards.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,4 @@
1
1
  export { createProjectAccessInputBuilder, type ProjectAccessFlags, type ProjectAccessInputBuilder, type ProjectAccessInputDeps } from './project-access-input.js';
2
+ export * from './guards.js';
3
+ export { splitFlatPermissions, type SplitPermissions } from './permissions-scope.js';
2
4
  //# sourceMappingURL=index.d.ts.map