fullstackgtm 0.45.0 → 0.47.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 +115 -1
- package/INSTALL_FOR_AGENTS.md +13 -11
- package/README.md +27 -18
- package/dist/backfill.d.ts +86 -0
- package/dist/backfill.js +251 -0
- package/dist/bin.js +4 -1
- package/dist/cli/auth.d.ts +2 -0
- package/dist/cli/auth.js +119 -12
- package/dist/cli/backfill.d.ts +1 -0
- package/dist/cli/backfill.js +125 -0
- package/dist/cli/backfillRuns.d.ts +1 -0
- package/dist/cli/backfillRuns.js +187 -0
- package/dist/cli/call.js +23 -9
- package/dist/cli/enrich.js +28 -10
- package/dist/cli/fix.js +9 -7
- package/dist/cli/help.js +60 -23
- package/dist/cli/plans.js +13 -11
- package/dist/cli/shared.d.ts +4 -3
- package/dist/cli/shared.js +31 -20
- package/dist/cli/ui.d.ts +21 -0
- package/dist/cli/ui.js +53 -1
- package/dist/cli.js +37 -41
- package/dist/connector.d.ts +8 -0
- package/dist/connector.js +104 -21
- package/dist/connectors/hubspot.d.ts +8 -1
- package/dist/connectors/hubspot.js +406 -13
- package/dist/connectors/hubspotAuth.js +5 -1
- package/dist/connectors/linkedin.js +14 -14
- package/dist/connectors/salesforce.d.ts +8 -1
- package/dist/connectors/salesforce.js +163 -2
- package/dist/connectors/stripe.d.ts +37 -0
- package/dist/connectors/stripe.js +103 -31
- package/dist/enrich.d.ts +7 -0
- package/dist/enrich.js +7 -0
- package/dist/health.d.ts +11 -69
- package/dist/health.js +4 -134
- package/dist/healthScore.d.ts +71 -0
- package/dist/healthScore.js +143 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/llm.d.ts +29 -0
- package/dist/llm.js +206 -0
- package/dist/market.d.ts +39 -1
- package/dist/market.js +116 -44
- package/dist/marketClassify.d.ts +9 -1
- package/dist/marketClassify.js +10 -1
- package/dist/marketTaxonomy.d.ts +6 -1
- package/dist/marketTaxonomy.js +4 -2
- package/dist/mcp-bin.js +29 -0
- package/dist/mcp.js +117 -4
- package/dist/progress.d.ts +96 -0
- package/dist/progress.js +142 -0
- package/dist/runReport.d.ts +24 -0
- package/dist/runReport.js +139 -4
- package/dist/types.d.ts +33 -1
- package/docs/api.md +4 -2
- package/docs/architecture.md +2 -0
- package/docs/linkedin-connector-spec.md +1 -1
- package/llms.txt +3 -3
- package/package.json +10 -3
- package/skills/fullstackgtm/SKILL.md +1 -0
- package/src/backfill.ts +340 -0
- package/src/bin.ts +5 -1
- package/src/cli/auth.ts +135 -15
- package/src/cli/backfill.ts +156 -0
- package/src/cli/backfillRuns.ts +198 -0
- package/src/cli/call.ts +26 -10
- package/src/cli/enrich.ts +33 -10
- package/src/cli/fix.ts +11 -10
- package/src/cli/help.ts +61 -23
- package/src/cli/plans.ts +15 -14
- package/src/cli/shared.ts +44 -27
- package/src/cli/ui.ts +72 -1
- package/src/cli.ts +38 -41
- package/src/connector.ts +110 -16
- package/src/connectors/hubspot.ts +423 -14
- package/src/connectors/hubspotAuth.ts +5 -1
- package/src/connectors/linkedin.ts +14 -14
- package/src/connectors/salesforce.ts +168 -3
- package/src/connectors/stripe.ts +154 -34
- package/src/enrich.ts +13 -0
- package/src/health.ts +14 -213
- package/src/healthScore.ts +223 -0
- package/src/index.ts +28 -1
- package/src/llm.ts +239 -0
- package/src/market.ts +157 -44
- package/src/marketClassify.ts +18 -1
- package/src/marketTaxonomy.ts +10 -2
- package/src/mcp-bin.ts +32 -0
- package/src/mcp.ts +140 -6
- package/src/progress.ts +197 -0
- package/src/runReport.ts +159 -4
- package/src/types.ts +35 -2
- package/docs/dx-punch-list.md +0 -87
- package/docs/roadmap-to-1.0.md +0 -211
package/dist/cli.js
CHANGED
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { activeProfile, listProfiles, setActiveProfile } from "./credentials.js";
|
|
2
|
-
import { audit, healthCommand, reportCommand, rulesCommand, snapshotCommand } from "./cli/audit.js";
|
|
3
|
-
import { doctorCommand, login, logout } from "./cli/auth.js";
|
|
4
2
|
import { capabilitiesCommand, printCommandHelpJson, robotDocsCommand, unknownCommandEnvelope } from "./cli/capabilities.js";
|
|
5
|
-
import { callCommand } from "./cli/call.js";
|
|
6
|
-
import { draftCommand } from "./cli/draft.js";
|
|
7
|
-
import { enrichCommand } from "./cli/enrich.js";
|
|
8
|
-
import { bulkUpdateCommand, dedupeCommand, fixCommand, reassignCommand, resolveCommand, suggest } from "./cli/fix.js";
|
|
9
3
|
import { BESPOKE_HELP, commandHelp, HELP, shortUsage, stylizeShortUsage, usage } from "./cli/help.js";
|
|
10
|
-
import { icpCommand } from "./cli/icp.js";
|
|
11
|
-
import { initCommand } from "./cli/init.js";
|
|
12
|
-
import { marketCommand } from "./cli/market.js";
|
|
13
|
-
import { apply, auditLogCommand, diffCommand, mergeCommand, plansCommand } from "./cli/plans.js";
|
|
14
|
-
import { scheduleCommand } from "./cli/schedule.js";
|
|
15
4
|
import { readPackageInfo } from "./cli/shared.js";
|
|
16
5
|
import { correctedCommand, detectFlagTypo, suggestCommand, unknownFlagEnvelope } from "./cli/suggest.js";
|
|
17
6
|
import { colorEnabled, paint } from "./cli/ui.js";
|
|
18
|
-
|
|
19
|
-
import
|
|
7
|
+
// Verb modules load lazily inside their dispatch branch below. The dispatcher
|
|
8
|
+
// used to import all of them eagerly, so `--version` compiled the full
|
|
9
|
+
// 78-module graph (audit, market, enrich, signals, schedule, …) before
|
|
10
|
+
// printing one line. Each branch now `await import()`s only its own module;
|
|
11
|
+
// help/typo/error paths and the exports above stay eager and byte-identical.
|
|
20
12
|
/**
|
|
21
13
|
* Pull the global `--profile <name>` flag out of argv (it may appear before
|
|
22
14
|
* or after the command) and activate it. Stripping it keeps positional
|
|
@@ -126,95 +118,99 @@ export async function runCli(argv) {
|
|
|
126
118
|
return;
|
|
127
119
|
}
|
|
128
120
|
if (command === "login") {
|
|
129
|
-
await login(args);
|
|
121
|
+
await (await import("./cli/auth.js")).login(args);
|
|
130
122
|
return;
|
|
131
123
|
}
|
|
132
124
|
if (command === "logout") {
|
|
133
|
-
logout(args);
|
|
125
|
+
(await import("./cli/auth.js")).logout(args);
|
|
134
126
|
return;
|
|
135
127
|
}
|
|
136
128
|
if (command === "snapshot") {
|
|
137
|
-
await snapshotCommand(args);
|
|
129
|
+
await (await import("./cli/audit.js")).snapshotCommand(args);
|
|
138
130
|
return;
|
|
139
131
|
}
|
|
140
132
|
if (command === "audit") {
|
|
141
|
-
await audit(args);
|
|
133
|
+
await (await import("./cli/audit.js")).audit(args);
|
|
142
134
|
return;
|
|
143
135
|
}
|
|
144
136
|
if (command === "report") {
|
|
145
|
-
await reportCommand(args);
|
|
137
|
+
await (await import("./cli/audit.js")).reportCommand(args);
|
|
146
138
|
return;
|
|
147
139
|
}
|
|
148
140
|
if (command === "rules") {
|
|
149
|
-
await rulesCommand(args);
|
|
141
|
+
await (await import("./cli/audit.js")).rulesCommand(args);
|
|
150
142
|
return;
|
|
151
143
|
}
|
|
152
144
|
if (command === "doctor") {
|
|
153
|
-
await doctorCommand(args);
|
|
145
|
+
await (await import("./cli/auth.js")).doctorCommand(args);
|
|
154
146
|
return;
|
|
155
147
|
}
|
|
156
148
|
if (command === "health") {
|
|
157
|
-
healthCommand(args);
|
|
149
|
+
(await import("./cli/audit.js")).healthCommand(args);
|
|
158
150
|
return;
|
|
159
151
|
}
|
|
160
152
|
if (command === "suggest") {
|
|
161
|
-
await suggest(args);
|
|
153
|
+
await (await import("./cli/fix.js")).suggest(args);
|
|
162
154
|
return;
|
|
163
155
|
}
|
|
164
156
|
if (command === "call") {
|
|
165
|
-
await callCommand(args);
|
|
157
|
+
await (await import("./cli/call.js")).callCommand(args);
|
|
166
158
|
return;
|
|
167
159
|
}
|
|
168
160
|
if (command === "resolve") {
|
|
169
|
-
await resolveCommand(args);
|
|
161
|
+
await (await import("./cli/fix.js")).resolveCommand(args);
|
|
170
162
|
return;
|
|
171
163
|
}
|
|
172
164
|
if (command === "bulk-update") {
|
|
173
|
-
await bulkUpdateCommand(args);
|
|
165
|
+
await (await import("./cli/fix.js")).bulkUpdateCommand(args);
|
|
174
166
|
return;
|
|
175
167
|
}
|
|
176
168
|
if (command === "dedupe") {
|
|
177
|
-
await dedupeCommand(args);
|
|
169
|
+
await (await import("./cli/fix.js")).dedupeCommand(args);
|
|
178
170
|
return;
|
|
179
171
|
}
|
|
180
172
|
if (command === "reassign") {
|
|
181
|
-
await reassignCommand(args);
|
|
173
|
+
await (await import("./cli/fix.js")).reassignCommand(args);
|
|
182
174
|
return;
|
|
183
175
|
}
|
|
184
176
|
if (command === "fix") {
|
|
185
|
-
await fixCommand(args);
|
|
177
|
+
await (await import("./cli/fix.js")).fixCommand(args);
|
|
186
178
|
return;
|
|
187
179
|
}
|
|
188
180
|
if (command === "market") {
|
|
189
|
-
await marketCommand(args);
|
|
181
|
+
await (await import("./cli/market.js")).marketCommand(args);
|
|
190
182
|
return;
|
|
191
183
|
}
|
|
192
184
|
if (command === "enrich") {
|
|
193
|
-
await enrichCommand(args);
|
|
185
|
+
await (await import("./cli/enrich.js")).enrichCommand(args);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (command === "backfill") {
|
|
189
|
+
await (await import("./cli/backfill.js")).backfillCommand(args);
|
|
194
190
|
return;
|
|
195
191
|
}
|
|
196
192
|
if (command === "init") {
|
|
197
|
-
initCommand(args);
|
|
193
|
+
(await import("./cli/init.js")).initCommand(args);
|
|
198
194
|
return;
|
|
199
195
|
}
|
|
200
196
|
if (command === "tam") {
|
|
201
|
-
await tamCommand(args);
|
|
197
|
+
await (await import("./cli/tam.js")).tamCommand(args);
|
|
202
198
|
return;
|
|
203
199
|
}
|
|
204
200
|
if (command === "icp") {
|
|
205
|
-
await icpCommand(args);
|
|
201
|
+
await (await import("./cli/icp.js")).icpCommand(args);
|
|
206
202
|
return;
|
|
207
203
|
}
|
|
208
204
|
if (command === "signals") {
|
|
209
|
-
await signalsCommand(args);
|
|
205
|
+
await (await import("./cli/signals.js")).signalsCommand(args);
|
|
210
206
|
return;
|
|
211
207
|
}
|
|
212
208
|
if (command === "draft") {
|
|
213
|
-
await draftCommand(args);
|
|
209
|
+
await (await import("./cli/draft.js")).draftCommand(args);
|
|
214
210
|
return;
|
|
215
211
|
}
|
|
216
212
|
if (command === "schedule") {
|
|
217
|
-
await scheduleCommand(args);
|
|
213
|
+
await (await import("./cli/schedule.js")).scheduleCommand(args);
|
|
218
214
|
return;
|
|
219
215
|
}
|
|
220
216
|
if (command === "profiles") {
|
|
@@ -222,23 +218,23 @@ export async function runCli(argv) {
|
|
|
222
218
|
return;
|
|
223
219
|
}
|
|
224
220
|
if (command === "diff") {
|
|
225
|
-
await diffCommand(args);
|
|
221
|
+
await (await import("./cli/plans.js")).diffCommand(args);
|
|
226
222
|
return;
|
|
227
223
|
}
|
|
228
224
|
if (command === "merge") {
|
|
229
|
-
await mergeCommand(args);
|
|
225
|
+
await (await import("./cli/plans.js")).mergeCommand(args);
|
|
230
226
|
return;
|
|
231
227
|
}
|
|
232
228
|
if (command === "plans") {
|
|
233
|
-
await plansCommand(args);
|
|
229
|
+
await (await import("./cli/plans.js")).plansCommand(args);
|
|
234
230
|
return;
|
|
235
231
|
}
|
|
236
232
|
if (command === "audit-log") {
|
|
237
|
-
await auditLogCommand(args);
|
|
233
|
+
await (await import("./cli/plans.js")).auditLogCommand(args);
|
|
238
234
|
return;
|
|
239
235
|
}
|
|
240
236
|
if (command === "apply") {
|
|
241
|
-
await apply(args);
|
|
237
|
+
await (await import("./cli/plans.js")).apply(args);
|
|
242
238
|
return;
|
|
243
239
|
}
|
|
244
240
|
// Machine callers get a structured envelope with a did-you-mean hint
|
package/dist/connector.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ProgressEmitter } from "./progress.ts";
|
|
1
2
|
import type { GtmConnector, PatchPlan, PatchPlanRun } from "./types.ts";
|
|
2
3
|
export type ApplyPatchPlanOptions = {
|
|
3
4
|
/**
|
|
@@ -31,6 +32,13 @@ export type ApplyPatchPlanOptions = {
|
|
|
31
32
|
* full operation count.
|
|
32
33
|
*/
|
|
33
34
|
onOperation?: (progress: ApplyProgress) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Shared progress vocabulary (src/progress.ts): the run emits the
|
|
37
|
+
* APPLY_STAGES (preflight → operations → results), one `opResult` per
|
|
38
|
+
* resolved operation (id + status only — no values), and `items` over the
|
|
39
|
+
* plan's operations. Additive alongside `onOperation`; presentation only.
|
|
40
|
+
*/
|
|
41
|
+
progress?: ProgressEmitter;
|
|
34
42
|
};
|
|
35
43
|
export type ApplyProgress = {
|
|
36
44
|
completed: number;
|
package/dist/connector.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { dedupeKey } from "./dedupe.js";
|
|
2
|
+
import { APPLY_STAGES } from "./progress.js";
|
|
2
3
|
import { requiresHumanInput } from "./rules.js";
|
|
3
4
|
const IRREVERSIBLE_OPERATIONS = new Set(["merge_records", "archive_record"]);
|
|
4
5
|
const IDENTITY_KEY_BY_TYPE = {
|
|
@@ -70,6 +71,13 @@ function normalizeForComparison(value) {
|
|
|
70
71
|
return null;
|
|
71
72
|
return String(value);
|
|
72
73
|
}
|
|
74
|
+
function isApplyBatchCandidate(operation) {
|
|
75
|
+
return (((operation.operation === "set_field" || operation.operation === "clear_field") && Boolean(operation.field)) ||
|
|
76
|
+
operation.operation === "archive_record");
|
|
77
|
+
}
|
|
78
|
+
function sameApplyBatchKind(a, b) {
|
|
79
|
+
return a.operation === b.operation && a.objectType === b.objectType;
|
|
80
|
+
}
|
|
73
81
|
/**
|
|
74
82
|
* Apply an approved subset of a patch plan through a connector.
|
|
75
83
|
*
|
|
@@ -83,6 +91,8 @@ export async function applyPatchPlan(connector, plan, options) {
|
|
|
83
91
|
throw new Error(`The ${connector.provider} connector is read-only.`);
|
|
84
92
|
}
|
|
85
93
|
const startedAt = new Date().toISOString();
|
|
94
|
+
const emitStage = (stage) => options.progress?.stage(stage, APPLY_STAGES.indexOf(stage), APPLY_STAGES.length);
|
|
95
|
+
emitStage("preflight");
|
|
86
96
|
const approved = new Set(options.approvedOperationIds);
|
|
87
97
|
const checkConflicts = options.checkConflicts ?? typeof connector.readField === "function";
|
|
88
98
|
const results = [];
|
|
@@ -157,6 +167,7 @@ export async function applyPatchPlan(connector, plan, options) {
|
|
|
157
167
|
: "Operation was not approved.",
|
|
158
168
|
});
|
|
159
169
|
}
|
|
170
|
+
emitStage("results");
|
|
160
171
|
return {
|
|
161
172
|
planId: plan.id,
|
|
162
173
|
provider: connector.provider,
|
|
@@ -190,6 +201,11 @@ export async function applyPatchPlan(connector, plan, options) {
|
|
|
190
201
|
for (const operation of plan.operations) {
|
|
191
202
|
if (!approved.has(operation.id) || conflicts.has(operation.id))
|
|
192
203
|
continue;
|
|
204
|
+
// Generic batch connectors (Salesforce) do their own batched CAS read for
|
|
205
|
+
// eligible field writes, so don't pre-read those one-by-one here.
|
|
206
|
+
if (connector.applyBatch && isApplyBatchCandidate(operation) && !operation.groupId && !operation.preconditions?.length) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
193
209
|
let conflict = null;
|
|
194
210
|
if (operation.field && FIELD_WRITE_OPERATIONS.has(operation.operation)) {
|
|
195
211
|
const current = await connector.readField(operation.objectType, operation.objectId, operation.field);
|
|
@@ -260,30 +276,40 @@ export async function applyPatchPlan(connector, plan, options) {
|
|
|
260
276
|
const resultsBefore = results.length;
|
|
261
277
|
let lastNotified = results.length;
|
|
262
278
|
const notifyProgress = () => {
|
|
263
|
-
if (!options.onOperation || results.length === lastNotified)
|
|
279
|
+
if ((!options.onOperation && !options.progress) || results.length === lastNotified)
|
|
264
280
|
return;
|
|
265
|
-
lastNotified
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
281
|
+
while (lastNotified < results.length) {
|
|
282
|
+
const last = results[lastNotified];
|
|
283
|
+
lastNotified += 1;
|
|
284
|
+
if (last.status === "applied")
|
|
285
|
+
progressCounts.applied += 1;
|
|
286
|
+
else if (last.status === "failed")
|
|
287
|
+
progressCounts.failed += 1;
|
|
288
|
+
else if (last.status === "conflict")
|
|
289
|
+
progressCounts.conflicts += 1;
|
|
290
|
+
else
|
|
291
|
+
progressCounts.skipped += 1;
|
|
292
|
+
// Shared vocabulary: operation id + status only — a conflict/failure
|
|
293
|
+
// detail can echo field values, which never leave the machine.
|
|
294
|
+
options.progress?.opResult(last.operationId, last.status);
|
|
295
|
+
options.progress?.items(results.length - resultsBefore, plan.operations.length);
|
|
296
|
+
if (options.onOperation) {
|
|
297
|
+
try {
|
|
298
|
+
options.onOperation({
|
|
299
|
+
completed: lastNotified - resultsBefore,
|
|
300
|
+
total: plan.operations.length,
|
|
301
|
+
...progressCounts,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// progress is presentation-only
|
|
306
|
+
}
|
|
307
|
+
}
|
|
284
308
|
}
|
|
285
309
|
};
|
|
286
|
-
|
|
310
|
+
emitStage("operations");
|
|
311
|
+
for (let opIndex = 0; opIndex < plan.operations.length; opIndex++) {
|
|
312
|
+
const operation = plan.operations[opIndex];
|
|
287
313
|
// Report the previous iteration's result (guarded: no-op if it pushed
|
|
288
314
|
// nothing). One-iteration lag keeps this a two-line hook instead of a
|
|
289
315
|
// notify after all ten push sites; the loop-exit call below flushes the last.
|
|
@@ -351,6 +377,62 @@ export async function applyPatchPlan(connector, plan, options) {
|
|
|
351
377
|
});
|
|
352
378
|
continue;
|
|
353
379
|
}
|
|
380
|
+
if (connector.applyBatch && isApplyBatchCandidate(operation) && (checkConflicts || operation.operation === "archive_record") && !operation.groupId && !operation.preconditions?.length) {
|
|
381
|
+
const chunk = [];
|
|
382
|
+
const applyBatchLimit = Math.max(1, connector.applyBatchLimit ?? 200);
|
|
383
|
+
for (let scan = opIndex; scan < plan.operations.length && chunk.length < applyBatchLimit; scan++) {
|
|
384
|
+
const candidate = plan.operations[scan];
|
|
385
|
+
if (!sameApplyBatchKind(operation, candidate) || !isApplyBatchCandidate(candidate))
|
|
386
|
+
break;
|
|
387
|
+
const candidateOverride = options.valueOverrides?.[candidate.id];
|
|
388
|
+
if (!approved.has(candidate.id) ||
|
|
389
|
+
(requiresHumanInput(candidate.afterValue) && candidateOverride === undefined) ||
|
|
390
|
+
conflicts.has(candidate.id) ||
|
|
391
|
+
Boolean(candidate.groupId) ||
|
|
392
|
+
Boolean(candidate.preconditions?.length) ||
|
|
393
|
+
(staleByFilter && staleByFilter.has(candidate.objectId)) ||
|
|
394
|
+
irreversibleStale.has(candidate.id)) {
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
397
|
+
chunk.push(candidateOverride === undefined ? candidate : { ...candidate, afterValue: candidateOverride });
|
|
398
|
+
}
|
|
399
|
+
if (chunk.length > 1) {
|
|
400
|
+
try {
|
|
401
|
+
const batchResults = await connector.applyBatch(chunk);
|
|
402
|
+
const byOperationId = new Map(batchResults.map((result) => [result.operationId, result]));
|
|
403
|
+
for (const batchOperation of chunk) {
|
|
404
|
+
const result = byOperationId.get(batchOperation.id) ?? {
|
|
405
|
+
operationId: batchOperation.id,
|
|
406
|
+
status: "failed",
|
|
407
|
+
detail: "Batch connector did not return a result for this operation.",
|
|
408
|
+
};
|
|
409
|
+
results.push(result);
|
|
410
|
+
if (result.status === "applied" || result.status === "failed")
|
|
411
|
+
attempted += 1;
|
|
412
|
+
if (result.status === "applied")
|
|
413
|
+
applied += 1;
|
|
414
|
+
}
|
|
415
|
+
const appliedInBatch = batchResults.filter((result) => result.status === "applied").length;
|
|
416
|
+
appliedSinceRecheck += appliedInBatch;
|
|
417
|
+
if (appliedInBatch > 0 && (applied === appliedInBatch || appliedSinceRecheck >= recheckEvery)) {
|
|
418
|
+
appliedSinceRecheck = 0;
|
|
419
|
+
await refreshSnapshotChecks();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
catch (error) {
|
|
423
|
+
for (const batchOperation of chunk) {
|
|
424
|
+
results.push({
|
|
425
|
+
operationId: batchOperation.id,
|
|
426
|
+
status: "failed",
|
|
427
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
428
|
+
});
|
|
429
|
+
attempted += 1;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
opIndex += chunk.length - 1;
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
354
436
|
const resolved = override === undefined ? operation : { ...operation, afterValue: override };
|
|
355
437
|
attempted += 1;
|
|
356
438
|
try {
|
|
@@ -377,6 +459,7 @@ export async function applyPatchPlan(connector, plan, options) {
|
|
|
377
459
|
}
|
|
378
460
|
}
|
|
379
461
|
notifyProgress();
|
|
462
|
+
emitStage("results");
|
|
380
463
|
return {
|
|
381
464
|
planId: plan.id,
|
|
382
465
|
provider: connector.provider,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type FieldMappings } from "../mappings.ts";
|
|
2
2
|
import type { GtmConnector, SnapshotProgress } from "../types.ts";
|
|
3
|
+
import { type ProgressEmitter } from "../progress.ts";
|
|
3
4
|
export type HubspotConnectorOptions = {
|
|
4
5
|
/** Returns a HubSpot access token (private app token or OAuth access token). */
|
|
5
6
|
getAccessToken: () => string | Promise<string>;
|
|
@@ -10,6 +11,12 @@ export type HubspotConnectorOptions = {
|
|
|
10
11
|
fetchImpl?: typeof fetch;
|
|
11
12
|
/** Per-page snapshot-pull progress (presentation only — errors are swallowed). */
|
|
12
13
|
onProgress?: (progress: SnapshotProgress) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Shared progress vocabulary (src/progress.ts): the snapshot pull emits a
|
|
16
|
+
* `stage` per object type and an `items` heartbeat per page. Additive
|
|
17
|
+
* alongside the legacy `onProgress` callback; both are presentation-only.
|
|
18
|
+
*/
|
|
19
|
+
progress?: ProgressEmitter;
|
|
13
20
|
};
|
|
14
21
|
/**
|
|
15
22
|
* Reference connector for HubSpot.
|
|
@@ -19,4 +26,4 @@ export type HubspotConnectorOptions = {
|
|
|
19
26
|
* amountless deals — so audit rules can surface the gaps instead of hiding
|
|
20
27
|
* them.
|
|
21
28
|
*/
|
|
22
|
-
export declare function createHubspotConnector(options: HubspotConnectorOptions):
|
|
29
|
+
export declare function createHubspotConnector(options: HubspotConnectorOptions): GtmConnector;
|