@open-mercato/core 0.6.3-develop.3593.1.8eda8943fa → 0.6.3-develop.3598.1.259c138c7d

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.
@@ -46,137 +46,147 @@ export const openApi = {
46
46
  }
47
47
 
48
48
  export async function POST(request: Request) {
49
- const auth = await getAuthFromRequest(request)
50
- if (!auth?.tenantId) {
51
- return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
52
- }
53
-
54
- const payload = await readJsonSafe(request)
55
- const parsedPayload = syncExcelImportRequestSchema.safeParse(payload)
56
- if (!parsedPayload.success) {
57
- return NextResponse.json({ error: 'Invalid import payload.' }, { status: 422 })
58
- }
59
-
60
- const container = await createRequestContainer()
61
- const em = container.resolve('em') as EntityManager
62
- const syncRunService = container.resolve('dataSyncRunService') as SyncRunService
63
- const progressService = container.resolve('progressService') as ProgressService
64
- const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService
65
- const integrationStateService = container.resolve('integrationStateService') as IntegrationStateService
66
- const scopeResult = await resolveSyncExcelConcreteScope({ auth, container, request })
67
- if (!scopeResult.ok) {
68
- return NextResponse.json({ error: scopeResult.error }, { status: scopeResult.status })
69
- }
70
- const { scope } = scopeResult
71
-
72
- const upload = await findOneWithDecryption(
73
- em,
74
- SyncExcelUpload,
75
- {
76
- id: parsedPayload.data.uploadId,
77
- organizationId: scope.organizationId,
78
- tenantId: scope.tenantId,
79
- },
80
- undefined,
81
- scope,
82
- )
83
-
84
- if (!upload) {
85
- return NextResponse.json({ error: 'Upload preview not found.' }, { status: 404 })
86
- }
87
-
88
- const attachment = await findOneWithDecryption(
89
- em,
90
- Attachment,
91
- {
92
- id: upload.attachmentId,
93
- organizationId: scope.organizationId,
94
- tenantId: scope.tenantId,
95
- },
96
- undefined,
97
- scope,
98
- )
99
-
100
- if (!attachment) {
101
- return NextResponse.json({ error: 'Upload attachment not found.' }, { status: 404 })
102
- }
103
-
104
- if (upload.entityType !== parsedPayload.data.entityType) {
105
- return NextResponse.json({ error: 'Upload entity type does not match requested import target.' }, { status: 422 })
106
- }
107
-
108
- if (parsedPayload.data.mapping.entityType !== parsedPayload.data.entityType) {
109
- return NextResponse.json({ error: 'Mapping entity type does not match requested import target.' }, { status: 422 })
110
- }
111
-
112
- const overlap = await syncRunService.findRunningOverlap('sync_excel', parsedPayload.data.entityType, 'import', scope)
113
- if (overlap) {
114
- return NextResponse.json({ error: 'A sync_excel import is already in progress for this entity type.' }, { status: 409 })
115
- }
116
-
117
- const existingMapping = await findOneWithDecryption(
118
- em,
119
- SyncMapping,
120
- {
121
- integrationId: 'sync_excel',
122
- entityType: parsedPayload.data.entityType,
123
- organizationId: scope.organizationId,
124
- tenantId: scope.tenantId,
125
- },
126
- undefined,
127
- scope,
128
- )
129
-
130
- if (existingMapping) {
131
- existingMapping.mapping = parsedPayload.data.mapping
132
- } else {
133
- em.persist(em.create(SyncMapping, {
134
- integrationId: 'sync_excel',
135
- entityType: parsedPayload.data.entityType,
136
- mapping: parsedPayload.data.mapping,
137
- organizationId: scope.organizationId,
138
- tenantId: scope.tenantId,
139
- }))
140
- }
141
-
142
- await credentialsService.save('sync_excel', {}, scope)
143
- await integrationStateService.upsert('sync_excel', { isEnabled: true }, scope)
144
- await em.flush()
145
-
146
- const { run, progressJob } = await startDataSyncRun({
147
- syncRunService,
148
- progressService,
149
- scope: {
150
- ...scope,
151
- userId: auth.sub,
152
- },
153
- input: {
154
- integrationId: 'sync_excel',
155
- entityType: parsedPayload.data.entityType,
156
- direction: 'import',
157
- cursor: createCursor(upload.id, 0),
158
- triggeredBy: auth.sub,
159
- batchSize: parsedPayload.data.batchSize ?? 100,
160
- progressJob: {
161
- jobType: 'sync_excel:import',
162
- name: `CSV import — ${parsedPayload.data.entityType}`,
163
- description: upload.filename,
164
- meta: {
165
- integrationId: 'sync_excel',
166
- uploadId: upload.id,
167
- hiddenFromTopBar: false,
49
+ try {
50
+ const auth = await getAuthFromRequest(request)
51
+ if (!auth?.tenantId) {
52
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
53
+ }
54
+
55
+ const payload = await readJsonSafe(request)
56
+ const parsedPayload = syncExcelImportRequestSchema.safeParse(payload)
57
+ if (!parsedPayload.success) {
58
+ return NextResponse.json({ error: 'Invalid import payload.' }, { status: 422 })
59
+ }
60
+
61
+ const container = await createRequestContainer()
62
+ const em = container.resolve('em') as EntityManager
63
+ const syncRunService = container.resolve('dataSyncRunService') as SyncRunService
64
+ const progressService = container.resolve('progressService') as ProgressService
65
+ const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService
66
+ const integrationStateService = container.resolve('integrationStateService') as IntegrationStateService
67
+ const scopeResult = await resolveSyncExcelConcreteScope({ auth, container, request })
68
+ if (!scopeResult.ok) {
69
+ return NextResponse.json({ error: scopeResult.error }, { status: scopeResult.status })
70
+ }
71
+ const { scope } = scopeResult
72
+
73
+ const upload = await findOneWithDecryption(
74
+ em,
75
+ SyncExcelUpload,
76
+ {
77
+ id: parsedPayload.data.uploadId,
78
+ organizationId: scope.organizationId,
79
+ tenantId: scope.tenantId,
80
+ },
81
+ undefined,
82
+ scope,
83
+ )
84
+
85
+ if (!upload) {
86
+ return NextResponse.json({ error: 'Upload preview not found.' }, { status: 404 })
87
+ }
88
+
89
+ const attachment = await findOneWithDecryption(
90
+ em,
91
+ Attachment,
92
+ {
93
+ id: upload.attachmentId,
94
+ organizationId: scope.organizationId,
95
+ tenantId: scope.tenantId,
96
+ },
97
+ undefined,
98
+ scope,
99
+ )
100
+
101
+ if (!attachment) {
102
+ return NextResponse.json({ error: 'Upload attachment not found.' }, { status: 404 })
103
+ }
104
+
105
+ if (upload.entityType !== parsedPayload.data.entityType) {
106
+ return NextResponse.json({ error: 'Upload entity type does not match requested import target.' }, { status: 422 })
107
+ }
108
+
109
+ if (parsedPayload.data.mapping.entityType !== parsedPayload.data.entityType) {
110
+ return NextResponse.json({ error: 'Mapping entity type does not match requested import target.' }, { status: 422 })
111
+ }
112
+
113
+ const overlap = await syncRunService.findRunningOverlap('sync_excel', parsedPayload.data.entityType, 'import', scope)
114
+ if (overlap) {
115
+ return NextResponse.json({ error: 'A sync_excel import is already in progress for this entity type.' }, { status: 409 })
116
+ }
117
+
118
+ const existingMapping = await findOneWithDecryption(
119
+ em,
120
+ SyncMapping,
121
+ {
122
+ integrationId: 'sync_excel',
123
+ entityType: parsedPayload.data.entityType,
124
+ organizationId: scope.organizationId,
125
+ tenantId: scope.tenantId,
126
+ },
127
+ undefined,
128
+ scope,
129
+ )
130
+
131
+ if (existingMapping) {
132
+ existingMapping.mapping = parsedPayload.data.mapping
133
+ } else {
134
+ em.persist(em.create(SyncMapping, {
135
+ integrationId: 'sync_excel',
136
+ entityType: parsedPayload.data.entityType,
137
+ mapping: parsedPayload.data.mapping,
138
+ organizationId: scope.organizationId,
139
+ tenantId: scope.tenantId,
140
+ }))
141
+ }
142
+
143
+ await credentialsService.save('sync_excel', {}, scope)
144
+ await integrationStateService.upsert('sync_excel', { isEnabled: true }, scope)
145
+ await em.flush()
146
+
147
+ const { run, progressJob } = await startDataSyncRun({
148
+ syncRunService,
149
+ progressService,
150
+ scope: {
151
+ ...scope,
152
+ userId: auth.sub,
153
+ },
154
+ input: {
155
+ integrationId: 'sync_excel',
156
+ entityType: parsedPayload.data.entityType,
157
+ direction: 'import',
158
+ cursor: createCursor(upload.id, 0),
159
+ triggeredBy: auth.sub,
160
+ batchSize: parsedPayload.data.batchSize ?? 100,
161
+ progressJob: {
162
+ jobType: 'sync_excel:import',
163
+ name: `CSV import — ${parsedPayload.data.entityType}`,
164
+ description: upload.filename,
165
+ meta: {
166
+ integrationId: 'sync_excel',
167
+ uploadId: upload.id,
168
+ hiddenFromTopBar: false,
169
+ },
168
170
  },
169
171
  },
170
- },
171
- })
172
-
173
- upload.syncRunId = run.id
174
- upload.status = 'importing'
175
- await em.flush()
176
-
177
- return NextResponse.json(syncExcelImportResponseSchema.parse({
178
- runId: run.id,
179
- progressJobId: progressJob?.id ?? null,
180
- status: run.status,
181
- }), { status: 201 })
172
+ })
173
+
174
+ upload.syncRunId = run.id
175
+ upload.status = 'importing'
176
+ await em.flush()
177
+
178
+ return NextResponse.json(syncExcelImportResponseSchema.parse({
179
+ runId: run.id,
180
+ progressJobId: progressJob?.id ?? null,
181
+ status: run.status,
182
+ }), { status: 201 })
183
+ } catch (error) {
184
+ const message = error instanceof Error ? error.message : String(error)
185
+ const stack = error instanceof Error ? error.stack : undefined
186
+ console.error('[sync_excel.import] unhandled error', { message, stack })
187
+ return NextResponse.json(
188
+ { error: 'Failed to start sync_excel import.', message },
189
+ { status: 500 },
190
+ )
191
+ }
182
192
  }