@tomflow/proflow-execution-browser-extension 0.1.19 → 0.1.20

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.
@@ -24,7 +24,7 @@ export declare const behaviorAdapter: {
24
24
  ok: true;
25
25
  status: "SUCCEEDED";
26
26
  moduleRef: "execution-browser-extension";
27
- moduleVersion: "0.1.19";
27
+ moduleVersion: "0.1.20";
28
28
  data: {
29
29
  loadDir: string;
30
30
  };
@@ -37,7 +37,7 @@ export declare const behaviorAdapter: {
37
37
  readonly ok: true;
38
38
  readonly status: "SUCCEEDED";
39
39
  readonly moduleRef: "execution-browser-extension";
40
- readonly moduleVersion: "0.1.19";
40
+ readonly moduleVersion: "0.1.20";
41
41
  };
42
42
  observedEffects: never[];
43
43
  }>;
@@ -47,7 +47,7 @@ export declare const behaviorAdapter: {
47
47
  ok: true;
48
48
  status: "SUCCEEDED";
49
49
  moduleRef: "execution-browser-extension";
50
- moduleVersion: "0.1.19";
50
+ moduleVersion: "0.1.20";
51
51
  data: {
52
52
  setupStatus: "ACTION_REQUIRED" | "READY";
53
53
  runtimeStatus: "NOT_APPLICABLE";
@@ -66,7 +66,7 @@ export declare const behaviorAdapter: {
66
66
  result: {
67
67
  contract: "deployment.result.v1";
68
68
  moduleRef: "execution-browser-extension";
69
- moduleVersion: "0.1.19";
69
+ moduleVersion: "0.1.20";
70
70
  ok: false;
71
71
  status: "ACTION_REQUIRED";
72
72
  data: {
@@ -98,14 +98,14 @@ export declare const behaviorAdapter: {
98
98
  readonly ok: true;
99
99
  readonly status: "SUCCEEDED";
100
100
  readonly moduleRef: "execution-browser-extension";
101
- readonly moduleVersion: "0.1.19";
101
+ readonly moduleVersion: "0.1.20";
102
102
  };
103
103
  observedEffects: string[];
104
104
  } | {
105
105
  result: {
106
106
  contract: "deployment.result.v1";
107
107
  moduleRef: "execution-browser-extension";
108
- moduleVersion: "0.1.19";
108
+ moduleVersion: "0.1.20";
109
109
  ok: false;
110
110
  status: "FAILED";
111
111
  error: {
@@ -138,7 +138,7 @@ export declare const behaviorAdapter: {
138
138
  ok: true;
139
139
  status: "SUCCEEDED";
140
140
  moduleRef: "execution-browser-extension";
141
- moduleVersion: "0.1.19";
141
+ moduleVersion: "0.1.20";
142
142
  data: {
143
143
  docs: string;
144
144
  };
@@ -151,11 +151,11 @@ export declare const behaviorAdapter: {
151
151
  readonly ok: true;
152
152
  readonly status: "SUCCEEDED";
153
153
  readonly moduleRef: "execution-browser-extension";
154
- readonly moduleVersion: "0.1.19";
154
+ readonly moduleVersion: "0.1.20";
155
155
  } | {
156
156
  contract: "deployment.result.v1";
157
157
  moduleRef: "execution-browser-extension";
158
- moduleVersion: "0.1.19";
158
+ moduleVersion: "0.1.20";
159
159
  ok: false;
160
160
  status: "FAILED";
161
161
  error: {
@@ -172,7 +172,7 @@ export declare const behaviorAdapter: {
172
172
  readonly ok: true;
173
173
  readonly status: "SUCCEEDED";
174
174
  readonly moduleRef: "execution-browser-extension";
175
- readonly moduleVersion: "0.1.19";
175
+ readonly moduleVersion: "0.1.20";
176
176
  };
177
177
  observedEffects: never[];
178
178
  }>;
@@ -133,11 +133,12 @@ async function persistDeveloperModeConfirmation(context) {
133
133
  await mkdir(stateDir(context), { recursive: true, mode: 0o700 });
134
134
  await writeFile(installFlowFile(context), `${JSON.stringify({ developerModeConfirmed: true })}\n`, { mode: 0o600 });
135
135
  }
136
- async function readEvidence(context, loadDir) {
136
+ async function readEvidenceCandidate(context, loadDir) {
137
137
  try {
138
138
  const raw = JSON.parse(await readFile(verificationFile(context), "utf8"));
139
139
  return raw.contract === "proflow.browser-extension-verification.v1" &&
140
- raw.moduleVersion === descriptor.moduleVersion &&
140
+ typeof raw.moduleVersion === "string" &&
141
+ raw.moduleVersion.length > 0 &&
141
142
  raw.loadDir === loadDir &&
142
143
  typeof raw.extensionId === "string" &&
143
144
  /^[a-z]{32}$/.test(raw.extensionId) &&
@@ -154,6 +155,12 @@ async function readEvidence(context, loadDir) {
154
155
  return undefined;
155
156
  }
156
157
  }
158
+ async function readEvidence(context, loadDir) {
159
+ const evidence = await readEvidenceCandidate(context, loadDir);
160
+ return evidence?.moduleVersion === descriptor.moduleVersion
161
+ ? evidence
162
+ : undefined;
163
+ }
157
164
  async function ownFacts(context) {
158
165
  await mkdir(stateDir(context), { recursive: true, mode: 0o700 });
159
166
  const loadDir = browserExtensionLoadDir(context.workspaceRoot);
@@ -248,15 +255,83 @@ async function persistPairedBrowserExtension(context, prepared, identity) {
248
255
  await writeFile(verificationFile(context), `${JSON.stringify(evidence, null, 2)}\n`, { mode: 0o600 });
249
256
  return identity;
250
257
  }
258
+ function connectionRefused(error) {
259
+ if (!(error instanceof TypeError))
260
+ return false;
261
+ const cause = Reflect.get(error, "cause");
262
+ return (typeof cause === "object" &&
263
+ cause !== null &&
264
+ Reflect.get(cause, "code") === "ECONNREFUSED");
265
+ }
266
+ async function probeRunningBridgeSession(prepared, extensionId, timeoutMs) {
267
+ try {
268
+ const response = await fetch(`${prepared.bridgeEndpoint}/v1/session/status`, {
269
+ headers: {
270
+ authorization: `Bearer ${await credential(prepared.bridgeTokenFile)}`,
271
+ origin: `chrome-extension://${extensionId}`,
272
+ },
273
+ signal: AbortSignal.timeout(Math.max(25, Math.min(500, timeoutMs))),
274
+ });
275
+ if (!response.ok)
276
+ throw new Error(`RUNNING_BRIDGE_STATUS_${response.status}`);
277
+ const body = (await response.json());
278
+ if (typeof body !== "object" || body === null || Array.isArray(body))
279
+ throw new Error("RUNNING_BRIDGE_STATUS_INVALID");
280
+ if (Reflect.get(body, "online") !== true)
281
+ return { kind: "PRESENT" };
282
+ const extensionInstanceId = Reflect.get(body, "extensionInstanceId");
283
+ if (typeof extensionInstanceId !== "string" ||
284
+ extensionInstanceId.length === 0)
285
+ throw new Error("RUNNING_BRIDGE_STATUS_INVALID");
286
+ return {
287
+ kind: "PRESENT",
288
+ identity: { extensionId, extensionInstanceId },
289
+ };
290
+ }
291
+ catch (error) {
292
+ if (connectionRefused(error))
293
+ return { kind: "ABSENT" };
294
+ throw error;
295
+ }
296
+ }
297
+ async function revalidateRunningBridge(prepared, extensionId, timeoutMs, onWaiting) {
298
+ const startedAt = Date.now();
299
+ const graceMs = Math.min(2_000, Math.max(25, Math.floor(timeoutMs / 4)));
300
+ let waitingShown = false;
301
+ while (true) {
302
+ const remainingMs = Math.max(1, timeoutMs - (Date.now() - startedAt));
303
+ const probe = await probeRunningBridgeSession(prepared, extensionId, remainingMs);
304
+ if (probe.kind === "ABSENT")
305
+ return undefined;
306
+ if (probe.identity)
307
+ return probe.identity;
308
+ const elapsedMs = Date.now() - startedAt;
309
+ if (!waitingShown && elapsedMs >= graceMs) {
310
+ waitingShown = true;
311
+ await onWaiting?.({
312
+ loadDir: prepared.loadDir,
313
+ endpoint: prepared.bridgeEndpoint,
314
+ });
315
+ }
316
+ if (elapsedMs >= timeoutMs)
317
+ throw new Error("PAIRING_TIMEOUT");
318
+ await new Promise((resolve) => setTimeout(resolve, Math.min(100, Math.max(10, timeoutMs - elapsedMs))));
319
+ }
320
+ }
251
321
  export async function pairBrowserExtensionSetup(context, options = {}) {
252
322
  await mkdir(stateDir(context), { recursive: true, mode: 0o700 });
253
323
  await installPackage(context);
254
324
  const existingSetup = await readSetup(context);
255
- const existingEvidence = await readEvidence(context, browserExtensionLoadDir(context.workspaceRoot));
325
+ const existingEvidence = await readEvidenceCandidate(context, browserExtensionLoadDir(context.workspaceRoot));
256
326
  const canRevalidateExisting = Boolean(existingSetup &&
257
327
  existingEvidence &&
258
328
  existingSetup.extensionId === existingEvidence.extensionId);
259
329
  const prepared = await materializeRuntimeConfig(context);
330
+ if (canRevalidateExisting && existingSetup) {
331
+ const runningIdentity = await revalidateRunningBridge(prepared, existingSetup.extensionId, options.timeoutMs ?? 120_000, options.onWaiting);
332
+ if (runningIdentity)
333
+ return persistPairedBrowserExtension(context, prepared, runningIdentity);
334
+ }
260
335
  const pairing = await createBrowserExtensionPairingServer({
261
336
  token: await credential(prepared.bridgeTokenFile),
262
337
  host: "127.0.0.1",
@@ -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.19";
6
+ readonly moduleVersion: "0.1.20";
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.19",
6
+ moduleVersion: "0.1.20",
7
7
  kind: "browser-extension",
8
8
  templateVersion: "1.0.0",
9
9
  platformCompatibility: ">=1.0.0 <2.0.0",
@@ -129,6 +129,15 @@ export async function createBrowserRealityBridgeServer(options) {
129
129
  send(response, 200, { accepted: true });
130
130
  return;
131
131
  }
132
+ if (request.method === "GET" && url.pathname === "/v1/session/status") {
133
+ const online = session !== undefined &&
134
+ now().getTime() - session.lastHeartbeatAt <= freshnessMs;
135
+ send(response, 200, {
136
+ online,
137
+ extensionInstanceId: session?.extensionInstanceId ?? null,
138
+ });
139
+ return;
140
+ }
132
141
  if (!session)
133
142
  throw new BrowserRealityBridgeError("BRIDGE_OFFLINE", "extension session has not completed hello");
134
143
  if (url.searchParams.get("extensionInstanceId") !==
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "ProFlow Execution Browser",
4
- "version": "0.1.19",
4
+ "version": "0.1.20",
5
5
  "permissions": ["tabs", "storage", "sidePanel"],
6
6
  "host_permissions": ["https://chatgpt.com/*", "http://127.0.0.1/*"],
7
7
  "background": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/proflow-execution-browser-extension",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "Execution-owned MV3 Browser executor, evidence provider and browser application surface.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -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.19",
6
+ "moduleVersion": "0.1.20",
7
7
  "kind": "browser-extension",
8
8
  "templateVersion": "1.0.0",
9
9
  "platformCompatibility": ">=1.0.0 <2.0.0",