@tomflow/proflow-execution-browser-extension 0.1.35 → 0.1.37
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/deployment/adapter.d.ts +10 -10
- package/dist/deployment/descriptor.d.ts +1 -1
- package/dist/deployment/descriptor.js +1 -1
- package/dist/extension/content.js +100 -79
- package/dist/src/bridge.js +6 -1
- package/dist/src/pairing.js +12 -8
- package/manifest.json +1 -1
- package/package.json +3 -3
- package/proflow.module.json +1 -1
|
@@ -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.
|
|
50
|
+
moduleVersion: "0.1.37";
|
|
51
51
|
data: {
|
|
52
52
|
loadDir: string;
|
|
53
53
|
};
|
|
@@ -60,7 +60,7 @@ export declare const behaviorAdapter: {
|
|
|
60
60
|
readonly ok: true;
|
|
61
61
|
readonly status: "SUCCEEDED";
|
|
62
62
|
readonly moduleRef: "execution-browser-extension";
|
|
63
|
-
readonly moduleVersion: "0.1.
|
|
63
|
+
readonly moduleVersion: "0.1.37";
|
|
64
64
|
};
|
|
65
65
|
observedEffects: never[];
|
|
66
66
|
}>;
|
|
@@ -70,7 +70,7 @@ export declare const behaviorAdapter: {
|
|
|
70
70
|
ok: true;
|
|
71
71
|
status: "SUCCEEDED";
|
|
72
72
|
moduleRef: "execution-browser-extension";
|
|
73
|
-
moduleVersion: "0.1.
|
|
73
|
+
moduleVersion: "0.1.37";
|
|
74
74
|
data: {
|
|
75
75
|
setupStatus: "ACTION_REQUIRED" | "READY";
|
|
76
76
|
runtimeStatus: "NOT_APPLICABLE";
|
|
@@ -95,7 +95,7 @@ export declare const behaviorAdapter: {
|
|
|
95
95
|
result: {
|
|
96
96
|
contract: "deployment.result.v1";
|
|
97
97
|
moduleRef: "execution-browser-extension";
|
|
98
|
-
moduleVersion: "0.1.
|
|
98
|
+
moduleVersion: "0.1.37";
|
|
99
99
|
ok: false;
|
|
100
100
|
status: "ACTION_REQUIRED";
|
|
101
101
|
data: {
|
|
@@ -127,14 +127,14 @@ export declare const behaviorAdapter: {
|
|
|
127
127
|
readonly ok: true;
|
|
128
128
|
readonly status: "SUCCEEDED";
|
|
129
129
|
readonly moduleRef: "execution-browser-extension";
|
|
130
|
-
readonly moduleVersion: "0.1.
|
|
130
|
+
readonly moduleVersion: "0.1.37";
|
|
131
131
|
};
|
|
132
132
|
observedEffects: string[];
|
|
133
133
|
} | {
|
|
134
134
|
result: {
|
|
135
135
|
contract: "deployment.result.v1";
|
|
136
136
|
moduleRef: "execution-browser-extension";
|
|
137
|
-
moduleVersion: "0.1.
|
|
137
|
+
moduleVersion: "0.1.37";
|
|
138
138
|
ok: false;
|
|
139
139
|
status: "FAILED";
|
|
140
140
|
error: {
|
|
@@ -167,7 +167,7 @@ export declare const behaviorAdapter: {
|
|
|
167
167
|
ok: true;
|
|
168
168
|
status: "SUCCEEDED";
|
|
169
169
|
moduleRef: "execution-browser-extension";
|
|
170
|
-
moduleVersion: "0.1.
|
|
170
|
+
moduleVersion: "0.1.37";
|
|
171
171
|
data: {
|
|
172
172
|
docs: string;
|
|
173
173
|
};
|
|
@@ -180,11 +180,11 @@ export declare const behaviorAdapter: {
|
|
|
180
180
|
readonly ok: true;
|
|
181
181
|
readonly status: "SUCCEEDED";
|
|
182
182
|
readonly moduleRef: "execution-browser-extension";
|
|
183
|
-
readonly moduleVersion: "0.1.
|
|
183
|
+
readonly moduleVersion: "0.1.37";
|
|
184
184
|
} | {
|
|
185
185
|
contract: "deployment.result.v1";
|
|
186
186
|
moduleRef: "execution-browser-extension";
|
|
187
|
-
moduleVersion: "0.1.
|
|
187
|
+
moduleVersion: "0.1.37";
|
|
188
188
|
ok: false;
|
|
189
189
|
status: "FAILED";
|
|
190
190
|
error: {
|
|
@@ -201,7 +201,7 @@ export declare const behaviorAdapter: {
|
|
|
201
201
|
readonly ok: true;
|
|
202
202
|
readonly status: "SUCCEEDED";
|
|
203
203
|
readonly moduleRef: "execution-browser-extension";
|
|
204
|
-
readonly moduleVersion: "0.1.
|
|
204
|
+
readonly moduleVersion: "0.1.37";
|
|
205
205
|
};
|
|
206
206
|
observedEffects: never[];
|
|
207
207
|
}>;
|
|
@@ -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.37";
|
|
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.37",
|
|
7
7
|
kind: "browser-extension",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
|
@@ -1,94 +1,115 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
(() => {
|
|
3
|
+
// packages/execution-browser-extension/src/submitted-message.ts
|
|
4
|
+
function containsSubmittedFingerprint(candidates, fingerprint) {
|
|
5
|
+
if (!fingerprint) return false;
|
|
6
|
+
for (const candidate of candidates) {
|
|
7
|
+
if (candidate.authorRole === "user" && candidate.textContent?.includes(fingerprint))
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// packages/execution-browser-extension/extension/content.ts
|
|
14
|
+
var contentInstanceId = `content:${crypto.randomUUID()}`;
|
|
15
|
+
function pageState() {
|
|
4
16
|
if (document.querySelector('[role="dialog"]'))
|
|
5
|
-
|
|
6
|
-
if (document.querySelector(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
17
|
+
return { pageState: "BLOCKED", activityKind: "ACTION_PERMISSION" };
|
|
18
|
+
if (document.querySelector(
|
|
19
|
+
'[data-testid="stop-button"], button[aria-label*="Stop"]'
|
|
20
|
+
))
|
|
21
|
+
return { pageState: "BUSY", activityKind: "GENERATING" };
|
|
22
|
+
if (document.querySelector(
|
|
23
|
+
'#prompt-textarea, textarea, [contenteditable="true"]'
|
|
24
|
+
))
|
|
25
|
+
return { pageState: "IDLE", activityKind: null };
|
|
10
26
|
return { pageState: "UNKNOWN", activityKind: null };
|
|
11
|
-
}
|
|
12
|
-
function observation() {
|
|
27
|
+
}
|
|
28
|
+
function observation() {
|
|
13
29
|
return {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
30
|
+
url: location.href,
|
|
31
|
+
contentInstanceId,
|
|
32
|
+
...pageState(),
|
|
33
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
18
34
|
};
|
|
19
|
-
}
|
|
20
|
-
function safeElement(selector) {
|
|
21
|
-
if (!selector || selector.length > 512)
|
|
22
|
-
throw new Error("SELECTOR_INVALID");
|
|
35
|
+
}
|
|
36
|
+
function safeElement(selector) {
|
|
37
|
+
if (!selector || selector.length > 512) throw new Error("SELECTOR_INVALID");
|
|
23
38
|
const element = document.querySelector(selector);
|
|
24
|
-
if (!(element instanceof HTMLElement))
|
|
25
|
-
throw new Error("ELEMENT_NOT_FOUND");
|
|
39
|
+
if (!(element instanceof HTMLElement)) throw new Error("ELEMENT_NOT_FOUND");
|
|
26
40
|
return element;
|
|
27
|
-
}
|
|
28
|
-
function hasFingerprint(fingerprint) {
|
|
29
|
-
return containsSubmittedFingerprint(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
}
|
|
42
|
+
function hasFingerprint(fingerprint) {
|
|
43
|
+
return containsSubmittedFingerprint(
|
|
44
|
+
[...document.querySelectorAll('[data-message-author-role="user"]')].map(
|
|
45
|
+
(element) => ({
|
|
46
|
+
authorRole: element.getAttribute("data-message-author-role"),
|
|
47
|
+
textContent: element.textContent
|
|
48
|
+
})
|
|
49
|
+
),
|
|
50
|
+
fingerprint
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
chrome.runtime.onMessage.addListener((command, _sender, sendResponse) => {
|
|
35
54
|
void (async () => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
throw new Error("PAGE_PERMISSION_REQUIRES_HUMAN");
|
|
49
|
-
if (command.operation === "click") {
|
|
50
|
-
safeElement(command.selector).click();
|
|
51
|
-
return observation();
|
|
52
|
-
}
|
|
53
|
-
const input = safeElement(command.selector ?? "#prompt-textarea");
|
|
54
|
-
if (command.value === undefined || command.value.length > 4_096)
|
|
55
|
-
throw new Error("INPUT_BUDGET_EXCEEDED");
|
|
56
|
-
input.focus();
|
|
57
|
-
if (input instanceof HTMLTextAreaElement ||
|
|
58
|
-
input instanceof HTMLInputElement)
|
|
59
|
-
input.value = command.value;
|
|
60
|
-
else
|
|
61
|
-
input.textContent = command.value;
|
|
62
|
-
input.dispatchEvent(new InputEvent("input", {
|
|
63
|
-
bubbles: true,
|
|
64
|
-
inputType: "insertText",
|
|
65
|
-
data: command.value,
|
|
66
|
-
}));
|
|
67
|
-
if (command.operation === "submit")
|
|
68
|
-
safeElement('button[data-testid="send-button"], button[aria-label*="Send"]').click();
|
|
55
|
+
if (command.type !== "PROFLOW_PAGE_COMMAND" || command.contentInstanceId !== contentInstanceId || command.expectedUrl !== location.href)
|
|
56
|
+
throw new Error("STALE_CONTENT_SESSION");
|
|
57
|
+
if (command.operation === "observe") return observation();
|
|
58
|
+
if (command.operation === "verify")
|
|
59
|
+
return {
|
|
60
|
+
...observation(),
|
|
61
|
+
verified: hasFingerprint(command.fingerprint)
|
|
62
|
+
};
|
|
63
|
+
if (pageState().pageState === "BLOCKED")
|
|
64
|
+
throw new Error("PAGE_PERMISSION_REQUIRES_HUMAN");
|
|
65
|
+
if (command.operation === "click") {
|
|
66
|
+
safeElement(command.selector).click();
|
|
69
67
|
return observation();
|
|
70
|
-
|
|
68
|
+
}
|
|
69
|
+
const input = safeElement(command.selector ?? "#prompt-textarea");
|
|
70
|
+
if (command.value === void 0 || command.value.length > 4096)
|
|
71
|
+
throw new Error("INPUT_BUDGET_EXCEEDED");
|
|
72
|
+
input.focus();
|
|
73
|
+
if (input instanceof HTMLTextAreaElement || input instanceof HTMLInputElement)
|
|
74
|
+
input.value = command.value;
|
|
75
|
+
else input.textContent = command.value;
|
|
76
|
+
input.dispatchEvent(
|
|
77
|
+
new InputEvent("input", {
|
|
78
|
+
bubbles: true,
|
|
79
|
+
inputType: "insertText",
|
|
80
|
+
data: command.value
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
if (command.operation === "submit")
|
|
84
|
+
safeElement(
|
|
85
|
+
'button[data-testid="send-button"], button[aria-label*="Send"]'
|
|
86
|
+
).click();
|
|
87
|
+
return observation();
|
|
88
|
+
})().then(
|
|
89
|
+
(value) => sendResponse({ ok: true, value }),
|
|
90
|
+
(error) => sendResponse({
|
|
71
91
|
ok: false,
|
|
72
|
-
error: error instanceof Error ? error.message : "PAGE_COMMAND_FAILED"
|
|
73
|
-
|
|
92
|
+
error: error instanceof Error ? error.message : "PAGE_COMMAND_FAILED"
|
|
93
|
+
})
|
|
94
|
+
);
|
|
74
95
|
return true;
|
|
75
|
-
});
|
|
76
|
-
|
|
96
|
+
});
|
|
97
|
+
var publish = () => chrome.runtime.sendMessage({
|
|
77
98
|
type: "PROFLOW_CONTENT_OBSERVATION",
|
|
78
|
-
observation: observation()
|
|
79
|
-
});
|
|
80
|
-
void publish();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (publishTimer !==
|
|
84
|
-
clearTimeout(publishTimer);
|
|
99
|
+
observation: observation()
|
|
100
|
+
});
|
|
101
|
+
void publish();
|
|
102
|
+
var publishTimer;
|
|
103
|
+
var observer = new MutationObserver(() => {
|
|
104
|
+
if (publishTimer !== void 0) clearTimeout(publishTimer);
|
|
85
105
|
publishTimer = setTimeout(() => {
|
|
86
|
-
|
|
87
|
-
|
|
106
|
+
publishTimer = void 0;
|
|
107
|
+
void publish();
|
|
88
108
|
}, 100);
|
|
89
|
-
});
|
|
90
|
-
observer.observe(document.documentElement, {
|
|
109
|
+
});
|
|
110
|
+
observer.observe(document.documentElement, {
|
|
91
111
|
subtree: true,
|
|
92
112
|
childList: true,
|
|
93
|
-
attributes: true
|
|
94
|
-
});
|
|
113
|
+
attributes: true
|
|
114
|
+
});
|
|
115
|
+
})();
|
package/dist/src/bridge.js
CHANGED
|
@@ -152,9 +152,13 @@ export async function createBrowserRealityBridgeServer(options) {
|
|
|
152
152
|
const origin = request.headers.origin;
|
|
153
153
|
if (!authorization?.startsWith("Bearer ") ||
|
|
154
154
|
!safeEqual(authorization.slice(7), options.token) ||
|
|
155
|
-
origin !== expectedOrigin)
|
|
155
|
+
(origin !== undefined && origin !== expectedOrigin))
|
|
156
156
|
throw new BrowserRealityBridgeError("BRIDGE_AUTH_INVALID", "bridge authentication failed");
|
|
157
157
|
};
|
|
158
|
+
const requireExtensionOrigin = (request) => {
|
|
159
|
+
if (request.headers.origin !== expectedOrigin)
|
|
160
|
+
throw new BrowserRealityBridgeError("BRIDGE_AUTH_INVALID", "bridge extension origin is required");
|
|
161
|
+
};
|
|
158
162
|
const server = createServer(async (request, response) => {
|
|
159
163
|
try {
|
|
160
164
|
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
@@ -246,6 +250,7 @@ export async function createBrowserRealityBridgeServer(options) {
|
|
|
246
250
|
return;
|
|
247
251
|
}
|
|
248
252
|
if (request.method === "POST" && url.pathname === "/v1/session/hello") {
|
|
253
|
+
requireExtensionOrigin(request);
|
|
249
254
|
const body = await readJson(request);
|
|
250
255
|
if (!isRecord(body) ||
|
|
251
256
|
stringField(body, "extensionId") !== options.extensionId)
|
package/dist/src/pairing.js
CHANGED
|
@@ -34,9 +34,9 @@ function text(value) {
|
|
|
34
34
|
}
|
|
35
35
|
function extensionIdentity(request) {
|
|
36
36
|
const origin = request.headers.origin;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
if (origin === undefined)
|
|
38
|
+
return undefined;
|
|
39
|
+
const match = /^chrome-extension:\/\/([a-z]{32})$/.exec(origin);
|
|
40
40
|
if (!match)
|
|
41
41
|
throw new Error("PAIRING_AUTH_INVALID");
|
|
42
42
|
return match[1];
|
|
@@ -47,7 +47,6 @@ function authenticate(request, token) {
|
|
|
47
47
|
!safeEqual(authorization.slice(7), token)) {
|
|
48
48
|
throw new Error("PAIRING_AUTH_INVALID");
|
|
49
49
|
}
|
|
50
|
-
return extensionIdentity(request);
|
|
51
50
|
}
|
|
52
51
|
export async function createBrowserExtensionPairingServer(options) {
|
|
53
52
|
if (options.token.length < 32) {
|
|
@@ -75,9 +74,13 @@ export async function createBrowserExtensionPairingServer(options) {
|
|
|
75
74
|
const server = createServer(async (request, response) => {
|
|
76
75
|
try {
|
|
77
76
|
const originId = extensionIdentity(request);
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
if (originId) {
|
|
78
|
+
response.setHeader("access-control-allow-origin", `chrome-extension://${originId}`);
|
|
79
|
+
response.setHeader("vary", "origin");
|
|
80
|
+
}
|
|
80
81
|
if (request.method === "OPTIONS") {
|
|
82
|
+
if (!originId)
|
|
83
|
+
throw new Error("PAIRING_AUTH_INVALID");
|
|
81
84
|
response.setHeader("access-control-allow-headers", "authorization, content-type");
|
|
82
85
|
response.setHeader("access-control-allow-methods", "GET, POST, OPTIONS");
|
|
83
86
|
response.writeHead(204);
|
|
@@ -90,7 +93,7 @@ export async function createBrowserExtensionPairingServer(options) {
|
|
|
90
93
|
const body = await readJson(request);
|
|
91
94
|
const extensionId = text(body.extensionId);
|
|
92
95
|
const extensionInstanceId = text(body.extensionInstanceId);
|
|
93
|
-
if (extensionId !== originId)
|
|
96
|
+
if (!originId || extensionId !== originId)
|
|
94
97
|
throw new Error("PAIRING_AUTH_INVALID");
|
|
95
98
|
if (identity && identity.extensionId !== extensionId) {
|
|
96
99
|
throw new Error("PAIRING_AUTH_INVALID");
|
|
@@ -99,7 +102,8 @@ export async function createBrowserExtensionPairingServer(options) {
|
|
|
99
102
|
send(response, 200, { accepted: true });
|
|
100
103
|
return;
|
|
101
104
|
}
|
|
102
|
-
if (!identity ||
|
|
105
|
+
if (!identity ||
|
|
106
|
+
(originId !== undefined && originId !== identity.extensionId)) {
|
|
103
107
|
throw new Error("PAIRING_AUTH_INVALID");
|
|
104
108
|
}
|
|
105
109
|
if (url.searchParams.get("extensionInstanceId") !==
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomflow/proflow-execution-browser-extension",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.37",
|
|
4
4
|
"description": "Execution-owned MV3 Browser executor, evidence provider and browser application surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"SETUP.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@tomflow/proflow-
|
|
31
|
-
"@tomflow/proflow-
|
|
30
|
+
"@tomflow/proflow-execution-contracts": "^0.1.10",
|
|
31
|
+
"@tomflow/proflow-module-contract": "^0.1.13"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@tomflow/proflow-deployment-conformance": "^0.1.13",
|
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.37",
|
|
7
7
|
"kind": "browser-extension",
|
|
8
8
|
"templateVersion": "1.0.0",
|
|
9
9
|
"platformCompatibility": ">=1.0.0 <2.0.0",
|