@open-mercato/core 0.6.7-develop.6606.1.3b1ec9b1ea → 0.6.7-develop.6621.1.cdbe9dee3d

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 (102) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/auth/api/session/refresh.js +12 -11
  3. package/dist/modules/auth/api/session/refresh.js.map +2 -2
  4. package/dist/modules/auth/lib/rateLimitCheck.js +4 -4
  5. package/dist/modules/auth/lib/rateLimitCheck.js.map +2 -2
  6. package/dist/modules/catalog/api/categories/route.js +8 -14
  7. package/dist/modules/catalog/api/categories/route.js.map +2 -2
  8. package/dist/modules/catalog/api/tags/route.js +3 -10
  9. package/dist/modules/catalog/api/tags/route.js.map +2 -2
  10. package/dist/modules/customers/api/interactions/[id]/visibility/route.js +15 -17
  11. package/dist/modules/customers/api/interactions/[id]/visibility/route.js.map +2 -2
  12. package/dist/modules/customers/api/people/[id]/email-threads/route.js +6 -4
  13. package/dist/modules/customers/api/people/[id]/email-threads/route.js.map +2 -2
  14. package/dist/modules/customers/api/people/[id]/emails/route.js +19 -17
  15. package/dist/modules/customers/api/people/[id]/emails/route.js.map +2 -2
  16. package/dist/modules/customers/components/detail/CustomFieldValuesList.js +22 -5
  17. package/dist/modules/customers/components/detail/CustomFieldValuesList.js.map +2 -2
  18. package/dist/modules/customers/components/detail/create/CreateDealForm.js +5 -2
  19. package/dist/modules/customers/components/detail/create/CreateDealForm.js.map +2 -2
  20. package/dist/modules/customers/components/detail/customFieldUtils.js +10 -3
  21. package/dist/modules/customers/components/detail/customFieldUtils.js.map +2 -2
  22. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.meta.js +4 -2
  23. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.meta.js.map +2 -2
  24. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.meta.js +4 -2
  25. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.meta.js.map +2 -2
  26. package/dist/modules/integrations/api/[id]/credentials/route.js +10 -7
  27. package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
  28. package/dist/modules/integrations/api/[id]/health/route.js +6 -4
  29. package/dist/modules/integrations/api/[id]/health/route.js.map +2 -2
  30. package/dist/modules/integrations/api/[id]/route.js +4 -2
  31. package/dist/modules/integrations/api/[id]/route.js.map +2 -2
  32. package/dist/modules/integrations/api/[id]/state/route.js +7 -5
  33. package/dist/modules/integrations/api/[id]/state/route.js.map +2 -2
  34. package/dist/modules/integrations/api/[id]/version/route.js +7 -5
  35. package/dist/modules/integrations/api/[id]/version/route.js.map +2 -2
  36. package/dist/modules/integrations/api/logs/route.js +4 -2
  37. package/dist/modules/integrations/api/logs/route.js.map +2 -2
  38. package/dist/modules/integrations/api/route.js +4 -2
  39. package/dist/modules/integrations/api/route.js.map +2 -2
  40. package/dist/modules/integrations/api/umes-read.js +2 -1
  41. package/dist/modules/integrations/api/umes-read.js.map +2 -2
  42. package/dist/modules/integrations/lib/organization-scope.js +12 -0
  43. package/dist/modules/integrations/lib/organization-scope.js.map +7 -0
  44. package/dist/modules/payment_gateways/lib/gateway-service.js +10 -1
  45. package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
  46. package/dist/modules/sales/api/document-history/route.js +6 -9
  47. package/dist/modules/sales/api/document-history/route.js.map +2 -2
  48. package/dist/modules/sales/api/quotes/accept/route.js +3 -3
  49. package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
  50. package/dist/modules/sales/api/returns/[id]/route.js +6 -9
  51. package/dist/modules/sales/api/returns/[id]/route.js.map +2 -2
  52. package/dist/modules/sales/backend/sales/documents/[id]/page.js +6 -2
  53. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  54. package/dist/modules/sales/components/documents/AddressesSection.js +6 -4
  55. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  56. package/dist/modules/sales/workflows.js +1 -1
  57. package/dist/modules/sales/workflows.js.map +1 -1
  58. package/dist/modules/workflows/api/definitions/[id]/route.js +10 -1
  59. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  60. package/dist/modules/workflows/lib/event-trigger-service.js +44 -3
  61. package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
  62. package/package.json +7 -7
  63. package/src/modules/auth/api/session/refresh.ts +19 -11
  64. package/src/modules/auth/lib/rateLimitCheck.ts +4 -4
  65. package/src/modules/catalog/api/categories/route.ts +14 -16
  66. package/src/modules/catalog/api/tags/route.ts +6 -10
  67. package/src/modules/catalog/i18n/pl.json +9 -9
  68. package/src/modules/customer_accounts/i18n/pl.json +129 -129
  69. package/src/modules/customers/api/interactions/[id]/visibility/route.ts +24 -20
  70. package/src/modules/customers/api/people/[id]/email-threads/route.ts +10 -6
  71. package/src/modules/customers/api/people/[id]/emails/route.ts +25 -21
  72. package/src/modules/customers/components/detail/CustomFieldValuesList.tsx +28 -4
  73. package/src/modules/customers/components/detail/create/CreateDealForm.tsx +7 -2
  74. package/src/modules/customers/components/detail/customFieldUtils.ts +15 -3
  75. package/src/modules/data_sync/i18n/pl.json +68 -68
  76. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.meta.ts +4 -2
  77. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.meta.ts +4 -2
  78. package/src/modules/integrations/api/[id]/credentials/route.ts +10 -7
  79. package/src/modules/integrations/api/[id]/health/route.ts +6 -4
  80. package/src/modules/integrations/api/[id]/route.ts +4 -2
  81. package/src/modules/integrations/api/[id]/state/route.ts +7 -5
  82. package/src/modules/integrations/api/[id]/version/route.ts +7 -5
  83. package/src/modules/integrations/api/logs/route.ts +4 -2
  84. package/src/modules/integrations/api/route.ts +4 -2
  85. package/src/modules/integrations/api/umes-read.ts +2 -1
  86. package/src/modules/integrations/i18n/de.json +0 -76
  87. package/src/modules/integrations/i18n/en.json +0 -76
  88. package/src/modules/integrations/i18n/es.json +0 -76
  89. package/src/modules/integrations/i18n/pl.json +0 -76
  90. package/src/modules/integrations/lib/organization-scope.ts +27 -0
  91. package/src/modules/payment_gateways/lib/gateway-service.ts +12 -1
  92. package/src/modules/sales/api/document-history/route.ts +10 -9
  93. package/src/modules/sales/api/quotes/accept/route.ts +3 -3
  94. package/src/modules/sales/api/returns/[id]/route.ts +10 -9
  95. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +26 -19
  96. package/src/modules/sales/components/documents/AddressesSection.tsx +8 -4
  97. package/src/modules/sales/i18n/pl.json +24 -24
  98. package/src/modules/sales/workflows.ts +1 -1
  99. package/src/modules/staff/i18n/pl.json +178 -178
  100. package/src/modules/workflows/api/definitions/[id]/route.ts +14 -1
  101. package/src/modules/workflows/i18n/pl.json +128 -128
  102. package/src/modules/workflows/lib/event-trigger-service.ts +87 -8
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/integrations/api/%5Bid%5D/credentials/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 { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { emitIntegrationsEvent } from '../../../events'\nimport { saveCredentialsSchema } from '../../../data/validators'\nimport {\n isCredentialsEncryptionUnavailableError,\n type CredentialsService,\n} from '../../../lib/credentials-service'\nimport { collectCredentialUrlValidationErrors } from '../../../lib/credentials-field-validation'\nimport {\n maskSecretCredentials,\n mergeMaskedSecretCredentials,\n} from '../../../lib/credentials-masking'\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 GET: { requireAuth: true, requireFeatures: ['integrations.credentials.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['integrations.credentials.manage'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'Get or save integration credentials',\n}\n\nfunction resolveParams(ctx: { params?: Promise<{ id?: string }> | { id?: string } }): Promise<{ id?: string } | undefined> | { id?: string } | undefined {\n if (!ctx.params) return undefined\n if (typeof (ctx.params as Promise<unknown>).then === 'function') {\n return ctx.params as Promise<{ id?: string }>\n }\n return ctx.params as { id?: string }\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 = await resolveParams(ctx)\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 scope = { organizationId: auth.orgId as string, tenantId: auth.tenantId }\n\n let values: Record<string, unknown> | null\n let updatedAt: Date | null\n try {\n values = await credentialsService.resolve(integration.id, scope)\n updatedAt = await credentialsService.resolveUpdatedAt(integration.id, scope)\n } catch (error) {\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n const schema = credentialsService.getSchema(integration.id)\n const { credentials, secretFieldsConfigured } = maskSecretCredentials(schema, values ?? {})\n\n return NextResponse.json({\n integrationId: integration.id,\n schema,\n credentials,\n secretFieldsConfigured,\n updatedAt: updatedAt?.toISOString() ?? null,\n })\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 = await resolveParams(ctx)\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 = saveCredentialsSchema.safeParse(payload)\n if (!parsedBody.success) {\n return NextResponse.json({ error: 'Invalid credentials 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 = saveCredentialsSchema.safeParse(mergedPayload)\n if (!reparsed.success) {\n return NextResponse.json({ error: 'Invalid credentials payload after guard transform', details: reparsed.error.flatten() }, { status: 422 })\n }\n payloadData = reparsed.data\n }\n\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const scope = { organizationId: auth.orgId as string, tenantId: auth.tenantId }\n const schema = credentialsService.getSchema(integration.id)\n\n try {\n const currentUpdatedAt = await credentialsService.resolveUpdatedAt(integration.id, scope)\n enforceCommandOptimisticLock({\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n current: currentUpdatedAt,\n request: req,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n const credentialFieldErrors = collectCredentialUrlValidationErrors(\n schema,\n payloadData.credentials,\n )\n if (Object.keys(credentialFieldErrors).length > 0) {\n return NextResponse.json(\n { error: 'Invalid credentials payload', details: { fieldErrors: credentialFieldErrors } },\n { status: 422 },\n )\n }\n\n try {\n // Secret fields are returned masked on GET; when the client round-trips the\n // mask sentinel it means \"unchanged\", so restore the existing stored secret\n // instead of overwriting it with the placeholder.\n const existing = await credentialsService.resolve(integration.id, scope)\n const credentialsToSave = mergeMaskedSecretCredentials(schema, payloadData.credentials, existing ?? {})\n await credentialsService.save(integration.id, credentialsToSave, scope)\n } catch (error) {\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n await emitIntegrationsEvent('integrations.credentials.updated', {\n integrationId: integration.id,\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({ ok: true })\n}\n"],
5
- "mappings": "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",
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 { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { emitIntegrationsEvent } from '../../../events'\nimport { saveCredentialsSchema } from '../../../data/validators'\nimport {\n isCredentialsEncryptionUnavailableError,\n type CredentialsService,\n} from '../../../lib/credentials-service'\nimport { collectCredentialUrlValidationErrors } from '../../../lib/credentials-field-validation'\nimport {\n maskSecretCredentials,\n mergeMaskedSecretCredentials,\n} from '../../../lib/credentials-masking'\nimport {\n resolveUserFeatures,\n runIntegrationMutationGuardAfterSuccess,\n runIntegrationMutationGuards,\n} from '../../guards'\nimport { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'\n\nconst idParamsSchema = z.object({ id: z.string().min(1) })\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.credentials.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['integrations.credentials.manage'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'Get or save integration credentials',\n}\n\nfunction resolveParams(ctx: { params?: Promise<{ id?: string }> | { id?: string } }): Promise<{ id?: string } | undefined> | { id?: string } | undefined {\n if (!ctx.params) return undefined\n if (typeof (ctx.params as Promise<unknown>).then === 'function') {\n return ctx.params as Promise<{ id?: string }>\n }\n return ctx.params as { id?: string }\n}\n\nexport async function GET(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const rawParams = await resolveParams(ctx)\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 scope = { organizationId: organizationId, tenantId: auth.tenantId }\n\n let values: Record<string, unknown> | null\n let updatedAt: Date | null\n try {\n values = await credentialsService.resolve(integration.id, scope)\n updatedAt = await credentialsService.resolveUpdatedAt(integration.id, scope)\n } catch (error) {\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n const schema = credentialsService.getSchema(integration.id)\n const { credentials, secretFieldsConfigured } = maskSecretCredentials(schema, values ?? {})\n\n return NextResponse.json({\n integrationId: integration.id,\n schema,\n credentials,\n secretFieldsConfigured,\n updatedAt: updatedAt?.toISOString() ?? null,\n })\n}\n\nexport async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const rawParams = await resolveParams(ctx)\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 = saveCredentialsSchema.safeParse(payload)\n if (!parsedBody.success) {\n return NextResponse.json({ error: 'Invalid credentials 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,\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 = saveCredentialsSchema.safeParse(mergedPayload)\n if (!reparsed.success) {\n return NextResponse.json({ error: 'Invalid credentials payload after guard transform', details: reparsed.error.flatten() }, { status: 422 })\n }\n payloadData = reparsed.data\n }\n\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const scope = { organizationId: organizationId, tenantId: auth.tenantId }\n const schema = credentialsService.getSchema(integration.id)\n\n try {\n const currentUpdatedAt = await credentialsService.resolveUpdatedAt(integration.id, scope)\n enforceCommandOptimisticLock({\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n current: currentUpdatedAt,\n request: req,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n const credentialFieldErrors = collectCredentialUrlValidationErrors(\n schema,\n payloadData.credentials,\n )\n if (Object.keys(credentialFieldErrors).length > 0) {\n return NextResponse.json(\n { error: 'Invalid credentials payload', details: { fieldErrors: credentialFieldErrors } },\n { status: 422 },\n )\n }\n\n try {\n // Secret fields are returned masked on GET; when the client round-trips the\n // mask sentinel it means \"unchanged\", so restore the existing stored secret\n // instead of overwriting it with the placeholder.\n const existing = await credentialsService.resolve(integration.id, scope)\n const credentialsToSave = mergeMaskedSecretCredentials(schema, payloadData.credentials, existing ?? {})\n await credentialsService.save(integration.id, credentialsToSave, scope)\n } catch (error) {\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n await emitIntegrationsEvent('integrations.credentials.updated', {\n integrationId: integration.id,\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub,\n })\n\n await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {\n tenantId: auth.tenantId,\n organizationId,\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({ ok: true })\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -8,6 +8,7 @@ import {
8
8
  runIntegrationMutationGuardAfterSuccess,
9
9
  runIntegrationMutationGuards
10
10
  } from "../../guards.js";
11
+ import { resolveIntegrationsOrganizationId } from "../../../lib/organization-scope.js";
11
12
  const idParamsSchema = z.object({ id: z.string().min(1) });
12
13
  const metadata = {
13
14
  POST: { requireAuth: true, requireFeatures: ["integrations.manage"] }
@@ -18,7 +19,8 @@ const openApi = {
18
19
  };
19
20
  async function POST(req, ctx) {
20
21
  const auth = await getAuthFromRequest(req);
21
- if (!auth?.tenantId || !auth.orgId) {
22
+ const organizationId = resolveIntegrationsOrganizationId(auth);
23
+ if (!auth?.tenantId || !organizationId) {
22
24
  return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
23
25
  }
24
26
  const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
@@ -35,7 +37,7 @@ async function POST(req, ctx) {
35
37
  container,
36
38
  {
37
39
  tenantId: auth.tenantId,
38
- organizationId: auth.orgId,
40
+ organizationId,
39
41
  userId: auth.sub ?? "",
40
42
  resourceKind: "integrations.integration",
41
43
  resourceId: integration.id,
@@ -52,11 +54,11 @@ async function POST(req, ctx) {
52
54
  const healthService = container.resolve("integrationHealthService");
53
55
  const result = await healthService.runHealthCheck(
54
56
  integration.id,
55
- { organizationId: auth.orgId, tenantId: auth.tenantId }
57
+ { organizationId, tenantId: auth.tenantId }
56
58
  );
57
59
  await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
58
60
  tenantId: auth.tenantId,
59
- organizationId: auth.orgId,
61
+ organizationId,
60
62
  userId: auth.sub ?? "",
61
63
  resourceKind: "integrations.integration",
62
64
  resourceId: integration.id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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'\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 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 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: { integrationId: integration.id },\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 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 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 status: result.status,\n message: result.message ?? null,\n details: result.details ?? null,\n latencyMs: result.latencyMs,\n checkedAt: result.checkedAt,\n })\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,sBAAsB;AAE/B;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,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,cAAc,MAAM;AAAA,IACxB;AAAA,IACA;AAAA,MACE,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,EAAE,eAAe,YAAY,GAAG;AAAA,IACnD;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,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,QAAM,wCAAwC,YAAY,uBAAuB;AAAA,IAC/E,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;AAED,SAAO,aAAa,KAAK;AAAA,IACvB,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO,WAAW;AAAA,IAC3B,SAAS,OAAO,WAAW;AAAA,IAC3B,WAAW,OAAO;AAAA,IAClB,WAAW,OAAO;AAAA,EACpB,CAAC;AACH;",
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'\nimport {\n resolveUserFeatures,\n runIntegrationMutationGuardAfterSuccess,\n runIntegrationMutationGuards,\n} from '../../guards'\nimport { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'\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 const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\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 guardResult = await runIntegrationMutationGuards(\n container,\n {\n tenantId: auth.tenantId,\n organizationId,\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: { integrationId: integration.id },\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 const healthService = container.resolve('integrationHealthService') as IntegrationHealthService\n\n const result = await healthService.runHealthCheck(\n integration.id,\n { organizationId: organizationId, tenantId: auth.tenantId },\n )\n\n await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {\n tenantId: auth.tenantId,\n organizationId,\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 status: result.status,\n message: result.message ?? null,\n details: result.details ?? null,\n latencyMs: result.latencyMs,\n checkedAt: result.checkedAt,\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,sBAAsB;AAE/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,yCAAyC;AAElD,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,QAAM,iBAAiB,kCAAkC,IAAI;AAC7D,MAAI,CAAC,MAAM,YAAY,CAAC,gBAAgB;AACtC,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,cAAc,MAAM;AAAA,IACxB;AAAA,IACA;AAAA,MACE,UAAU,KAAK;AAAA,MACf;AAAA,MACA,QAAQ,KAAK,OAAO;AAAA,MACpB,cAAc;AAAA,MACd,YAAY,YAAY;AAAA,MACxB,WAAW;AAAA,MACX,eAAe,IAAI;AAAA,MACnB,gBAAgB,IAAI;AAAA,MACpB,iBAAiB,EAAE,eAAe,YAAY,GAAG;AAAA,IACnD;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,QAAM,gBAAgB,UAAU,QAAQ,0BAA0B;AAElE,QAAM,SAAS,MAAM,cAAc;AAAA,IACjC,YAAY;AAAA,IACZ,EAAE,gBAAgC,UAAU,KAAK,SAAS;AAAA,EAC5D;AAEA,QAAM,wCAAwC,YAAY,uBAAuB;AAAA,IAC/E,UAAU,KAAK;AAAA,IACf;AAAA,IACA,QAAQ,KAAK,OAAO;AAAA,IACpB,cAAc;AAAA,IACd,YAAY,YAAY;AAAA,IACxB,WAAW;AAAA,IACX,eAAe,IAAI;AAAA,IACnB,gBAAgB,IAAI;AAAA,EACtB,CAAC;AAED,SAAO,aAAa,KAAK;AAAA,IACvB,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO,WAAW;AAAA,IAC3B,SAAS,OAAO,WAAW;AAAA,IAC3B,WAAW,OAAO;AAAA,IAClB,WAAW,OAAO;AAAA,EACpB,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -10,6 +10,7 @@ import {
10
10
  integrationApiRoutePaths,
11
11
  runIntegrationsReadBeforeInterceptors
12
12
  } from "../umes-read.js";
13
+ import { resolveIntegrationsOrganizationId } from "../../lib/organization-scope.js";
13
14
  const idParamsSchema = z.object({ id: z.string().min(1) });
14
15
  const metadata = {
15
16
  GET: { requireAuth: true, requireFeatures: ["integrations.view"] }
@@ -20,7 +21,8 @@ const openApi = {
20
21
  };
21
22
  async function GET(req, ctx) {
22
23
  const auth = await getAuthFromRequest(req);
23
- if (!auth?.tenantId || !auth.orgId) {
24
+ const organizationId = resolveIntegrationsOrganizationId(auth);
25
+ if (!auth?.tenantId || !organizationId) {
24
26
  return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
25
27
  }
26
28
  const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
@@ -45,7 +47,7 @@ async function GET(req, ctx) {
45
47
  const credentialsService = container.resolve("integrationCredentialsService");
46
48
  const stateService = container.resolve("integrationStateService");
47
49
  const logService = container.resolve("integrationLogService");
48
- const scope = { organizationId: auth.orgId, tenantId: auth.tenantId };
50
+ const scope = { organizationId, tenantId: auth.tenantId };
49
51
  const [credentials, credentialsUpdatedAt, state, analyticsMap] = await Promise.all([
50
52
  credentialsService.resolve(integration.id, scope).catch((err) => {
51
53
  if (err instanceof CredentialsEncryptionUnavailableError) return null;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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 { CredentialsEncryptionUnavailableError, type CredentialsService } from '../../lib/credentials-service'\nimport type { IntegrationStateService } from '../../lib/state-service'\nimport type { IntegrationLogService } from '../../lib/log-service'\nimport { deriveIntegrationHealthStatus, getEffectiveHealthCheckConfig } from '../../lib/health-service'\nimport {\n finalizeIntegrationsReadResponse,\n integrationApiRoutePaths,\n runIntegrationsReadBeforeInterceptors,\n} from '../umes-read'\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 beforeInterceptors = await runIntegrationsReadBeforeInterceptors({\n routePath: integrationApiRoutePaths.detail,\n request: req,\n auth,\n container,\n })\n if (!beforeInterceptors.ok) {\n return NextResponse.json(beforeInterceptors.body, { status: beforeInterceptors.statusCode })\n }\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const stateService = container.resolve('integrationStateService') as IntegrationStateService\n const logService = container.resolve('integrationLogService') as IntegrationLogService\n const scope = { organizationId: auth.orgId as string, tenantId: auth.tenantId }\n\n const [credentials, credentialsUpdatedAt, state, analyticsMap] = await Promise.all([\n credentialsService.resolve(integration.id, scope).catch((err) => {\n if (err instanceof CredentialsEncryptionUnavailableError) return null\n throw err\n }),\n credentialsService.resolveUpdatedAt(integration.id, scope).catch((err) => {\n if (err instanceof CredentialsEncryptionUnavailableError) return null\n throw err\n }),\n stateService.resolveState(integration.id, scope),\n logService.aggregateAnalytics([integration.id], scope, 30),\n ])\n\n const hasCredentials = credentials != null && Object.keys(credentials).length > 0\n const healthConfig = getEffectiveHealthCheckConfig(integration.id)\n const hasHealthCheck = Boolean(healthConfig?.service)\n const healthStatus = deriveIntegrationHealthStatus({\n hasHealthCheck,\n hasCredentials,\n lastHealthStatus: state.lastHealthStatus,\n lastHealthCheckedAt: state.lastHealthCheckedAt,\n })\n\n const analytics = analyticsMap.get(integration.id) ?? {\n lastActivityAt: null,\n totalCount: 0,\n errorCount: 0,\n errorRate: 0,\n dailyCounts: Array.from({ length: 30 }, () => 0),\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 resolvedState = await stateService.resolveState(item.id, scope)\n return {\n ...item,\n isEnabled: resolvedState.isEnabled,\n state: {\n isEnabled: resolvedState.isEnabled,\n apiVersion: resolvedState.apiVersion,\n reauthRequired: resolvedState.reauthRequired,\n lastHealthStatus: resolvedState.lastHealthStatus,\n lastHealthCheckedAt: resolvedState.lastHealthCheckedAt?.toISOString() ?? null,\n lastHealthLatencyMs: resolvedState.lastHealthLatencyMs,\n enabledAt: resolvedState.enabledAt?.toISOString() ?? null,\n updatedAt: resolvedState.updatedAt?.toISOString() ?? null,\n },\n }\n }),\n )\n : []\n\n return finalizeIntegrationsReadResponse({\n routePath: integrationApiRoutePaths.detail,\n request: req,\n auth,\n container,\n interceptorRequest: beforeInterceptors.request,\n beforeMetadata: beforeInterceptors.metadataByInterceptor,\n enrich: {\n targetEntity: 'integrations.integration',\n recordKeys: ['integration'],\n listKeys: ['bundleIntegrations'],\n },\n body: {\n integration,\n bundle,\n bundleIntegrations,\n state: {\n isEnabled: state.isEnabled,\n apiVersion: state.apiVersion,\n reauthRequired: state.reauthRequired,\n lastHealthStatus: state.lastHealthStatus,\n lastHealthCheckedAt: state.lastHealthCheckedAt?.toISOString() ?? null,\n lastHealthLatencyMs: state.lastHealthLatencyMs,\n enabledAt: state.enabledAt?.toISOString() ?? null,\n updatedAt: state.updatedAt?.toISOString() ?? null,\n },\n hasCredentials,\n credentialsUpdatedAt: credentialsUpdatedAt?.toISOString() ?? null,\n healthStatus,\n analytics,\n },\n })\n}\n"],
5
- "mappings": "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",
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 { CredentialsEncryptionUnavailableError, type CredentialsService } from '../../lib/credentials-service'\nimport type { IntegrationStateService } from '../../lib/state-service'\nimport type { IntegrationLogService } from '../../lib/log-service'\nimport { deriveIntegrationHealthStatus, getEffectiveHealthCheckConfig } from '../../lib/health-service'\nimport {\n finalizeIntegrationsReadResponse,\n integrationApiRoutePaths,\n runIntegrationsReadBeforeInterceptors,\n} from '../umes-read'\nimport { resolveIntegrationsOrganizationId } from '../../lib/organization-scope'\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 const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\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 beforeInterceptors = await runIntegrationsReadBeforeInterceptors({\n routePath: integrationApiRoutePaths.detail,\n request: req,\n auth,\n container,\n })\n if (!beforeInterceptors.ok) {\n return NextResponse.json(beforeInterceptors.body, { status: beforeInterceptors.statusCode })\n }\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const stateService = container.resolve('integrationStateService') as IntegrationStateService\n const logService = container.resolve('integrationLogService') as IntegrationLogService\n const scope = { organizationId: organizationId, tenantId: auth.tenantId }\n\n const [credentials, credentialsUpdatedAt, state, analyticsMap] = await Promise.all([\n credentialsService.resolve(integration.id, scope).catch((err) => {\n if (err instanceof CredentialsEncryptionUnavailableError) return null\n throw err\n }),\n credentialsService.resolveUpdatedAt(integration.id, scope).catch((err) => {\n if (err instanceof CredentialsEncryptionUnavailableError) return null\n throw err\n }),\n stateService.resolveState(integration.id, scope),\n logService.aggregateAnalytics([integration.id], scope, 30),\n ])\n\n const hasCredentials = credentials != null && Object.keys(credentials).length > 0\n const healthConfig = getEffectiveHealthCheckConfig(integration.id)\n const hasHealthCheck = Boolean(healthConfig?.service)\n const healthStatus = deriveIntegrationHealthStatus({\n hasHealthCheck,\n hasCredentials,\n lastHealthStatus: state.lastHealthStatus,\n lastHealthCheckedAt: state.lastHealthCheckedAt,\n })\n\n const analytics = analyticsMap.get(integration.id) ?? {\n lastActivityAt: null,\n totalCount: 0,\n errorCount: 0,\n errorRate: 0,\n dailyCounts: Array.from({ length: 30 }, () => 0),\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 resolvedState = await stateService.resolveState(item.id, scope)\n return {\n ...item,\n isEnabled: resolvedState.isEnabled,\n state: {\n isEnabled: resolvedState.isEnabled,\n apiVersion: resolvedState.apiVersion,\n reauthRequired: resolvedState.reauthRequired,\n lastHealthStatus: resolvedState.lastHealthStatus,\n lastHealthCheckedAt: resolvedState.lastHealthCheckedAt?.toISOString() ?? null,\n lastHealthLatencyMs: resolvedState.lastHealthLatencyMs,\n enabledAt: resolvedState.enabledAt?.toISOString() ?? null,\n updatedAt: resolvedState.updatedAt?.toISOString() ?? null,\n },\n }\n }),\n )\n : []\n\n return finalizeIntegrationsReadResponse({\n routePath: integrationApiRoutePaths.detail,\n request: req,\n auth,\n container,\n interceptorRequest: beforeInterceptors.request,\n beforeMetadata: beforeInterceptors.metadataByInterceptor,\n enrich: {\n targetEntity: 'integrations.integration',\n recordKeys: ['integration'],\n listKeys: ['bundleIntegrations'],\n },\n body: {\n integration,\n bundle,\n bundleIntegrations,\n state: {\n isEnabled: state.isEnabled,\n apiVersion: state.apiVersion,\n reauthRequired: state.reauthRequired,\n lastHealthStatus: state.lastHealthStatus,\n lastHealthCheckedAt: state.lastHealthCheckedAt?.toISOString() ?? null,\n lastHealthLatencyMs: state.lastHealthLatencyMs,\n enabledAt: state.enabledAt?.toISOString() ?? null,\n updatedAt: state.updatedAt?.toISOString() ?? null,\n },\n hasCredentials,\n credentialsUpdatedAt: credentialsUpdatedAt?.toISOString() ?? null,\n healthStatus,\n analytics,\n },\n })\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -12,6 +12,7 @@ import {
12
12
  runIntegrationMutationGuardAfterSuccess,
13
13
  runIntegrationMutationGuards
14
14
  } from "../../guards.js";
15
+ import { resolveIntegrationsOrganizationId } from "../../../lib/organization-scope.js";
15
16
  const idParamsSchema = z.object({ id: z.string().min(1) });
16
17
  const metadata = {
17
18
  PUT: { requireAuth: true, requireFeatures: ["integrations.manage"] }
@@ -22,7 +23,8 @@ const openApi = {
22
23
  };
23
24
  async function PUT(req, ctx) {
24
25
  const auth = await getAuthFromRequest(req);
25
- if (!auth?.tenantId || !auth.orgId) {
26
+ const organizationId = resolveIntegrationsOrganizationId(auth);
27
+ if (!auth?.tenantId || !organizationId) {
26
28
  return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
27
29
  }
28
30
  const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
@@ -44,7 +46,7 @@ async function PUT(req, ctx) {
44
46
  container,
45
47
  {
46
48
  tenantId: auth.tenantId,
47
- organizationId: auth.orgId,
49
+ organizationId,
48
50
  userId: auth.sub ?? "",
49
51
  resourceKind: "integrations.integration",
50
52
  resourceId: integration.id,
@@ -68,7 +70,7 @@ async function PUT(req, ctx) {
68
70
  payloadData = reparsed.data;
69
71
  }
70
72
  const stateService = container.resolve("integrationStateService");
71
- const stateScope = { organizationId: auth.orgId, tenantId: auth.tenantId };
73
+ const stateScope = { organizationId, tenantId: auth.tenantId };
72
74
  try {
73
75
  const current = await stateService.resolveState(integration.id, stateScope);
74
76
  enforceCommandOptimisticLock({
@@ -96,12 +98,12 @@ async function PUT(req, ctx) {
96
98
  isEnabled: state.isEnabled,
97
99
  reauthRequired: state.reauthRequired,
98
100
  tenantId: auth.tenantId,
99
- organizationId: auth.orgId,
101
+ organizationId,
100
102
  userId: auth.sub
101
103
  });
102
104
  await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
103
105
  tenantId: auth.tenantId,
104
- organizationId: auth.orgId,
106
+ organizationId,
105
107
  userId: auth.sub ?? "",
106
108
  resourceKind: "integrations.integration",
107
109
  resourceId: integration.id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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 { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\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 const stateScope = { organizationId: auth.orgId as string, tenantId: auth.tenantId }\n\n try {\n const current = await stateService.resolveState(integration.id, stateScope)\n enforceCommandOptimisticLock({\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n current: current.updatedAt,\n request: req,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n throw error\n }\n\n const state = await stateService.upsert(\n integration.id,\n {\n isEnabled: payloadData.isEnabled,\n reauthRequired: payloadData.reauthRequired,\n },\n stateScope,\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 updatedAt: state.updatedAt?.toISOString() ?? null,\n })\n}\n"],
5
- "mappings": "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",
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 { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\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'\nimport { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'\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 const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\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,\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 const stateScope = { organizationId: organizationId, tenantId: auth.tenantId }\n\n try {\n const current = await stateService.resolveState(integration.id, stateScope)\n enforceCommandOptimisticLock({\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n current: current.updatedAt,\n request: req,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n throw error\n }\n\n const state = await stateService.upsert(\n integration.id,\n {\n isEnabled: payloadData.isEnabled,\n reauthRequired: payloadData.reauthRequired,\n },\n stateScope,\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,\n userId: auth.sub,\n })\n\n await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {\n tenantId: auth.tenantId,\n organizationId,\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 updatedAt: state.updatedAt?.toISOString() ?? null,\n })\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -13,6 +13,7 @@ import {
13
13
  runIntegrationMutationGuardAfterSuccess,
14
14
  runIntegrationMutationGuards
15
15
  } from "../../guards.js";
16
+ import { resolveIntegrationsOrganizationId } from "../../../lib/organization-scope.js";
16
17
  const idParamsSchema = z.object({ id: z.string().min(1) });
17
18
  const metadata = {
18
19
  PUT: { requireAuth: true, requireFeatures: ["integrations.manage"] }
@@ -23,7 +24,8 @@ const openApi = {
23
24
  };
24
25
  async function PUT(req, ctx) {
25
26
  const auth = await getAuthFromRequest(req);
26
- if (!auth?.tenantId || !auth.orgId) {
27
+ const organizationId = resolveIntegrationsOrganizationId(auth);
28
+ if (!auth?.tenantId || !organizationId) {
27
29
  return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
28
30
  }
29
31
  const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
@@ -58,7 +60,7 @@ async function PUT(req, ctx) {
58
60
  container,
59
61
  {
60
62
  tenantId: auth.tenantId,
61
- organizationId: auth.orgId,
63
+ organizationId,
62
64
  userId: auth.sub ?? "",
63
65
  resourceKind: "integrations.integration",
64
66
  resourceId: integration.id,
@@ -85,7 +87,7 @@ async function PUT(req, ctx) {
85
87
  return NextResponse.json({ error: "Unknown integration version" }, { status: 422 });
86
88
  }
87
89
  const stateService = container.resolve("integrationStateService");
88
- const scope = { organizationId: auth.orgId, tenantId: auth.tenantId };
90
+ const scope = { organizationId, tenantId: auth.tenantId };
89
91
  const currentState = await stateService.resolveState(integration.id, scope);
90
92
  try {
91
93
  enforceCommandOptimisticLock({
@@ -107,12 +109,12 @@ async function PUT(req, ctx) {
107
109
  previousVersion: before ?? defaultVersion,
108
110
  apiVersion: payloadData.apiVersion,
109
111
  tenantId: auth.tenantId,
110
- organizationId: auth.orgId,
112
+ organizationId,
111
113
  userId: auth.sub
112
114
  });
113
115
  await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
114
116
  tenantId: auth.tenantId,
115
- organizationId: auth.orgId,
117
+ organizationId,
116
118
  userId: auth.sub ?? "",
117
119
  resourceKind: "integrations.integration",
118
120
  resourceId: integration.id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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 { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\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 currentState = await stateService.resolveState(integration.id, scope)\n try {\n enforceCommandOptimisticLock({\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n current: currentState.updatedAt,\n request: req,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n throw error\n }\n\n const before = currentState.apiVersion\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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",
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 { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\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'\nimport { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'\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 const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\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,\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: organizationId, tenantId: auth.tenantId }\n\n const currentState = await stateService.resolveState(integration.id, scope)\n try {\n enforceCommandOptimisticLock({\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n current: currentState.updatedAt,\n request: req,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n throw error\n }\n\n const before = currentState.apiVersion\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,\n userId: auth.sub,\n })\n\n await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {\n tenantId: auth.tenantId,\n organizationId,\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
6
  "names": []
7
7
  }
@@ -7,6 +7,7 @@ import {
7
7
  integrationApiRoutePaths,
8
8
  runIntegrationsReadBeforeInterceptors
9
9
  } from "../umes-read.js";
10
+ import { resolveIntegrationsOrganizationId } from "../../lib/organization-scope.js";
10
11
  const metadata = {
11
12
  GET: { requireAuth: true, requireFeatures: ["integrations.manage"] }
12
13
  };
@@ -16,7 +17,8 @@ const openApi = {
16
17
  };
17
18
  async function GET(req) {
18
19
  const auth = await getAuthFromRequest(req);
19
- if (!auth?.tenantId || !auth.orgId) {
20
+ const organizationId = resolveIntegrationsOrganizationId(auth);
21
+ if (!auth?.tenantId || !organizationId) {
20
22
  return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
21
23
  }
22
24
  const container = await createRequestContainer();
@@ -44,7 +46,7 @@ async function GET(req) {
44
46
  }
45
47
  const logService = container.resolve("integrationLogService");
46
48
  const { items, total } = await logService.query(parsed.data, {
47
- organizationId: auth.orgId,
49
+ organizationId,
48
50
  tenantId: auth.tenantId
49
51
  });
50
52
  return finalizeIntegrationsReadResponse({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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 '@open-mercato/core/modules/integrations/data/validators'\nimport type { IntegrationLogService } from '@open-mercato/core/modules/integrations/lib/log-service'\nimport {\n finalizeIntegrationsReadResponse,\n integrationApiRoutePaths,\n runIntegrationsReadBeforeInterceptors,\n} from '../umes-read'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.manage'] },\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 container = await createRequestContainer()\n const beforeInterceptors = await runIntegrationsReadBeforeInterceptors({\n routePath: integrationApiRoutePaths.logs,\n request: req,\n auth,\n container,\n })\n if (!beforeInterceptors.ok) {\n return NextResponse.json(beforeInterceptors.body, { status: beforeInterceptors.statusCode })\n }\n\n const query = beforeInterceptors.request.query ?? {}\n const parsed = listIntegrationLogsQuerySchema.safeParse({\n integrationId: typeof query.integrationId === 'string' ? query.integrationId : undefined,\n level: typeof query.level === 'string' ? query.level : undefined,\n runId: typeof query.runId === 'string' ? query.runId : undefined,\n entityType: typeof query.entityType === 'string' ? query.entityType : undefined,\n entityId: typeof query.entityId === 'string' ? query.entityId : undefined,\n page: typeof query.page === 'string' ? query.page : undefined,\n pageSize: typeof query.pageSize === 'string' ? query.pageSize : undefined,\n })\n\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid query', details: parsed.error.flatten() }, { status: 400 })\n }\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 finalizeIntegrationsReadResponse({\n routePath: integrationApiRoutePaths.logs,\n request: req,\n auth,\n container,\n interceptorRequest: beforeInterceptors.request,\n beforeMetadata: beforeInterceptors.metadataByInterceptor,\n enrich: {\n targetEntity: 'integrations.log',\n listKeys: ['items'],\n },\n body: {\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}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,sCAAsC;AAE/C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,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;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,YAAY,MAAM,uBAAuB;AAC/C,QAAM,qBAAqB,MAAM,sCAAsC;AAAA,IACrE,WAAW,yBAAyB;AAAA,IACpC,SAAS;AAAA,IACT;AAAA,IACA;AAAA,EACF,CAAC;AACD,MAAI,CAAC,mBAAmB,IAAI;AAC1B,WAAO,aAAa,KAAK,mBAAmB,MAAM,EAAE,QAAQ,mBAAmB,WAAW,CAAC;AAAA,EAC7F;AAEA,QAAM,QAAQ,mBAAmB,QAAQ,SAAS,CAAC;AACnD,QAAM,SAAS,+BAA+B,UAAU;AAAA,IACtD,eAAe,OAAO,MAAM,kBAAkB,WAAW,MAAM,gBAAgB;AAAA,IAC/E,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,IACvD,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,IACvD,YAAY,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa;AAAA,IACtE,UAAU,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW;AAAA,IAChE,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAAA,IACpD,UAAU,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW;AAAA,EAClE,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;AACA,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,iCAAiC;AAAA,IACtC,WAAW,yBAAyB;AAAA,IACpC,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,oBAAoB,mBAAmB;AAAA,IACvC,gBAAgB,mBAAmB;AAAA,IACnC,QAAQ;AAAA,MACN,cAAc;AAAA,MACd,UAAU,CAAC,OAAO;AAAA,IACpB;AAAA,IACA,MAAM;AAAA,MACJ,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,QAC1B,IAAI,KAAK;AAAA,QACT,eAAe,KAAK;AAAA,QACpB,OAAO,KAAK,SAAS;AAAA,QACrB,iBAAiB,KAAK,mBAAmB;AAAA,QACzC,eAAe,KAAK,iBAAiB;AAAA,QACrC,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,QACd,MAAM,KAAK,QAAQ;AAAA,QACnB,SAAS,KAAK,WAAW;AAAA,QACzB,WAAW,KAAK,UAAU,YAAY;AAAA,MACxC,EAAE;AAAA,MACF;AAAA,MACA,MAAM,OAAO,KAAK;AAAA,MAClB,UAAU,OAAO,KAAK;AAAA,MACtB,YAAY,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,OAAO,KAAK,QAAQ,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AACH;",
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 '@open-mercato/core/modules/integrations/data/validators'\nimport type { IntegrationLogService } from '@open-mercato/core/modules/integrations/lib/log-service'\nimport {\n finalizeIntegrationsReadResponse,\n integrationApiRoutePaths,\n runIntegrationsReadBeforeInterceptors,\n} from '../umes-read'\nimport { resolveIntegrationsOrganizationId } from '../../lib/organization-scope'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.manage'] },\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 const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const beforeInterceptors = await runIntegrationsReadBeforeInterceptors({\n routePath: integrationApiRoutePaths.logs,\n request: req,\n auth,\n container,\n })\n if (!beforeInterceptors.ok) {\n return NextResponse.json(beforeInterceptors.body, { status: beforeInterceptors.statusCode })\n }\n\n const query = beforeInterceptors.request.query ?? {}\n const parsed = listIntegrationLogsQuerySchema.safeParse({\n integrationId: typeof query.integrationId === 'string' ? query.integrationId : undefined,\n level: typeof query.level === 'string' ? query.level : undefined,\n runId: typeof query.runId === 'string' ? query.runId : undefined,\n entityType: typeof query.entityType === 'string' ? query.entityType : undefined,\n entityId: typeof query.entityId === 'string' ? query.entityId : undefined,\n page: typeof query.page === 'string' ? query.page : undefined,\n pageSize: typeof query.pageSize === 'string' ? query.pageSize : undefined,\n })\n\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid query', details: parsed.error.flatten() }, { status: 400 })\n }\n const logService = container.resolve('integrationLogService') as IntegrationLogService\n\n const { items, total } = await logService.query(parsed.data, {\n organizationId: organizationId,\n tenantId: auth.tenantId,\n })\n\n return finalizeIntegrationsReadResponse({\n routePath: integrationApiRoutePaths.logs,\n request: req,\n auth,\n container,\n interceptorRequest: beforeInterceptors.request,\n beforeMetadata: beforeInterceptors.metadataByInterceptor,\n enrich: {\n targetEntity: 'integrations.log',\n listKeys: ['items'],\n },\n body: {\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}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -11,6 +11,7 @@ import {
11
11
  integrationApiRoutePaths,
12
12
  runIntegrationsReadBeforeInterceptors
13
13
  } from "./umes-read.js";
14
+ import { resolveIntegrationsOrganizationId } from "../lib/organization-scope.js";
14
15
  const metadata = {
15
16
  GET: { requireAuth: true, requireFeatures: ["integrations.view"] }
16
17
  };
@@ -35,7 +36,8 @@ function matchesSearchQuery(integration, queryNormalized) {
35
36
  }
36
37
  async function GET(req) {
37
38
  const auth = await getAuthFromRequest(req);
38
- if (!auth?.tenantId || !auth.orgId) {
39
+ const organizationId = resolveIntegrationsOrganizationId(auth);
40
+ if (!auth?.tenantId || !organizationId) {
39
41
  return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
40
42
  }
41
43
  const url = new URL(req.url);
@@ -57,7 +59,7 @@ async function GET(req) {
57
59
  const credentialsService = container.resolve("integrationCredentialsService");
58
60
  const stateService = container.resolve("integrationStateService");
59
61
  const logService = container.resolve("integrationLogService");
60
- const scope = { organizationId: auth.orgId, tenantId: auth.tenantId };
62
+ const scope = { organizationId, tenantId: auth.tenantId };
61
63
  const searchNeedle = query.q?.trim().toLowerCase() ?? "";
62
64
  const baseRows = await Promise.all(
63
65
  getAllIntegrations().map(async (integration) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/integrations/api/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 { CredentialsEncryptionUnavailableError, type CredentialsService } from '../lib/credentials-service'\nimport type { IntegrationStateService } from '../lib/state-service'\nimport type { IntegrationLogService } from '../lib/log-service'\nimport { deriveIntegrationHealthStatus, getEffectiveHealthCheckConfig } from '../lib/health-service'\nimport type { IntegrationHealthDisplayStatus } from '../lib/health-service'\nimport { getAllBundles, getAllIntegrations } from '@open-mercato/shared/modules/integrations/types'\nimport { listIntegrationsQuerySchema } from '../data/validators'\nimport { buildIntegrationsCrudOpenApi, integrationsListResponseSchema } from './openapi'\nimport {\n finalizeIntegrationsReadResponse,\n integrationApiRoutePaths,\n runIntegrationsReadBeforeInterceptors,\n} from './umes-read'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.view'] },\n}\n\nexport const openApi = buildIntegrationsCrudOpenApi({\n resourceName: 'Integration',\n pluralName: 'Integrations',\n listResponseSchema: integrationsListResponseSchema,\n querySchema: listIntegrationsQuerySchema,\n})\n\nconst HEALTH_SORT_RANK: Record<IntegrationHealthDisplayStatus, number> = {\n healthy: 0,\n degraded: 1,\n unhealthy: 2,\n unconfigured: 3,\n}\n\nfunction matchesSearchQuery(\n integration: { title: string; description?: string; tags?: string[] },\n queryNormalized: string,\n): boolean {\n if (!queryNormalized) return true\n if (integration.title.toLowerCase().includes(queryNormalized)) return true\n if (integration.description?.toLowerCase().includes(queryNormalized)) return true\n const tags = integration.tags ?? []\n return tags.some((tag) => tag.toLowerCase().includes(queryNormalized))\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 parsedQuery = listIntegrationsQuerySchema.safeParse(Object.fromEntries(url.searchParams.entries()))\n if (!parsedQuery.success) {\n return NextResponse.json({ error: 'Invalid query', details: parsedQuery.error.flatten() }, { status: 400 })\n }\n const query = parsedQuery.data\n\n const container = await createRequestContainer()\n const beforeInterceptors = await runIntegrationsReadBeforeInterceptors({\n routePath: integrationApiRoutePaths.list,\n request: req,\n auth,\n container,\n })\n if (!beforeInterceptors.ok) {\n return NextResponse.json(beforeInterceptors.body, { status: beforeInterceptors.statusCode })\n }\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const stateService = container.resolve('integrationStateService') as IntegrationStateService\n const logService = container.resolve('integrationLogService') as IntegrationLogService\n\n const scope = { organizationId: auth.orgId as string, tenantId: auth.tenantId as string }\n const searchNeedle = query.q?.trim().toLowerCase() ?? ''\n\n type ListRow = {\n id: string\n title: string\n description: string | null\n category: string | null\n tags: string[]\n hub: string | null\n providerKey: string | null\n bundleId: string | null\n author: string | null\n company: string | null\n version: string | null\n hasCredentials: boolean\n isEnabled: boolean\n apiVersion: string | null\n healthStatus: IntegrationHealthDisplayStatus\n lastHealthCheckedAt: string | null\n lastHealthLatencyMs: number | null\n enabledAt: string | null\n stateUpdatedAt: string | null\n sortEnabledAtMs: number\n sortTitle: string\n sortCategory: string\n }\n\n const baseRows: ListRow[] = await Promise.all(\n getAllIntegrations().map(async (integration) => {\n const [resolvedCredentials, state] = await Promise.all([\n credentialsService.resolve(integration.id, scope).catch((err) => {\n if (err instanceof CredentialsEncryptionUnavailableError) return null\n throw err\n }),\n stateService.resolveState(integration.id, scope),\n ])\n\n const hasCredentials =\n resolvedCredentials != null && Object.keys(resolvedCredentials).length > 0\n const healthConfig = getEffectiveHealthCheckConfig(integration.id)\n const hasHealthCheck = Boolean(healthConfig?.service)\n const healthStatus = deriveIntegrationHealthStatus({\n hasHealthCheck,\n hasCredentials,\n lastHealthStatus: state.lastHealthStatus,\n lastHealthCheckedAt: state.lastHealthCheckedAt,\n })\n\n const enabledAtMs = state.enabledAt?.getTime() ?? 0\n\n return {\n id: integration.id,\n title: integration.title,\n description: integration.description ?? null,\n category: integration.category ?? null,\n tags: integration.tags ?? [],\n hub: integration.hub ?? null,\n providerKey: integration.providerKey ?? null,\n bundleId: integration.bundleId ?? null,\n author: integration.author ?? null,\n company: integration.company ?? null,\n version: integration.version ?? null,\n hasCredentials,\n isEnabled: state.isEnabled,\n apiVersion: state.apiVersion,\n healthStatus,\n lastHealthCheckedAt: state.lastHealthCheckedAt?.toISOString() ?? null,\n lastHealthLatencyMs: state.lastHealthLatencyMs,\n enabledAt: state.enabledAt?.toISOString() ?? null,\n stateUpdatedAt: state.updatedAt?.toISOString() ?? null,\n sortEnabledAtMs: enabledAtMs,\n sortTitle: integration.title.toLowerCase(),\n sortCategory: (integration.category ?? '').toLowerCase(),\n }\n }),\n )\n\n let filtered = baseRows.filter((row) => matchesSearchQuery(\n { title: row.title, description: row.description ?? undefined, tags: row.tags },\n searchNeedle,\n ))\n\n if (query.category) {\n filtered = filtered.filter((row) => row.category === query.category)\n }\n if (query.bundleId) {\n filtered = filtered.filter((row) => row.bundleId === query.bundleId)\n }\n if (query.isEnabled !== undefined) {\n filtered = filtered.filter((row) => row.isEnabled === query.isEnabled)\n }\n if (query.healthStatus) {\n filtered = filtered.filter((row) => row.healthStatus === query.healthStatus)\n }\n\n const sortKey = query.sort ?? 'title'\n const orderSign = query.order === 'desc' ? -1 : 1\n\n const sorted = [...filtered].sort((rowA, rowB) => {\n let cmp = 0\n if (sortKey === 'title') {\n cmp = rowA.sortTitle.localeCompare(rowB.sortTitle)\n } else if (sortKey === 'category') {\n cmp = rowA.sortCategory.localeCompare(rowB.sortCategory)\n if (cmp === 0) cmp = rowA.sortTitle.localeCompare(rowB.sortTitle)\n } else if (sortKey === 'enabledAt') {\n cmp = rowA.sortEnabledAtMs - rowB.sortEnabledAtMs\n if (cmp === 0) cmp = rowA.sortTitle.localeCompare(rowB.sortTitle)\n } else if (sortKey === 'healthStatus') {\n cmp = HEALTH_SORT_RANK[rowA.healthStatus] - HEALTH_SORT_RANK[rowB.healthStatus]\n if (cmp === 0) cmp = rowA.sortTitle.localeCompare(rowB.sortTitle)\n }\n return cmp * orderSign\n })\n\n const total = sorted.length\n const pageSize = query.pageSize\n const page = query.page\n const totalPages = Math.max(1, Math.ceil(total / pageSize) || 1)\n const safePage = Math.min(page, totalPages)\n const offset = (safePage - 1) * pageSize\n const pageSlice = sorted.slice(offset, offset + pageSize)\n\n const analyticsMap = await logService.aggregateAnalytics(\n pageSlice.map((row) => row.id),\n scope,\n 30,\n )\n\n const items = pageSlice.map((row) => {\n const analytics = analyticsMap.get(row.id)\n return {\n id: row.id,\n title: row.title,\n description: row.description,\n category: row.category,\n tags: row.tags,\n hub: row.hub,\n providerKey: row.providerKey,\n bundleId: row.bundleId,\n author: row.author,\n company: row.company,\n version: row.version,\n hasCredentials: row.hasCredentials,\n isEnabled: row.isEnabled,\n apiVersion: row.apiVersion,\n healthStatus: row.healthStatus,\n lastHealthCheckedAt: row.lastHealthCheckedAt,\n lastHealthLatencyMs: row.lastHealthLatencyMs,\n enabledAt: row.enabledAt,\n stateUpdatedAt: row.stateUpdatedAt,\n analytics: analytics ?? {\n lastActivityAt: null,\n totalCount: 0,\n errorCount: 0,\n errorRate: 0,\n dailyCounts: Array.from({ length: 30 }, () => 0),\n },\n }\n })\n\n const bundles = getAllBundles().map((bundle) => {\n const bundleIntegrations = filtered.filter((row) => row.bundleId === bundle.id)\n const enabledCount = bundleIntegrations.reduce((count, integration) => count + (integration.isEnabled ? 1 : 0), 0)\n\n return {\n id: bundle.id,\n title: bundle.title,\n description: bundle.description,\n icon: bundle.icon ?? null,\n integrationCount: bundleIntegrations.length,\n enabledCount,\n }\n })\n\n return finalizeIntegrationsReadResponse({\n routePath: integrationApiRoutePaths.list,\n request: req,\n auth,\n container,\n interceptorRequest: beforeInterceptors.request,\n beforeMetadata: beforeInterceptors.metadataByInterceptor,\n enrich: {\n targetEntity: 'integrations.integration',\n listKeys: ['items'],\n },\n body: {\n items,\n bundles,\n total,\n page: safePage,\n pageSize,\n totalPages,\n },\n })\n}\n"],
5
- "mappings": "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",
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 { CredentialsEncryptionUnavailableError, type CredentialsService } from '../lib/credentials-service'\nimport type { IntegrationStateService } from '../lib/state-service'\nimport type { IntegrationLogService } from '../lib/log-service'\nimport { deriveIntegrationHealthStatus, getEffectiveHealthCheckConfig } from '../lib/health-service'\nimport type { IntegrationHealthDisplayStatus } from '../lib/health-service'\nimport { getAllBundles, getAllIntegrations } from '@open-mercato/shared/modules/integrations/types'\nimport { listIntegrationsQuerySchema } from '../data/validators'\nimport { buildIntegrationsCrudOpenApi, integrationsListResponseSchema } from './openapi'\nimport {\n finalizeIntegrationsReadResponse,\n integrationApiRoutePaths,\n runIntegrationsReadBeforeInterceptors,\n} from './umes-read'\nimport { resolveIntegrationsOrganizationId } from '../lib/organization-scope'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.view'] },\n}\n\nexport const openApi = buildIntegrationsCrudOpenApi({\n resourceName: 'Integration',\n pluralName: 'Integrations',\n listResponseSchema: integrationsListResponseSchema,\n querySchema: listIntegrationsQuerySchema,\n})\n\nconst HEALTH_SORT_RANK: Record<IntegrationHealthDisplayStatus, number> = {\n healthy: 0,\n degraded: 1,\n unhealthy: 2,\n unconfigured: 3,\n}\n\nfunction matchesSearchQuery(\n integration: { title: string; description?: string; tags?: string[] },\n queryNormalized: string,\n): boolean {\n if (!queryNormalized) return true\n if (integration.title.toLowerCase().includes(queryNormalized)) return true\n if (integration.description?.toLowerCase().includes(queryNormalized)) return true\n const tags = integration.tags ?? []\n return tags.some((tag) => tag.toLowerCase().includes(queryNormalized))\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const url = new URL(req.url)\n const parsedQuery = listIntegrationsQuerySchema.safeParse(Object.fromEntries(url.searchParams.entries()))\n if (!parsedQuery.success) {\n return NextResponse.json({ error: 'Invalid query', details: parsedQuery.error.flatten() }, { status: 400 })\n }\n const query = parsedQuery.data\n\n const container = await createRequestContainer()\n const beforeInterceptors = await runIntegrationsReadBeforeInterceptors({\n routePath: integrationApiRoutePaths.list,\n request: req,\n auth,\n container,\n })\n if (!beforeInterceptors.ok) {\n return NextResponse.json(beforeInterceptors.body, { status: beforeInterceptors.statusCode })\n }\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const stateService = container.resolve('integrationStateService') as IntegrationStateService\n const logService = container.resolve('integrationLogService') as IntegrationLogService\n\n const scope = { organizationId: organizationId, tenantId: auth.tenantId as string }\n const searchNeedle = query.q?.trim().toLowerCase() ?? ''\n\n type ListRow = {\n id: string\n title: string\n description: string | null\n category: string | null\n tags: string[]\n hub: string | null\n providerKey: string | null\n bundleId: string | null\n author: string | null\n company: string | null\n version: string | null\n hasCredentials: boolean\n isEnabled: boolean\n apiVersion: string | null\n healthStatus: IntegrationHealthDisplayStatus\n lastHealthCheckedAt: string | null\n lastHealthLatencyMs: number | null\n enabledAt: string | null\n stateUpdatedAt: string | null\n sortEnabledAtMs: number\n sortTitle: string\n sortCategory: string\n }\n\n const baseRows: ListRow[] = await Promise.all(\n getAllIntegrations().map(async (integration) => {\n const [resolvedCredentials, state] = await Promise.all([\n credentialsService.resolve(integration.id, scope).catch((err) => {\n if (err instanceof CredentialsEncryptionUnavailableError) return null\n throw err\n }),\n stateService.resolveState(integration.id, scope),\n ])\n\n const hasCredentials =\n resolvedCredentials != null && Object.keys(resolvedCredentials).length > 0\n const healthConfig = getEffectiveHealthCheckConfig(integration.id)\n const hasHealthCheck = Boolean(healthConfig?.service)\n const healthStatus = deriveIntegrationHealthStatus({\n hasHealthCheck,\n hasCredentials,\n lastHealthStatus: state.lastHealthStatus,\n lastHealthCheckedAt: state.lastHealthCheckedAt,\n })\n\n const enabledAtMs = state.enabledAt?.getTime() ?? 0\n\n return {\n id: integration.id,\n title: integration.title,\n description: integration.description ?? null,\n category: integration.category ?? null,\n tags: integration.tags ?? [],\n hub: integration.hub ?? null,\n providerKey: integration.providerKey ?? null,\n bundleId: integration.bundleId ?? null,\n author: integration.author ?? null,\n company: integration.company ?? null,\n version: integration.version ?? null,\n hasCredentials,\n isEnabled: state.isEnabled,\n apiVersion: state.apiVersion,\n healthStatus,\n lastHealthCheckedAt: state.lastHealthCheckedAt?.toISOString() ?? null,\n lastHealthLatencyMs: state.lastHealthLatencyMs,\n enabledAt: state.enabledAt?.toISOString() ?? null,\n stateUpdatedAt: state.updatedAt?.toISOString() ?? null,\n sortEnabledAtMs: enabledAtMs,\n sortTitle: integration.title.toLowerCase(),\n sortCategory: (integration.category ?? '').toLowerCase(),\n }\n }),\n )\n\n let filtered = baseRows.filter((row) => matchesSearchQuery(\n { title: row.title, description: row.description ?? undefined, tags: row.tags },\n searchNeedle,\n ))\n\n if (query.category) {\n filtered = filtered.filter((row) => row.category === query.category)\n }\n if (query.bundleId) {\n filtered = filtered.filter((row) => row.bundleId === query.bundleId)\n }\n if (query.isEnabled !== undefined) {\n filtered = filtered.filter((row) => row.isEnabled === query.isEnabled)\n }\n if (query.healthStatus) {\n filtered = filtered.filter((row) => row.healthStatus === query.healthStatus)\n }\n\n const sortKey = query.sort ?? 'title'\n const orderSign = query.order === 'desc' ? -1 : 1\n\n const sorted = [...filtered].sort((rowA, rowB) => {\n let cmp = 0\n if (sortKey === 'title') {\n cmp = rowA.sortTitle.localeCompare(rowB.sortTitle)\n } else if (sortKey === 'category') {\n cmp = rowA.sortCategory.localeCompare(rowB.sortCategory)\n if (cmp === 0) cmp = rowA.sortTitle.localeCompare(rowB.sortTitle)\n } else if (sortKey === 'enabledAt') {\n cmp = rowA.sortEnabledAtMs - rowB.sortEnabledAtMs\n if (cmp === 0) cmp = rowA.sortTitle.localeCompare(rowB.sortTitle)\n } else if (sortKey === 'healthStatus') {\n cmp = HEALTH_SORT_RANK[rowA.healthStatus] - HEALTH_SORT_RANK[rowB.healthStatus]\n if (cmp === 0) cmp = rowA.sortTitle.localeCompare(rowB.sortTitle)\n }\n return cmp * orderSign\n })\n\n const total = sorted.length\n const pageSize = query.pageSize\n const page = query.page\n const totalPages = Math.max(1, Math.ceil(total / pageSize) || 1)\n const safePage = Math.min(page, totalPages)\n const offset = (safePage - 1) * pageSize\n const pageSlice = sorted.slice(offset, offset + pageSize)\n\n const analyticsMap = await logService.aggregateAnalytics(\n pageSlice.map((row) => row.id),\n scope,\n 30,\n )\n\n const items = pageSlice.map((row) => {\n const analytics = analyticsMap.get(row.id)\n return {\n id: row.id,\n title: row.title,\n description: row.description,\n category: row.category,\n tags: row.tags,\n hub: row.hub,\n providerKey: row.providerKey,\n bundleId: row.bundleId,\n author: row.author,\n company: row.company,\n version: row.version,\n hasCredentials: row.hasCredentials,\n isEnabled: row.isEnabled,\n apiVersion: row.apiVersion,\n healthStatus: row.healthStatus,\n lastHealthCheckedAt: row.lastHealthCheckedAt,\n lastHealthLatencyMs: row.lastHealthLatencyMs,\n enabledAt: row.enabledAt,\n stateUpdatedAt: row.stateUpdatedAt,\n analytics: analytics ?? {\n lastActivityAt: null,\n totalCount: 0,\n errorCount: 0,\n errorRate: 0,\n dailyCounts: Array.from({ length: 30 }, () => 0),\n },\n }\n })\n\n const bundles = getAllBundles().map((bundle) => {\n const bundleIntegrations = filtered.filter((row) => row.bundleId === bundle.id)\n const enabledCount = bundleIntegrations.reduce((count, integration) => count + (integration.isEnabled ? 1 : 0), 0)\n\n return {\n id: bundle.id,\n title: bundle.title,\n description: bundle.description,\n icon: bundle.icon ?? null,\n integrationCount: bundleIntegrations.length,\n enabledCount,\n }\n })\n\n return finalizeIntegrationsReadResponse({\n routePath: integrationApiRoutePaths.list,\n request: req,\n auth,\n container,\n interceptorRequest: beforeInterceptors.request,\n beforeMetadata: beforeInterceptors.metadataByInterceptor,\n enrich: {\n targetEntity: 'integrations.integration',\n listKeys: ['items'],\n },\n body: {\n items,\n bundles,\n total,\n page: safePage,\n pageSize,\n totalPages,\n },\n })\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }