codeplay-common 4.6.0 → 4.6.2

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
@@ -28,11 +28,15 @@ For example, publish `agents-1.1.zip` and add this entry to the server's
28
28
  "agents": "1.1"
29
29
  ```
30
30
 
31
- Donate to get full code including many common functions
32
- https://ko-fi.com/codeplay
33
-
34
- 4.2.8
35
- baseline profile code modifications
31
+ Donate to get full code including many common functions
32
+ https://ko-fi.com/codeplay
33
+
34
+ Version 4.6.1
35
+ Added automatic IAP startup integration for Framework7 home pages.
36
+ Updated minimum shared versions to IAP 4.2 and AdMob nextgen 2.5.
37
+
38
+ 4.2.8
39
+ baseline profile code modifications
36
40
 
37
41
  Version 4.2.3
38
42
  Added build warning confirmation when android.ORIENTATION is not "auto" or android.RESIZEABLE_ACTIVITY is not true.
@@ -502,120 +502,107 @@ checkAppUniqueId();
502
502
 
503
503
 
504
504
 
505
- // ======================================================
506
- // 🚫 BLOCK STATIC IMPORT OF showSubscribePopup (ANY VERSION)
507
- // ======================================================
508
-
509
- const STATIC_SUBSCRIBE_REGEX = /import\s*{\s*showSubscribePopup\s*}\s*from\s*['"].*\/js\/Ads\/IAP-\d+(\.\d+)*\/IAP-check-And-LoadAd\.js['"]/;
510
-
511
- // ✅ Detect dynamic import (valid)
512
- const DYNAMIC_SUBSCRIBE_REGEX = /await\s+import\s*\(\s*['"].*\/js\/Ads\/IAP-\d+(\.\d+)*\/IAP-check-And-LoadAd\.js['"]\s*\)/;
513
-
514
- let subscribeImportError = false;
515
-
516
- function scanSubscribeImport(dir) {
517
- const files = fs.readdirSync(dir);
518
-
519
- for (const file of files) {
520
- const fullPath = path.join(dir, file);
521
- const stat = fs.statSync(fullPath);
522
-
523
- if (stat.isDirectory()) {
524
- scanSubscribeImport(fullPath);
525
- }
526
- else if (file.endsWith(".js") || file.endsWith(".ts") || file.endsWith(".f7")) {
527
-
528
- const content = fs.readFileSync(fullPath, "utf-8");
529
- const lines = content.split("\n");
530
-
531
- lines.forEach((line, index) => {
532
-
533
- // ❌ STATIC import → ERROR
534
- if (STATIC_SUBSCRIBE_REGEX.test(line)) {
535
- console.error(`
536
- ❌ Forbidden static import detected!
537
-
538
- File: ${fullPath}
539
- Line: ${index + 1}
540
- Code: ${line.trim()}
541
-
542
- 🚫 DO NOT use static import for showSubscribePopup
543
-
544
- 👉 Remove:
545
- import { showSubscribePopup } from './../js/Ads/IAP-x.x/IAP-check-And-LoadAd.js'
546
-
547
-
548
- ✅ Use dynamic import (ANY version allowed):
549
-
550
- let IAPModule = null;
551
- const loadIAP = async () => {
552
- if (!IAPModule) {
553
- IAPModule = await import('./../js/Ads/IAP-x.x/IAP-check-And-LoadAd.js');
554
- IAPModule.initIAP?.();
555
- }
556
-
557
- return IAPModule;
558
- };
559
-
560
- $on('pageAfterIn', async () => {
561
- await loadIAP();
562
- });
563
-
564
- const subscribeOrProLink = async () => {
565
-
566
- //This is only allowed if samsung have pro version
567
- if(_storeid==2)
568
- gotoBuyPro("com.html.codeplay.pro",noAppOpenShowUntilResume)
569
- else{
570
- const module = await loadIAP();
571
- module.showSubscribePopup();
572
- }
573
- };
574
- `);
575
- subscribeImportError = true;
576
- }
577
-
578
- // ❌ Optional: detect wrong dynamic usage (no await)
579
- if (
580
- line.includes("import(") &&
581
- line.includes("IAP-") &&
582
- !line.includes("await")
583
- ) {
584
- console.warn(`
585
- ⚠️ Warning: Dynamic import without await
586
-
587
- File: ${fullPath}
588
- Line: ${index + 1}
589
- Code: ${line.trim()}
590
-
591
- 👉 Always use:
592
- const { showSubscribePopup } = await import(...)
593
- `);
594
- }
595
-
596
- });
597
- }
598
- }
599
- }
600
-
601
-
602
- // Run scan
603
- scanSubscribeImport(ROOT_DIR);
604
-
605
- // Stop build
606
- if (subscribeImportError) {
607
- console.error("🚫 Build failed due to forbidden showSubscribePopup static import.");
608
- process.exit(1);
609
- } else {
610
- console.log("✅ showSubscribePopup import usage is valid.");
611
- }
612
-
613
-
614
-
615
-
616
- // ======================================================
617
- // 🚫 BLOCK STATIC IMPORT OF showSubscribePopup (ANY VERSION) END
618
- // ======================================================
505
+ // ======================================================
506
+ // ENSURE IAP STARTS FROM THE HOME PAGE
507
+ // ======================================================
508
+
509
+ const getHomePagePath = () => {
510
+ const pagesDir = path.join(ROOT_DIR, "pages");
511
+ if (!fs.existsSync(pagesDir)) return null;
512
+
513
+ const exactHomePath = path.join(pagesDir, "home.f7");
514
+ if (fs.existsSync(exactHomePath)) return exactHomePath;
515
+
516
+ const pageFiles = fs.readdirSync(pagesDir)
517
+ .filter(fileName => fileName.endsWith(".f7"));
518
+
519
+ return pageFiles
520
+ .map(fileName => path.join(pagesDir, fileName))
521
+ .find(filePath => /data-name\s*=\s*['"]home['"]/.test(fs.readFileSync(filePath, "utf8"))) || null;
522
+ };
523
+
524
+ const getRelativeModuleImport = (sourceFile, targetFile) => {
525
+ let relativePath = path.relative(path.dirname(sourceFile), targetFile).replace(/\\/g, "/");
526
+ if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
527
+ return relativePath;
528
+ };
529
+
530
+ const addInitIapToExistingImport = (content) => {
531
+ const iapImportRegex = /import\s*\{([^}]*)\}\s*from\s*(['"])([^'"]*\/IAP-\d+(?:\.\d+)*\/IAP-check-And-LoadAd\.js)\2\s*;?/;
532
+ const match = content.match(iapImportRegex);
533
+ if (!match || /\binitIAP\b/.test(match[1])) return content;
534
+
535
+ const importNames = match[1].trim();
536
+ const nextImportNames = importNames ? `initIAP, ${importNames}` : "initIAP";
537
+ return content.replace(iapImportRegex, `import { ${nextImportNames} } from ${match[2]}${match[3]}${match[2]};`);
538
+ };
539
+
540
+ const addInitIapCall = (content) => {
541
+ if (/\binitIAP\s*\(/.test(content)) return content;
542
+
543
+ const pageInitRegex = /(\$on\(\s*(['"])pageInit\2\s*,\s*(?:async\s*)?\(\)\s*=>\s*\{\s*\r?\n)/;
544
+ if (pageInitRegex.test(content)) {
545
+ return content.replace(pageInitRegex, "$1 initIAP();\n");
546
+ }
547
+
548
+ const componentStartRegex = /(export\s+default\s*\([^)]*\)\s*=>\s*\{\s*\r?\n)/;
549
+ if (componentStartRegex.test(content)) {
550
+ return content.replace(componentStartRegex, "$1 initIAP();\n");
551
+ }
552
+
553
+ throw new Error("Unable to find a Framework7 component or pageInit lifecycle for IAP startup.");
554
+ };
555
+
556
+ const ensureIapStartupOnHomePage = () => {
557
+ const iapConfig = getAdmobIapConfig()?.IAP;
558
+ if (!isAnyIapStoreEnabled(iapConfig)) {
559
+ console.log("ℹ️ IAP is disabled for every store. AdMob will use direct startup.");
560
+ return;
561
+ }
562
+
563
+ const latestIapDir = getLatestIapDir();
564
+ if (!latestIapDir) {
565
+ throw new Error("IAP is enabled but no IAP-x.x folder was found.");
566
+ }
567
+
568
+ const homePagePath = getHomePagePath();
569
+ if (!homePagePath) {
570
+ throw new Error("IAP is enabled but a Framework7 Home page could not be found in src/pages.");
571
+ }
572
+
573
+ const iapModulePath = path.join(latestIapDir, "IAP-check-And-LoadAd.js");
574
+ if (!fs.existsSync(iapModulePath)) {
575
+ throw new Error(`IAP startup module is missing: ${iapModulePath}`);
576
+ }
577
+
578
+ let content = fs.readFileSync(homePagePath, "utf8");
579
+ const originalContent = content;
580
+ const staticInitImportRegex = /import\s*\{[^}]*\binitIAP\b[^}]*\}\s*from\s*['"][^'"]*\/IAP-\d+(?:\.\d+)*\/IAP-check-And-LoadAd\.js['"]\s*;?/;
581
+
582
+ content = addInitIapToExistingImport(content);
583
+
584
+ if (!staticInitImportRegex.test(content)) {
585
+ const relativeImport = getRelativeModuleImport(homePagePath, iapModulePath);
586
+ const scriptStartRegex = /<script>\s*\r?\n/;
587
+ if (!scriptStartRegex.test(content)) {
588
+ throw new Error(`Unable to find the script block in ${homePagePath}`);
589
+ }
590
+ content = content.replace(scriptStartRegex, `$&import { initIAP } from '${relativeImport}';\n`);
591
+ }
592
+
593
+ content = addInitIapCall(content);
594
+
595
+ if (content !== originalContent) {
596
+ fs.writeFileSync(homePagePath, content, "utf8");
597
+ console.log(`✅ Added direct IAP startup to ${path.relative(process.cwd(), homePagePath)}.`);
598
+ } else {
599
+ console.log(`ℹ️ Direct IAP startup already configured in ${path.relative(process.cwd(), homePagePath)}.`);
600
+ }
601
+ };
602
+
603
+ // ======================================================
604
+ // ENSURE IAP STARTS FROM THE HOME PAGE END
605
+ // ======================================================
619
606
 
620
607
 
621
608
 
@@ -4184,9 +4171,10 @@ async function main() {
4184
4171
  await syncAgentInstructions();
4185
4172
 
4186
4173
  await syncAdmobNextgenMigration();
4187
- syncSystemBarsSafeAreaMigration();
4188
- await checkPlugins();
4189
- syncRevenueCatIapSetup();
4174
+ syncSystemBarsSafeAreaMigration();
4175
+ await checkPlugins();
4176
+ ensureIapStartupOnHomePage();
4177
+ syncRevenueCatIapSetup();
4190
4178
  syncFirebaseAnalyticsSetup();
4191
4179
  checkAndupdateDropInViteConfig();
4192
4180
  checkAdmobConfigurationProperty();
@@ -133,7 +133,11 @@ import androidx.activity.EdgeToEdge;
133
133
  protected void onCreate(Bundle savedInstanceState) {
134
134
  super.onCreate(savedInstanceState);
135
135
 
136
- EdgeToEdge.enable(this);
136
+ // Android 15+ enforces edge-to-edge. Older Android and Fire OS
137
+ // should let the system keep the WebView clear of system bars.
138
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
139
+ EdgeToEdge.enable(this);
140
+ }
137
141
 
138
142
  // Handle custom splash screen exit animation
139
143
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
@@ -3,7 +3,7 @@
3
3
  {"name":"backbutton","pattern":"backbutton-(\\d+\\.\\d+)\\.js$","minVersion":"2.1","baseDir":"js","mandatoryUpdate":true},
4
4
  {"name":"common-js","pattern":"common-(\\d+\\.\\d+)(?:-beta-(\\d+))?\\.js$","minVersion":"6.7","baseDir":"js","mandatoryUpdate":true},
5
5
 
6
- {"name":"admob-emi-nextgen","pattern":"Ads[\\\\/]admob-emi-nextgen-(\\d+\\.\\d+)\\.js$","minVersion":"1.0","baseDir":"js","mandatoryUpdate":true},
6
+ {"name":"admob-emi-nextgen","pattern":"Ads[\\\\/]admob-emi-nextgen-(\\d+\\.\\d+)\\.js$","minVersion":"2.5","baseDir":"js","mandatoryUpdate":true},
7
7
  {"name":"video-player","pattern":"video-player-(\\d+\\.\\d+)\\.js$","minVersion":"1.6","baseDir":"js","mandatoryUpdate":true},
8
8
  {"name":"image-cropper","pattern":"image-cropper-(\\d+\\.\\d+)\\.js$","minVersion":"1.1","baseDir":"js","mandatoryUpdate":true},
9
9
  {"name":"beautify","pattern":"beautify-(\\d+\\.\\d+)\\.js$","minVersion":"1.1","baseDir":"js","mandatoryUpdate":true},
@@ -17,7 +17,7 @@
17
17
  {"name":"ffmpeg","pattern":"ffmpeg-(\\d+\\.\\d+)$","minVersion":"1.6","baseDir":"js","mandatoryUpdate":true,"isFolder":true},
18
18
  {"name":"theme","pattern":"theme-(\\d+\\.\\d+)$","minVersion":"3.5","baseDir":"theme","destDir":"theme","mandatoryUpdate":true,"isFolder":true},
19
19
  {"name":"certificatejs","pattern":"certificatejs-(\\d+\\.\\d+)$","minVersion":"1.9","baseDir":"certificate","destDir":"certificate","mandatoryUpdate":true,"isFolder":true},
20
- {"name":"IAP","pattern":"IAP-(\\d+\\.\\d+)$","minVersion":"3.6","baseDir":"js/Ads","mandatoryUpdate":true,"isFolder":true},
20
+ {"name":"IAP","pattern":"IAP-(\\d+\\.\\d+)$","minVersion":"4.2","baseDir":"js/Ads","mandatoryUpdate":true,"isFolder":true},
21
21
  {"name":"common-less","pattern":"common-(\\d+\\.\\d+)\\.less$","minVersion":"1.8","baseDir":"assets/css","mandatoryUpdate":true},
22
22
  {"name":"localNotification_AppSettings","pattern":"localNotification_AppSettings-(\\d+\\.\\d+)\\.js$","minVersion":"1.0","baseDir":"js","mandatoryUpdate":true},
23
23
  {"name":"localNotification","pattern":"localNotification-(\\d+\\.\\d+)\\.js$","minVersion":"2.2","baseDir":"js","mandatoryUpdate":true},
@@ -703,7 +703,7 @@ function findGradleBlock(content, headerPattern) {
703
703
  const amazonWindowExtensionsDependency = 'implementation "androidx.window.extensions.core:core:1.0.0"';
704
704
  const amazonWindowExtensionsDependencyPattern = /^[ \t]*implementation\s+["']androidx\.window\.extensions\.core:core:[^"']+["'][ \t]*(?:\r?\n)?/gm;
705
705
 
706
- function setAmazonWindowExtensionsDependency(enabled) {
706
+ function setAmazonWindowExtensionsDependency(enabled, { cleanup = false } = {}) {
707
707
  const currentGradleContent = readFileSync(gradleFilePath, 'utf8');
708
708
  let nextGradleContent = currentGradleContent.replace(amazonWindowExtensionsDependencyPattern, '');
709
709
 
@@ -728,7 +728,9 @@ function setAmazonWindowExtensionsDependency(enabled) {
728
728
 
729
729
  console.log(enabled
730
730
  ? '✅ Added Amazon Fire WebView compatibility dependency for Store ID 7.'
731
- : 'ℹ️ Amazon Fire WebView compatibility dependency is not included for this build.');
731
+ : cleanup
732
+ ? 'ℹ️ Removed temporary Amazon Fire WebView compatibility dependency after build cleanup.'
733
+ : 'ℹ️ Amazon Fire WebView compatibility dependency is not included for this build.');
732
734
  }
733
735
 
734
736
  const versionCodeMatch = gradleContent.match(/versionCode\s+(\d+)/);
@@ -1002,11 +1004,15 @@ rl.question('Enter new versionCode (press enter to keep current): ', (newVersion
1002
1004
  } catch (error) {
1003
1005
  console.error(`❌ Error during build for Store ID ${id}:`, error);
1004
1006
  restoreFlowchartStoreApi();
1005
- setAmazonWindowExtensionsDependency(false);
1007
+ setAmazonWindowExtensionsDependency(false, {
1008
+ cleanup: String(id) === '7' && amazon === true,
1009
+ });
1006
1010
  process.exit(1);
1007
1011
  } finally {
1008
1012
  restoreFlowchartStoreApi();
1009
- setAmazonWindowExtensionsDependency(false);
1013
+ setAmazonWindowExtensionsDependency(false, {
1014
+ cleanup: String(id) === '7' && amazon === true,
1015
+ });
1010
1016
  }
1011
1017
  });
1012
1018
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeplay-common",
3
- "version": "4.6.0",
3
+ "version": "4.6.2",
4
4
  "description": "Common build scripts and files",
5
5
  "scripts": {
6
6
  "postinstall": "node scripts/sync-files.js",