@agent-native/creative-context 0.5.11 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/list-context-connections.js +1 -1
- package/dist/client/CreativeContextPanel.js +1 -1
- package/dist/connectors/index.d.ts +1 -0
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/index.js +1 -0
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/rendered-design.d.ts +68 -0
- package/dist/connectors/rendered-design.d.ts.map +1 -0
- package/dist/connectors/rendered-design.js +362 -0
- package/dist/connectors/rendered-design.js.map +1 -0
- package/dist/connectors/rendered-page.d.ts +19 -1
- package/dist/connectors/rendered-page.d.ts.map +1 -1
- package/dist/connectors/rendered-page.js +385 -129
- package/dist/connectors/rendered-page.js.map +1 -1
- package/dist/jobs/server-worker.d.ts.map +1 -1
- package/dist/jobs/server-worker.js +5 -3
- package/dist/jobs/server-worker.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +5 -2
- package/dist/server/index.js.map +1 -1
- package/package.json +3 -3
- package/src/actions/list-context-connections.ts +1 -1
- package/src/client/CreativeContextPanel.tsx +1 -1
- package/src/connectors/index.ts +9 -0
- package/src/connectors/rendered-design.spec.ts +171 -0
- package/src/connectors/rendered-design.ts +498 -0
- package/src/connectors/rendered-page.spec.ts +94 -0
- package/src/connectors/rendered-page.ts +494 -174
- package/src/connectors/website.spec.ts +27 -71
- package/src/jobs/server-worker.spec.ts +32 -10
- package/src/jobs/server-worker.ts +5 -2
- package/src/server/index.spec.ts +15 -0
- package/src/server/index.ts +13 -1
|
@@ -155,84 +155,40 @@ describe("website context connector", () => {
|
|
|
155
155
|
).rejects.toThrow(/SSRF blocked/i);
|
|
156
156
|
});
|
|
157
157
|
|
|
158
|
-
it("
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
it("disables arbitrary Chromium navigation and keeps the static fallback", async () => {
|
|
159
|
+
const staticFetch = vi.fn(async (url: string) =>
|
|
160
|
+
response(
|
|
161
|
+
url,
|
|
162
|
+
"<html><head><title>Public page</title></head><body>Static content</body></html>",
|
|
163
|
+
"text/html",
|
|
164
|
+
),
|
|
161
165
|
);
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const page = {
|
|
166
|
-
async route(
|
|
167
|
-
_pattern: string,
|
|
168
|
-
handler: (route: unknown) => Promise<void>,
|
|
169
|
-
) {
|
|
170
|
-
routeHandler = handler;
|
|
171
|
-
},
|
|
172
|
-
async goto() {
|
|
173
|
-
await routeHandler?.({
|
|
174
|
-
request: () => ({
|
|
175
|
-
url: () => "http://10.0.0.7/secret.png",
|
|
176
|
-
isNavigationRequest: () => false,
|
|
177
|
-
resourceType: () => "image",
|
|
178
|
-
}),
|
|
179
|
-
abort,
|
|
180
|
-
continue: continueRoute,
|
|
181
|
-
});
|
|
182
|
-
},
|
|
183
|
-
async title() {
|
|
184
|
-
return "Public page";
|
|
185
|
-
},
|
|
186
|
-
url() {
|
|
187
|
-
return "https://example.com/";
|
|
188
|
-
},
|
|
189
|
-
locator() {
|
|
190
|
-
return { innerText: async () => "Public content" };
|
|
191
|
-
},
|
|
192
|
-
async setViewportSize() {},
|
|
193
|
-
async screenshot() {
|
|
194
|
-
return new Uint8Array([1, 2, 3]);
|
|
195
|
-
},
|
|
196
|
-
async evaluate() {
|
|
197
|
-
return {
|
|
198
|
-
title: "Public page",
|
|
199
|
-
text: "Public content",
|
|
200
|
-
assets: [],
|
|
201
|
-
internalLinks: [],
|
|
202
|
-
designTokens: {
|
|
203
|
-
colors: [],
|
|
204
|
-
typography: [],
|
|
205
|
-
spacing: [],
|
|
206
|
-
radii: [],
|
|
207
|
-
cssVariables: {},
|
|
208
|
-
},
|
|
209
|
-
};
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
const browser = {
|
|
213
|
-
contexts: () => [{ pages: () => [page], newPage: async () => page }],
|
|
214
|
-
newContext: async () => ({
|
|
215
|
-
pages: () => [page],
|
|
216
|
-
newPage: async () => page,
|
|
217
|
-
}),
|
|
218
|
-
close: async () => {},
|
|
219
|
-
};
|
|
166
|
+
const loadPlaywright = vi.fn(async () => {
|
|
167
|
+
throw new Error("Chromium must not be loaded for arbitrary URLs");
|
|
168
|
+
});
|
|
220
169
|
const renderer = new LayeredRenderedPageProvider({
|
|
221
|
-
loadPlaywright
|
|
222
|
-
|
|
223
|
-
chromium: {
|
|
224
|
-
connectOverCDP: async () => browser,
|
|
225
|
-
launch: async () => browser,
|
|
226
|
-
},
|
|
227
|
-
}) as never,
|
|
170
|
+
loadPlaywright,
|
|
171
|
+
staticFetch: staticFetch as never,
|
|
228
172
|
});
|
|
229
173
|
|
|
230
|
-
await renderer.render({
|
|
174
|
+
const result = await renderer.render({
|
|
231
175
|
url: "https://example.com/",
|
|
232
176
|
preferHosted: false,
|
|
233
177
|
});
|
|
234
|
-
|
|
235
|
-
expect(
|
|
178
|
+
|
|
179
|
+
expect(loadPlaywright).not.toHaveBeenCalled();
|
|
180
|
+
expect(staticFetch).toHaveBeenCalledTimes(1);
|
|
181
|
+
expect(result).toMatchObject({
|
|
182
|
+
method: "static-html",
|
|
183
|
+
rendered: false,
|
|
184
|
+
text: "Public page Static content",
|
|
185
|
+
});
|
|
186
|
+
expect(result.warnings).toEqual(
|
|
187
|
+
expect.arrayContaining([
|
|
188
|
+
expect.stringContaining("connect-time SSRF guard"),
|
|
189
|
+
expect.stringContaining("SSRF-safe static HTML fallback"),
|
|
190
|
+
]),
|
|
191
|
+
);
|
|
236
192
|
});
|
|
237
193
|
|
|
238
194
|
it("persists rendered desktop/mobile evidence and extracted design signals privately", async () => {
|
|
@@ -7,9 +7,20 @@ const mocks = vi.hoisted(() => ({
|
|
|
7
7
|
registerDispatcher: vi.fn(),
|
|
8
8
|
processImport: vi.fn(),
|
|
9
9
|
processDue: vi.fn(async () => ({ discovered: 0, dispatched: 0, failed: 0 })),
|
|
10
|
+
processDueBackground: vi.fn(async () => ({
|
|
11
|
+
discovered: 0,
|
|
12
|
+
dispatched: 0,
|
|
13
|
+
failed: 0,
|
|
14
|
+
})),
|
|
15
|
+
enqueueDailyMaintenance: vi.fn(async () => ({
|
|
16
|
+
discovered: 0,
|
|
17
|
+
queued: 0,
|
|
18
|
+
failed: 0,
|
|
19
|
+
})),
|
|
10
20
|
h3Use: vi.fn(),
|
|
11
21
|
verifyInternalToken: vi.fn(() => true),
|
|
12
22
|
isLocalDatabase: vi.fn(() => true),
|
|
23
|
+
isInBackgroundFunctionRuntime: vi.fn(() => false),
|
|
13
24
|
}));
|
|
14
25
|
|
|
15
26
|
vi.mock("@agent-native/core/db", async (importOriginal) => ({
|
|
@@ -23,6 +34,7 @@ vi.mock("@agent-native/core/server", () => ({
|
|
|
23
34
|
fireInternalDispatch: mocks.fireInternalDispatch,
|
|
24
35
|
FRAMEWORK_ROUTE_PREFIX: "/_agent-native",
|
|
25
36
|
getH3App: mocks.getH3App,
|
|
37
|
+
isInBackgroundFunctionRuntime: mocks.isInBackgroundFunctionRuntime,
|
|
26
38
|
readBody: mocks.readBody,
|
|
27
39
|
verifyInternalToken: mocks.verifyInternalToken,
|
|
28
40
|
}));
|
|
@@ -34,17 +46,9 @@ vi.mock("./worker.js", () => ({
|
|
|
34
46
|
}));
|
|
35
47
|
|
|
36
48
|
vi.mock("./background-worker.js", () => ({
|
|
37
|
-
enqueueCreativeContextDailyMaintenance:
|
|
38
|
-
discovered: 0,
|
|
39
|
-
queued: 0,
|
|
40
|
-
failed: 0,
|
|
41
|
-
})),
|
|
49
|
+
enqueueCreativeContextDailyMaintenance: mocks.enqueueDailyMaintenance,
|
|
42
50
|
processCreativeContextBackgroundJob: vi.fn(),
|
|
43
|
-
processDueCreativeContextBackgroundJobs:
|
|
44
|
-
discovered: 0,
|
|
45
|
-
dispatched: 0,
|
|
46
|
-
failed: 0,
|
|
47
|
-
})),
|
|
51
|
+
processDueCreativeContextBackgroundJobs: mocks.processDueBackground,
|
|
48
52
|
registerCreativeContextBackgroundDispatcher: vi.fn(),
|
|
49
53
|
}));
|
|
50
54
|
|
|
@@ -60,11 +64,15 @@ describe("creative context hosted worker", () => {
|
|
|
60
64
|
mocks.fireInternalDispatch.mockClear();
|
|
61
65
|
mocks.registerDispatcher.mockClear();
|
|
62
66
|
mocks.processDue.mockClear();
|
|
67
|
+
mocks.processDueBackground.mockClear();
|
|
68
|
+
mocks.enqueueDailyMaintenance.mockClear();
|
|
63
69
|
mocks.h3Use.mockClear();
|
|
64
70
|
mocks.verifyInternalToken.mockReset();
|
|
65
71
|
mocks.verifyInternalToken.mockReturnValue(true);
|
|
66
72
|
mocks.isLocalDatabase.mockReset();
|
|
67
73
|
mocks.isLocalDatabase.mockReturnValue(true);
|
|
74
|
+
mocks.isInBackgroundFunctionRuntime.mockReset();
|
|
75
|
+
mocks.isInBackgroundFunctionRuntime.mockReturnValue(false);
|
|
68
76
|
mocks.getH3App.mockReturnValue({ use: mocks.h3Use });
|
|
69
77
|
mocks.readBody.mockReset();
|
|
70
78
|
vi.unstubAllEnvs();
|
|
@@ -115,6 +123,20 @@ describe("creative context hosted worker", () => {
|
|
|
115
123
|
expect(mocks.registerDispatcher).not.toHaveBeenCalled();
|
|
116
124
|
});
|
|
117
125
|
|
|
126
|
+
it("mounts processors without starting database sweeps in background runtime", async () => {
|
|
127
|
+
mocks.isInBackgroundFunctionRuntime.mockReturnValue(true);
|
|
128
|
+
|
|
129
|
+
await createCreativeContextWorkerPlugin({ appId: "analytics" })({});
|
|
130
|
+
|
|
131
|
+
expect(mocks.h3Use).toHaveBeenCalledWith(
|
|
132
|
+
CREATIVE_CONTEXT_IMPORT_PROCESSOR_ROUTE,
|
|
133
|
+
expect.any(Function),
|
|
134
|
+
);
|
|
135
|
+
expect(mocks.processDue).not.toHaveBeenCalled();
|
|
136
|
+
expect(mocks.processDueBackground).not.toHaveBeenCalled();
|
|
137
|
+
expect(mocks.enqueueDailyMaintenance).not.toHaveBeenCalled();
|
|
138
|
+
});
|
|
139
|
+
|
|
118
140
|
it("rejects invalid signed dispatches", async () => {
|
|
119
141
|
vi.stubEnv("A2A_SECRET", "configured-secret");
|
|
120
142
|
mocks.verifyInternalToken.mockReturnValue(false);
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
fireInternalDispatch,
|
|
6
6
|
FRAMEWORK_ROUTE_PREFIX,
|
|
7
7
|
getH3App,
|
|
8
|
+
isInBackgroundFunctionRuntime,
|
|
8
9
|
readBody,
|
|
9
10
|
verifyInternalToken,
|
|
10
11
|
type NitroPluginDef,
|
|
@@ -51,8 +52,10 @@ export function createCreativeContextWorkerPlugin(input: {
|
|
|
51
52
|
registerCreativeContextBackgroundDispatcher((dispatch) =>
|
|
52
53
|
scheduleHostedBackgroundDispatch({ ...dispatch, appId }),
|
|
53
54
|
);
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
if (!isInBackgroundFunctionRuntime()) {
|
|
56
|
+
startCreativeContextImportSweep({ appId });
|
|
57
|
+
startCreativeContextDailyMaintenance({ appId });
|
|
58
|
+
}
|
|
56
59
|
const h3App = getH3App(nitroApp);
|
|
57
60
|
h3App.use(CREATIVE_CONTEXT_IMPORT_PROCESSOR_ROUTE, async (event: any) => {
|
|
58
61
|
if (event?.req?.method !== "POST") {
|
package/src/server/index.spec.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
|
|
1
3
|
import { getShareableResource } from "@agent-native/core/sharing";
|
|
2
4
|
import { describe, expect, it } from "vitest";
|
|
3
5
|
|
|
4
6
|
import "./index.js";
|
|
5
7
|
|
|
8
|
+
const indexTsSource = readFileSync(
|
|
9
|
+
new URL("./index.ts", import.meta.url),
|
|
10
|
+
"utf8",
|
|
11
|
+
);
|
|
12
|
+
|
|
6
13
|
describe("creative context shareable registrations", () => {
|
|
7
14
|
it("requires org membership for creative context pack user shares", () => {
|
|
8
15
|
const registration = getShareableResource("creative-context-pack");
|
|
@@ -13,3 +20,11 @@ describe("creative context shareable registrations", () => {
|
|
|
13
20
|
});
|
|
14
21
|
});
|
|
15
22
|
});
|
|
23
|
+
|
|
24
|
+
describe("creative context background startup", () => {
|
|
25
|
+
it("does not run package migrations in durable background functions", () => {
|
|
26
|
+
expect(indexTsSource).toMatch(
|
|
27
|
+
/if \(!isInBackgroundFunctionRuntime\(\)\) \{\s*await creativeContextDbPlugin\(nitroApp\);/,
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
});
|
package/src/server/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { runMigrations } from "@agent-native/core/db";
|
|
2
2
|
import {
|
|
3
|
+
isInBackgroundFunctionRuntime,
|
|
3
4
|
registerPackageActions,
|
|
4
5
|
type NitroPluginDef,
|
|
5
6
|
} from "@agent-native/core/server";
|
|
@@ -125,7 +126,9 @@ export function setupCreativeContext(
|
|
|
125
126
|
});
|
|
126
127
|
const mediaPlugin = createCreativeContextMediaPlugin();
|
|
127
128
|
return async (nitroApp) => {
|
|
128
|
-
|
|
129
|
+
if (!isInBackgroundFunctionRuntime()) {
|
|
130
|
+
await creativeContextDbPlugin(nitroApp);
|
|
131
|
+
}
|
|
129
132
|
await workerPlugin(nitroApp);
|
|
130
133
|
await mediaPlugin(nitroApp);
|
|
131
134
|
};
|
|
@@ -142,6 +145,15 @@ export * from "./untrusted-reference.js";
|
|
|
142
145
|
export * from "./media.js";
|
|
143
146
|
export * from "./native-resource-capture.js";
|
|
144
147
|
export * from "./safe-native-preview.js";
|
|
148
|
+
export {
|
|
149
|
+
brandKitDataFromExtraction,
|
|
150
|
+
buildDesignMarkdown,
|
|
151
|
+
extractRenderedDesignSystemFromUrl,
|
|
152
|
+
styleBriefFromRenderedDesign,
|
|
153
|
+
type ExtractRenderedDesignOptions,
|
|
154
|
+
type RenderedDesignExtraction,
|
|
155
|
+
type RenderedDesignExtractionStatus,
|
|
156
|
+
} from "../connectors/rendered-design.js";
|
|
145
157
|
export { serializePrivateBlobHandle } from "../connectors/private-artifacts.js";
|
|
146
158
|
export { resolveNativeContextCloneReference } from "../store/contexts.js";
|
|
147
159
|
export {
|