@exodus/stasis-plugins 1.0.0-beta.12 → 1.0.0-beta.14
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/package.json +2 -2
- package/src/esbuild.js +25 -22
- package/src/metro-babel-transformer.js +87 -23
- package/src/metro-native.js +180 -42
- package/src/metro-transformer.js +28 -35
- package/src/metro.js +223 -58
- package/src/plugins.js +48 -51
- package/src/rollup.js +11 -24
- package/src/webpack.js +11 -27
package/src/rollup.js
CHANGED
|
@@ -6,12 +6,12 @@ import { dirname, isAbsolute, resolve as resolvePath } from 'node:path'
|
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
7
7
|
|
|
8
8
|
import { Bundle } from '@exodus/stasis-core/bundle'
|
|
9
|
-
import { resolvePluginState } from './plugins.js'
|
|
9
|
+
import { attestedImport, resolvePluginState, unsupportedExtension } from './plugins.js'
|
|
10
10
|
import { State } from '@exodus/stasis-core/state'
|
|
11
11
|
// Pre-patch snapshot, not `import { readFile }`: under --fs=async that builtin is patched, and
|
|
12
12
|
// this plugin loads after, so a direct import would route rollup's reads through the capture hook.
|
|
13
|
-
import { realReadFile } from '@exodus/stasis-core/state-util'
|
|
14
|
-
import { classifyExtension } from '@exodus/stasis-core/util'
|
|
13
|
+
import { inScope, realReadFile } from '@exodus/stasis-core/state-util'
|
|
14
|
+
import { classifyExtension, isPathWithin } from '@exodus/stasis-core/util'
|
|
15
15
|
|
|
16
16
|
// Rollup chains resolveId/load hooks first-non-null-wins, so put this plugin FIRST in `plugins`:
|
|
17
17
|
// listed later, a sibling resolver (node-resolve, commonjs) answers before stasis sees the edge --
|
|
@@ -145,20 +145,13 @@ export class StasisRollup {
|
|
|
145
145
|
#classifyOrThrow(id) {
|
|
146
146
|
const kind = classifyExtension(id, this.#resources)
|
|
147
147
|
if (kind === 'unknown') {
|
|
148
|
-
throw new Error(
|
|
149
|
-
`StasisRollup: unsupported extension for '${id}' -- add its extension or filename to the plugin's resources option or stop importing it`
|
|
150
|
-
)
|
|
148
|
+
throw new Error(unsupportedExtension('StasisRollup', `'${id}'`))
|
|
151
149
|
}
|
|
152
150
|
return kind
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
#inRoot(path) {
|
|
156
|
-
|
|
157
|
-
this.#state.relative(path)
|
|
158
|
-
return true
|
|
159
|
-
} catch {
|
|
160
|
-
return false
|
|
161
|
-
}
|
|
154
|
+
return isPathWithin(this.#state.root, path)
|
|
162
155
|
}
|
|
163
156
|
|
|
164
157
|
async #resolveId(ctx, source, importer, opts) {
|
|
@@ -191,21 +184,15 @@ export class StasisRollup {
|
|
|
191
184
|
this.#assertPersistableAttributes(attrs)
|
|
192
185
|
// Forward import attributes (`with { type: 'json' }`) so plugin-capture round-trips to
|
|
193
186
|
// plugin-load, both keyed under `* (with: ...)`.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
// No attested edge -- at a successful capture that's an EXTERNAL (never recorded as an
|
|
199
|
-
// edge), so hand it back to rollup. File BYTES still fail closed at the load hook.
|
|
200
|
-
// A non-MODULE_NOT_FOUND error is a real fault -- rethrow.
|
|
201
|
-
if (err?.code === 'ERR_MODULE_NOT_FOUND') return null
|
|
202
|
-
throw err
|
|
203
|
-
}
|
|
187
|
+
// No attested edge: rollup's. File BYTES still fail closed at the load hook.
|
|
188
|
+
const attested = attestedImport(this.#state, parentURL, source, { importAttributes: attrs })
|
|
189
|
+
if (attested === undefined) return null
|
|
190
|
+
const { url, format } = attested
|
|
204
191
|
const path = fileURLToPath(url)
|
|
205
192
|
// Refuse a resource only when load mode would actually serve it: an out-of-scope workspace
|
|
206
193
|
// resource under node_modules scope comes from disk via the user's asset plugin, exactly
|
|
207
194
|
// like a capture build (the load hook defers it with the same scope gate).
|
|
208
|
-
if (Bundle.isResourceFormat(format) && (this.#state
|
|
195
|
+
if (Bundle.isResourceFormat(format) && inScope(this.#state, url)) {
|
|
209
196
|
this.#refuseResourceLoad(path)
|
|
210
197
|
}
|
|
211
198
|
// KNOWN GAP: sibling resolution metadata (moduleSideEffects, syntheticNamedExports, meta)
|
|
@@ -253,7 +240,7 @@ export class StasisRollup {
|
|
|
253
240
|
// a sibling's bare resolve() probe carries isEntry too but never loads, so only genuine
|
|
254
241
|
// roots reach this gate.
|
|
255
242
|
if (this.#state.config.full && ctx.getModuleInfo(id)?.isEntry) this.#state.assertEntry(url)
|
|
256
|
-
if (!this.#state
|
|
243
|
+
if (!inScope(this.#state, url)) return null
|
|
257
244
|
const { source, format } = this.#state.getFile(url)
|
|
258
245
|
if (Bundle.isResourceFormat(format)) this.#refuseResourceLoad(id)
|
|
259
246
|
// Code is stored as UTF-8 text, exactly what rollup's parser expects.
|
package/src/webpack.js
CHANGED
|
@@ -5,9 +5,9 @@ import { createRequire, isBuiltin } from 'node:module'
|
|
|
5
5
|
import path from 'node:path'
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
7
7
|
|
|
8
|
-
import { resolvePluginState } from './plugins.js'
|
|
8
|
+
import { attestedImport, resolvePluginState, unsupportedExtension } from './plugins.js'
|
|
9
9
|
import { State } from '@exodus/stasis-core/state'
|
|
10
|
-
import { realReadFileSync } from '@exodus/stasis-core/state-util'
|
|
10
|
+
import { realReadFileSync, servedByBundle } from '@exodus/stasis-core/state-util'
|
|
11
11
|
import { classifyExtension } from '@exodus/stasis-core/util'
|
|
12
12
|
|
|
13
13
|
// CJS require anchored here, used only to locate the PROJECT's babel-plugin-module-resolver below.
|
|
@@ -95,14 +95,8 @@ export class StasisWebpack {
|
|
|
95
95
|
const state = this.#state
|
|
96
96
|
const orig = compiler.inputFileSystem
|
|
97
97
|
|
|
98
|
-
// True iff `p` is
|
|
99
|
-
|
|
100
|
-
const inScope = (p) => {
|
|
101
|
-
if (typeof p !== 'string') return false
|
|
102
|
-
try { state.relative(p) } catch { return false }
|
|
103
|
-
if (state.config.full) return true
|
|
104
|
-
return state.inNodeModules(pathToFileURL(p).toString())
|
|
105
|
-
}
|
|
98
|
+
// True iff `p` is served from the bundle under load (servedByBundle).
|
|
99
|
+
const served = (p) => typeof p === 'string' && p !== '' && servedByBundle(state, p)
|
|
106
100
|
|
|
107
101
|
// Family = the sidecar's own app-graph bundle first, then its parent (loaders + resolution-path
|
|
108
102
|
// dirs the ambient preload captured). Both share one lockfile; no parent -> just [state].
|
|
@@ -121,7 +115,7 @@ export class StasisWebpack {
|
|
|
121
115
|
// must keep `this` = orig; we override only readFile and stat.
|
|
122
116
|
const wrappedReadFile = (p, options, callback) => {
|
|
123
117
|
if (typeof options === 'function') { callback = options; options = undefined }
|
|
124
|
-
if (
|
|
118
|
+
if (served(p)) {
|
|
125
119
|
try {
|
|
126
120
|
const src = serveFromBundle(p)
|
|
127
121
|
const buf = Buffer.isBuffer(src) ? src : Buffer.from(src)
|
|
@@ -136,7 +130,7 @@ export class StasisWebpack {
|
|
|
136
130
|
return orig.readFile(p, options, callback)
|
|
137
131
|
}
|
|
138
132
|
const wrappedStat = (p, callback) => {
|
|
139
|
-
if (
|
|
133
|
+
if (served(p)) {
|
|
140
134
|
// Directories have no bundle content, so serve a synthetic dir Stats from the family's
|
|
141
135
|
// existence record (getFsStat) -- webpack's resolver stat()s intermediate dirs while walking.
|
|
142
136
|
const url = pathToFileURL(p).toString()
|
|
@@ -168,21 +162,14 @@ export class StasisWebpack {
|
|
|
168
162
|
const issuer = data.contextInfo?.issuer
|
|
169
163
|
if (!issuer) return // entries: already absolute, inputFileSystem covers them
|
|
170
164
|
// Out-of-scope parents were never the bundle's responsibility -- defer to webpack's resolver.
|
|
171
|
-
if (!
|
|
165
|
+
if (!served(issuer)) return
|
|
172
166
|
// Built-ins are never bundled or recorded as edges; skip up front. SECURITY: never consult
|
|
173
167
|
// getImport for a builtin name, so a tampered bundle can't redirect `fs` to an arbitrary file.
|
|
174
168
|
if (isBuiltin(data.request)) return
|
|
175
169
|
const parentURL = pathToFileURL(issuer).toString()
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
} catch (err) {
|
|
180
|
-
// No attested edge -- at a successful capture that's an EXTERNAL (never recorded as an
|
|
181
|
-
// edge), so defer to webpack. File BYTES still fail closed at the inputFileSystem wrapper.
|
|
182
|
-
// A non-MODULE_NOT_FOUND error is a real fault -- rethrow.
|
|
183
|
-
if (err?.code === 'ERR_MODULE_NOT_FOUND') return
|
|
184
|
-
throw err
|
|
185
|
-
}
|
|
170
|
+
// No attested edge: defer to webpack. File BYTES still fail closed at the inputFileSystem wrapper.
|
|
171
|
+
const resolved = attestedImport(state, parentURL, data.request)
|
|
172
|
+
if (resolved === undefined) return
|
|
186
173
|
// Redirect the resolver to the absolute bundle path; the stat wrapper then reports it exists.
|
|
187
174
|
data.request = fileURLToPath(resolved.url)
|
|
188
175
|
})
|
|
@@ -267,10 +254,7 @@ export class StasisWebpack {
|
|
|
267
254
|
|
|
268
255
|
const kind = classifyExtension(filePath, this.#resources)
|
|
269
256
|
if (kind === 'unknown') {
|
|
270
|
-
throw new Error(
|
|
271
|
-
`StasisWebpack: unsupported extension for '${filePath}' -- ` +
|
|
272
|
-
`add its extension or filename to the plugin's resources option or stop importing it`
|
|
273
|
-
)
|
|
257
|
+
throw new Error(unsupportedExtension('StasisWebpack', `'${filePath}'`))
|
|
274
258
|
}
|
|
275
259
|
|
|
276
260
|
const url = pathToFileURL(filePath).toString()
|