@memberjunction/integration-engine 6.1.0-edge.1 → 6.1.0-edge.3
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/LICENSE +180 -4
- package/dist/BaseIntegrationConnector.d.ts +97 -3
- package/dist/BaseIntegrationConnector.d.ts.map +1 -1
- package/dist/BaseIntegrationConnector.js +82 -6
- package/dist/BaseIntegrationConnector.js.map +1 -1
- package/dist/BaseRESTIntegrationConnector.d.ts +1 -1
- package/dist/BaseRESTIntegrationConnector.d.ts.map +1 -1
- package/dist/BaseRESTIntegrationConnector.js +12 -2
- package/dist/BaseRESTIntegrationConnector.js.map +1 -1
- package/dist/IntegrationConnectorCreationPipeline.d.ts +92 -1
- package/dist/IntegrationConnectorCreationPipeline.d.ts.map +1 -1
- package/dist/IntegrationConnectorCreationPipeline.js +173 -11
- package/dist/IntegrationConnectorCreationPipeline.js.map +1 -1
- package/dist/IntegrationEngine.d.ts +161 -21
- package/dist/IntegrationEngine.d.ts.map +1 -1
- package/dist/IntegrationEngine.js +705 -82
- package/dist/IntegrationEngine.js.map +1 -1
- package/dist/RunOwnershipService.d.ts +177 -0
- package/dist/RunOwnershipService.d.ts.map +1 -0
- package/dist/RunOwnershipService.js +279 -0
- package/dist/RunOwnershipService.js.map +1 -0
- package/dist/auth-helpers/OAuth2TokenManager.d.ts.map +1 -1
- package/dist/auth-helpers/OAuth2TokenManager.js +8 -2
- package/dist/auth-helpers/OAuth2TokenManager.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type { DatabaseProviderBase, UserInfo } from '@memberjunction/core';
|
|
2
|
+
import type { MJCompanyIntegrationRunEntity } from '@memberjunction/core-entities';
|
|
3
|
+
/**
|
|
4
|
+
* Thrown at a batch boundary when this process discovers it no longer owns the
|
|
5
|
+
* run row (lease reclaimed by a stale-sweep or another worker bumped the fence).
|
|
6
|
+
* The sync loop MUST let this propagate — per-record error handling must never
|
|
7
|
+
* swallow it, because continuing to write after ownership loss is exactly the
|
|
8
|
+
* split-brain hazard the fence exists to prevent.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The states a run can be released INTO — the terminal subset of the entity's Status value list.
|
|
12
|
+
* Derived with `Extract` rather than hand-written so it stays pinned to the CHECK-constraint union
|
|
13
|
+
* CodeGen generates: if one of these values were ever removed from the column, this type narrows and
|
|
14
|
+
* every call site fails to compile, instead of silently passing a status the constraint rejects at
|
|
15
|
+
* runtime. 'In Progress' / 'Pending' / 'Queued' are deliberately excluded — they are not terminal.
|
|
16
|
+
*/
|
|
17
|
+
export type TerminalRunStatus = Extract<MJCompanyIntegrationRunEntity['Status'], 'Success' | 'Failed' | 'Cancelled'>;
|
|
18
|
+
export declare class RunOwnershipLostError extends Error {
|
|
19
|
+
readonly RunID: string;
|
|
20
|
+
constructor(runID: string, detail: string);
|
|
21
|
+
}
|
|
22
|
+
/** Result of a lease renewal attempt. */
|
|
23
|
+
export interface RenewResult {
|
|
24
|
+
/** True when the DB confirmed our token+fence still own the row and extended the lease. */
|
|
25
|
+
Renewed: boolean;
|
|
26
|
+
/** True when a cooperative cancel has been requested on the run row (only meaningful when Renewed). */
|
|
27
|
+
CancelRequested: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** Result of a batch-boundary ownership check. */
|
|
30
|
+
export interface BoundaryCheckResult {
|
|
31
|
+
/** True when the row's OwnerToken + FenceToken still match ours. */
|
|
32
|
+
Owned: boolean;
|
|
33
|
+
/** True when CancelRequestedAt is set on the row. */
|
|
34
|
+
CancelRequested: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Options for the background heartbeat started via {@link RunOwnershipService.StartHeartbeat}. */
|
|
37
|
+
export interface HeartbeatOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Called (once) when a renewal discovers ownership has been lost. The engine
|
|
40
|
+
* uses this to abort the in-flight sync locally; writes are additionally
|
|
41
|
+
* fenced at every batch boundary, so this is fast-fail, not the safety net.
|
|
42
|
+
*/
|
|
43
|
+
onLost?: () => void;
|
|
44
|
+
/** Called (once per request) when a renewal observes CancelRequestedAt set. */
|
|
45
|
+
onCancelRequested?: () => void;
|
|
46
|
+
/** Supplies the latest progress JSON to piggyback on each renewal write. */
|
|
47
|
+
progressSupplier?: () => string | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Per-run ownership manager for durable CompanyIntegrationRun execution
|
|
51
|
+
* (GH tasks.md PR 1). One instance is created per sync run and owns:
|
|
52
|
+
*
|
|
53
|
+
* - **Claim**: a single atomic UPDATE...WHERE (unowned OR lease expired) via
|
|
54
|
+
* spClaimCompanyIntegrationRun — never select-then-update. Claiming bumps
|
|
55
|
+
* FenceToken, invalidating any prior holder's writes.
|
|
56
|
+
* - **Renew**: timer-driven lease extension (interval ≈ lease/3) via
|
|
57
|
+
* spRenewCompanyIntegrationRunLease, token+fence-checked. The renewal result
|
|
58
|
+
* doubles as the cross-process cancel signal (returns CancelRequestedAt).
|
|
59
|
+
* - **Boundary fence**: {@link CheckBoundary} — a cheap SELECT the sync loop
|
|
60
|
+
* calls before every batch's writes. Ownership lost ⇒ the loop throws
|
|
61
|
+
* {@link RunOwnershipLostError} and writes nothing further.
|
|
62
|
+
* - **Release**: terminal status write + owner clear, token-checked so a stale
|
|
63
|
+
* holder's release no-ops.
|
|
64
|
+
*
|
|
65
|
+
* All sproc calls use the dialect-portable positional-parameter convention
|
|
66
|
+
* (same pattern as ScheduledJobEngine's lock sprocs): SQL Server binds the
|
|
67
|
+
* sproc's named params to positional `@pN` placeholders via EXEC; PostgreSQL
|
|
68
|
+
* calls the plpgsql port via `SELECT * FROM fn($1,...)`. The SAME value array
|
|
69
|
+
* serves both.
|
|
70
|
+
*/
|
|
71
|
+
export declare class RunOwnershipService {
|
|
72
|
+
/** Default lease when the caller supplies no MaxRuntimeMinutes. */
|
|
73
|
+
static readonly DEFAULT_LEASE_MINUTES = 10;
|
|
74
|
+
private readonly provider;
|
|
75
|
+
private readonly contextUser;
|
|
76
|
+
private readonly runID;
|
|
77
|
+
private readonly ownerToken;
|
|
78
|
+
private readonly leaseMinutes;
|
|
79
|
+
private fenceToken;
|
|
80
|
+
private lastKnownLeaseExpiresAt;
|
|
81
|
+
private heartbeatTimer;
|
|
82
|
+
private lostNotified;
|
|
83
|
+
private cancelNotified;
|
|
84
|
+
private renewInFlight;
|
|
85
|
+
/**
|
|
86
|
+
* @param provider the run's OWN provider connection (per-run, never a shared
|
|
87
|
+
* engine-level provider — see the per-run-connection requirement).
|
|
88
|
+
* @param runID CompanyIntegrationRun.ID this service governs.
|
|
89
|
+
* @param leaseMinutes lease length; callers pass
|
|
90
|
+
* max(DEFAULT_LEASE_MINUTES, options.MaxRuntimeMinutes ?? 0) so a
|
|
91
|
+
* long-batch override only ever EXTENDS protection.
|
|
92
|
+
*/
|
|
93
|
+
constructor(provider: DatabaseProviderBase, runID: string, leaseMinutes?: number, contextUser?: UserInfo);
|
|
94
|
+
/** The CompanyIntegrationRun ID this service governs. */
|
|
95
|
+
get RunID(): string;
|
|
96
|
+
/** The opaque owner token minted for this execution. */
|
|
97
|
+
get OwnerToken(): string;
|
|
98
|
+
/** The fence token returned by the successful claim (null before claim). */
|
|
99
|
+
get FenceToken(): number | null;
|
|
100
|
+
/** Last lease expiry the DB confirmed for us (null before claim). */
|
|
101
|
+
get LeaseExpiresAt(): Date | null;
|
|
102
|
+
/** Lease length in minutes this service renews with. */
|
|
103
|
+
get LeaseMinutes(): number;
|
|
104
|
+
/**
|
|
105
|
+
* Atomically claim the run row. Returns true iff WE now own it (the sproc's
|
|
106
|
+
* single UPDATE succeeded because the row was unowned or its lease had
|
|
107
|
+
* expired). On success the DB-assigned FenceToken (bumped by the claim) and
|
|
108
|
+
* lease expiry are cached for renewals and boundary checks.
|
|
109
|
+
*/
|
|
110
|
+
Claim(): Promise<boolean>;
|
|
111
|
+
/**
|
|
112
|
+
* Renew the lease (token+fence-checked). Zero rows back ⇒ ownership lost.
|
|
113
|
+
* Optionally piggybacks a progress snapshot onto the same write, and always
|
|
114
|
+
* surfaces the row's CancelRequestedAt so the heartbeat doubles as the
|
|
115
|
+
* cross-process cancel poll.
|
|
116
|
+
*/
|
|
117
|
+
Renew(progressJSON?: string | null): Promise<RenewResult>;
|
|
118
|
+
/**
|
|
119
|
+
* Batch-boundary fence: a cheap SELECT of the ownership columns. The sync
|
|
120
|
+
* loop calls this BEFORE each batch's writes; if we no longer own the row,
|
|
121
|
+
* the caller must throw {@link RunOwnershipLostError} and stop writing.
|
|
122
|
+
* Deliberately a plain read (no lease extension) — renewal belongs to the
|
|
123
|
+
* heartbeat timer, and a boundary check must stay cheap enough to run
|
|
124
|
+
* every batch.
|
|
125
|
+
*/
|
|
126
|
+
CheckBoundary(): Promise<BoundaryCheckResult>;
|
|
127
|
+
/**
|
|
128
|
+
* Terminal release: set the final status, clear OwnerToken/LeaseExpiresAt,
|
|
129
|
+
* stamp EndedAt if unset. Token- AND fence-checked — a stale holder (lease
|
|
130
|
+
* reclaimed) releasing late is a harmless no-op (returns false).
|
|
131
|
+
*
|
|
132
|
+
* The fence is sent for the same reason Renew() sends it: the owner token proves
|
|
133
|
+
* only that *some* context using this token owns the row, not that THIS context
|
|
134
|
+
* still does. Each instance mints its own token and claims once, so the two are
|
|
135
|
+
* equivalent today — but Claim() is re-callable and overwrites the fence, so
|
|
136
|
+
* passing it keeps the guarantee in the procedure rather than in call-site
|
|
137
|
+
* discipline.
|
|
138
|
+
*/
|
|
139
|
+
Release(finalStatus: TerminalRunStatus): Promise<boolean>;
|
|
140
|
+
/**
|
|
141
|
+
* Start the background renewal timer at interval ≈ lease/3 (so a renewal
|
|
142
|
+
* must fail ~3 consecutive times before the lease can lapse). The timer
|
|
143
|
+
* body is best-effort and never throws; renewal failures surface through
|
|
144
|
+
* opts.onLost exactly once. Idempotent — restarting replaces the timer.
|
|
145
|
+
*/
|
|
146
|
+
StartHeartbeat(opts?: HeartbeatOptions): void;
|
|
147
|
+
/** Stop the renewal timer (idempotent). */
|
|
148
|
+
StopHeartbeat(): void;
|
|
149
|
+
/**
|
|
150
|
+
* Sync the entity's in-memory ownership columns to the service's last-known
|
|
151
|
+
* authoritative values before ANY full-row `run.Save()`. The generated
|
|
152
|
+
* spUpdate writes every column from the entity's in-memory state, so a
|
|
153
|
+
* terminal Save without this sync would clobber the DB's live
|
|
154
|
+
* FenceToken/OwnerToken/LeaseExpiresAt with the stale values the entity was
|
|
155
|
+
* loaded with (typically pre-claim). Call this immediately before each
|
|
156
|
+
* Save on the run row; Release() then clears ownership atomically.
|
|
157
|
+
*/
|
|
158
|
+
SyncEntityOwnershipFields(run: MJCompanyIntegrationRunEntity): void;
|
|
159
|
+
private lastProgressWriteMs;
|
|
160
|
+
/**
|
|
161
|
+
* Persist a progress snapshot to the run row's ProgressJSON (PR 1 item 4 —
|
|
162
|
+
* progress lives in the database; readers query the row). Ownership-guarded
|
|
163
|
+
* (WHERE OwnerToken AND FenceToken) so a reclaimed run can never overwrite the
|
|
164
|
+
* new owner's progress. Throttled internally (default once per 5s) so progress
|
|
165
|
+
* never becomes its own hot path; best-effort — a progress write failure must
|
|
166
|
+
* never fault the sync.
|
|
167
|
+
*/
|
|
168
|
+
WriteProgress(progressJSON: string, minIntervalMs?: number): Promise<void>;
|
|
169
|
+
/** One heartbeat tick: renew, then fan out lost/cancel notifications once each. */
|
|
170
|
+
private heartbeatOnce;
|
|
171
|
+
/**
|
|
172
|
+
* Dialect-portable sproc call, preserving the MJ positional-parameter-array
|
|
173
|
+
* convention (same helper shape as ScheduledJobEngine.buildLockSprocCall).
|
|
174
|
+
*/
|
|
175
|
+
private buildSprocCall;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=RunOwnershipService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunOwnershipService.d.ts","sourceRoot":"","sources":["../src/RunOwnershipService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { LogErrorEx, LogStatusEx } from '@memberjunction/core';
|
|
3
|
+
export class RunOwnershipLostError extends Error {
|
|
4
|
+
constructor(runID, detail) {
|
|
5
|
+
super(`Ownership of CompanyIntegrationRun ${runID} lost: ${detail}`);
|
|
6
|
+
this.name = 'RunOwnershipLostError';
|
|
7
|
+
this.RunID = runID;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Per-run ownership manager for durable CompanyIntegrationRun execution
|
|
12
|
+
* (GH tasks.md PR 1). One instance is created per sync run and owns:
|
|
13
|
+
*
|
|
14
|
+
* - **Claim**: a single atomic UPDATE...WHERE (unowned OR lease expired) via
|
|
15
|
+
* spClaimCompanyIntegrationRun — never select-then-update. Claiming bumps
|
|
16
|
+
* FenceToken, invalidating any prior holder's writes.
|
|
17
|
+
* - **Renew**: timer-driven lease extension (interval ≈ lease/3) via
|
|
18
|
+
* spRenewCompanyIntegrationRunLease, token+fence-checked. The renewal result
|
|
19
|
+
* doubles as the cross-process cancel signal (returns CancelRequestedAt).
|
|
20
|
+
* - **Boundary fence**: {@link CheckBoundary} — a cheap SELECT the sync loop
|
|
21
|
+
* calls before every batch's writes. Ownership lost ⇒ the loop throws
|
|
22
|
+
* {@link RunOwnershipLostError} and writes nothing further.
|
|
23
|
+
* - **Release**: terminal status write + owner clear, token-checked so a stale
|
|
24
|
+
* holder's release no-ops.
|
|
25
|
+
*
|
|
26
|
+
* All sproc calls use the dialect-portable positional-parameter convention
|
|
27
|
+
* (same pattern as ScheduledJobEngine's lock sprocs): SQL Server binds the
|
|
28
|
+
* sproc's named params to positional `@pN` placeholders via EXEC; PostgreSQL
|
|
29
|
+
* calls the plpgsql port via `SELECT * FROM fn($1,...)`. The SAME value array
|
|
30
|
+
* serves both.
|
|
31
|
+
*/
|
|
32
|
+
export class RunOwnershipService {
|
|
33
|
+
/** Default lease when the caller supplies no MaxRuntimeMinutes. */
|
|
34
|
+
static { this.DEFAULT_LEASE_MINUTES = 10; }
|
|
35
|
+
/**
|
|
36
|
+
* @param provider the run's OWN provider connection (per-run, never a shared
|
|
37
|
+
* engine-level provider — see the per-run-connection requirement).
|
|
38
|
+
* @param runID CompanyIntegrationRun.ID this service governs.
|
|
39
|
+
* @param leaseMinutes lease length; callers pass
|
|
40
|
+
* max(DEFAULT_LEASE_MINUTES, options.MaxRuntimeMinutes ?? 0) so a
|
|
41
|
+
* long-batch override only ever EXTENDS protection.
|
|
42
|
+
*/
|
|
43
|
+
constructor(provider, runID, leaseMinutes, contextUser) {
|
|
44
|
+
this.fenceToken = null;
|
|
45
|
+
this.lastKnownLeaseExpiresAt = null;
|
|
46
|
+
this.heartbeatTimer = null;
|
|
47
|
+
this.lostNotified = false;
|
|
48
|
+
this.cancelNotified = false;
|
|
49
|
+
this.renewInFlight = false;
|
|
50
|
+
this.lastProgressWriteMs = 0;
|
|
51
|
+
this.provider = provider;
|
|
52
|
+
this.runID = runID;
|
|
53
|
+
this.contextUser = contextUser;
|
|
54
|
+
// Cryptographic UUID — token identity IS execution identity; a collision
|
|
55
|
+
// between concurrent workers would defeat the fence.
|
|
56
|
+
this.ownerToken = randomUUID();
|
|
57
|
+
this.leaseMinutes = Math.max(RunOwnershipService.DEFAULT_LEASE_MINUTES, leaseMinutes ?? 0);
|
|
58
|
+
}
|
|
59
|
+
/** The CompanyIntegrationRun ID this service governs. */
|
|
60
|
+
get RunID() {
|
|
61
|
+
return this.runID;
|
|
62
|
+
}
|
|
63
|
+
/** The opaque owner token minted for this execution. */
|
|
64
|
+
get OwnerToken() {
|
|
65
|
+
return this.ownerToken;
|
|
66
|
+
}
|
|
67
|
+
/** The fence token returned by the successful claim (null before claim). */
|
|
68
|
+
get FenceToken() {
|
|
69
|
+
return this.fenceToken;
|
|
70
|
+
}
|
|
71
|
+
/** Last lease expiry the DB confirmed for us (null before claim). */
|
|
72
|
+
get LeaseExpiresAt() {
|
|
73
|
+
return this.lastKnownLeaseExpiresAt;
|
|
74
|
+
}
|
|
75
|
+
/** Lease length in minutes this service renews with. */
|
|
76
|
+
get LeaseMinutes() {
|
|
77
|
+
return this.leaseMinutes;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Atomically claim the run row. Returns true iff WE now own it (the sproc's
|
|
81
|
+
* single UPDATE succeeded because the row was unowned or its lease had
|
|
82
|
+
* expired). On success the DB-assigned FenceToken (bumped by the claim) and
|
|
83
|
+
* lease expiry are cached for renewals and boundary checks.
|
|
84
|
+
*/
|
|
85
|
+
async Claim() {
|
|
86
|
+
const rows = await this.provider.ExecuteSQL(this.buildSprocCall('spClaimCompanyIntegrationRun', ['RunID', 'OwnerToken', 'LeaseMinutes']), [this.runID, this.ownerToken, this.leaseMinutes], { isMutation: true, description: 'spClaimCompanyIntegrationRun' }, this.contextUser);
|
|
87
|
+
const row = rows?.[0];
|
|
88
|
+
if (!row) {
|
|
89
|
+
return false; // someone else holds a live lease
|
|
90
|
+
}
|
|
91
|
+
this.fenceToken = Number(row.FenceToken);
|
|
92
|
+
this.lastKnownLeaseExpiresAt = new Date(row.LeaseExpiresAt);
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Renew the lease (token+fence-checked). Zero rows back ⇒ ownership lost.
|
|
97
|
+
* Optionally piggybacks a progress snapshot onto the same write, and always
|
|
98
|
+
* surfaces the row's CancelRequestedAt so the heartbeat doubles as the
|
|
99
|
+
* cross-process cancel poll.
|
|
100
|
+
*/
|
|
101
|
+
async Renew(progressJSON) {
|
|
102
|
+
if (this.fenceToken == null) {
|
|
103
|
+
return { Renewed: false, CancelRequested: false };
|
|
104
|
+
}
|
|
105
|
+
const rows = await this.provider.ExecuteSQL(this.buildSprocCall('spRenewCompanyIntegrationRunLease', ['RunID', 'OwnerToken', 'FenceToken', 'LeaseMinutes', 'ProgressJSON']), [this.runID, this.ownerToken, this.fenceToken, this.leaseMinutes, progressJSON ?? null], { isMutation: true, description: 'spRenewCompanyIntegrationRunLease' }, this.contextUser);
|
|
106
|
+
const row = rows?.[0];
|
|
107
|
+
if (!row) {
|
|
108
|
+
return { Renewed: false, CancelRequested: false };
|
|
109
|
+
}
|
|
110
|
+
this.lastKnownLeaseExpiresAt = new Date(row.LeaseExpiresAt);
|
|
111
|
+
return { Renewed: true, CancelRequested: row.CancelRequestedAt != null };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Batch-boundary fence: a cheap SELECT of the ownership columns. The sync
|
|
115
|
+
* loop calls this BEFORE each batch's writes; if we no longer own the row,
|
|
116
|
+
* the caller must throw {@link RunOwnershipLostError} and stop writing.
|
|
117
|
+
* Deliberately a plain read (no lease extension) — renewal belongs to the
|
|
118
|
+
* heartbeat timer, and a boundary check must stay cheap enough to run
|
|
119
|
+
* every batch.
|
|
120
|
+
*/
|
|
121
|
+
async CheckBoundary() {
|
|
122
|
+
const d = this.provider.Dialect;
|
|
123
|
+
const schema = d.QuoteIdentifier(this.provider.MJCoreSchemaName);
|
|
124
|
+
const table = d.QuoteIdentifier('CompanyIntegrationRun');
|
|
125
|
+
const placeholder = this.provider.BuildParameterPlaceholder(0);
|
|
126
|
+
const rows = await this.provider.ExecuteSQL(`SELECT ${d.QuoteIdentifier('OwnerToken')} AS OwnerToken, ` +
|
|
127
|
+
`${d.QuoteIdentifier('FenceToken')} AS FenceToken, ` +
|
|
128
|
+
`${d.QuoteIdentifier('CancelRequestedAt')} AS CancelRequestedAt ` +
|
|
129
|
+
`FROM ${schema}.${table} WHERE ${d.QuoteIdentifier('ID')} = ${placeholder}`, [this.runID], { isMutation: false, description: 'CompanyIntegrationRun ownership boundary check' }, this.contextUser);
|
|
130
|
+
const row = rows?.[0];
|
|
131
|
+
if (!row) {
|
|
132
|
+
return { Owned: false, CancelRequested: false }; // row gone ⇒ definitely not ours
|
|
133
|
+
}
|
|
134
|
+
const owned = row.OwnerToken != null
|
|
135
|
+
&& row.OwnerToken.toLowerCase() === this.ownerToken.toLowerCase()
|
|
136
|
+
&& Number(row.FenceToken) === this.fenceToken;
|
|
137
|
+
return { Owned: owned, CancelRequested: row.CancelRequestedAt != null };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Terminal release: set the final status, clear OwnerToken/LeaseExpiresAt,
|
|
141
|
+
* stamp EndedAt if unset. Token- AND fence-checked — a stale holder (lease
|
|
142
|
+
* reclaimed) releasing late is a harmless no-op (returns false).
|
|
143
|
+
*
|
|
144
|
+
* The fence is sent for the same reason Renew() sends it: the owner token proves
|
|
145
|
+
* only that *some* context using this token owns the row, not that THIS context
|
|
146
|
+
* still does. Each instance mints its own token and claims once, so the two are
|
|
147
|
+
* equivalent today — but Claim() is re-callable and overwrites the fence, so
|
|
148
|
+
* passing it keeps the guarantee in the procedure rather than in call-site
|
|
149
|
+
* discipline.
|
|
150
|
+
*/
|
|
151
|
+
async Release(finalStatus) {
|
|
152
|
+
this.StopHeartbeat();
|
|
153
|
+
const rows = await this.provider.ExecuteSQL(this.buildSprocCall('spReleaseCompanyIntegrationRun', ['RunID', 'OwnerToken', 'FinalStatus', 'FenceToken']), [this.runID, this.ownerToken, finalStatus, this.fenceToken], { isMutation: true, description: 'spReleaseCompanyIntegrationRun' }, this.contextUser);
|
|
154
|
+
return (rows?.length ?? 0) > 0;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Start the background renewal timer at interval ≈ lease/3 (so a renewal
|
|
158
|
+
* must fail ~3 consecutive times before the lease can lapse). The timer
|
|
159
|
+
* body is best-effort and never throws; renewal failures surface through
|
|
160
|
+
* opts.onLost exactly once. Idempotent — restarting replaces the timer.
|
|
161
|
+
*/
|
|
162
|
+
StartHeartbeat(opts) {
|
|
163
|
+
this.StopHeartbeat();
|
|
164
|
+
const intervalMs = Math.max(5_000, Math.floor((this.leaseMinutes * 60_000) / 3));
|
|
165
|
+
this.heartbeatTimer = setInterval(() => {
|
|
166
|
+
void this.heartbeatOnce(opts);
|
|
167
|
+
}, intervalMs);
|
|
168
|
+
// Never keep the process alive just to renew a lease.
|
|
169
|
+
this.heartbeatTimer.unref?.();
|
|
170
|
+
}
|
|
171
|
+
/** Stop the renewal timer (idempotent). */
|
|
172
|
+
StopHeartbeat() {
|
|
173
|
+
if (this.heartbeatTimer) {
|
|
174
|
+
clearInterval(this.heartbeatTimer);
|
|
175
|
+
this.heartbeatTimer = null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Sync the entity's in-memory ownership columns to the service's last-known
|
|
180
|
+
* authoritative values before ANY full-row `run.Save()`. The generated
|
|
181
|
+
* spUpdate writes every column from the entity's in-memory state, so a
|
|
182
|
+
* terminal Save without this sync would clobber the DB's live
|
|
183
|
+
* FenceToken/OwnerToken/LeaseExpiresAt with the stale values the entity was
|
|
184
|
+
* loaded with (typically pre-claim). Call this immediately before each
|
|
185
|
+
* Save on the run row; Release() then clears ownership atomically.
|
|
186
|
+
*/
|
|
187
|
+
SyncEntityOwnershipFields(run) {
|
|
188
|
+
run.OwnerToken = this.ownerToken;
|
|
189
|
+
run.LeaseExpiresAt = this.lastKnownLeaseExpiresAt;
|
|
190
|
+
run.HeartbeatAt = new Date();
|
|
191
|
+
if (this.fenceToken != null) {
|
|
192
|
+
run.FenceToken = this.fenceToken;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Persist a progress snapshot to the run row's ProgressJSON (PR 1 item 4 —
|
|
197
|
+
* progress lives in the database; readers query the row). Ownership-guarded
|
|
198
|
+
* (WHERE OwnerToken AND FenceToken) so a reclaimed run can never overwrite the
|
|
199
|
+
* new owner's progress. Throttled internally (default once per 5s) so progress
|
|
200
|
+
* never becomes its own hot path; best-effort — a progress write failure must
|
|
201
|
+
* never fault the sync.
|
|
202
|
+
*/
|
|
203
|
+
async WriteProgress(progressJSON, minIntervalMs = 5_000) {
|
|
204
|
+
if (this.fenceToken == null)
|
|
205
|
+
return;
|
|
206
|
+
const now = Date.now();
|
|
207
|
+
if (now - this.lastProgressWriteMs < minIntervalMs)
|
|
208
|
+
return;
|
|
209
|
+
this.lastProgressWriteMs = now;
|
|
210
|
+
try {
|
|
211
|
+
const d = this.provider.Dialect;
|
|
212
|
+
const schema = d.QuoteIdentifier(this.provider.MJCoreSchemaName);
|
|
213
|
+
const table = d.QuoteIdentifier('CompanyIntegrationRun');
|
|
214
|
+
const ph = (i) => this.provider.BuildParameterPlaceholder(i);
|
|
215
|
+
await this.provider.ExecuteSQL(`UPDATE ${schema}.${table} SET ${d.QuoteIdentifier('ProgressJSON')} = ${ph(0)}, ` +
|
|
216
|
+
`${d.QuoteIdentifier('HeartbeatAt')} = ${d.CurrentTimestampUTC()} ` +
|
|
217
|
+
`WHERE ${d.QuoteIdentifier('ID')} = ${ph(1)} AND ${d.QuoteIdentifier('OwnerToken')} = ${ph(2)} ` +
|
|
218
|
+
`AND ${d.QuoteIdentifier('FenceToken')} = ${ph(3)}`, [progressJSON, this.runID, this.ownerToken, this.fenceToken], { isMutation: true, description: 'CompanyIntegrationRun progress write (ownership-guarded)' }, this.contextUser);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
LogErrorEx({
|
|
222
|
+
message: `[RunOwnership] Progress write failed for run ${this.runID.substring(0, 8)} (non-fatal)`,
|
|
223
|
+
category: 'IntegrationEngine',
|
|
224
|
+
error: error instanceof Error ? error : undefined,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/** One heartbeat tick: renew, then fan out lost/cancel notifications once each. */
|
|
229
|
+
async heartbeatOnce(opts) {
|
|
230
|
+
if (this.renewInFlight) {
|
|
231
|
+
return; // never stack renewals behind a slow DB
|
|
232
|
+
}
|
|
233
|
+
this.renewInFlight = true;
|
|
234
|
+
try {
|
|
235
|
+
const progress = opts?.progressSupplier ? opts.progressSupplier() : null;
|
|
236
|
+
const result = await this.Renew(progress);
|
|
237
|
+
if (!result.Renewed) {
|
|
238
|
+
if (!this.lostNotified) {
|
|
239
|
+
this.lostNotified = true;
|
|
240
|
+
LogStatusEx({
|
|
241
|
+
message: `[RunOwnership] Lease for run ${this.runID.substring(0, 8)} NOT renewed ` +
|
|
242
|
+
`(token/fence mismatch — reclaimed by another holder). Aborting locally.`,
|
|
243
|
+
category: 'IntegrationEngine',
|
|
244
|
+
});
|
|
245
|
+
opts?.onLost?.();
|
|
246
|
+
}
|
|
247
|
+
this.StopHeartbeat(); // no point renewing a lost lease
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (result.CancelRequested && !this.cancelNotified) {
|
|
251
|
+
this.cancelNotified = true;
|
|
252
|
+
opts?.onCancelRequested?.();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
// Best-effort: a transient renewal failure must never fault the sync.
|
|
257
|
+
// The lease covers ~3 intervals, so one failed tick is survivable.
|
|
258
|
+
LogErrorEx({
|
|
259
|
+
message: `[RunOwnership] Lease renewal failed for run ${this.runID.substring(0, 8)} (non-fatal)`,
|
|
260
|
+
category: 'IntegrationEngine',
|
|
261
|
+
error: error instanceof Error ? error : undefined,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
this.renewInFlight = false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Dialect-portable sproc call, preserving the MJ positional-parameter-array
|
|
270
|
+
* convention (same helper shape as ScheduledJobEngine.buildLockSprocCall).
|
|
271
|
+
*/
|
|
272
|
+
buildSprocCall(sprocName, paramNames) {
|
|
273
|
+
const placeholders = this.provider.PlatformKey === 'postgresql'
|
|
274
|
+
? paramNames.map((_name, i) => `$${i + 1}`)
|
|
275
|
+
: paramNames.map((name, i) => `@${name}=@p${i}`);
|
|
276
|
+
return this.provider.Dialect.ProcedureCallSyntax(this.provider.MJCoreSchemaName, sprocName, placeholders);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=RunOwnershipService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunOwnershipService.js","sourceRoot":"","sources":["../src/RunOwnershipService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OAuth2TokenManager.d.ts","sourceRoot":"","sources":["../../src/auth-helpers/OAuth2TokenManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;
|
|
1
|
+
{"version":3,"file":"OAuth2TokenManager.d.ts","sourceRoot":"","sources":["../../src/auth-helpers/OAuth2TokenManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,qDAAqD;AACrD,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,UAAU,GAAG,oBAAoB,CAAC;AAElF,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IAC/B,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sFAAsF;IACtF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qDAAqD;AACrD,MAAM,WAAW,WAAW;IACxB,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAgBD;;;;GAIG;AACH,qBAAa,kBAAkB;IAC3B,+DAA+D;IACxD,eAAe,SAAU;IAEhC,OAAO,CAAC,MAAM,CAA4B;IAC1C,0EAA0E;IAC1E,OAAO,CAAC,gBAAgB,CAAqB;IAE7C;;;;;OAKG;IACU,cAAc,CAAC,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAclG,iFAAiF;IAC1E,KAAK,IAAI,IAAI;IAKpB,mEAAmE;YACrD,YAAY;IAiD1B,qFAAqF;IACrF,OAAO,CAAC,cAAc;CAmCzB"}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* — there is no signing/HMAC here. It exists so connectors share ONE correct token
|
|
24
24
|
* round-trip rather than each re-implementing `grant_type` form bodies.
|
|
25
25
|
*/
|
|
26
|
+
import { DescribeTokenEndpointFailure } from '@memberjunction/global';
|
|
26
27
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
27
28
|
const DEFAULT_EXPIRES_IN_S = 3_600;
|
|
28
29
|
/**
|
|
@@ -92,8 +93,13 @@ export class OAuth2TokenManager {
|
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
if (!response.ok || !parsed.access_token) {
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
// SECURITY: never fall back to the raw response body. This branch is also
|
|
97
|
+
// reached on an HTTP 200 whose token sits somewhere `parsed` did not look
|
|
98
|
+
// (a vendor envelope, a nested `data` object) — in which case the body IS
|
|
99
|
+
// the token. `DescribeTokenEndpointFailure` surfaces only the RFC 6749 §5.2
|
|
100
|
+
// error fields, which by spec describe the failure and carry no credentials.
|
|
101
|
+
throw new Error(`OAuth2 ${grant} token request to ${req.TokenURL} failed: ` +
|
|
102
|
+
`HTTP ${response.status}${DescribeTokenEndpointFailure(text)}`);
|
|
97
103
|
}
|
|
98
104
|
const expiresInS = typeof parsed.expires_in === 'number' ? parsed.expires_in : DEFAULT_EXPIRES_IN_S;
|
|
99
105
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OAuth2TokenManager.js","sourceRoot":"","sources":["../../src/auth-helpers/OAuth2TokenManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;
|
|
1
|
+
{"version":3,"file":"OAuth2TokenManager.js","sourceRoot":"","sources":["../../src/auth-helpers/OAuth2TokenManager.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export type { IIntegrationSourceType, ICompanyIntegrationEntityMap, ICompanyInte
|
|
|
2
2
|
export type { SyncDirection, SyncTriggerType, WatermarkType, ConflictResolution, DeleteBehavior, RecordChangeType, IntegrationRunStatus, ExternalRecord, MappedRecord, SyncResult, SyncRecordError, DefaultFieldMapping, SyncErrorCode, ErrorSeverity, SyncProgress, SyncProgressSnapshot, OnProgressCallback, SyncNotificationEvent, SyncNotificationSeverity, SyncNotification, OnNotificationCallback, IntegrationSyncOptions, EntityMapSyncResult, SourceSchemaInfo, SourceObjectInfo, SourceFieldInfo, SourceRelationshipInfo, IntrospectSchemaOptions, CRUDContext, CreateRecordContext, UpdateRecordContext, UpsertRecordContext, DeleteRecordContext, GetRecordContext, CRUDResult, SearchContext, SearchResult, ListContext, ListResult, SchemaPromotionResult, PostSyncSchemaPromotionCallback, CustomKeyStat, } from './types.js';
|
|
3
3
|
export { IsRetryableError, ClassifyError } from './types.js';
|
|
4
4
|
export type { TransformType, TransformOnError, TransformStep, TransformConfig, DirectConfig, RegexConfig, SplitConfig, CombineConfig, LookupConfig, FormatConfig, CoerceConfig, SubstringConfig, CustomConfig, } from './transforms.js';
|
|
5
|
-
export { BaseIntegrationConnector, WithTimeout, DEFAULT_OPERATION_TIMEOUTS } from './BaseIntegrationConnector.js';
|
|
5
|
+
export { BaseIntegrationConnector, WithTimeout, OperationTimeoutError, DEFAULT_OPERATION_TIMEOUTS } from './BaseIntegrationConnector.js';
|
|
6
6
|
export type { ConnectionTestResult, ExternalObjectSchema, ExternalFieldSchema, FetchContext, FetchBatchResult, OperationTimeouts, DefaultIntegrationConfig, DefaultObjectConfig, RateLimitPolicy, } from './BaseIntegrationConnector.js';
|
|
7
7
|
export { BaseRESTIntegrationConnector } from './BaseRESTIntegrationConnector.js';
|
|
8
8
|
export type { RESTAuthContext, RESTResponse, PaginationState, PaginationType } from './BaseRESTIntegrationConnector.js';
|
|
@@ -18,6 +18,8 @@ export type { IntegrationObjectInfo, IntegrationFieldInfo, ActionGeneratorConfig
|
|
|
18
18
|
export { IntegrationActionGenerator } from './IntegrationActionGenerator.js';
|
|
19
19
|
export type { IntegrationActionVerb, GenerateIntegrationActionResult } from './IntegrationActionGenerator.js';
|
|
20
20
|
export { IntegrationEngine } from './IntegrationEngine.js';
|
|
21
|
+
export { RunOwnershipService, RunOwnershipLostError } from './RunOwnershipService.js';
|
|
22
|
+
export type { RenewResult, BoundaryCheckResult, HeartbeatOptions, TerminalRunStatus } from './RunOwnershipService.js';
|
|
21
23
|
export { IntegrationSchemaSync } from './IntegrationSchemaSync.js';
|
|
22
24
|
export type { PersistSchemaOptions, PersistSchemaResult } from './IntegrationSchemaSync.js';
|
|
23
25
|
export { computeContentHash, CONTENT_HASH_COLUMN } from './ContentHash.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,gCAAgC,EAAE,MAAM,mBAAmB,CAAC;AAG7J,YAAY,EACV,aAAa,EACb,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,uBAAuB,EACvB,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,YAAY,EACZ,WAAW,EACX,UAAU,EACV,qBAAqB,EACrB,+BAA+B,EAC/B,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG7D,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,WAAW,EACX,WAAW,EACX,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,YAAY,GACb,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Error classification helpers
|
|
2
2
|
export { IsRetryableError, ClassifyError } from './types.js';
|
|
3
3
|
// Connector
|
|
4
|
-
export { BaseIntegrationConnector, WithTimeout, DEFAULT_OPERATION_TIMEOUTS } from './BaseIntegrationConnector.js';
|
|
4
|
+
export { BaseIntegrationConnector, WithTimeout, OperationTimeoutError, DEFAULT_OPERATION_TIMEOUTS } from './BaseIntegrationConnector.js';
|
|
5
5
|
// REST Connector Base
|
|
6
6
|
export { BaseRESTIntegrationConnector } from './BaseRESTIntegrationConnector.js';
|
|
7
7
|
// Factory
|
|
@@ -21,6 +21,7 @@ export { IntegrationActionGenerator } from './IntegrationActionGenerator.js';
|
|
|
21
21
|
// Integration Engine (server-side, wraps IntegrationEngineBase via composition)
|
|
22
22
|
// NOTE: For IntegrationEngineBase (client-safe metadata), import from @memberjunction/integration-engine-base
|
|
23
23
|
export { IntegrationEngine } from './IntegrationEngine.js';
|
|
24
|
+
export { RunOwnershipService, RunOwnershipLostError } from './RunOwnershipService.js';
|
|
24
25
|
// Schema persistence — upserts dynamically discovered objects/fields to IntegrationObject/Field tables
|
|
25
26
|
export { IntegrationSchemaSync } from './IntegrationSchemaSync.js';
|
|
26
27
|
// ── Restored module exports dropped by the origin/next index.ts merge (union) ──
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiDA,+BAA+B;AAC/B,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAmB7D,YAAY;AACZ,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiDA,+BAA+B;AAC/B,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAmB7D,YAAY;AACZ,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAazI,sBAAsB;AACtB,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AAGjF,UAAU;AACV,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,UAAU;AACV,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,WAAW;AACX,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,QAAQ;AACR,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAGnE,4BAA4B;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,qHAAqH;AACrH,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAG7E,gFAAgF;AAChF,8GAA8G;AAC9G,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAMtF,uGAAuG;AACvG,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,kFAAkF;AAClF,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAElJ,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAClL,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAGtF,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAE/G,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,oCAAoC,EAAE,MAAM,2CAA2C,CAAC;AAEjG,OAAO,EAAE,6BAA6B,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAItF,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAGzE,qEAAqE;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -276,6 +276,14 @@ export interface IntegrationSyncOptions {
|
|
|
276
276
|
* Pull = external → MJ only. Push = MJ → external only. Bidirectional = both.
|
|
277
277
|
*/
|
|
278
278
|
SyncDirection?: 'Pull' | 'Push' | 'Bidirectional';
|
|
279
|
+
/**
|
|
280
|
+
* Expected maximum runtime for this sync, in minutes. Sizes the run's OWNERSHIP LEASE
|
|
281
|
+
* (durable-run claim/renew): the lease is max(engine default, this value), so a run with a
|
|
282
|
+
* known long single batch is not falsely reclaimed as dead by the stale sweep while a batch
|
|
283
|
+
* is still in flight. The lease is renewed on a timer regardless; this only raises the
|
|
284
|
+
* worst-case window a crashed run stays unclaimed. Omit for the engine default.
|
|
285
|
+
*/
|
|
286
|
+
MaxRuntimeMinutes?: number;
|
|
279
287
|
}
|
|
280
288
|
/** Top-level container returned by a connector's IntrospectSchema(). */
|
|
281
289
|
export interface SourceSchemaInfo {
|