flowboard-react 0.6.5 → 0.6.7

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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/bin/setup.js +132 -9
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -30,6 +30,8 @@ npx --package flowboard-react flowboard-setup --dry-run
30
30
 
31
31
  `flowboard-react` keeps heavy native modules as peer dependencies to avoid duplicate binaries and version conflicts in host apps. The setup command installs the required peer set for you.
32
32
 
33
+ By default, `flowboard-setup` installs only missing peers. If your app already declares one of these native packages, the setup command leaves it untouched so it does not force a downgrade. Use `--upgrade` to install Flowboard's validated package matrix explicitly.
34
+
33
35
  ## Expo Support
34
36
 
35
37
  Expo Go is not supported. This SDK depends on custom native modules, so Expo users need a development build, `expo prebuild`, or EAS Build.
package/bin/setup.js CHANGED
@@ -13,7 +13,7 @@ const BASE_PACKAGES = [
13
13
  ['react-native-get-random-values', '1.11.0'],
14
14
  ['react-native-in-app-review', '4.3.3'],
15
15
  ['react-native-linear-gradient', '2.8.3'],
16
- ['react-native-pager-view', '6.2.4'],
16
+ ['react-native-pager-view', '6.2.3'],
17
17
  ['react-native-permissions', '4.1.5'],
18
18
  ['react-native-safe-area-context', '5.0.0'],
19
19
  ['react-native-svg', '15.10.1'],
@@ -64,6 +64,14 @@ function compareSemver(left, right) {
64
64
  return left.patch - right.patch;
65
65
  }
66
66
 
67
+ function incrementPatch(version) {
68
+ return {
69
+ major: version.major,
70
+ minor: version.minor,
71
+ patch: version.patch + 1,
72
+ };
73
+ }
74
+
67
75
  function rangeAcceptsVersion(spec, version) {
68
76
  const normalized = String(spec || '').trim();
69
77
  if (!normalized) return false;
@@ -118,6 +126,74 @@ function rangeAcceptsVersion(spec, version) {
118
126
  }
119
127
  }
120
128
 
129
+ function extractLowerBound(spec) {
130
+ const normalized = String(spec || '').trim();
131
+ if (
132
+ !normalized ||
133
+ normalized === '*' ||
134
+ normalized === 'latest' ||
135
+ normalized.startsWith('workspace:')
136
+ ) {
137
+ return null;
138
+ }
139
+
140
+ if (normalized.includes('||')) {
141
+ const bounds = normalized
142
+ .split('||')
143
+ .map((part) => extractLowerBound(part.trim()))
144
+ .filter(Boolean);
145
+
146
+ if (bounds.length === 0) return null;
147
+
148
+ return bounds.reduce((lowest, candidate) =>
149
+ compareSemver(candidate, lowest) < 0 ? candidate : lowest
150
+ );
151
+ }
152
+
153
+ const comparators = normalized.split(/\s+/).filter(Boolean);
154
+ if (comparators.length > 1) {
155
+ const lowerBounds = comparators
156
+ .map((part) => extractLowerBound(part))
157
+ .filter(Boolean);
158
+
159
+ if (lowerBounds.length === 0) return null;
160
+
161
+ return lowerBounds.reduce((highest, candidate) =>
162
+ compareSemver(candidate, highest) > 0 ? candidate : highest
163
+ );
164
+ }
165
+
166
+ const operatorMatch = normalized.match(/^(>=|<=|>|<|\^|~)/);
167
+ const operator = operatorMatch ? operatorMatch[1] : '';
168
+ const base = parseSemver(normalized.slice(operator.length));
169
+ if (!base) {
170
+ return parseSemver(normalized);
171
+ }
172
+
173
+ switch (operator) {
174
+ case '>':
175
+ return incrementPatch(base);
176
+ case '>=':
177
+ case '^':
178
+ case '~':
179
+ case '':
180
+ return base;
181
+ default:
182
+ return null;
183
+ }
184
+ }
185
+
186
+ function specMeetsValidatedFloor(spec, version) {
187
+ if (!spec) return false;
188
+ if (rangeAcceptsVersion(spec, version)) return true;
189
+
190
+ const lowerBound = extractLowerBound(spec);
191
+ const validated = parseSemver(version);
192
+
193
+ if (!lowerBound || !validated) return false;
194
+ return compareSemver(lowerBound, validated) >= 0;
195
+ }
196
+
121
197
  function getManifest(root) {
122
198
  const manifestPath = path.join(root, 'package.json');
123
199
  if (!fs.existsSync(manifestPath)) {
@@ -170,13 +246,33 @@ function hasReactNative(manifest) {
170
246
  }
171
247
 
172
248
  function selectPackages(manifest, options) {
173
- return BASE_PACKAGES.filter(([packageName, version]) => {
249
+ return BASE_PACKAGES.filter(([packageName]) => {
174
250
  if (options.upgrade) return true;
175
251
  const existingSpec = getPackageSpec(manifest, packageName);
176
- return !rangeAcceptsVersion(existingSpec, version);
252
+
253
+ // Never replace an existing host-app dependency unless the user opts into
254
+ // the validated matrix with --upgrade.
255
+ if (existingSpec) return false;
256
+
257
+ return true;
177
258
  }).map(([name, version]) => ({ name, version }));
178
259
  }
179
260
 
261
+ function collectCompatibilityWarnings(manifest, options) {
262
+ if (options.upgrade) return [];
263
+
264
+ return BASE_PACKAGES.reduce((warnings, [packageName, version]) => {
265
+ const existingSpec = getPackageSpec(manifest, packageName);
266
+ if (!existingSpec) return warnings;
267
+ if (specMeetsValidatedFloor(existingSpec, version)) return warnings;
268
+
269
+ warnings.push(
270
+ `${packageName}@${existingSpec} is already declared in the host app and may be below Flowboard's validated floor (${version}). flowboard-setup will leave it untouched to avoid forcing a downgrade. Use --upgrade to install the validated version explicitly.`
271
+ );
272
+ return warnings;
273
+ }, []);
274
+ }
275
+
180
276
  function selectExpoExtras(manifest, options) {
181
277
  return EXPO_EXTRA_PACKAGES.filter((packageName) => {
182
278
  if (options.upgrade) return true;
@@ -222,7 +318,7 @@ function buildInstallCommands({ expo, packageManager, packages, expoExtras }) {
222
318
  commands.push({
223
319
  args: installArgsByManager[packageManager] || installArgsByManager.npm,
224
320
  command: commandName(packageManager),
225
- title: 'Install validated React Native peer versions',
321
+ title: 'Install missing React Native peer dependencies',
226
322
  });
227
323
 
228
324
  return commands;
@@ -303,7 +399,14 @@ function printNextSteps({ expo, projectRoot }) {
303
399
  );
304
400
  }
305
401
 
306
- function printPlan({ expo, packageManager, packages, expoExtras, commands }) {
402
+ function printPlan({
403
+ expo,
404
+ packageManager,
405
+ packages,
406
+ expoExtras,
407
+ commands,
408
+ warnings,
409
+ }) {
307
410
  console.log(
308
411
  `[flowboard-setup] Target: ${
309
412
  expo ? 'Expo development build' : `React Native CLI (${packageManager})`
@@ -311,14 +414,23 @@ function printPlan({ expo, packageManager, packages, expoExtras, commands }) {
311
414
  );
312
415
 
313
416
  if (packages.length > 0) {
314
- console.log('[flowboard-setup] Packages to install:');
417
+ console.log('[flowboard-setup] Packages to install (missing):');
315
418
  packages.forEach((entry) => {
316
419
  console.log(` - ${entry.name}${expo ? '' : `@${entry.version}`}`);
317
420
  });
318
421
  } else {
319
422
  console.log(
320
- '[flowboard-setup] Base Flowboard peer dependencies already look compatible.'
423
+ '[flowboard-setup] All required peer dependencies are already present in your package.json.'
424
+ );
425
+ }
426
+
427
+ if (warnings.length > 0) {
428
+ console.log(
429
+ '[flowboard-setup] Compatibility warnings for existing host-app packages:'
321
430
  );
431
+ warnings.forEach((warning) => {
432
+ console.log(` - ${warning}`);
433
+ });
322
434
  }
323
435
 
324
436
  if (expoExtras.length > 0) {
@@ -329,7 +441,7 @@ function printPlan({ expo, packageManager, packages, expoExtras, commands }) {
329
441
  }
330
442
 
331
443
  if (commands.length > 0) {
332
- console.log('[flowboard-setup] Commands:');
444
+ console.log('[flowboard-setup] Commands to be executed:');
333
445
  commands.forEach((command) => {
334
446
  console.log(` - ${formatCommand(command)}`);
335
447
  });
@@ -363,6 +475,7 @@ async function main(rawArgs = process.argv.slice(2)) {
363
475
  const expo = isExpoProject(manifest);
364
476
  const packageManager = detectPackageManager(projectRoot, manifest);
365
477
  const packages = selectPackages(manifest, options);
478
+ const warnings = collectCompatibilityWarnings(manifest, options);
366
479
  const expoExtras = expo ? selectExpoExtras(manifest, options) : [];
367
480
  const commands = buildInstallCommands({
368
481
  expo,
@@ -371,7 +484,14 @@ async function main(rawArgs = process.argv.slice(2)) {
371
484
  packages,
372
485
  });
373
486
 
374
- printPlan({ commands, expo, expoExtras, packageManager, packages });
487
+ printPlan({
488
+ commands,
489
+ expo,
490
+ expoExtras,
491
+ packageManager,
492
+ packages,
493
+ warnings,
494
+ });
375
495
 
376
496
  if (commands.length === 0) {
377
497
  printNextSteps({ expo, projectRoot });
@@ -415,9 +535,12 @@ module.exports = {
415
535
  main,
416
536
  parseArgs,
417
537
  parseSemver,
538
+ collectCompatibilityWarnings,
539
+ extractLowerBound,
418
540
  rangeAcceptsVersion,
419
541
  selectExpoExtras,
420
542
  selectPackages,
543
+ specMeetsValidatedFloor,
421
544
  };
422
545
 
423
546
  if (require.main === module) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowboard-react",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "Onboard your users with one click",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -108,7 +108,7 @@
108
108
  "react-native-get-random-values": ">= 1.11.0",
109
109
  "react-native-in-app-review": ">= 4.3.0",
110
110
  "react-native-linear-gradient": ">= 2.8.3",
111
- "react-native-pager-view": ">= 6.2.4",
111
+ "react-native-pager-view": ">= 6.2.3",
112
112
  "react-native-permissions": ">= 4.1.5",
113
113
  "react-native-safe-area-context": ">= 5.0.0",
114
114
  "react-native-svg": ">= 15.10.1",