@skedulo/integration-sdk 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/actions/action-registry.d.ts.map +1 -1
- package/dist/actions/action-registry.js +1 -0
- package/dist/actions/action-registry.js.map +1 -1
- package/dist/actions/data-flow.action.d.ts +62 -0
- package/dist/actions/data-flow.action.d.ts.map +1 -0
- package/dist/actions/data-flow.action.js +217 -0
- package/dist/actions/data-flow.action.js.map +1 -0
- package/dist/actions/event/on-skedulo.action.d.ts.map +1 -1
- package/dist/actions/event/on-skedulo.action.js +12 -1
- package/dist/actions/event/on-skedulo.action.js.map +1 -1
- package/dist/actions/event/types.d.ts +2 -0
- package/dist/actions/event/types.d.ts.map +1 -1
- package/dist/actions/event.action.d.ts +32 -0
- package/dist/actions/event.action.d.ts.map +1 -0
- package/dist/actions/event.action.js +113 -0
- package/dist/actions/event.action.js.map +1 -0
- package/dist/actions/metadata.action.d.ts +44 -0
- package/dist/actions/metadata.action.d.ts.map +1 -0
- package/dist/actions/metadata.action.js +96 -0
- package/dist/actions/metadata.action.js.map +1 -0
- package/dist/actions/scheduled-job.action.d.ts +73 -0
- package/dist/actions/scheduled-job.action.d.ts.map +1 -0
- package/dist/actions/scheduled-job.action.js +355 -0
- package/dist/actions/scheduled-job.action.js.map +1 -0
- package/dist/actions/sync/index.d.ts +1 -0
- package/dist/actions/sync/index.d.ts.map +1 -1
- package/dist/actions/sync/index.js +3 -1
- package/dist/actions/sync/index.js.map +1 -1
- package/dist/actions/sync/retry-failed.action.d.ts +10 -0
- package/dist/actions/sync/retry-failed.action.d.ts.map +1 -0
- package/dist/actions/sync/retry-failed.action.js +61 -0
- package/dist/actions/sync/retry-failed.action.js.map +1 -0
- package/dist/actions/sync/types.d.ts +11 -0
- package/dist/actions/sync/types.d.ts.map +1 -1
- package/dist/actions/sync.action.d.ts +26 -0
- package/dist/actions/sync.action.d.ts.map +1 -0
- package/dist/actions/sync.action.js +81 -0
- package/dist/actions/sync.action.js.map +1 -0
- package/dist/actions/utils/action-names.d.ts +1 -0
- package/dist/actions/utils/action-names.d.ts.map +1 -1
- package/dist/actions/utils/action-names.js +1 -0
- package/dist/actions/utils/action-names.js.map +1 -1
- package/dist/actions/utils/types.d.ts +2 -0
- package/dist/actions/utils/types.d.ts.map +1 -1
- package/dist/adapters/base-adapter-handler.d.ts +2 -0
- package/dist/adapters/base-adapter-handler.d.ts.map +1 -1
- package/dist/adapters/base-adapter-handler.js +4 -1
- package/dist/adapters/base-adapter-handler.js.map +1 -1
- package/dist/adapters/capabilities-defaults.d.ts.map +1 -1
- package/dist/adapters/capabilities-defaults.js +7 -1
- package/dist/adapters/capabilities-defaults.js.map +1 -1
- package/dist/adapters/skedulo-mutation-result.d.ts +18 -0
- package/dist/adapters/skedulo-mutation-result.d.ts.map +1 -0
- package/dist/adapters/skedulo-mutation-result.js +124 -0
- package/dist/adapters/skedulo-mutation-result.js.map +1 -0
- package/dist/adapters/skedulo.adapter.d.ts +5 -0
- package/dist/adapters/skedulo.adapter.d.ts.map +1 -1
- package/dist/adapters/skedulo.adapter.js +139 -35
- package/dist/adapters/skedulo.adapter.js.map +1 -1
- package/dist/clients/failed-record.client.d.ts +37 -0
- package/dist/clients/failed-record.client.d.ts.map +1 -0
- package/dist/clients/failed-record.client.js +48 -0
- package/dist/clients/failed-record.client.js.map +1 -0
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +8 -1
- package/dist/constants.js.map +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +5 -0
- package/dist/context.js.map +1 -1
- package/dist/interfaces/adapter.interface.d.ts +13 -0
- package/dist/interfaces/adapter.interface.d.ts.map +1 -1
- package/dist/interfaces/integration-capabilities.interface.d.ts +22 -0
- package/dist/interfaces/integration-capabilities.interface.d.ts.map +1 -1
- package/dist/interfaces/sync-pipeline.interface.d.ts +11 -0
- package/dist/interfaces/sync-pipeline.interface.d.ts.map +1 -1
- package/dist/services/artifact-builder.d.ts +95 -0
- package/dist/services/artifact-builder.d.ts.map +1 -0
- package/dist/services/artifact-builder.js +142 -0
- package/dist/services/artifact-builder.js.map +1 -0
- package/dist/services/external-id-sync.strategy.d.ts.map +1 -1
- package/dist/services/external-id-sync.strategy.js +23 -24
- package/dist/services/external-id-sync.strategy.js.map +1 -1
- package/dist/services/id-mapping-sync.strategy.d.ts.map +1 -1
- package/dist/services/id-mapping-sync.strategy.js +35 -21
- package/dist/services/id-mapping-sync.strategy.js.map +1 -1
- package/dist/services/id-mapping.service.d.ts +2 -0
- package/dist/services/id-mapping.service.d.ts.map +1 -1
- package/dist/services/id-mapping.service.js +57 -2
- package/dist/services/id-mapping.service.js.map +1 -1
- package/dist/services/run-log-builder.d.ts +4 -5
- package/dist/services/run-log-builder.d.ts.map +1 -1
- package/dist/services/run-log-builder.js +4 -5
- package/dist/services/run-log-builder.js.map +1 -1
- package/dist/services/sync-pipeline-errors.d.ts +24 -0
- package/dist/services/sync-pipeline-errors.d.ts.map +1 -0
- package/dist/services/sync-pipeline-errors.js +52 -0
- package/dist/services/sync-pipeline-errors.js.map +1 -0
- package/dist/services/sync-runner.d.ts +15 -0
- package/dist/services/sync-runner.d.ts.map +1 -1
- package/dist/services/sync-runner.js +250 -10
- package/dist/services/sync-runner.js.map +1 -1
- package/dist/services/sync.service.d.ts +4 -1
- package/dist/services/sync.service.d.ts.map +1 -1
- package/dist/services/sync.service.js +3 -2
- package/dist/services/sync.service.js.map +1 -1
- package/package.json +2 -2
- package/yarn.lock +4 -4
- package/.claude/worktrees/agent-a16acadaf5412dffd/jest.config.js +0 -12
- package/.claude/worktrees/agent-a33c3e4636d488e49/jest.config.js +0 -12
- package/.claude/worktrees/agent-a5b1d2ffa4ceef4a6/jest.config.js +0 -12
- package/.claude/worktrees/agent-aa1db4c22eabbde8e/jest.config.js +0 -12
- package/.claude/worktrees/agent-ac197ae8c69d7061c/jest.config.js +0 -12
- package/dist/handlers/metadata.handler.d.ts +0 -17
- package/dist/handlers/metadata.handler.d.ts.map +0 -1
- package/dist/handlers/metadata.handler.js +0 -50
- package/dist/handlers/metadata.handler.js.map +0 -1
- package/dist/utils/normalizeDataFlow.d.ts +0 -3
- package/dist/utils/normalizeDataFlow.d.ts.map +0 -1
- package/dist/utils/normalizeDataFlow.js +0 -37
- package/dist/utils/normalizeDataFlow.js.map +0 -1
- package/dist/utils.d.ts +0 -2
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -10
- package/dist/utils.js.map +0 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ArtifactClient } from '@skedulo/pulse-solution-services';
|
|
2
|
+
import type { DataFlow } from '../interfaces/data-flow-spec.interface';
|
|
3
|
+
import { ACTIONS } from '../actions/utils/action-names';
|
|
4
|
+
/**
|
|
5
|
+
* Deterministic artifact name used as the idempotency key for the
|
|
6
|
+
* webhook / triggered action provisioned for a DataFlow.
|
|
7
|
+
*
|
|
8
|
+
* Format: `sked-int-${integrationType}-${sourceObject}-to-${targetObject}-flow${id}`
|
|
9
|
+
* Throws if the result exceeds 100 chars (we don't truncate, since collisions
|
|
10
|
+
* on the prefix would cause silent cross-flow overwrites).
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildArtifactName(flow: DataFlow, integrationType: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Convert `intervalMinutes` to a 5-field cron expression.
|
|
15
|
+
* - n <= 1 → `* * * * *` (every minute)
|
|
16
|
+
* - 1 < n < 60 → `*\/n * * * *`
|
|
17
|
+
* - 60 <= n, multiples of 60 → `0 *\/h * * *` (every h hours)
|
|
18
|
+
* - otherwise → fall back to `*\/n * * * *` (cron itself rejects > 59 in min field;
|
|
19
|
+
* callers should pass a divisor of 60 for n >= 60)
|
|
20
|
+
*/
|
|
21
|
+
export declare function intervalMinutesToCron(intervalMinutes: number): string;
|
|
22
|
+
/**
|
|
23
|
+
* GraphQL selection-set fragment for the triggered action's `action.query`.
|
|
24
|
+
* ES executes this against the Skedulo schema and POSTs the result as the
|
|
25
|
+
* function body, so it MUST include every Skedulo field the mapping reads.
|
|
26
|
+
* `UID` is always included since we use it as the record identifier.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildSkeduloQuery(flow: DataFlow): string;
|
|
29
|
+
export interface BuildScheduledWebhookOpts {
|
|
30
|
+
name: string;
|
|
31
|
+
url: string;
|
|
32
|
+
cron: string;
|
|
33
|
+
/** Value placed on the dispatcher action header so the function knows which action to run. */
|
|
34
|
+
action: typeof ACTIONS.sync.push | typeof ACTIONS.sync.scheduledPull;
|
|
35
|
+
dataFlowId: number;
|
|
36
|
+
}
|
|
37
|
+
export declare function buildScheduledWebhookArtifact(opts: BuildScheduledWebhookOpts): {
|
|
38
|
+
name: string;
|
|
39
|
+
metadata: {
|
|
40
|
+
type: string;
|
|
41
|
+
};
|
|
42
|
+
webhook: {
|
|
43
|
+
type: string;
|
|
44
|
+
url: string;
|
|
45
|
+
cron: string;
|
|
46
|
+
headers: {
|
|
47
|
+
Authorization: string;
|
|
48
|
+
"sked-integration-action": "sync.push" | "sync.scheduled-pull";
|
|
49
|
+
'sked-data-flow-id': string;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export interface BuildTriggeredActionOpts {
|
|
54
|
+
name: string;
|
|
55
|
+
url: string;
|
|
56
|
+
/** Skedulo schema name to subscribe to (e.g. `"Jobs"`). */
|
|
57
|
+
schemaName: string;
|
|
58
|
+
/** GraphQL selection-set fragment, e.g. `"{ UID Name JobStatus }"`. */
|
|
59
|
+
query: string;
|
|
60
|
+
dataFlowId: number;
|
|
61
|
+
}
|
|
62
|
+
export declare function buildTriggeredActionArtifact(opts: BuildTriggeredActionOpts): {
|
|
63
|
+
name: string;
|
|
64
|
+
metadata: {
|
|
65
|
+
type: string;
|
|
66
|
+
};
|
|
67
|
+
enabled: boolean;
|
|
68
|
+
trigger: {
|
|
69
|
+
type: string;
|
|
70
|
+
schemaName: string;
|
|
71
|
+
filter: string;
|
|
72
|
+
};
|
|
73
|
+
action: {
|
|
74
|
+
type: string;
|
|
75
|
+
url: string;
|
|
76
|
+
headers: {
|
|
77
|
+
Authorization: string;
|
|
78
|
+
"sked-integration-action": "event.on-skedulo";
|
|
79
|
+
'sked-data-flow-id': string;
|
|
80
|
+
};
|
|
81
|
+
query: string;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Idempotent upsert: try `get` then `update`; on any error (including not-found)
|
|
86
|
+
* fall back to `create`. The PSS artifact API is name-keyed, so this collapses
|
|
87
|
+
* "create" and "replace" into a single safe call.
|
|
88
|
+
*/
|
|
89
|
+
export declare function upsertArtifact(client: ArtifactClient, name: string, artifact: unknown): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Delete by name, swallowing not-found errors so deactivate is idempotent.
|
|
92
|
+
* The PSS client throws `Error("HTTP error! Status: 404. …")`; match on that.
|
|
93
|
+
*/
|
|
94
|
+
export declare function deleteArtifactIfExists(client: ArtifactClient, name: string): Promise<void>;
|
|
95
|
+
//# sourceMappingURL=artifact-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-builder.d.ts","sourceRoot":"","sources":["../../src/services/artifact-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AACvE,OAAO,EAAiB,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAWvE;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAajF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAQrE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAUxD;AAMD,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,MAAM,EAAE,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC;IACrE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,yBAAyB;;;;;;;;;;;;;;;EAe5E;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,wBAAwB;;;;;;;;;;;;;;;;;;;;;EAqB1E;AAID;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhG"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildArtifactName = buildArtifactName;
|
|
4
|
+
exports.intervalMinutesToCron = intervalMinutesToCron;
|
|
5
|
+
exports.buildSkeduloQuery = buildSkeduloQuery;
|
|
6
|
+
exports.buildScheduledWebhookArtifact = buildScheduledWebhookArtifact;
|
|
7
|
+
exports.buildTriggeredActionArtifact = buildTriggeredActionArtifact;
|
|
8
|
+
exports.upsertArtifact = upsertArtifact;
|
|
9
|
+
exports.deleteArtifactIfExists = deleteArtifactIfExists;
|
|
10
|
+
const action_names_1 = require("../actions/utils/action-names");
|
|
11
|
+
const MAX_NAME_LENGTH = 100;
|
|
12
|
+
function slugify(value) {
|
|
13
|
+
return value
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
16
|
+
.replace(/^-+|-+$/g, '');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Deterministic artifact name used as the idempotency key for the
|
|
20
|
+
* webhook / triggered action provisioned for a DataFlow.
|
|
21
|
+
*
|
|
22
|
+
* Format: `sked-int-${integrationType}-${sourceObject}-to-${targetObject}-flow${id}`
|
|
23
|
+
* Throws if the result exceeds 100 chars (we don't truncate, since collisions
|
|
24
|
+
* on the prefix would cause silent cross-flow overwrites).
|
|
25
|
+
*/
|
|
26
|
+
function buildArtifactName(flow, integrationType) {
|
|
27
|
+
if (!integrationType) {
|
|
28
|
+
throw new Error('buildArtifactName requires an integrationType');
|
|
29
|
+
}
|
|
30
|
+
const name = `sked-int-${slugify(integrationType)}-${slugify(flow.sourceObject)}-to-${slugify(flow.targetObject)}-flow${flow.id}`;
|
|
31
|
+
if (name.length > MAX_NAME_LENGTH) {
|
|
32
|
+
throw new Error(`buildArtifactName produced a name of ${name.length} characters (max ${MAX_NAME_LENGTH}): "${name}"`);
|
|
33
|
+
}
|
|
34
|
+
return name;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Convert `intervalMinutes` to a 5-field cron expression.
|
|
38
|
+
* - n <= 1 → `* * * * *` (every minute)
|
|
39
|
+
* - 1 < n < 60 → `*\/n * * * *`
|
|
40
|
+
* - 60 <= n, multiples of 60 → `0 *\/h * * *` (every h hours)
|
|
41
|
+
* - otherwise → fall back to `*\/n * * * *` (cron itself rejects > 59 in min field;
|
|
42
|
+
* callers should pass a divisor of 60 for n >= 60)
|
|
43
|
+
*/
|
|
44
|
+
function intervalMinutesToCron(intervalMinutes) {
|
|
45
|
+
if (!Number.isInteger(intervalMinutes) || intervalMinutes <= 1)
|
|
46
|
+
return '* * * * *';
|
|
47
|
+
if (intervalMinutes < 60)
|
|
48
|
+
return `*/${intervalMinutes} * * * *`;
|
|
49
|
+
if (intervalMinutes % 60 === 0) {
|
|
50
|
+
const hours = intervalMinutes / 60;
|
|
51
|
+
return hours === 1 ? '0 * * * *' : `0 */${hours} * * *`;
|
|
52
|
+
}
|
|
53
|
+
return `*/${intervalMinutes} * * * *`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* GraphQL selection-set fragment for the triggered action's `action.query`.
|
|
57
|
+
* ES executes this against the Skedulo schema and POSTs the result as the
|
|
58
|
+
* function body, so it MUST include every Skedulo field the mapping reads.
|
|
59
|
+
* `UID` is always included since we use it as the record identifier.
|
|
60
|
+
*/
|
|
61
|
+
function buildSkeduloQuery(flow) {
|
|
62
|
+
var _a, _b, _c;
|
|
63
|
+
const fields = new Set(['UID']);
|
|
64
|
+
// IS does not return `sourceFields`; the Skedulo source fields are the
|
|
65
|
+
// mapping expressions (mirrors skedulo.adapter fetch).
|
|
66
|
+
const sourceFields = (_c = (_a = flow.sourceFields) !== null && _a !== void 0 ? _a : (_b = flow.mappingConfig) === null || _b === void 0 ? void 0 : _b.mappings.map((m) => m.expression)) !== null && _c !== void 0 ? _c : [];
|
|
67
|
+
for (const f of sourceFields) {
|
|
68
|
+
if (f && typeof f === 'string')
|
|
69
|
+
fields.add(f);
|
|
70
|
+
}
|
|
71
|
+
return `{ ${Array.from(fields).join(' ')} }`;
|
|
72
|
+
}
|
|
73
|
+
// ── Artifact bodies ──────────────────────────────────────────────────────────
|
|
74
|
+
const ADMIN_AUTH_HEADER = 'Bearer {{ INTEGRATION_ADMIN_TOKEN }}';
|
|
75
|
+
function buildScheduledWebhookArtifact(opts) {
|
|
76
|
+
return {
|
|
77
|
+
name: opts.name,
|
|
78
|
+
metadata: { type: 'Webhook' },
|
|
79
|
+
webhook: {
|
|
80
|
+
type: 'scheduled',
|
|
81
|
+
url: opts.url,
|
|
82
|
+
cron: opts.cron,
|
|
83
|
+
headers: {
|
|
84
|
+
Authorization: ADMIN_AUTH_HEADER,
|
|
85
|
+
[action_names_1.ACTION_HEADER]: opts.action,
|
|
86
|
+
'sked-data-flow-id': String(opts.dataFlowId),
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function buildTriggeredActionArtifact(opts) {
|
|
92
|
+
return {
|
|
93
|
+
name: opts.name,
|
|
94
|
+
metadata: { type: 'TriggeredAction' },
|
|
95
|
+
enabled: true,
|
|
96
|
+
trigger: {
|
|
97
|
+
type: 'object_modified',
|
|
98
|
+
schemaName: opts.schemaName,
|
|
99
|
+
filter: "Operation == 'INSERT' OR Operation == 'UPDATE' OR Operation == 'DELETE'",
|
|
100
|
+
},
|
|
101
|
+
action: {
|
|
102
|
+
type: 'call_url',
|
|
103
|
+
url: opts.url,
|
|
104
|
+
headers: {
|
|
105
|
+
Authorization: ADMIN_AUTH_HEADER,
|
|
106
|
+
[action_names_1.ACTION_HEADER]: action_names_1.ACTIONS.event.onSkedulo,
|
|
107
|
+
'sked-data-flow-id': String(opts.dataFlowId),
|
|
108
|
+
},
|
|
109
|
+
query: opts.query,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// ── Upsert / delete helpers ──────────────────────────────────────────────────
|
|
114
|
+
/**
|
|
115
|
+
* Idempotent upsert: try `get` then `update`; on any error (including not-found)
|
|
116
|
+
* fall back to `create`. The PSS artifact API is name-keyed, so this collapses
|
|
117
|
+
* "create" and "replace" into a single safe call.
|
|
118
|
+
*/
|
|
119
|
+
async function upsertArtifact(client, name, artifact) {
|
|
120
|
+
try {
|
|
121
|
+
await client.get({ name });
|
|
122
|
+
await client.update({ name }, artifact);
|
|
123
|
+
}
|
|
124
|
+
catch (_a) {
|
|
125
|
+
await client.create({ name }, artifact);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Delete by name, swallowing not-found errors so deactivate is idempotent.
|
|
130
|
+
* The PSS client throws `Error("HTTP error! Status: 404. …")`; match on that.
|
|
131
|
+
*/
|
|
132
|
+
async function deleteArtifactIfExists(client, name) {
|
|
133
|
+
try {
|
|
134
|
+
await client.delete({ name });
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
if (err instanceof Error && /Status:\s*404\b/.test(err.message))
|
|
138
|
+
return;
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=artifact-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-builder.js","sourceRoot":"","sources":["../../src/services/artifact-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-id-sync.strategy.d.ts","sourceRoot":"","sources":["../../src/services/external-id-sync.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAanF,qBAAa,sBAAuB,YAAW,gBAAgB;IACvD,YAAY,CAChB,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAClC,WAAW,EAAE,UAAU,GAAG,IAAI,GAC7B,OAAO,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"external-id-sync.strategy.d.ts","sourceRoot":"","sources":["../../src/services/external-id-sync.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAanF,qBAAa,sBAAuB,YAAW,gBAAgB;IACvD,YAAY,CAChB,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAClC,WAAW,EAAE,UAAU,GAAG,IAAI,GAC7B,OAAO,CAAC,WAAW,CAAC;IA0GjB,iBAAiB,CACrB,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC;IAiBhB,iBAAiB,CACrB,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,UAAU,CAAC;CAoDvB"}
|
|
@@ -13,6 +13,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
14
|
exports.ExternalIdSyncStrategy = void 0;
|
|
15
15
|
const field_mapping_service_1 = require("./field-mapping.service");
|
|
16
|
+
const sync_pipeline_errors_1 = require("./sync-pipeline-errors");
|
|
16
17
|
const helpers_1 = require("../utils/helpers");
|
|
17
18
|
// ExternalIdSyncStrategy encapsulates the original SyncService batch and event logic.
|
|
18
19
|
//
|
|
@@ -25,7 +26,7 @@ class ExternalIdSyncStrategy {
|
|
|
25
26
|
const _q = await (0, field_mapping_service_1.filterAndMapBatch)(flow, records, localFilter, (_b = (_a = source === null || source === void 0 ? void 0 : source.getRecordIdField) === null || _a === void 0 ? void 0 : _a.call(source)) !== null && _b !== void 0 ? _b : 'id'), { pairs, sourceIds: _sourceIds, errors: mapErrors } = _q, filterStats = __rest(_q, ["pairs", "sourceIds", "errors"]);
|
|
26
27
|
// Surface mapping failures to the run log instead of dropping them as "filtered".
|
|
27
28
|
for (const e of mapErrors) {
|
|
28
|
-
captureRecordError(ctx, 'map', e.index, e.message, e.record);
|
|
29
|
+
(0, sync_pipeline_errors_1.captureRecordError)(ctx, 'map', e.index, e.message, e.record);
|
|
29
30
|
ctx.logger.error(`dlq_write: dataFlowId=${flow.id} error=${(0, helpers_1.truncate)(e.message)}`);
|
|
30
31
|
}
|
|
31
32
|
const stats = Object.assign(Object.assign({}, filterStats), { skipped: 0 });
|
|
@@ -48,7 +49,8 @@ class ExternalIdSyncStrategy {
|
|
|
48
49
|
}
|
|
49
50
|
catch (err) {
|
|
50
51
|
const message = err instanceof Error ? err.message : String(err);
|
|
51
|
-
|
|
52
|
+
// Per-record so each failed record is recordable (SyncRunner can advance rather than hold).
|
|
53
|
+
(0, sync_pipeline_errors_1.capturePerRecord)(ctx, 'resolve', message, pairs.map((p) => ({ raw: p.raw })));
|
|
52
54
|
stats.failed += stats.succeeded;
|
|
53
55
|
stats.succeeded = 0;
|
|
54
56
|
return stats;
|
|
@@ -59,6 +61,9 @@ class ExternalIdSyncStrategy {
|
|
|
59
61
|
// Step 5: write to target.
|
|
60
62
|
await ((_j = source === null || source === void 0 ? void 0 : source.beforeUpsert) === null || _j === void 0 ? void 0 : _j.call(source, ctx));
|
|
61
63
|
await ((_k = target.beforeUpsert) === null || _k === void 0 ? void 0 : _k.call(target, ctx));
|
|
64
|
+
// True once each write outcome has been captured + counted; a later afterUpsert throw must
|
|
65
|
+
// not re-capture (duplicate rows) or re-count records that already landed.
|
|
66
|
+
let outcomesCounted = false;
|
|
62
67
|
try {
|
|
63
68
|
const outcomes = await target.upsert(ctx, flow, pairs.map((p) => p.mapped));
|
|
64
69
|
if (ctx.pipeline)
|
|
@@ -66,7 +71,9 @@ class ExternalIdSyncStrategy {
|
|
|
66
71
|
for (let i = 0; i < outcomes.length; i++) {
|
|
67
72
|
if (outcomes[i].status !== 'ok') {
|
|
68
73
|
const message = (_l = outcomes[i].error) !== null && _l !== void 0 ? _l : outcomes[i].status;
|
|
69
|
-
|
|
74
|
+
// Use the adapter's own classification, not a re-derivation from the message text.
|
|
75
|
+
const errorClass = outcomes[i].status === 'transient' ? 'transient' : 'permanent';
|
|
76
|
+
(0, sync_pipeline_errors_1.captureRecordError)(ctx, 'upsert', i, message, (_m = pairs[i]) === null || _m === void 0 ? void 0 : _m.raw, undefined, errorClass);
|
|
70
77
|
// Identifiers + clamped message only — the raw record is captured into the
|
|
71
78
|
// pipeline error (persisted log), so dumping it here is redundant + leaks PII.
|
|
72
79
|
ctx.logger.error(`upsert_failed: dataFlowId=${flow.id} recordIndex=${i} status=${outcomes[i].status} error=${(0, helpers_1.truncate)(String(message))}`);
|
|
@@ -74,14 +81,21 @@ class ExternalIdSyncStrategy {
|
|
|
74
81
|
stats.failed++;
|
|
75
82
|
}
|
|
76
83
|
}
|
|
84
|
+
outcomesCounted = true;
|
|
77
85
|
await ((_o = source === null || source === void 0 ? void 0 : source.afterUpsert) === null || _o === void 0 ? void 0 : _o.call(source, ctx));
|
|
78
86
|
await ((_p = target.afterUpsert) === null || _p === void 0 ? void 0 : _p.call(target, ctx));
|
|
79
87
|
}
|
|
80
88
|
catch (err) {
|
|
81
89
|
const message = err instanceof Error ? err.message : String(err);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
if (outcomesCounted) {
|
|
91
|
+
// Write done + counted; only a post-write hook threw. Log — don't re-record landed rows.
|
|
92
|
+
ctx.logger.error(`afterUpsert_failed: dataFlowId=${flow.id} error=${(0, helpers_1.truncate)(message)}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
(0, sync_pipeline_errors_1.capturePerRecord)(ctx, 'upsert', message, pairs.map((p) => ({ raw: p.raw })));
|
|
96
|
+
stats.failed += stats.succeeded;
|
|
97
|
+
stats.succeeded = 0;
|
|
98
|
+
}
|
|
85
99
|
}
|
|
86
100
|
return stats;
|
|
87
101
|
}
|
|
@@ -95,7 +109,7 @@ class ExternalIdSyncStrategy {
|
|
|
95
109
|
}
|
|
96
110
|
catch (err) {
|
|
97
111
|
const message = err instanceof Error ? err.message : String(err);
|
|
98
|
-
captureProcessError(ctx, 'delete', message, 1);
|
|
112
|
+
(0, sync_pipeline_errors_1.captureProcessError)(ctx, 'delete', message, 1);
|
|
99
113
|
ctx.logger.error(`delete_failed: dataFlowId=${flow.id} recordId=${recordId} error=${message}`);
|
|
100
114
|
return { status: 'failed', recordsProcessed: 0, error: message };
|
|
101
115
|
}
|
|
@@ -120,7 +134,7 @@ class ExternalIdSyncStrategy {
|
|
|
120
134
|
}
|
|
121
135
|
if (detail.status !== 'success') {
|
|
122
136
|
const message = (0, field_mapping_service_1.mappingErrorMessage)(detail);
|
|
123
|
-
captureRecordError(ctx, 'map', 0, message, raw);
|
|
137
|
+
(0, sync_pipeline_errors_1.captureRecordError)(ctx, 'map', 0, message, raw);
|
|
124
138
|
ctx.logger.error(`map_failed: dataFlowId=${flow.id} recordId=${event.recordId} error=${(0, helpers_1.truncate)(message)}`);
|
|
125
139
|
return { status: 'failed', recordsProcessed: 0, error: message };
|
|
126
140
|
}
|
|
@@ -139,26 +153,11 @@ class ExternalIdSyncStrategy {
|
|
|
139
153
|
return { status: 'synced', recordsProcessed: 1 };
|
|
140
154
|
}
|
|
141
155
|
const message = (_g = outcome.error) !== null && _g !== void 0 ? _g : outcome.status;
|
|
142
|
-
captureRecordError(ctx, 'upsert', 0, message, raw);
|
|
156
|
+
(0, sync_pipeline_errors_1.captureRecordError)(ctx, 'upsert', 0, message, raw);
|
|
143
157
|
// No raw record here — it's persisted via captureRecordError; console keeps identifiers only.
|
|
144
158
|
ctx.logger.error(`push_failed: dataFlowId=${flow.id} recordId=${event.recordId} status=${outcome.status} error=${(0, helpers_1.truncate)(String(message))}`);
|
|
145
159
|
return { status: 'failed', recordsProcessed: 0, error: message };
|
|
146
160
|
}
|
|
147
161
|
}
|
|
148
162
|
exports.ExternalIdSyncStrategy = ExternalIdSyncStrategy;
|
|
149
|
-
// Captures a record-level pipeline error and logs it. recordIndex is the position in
|
|
150
|
-
// ctx.pipeline.data. data is the raw source record at the point of failure.
|
|
151
|
-
function captureRecordError(ctx, stage, recordIndex, message, data) {
|
|
152
|
-
var _a;
|
|
153
|
-
(_a = ctx.pipeline) === null || _a === void 0 ? void 0 : _a.errors.push({ stage, message, recordIndex, data });
|
|
154
|
-
}
|
|
155
|
-
// Captures a process-level (whole-batch) pipeline error and logs it.
|
|
156
|
-
// affectedCount is how many records were lost due to the failure.
|
|
157
|
-
function captureProcessError(ctx, stage, message, affectedCount) {
|
|
158
|
-
var _a;
|
|
159
|
-
if (ctx.pipeline)
|
|
160
|
-
ctx.pipeline.failedAtStage = stage;
|
|
161
|
-
(_a = ctx.pipeline) === null || _a === void 0 ? void 0 : _a.errors.push({ stage, message });
|
|
162
|
-
ctx.logger.error(`process_failed: stage=${stage} message=${message} affectedRecords=${affectedCount}`);
|
|
163
|
-
}
|
|
164
163
|
//# sourceMappingURL=external-id-sync.strategy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-id-sync.strategy.js","sourceRoot":"","sources":["../../src/services/external-id-sync.strategy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"external-id-sync.strategy.js","sourceRoot":"","sources":["../../src/services/external-id-sync.strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id-mapping-sync.strategy.d.ts","sourceRoot":"","sources":["../../src/services/id-mapping-sync.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAiC,MAAM,iCAAiC,CAAC;AAC9F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;
|
|
1
|
+
{"version":3,"file":"id-mapping-sync.strategy.d.ts","sourceRoot":"","sources":["../../src/services/id-mapping-sync.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAiC,MAAM,iCAAiC,CAAC;AAC9F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAEnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAqDxD,qBAAa,qBAAsB,YAAW,gBAAgB;IAChD,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,gBAAgB;IAEzD,YAAY,CAChB,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAClC,WAAW,EAAE,UAAU,GAAG,IAAI,GAC7B,OAAO,CAAC,WAAW,CAAC;YAuMT,qBAAqB;YAyBrB,oBAAoB;IAsB5B,iBAAiB,CACrB,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC;IAqDhB,iBAAiB,CACrB,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,UAAU,CAAC;IA6ItB,OAAO,CAAC,mBAAmB;YAsCb,0BAA0B;YAmG1B,wBAAwB;YAkExB,oBAAoB;CAmDnC"}
|
|
@@ -13,6 +13,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
14
|
exports.IdMappingSyncStrategy = void 0;
|
|
15
15
|
const field_mapping_service_1 = require("./field-mapping.service");
|
|
16
|
+
const sync_pipeline_errors_1 = require("./sync-pipeline-errors");
|
|
16
17
|
const helpers_1 = require("../utils/helpers");
|
|
17
18
|
// IdMappingSyncStrategy resolves cross-system identity via the IntegrationIdMapping
|
|
18
19
|
// custom object rather than ExternalId custom fields.
|
|
@@ -63,7 +64,7 @@ class IdMappingSyncStrategy {
|
|
|
63
64
|
const _q = await (0, field_mapping_service_1.filterAndMapBatch)(flow, records, localFilter, sourceIdField), { pairs, sourceIds: activeSourceIds, errors: mapErrors } = _q, filterStats = __rest(_q, ["pairs", "sourceIds", "errors"]);
|
|
64
65
|
// Surface mapping failures to the run log instead of dropping them as "filtered".
|
|
65
66
|
for (const e of mapErrors) {
|
|
66
|
-
captureRecordError(ctx, 'map', e.index, e.message, e.record);
|
|
67
|
+
(0, sync_pipeline_errors_1.captureRecordError)(ctx, 'map', e.index, e.message, e.record);
|
|
67
68
|
ctx.logger.error(`dlq_write: dataFlowId=${flow.id} error=${(0, helpers_1.truncate)(e.message)}`);
|
|
68
69
|
}
|
|
69
70
|
const stats = Object.assign(Object.assign({}, filterStats), { skipped: 0 });
|
|
@@ -117,6 +118,10 @@ class IdMappingSyncStrategy {
|
|
|
117
118
|
await ((_j = source === null || source === void 0 ? void 0 : source.beforeUpsert) === null || _j === void 0 ? void 0 : _j.call(source, ctx));
|
|
118
119
|
await ((_k = target.beforeUpsert) === null || _k === void 0 ? void 0 : _k.call(target, ctx));
|
|
119
120
|
let outcomes = new Array(dispatchPairs.length);
|
|
121
|
+
// True once the per-outcome loop has captured + counted each write result. If a later
|
|
122
|
+
// afterUpsert hook throws, the catch must NOT re-capture/re-count those outcomes (that
|
|
123
|
+
// would write duplicate (flow, sourceId) rows the store rejects, and corrupt the counts).
|
|
124
|
+
let outcomesCounted = false;
|
|
120
125
|
try {
|
|
121
126
|
if (typeof target.insert === 'function' || typeof target.update === 'function') {
|
|
122
127
|
const { inserts, updates } = splitForDispatch(dispatchPairs);
|
|
@@ -147,7 +152,11 @@ class IdMappingSyncStrategy {
|
|
|
147
152
|
for (let i = 0; i < outcomes.length; i++) {
|
|
148
153
|
if (outcomes[i].status !== 'ok') {
|
|
149
154
|
const message = (_l = outcomes[i].error) !== null && _l !== void 0 ? _l : outcomes[i].status;
|
|
150
|
-
|
|
155
|
+
// Use the adapter's own classification (HTTP status → transient/permanent) rather than
|
|
156
|
+
// re-deriving from message text; precondition is a permanent config gap.
|
|
157
|
+
const errorClass = outcomes[i].status === 'transient' ? 'transient' : 'permanent';
|
|
158
|
+
// Pass the source id explicitly so the row is recordable even if raw lacks the id field.
|
|
159
|
+
(0, sync_pipeline_errors_1.captureRecordError)(ctx, 'upsert', i, message, (_m = dispatchPairs[i]) === null || _m === void 0 ? void 0 : _m.raw, dispatchSrcIds[i], errorClass);
|
|
151
160
|
// Identifiers + clamped message only — the raw record is captured into the
|
|
152
161
|
// pipeline error (persisted log), so dumping it here is redundant + leaks PII.
|
|
153
162
|
ctx.logger.error(`upsert_failed: dataFlowId=${flow.id} recordIndex=${i} status=${outcomes[i].status} error=${(0, helpers_1.truncate)(String(message))}`);
|
|
@@ -155,14 +164,24 @@ class IdMappingSyncStrategy {
|
|
|
155
164
|
stats.failed++;
|
|
156
165
|
}
|
|
157
166
|
}
|
|
167
|
+
outcomesCounted = true;
|
|
158
168
|
await ((_o = source === null || source === void 0 ? void 0 : source.afterUpsert) === null || _o === void 0 ? void 0 : _o.call(source, ctx));
|
|
159
169
|
await ((_p = target.afterUpsert) === null || _p === void 0 ? void 0 : _p.call(target, ctx));
|
|
160
170
|
}
|
|
161
171
|
catch (err) {
|
|
162
172
|
const message = err instanceof Error ? err.message : String(err);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
173
|
+
if (outcomesCounted) {
|
|
174
|
+
// The write completed and every outcome was already captured + counted above; only a
|
|
175
|
+
// post-write hook (afterUpsert) threw. Log it — re-capturing would duplicate rows and
|
|
176
|
+
// re-counting would corrupt the totals. The mapping finalize below still runs.
|
|
177
|
+
ctx.logger.error(`afterUpsert_failed: dataFlowId=${flow.id} error=${(0, helpers_1.truncate)(message)}`);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// The write itself threw — no outcomes. Record each dispatched record so it's recoverable.
|
|
181
|
+
(0, sync_pipeline_errors_1.capturePerRecord)(ctx, 'upsert', message, dispatchPairs.map((p, i) => ({ sourceId: dispatchSrcIds[i], raw: p.raw })));
|
|
182
|
+
stats.failed += dispatchPairs.length;
|
|
183
|
+
stats.succeeded -= dispatchPairs.length;
|
|
184
|
+
}
|
|
166
185
|
// Outcomes can be partial — one dispatch bucket may have landed before the other threw.
|
|
167
186
|
// Finalize any create that actually succeeded (so it isn't re-created as a duplicate next
|
|
168
187
|
// run) and release reservations only for creates with no successful outcome.
|
|
@@ -249,7 +268,7 @@ class IdMappingSyncStrategy {
|
|
|
249
268
|
}
|
|
250
269
|
catch (err) {
|
|
251
270
|
const msg = err instanceof Error ? err.message : String(err);
|
|
252
|
-
captureProcessError(ctx, 'delete', msg, 1);
|
|
271
|
+
(0, sync_pipeline_errors_1.captureProcessError)(ctx, 'delete', msg, 1);
|
|
253
272
|
ctx.logger.error(`id_mapping_delete_failed: sourceId=${recordId} targetId=${targetId} error=${msg} — mapping entry kept`);
|
|
254
273
|
return { status: 'failed', recordsProcessed: 0, error: msg };
|
|
255
274
|
}
|
|
@@ -280,7 +299,7 @@ class IdMappingSyncStrategy {
|
|
|
280
299
|
}
|
|
281
300
|
if (detail.status !== 'success') {
|
|
282
301
|
const message = (0, field_mapping_service_1.mappingErrorMessage)(detail);
|
|
283
|
-
captureRecordError(ctx, 'map', 0, message, raw);
|
|
302
|
+
(0, sync_pipeline_errors_1.captureRecordError)(ctx, 'map', 0, message, raw);
|
|
284
303
|
ctx.logger.error(`map_failed: dataFlowId=${flow.id} recordId=${event.recordId} error=${(0, helpers_1.truncate)(message)}`);
|
|
285
304
|
return { status: 'failed', recordsProcessed: 0, error: message };
|
|
286
305
|
}
|
|
@@ -432,7 +451,7 @@ class IdMappingSyncStrategy {
|
|
|
432
451
|
}
|
|
433
452
|
catch (err) {
|
|
434
453
|
const message = err instanceof Error ? err.message : String(err);
|
|
435
|
-
|
|
454
|
+
(0, sync_pipeline_errors_1.capturePerRecord)(ctx, 'resolve', message, pairs.map((p, i) => ({ sourceId: activeSourceIds[i], raw: p.raw })));
|
|
436
455
|
stats.failed += stats.succeeded;
|
|
437
456
|
stats.succeeded = 0;
|
|
438
457
|
return null;
|
|
@@ -467,6 +486,10 @@ class IdMappingSyncStrategy {
|
|
|
467
486
|
stats.filtered += rule.onMissing === 'skip' ? 1 : 0;
|
|
468
487
|
stats.failed += rule.onMissing === 'error' ? 1 : 0;
|
|
469
488
|
stats.succeeded--;
|
|
489
|
+
// An 'error' miss is a failure — record it; a 'skip' miss is intentional, so don't.
|
|
490
|
+
if (rule.onMissing === 'error') {
|
|
491
|
+
(0, sync_pipeline_errors_1.captureRecordError)(ctx, 'resolve', i, `lookup_miss: ${mapping.target} object=${rule.object} value=${rawValue}`, pairs[i].raw, activeSourceIds[i]);
|
|
492
|
+
}
|
|
470
493
|
}
|
|
471
494
|
else {
|
|
472
495
|
// 'warn': remove the unresolved field and continue
|
|
@@ -503,7 +526,7 @@ class IdMappingSyncStrategy {
|
|
|
503
526
|
}
|
|
504
527
|
catch (err) {
|
|
505
528
|
const message = err instanceof Error ? err.message : String(err);
|
|
506
|
-
captureProcessError(ctx, 'resolve', message, 1);
|
|
529
|
+
(0, sync_pipeline_errors_1.captureProcessError)(ctx, 'resolve', message, 1);
|
|
507
530
|
return { status: 'failed', recordsProcessed: 0, error: message };
|
|
508
531
|
}
|
|
509
532
|
mapped['__targetUID'] = (_e = primaryTable.get(`${flow.targetObject}:${sourceId}`)) !== null && _e !== void 0 ? _e : null;
|
|
@@ -567,23 +590,14 @@ class IdMappingSyncStrategy {
|
|
|
567
590
|
return;
|
|
568
591
|
await retryOnce(() => this.idMappingService.upsertMappings(ctx, entries)).catch((err) => {
|
|
569
592
|
const message = err instanceof Error ? err.message : String(err);
|
|
570
|
-
|
|
593
|
+
// These records DID land in the target but their id pair wasn't saved, so the next run
|
|
594
|
+
// would re-create duplicates. Record per source id so they surface for reconciliation.
|
|
595
|
+
(0, sync_pipeline_errors_1.capturePerRecord)(ctx, 'mapping_write', message, createSourceIds.map((sourceId) => ({ sourceId })));
|
|
571
596
|
ctx.logger.error(`mapping_write_failed: dataFlowId=${flow.id} error=${(0, helpers_1.truncate)(message)} entries=${entries.length}`);
|
|
572
597
|
});
|
|
573
598
|
}
|
|
574
599
|
}
|
|
575
600
|
exports.IdMappingSyncStrategy = IdMappingSyncStrategy;
|
|
576
|
-
function captureRecordError(ctx, stage, recordIndex, message, data) {
|
|
577
|
-
var _a;
|
|
578
|
-
(_a = ctx.pipeline) === null || _a === void 0 ? void 0 : _a.errors.push({ stage, message, recordIndex, data });
|
|
579
|
-
}
|
|
580
|
-
function captureProcessError(ctx, stage, message, affectedCount) {
|
|
581
|
-
var _a;
|
|
582
|
-
if (ctx.pipeline)
|
|
583
|
-
ctx.pipeline.failedAtStage = stage;
|
|
584
|
-
(_a = ctx.pipeline) === null || _a === void 0 ? void 0 : _a.errors.push({ stage, message });
|
|
585
|
-
ctx.logger.error(`process_failed: stage=${stage} message=${message} affectedRecords=${affectedCount}`);
|
|
586
|
-
}
|
|
587
601
|
async function retryOnce(fn) {
|
|
588
602
|
try {
|
|
589
603
|
return await fn();
|