@classytic/arc 1.1.0 → 2.1.3

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 (200) hide show
  1. package/README.md +247 -794
  2. package/bin/arc.js +91 -52
  3. package/dist/EventTransport-BkUDYZEb.d.mts +99 -0
  4. package/dist/HookSystem-BsGV-j2l.mjs +404 -0
  5. package/dist/ResourceRegistry-7Ic20ZMw.mjs +249 -0
  6. package/dist/adapters/index.d.mts +5 -0
  7. package/dist/adapters/index.mjs +3 -0
  8. package/dist/audit/index.d.mts +81 -0
  9. package/dist/audit/index.mjs +275 -0
  10. package/dist/audit/mongodb.d.mts +5 -0
  11. package/dist/audit/mongodb.mjs +3 -0
  12. package/dist/audited-CGdLiSlE.mjs +140 -0
  13. package/dist/auth/index.d.mts +188 -0
  14. package/dist/auth/index.mjs +1096 -0
  15. package/dist/auth/redis-session.d.mts +43 -0
  16. package/dist/auth/redis-session.mjs +75 -0
  17. package/dist/betterAuthOpenApi-DjWDddNc.mjs +249 -0
  18. package/dist/cache/index.d.mts +145 -0
  19. package/dist/cache/index.mjs +91 -0
  20. package/dist/caching-GSDJcA6-.mjs +93 -0
  21. package/dist/chunk-C7Uep-_p.mjs +20 -0
  22. package/dist/circuitBreaker-DYhWBW_D.mjs +1096 -0
  23. package/dist/cli/commands/describe.d.mts +18 -0
  24. package/dist/cli/commands/describe.mjs +238 -0
  25. package/dist/cli/commands/docs.d.mts +13 -0
  26. package/dist/cli/commands/docs.mjs +52 -0
  27. package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -2
  28. package/dist/cli/commands/generate.mjs +357 -0
  29. package/dist/cli/commands/{init.d.ts → init.d.mts} +11 -8
  30. package/dist/cli/commands/{init.js → init.mjs} +807 -617
  31. package/dist/cli/commands/introspect.d.mts +10 -0
  32. package/dist/cli/commands/introspect.mjs +75 -0
  33. package/dist/cli/index.d.mts +16 -0
  34. package/dist/cli/index.mjs +156 -0
  35. package/dist/constants-DdXFXQtN.mjs +84 -0
  36. package/dist/core/index.d.mts +5 -0
  37. package/dist/core/index.mjs +4 -0
  38. package/dist/createApp-D2D5XXaV.mjs +559 -0
  39. package/dist/defineResource-PXzSJ15_.mjs +2197 -0
  40. package/dist/discovery/index.d.mts +46 -0
  41. package/dist/discovery/index.mjs +109 -0
  42. package/dist/docs/index.d.mts +162 -0
  43. package/dist/docs/index.mjs +74 -0
  44. package/dist/elevation-DGo5shaX.d.mts +87 -0
  45. package/dist/elevation-DSTbVvYj.mjs +113 -0
  46. package/dist/errorHandler-C3GY3_ow.mjs +108 -0
  47. package/dist/errorHandler-CW3OOeYq.d.mts +72 -0
  48. package/dist/errors-DAWRdiYP.d.mts +124 -0
  49. package/dist/errors-DBANPbGr.mjs +211 -0
  50. package/dist/eventPlugin-BEOvaDqo.mjs +229 -0
  51. package/dist/eventPlugin-H6wDDjGO.d.mts +124 -0
  52. package/dist/events/index.d.mts +53 -0
  53. package/dist/events/index.mjs +51 -0
  54. package/dist/events/transports/redis-stream-entry.d.mts +2 -0
  55. package/dist/events/transports/redis-stream-entry.mjs +177 -0
  56. package/dist/events/transports/redis.d.mts +76 -0
  57. package/dist/events/transports/redis.mjs +124 -0
  58. package/dist/externalPaths-SyPF2tgK.d.mts +50 -0
  59. package/dist/factory/index.d.mts +63 -0
  60. package/dist/factory/index.mjs +3 -0
  61. package/dist/fastifyAdapter-C8DlE0YH.d.mts +216 -0
  62. package/dist/fields-Bi_AVKSo.d.mts +109 -0
  63. package/dist/fields-CTd_CrKr.mjs +114 -0
  64. package/dist/hooks/index.d.mts +4 -0
  65. package/dist/hooks/index.mjs +3 -0
  66. package/dist/idempotency/index.d.mts +96 -0
  67. package/dist/idempotency/index.mjs +319 -0
  68. package/dist/idempotency/mongodb.d.mts +2 -0
  69. package/dist/idempotency/mongodb.mjs +114 -0
  70. package/dist/idempotency/redis.d.mts +2 -0
  71. package/dist/idempotency/redis.mjs +103 -0
  72. package/dist/index.d.mts +260 -0
  73. package/dist/index.mjs +104 -0
  74. package/dist/integrations/event-gateway.d.mts +46 -0
  75. package/dist/integrations/event-gateway.mjs +43 -0
  76. package/dist/integrations/index.d.mts +5 -0
  77. package/dist/integrations/index.mjs +1 -0
  78. package/dist/integrations/jobs.d.mts +103 -0
  79. package/dist/integrations/jobs.mjs +123 -0
  80. package/dist/integrations/streamline.d.mts +60 -0
  81. package/dist/integrations/streamline.mjs +125 -0
  82. package/dist/integrations/websocket.d.mts +82 -0
  83. package/dist/integrations/websocket.mjs +288 -0
  84. package/dist/interface-CSNjltAc.d.mts +77 -0
  85. package/dist/interface-DTbsvIWe.d.mts +54 -0
  86. package/dist/interface-e9XfSsUV.d.mts +1097 -0
  87. package/dist/introspectionPlugin-B3JkrjwU.mjs +53 -0
  88. package/dist/keys-DhqDRxv3.mjs +42 -0
  89. package/dist/logger-ByrvQWZO.mjs +78 -0
  90. package/dist/memory-B2v7KrCB.mjs +143 -0
  91. package/dist/migrations/index.d.mts +156 -0
  92. package/dist/migrations/index.mjs +260 -0
  93. package/dist/mongodb-ClykrfGo.d.mts +118 -0
  94. package/dist/mongodb-DNKEExbf.mjs +93 -0
  95. package/dist/mongodb-Dg8O_gvd.d.mts +71 -0
  96. package/dist/openapi-9nB_kiuR.mjs +525 -0
  97. package/dist/org/index.d.mts +68 -0
  98. package/dist/org/index.mjs +513 -0
  99. package/dist/org/types.d.mts +82 -0
  100. package/dist/org/types.mjs +1 -0
  101. package/dist/permissions/index.d.mts +278 -0
  102. package/dist/permissions/index.mjs +579 -0
  103. package/dist/plugins/index.d.mts +172 -0
  104. package/dist/plugins/index.mjs +522 -0
  105. package/dist/plugins/response-cache.d.mts +87 -0
  106. package/dist/plugins/response-cache.mjs +283 -0
  107. package/dist/plugins/tracing-entry.d.mts +2 -0
  108. package/dist/plugins/tracing-entry.mjs +185 -0
  109. package/dist/pluralize-CM-jZg7p.mjs +86 -0
  110. package/dist/policies/{index.d.ts → index.d.mts} +204 -170
  111. package/dist/policies/index.mjs +321 -0
  112. package/dist/presets/{index.d.ts → index.d.mts} +62 -131
  113. package/dist/presets/index.mjs +143 -0
  114. package/dist/presets/multiTenant.d.mts +24 -0
  115. package/dist/presets/multiTenant.mjs +113 -0
  116. package/dist/presets-BTeYbw7h.d.mts +57 -0
  117. package/dist/presets-CeFtfDR8.mjs +119 -0
  118. package/dist/prisma-C3iornoK.d.mts +274 -0
  119. package/dist/prisma-DJbMt3yf.mjs +627 -0
  120. package/dist/queryCachePlugin-B6R0d4av.mjs +138 -0
  121. package/dist/queryCachePlugin-Q6SYuHZ6.d.mts +71 -0
  122. package/dist/redis-UwjEp8Ea.d.mts +49 -0
  123. package/dist/redis-stream-CBg0upHI.d.mts +103 -0
  124. package/dist/registry/index.d.mts +11 -0
  125. package/dist/registry/index.mjs +4 -0
  126. package/dist/requestContext-xi6OKBL-.mjs +55 -0
  127. package/dist/schemaConverter-Dtg0Kt9T.mjs +98 -0
  128. package/dist/schemas/index.d.mts +63 -0
  129. package/dist/schemas/index.mjs +82 -0
  130. package/dist/scope/index.d.mts +21 -0
  131. package/dist/scope/index.mjs +65 -0
  132. package/dist/sessionManager-D_iEHjQl.d.mts +186 -0
  133. package/dist/sse-DkqQ1uxb.mjs +123 -0
  134. package/dist/testing/index.d.mts +907 -0
  135. package/dist/testing/index.mjs +1976 -0
  136. package/dist/tracing-8CEbhF0w.d.mts +70 -0
  137. package/dist/typeGuards-DwxA1t_L.mjs +9 -0
  138. package/dist/types/index.d.mts +946 -0
  139. package/dist/types/index.mjs +14 -0
  140. package/dist/types-B0dhNrnd.d.mts +445 -0
  141. package/dist/types-Beqn1Un7.mjs +38 -0
  142. package/dist/types-DelU6kln.mjs +25 -0
  143. package/dist/types-RLkFVgaw.d.mts +101 -0
  144. package/dist/utils/index.d.mts +747 -0
  145. package/dist/utils/index.mjs +6 -0
  146. package/package.json +194 -68
  147. package/dist/BaseController-DVAiHxEQ.d.ts +0 -233
  148. package/dist/adapters/index.d.ts +0 -237
  149. package/dist/adapters/index.js +0 -668
  150. package/dist/arcCorePlugin-CsShQdyP.d.ts +0 -273
  151. package/dist/audit/index.d.ts +0 -195
  152. package/dist/audit/index.js +0 -319
  153. package/dist/auth/index.d.ts +0 -47
  154. package/dist/auth/index.js +0 -174
  155. package/dist/cli/commands/docs.d.ts +0 -11
  156. package/dist/cli/commands/docs.js +0 -474
  157. package/dist/cli/commands/generate.js +0 -334
  158. package/dist/cli/commands/introspect.d.ts +0 -8
  159. package/dist/cli/commands/introspect.js +0 -338
  160. package/dist/cli/index.d.ts +0 -4
  161. package/dist/cli/index.js +0 -3269
  162. package/dist/core/index.d.ts +0 -220
  163. package/dist/core/index.js +0 -2786
  164. package/dist/createApp-Ce9wl8W9.d.ts +0 -77
  165. package/dist/docs/index.d.ts +0 -166
  166. package/dist/docs/index.js +0 -658
  167. package/dist/errors-8WIxGS_6.d.ts +0 -122
  168. package/dist/events/index.d.ts +0 -117
  169. package/dist/events/index.js +0 -89
  170. package/dist/factory/index.d.ts +0 -38
  171. package/dist/factory/index.js +0 -1652
  172. package/dist/hooks/index.d.ts +0 -4
  173. package/dist/hooks/index.js +0 -199
  174. package/dist/idempotency/index.d.ts +0 -323
  175. package/dist/idempotency/index.js +0 -500
  176. package/dist/index-B4t03KQ0.d.ts +0 -1366
  177. package/dist/index.d.ts +0 -135
  178. package/dist/index.js +0 -4756
  179. package/dist/migrations/index.d.ts +0 -185
  180. package/dist/migrations/index.js +0 -274
  181. package/dist/org/index.d.ts +0 -129
  182. package/dist/org/index.js +0 -220
  183. package/dist/permissions/index.d.ts +0 -144
  184. package/dist/permissions/index.js +0 -103
  185. package/dist/plugins/index.d.ts +0 -46
  186. package/dist/plugins/index.js +0 -1069
  187. package/dist/policies/index.js +0 -196
  188. package/dist/presets/index.js +0 -384
  189. package/dist/presets/multiTenant.d.ts +0 -39
  190. package/dist/presets/multiTenant.js +0 -112
  191. package/dist/registry/index.d.ts +0 -16
  192. package/dist/registry/index.js +0 -253
  193. package/dist/testing/index.d.ts +0 -618
  194. package/dist/testing/index.js +0 -48020
  195. package/dist/types/index.d.ts +0 -4
  196. package/dist/types/index.js +0 -8
  197. package/dist/types-B99TBmFV.d.ts +0 -76
  198. package/dist/types-BvckRbs2.d.ts +0 -143
  199. package/dist/utils/index.d.ts +0 -679
  200. package/dist/utils/index.js +0 -931
@@ -0,0 +1,321 @@
1
+ //#region src/policies/PolicyInterface.ts
2
+ /**
3
+ * Create a PermissionCheck from access control statements.
4
+ *
5
+ * Maps Better Auth's statement-based access control model to Arc's
6
+ * PermissionCheck function, which can be used directly in resource permissions.
7
+ *
8
+ * The returned PermissionCheck:
9
+ * 1. Looks up the resource + action in the statements list
10
+ * 2. If no matching statement exists, denies access
11
+ * 3. If a matching statement exists and `checkPermission` is provided,
12
+ * calls it for dynamic verification (e.g., check org role)
13
+ * 4. If `checkPermission` is not provided, allows access based on static statements
14
+ *
15
+ * @example Static statements only
16
+ * ```typescript
17
+ * import { createAccessControlPolicy } from '@classytic/arc/policies';
18
+ *
19
+ * const editorPermissions = createAccessControlPolicy({
20
+ * statements: [
21
+ * { resource: 'product', action: ['create', 'update'] },
22
+ * { resource: 'order', action: ['read'] },
23
+ * ],
24
+ * });
25
+ *
26
+ * // Use in resource config
27
+ * defineResource({
28
+ * name: 'product',
29
+ * permissions: {
30
+ * create: editorPermissions,
31
+ * update: editorPermissions,
32
+ * },
33
+ * });
34
+ * ```
35
+ *
36
+ * @example With dynamic permission check (Better Auth org roles)
37
+ * ```typescript
38
+ * const policy = createAccessControlPolicy({
39
+ * statements: [
40
+ * { resource: 'product', action: ['create', 'update'] },
41
+ * { resource: 'order', action: ['read'] },
42
+ * ],
43
+ * checkPermission: async (userId, resource, action) => {
44
+ * return hasOrgPermission(userId, resource, action);
45
+ * },
46
+ * });
47
+ * ```
48
+ */
49
+ function createAccessControlPolicy(options) {
50
+ const statementMap = /* @__PURE__ */ new Map();
51
+ for (const statement of options.statements) {
52
+ const existing = statementMap.get(statement.resource);
53
+ if (existing) for (const action of statement.action) existing.add(action);
54
+ else statementMap.set(statement.resource, new Set(statement.action));
55
+ }
56
+ const permissionCheck = async (context) => {
57
+ const { user, resource, action } = context;
58
+ const allowedActions = statementMap.get(resource);
59
+ if (!allowedActions || !allowedActions.has(action)) return {
60
+ granted: false,
61
+ reason: `Action '${action}' is not permitted on resource '${resource}'`
62
+ };
63
+ if (options.checkPermission) {
64
+ const userId = user?.id ?? user?._id;
65
+ if (!userId) return {
66
+ granted: false,
67
+ reason: "Authentication required"
68
+ };
69
+ if (!await options.checkPermission(String(userId), resource, action)) return {
70
+ granted: false,
71
+ reason: `User does not have '${action}' permission on '${resource}'`
72
+ };
73
+ }
74
+ return { granted: true };
75
+ };
76
+ return permissionCheck;
77
+ }
78
+
79
+ //#endregion
80
+ //#region src/policies/helpers.ts
81
+ /**
82
+ * Helper to create Fastify middleware from any PolicyEngine implementation
83
+ *
84
+ * This is a convenience function that provides a standard middleware pattern.
85
+ * Most policies can use this instead of implementing toMiddleware() manually.
86
+ *
87
+ * @param policy - Policy engine instance
88
+ * @param operation - Operation name (list, get, create, update, delete)
89
+ * @returns Fastify preHandler middleware
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * class SimplePolicy implements PolicyEngine {
94
+ * can(user, operation) {
95
+ * return { allowed: user.isActive };
96
+ * }
97
+ *
98
+ * toMiddleware(operation) {
99
+ * return createPolicyMiddleware(this, operation);
100
+ * }
101
+ * }
102
+ * ```
103
+ */
104
+ function createPolicyMiddleware(policy, operation) {
105
+ return async function policyMiddleware(request, reply) {
106
+ const context = {
107
+ document: request.document,
108
+ body: request.body,
109
+ params: request.params,
110
+ query: request.query
111
+ };
112
+ const result = await policy.can(request.user, operation, context);
113
+ if (!result.allowed) return reply.code(403).send({
114
+ success: false,
115
+ error: "Access denied",
116
+ message: result.reason || "You do not have permission to perform this action"
117
+ });
118
+ request.policyResult = result;
119
+ if (result.filters && Object.keys(result.filters).length > 0) request._policyFilters = result.filters;
120
+ if (result.fieldMask) request.fieldMask = result.fieldMask;
121
+ if (result.metadata) request.policyMetadata = result.metadata;
122
+ };
123
+ }
124
+ /**
125
+ * Combine multiple policies with AND logic
126
+ *
127
+ * All policies must allow the operation for it to succeed.
128
+ * First denial stops evaluation and returns the denial reason.
129
+ *
130
+ * @param policies - Array of policy engines to combine
131
+ * @returns Combined policy engine
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * const combinedPolicy = combinePolicies(
136
+ * rbacPolicy, // Must have correct role
137
+ * ownershipPolicy, // Must own the resource
138
+ * auditPolicy, // Logs access for compliance
139
+ * );
140
+ *
141
+ * // All three policies must pass for the operation to succeed
142
+ * const result = await combinedPolicy.can(user, 'update', context);
143
+ * ```
144
+ *
145
+ * @example Multi-tenant + RBAC
146
+ * ```typescript
147
+ * const policy = combinePolicies(
148
+ * definePolicy({ tenant: { field: 'organizationId' } }),
149
+ * definePolicy({ roles: { update: ['admin', 'editor'] } }),
150
+ * );
151
+ * ```
152
+ */
153
+ function combinePolicies(...policies) {
154
+ if (policies.length === 0) throw new Error("combinePolicies requires at least one policy");
155
+ if (policies.length === 1) return policies[0];
156
+ return {
157
+ async can(user, operation, context) {
158
+ const results = [];
159
+ for (const policy of policies) {
160
+ const result = await policy.can(user, operation, context);
161
+ if (!result.allowed) return result;
162
+ results.push(result);
163
+ }
164
+ const mergedResult = {
165
+ allowed: true,
166
+ filters: {},
167
+ metadata: {}
168
+ };
169
+ for (const result of results) if (result.filters) Object.assign(mergedResult.filters, result.filters);
170
+ const allExcludes = /* @__PURE__ */ new Set();
171
+ const allIncludes = [];
172
+ for (const result of results) {
173
+ if (result.fieldMask?.exclude) result.fieldMask.exclude.forEach((field) => allExcludes.add(field));
174
+ if (result.fieldMask?.include) allIncludes.push(new Set(result.fieldMask.include));
175
+ }
176
+ if (allExcludes.size > 0 || allIncludes.length > 0) {
177
+ mergedResult.fieldMask = {};
178
+ if (allExcludes.size > 0) mergedResult.fieldMask.exclude = Array.from(allExcludes);
179
+ if (allIncludes.length > 0) {
180
+ const intersection = allIncludes.reduce((acc, set) => {
181
+ return new Set([...acc].filter((x) => set.has(x)));
182
+ });
183
+ if (intersection.size > 0) mergedResult.fieldMask.include = Array.from(intersection);
184
+ }
185
+ }
186
+ for (const result of results) if (result.metadata) Object.assign(mergedResult.metadata, result.metadata);
187
+ if (Object.keys(mergedResult.filters).length === 0) delete mergedResult.filters;
188
+ if (Object.keys(mergedResult.metadata).length === 0) delete mergedResult.metadata;
189
+ return mergedResult;
190
+ },
191
+ toMiddleware(operation) {
192
+ const middlewares = policies.map((p) => p.toMiddleware(operation));
193
+ return async (request, reply) => {
194
+ for (const middleware of middlewares) {
195
+ await middleware(request, reply);
196
+ if (reply.sent) return;
197
+ }
198
+ };
199
+ }
200
+ };
201
+ }
202
+ /**
203
+ * Combine multiple policies with OR logic
204
+ *
205
+ * At least one policy must allow the operation for it to succeed.
206
+ * If all policies deny, returns the first denial reason.
207
+ *
208
+ * @param policies - Array of policy engines to combine
209
+ * @returns Combined policy engine
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * const policy = anyPolicy(
214
+ * ownerPolicy, // User owns the resource
215
+ * adminPolicy, // OR user is admin
216
+ * publicPolicy, // OR resource is public
217
+ * );
218
+ *
219
+ * // Any one of these policies passing allows the operation
220
+ * ```
221
+ */
222
+ function anyPolicy(...policies) {
223
+ if (policies.length === 0) throw new Error("anyPolicy requires at least one policy");
224
+ if (policies.length === 1) return policies[0];
225
+ return {
226
+ async can(user, operation, context) {
227
+ let firstDenial = null;
228
+ for (const policy of policies) {
229
+ const result = await policy.can(user, operation, context);
230
+ if (result.allowed) return result;
231
+ if (!firstDenial) firstDenial = result;
232
+ }
233
+ return firstDenial;
234
+ },
235
+ toMiddleware(operation) {
236
+ return async (request, reply) => {
237
+ const results = [];
238
+ for (const policy of policies) {
239
+ const result = await policy.can(request.user, operation, {
240
+ document: request.document,
241
+ body: request.body,
242
+ params: request.params,
243
+ query: request.query
244
+ });
245
+ if (result.allowed) {
246
+ request.policyResult = result;
247
+ if (result.filters) request._policyFilters = result.filters;
248
+ if (result.fieldMask) request.fieldMask = result.fieldMask;
249
+ if (result.metadata) request.policyMetadata = result.metadata;
250
+ return;
251
+ }
252
+ results.push(result);
253
+ }
254
+ return reply.code(403).send({
255
+ success: false,
256
+ error: "Access denied",
257
+ message: results[0]?.reason || "You do not have permission to perform this action"
258
+ });
259
+ };
260
+ }
261
+ };
262
+ }
263
+ /**
264
+ * Create a pass-through policy that always allows
265
+ *
266
+ * Useful for testing or for routes that don't need authorization.
267
+ *
268
+ * @example
269
+ * ```typescript
270
+ * const policy = allowAll();
271
+ * const result = await policy.can(user, 'any-operation');
272
+ * // result.allowed === true
273
+ * ```
274
+ */
275
+ function allowAll() {
276
+ return {
277
+ can() {
278
+ return { allowed: true };
279
+ },
280
+ toMiddleware() {
281
+ return async () => {};
282
+ }
283
+ };
284
+ }
285
+ /**
286
+ * Create a policy that always denies
287
+ *
288
+ * Useful for explicitly blocking operations or for testing.
289
+ *
290
+ * @param reason - Denial reason
291
+ *
292
+ * @example
293
+ * ```typescript
294
+ * const policy = denyAll('This resource is deprecated');
295
+ * const result = await policy.can(user, 'any-operation');
296
+ * // result.allowed === false
297
+ * // result.reason === 'This resource is deprecated'
298
+ * ```
299
+ */
300
+ function denyAll(reason = "Operation not allowed") {
301
+ return {
302
+ can() {
303
+ return {
304
+ allowed: false,
305
+ reason
306
+ };
307
+ },
308
+ toMiddleware() {
309
+ return async (request, reply) => {
310
+ return reply.code(403).send({
311
+ success: false,
312
+ error: "Access denied",
313
+ message: reason
314
+ });
315
+ };
316
+ }
317
+ };
318
+ }
319
+
320
+ //#endregion
321
+ export { allowAll, anyPolicy, combinePolicies, createAccessControlPolicy, createPolicyMiddleware, denyAll };
@@ -1,115 +1,43 @@
1
- import { MultiTenantOptions } from './multiTenant.js';
2
- export { default as multiTenantPreset } from './multiTenant.js';
3
- import { f as PresetResult, a as IRequestContext, c as IControllerResponse, P as PaginatedResult, A as AnyRecord, l as ResourceConfig } from '../index-B4t03KQ0.js';
4
- import 'mongoose';
5
- import 'fastify';
6
- import '../types-B99TBmFV.js';
7
-
8
- /**
9
- * Soft Delete Preset
10
- *
11
- * Adds routes for listing deleted items and restoring them.
12
- */
13
-
14
- interface SoftDeleteOptions {
15
- deletedField?: string;
16
- }
17
- declare function softDeletePreset(options?: SoftDeleteOptions): PresetResult;
18
-
19
- /**
20
- * Slug Lookup Preset
21
- *
22
- * Adds a route to get resource by slug.
23
- */
1
+ import "../elevation-DGo5shaX.mjs";
2
+ import { b as IControllerResponse, k as PaginatedResult, x as IRequestContext } from "../interface-e9XfSsUV.mjs";
3
+ import "../types-RLkFVgaw.mjs";
4
+ import { AnyRecord, PresetResult, ResourceConfig } from "../types/index.mjs";
5
+ import multiTenantPreset, { MultiTenantOptions } from "./multiTenant.mjs";
24
6
 
7
+ //#region src/presets/softDelete.d.ts
8
+ declare function softDeletePreset(): PresetResult;
9
+ //#endregion
10
+ //#region src/presets/slugLookup.d.ts
25
11
  interface SlugLookupOptions {
26
- slugField?: string;
12
+ slugField?: string;
27
13
  }
28
14
  declare function slugLookupPreset(options?: SlugLookupOptions): PresetResult;
29
-
30
- /**
31
- * Owned By User Preset
32
- *
33
- * Adds ownership validation for update/delete operations.
34
- *
35
- * BEHAVIOR:
36
- * - On update/remove, sets _ownershipCheck on request
37
- * - BaseController enforces ownership before mutation
38
- * - Users can only modify resources where ownerField matches their ID
39
- *
40
- * BYPASS:
41
- * - Users with bypassRoles (default: ['admin', 'superadmin']) skip check
42
- * - Resources without the ownerField are not checked
43
- *
44
- * @example
45
- * defineResource({
46
- * name: 'post',
47
- * presets: [{ name: 'ownedByUser', ownerField: 'authorId' }],
48
- * });
49
- *
50
- * // User A cannot update/delete User B's posts
51
- * // Admins can modify any post
52
- */
53
-
15
+ //#endregion
16
+ //#region src/presets/ownedByUser.d.ts
54
17
  interface OwnedByUserOptions {
55
- ownerField?: string;
56
- bypassRoles?: string[];
18
+ ownerField?: string;
57
19
  }
58
20
  declare function ownedByUserPreset(options?: OwnedByUserOptions): PresetResult;
59
-
60
- /**
61
- * Tree Preset
62
- *
63
- * Adds routes for hierarchical tree structures.
64
- */
65
-
21
+ //#endregion
22
+ //#region src/presets/tree.d.ts
66
23
  interface TreeOptions {
67
- parentField?: string;
24
+ parentField?: string;
68
25
  }
69
26
  declare function treePreset(options?: TreeOptions): PresetResult;
70
-
71
- /**
72
- * Audited Preset
73
- *
74
- * Adds createdBy/updatedBy tracking to resources.
75
- * Works with the audit plugin for full change tracking.
76
- *
77
- * @example
78
- * defineResource({
79
- * name: 'product',
80
- * presets: ['audited'],
81
- * // Fields createdBy, updatedBy auto-populated from user context
82
- * });
83
- */
84
-
27
+ //#endregion
28
+ //#region src/presets/audited.d.ts
85
29
  interface AuditedPresetOptions {
86
- /** Field name for creator (default: 'createdBy') */
87
- createdByField?: string;
88
- /** Field name for updater (default: 'updatedBy') */
89
- updatedByField?: string;
30
+ /** Field name for creator (default: 'createdBy') */
31
+ createdByField?: string;
32
+ /** Field name for updater (default: 'updatedBy') */
33
+ updatedByField?: string;
90
34
  }
91
35
  /**
92
36
  * Audited preset - adds createdBy/updatedBy tracking
93
37
  */
94
38
  declare function auditedPreset(options?: AuditedPresetOptions): PresetResult;
95
-
96
- /**
97
- * Preset Type Interfaces
98
- *
99
- * TypeScript interfaces that document the controller methods required by each preset.
100
- * These interfaces help with type safety when using presets.
101
- *
102
- * @example Using with custom controllers
103
- * ```typescript
104
- * import { BaseController } from '@classytic/arc';
105
- * import type { ISoftDeleteController } from '@classytic/arc/presets';
106
- *
107
- * class ProductController extends BaseController<Product> implements ISoftDeleteController {
108
- * // TypeScript now ensures you have getDeleted() and restore() methods
109
- * }
110
- * ```
111
- */
112
-
39
+ //#endregion
40
+ //#region src/presets/types.d.ts
113
41
  /**
114
42
  * Soft Delete Preset Interface
115
43
  *
@@ -138,16 +66,16 @@ declare function auditedPreset(options?: AuditedPresetOptions): PresetResult;
138
66
  * ```
139
67
  */
140
68
  interface ISoftDeleteController<TDoc = unknown> {
141
- /**
142
- * Get all soft-deleted items
143
- * Called by: GET /deleted
144
- */
145
- getDeleted(req: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
146
- /**
147
- * Restore a soft-deleted item by ID
148
- * Called by: POST /:id/restore
149
- */
150
- restore(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
69
+ /**
70
+ * Get all soft-deleted items
71
+ * Called by: GET /deleted
72
+ */
73
+ getDeleted(req: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
74
+ /**
75
+ * Restore a soft-deleted item by ID
76
+ * Called by: POST /:id/restore
77
+ */
78
+ restore(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
151
79
  }
152
80
  /**
153
81
  * Slug Lookup Preset Interface
@@ -175,11 +103,11 @@ interface ISoftDeleteController<TDoc = unknown> {
175
103
  * ```
176
104
  */
177
105
  interface ISlugLookupController<TDoc = unknown> {
178
- /**
179
- * Get a resource by its slug
180
- * Called by: GET /slug/:slug
181
- */
182
- getBySlug(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
106
+ /**
107
+ * Get a resource by its slug
108
+ * Called by: GET /slug/:slug
109
+ */
110
+ getBySlug(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
183
111
  }
184
112
  /**
185
113
  * Tree Preset Interface
@@ -209,16 +137,16 @@ interface ISlugLookupController<TDoc = unknown> {
209
137
  * ```
210
138
  */
211
139
  interface ITreeController<TDoc = unknown> {
212
- /**
213
- * Get the full hierarchical tree
214
- * Called by: GET /tree
215
- */
216
- getTree(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
217
- /**
218
- * Get direct children of a parent node
219
- * Called by: GET /:parent/children
220
- */
221
- getChildren(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
140
+ /**
141
+ * Get the full hierarchical tree
142
+ * Called by: GET /tree
143
+ */
144
+ getTree(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
145
+ /**
146
+ * Get direct children of a parent node
147
+ * Called by: GET /:parent/children
148
+ */
149
+ getChildren(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
222
150
  }
223
151
  /**
224
152
  * Owned By User Preset
@@ -301,36 +229,39 @@ type IAuditedPreset = never;
301
229
  * ```
302
230
  */
303
231
  type IPresetController<TDoc = unknown, TPresets extends 'softDelete' | 'slugLookup' | 'tree' | never = never> = TPresets extends 'softDelete' ? ISoftDeleteController<TDoc> : TPresets extends 'slugLookup' ? ISlugLookupController<TDoc> : TPresets extends 'tree' ? ITreeController<TDoc> : unknown;
304
-
232
+ //#endregion
233
+ //#region src/presets/index.d.ts
305
234
  /**
306
235
  * Convenience alias for multiTenantPreset with public list/get routes
307
236
  * Equivalent to: multiTenantPreset({ allowPublic: ['list', 'get'] })
308
237
  */
309
238
  declare const flexibleMultiTenantPreset: (options?: Omit<MultiTenantOptions, "allowPublic">) => PresetResult;
310
-
311
239
  type PresetFactory = (options?: AnyRecord) => PresetResult;
312
240
  /**
313
241
  * Get preset by name with options
314
242
  */
315
243
  declare function getPreset(nameOrConfig: string | {
316
- name: string;
317
- [key: string]: unknown;
244
+ name: string;
245
+ [key: string]: unknown;
318
246
  }): PresetResult;
319
247
  /**
320
248
  * Register a custom preset
321
249
  */
322
- declare function registerPreset(name: string, factory: PresetFactory): void;
250
+ declare function registerPreset(name: string, factory: PresetFactory, options?: {
251
+ override?: boolean;
252
+ }): void;
323
253
  /**
324
254
  * Get all available preset names
325
255
  */
326
256
  declare function getAvailablePresets(): string[];
327
257
  type PresetInput = string | PresetResult | {
328
- name: string;
329
- [key: string]: unknown;
258
+ name: string;
259
+ [key: string]: unknown;
330
260
  };
331
261
  /**
332
- * Apply presets to resource config
262
+ * Apply presets to resource config.
263
+ * Validates preset combinations for conflicts before merging.
333
264
  */
334
265
  declare function applyPresets<TDoc = AnyRecord>(config: ResourceConfig<TDoc>, presets?: PresetInput[]): ResourceConfig<TDoc>;
335
-
336
- export { type AuditedPresetOptions, type IAuditedPreset, type IMultiTenantPreset, type IOwnedByUserPreset, type IPresetController, type ISlugLookupController, type ISoftDeleteController, type ITreeController, MultiTenantOptions, type OwnedByUserOptions, type SlugLookupOptions, type SoftDeleteOptions, type TreeOptions, applyPresets, auditedPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, ownedByUserPreset, registerPreset, slugLookupPreset, softDeletePreset, treePreset };
266
+ //#endregion
267
+ export { type AuditedPresetOptions, type IAuditedPreset, type IMultiTenantPreset, type IOwnedByUserPreset, type IPresetController, type ISlugLookupController, type ISoftDeleteController, type ITreeController, type MultiTenantOptions, type OwnedByUserOptions, type SlugLookupOptions, type TreeOptions, applyPresets, auditedPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, slugLookupPreset, softDeletePreset, treePreset };