react-native-webrtc-kaleidoscope 2.2.0 → 2.2.1
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/llms.txt +1 -1
- package/package.json +1 -1
- package/plugin/build/lib/preset-book.js +48 -15
package/llms.txt
CHANGED
|
@@ -81,7 +81,7 @@ Web (Chromium only) runs with no prebuild: `bunx expo start --web`.
|
|
|
81
81
|
The plugin statically analyzes ONE file to decide which image assets ship in your native bundle. The contract:
|
|
82
82
|
|
|
83
83
|
1. **Exact filename, exact location:** `kaleidoscope.preset-book.ts` at the **project root** (the directory containing `package.json` and your app config). A book named or placed differently still typechecks and still works on web, but at prebuild NO assets are copied and every image background silently renders nothing on native. This is the most common integration mistake; the failure is silent.
|
|
84
|
-
2. **The book is parsed as text, never executed.** Keep every `image` layer's `source` statically analyzable: a single named import from `react-native-webrtc-kaleidoscope/images/<category>/<leaf>`, a `require('./local.webp')` literal, or a `const X = Asset.fromModule(require('./local.webp')).uri` binding. Do not compute sources, build layers in helper functions, or re-export the book through a barrel; the parser will not follow them and
|
|
84
|
+
2. **The book is parsed as text, never executed.** Keep every `image` layer's `source` statically analyzable: a single named import from `react-native-webrtc-kaleidoscope/images/<category>/<leaf>`, a `require('./local.webp')` literal, or a `const X = Asset.fromModule(require('./local.webp')).uri` binding (the binding may span lines; a formatter wrapping it at a narrow print width is fine). Do not compute sources, build layers in helper functions, or re-export the book through a barrel; the parser will not follow them, and each skipped `image` layer warns at prebuild naming the layer id.
|
|
85
85
|
3. **An `image` layer's `id` doubles as its native plate id**: keep it equal to the image file's basename (`office-dark`, `my-bg`). Your own background images must be `.webp` (native resolves `assets/images/<id>.webp`).
|
|
86
86
|
4. **Re-run `bunx expo prebuild` after editing the book** (adding/deleting presets changes the native asset set). JS-only uniform tweaks hot-reload without it.
|
|
87
87
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-webrtc-kaleidoscope",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Live video effects (blur, background replacement, generative backgrounds, flip/rotate) for react-native-webrtc, packaged as a managed-Expo-friendly Expo Module. Working on web, Android, and iOS. Active development.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -18,8 +18,11 @@
|
|
|
18
18
|
// each `image` layer is `{ id, shader: 'image', source: <ref> }`, where <ref> is
|
|
19
19
|
// a `require('./x.webp')` literal, a single named import from an
|
|
20
20
|
// `.../images/<category>/<leaf>` specifier, or a `const X = ...require('./x.webp')...`
|
|
21
|
-
// binding.
|
|
22
|
-
//
|
|
21
|
+
// binding. A binding's initializer may span lines (a consumer's formatter wraps
|
|
22
|
+
// the idiomatic `Asset.fromModule(require(...)).uri` at narrow print widths), so
|
|
23
|
+
// the parse reads statements, not lines. Anything that can't be parsed or
|
|
24
|
+
// resolved warns (never throws), matching the plugin's non-fatal contract; an
|
|
25
|
+
// `image` layer dropped silently at prebuild is a bug, not a policy.
|
|
23
26
|
var __importDefault =
|
|
24
27
|
(this && this.__importDefault) ||
|
|
25
28
|
function (mod) {
|
|
@@ -30,6 +33,7 @@ exports.PRESET_BOOK_FILENAME = void 0;
|
|
|
30
33
|
exports.collectReferencedAssets = collectReferencedAssets;
|
|
31
34
|
const node_fs_1 = __importDefault(require('node:fs'));
|
|
32
35
|
const node_path_1 = __importDefault(require('node:path'));
|
|
36
|
+
const constants_1 = require('./constants');
|
|
33
37
|
const file_manipulation_1 = require('./file-manipulation');
|
|
34
38
|
/** The file a consumer declares at their project root. */
|
|
35
39
|
exports.PRESET_BOOK_FILENAME = 'kaleidoscope.preset-book.ts';
|
|
@@ -48,8 +52,12 @@ function parseImports(source) {
|
|
|
48
52
|
const specifier = m[3];
|
|
49
53
|
if (local && specifier) imports[local] = specifier;
|
|
50
54
|
}
|
|
55
|
+
// The initializer scan crosses newlines (formatters wrap the binding) but
|
|
56
|
+
// stops at `;` and refuses to run into a following declaration, so a
|
|
57
|
+
// no-semicolon style cannot misattribute a later require() to an earlier
|
|
58
|
+
// binding.
|
|
51
59
|
const requireBindingRe =
|
|
52
|
-
/(?:const|let|var)\s+([A-Za-z0-9_$]+)\s*=\s*[
|
|
60
|
+
/(?:const|let|var)\s+([A-Za-z0-9_$]+)\s*=\s*(?:(?!\b(?:const|let|var)\b)[^;])*?\brequire\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
53
61
|
for (const m of source.matchAll(requireBindingRe)) {
|
|
54
62
|
const local = m[1];
|
|
55
63
|
const specifier = m[2];
|
|
@@ -81,14 +89,27 @@ function parseImageRefs(source) {
|
|
|
81
89
|
for (const m of source.matchAll(layerRe)) {
|
|
82
90
|
const body = m[1];
|
|
83
91
|
if (!body) continue;
|
|
92
|
+
const layerId = body.match(/\bid\s*:\s*['"]([\w-]+)['"]/)?.[1];
|
|
84
93
|
const sourceM = body.match(/source\s*:\s*(require\(\s*['"][^'"]+['"]\s*\)|[A-Za-z0-9_$]+)/);
|
|
85
94
|
const expr = sourceM?.[1];
|
|
86
|
-
|
|
95
|
+
// The warn-never-throw contract: a layer the parse cannot follow is skipped
|
|
96
|
+
// LOUDLY, naming the layer, so the missing plate surfaces at prebuild
|
|
97
|
+
// instead of on-device.
|
|
98
|
+
if (!expr) {
|
|
99
|
+
console.warn(
|
|
100
|
+
`${constants_1.LOG_TAG} Could not parse the 'source' of image layer '${layerId ?? '<no id>'}'; skipping its asset. An image layer's source must be a require('...') literal or an identifier bound by a single named import or a require() binding.`,
|
|
101
|
+
);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
87
104
|
const requireLiteral = expr.match(/require\(\s*['"]([^'"]+)['"]\s*\)/);
|
|
88
105
|
const specifier = requireLiteral ? requireLiteral[1] : (imports[expr] ?? null);
|
|
89
|
-
if (!specifier)
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
if (!specifier) {
|
|
107
|
+
console.warn(
|
|
108
|
+
`${constants_1.LOG_TAG} Could not resolve '${expr}' (the 'source' of image layer '${layerId ?? '<no id>'}') to an import or require() binding; skipping its asset.`,
|
|
109
|
+
);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const id = layerId ?? imageIdFromSpecifier(specifier);
|
|
92
113
|
if (seen.has(id)) continue;
|
|
93
114
|
seen.add(id);
|
|
94
115
|
refs.push({ id, specifier });
|
|
@@ -96,13 +117,21 @@ function parseImageRefs(source) {
|
|
|
96
117
|
return refs;
|
|
97
118
|
}
|
|
98
119
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
120
|
+
* The composite a specifier references: `<pkg>/composites/<name>` or any of its
|
|
121
|
+
* per-composite subpaths (today `/controls`). A consumer importing ONLY a
|
|
122
|
+
* composite's controls is still using that composite, so both forms count.
|
|
123
|
+
*/
|
|
124
|
+
function compositeNameFromSpecifier(specifier) {
|
|
125
|
+
return specifier.match(/(?:^|\/)composites\/([\w-]+)(?:\/controls)?$/)?.[1] ?? null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Resolve an imported-composite specifier (`<pkg>/composites/<name>`, or its
|
|
129
|
+
* `/controls` subpath) to the composite's source `.ts` on disk. Returns null
|
|
130
|
+
* for a non-composite specifier or an unresolvable package.
|
|
102
131
|
*/
|
|
103
132
|
function resolveCompositeSource(specifier, projectRoot) {
|
|
104
|
-
|
|
105
|
-
|
|
133
|
+
const name = compositeNameFromSpecifier(specifier);
|
|
134
|
+
if (!name) return null;
|
|
106
135
|
try {
|
|
107
136
|
const pkgJson = require.resolve('react-native-webrtc-kaleidoscope/package.json', {
|
|
108
137
|
paths: [projectRoot],
|
|
@@ -143,9 +172,13 @@ function resolveAssetPath(specifier, baseDir, projectRoot) {
|
|
|
143
172
|
// collectors so neither drifts from the other.
|
|
144
173
|
function walkBookSources(bookSource, projectRoot) {
|
|
145
174
|
const sources = [{ source: bookSource, baseDir: projectRoot }];
|
|
175
|
+
// A composite and its `/controls` subpath resolve to the SAME source file;
|
|
176
|
+
// parse it once.
|
|
177
|
+
const seenPaths = new Set();
|
|
146
178
|
for (const specifier of Object.values(parseImports(bookSource))) {
|
|
147
179
|
const compositePath = resolveCompositeSource(specifier, projectRoot);
|
|
148
|
-
if (!compositePath) continue;
|
|
180
|
+
if (!compositePath || seenPaths.has(compositePath)) continue;
|
|
181
|
+
seenPaths.add(compositePath);
|
|
149
182
|
const compositeSource = (0, file_manipulation_1.readTextOrNull)(compositePath);
|
|
150
183
|
// Non-fatal: a composite we cannot read contributes nothing.
|
|
151
184
|
if (compositeSource !== null) {
|
|
@@ -182,10 +215,10 @@ function collectCompositeThumbRefs(bookSource, projectRoot) {
|
|
|
182
215
|
const refs = [];
|
|
183
216
|
const seen = new Set();
|
|
184
217
|
for (const specifier of Object.values(parseImports(bookSource))) {
|
|
218
|
+
const name = compositeNameFromSpecifier(specifier);
|
|
219
|
+
if (!name || seen.has(name)) continue;
|
|
185
220
|
const compositeTs = resolveCompositeSource(specifier, projectRoot);
|
|
186
221
|
if (!compositeTs) continue;
|
|
187
|
-
const name = specifier.substring(specifier.lastIndexOf('/') + 1);
|
|
188
|
-
if (seen.has(name)) continue;
|
|
189
222
|
const thumbPath = node_path_1.default.join(
|
|
190
223
|
node_path_1.default.dirname(compositeTs),
|
|
191
224
|
`${name}.thumb.webp`,
|