@tomflow/proflow-execution-browser-extension 0.1.48 → 0.1.50
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 +7 -0
- package/dist/deployment/adapter.d.ts +10 -10
- package/dist/deployment/descriptor.d.ts +1 -1
- package/dist/deployment/descriptor.js +1 -1
- package/dist/extension/background.js +106 -8
- package/dist/src/observer-recovery-rearm.d.ts +4 -0
- package/dist/src/observer-recovery-rearm.js +23 -0
- package/extension/background.ts +96 -14
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/proflow.module.json +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @tomflow/proflow-execution-browser-extension
|
|
2
|
+
|
|
3
|
+
## 0.1.50
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Preserve Observer recovery demand while a recovery pass is already in flight by coalescing reconnect, retry, and recovery requests into one trailing pass, without introducing concurrent recovery or stale retry replay.
|
|
@@ -53,7 +53,7 @@ export declare const behaviorAdapter: {
|
|
|
53
53
|
ok: true;
|
|
54
54
|
status: "SUCCEEDED";
|
|
55
55
|
moduleRef: "execution-browser-extension";
|
|
56
|
-
moduleVersion: "0.1.
|
|
56
|
+
moduleVersion: "0.1.50";
|
|
57
57
|
data: {
|
|
58
58
|
loadDir: string;
|
|
59
59
|
};
|
|
@@ -66,7 +66,7 @@ export declare const behaviorAdapter: {
|
|
|
66
66
|
readonly ok: true;
|
|
67
67
|
readonly status: "SUCCEEDED";
|
|
68
68
|
readonly moduleRef: "execution-browser-extension";
|
|
69
|
-
readonly moduleVersion: "0.1.
|
|
69
|
+
readonly moduleVersion: "0.1.50";
|
|
70
70
|
};
|
|
71
71
|
observedEffects: never[];
|
|
72
72
|
}>;
|
|
@@ -76,7 +76,7 @@ export declare const behaviorAdapter: {
|
|
|
76
76
|
ok: true;
|
|
77
77
|
status: "SUCCEEDED";
|
|
78
78
|
moduleRef: "execution-browser-extension";
|
|
79
|
-
moduleVersion: "0.1.
|
|
79
|
+
moduleVersion: "0.1.50";
|
|
80
80
|
data: {
|
|
81
81
|
setupStatus: "ACTION_REQUIRED" | "READY";
|
|
82
82
|
runtimeStatus: "NOT_APPLICABLE";
|
|
@@ -101,7 +101,7 @@ export declare const behaviorAdapter: {
|
|
|
101
101
|
result: {
|
|
102
102
|
contract: "deployment.result.v1";
|
|
103
103
|
moduleRef: "execution-browser-extension";
|
|
104
|
-
moduleVersion: "0.1.
|
|
104
|
+
moduleVersion: "0.1.50";
|
|
105
105
|
ok: false;
|
|
106
106
|
status: "ACTION_REQUIRED";
|
|
107
107
|
data: {
|
|
@@ -133,14 +133,14 @@ export declare const behaviorAdapter: {
|
|
|
133
133
|
readonly ok: true;
|
|
134
134
|
readonly status: "SUCCEEDED";
|
|
135
135
|
readonly moduleRef: "execution-browser-extension";
|
|
136
|
-
readonly moduleVersion: "0.1.
|
|
136
|
+
readonly moduleVersion: "0.1.50";
|
|
137
137
|
};
|
|
138
138
|
observedEffects: string[];
|
|
139
139
|
} | {
|
|
140
140
|
result: {
|
|
141
141
|
contract: "deployment.result.v1";
|
|
142
142
|
moduleRef: "execution-browser-extension";
|
|
143
|
-
moduleVersion: "0.1.
|
|
143
|
+
moduleVersion: "0.1.50";
|
|
144
144
|
ok: false;
|
|
145
145
|
status: "FAILED";
|
|
146
146
|
error: {
|
|
@@ -173,7 +173,7 @@ export declare const behaviorAdapter: {
|
|
|
173
173
|
ok: true;
|
|
174
174
|
status: "SUCCEEDED";
|
|
175
175
|
moduleRef: "execution-browser-extension";
|
|
176
|
-
moduleVersion: "0.1.
|
|
176
|
+
moduleVersion: "0.1.50";
|
|
177
177
|
data: {
|
|
178
178
|
docs: string;
|
|
179
179
|
};
|
|
@@ -186,11 +186,11 @@ export declare const behaviorAdapter: {
|
|
|
186
186
|
readonly ok: true;
|
|
187
187
|
readonly status: "SUCCEEDED";
|
|
188
188
|
readonly moduleRef: "execution-browser-extension";
|
|
189
|
-
readonly moduleVersion: "0.1.
|
|
189
|
+
readonly moduleVersion: "0.1.50";
|
|
190
190
|
} | {
|
|
191
191
|
contract: "deployment.result.v1";
|
|
192
192
|
moduleRef: "execution-browser-extension";
|
|
193
|
-
moduleVersion: "0.1.
|
|
193
|
+
moduleVersion: "0.1.50";
|
|
194
194
|
ok: false;
|
|
195
195
|
status: "FAILED";
|
|
196
196
|
error: {
|
|
@@ -207,7 +207,7 @@ export declare const behaviorAdapter: {
|
|
|
207
207
|
readonly ok: true;
|
|
208
208
|
readonly status: "SUCCEEDED";
|
|
209
209
|
readonly moduleRef: "execution-browser-extension";
|
|
210
|
-
readonly moduleVersion: "0.1.
|
|
210
|
+
readonly moduleVersion: "0.1.50";
|
|
211
211
|
};
|
|
212
212
|
observedEffects: never[];
|
|
213
213
|
}>;
|
|
@@ -3,7 +3,7 @@ export declare const descriptor: {
|
|
|
3
3
|
readonly contractVersion: "1.0.0";
|
|
4
4
|
readonly moduleRef: "execution-browser-extension";
|
|
5
5
|
readonly packageName: "@tomflow/proflow-execution-browser-extension";
|
|
6
|
-
readonly moduleVersion: "0.1.
|
|
6
|
+
readonly moduleVersion: "0.1.50";
|
|
7
7
|
readonly kind: "browser-extension";
|
|
8
8
|
readonly templateVersion: "1.0.0";
|
|
9
9
|
readonly platformCompatibility: ">=1.0.0 <2.0.0";
|
|
@@ -3,7 +3,7 @@ export const descriptor = {
|
|
|
3
3
|
contractVersion: "1.0.0",
|
|
4
4
|
moduleRef: "execution-browser-extension",
|
|
5
5
|
packageName: "@tomflow/proflow-execution-browser-extension",
|
|
6
|
-
moduleVersion: "0.1.
|
|
6
|
+
moduleVersion: "0.1.50",
|
|
7
7
|
kind: "browser-extension",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
|
@@ -13843,6 +13843,29 @@ function createCollaborationCarrierApplication(options) {
|
|
|
13843
13843
|
return Object.freeze({ deliverMessage, recoverPending });
|
|
13844
13844
|
}
|
|
13845
13845
|
|
|
13846
|
+
// packages/execution-browser-extension/src/observer-recovery-rearm.ts
|
|
13847
|
+
function createObserverRecoveryRearm(recover) {
|
|
13848
|
+
let startupReady = false;
|
|
13849
|
+
let latestBridgeSessionEpoch = 0;
|
|
13850
|
+
const startupReadyAfterDenialRestore = () => {
|
|
13851
|
+
startupReady = true;
|
|
13852
|
+
recover();
|
|
13853
|
+
};
|
|
13854
|
+
const bridgeSessionEstablished = (epoch) => {
|
|
13855
|
+
if (!Number.isInteger(epoch) || epoch <= 0)
|
|
13856
|
+
throw new TypeError("bridge session epoch must be a positive integer");
|
|
13857
|
+
if (epoch <= latestBridgeSessionEpoch) return false;
|
|
13858
|
+
latestBridgeSessionEpoch = epoch;
|
|
13859
|
+
if (!startupReady) return false;
|
|
13860
|
+
recover();
|
|
13861
|
+
return true;
|
|
13862
|
+
};
|
|
13863
|
+
return Object.freeze({
|
|
13864
|
+
startupReady: startupReadyAfterDenialRestore,
|
|
13865
|
+
bridgeSessionEstablished
|
|
13866
|
+
});
|
|
13867
|
+
}
|
|
13868
|
+
|
|
13846
13869
|
// packages/execution-browser-extension/src/recovery-trigger.ts
|
|
13847
13870
|
async function boundedRecoveryObservation(observe, timeoutMs) {
|
|
13848
13871
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
@@ -14412,6 +14435,16 @@ async function emitStructuredLog(entry) {
|
|
|
14412
14435
|
body: JSON.stringify({ timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...entry })
|
|
14413
14436
|
}).catch(() => void 0);
|
|
14414
14437
|
}
|
|
14438
|
+
function emitObserverRecoveryDiagnostic(status, attemptNo, operationRef) {
|
|
14439
|
+
void emitStructuredLog({
|
|
14440
|
+
level: "INFO",
|
|
14441
|
+
component: "browser-observer-recovery",
|
|
14442
|
+
operation: "observer.recovery",
|
|
14443
|
+
status,
|
|
14444
|
+
attemptNo,
|
|
14445
|
+
operationRef
|
|
14446
|
+
}).catch(() => void 0);
|
|
14447
|
+
}
|
|
14415
14448
|
async function invokeObserverApplication(operation, input) {
|
|
14416
14449
|
const config2 = await taskApplicationConfig();
|
|
14417
14450
|
if (!config2) throw new Error("OBSERVER_APPLICATION_NOT_CONFIGURED");
|
|
@@ -14512,9 +14545,23 @@ var collaborationCarrier = createCollaborationCarrierApplication({
|
|
|
14512
14545
|
},
|
|
14513
14546
|
agent: {
|
|
14514
14547
|
async listPendingMessages(limit) {
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
|
|
14548
|
+
const recoveryTriggerRef = `bridge-session:${bridgeSessionEpoch}`;
|
|
14549
|
+
emitObserverRecoveryDiagnostic(
|
|
14550
|
+
"COLLABORATION_LIST_PENDING_BEGIN",
|
|
14551
|
+
observerRecoveryAttemptNo,
|
|
14552
|
+
recoveryTriggerRef
|
|
14553
|
+
);
|
|
14554
|
+
try {
|
|
14555
|
+
return await invokeObserverApplication("collaboration.listPending", {
|
|
14556
|
+
limit
|
|
14557
|
+
});
|
|
14558
|
+
} finally {
|
|
14559
|
+
emitObserverRecoveryDiagnostic(
|
|
14560
|
+
"COLLABORATION_LIST_PENDING_SETTLED",
|
|
14561
|
+
observerRecoveryAttemptNo,
|
|
14562
|
+
recoveryTriggerRef
|
|
14563
|
+
);
|
|
14564
|
+
}
|
|
14518
14565
|
},
|
|
14519
14566
|
async getPendingMessage(messageRef) {
|
|
14520
14567
|
return await invokeObserverApplication("collaboration.getPending", {
|
|
@@ -14589,18 +14636,46 @@ async function persistSystemObserverState(result) {
|
|
|
14589
14636
|
});
|
|
14590
14637
|
}
|
|
14591
14638
|
var observerRecoveryInFlight = null;
|
|
14639
|
+
var observerRecoveryTrailingRequested = false;
|
|
14592
14640
|
var observerRecoveryRetryCount = 0;
|
|
14641
|
+
var observerRecoveryAttemptNo = 0;
|
|
14593
14642
|
var nextRecoverySuppressions = [];
|
|
14594
14643
|
function suppressNextObserverRecovery(denials) {
|
|
14595
14644
|
nextRecoverySuppressions = denials;
|
|
14596
14645
|
}
|
|
14597
14646
|
function runObserverRecovery() {
|
|
14598
|
-
|
|
14647
|
+
const recoveryTriggerRef = `bridge-session:${bridgeSessionEpoch}`;
|
|
14648
|
+
if (observerRecoveryInFlight) {
|
|
14649
|
+
observerRecoveryTrailingRequested = true;
|
|
14650
|
+
emitObserverRecoveryDiagnostic(
|
|
14651
|
+
"REUSED_IN_FLIGHT",
|
|
14652
|
+
observerRecoveryAttemptNo,
|
|
14653
|
+
recoveryTriggerRef
|
|
14654
|
+
);
|
|
14655
|
+
return observerRecoveryInFlight;
|
|
14656
|
+
}
|
|
14657
|
+
observerRecoveryAttemptNo += 1;
|
|
14658
|
+
const recoveryAttemptNo = observerRecoveryAttemptNo;
|
|
14659
|
+
emitObserverRecoveryDiagnostic(
|
|
14660
|
+
"STARTED",
|
|
14661
|
+
recoveryAttemptNo,
|
|
14662
|
+
recoveryTriggerRef
|
|
14663
|
+
);
|
|
14599
14664
|
const suppressedContinuations = nextRecoverySuppressions;
|
|
14600
14665
|
nextRecoverySuppressions = [];
|
|
14601
14666
|
observerRecoveryInFlight = (async () => {
|
|
14602
14667
|
let recoveryNeedsRetry = false;
|
|
14668
|
+
emitObserverRecoveryDiagnostic(
|
|
14669
|
+
"COLLABORATION_RECOVERY_BEGIN",
|
|
14670
|
+
recoveryAttemptNo,
|
|
14671
|
+
recoveryTriggerRef
|
|
14672
|
+
);
|
|
14603
14673
|
await collaborationCarrier.recoverPending(50).catch(() => void 0);
|
|
14674
|
+
emitObserverRecoveryDiagnostic(
|
|
14675
|
+
"COLLABORATION_RECOVERY_SETTLED",
|
|
14676
|
+
recoveryAttemptNo,
|
|
14677
|
+
recoveryTriggerRef
|
|
14678
|
+
);
|
|
14604
14679
|
const signalBatch = await invokeObserverApplication(
|
|
14605
14680
|
"execution.listSignals",
|
|
14606
14681
|
{ limit: 50 }
|
|
@@ -14676,7 +14751,11 @@ function runObserverRecovery() {
|
|
|
14676
14751
|
}
|
|
14677
14752
|
if (recoveryNeedsRetry && observerRecoveryRetryCount < 6) {
|
|
14678
14753
|
observerRecoveryRetryCount += 1;
|
|
14679
|
-
|
|
14754
|
+
const retryScheduledFromAttemptNo = recoveryAttemptNo;
|
|
14755
|
+
setTimeout(() => {
|
|
14756
|
+
if (observerRecoveryAttemptNo !== retryScheduledFromAttemptNo) return;
|
|
14757
|
+
void runObserverRecovery();
|
|
14758
|
+
}, 2e3);
|
|
14680
14759
|
} else if (!recoveryNeedsRetry) {
|
|
14681
14760
|
observerRecoveryRetryCount = 0;
|
|
14682
14761
|
}
|
|
@@ -14692,9 +14771,20 @@ function runObserverRecovery() {
|
|
|
14692
14771
|
}
|
|
14693
14772
|
})().finally(() => {
|
|
14694
14773
|
observerRecoveryInFlight = null;
|
|
14774
|
+
if (!observerRecoveryTrailingRequested) return;
|
|
14775
|
+
observerRecoveryTrailingRequested = false;
|
|
14776
|
+
void runObserverRecovery();
|
|
14695
14777
|
});
|
|
14696
14778
|
return observerRecoveryInFlight;
|
|
14697
14779
|
}
|
|
14780
|
+
var observerRecoveryRearm = createObserverRecoveryRearm(() => {
|
|
14781
|
+
emitObserverRecoveryDiagnostic(
|
|
14782
|
+
"REARM_CALLBACK_ENTERED",
|
|
14783
|
+
bridgeSessionEpoch,
|
|
14784
|
+
`bridge-session:${bridgeSessionEpoch}`
|
|
14785
|
+
);
|
|
14786
|
+
void runObserverRecovery();
|
|
14787
|
+
});
|
|
14698
14788
|
function observationFor(tabId) {
|
|
14699
14789
|
const observed = sessions.get(tabId);
|
|
14700
14790
|
if (!observed) throw new Error("CONTENT_SESSION_NOT_READY");
|
|
@@ -15274,6 +15364,7 @@ async function bridgeFetch(config2, path, init = {}) {
|
|
|
15274
15364
|
});
|
|
15275
15365
|
}
|
|
15276
15366
|
var bridgeLoopStarted = false;
|
|
15367
|
+
var bridgeSessionEpoch = 0;
|
|
15277
15368
|
async function runBridgeLoop() {
|
|
15278
15369
|
if (bridgeLoopStarted) return;
|
|
15279
15370
|
bridgeLoopStarted = true;
|
|
@@ -15294,6 +15385,13 @@ async function runBridgeLoop() {
|
|
|
15294
15385
|
})
|
|
15295
15386
|
});
|
|
15296
15387
|
if (!hello.ok) throw new Error("BRIDGE_HELLO_REJECTED");
|
|
15388
|
+
bridgeSessionEpoch += 1;
|
|
15389
|
+
emitObserverRecoveryDiagnostic(
|
|
15390
|
+
"BRIDGE_EPOCH_ACCEPTED",
|
|
15391
|
+
bridgeSessionEpoch,
|
|
15392
|
+
`bridge-session:${bridgeSessionEpoch}`
|
|
15393
|
+
);
|
|
15394
|
+
observerRecoveryRearm.bridgeSessionEstablished(bridgeSessionEpoch);
|
|
15297
15395
|
await publishCarrierAttentions();
|
|
15298
15396
|
let lastHeartbeatAt = Date.now();
|
|
15299
15397
|
let lastExtensionKeepaliveAt = Date.now();
|
|
@@ -15627,7 +15725,7 @@ async function startBackgroundRuntime() {
|
|
|
15627
15725
|
void runProvisioningBridgeLoop();
|
|
15628
15726
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
15629
15727
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
15630
|
-
|
|
15728
|
+
observerRecoveryRearm.startupReady();
|
|
15631
15729
|
}
|
|
15632
15730
|
chrome.action.onClicked.addListener(() => {
|
|
15633
15731
|
void openTaskPage();
|
|
@@ -15639,7 +15737,7 @@ chrome.runtime.onInstalled.addListener(() => {
|
|
|
15639
15737
|
void runBridgeLoop();
|
|
15640
15738
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
15641
15739
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
15642
|
-
|
|
15740
|
+
observerRecoveryRearm.startupReady();
|
|
15643
15741
|
});
|
|
15644
15742
|
});
|
|
15645
15743
|
chrome.runtime.onStartup.addListener(() => {
|
|
@@ -15650,7 +15748,7 @@ chrome.runtime.onStartup.addListener(() => {
|
|
|
15650
15748
|
void runBridgeLoop();
|
|
15651
15749
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
15652
15750
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
15653
|
-
|
|
15751
|
+
observerRecoveryRearm.startupReady();
|
|
15654
15752
|
});
|
|
15655
15753
|
});
|
|
15656
15754
|
void startBackgroundRuntime();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function createObserverRecoveryRearm(recover) {
|
|
2
|
+
let startupReady = false;
|
|
3
|
+
let latestBridgeSessionEpoch = 0;
|
|
4
|
+
const startupReadyAfterDenialRestore = () => {
|
|
5
|
+
startupReady = true;
|
|
6
|
+
recover();
|
|
7
|
+
};
|
|
8
|
+
const bridgeSessionEstablished = (epoch) => {
|
|
9
|
+
if (!Number.isInteger(epoch) || epoch <= 0)
|
|
10
|
+
throw new TypeError("bridge session epoch must be a positive integer");
|
|
11
|
+
if (epoch <= latestBridgeSessionEpoch)
|
|
12
|
+
return false;
|
|
13
|
+
latestBridgeSessionEpoch = epoch;
|
|
14
|
+
if (!startupReady)
|
|
15
|
+
return false;
|
|
16
|
+
recover();
|
|
17
|
+
return true;
|
|
18
|
+
};
|
|
19
|
+
return Object.freeze({
|
|
20
|
+
startupReady: startupReadyAfterDenialRestore,
|
|
21
|
+
bridgeSessionEstablished,
|
|
22
|
+
});
|
|
23
|
+
}
|
package/extension/background.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
resolveRoutineCarrierPermission,
|
|
19
19
|
} from "../src/carrier-permission-lifecycle.js";
|
|
20
20
|
import { createCollaborationCarrierApplication } from "../src/collaboration-carrier.js";
|
|
21
|
+
import { createObserverRecoveryRearm } from "../src/observer-recovery-rearm.js";
|
|
21
22
|
import {
|
|
22
23
|
boundedRecoveryObservation,
|
|
23
24
|
shouldTriggerObserverRecovery,
|
|
@@ -472,6 +473,21 @@ async function emitStructuredLog(entry: BrowserStructuredLogEntry) {
|
|
|
472
473
|
}).catch(() => undefined);
|
|
473
474
|
}
|
|
474
475
|
|
|
476
|
+
function emitObserverRecoveryDiagnostic(
|
|
477
|
+
status: string,
|
|
478
|
+
attemptNo: number,
|
|
479
|
+
operationRef: string,
|
|
480
|
+
): void {
|
|
481
|
+
void emitStructuredLog({
|
|
482
|
+
level: "INFO",
|
|
483
|
+
component: "browser-observer-recovery",
|
|
484
|
+
operation: "observer.recovery",
|
|
485
|
+
status,
|
|
486
|
+
attemptNo,
|
|
487
|
+
operationRef,
|
|
488
|
+
}).catch(() => undefined);
|
|
489
|
+
}
|
|
490
|
+
|
|
475
491
|
async function invokeObserverApplication(
|
|
476
492
|
operation: string,
|
|
477
493
|
input: Record<string, unknown>,
|
|
@@ -598,15 +614,29 @@ const collaborationCarrier = createCollaborationCarrierApplication({
|
|
|
598
614
|
},
|
|
599
615
|
agent: {
|
|
600
616
|
async listPendingMessages(limit) {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
617
|
+
const recoveryTriggerRef = `bridge-session:${bridgeSessionEpoch}`;
|
|
618
|
+
emitObserverRecoveryDiagnostic(
|
|
619
|
+
"COLLABORATION_LIST_PENDING_BEGIN",
|
|
620
|
+
observerRecoveryAttemptNo,
|
|
621
|
+
recoveryTriggerRef,
|
|
622
|
+
);
|
|
623
|
+
try {
|
|
624
|
+
return (await invokeObserverApplication("collaboration.listPending", {
|
|
625
|
+
limit,
|
|
626
|
+
})) as Awaited<
|
|
627
|
+
ReturnType<
|
|
628
|
+
Parameters<
|
|
629
|
+
typeof createCollaborationCarrierApplication
|
|
630
|
+
>[0]["agent"]["listPendingMessages"]
|
|
631
|
+
>
|
|
632
|
+
>;
|
|
633
|
+
} finally {
|
|
634
|
+
emitObserverRecoveryDiagnostic(
|
|
635
|
+
"COLLABORATION_LIST_PENDING_SETTLED",
|
|
636
|
+
observerRecoveryAttemptNo,
|
|
637
|
+
recoveryTriggerRef,
|
|
638
|
+
);
|
|
639
|
+
}
|
|
610
640
|
},
|
|
611
641
|
async getPendingMessage(messageRef) {
|
|
612
642
|
return (await invokeObserverApplication("collaboration.getPending", {
|
|
@@ -720,7 +750,9 @@ async function persistSystemObserverState(
|
|
|
720
750
|
}
|
|
721
751
|
|
|
722
752
|
let observerRecoveryInFlight: Promise<void> | null = null;
|
|
753
|
+
let observerRecoveryTrailingRequested = false;
|
|
723
754
|
let observerRecoveryRetryCount = 0;
|
|
755
|
+
let observerRecoveryAttemptNo = 0;
|
|
724
756
|
let nextRecoverySuppressions: readonly CarrierContinuationDenial[] = [];
|
|
725
757
|
function suppressNextObserverRecovery(
|
|
726
758
|
denials: readonly CarrierContinuationDenial[],
|
|
@@ -728,12 +760,38 @@ function suppressNextObserverRecovery(
|
|
|
728
760
|
nextRecoverySuppressions = denials;
|
|
729
761
|
}
|
|
730
762
|
function runObserverRecovery() {
|
|
731
|
-
|
|
763
|
+
const recoveryTriggerRef = `bridge-session:${bridgeSessionEpoch}`;
|
|
764
|
+
if (observerRecoveryInFlight) {
|
|
765
|
+
observerRecoveryTrailingRequested = true;
|
|
766
|
+
emitObserverRecoveryDiagnostic(
|
|
767
|
+
"REUSED_IN_FLIGHT",
|
|
768
|
+
observerRecoveryAttemptNo,
|
|
769
|
+
recoveryTriggerRef,
|
|
770
|
+
);
|
|
771
|
+
return observerRecoveryInFlight;
|
|
772
|
+
}
|
|
773
|
+
observerRecoveryAttemptNo += 1;
|
|
774
|
+
const recoveryAttemptNo = observerRecoveryAttemptNo;
|
|
775
|
+
emitObserverRecoveryDiagnostic(
|
|
776
|
+
"STARTED",
|
|
777
|
+
recoveryAttemptNo,
|
|
778
|
+
recoveryTriggerRef,
|
|
779
|
+
);
|
|
732
780
|
const suppressedContinuations = nextRecoverySuppressions;
|
|
733
781
|
nextRecoverySuppressions = [];
|
|
734
782
|
observerRecoveryInFlight = (async () => {
|
|
735
783
|
let recoveryNeedsRetry = false;
|
|
784
|
+
emitObserverRecoveryDiagnostic(
|
|
785
|
+
"COLLABORATION_RECOVERY_BEGIN",
|
|
786
|
+
recoveryAttemptNo,
|
|
787
|
+
recoveryTriggerRef,
|
|
788
|
+
);
|
|
736
789
|
await collaborationCarrier.recoverPending(50).catch(() => undefined);
|
|
790
|
+
emitObserverRecoveryDiagnostic(
|
|
791
|
+
"COLLABORATION_RECOVERY_SETTLED",
|
|
792
|
+
recoveryAttemptNo,
|
|
793
|
+
recoveryTriggerRef,
|
|
794
|
+
);
|
|
737
795
|
const signalBatch = await invokeObserverApplication(
|
|
738
796
|
"execution.listSignals",
|
|
739
797
|
{ limit: 50 },
|
|
@@ -845,7 +903,11 @@ function runObserverRecovery() {
|
|
|
845
903
|
// remains the no-blind-replay authority for APPLIED/NOT_APPLIED/UNKNOWN.
|
|
846
904
|
if (recoveryNeedsRetry && observerRecoveryRetryCount < 6) {
|
|
847
905
|
observerRecoveryRetryCount += 1;
|
|
848
|
-
|
|
906
|
+
const retryScheduledFromAttemptNo = recoveryAttemptNo;
|
|
907
|
+
setTimeout(() => {
|
|
908
|
+
if (observerRecoveryAttemptNo !== retryScheduledFromAttemptNo) return;
|
|
909
|
+
void runObserverRecovery();
|
|
910
|
+
}, 2_000);
|
|
849
911
|
} else if (!recoveryNeedsRetry) {
|
|
850
912
|
observerRecoveryRetryCount = 0;
|
|
851
913
|
}
|
|
@@ -863,10 +925,22 @@ function runObserverRecovery() {
|
|
|
863
925
|
}
|
|
864
926
|
})().finally(() => {
|
|
865
927
|
observerRecoveryInFlight = null;
|
|
928
|
+
if (!observerRecoveryTrailingRequested) return;
|
|
929
|
+
observerRecoveryTrailingRequested = false;
|
|
930
|
+
void runObserverRecovery();
|
|
866
931
|
});
|
|
867
932
|
return observerRecoveryInFlight;
|
|
868
933
|
}
|
|
869
934
|
|
|
935
|
+
const observerRecoveryRearm = createObserverRecoveryRearm(() => {
|
|
936
|
+
emitObserverRecoveryDiagnostic(
|
|
937
|
+
"REARM_CALLBACK_ENTERED",
|
|
938
|
+
bridgeSessionEpoch,
|
|
939
|
+
`bridge-session:${bridgeSessionEpoch}`,
|
|
940
|
+
);
|
|
941
|
+
void runObserverRecovery();
|
|
942
|
+
});
|
|
943
|
+
|
|
870
944
|
function observationFor(tabId: number): ContentObservation {
|
|
871
945
|
const observed = sessions.get(tabId);
|
|
872
946
|
if (!observed) throw new Error("CONTENT_SESSION_NOT_READY");
|
|
@@ -1623,6 +1697,7 @@ async function bridgeFetch(
|
|
|
1623
1697
|
}
|
|
1624
1698
|
|
|
1625
1699
|
let bridgeLoopStarted = false;
|
|
1700
|
+
let bridgeSessionEpoch = 0;
|
|
1626
1701
|
async function runBridgeLoop() {
|
|
1627
1702
|
if (bridgeLoopStarted) return;
|
|
1628
1703
|
bridgeLoopStarted = true;
|
|
@@ -1643,6 +1718,13 @@ async function runBridgeLoop() {
|
|
|
1643
1718
|
}),
|
|
1644
1719
|
});
|
|
1645
1720
|
if (!hello.ok) throw new Error("BRIDGE_HELLO_REJECTED");
|
|
1721
|
+
bridgeSessionEpoch += 1;
|
|
1722
|
+
emitObserverRecoveryDiagnostic(
|
|
1723
|
+
"BRIDGE_EPOCH_ACCEPTED",
|
|
1724
|
+
bridgeSessionEpoch,
|
|
1725
|
+
`bridge-session:${bridgeSessionEpoch}`,
|
|
1726
|
+
);
|
|
1727
|
+
observerRecoveryRearm.bridgeSessionEstablished(bridgeSessionEpoch);
|
|
1646
1728
|
await publishCarrierAttentions();
|
|
1647
1729
|
// Hello only establishes a session. The first inner-loop action must be
|
|
1648
1730
|
// a real command poll so Runtime readiness cannot be granted by hello alone.
|
|
@@ -2046,7 +2128,7 @@ async function startBackgroundRuntime(): Promise<void> {
|
|
|
2046
2128
|
void runProvisioningBridgeLoop();
|
|
2047
2129
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
2048
2130
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
2049
|
-
|
|
2131
|
+
observerRecoveryRearm.startupReady();
|
|
2050
2132
|
}
|
|
2051
2133
|
|
|
2052
2134
|
chrome.action.onClicked.addListener(() => {
|
|
@@ -2059,7 +2141,7 @@ chrome.runtime.onInstalled.addListener(() => {
|
|
|
2059
2141
|
void runBridgeLoop();
|
|
2060
2142
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
2061
2143
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
2062
|
-
|
|
2144
|
+
observerRecoveryRearm.startupReady();
|
|
2063
2145
|
});
|
|
2064
2146
|
});
|
|
2065
2147
|
chrome.runtime.onStartup.addListener(() => {
|
|
@@ -2070,7 +2152,7 @@ chrome.runtime.onStartup.addListener(() => {
|
|
|
2070
2152
|
void runBridgeLoop();
|
|
2071
2153
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
2072
2154
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
2073
|
-
|
|
2155
|
+
observerRecoveryRearm.startupReady();
|
|
2074
2156
|
});
|
|
2075
2157
|
});
|
|
2076
2158
|
void startBackgroundRuntime();
|
package/manifest.json
CHANGED
package/package.json
CHANGED
package/proflow.module.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"contractVersion": "1.0.0",
|
|
4
4
|
"moduleRef": "execution-browser-extension",
|
|
5
5
|
"packageName": "@tomflow/proflow-execution-browser-extension",
|
|
6
|
-
"moduleVersion": "0.1.
|
|
6
|
+
"moduleVersion": "0.1.50",
|
|
7
7
|
"kind": "browser-extension",
|
|
8
8
|
"templateVersion": "1.0.0",
|
|
9
9
|
"platformCompatibility": ">=1.0.0 <2.0.0",
|