@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.
- package/AGENTS.md +10 -0
- package/dist/generated/entities/integration_credentials/index.js +19 -0
- package/dist/generated/entities/integration_credentials/index.js.map +7 -0
- package/dist/generated/entities/integration_log/index.js +27 -0
- package/dist/generated/entities/integration_log/index.js.map +7 -0
- package/dist/generated/entities/integration_state/index.js +27 -0
- package/dist/generated/entities/integration_state/index.js.map +7 -0
- package/dist/generated/entities/sync_cursor/index.js +19 -0
- package/dist/generated/entities/sync_cursor/index.js.map +7 -0
- package/dist/generated/entities/sync_external_id_mapping/index.js +27 -0
- package/dist/generated/entities/sync_external_id_mapping/index.js.map +7 -0
- package/dist/generated/entities/sync_mapping/index.js +19 -0
- package/dist/generated/entities/sync_mapping/index.js.map +7 -0
- package/dist/generated/entities/sync_run/index.js +45 -0
- package/dist/generated/entities/sync_run/index.js.map +7 -0
- package/dist/generated/entities/sync_schedule/index.js +35 -0
- package/dist/generated/entities/sync_schedule/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +14 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +16 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/data_sync/acl.js +11 -0
- package/dist/modules/data_sync/acl.js.map +7 -0
- package/dist/modules/data_sync/api/mappings/[id]/route.js +137 -0
- package/dist/modules/data_sync/api/mappings/[id]/route.js.map +7 -0
- package/dist/modules/data_sync/api/mappings/route.js +132 -0
- package/dist/modules/data_sync/api/mappings/route.js.map +7 -0
- package/dist/modules/data_sync/api/run.js +87 -0
- package/dist/modules/data_sync/api/run.js.map +7 -0
- package/dist/modules/data_sync/api/runs/[id]/cancel.js +49 -0
- package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +7 -0
- package/dist/modules/data_sync/api/runs/[id]/retry.js +93 -0
- package/dist/modules/data_sync/api/runs/[id]/retry.js.map +7 -0
- package/dist/modules/data_sync/api/runs/[id]/route.js +69 -0
- package/dist/modules/data_sync/api/runs/[id]/route.js.map +7 -0
- package/dist/modules/data_sync/api/runs.js +66 -0
- package/dist/modules/data_sync/api/runs.js.map +7 -0
- package/dist/modules/data_sync/api/validate.js +66 -0
- package/dist/modules/data_sync/api/validate.js.map +7 -0
- package/dist/modules/data_sync/backend/data-sync/page.js +216 -0
- package/dist/modules/data_sync/backend/data-sync/page.js.map +7 -0
- package/dist/modules/data_sync/backend/data-sync/page.meta.js +25 -0
- package/dist/modules/data_sync/backend/data-sync/page.meta.js.map +7 -0
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +178 -0
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +7 -0
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.meta.js +14 -0
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.meta.js.map +7 -0
- package/dist/modules/data_sync/data/entities.js +228 -0
- package/dist/modules/data_sync/data/entities.js.map +7 -0
- package/dist/modules/data_sync/data/validators.js +32 -0
- package/dist/modules/data_sync/data/validators.js.map +7 -0
- package/dist/modules/data_sync/di.js +26 -0
- package/dist/modules/data_sync/di.js.map +7 -0
- package/dist/modules/data_sync/events.js +16 -0
- package/dist/modules/data_sync/events.js.map +7 -0
- package/dist/modules/data_sync/index.js +9 -0
- package/dist/modules/data_sync/index.js.map +7 -0
- package/dist/modules/data_sync/lib/adapter-registry.js +16 -0
- package/dist/modules/data_sync/lib/adapter-registry.js.map +7 -0
- package/dist/modules/data_sync/lib/adapter.js +1 -0
- package/dist/modules/data_sync/lib/adapter.js.map +7 -0
- package/dist/modules/data_sync/lib/id-mapping.js +79 -0
- package/dist/modules/data_sync/lib/id-mapping.js.map +7 -0
- package/dist/modules/data_sync/lib/queue.js +17 -0
- package/dist/modules/data_sync/lib/queue.js.map +7 -0
- package/dist/modules/data_sync/lib/sync-engine.js +309 -0
- package/dist/modules/data_sync/lib/sync-engine.js.map +7 -0
- package/dist/modules/data_sync/lib/sync-run-service.js +148 -0
- package/dist/modules/data_sync/lib/sync-run-service.js.map +7 -0
- package/dist/modules/data_sync/migrations/Migration20260304113737.js +17 -0
- package/dist/modules/data_sync/migrations/Migration20260304113737.js.map +7 -0
- package/dist/modules/data_sync/setup.js +13 -0
- package/dist/modules/data_sync/setup.js.map +7 -0
- package/dist/modules/data_sync/workers/sync-export.js +14 -0
- package/dist/modules/data_sync/workers/sync-export.js.map +7 -0
- package/dist/modules/data_sync/workers/sync-import.js +14 -0
- package/dist/modules/data_sync/workers/sync-import.js.map +7 -0
- package/dist/modules/data_sync/workers/sync-scheduled.js +63 -0
- package/dist/modules/data_sync/workers/sync-scheduled.js.map +7 -0
- package/dist/modules/entities/lib/encryptionDefaults.js +4 -0
- package/dist/modules/entities/lib/encryptionDefaults.js.map +2 -2
- package/dist/modules/integrations/acl.js +4 -1
- package/dist/modules/integrations/acl.js.map +2 -2
- package/dist/modules/integrations/api/[id]/credentials/route.js +127 -0
- package/dist/modules/integrations/api/[id]/credentials/route.js.map +7 -0
- package/dist/modules/integrations/api/[id]/health/route.js +46 -0
- package/dist/modules/integrations/api/[id]/health/route.js.map +7 -0
- package/dist/modules/integrations/api/[id]/route.js +65 -0
- package/dist/modules/integrations/api/[id]/route.js.map +7 -0
- package/dist/modules/integrations/api/[id]/state/route.js +109 -0
- package/dist/modules/integrations/api/[id]/state/route.js.map +7 -0
- package/dist/modules/integrations/api/[id]/version/route.js +117 -0
- package/dist/modules/integrations/api/[id]/version/route.js.map +7 -0
- package/dist/modules/integrations/api/guards.js +31 -0
- package/dist/modules/integrations/api/guards.js.map +7 -0
- package/dist/modules/integrations/api/logs/route.js +60 -0
- package/dist/modules/integrations/api/logs/route.js.map +7 -0
- package/dist/modules/integrations/api/openapi.js +25 -0
- package/dist/modules/integrations/api/openapi.js.map +7 -0
- package/dist/modules/integrations/api/route.js +68 -0
- package/dist/modules/integrations/api/route.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/[id]/page.js +313 -0
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/[id]/page.meta.js +15 -0
- package/dist/modules/integrations/backend/integrations/[id]/page.meta.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +189 -0
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.meta.js +15 -0
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.meta.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/page.js +212 -0
- package/dist/modules/integrations/backend/integrations/page.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/page.meta.js +22 -0
- package/dist/modules/integrations/backend/integrations/page.meta.js.map +7 -0
- package/dist/modules/integrations/data/enrichers.js +27 -12
- package/dist/modules/integrations/data/enrichers.js.map +2 -2
- package/dist/modules/integrations/data/entities.js +136 -1
- package/dist/modules/integrations/data/entities.js.map +2 -2
- package/dist/modules/integrations/data/validators.js +36 -0
- package/dist/modules/integrations/data/validators.js.map +7 -0
- package/dist/modules/integrations/di.js +24 -0
- package/dist/modules/integrations/di.js.map +7 -0
- package/dist/modules/integrations/events.js +19 -0
- package/dist/modules/integrations/events.js.map +7 -0
- package/dist/modules/integrations/lib/credentials-service.js +159 -0
- package/dist/modules/integrations/lib/credentials-service.js.map +7 -0
- package/dist/modules/integrations/lib/health-service.js +37 -0
- package/dist/modules/integrations/lib/health-service.js.map +7 -0
- package/dist/modules/integrations/lib/log-service.js +66 -0
- package/dist/modules/integrations/lib/log-service.js.map +7 -0
- package/dist/modules/integrations/lib/registry-service.js +33 -0
- package/dist/modules/integrations/lib/registry-service.js.map +7 -0
- package/dist/modules/integrations/lib/state-service.js +55 -0
- package/dist/modules/integrations/lib/state-service.js.map +7 -0
- package/dist/modules/integrations/lib/types.js +1 -0
- package/dist/modules/integrations/lib/types.js.map +7 -0
- package/dist/modules/integrations/migrations/Migration20260304113737.js +19 -0
- package/dist/modules/integrations/migrations/Migration20260304113737.js.map +7 -0
- package/dist/modules/integrations/setup.js +2 -2
- package/dist/modules/integrations/setup.js.map +2 -2
- package/dist/modules/integrations/widgets/injection-table.js.map +1 -1
- package/dist/modules/integrations/workers/log-pruner.js +18 -0
- package/dist/modules/integrations/workers/log-pruner.js.map +7 -0
- package/generated/entities/integration_credentials/index.ts +8 -0
- package/generated/entities/integration_log/index.ts +12 -0
- package/generated/entities/integration_state/index.ts +12 -0
- package/generated/entities/sync_cursor/index.ts +8 -0
- package/generated/entities/sync_external_id_mapping/index.ts +12 -0
- package/generated/entities/sync_mapping/index.ts +8 -0
- package/generated/entities/sync_run/index.ts +21 -0
- package/generated/entities/sync_schedule/index.ts +16 -0
- package/generated/entities.ids.generated.ts +14 -0
- package/generated/entity-fields-registry.ts +16 -0
- package/package.json +2 -2
- package/src/modules/data_sync/AGENTS.md +157 -0
- package/src/modules/data_sync/acl.ts +7 -0
- package/src/modules/data_sync/api/mappings/[id]/route.ts +158 -0
- package/src/modules/data_sync/api/mappings/route.ts +144 -0
- package/src/modules/data_sync/api/run.ts +97 -0
- package/src/modules/data_sync/api/runs/[id]/cancel.ts +57 -0
- package/src/modules/data_sync/api/runs/[id]/retry.ts +108 -0
- package/src/modules/data_sync/api/runs/[id]/route.ts +81 -0
- package/src/modules/data_sync/api/runs.ts +69 -0
- package/src/modules/data_sync/api/validate.ts +73 -0
- package/src/modules/data_sync/backend/data-sync/page.meta.ts +21 -0
- package/src/modules/data_sync/backend/data-sync/page.tsx +244 -0
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.meta.ts +10 -0
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +278 -0
- package/src/modules/data_sync/data/entities.ts +180 -0
- package/src/modules/data_sync/data/validators.ts +35 -0
- package/src/modules/data_sync/di.ts +38 -0
- package/src/modules/data_sync/events.ts +12 -0
- package/src/modules/data_sync/i18n/de.json +48 -0
- package/src/modules/data_sync/i18n/en.json +48 -0
- package/src/modules/data_sync/i18n/es.json +48 -0
- package/src/modules/data_sync/i18n/pl.json +48 -0
- package/src/modules/data_sync/index.ts +5 -0
- package/src/modules/data_sync/lib/adapter-registry.ts +15 -0
- package/src/modules/data_sync/lib/adapter.ts +90 -0
- package/src/modules/data_sync/lib/id-mapping.ts +95 -0
- package/src/modules/data_sync/lib/queue.ts +19 -0
- package/src/modules/data_sync/lib/sync-engine.ts +375 -0
- package/src/modules/data_sync/lib/sync-run-service.ts +187 -0
- package/src/modules/data_sync/migrations/.snapshot-open-mercato.json +653 -0
- package/src/modules/data_sync/migrations/Migration20260304113737.ts +19 -0
- package/src/modules/data_sync/setup.ts +11 -0
- package/src/modules/data_sync/workers/sync-export.ts +27 -0
- package/src/modules/data_sync/workers/sync-import.ts +27 -0
- package/src/modules/data_sync/workers/sync-scheduled.ts +84 -0
- package/src/modules/entities/lib/encryptionDefaults.ts +4 -0
- package/src/modules/integrations/AGENTS.md +160 -0
- package/src/modules/integrations/acl.ts +3 -0
- package/src/modules/integrations/api/[id]/credentials/route.ts +142 -0
- package/src/modules/integrations/api/[id]/health/route.ts +53 -0
- package/src/modules/integrations/api/[id]/route.ts +76 -0
- package/src/modules/integrations/api/[id]/state/route.ts +121 -0
- package/src/modules/integrations/api/[id]/version/route.ts +132 -0
- package/src/modules/integrations/api/guards.ts +59 -0
- package/src/modules/integrations/api/logs/route.ts +63 -0
- package/src/modules/integrations/api/openapi.ts +22 -0
- package/src/modules/integrations/api/route.ts +73 -0
- package/src/modules/integrations/backend/integrations/[id]/page.meta.ts +11 -0
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +424 -0
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.meta.ts +11 -0
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +249 -0
- package/src/modules/integrations/backend/integrations/page.meta.ts +18 -0
- package/src/modules/integrations/backend/integrations/page.tsx +296 -0
- package/src/modules/integrations/data/enrichers.ts +35 -18
- package/src/modules/integrations/data/entities.ts +114 -5
- package/src/modules/integrations/data/validators.ts +41 -0
- package/src/modules/integrations/di.ts +31 -0
- package/src/modules/integrations/events.ts +17 -0
- package/src/modules/integrations/i18n/de.json +70 -0
- package/src/modules/integrations/i18n/en.json +70 -0
- package/src/modules/integrations/i18n/es.json +70 -0
- package/src/modules/integrations/i18n/pl.json +70 -0
- package/src/modules/integrations/lib/credentials-service.ts +204 -0
- package/src/modules/integrations/lib/health-service.ts +59 -0
- package/src/modules/integrations/lib/log-service.ts +84 -0
- package/src/modules/integrations/lib/registry-service.ts +42 -0
- package/src/modules/integrations/lib/state-service.ts +64 -0
- package/src/modules/integrations/lib/types.ts +4 -0
- package/src/modules/integrations/migrations/.snapshot-open-mercato.json +582 -0
- package/src/modules/integrations/migrations/Migration20260304113737.ts +21 -0
- package/src/modules/integrations/setup.ts +2 -2
- package/src/modules/integrations/widgets/injection-table.ts +1 -1
- 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": "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",
|
|
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
|