@daeda/mcp-pro 0.1.53 → 0.1.55
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/dist/index.js +313 -214
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -84095,36 +84095,6 @@ async function deleteRowsForObjectTypes(connection, tableName, objectTypes) {
|
|
|
84095
84095
|
);
|
|
84096
84096
|
}
|
|
84097
84097
|
}
|
|
84098
|
-
async function readPropertyDefinitionStatesForTypes(connection, objectTypes) {
|
|
84099
|
-
if (objectTypes.length === 0) {
|
|
84100
|
-
return /* @__PURE__ */ new Map();
|
|
84101
|
-
}
|
|
84102
|
-
const states = /* @__PURE__ */ new Map();
|
|
84103
|
-
for (const batch of chunk([...objectTypes], DELETE_BATCH_SIZE)) {
|
|
84104
|
-
const reader = await connection.runAndReadAll(
|
|
84105
|
-
`SELECT object_type, object_type_id, fingerprint, property_count, group_count, last_checked_at, last_changed_at, status, error
|
|
84106
|
-
FROM property_definition_object_state
|
|
84107
|
-
WHERE object_type IN (${buildSqlPlaceholders(batch.length)})`,
|
|
84108
|
-
batch
|
|
84109
|
-
);
|
|
84110
|
-
const rows = reader.getRowObjects();
|
|
84111
|
-
for (const row of rows) {
|
|
84112
|
-
const parsed = PROPERTY_DEFINITION_OBJECT_STATE_ROW_SCHEMA.parse({
|
|
84113
|
-
objectType: row.object_type,
|
|
84114
|
-
objectTypeId: row.object_type_id,
|
|
84115
|
-
fingerprint: row.fingerprint,
|
|
84116
|
-
propertyCount: typeof row.property_count === "number" ? row.property_count : Number(row.property_count ?? 0),
|
|
84117
|
-
groupCount: typeof row.group_count === "number" ? row.group_count : Number(row.group_count ?? 0),
|
|
84118
|
-
lastCheckedAt: row.last_checked_at,
|
|
84119
|
-
lastChangedAt: row.last_changed_at,
|
|
84120
|
-
status: row.status,
|
|
84121
|
-
error: row.error ?? null
|
|
84122
|
-
});
|
|
84123
|
-
states.set(parsed.objectType, parsed);
|
|
84124
|
-
}
|
|
84125
|
-
}
|
|
84126
|
-
return states;
|
|
84127
|
-
}
|
|
84128
84098
|
async function replacePropertyDefinitionSlices(connection, objectTypes, propertyDefinitions, propertyGroups, objectStates) {
|
|
84129
84099
|
await deleteRowsForObjectTypes(connection, "property_definitions", objectTypes);
|
|
84130
84100
|
await deleteRowsForObjectTypes(connection, "property_groups", objectTypes);
|
|
@@ -84254,108 +84224,6 @@ async function syncAssociationSchemaSnapshot({
|
|
|
84254
84224
|
});
|
|
84255
84225
|
return { portalId };
|
|
84256
84226
|
}
|
|
84257
|
-
async function syncPropertyDefinitionsSnapshot({
|
|
84258
|
-
masterLock,
|
|
84259
|
-
portalId,
|
|
84260
|
-
snapshot
|
|
84261
|
-
}) {
|
|
84262
|
-
assertWritable(masterLock);
|
|
84263
|
-
const handle = await getDatabaseConnection(portalId, null);
|
|
84264
|
-
const parsedSnapshot = PROPERTY_DEFINITIONS_SNAPSHOT_SCHEMA.parse(snapshot);
|
|
84265
|
-
await initializeDb(handle.connection);
|
|
84266
|
-
await ensureDataPluginSchema(handle.connection, "property-definitions");
|
|
84267
|
-
await withTransaction(handle.connection, async () => {
|
|
84268
|
-
await ensureTable(handle.connection, PROPERTY_DEFINITIONS_TABLE_STATEMENTS);
|
|
84269
|
-
const skippedObjectTypes = new Set(
|
|
84270
|
-
parsedSnapshot.partial?.skippedObjects.map((item) => item.objectType) ?? []
|
|
84271
|
-
);
|
|
84272
|
-
if (skippedObjectTypes.size === 0) {
|
|
84273
|
-
await replacePluginTable(
|
|
84274
|
-
handle.connection,
|
|
84275
|
-
/* @__PURE__ */ new Set([
|
|
84276
|
-
"property_definitions",
|
|
84277
|
-
"property_groups",
|
|
84278
|
-
"property_definition_object_state"
|
|
84279
|
-
]),
|
|
84280
|
-
"property_definitions",
|
|
84281
|
-
propertyDefinitionRowsToColumns(parsedSnapshot.propertyDefinitions)
|
|
84282
|
-
);
|
|
84283
|
-
await replacePluginTable(
|
|
84284
|
-
handle.connection,
|
|
84285
|
-
/* @__PURE__ */ new Set([
|
|
84286
|
-
"property_definitions",
|
|
84287
|
-
"property_groups",
|
|
84288
|
-
"property_definition_object_state"
|
|
84289
|
-
]),
|
|
84290
|
-
"property_groups",
|
|
84291
|
-
propertyGroupRowsToColumns(parsedSnapshot.propertyGroups)
|
|
84292
|
-
);
|
|
84293
|
-
await replacePluginTable(
|
|
84294
|
-
handle.connection,
|
|
84295
|
-
/* @__PURE__ */ new Set([
|
|
84296
|
-
"property_definitions",
|
|
84297
|
-
"property_groups",
|
|
84298
|
-
"property_definition_object_state"
|
|
84299
|
-
]),
|
|
84300
|
-
"property_definition_object_state",
|
|
84301
|
-
propertyDefinitionObjectStateRowsToColumns(parsedSnapshot.objectStates)
|
|
84302
|
-
);
|
|
84303
|
-
return;
|
|
84304
|
-
}
|
|
84305
|
-
const includedObjectTypes = [
|
|
84306
|
-
...new Set(parsedSnapshot.objectStates.map((row) => row.objectType))
|
|
84307
|
-
].filter((objectType) => !skippedObjectTypes.has(objectType));
|
|
84308
|
-
const existingSkippedStates = await readPropertyDefinitionStatesForTypes(
|
|
84309
|
-
handle.connection,
|
|
84310
|
-
parsedSnapshot.partial?.skippedObjects.map((item) => item.objectType) ?? []
|
|
84311
|
-
);
|
|
84312
|
-
const mergedObjectStates = parsedSnapshot.objectStates.map((row) => {
|
|
84313
|
-
if (!skippedObjectTypes.has(row.objectType)) {
|
|
84314
|
-
return row;
|
|
84315
|
-
}
|
|
84316
|
-
const existing = existingSkippedStates.get(row.objectType);
|
|
84317
|
-
if (!existing) {
|
|
84318
|
-
return row;
|
|
84319
|
-
}
|
|
84320
|
-
return {
|
|
84321
|
-
...existing,
|
|
84322
|
-
objectTypeId: row.objectTypeId,
|
|
84323
|
-
lastCheckedAt: row.lastCheckedAt,
|
|
84324
|
-
status: row.status,
|
|
84325
|
-
error: row.error
|
|
84326
|
-
};
|
|
84327
|
-
});
|
|
84328
|
-
await replacePropertyDefinitionSlices(
|
|
84329
|
-
handle.connection,
|
|
84330
|
-
includedObjectTypes,
|
|
84331
|
-
parsedSnapshot.propertyDefinitions.filter(
|
|
84332
|
-
(row) => !skippedObjectTypes.has(row.objectType)
|
|
84333
|
-
),
|
|
84334
|
-
parsedSnapshot.propertyGroups.filter(
|
|
84335
|
-
(row) => !skippedObjectTypes.has(row.objectType)
|
|
84336
|
-
),
|
|
84337
|
-
mergedObjectStates.filter(
|
|
84338
|
-
(row) => !skippedObjectTypes.has(row.objectType)
|
|
84339
|
-
)
|
|
84340
|
-
);
|
|
84341
|
-
const skippedStates = mergedObjectStates.filter(
|
|
84342
|
-
(row) => skippedObjectTypes.has(row.objectType)
|
|
84343
|
-
);
|
|
84344
|
-
if (skippedStates.length > 0) {
|
|
84345
|
-
await deleteRowsForObjectTypes(
|
|
84346
|
-
handle.connection,
|
|
84347
|
-
"property_definition_object_state",
|
|
84348
|
-
skippedStates.map((row) => row.objectType)
|
|
84349
|
-
);
|
|
84350
|
-
await bulkAppend(
|
|
84351
|
-
handle.connection,
|
|
84352
|
-
"property_definition_object_state",
|
|
84353
|
-
propertyDefinitionObjectStateRowsToColumns(skippedStates)
|
|
84354
|
-
);
|
|
84355
|
-
}
|
|
84356
|
-
});
|
|
84357
|
-
return { portalId };
|
|
84358
|
-
}
|
|
84359
84227
|
async function applyWorkflowDelta({
|
|
84360
84228
|
masterLock,
|
|
84361
84229
|
portalId,
|
|
@@ -84656,6 +84524,20 @@ async function evictDatabaseConnections(portalId) {
|
|
|
84656
84524
|
}
|
|
84657
84525
|
}
|
|
84658
84526
|
}
|
|
84527
|
+
async function evictReadOnlyDatabaseConnections(portalId) {
|
|
84528
|
+
const readOnlyCachePrefix = `${portalId}:read_only:`;
|
|
84529
|
+
const matchingEntries = [...databaseConnectionCache.entries()].filter(
|
|
84530
|
+
([cacheKey]) => cacheKey.startsWith(readOnlyCachePrefix)
|
|
84531
|
+
);
|
|
84532
|
+
for (const [cacheKey, handlePromise] of matchingEntries) {
|
|
84533
|
+
databaseConnectionCache.delete(cacheKey);
|
|
84534
|
+
try {
|
|
84535
|
+
const handle = await handlePromise;
|
|
84536
|
+
await closeDatabaseHandle(handle);
|
|
84537
|
+
} catch {
|
|
84538
|
+
}
|
|
84539
|
+
}
|
|
84540
|
+
}
|
|
84659
84541
|
|
|
84660
84542
|
// src/pure/query-sql.ts
|
|
84661
84543
|
var isWordCharacter = (char) => char !== void 0 && /[A-Za-z0-9_]/.test(char);
|
|
@@ -84767,6 +84649,7 @@ var resolveMasterLockDependencies = (config, defaults) => ({
|
|
|
84767
84649
|
|
|
84768
84650
|
// src/pure/master-lock-events.ts
|
|
84769
84651
|
var promotionListeners = /* @__PURE__ */ new Set();
|
|
84652
|
+
var demotionListeners = /* @__PURE__ */ new Set();
|
|
84770
84653
|
var onPromotedToMaster = (listener) => {
|
|
84771
84654
|
promotionListeners.add(listener);
|
|
84772
84655
|
return () => {
|
|
@@ -84782,6 +84665,21 @@ var emitPromotedToMaster = () => {
|
|
|
84782
84665
|
}
|
|
84783
84666
|
}
|
|
84784
84667
|
};
|
|
84668
|
+
var onDemotedToReadOnly = (listener) => {
|
|
84669
|
+
demotionListeners.add(listener);
|
|
84670
|
+
return () => {
|
|
84671
|
+
demotionListeners.delete(listener);
|
|
84672
|
+
};
|
|
84673
|
+
};
|
|
84674
|
+
var emitDemotedToReadOnly = () => {
|
|
84675
|
+
for (const listener of demotionListeners) {
|
|
84676
|
+
try {
|
|
84677
|
+
listener();
|
|
84678
|
+
} catch (error) {
|
|
84679
|
+
console.error("[master-lock] Demotion listener failed:", error);
|
|
84680
|
+
}
|
|
84681
|
+
}
|
|
84682
|
+
};
|
|
84785
84683
|
|
|
84786
84684
|
// src/layers/MasterLockLive.ts
|
|
84787
84685
|
var PROMOTION_POLL_MS = 3e3;
|
|
@@ -84832,6 +84730,7 @@ var handleCompromisedLease = (runtime, error) => pipe19(
|
|
|
84832
84730
|
`[master-lock] master lease compromised: ${error.message}`
|
|
84833
84731
|
),
|
|
84834
84732
|
Effect30.flatMap(() => Ref.set(runtime.connectionTypeRef, "READ_ONLY")),
|
|
84733
|
+
Effect30.tap(() => Effect30.sync(() => emitDemotedToReadOnly())),
|
|
84835
84734
|
Effect30.flatMap(() => startPromotionPolling(runtime))
|
|
84836
84735
|
);
|
|
84837
84736
|
})
|
|
@@ -85334,6 +85233,32 @@ var DuckDBInterfaceLiveBase = Layer4.effect(
|
|
|
85334
85233
|
}))
|
|
85335
85234
|
)
|
|
85336
85235
|
);
|
|
85236
|
+
const setMetadataWithoutReplica = (portalId, key2, value) => withPortalWritePermit(
|
|
85237
|
+
portalId,
|
|
85238
|
+
"setMetadataWithoutReplica",
|
|
85239
|
+
Effect32.orDie(
|
|
85240
|
+
Effect32.tryPromise({
|
|
85241
|
+
try: () => setPortalMetadata({
|
|
85242
|
+
masterLock: { isMaster: true },
|
|
85243
|
+
portalId,
|
|
85244
|
+
key: key2,
|
|
85245
|
+
value
|
|
85246
|
+
}),
|
|
85247
|
+
catch: (error) => error
|
|
85248
|
+
})
|
|
85249
|
+
)
|
|
85250
|
+
);
|
|
85251
|
+
const publishReplica2 = (input) => withPortalWritePermit(
|
|
85252
|
+
input.portalId,
|
|
85253
|
+
"publishReplica",
|
|
85254
|
+
Effect32.orDie(
|
|
85255
|
+
replica.syncReplica({
|
|
85256
|
+
portalId: input.portalId,
|
|
85257
|
+
reason: input.reason,
|
|
85258
|
+
mode: input.mode
|
|
85259
|
+
})
|
|
85260
|
+
)
|
|
85261
|
+
);
|
|
85337
85262
|
const syncObjectArtifact2 = (input) => withPortalWritePermit(
|
|
85338
85263
|
input.portalId,
|
|
85339
85264
|
"syncObjectArtifact",
|
|
@@ -85421,23 +85346,6 @@ var DuckDBInterfaceLiveBase = Layer4.effect(
|
|
|
85421
85346
|
}))
|
|
85422
85347
|
)
|
|
85423
85348
|
);
|
|
85424
|
-
const syncPropertyDefinitionsSnapshot2 = (input) => withPortalWritePermit(
|
|
85425
|
-
input.portalId,
|
|
85426
|
-
"syncPropertyDefinitionsSnapshot",
|
|
85427
|
-
Effect32.orDie(
|
|
85428
|
-
syncReplicaAfterWrite({
|
|
85429
|
-
portalId: input.portalId,
|
|
85430
|
-
reason: "syncPropertyDefinitionsSnapshot"
|
|
85431
|
-
}, Effect32.tryPromise({
|
|
85432
|
-
try: () => syncPropertyDefinitionsSnapshot({
|
|
85433
|
-
masterLock: { isMaster: true },
|
|
85434
|
-
portalId: input.portalId,
|
|
85435
|
-
snapshot: input.snapshot
|
|
85436
|
-
}),
|
|
85437
|
-
catch: (error) => error
|
|
85438
|
-
}))
|
|
85439
|
-
)
|
|
85440
|
-
);
|
|
85441
85349
|
const applyWorkflowDelta2 = (input) => withPortalWritePermit(
|
|
85442
85350
|
input.portalId,
|
|
85443
85351
|
"applyWorkflowDelta",
|
|
@@ -85555,12 +85463,13 @@ var DuckDBInterfaceLiveBase = Layer4.effect(
|
|
|
85555
85463
|
getPropertyDefinitionStateSummary: getPropertyDefinitionStateSummary2,
|
|
85556
85464
|
getWorkflowStateSummary: getWorkflowStateSummary2,
|
|
85557
85465
|
setMetadata: setMetadata2,
|
|
85466
|
+
setMetadataWithoutReplica,
|
|
85467
|
+
publishReplica: publishReplica2,
|
|
85558
85468
|
syncObjectArtifact: syncObjectArtifact2,
|
|
85559
85469
|
syncAssociationArtifact: syncAssociationArtifact2,
|
|
85560
85470
|
syncPlugin: syncPlugin2,
|
|
85561
85471
|
replaceWorkflowRows: replaceWorkflowRows2,
|
|
85562
85472
|
syncAssociationSchemaSnapshot: syncAssociationSchemaSnapshot2,
|
|
85563
|
-
syncPropertyDefinitionsSnapshot: syncPropertyDefinitionsSnapshot2,
|
|
85564
85473
|
applyWorkflowDelta: applyWorkflowDelta2,
|
|
85565
85474
|
applyPropertyDefinitionsDelta: applyPropertyDefinitionsDelta2,
|
|
85566
85475
|
applyDiffBatch: applyDiffBatch2,
|
|
@@ -85570,9 +85479,13 @@ var DuckDBInterfaceLiveBase = Layer4.effect(
|
|
|
85570
85479
|
})
|
|
85571
85480
|
)
|
|
85572
85481
|
);
|
|
85482
|
+
var SharedMasterLockLive = Layer4.orDie(MasterLockLive);
|
|
85483
|
+
var SharedReplicaLive = makeReplicaLive({
|
|
85484
|
+
masterLockLayer: SharedMasterLockLive
|
|
85485
|
+
});
|
|
85573
85486
|
var DuckDBInterfaceLive = pipe21(
|
|
85574
85487
|
DuckDBInterfaceLiveBase,
|
|
85575
|
-
Layer4.provide(Layer4.mergeAll(
|
|
85488
|
+
Layer4.provide(Layer4.mergeAll(SharedMasterLockLive, SharedReplicaLive))
|
|
85576
85489
|
);
|
|
85577
85490
|
|
|
85578
85491
|
// src/layers/FileDownloadLive.ts
|
|
@@ -86431,7 +86344,7 @@ var getReadConnection = (portalId, options8) => pipe25(
|
|
|
86431
86344
|
return openLiveConnection(portalId, error);
|
|
86432
86345
|
})
|
|
86433
86346
|
);
|
|
86434
|
-
var closeReadConnection = (portalId) => Effect37.promise(() =>
|
|
86347
|
+
var closeReadConnection = (portalId) => Effect37.promise(() => evictReadOnlyDatabaseConnections(portalId));
|
|
86435
86348
|
|
|
86436
86349
|
// src/layers/PortalFileStateLive.ts
|
|
86437
86350
|
import { Effect as Effect38, Layer as Layer6, pipe as pipe26 } from "effect";
|
|
@@ -87095,36 +87008,6 @@ var PortalDataLiveBase = Layer7.effect(
|
|
|
87095
87008
|
)
|
|
87096
87009
|
)
|
|
87097
87010
|
);
|
|
87098
|
-
const syncPropertyDefinitionsSnapshot2 = (input) => pipe27(
|
|
87099
|
-
requireMasterConnection(input.portalId, "syncPropertyDefinitionsSnapshot"),
|
|
87100
|
-
Effect39.flatMap(
|
|
87101
|
-
() => pipe27(
|
|
87102
|
-
duckDb.syncPropertyDefinitionsSnapshot({
|
|
87103
|
-
portalId: input.portalId,
|
|
87104
|
-
snapshot: input.snapshot
|
|
87105
|
-
}),
|
|
87106
|
-
Effect39.flatMap(
|
|
87107
|
-
() => duckDb.setMetadata(
|
|
87108
|
-
input.portalId,
|
|
87109
|
-
"last_synced:property_definitions",
|
|
87110
|
-
(/* @__PURE__ */ new Date()).toISOString()
|
|
87111
|
-
)
|
|
87112
|
-
),
|
|
87113
|
-
Effect39.flatMap(
|
|
87114
|
-
() => swallowPortalFileStateError(portalFileState.touchSyncedAt(input.portalId))
|
|
87115
|
-
),
|
|
87116
|
-
Effect39.map(() => ({
|
|
87117
|
-
portalId: input.portalId
|
|
87118
|
-
})),
|
|
87119
|
-
Effect39.catchAllCause(
|
|
87120
|
-
(cause) => toSyncFailure(
|
|
87121
|
-
`Failed to sync property definitions snapshot for portal ${input.portalId}`,
|
|
87122
|
-
cause
|
|
87123
|
-
)
|
|
87124
|
-
)
|
|
87125
|
-
)
|
|
87126
|
-
)
|
|
87127
|
-
);
|
|
87128
87011
|
const applyWorkflowDelta2 = (input) => pipe27(
|
|
87129
87012
|
requireMasterConnection(input.portalId, "applyWorkflowDelta"),
|
|
87130
87013
|
Effect39.flatMap(
|
|
@@ -87258,7 +87141,6 @@ var PortalDataLiveBase = Layer7.effect(
|
|
|
87258
87141
|
syncPluginPayload,
|
|
87259
87142
|
replaceWorkflowRows: replaceWorkflowRows2,
|
|
87260
87143
|
syncAssociationSchemaSnapshot: syncAssociationSchemaSnapshot2,
|
|
87261
|
-
syncPropertyDefinitionsSnapshot: syncPropertyDefinitionsSnapshot2,
|
|
87262
87144
|
applyWorkflowDelta: applyWorkflowDelta2,
|
|
87263
87145
|
applyPropertyDefinitionsDelta: applyPropertyDefinitionsDelta2,
|
|
87264
87146
|
applyDiffBatch: applyDiffBatch2,
|
|
@@ -88883,7 +88765,9 @@ Optional: pass portalIds to run the same query across one or more specific porta
|
|
|
88883
88765
|
|
|
88884
88766
|
Data freshness: enabled portals are automatically checked for freshness before querying. If portal sync is disabled, queries use stale local data when available and otherwise return an error.
|
|
88885
88767
|
|
|
88886
|
-
|
|
88768
|
+
IMPORTANT: the automatic freshness check covers artifact-backed CRM data, but it does NOT make lightweight message-plugin tables current. Before querying plugin-backed tables such as lists, owners, pipelines, forms, inboxes, or sequences when current values matter, first inspect status(section="schema"), call refresh_plugins if needed, and wait for replica-verified completion via status(section="schema") before running the query.
|
|
88769
|
+
|
|
88770
|
+
If your task depends on both artifact-backed data and plugin-backed metadata, refresh the plugin data first, wait for completion, then run the query.
|
|
88887
88771
|
|
|
88888
88772
|
IMPORTANT: Always use the 'status' tool with section "schema" first to discover available object types and property names before writing queries. Do not guess property names.
|
|
88889
88773
|
|
|
@@ -89246,7 +89130,7 @@ Optional: pass portalIds to run the same chart query across one or more specific
|
|
|
89246
89130
|
|
|
89247
89131
|
Data freshness: enabled portals are automatically checked for freshness before charting. If portal sync is disabled, charting uses stale local data when available and otherwise returns an error.
|
|
89248
89132
|
|
|
89249
|
-
|
|
89133
|
+
IMPORTANT: the automatic freshness check covers artifact-backed CRM data, but it does NOT automatically refresh lightweight message-plugin tables. Before charting plugin-backed tables such as lists, owners, pipelines, forms, inboxes, or sequences when current values matter, first inspect status(section="schema"), call refresh_plugins if needed, and wait for replica-verified completion via status(section="schema") before charting.
|
|
89250
89134
|
|
|
89251
89135
|
The query results map to the chart as follows:
|
|
89252
89136
|
- First column \u2192 X-axis labels (categories)
|
|
@@ -89422,6 +89306,7 @@ SELECT json_extract_string(properties, '$.dealstage') as stage, COUNT(*) as coun
|
|
|
89422
89306
|
import { z as z25 } from "zod";
|
|
89423
89307
|
import fs12 from "fs";
|
|
89424
89308
|
import { Effect as Effect66 } from "effect";
|
|
89309
|
+
var PLUGIN_SYNC_METADATA_PREFIX = "last_synced:plugin:";
|
|
89425
89310
|
function formatBytes(bytes) {
|
|
89426
89311
|
if (bytes === 0) return "0 B";
|
|
89427
89312
|
const units = ["B", "KB", "MB", "GB"];
|
|
@@ -89434,12 +89319,16 @@ function getDbFileSize(portalId) {
|
|
|
89434
89319
|
if (!fs12.existsSync(db2)) return null;
|
|
89435
89320
|
return fs12.statSync(db2).size;
|
|
89436
89321
|
}
|
|
89437
|
-
var buildLightweightPluginFreshnessSection = (portalState, now = Date.now()) => Object.fromEntries(
|
|
89322
|
+
var buildLightweightPluginFreshnessSection = (portalState, now = Date.now(), replicaPluginSyncMetadata = {}) => Object.fromEntries(
|
|
89438
89323
|
getMessagePlugins().map((plugin) => {
|
|
89439
89324
|
const pluginState = portalState?.plugins.find((entry) => entry.name === plugin.name) ?? null;
|
|
89440
|
-
const
|
|
89325
|
+
const replicaLastSynced = replicaPluginSyncMetadata[`${PLUGIN_SYNC_METADATA_PREFIX}${plugin.name}`] ?? null;
|
|
89326
|
+
const freshness = buildPluginFreshness(
|
|
89327
|
+
replicaLastSynced ?? pluginState?.lastSynced?.toISOString() ?? null,
|
|
89328
|
+
now
|
|
89329
|
+
);
|
|
89441
89330
|
return [plugin.name, {
|
|
89442
|
-
status: pluginState?.status ?? "NOT_STARTED",
|
|
89331
|
+
status: pluginState?.status ?? (replicaLastSynced === null ? "NOT_STARTED" : "SYNCED"),
|
|
89443
89332
|
error: pluginState?.error ?? null,
|
|
89444
89333
|
lastRefreshedAt: freshness.lastRefreshedAt,
|
|
89445
89334
|
ageMs: freshness.ageMs,
|
|
@@ -89447,6 +89336,29 @@ var buildLightweightPluginFreshnessSection = (portalState, now = Date.now()) =>
|
|
|
89447
89336
|
}];
|
|
89448
89337
|
})
|
|
89449
89338
|
);
|
|
89339
|
+
var isMissingSyncMetadataTableError2 = (error) => {
|
|
89340
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
89341
|
+
return message.includes("sync_metadata") && message.includes("does not exist");
|
|
89342
|
+
};
|
|
89343
|
+
var loadReplicaPluginSyncMetadata = async (conn) => {
|
|
89344
|
+
try {
|
|
89345
|
+
const reader = await conn.runAndReadAll(
|
|
89346
|
+
`SELECT key, value FROM sync_metadata WHERE key LIKE '${PLUGIN_SYNC_METADATA_PREFIX}%'`
|
|
89347
|
+
);
|
|
89348
|
+
const rows = reader.getRowObjects();
|
|
89349
|
+
const result = {};
|
|
89350
|
+
for (const row of rows) {
|
|
89351
|
+
if (typeof row.key !== "string" || typeof row.value !== "string") continue;
|
|
89352
|
+
result[row.key] = row.value;
|
|
89353
|
+
}
|
|
89354
|
+
return result;
|
|
89355
|
+
} catch (error) {
|
|
89356
|
+
if (isMissingSyncMetadataTableError2(error)) {
|
|
89357
|
+
return {};
|
|
89358
|
+
}
|
|
89359
|
+
throw error;
|
|
89360
|
+
}
|
|
89361
|
+
};
|
|
89450
89362
|
async function buildConnectionSection(deps) {
|
|
89451
89363
|
const selectedPortalId2 = deps.getSelectedPortalId();
|
|
89452
89364
|
const connectionState = deps.getConnectionState();
|
|
@@ -89489,7 +89401,12 @@ async function buildSchemaSection(portalId, deps) {
|
|
|
89489
89401
|
);
|
|
89490
89402
|
const allPluginTableNames = new Set(getAllTableNames());
|
|
89491
89403
|
const portalState = await deps.getPortalState(portalId);
|
|
89492
|
-
const
|
|
89404
|
+
const replicaPluginSyncMetadata = await loadReplicaPluginSyncMetadata(conn);
|
|
89405
|
+
const lightweightPlugins = buildLightweightPluginFreshnessSection(
|
|
89406
|
+
portalState,
|
|
89407
|
+
Date.now(),
|
|
89408
|
+
replicaPluginSyncMetadata
|
|
89409
|
+
);
|
|
89493
89410
|
const sectionResults = await Promise.all(
|
|
89494
89411
|
getPlugins().map(async (plugin) => {
|
|
89495
89412
|
try {
|
|
@@ -89563,6 +89480,10 @@ The schema output also includes lightweight plugin freshness data so you can see
|
|
|
89563
89480
|
|
|
89564
89481
|
Status output also includes active and recent lightweight plugin refresh jobs so callers can inspect queued, running, completed, or failed manual refresh requests without blocking on the initial tool call.
|
|
89565
89482
|
|
|
89483
|
+
Use status(section="schema") as the authoritative freshness gate for lightweight plugins. After calling refresh_plugins, poll status(section="schema") for the same portal until the matching refresh job is COMPLETED, none of the requested plugins are still QUEUED, RUNNING, or REPLICATING, and the requested plugins show updated replica-backed lastRefreshedAt values. COMPLETED means the executor verified the newly published read replica, not merely that remote execution finished. Do not proceed with plugin-dependent work before those conditions are met.
|
|
89484
|
+
|
|
89485
|
+
Artifact-backed CRM data and lightweight plugin metadata have different freshness rules. Artifact freshness is handled automatically for query/chart reads, but lightweight plugin freshness is not.
|
|
89486
|
+
|
|
89566
89487
|
Optional: pass portalIds to fetch schema status for specific portals. When portalIds is provided, schema output is a JSON object keyed by portal ID.
|
|
89567
89488
|
|
|
89568
89489
|
Data readiness: only portals with sync enabled are refreshed automatically. Disabled portals can still report schema from stale local data if a local DB already exists.
|
|
@@ -133956,6 +133877,8 @@ VIEWING THE PLAN:
|
|
|
133956
133877
|
|
|
133957
133878
|
IMPORTANT: After building the plan, present it to the user and ask for confirmation before calling submit_plan.
|
|
133958
133879
|
|
|
133880
|
+
When building operations that depend on current lightweight metadata or IDs from local tables, such as owners, lists, pipelines, forms, inboxes, or sequences, first ensure those plugin tables are fresh. Use status(section="schema") to inspect freshness, refresh_plugins to refresh the required plugin set, and wait for replica-verified completion with status(section="schema") before resolving IDs or constructing operations that depend on them.
|
|
133881
|
+
|
|
133959
133882
|
WORKFLOW:
|
|
133960
133883
|
1. describe_operations - Discover available operation types and their required fields
|
|
133961
133884
|
2. build_plan - Create draft with title, description, and operations
|
|
@@ -134614,11 +134537,17 @@ function registerRefreshPluginsTool(server2, deps) {
|
|
|
134614
134537
|
|
|
134615
134538
|
Lightweight plugins are not kept fresh automatically in real time. Their data may become stale until you explicitly refresh them with this tool.
|
|
134616
134539
|
|
|
134617
|
-
Use this when you need
|
|
134540
|
+
Use this when you need current lightweight metadata, such as lists, owners, pipelines, forms, inboxes, sequences, or other message-backed plugin data.
|
|
134541
|
+
|
|
134542
|
+
Before calling this tool, first determine the full set of plugin-backed metadata you will need for the task. Prefer a single refresh_plugins call with the union of all needed pluginNames rather than separate calls per plugin.
|
|
134618
134543
|
|
|
134619
134544
|
The requested pluginNames array is required. Optional portalIds lets you refresh the same plugins across multiple portals; otherwise the selected portal is used.
|
|
134620
134545
|
|
|
134621
|
-
This tool
|
|
134546
|
+
This tool starts an asynchronous refresh job and returns immediately. It does NOT wait for fresh data to be available.
|
|
134547
|
+
|
|
134548
|
+
After calling refresh_plugins, do not run any query, chart, or plan-building step that depends on those plugin tables until you confirm completion with status(section="schema"). Wait until the relevant refresh job is COMPLETED and the requested plugins show updated replica-backed freshness data. COMPLETED means the executor verified the newly published read replica, not merely that remote execution finished. If the job FAILED, surface the error instead of proceeding.
|
|
134549
|
+
|
|
134550
|
+
If the same plugin set is needed across multiple portals, prefer one call using portalIds. Use \`status\` to inspect in-flight and recent refresh jobs.`,
|
|
134622
134551
|
inputSchema: {
|
|
134623
134552
|
pluginNames: z97.array(z97.string()).min(1).describe("Required lightweight plugin names to refresh, for example ['lists', 'owners']."),
|
|
134624
134553
|
portalIds: z97.array(z97.number()).optional().describe("Optional explicit portal IDs to refresh. If omitted, the selected portal is used.")
|
|
@@ -134793,7 +134722,7 @@ var createPluginRefreshJobStore = () => {
|
|
|
134793
134722
|
error: payload.error ?? null,
|
|
134794
134723
|
coalescedRequests: 0,
|
|
134795
134724
|
plugins: buildPluginSnapshots(pluginNames),
|
|
134796
|
-
active: payload.status === "QUEUED" || payload.status === "RUNNING"
|
|
134725
|
+
active: payload.status === "QUEUED" || payload.status === "RUNNING" || payload.status === "REPLICATING"
|
|
134797
134726
|
};
|
|
134798
134727
|
job.portalId = payload.target_portal;
|
|
134799
134728
|
job.pluginNames = pluginNames;
|
|
@@ -134803,7 +134732,7 @@ var createPluginRefreshJobStore = () => {
|
|
|
134803
134732
|
job.startedAt = payload.started_at ?? job.startedAt ?? null;
|
|
134804
134733
|
job.finishedAt = payload.finished_at ?? (payload.status === "COMPLETED" || payload.status === "FAILED" ? (/* @__PURE__ */ new Date()).toISOString() : null);
|
|
134805
134734
|
job.error = payload.error ?? null;
|
|
134806
|
-
job.active = payload.status === "QUEUED" || payload.status === "RUNNING";
|
|
134735
|
+
job.active = payload.status === "QUEUED" || payload.status === "RUNNING" || payload.status === "REPLICATING";
|
|
134807
134736
|
const pluginMap = new Map(job.plugins.map((plugin) => [plugin.pluginName, plugin]));
|
|
134808
134737
|
for (const pluginName of pluginNames) {
|
|
134809
134738
|
if (!pluginMap.has(pluginName)) {
|
|
@@ -134897,6 +134826,72 @@ var createPluginRefreshJobStore = () => {
|
|
|
134897
134826
|
};
|
|
134898
134827
|
};
|
|
134899
134828
|
|
|
134829
|
+
// src/pure/manual-plugin-refresh-job.ts
|
|
134830
|
+
var earliestStartedAt = (plugins2) => plugins2.map((plugin) => plugin.startedAt).filter((value) => value !== null).sort()[0] ?? null;
|
|
134831
|
+
var finalizeManualPluginRefreshJob = async (input) => {
|
|
134832
|
+
const startedAt = earliestStartedAt(input.plugins);
|
|
134833
|
+
try {
|
|
134834
|
+
await input.prepareReplicaVerification();
|
|
134835
|
+
} catch (error) {
|
|
134836
|
+
const message = input.formatError(error);
|
|
134837
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
134838
|
+
await input.updateJobProgress({
|
|
134839
|
+
jobId: input.jobId,
|
|
134840
|
+
portalId: input.portalId,
|
|
134841
|
+
pluginNames: input.pluginNames,
|
|
134842
|
+
createdAt: input.createdAt,
|
|
134843
|
+
status: "FAILED",
|
|
134844
|
+
plugins: input.plugins,
|
|
134845
|
+
startedAt,
|
|
134846
|
+
finishedAt,
|
|
134847
|
+
error: message,
|
|
134848
|
+
relayToServer: input.relayToServer
|
|
134849
|
+
});
|
|
134850
|
+
return;
|
|
134851
|
+
}
|
|
134852
|
+
await input.updateJobProgress({
|
|
134853
|
+
jobId: input.jobId,
|
|
134854
|
+
portalId: input.portalId,
|
|
134855
|
+
pluginNames: input.pluginNames,
|
|
134856
|
+
createdAt: input.createdAt,
|
|
134857
|
+
status: "REPLICATING",
|
|
134858
|
+
plugins: input.plugins,
|
|
134859
|
+
startedAt,
|
|
134860
|
+
relayToServer: input.relayToServer
|
|
134861
|
+
});
|
|
134862
|
+
try {
|
|
134863
|
+
await input.publishReplica();
|
|
134864
|
+
await input.verifyReplica();
|
|
134865
|
+
} catch (error) {
|
|
134866
|
+
const message = input.formatError(error);
|
|
134867
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
134868
|
+
await input.updateJobProgress({
|
|
134869
|
+
jobId: input.jobId,
|
|
134870
|
+
portalId: input.portalId,
|
|
134871
|
+
pluginNames: input.pluginNames,
|
|
134872
|
+
createdAt: input.createdAt,
|
|
134873
|
+
status: "FAILED",
|
|
134874
|
+
plugins: input.plugins,
|
|
134875
|
+
startedAt,
|
|
134876
|
+
finishedAt,
|
|
134877
|
+
error: message,
|
|
134878
|
+
relayToServer: input.relayToServer
|
|
134879
|
+
});
|
|
134880
|
+
return;
|
|
134881
|
+
}
|
|
134882
|
+
await input.updateJobProgress({
|
|
134883
|
+
jobId: input.jobId,
|
|
134884
|
+
portalId: input.portalId,
|
|
134885
|
+
pluginNames: input.pluginNames,
|
|
134886
|
+
createdAt: input.createdAt,
|
|
134887
|
+
status: "COMPLETED",
|
|
134888
|
+
plugins: input.plugins,
|
|
134889
|
+
startedAt,
|
|
134890
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
134891
|
+
relayToServer: input.relayToServer
|
|
134892
|
+
});
|
|
134893
|
+
};
|
|
134894
|
+
|
|
134900
134895
|
// src/effects/ensure-fresh.ts
|
|
134901
134896
|
import fs20 from "fs";
|
|
134902
134897
|
var DEFAULT_QUEUE_DRAIN_TIMEOUT_MS = 12e4;
|
|
@@ -135293,6 +135288,7 @@ var STATUS_METADATA = {
|
|
|
135293
135288
|
};
|
|
135294
135289
|
var UPDATE_CHECK_TIMEOUT_MS = 2e3;
|
|
135295
135290
|
var UPDATE_CHECK_CACHE_TTL_MS = 5 * 6e4;
|
|
135291
|
+
var PLUGIN_REFRESH_VERIFICATION_PREFIX = "plugin_refresh_verification:";
|
|
135296
135292
|
var latestPackageVersionCache = null;
|
|
135297
135293
|
var fetchLatestPackageVersion = async (packageName) => {
|
|
135298
135294
|
const now = Date.now();
|
|
@@ -135368,6 +135364,26 @@ var mainProgram = Effect147.gen(function* () {
|
|
|
135368
135364
|
const isMasterClient = () => getConnectionType() === "MASTER";
|
|
135369
135365
|
const getSyncRole = () => isMasterClient() ? "master" : "read_only";
|
|
135370
135366
|
const formatErrorMessage2 = (error) => error instanceof Error ? error.message : String(error);
|
|
135367
|
+
const buildPluginRefreshVerificationKey = (jobId) => `${PLUGIN_REFRESH_VERIFICATION_PREFIX}${jobId}`;
|
|
135368
|
+
const buildStalePluginRefreshExecutorProgress = (jobId, portalId, pluginNames) => {
|
|
135369
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
135370
|
+
const error = `Rejected plugin refresh execute for portal ${portalId} because this client is read-only locally.`;
|
|
135371
|
+
return {
|
|
135372
|
+
job_id: jobId,
|
|
135373
|
+
target_portal: portalId,
|
|
135374
|
+
plugin_names: [...pluginNames],
|
|
135375
|
+
status: "FAILED",
|
|
135376
|
+
plugins: pluginNames.map((pluginName) => ({
|
|
135377
|
+
plugin_name: pluginName,
|
|
135378
|
+
status: "FAILED",
|
|
135379
|
+
error,
|
|
135380
|
+
finished_at: finishedAt
|
|
135381
|
+
})),
|
|
135382
|
+
created_at: finishedAt,
|
|
135383
|
+
finished_at: finishedAt,
|
|
135384
|
+
error
|
|
135385
|
+
};
|
|
135386
|
+
};
|
|
135371
135387
|
const logReadOnlySkip = (action, portalId) => {
|
|
135372
135388
|
const portalPart = portalId === void 0 ? "" : ` for portal ${portalId}`;
|
|
135373
135389
|
console.error(`[sync] Skipping ${action}${portalPart} on read-only client`);
|
|
@@ -135394,6 +135410,20 @@ var mainProgram = Effect147.gen(function* () {
|
|
|
135394
135410
|
syncRole: getSyncRole()
|
|
135395
135411
|
})
|
|
135396
135412
|
);
|
|
135413
|
+
const refreshRegistrationForConnectionTypeChange = (reason) => {
|
|
135414
|
+
scheduleRuntimeReconcile();
|
|
135415
|
+
Effect147.runFork(
|
|
135416
|
+
pipe122(
|
|
135417
|
+
Effect147.promise(() => syncRegistrationContext()),
|
|
135418
|
+
Effect147.flatMap(() => ws6.refreshRegistration()),
|
|
135419
|
+
Effect147.catchAll(
|
|
135420
|
+
(error) => Effect147.sync(() => {
|
|
135421
|
+
console.error(`[ws] Failed to refresh registration after ${reason}:`, error);
|
|
135422
|
+
})
|
|
135423
|
+
)
|
|
135424
|
+
)
|
|
135425
|
+
);
|
|
135426
|
+
};
|
|
135397
135427
|
const ensureFresh = makeEnsureFresh({
|
|
135398
135428
|
getSelectedPortalId: getPortalId,
|
|
135399
135429
|
isMasterClient,
|
|
@@ -135595,17 +135625,76 @@ var mainProgram = Effect147.gen(function* () {
|
|
|
135595
135625
|
const allDone = plugins2.every(
|
|
135596
135626
|
(plugin) => plugin.status === "SYNCED" || plugin.status === "PARTIAL" || plugin.status === "FAILED"
|
|
135597
135627
|
);
|
|
135598
|
-
|
|
135628
|
+
if (!allDone) {
|
|
135629
|
+
await updateJobProgress({
|
|
135630
|
+
jobId: input.jobId,
|
|
135631
|
+
portalId: input.portalId,
|
|
135632
|
+
pluginNames: input.pluginNames,
|
|
135633
|
+
createdAt: input.createdAt,
|
|
135634
|
+
status: "RUNNING",
|
|
135635
|
+
plugins: plugins2,
|
|
135636
|
+
startedAt: plugins2.map((plugin) => plugin.startedAt).filter((value) => value !== null).sort()[0] ?? null,
|
|
135637
|
+
relayToServer: input.relayToServer
|
|
135638
|
+
});
|
|
135639
|
+
return;
|
|
135640
|
+
}
|
|
135641
|
+
if (hasFailure) {
|
|
135642
|
+
await updateJobProgress({
|
|
135643
|
+
jobId: input.jobId,
|
|
135644
|
+
portalId: input.portalId,
|
|
135645
|
+
pluginNames: input.pluginNames,
|
|
135646
|
+
createdAt: input.createdAt,
|
|
135647
|
+
status: "FAILED",
|
|
135648
|
+
plugins: plugins2,
|
|
135649
|
+
startedAt: plugins2.map((plugin) => plugin.startedAt).filter((value) => value !== null).sort()[0] ?? null,
|
|
135650
|
+
finishedAt: now,
|
|
135651
|
+
error: plugins2.find((plugin) => plugin.status === "FAILED")?.error ?? null,
|
|
135652
|
+
relayToServer: input.relayToServer
|
|
135653
|
+
});
|
|
135654
|
+
return;
|
|
135655
|
+
}
|
|
135656
|
+
const verificationMarker = {
|
|
135657
|
+
key: buildPluginRefreshVerificationKey(input.jobId),
|
|
135658
|
+
value: (/* @__PURE__ */ new Date()).toISOString()
|
|
135659
|
+
};
|
|
135660
|
+
await finalizeManualPluginRefreshJob({
|
|
135599
135661
|
jobId: input.jobId,
|
|
135600
135662
|
portalId: input.portalId,
|
|
135601
135663
|
pluginNames: input.pluginNames,
|
|
135602
135664
|
createdAt: input.createdAt,
|
|
135603
|
-
status: allDone ? hasFailure ? "FAILED" : "COMPLETED" : "RUNNING",
|
|
135604
135665
|
plugins: plugins2,
|
|
135605
|
-
|
|
135606
|
-
|
|
135607
|
-
|
|
135608
|
-
|
|
135666
|
+
relayToServer: input.relayToServer,
|
|
135667
|
+
prepareReplicaVerification: async () => {
|
|
135668
|
+
await Effect147.runPromise(
|
|
135669
|
+
duckDb.setMetadataWithoutReplica(
|
|
135670
|
+
input.portalId,
|
|
135671
|
+
verificationMarker.key,
|
|
135672
|
+
verificationMarker.value
|
|
135673
|
+
)
|
|
135674
|
+
);
|
|
135675
|
+
},
|
|
135676
|
+
updateJobProgress,
|
|
135677
|
+
publishReplica: () => Effect147.runPromise(
|
|
135678
|
+
duckDb.publishReplica({
|
|
135679
|
+
portalId: input.portalId,
|
|
135680
|
+
reason: `manualPluginRefresh:${input.jobId}`,
|
|
135681
|
+
mode: "immediate"
|
|
135682
|
+
})
|
|
135683
|
+
),
|
|
135684
|
+
verifyReplica: async () => {
|
|
135685
|
+
await evictReadOnlyDatabaseConnections(input.portalId);
|
|
135686
|
+
const replicatedValue = await getPortalMetadata({
|
|
135687
|
+
portalId: input.portalId,
|
|
135688
|
+
key: verificationMarker.key,
|
|
135689
|
+
masterLock: { isMaster: false }
|
|
135690
|
+
});
|
|
135691
|
+
if (replicatedValue !== verificationMarker.value) {
|
|
135692
|
+
throw new Error(
|
|
135693
|
+
`Replica verification failed for portal ${input.portalId}: expected marker '${verificationMarker.key}' to equal '${verificationMarker.value}', got '${replicatedValue ?? "null"}'.`
|
|
135694
|
+
);
|
|
135695
|
+
}
|
|
135696
|
+
},
|
|
135697
|
+
formatError: formatErrorMessage2
|
|
135609
135698
|
});
|
|
135610
135699
|
}
|
|
135611
135700
|
});
|
|
@@ -135796,11 +135885,8 @@ var mainProgram = Effect147.gen(function* () {
|
|
|
135796
135885
|
const workflowsArtifactReady = portalState?.artifacts.some(
|
|
135797
135886
|
(artifact) => artifact.object_type === "workflows" && isArtifactBaselineReady(artifact.status)
|
|
135798
135887
|
) ?? false;
|
|
135799
|
-
const propertyDefinitionsArtifactReady = portalState?.artifacts.some(
|
|
135800
|
-
(artifact) => artifact.object_type === "property_definitions" && isArtifactBaselineReady(artifact.status)
|
|
135801
|
-
) ?? false;
|
|
135802
135888
|
const workflowBaselineReady = workflowStateResult.readable && (workflowLastSyncedAt !== null || workflowsArtifactReady);
|
|
135803
|
-
const propertyDefinitionBaselineReady = propertyDefinitionStateResult.readable &&
|
|
135889
|
+
const propertyDefinitionBaselineReady = propertyDefinitionStateResult.readable && propertyDefinitionLastSyncedAt !== null;
|
|
135804
135890
|
return {
|
|
135805
135891
|
clientUuid: clientState.clientUuid,
|
|
135806
135892
|
portalId,
|
|
@@ -136011,17 +136097,10 @@ var mainProgram = Effect147.gen(function* () {
|
|
|
136011
136097
|
scheduleRuntimeReconcile = runtimeReconciler.scheduleReconcile;
|
|
136012
136098
|
runtimeReconciler.startPolling();
|
|
136013
136099
|
onPromotedToMaster(() => {
|
|
136014
|
-
|
|
136015
|
-
|
|
136016
|
-
|
|
136017
|
-
|
|
136018
|
-
Effect147.catchAll(
|
|
136019
|
-
(error) => Effect147.sync(() => {
|
|
136020
|
-
console.error("[ws] Failed to refresh registration after promotion:", error);
|
|
136021
|
-
})
|
|
136022
|
-
)
|
|
136023
|
-
)
|
|
136024
|
-
);
|
|
136100
|
+
refreshRegistrationForConnectionTypeChange("promotion");
|
|
136101
|
+
});
|
|
136102
|
+
onDemotedToReadOnly(() => {
|
|
136103
|
+
refreshRegistrationForConnectionTypeChange("demotion");
|
|
136025
136104
|
});
|
|
136026
136105
|
runtimeReconciler.scheduleReconcile();
|
|
136027
136106
|
configureArtifactQueue(
|
|
@@ -136299,6 +136378,26 @@ var mainProgram = Effect147.gen(function* () {
|
|
|
136299
136378
|
onPluginRefreshExecute: (payload) => {
|
|
136300
136379
|
if (!isMasterClient()) {
|
|
136301
136380
|
logReadOnlySkip("plugin refresh execute", payload.target_portal);
|
|
136381
|
+
refreshRegistrationForConnectionTypeChange("demotion");
|
|
136382
|
+
Effect147.runFork(
|
|
136383
|
+
pipe122(
|
|
136384
|
+
ws6.sendPluginRefreshProgress(
|
|
136385
|
+
buildStalePluginRefreshExecutorProgress(
|
|
136386
|
+
payload.job_id,
|
|
136387
|
+
payload.target_portal,
|
|
136388
|
+
payload.plugin_names
|
|
136389
|
+
)
|
|
136390
|
+
),
|
|
136391
|
+
Effect147.catchAll(
|
|
136392
|
+
(error) => Effect147.sync(() => {
|
|
136393
|
+
console.error(
|
|
136394
|
+
`[plugin-refresh] Failed to reject stale executor for portal ${payload.target_portal}:`,
|
|
136395
|
+
error
|
|
136396
|
+
);
|
|
136397
|
+
})
|
|
136398
|
+
)
|
|
136399
|
+
)
|
|
136400
|
+
);
|
|
136302
136401
|
return;
|
|
136303
136402
|
}
|
|
136304
136403
|
const existing = refreshJobStore.getSnapshot(payload.job_id);
|