react-native-webrtc-kaleidoscope 2.7.6 → 2.7.8

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/README.md CHANGED
@@ -284,6 +284,7 @@ The demo book's [`wolf-cave`](./demo/kaleidoscope.preset-book.ts) is a runnable
284
284
  - **Bundled images** ship as tree-shakeable `image` layers, filed by category and imported per image (`import { officeDark } from 'react-native-webrtc-kaleidoscope/images/office/office-dark'`). On web a `source` can also be any image URL or data URI; native resolves bundled ids only. See [`catalog/images/README.md`](./catalog/images/README.md).
285
285
  - **New shaders** drop a single `.frag` + typed `.ts` into `catalog/shaders/<name>/`; `bun run build:shaders` codegens the web and Android sources and transpiles the iOS Metal. The canonical upright frame and the mask stencil come for free; you write zero orientation code. See [`catalog/shaders/README.md`](./catalog/shaders/README.md).
286
286
  - **Packaged composites** (the Worlds) live in `catalog/composites/<name>/` behind a `./composites/<name>` subpath export; import and spread one into your book.
287
+ - **Thumbnails** are a bundled-asset reference, not a URL string: pass a bare `require('./thumb.webp')` (what `bun run thumbs` emits), or an imported image module (`thumbnail: officeDark`). Both resolve on every platform; native loads the bundled asset, web the asset pipeline. Do **not** wrap the require in `Asset.fromModule(require('./thumb.webp')).uri` in a single-file book: the resolved string renders on web but is empty in a native release build.
287
288
 
288
289
  After adding a preset to the demo book, regenerate its thumbnail and this README's gallery: `bun run thumbs && bun run gen:waffle` (see [Authoring tooling](#authoring-tooling)).
289
290
 
@@ -2,12 +2,18 @@
2
2
  // procedural; no image layer.
3
3
  //
4
4
  // A packaged composite consumers can list by importing this module.
5
+ //
6
+ // Native variant. The thumbnail is the string id the prebuild plugin
7
+ // (app.plugin.js) bundles `clouds.thumb.webp` as into the native app target;
8
+ // `resolveImageUri` looks it up in Bundle.main. The web sibling (clouds.web.ts)
9
+ // keeps the `Asset.fromModule(...).uri` pattern; mirrors the other composites.
5
10
 
6
11
  import type { KaleidoscopePreset } from '../../../src/kaleidoscope.preset-book.types';
7
12
 
8
13
  export const clouds = {
9
14
  name: 'Daytime',
10
15
  taxonomy: ['Shaders', 'Sky'],
16
+ thumbnail: 'clouds-thumb',
11
17
  layers: [
12
18
  {
13
19
  id: 'sky',
@@ -0,0 +1,35 @@
1
+ // Web variant. Resolves the thumbnail URI via expo-asset at module-load time;
2
+ // safe on web (react-native-web has no Image.resolveAssetSource and `.uri` is
3
+ // set synchronously by fromModule). Native is clouds.ts (a string-id thumbnail
4
+ // the prebuild plugin bundles). Mirrors the other composites' {<id>.ts,<id>.web.ts}.
5
+
6
+ import { Asset } from 'expo-asset';
7
+ import type { KaleidoscopePreset } from '../../../src/kaleidoscope.preset-book.types';
8
+ import cloudsThumb from './clouds.thumb.webp';
9
+
10
+ export const clouds = {
11
+ name: 'Daytime',
12
+ taxonomy: ['Shaders', 'Sky'],
13
+ thumbnail: Asset.fromModule(cloudsThumb).uri,
14
+ layers: [
15
+ {
16
+ id: 'sky',
17
+ shader: 'clouds',
18
+ uniforms: {
19
+ uSkyLowColor: [0.09, 0.63, 0.95],
20
+ uSkyHighColor: [0.04, 0.03, 0.86],
21
+ uCloudLightColor: [1.0, 0.91, 0.77],
22
+ uCloudDarkColor: [0.3, 0.3, 0.5],
23
+ uExposure: 1.27,
24
+ uStepSize: 0.16,
25
+ uCloudSpeed: 0.52,
26
+ uCloudScale: 1.08,
27
+ uDensity: 0.245,
28
+ uCoverage: 0.47,
29
+ uSoftness: 0.28,
30
+ },
31
+ },
32
+ // You, under the sky.
33
+ { id: 'you', shader: 'direct', target: 'subject' },
34
+ ],
35
+ } as const satisfies KaleidoscopePreset;
@@ -1,6 +1,7 @@
1
1
  export declare const clouds: {
2
2
  readonly name: 'Daytime';
3
3
  readonly taxonomy: readonly ["Shaders", "Sky"];
4
+ readonly thumbnail: 'clouds-thumb';
4
5
  readonly layers: readonly [{
5
6
  readonly id: 'sky';
6
7
  readonly shader: 'clouds';
@@ -1 +1 @@
1
- {"version":3,"file":"clouds.d.ts","sourceRoot":"","sources":["../../../../catalog/composites/clouds/clouds.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,MAAM;mBACX,SAAS;;;qBAIP,KAAK;yBACD,QAAQ;;qBAEd,YAAY;qBACZ,aAAa;qBACb,gBAAgB;qBAChB,eAAe;qBACf,SAAS,EAAE,IAAI;qBACf,SAAS,EAAE,IAAI;qBACf,WAAW,EAAE,IAAI;qBACjB,WAAW,EAAE,IAAI;qBACjB,QAAQ,EAAE,KAAK;qBACf,SAAS,EAAE,IAAI;qBACf,SAAS,EAAE,IAAI;;;qBAIb,KAAK;yBAAU,QAAQ;yBAAU,SAAS;;CAEb,CAAC"}
1
+ {"version":3,"file":"clouds.d.ts","sourceRoot":"","sources":["../../../../catalog/composites/clouds/clouds.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,MAAM;mBACX,SAAS;;wBAEJ,cAAc;;qBAGjB,KAAK;yBACD,QAAQ;;qBAEd,YAAY;qBACZ,aAAa;qBACb,gBAAgB;qBAChB,eAAe;qBACf,SAAS,EAAE,IAAI;qBACf,SAAS,EAAE,IAAI;qBACf,WAAW,EAAE,IAAI;qBACjB,WAAW,EAAE,IAAI;qBACjB,QAAQ,EAAE,KAAK;qBACf,SAAS,EAAE,IAAI;qBACf,SAAS,EAAE,IAAI;;;qBAIb,KAAK;yBAAU,QAAQ;yBAAU,SAAS;;CAEb,CAAC"}
@@ -3,11 +3,17 @@
3
3
  // procedural; no image layer.
4
4
  //
5
5
  // A packaged composite consumers can list by importing this module.
6
+ //
7
+ // Native variant. The thumbnail is the string id the prebuild plugin
8
+ // (app.plugin.js) bundles `clouds.thumb.webp` as into the native app target;
9
+ // `resolveImageUri` looks it up in Bundle.main. The web sibling (clouds.web.ts)
10
+ // keeps the `Asset.fromModule(...).uri` pattern; mirrors the other composites.
6
11
  Object.defineProperty(exports, "__esModule", { value: true });
7
12
  exports.clouds = void 0;
8
13
  exports.clouds = {
9
14
  name: 'Daytime',
10
15
  taxonomy: ['Shaders', 'Sky'],
16
+ thumbnail: 'clouds-thumb',
11
17
  layers: [
12
18
  {
13
19
  id: 'sky',
@@ -1 +1 @@
1
- {"version":3,"file":"clouds.js","sourceRoot":"","sources":["../../../../catalog/composites/clouds/clouds.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,8BAA8B;AAC9B,EAAE;AACF,oEAAoE;;;AAIvD,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE,SAAS;IACf,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC;IAC5B,MAAM,EAAE;QACN;YACE,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE;gBACR,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;gBAChC,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;gBACjC,gBAAgB,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC;gBACnC,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;gBAChC,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,IAAI;gBACjB,WAAW,EAAE,IAAI;gBACjB,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,IAAI;aAChB;SACF;QACD,sBAAsB;QACtB,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE;KACnD;CACoC,CAAC","sourcesContent":["// Sky: raymarched daytime clouds with you composited over them. Fully\n// procedural; no image layer.\n//\n// A packaged composite consumers can list by importing this module.\n\nimport type { KaleidoscopePreset } from '../../../src/kaleidoscope.preset-book.types';\n\nexport const clouds = {\n name: 'Daytime',\n taxonomy: ['Shaders', 'Sky'],\n layers: [\n {\n id: 'sky',\n shader: 'clouds',\n uniforms: {\n uSkyLowColor: [0.09, 0.63, 0.95],\n uSkyHighColor: [0.04, 0.03, 0.86],\n uCloudLightColor: [1.0, 0.91, 0.77],\n uCloudDarkColor: [0.3, 0.3, 0.5],\n uExposure: 1.27,\n uStepSize: 0.16,\n uCloudSpeed: 0.52,\n uCloudScale: 1.08,\n uDensity: 0.245,\n uCoverage: 0.47,\n uSoftness: 0.28,\n },\n },\n // You, under the sky.\n { id: 'you', shader: 'direct', target: 'subject' },\n ],\n} as const satisfies KaleidoscopePreset;\n"]}
1
+ {"version":3,"file":"clouds.js","sourceRoot":"","sources":["../../../../catalog/composites/clouds/clouds.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,8BAA8B;AAC9B,EAAE;AACF,oEAAoE;AACpE,EAAE;AACF,qEAAqE;AACrE,6EAA6E;AAC7E,gFAAgF;AAChF,+EAA+E;;;AAIlE,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE,SAAS;IACf,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC;IAC5B,SAAS,EAAE,cAAc;IACzB,MAAM,EAAE;QACN;YACE,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE;gBACR,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;gBAChC,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;gBACjC,gBAAgB,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC;gBACnC,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;gBAChC,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,IAAI;gBACjB,WAAW,EAAE,IAAI;gBACjB,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,IAAI;aAChB;SACF;QACD,sBAAsB;QACtB,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE;KACnD;CACoC,CAAC","sourcesContent":["// Sky: raymarched daytime clouds with you composited over them. Fully\n// procedural; no image layer.\n//\n// A packaged composite consumers can list by importing this module.\n//\n// Native variant. The thumbnail is the string id the prebuild plugin\n// (app.plugin.js) bundles `clouds.thumb.webp` as into the native app target;\n// `resolveImageUri` looks it up in Bundle.main. The web sibling (clouds.web.ts)\n// keeps the `Asset.fromModule(...).uri` pattern; mirrors the other composites.\n\nimport type { KaleidoscopePreset } from '../../../src/kaleidoscope.preset-book.types';\n\nexport const clouds = {\n name: 'Daytime',\n taxonomy: ['Shaders', 'Sky'],\n thumbnail: 'clouds-thumb',\n layers: [\n {\n id: 'sky',\n shader: 'clouds',\n uniforms: {\n uSkyLowColor: [0.09, 0.63, 0.95],\n uSkyHighColor: [0.04, 0.03, 0.86],\n uCloudLightColor: [1.0, 0.91, 0.77],\n uCloudDarkColor: [0.3, 0.3, 0.5],\n uExposure: 1.27,\n uStepSize: 0.16,\n uCloudSpeed: 0.52,\n uCloudScale: 1.08,\n uDensity: 0.245,\n uCoverage: 0.47,\n uSoftness: 0.28,\n },\n },\n // You, under the sky.\n { id: 'you', shader: 'direct', target: 'subject' },\n ],\n} as const satisfies KaleidoscopePreset;\n"]}
@@ -0,0 +1,27 @@
1
+ export declare const clouds: {
2
+ readonly name: 'Daytime';
3
+ readonly taxonomy: readonly ["Shaders", "Sky"];
4
+ readonly thumbnail: string;
5
+ readonly layers: readonly [{
6
+ readonly id: 'sky';
7
+ readonly shader: 'clouds';
8
+ readonly uniforms: {
9
+ readonly uSkyLowColor: readonly [0.09, 0.63, 0.95];
10
+ readonly uSkyHighColor: readonly [0.04, 0.03, 0.86];
11
+ readonly uCloudLightColor: readonly [1, 0.91, 0.77];
12
+ readonly uCloudDarkColor: readonly [0.3, 0.3, 0.5];
13
+ readonly uExposure: 1.27;
14
+ readonly uStepSize: 0.16;
15
+ readonly uCloudSpeed: 0.52;
16
+ readonly uCloudScale: 1.08;
17
+ readonly uDensity: 0.245;
18
+ readonly uCoverage: 0.47;
19
+ readonly uSoftness: 0.28;
20
+ };
21
+ }, {
22
+ readonly id: 'you';
23
+ readonly shader: 'direct';
24
+ readonly target: 'subject';
25
+ }];
26
+ };
27
+ //# sourceMappingURL=clouds.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clouds.web.d.ts","sourceRoot":"","sources":["../../../../catalog/composites/clouds/clouds.web.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,MAAM;mBACX,SAAS;;;;qBAKP,KAAK;yBACD,QAAQ;;qBAEd,YAAY;qBACZ,aAAa;qBACb,gBAAgB;qBAChB,eAAe;qBACf,SAAS,EAAE,IAAI;qBACf,SAAS,EAAE,IAAI;qBACf,WAAW,EAAE,IAAI;qBACjB,WAAW,EAAE,IAAI;qBACjB,QAAQ,EAAE,KAAK;qBACf,SAAS,EAAE,IAAI;qBACf,SAAS,EAAE,IAAI;;;qBAIb,KAAK;yBAAU,QAAQ;yBAAU,SAAS;;CAEb,CAAC"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ // Web variant. Resolves the thumbnail URI via expo-asset at module-load time;
3
+ // safe on web (react-native-web has no Image.resolveAssetSource and `.uri` is
4
+ // set synchronously by fromModule). Native is clouds.ts (a string-id thumbnail
5
+ // the prebuild plugin bundles). Mirrors the other composites' {<id>.ts,<id>.web.ts}.
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.clouds = void 0;
11
+ const expo_asset_1 = require("expo-asset");
12
+ const clouds_thumb_webp_1 = __importDefault(require("./clouds.thumb.webp"));
13
+ exports.clouds = {
14
+ name: 'Daytime',
15
+ taxonomy: ['Shaders', 'Sky'],
16
+ thumbnail: expo_asset_1.Asset.fromModule(clouds_thumb_webp_1.default).uri,
17
+ layers: [
18
+ {
19
+ id: 'sky',
20
+ shader: 'clouds',
21
+ uniforms: {
22
+ uSkyLowColor: [0.09, 0.63, 0.95],
23
+ uSkyHighColor: [0.04, 0.03, 0.86],
24
+ uCloudLightColor: [1.0, 0.91, 0.77],
25
+ uCloudDarkColor: [0.3, 0.3, 0.5],
26
+ uExposure: 1.27,
27
+ uStepSize: 0.16,
28
+ uCloudSpeed: 0.52,
29
+ uCloudScale: 1.08,
30
+ uDensity: 0.245,
31
+ uCoverage: 0.47,
32
+ uSoftness: 0.28,
33
+ },
34
+ },
35
+ // You, under the sky.
36
+ { id: 'you', shader: 'direct', target: 'subject' },
37
+ ],
38
+ };
39
+ //# sourceMappingURL=clouds.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clouds.web.js","sourceRoot":"","sources":["../../../../catalog/composites/clouds/clouds.web.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,qFAAqF;;;;;;AAErF,2CAAmC;AAEnC,4EAA8C;AAEjC,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE,SAAS;IACf,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC;IAC5B,SAAS,EAAE,kBAAK,CAAC,UAAU,CAAC,2BAAW,CAAC,CAAC,GAAG;IAC5C,MAAM,EAAE;QACN;YACE,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE;gBACR,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;gBAChC,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;gBACjC,gBAAgB,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC;gBACnC,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;gBAChC,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,IAAI;gBACjB,WAAW,EAAE,IAAI;gBACjB,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,IAAI;aAChB;SACF;QACD,sBAAsB;QACtB,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE;KACnD;CACoC,CAAC","sourcesContent":["// Web variant. Resolves the thumbnail URI via expo-asset at module-load time;\n// safe on web (react-native-web has no Image.resolveAssetSource and `.uri` is\n// set synchronously by fromModule). Native is clouds.ts (a string-id thumbnail\n// the prebuild plugin bundles). Mirrors the other composites' {<id>.ts,<id>.web.ts}.\n\nimport { Asset } from 'expo-asset';\nimport type { KaleidoscopePreset } from '../../../src/kaleidoscope.preset-book.types';\nimport cloudsThumb from './clouds.thumb.webp';\n\nexport const clouds = {\n name: 'Daytime',\n taxonomy: ['Shaders', 'Sky'],\n thumbnail: Asset.fromModule(cloudsThumb).uri,\n layers: [\n {\n id: 'sky',\n shader: 'clouds',\n uniforms: {\n uSkyLowColor: [0.09, 0.63, 0.95],\n uSkyHighColor: [0.04, 0.03, 0.86],\n uCloudLightColor: [1.0, 0.91, 0.77],\n uCloudDarkColor: [0.3, 0.3, 0.5],\n uExposure: 1.27,\n uStepSize: 0.16,\n uCloudSpeed: 0.52,\n uCloudScale: 1.08,\n uDensity: 0.245,\n uCoverage: 0.47,\n uSoftness: 0.28,\n },\n },\n // You, under the sky.\n { id: 'you', shader: 'direct', target: 'subject' },\n ],\n} as const satisfies KaleidoscopePreset;\n"]}
package/llms.txt CHANGED
@@ -484,7 +484,7 @@ Each book entry is a `KaleidoscopePreset`:
484
484
 
485
485
  - `name`: human label shown in the picker.
486
486
  - `taxonomy`: the picker's grouping path, root first: `[group]` or `[group, category]` (e.g. `['Backgrounds', 'Office']`). Group is the tab; category is the second-level menu. (This field is named `taxonomy`, NOT `category`.)
487
- - `thumbnail?`: optional preview source for the picker tile.
487
+ - `thumbnail?`: optional preview source for the picker tile. Pass a bundled-asset reference: a bare `require('./thumb.webp')` (what `bun run thumbs` emits) or an imported image module (`thumbnail: officeDark`). Do NOT use `Asset.fromModule(require('./thumb.webp')).uri` in a single-file book; that string renders on web but is empty in a native release build.
488
488
  - `controls?`: optional editor component for the live-controls panel (see below).
489
489
  - `layers`: the painter's stack, rendered back to front. A layer is `{ id, shader, target?, blend? }` plus the shader's own fields:
490
490
  - `shader: 'image'` takes a `source` (a bundled image id on native; a URL/data-URI also allowed on web).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-webrtc-kaleidoscope",
3
- "version": "2.7.6",
3
+ "version": "2.7.8",
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",
@@ -331,6 +331,7 @@
331
331
  "./composites/clouds": {
332
332
  "types": "./dist/catalog/composites/clouds/clouds.d.ts",
333
333
  "react-native": "./catalog/composites/clouds/clouds.ts",
334
+ "browser": "./dist/catalog/composites/clouds/clouds.web.js",
334
335
  "import": "./dist/catalog/composites/clouds/clouds.js",
335
336
  "default": "./dist/catalog/composites/clouds/clouds.js"
336
337
  },
@@ -565,7 +566,8 @@
565
566
  "lint:fix": "biome check --write",
566
567
  "format": "biome format --write .",
567
568
  "test": "bun test",
568
- "check": "bun run lint:fix && bun run typecheck && bun run typecheck:test && bun run typecheck:demo && bun run check:react-compiler && bun run check:plugin && bun run build && (cd demo && bun run build) && bun run test && bun run check:knip && bun run check:package && bun run check:kotlin && bun run check:swift",
569
+ "check": "bun run lint:fix && bun run typecheck && bun run typecheck:test && bun run typecheck:demo && bun run check:react-compiler && bun run check:assets && bun run check:plugin && bun run build && (cd demo && bun run build) && bun run test && bun run check:knip && bun run check:package && bun run check:kotlin && bun run check:swift",
570
+ "check:assets": "bun run scripts/check-book-assets.ts",
569
571
  "check:package": "publint --strict",
570
572
  "check:knip": "knip",
571
573
  "check:react-compiler": "eslint src/components 'catalog/composites/**/*.controls.tsx' 'catalog/shaders/**/*.form.tsx'",
@@ -16,10 +16,14 @@ exports.bumpDeploymentTarget = bumpDeploymentTarget;
16
16
  const node_fs_1 = __importDefault(require('node:fs'));
17
17
  const node_path_1 = __importDefault(require('node:path'));
18
18
  const constants_1 = require('../lib/constants');
19
- // Mirrors ios/Kaleidoscope.podspec :ios => '15.0'. Bumping the podspec requires
20
- // bumping this constant; the drift cost is a silent pod-install drop (the bug
21
- // this plugin fixes): expo-modules-autolinking drops any pod whose declared
22
- // minimum platform exceeds the Podfile platform.
19
+ // The Kaleidoscope POD's own iOS floor; mirrors ios/Kaleidoscope.podspec
20
+ // :ios => '15.0'. Bumping the podspec requires bumping this constant. It is
21
+ // reconciled against the HOST RN's floor at write time (see bumpDeploymentTarget):
22
+ // the pod floor is only forced when it EXCEEDS the floor the generated Podfile
23
+ // already defaults to, because expo-modules-autolinking drops any pod whose
24
+ // declared minimum platform exceeds the Podfile platform. It is never written
25
+ // BELOW the Podfile's own default, which would lower RN's floor and fail pod
26
+ // install on RN's core pods (issue #86: RN >= 0.81's floor 15.1 exceeds this).
23
27
  const IOS_DEPLOYMENT_TARGET = '15.0';
24
28
  /**
25
29
  * Compare two dotted version strings element-wise. Returns true iff `existing`
@@ -42,15 +46,62 @@ function isVersionLessThan(existing, target) {
42
46
  return false; // equal
43
47
  }
44
48
  /**
45
- * Raise `ios.deploymentTarget` in Podfile.properties.json to the library
46
- * minimum. The generated Podfile reads `podfile_properties['ios.deploymentTarget']`
47
- * at the top, so this is the canonical, no-Podfile-edit override seam. Without
48
- * this bump the Kaleidoscope pod is silently dropped and the runtime module
49
- * lookup throws. Non-downgrading, idempotent, non-fatal (warn, never throw).
49
+ * The iOS deployment-target FLOOR the generated Podfile falls back to when
50
+ * `ios.deploymentTarget` is unset. Expo/RN prebuild bakes the host RN's own floor
51
+ * (`min_ios_version_supported`) into the Podfile's platform line as a literal,
52
+ * e.g. `platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'` (or a
53
+ * bare `platform :ios, '15.1'`). That literal is exactly the value the Podfile
54
+ * uses when we leave the props key alone, so it is the floor we must not drop
55
+ * below. Returns the dotted version, or undefined if the Podfile is absent,
56
+ * unreadable, or states its fallback as a non-literal (a Ruby call) we cannot read
57
+ * statically; the caller then conservatively forces the pod floor (prior behavior).
50
58
  *
51
- * Reads the file by hand (not readTextOrNull) because it must DISTINGUISH a
52
- * missing file (treat as `{}` and write the bump) from an unreadable one (bail
53
- * without clobbering); a distinction readTextOrNull deliberately flattens.
59
+ * The Podfile, already on disk at mod-execution time, is preferred over reaching
60
+ * into react-native's Ruby helper: no dependency to resolve, no coupling to RN's
61
+ * internal file layout or `exports` map, and it reflects any consumer Podfile
62
+ * override too.
63
+ */
64
+ function readPodfileIosFloor(platformProjectRoot) {
65
+ try {
66
+ const podfile = node_fs_1.default.readFileSync(
67
+ node_path_1.default.join(platformProjectRoot, 'Podfile'),
68
+ 'utf8',
69
+ );
70
+ const platformLine = podfile.match(/^[ \t]*platform[ \t]+:ios\b.*$/m)?.[0];
71
+ if (!platformLine) return undefined;
72
+ // The only dotted-numeric quoted token on the platform line is the floor
73
+ // literal; `'ios.deploymentTarget'` is non-numeric. Take the last match so a
74
+ // bare `platform :ios, 'X.Y'` and the `|| 'X.Y'` fallback form both resolve.
75
+ const versions = platformLine.match(/['"]\d+\.\d+(?:\.\d+)?['"]/g);
76
+ const last = versions?.[versions.length - 1];
77
+ return last ? last.replace(/['"]/g, '') : undefined;
78
+ } catch {
79
+ return undefined;
80
+ }
81
+ }
82
+ /**
83
+ * Reconcile `ios.deploymentTarget` in Podfile.properties.json so the Kaleidoscope
84
+ * pod is not dropped by expo-modules-autolinking (which drops any pod whose
85
+ * declared minimum platform exceeds the Podfile platform), WITHOUT ever lowering
86
+ * the host RN's own floor. The generated Podfile reads
87
+ * `podfile_properties['ios.deploymentTarget']` at the top, so this props key is the
88
+ * canonical, no-Podfile-edit override seam.
89
+ *
90
+ * Given the pod floor (IOS_DEPLOYMENT_TARGET) and the Podfile's own fallback floor
91
+ * (readPodfileIosFloor, i.e. the host RN's floor):
92
+ * - key set >= pod floor: leave it (never downgrade).
93
+ * - key set < pod floor: raise it to the pod floor.
94
+ * - key unset, Podfile floor already >= pod floor: DEFER (leave unset). The
95
+ * Podfile's `|| <floor>` already satisfies the pod, so writing the lower pod
96
+ * floor would clobber it and break pod install on RN's core pods (issue #86).
97
+ * Deferring also auto-tracks future RN floor bumps with no code change.
98
+ * - key unset, Podfile floor below or unknown: force the pod floor (prior
99
+ * behavior, e.g. RN 0.74's 13.4 < 15.0).
100
+ * Idempotent, non-fatal (warn, never throw).
101
+ *
102
+ * Reads the props file by hand (not readTextOrNull) because it must DISTINGUISH a
103
+ * missing file (treat as `{}`) from an unreadable one (bail without clobbering);
104
+ * a distinction readTextOrNull deliberately flattens.
54
105
  */
55
106
  function bumpDeploymentTarget(platformProjectRoot) {
56
107
  const propsPath = node_path_1.default.join(platformProjectRoot, 'Podfile.properties.json');
@@ -90,10 +141,20 @@ function bumpDeploymentTarget(platformProjectRoot) {
90
141
  for (const key of Object.keys(parsed)) {
91
142
  next[key] = parsed[key];
92
143
  }
93
- const existing = next['ios.deploymentTarget'];
94
- if (
95
- isVersionLessThan(typeof existing === 'string' ? existing : undefined, IOS_DEPLOYMENT_TARGET)
96
- ) {
144
+ const existingRaw = next['ios.deploymentTarget'];
145
+ const existing = typeof existingRaw === 'string' ? existingRaw : undefined;
146
+ if (existing === undefined) {
147
+ // Unset: the Podfile resolves `|| <floor literal>`, which tracks the host
148
+ // RN's own iOS floor. Only force the pod floor when that fallback floor is
149
+ // below it (or unreadable); otherwise defer so we never lower RN's floor.
150
+ // `isVersionLessThan(undefined, ...)` is true, so an unreadable Podfile floor
151
+ // falls back to forcing the pod floor (prior behavior).
152
+ const podfileFloor = readPodfileIosFloor(platformProjectRoot);
153
+ if (isVersionLessThan(podfileFloor, IOS_DEPLOYMENT_TARGET)) {
154
+ next['ios.deploymentTarget'] = IOS_DEPLOYMENT_TARGET;
155
+ }
156
+ } else if (isVersionLessThan(existing, IOS_DEPLOYMENT_TARGET)) {
157
+ // Explicit value below the pod floor: raise it. At or above: leave it.
97
158
  next['ios.deploymentTarget'] = IOS_DEPLOYMENT_TARGET;
98
159
  }
99
160
  node_fs_1.default.writeFileSync(propsPath, `${JSON.stringify(next, null, 2)}\n`);