@open-mercato/core 0.4.6-develop-a88276bc52 → 0.4.6-develop-806a2ed6b9

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 (226) hide show
  1. package/AGENTS.md +10 -0
  2. package/dist/generated/entities/integration_credentials/index.js +19 -0
  3. package/dist/generated/entities/integration_credentials/index.js.map +7 -0
  4. package/dist/generated/entities/integration_log/index.js +27 -0
  5. package/dist/generated/entities/integration_log/index.js.map +7 -0
  6. package/dist/generated/entities/integration_state/index.js +27 -0
  7. package/dist/generated/entities/integration_state/index.js.map +7 -0
  8. package/dist/generated/entities/sync_cursor/index.js +19 -0
  9. package/dist/generated/entities/sync_cursor/index.js.map +7 -0
  10. package/dist/generated/entities/sync_external_id_mapping/index.js +27 -0
  11. package/dist/generated/entities/sync_external_id_mapping/index.js.map +7 -0
  12. package/dist/generated/entities/sync_mapping/index.js +19 -0
  13. package/dist/generated/entities/sync_mapping/index.js.map +7 -0
  14. package/dist/generated/entities/sync_run/index.js +45 -0
  15. package/dist/generated/entities/sync_run/index.js.map +7 -0
  16. package/dist/generated/entities/sync_schedule/index.js +35 -0
  17. package/dist/generated/entities/sync_schedule/index.js.map +7 -0
  18. package/dist/generated/entities.ids.generated.js +14 -0
  19. package/dist/generated/entities.ids.generated.js.map +2 -2
  20. package/dist/generated/entity-fields-registry.js +16 -0
  21. package/dist/generated/entity-fields-registry.js.map +2 -2
  22. package/dist/modules/data_sync/acl.js +11 -0
  23. package/dist/modules/data_sync/acl.js.map +7 -0
  24. package/dist/modules/data_sync/api/mappings/[id]/route.js +137 -0
  25. package/dist/modules/data_sync/api/mappings/[id]/route.js.map +7 -0
  26. package/dist/modules/data_sync/api/mappings/route.js +132 -0
  27. package/dist/modules/data_sync/api/mappings/route.js.map +7 -0
  28. package/dist/modules/data_sync/api/run.js +87 -0
  29. package/dist/modules/data_sync/api/run.js.map +7 -0
  30. package/dist/modules/data_sync/api/runs/[id]/cancel.js +49 -0
  31. package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +7 -0
  32. package/dist/modules/data_sync/api/runs/[id]/retry.js +93 -0
  33. package/dist/modules/data_sync/api/runs/[id]/retry.js.map +7 -0
  34. package/dist/modules/data_sync/api/runs/[id]/route.js +69 -0
  35. package/dist/modules/data_sync/api/runs/[id]/route.js.map +7 -0
  36. package/dist/modules/data_sync/api/runs.js +66 -0
  37. package/dist/modules/data_sync/api/runs.js.map +7 -0
  38. package/dist/modules/data_sync/api/validate.js +66 -0
  39. package/dist/modules/data_sync/api/validate.js.map +7 -0
  40. package/dist/modules/data_sync/backend/data-sync/page.js +216 -0
  41. package/dist/modules/data_sync/backend/data-sync/page.js.map +7 -0
  42. package/dist/modules/data_sync/backend/data-sync/page.meta.js +25 -0
  43. package/dist/modules/data_sync/backend/data-sync/page.meta.js.map +7 -0
  44. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +178 -0
  45. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +7 -0
  46. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.meta.js +14 -0
  47. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.meta.js.map +7 -0
  48. package/dist/modules/data_sync/data/entities.js +228 -0
  49. package/dist/modules/data_sync/data/entities.js.map +7 -0
  50. package/dist/modules/data_sync/data/validators.js +32 -0
  51. package/dist/modules/data_sync/data/validators.js.map +7 -0
  52. package/dist/modules/data_sync/di.js +26 -0
  53. package/dist/modules/data_sync/di.js.map +7 -0
  54. package/dist/modules/data_sync/events.js +16 -0
  55. package/dist/modules/data_sync/events.js.map +7 -0
  56. package/dist/modules/data_sync/index.js +9 -0
  57. package/dist/modules/data_sync/index.js.map +7 -0
  58. package/dist/modules/data_sync/lib/adapter-registry.js +16 -0
  59. package/dist/modules/data_sync/lib/adapter-registry.js.map +7 -0
  60. package/dist/modules/data_sync/lib/adapter.js +1 -0
  61. package/dist/modules/data_sync/lib/adapter.js.map +7 -0
  62. package/dist/modules/data_sync/lib/id-mapping.js +79 -0
  63. package/dist/modules/data_sync/lib/id-mapping.js.map +7 -0
  64. package/dist/modules/data_sync/lib/queue.js +17 -0
  65. package/dist/modules/data_sync/lib/queue.js.map +7 -0
  66. package/dist/modules/data_sync/lib/sync-engine.js +309 -0
  67. package/dist/modules/data_sync/lib/sync-engine.js.map +7 -0
  68. package/dist/modules/data_sync/lib/sync-run-service.js +148 -0
  69. package/dist/modules/data_sync/lib/sync-run-service.js.map +7 -0
  70. package/dist/modules/data_sync/migrations/Migration20260304113737.js +17 -0
  71. package/dist/modules/data_sync/migrations/Migration20260304113737.js.map +7 -0
  72. package/dist/modules/data_sync/setup.js +13 -0
  73. package/dist/modules/data_sync/setup.js.map +7 -0
  74. package/dist/modules/data_sync/workers/sync-export.js +14 -0
  75. package/dist/modules/data_sync/workers/sync-export.js.map +7 -0
  76. package/dist/modules/data_sync/workers/sync-import.js +14 -0
  77. package/dist/modules/data_sync/workers/sync-import.js.map +7 -0
  78. package/dist/modules/data_sync/workers/sync-scheduled.js +63 -0
  79. package/dist/modules/data_sync/workers/sync-scheduled.js.map +7 -0
  80. package/dist/modules/entities/lib/encryptionDefaults.js +4 -0
  81. package/dist/modules/entities/lib/encryptionDefaults.js.map +2 -2
  82. package/dist/modules/integrations/acl.js +4 -1
  83. package/dist/modules/integrations/acl.js.map +2 -2
  84. package/dist/modules/integrations/api/[id]/credentials/route.js +127 -0
  85. package/dist/modules/integrations/api/[id]/credentials/route.js.map +7 -0
  86. package/dist/modules/integrations/api/[id]/health/route.js +46 -0
  87. package/dist/modules/integrations/api/[id]/health/route.js.map +7 -0
  88. package/dist/modules/integrations/api/[id]/route.js +65 -0
  89. package/dist/modules/integrations/api/[id]/route.js.map +7 -0
  90. package/dist/modules/integrations/api/[id]/state/route.js +109 -0
  91. package/dist/modules/integrations/api/[id]/state/route.js.map +7 -0
  92. package/dist/modules/integrations/api/[id]/version/route.js +117 -0
  93. package/dist/modules/integrations/api/[id]/version/route.js.map +7 -0
  94. package/dist/modules/integrations/api/guards.js +31 -0
  95. package/dist/modules/integrations/api/guards.js.map +7 -0
  96. package/dist/modules/integrations/api/logs/route.js +60 -0
  97. package/dist/modules/integrations/api/logs/route.js.map +7 -0
  98. package/dist/modules/integrations/api/openapi.js +25 -0
  99. package/dist/modules/integrations/api/openapi.js.map +7 -0
  100. package/dist/modules/integrations/api/route.js +68 -0
  101. package/dist/modules/integrations/api/route.js.map +7 -0
  102. package/dist/modules/integrations/backend/integrations/[id]/page.js +313 -0
  103. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +7 -0
  104. package/dist/modules/integrations/backend/integrations/[id]/page.meta.js +15 -0
  105. package/dist/modules/integrations/backend/integrations/[id]/page.meta.js.map +7 -0
  106. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +189 -0
  107. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +7 -0
  108. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.meta.js +15 -0
  109. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.meta.js.map +7 -0
  110. package/dist/modules/integrations/backend/integrations/page.js +212 -0
  111. package/dist/modules/integrations/backend/integrations/page.js.map +7 -0
  112. package/dist/modules/integrations/backend/integrations/page.meta.js +22 -0
  113. package/dist/modules/integrations/backend/integrations/page.meta.js.map +7 -0
  114. package/dist/modules/integrations/data/enrichers.js +27 -12
  115. package/dist/modules/integrations/data/enrichers.js.map +2 -2
  116. package/dist/modules/integrations/data/entities.js +136 -1
  117. package/dist/modules/integrations/data/entities.js.map +2 -2
  118. package/dist/modules/integrations/data/validators.js +36 -0
  119. package/dist/modules/integrations/data/validators.js.map +7 -0
  120. package/dist/modules/integrations/di.js +24 -0
  121. package/dist/modules/integrations/di.js.map +7 -0
  122. package/dist/modules/integrations/events.js +19 -0
  123. package/dist/modules/integrations/events.js.map +7 -0
  124. package/dist/modules/integrations/lib/credentials-service.js +159 -0
  125. package/dist/modules/integrations/lib/credentials-service.js.map +7 -0
  126. package/dist/modules/integrations/lib/health-service.js +37 -0
  127. package/dist/modules/integrations/lib/health-service.js.map +7 -0
  128. package/dist/modules/integrations/lib/log-service.js +66 -0
  129. package/dist/modules/integrations/lib/log-service.js.map +7 -0
  130. package/dist/modules/integrations/lib/registry-service.js +33 -0
  131. package/dist/modules/integrations/lib/registry-service.js.map +7 -0
  132. package/dist/modules/integrations/lib/state-service.js +55 -0
  133. package/dist/modules/integrations/lib/state-service.js.map +7 -0
  134. package/dist/modules/integrations/lib/types.js +1 -0
  135. package/dist/modules/integrations/lib/types.js.map +7 -0
  136. package/dist/modules/integrations/migrations/Migration20260304113737.js +19 -0
  137. package/dist/modules/integrations/migrations/Migration20260304113737.js.map +7 -0
  138. package/dist/modules/integrations/setup.js +2 -2
  139. package/dist/modules/integrations/setup.js.map +2 -2
  140. package/dist/modules/integrations/widgets/injection-table.js.map +1 -1
  141. package/dist/modules/integrations/workers/log-pruner.js +18 -0
  142. package/dist/modules/integrations/workers/log-pruner.js.map +7 -0
  143. package/generated/entities/integration_credentials/index.ts +8 -0
  144. package/generated/entities/integration_log/index.ts +12 -0
  145. package/generated/entities/integration_state/index.ts +12 -0
  146. package/generated/entities/sync_cursor/index.ts +8 -0
  147. package/generated/entities/sync_external_id_mapping/index.ts +12 -0
  148. package/generated/entities/sync_mapping/index.ts +8 -0
  149. package/generated/entities/sync_run/index.ts +21 -0
  150. package/generated/entities/sync_schedule/index.ts +16 -0
  151. package/generated/entities.ids.generated.ts +14 -0
  152. package/generated/entity-fields-registry.ts +16 -0
  153. package/package.json +2 -2
  154. package/src/modules/data_sync/AGENTS.md +157 -0
  155. package/src/modules/data_sync/acl.ts +7 -0
  156. package/src/modules/data_sync/api/mappings/[id]/route.ts +158 -0
  157. package/src/modules/data_sync/api/mappings/route.ts +144 -0
  158. package/src/modules/data_sync/api/run.ts +97 -0
  159. package/src/modules/data_sync/api/runs/[id]/cancel.ts +57 -0
  160. package/src/modules/data_sync/api/runs/[id]/retry.ts +108 -0
  161. package/src/modules/data_sync/api/runs/[id]/route.ts +81 -0
  162. package/src/modules/data_sync/api/runs.ts +69 -0
  163. package/src/modules/data_sync/api/validate.ts +73 -0
  164. package/src/modules/data_sync/backend/data-sync/page.meta.ts +21 -0
  165. package/src/modules/data_sync/backend/data-sync/page.tsx +244 -0
  166. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.meta.ts +10 -0
  167. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +278 -0
  168. package/src/modules/data_sync/data/entities.ts +180 -0
  169. package/src/modules/data_sync/data/validators.ts +35 -0
  170. package/src/modules/data_sync/di.ts +38 -0
  171. package/src/modules/data_sync/events.ts +12 -0
  172. package/src/modules/data_sync/i18n/de.json +48 -0
  173. package/src/modules/data_sync/i18n/en.json +48 -0
  174. package/src/modules/data_sync/i18n/es.json +48 -0
  175. package/src/modules/data_sync/i18n/pl.json +48 -0
  176. package/src/modules/data_sync/index.ts +5 -0
  177. package/src/modules/data_sync/lib/adapter-registry.ts +15 -0
  178. package/src/modules/data_sync/lib/adapter.ts +90 -0
  179. package/src/modules/data_sync/lib/id-mapping.ts +95 -0
  180. package/src/modules/data_sync/lib/queue.ts +19 -0
  181. package/src/modules/data_sync/lib/sync-engine.ts +375 -0
  182. package/src/modules/data_sync/lib/sync-run-service.ts +187 -0
  183. package/src/modules/data_sync/migrations/.snapshot-open-mercato.json +653 -0
  184. package/src/modules/data_sync/migrations/Migration20260304113737.ts +19 -0
  185. package/src/modules/data_sync/setup.ts +11 -0
  186. package/src/modules/data_sync/workers/sync-export.ts +27 -0
  187. package/src/modules/data_sync/workers/sync-import.ts +27 -0
  188. package/src/modules/data_sync/workers/sync-scheduled.ts +84 -0
  189. package/src/modules/entities/lib/encryptionDefaults.ts +4 -0
  190. package/src/modules/integrations/AGENTS.md +160 -0
  191. package/src/modules/integrations/acl.ts +3 -0
  192. package/src/modules/integrations/api/[id]/credentials/route.ts +142 -0
  193. package/src/modules/integrations/api/[id]/health/route.ts +53 -0
  194. package/src/modules/integrations/api/[id]/route.ts +76 -0
  195. package/src/modules/integrations/api/[id]/state/route.ts +121 -0
  196. package/src/modules/integrations/api/[id]/version/route.ts +132 -0
  197. package/src/modules/integrations/api/guards.ts +59 -0
  198. package/src/modules/integrations/api/logs/route.ts +63 -0
  199. package/src/modules/integrations/api/openapi.ts +22 -0
  200. package/src/modules/integrations/api/route.ts +73 -0
  201. package/src/modules/integrations/backend/integrations/[id]/page.meta.ts +11 -0
  202. package/src/modules/integrations/backend/integrations/[id]/page.tsx +424 -0
  203. package/src/modules/integrations/backend/integrations/bundle/[id]/page.meta.ts +11 -0
  204. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +249 -0
  205. package/src/modules/integrations/backend/integrations/page.meta.ts +18 -0
  206. package/src/modules/integrations/backend/integrations/page.tsx +296 -0
  207. package/src/modules/integrations/data/enrichers.ts +35 -18
  208. package/src/modules/integrations/data/entities.ts +114 -5
  209. package/src/modules/integrations/data/validators.ts +41 -0
  210. package/src/modules/integrations/di.ts +31 -0
  211. package/src/modules/integrations/events.ts +17 -0
  212. package/src/modules/integrations/i18n/de.json +70 -0
  213. package/src/modules/integrations/i18n/en.json +70 -0
  214. package/src/modules/integrations/i18n/es.json +70 -0
  215. package/src/modules/integrations/i18n/pl.json +70 -0
  216. package/src/modules/integrations/lib/credentials-service.ts +204 -0
  217. package/src/modules/integrations/lib/health-service.ts +59 -0
  218. package/src/modules/integrations/lib/log-service.ts +84 -0
  219. package/src/modules/integrations/lib/registry-service.ts +42 -0
  220. package/src/modules/integrations/lib/state-service.ts +64 -0
  221. package/src/modules/integrations/lib/types.ts +4 -0
  222. package/src/modules/integrations/migrations/.snapshot-open-mercato.json +582 -0
  223. package/src/modules/integrations/migrations/Migration20260304113737.ts +21 -0
  224. package/src/modules/integrations/setup.ts +2 -2
  225. package/src/modules/integrations/widgets/injection-table.ts +1 -1
  226. package/src/modules/integrations/workers/log-pruner.ts +30 -0
@@ -0,0 +1,46 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
+ import { getIntegration } from "@open-mercato/shared/modules/integrations/types";
6
+ const idParamsSchema = z.object({ id: z.string().min(1) });
7
+ const metadata = {
8
+ POST: { requireAuth: true, requireFeatures: ["integrations.manage"] }
9
+ };
10
+ const openApi = {
11
+ tags: ["Integrations"],
12
+ summary: "Run health check for an integration"
13
+ };
14
+ async function POST(req, ctx) {
15
+ const auth = await getAuthFromRequest(req);
16
+ if (!auth?.tenantId || !auth.orgId) {
17
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
18
+ }
19
+ const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
20
+ const parsedParams = idParamsSchema.safeParse(rawParams);
21
+ if (!parsedParams.success) {
22
+ return NextResponse.json({ error: "Invalid integration id" }, { status: 400 });
23
+ }
24
+ const integration = getIntegration(parsedParams.data.id);
25
+ if (!integration) {
26
+ return NextResponse.json({ error: "Integration not found" }, { status: 404 });
27
+ }
28
+ const container = await createRequestContainer();
29
+ const healthService = container.resolve("integrationHealthService");
30
+ const result = await healthService.runHealthCheck(
31
+ integration.id,
32
+ { organizationId: auth.orgId, tenantId: auth.tenantId }
33
+ );
34
+ return NextResponse.json({
35
+ status: result.status,
36
+ message: result.message ?? null,
37
+ details: result.details ?? null,
38
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
39
+ });
40
+ }
41
+ export {
42
+ POST,
43
+ metadata,
44
+ openApi
45
+ };
46
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/integrations/api/%5Bid%5D/health/route.ts"],
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getIntegration } from '@open-mercato/shared/modules/integrations/types'\nimport type { IntegrationHealthService } from '../../../lib/health-service'\n\nconst idParamsSchema = z.object({ id: z.string().min(1) })\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['integrations.manage'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'Run health check for an integration',\n}\n\nexport async function POST(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const rawParams = (ctx.params && typeof (ctx.params as Promise<unknown>).then === 'function')\n ? await (ctx.params as Promise<{ id?: string }>)\n : (ctx.params as { id?: string } | undefined)\n\n const parsedParams = idParamsSchema.safeParse(rawParams)\n if (!parsedParams.success) {\n return NextResponse.json({ error: 'Invalid integration id' }, { status: 400 })\n }\n\n const integration = getIntegration(parsedParams.data.id)\n if (!integration) {\n return NextResponse.json({ error: 'Integration not found' }, { status: 404 })\n }\n\n const container = await createRequestContainer()\n const healthService = container.resolve('integrationHealthService') as IntegrationHealthService\n\n const result = await healthService.runHealthCheck(\n integration.id,\n { organizationId: auth.orgId as string, tenantId: auth.tenantId },\n )\n\n return NextResponse.json({\n status: result.status,\n message: result.message ?? null,\n details: result.details ?? null,\n checkedAt: new Date().toISOString(),\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,sBAAsB;AAG/B,MAAM,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;AAElD,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,qBAAqB,EAAE;AACtE;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,cAAc;AAAA,EACrB,SAAS;AACX;AAEA,eAAsB,KAAK,KAAc,KAA8D;AACrG,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,YAAY,CAAC,KAAK,OAAO;AAClC,WAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrE;AAEA,QAAM,YAAa,IAAI,UAAU,OAAQ,IAAI,OAA4B,SAAS,aAC9E,MAAO,IAAI,SACV,IAAI;AAET,QAAM,eAAe,eAAe,UAAU,SAAS;AACvD,MAAI,CAAC,aAAa,SAAS;AACzB,WAAO,aAAa,KAAK,EAAE,OAAO,yBAAyB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/E;AAEA,QAAM,cAAc,eAAe,aAAa,KAAK,EAAE;AACvD,MAAI,CAAC,aAAa;AAChB,WAAO,aAAa,KAAK,EAAE,OAAO,wBAAwB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC9E;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,gBAAgB,UAAU,QAAQ,0BAA0B;AAElE,QAAM,SAAS,MAAM,cAAc;AAAA,IACjC,YAAY;AAAA,IACZ,EAAE,gBAAgB,KAAK,OAAiB,UAAU,KAAK,SAAS;AAAA,EAClE;AAEA,SAAO,aAAa,KAAK;AAAA,IACvB,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO,WAAW;AAAA,IAC3B,SAAS,OAAO,WAAW;AAAA,IAC3B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,65 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
+ import { getBundle, getBundleIntegrations, getIntegration } from "@open-mercato/shared/modules/integrations/types";
6
+ const idParamsSchema = z.object({ id: z.string().min(1) });
7
+ const metadata = {
8
+ GET: { requireAuth: true, requireFeatures: ["integrations.view"] }
9
+ };
10
+ const openApi = {
11
+ tags: ["Integrations"],
12
+ summary: "Get integration detail"
13
+ };
14
+ async function GET(req, ctx) {
15
+ const auth = await getAuthFromRequest(req);
16
+ if (!auth?.tenantId || !auth.orgId) {
17
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
18
+ }
19
+ const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
20
+ const parsedParams = idParamsSchema.safeParse(rawParams);
21
+ if (!parsedParams.success) {
22
+ return NextResponse.json({ error: "Invalid integration id" }, { status: 400 });
23
+ }
24
+ const integration = getIntegration(parsedParams.data.id);
25
+ if (!integration) {
26
+ return NextResponse.json({ error: "Integration not found" }, { status: 404 });
27
+ }
28
+ const container = await createRequestContainer();
29
+ const credentialsService = container.resolve("integrationCredentialsService");
30
+ const stateService = container.resolve("integrationStateService");
31
+ const scope = { organizationId: auth.orgId, tenantId: auth.tenantId };
32
+ const [credentials, state] = await Promise.all([
33
+ credentialsService.resolve(integration.id, scope),
34
+ stateService.get(integration.id, scope)
35
+ ]);
36
+ const bundle = integration.bundleId ? getBundle(integration.bundleId) : void 0;
37
+ const bundleIntegrations = integration.bundleId ? await Promise.all(
38
+ getBundleIntegrations(integration.bundleId).map(async (item) => {
39
+ const itemState = await stateService.get(item.id, scope);
40
+ return {
41
+ ...item,
42
+ isEnabled: itemState?.isEnabled ?? true
43
+ };
44
+ })
45
+ ) : [];
46
+ return NextResponse.json({
47
+ integration,
48
+ bundle,
49
+ bundleIntegrations,
50
+ state: {
51
+ isEnabled: state?.isEnabled ?? true,
52
+ apiVersion: state?.apiVersion ?? null,
53
+ reauthRequired: state?.reauthRequired ?? false,
54
+ lastHealthStatus: state?.lastHealthStatus ?? null,
55
+ lastHealthCheckedAt: state?.lastHealthCheckedAt?.toISOString() ?? null
56
+ },
57
+ hasCredentials: Boolean(credentials)
58
+ });
59
+ }
60
+ export {
61
+ GET,
62
+ metadata,
63
+ openApi
64
+ };
65
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/integrations/api/%5Bid%5D/route.ts"],
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getBundle, getBundleIntegrations, getIntegration } from '@open-mercato/shared/modules/integrations/types'\nimport type { CredentialsService } from '../../lib/credentials-service'\nimport type { IntegrationStateService } from '../../lib/state-service'\n\nconst idParamsSchema = z.object({ id: z.string().min(1) })\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.view'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'Get integration detail',\n}\n\nexport async function GET(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const rawParams = (ctx.params && typeof (ctx.params as Promise<unknown>).then === 'function')\n ? await (ctx.params as Promise<{ id?: string }>)\n : (ctx.params as { id?: string } | undefined)\n\n const parsedParams = idParamsSchema.safeParse(rawParams)\n if (!parsedParams.success) {\n return NextResponse.json({ error: 'Invalid integration id' }, { status: 400 })\n }\n\n const integration = getIntegration(parsedParams.data.id)\n if (!integration) {\n return NextResponse.json({ error: 'Integration not found' }, { status: 404 })\n }\n\n const container = await createRequestContainer()\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const stateService = container.resolve('integrationStateService') as IntegrationStateService\n const scope = { organizationId: auth.orgId as string, tenantId: auth.tenantId }\n\n const [credentials, state] = await Promise.all([\n credentialsService.resolve(integration.id, scope),\n stateService.get(integration.id, scope),\n ])\n\n const bundle = integration.bundleId ? getBundle(integration.bundleId) : undefined\n const bundleIntegrations = integration.bundleId\n ? await Promise.all(\n getBundleIntegrations(integration.bundleId).map(async (item) => {\n const itemState = await stateService.get(item.id, scope)\n return {\n ...item,\n isEnabled: itemState?.isEnabled ?? true,\n }\n }),\n )\n : []\n\n return NextResponse.json({\n integration,\n bundle,\n bundleIntegrations,\n state: {\n isEnabled: state?.isEnabled ?? true,\n apiVersion: state?.apiVersion ?? null,\n reauthRequired: state?.reauthRequired ?? false,\n lastHealthStatus: state?.lastHealthStatus ?? null,\n lastHealthCheckedAt: state?.lastHealthCheckedAt?.toISOString() ?? null,\n },\n hasCredentials: Boolean(credentials),\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,WAAW,uBAAuB,sBAAsB;AAIjE,MAAM,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;AAElD,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,mBAAmB,EAAE;AACnE;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,cAAc;AAAA,EACrB,SAAS;AACX;AAEA,eAAsB,IAAI,KAAc,KAA8D;AACpG,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,YAAY,CAAC,KAAK,OAAO;AAClC,WAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrE;AAEA,QAAM,YAAa,IAAI,UAAU,OAAQ,IAAI,OAA4B,SAAS,aAC9E,MAAO,IAAI,SACV,IAAI;AAET,QAAM,eAAe,eAAe,UAAU,SAAS;AACvD,MAAI,CAAC,aAAa,SAAS;AACzB,WAAO,aAAa,KAAK,EAAE,OAAO,yBAAyB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/E;AAEA,QAAM,cAAc,eAAe,aAAa,KAAK,EAAE;AACvD,MAAI,CAAC,aAAa;AAChB,WAAO,aAAa,KAAK,EAAE,OAAO,wBAAwB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC9E;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,qBAAqB,UAAU,QAAQ,+BAA+B;AAC5E,QAAM,eAAe,UAAU,QAAQ,yBAAyB;AAChE,QAAM,QAAQ,EAAE,gBAAgB,KAAK,OAAiB,UAAU,KAAK,SAAS;AAE9E,QAAM,CAAC,aAAa,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC7C,mBAAmB,QAAQ,YAAY,IAAI,KAAK;AAAA,IAChD,aAAa,IAAI,YAAY,IAAI,KAAK;AAAA,EACxC,CAAC;AAED,QAAM,SAAS,YAAY,WAAW,UAAU,YAAY,QAAQ,IAAI;AACxE,QAAM,qBAAqB,YAAY,WACnC,MAAM,QAAQ;AAAA,IACd,sBAAsB,YAAY,QAAQ,EAAE,IAAI,OAAO,SAAS;AAC9D,YAAM,YAAY,MAAM,aAAa,IAAI,KAAK,IAAI,KAAK;AACvD,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW,WAAW,aAAa;AAAA,MACrC;AAAA,IACF,CAAC;AAAA,EACH,IACE,CAAC;AAEL,SAAO,aAAa,KAAK;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,MACL,WAAW,OAAO,aAAa;AAAA,MAC/B,YAAY,OAAO,cAAc;AAAA,MACjC,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,kBAAkB,OAAO,oBAAoB;AAAA,MAC7C,qBAAqB,OAAO,qBAAqB,YAAY,KAAK;AAAA,IACpE;AAAA,IACA,gBAAgB,QAAQ,WAAW;AAAA,EACrC,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,109 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
+ import { getIntegration } from "@open-mercato/shared/modules/integrations/types";
6
+ import { emitIntegrationsEvent } from "../../../events.js";
7
+ import { updateStateSchema } from "../../../data/validators.js";
8
+ import {
9
+ resolveUserFeatures,
10
+ runIntegrationMutationGuardAfterSuccess,
11
+ runIntegrationMutationGuards
12
+ } from "../../guards.js";
13
+ const idParamsSchema = z.object({ id: z.string().min(1) });
14
+ const metadata = {
15
+ PUT: { requireAuth: true, requireFeatures: ["integrations.manage"] }
16
+ };
17
+ const openApi = {
18
+ tags: ["Integrations"],
19
+ summary: "Update integration state"
20
+ };
21
+ async function PUT(req, ctx) {
22
+ const auth = await getAuthFromRequest(req);
23
+ if (!auth?.tenantId || !auth.orgId) {
24
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
25
+ }
26
+ const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
27
+ const parsedParams = idParamsSchema.safeParse(rawParams);
28
+ if (!parsedParams.success) {
29
+ return NextResponse.json({ error: "Invalid integration id" }, { status: 400 });
30
+ }
31
+ const integration = getIntegration(parsedParams.data.id);
32
+ if (!integration) {
33
+ return NextResponse.json({ error: "Integration not found" }, { status: 404 });
34
+ }
35
+ const payload = await req.json().catch(() => null);
36
+ const parsedBody = updateStateSchema.safeParse(payload);
37
+ if (!parsedBody.success) {
38
+ return NextResponse.json({ error: "Invalid state payload", details: parsedBody.error.flatten() }, { status: 422 });
39
+ }
40
+ const container = await createRequestContainer();
41
+ const guardResult = await runIntegrationMutationGuards(
42
+ container,
43
+ {
44
+ tenantId: auth.tenantId,
45
+ organizationId: auth.orgId,
46
+ userId: auth.sub ?? "",
47
+ resourceKind: "integrations.integration",
48
+ resourceId: integration.id,
49
+ operation: "update",
50
+ requestMethod: req.method,
51
+ requestHeaders: req.headers,
52
+ mutationPayload: parsedBody.data
53
+ },
54
+ resolveUserFeatures(auth)
55
+ );
56
+ if (!guardResult.ok) {
57
+ return NextResponse.json(guardResult.errorBody ?? { error: "Operation blocked by guard" }, { status: guardResult.errorStatus ?? 422 });
58
+ }
59
+ let payloadData = parsedBody.data;
60
+ if (guardResult.modifiedPayload) {
61
+ const mergedPayload = { ...parsedBody.data, ...guardResult.modifiedPayload };
62
+ const reparsed = updateStateSchema.safeParse(mergedPayload);
63
+ if (!reparsed.success) {
64
+ return NextResponse.json({ error: "Invalid state payload after guard transform", details: reparsed.error.flatten() }, { status: 422 });
65
+ }
66
+ payloadData = reparsed.data;
67
+ }
68
+ const stateService = container.resolve("integrationStateService");
69
+ const state = await stateService.upsert(
70
+ integration.id,
71
+ {
72
+ isEnabled: payloadData.isEnabled,
73
+ reauthRequired: payloadData.reauthRequired
74
+ },
75
+ {
76
+ organizationId: auth.orgId,
77
+ tenantId: auth.tenantId
78
+ }
79
+ );
80
+ await emitIntegrationsEvent("integrations.state.updated", {
81
+ integrationId: integration.id,
82
+ isEnabled: state.isEnabled,
83
+ reauthRequired: state.reauthRequired,
84
+ tenantId: auth.tenantId,
85
+ organizationId: auth.orgId,
86
+ userId: auth.sub
87
+ });
88
+ await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
89
+ tenantId: auth.tenantId,
90
+ organizationId: auth.orgId,
91
+ userId: auth.sub ?? "",
92
+ resourceKind: "integrations.integration",
93
+ resourceId: integration.id,
94
+ operation: "update",
95
+ requestMethod: req.method,
96
+ requestHeaders: req.headers
97
+ });
98
+ return NextResponse.json({
99
+ isEnabled: state.isEnabled,
100
+ reauthRequired: state.reauthRequired,
101
+ apiVersion: state.apiVersion ?? null
102
+ });
103
+ }
104
+ export {
105
+ PUT,
106
+ metadata,
107
+ openApi
108
+ };
109
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/integrations/api/%5Bid%5D/state/route.ts"],
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getIntegration } from '@open-mercato/shared/modules/integrations/types'\nimport { emitIntegrationsEvent } from '../../../events'\nimport { updateStateSchema } from '../../../data/validators'\nimport type { IntegrationStateService } from '../../../lib/state-service'\nimport {\n resolveUserFeatures,\n runIntegrationMutationGuardAfterSuccess,\n runIntegrationMutationGuards,\n} from '../../guards'\n\nconst idParamsSchema = z.object({ id: z.string().min(1) })\n\nexport const metadata = {\n PUT: { requireAuth: true, requireFeatures: ['integrations.manage'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'Update integration state',\n}\n\nexport async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const rawParams = (ctx.params && typeof (ctx.params as Promise<unknown>).then === 'function')\n ? await (ctx.params as Promise<{ id?: string }>)\n : (ctx.params as { id?: string } | undefined)\n\n const parsedParams = idParamsSchema.safeParse(rawParams)\n if (!parsedParams.success) {\n return NextResponse.json({ error: 'Invalid integration id' }, { status: 400 })\n }\n\n const integration = getIntegration(parsedParams.data.id)\n if (!integration) {\n return NextResponse.json({ error: 'Integration not found' }, { status: 404 })\n }\n\n const payload = await req.json().catch(() => null)\n const parsedBody = updateStateSchema.safeParse(payload)\n if (!parsedBody.success) {\n return NextResponse.json({ error: 'Invalid state payload', details: parsedBody.error.flatten() }, { status: 422 })\n }\n\n const container = await createRequestContainer()\n const guardResult = await runIntegrationMutationGuards(\n container,\n {\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n userId: auth.sub ?? '',\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsedBody.data as Record<string, unknown>,\n },\n resolveUserFeatures(auth),\n )\n if (!guardResult.ok) {\n return NextResponse.json(guardResult.errorBody ?? { error: 'Operation blocked by guard' }, { status: guardResult.errorStatus ?? 422 })\n }\n\n let payloadData = parsedBody.data\n if (guardResult.modifiedPayload) {\n const mergedPayload = { ...parsedBody.data, ...guardResult.modifiedPayload }\n const reparsed = updateStateSchema.safeParse(mergedPayload)\n if (!reparsed.success) {\n return NextResponse.json({ error: 'Invalid state payload after guard transform', details: reparsed.error.flatten() }, { status: 422 })\n }\n payloadData = reparsed.data\n }\n\n const stateService = container.resolve('integrationStateService') as IntegrationStateService\n\n const state = await stateService.upsert(\n integration.id,\n {\n isEnabled: payloadData.isEnabled,\n reauthRequired: payloadData.reauthRequired,\n },\n {\n organizationId: auth.orgId as string,\n tenantId: auth.tenantId,\n },\n )\n\n await emitIntegrationsEvent('integrations.state.updated', {\n integrationId: integration.id,\n isEnabled: state.isEnabled,\n reauthRequired: state.reauthRequired,\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n userId: auth.sub,\n })\n\n await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n userId: auth.sub ?? '',\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n\n return NextResponse.json({\n isEnabled: state.isEnabled,\n reauthRequired: state.reauthRequired,\n apiVersion: state.apiVersion ?? null,\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,yBAAyB;AAElC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;AAElD,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,qBAAqB,EAAE;AACrE;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,cAAc;AAAA,EACrB,SAAS;AACX;AAEA,eAAsB,IAAI,KAAc,KAA8D;AACpG,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,YAAY,CAAC,KAAK,OAAO;AAClC,WAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrE;AAEA,QAAM,YAAa,IAAI,UAAU,OAAQ,IAAI,OAA4B,SAAS,aAC9E,MAAO,IAAI,SACV,IAAI;AAET,QAAM,eAAe,eAAe,UAAU,SAAS;AACvD,MAAI,CAAC,aAAa,SAAS;AACzB,WAAO,aAAa,KAAK,EAAE,OAAO,yBAAyB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/E;AAEA,QAAM,cAAc,eAAe,aAAa,KAAK,EAAE;AACvD,MAAI,CAAC,aAAa;AAChB,WAAO,aAAa,KAAK,EAAE,OAAO,wBAAwB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC9E;AAEA,QAAM,UAAU,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AACjD,QAAM,aAAa,kBAAkB,UAAU,OAAO;AACtD,MAAI,CAAC,WAAW,SAAS;AACvB,WAAO,aAAa,KAAK,EAAE,OAAO,yBAAyB,SAAS,WAAW,MAAM,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACnH;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,cAAc,MAAM;AAAA,IACxB;AAAA,IACA;AAAA,MACA,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,QAAQ,KAAK,OAAO;AAAA,MACpB,cAAc;AAAA,MACd,YAAY,YAAY;AAAA,MACxB,WAAW;AAAA,MACX,eAAe,IAAI;AAAA,MACnB,gBAAgB,IAAI;AAAA,MACpB,iBAAiB,WAAW;AAAA,IAC5B;AAAA,IACA,oBAAoB,IAAI;AAAA,EAC1B;AACA,MAAI,CAAC,YAAY,IAAI;AACnB,WAAO,aAAa,KAAK,YAAY,aAAa,EAAE,OAAO,6BAA6B,GAAG,EAAE,QAAQ,YAAY,eAAe,IAAI,CAAC;AAAA,EACvI;AAEA,MAAI,cAAc,WAAW;AAC7B,MAAI,YAAY,iBAAiB;AAC/B,UAAM,gBAAgB,EAAE,GAAG,WAAW,MAAM,GAAG,YAAY,gBAAgB;AAC3E,UAAM,WAAW,kBAAkB,UAAU,aAAa;AAC1D,QAAI,CAAC,SAAS,SAAS;AACrB,aAAO,aAAa,KAAK,EAAE,OAAO,+CAA+C,SAAS,SAAS,MAAM,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACvI;AACA,kBAAc,SAAS;AAAA,EACzB;AAEA,QAAM,eAAe,UAAU,QAAQ,yBAAyB;AAEhE,QAAM,QAAQ,MAAM,aAAa;AAAA,IAC/B,YAAY;AAAA,IACZ;AAAA,MACE,WAAW,YAAY;AAAA,MACvB,gBAAgB,YAAY;AAAA,IAC9B;AAAA,IACA;AAAA,MACE,gBAAgB,KAAK;AAAA,MACrB,UAAU,KAAK;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,sBAAsB,8BAA8B;AAAA,IACxD,eAAe,YAAY;AAAA,IAC3B,WAAW,MAAM;AAAA,IACjB,gBAAgB,MAAM;AAAA,IACtB,UAAU,KAAK;AAAA,IACf,gBAAgB,KAAK;AAAA,IACrB,QAAQ,KAAK;AAAA,EACf,CAAC;AAED,QAAM,wCAAwC,YAAY,uBAAuB;AAAA,IAC7E,UAAU,KAAK;AAAA,IACf,gBAAgB,KAAK;AAAA,IACrB,QAAQ,KAAK,OAAO;AAAA,IACpB,cAAc;AAAA,IACd,YAAY,YAAY;AAAA,IACxB,WAAW;AAAA,IACX,eAAe,IAAI;AAAA,IACnB,gBAAgB,IAAI;AAAA,EACtB,CAAC;AAEH,SAAO,aAAa,KAAK;AAAA,IACvB,WAAW,MAAM;AAAA,IACjB,gBAAgB,MAAM;AAAA,IACtB,YAAY,MAAM,cAAc;AAAA,EAClC,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,117 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
+ import { getIntegration } from "@open-mercato/shared/modules/integrations/types";
6
+ import { emitIntegrationsEvent } from "../../../events.js";
7
+ import { updateVersionSchema } from "../../../data/validators.js";
8
+ import { resolveDefaultApiVersion } from "../../../lib/registry-service.js";
9
+ import {
10
+ resolveUserFeatures,
11
+ runIntegrationMutationGuardAfterSuccess,
12
+ runIntegrationMutationGuards
13
+ } from "../../guards.js";
14
+ const idParamsSchema = z.object({ id: z.string().min(1) });
15
+ const metadata = {
16
+ PUT: { requireAuth: true, requireFeatures: ["integrations.manage"] }
17
+ };
18
+ const openApi = {
19
+ tags: ["Integrations"],
20
+ summary: "Change integration API version"
21
+ };
22
+ async function PUT(req, ctx) {
23
+ const auth = await getAuthFromRequest(req);
24
+ if (!auth?.tenantId || !auth.orgId) {
25
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
26
+ }
27
+ const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
28
+ const parsedParams = idParamsSchema.safeParse(rawParams);
29
+ if (!parsedParams.success) {
30
+ return NextResponse.json({ error: "Invalid integration id" }, { status: 400 });
31
+ }
32
+ const integration = getIntegration(parsedParams.data.id);
33
+ if (!integration) {
34
+ return NextResponse.json({ error: "Integration not found" }, { status: 404 });
35
+ }
36
+ const payload = await req.json().catch(() => null);
37
+ const parsedBody = updateVersionSchema.safeParse(payload);
38
+ if (!parsedBody.success) {
39
+ return NextResponse.json({ error: "Invalid payload", details: parsedBody.error.flatten() }, { status: 422 });
40
+ }
41
+ const requestedVersion = parsedBody.data.apiVersion;
42
+ const availableVersions = integration.apiVersions ?? [];
43
+ if (availableVersions.length === 0) {
44
+ return NextResponse.json({ error: "This integration is not versioned" }, { status: 422 });
45
+ }
46
+ const exists = availableVersions.some((version) => version.id === requestedVersion);
47
+ if (!exists) {
48
+ return NextResponse.json({ error: "Unknown integration version" }, { status: 422 });
49
+ }
50
+ const defaultVersion = resolveDefaultApiVersion(availableVersions);
51
+ if (!defaultVersion) {
52
+ return NextResponse.json({ error: "Integration version configuration is invalid" }, { status: 422 });
53
+ }
54
+ const container = await createRequestContainer();
55
+ const guardResult = await runIntegrationMutationGuards(
56
+ container,
57
+ {
58
+ tenantId: auth.tenantId,
59
+ organizationId: auth.orgId,
60
+ userId: auth.sub ?? "",
61
+ resourceKind: "integrations.integration",
62
+ resourceId: integration.id,
63
+ operation: "update",
64
+ requestMethod: req.method,
65
+ requestHeaders: req.headers,
66
+ mutationPayload: parsedBody.data
67
+ },
68
+ resolveUserFeatures(auth)
69
+ );
70
+ if (!guardResult.ok) {
71
+ return NextResponse.json(guardResult.errorBody ?? { error: "Operation blocked by guard" }, { status: guardResult.errorStatus ?? 422 });
72
+ }
73
+ let payloadData = parsedBody.data;
74
+ if (guardResult.modifiedPayload) {
75
+ const mergedPayload = { ...parsedBody.data, ...guardResult.modifiedPayload };
76
+ const reparsed = updateVersionSchema.safeParse(mergedPayload);
77
+ if (!reparsed.success) {
78
+ return NextResponse.json({ error: "Invalid payload after guard transform", details: reparsed.error.flatten() }, { status: 422 });
79
+ }
80
+ payloadData = reparsed.data;
81
+ }
82
+ if (!availableVersions.some((version) => version.id === payloadData.apiVersion)) {
83
+ return NextResponse.json({ error: "Unknown integration version" }, { status: 422 });
84
+ }
85
+ const stateService = container.resolve("integrationStateService");
86
+ const scope = { organizationId: auth.orgId, tenantId: auth.tenantId };
87
+ const before = await stateService.resolveApiVersion(integration.id, scope);
88
+ await stateService.upsert(integration.id, { apiVersion: payloadData.apiVersion }, scope);
89
+ await emitIntegrationsEvent("integrations.version.changed", {
90
+ integrationId: integration.id,
91
+ previousVersion: before ?? defaultVersion,
92
+ apiVersion: payloadData.apiVersion,
93
+ tenantId: auth.tenantId,
94
+ organizationId: auth.orgId,
95
+ userId: auth.sub
96
+ });
97
+ await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
98
+ tenantId: auth.tenantId,
99
+ organizationId: auth.orgId,
100
+ userId: auth.sub ?? "",
101
+ resourceKind: "integrations.integration",
102
+ resourceId: integration.id,
103
+ operation: "update",
104
+ requestMethod: req.method,
105
+ requestHeaders: req.headers
106
+ });
107
+ return NextResponse.json({
108
+ apiVersion: payloadData.apiVersion,
109
+ previousVersion: before ?? defaultVersion
110
+ });
111
+ }
112
+ export {
113
+ PUT,
114
+ metadata,
115
+ openApi
116
+ };
117
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/integrations/api/%5Bid%5D/version/route.ts"],
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getIntegration } from '@open-mercato/shared/modules/integrations/types'\nimport { emitIntegrationsEvent } from '../../../events'\nimport { updateVersionSchema } from '../../../data/validators'\nimport type { IntegrationStateService } from '../../../lib/state-service'\nimport { resolveDefaultApiVersion } from '../../../lib/registry-service'\nimport {\n resolveUserFeatures,\n runIntegrationMutationGuardAfterSuccess,\n runIntegrationMutationGuards,\n} from '../../guards'\n\nconst idParamsSchema = z.object({ id: z.string().min(1) })\n\nexport const metadata = {\n PUT: { requireAuth: true, requireFeatures: ['integrations.manage'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'Change integration API version',\n}\n\nexport async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const rawParams = (ctx.params && typeof (ctx.params as Promise<unknown>).then === 'function')\n ? await (ctx.params as Promise<{ id?: string }>)\n : (ctx.params as { id?: string } | undefined)\n\n const parsedParams = idParamsSchema.safeParse(rawParams)\n if (!parsedParams.success) {\n return NextResponse.json({ error: 'Invalid integration id' }, { status: 400 })\n }\n\n const integration = getIntegration(parsedParams.data.id)\n if (!integration) {\n return NextResponse.json({ error: 'Integration not found' }, { status: 404 })\n }\n\n const payload = await req.json().catch(() => null)\n const parsedBody = updateVersionSchema.safeParse(payload)\n if (!parsedBody.success) {\n return NextResponse.json({ error: 'Invalid payload', details: parsedBody.error.flatten() }, { status: 422 })\n }\n\n const requestedVersion = parsedBody.data.apiVersion\n const availableVersions = integration.apiVersions ?? []\n if (availableVersions.length === 0) {\n return NextResponse.json({ error: 'This integration is not versioned' }, { status: 422 })\n }\n\n const exists = availableVersions.some((version) => version.id === requestedVersion)\n if (!exists) {\n return NextResponse.json({ error: 'Unknown integration version' }, { status: 422 })\n }\n\n const defaultVersion = resolveDefaultApiVersion(availableVersions)\n if (!defaultVersion) {\n return NextResponse.json({ error: 'Integration version configuration is invalid' }, { status: 422 })\n }\n\n const container = await createRequestContainer()\n const guardResult = await runIntegrationMutationGuards(\n container,\n {\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n userId: auth.sub ?? '',\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsedBody.data as Record<string, unknown>,\n },\n resolveUserFeatures(auth),\n )\n if (!guardResult.ok) {\n return NextResponse.json(guardResult.errorBody ?? { error: 'Operation blocked by guard' }, { status: guardResult.errorStatus ?? 422 })\n }\n\n let payloadData = parsedBody.data\n if (guardResult.modifiedPayload) {\n const mergedPayload = { ...parsedBody.data, ...guardResult.modifiedPayload }\n const reparsed = updateVersionSchema.safeParse(mergedPayload)\n if (!reparsed.success) {\n return NextResponse.json({ error: 'Invalid payload after guard transform', details: reparsed.error.flatten() }, { status: 422 })\n }\n payloadData = reparsed.data\n }\n if (!availableVersions.some((version) => version.id === payloadData.apiVersion)) {\n return NextResponse.json({ error: 'Unknown integration version' }, { status: 422 })\n }\n\n const stateService = container.resolve('integrationStateService') as IntegrationStateService\n const scope = { organizationId: auth.orgId as string, tenantId: auth.tenantId }\n\n const before = await stateService.resolveApiVersion(integration.id, scope)\n await stateService.upsert(integration.id, { apiVersion: payloadData.apiVersion }, scope)\n\n await emitIntegrationsEvent('integrations.version.changed', {\n integrationId: integration.id,\n previousVersion: before ?? defaultVersion,\n apiVersion: payloadData.apiVersion,\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n userId: auth.sub,\n })\n\n await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n userId: auth.sub ?? '',\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n\n return NextResponse.json({\n apiVersion: payloadData.apiVersion,\n previousVersion: before ?? defaultVersion,\n })\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ bridgeLegacyGuard,
3
+ runMutationGuards
4
+ } from "@open-mercato/shared/lib/crud/mutation-guard-registry";
5
+ function resolveUserFeatures(auth) {
6
+ const features = auth?.features;
7
+ if (!Array.isArray(features)) return [];
8
+ return features.filter((value) => typeof value === "string");
9
+ }
10
+ async function runIntegrationMutationGuards(container, input, userFeatures) {
11
+ const legacyGuard = bridgeLegacyGuard(container);
12
+ if (!legacyGuard) {
13
+ return { ok: true, afterSuccessCallbacks: [] };
14
+ }
15
+ return runMutationGuards([legacyGuard], input, { userFeatures });
16
+ }
17
+ async function runIntegrationMutationGuardAfterSuccess(callbacks, input) {
18
+ for (const callback of callbacks) {
19
+ if (!callback.guard.afterSuccess) continue;
20
+ await callback.guard.afterSuccess({
21
+ ...input,
22
+ metadata: callback.metadata ?? null
23
+ });
24
+ }
25
+ }
26
+ export {
27
+ resolveUserFeatures,
28
+ runIntegrationMutationGuardAfterSuccess,
29
+ runIntegrationMutationGuards
30
+ };
31
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/integrations/api/guards.ts"],
4
+ "sourcesContent": ["import type { AwilixContainer } from 'awilix'\nimport {\n bridgeLegacyGuard,\n runMutationGuards,\n type MutationGuard,\n type MutationGuardInput,\n} from '@open-mercato/shared/lib/crud/mutation-guard-registry'\n\ntype GuardAfterCallback = {\n guard: MutationGuard\n metadata: Record<string, unknown> | null\n}\n\nexport function resolveUserFeatures(auth: unknown): string[] {\n const features = (auth as { features?: unknown })?.features\n if (!Array.isArray(features)) return []\n return features.filter((value): value is string => typeof value === 'string')\n}\n\nexport async function runIntegrationMutationGuards(\n container: AwilixContainer,\n input: MutationGuardInput,\n userFeatures: string[],\n): Promise<{\n ok: boolean\n errorBody?: Record<string, unknown>\n errorStatus?: number\n modifiedPayload?: Record<string, unknown>\n afterSuccessCallbacks: GuardAfterCallback[]\n}> {\n const legacyGuard = bridgeLegacyGuard(container)\n if (!legacyGuard) {\n return { ok: true, afterSuccessCallbacks: [] }\n }\n\n return runMutationGuards([legacyGuard], input, { userFeatures })\n}\n\nexport async function runIntegrationMutationGuardAfterSuccess(\n callbacks: GuardAfterCallback[],\n input: {\n tenantId: string\n organizationId: string | null\n userId: string\n resourceKind: string\n resourceId: string\n operation: 'create' | 'update' | 'delete'\n requestMethod: string\n requestHeaders: Headers\n },\n): Promise<void> {\n for (const callback of callbacks) {\n if (!callback.guard.afterSuccess) continue\n await callback.guard.afterSuccess({\n ...input,\n metadata: callback.metadata ?? null,\n })\n }\n}\n"],
5
+ "mappings": "AACA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAOA,SAAS,oBAAoB,MAAyB;AAC3D,QAAM,WAAY,MAAiC;AACnD,MAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG,QAAO,CAAC;AACtC,SAAO,SAAS,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ;AAC9E;AAEA,eAAsB,6BACpB,WACA,OACA,cAOC;AACD,QAAM,cAAc,kBAAkB,SAAS;AAC/C,MAAI,CAAC,aAAa;AAChB,WAAO,EAAE,IAAI,MAAM,uBAAuB,CAAC,EAAE;AAAA,EAC/C;AAEA,SAAO,kBAAkB,CAAC,WAAW,GAAG,OAAO,EAAE,aAAa,CAAC;AACjE;AAEA,eAAsB,wCACpB,WACA,OAUe;AACf,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,SAAS,MAAM,aAAc;AAClC,UAAM,SAAS,MAAM,aAAa;AAAA,MAChC,GAAG;AAAA,MACH,UAAU,SAAS,YAAY;AAAA,IACjC,CAAC;AAAA,EACH;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,60 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
3
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
+ import { listIntegrationLogsQuerySchema } from "../../data/validators.js";
5
+ const metadata = {
6
+ GET: { requireAuth: true, requireFeatures: ["integrations.view"] }
7
+ };
8
+ const openApi = {
9
+ tags: ["Integrations"],
10
+ summary: "List integration logs"
11
+ };
12
+ async function GET(req) {
13
+ const auth = await getAuthFromRequest(req);
14
+ if (!auth?.tenantId || !auth.orgId) {
15
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
16
+ }
17
+ const url = new URL(req.url);
18
+ const parsed = listIntegrationLogsQuerySchema.safeParse({
19
+ integrationId: url.searchParams.get("integrationId") ?? void 0,
20
+ level: url.searchParams.get("level") ?? void 0,
21
+ runId: url.searchParams.get("runId") ?? void 0,
22
+ entityType: url.searchParams.get("entityType") ?? void 0,
23
+ entityId: url.searchParams.get("entityId") ?? void 0,
24
+ page: url.searchParams.get("page") ?? void 0,
25
+ pageSize: url.searchParams.get("pageSize") ?? void 0
26
+ });
27
+ if (!parsed.success) {
28
+ return NextResponse.json({ error: "Invalid query", details: parsed.error.flatten() }, { status: 400 });
29
+ }
30
+ const container = await createRequestContainer();
31
+ const logService = container.resolve("integrationLogService");
32
+ const { items, total } = await logService.query(parsed.data, {
33
+ organizationId: auth.orgId,
34
+ tenantId: auth.tenantId
35
+ });
36
+ return NextResponse.json({
37
+ items: items.map((item) => ({
38
+ id: item.id,
39
+ integrationId: item.integrationId,
40
+ runId: item.runId ?? null,
41
+ scopeEntityType: item.scopeEntityType ?? null,
42
+ scopeEntityId: item.scopeEntityId ?? null,
43
+ level: item.level,
44
+ message: item.message,
45
+ code: item.code ?? null,
46
+ payload: item.payload ?? null,
47
+ createdAt: item.createdAt.toISOString()
48
+ })),
49
+ total,
50
+ page: parsed.data.page,
51
+ pageSize: parsed.data.pageSize,
52
+ totalPages: Math.max(1, Math.ceil(total / parsed.data.pageSize))
53
+ });
54
+ }
55
+ export {
56
+ GET,
57
+ metadata,
58
+ openApi
59
+ };
60
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/integrations/api/logs/route.ts"],
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { listIntegrationLogsQuerySchema } from '../../data/validators'\nimport type { IntegrationLogService } from '../../lib/log-service'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.view'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'List integration logs',\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const url = new URL(req.url)\n const parsed = listIntegrationLogsQuerySchema.safeParse({\n integrationId: url.searchParams.get('integrationId') ?? undefined,\n level: url.searchParams.get('level') ?? undefined,\n runId: url.searchParams.get('runId') ?? undefined,\n entityType: url.searchParams.get('entityType') ?? undefined,\n entityId: url.searchParams.get('entityId') ?? undefined,\n page: url.searchParams.get('page') ?? undefined,\n pageSize: url.searchParams.get('pageSize') ?? undefined,\n })\n\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid query', details: parsed.error.flatten() }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const logService = container.resolve('integrationLogService') as IntegrationLogService\n\n const { items, total } = await logService.query(parsed.data, {\n organizationId: auth.orgId as string,\n tenantId: auth.tenantId,\n })\n\n return NextResponse.json({\n items: items.map((item) => ({\n id: item.id,\n integrationId: item.integrationId,\n runId: item.runId ?? null,\n scopeEntityType: item.scopeEntityType ?? null,\n scopeEntityId: item.scopeEntityId ?? null,\n level: item.level,\n message: item.message,\n code: item.code ?? null,\n payload: item.payload ?? null,\n createdAt: item.createdAt.toISOString(),\n })),\n total,\n page: parsed.data.page,\n pageSize: parsed.data.pageSize,\n totalPages: Math.max(1, Math.ceil(total / parsed.data.pageSize)),\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,sCAAsC;AAGxC,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,mBAAmB,EAAE;AACnE;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,cAAc;AAAA,EACrB,SAAS;AACX;AAEA,eAAsB,IAAI,KAAc;AACtC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,YAAY,CAAC,KAAK,OAAO;AAClC,WAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrE;AAEA,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,QAAM,SAAS,+BAA+B,UAAU;AAAA,IACtD,eAAe,IAAI,aAAa,IAAI,eAAe,KAAK;AAAA,IACxD,OAAO,IAAI,aAAa,IAAI,OAAO,KAAK;AAAA,IACxC,OAAO,IAAI,aAAa,IAAI,OAAO,KAAK;AAAA,IACxC,YAAY,IAAI,aAAa,IAAI,YAAY,KAAK;AAAA,IAClD,UAAU,IAAI,aAAa,IAAI,UAAU,KAAK;AAAA,IAC9C,MAAM,IAAI,aAAa,IAAI,MAAM,KAAK;AAAA,IACtC,UAAU,IAAI,aAAa,IAAI,UAAU,KAAK;AAAA,EAChD,CAAC;AAED,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,aAAa,KAAK,EAAE,OAAO,iBAAiB,SAAS,OAAO,MAAM,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACvG;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,aAAa,UAAU,QAAQ,uBAAuB;AAE5D,QAAM,EAAE,OAAO,MAAM,IAAI,MAAM,WAAW,MAAM,OAAO,MAAM;AAAA,IAC3D,gBAAgB,KAAK;AAAA,IACrB,UAAU,KAAK;AAAA,EACjB,CAAC;AAED,SAAO,aAAa,KAAK;AAAA,IACvB,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,MAC1B,IAAI,KAAK;AAAA,MACT,eAAe,KAAK;AAAA,MACpB,OAAO,KAAK,SAAS;AAAA,MACrB,iBAAiB,KAAK,mBAAmB;AAAA,MACzC,eAAe,KAAK,iBAAiB;AAAA,MACrC,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,MAAM,KAAK,QAAQ;AAAA,MACnB,SAAS,KAAK,WAAW;AAAA,MACzB,WAAW,KAAK,UAAU,YAAY;AAAA,IACxC,EAAE;AAAA,IACF;AAAA,IACA,MAAM,OAAO,KAAK;AAAA,IAClB,UAAU,OAAO,KAAK;AAAA,IACtB,YAAY,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,OAAO,KAAK,QAAQ,CAAC;AAAA,EACjE,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ import { createCrudOpenApiFactory, createPagedListResponseSchema as createSharedPagedListResponseSchema } from "@open-mercato/shared/lib/openapi/crud";
3
+ function createPagedListResponseSchema(itemSchema) {
4
+ return createSharedPagedListResponseSchema(itemSchema, { paginationMetaOptional: true });
5
+ }
6
+ const integrationInfoSchema = z.object({
7
+ id: z.string(),
8
+ title: z.string(),
9
+ category: z.string().nullable(),
10
+ hub: z.string().nullable(),
11
+ providerKey: z.string().nullable(),
12
+ bundleId: z.string().nullable(),
13
+ hasCredentials: z.boolean(),
14
+ isEnabled: z.boolean(),
15
+ apiVersion: z.string().nullable()
16
+ });
17
+ const buildIntegrationsCrudOpenApi = createCrudOpenApiFactory({
18
+ defaultTag: "Integrations"
19
+ });
20
+ export {
21
+ buildIntegrationsCrudOpenApi,
22
+ createPagedListResponseSchema,
23
+ integrationInfoSchema
24
+ };
25
+ //# sourceMappingURL=openapi.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/integrations/api/openapi.ts"],
4
+ "sourcesContent": ["import { z, type ZodTypeAny } from 'zod'\nimport { createCrudOpenApiFactory, createPagedListResponseSchema as createSharedPagedListResponseSchema } from '@open-mercato/shared/lib/openapi/crud'\n\nexport function createPagedListResponseSchema(itemSchema: ZodTypeAny) {\n return createSharedPagedListResponseSchema(itemSchema, { paginationMetaOptional: true })\n}\n\nexport const integrationInfoSchema = z.object({\n id: z.string(),\n title: z.string(),\n category: z.string().nullable(),\n hub: z.string().nullable(),\n providerKey: z.string().nullable(),\n bundleId: z.string().nullable(),\n hasCredentials: z.boolean(),\n isEnabled: z.boolean(),\n apiVersion: z.string().nullable(),\n})\n\nexport const buildIntegrationsCrudOpenApi = createCrudOpenApiFactory({\n defaultTag: 'Integrations',\n})\n"],
5
+ "mappings": "AAAA,SAAS,SAA0B;AACnC,SAAS,0BAA0B,iCAAiC,2CAA2C;AAExG,SAAS,8BAA8B,YAAwB;AACpE,SAAO,oCAAoC,YAAY,EAAE,wBAAwB,KAAK,CAAC;AACzF;AAEO,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,IAAI,EAAE,OAAO;AAAA,EACb,OAAO,EAAE,OAAO;AAAA,EAChB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA,EACzB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,gBAAgB,EAAE,QAAQ;AAAA,EAC1B,WAAW,EAAE,QAAQ;AAAA,EACrB,YAAY,EAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AAEM,MAAM,+BAA+B,yBAAyB;AAAA,EACnE,YAAY;AACd,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,68 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
3
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
+ import { getAllBundles, getAllIntegrations } from "@open-mercato/shared/modules/integrations/types";
5
+ import { buildIntegrationsCrudOpenApi, createPagedListResponseSchema, integrationInfoSchema } from "./openapi.js";
6
+ const metadata = {
7
+ GET: { requireAuth: true, requireFeatures: ["integrations.view"] }
8
+ };
9
+ const openApi = buildIntegrationsCrudOpenApi({
10
+ resourceName: "Integration",
11
+ pluralName: "Integrations",
12
+ listResponseSchema: createPagedListResponseSchema(integrationInfoSchema),
13
+ querySchema: void 0
14
+ });
15
+ async function GET(req) {
16
+ const auth = await getAuthFromRequest(req);
17
+ if (!auth?.tenantId || !auth.orgId) {
18
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
19
+ }
20
+ const container = await createRequestContainer();
21
+ const credentialsService = container.resolve("integrationCredentialsService");
22
+ const stateService = container.resolve("integrationStateService");
23
+ const rows = await Promise.all(
24
+ getAllIntegrations().map(async (integration) => {
25
+ const [resolvedCredentials, state] = await Promise.all([
26
+ credentialsService.resolve(integration.id, { organizationId: auth.orgId, tenantId: auth.tenantId }),
27
+ stateService.get(integration.id, { organizationId: auth.orgId, tenantId: auth.tenantId })
28
+ ]);
29
+ return {
30
+ id: integration.id,
31
+ title: integration.title,
32
+ category: integration.category ?? null,
33
+ hub: integration.hub ?? null,
34
+ providerKey: integration.providerKey ?? null,
35
+ bundleId: integration.bundleId ?? null,
36
+ hasCredentials: Boolean(resolvedCredentials),
37
+ isEnabled: state?.isEnabled ?? true,
38
+ apiVersion: state?.apiVersion ?? null
39
+ };
40
+ })
41
+ );
42
+ const bundles = getAllBundles().map((bundle) => {
43
+ const bundleIntegrations = rows.filter((row) => row.bundleId === bundle.id);
44
+ const enabledCount = bundleIntegrations.reduce((count, integration) => count + (integration.isEnabled ? 1 : 0), 0);
45
+ return {
46
+ id: bundle.id,
47
+ title: bundle.title,
48
+ description: bundle.description,
49
+ icon: bundle.icon ?? null,
50
+ integrationCount: bundleIntegrations.length,
51
+ enabledCount
52
+ };
53
+ });
54
+ return NextResponse.json({
55
+ items: rows,
56
+ bundles,
57
+ total: rows.length,
58
+ page: 1,
59
+ pageSize: 100,
60
+ totalPages: 1
61
+ });
62
+ }
63
+ export {
64
+ GET,
65
+ metadata,
66
+ openApi
67
+ };
68
+ //# sourceMappingURL=route.js.map