@soulbatical/tetra-core 0.1.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 (181) hide show
  1. package/dist/core/SupabaseUserClient.d.ts +14 -0
  2. package/dist/core/SupabaseUserClient.d.ts.map +1 -0
  3. package/dist/core/SupabaseUserClient.js +49 -0
  4. package/dist/core/SupabaseUserClient.js.map +1 -0
  5. package/dist/core/adminDb.d.ts +21 -0
  6. package/dist/core/adminDb.d.ts.map +1 -0
  7. package/dist/core/adminDb.js +43 -0
  8. package/dist/core/adminDb.js.map +1 -0
  9. package/dist/core/publicDb.d.ts +19 -0
  10. package/dist/core/publicDb.d.ts.map +1 -0
  11. package/dist/core/publicDb.js +29 -0
  12. package/dist/core/publicDb.js.map +1 -0
  13. package/dist/core/superadminDb.d.ts +29 -0
  14. package/dist/core/superadminDb.d.ts.map +1 -0
  15. package/dist/core/superadminDb.js +53 -0
  16. package/dist/core/superadminDb.js.map +1 -0
  17. package/dist/core/systemDb.d.ts +34 -0
  18. package/dist/core/systemDb.d.ts.map +1 -0
  19. package/dist/core/systemDb.js +64 -0
  20. package/dist/core/systemDb.js.map +1 -0
  21. package/dist/core/userDb.d.ts +22 -0
  22. package/dist/core/userDb.d.ts.map +1 -0
  23. package/dist/core/userDb.js +36 -0
  24. package/dist/core/userDb.js.map +1 -0
  25. package/dist/core/webhookDb.d.ts +16 -0
  26. package/dist/core/webhookDb.d.ts.map +1 -0
  27. package/dist/core/webhookDb.js +26 -0
  28. package/dist/core/webhookDb.js.map +1 -0
  29. package/dist/frontend/components/FeatureFilters.d.ts +81 -0
  30. package/dist/frontend/components/FeatureFilters.d.ts.map +1 -0
  31. package/dist/frontend/components/FeatureFilters.js +257 -0
  32. package/dist/frontend/components/FeatureFilters.js.map +1 -0
  33. package/dist/frontend/components/FeatureTable.d.ts +96 -0
  34. package/dist/frontend/components/FeatureTable.d.ts.map +1 -0
  35. package/dist/frontend/components/FeatureTable.js +279 -0
  36. package/dist/frontend/components/FeatureTable.js.map +1 -0
  37. package/dist/frontend/hooks/useFeature.d.ts +108 -0
  38. package/dist/frontend/hooks/useFeature.d.ts.map +1 -0
  39. package/dist/frontend/hooks/useFeature.js +354 -0
  40. package/dist/frontend/hooks/useFeature.js.map +1 -0
  41. package/dist/frontend/index.d.ts +17 -0
  42. package/dist/frontend/index.d.ts.map +1 -0
  43. package/dist/frontend/index.js +14 -0
  44. package/dist/frontend/index.js.map +1 -0
  45. package/dist/index.d.ts +78 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +71 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/middleware/authMiddleware.d.ts +137 -0
  50. package/dist/middleware/authMiddleware.d.ts.map +1 -0
  51. package/dist/middleware/authMiddleware.js +292 -0
  52. package/dist/middleware/authMiddleware.js.map +1 -0
  53. package/dist/middleware/autoRegisterValidators.d.ts +31 -0
  54. package/dist/middleware/autoRegisterValidators.d.ts.map +1 -0
  55. package/dist/middleware/autoRegisterValidators.js +125 -0
  56. package/dist/middleware/autoRegisterValidators.js.map +1 -0
  57. package/dist/middleware/validateQueryParams.d.ts +62 -0
  58. package/dist/middleware/validateQueryParams.d.ts.map +1 -0
  59. package/dist/middleware/validateQueryParams.js +321 -0
  60. package/dist/middleware/validateQueryParams.js.map +1 -0
  61. package/dist/shared/controllers/BaseMutationController.d.ts +79 -0
  62. package/dist/shared/controllers/BaseMutationController.d.ts.map +1 -0
  63. package/dist/shared/controllers/BaseMutationController.js +241 -0
  64. package/dist/shared/controllers/BaseMutationController.js.map +1 -0
  65. package/dist/shared/controllers/BaseQueryController.d.ts +72 -0
  66. package/dist/shared/controllers/BaseQueryController.d.ts.map +1 -0
  67. package/dist/shared/controllers/BaseQueryController.js +375 -0
  68. package/dist/shared/controllers/BaseQueryController.js.map +1 -0
  69. package/dist/shared/controllers/FilterConfigController.d.ts +37 -0
  70. package/dist/shared/controllers/FilterConfigController.d.ts.map +1 -0
  71. package/dist/shared/controllers/FilterConfigController.js +94 -0
  72. package/dist/shared/controllers/FilterConfigController.js.map +1 -0
  73. package/dist/shared/controllers/index.d.ts +5 -0
  74. package/dist/shared/controllers/index.d.ts.map +1 -0
  75. package/dist/shared/controllers/index.js +4 -0
  76. package/dist/shared/controllers/index.js.map +1 -0
  77. package/dist/shared/controllers/types.d.ts +57 -0
  78. package/dist/shared/controllers/types.d.ts.map +1 -0
  79. package/dist/shared/controllers/types.js +2 -0
  80. package/dist/shared/controllers/types.js.map +1 -0
  81. package/dist/shared/factories/BatchRouteFactory.d.ts +33 -0
  82. package/dist/shared/factories/BatchRouteFactory.d.ts.map +1 -0
  83. package/dist/shared/factories/BatchRouteFactory.js +54 -0
  84. package/dist/shared/factories/BatchRouteFactory.js.map +1 -0
  85. package/dist/shared/factories/MutationRouteFactory.d.ts +27 -0
  86. package/dist/shared/factories/MutationRouteFactory.d.ts.map +1 -0
  87. package/dist/shared/factories/MutationRouteFactory.js +39 -0
  88. package/dist/shared/factories/MutationRouteFactory.js.map +1 -0
  89. package/dist/shared/factories/PhaseRouteFactory.d.ts +33 -0
  90. package/dist/shared/factories/PhaseRouteFactory.d.ts.map +1 -0
  91. package/dist/shared/factories/PhaseRouteFactory.js +67 -0
  92. package/dist/shared/factories/PhaseRouteFactory.js.map +1 -0
  93. package/dist/shared/factories/QueryRouteFactory.d.ts +37 -0
  94. package/dist/shared/factories/QueryRouteFactory.d.ts.map +1 -0
  95. package/dist/shared/factories/QueryRouteFactory.js +244 -0
  96. package/dist/shared/factories/QueryRouteFactory.js.map +1 -0
  97. package/dist/shared/factories/QueryServiceFactory.d.ts +282 -0
  98. package/dist/shared/factories/QueryServiceFactory.d.ts.map +1 -0
  99. package/dist/shared/factories/QueryServiceFactory.js +277 -0
  100. package/dist/shared/factories/QueryServiceFactory.js.map +1 -0
  101. package/dist/shared/factories/index.d.ts +8 -0
  102. package/dist/shared/factories/index.d.ts.map +1 -0
  103. package/dist/shared/factories/index.js +6 -0
  104. package/dist/shared/factories/index.js.map +1 -0
  105. package/dist/shared/factories/types.d.ts +98 -0
  106. package/dist/shared/factories/types.d.ts.map +1 -0
  107. package/dist/shared/factories/types.js +8 -0
  108. package/dist/shared/factories/types.js.map +1 -0
  109. package/dist/shared/ownership/types.d.ts +84 -0
  110. package/dist/shared/ownership/types.d.ts.map +1 -0
  111. package/dist/shared/ownership/types.js +8 -0
  112. package/dist/shared/ownership/types.js.map +1 -0
  113. package/dist/shared/rfc7807ErrorResponse.d.ts +54 -0
  114. package/dist/shared/rfc7807ErrorResponse.d.ts.map +1 -0
  115. package/dist/shared/rfc7807ErrorResponse.js +98 -0
  116. package/dist/shared/rfc7807ErrorResponse.js.map +1 -0
  117. package/dist/shared/services/BaseCronService.d.ts +171 -0
  118. package/dist/shared/services/BaseCronService.d.ts.map +1 -0
  119. package/dist/shared/services/BaseCronService.js +444 -0
  120. package/dist/shared/services/BaseCronService.js.map +1 -0
  121. package/dist/shared/services/BasePhaseService.d.ts +170 -0
  122. package/dist/shared/services/BasePhaseService.d.ts.map +1 -0
  123. package/dist/shared/services/BasePhaseService.js +409 -0
  124. package/dist/shared/services/BasePhaseService.js.map +1 -0
  125. package/dist/shared/services/CronRegistry.d.ts +67 -0
  126. package/dist/shared/services/CronRegistry.d.ts.map +1 -0
  127. package/dist/shared/services/CronRegistry.js +68 -0
  128. package/dist/shared/services/CronRegistry.js.map +1 -0
  129. package/dist/shared/services/SimpleRPCQueryService.d.ts +111 -0
  130. package/dist/shared/services/SimpleRPCQueryService.d.ts.map +1 -0
  131. package/dist/shared/services/SimpleRPCQueryService.js +265 -0
  132. package/dist/shared/services/SimpleRPCQueryService.js.map +1 -0
  133. package/dist/shared/types/feature-config.d.ts +611 -0
  134. package/dist/shared/types/feature-config.d.ts.map +1 -0
  135. package/dist/shared/types/feature-config.js +85 -0
  136. package/dist/shared/types/feature-config.js.map +1 -0
  137. package/dist/shared/types/query-config.d.ts +41 -0
  138. package/dist/shared/types/query-config.d.ts.map +1 -0
  139. package/dist/shared/types/query-config.js +6 -0
  140. package/dist/shared/types/query-config.js.map +1 -0
  141. package/dist/shared/utils/config-driven-filters.d.ts +215 -0
  142. package/dist/shared/utils/config-driven-filters.d.ts.map +1 -0
  143. package/dist/shared/utils/config-driven-filters.js +451 -0
  144. package/dist/shared/utils/config-driven-filters.js.map +1 -0
  145. package/dist/shared/utils/controllerErrorHandler.d.ts +44 -0
  146. package/dist/shared/utils/controllerErrorHandler.d.ts.map +1 -0
  147. package/dist/shared/utils/controllerErrorHandler.js +126 -0
  148. package/dist/shared/utils/controllerErrorHandler.js.map +1 -0
  149. package/dist/shared/utils/parseInclude.d.ts +14 -0
  150. package/dist/shared/utils/parseInclude.d.ts.map +1 -0
  151. package/dist/shared/utils/parseInclude.js +28 -0
  152. package/dist/shared/utils/parseInclude.js.map +1 -0
  153. package/dist/shared/utils/queryHelpers.d.ts +62 -0
  154. package/dist/shared/utils/queryHelpers.d.ts.map +1 -0
  155. package/dist/shared/utils/queryHelpers.js +61 -0
  156. package/dist/shared/utils/queryHelpers.js.map +1 -0
  157. package/dist/shared/utils/response-mapper.d.ts +42 -0
  158. package/dist/shared/utils/response-mapper.d.ts.map +1 -0
  159. package/dist/shared/utils/response-mapper.js +176 -0
  160. package/dist/shared/utils/response-mapper.js.map +1 -0
  161. package/dist/shared/utils/responseBuilder.d.ts +103 -0
  162. package/dist/shared/utils/responseBuilder.d.ts.map +1 -0
  163. package/dist/shared/utils/responseBuilder.js +131 -0
  164. package/dist/shared/utils/responseBuilder.js.map +1 -0
  165. package/dist/shared/validators/featureConfigValidator.d.ts +23 -0
  166. package/dist/shared/validators/featureConfigValidator.d.ts.map +1 -0
  167. package/dist/shared/validators/featureConfigValidator.js +143 -0
  168. package/dist/shared/validators/featureConfigValidator.js.map +1 -0
  169. package/dist/shared/validators/organizationValidator.d.ts +53 -0
  170. package/dist/shared/validators/organizationValidator.d.ts.map +1 -0
  171. package/dist/shared/validators/organizationValidator.js +69 -0
  172. package/dist/shared/validators/organizationValidator.js.map +1 -0
  173. package/dist/shared/validators/uuidValidator.d.ts +57 -0
  174. package/dist/shared/validators/uuidValidator.d.ts.map +1 -0
  175. package/dist/shared/validators/uuidValidator.js +77 -0
  176. package/dist/shared/validators/uuidValidator.js.map +1 -0
  177. package/dist/utils/logger.d.ts +40 -0
  178. package/dist/utils/logger.d.ts.map +1 -0
  179. package/dist/utils/logger.js +47 -0
  180. package/dist/utils/logger.js.map +1 -0
  181. package/package.json +80 -0
@@ -0,0 +1,14 @@
1
+ import { SupabaseClient } from '@supabase/supabase-js';
2
+ export declare class SupabaseUserClient {
3
+ /**
4
+ * Create a public Supabase client (no authentication)
5
+ * Use this for public endpoints that don't require a user token
6
+ */
7
+ static getPublicClient(): SupabaseClient;
8
+ /**
9
+ * Create a Supabase client with user authentication context
10
+ * This ensures RLS policies use the authenticated user's permissions
11
+ */
12
+ static createForUser(userToken: string): Promise<SupabaseClient>;
13
+ }
14
+ //# sourceMappingURL=SupabaseUserClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SupabaseUserClient.d.ts","sourceRoot":"","sources":["../../src/core/SupabaseUserClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAKrE,qBAAa,kBAAkB;IAC7B;;;OAGG;IACH,MAAM,CAAC,eAAe,IAAI,cAAc;IAgBxC;;;OAGG;WACU,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAyBvE"}
@@ -0,0 +1,49 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+ import { createLogger } from '../utils/logger.js';
3
+ const logger = createLogger('database:client:user');
4
+ export class SupabaseUserClient {
5
+ /**
6
+ * Create a public Supabase client (no authentication)
7
+ * Use this for public endpoints that don't require a user token
8
+ */
9
+ static getPublicClient() {
10
+ const supabaseUrl = process.env.SUPABASE_URL;
11
+ const supabaseAnonKey = process.env.SUPABASE_ANON_KEY;
12
+ if (!supabaseAnonKey) {
13
+ throw new Error('SUPABASE_ANON_KEY not found in environment');
14
+ }
15
+ return createClient(supabaseUrl, supabaseAnonKey, {
16
+ auth: {
17
+ persistSession: false,
18
+ autoRefreshToken: false
19
+ }
20
+ });
21
+ }
22
+ /**
23
+ * Create a Supabase client with user authentication context
24
+ * This ensures RLS policies use the authenticated user's permissions
25
+ */
26
+ static async createForUser(userToken) {
27
+ const supabaseUrl = process.env.SUPABASE_URL;
28
+ const supabaseAnonKey = process.env.SUPABASE_ANON_KEY;
29
+ if (!supabaseAnonKey) {
30
+ throw new Error('SUPABASE_ANON_KEY not found in environment');
31
+ }
32
+ if (!userToken) {
33
+ logger.error('No user token provided for authenticated client');
34
+ throw new Error('User token required for authenticated database access');
35
+ }
36
+ return createClient(supabaseUrl, supabaseAnonKey, {
37
+ global: {
38
+ headers: {
39
+ Authorization: `Bearer ${userToken}`
40
+ }
41
+ },
42
+ auth: {
43
+ persistSession: false,
44
+ autoRefreshToken: false
45
+ }
46
+ });
47
+ }
48
+ }
49
+ //# sourceMappingURL=SupabaseUserClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SupabaseUserClient.js","sourceRoot":"","sources":["../../src/core/SupabaseUserClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkB,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,YAAY,CAAC,sBAAsB,CAAC,CAAC;AAEpD,MAAM,OAAO,kBAAkB;IAC7B;;;OAGG;IACH,MAAM,CAAC,eAAe;QACpB,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAa,CAAC;QAC9C,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAkB,CAAC;QAEvD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,YAAY,CAAC,WAAW,EAAE,eAAe,EAAE;YAChD,IAAI,EAAE;gBACJ,cAAc,EAAE,KAAK;gBACrB,gBAAgB,EAAE,KAAK;aACxB;SACF,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,SAAiB;QAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAa,CAAC;QAC9C,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAkB,CAAC;QAEvD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,YAAY,CAAC,WAAW,EAAE,eAAe,EAAE;YAChD,MAAM,EAAE;gBACN,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,SAAS,EAAE;iBACrC;aACF;YACD,IAAI,EAAE;gBACJ,cAAc,EAAE,KAAK;gBACrB,gBAAgB,EAAE,KAAK;aACxB;SACF,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,21 @@
1
+ import { AuthenticatedRequest } from '../middleware/authMiddleware.js';
2
+ /**
3
+ * Admin database helper - for organization admin operations
4
+ * Enforces admin role and logs access for audit
5
+ * RLS policies will allow access to all organization data
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { adminDB } from '@tetra/core';
10
+ *
11
+ * async getAllOrgOrders(req: AuthenticatedRequest, res: Response) {
12
+ * const supabase = await adminDB(req);
13
+ * const { data, error } = await supabase
14
+ * .from('orders')
15
+ * .select('*');
16
+ * // RLS will filter to organization data only
17
+ * }
18
+ * ```
19
+ */
20
+ export declare function adminDB(req: AuthenticatedRequest): Promise<import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>>;
21
+ //# sourceMappingURL=adminDb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adminDb.d.ts","sourceRoot":"","sources":["../../src/core/adminDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAMvE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,oBAAoB,8FAyBtD"}
@@ -0,0 +1,43 @@
1
+ import { SupabaseUserClient } from './SupabaseUserClient.js';
2
+ import { createLogger } from '../utils/logger.js';
3
+ const logger = createLogger('security:db:admin');
4
+ /**
5
+ * Admin database helper - for organization admin operations
6
+ * Enforces admin role and logs access for audit
7
+ * RLS policies will allow access to all organization data
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { adminDB } from '@tetra/core';
12
+ *
13
+ * async getAllOrgOrders(req: AuthenticatedRequest, res: Response) {
14
+ * const supabase = await adminDB(req);
15
+ * const { data, error } = await supabase
16
+ * .from('orders')
17
+ * .select('*');
18
+ * // RLS will filter to organization data only
19
+ * }
20
+ * ```
21
+ */
22
+ export async function adminDB(req) {
23
+ if (!req.userToken) {
24
+ throw new Error('Unauthorized: No user token provided');
25
+ }
26
+ // Check if user has admin privileges (either org admin or superadmin)
27
+ if (!req.user?.organizationId && !req.user?.is_superadmin) {
28
+ logger.error(`Admin access denied - no organization for user ${req.user?.id}`);
29
+ throw new Error('Forbidden: No active organization');
30
+ }
31
+ // For superadmins, they have admin access to any org
32
+ // For regular admins, RLS will enforce org boundaries
33
+ const isAdmin = req.user?.is_superadmin || req.user?.organizationId;
34
+ if (!isAdmin) {
35
+ logger.error(`Admin access denied for user ${req.user?.id}`);
36
+ throw new Error('Forbidden: Admin access required');
37
+ }
38
+ // Admin calls are expected and common - only log at debug level
39
+ logger.debug(`Admin database access: user=${req.user.id} org=${req.user.organizationId || 'superadmin'}`);
40
+ // Use regular user client - RLS will handle admin permissions
41
+ return SupabaseUserClient.createForUser(req.userToken);
42
+ }
43
+ //# sourceMappingURL=adminDb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adminDb.js","sourceRoot":"","sources":["../../src/core/adminDb.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAyB;IACrD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,sEAAsE;IACtE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,cAAc,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,kDAAkD,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/E,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,qDAAqD;IACrD,sDAAsD;IACtD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,aAAa,IAAI,GAAG,CAAC,IAAI,EAAE,cAAc,CAAC;IAEpE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,gCAAgC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,gEAAgE;IAChE,MAAM,CAAC,KAAK,CAAC,+BAA+B,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,YAAY,EAAE,CAAC,CAAC;IAE1G,8DAA8D;IAC9D,OAAO,kBAAkB,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Public database helper - uses anonymous key for public access
3
+ * Respects RLS policies for public data access
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * import { publicDB } from '../../core/publicDb.js';
8
+ *
9
+ * async getPublicProducts(req: Request, res: Response) {
10
+ * const supabase = publicDB();
11
+ * const { data, error } = await supabase
12
+ * .from('products')
13
+ * .select('*')
14
+ * .eq('active', true);
15
+ * }
16
+ * ```
17
+ */
18
+ export declare function publicDB(): import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>;
19
+ //# sourceMappingURL=publicDb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicDb.d.ts","sourceRoot":"","sources":["../../src/core/publicDb.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,QAAQ,sFAUvB"}
@@ -0,0 +1,29 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+ /**
3
+ * Public database helper - uses anonymous key for public access
4
+ * Respects RLS policies for public data access
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { publicDB } from '../../core/publicDb.js';
9
+ *
10
+ * async getPublicProducts(req: Request, res: Response) {
11
+ * const supabase = publicDB();
12
+ * const { data, error } = await supabase
13
+ * .from('products')
14
+ * .select('*')
15
+ * .eq('active', true);
16
+ * }
17
+ * ```
18
+ */
19
+ export function publicDB() {
20
+ const supabaseUrl = process.env.SUPABASE_URL;
21
+ const supabaseAnonKey = process.env.SUPABASE_ANON_KEY;
22
+ if (!supabaseUrl || !supabaseAnonKey) {
23
+ throw new Error('Missing Supabase configuration for public access');
24
+ }
25
+ // Create client with anon key - respects RLS policies
26
+ return createClient(supabaseUrl, supabaseAnonKey);
27
+ }
28
+ // NO ALIASES - BE EXPLICIT!
29
+ //# sourceMappingURL=publicDb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicDb.js","sourceRoot":"","sources":["../../src/core/publicDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC7C,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAEtD,IAAI,CAAC,WAAW,IAAI,CAAC,eAAe,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IAED,sDAAsD;IACtD,OAAO,YAAY,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;AACpD,CAAC;AAED,4BAA4B"}
@@ -0,0 +1,29 @@
1
+ import { AuthenticatedRequest } from '../middleware/authMiddleware.js';
2
+ /**
3
+ * Superadmin database helper - for cross-organization operations
4
+ * Only for users with is_superadmin = true
5
+ * Uses system database with full audit logging
6
+ *
7
+ * ⚠️ SECURITY WARNING:
8
+ * This provides FULL database access across ALL organizations!
9
+ * Only use for legitimate superadmin operations like:
10
+ * - Cross-organization reporting
11
+ * - System-wide maintenance
12
+ * - Emergency fixes
13
+ * - Data migrations
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { superadminDB } from '../../core/superadminDb.js';
18
+ *
19
+ * async getAllSystemOrders(req: AuthenticatedRequest, res: Response) {
20
+ * const supabase = await superadminDB(req);
21
+ * const { data, error } = await supabase
22
+ * .from('orders')
23
+ * .select('*');
24
+ * // No RLS filtering - returns ALL orders from ALL organizations
25
+ * }
26
+ * ```
27
+ */
28
+ export declare function superadminDB(req: AuthenticatedRequest): Promise<import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>>;
29
+ //# sourceMappingURL=superadminDb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"superadminDb.d.ts","sourceRoot":"","sources":["../../src/core/superadminDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAMvE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,oBAAoB,8FAyB3D"}
@@ -0,0 +1,53 @@
1
+ import { systemDB } from './systemDb.js';
2
+ import { createLogger } from '../utils/logger.js';
3
+ const logger = createLogger('security:db:superadmin');
4
+ /**
5
+ * Superadmin database helper - for cross-organization operations
6
+ * Only for users with is_superadmin = true
7
+ * Uses system database with full audit logging
8
+ *
9
+ * ⚠️ SECURITY WARNING:
10
+ * This provides FULL database access across ALL organizations!
11
+ * Only use for legitimate superadmin operations like:
12
+ * - Cross-organization reporting
13
+ * - System-wide maintenance
14
+ * - Emergency fixes
15
+ * - Data migrations
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { superadminDB } from '../../core/superadminDb.js';
20
+ *
21
+ * async getAllSystemOrders(req: AuthenticatedRequest, res: Response) {
22
+ * const supabase = await superadminDB(req);
23
+ * const { data, error } = await supabase
24
+ * .from('orders')
25
+ * .select('*');
26
+ * // No RLS filtering - returns ALL orders from ALL organizations
27
+ * }
28
+ * ```
29
+ */
30
+ export async function superadminDB(req) {
31
+ if (!req.user) {
32
+ throw new Error('Unauthorized: No authenticated user');
33
+ }
34
+ if (!req.user?.isSuperAdmin) {
35
+ logger.error(`🚫 Superadmin access denied for user ${req.user?.id}`);
36
+ throw new Error('Forbidden: Superadmin access required');
37
+ }
38
+ const context = `superadmin:${req.user.id}:${req.method}:${req.path}`;
39
+ logger.warn(`👑 Superadmin database access: ${context}`);
40
+ // Log additional details for audit trail
41
+ logger.info({
42
+ userId: req.user.id,
43
+ email: req.user.email,
44
+ method: req.method,
45
+ path: req.path,
46
+ timestamp: new Date().toISOString()
47
+ }, `Superadmin operation details:`);
48
+ // Superadmins get system access with full audit trail
49
+ // This bypasses RLS for cross-organizational operations
50
+ return systemDB(context);
51
+ }
52
+ // NO ALIASES - BE EXPLICIT!
53
+ //# sourceMappingURL=superadminDb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"superadminDb.js","sourceRoot":"","sources":["../../src/core/superadminDb.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,YAAY,CAAC,wBAAwB,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAyB;IAC1D,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAK,CAAC,wCAAwC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;IACtE,MAAM,CAAC,IAAI,CAAC,kCAAkC,OAAO,EAAE,CAAC,CAAC;IAEzD,yCAAyC;IACzC,MAAM,CAAC,IAAI,CAAC;QACV,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE;QACnB,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK;QACrB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,EAAE,+BAA+B,CAAC,CAAC;IAEpC,sDAAsD;IACtD,wDAAwD;IACxD,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;AAED,4BAA4B"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * System Database Client — Service Role Key (bypasses RLS)
3
+ *
4
+ * For background tasks, cron jobs, and system operations that need
5
+ * full database access without user context.
6
+ *
7
+ * Projects should register their known contexts via addWhitelistedContexts()
8
+ * to avoid warning logs for legitimate system operations.
9
+ */
10
+ import { SupabaseClient } from '@supabase/supabase-js';
11
+ /**
12
+ * Register additional whitelisted contexts for your project.
13
+ * Call at app startup.
14
+ *
15
+ * @example
16
+ * addWhitelistedContexts([
17
+ * 'order-sync-service',
18
+ * 'email-queue-processor',
19
+ * 'phase-cron-service',
20
+ * ]);
21
+ */
22
+ export declare function addWhitelistedContexts(contexts: string[]): void;
23
+ /**
24
+ * Create a system-level Supabase client (service role key, bypasses RLS).
25
+ *
26
+ * @param context - Descriptive string for audit logging (e.g., 'order-sync-service')
27
+ */
28
+ export declare function systemDB(context: string): SupabaseClient;
29
+ /**
30
+ * Secure system DB — same as systemDB but with stricter logging.
31
+ * Use for operations that modify critical data.
32
+ */
33
+ export declare function secureSystemDB(context: string): SupabaseClient;
34
+ //# sourceMappingURL=systemDb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"systemDb.d.ts","sourceRoot":"","sources":["../../src/core/systemDb.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAgB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAerE;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAI/D;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAexD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAG9D"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * System Database Client — Service Role Key (bypasses RLS)
3
+ *
4
+ * For background tasks, cron jobs, and system operations that need
5
+ * full database access without user context.
6
+ *
7
+ * Projects should register their known contexts via addWhitelistedContexts()
8
+ * to avoid warning logs for legitimate system operations.
9
+ */
10
+ import { createClient } from '@supabase/supabase-js';
11
+ import { createLogger } from '../utils/logger.js';
12
+ const logger = createLogger('security:db:system');
13
+ /**
14
+ * Whitelist of known/approved system database contexts.
15
+ * Projects add their own via addWhitelistedContexts().
16
+ */
17
+ const WHITELISTED_CONTEXTS = new Set([
18
+ // Tetra core
19
+ 'system-migration',
20
+ 'system-health-check',
21
+ ]);
22
+ /**
23
+ * Register additional whitelisted contexts for your project.
24
+ * Call at app startup.
25
+ *
26
+ * @example
27
+ * addWhitelistedContexts([
28
+ * 'order-sync-service',
29
+ * 'email-queue-processor',
30
+ * 'phase-cron-service',
31
+ * ]);
32
+ */
33
+ export function addWhitelistedContexts(contexts) {
34
+ for (const ctx of contexts) {
35
+ WHITELISTED_CONTEXTS.add(ctx);
36
+ }
37
+ }
38
+ /**
39
+ * Create a system-level Supabase client (service role key, bypasses RLS).
40
+ *
41
+ * @param context - Descriptive string for audit logging (e.g., 'order-sync-service')
42
+ */
43
+ export function systemDB(context) {
44
+ const url = process.env.SUPABASE_URL;
45
+ const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
46
+ if (!url || !serviceKey) {
47
+ throw new Error('Missing SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY environment variables');
48
+ }
49
+ if (!WHITELISTED_CONTEXTS.has(context)) {
50
+ logger.warn({ context }, 'systemDB called with unknown context — consider whitelisting');
51
+ }
52
+ return createClient(url, serviceKey, {
53
+ auth: { persistSession: false }
54
+ });
55
+ }
56
+ /**
57
+ * Secure system DB — same as systemDB but with stricter logging.
58
+ * Use for operations that modify critical data.
59
+ */
60
+ export function secureSystemDB(context) {
61
+ logger.info({ context }, 'secureSystemDB access');
62
+ return systemDB(context);
63
+ }
64
+ //# sourceMappingURL=systemDb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"systemDb.js","sourceRoot":"","sources":["../../src/core/systemDb.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAkB,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,YAAY,CAAC,oBAAoB,CAAC,CAAC;AAElD;;;GAGG;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAS;IAC3C,aAAa;IACb,kBAAkB;IAClB,qBAAqB;CACtB,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAAkB;IACvD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACrC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IAEzD,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,8DAA8D,CAAC,CAAC;IAC3F,CAAC;IAED,OAAO,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE;QACnC,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE;KAChC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,uBAAuB,CAAC,CAAC;IAClD,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { AuthenticatedRequest } from '../middleware/authMiddleware.js';
2
+ /**
3
+ * User database helper - for accessing user's own data
4
+ * Enforces JWT authentication and user context
5
+ * RLS policies will filter to user's own records
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { userDB } from '@tetra/core';
10
+ *
11
+ * async getUserProfile(req: AuthenticatedRequest, res: Response) {
12
+ * const supabase = await userDB(req);
13
+ * const { data, error } = await supabase
14
+ * .from('users_public')
15
+ * .select('*')
16
+ * .eq('id', req.user.id)
17
+ * .single();
18
+ * }
19
+ * ```
20
+ */
21
+ export declare function userDB(req: AuthenticatedRequest): Promise<import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>>;
22
+ //# sourceMappingURL=userDb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userDb.d.ts","sourceRoot":"","sources":["../../src/core/userDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAMvE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,MAAM,CAAC,GAAG,EAAE,oBAAoB,8FAerD"}
@@ -0,0 +1,36 @@
1
+ import { SupabaseUserClient } from './SupabaseUserClient.js';
2
+ import { createLogger } from '../utils/logger.js';
3
+ const logger = createLogger('security:db:user');
4
+ /**
5
+ * User database helper - for accessing user's own data
6
+ * Enforces JWT authentication and user context
7
+ * RLS policies will filter to user's own records
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { userDB } from '@tetra/core';
12
+ *
13
+ * async getUserProfile(req: AuthenticatedRequest, res: Response) {
14
+ * const supabase = await userDB(req);
15
+ * const { data, error } = await supabase
16
+ * .from('users_public')
17
+ * .select('*')
18
+ * .eq('id', req.user.id)
19
+ * .single();
20
+ * }
21
+ * ```
22
+ */
23
+ export async function userDB(req) {
24
+ if (!req.userToken) {
25
+ logger.error('No user token in request!');
26
+ throw new Error('Unauthorized: No user token provided');
27
+ }
28
+ if (!req.user?.id) {
29
+ logger.error('No user context in request!');
30
+ throw new Error('Unauthorized: No user context');
31
+ }
32
+ logger.debug(`User database access: user=${req.user.id} org=${req.user.organizationId || 'none'}`);
33
+ // Use user client - RLS will filter to user's own data
34
+ return SupabaseUserClient.createForUser(req.userToken);
35
+ }
36
+ //# sourceMappingURL=userDb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userDb.js","sourceRoot":"","sources":["../../src/core/userDb.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,YAAY,CAAC,kBAAkB,CAAC,CAAC;AAEhD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAyB;IACpD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC;QAClB,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,8BAA8B,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,MAAM,EAAE,CAAC,CAAC;IAEnG,uDAAuD;IACvD,OAAO,kBAAkB,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Webhook database helper - for external webhook endpoints
3
+ * Uses Service Role Key to bypass RLS for webhook operations
4
+ * Automatically prefixes context with "webhook:" for audit trail
5
+ *
6
+ * @param webhookSource - Name of the webhook source (e.g., 'buildship', 'stripe', 'mollie')
7
+ * @returns Supabase client with full system access
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // In a webhook controller
12
+ * const supabase = webhookDB('stripe');
13
+ * ```
14
+ */
15
+ export declare function webhookDB(webhookSource: string): import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>;
16
+ //# sourceMappingURL=webhookDb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhookDb.d.ts","sourceRoot":"","sources":["../../src/core/webhookDb.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,MAAM,qFAQ9C"}
@@ -0,0 +1,26 @@
1
+ import { systemDB } from './systemDb.js';
2
+ import { createLogger } from '../utils/logger.js';
3
+ const logger = createLogger('security:db:webhook');
4
+ /**
5
+ * Webhook database helper - for external webhook endpoints
6
+ * Uses Service Role Key to bypass RLS for webhook operations
7
+ * Automatically prefixes context with "webhook:" for audit trail
8
+ *
9
+ * @param webhookSource - Name of the webhook source (e.g., 'buildship', 'stripe', 'mollie')
10
+ * @returns Supabase client with full system access
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // In a webhook controller
15
+ * const supabase = webhookDB('stripe');
16
+ * ```
17
+ */
18
+ export function webhookDB(webhookSource) {
19
+ const context = `webhook:${webhookSource}`;
20
+ // Log webhook access for security auditing
21
+ logger.info(`🔗 Webhook database access: ${context}`);
22
+ // Use systemDB under the hood with webhook-specific context
23
+ return systemDB(context);
24
+ }
25
+ // NO ALIASES - BE EXPLICIT!
26
+ //# sourceMappingURL=webhookDb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhookDb.js","sourceRoot":"","sources":["../../src/core/webhookDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,SAAS,CAAC,aAAqB;IAC7C,MAAM,OAAO,GAAG,WAAW,aAAa,EAAE,CAAC;IAE3C,2CAA2C;IAC3C,MAAM,CAAC,IAAI,CAAC,+BAA+B,OAAO,EAAE,CAAC,CAAC;IAEtD,4DAA4D;IAC5D,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;AAED,4BAA4B"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * FeatureFilters — Config-driven filter bar component
3
+ *
4
+ * Replaces ALL per-feature filter implementations with a single generic component
5
+ * driven by FeatureConfig.filters[].
6
+ *
7
+ * Before (50+ lines boilerplate PER feature):
8
+ * <Select value={status} onChange={setStatus} options={statusOptions} />
9
+ * <Input value={search} onChange={setSearch} placeholder="Search..." />
10
+ * <DatePicker value={dateRange} onChange={setDateRange} />
11
+ *
12
+ * After (ZERO boilerplate):
13
+ * <FeatureFilters config={ordersConfig} feature={feature} />
14
+ *
15
+ * Filter type → UI mapping:
16
+ * - search → SearchInput (debounced text input)
17
+ * - enum → Select dropdown
18
+ * - column → Select dropdown (same as enum, column-based)
19
+ * - boolean → Toggle / Switch
20
+ * - multiselect → Multi-select with checkboxes
21
+ * - daterange → Date range picker (from/to)
22
+ * - time → Select dropdown (preset time periods)
23
+ * - nullable → Select dropdown (all/with/without)
24
+ * - related → Select dropdown (all/with/without)
25
+ * - numeric → Number range inputs (min/max)
26
+ * - array → Multi-select (same UI as multiselect)
27
+ *
28
+ * @module @tetra/core/frontend
29
+ * Created: February 20, 2026
30
+ */
31
+ import React from 'react';
32
+ import type { FeatureConfig, FilterConfig } from '../../shared/types/feature-config.js';
33
+ import type { UseFeatureResult } from '../hooks/useFeature.js';
34
+ export interface FeatureFiltersProps<TItem = Record<string, unknown>> {
35
+ /** Feature configuration with filters[] */
36
+ config: FeatureConfig<TItem>;
37
+ /** Result from useFeature() hook */
38
+ feature: UseFeatureResult<TItem>;
39
+ /** CSS class for the filter bar wrapper */
40
+ className?: string;
41
+ /** Layout: horizontal bar or vertical stack (default: 'horizontal') */
42
+ layout?: 'horizontal' | 'vertical';
43
+ /** Show reset button (default: true) */
44
+ showReset?: boolean;
45
+ /** Reset button label (default: 'Reset') */
46
+ resetLabel?: string;
47
+ /** Show active filter count badge (default: true) */
48
+ showActiveCount?: boolean;
49
+ /** Collapse filters behind a "More filters" button (default: auto based on filter count) */
50
+ collapsible?: boolean;
51
+ /** Max visible filters before collapsing (default: 4) */
52
+ maxVisible?: number;
53
+ /** "More filters" button label (default: 'More filters') */
54
+ moreLabel?: string;
55
+ /** Show filter count badges from feature.counts (default: true) */
56
+ showCounts?: boolean;
57
+ /** Custom filter renderers (keyed by filter name) */
58
+ filterRenderers?: Record<string, (filter: FilterConfig, value: string | string[] | undefined, onChange: (value: string | string[] | undefined) => void, counts?: Record<string, number>) => React.ReactNode>;
59
+ }
60
+ /**
61
+ * FeatureFilters — Config-driven filter bar
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * import { ordersConfig } from '@/config/features/orders.config';
66
+ * import { useFeature, FeatureFilters, FeatureTable } from '@tetra/core/frontend';
67
+ *
68
+ * function OrdersPage() {
69
+ * const feature = useFeature(ordersConfig, supabase, { organizationId });
70
+ *
71
+ * return (
72
+ * <div>
73
+ * <FeatureFilters config={ordersConfig} feature={feature} />
74
+ * <FeatureTable config={ordersConfig} feature={feature} />
75
+ * </div>
76
+ * );
77
+ * }
78
+ * ```
79
+ */
80
+ export declare function FeatureFilters<TItem = Record<string, unknown>>({ config, feature, className, layout, showReset, resetLabel, showActiveCount, collapsible, maxVisible, moreLabel, showCounts, filterRenderers, }: FeatureFiltersProps<TItem>): import("react/jsx-runtime").JSX.Element;
81
+ //# sourceMappingURL=FeatureFilters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeatureFilters.d.ts","sourceRoot":"","sources":["../../../src/frontend/components/FeatureFilters.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAyC,MAAM,OAAO,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAkB,MAAM,sCAAsC,CAAC;AACxG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAW/D,MAAM,WAAW,mBAAmB,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,2CAA2C;IAC3C,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAE7B,oCAAoC;IACpC,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEjC,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,uEAAuE;IACvE,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IAEnC,wCAAwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,qDAAqD;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,4FAA4F;IAC5F,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,mEAAmE;IACnE,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAC/B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAK,IAAI,EACxD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC5B,KAAK,CAAC,SAAS,CAAC,CAAC;CACvB;AAoaD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC9D,MAAM,EACN,OAAO,EACP,SAAS,EACT,MAAqB,EACrB,SAAgB,EAChB,UAAoB,EACpB,eAAsB,EACtB,WAAW,EACX,UAAc,EACd,SAA0B,EAC1B,UAAiB,EACjB,eAAe,GAChB,EAAE,mBAAmB,CAAC,KAAK,CAAC,2CAuI5B"}