adnbn 0.12.0 → 0.13.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/cli/bundler/layers.d.ts +3 -3
- package/dist/cli/bundler/layers.js +6 -7
- package/dist/cli/bundler/layers.js.map +1 -1
- package/dist/cli/bundler/plugins/build-assets-map/BuildAssetsMapPlugin.js +42 -14
- package/dist/cli/bundler/plugins/build-assets-map/BuildAssetsMapPlugin.js.map +1 -1
- package/dist/cli/bundler/plugins/build-assets-map/normalize.d.ts +3 -0
- package/dist/cli/bundler/plugins/build-assets-map/normalize.js +24 -0
- package/dist/cli/bundler/plugins/build-assets-map/normalize.js.map +1 -0
- package/dist/cli/bundler/plugins/build-assets-map/templates/runtime.template.d.ts +2 -0
- package/dist/cli/bundler/plugins/build-assets-map/templates.d.ts +9 -0
- package/dist/cli/bundler/plugins/build-assets-map/templates.js +32 -0
- package/dist/cli/bundler/plugins/entrypoint/EntrypointPlugin.js +11 -0
- package/dist/cli/bundler/plugins/entrypoint/EntrypointPlugin.js.map +1 -1
- package/dist/cli/bundler/plugins/isolated-styles/IsolatedStylesPlugin.d.ts +1 -1
- package/dist/cli/bundler/plugins/isolated-styles/IsolatedStylesPlugin.js +38 -13
- package/dist/cli/bundler/plugins/isolated-styles/IsolatedStylesPlugin.js.map +1 -1
- package/dist/cli/bundler/plugins/isolated-styles/chunks.d.ts +5 -1
- package/dist/cli/bundler/plugins/isolated-styles/chunks.js +17 -16
- package/dist/cli/bundler/plugins/isolated-styles/chunks.js.map +1 -1
- package/dist/cli/bundler/plugins/isolated-styles/split-chunks.d.ts +4 -0
- package/dist/cli/bundler/plugins/isolated-styles/split-chunks.js +51 -0
- package/dist/cli/bundler/plugins/isolated-styles/split-chunks.js.map +1 -0
- package/dist/cli/bundler/plugins/isolated-styles/templates.js +36 -6
- package/dist/cli/plugins/content/bundler.d.ts +0 -3
- package/dist/cli/plugins/content/bundler.js +4 -20
- package/dist/cli/plugins/content/bundler.js.map +1 -1
- package/dist/cli/plugins/content/index.js +2 -3
- package/dist/cli/plugins/content/index.js.map +1 -1
- package/dist/cli/plugins/locale/Locale.js +5 -2
- package/dist/cli/plugins/locale/Locale.js.map +1 -1
- package/dist/cli/plugins/style/index.d.ts +1 -2
- package/dist/cli/plugins/style/index.js +19 -30
- package/dist/cli/plugins/style/index.js.map +1 -1
- package/dist/cli/resolvers/config.js +1 -2
- package/dist/cli/resolvers/config.js.map +1 -1
- package/dist/entry/content/adapters/react/Builder.d.ts +4 -2
- package/dist/entry/content/adapters/react/Builder.js +11 -5
- package/dist/entry/content/adapters/react/Builder.js.map +1 -1
- package/dist/entry/content/adapters/react/Node.js +2 -2
- package/dist/entry/content/adapters/react/Node.js.map +1 -1
- package/dist/entry/content/adapters/react/definition.d.ts +2 -0
- package/dist/entry/content/adapters/react/{resolvers/definition.js → definition.js} +1 -1
- package/dist/entry/content/adapters/react/definition.js.map +1 -0
- package/dist/entry/content/adapters/react/index.d.ts +1 -1
- package/dist/entry/content/adapters/react/index.js +1 -1
- package/dist/entry/content/adapters/react/index.js.map +1 -1
- package/dist/entry/content/adapters/vanilla/Builder.d.ts +4 -2
- package/dist/entry/content/adapters/vanilla/Builder.js +14 -5
- package/dist/entry/content/adapters/vanilla/Builder.js.map +1 -1
- package/dist/entry/content/adapters/vanilla/definition.d.ts +2 -0
- package/dist/entry/content/adapters/vanilla/{resolvers/definition.js → definition.js} +2 -2
- package/dist/entry/content/adapters/vanilla/definition.js.map +1 -0
- package/dist/entry/content/adapters/vanilla/index.d.ts +1 -1
- package/dist/entry/content/adapters/vanilla/index.js +1 -1
- package/dist/entry/content/adapters/vanilla/index.js.map +1 -1
- package/dist/entry/content/adapters/vanilla/utils.d.ts +1 -0
- package/dist/entry/content/adapters/vanilla/utils.js +7 -0
- package/dist/entry/content/adapters/vanilla/utils.js.map +1 -0
- package/dist/entry/content/lifecycle/Builder.d.ts +10 -4
- package/dist/entry/content/lifecycle/Builder.js +102 -60
- package/dist/entry/content/lifecycle/Builder.js.map +1 -1
- package/dist/entry/content/lifecycle/MountBuilder.d.ts +6 -3
- package/dist/entry/content/lifecycle/MountBuilder.js +32 -16
- package/dist/entry/content/lifecycle/MountBuilder.js.map +1 -1
- package/dist/entry/content/lifecycle/context/ContainerRegistry.d.ts +7 -0
- package/dist/entry/content/lifecycle/context/ContainerRegistry.js +45 -0
- package/dist/entry/content/lifecycle/context/ContainerRegistry.js.map +1 -0
- package/dist/entry/content/lifecycle/context/Context.d.ts +6 -3
- package/dist/entry/content/lifecycle/context/Context.js +21 -6
- package/dist/entry/content/lifecycle/context/Context.js.map +1 -1
- package/dist/entry/content/lifecycle/context/ManagedContext.d.ts +4 -1
- package/dist/entry/content/lifecycle/context/ManagedContext.js +7 -0
- package/dist/entry/content/lifecycle/context/ManagedContext.js.map +1 -1
- package/dist/entry/content/lifecycle/context/index.d.ts +1 -0
- package/dist/entry/content/lifecycle/context/index.js +6 -4
- package/dist/entry/content/lifecycle/context/index.js.map +1 -1
- package/dist/entry/content/lifecycle/markers/AttributeMarker.js +3 -1
- package/dist/entry/content/lifecycle/markers/AttributeMarker.js.map +1 -1
- package/dist/entry/content/lifecycle/nodes/EventNode.d.ts +4 -2
- package/dist/entry/content/lifecycle/nodes/EventNode.js +7 -2
- package/dist/entry/content/lifecycle/nodes/EventNode.js.map +1 -1
- package/dist/entry/content/lifecycle/nodes/FrameNode.d.ts +2 -1
- package/dist/entry/content/lifecycle/nodes/FrameNode.js +3 -0
- package/dist/entry/content/lifecycle/nodes/FrameNode.js.map +1 -1
- package/dist/entry/content/lifecycle/nodes/MarkerNode.d.ts +1 -1
- package/dist/entry/content/lifecycle/nodes/MarkerNode.js.map +1 -1
- package/dist/entry/content/lifecycle/nodes/MountNode.d.ts +7 -3
- package/dist/entry/content/lifecycle/nodes/MountNode.js +47 -12
- package/dist/entry/content/lifecycle/nodes/MountNode.js.map +1 -1
- package/dist/entry/content/lifecycle/nodes/Node.d.ts +1 -1
- package/dist/entry/content/lifecycle/nodes/Node.js.map +1 -1
- package/dist/entry/content/lifecycle/nodes/RenderNode.d.ts +13 -4
- package/dist/entry/content/lifecycle/nodes/RenderNode.js +71 -6
- package/dist/entry/content/lifecycle/nodes/RenderNode.js.map +1 -1
- package/dist/entry/content/lifecycle/nodes/ShadowNode.d.ts +2 -1
- package/dist/entry/content/lifecycle/nodes/ShadowNode.js +3 -0
- package/dist/entry/content/lifecycle/nodes/ShadowNode.js.map +1 -1
- package/dist/entry/content/lifecycle/types.d.ts +28 -0
- package/dist/entry/content/resolvers/watch.d.ts +1 -1
- package/dist/entry/content/resolvers/watch.js +29 -14
- package/dist/entry/content/resolvers/watch.js.map +1 -1
- package/dist/entry/relay/index.js.map +1 -1
- package/dist/shared/locale/index.d.ts +1 -1
- package/dist/shared/locale/index.js +3 -1
- package/dist/shared/locale/index.js.map +1 -1
- package/dist/shared/locale/messages.d.ts +4 -0
- package/dist/shared/locale/messages.js +12 -0
- package/dist/shared/locale/messages.js.map +1 -1
- package/dist/types/content/common.d.ts +8 -0
- package/dist/types/content/common.js.map +1 -1
- package/dist/types/content/definition.d.ts +5 -0
- package/dist/types/locale.d.ts +3 -0
- package/dist/types/locale.js.map +1 -1
- package/package.json +1 -3
- package/types/client.d.ts +3 -3
- package/dist/cli/plugins/style/types.d.ts +0 -5
- package/dist/entry/content/adapters/react/resolvers/definition.d.ts +0 -2
- package/dist/entry/content/adapters/react/resolvers/definition.js.map +0 -1
- package/dist/entry/content/adapters/react/resolvers/render.d.ts +0 -2
- package/dist/entry/content/adapters/react/resolvers/render.js +0 -9
- package/dist/entry/content/adapters/react/resolvers/render.js.map +0 -1
- package/dist/entry/content/adapters/vanilla/resolvers/definition.d.ts +0 -2
- package/dist/entry/content/adapters/vanilla/resolvers/definition.js.map +0 -1
- package/dist/entry/content/adapters/vanilla/resolvers/render.d.ts +0 -3
- package/dist/entry/content/adapters/vanilla/resolvers/render.js +0 -15
- package/dist/entry/content/adapters/vanilla/resolvers/render.js.map +0 -1
- /package/dist/{cli/plugins/style → entry/content/lifecycle}/types.js +0 -0
- /package/dist/{cli/plugins/style → entry/content/lifecycle}/types.js.map +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { isContentScriptFrameNavigation, resolveContentScriptIsolation } from "./../../../shared/content/index.js";
|
|
2
|
-
import AwaitLock from "await-lock";
|
|
3
2
|
import EntrypointBuilder from "./../../../entry/core/Builder.js";
|
|
4
3
|
import {
|
|
5
4
|
createAnchorResolver,
|
|
@@ -17,7 +16,7 @@ import {
|
|
|
17
16
|
ContentScriptMarker
|
|
18
17
|
} from "./../../../types/content/index.js";
|
|
19
18
|
class Builder extends EntrypointBuilder {
|
|
20
|
-
|
|
19
|
+
cycle;
|
|
21
20
|
generation = 0;
|
|
22
21
|
definition;
|
|
23
22
|
emitter = new EventEmitter();
|
|
@@ -27,27 +26,15 @@ class Builder extends EntrypointBuilder {
|
|
|
27
26
|
constructor(input) {
|
|
28
27
|
super();
|
|
29
28
|
const definition = input;
|
|
30
|
-
const isolation = resolveContentScriptIsolation(definition.isolation, "render" in definition);
|
|
31
|
-
if (definition.boundary !== void 0) {
|
|
32
|
-
if (typeof definition.boundary !== "function") {
|
|
33
|
-
throw new Error("Content script boundary must be a synchronous setup handler");
|
|
34
|
-
}
|
|
35
|
-
if (isolation.type === "none") {
|
|
36
|
-
throw new Error("Content script boundary requires Shadow DOM or an iframe");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (definition.target !== void 0 && (isolation.type === "none" || isContentScriptFrameNavigation(isolation))) {
|
|
40
|
-
throw new Error("Content script target requires Shadow DOM or an iframe with local rendering");
|
|
41
|
-
}
|
|
42
29
|
this.definition = {
|
|
43
30
|
...definition,
|
|
44
31
|
marker: this.resolveMarker(definition.marker),
|
|
45
32
|
anchor: this.resolveAnchor(definition.anchor),
|
|
46
33
|
mount: this.resolveMount(definition.mount),
|
|
47
34
|
container: this.resolveContainer(definition.container),
|
|
48
|
-
target:
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
target: this.resolveTarget(definition.target),
|
|
36
|
+
isolation: this.resolveIsolation(definition),
|
|
37
|
+
render: this.resolveRender(definition.render),
|
|
51
38
|
watch: this.resolveWatch(definition.watch)
|
|
52
39
|
};
|
|
53
40
|
}
|
|
@@ -80,11 +67,29 @@ class Builder extends EntrypointBuilder {
|
|
|
80
67
|
resolveContainer(container) {
|
|
81
68
|
return createContainerResolver(container);
|
|
82
69
|
}
|
|
70
|
+
resolveTarget(target) {
|
|
71
|
+
return createTargetResolver(target);
|
|
72
|
+
}
|
|
73
|
+
resolveIsolation(definition) {
|
|
74
|
+
const isolation = resolveContentScriptIsolation(definition.isolation, "render" in definition);
|
|
75
|
+
if (definition.boundary !== void 0) {
|
|
76
|
+
if (typeof definition.boundary !== "function") {
|
|
77
|
+
throw new Error("Content script boundary must be a synchronous setup handler");
|
|
78
|
+
}
|
|
79
|
+
if (isolation.type === "none") {
|
|
80
|
+
throw new Error("Content script boundary requires Shadow DOM or an iframe");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (definition.target !== void 0 && (isolation.type === "none" || isContentScriptFrameNavigation(isolation))) {
|
|
84
|
+
throw new Error("Content script target requires Shadow DOM or an iframe with local rendering");
|
|
85
|
+
}
|
|
86
|
+
return isolation;
|
|
87
|
+
}
|
|
83
88
|
resolveRender(render) {
|
|
84
|
-
if (render
|
|
85
|
-
|
|
89
|
+
if (render === true || render === void 0) {
|
|
90
|
+
return render;
|
|
86
91
|
}
|
|
87
|
-
|
|
92
|
+
throw new Error("Content script rendering requires a renderer adapter");
|
|
88
93
|
}
|
|
89
94
|
resolveWatch(watch) {
|
|
90
95
|
if (watch === void 0) {
|
|
@@ -105,42 +110,38 @@ class Builder extends EntrypointBuilder {
|
|
|
105
110
|
return;
|
|
106
111
|
}
|
|
107
112
|
const { render, prepare, main, anchor, marker, container, boundary, target, watch, mount, ...options } = this.definition;
|
|
108
|
-
const resolvedMarker = await marker(options);
|
|
109
|
-
if (generation !== this.generation) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
this.marker = resolvedMarker;
|
|
113
113
|
await (main == null ? void 0 : main(this.context, options));
|
|
114
114
|
if (generation !== this.generation) {
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
117
|
if (render !== void 0 || prepare !== void 0 || isContentScriptFrameNavigation(this.definition.isolation)) {
|
|
118
|
-
await
|
|
118
|
+
const resolvedMarker = await marker(options);
|
|
119
119
|
if (generation !== this.generation) {
|
|
120
120
|
return;
|
|
121
121
|
}
|
|
122
|
-
this.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
}, this.context);
|
|
122
|
+
this.marker = resolvedMarker;
|
|
123
|
+
await this.requestProcessing(generation);
|
|
124
|
+
if (generation !== this.generation) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const onError = (error) => {
|
|
128
|
+
console.error("Content script processing on watch error", error);
|
|
129
|
+
};
|
|
130
|
+
this.unwatch = watch(() => this.requestProcessing(generation, onError), this.context);
|
|
133
131
|
}
|
|
134
132
|
}
|
|
135
133
|
async destroy() {
|
|
136
134
|
var _a;
|
|
137
135
|
this.generation++;
|
|
138
|
-
this.
|
|
136
|
+
this.cycle = void 0;
|
|
139
137
|
(_a = this.unwatch) == null ? void 0 : _a.call(this);
|
|
140
138
|
this.unwatch = void 0;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
try {
|
|
140
|
+
this.context.clear();
|
|
141
|
+
} finally {
|
|
142
|
+
this.context.unwatch();
|
|
143
|
+
this.marker.reset();
|
|
144
|
+
}
|
|
144
145
|
}
|
|
145
146
|
getPrepareProps(anchor) {
|
|
146
147
|
const {
|
|
@@ -158,46 +159,75 @@ class Builder extends EntrypointBuilder {
|
|
|
158
159
|
} = this.definition;
|
|
159
160
|
return { ...options, anchor };
|
|
160
161
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
requestProcessing(generation, onError) {
|
|
163
|
+
var _a;
|
|
164
|
+
if (generation !== this.generation) {
|
|
165
|
+
return Promise.resolve();
|
|
166
|
+
}
|
|
167
|
+
if (((_a = this.cycle) == null ? void 0 : _a.generation) === generation) {
|
|
168
|
+
this.cycle.pending = true;
|
|
169
|
+
return this.cycle.promise;
|
|
170
|
+
}
|
|
171
|
+
const cycle = {
|
|
172
|
+
generation,
|
|
173
|
+
pending: true,
|
|
174
|
+
promise: Promise.resolve().then(() => this.drainProcessing(cycle))
|
|
175
|
+
};
|
|
176
|
+
if (onError) {
|
|
177
|
+
cycle.promise = cycle.promise.catch(onError);
|
|
178
|
+
}
|
|
179
|
+
this.cycle = cycle;
|
|
180
|
+
return cycle.promise;
|
|
181
|
+
}
|
|
182
|
+
async drainProcessing(cycle) {
|
|
164
183
|
try {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const anchors = this.marker.for(anchor).unmarked().filter((anchor2) => anchor2.isConnected);
|
|
173
|
-
const results = await Promise.allSettled(anchors.map((anchor2) => this.processAnchor(anchor2, generation)));
|
|
174
|
-
const errors = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
175
|
-
if (errors.length && generation === this.generation) {
|
|
176
|
-
console.error(new AggregateError(errors, "Content script anchor processing failed"));
|
|
184
|
+
while (cycle.pending && cycle.generation === this.generation) {
|
|
185
|
+
cycle.pending = false;
|
|
186
|
+
this.context.mount();
|
|
187
|
+
if (cycle.generation !== this.generation) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
await this.processing(cycle.generation);
|
|
177
191
|
}
|
|
178
192
|
} finally {
|
|
179
|
-
|
|
193
|
+
if (this.cycle === cycle) {
|
|
194
|
+
this.cycle = void 0;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async processing(generation) {
|
|
199
|
+
const anchor = await this.definition.anchor();
|
|
200
|
+
if (generation !== this.generation) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const anchors = this.marker.for(anchor).unmarked().filter((anchor2) => anchor2.isConnected);
|
|
204
|
+
const results = await Promise.allSettled(anchors.map((anchor2) => this.processAnchor(anchor2, generation)));
|
|
205
|
+
const errors = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
206
|
+
if (errors.length && generation === this.generation) {
|
|
207
|
+
console.error(new AggregateError(errors, "Content script anchor processing failed"));
|
|
180
208
|
}
|
|
181
209
|
}
|
|
182
210
|
async processAnchor(anchor, generation) {
|
|
183
|
-
var _a, _b, _c;
|
|
211
|
+
var _a, _b, _c, _d;
|
|
184
212
|
const current = () => generation === this.generation && anchor.isConnected;
|
|
185
213
|
const data = await ((_b = (_a = this.definition).prepare) == null ? void 0 : _b.call(_a, this.getPrepareProps(anchor)));
|
|
186
214
|
if (!current()) {
|
|
187
215
|
return;
|
|
188
216
|
}
|
|
189
|
-
const
|
|
217
|
+
const assembly = await this.createNode(anchor, data);
|
|
218
|
+
const node = new EventNode(assembly.node, this.emitter, assembly.renderer);
|
|
190
219
|
if (!current()) {
|
|
191
220
|
node.unmount();
|
|
192
221
|
return;
|
|
193
222
|
}
|
|
223
|
+
(_c = assembly.renderer) == null ? void 0 : _c.setErrorHandler((error) => this.handleRenderError(node, error, generation));
|
|
194
224
|
this.context.add(node);
|
|
195
225
|
if (generation !== this.generation) {
|
|
196
226
|
return;
|
|
197
227
|
}
|
|
198
228
|
try {
|
|
199
229
|
node.mount();
|
|
200
|
-
if (!current() && !((
|
|
230
|
+
if (!current() && !((_d = node.container) == null ? void 0 : _d.isConnected)) {
|
|
201
231
|
this.context.remove(node);
|
|
202
232
|
}
|
|
203
233
|
} catch (error) {
|
|
@@ -205,6 +235,18 @@ class Builder extends EntrypointBuilder {
|
|
|
205
235
|
throw error;
|
|
206
236
|
}
|
|
207
237
|
}
|
|
238
|
+
handleRenderError(node, error, generation) {
|
|
239
|
+
if (generation !== this.generation) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const errors = [error];
|
|
243
|
+
try {
|
|
244
|
+
this.context.remove(node);
|
|
245
|
+
} catch (cause) {
|
|
246
|
+
errors.push(cause);
|
|
247
|
+
}
|
|
248
|
+
console.error(new AggregateError(errors, "Content script deferred mount failed"));
|
|
249
|
+
}
|
|
208
250
|
}
|
|
209
251
|
export {
|
|
210
252
|
Builder as default
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/entry/content/lifecycle/Builder.ts"],"sourcesContent":["import {isContentScriptFrameNavigation, resolveContentScriptIsolation} from \"@shared/content\";\nimport AwaitLock from \"await-lock\";\n\nimport EntrypointBuilder from \"@entry/core/Builder\";\n\nimport {\n createAnchorResolver,\n createAwaitFirstStrategy,\n createContainerResolver,\n createTargetResolver,\n withLocationTracking,\n createAppendMountHandler,\n createMutationObserverStrategy,\n} from \"../resolvers\";\n\nimport {ManagedContext, EventEmitter} from \"./context\";\nimport {AttributeMarker, WeakMarker} from \"./markers\";\nimport {EventNode} from \"./nodes\";\n\nimport {\n ContentScriptAnchor,\n ContentScriptAnchorGetter,\n ContentScriptBuilder,\n ContentScriptContainerCreator,\n ContentScriptContainerFactory,\n ContentScriptContainerOptions,\n ContentScriptContainerTag,\n ContentScriptContext,\n ContentScriptDefinition,\n ContentScriptIsolation,\n ContentScriptMarker,\n ContentScriptMarkerContract,\n ContentScriptMarkerGetter,\n ContentScriptMarkerResolver,\n ContentScriptMarkerType,\n ContentScriptMountFunction,\n ContentScriptNode,\n ContentScriptPrepareProps,\n ContentScriptOptions,\n ContentScriptRenderHandler,\n ContentScriptRenderValue,\n ContentScriptResolvedDefinition,\n ContentScriptWatchStrategy,\n} from \"@typing/content\";\n\nexport default abstract class Builder<\n Data = unknown,\n Isolation extends `${ContentScriptIsolation}` = `${ContentScriptIsolation}`,\n>\n extends EntrypointBuilder\n implements ContentScriptBuilder\n{\n private lock = new AwaitLock();\n\n protected generation = 0;\n\n protected readonly definition: ContentScriptResolvedDefinition<Data>;\n\n protected readonly emitter = new EventEmitter();\n\n protected readonly context = new ManagedContext(this.emitter);\n\n protected marker: ContentScriptMarkerContract = new AttributeMarker();\n\n protected unwatch?: () => void;\n\n protected abstract createNode(anchor: Element, data: Data, enabled: boolean): Promise<ContentScriptNode>;\n\n protected constructor(input: ContentScriptDefinition<Data, Isolation>) {\n super();\n\n // Normalization selects the isolation at runtime; its node supplies the matching callback props.\n const definition = input as ContentScriptDefinition<Data>;\n const isolation = resolveContentScriptIsolation(definition.isolation, \"render\" in definition);\n\n if (definition.boundary !== undefined) {\n if (typeof definition.boundary !== \"function\") {\n throw new Error(\"Content script boundary must be a synchronous setup handler\");\n }\n\n if (isolation.type === \"none\") {\n throw new Error(\"Content script boundary requires Shadow DOM or an iframe\");\n }\n }\n\n if (\n definition.target !== undefined &&\n (isolation.type === \"none\" || isContentScriptFrameNavigation(isolation))\n ) {\n throw new Error(\"Content script target requires Shadow DOM or an iframe with local rendering\");\n }\n\n this.definition = {\n ...definition,\n marker: this.resolveMarker(definition.marker),\n anchor: this.resolveAnchor(definition.anchor),\n mount: this.resolveMount(definition.mount),\n container: this.resolveContainer(definition.container),\n target: createTargetResolver(definition.target),\n render: definition.render === true ? true : this.resolveRender(definition.render),\n isolation,\n watch: this.resolveWatch(definition.watch),\n };\n }\n\n protected resolveMarker(marker: ContentScriptMarkerType | ContentScriptMarkerGetter): ContentScriptMarkerResolver {\n return async (options: ContentScriptOptions) => {\n if (typeof marker === \"function\") {\n marker = await marker(options);\n }\n\n if (!marker) {\n marker = ContentScriptMarker.Attribute;\n }\n\n if (typeof marker === \"string\") {\n switch (marker) {\n case ContentScriptMarker.Weak:\n return new WeakMarker();\n\n case ContentScriptMarker.Attribute:\n default:\n return new AttributeMarker();\n }\n }\n\n return marker;\n };\n }\n\n protected resolveAnchor(anchor?: ContentScriptAnchor | ContentScriptAnchorGetter): ContentScriptAnchorGetter {\n return createAnchorResolver(anchor);\n }\n\n protected resolveMount(mount?: ContentScriptMountFunction): ContentScriptMountFunction {\n return mount || createAppendMountHandler();\n }\n\n protected resolveContainer(\n container?: ContentScriptContainerTag | ContentScriptContainerOptions | ContentScriptContainerFactory<Data>\n ): ContentScriptContainerCreator<Data> {\n return createContainerResolver(container);\n }\n\n protected resolveRender(\n render?: ContentScriptRenderValue<Data> | ContentScriptRenderHandler<Data>\n ): ContentScriptRenderHandler<Data> | undefined {\n if (render !== undefined) {\n throw new Error(\"Content script rendering requires a renderer adapter\");\n }\n\n return undefined;\n }\n\n protected resolveWatch(watch?: true | ContentScriptWatchStrategy): ContentScriptWatchStrategy {\n if (watch === undefined) {\n watch = createAwaitFirstStrategy();\n } else if (watch === true) {\n watch = createMutationObserverStrategy();\n }\n\n return withLocationTracking(watch);\n }\n\n public getContext(): ContentScriptContext {\n return this.context;\n }\n\n public async build(): Promise<void> {\n const destroying = this.destroy();\n const generation = this.generation;\n await destroying;\n\n if (generation !== this.generation) {\n return;\n }\n\n const {render, prepare, main, anchor, marker, container, boundary, target, watch, mount, ...options} =\n this.definition;\n\n const resolvedMarker = await marker(options);\n\n if (generation !== this.generation) {\n return;\n }\n\n this.marker = resolvedMarker;\n\n await main?.(this.context, options);\n\n if (generation !== this.generation) {\n return;\n }\n\n if (\n render !== undefined ||\n prepare !== undefined ||\n isContentScriptFrameNavigation(this.definition.isolation)\n ) {\n await this.processing(generation);\n\n if (generation !== this.generation) {\n return;\n }\n\n this.unwatch = watch(async () => {\n if (generation !== this.generation) {\n return;\n }\n\n try {\n this.context.mount();\n await this.processing(generation);\n } catch (error) {\n console.error(\"Content script processing on watch error\", error);\n }\n }, this.context);\n }\n }\n\n public async destroy(): Promise<void> {\n this.generation++;\n this.lock = new AwaitLock();\n\n this.unwatch?.();\n this.unwatch = undefined;\n\n this.context.clear();\n this.context.unwatch();\n this.marker.reset();\n }\n\n protected getPrepareProps(anchor: Element): ContentScriptPrepareProps {\n const {\n anchor: _,\n marker,\n mount,\n watch,\n prepare,\n render,\n container,\n boundary,\n target,\n main,\n ...options\n } = this.definition;\n\n return {...options, anchor};\n }\n\n protected async processing(generation: number): Promise<void> {\n const lock = this.lock;\n await lock.acquireAsync();\n\n try {\n if (generation !== this.generation) {\n return;\n }\n\n const anchor = await this.definition.anchor();\n\n if (generation !== this.generation) {\n return;\n }\n\n const anchors = this.marker\n .for(anchor)\n .unmarked()\n .filter(anchor => anchor.isConnected);\n\n const results = await Promise.allSettled(anchors.map(anchor => this.processAnchor(anchor, generation)));\n const errors = results.flatMap(result => (result.status === \"rejected\" ? [result.reason] : []));\n\n if (errors.length && generation === this.generation) {\n console.error(new AggregateError(errors, \"Content script anchor processing failed\"));\n }\n } finally {\n lock.release();\n }\n }\n\n protected async processAnchor(anchor: Element, generation: number): Promise<void> {\n const current = () => generation === this.generation && anchor.isConnected;\n const data = await this.definition.prepare?.(this.getPrepareProps(anchor));\n\n if (!current()) {\n return;\n }\n\n const node = new EventNode(await this.createNode(anchor, data as Data, data !== false), this.emitter);\n\n if (!current()) {\n node.unmount();\n\n return;\n }\n\n this.context.add(node);\n\n if (generation !== this.generation) {\n return;\n }\n\n try {\n node.mount();\n\n if (!current() && !node.container?.isConnected) {\n this.context.remove(node);\n }\n } catch (error) {\n this.context.remove(node);\n throw error;\n }\n }\n}\n"],"mappings":"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","names":["anchor"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/entry/content/lifecycle/Builder.ts"],"sourcesContent":["import {isContentScriptFrameNavigation, resolveContentScriptIsolation} from \"@shared/content\";\n\nimport EntrypointBuilder from \"@entry/core/Builder\";\n\nimport {\n createAnchorResolver,\n createAwaitFirstStrategy,\n createContainerResolver,\n createTargetResolver,\n withLocationTracking,\n createAppendMountHandler,\n createMutationObserverStrategy,\n} from \"../resolvers\";\n\nimport {ManagedContext, EventEmitter} from \"./context\";\nimport {AttributeMarker, WeakMarker} from \"./markers\";\nimport {EventNode} from \"./nodes\";\n\nimport type {ContentScriptNodeAssembly, ContentScriptCycle} from \"./types\";\n\nimport {\n ContentScriptNode,\n ContentScriptAnchor,\n ContentScriptAnchorGetter,\n ContentScriptBuilder,\n ContentScriptContainerCreator,\n ContentScriptContainerFactory,\n ContentScriptContainerOptions,\n ContentScriptContainerTag,\n ContentScriptContext,\n ContentScriptDefinition,\n ContentScriptIsolation,\n ContentScriptIsolationOptions,\n ContentScriptMarker,\n ContentScriptMarkerContract,\n ContentScriptMarkerGetter,\n ContentScriptMarkerResolver,\n ContentScriptMarkerType,\n ContentScriptMountFunction,\n ContentScriptPrepareProps,\n ContentScriptPrepareResult,\n ContentScriptOptions,\n ContentScriptRenderHandler,\n ContentScriptRenderValue,\n ContentScriptResolvedDefinition,\n ContentScriptTarget,\n ContentScriptTargetCreator,\n ContentScriptWatchStrategy,\n} from \"@typing/content\";\n\nexport default abstract class Builder<\n Data = unknown,\n Isolation extends `${ContentScriptIsolation}` = `${ContentScriptIsolation}`,\n>\n extends EntrypointBuilder\n implements ContentScriptBuilder\n{\n private cycle?: ContentScriptCycle;\n\n protected generation = 0;\n\n protected readonly definition: ContentScriptResolvedDefinition<Data>;\n\n protected readonly emitter = new EventEmitter();\n\n protected readonly context = new ManagedContext(this.emitter);\n\n protected marker: ContentScriptMarkerContract = new AttributeMarker();\n\n protected unwatch?: () => void;\n\n protected abstract createNode(\n anchor: Element,\n result: ContentScriptPrepareResult<Data> | undefined\n ): Promise<ContentScriptNodeAssembly>;\n\n protected constructor(input: ContentScriptDefinition<Data, Isolation>) {\n super();\n\n // Normalization selects the isolation at runtime; its node supplies the matching callback props.\n const definition = input as ContentScriptDefinition<Data>;\n\n this.definition = {\n ...definition,\n marker: this.resolveMarker(definition.marker),\n anchor: this.resolveAnchor(definition.anchor),\n mount: this.resolveMount(definition.mount),\n container: this.resolveContainer(definition.container),\n target: this.resolveTarget(definition.target),\n isolation: this.resolveIsolation(definition),\n render: this.resolveRender(definition.render),\n watch: this.resolveWatch(definition.watch),\n };\n }\n\n protected resolveMarker(marker: ContentScriptMarkerType | ContentScriptMarkerGetter): ContentScriptMarkerResolver {\n return async (options: ContentScriptOptions) => {\n if (typeof marker === \"function\") {\n marker = await marker(options);\n }\n\n if (!marker) {\n marker = ContentScriptMarker.Attribute;\n }\n\n if (typeof marker === \"string\") {\n switch (marker) {\n case ContentScriptMarker.Weak:\n return new WeakMarker();\n\n case ContentScriptMarker.Attribute:\n default:\n return new AttributeMarker();\n }\n }\n\n return marker;\n };\n }\n\n protected resolveAnchor(anchor?: ContentScriptAnchor | ContentScriptAnchorGetter): ContentScriptAnchorGetter {\n return createAnchorResolver(anchor);\n }\n\n protected resolveMount(mount?: ContentScriptMountFunction): ContentScriptMountFunction {\n return mount || createAppendMountHandler();\n }\n\n protected resolveContainer(\n container?: ContentScriptContainerTag | ContentScriptContainerOptions | ContentScriptContainerFactory<Data>\n ): ContentScriptContainerCreator<Data> {\n return createContainerResolver(container);\n }\n\n protected resolveTarget(target?: ContentScriptTarget<Data>): ContentScriptTargetCreator<Data> {\n return createTargetResolver(target);\n }\n\n protected resolveIsolation(definition: ContentScriptDefinition<Data>): ContentScriptIsolationOptions {\n const isolation = resolveContentScriptIsolation(definition.isolation, \"render\" in definition);\n\n if (definition.boundary !== undefined) {\n if (typeof definition.boundary !== \"function\") {\n throw new Error(\"Content script boundary must be a synchronous setup handler\");\n }\n\n if (isolation.type === \"none\") {\n throw new Error(\"Content script boundary requires Shadow DOM or an iframe\");\n }\n }\n\n if (\n definition.target !== undefined &&\n (isolation.type === \"none\" || isContentScriptFrameNavigation(isolation))\n ) {\n throw new Error(\"Content script target requires Shadow DOM or an iframe with local rendering\");\n }\n\n return isolation;\n }\n\n protected resolveRender(\n render?: ContentScriptRenderValue<Data> | ContentScriptRenderHandler<Data>\n ): true | ContentScriptRenderHandler<Data> | undefined {\n if (render === true || render === undefined) {\n return render;\n }\n\n throw new Error(\"Content script rendering requires a renderer adapter\");\n }\n\n protected resolveWatch(watch?: true | ContentScriptWatchStrategy): ContentScriptWatchStrategy {\n if (watch === undefined) {\n watch = createAwaitFirstStrategy();\n } else if (watch === true) {\n watch = createMutationObserverStrategy();\n }\n\n return withLocationTracking(watch);\n }\n\n public getContext(): ContentScriptContext {\n return this.context;\n }\n\n public async build(): Promise<void> {\n const destroying = this.destroy();\n const generation = this.generation;\n await destroying;\n\n if (generation !== this.generation) {\n return;\n }\n\n const {render, prepare, main, anchor, marker, container, boundary, target, watch, mount, ...options} =\n this.definition;\n\n await main?.(this.context, options);\n\n if (generation !== this.generation) {\n return;\n }\n\n if (\n render !== undefined ||\n prepare !== undefined ||\n isContentScriptFrameNavigation(this.definition.isolation)\n ) {\n const resolvedMarker = await marker(options);\n\n if (generation !== this.generation) {\n return;\n }\n\n this.marker = resolvedMarker;\n\n await this.requestProcessing(generation);\n\n if (generation !== this.generation) {\n return;\n }\n\n const onError = (error: unknown): void => {\n console.error(\"Content script processing on watch error\", error);\n };\n\n this.unwatch = watch(() => this.requestProcessing(generation, onError), this.context);\n }\n }\n\n public async destroy(): Promise<void> {\n this.generation++;\n this.cycle = undefined;\n\n this.unwatch?.();\n this.unwatch = undefined;\n\n try {\n this.context.clear();\n } finally {\n this.context.unwatch();\n this.marker.reset();\n }\n }\n\n protected getPrepareProps(anchor: Element): ContentScriptPrepareProps {\n const {\n anchor: _,\n marker,\n mount,\n watch,\n prepare,\n render,\n container,\n boundary,\n target,\n main,\n ...options\n } = this.definition;\n\n return {...options, anchor};\n }\n\n private requestProcessing(generation: number, onError?: (error: unknown) => void): Promise<void> {\n if (generation !== this.generation) {\n return Promise.resolve();\n }\n\n if (this.cycle?.generation === generation) {\n this.cycle.pending = true;\n\n return this.cycle.promise;\n }\n\n const cycle: ContentScriptCycle = {\n generation,\n pending: true,\n promise: Promise.resolve().then(() => this.drainProcessing(cycle)),\n };\n\n if (onError) {\n // One handler per cycle, not one suspended async callback per watch notification.\n cycle.promise = cycle.promise.catch(onError);\n }\n\n this.cycle = cycle;\n\n return cycle.promise;\n }\n\n private async drainProcessing(cycle: ContentScriptCycle): Promise<void> {\n try {\n while (cycle.pending && cycle.generation === this.generation) {\n cycle.pending = false;\n this.context.mount();\n\n if (cycle.generation !== this.generation) {\n return;\n }\n\n await this.processing(cycle.generation);\n }\n } finally {\n if (this.cycle === cycle) {\n this.cycle = undefined;\n }\n }\n }\n\n protected async processing(generation: number): Promise<void> {\n const anchor = await this.definition.anchor();\n\n if (generation !== this.generation) {\n return;\n }\n\n const anchors = this.marker\n .for(anchor)\n .unmarked()\n .filter(anchor => anchor.isConnected);\n\n const results = await Promise.allSettled(anchors.map(anchor => this.processAnchor(anchor, generation)));\n const errors = results.flatMap(result => (result.status === \"rejected\" ? [result.reason] : []));\n\n if (errors.length && generation === this.generation) {\n console.error(new AggregateError(errors, \"Content script anchor processing failed\"));\n }\n }\n\n protected async processAnchor(anchor: Element, generation: number): Promise<void> {\n const current = () => generation === this.generation && anchor.isConnected;\n const data = await this.definition.prepare?.(this.getPrepareProps(anchor));\n\n if (!current()) {\n return;\n }\n\n const assembly = await this.createNode(anchor, data);\n const node = new EventNode(assembly.node, this.emitter, assembly.renderer);\n\n if (!current()) {\n node.unmount();\n\n return;\n }\n\n // Add listeners can mount immediately, so connect the renderer before publishing the node.\n assembly.renderer?.setErrorHandler(error => this.handleRenderError(node, error, generation));\n this.context.add(node);\n\n if (generation !== this.generation) {\n return;\n }\n\n try {\n node.mount();\n\n if (!current() && !node.container?.isConnected) {\n this.context.remove(node);\n }\n } catch (error) {\n this.context.remove(node);\n throw error;\n }\n }\n\n private handleRenderError(node: ContentScriptNode, error: unknown, generation: number): void {\n if (generation !== this.generation) {\n return;\n }\n\n const errors = [error];\n\n try {\n this.context.remove(node);\n } catch (cause) {\n errors.push(cause);\n }\n\n console.error(new AggregateError(errors, \"Content script deferred mount failed\"));\n }\n}\n"],"mappings":"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","names":["anchor"]}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import Builder from "./Builder.js";
|
|
2
|
-
import {
|
|
2
|
+
import type { ContentScriptIsolationAssembly, ContentScriptNodeAssembly, ContentScriptRenderLifecycle, ContentScriptRenderOptions } from "./types.js";
|
|
3
|
+
import { ContentScriptDefinition, ContentScriptIsolation, ContentScriptNode, ContentScriptPrepareResult, ContentScriptProps, ContentScriptRenderHandler } from "../../../types/content/index.js";
|
|
3
4
|
export default class MountBuilder<Data = unknown, Isolation extends `${ContentScriptIsolation}` = `${ContentScriptIsolation}`> extends Builder<Data, Isolation> {
|
|
4
5
|
constructor(definition: ContentScriptDefinition<Data, Isolation>);
|
|
5
6
|
protected getProps(node: ContentScriptNode, data: Data): ContentScriptProps<Data>;
|
|
6
|
-
protected createNode(anchor: Element,
|
|
7
|
-
protected
|
|
7
|
+
protected createNode(anchor: Element, result: ContentScriptPrepareResult<Data> | undefined): Promise<ContentScriptNodeAssembly>;
|
|
8
|
+
protected createMountNode(anchor: Element, data: Data): Promise<ContentScriptNode>;
|
|
9
|
+
protected createIsolation(node: ContentScriptNode, data: Data): ContentScriptIsolationAssembly;
|
|
10
|
+
protected createRenderer(node: ContentScriptNode, render: ContentScriptRenderHandler<Data>, props: () => ContentScriptProps<Data>, options: ContentScriptRenderOptions): ContentScriptNode & ContentScriptRenderLifecycle;
|
|
8
11
|
}
|
|
@@ -21,33 +21,49 @@ class MountBuilder extends Builder {
|
|
|
21
21
|
boundary: node.boundary
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
async createNode(anchor,
|
|
24
|
+
async createNode(anchor, result) {
|
|
25
25
|
const navigation = isContentScriptFrameNavigation(this.definition.isolation);
|
|
26
26
|
const render = this.definition.render;
|
|
27
|
-
if (
|
|
28
|
-
return new MarkerNode(new Node(anchor), this.marker);
|
|
27
|
+
if (result === false || !navigation && (render === void 0 || render === true)) {
|
|
28
|
+
return { node: new MarkerNode(new Node(anchor), this.marker) };
|
|
29
29
|
}
|
|
30
|
+
const data = result;
|
|
31
|
+
const mountedNode = await this.createMountNode(anchor, data);
|
|
32
|
+
const { node, ready } = this.createIsolation(mountedNode, data);
|
|
33
|
+
if (navigation || typeof render !== "function") {
|
|
34
|
+
return { node };
|
|
35
|
+
}
|
|
36
|
+
const renderer = this.createRenderer(node, render, () => this.getProps(node, data), { ready });
|
|
37
|
+
return { node: renderer, renderer };
|
|
38
|
+
}
|
|
39
|
+
async createMountNode(anchor, data) {
|
|
30
40
|
const marker = this.marker;
|
|
31
41
|
const container = await this.definition.container({ ...this.getPrepareProps(anchor), data });
|
|
32
|
-
|
|
42
|
+
return new MountNode(
|
|
43
|
+
new MarkerNode(new Node(anchor, container), marker),
|
|
44
|
+
this.context.containers,
|
|
45
|
+
this.definition.mount
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
createIsolation(node, data) {
|
|
49
|
+
const options = this.definition.isolation;
|
|
50
|
+
if (options.type === ContentScriptIsolation.None) {
|
|
51
|
+
return { node };
|
|
52
|
+
}
|
|
33
53
|
const setup = new IsolationSetup({
|
|
34
|
-
props: () => ({ ...this.getPrepareProps(anchor), data }),
|
|
35
|
-
container: () =>
|
|
54
|
+
props: () => ({ ...this.getPrepareProps(node.anchor), data }),
|
|
55
|
+
container: () => node.container,
|
|
36
56
|
boundary: this.definition.boundary,
|
|
37
57
|
target: this.definition.target
|
|
38
58
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
node = new ShadowNode(mountedNode, this.definition.isolation, setup);
|
|
43
|
-
break;
|
|
44
|
-
case ContentScriptIsolation.Iframe:
|
|
45
|
-
node = new FrameNode(mountedNode, this.definition.isolation, () => this.context.mount(), setup);
|
|
46
|
-
break;
|
|
59
|
+
if (options.type === ContentScriptIsolation.Shadow) {
|
|
60
|
+
const shadow = new ShadowNode(node, options, setup);
|
|
61
|
+
return { node: shadow, ready: () => shadow.ready() };
|
|
47
62
|
}
|
|
48
|
-
|
|
63
|
+
const frame = new FrameNode(node, options, () => this.context.mount(), setup);
|
|
64
|
+
return { node: frame, ready: () => frame.ready() };
|
|
49
65
|
}
|
|
50
|
-
createRenderer(node, render, props) {
|
|
66
|
+
createRenderer(node, render, props, options) {
|
|
51
67
|
throw new Error("Content script rendering requires a renderer adapter");
|
|
52
68
|
}
|
|
53
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/entry/content/lifecycle/MountBuilder.ts"],"sourcesContent":["import Builder from \"./Builder\";\nimport IsolationSetup from \"./IsolationSetup\";\nimport {FrameNode, MountNode, MarkerNode, ShadowNode, Node} from \"./nodes\";\nimport {isContentScriptFrameNavigation} from \"@shared/content\";\n\nimport {\n ContentScriptDefinition,\n ContentScriptIsolation,\n ContentScriptNode,\n ContentScriptProps,\n ContentScriptRenderHandler,\n} from \"@typing/content\";\n\nexport default class MountBuilder<\n Data = unknown,\n Isolation extends `${ContentScriptIsolation}` = `${ContentScriptIsolation}`,\n> extends Builder<Data, Isolation> {\n public constructor(definition: ContentScriptDefinition<Data, Isolation>) {\n super(definition);\n }\n\n protected getProps(node: ContentScriptNode, data: Data): ContentScriptProps<Data> {\n if (!node.container || !node.target) {\n throw new Error(\"Content script render requires a container and target\");\n }\n\n return {\n ...this.getPrepareProps(node.anchor),\n data,\n container: node.container,\n target: node.target,\n boundary: node.boundary,\n };\n }\n\n protected async createNode(anchor: Element
|
|
1
|
+
{"version":3,"sources":["../../../../src/entry/content/lifecycle/MountBuilder.ts"],"sourcesContent":["import Builder from \"./Builder\";\nimport IsolationSetup from \"./IsolationSetup\";\nimport {FrameNode, MountNode, MarkerNode, ShadowNode, Node} from \"./nodes\";\n\nimport {isContentScriptFrameNavigation} from \"@shared/content\";\n\nimport type {\n ContentScriptIsolationAssembly,\n ContentScriptNodeAssembly,\n ContentScriptRenderLifecycle,\n ContentScriptRenderOptions,\n} from \"./types\";\n\nimport {\n ContentScriptDefinition,\n ContentScriptIsolation,\n ContentScriptNode,\n ContentScriptPrepareResult,\n ContentScriptProps,\n ContentScriptRenderHandler,\n} from \"@typing/content\";\n\nexport default class MountBuilder<\n Data = unknown,\n Isolation extends `${ContentScriptIsolation}` = `${ContentScriptIsolation}`,\n> extends Builder<Data, Isolation> {\n public constructor(definition: ContentScriptDefinition<Data, Isolation>) {\n super(definition);\n }\n\n protected getProps(node: ContentScriptNode, data: Data): ContentScriptProps<Data> {\n if (!node.container || !node.target) {\n throw new Error(\"Content script render requires a container and target\");\n }\n\n return {\n ...this.getPrepareProps(node.anchor),\n data,\n container: node.container,\n target: node.target,\n boundary: node.boundary,\n };\n }\n\n protected async createNode(\n anchor: Element,\n result: ContentScriptPrepareResult<Data> | undefined\n ): Promise<ContentScriptNodeAssembly> {\n const navigation = isContentScriptFrameNavigation(this.definition.isolation);\n const render = this.definition.render;\n\n if (result === false || (!navigation && (render === undefined || render === true))) {\n return {node: new MarkerNode(new Node(anchor), this.marker)};\n }\n\n const data = result as Data;\n const mountedNode = await this.createMountNode(anchor, data);\n const {node, ready} = this.createIsolation(mountedNode, data);\n\n if (navigation || typeof render !== \"function\") {\n return {node};\n }\n\n const renderer = this.createRenderer(node, render, () => this.getProps(node, data), {ready});\n\n return {node: renderer, renderer};\n }\n\n protected async createMountNode(anchor: Element, data: Data): Promise<ContentScriptNode> {\n const marker = this.marker;\n const container = await this.definition.container({...this.getPrepareProps(anchor), data});\n\n return new MountNode(\n new MarkerNode(new Node(anchor, container), marker),\n this.context.containers,\n this.definition.mount\n );\n }\n\n protected createIsolation(node: ContentScriptNode, data: Data): ContentScriptIsolationAssembly {\n const options = this.definition.isolation;\n\n if (options.type === ContentScriptIsolation.None) {\n return {node};\n }\n\n const setup = new IsolationSetup({\n props: () => ({...this.getPrepareProps(node.anchor), data}),\n container: () => node.container,\n boundary: this.definition.boundary,\n target: this.definition.target,\n });\n\n if (options.type === ContentScriptIsolation.Shadow) {\n const shadow = new ShadowNode(node, options, setup);\n\n return {node: shadow, ready: () => shadow.ready()};\n }\n\n const frame = new FrameNode(node, options, () => this.context.mount(), setup);\n\n return {node: frame, ready: () => frame.ready()};\n }\n\n protected createRenderer(\n node: ContentScriptNode,\n render: ContentScriptRenderHandler<Data>,\n props: () => ContentScriptProps<Data>,\n options: ContentScriptRenderOptions\n ): ContentScriptNode & ContentScriptRenderLifecycle {\n throw new Error(\"Content script rendering requires a renderer adapter\");\n }\n}\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,OAAO,oBAAoB;AAC3B,SAAQ,WAAW,WAAW,YAAY,YAAY,YAAW;AAEjE,SAAQ,sCAAqC;AAS7C;AAAA,EAEI;AAAA,OAKG;AAEP,MAAO,qBAGG,QAAyB;AAAA,EACxB,YAAY,YAAsD;AACrE,UAAM,UAAU;AAAA,EACpB;AAAA,EAEU,SAAS,MAAyB,MAAsC;AAC9E,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK,QAAQ;AACjC,YAAM,IAAI,MAAM,uDAAuD;AAAA,IAC3E;AAEA,WAAO;AAAA,MACH,GAAG,KAAK,gBAAgB,KAAK,MAAM;AAAA,MACnC;AAAA,MACA,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,IACnB;AAAA,EACJ;AAAA,EAEA,MAAgB,WACZ,QACA,QACkC;AAClC,UAAM,aAAa,+BAA+B,KAAK,WAAW,SAAS;AAC3E,UAAM,SAAS,KAAK,WAAW;AAE/B,QAAI,WAAW,SAAU,CAAC,eAAe,WAAW,UAAa,WAAW,OAAQ;AAChF,aAAO,EAAC,MAAM,IAAI,WAAW,IAAI,KAAK,MAAM,GAAG,KAAK,MAAM,EAAC;AAAA,IAC/D;AAEA,UAAM,OAAO;AACb,UAAM,cAAc,MAAM,KAAK,gBAAgB,QAAQ,IAAI;AAC3D,UAAM,EAAC,MAAM,MAAK,IAAI,KAAK,gBAAgB,aAAa,IAAI;AAE5D,QAAI,cAAc,OAAO,WAAW,YAAY;AAC5C,aAAO,EAAC,KAAI;AAAA,IAChB;AAEA,UAAM,WAAW,KAAK,eAAe,MAAM,QAAQ,MAAM,KAAK,SAAS,MAAM,IAAI,GAAG,EAAC,MAAK,CAAC;AAE3F,WAAO,EAAC,MAAM,UAAU,SAAQ;AAAA,EACpC;AAAA,EAEA,MAAgB,gBAAgB,QAAiB,MAAwC;AACrF,UAAM,SAAS,KAAK;AACpB,UAAM,YAAY,MAAM,KAAK,WAAW,UAAU,EAAC,GAAG,KAAK,gBAAgB,MAAM,GAAG,KAAI,CAAC;AAEzF,WAAO,IAAI;AAAA,MACP,IAAI,WAAW,IAAI,KAAK,QAAQ,SAAS,GAAG,MAAM;AAAA,MAClD,KAAK,QAAQ;AAAA,MACb,KAAK,WAAW;AAAA,IACpB;AAAA,EACJ;AAAA,EAEU,gBAAgB,MAAyB,MAA4C;AAC3F,UAAM,UAAU,KAAK,WAAW;AAEhC,QAAI,QAAQ,SAAS,uBAAuB,MAAM;AAC9C,aAAO,EAAC,KAAI;AAAA,IAChB;AAEA,UAAM,QAAQ,IAAI,eAAe;AAAA,MAC7B,OAAO,OAAO,EAAC,GAAG,KAAK,gBAAgB,KAAK,MAAM,GAAG,KAAI;AAAA,MACzD,WAAW,MAAM,KAAK;AAAA,MACtB,UAAU,KAAK,WAAW;AAAA,MAC1B,QAAQ,KAAK,WAAW;AAAA,IAC5B,CAAC;AAED,QAAI,QAAQ,SAAS,uBAAuB,QAAQ;AAChD,YAAM,SAAS,IAAI,WAAW,MAAM,SAAS,KAAK;AAElD,aAAO,EAAC,MAAM,QAAQ,OAAO,MAAM,OAAO,MAAM,EAAC;AAAA,IACrD;AAEA,UAAM,QAAQ,IAAI,UAAU,MAAM,SAAS,MAAM,KAAK,QAAQ,MAAM,GAAG,KAAK;AAE5E,WAAO,EAAC,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,EAAC;AAAA,EACnD;AAAA,EAEU,eACN,MACA,QACA,OACA,SACgD;AAChD,UAAM,IAAI,MAAM,sDAAsD;AAAA,EAC1E;AACJ;","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Tracks independent mount registrations without adding ownership to lifecycle nodes. */
|
|
2
|
+
export default class ContainerRegistry {
|
|
3
|
+
private readonly registrations;
|
|
4
|
+
register(container: Element, anchor: Element): () => void;
|
|
5
|
+
owns(target: Node): boolean;
|
|
6
|
+
clear(): void;
|
|
7
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class ContainerRegistry {
|
|
2
|
+
registrations = /* @__PURE__ */ new Map();
|
|
3
|
+
register(container, anchor) {
|
|
4
|
+
let registrations = this.registrations.get(container);
|
|
5
|
+
if (!registrations) {
|
|
6
|
+
registrations = /* @__PURE__ */ new Set();
|
|
7
|
+
this.registrations.set(container, registrations);
|
|
8
|
+
}
|
|
9
|
+
const registration = { anchor };
|
|
10
|
+
const current = registrations;
|
|
11
|
+
current.add(registration);
|
|
12
|
+
return () => {
|
|
13
|
+
if (!current.delete(registration)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (current.size === 0 && this.registrations.get(container) === current) {
|
|
17
|
+
this.registrations.delete(container);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
owns(target) {
|
|
22
|
+
var _a, _b;
|
|
23
|
+
if (this.registrations.size === 0) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
let current = target;
|
|
27
|
+
while (current) {
|
|
28
|
+
const registrations = this.registrations.get(current);
|
|
29
|
+
const container = current;
|
|
30
|
+
if (registrations && !Array.from(registrations).some(({ anchor }) => container.contains(anchor))) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
const shadowRoot = ((_b = (_a = current.ownerDocument) == null ? void 0 : _a.defaultView) == null ? void 0 : _b.ShadowRoot) ?? ShadowRoot;
|
|
34
|
+
current = current.parentNode ?? (current instanceof shadowRoot ? current.host : null);
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
clear() {
|
|
39
|
+
this.registrations.clear();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
ContainerRegistry as default
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=ContainerRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/entry/content/lifecycle/context/ContainerRegistry.ts"],"sourcesContent":["/** Tracks independent mount registrations without adding ownership to lifecycle nodes. */\nexport default class ContainerRegistry {\n private readonly registrations = new Map<Node, Set<{anchor: Element}>>();\n\n public register(container: Element, anchor: Element): () => void {\n let registrations = this.registrations.get(container);\n\n if (!registrations) {\n registrations = new Set();\n this.registrations.set(container, registrations);\n }\n\n const registration = {anchor};\n const current = registrations;\n current.add(registration);\n\n return () => {\n if (!current.delete(registration)) {\n return;\n }\n\n if (current.size === 0 && this.registrations.get(container) === current) {\n this.registrations.delete(container);\n }\n };\n }\n\n public owns(target: Node): boolean {\n if (this.registrations.size === 0) {\n return false;\n }\n\n let current: Node | null = target;\n\n while (current) {\n const registrations = this.registrations.get(current);\n const container = current;\n\n if (registrations && !Array.from(registrations).some(({anchor}) => container.contains(anchor))) {\n return true;\n }\n\n const shadowRoot: typeof ShadowRoot = current.ownerDocument?.defaultView?.ShadowRoot ?? ShadowRoot;\n current = current.parentNode ?? (current instanceof shadowRoot ? current.host : null);\n }\n\n return false;\n }\n\n public clear(): void {\n this.registrations.clear();\n }\n}\n"],"mappings":"AACA,MAAO,kBAAgC;AAAA,EAClB,gBAAgB,oBAAI,IAAkC;AAAA,EAEhE,SAAS,WAAoB,QAA6B;AAC7D,QAAI,gBAAgB,KAAK,cAAc,IAAI,SAAS;AAEpD,QAAI,CAAC,eAAe;AAChB,sBAAgB,oBAAI,IAAI;AACxB,WAAK,cAAc,IAAI,WAAW,aAAa;AAAA,IACnD;AAEA,UAAM,eAAe,EAAC,OAAM;AAC5B,UAAM,UAAU;AAChB,YAAQ,IAAI,YAAY;AAExB,WAAO,MAAM;AACT,UAAI,CAAC,QAAQ,OAAO,YAAY,GAAG;AAC/B;AAAA,MACJ;AAEA,UAAI,QAAQ,SAAS,KAAK,KAAK,cAAc,IAAI,SAAS,MAAM,SAAS;AACrE,aAAK,cAAc,OAAO,SAAS;AAAA,MACvC;AAAA,IACJ;AAAA,EACJ;AAAA,EAEO,KAAK,QAAuB;AA3BvC;AA4BQ,QAAI,KAAK,cAAc,SAAS,GAAG;AAC/B,aAAO;AAAA,IACX;AAEA,QAAI,UAAuB;AAE3B,WAAO,SAAS;AACZ,YAAM,gBAAgB,KAAK,cAAc,IAAI,OAAO;AACpD,YAAM,YAAY;AAElB,UAAI,iBAAiB,CAAC,MAAM,KAAK,aAAa,EAAE,KAAK,CAAC,EAAC,OAAM,MAAM,UAAU,SAAS,MAAM,CAAC,GAAG;AAC5F,eAAO;AAAA,MACX;AAEA,YAAM,eAAgC,mBAAQ,kBAAR,mBAAuB,gBAAvB,mBAAoC,eAAc;AACxF,gBAAU,QAAQ,eAAe,mBAAmB,aAAa,QAAQ,OAAO;AAAA,IACpF;AAEA,WAAO;AAAA,EACX;AAAA,EAEO,QAAc;AACjB,SAAK,cAAc,MAAM;AAAA,EAC7B;AACJ;","names":[]}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type ContainerRegistry from "./ContainerRegistry.js";
|
|
2
|
+
import { ContentScriptNode, ContentScriptContext, ContentScriptEventCallback, ContentScriptEventEmitter } from "../../../../types/content/index.js";
|
|
2
3
|
export default class Context implements ContentScriptContext {
|
|
3
4
|
protected readonly emitter: ContentScriptEventEmitter;
|
|
4
|
-
|
|
5
|
+
private readonly registry;
|
|
6
|
+
protected readonly collection: Set<ContentScriptNode>;
|
|
5
7
|
private unmounting;
|
|
6
|
-
constructor(emitter: ContentScriptEventEmitter);
|
|
8
|
+
constructor(emitter: ContentScriptEventEmitter, registry: ContainerRegistry);
|
|
7
9
|
get nodes(): ReadonlySet<ContentScriptNode>;
|
|
10
|
+
owns(target: Node): boolean;
|
|
8
11
|
mount(): void;
|
|
9
12
|
unmount(): void;
|
|
10
13
|
remove(node: ContentScriptNode): void;
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
class Context {
|
|
2
|
-
constructor(emitter) {
|
|
2
|
+
constructor(emitter, registry) {
|
|
3
3
|
this.emitter = emitter;
|
|
4
|
+
this.registry = registry;
|
|
4
5
|
}
|
|
5
6
|
emitter;
|
|
7
|
+
registry;
|
|
6
8
|
collection = /* @__PURE__ */ new Set();
|
|
7
9
|
unmounting = false;
|
|
8
10
|
get nodes() {
|
|
9
11
|
return this.collection;
|
|
10
12
|
}
|
|
13
|
+
owns(target) {
|
|
14
|
+
return this.registry.owns(target);
|
|
15
|
+
}
|
|
11
16
|
mount() {
|
|
12
17
|
if (this.unmounting) {
|
|
13
18
|
return;
|
|
@@ -41,21 +46,31 @@ class Context {
|
|
|
41
46
|
if (!this.collection.delete(node)) {
|
|
42
47
|
return;
|
|
43
48
|
}
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
try {
|
|
50
|
+
node.unmount();
|
|
51
|
+
} finally {
|
|
52
|
+
this.emitter.emitRemove(node);
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
clear() {
|
|
48
56
|
const unmounting = this.unmounting;
|
|
49
57
|
this.unmounting = true;
|
|
58
|
+
const errors = [];
|
|
50
59
|
try {
|
|
51
60
|
for (const node of this.collection) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
try {
|
|
62
|
+
this.remove(node);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
errors.push(error);
|
|
65
|
+
}
|
|
55
66
|
}
|
|
56
67
|
} finally {
|
|
68
|
+
this.registry.clear();
|
|
57
69
|
this.unmounting = unmounting;
|
|
58
70
|
}
|
|
71
|
+
if (errors.length > 0) {
|
|
72
|
+
throw new AggregateError(errors, "Content script context cleanup failed");
|
|
73
|
+
}
|
|
59
74
|
}
|
|
60
75
|
watch(callback) {
|
|
61
76
|
this.emitter.on(callback);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/entry/content/lifecycle/context/Context.ts"],"sourcesContent":["import {\n ContentScriptContext,\n ContentScriptEventCallback,\n ContentScriptEventEmitter,\n
|
|
1
|
+
{"version":3,"sources":["../../../../../src/entry/content/lifecycle/context/Context.ts"],"sourcesContent":["import type ContainerRegistry from \"./ContainerRegistry\";\n\nimport {\n ContentScriptNode,\n ContentScriptContext,\n ContentScriptEventCallback,\n ContentScriptEventEmitter,\n} from \"@typing/content\";\n\nexport default class Context implements ContentScriptContext {\n protected readonly collection = new Set<ContentScriptNode>();\n private unmounting = false;\n\n constructor(\n protected readonly emitter: ContentScriptEventEmitter,\n private readonly registry: ContainerRegistry\n ) {}\n\n public get nodes(): ReadonlySet<ContentScriptNode> {\n return this.collection;\n }\n\n public owns(target: Node): boolean {\n return this.registry.owns(target);\n }\n\n public mount(): void {\n if (this.unmounting) {\n return;\n }\n\n for (const node of this.collection) {\n if (!node.anchor.isConnected) {\n node.unmount();\n\n this.collection.delete(node);\n\n this.emitter.emitRemove(node);\n\n continue;\n }\n\n node.mount();\n }\n }\n\n public unmount(): void {\n const unmounting = this.unmounting;\n this.unmounting = true;\n\n try {\n for (const node of this.collection) {\n node.unmount();\n\n if (!node.anchor.isConnected) {\n this.collection.delete(node);\n\n this.emitter.emitRemove(node);\n }\n }\n } finally {\n this.unmounting = unmounting;\n }\n }\n\n public remove(node: ContentScriptNode): void {\n if (!this.collection.delete(node)) {\n return;\n }\n\n try {\n node.unmount();\n } finally {\n this.emitter.emitRemove(node);\n }\n }\n\n public clear(): void {\n const unmounting = this.unmounting;\n\n this.unmounting = true;\n\n const errors: unknown[] = [];\n\n try {\n for (const node of this.collection) {\n try {\n this.remove(node);\n } catch (error) {\n errors.push(error);\n }\n }\n } finally {\n this.registry.clear();\n this.unmounting = unmounting;\n }\n\n if (errors.length > 0) {\n throw new AggregateError(errors, \"Content script context cleanup failed\");\n }\n }\n\n public watch(callback: ContentScriptEventCallback): () => void {\n this.emitter.on(callback);\n\n return () => {\n this.emitter.off(callback);\n };\n }\n\n public unwatch(): void {\n this.emitter.removeAllListeners();\n }\n}\n"],"mappings":"AASA,MAAO,QAAsD;AAAA,EAIzD,YACuB,SACF,UACnB;AAFqB;AACF;AAAA,EAClB;AAAA,EAFoB;AAAA,EACF;AAAA,EALF,aAAa,oBAAI,IAAuB;AAAA,EACnD,aAAa;AAAA,EAOrB,IAAW,QAAwC;AAC/C,WAAO,KAAK;AAAA,EAChB;AAAA,EAEO,KAAK,QAAuB;AAC/B,WAAO,KAAK,SAAS,KAAK,MAAM;AAAA,EACpC;AAAA,EAEO,QAAc;AACjB,QAAI,KAAK,YAAY;AACjB;AAAA,IACJ;AAEA,eAAW,QAAQ,KAAK,YAAY;AAChC,UAAI,CAAC,KAAK,OAAO,aAAa;AAC1B,aAAK,QAAQ;AAEb,aAAK,WAAW,OAAO,IAAI;AAE3B,aAAK,QAAQ,WAAW,IAAI;AAE5B;AAAA,MACJ;AAEA,WAAK,MAAM;AAAA,IACf;AAAA,EACJ;AAAA,EAEO,UAAgB;AACnB,UAAM,aAAa,KAAK;AACxB,SAAK,aAAa;AAElB,QAAI;AACA,iBAAW,QAAQ,KAAK,YAAY;AAChC,aAAK,QAAQ;AAEb,YAAI,CAAC,KAAK,OAAO,aAAa;AAC1B,eAAK,WAAW,OAAO,IAAI;AAE3B,eAAK,QAAQ,WAAW,IAAI;AAAA,QAChC;AAAA,MACJ;AAAA,IACJ,UAAE;AACE,WAAK,aAAa;AAAA,IACtB;AAAA,EACJ;AAAA,EAEO,OAAO,MAA+B;AACzC,QAAI,CAAC,KAAK,WAAW,OAAO,IAAI,GAAG;AAC/B;AAAA,IACJ;AAEA,QAAI;AACA,WAAK,QAAQ;AAAA,IACjB,UAAE;AACE,WAAK,QAAQ,WAAW,IAAI;AAAA,IAChC;AAAA,EACJ;AAAA,EAEO,QAAc;AACjB,UAAM,aAAa,KAAK;AAExB,SAAK,aAAa;AAElB,UAAM,SAAoB,CAAC;AAE3B,QAAI;AACA,iBAAW,QAAQ,KAAK,YAAY;AAChC,YAAI;AACA,eAAK,OAAO,IAAI;AAAA,QACpB,SAAS,OAAO;AACZ,iBAAO,KAAK,KAAK;AAAA,QACrB;AAAA,MACJ;AAAA,IACJ,UAAE;AACE,WAAK,SAAS,MAAM;AACpB,WAAK,aAAa;AAAA,IACtB;AAEA,QAAI,OAAO,SAAS,GAAG;AACnB,YAAM,IAAI,eAAe,QAAQ,uCAAuC;AAAA,IAC5E;AAAA,EACJ;AAAA,EAEO,MAAM,UAAkD;AAC3D,SAAK,QAAQ,GAAG,QAAQ;AAExB,WAAO,MAAM;AACT,WAAK,QAAQ,IAAI,QAAQ;AAAA,IAC7B;AAAA,EACJ;AAAA,EAEO,UAAgB;AACnB,SAAK,QAAQ,mBAAmB;AAAA,EACpC;AACJ;","names":[]}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import Context from "./Context.js";
|
|
2
|
-
import
|
|
2
|
+
import ContainerRegistry from "./ContainerRegistry.js";
|
|
3
|
+
import type { ContentScriptNode, ContentScriptEventEmitter } from "../../../../types/content/index.js";
|
|
3
4
|
export default class ManagedContext extends Context {
|
|
5
|
+
readonly containers: ContainerRegistry;
|
|
6
|
+
constructor(emitter: ContentScriptEventEmitter);
|
|
4
7
|
add(node: ContentScriptNode): this;
|
|
5
8
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import Context from "./Context.js";
|
|
2
|
+
import ContainerRegistry from "./ContainerRegistry.js";
|
|
2
3
|
class ManagedContext extends Context {
|
|
4
|
+
containers;
|
|
5
|
+
constructor(emitter) {
|
|
6
|
+
const containers = new ContainerRegistry();
|
|
7
|
+
super(emitter, containers);
|
|
8
|
+
this.containers = containers;
|
|
9
|
+
}
|
|
3
10
|
add(node) {
|
|
4
11
|
this.collection.add(node);
|
|
5
12
|
this.emitter.emitAdd(node);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/entry/content/lifecycle/context/ManagedContext.ts"],"sourcesContent":["import Context from \"./Context\";\
|
|
1
|
+
{"version":3,"sources":["../../../../../src/entry/content/lifecycle/context/ManagedContext.ts"],"sourcesContent":["import Context from \"./Context\";\nimport ContainerRegistry from \"./ContainerRegistry\";\nimport type {ContentScriptNode, ContentScriptEventEmitter} from \"@typing/content\";\n\nexport default class ManagedContext extends Context {\n public readonly containers: ContainerRegistry;\n\n constructor(emitter: ContentScriptEventEmitter) {\n const containers = new ContainerRegistry();\n super(emitter, containers);\n this.containers = containers;\n }\n\n public add(node: ContentScriptNode): this {\n this.collection.add(node);\n\n this.emitter.emitAdd(node);\n\n return this;\n }\n}\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,OAAO,uBAAuB;AAG9B,MAAO,uBAAqC,QAAQ;AAAA,EAChC;AAAA,EAEhB,YAAY,SAAoC;AAC5C,UAAM,aAAa,IAAI,kBAAkB;AACzC,UAAM,SAAS,UAAU;AACzB,SAAK,aAAa;AAAA,EACtB;AAAA,EAEO,IAAI,MAA+B;AACtC,SAAK,WAAW,IAAI,IAAI;AAExB,SAAK,QAAQ,QAAQ,IAAI;AAEzB,WAAO;AAAA,EACX;AACJ;","names":[]}
|