@soulbatical/tetra-core 0.10.4 → 0.11.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 (271) hide show
  1. package/README.md +78 -38
  2. package/dist/core/createApp.d.ts +1 -1
  3. package/dist/core/createApp.d.ts.map +1 -1
  4. package/dist/core/createApp.js +77 -2
  5. package/dist/core/createApp.js.map +1 -1
  6. package/dist/core/dualWriteProxy.d.ts +7 -2
  7. package/dist/core/dualWriteProxy.d.ts.map +1 -1
  8. package/dist/core/dualWriteProxy.js +16 -5
  9. package/dist/core/dualWriteProxy.js.map +1 -1
  10. package/dist/core/routeContext.d.ts +24 -0
  11. package/dist/core/routeContext.d.ts.map +1 -1
  12. package/dist/core/routeContext.js +31 -4
  13. package/dist/core/routeContext.js.map +1 -1
  14. package/dist/core/systemDb.d.ts +2 -2
  15. package/dist/core/systemDb.js +2 -2
  16. package/dist/generators/rls-checker.d.ts +1 -1
  17. package/dist/generators/rls-checker.js +1 -1
  18. package/dist/generators/rls-exec-sql.d.ts +1 -1
  19. package/dist/generators/rls-exec-sql.js +1 -1
  20. package/dist/generators/rpc/index.d.ts +1 -1
  21. package/dist/generators/rpc/index.js +1 -1
  22. package/dist/index.d.ts +3 -31
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +4 -32
  25. package/dist/index.js.map +1 -1
  26. package/dist/middleware/securityMiddleware.d.ts +1 -1
  27. package/dist/middleware/securityMiddleware.d.ts.map +1 -1
  28. package/dist/middleware/validateBody.d.ts.map +1 -1
  29. package/dist/middleware/validateBody.js +51 -8
  30. package/dist/middleware/validateBody.js.map +1 -1
  31. package/dist/shared/rfc7807ErrorResponse.d.ts +7 -0
  32. package/dist/shared/rfc7807ErrorResponse.d.ts.map +1 -1
  33. package/dist/shared/rfc7807ErrorResponse.js +19 -5
  34. package/dist/shared/rfc7807ErrorResponse.js.map +1 -1
  35. package/dist/utils/logger.d.ts.map +1 -1
  36. package/dist/utils/logger.js +16 -1
  37. package/dist/utils/logger.js.map +1 -1
  38. package/package.json +33 -77
  39. package/dist/affiliate.d.ts +0 -11
  40. package/dist/affiliate.d.ts.map +0 -1
  41. package/dist/affiliate.js +0 -10
  42. package/dist/affiliate.js.map +0 -1
  43. package/dist/billing.d.ts +0 -8
  44. package/dist/billing.d.ts.map +0 -1
  45. package/dist/billing.js +0 -7
  46. package/dist/billing.js.map +0 -1
  47. package/dist/email.d.ts +0 -9
  48. package/dist/email.d.ts.map +0 -1
  49. package/dist/email.js +0 -8
  50. package/dist/email.js.map +0 -1
  51. package/dist/generators/rls-exec-sql.sql +0 -57
  52. package/dist/generators.d.ts +0 -15
  53. package/dist/generators.d.ts.map +0 -1
  54. package/dist/generators.js +0 -12
  55. package/dist/generators.js.map +0 -1
  56. package/dist/mcp.d.ts +0 -8
  57. package/dist/mcp.d.ts.map +0 -1
  58. package/dist/mcp.js +0 -7
  59. package/dist/mcp.js.map +0 -1
  60. package/dist/planner.d.ts +0 -8
  61. package/dist/planner.d.ts.map +0 -1
  62. package/dist/planner.js +0 -7
  63. package/dist/planner.js.map +0 -1
  64. package/dist/shared/affiliate/AffiliateAttributionService.d.ts +0 -47
  65. package/dist/shared/affiliate/AffiliateAttributionService.d.ts.map +0 -1
  66. package/dist/shared/affiliate/AffiliateAttributionService.js +0 -308
  67. package/dist/shared/affiliate/AffiliateAttributionService.js.map +0 -1
  68. package/dist/shared/affiliate/AffiliateClickService.d.ts +0 -35
  69. package/dist/shared/affiliate/AffiliateClickService.d.ts.map +0 -1
  70. package/dist/shared/affiliate/AffiliateClickService.js +0 -87
  71. package/dist/shared/affiliate/AffiliateClickService.js.map +0 -1
  72. package/dist/shared/affiliate/affiliateFeatureConfig.d.ts +0 -11
  73. package/dist/shared/affiliate/affiliateFeatureConfig.d.ts.map +0 -1
  74. package/dist/shared/affiliate/affiliateFeatureConfig.js +0 -242
  75. package/dist/shared/affiliate/affiliateFeatureConfig.js.map +0 -1
  76. package/dist/shared/affiliate/index.d.ts +0 -11
  77. package/dist/shared/affiliate/index.d.ts.map +0 -1
  78. package/dist/shared/affiliate/index.js +0 -13
  79. package/dist/shared/affiliate/index.js.map +0 -1
  80. package/dist/shared/affiliate/routes.d.ts +0 -87
  81. package/dist/shared/affiliate/routes.d.ts.map +0 -1
  82. package/dist/shared/affiliate/routes.js +0 -404
  83. package/dist/shared/affiliate/routes.js.map +0 -1
  84. package/dist/shared/affiliate/types.d.ts +0 -170
  85. package/dist/shared/affiliate/types.d.ts.map +0 -1
  86. package/dist/shared/affiliate/types.js +0 -11
  87. package/dist/shared/affiliate/types.js.map +0 -1
  88. package/dist/shared/billing/BillingService.d.ts +0 -56
  89. package/dist/shared/billing/BillingService.d.ts.map +0 -1
  90. package/dist/shared/billing/BillingService.js +0 -588
  91. package/dist/shared/billing/BillingService.js.map +0 -1
  92. package/dist/shared/billing/SeatBillingService.d.ts +0 -106
  93. package/dist/shared/billing/SeatBillingService.d.ts.map +0 -1
  94. package/dist/shared/billing/SeatBillingService.js +0 -292
  95. package/dist/shared/billing/SeatBillingService.js.map +0 -1
  96. package/dist/shared/billing/index.d.ts +0 -30
  97. package/dist/shared/billing/index.d.ts.map +0 -1
  98. package/dist/shared/billing/index.js +0 -27
  99. package/dist/shared/billing/index.js.map +0 -1
  100. package/dist/shared/billing/routes.d.ts +0 -45
  101. package/dist/shared/billing/routes.d.ts.map +0 -1
  102. package/dist/shared/billing/routes.js +0 -184
  103. package/dist/shared/billing/routes.js.map +0 -1
  104. package/dist/shared/billing/seat-pricing.d.ts +0 -53
  105. package/dist/shared/billing/seat-pricing.d.ts.map +0 -1
  106. package/dist/shared/billing/seat-pricing.js +0 -81
  107. package/dist/shared/billing/seat-pricing.js.map +0 -1
  108. package/dist/shared/billing/types.d.ts +0 -109
  109. package/dist/shared/billing/types.d.ts.map +0 -1
  110. package/dist/shared/billing/types.js +0 -8
  111. package/dist/shared/billing/types.js.map +0 -1
  112. package/dist/shared/email/EmailService.d.ts +0 -64
  113. package/dist/shared/email/EmailService.d.ts.map +0 -1
  114. package/dist/shared/email/EmailService.js +0 -300
  115. package/dist/shared/email/EmailService.js.map +0 -1
  116. package/dist/shared/email/adminRoutes.d.ts +0 -30
  117. package/dist/shared/email/adminRoutes.d.ts.map +0 -1
  118. package/dist/shared/email/adminRoutes.js +0 -227
  119. package/dist/shared/email/adminRoutes.js.map +0 -1
  120. package/dist/shared/email/gmail.d.ts +0 -208
  121. package/dist/shared/email/gmail.d.ts.map +0 -1
  122. package/dist/shared/email/gmail.js +0 -626
  123. package/dist/shared/email/gmail.js.map +0 -1
  124. package/dist/shared/email/index.d.ts +0 -15
  125. package/dist/shared/email/index.d.ts.map +0 -1
  126. package/dist/shared/email/index.js +0 -18
  127. package/dist/shared/email/index.js.map +0 -1
  128. package/dist/shared/email/mailgun.d.ts +0 -18
  129. package/dist/shared/email/mailgun.d.ts.map +0 -1
  130. package/dist/shared/email/mailgun.js +0 -76
  131. package/dist/shared/email/mailgun.js.map +0 -1
  132. package/dist/shared/email/sanitize.d.ts +0 -25
  133. package/dist/shared/email/sanitize.d.ts.map +0 -1
  134. package/dist/shared/email/sanitize.js +0 -39
  135. package/dist/shared/email/sanitize.js.map +0 -1
  136. package/dist/shared/email/smtp.d.ts +0 -20
  137. package/dist/shared/email/smtp.d.ts.map +0 -1
  138. package/dist/shared/email/smtp.js +0 -53
  139. package/dist/shared/email/smtp.js.map +0 -1
  140. package/dist/shared/email/types.d.ts +0 -113
  141. package/dist/shared/email/types.d.ts.map +0 -1
  142. package/dist/shared/email/types.js +0 -7
  143. package/dist/shared/email/types.js.map +0 -1
  144. package/dist/shared/email/webhookRoutes.d.ts +0 -29
  145. package/dist/shared/email/webhookRoutes.d.ts.map +0 -1
  146. package/dist/shared/email/webhookRoutes.js +0 -125
  147. package/dist/shared/email/webhookRoutes.js.map +0 -1
  148. package/dist/shared/mcp/index.d.ts +0 -51
  149. package/dist/shared/mcp/index.d.ts.map +0 -1
  150. package/dist/shared/mcp/index.js +0 -51
  151. package/dist/shared/mcp/index.js.map +0 -1
  152. package/dist/shared/mcp/mcp-auth-routes.d.ts +0 -26
  153. package/dist/shared/mcp/mcp-auth-routes.d.ts.map +0 -1
  154. package/dist/shared/mcp/mcp-auth-routes.js +0 -141
  155. package/dist/shared/mcp/mcp-auth-routes.js.map +0 -1
  156. package/dist/shared/mcp/mcp-db.d.ts +0 -99
  157. package/dist/shared/mcp/mcp-db.d.ts.map +0 -1
  158. package/dist/shared/mcp/mcp-db.js +0 -106
  159. package/dist/shared/mcp/mcp-db.js.map +0 -1
  160. package/dist/shared/mcp/mcp-routes.d.ts +0 -29
  161. package/dist/shared/mcp/mcp-routes.d.ts.map +0 -1
  162. package/dist/shared/mcp/mcp-routes.js +0 -171
  163. package/dist/shared/mcp/mcp-routes.js.map +0 -1
  164. package/dist/shared/mcp/mcp-tokens-routes.d.ts +0 -35
  165. package/dist/shared/mcp/mcp-tokens-routes.d.ts.map +0 -1
  166. package/dist/shared/mcp/mcp-tokens-routes.js +0 -94
  167. package/dist/shared/mcp/mcp-tokens-routes.js.map +0 -1
  168. package/dist/shared/mcp/mcp-usage-routes.d.ts +0 -17
  169. package/dist/shared/mcp/mcp-usage-routes.d.ts.map +0 -1
  170. package/dist/shared/mcp/mcp-usage-routes.js +0 -81
  171. package/dist/shared/mcp/mcp-usage-routes.js.map +0 -1
  172. package/dist/shared/mcp/tenant-context.d.ts +0 -59
  173. package/dist/shared/mcp/tenant-context.d.ts.map +0 -1
  174. package/dist/shared/mcp/tenant-context.js +0 -136
  175. package/dist/shared/mcp/tenant-context.js.map +0 -1
  176. package/dist/shared/mcp/types.d.ts +0 -74
  177. package/dist/shared/mcp/types.d.ts.map +0 -1
  178. package/dist/shared/mcp/types.js +0 -7
  179. package/dist/shared/mcp/types.js.map +0 -1
  180. package/dist/shared/planner/GoogleCalendarService.d.ts +0 -137
  181. package/dist/shared/planner/GoogleCalendarService.d.ts.map +0 -1
  182. package/dist/shared/planner/GoogleCalendarService.js +0 -525
  183. package/dist/shared/planner/GoogleCalendarService.js.map +0 -1
  184. package/dist/shared/planner/PlannerService.d.ts +0 -264
  185. package/dist/shared/planner/PlannerService.d.ts.map +0 -1
  186. package/dist/shared/planner/PlannerService.js +0 -1393
  187. package/dist/shared/planner/PlannerService.js.map +0 -1
  188. package/dist/shared/planner/index.d.ts +0 -37
  189. package/dist/shared/planner/index.d.ts.map +0 -1
  190. package/dist/shared/planner/index.js +0 -35
  191. package/dist/shared/planner/index.js.map +0 -1
  192. package/dist/shared/planner/intervals.d.ts +0 -60
  193. package/dist/shared/planner/intervals.d.ts.map +0 -1
  194. package/dist/shared/planner/intervals.js +0 -141
  195. package/dist/shared/planner/intervals.js.map +0 -1
  196. package/dist/shared/planner/routes.d.ts +0 -69
  197. package/dist/shared/planner/routes.d.ts.map +0 -1
  198. package/dist/shared/planner/routes.js +0 -770
  199. package/dist/shared/planner/routes.js.map +0 -1
  200. package/dist/shared/planner/types.d.ts +0 -328
  201. package/dist/shared/planner/types.d.ts.map +0 -1
  202. package/dist/shared/planner/types.js +0 -9
  203. package/dist/shared/planner/types.js.map +0 -1
  204. package/dist/shared/storage/ImageProcessingService.d.ts +0 -32
  205. package/dist/shared/storage/ImageProcessingService.d.ts.map +0 -1
  206. package/dist/shared/storage/ImageProcessingService.js +0 -127
  207. package/dist/shared/storage/ImageProcessingService.js.map +0 -1
  208. package/dist/shared/storage/StorageProxyService.d.ts +0 -47
  209. package/dist/shared/storage/StorageProxyService.d.ts.map +0 -1
  210. package/dist/shared/storage/StorageProxyService.js +0 -196
  211. package/dist/shared/storage/StorageProxyService.js.map +0 -1
  212. package/dist/shared/storage/StorageUploadService.d.ts +0 -126
  213. package/dist/shared/storage/StorageUploadService.d.ts.map +0 -1
  214. package/dist/shared/storage/StorageUploadService.js +0 -206
  215. package/dist/shared/storage/StorageUploadService.js.map +0 -1
  216. package/dist/shared/storage/creative-urls.d.ts +0 -14
  217. package/dist/shared/storage/creative-urls.d.ts.map +0 -1
  218. package/dist/shared/storage/creative-urls.js +0 -30
  219. package/dist/shared/storage/creative-urls.js.map +0 -1
  220. package/dist/shared/storage/index.d.ts +0 -28
  221. package/dist/shared/storage/index.d.ts.map +0 -1
  222. package/dist/shared/storage/index.js +0 -27
  223. package/dist/shared/storage/index.js.map +0 -1
  224. package/dist/shared/storage/routes.d.ts +0 -42
  225. package/dist/shared/storage/routes.d.ts.map +0 -1
  226. package/dist/shared/storage/routes.js +0 -160
  227. package/dist/shared/storage/routes.js.map +0 -1
  228. package/dist/shared/storage/types.d.ts +0 -53
  229. package/dist/shared/storage/types.d.ts.map +0 -1
  230. package/dist/shared/storage/types.js +0 -2
  231. package/dist/shared/storage/types.js.map +0 -1
  232. package/dist/shared/telegram/index.d.ts +0 -4
  233. package/dist/shared/telegram/index.d.ts.map +0 -1
  234. package/dist/shared/telegram/index.js +0 -3
  235. package/dist/shared/telegram/index.js.map +0 -1
  236. package/dist/shared/telegram/routes.d.ts +0 -43
  237. package/dist/shared/telegram/routes.d.ts.map +0 -1
  238. package/dist/shared/telegram/routes.js +0 -868
  239. package/dist/shared/telegram/routes.js.map +0 -1
  240. package/dist/shared/telegram/types.d.ts +0 -168
  241. package/dist/shared/telegram/types.d.ts.map +0 -1
  242. package/dist/shared/telegram/types.js +0 -7
  243. package/dist/shared/telegram/types.js.map +0 -1
  244. package/dist/shared/telegram/utils.d.ts +0 -44
  245. package/dist/shared/telegram/utils.d.ts.map +0 -1
  246. package/dist/shared/telegram/utils.js +0 -121
  247. package/dist/shared/telegram/utils.js.map +0 -1
  248. package/dist/storage.d.ts +0 -9
  249. package/dist/storage.d.ts.map +0 -1
  250. package/dist/storage.js +0 -8
  251. package/dist/storage.js.map +0 -1
  252. package/dist/telemetry.d.ts +0 -9
  253. package/dist/telemetry.d.ts.map +0 -1
  254. package/dist/telemetry.js +0 -8
  255. package/dist/telemetry.js.map +0 -1
  256. package/scripts/postinstall.js +0 -79
  257. package/src/shared/affiliate/migrations/001_create_affiliates.sql +0 -49
  258. package/src/shared/affiliate/migrations/002_create_affiliate_commissions.sql +0 -31
  259. package/src/shared/affiliate/migrations/003_create_affiliate_clicks.sql +0 -26
  260. package/src/shared/affiliate/migrations/004_create_affiliate_payments.sql +0 -34
  261. package/src/shared/affiliate/migrations/005_create_affiliate_tier_history.sql +0 -19
  262. package/src/shared/affiliate/migrations/006_create_affiliate_rpc_functions.sql +0 -209
  263. package/src/shared/affiliate/migrations/007_create_affiliate_rls_policies.sql +0 -123
  264. package/src/shared/billing/migrations/00000000000001_billing.sql +0 -114
  265. package/src/shared/email/migrations/000_create_email_logs.sql +0 -27
  266. package/src/shared/email/migrations/001_create_email_templates.sql +0 -27
  267. package/src/shared/email/migrations/002_add_rls_baseline_policies.sql +0 -37
  268. package/src/shared/email/migrations/003_create_gmail_accounts.sql +0 -82
  269. package/src/shared/email/migrations/004_add_email_logs_tracking_columns.sql +0 -15
  270. package/src/shared/mcp/migrations/001_mcp_api_tokens.sql +0 -21
  271. package/src/shared/mcp/migrations/002_mcp_audit_log.sql +0 -16
@@ -1,196 +0,0 @@
1
- /**
2
- * Storage Proxy Service — streams files from Supabase through the API
3
- *
4
- * Sets proper CORS/CORP/Cache headers so images work cross-origin.
5
- * Never exposes Supabase URLs to the client.
6
- *
7
- * Supports on-the-fly image transforms via query parameters:
8
- * ?w=400 — resize to max width 400px (aspect ratio preserved)
9
- * ?h=300 — resize to max height 300px
10
- * ?q=80 — quality 1-100 (default: 80)
11
- * ?f=webp — output format: webp, jpeg, png (default: auto from original)
12
- *
13
- * Transforms require sharp as optional peer dependency.
14
- * Without sharp, images are served at original size.
15
- */
16
- import { createLogger } from '../../utils/logger.js';
17
- const logger = createLogger('storage:proxy');
18
- // Simple LRU-ish in-memory cache for transformed images
19
- const transformCache = new Map();
20
- const MAX_CACHE_SIZE = 200;
21
- const CACHE_TTL_MS = 30 * 60 * 1000; // 30 minutes
22
- function getCached(key) {
23
- const entry = transformCache.get(key);
24
- if (!entry)
25
- return null;
26
- if (Date.now() - entry.timestamp > CACHE_TTL_MS) {
27
- transformCache.delete(key);
28
- return null;
29
- }
30
- return entry;
31
- }
32
- function setCache(key, buffer, contentType) {
33
- // Evict oldest if at capacity
34
- if (transformCache.size >= MAX_CACHE_SIZE) {
35
- const oldest = transformCache.keys().next().value;
36
- if (oldest)
37
- transformCache.delete(oldest);
38
- }
39
- transformCache.set(key, { buffer, contentType, timestamp: Date.now() });
40
- }
41
- export class StorageProxyService {
42
- supabaseUrl;
43
- cacheMaxAge;
44
- constructor(config) {
45
- this.supabaseUrl = config.supabaseUrl || process.env.SUPABASE_URL || '';
46
- this.cacheMaxAge = config.cacheMaxAge ?? 3600;
47
- }
48
- /**
49
- * Parse transform options from query parameters.
50
- */
51
- static parseTransformOptions(query) {
52
- const w = query.w ? parseInt(query.w, 10) : undefined;
53
- const h = query.h ? parseInt(query.h, 10) : undefined;
54
- const q = query.q ? parseInt(query.q, 10) : undefined;
55
- const f = query.f;
56
- if (!w && !h && !q && !f)
57
- return null;
58
- return {
59
- width: w && w > 0 && w <= 4000 ? w : undefined,
60
- height: h && h > 0 && h <= 4000 ? h : undefined,
61
- quality: q && q > 0 && q <= 100 ? q : 80,
62
- format: f && ['webp', 'jpeg', 'png'].includes(f) ? f : undefined,
63
- };
64
- }
65
- /**
66
- * Stream a file from Supabase storage by full path (wildcard).
67
- * Supports any depth: bucket/subfolder/org/file.png, etc.
68
- */
69
- async streamByPath(bucket, path, res, transform) {
70
- if (!this.supabaseUrl) {
71
- res.status(503).json({ success: false, error: 'Storage not configured' });
72
- return;
73
- }
74
- const cleanPath = path.startsWith('/') ? path.substring(1) : path;
75
- const url = `${this.supabaseUrl}/storage/v1/object/public/${bucket}/${cleanPath}`;
76
- return this._stream(url, res, transform);
77
- }
78
- /**
79
- * Stream a file from Supabase storage to the response.
80
- * Optionally transforms images on-the-fly with sharp.
81
- */
82
- async streamFile(bucket, orgId, fileId, res, transform) {
83
- if (!this.supabaseUrl) {
84
- res.status(503).json({ success: false, error: 'Storage not configured' });
85
- return;
86
- }
87
- const url = `${this.supabaseUrl}/storage/v1/object/public/${bucket}/${orgId}/${fileId}`;
88
- return this._stream(url, res, transform);
89
- }
90
- /** Internal: stream from a resolved Supabase URL */
91
- async _stream(url, res, transform) {
92
- // Check transform cache
93
- if (transform) {
94
- const cacheKey = `${url}:w${transform.width || ''}:h${transform.height || ''}:q${transform.quality || ''}:f${transform.format || ''}`;
95
- const cached = getCached(cacheKey);
96
- if (cached) {
97
- this.setHeaders(res, cached.contentType);
98
- res.setHeader('Content-Length', cached.buffer.length.toString());
99
- res.setHeader('X-Transform-Cache', 'hit');
100
- res.end(cached.buffer);
101
- return;
102
- }
103
- }
104
- try {
105
- const upstream = await fetch(url);
106
- if (!upstream.ok) {
107
- res.status(upstream.status === 404 ? 404 : 502).json({
108
- success: false,
109
- error: upstream.status === 404 ? 'File not found' : 'Storage error',
110
- });
111
- return;
112
- }
113
- const contentType = upstream.headers.get('content-type') || 'application/octet-stream';
114
- const isImage = contentType.startsWith('image/');
115
- // If transform requested and it's an image, try sharp
116
- if (transform && isImage) {
117
- try {
118
- const buffer = Buffer.from(await upstream.arrayBuffer());
119
- const transformed = await this.transformImage(buffer, transform);
120
- const outType = transform.format
121
- ? `image/${transform.format}`
122
- : contentType;
123
- // Cache the result
124
- const cacheKey = `${url}:w${transform.width || ''}:h${transform.height || ''}:q${transform.quality || ''}:f${transform.format || ''}`;
125
- setCache(cacheKey, transformed, outType);
126
- this.setHeaders(res, outType);
127
- res.setHeader('Content-Length', transformed.length.toString());
128
- res.setHeader('X-Transform', 'applied');
129
- res.end(transformed);
130
- return;
131
- }
132
- catch (transformError) {
133
- // Sharp not available or transform failed — fall through to stream original
134
- logger.debug({ error: transformError }, 'Transform failed, streaming original');
135
- }
136
- }
137
- // Stream original
138
- this.setHeaders(res, contentType);
139
- const contentLength = upstream.headers.get('content-length');
140
- if (contentLength) {
141
- res.setHeader('Content-Length', contentLength);
142
- }
143
- const reader = upstream.body?.getReader();
144
- if (!reader) {
145
- res.status(502).json({ success: false, error: 'No response body' });
146
- return;
147
- }
148
- while (true) {
149
- const { done, value } = await reader.read();
150
- if (done)
151
- break;
152
- res.write(value);
153
- }
154
- res.end();
155
- }
156
- catch (err) {
157
- logger.error({ error: err, url }, 'Failed to stream file');
158
- res.status(502).json({ success: false, error: 'Failed to fetch from storage' });
159
- }
160
- }
161
- setHeaders(res, contentType) {
162
- res.setHeader('Content-Type', contentType);
163
- res.setHeader('Cache-Control', `public, max-age=${this.cacheMaxAge}, immutable`);
164
- res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
165
- res.setHeader('Access-Control-Allow-Origin', '*');
166
- }
167
- async transformImage(buffer, options) {
168
- // Dynamic import — sharp is optional peer dep
169
- const sharp = (await import('sharp')).default;
170
- let pipeline = sharp(buffer);
171
- if (options.width || options.height) {
172
- pipeline = pipeline.resize(options.width, options.height, {
173
- fit: 'inside',
174
- withoutEnlargement: true,
175
- });
176
- }
177
- const quality = options.quality || 80;
178
- switch (options.format) {
179
- case 'webp':
180
- pipeline = pipeline.webp({ quality });
181
- break;
182
- case 'jpeg':
183
- pipeline = pipeline.jpeg({ quality, progressive: true });
184
- break;
185
- case 'png':
186
- pipeline = pipeline.png({ quality });
187
- break;
188
- default:
189
- // Auto-detect from original — apply quality
190
- pipeline = pipeline.jpeg({ quality, progressive: true });
191
- break;
192
- }
193
- return pipeline.toBuffer();
194
- }
195
- }
196
- //# sourceMappingURL=StorageProxyService.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StorageProxyService.js","sourceRoot":"","sources":["../../../src/shared/storage/StorageProxyService.ts"],"names":[],"mappings":"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"}
@@ -1,126 +0,0 @@
1
- /**
2
- * Storage Upload Service — server-side upload to Supabase Storage
3
- *
4
- * Centralizes all file uploads (images, PDFs, videos, any file type).
5
- * Returns proxy URLs, never Supabase URLs.
6
- *
7
- * Three upload modes:
8
- * 1. uploadFile() — single file upload, returns proxy URL
9
- * 2. uploadMultiSize() — image upload with resize to multiple sizes (sharp)
10
- * 3. uploadPrivate() — private bucket upload, returns signed URL
11
- *
12
- * Usage:
13
- * ```typescript
14
- * import { StorageUploadService } from '@soulbatical/tetra-core';
15
- *
16
- * const storage = new StorageUploadService(supabase, {
17
- * allowedBuckets: ['images', 'pdf-books', 'community-media'],
18
- * });
19
- *
20
- * // Public file
21
- * const result = await storage.uploadFile('images', buffer, {
22
- * path: 'ai-generated/org123/photo.jpg',
23
- * contentType: 'image/jpeg',
24
- * });
25
- * // result.proxyUrl → "/api/public/storage/images/ai-generated/org123/photo.jpg"
26
- *
27
- * // Multi-size image
28
- * const results = await storage.uploadMultiSize('images', buffer, {
29
- * prefix: 'ai-generated/org123',
30
- * baseFilename: 'photo.jpg',
31
- * });
32
- * // results[0].proxyUrl → ".../photo-thumb.jpg"
33
- *
34
- * // Private file (signed URL)
35
- * const result = await storage.uploadPrivate('pdf-books', buffer, {
36
- * path: 'books/user123/book.pdf',
37
- * contentType: 'application/pdf',
38
- * expiresIn: 3600 * 24 * 30, // 30 days
39
- * });
40
- * // result.signedUrl → "https://...supabase.co/storage/v1/sign/..."
41
- * ```
42
- */
43
- import type { SupabaseClient } from '@supabase/supabase-js';
44
- import type { StorageConfig, UploadResult, ImageSize } from './types.js';
45
- export interface FileUploadOptions {
46
- /** Storage path within bucket (e.g. "ai-generated/org123/photo.jpg") */
47
- path: string;
48
- /** MIME type (e.g. "image/jpeg", "application/pdf") */
49
- contentType: string;
50
- /** Overwrite if exists (default: false) */
51
- upsert?: boolean;
52
- }
53
- export interface MultiSizeUploadOptions {
54
- /** Folder prefix (e.g. "ai-generated/org123") */
55
- prefix: string;
56
- /** Base filename (e.g. "photo.jpg") — sizes will be "{base}-{size}.{ext}" */
57
- baseFilename: string;
58
- /** Custom sizes (defaults to STANDARD_IMAGE_SIZES) */
59
- sizes?: ImageSize[];
60
- /** Image format (defaults to 'jpeg') */
61
- format?: 'jpeg' | 'png' | 'webp';
62
- }
63
- export interface PrivateUploadOptions extends FileUploadOptions {
64
- /** Signed URL expiry in seconds (default: 30 days) */
65
- expiresIn?: number;
66
- }
67
- export interface PrivateUploadResult {
68
- bucket: string;
69
- path: string;
70
- signedUrl: string;
71
- contentType: string;
72
- size: number;
73
- }
74
- export interface MultiSizeUploadResult {
75
- /** All uploaded sizes with their proxy URLs */
76
- sizes: Array<UploadResult & {
77
- sizeName: string;
78
- }>;
79
- /** Base filename for DB storage */
80
- baseFilename: string;
81
- /** Storage prefix for DB storage */
82
- storagePrefix: string;
83
- }
84
- export declare class StorageUploadService {
85
- private readonly config;
86
- private readonly supabase;
87
- constructor(supabase: SupabaseClient, config: Partial<StorageConfig> & {
88
- allowedBuckets: string[];
89
- });
90
- private validateBucket;
91
- /**
92
- * Upload a single file to a public bucket.
93
- * Returns a proxy URL — never a Supabase URL.
94
- */
95
- uploadFile(bucket: string, buffer: Buffer, options: FileUploadOptions): Promise<UploadResult>;
96
- /**
97
- * Upload an image in multiple sizes (thumb, medium, large, original).
98
- * Requires sharp as a peer dependency.
99
- * Returns proxy URLs for all sizes.
100
- */
101
- uploadMultiSize(bucket: string, buffer: Buffer, options: MultiSizeUploadOptions): Promise<MultiSizeUploadResult>;
102
- /**
103
- * Upload a file to a private bucket.
104
- * Returns a signed URL (for PDFs, protected documents, etc.)
105
- */
106
- uploadPrivate(bucket: string, buffer: Buffer, options: PrivateUploadOptions): Promise<PrivateUploadResult>;
107
- /**
108
- * Delete a file from storage.
109
- */
110
- deleteFile(bucket: string, path: string): Promise<void>;
111
- /**
112
- * Ensure a bucket exists (create if missing).
113
- * Call once at startup if needed.
114
- */
115
- ensureBucket(bucket: string, options?: {
116
- public?: boolean;
117
- fileSizeLimit?: number;
118
- allowedMimeTypes?: string[];
119
- }): Promise<void>;
120
- /**
121
- * Build a proxy URL for a given bucket and path.
122
- * Use this when you already have the path and just need the URL.
123
- */
124
- static buildProxyUrl(bucket: string, path: string): string;
125
- }
126
- //# sourceMappingURL=StorageUploadService.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StorageUploadService.d.ts","sourceRoot":"","sources":["../../../src/shared/storage/StorageUploadService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAwB,MAAM,YAAY,CAAC;AAK/F,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IACpB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,KAAK,EAAE,KAAK,CAAC,YAAY,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,aAAa,EAAE,MAAM,CAAC;CACvB;AAOD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;gBAE9B,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG;QAAE,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE;IAWnG,OAAO,CAAC,cAAc;IAMtB;;;OAGG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;IAiCnG;;;;OAIG;IACG,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC;IAqCjC;;;OAGG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC;IAyC/B;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe7D;;;OAGG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GACtF,OAAO,CAAC,IAAI,CAAC;IAmBhB;;;OAGG;IACH,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;CAG3D"}
@@ -1,206 +0,0 @@
1
- /**
2
- * Storage Upload Service — server-side upload to Supabase Storage
3
- *
4
- * Centralizes all file uploads (images, PDFs, videos, any file type).
5
- * Returns proxy URLs, never Supabase URLs.
6
- *
7
- * Three upload modes:
8
- * 1. uploadFile() — single file upload, returns proxy URL
9
- * 2. uploadMultiSize() — image upload with resize to multiple sizes (sharp)
10
- * 3. uploadPrivate() — private bucket upload, returns signed URL
11
- *
12
- * Usage:
13
- * ```typescript
14
- * import { StorageUploadService } from '@soulbatical/tetra-core';
15
- *
16
- * const storage = new StorageUploadService(supabase, {
17
- * allowedBuckets: ['images', 'pdf-books', 'community-media'],
18
- * });
19
- *
20
- * // Public file
21
- * const result = await storage.uploadFile('images', buffer, {
22
- * path: 'ai-generated/org123/photo.jpg',
23
- * contentType: 'image/jpeg',
24
- * });
25
- * // result.proxyUrl → "/api/public/storage/images/ai-generated/org123/photo.jpg"
26
- *
27
- * // Multi-size image
28
- * const results = await storage.uploadMultiSize('images', buffer, {
29
- * prefix: 'ai-generated/org123',
30
- * baseFilename: 'photo.jpg',
31
- * });
32
- * // results[0].proxyUrl → ".../photo-thumb.jpg"
33
- *
34
- * // Private file (signed URL)
35
- * const result = await storage.uploadPrivate('pdf-books', buffer, {
36
- * path: 'books/user123/book.pdf',
37
- * contentType: 'application/pdf',
38
- * expiresIn: 3600 * 24 * 30, // 30 days
39
- * });
40
- * // result.signedUrl → "https://...supabase.co/storage/v1/sign/..."
41
- * ```
42
- */
43
- import { createLogger } from '../../utils/logger.js';
44
- const logger = createLogger('storage:upload');
45
- function buildProxyUrl(bucket, path) {
46
- const clean = path.startsWith('/') ? path.substring(1) : path;
47
- return `/api/public/storage/${bucket}/${clean}`;
48
- }
49
- export class StorageUploadService {
50
- config;
51
- supabase;
52
- constructor(supabase, config) {
53
- this.supabase = supabase;
54
- this.config = {
55
- allowedBuckets: config.allowedBuckets,
56
- supabaseUrl: config.supabaseUrl || process.env.SUPABASE_URL,
57
- supabaseServiceKey: config.supabaseServiceKey || process.env.SUPABASE_SERVICE_ROLE_KEY,
58
- maxUploadBytes: config.maxUploadBytes ?? 50 * 1024 * 1024,
59
- cacheMaxAge: config.cacheMaxAge ?? 3600,
60
- };
61
- }
62
- validateBucket(bucket) {
63
- if (!this.config.allowedBuckets.includes(bucket)) {
64
- throw new Error(`Bucket "${bucket}" is not in the allowed list: [${this.config.allowedBuckets.join(', ')}]`);
65
- }
66
- }
67
- /**
68
- * Upload a single file to a public bucket.
69
- * Returns a proxy URL — never a Supabase URL.
70
- */
71
- async uploadFile(bucket, buffer, options) {
72
- this.validateBucket(bucket);
73
- if (this.config.maxUploadBytes && buffer.length > this.config.maxUploadBytes) {
74
- throw new Error(`File size ${buffer.length} exceeds limit ${this.config.maxUploadBytes}`);
75
- }
76
- logger.debug({ bucket, path: options.path, size: buffer.length }, 'Uploading file');
77
- const { data, error } = await this.supabase.storage
78
- .from(bucket)
79
- .upload(options.path, buffer, {
80
- contentType: options.contentType,
81
- upsert: options.upsert ?? false,
82
- });
83
- if (error) {
84
- logger.error({ error, bucket, path: options.path }, 'Upload failed');
85
- throw new Error(`Upload failed: ${error.message}`);
86
- }
87
- const result = {
88
- bucket,
89
- path: data.path,
90
- proxyUrl: buildProxyUrl(bucket, data.path),
91
- contentType: options.contentType,
92
- size: buffer.length,
93
- };
94
- logger.info({ bucket, path: data.path, size: buffer.length }, 'File uploaded');
95
- return result;
96
- }
97
- /**
98
- * Upload an image in multiple sizes (thumb, medium, large, original).
99
- * Requires sharp as a peer dependency.
100
- * Returns proxy URLs for all sizes.
101
- */
102
- async uploadMultiSize(bucket, buffer, options) {
103
- this.validateBucket(bucket);
104
- // Dynamic import — sharp is optional peer dep
105
- const { ImageProcessingService, STANDARD_IMAGE_SIZES } = await import('./ImageProcessingService.js');
106
- const sizes = options.sizes || STANDARD_IMAGE_SIZES;
107
- const processed = await ImageProcessingService.generateMultipleSizes(buffer, {
108
- sizes,
109
- format: options.format,
110
- });
111
- const ext = options.baseFilename.split('.').pop() || 'jpg';
112
- const baseWithoutExt = options.baseFilename.replace(/\.[^.]+$/, '');
113
- const uploadResults = await Promise.all(processed.map(async (item) => {
114
- const filename = `${baseWithoutExt}-${item.size}.${ext}`;
115
- const path = `${options.prefix}/${filename}`;
116
- const result = await this.uploadFile(bucket, item.buffer, {
117
- path,
118
- contentType: `image/${options.format || 'jpeg'}`,
119
- upsert: true,
120
- });
121
- return { ...result, sizeName: item.size };
122
- }));
123
- return {
124
- sizes: uploadResults,
125
- baseFilename: options.baseFilename,
126
- storagePrefix: options.prefix,
127
- };
128
- }
129
- /**
130
- * Upload a file to a private bucket.
131
- * Returns a signed URL (for PDFs, protected documents, etc.)
132
- */
133
- async uploadPrivate(bucket, buffer, options) {
134
- this.validateBucket(bucket);
135
- if (this.config.maxUploadBytes && buffer.length > this.config.maxUploadBytes) {
136
- throw new Error(`File size ${buffer.length} exceeds limit ${this.config.maxUploadBytes}`);
137
- }
138
- logger.debug({ bucket, path: options.path, size: buffer.length }, 'Uploading private file');
139
- const { data, error } = await this.supabase.storage
140
- .from(bucket)
141
- .upload(options.path, buffer, {
142
- contentType: options.contentType,
143
- upsert: options.upsert ?? false,
144
- });
145
- if (error) {
146
- logger.error({ error, bucket, path: options.path }, 'Private upload failed');
147
- throw new Error(`Upload failed: ${error.message}`);
148
- }
149
- const expiresIn = options.expiresIn ?? 3600 * 24 * 30; // 30 days default
150
- const { data: signedData, error: signError } = await this.supabase.storage
151
- .from(bucket)
152
- .createSignedUrl(data.path, expiresIn);
153
- if (signError || !signedData?.signedUrl) {
154
- throw new Error(`Failed to create signed URL: ${signError?.message || 'No URL returned'}`);
155
- }
156
- logger.info({ bucket, path: data.path, size: buffer.length }, 'Private file uploaded');
157
- return {
158
- bucket,
159
- path: data.path,
160
- signedUrl: signedData.signedUrl,
161
- contentType: options.contentType,
162
- size: buffer.length,
163
- };
164
- }
165
- /**
166
- * Delete a file from storage.
167
- */
168
- async deleteFile(bucket, path) {
169
- this.validateBucket(bucket);
170
- const { error } = await this.supabase.storage
171
- .from(bucket)
172
- .remove([path]);
173
- if (error) {
174
- logger.error({ error, bucket, path }, 'Delete failed');
175
- throw new Error(`Delete failed: ${error.message}`);
176
- }
177
- logger.info({ bucket, path }, 'File deleted');
178
- }
179
- /**
180
- * Ensure a bucket exists (create if missing).
181
- * Call once at startup if needed.
182
- */
183
- async ensureBucket(bucket, options = {}) {
184
- const { data: buckets } = await this.supabase.storage.listBuckets();
185
- const exists = buckets?.some(b => b.name === bucket);
186
- if (!exists) {
187
- const { error } = await this.supabase.storage.createBucket(bucket, {
188
- public: options.public ?? true,
189
- fileSizeLimit: options.fileSizeLimit,
190
- allowedMimeTypes: options.allowedMimeTypes,
191
- });
192
- if (error) {
193
- throw new Error(`Failed to create bucket "${bucket}": ${error.message}`);
194
- }
195
- logger.info({ bucket }, 'Bucket created');
196
- }
197
- }
198
- /**
199
- * Build a proxy URL for a given bucket and path.
200
- * Use this when you already have the path and just need the URL.
201
- */
202
- static buildProxyUrl(bucket, path) {
203
- return buildProxyUrl(bucket, path);
204
- }
205
- }
206
- //# sourceMappingURL=StorageUploadService.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StorageUploadService.js","sourceRoot":"","sources":["../../../src/shared/storage/StorageUploadService.ts"],"names":[],"mappings":"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"}
@@ -1,14 +0,0 @@
1
- /**
2
- * Deterministic Storage URL Helpers
3
- *
4
- * All storage paths follow: {bucket}/{org_id}/{record_id}.{ext}
5
- * URLs are derived from the ID — no need to store them in the database.
6
- *
7
- * Returns absolute Supabase Storage URLs.
8
- * Falls back to relative proxy URLs when SUPABASE_URL is unavailable.
9
- */
10
- export declare function getCreativeUrl(creativeId: string, orgId: string): string;
11
- export declare function getCreativeStoragePath(creativeId: string, orgId: string): string;
12
- export declare function getAdLibraryThumbnailUrl(itemId: string, orgId: string): string;
13
- export declare function getAdLibraryThumbnailPath(itemId: string, orgId: string): string;
14
- //# sourceMappingURL=creative-urls.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"creative-urls.d.ts","sourceRoot":"","sources":["../../../src/shared/storage/creative-urls.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAYH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/E"}
@@ -1,30 +0,0 @@
1
- /**
2
- * Deterministic Storage URL Helpers
3
- *
4
- * All storage paths follow: {bucket}/{org_id}/{record_id}.{ext}
5
- * URLs are derived from the ID — no need to store them in the database.
6
- *
7
- * Returns absolute Supabase Storage URLs.
8
- * Falls back to relative proxy URLs when SUPABASE_URL is unavailable.
9
- */
10
- const getSupabaseUrl = () => process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL || '';
11
- function storageUrl(bucket, path) {
12
- const supabaseUrl = getSupabaseUrl();
13
- if (supabaseUrl) {
14
- return `${supabaseUrl}/storage/v1/object/public/${bucket}/${path}`;
15
- }
16
- return `/api/public/storage/${bucket}/${path}`;
17
- }
18
- export function getCreativeUrl(creativeId, orgId) {
19
- return storageUrl('ad-creatives', `${orgId}/${creativeId}.png`);
20
- }
21
- export function getCreativeStoragePath(creativeId, orgId) {
22
- return `${orgId}/${creativeId}.png`;
23
- }
24
- export function getAdLibraryThumbnailUrl(itemId, orgId) {
25
- return storageUrl('ad-library', `${orgId}/${itemId}.jpg`);
26
- }
27
- export function getAdLibraryThumbnailPath(itemId, orgId) {
28
- return `${orgId}/${itemId}.jpg`;
29
- }
30
- //# sourceMappingURL=creative-urls.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"creative-urls.js","sourceRoot":"","sources":["../../../src/shared/storage/creative-urls.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,EAAE,CAAC;AAEpG,SAAS,UAAU,CAAC,MAAc,EAAE,IAAY;IAC9C,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,GAAG,WAAW,6BAA6B,MAAM,IAAI,IAAI,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,uBAAuB,MAAM,IAAI,IAAI,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB,EAAE,KAAa;IAC9D,OAAO,UAAU,CAAC,cAAc,EAAE,GAAG,KAAK,IAAI,UAAU,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,UAAkB,EAAE,KAAa;IACtE,OAAO,GAAG,KAAK,IAAI,UAAU,MAAM,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAc,EAAE,KAAa;IACpE,OAAO,UAAU,CAAC,YAAY,EAAE,GAAG,KAAK,IAAI,MAAM,MAAM,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAE,KAAa;IACrE,OAAO,GAAG,KAAK,IAAI,MAAM,MAAM,CAAC;AAClC,CAAC"}
@@ -1,28 +0,0 @@
1
- /**
2
- * @module @soulbatical/tetra-core/storage
3
- *
4
- * Shared storage module — Supabase streaming proxy, upload, and image processing.
5
- *
6
- * Usage:
7
- * ```typescript
8
- * import {
9
- * addStorageProxyRoutes,
10
- * addStorageUploadRoutes,
11
- * ImageProcessingService,
12
- * } from '@soulbatical/tetra-core';
13
- *
14
- * const publicRouter = Router();
15
- * addStorageProxyRoutes(publicRouter, {
16
- * config: { allowedBuckets: ['ad-creatives'] },
17
- * });
18
- * app.use('/api/public/storage', publicRouter);
19
- * ```
20
- */
21
- export { addStorageProxyRoutes, addStorageUploadRoutes } from './routes.js';
22
- export { StorageProxyService } from './StorageProxyService.js';
23
- export { ImageProcessingService, STANDARD_IMAGE_SIZES } from './ImageProcessingService.js';
24
- export { StorageUploadService } from './StorageUploadService.js';
25
- export type { StorageConfig, StorageProxyOptions, StorageUploadOptions, UploadResult, ImageSize, ProcessedImageResult, ImageProcessingOptions, } from './types.js';
26
- export type { FileUploadOptions, MultiSizeUploadOptions, PrivateUploadOptions, PrivateUploadResult, MultiSizeUploadResult, } from './StorageUploadService.js';
27
- export { getCreativeUrl, getCreativeStoragePath, getAdLibraryThumbnailUrl, getAdLibraryThumbnailPath } from './creative-urls.js';
28
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/storage/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC"}