tw-plugin-rollup 1.0.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.
@@ -0,0 +1,356 @@
1
+ "use strict";
2
+ const __rslib_import_meta_url__ = /*#__PURE__*/ (function () {
3
+ return typeof document === 'undefined'
4
+ ? new (require('url'.replace('', '')).URL)('file:' + __filename).href
5
+ : (document.currentScript && document.currentScript.src) ||
6
+ new URL('main.js', document.baseURI).href;
7
+ })();
8
+ ;
9
+ // The require scope
10
+ var __webpack_require__ = {};
11
+
12
+ // webpack/runtime/define_property_getters
13
+ (() => {
14
+ __webpack_require__.d = (exports, getters, values) => {
15
+ var define = (defs, kind) => {
16
+ for(var key in defs) {
17
+ if(__webpack_require__.o(defs, key) && !__webpack_require__.o(exports, key)) {
18
+ Object.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] });
19
+ }
20
+ }
21
+ };
22
+ define(getters, "get");
23
+ define(values, "value");
24
+ };
25
+ })();
26
+ // webpack/runtime/has_own_property
27
+ (() => {
28
+ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
29
+ })();
30
+ // webpack/runtime/make_namespace_object
31
+ (() => {
32
+ // define __esModule on exports
33
+ __webpack_require__.r = (exports) => {
34
+ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
35
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
36
+ }
37
+ Object.defineProperty(exports, '__esModule', { value: true });
38
+ };
39
+ })();
40
+ var __webpack_exports__ = {};
41
+ // ESM COMPAT FLAG
42
+ __webpack_require__.r(__webpack_exports__);
43
+
44
+ // EXPORTS
45
+ __webpack_require__.d(__webpack_exports__, {
46
+ "default": () => (/* binding */ src),
47
+ turbowarpExtension: () => (/* binding */ turbowarpExtension)
48
+ });
49
+
50
+ ;// CONCATENATED MODULE: external "node:fs"
51
+ const external_node_fs_namespaceObject = require("node:fs");
52
+ ;// CONCATENATED MODULE: external "magic-string"
53
+ const external_magic_string_namespaceObject = require("magic-string");
54
+ ;// CONCATENATED MODULE: ./src/index.js
55
+ /**
56
+ * tw-plugin-rollup — bundle a multi-file TurboWarp / Scratch extension into a
57
+ * single unsandboxed-extension file with **Rollup**, **Rolldown**, or **Vite**
58
+ * (including Vite 8, which builds on Rolldown).
59
+ *
60
+ * Write your extension across as many ES modules as you like, `export default`
61
+ * the extension class (or an already-constructed instance) from the entry
62
+ * module, and this plugin wraps the bundle in the standard TurboWarp IIFE
63
+ * template and calls `Scratch.extensions.register()` for you:
64
+ *
65
+ * ```js
66
+ * (function (Scratch) {
67
+ * "use strict";
68
+ * // ...all of your bundled modules, inlined...
69
+ * Scratch.extensions.register(new MyExtension());
70
+ * })(Scratch);
71
+ * ```
72
+ *
73
+ * Because the entire bundle lives inside the IIFE, every bare reference to the
74
+ * `Scratch` global inside your code resolves to the local parameter — exactly
75
+ * the "personal copy of the Scratch API" the TurboWarp docs recommend.
76
+ *
77
+ * The plugin uses only the standard Rollup plugin API plus Node's `fs`, so the
78
+ * exact same object works in Rollup, Rolldown, and Vite without depending on
79
+ * any one of them.
80
+ *
81
+ * @module tw-plugin-rollup
82
+ */
83
+
84
+ const PLUGIN_NAME = 'turbowarp-extension';
85
+ // Assets imported by the extension are inlined as base64 `data:` URIs by
86
+ // default — a TurboWarp extension is a single file and can't reference separate
87
+ // asset files. SVG/PNG/etc. imports become the `data:` strings you hand to
88
+ // `menuIconURI` / `blockIconURI`.
89
+ const DEFAULT_ASSET_PATTERN = /\.(svg|png|jpe?g|gif|webp|avif)$/i;
90
+ // Maps the file extensions we inline to the MIME type the `data:` URI advertises.
91
+ const MIME_TYPES = {
92
+ svg: 'image/svg+xml',
93
+ png: 'image/png',
94
+ jpg: 'image/jpeg',
95
+ jpeg: 'image/jpeg',
96
+ gif: 'image/gif',
97
+ webp: 'image/webp',
98
+ avif: 'image/avif'
99
+ };
100
+ /**
101
+ * Registry metadata. Each field becomes a `// Key: Value` comment line at the
102
+ * very top of the file — the header the
103
+ * [TurboWarp extensions gallery](https://github.com/TurboWarp/extensions)
104
+ * requires for submission:
105
+ *
106
+ * ```js
107
+ * // Name: Consoles
108
+ * // ID: sipcconsole
109
+ * // Description: Blocks that interact with the developer console.
110
+ * // By: -SIPC-
111
+ * // License: MIT
112
+ * ```
113
+ *
114
+ * @typedef {object} TurboWarpExtensionMetadata
115
+ * @property {string} [name] Display name shown in the extension list.
116
+ * @property {string} [id] Unique extension id. **Must match** the `id` your
117
+ * `getInfo()` returns.
118
+ * @property {string} [description] One-line description for the gallery.
119
+ * @property {string | string[]} [by] Author(s). Each entry becomes its own
120
+ * `// By:` line and may include a profile link, e.g.
121
+ * `"GarboMuffin <https://scratch.mit.edu/users/GarboMuffin/>"`.
122
+ * @property {string | string[]} [original] Original author(s) when this is a
123
+ * derivative — one `// Original:` line each.
124
+ * @property {string} [license] SPDX license id, e.g. `"MPL-2.0"`.
125
+ * @property {string} [context] Extra `// Context:` line.
126
+ */ /**
127
+ * @typedef {object} TurboWarpExtensionPluginOptions
128
+ * @property {boolean} [register=true] Append a
129
+ * `Scratch.extensions.register(...)` call for the entry's chosen export. Set
130
+ * to `false` if you would rather call `register()` yourself somewhere in your
131
+ * own code (it still runs inside the IIFE, so the `Scratch` global is
132
+ * available there too).
133
+ * @property {boolean} [unsandboxed=false] Emit a guard at the top of the bundle
134
+ * that throws unless the extension is running unsandboxed
135
+ * (`Scratch.extensions.unsandboxed`). Use this for extensions that require
136
+ * direct access to the VM.
137
+ * @property {TurboWarpExtensionMetadata} [metadata] Registry metadata injected
138
+ * as the `// Name:` / `// ID:` / … comment header the TurboWarp gallery reads.
139
+ * Omit it for extensions you only ever load manually.
140
+ * @property {boolean | RegExp} [inlineAssets=true] Have the plugin resolve asset
141
+ * imports to a base64 `data:` URI — the form TurboWarp wants for
142
+ * `menuIconURI` / `blockIconURI`. With this on you can
143
+ * `import iconURI from './icon.svg'` and use `iconURI` directly. Defaults to
144
+ * matching `svg`, `png`, `jpg`, `gif`, `webp`, `avif`; pass a `RegExp` to use
145
+ * your own test, or `false` to leave asset handling to your own config (e.g.
146
+ * Vite's, which already inlines assets).
147
+ * @property {string} [name] Human-readable name used in the unsandboxed-guard
148
+ * error message. Defaults to `metadata.name` when set, otherwise
149
+ * `"This extension"`.
150
+ * @property {string} [varName="__turbowarpExtension__"] Identifier the bundle's
151
+ * export is assigned to before registration. Only change it if it somehow
152
+ * collides with a global your extension relies on.
153
+ * @property {string | string[]} [libraryExport="default"] Which export of the
154
+ * entry module is the extension. Defaults to the default export; pass a named
155
+ * export (or a path like `['nested', 'Extension']`) to use something else.
156
+ */ /**
157
+ * Rollup / Rolldown / Vite plugin that turns a normal multi-module bundle into
158
+ * a single-file TurboWarp unsandboxed extension.
159
+ *
160
+ * Returns a plain Rollup plugin object, so it slots straight into a Rollup or
161
+ * Rolldown `plugins` array, or a Vite config's `plugins`. It carries an
162
+ * `enforce: 'pre'` hint so that, under Vite, its asset `load` hook runs before
163
+ * Vite's own asset handling.
164
+ *
165
+ * @param {TurboWarpExtensionPluginOptions} [options]
166
+ * @returns {import('rollup').Plugin}
167
+ */ function turbowarpExtension(options = {}) {
168
+ /** @type {Required<TurboWarpExtensionPluginOptions>} */ const resolved = {
169
+ register: true,
170
+ unsandboxed: false,
171
+ metadata: null,
172
+ inlineAssets: true,
173
+ name: undefined,
174
+ varName: '__turbowarpExtension__',
175
+ libraryExport: 'default',
176
+ ...options
177
+ };
178
+ // Fall back to the metadata name so the guard message reads naturally without
179
+ // having to repeat the name in two places.
180
+ resolved.name = resolved.name ?? resolved.metadata?.name ?? 'This extension';
181
+ const assetPattern = resolved.inlineAssets instanceof RegExp ? resolved.inlineAssets : DEFAULT_ASSET_PATTERN;
182
+ const prefix = buildPrefix(resolved);
183
+ const suffix = buildSuffix(resolved);
184
+ return {
185
+ name: PLUGIN_NAME,
186
+ // Vite-only hint (ignored by Rollup/Rolldown): run our `load` hook ahead of
187
+ // Vite's asset plugins so `import icon from './icon.svg'` reaches us first.
188
+ enforce: 'pre',
189
+ // Shape the bundle so the entry's export is reachable: a single
190
+ // self-executing IIFE that captures the chosen export in `varName`, which
191
+ // the wrapper below reads and registers.
192
+ outputOptions (outputOptions) {
193
+ outputOptions.format = 'iife';
194
+ outputOptions.name = resolved.varName;
195
+ // `default` exposes the bare default export as `varName`; any other export
196
+ // selector needs the namespace object so we can index into it (see
197
+ // `exportAccessor`).
198
+ outputOptions.exports = resolved.libraryExport === 'default' ? 'default' : 'named';
199
+ // Single pasteable file: never split, even if the graph has dynamic imports.
200
+ outputOptions.inlineDynamicImports = true;
201
+ return outputOptions;
202
+ },
203
+ // Inline asset imports as base64 `data:` URIs so `import icon from
204
+ // './icon.svg'` yields a string usable as `menuIconURI` — and so nothing is
205
+ // emitted as a separate file (the extension must be self-contained).
206
+ load (id) {
207
+ if (!resolved.inlineAssets) return null;
208
+ // Strip any query/hash suffix bundlers tack on (e.g. Vite's `?import`).
209
+ const path = id.replace(/[?#].*$/, '');
210
+ if (!assetPattern.test(path)) return null;
211
+ const ext = path.slice(path.lastIndexOf('.') + 1).toLowerCase();
212
+ const mime = MIME_TYPES[ext] || 'application/octet-stream';
213
+ const base64 = (0,external_node_fs_namespaceObject.readFileSync)(path).toString('base64');
214
+ const dataUri = `data:${mime};base64,${base64}`;
215
+ return {
216
+ code: `export default ${JSON.stringify(dataUri)};`,
217
+ map: null
218
+ };
219
+ },
220
+ // Wrap the entry chunk in the TurboWarp IIFE template. Runs after Rollup has
221
+ // produced the inner `var varName = (function () { … })()` IIFE, so the
222
+ // export is already captured by the time the registration suffix reads it.
223
+ renderChunk (code, chunk, outputOptions) {
224
+ if (!chunk.isEntry) return null;
225
+ const magic = new external_magic_string_namespaceObject(code);
226
+ magic.prepend(`${prefix}\n`);
227
+ magic.append(`\n${suffix}`);
228
+ return {
229
+ code: magic.toString(),
230
+ map: outputOptions.sourcemap ? magic.generateMap({
231
+ hires: true
232
+ }) : null
233
+ };
234
+ }
235
+ };
236
+ }
237
+ /**
238
+ * The registry metadata header (`// Name:` / `// ID:` / …), in the order the
239
+ * gallery conventionally lists them, followed by the opening of the TurboWarp
240
+ * IIFE template and an optional unsandboxed guard.
241
+ *
242
+ * @param {Required<TurboWarpExtensionPluginOptions>} options
243
+ * @returns {string}
244
+ */ function buildPrefix(options) {
245
+ const lines = [];
246
+ const header = buildMetadataHeader(options.metadata);
247
+ if (header) lines.push(header, ''); // blank line between header and code
248
+ lines.push('(function (Scratch) {', '"use strict";');
249
+ if (options.unsandboxed) {
250
+ const message = JSON.stringify(`${options.name} must be run unsandboxed.`);
251
+ lines.push(`if (!Scratch.extensions.unsandboxed) { throw new Error(${message}); }`);
252
+ }
253
+ return lines.join('\n');
254
+ }
255
+ // Known metadata fields, paired with the exact label the gallery expects, in
256
+ // conventional order. Unlisted fields are emitted afterwards using their key
257
+ // verbatim as the label.
258
+ const METADATA_FIELDS = [
259
+ [
260
+ 'name',
261
+ 'Name'
262
+ ],
263
+ [
264
+ 'id',
265
+ 'ID'
266
+ ],
267
+ [
268
+ 'description',
269
+ 'Description'
270
+ ],
271
+ [
272
+ 'by',
273
+ 'By'
274
+ ],
275
+ [
276
+ 'original',
277
+ 'Original'
278
+ ],
279
+ [
280
+ 'license',
281
+ 'License'
282
+ ],
283
+ [
284
+ 'context',
285
+ 'Context'
286
+ ]
287
+ ];
288
+ /**
289
+ * Render registry metadata as a block of `// Key: Value` comment lines.
290
+ * Array-valued fields (e.g. `by`) produce one line per entry, and every value
291
+ * is collapsed onto a single line so it can't break out of the comment.
292
+ *
293
+ * @param {TurboWarpExtensionMetadata | null | undefined} metadata
294
+ * @returns {string} The joined comment lines, or `''` when there's nothing.
295
+ */ function buildMetadataHeader(metadata) {
296
+ if (!metadata) return '';
297
+ const lines = [];
298
+ const emit = (label, value)=>{
299
+ if (value == null) return;
300
+ for (const entry of Array.isArray(value) ? value : [
301
+ value
302
+ ]){
303
+ const text = String(entry).replace(/[\r\n]+/g, ' ').trim();
304
+ if (text) lines.push(`// ${label}: ${text}`);
305
+ }
306
+ };
307
+ const known = new Set();
308
+ for (const [key, label] of METADATA_FIELDS){
309
+ known.add(key);
310
+ if (key in metadata) emit(label, metadata[key]);
311
+ }
312
+ for (const key of Object.keys(metadata)){
313
+ if (!known.has(key)) emit(key, metadata[key]);
314
+ }
315
+ return lines.join('\n');
316
+ }
317
+ /**
318
+ * Build the JS expression that reads the chosen export off `varName`. For the
319
+ * default export that's just `varName`; a named export (or a nested path)
320
+ * indexes into the namespace object Rollup assigns to `varName`.
321
+ *
322
+ * @param {Required<TurboWarpExtensionPluginOptions>} options
323
+ * @returns {string}
324
+ */ function exportAccessor(options) {
325
+ if (options.libraryExport === 'default') return options.varName;
326
+ const path = Array.isArray(options.libraryExport) ? options.libraryExport : [
327
+ options.libraryExport
328
+ ];
329
+ return path.reduce((expr, key)=>`${expr}[${JSON.stringify(key)}]`, options.varName);
330
+ }
331
+ /**
332
+ * Closing of the IIFE template. When `register` is enabled, the entry's export
333
+ * is registered — instantiated first if it is a class (a function), or passed
334
+ * straight through if it is already an instance.
335
+ *
336
+ * @param {Required<TurboWarpExtensionPluginOptions>} options
337
+ * @returns {string}
338
+ */ function buildSuffix(options) {
339
+ const lines = [];
340
+ if (options.register) {
341
+ lines.push('(function () {', ` var extension = ${exportAccessor(options)};`, ' Scratch.extensions.register(', ' typeof extension === "function" ? new extension() : extension', ' );', '})();');
342
+ }
343
+ lines.push('})(Scratch);');
344
+ return lines.join('\n');
345
+ }
346
+
347
+ /* export default */ const src = (turbowarpExtension);
348
+
349
+ exports["default"] = __webpack_exports__["default"];
350
+ exports.turbowarpExtension = __webpack_exports__.turbowarpExtension;
351
+ for(var __rspack_i in __webpack_exports__) {
352
+ if(["default","turbowarpExtension"].indexOf(__rspack_i) === -1) {
353
+ exports[__rspack_i] = __webpack_exports__[__rspack_i];
354
+ }
355
+ }
356
+ Object.defineProperty(exports, '__esModule', { value: true });
@@ -0,0 +1,171 @@
1
+ export default turbowarpExtension;
2
+ /**
3
+ * Registry metadata. Each field becomes a `// Key: Value` comment line at the
4
+ * very top of the file — the header the
5
+ * [TurboWarp extensions gallery](https://github.com/TurboWarp/extensions)
6
+ * requires for submission:
7
+ *
8
+ * ```js
9
+ * // Name: Consoles
10
+ * // ID: sipcconsole
11
+ * // Description: Blocks that interact with the developer console.
12
+ * // By: -SIPC-
13
+ * // License: MIT
14
+ * ```
15
+ */
16
+ export type TurboWarpExtensionMetadata = {
17
+ /**
18
+ * Display name shown in the extension list.
19
+ */
20
+ name?: string | undefined;
21
+ /**
22
+ * Unique extension id. **Must match** the `id` your
23
+ * `getInfo()` returns.
24
+ */
25
+ id?: string | undefined;
26
+ /**
27
+ * One-line description for the gallery.
28
+ */
29
+ description?: string | undefined;
30
+ /**
31
+ * Author(s). Each entry becomes its own
32
+ * `// By:` line and may include a profile link, e.g.
33
+ * `"GarboMuffin <https://scratch.mit.edu/users/GarboMuffin/>"`.
34
+ */
35
+ by?: string | string[] | undefined;
36
+ /**
37
+ * Original author(s) when this is a
38
+ * derivative — one `// Original:` line each.
39
+ */
40
+ original?: string | string[] | undefined;
41
+ /**
42
+ * SPDX license id, e.g. `"MPL-2.0"`.
43
+ */
44
+ license?: string | undefined;
45
+ /**
46
+ * Extra `// Context:` line.
47
+ */
48
+ context?: string | undefined;
49
+ };
50
+ export type TurboWarpExtensionPluginOptions = {
51
+ /**
52
+ * Append a
53
+ * `Scratch.extensions.register(...)` call for the entry's chosen export. Set
54
+ * to `false` if you would rather call `register()` yourself somewhere in your
55
+ * own code (it still runs inside the IIFE, so the `Scratch` global is
56
+ * available there too).
57
+ */
58
+ register?: boolean | undefined;
59
+ /**
60
+ * Emit a guard at the top of the bundle
61
+ * that throws unless the extension is running unsandboxed
62
+ * (`Scratch.extensions.unsandboxed`). Use this for extensions that require
63
+ * direct access to the VM.
64
+ */
65
+ unsandboxed?: boolean | undefined;
66
+ /**
67
+ * Registry metadata injected
68
+ * as the `// Name:` / `// ID:` / … comment header the TurboWarp gallery reads.
69
+ * Omit it for extensions you only ever load manually.
70
+ */
71
+ metadata?: TurboWarpExtensionMetadata | undefined;
72
+ /**
73
+ * Have the plugin resolve asset
74
+ * imports to a base64 `data:` URI — the form TurboWarp wants for
75
+ * `menuIconURI` / `blockIconURI`. With this on you can
76
+ * `import iconURI from './icon.svg'` and use `iconURI` directly. Defaults to
77
+ * matching `svg`, `png`, `jpg`, `gif`, `webp`, `avif`; pass a `RegExp` to use
78
+ * your own test, or `false` to leave asset handling to your own config (e.g.
79
+ * Vite's, which already inlines assets).
80
+ */
81
+ inlineAssets?: boolean | RegExp | undefined;
82
+ /**
83
+ * Human-readable name used in the unsandboxed-guard
84
+ * error message. Defaults to `metadata.name` when set, otherwise
85
+ * `"This extension"`.
86
+ */
87
+ name?: string | undefined;
88
+ /**
89
+ * Identifier the bundle's
90
+ * export is assigned to before registration. Only change it if it somehow
91
+ * collides with a global your extension relies on.
92
+ */
93
+ varName?: string | undefined;
94
+ /**
95
+ * Which export of the
96
+ * entry module is the extension. Defaults to the default export; pass a named
97
+ * export (or a path like `['nested', 'Extension']`) to use something else.
98
+ */
99
+ libraryExport?: string | string[] | undefined;
100
+ };
101
+ /**
102
+ * Registry metadata. Each field becomes a `// Key: Value` comment line at the
103
+ * very top of the file — the header the
104
+ * [TurboWarp extensions gallery](https://github.com/TurboWarp/extensions)
105
+ * requires for submission:
106
+ *
107
+ * ```js
108
+ * // Name: Consoles
109
+ * // ID: sipcconsole
110
+ * // Description: Blocks that interact with the developer console.
111
+ * // By: -SIPC-
112
+ * // License: MIT
113
+ * ```
114
+ *
115
+ * @typedef {object} TurboWarpExtensionMetadata
116
+ * @property {string} [name] Display name shown in the extension list.
117
+ * @property {string} [id] Unique extension id. **Must match** the `id` your
118
+ * `getInfo()` returns.
119
+ * @property {string} [description] One-line description for the gallery.
120
+ * @property {string | string[]} [by] Author(s). Each entry becomes its own
121
+ * `// By:` line and may include a profile link, e.g.
122
+ * `"GarboMuffin <https://scratch.mit.edu/users/GarboMuffin/>"`.
123
+ * @property {string | string[]} [original] Original author(s) when this is a
124
+ * derivative — one `// Original:` line each.
125
+ * @property {string} [license] SPDX license id, e.g. `"MPL-2.0"`.
126
+ * @property {string} [context] Extra `// Context:` line.
127
+ */
128
+ /**
129
+ * @typedef {object} TurboWarpExtensionPluginOptions
130
+ * @property {boolean} [register=true] Append a
131
+ * `Scratch.extensions.register(...)` call for the entry's chosen export. Set
132
+ * to `false` if you would rather call `register()` yourself somewhere in your
133
+ * own code (it still runs inside the IIFE, so the `Scratch` global is
134
+ * available there too).
135
+ * @property {boolean} [unsandboxed=false] Emit a guard at the top of the bundle
136
+ * that throws unless the extension is running unsandboxed
137
+ * (`Scratch.extensions.unsandboxed`). Use this for extensions that require
138
+ * direct access to the VM.
139
+ * @property {TurboWarpExtensionMetadata} [metadata] Registry metadata injected
140
+ * as the `// Name:` / `// ID:` / … comment header the TurboWarp gallery reads.
141
+ * Omit it for extensions you only ever load manually.
142
+ * @property {boolean | RegExp} [inlineAssets=true] Have the plugin resolve asset
143
+ * imports to a base64 `data:` URI — the form TurboWarp wants for
144
+ * `menuIconURI` / `blockIconURI`. With this on you can
145
+ * `import iconURI from './icon.svg'` and use `iconURI` directly. Defaults to
146
+ * matching `svg`, `png`, `jpg`, `gif`, `webp`, `avif`; pass a `RegExp` to use
147
+ * your own test, or `false` to leave asset handling to your own config (e.g.
148
+ * Vite's, which already inlines assets).
149
+ * @property {string} [name] Human-readable name used in the unsandboxed-guard
150
+ * error message. Defaults to `metadata.name` when set, otherwise
151
+ * `"This extension"`.
152
+ * @property {string} [varName="__turbowarpExtension__"] Identifier the bundle's
153
+ * export is assigned to before registration. Only change it if it somehow
154
+ * collides with a global your extension relies on.
155
+ * @property {string | string[]} [libraryExport="default"] Which export of the
156
+ * entry module is the extension. Defaults to the default export; pass a named
157
+ * export (or a path like `['nested', 'Extension']`) to use something else.
158
+ */
159
+ /**
160
+ * Rollup / Rolldown / Vite plugin that turns a normal multi-module bundle into
161
+ * a single-file TurboWarp unsandboxed extension.
162
+ *
163
+ * Returns a plain Rollup plugin object, so it slots straight into a Rollup or
164
+ * Rolldown `plugins` array, or a Vite config's `plugins`. It carries an
165
+ * `enforce: 'pre'` hint so that, under Vite, its asset `load` hook runs before
166
+ * Vite's own asset handling.
167
+ *
168
+ * @param {TurboWarpExtensionPluginOptions} [options]
169
+ * @returns {import('rollup').Plugin}
170
+ */
171
+ export function turbowarpExtension(options?: TurboWarpExtensionPluginOptions): import("rollup").Plugin;