samre-cli 1.0.4 → 1.1.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "samre-cli",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "CLI officiel d'injection automatique du SDK Samré dans les applications mobiles (Flutter, React Native)",
5
5
  "main": "bin/samre.js",
6
6
  "bin": {
@@ -1,8 +1,8 @@
1
- // Modèle complet pour lib/samre_sdk.dart (Version 100% autonome sans dépendance au Navigator)
1
+ // Modèle complet pour lib/samre_sdk.dart (Version Professionnelle 100% Autonome)
2
2
 
3
3
  export function generateFlutterSdkCode({ apiUrl, apiKey, appId, appName, dureeJours }) {
4
4
  return `// =================================================================
5
- // SDK Samré Mobile pour Flutter (Généré automatiquement par samre-cli)
5
+ // SDK Samré Mobile pour Flutter (Généré par samre-cli)
6
6
  // Application : ${appName || 'App Samré'} (ID: ${appId})
7
7
  // Campagne : ${dureeJours || 12} jours
8
8
  // =================================================================
@@ -18,7 +18,7 @@ class SamreConfig {
18
18
  static const String apiUrl = "${apiUrl}";
19
19
  static const String apiKey = "${apiKey}";
20
20
  static const String appId = "${appId}";
21
- static const int requiredDurationSeconds = 25; // Compteur de sécurité anti-triche
21
+ static const int requiredDurationSeconds = 25; // Compteur anti-triche
22
22
  }
23
23
 
24
24
  /// Overlay automatique avec compteur de sécurité de 25 secondes
@@ -79,27 +79,27 @@ class _SamreOverlayState extends State<SamreOverlay> {
79
79
  children: [
80
80
  widget.child,
81
81
 
82
- // ── Bouton Flottant Rehaussé avec SafeArea (Au-dessus des barres de navigation) ──
82
+ // ── Bouton Flottant Rehaussé avec SafeArea ─────────────────────────
83
83
  Positioned(
84
- bottom: 48,
84
+ bottom: 56,
85
85
  right: 18,
86
86
  child: SafeArea(
87
87
  child: Material(
88
88
  elevation: 10,
89
- borderRadius: BorderRadius.circular(24),
89
+ borderRadius: BorderRadius.circular(30),
90
90
  color: _canSubmit ? const Color(0xFF2563EB) : Colors.black.withOpacity(0.85),
91
91
  child: InkWell(
92
- borderRadius: BorderRadius.circular(24),
92
+ borderRadius: BorderRadius.circular(30),
93
93
  onTap: _canSubmit ? _openDialog : null,
94
94
  child: Padding(
95
- padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
95
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
96
96
  child: Row(
97
97
  mainAxisSize: MainAxisSize.min,
98
98
  children: [
99
99
  Icon(
100
- _canSubmit ? Icons.verified_user : Icons.timer_outlined,
100
+ _canSubmit ? Icons.verified_user_rounded : Icons.timer_outlined,
101
101
  color: Colors.white,
102
- size: 18,
102
+ size: 20,
103
103
  ),
104
104
  const SizedBox(width: 8),
105
105
  Text(
@@ -107,7 +107,7 @@ class _SamreOverlayState extends State<SamreOverlay> {
107
107
  style: const TextStyle(
108
108
  color: Colors.white,
109
109
  fontWeight: FontWeight.bold,
110
- fontSize: 12,
110
+ fontSize: 13,
111
111
  decoration: TextDecoration.none,
112
112
  ),
113
113
  ),
@@ -119,7 +119,7 @@ class _SamreOverlayState extends State<SamreOverlay> {
119
119
  ),
120
120
  ),
121
121
 
122
- // ── Fenêtre Modale de Validation (Indépendante du Navigator) ─────
122
+ // ── Fenêtre Modale de Validation (100% Indépendante du Navigator) ──
123
123
  if (_showValidationDialog)
124
124
  Positioned.fill(
125
125
  child: Container(
@@ -233,8 +233,8 @@ class _SamreValidationCardState extends State<SamreValidationCard> {
233
233
  border: Border.all(color: const Color(0xFF334155), width: 1.5),
234
234
  boxShadow: [
235
235
  BoxShadow(
236
- color: Colors.black.withOpacity(0.5),
237
- blurRadius: 25,
236
+ color: Colors.black.withOpacity(0.6),
237
+ blurRadius: 30,
238
238
  spreadRadius: 5,
239
239
  ),
240
240
  ],
@@ -244,7 +244,7 @@ class _SamreValidationCardState extends State<SamreValidationCard> {
244
244
  mainAxisSize: MainAxisSize.min,
245
245
  crossAxisAlignment: CrossAxisAlignment.stretch,
246
246
  children: [
247
- // Titre
247
+ // En-tête
248
248
  Row(
249
249
  children: [
250
250
  Container(
@@ -54,6 +54,24 @@ export const FlutterUtil = {
54
54
  return sdkPath;
55
55
  },
56
56
 
57
+ cleanMainDartContent(rawContent) {
58
+ let content = rawContent;
59
+
60
+ // 1. Supprimer l'import du SDK Samré et les commentaires associés
61
+ content = content.replace(/import\s+['"]samre_sdk\.dart['"];\s*\n?/g, '');
62
+ content = content.replace(/\/\/\s*SDK Samré[^\n]*\n?/gi, '');
63
+ content = content.replace(/\/\/\s*👉\s*SamreOverlay[^\n]*\n?/gi, '');
64
+
65
+ // 2. Supprimer la propriété builder SamreOverlay dans MaterialApp
66
+ content = content.replace(/builder\s*:\s*\([^)]*\)\s*=>\s*SamreOverlay\s*\(\s*child\s*:\s*child\s*\?\?\s*const\s*SizedBox\(\)\s*\),?\s*\n?/g, '');
67
+ content = content.replace(/builder\s*:\s*\([^)]*\)\s*=>\s*SamreOverlay\s*\(\s*child\s*:\s*([^)]+)\),?\s*\n?/g, 'builder: (context, child) => $1,\n');
68
+
69
+ // 3. Déballer SamreOverlay s'il entoure un widget (ex: home: SamreOverlay(child: SplashPage()))
70
+ content = content.replace(/SamreOverlay\s*\(\s*child\s*:\s*([^)]+)\)/g, '$1');
71
+
72
+ return content;
73
+ },
74
+
57
75
  injectIntoMain(cwd = process.cwd()) {
58
76
  const mainPath = path.join(cwd, 'lib', 'main.dart');
59
77
  const backupPath = path.join(cwd, 'lib', 'main.dart.samre_bak');
@@ -62,49 +80,46 @@ export const FlutterUtil = {
62
80
  return { injected: false, reason: 'main.dart introuvable' };
63
81
  }
64
82
 
65
- const content = fs.readFileSync(mainPath, 'utf-8');
83
+ const originalContent = fs.readFileSync(mainPath, 'utf-8');
66
84
 
67
- // Sauvegarde de secours si pas encore existante
68
- if (!fs.existsSync(backupPath)) {
69
- fs.writeFileSync(backupPath, content, 'utf-8');
70
- }
85
+ // Nettoyer d'abord tout résidu ou ancienne injection pour garantir l'idempotence
86
+ let cleanContent = this.cleanMainDartContent(originalContent);
71
87
 
72
- // Si déjà injecté
73
- if (content.includes('SamreOverlay') || content.includes('samre_sdk.dart')) {
74
- return { injected: true, alreadyInjected: true, backupPath };
88
+ // Sauvegarde de secours du fichier propre initial
89
+ if (!fs.existsSync(backupPath)) {
90
+ fs.writeFileSync(backupPath, cleanContent, 'utf-8');
75
91
  }
76
92
 
77
- let modified = content;
93
+ let modified = cleanContent;
78
94
 
79
95
  // 1. Ajouter l'import de samre_sdk en haut (sans dupliquer material.dart)
80
96
  if (!modified.includes('samre_sdk.dart')) {
81
97
  modified = "import 'samre_sdk.dart';\n" + modified;
82
98
  }
83
99
 
84
- // 2. Tenter d'injecter dans builder de MaterialApp (Idéal pour tous les écrans et le routage)
85
- if (modified.includes('MaterialApp(') && !modified.includes('SamreOverlay')) {
86
- // Si MaterialApp a déjà une propriété builder
100
+ // 2. Injecter proprement dans builder de MaterialApp (supporte MaterialApp, MaterialApp.router, GetMaterialApp)
101
+ const appRegex = /((?:Get)?MaterialApp(?:\.router)?\s*\()/;
102
+ if (appRegex.test(modified)) {
103
+ // Si MaterialApp a déjà une propriété builder existante
87
104
  const builderRegex = /builder\s*:\s*\(([^)]*)\)\s*=>\s*([^,\n;]+)/;
88
105
  if (builderRegex.test(modified)) {
89
106
  modified = modified.replace(builderRegex, (match, args, body) => {
90
107
  return `builder: (${args}) => SamreOverlay(child: ${body.trim()})`;
91
108
  });
92
- fs.writeFileSync(mainPath, modified, 'utf-8');
93
- return { injected: true, modifiedBuilder: true, backupPath };
109
+ } else {
110
+ // Sinon insérer builder: (context, child) => SamreOverlay(...)
111
+ modified = modified.replace(
112
+ appRegex,
113
+ '$1\n builder: (context, child) => SamreOverlay(child: child ?? const SizedBox()),'
114
+ );
94
115
  }
95
-
96
- // Sinon insérer la propriété builder juste après MaterialApp(
97
- modified = modified.replace(
98
- /MaterialApp\s*\(/,
99
- 'MaterialApp(\n builder: (context, child) => SamreOverlay(child: child ?? const SizedBox()),'
100
- );
101
116
  fs.writeFileSync(mainPath, modified, 'utf-8');
102
117
  return { injected: true, modifiedBuilder: true, backupPath };
103
118
  }
104
119
 
105
120
  // Fallback : injection sur home:
106
121
  const homeRegex = /home\s*:\s*([^,\n\);]+)/;
107
- if (homeRegex.test(modified) && !modified.includes('SamreOverlay')) {
122
+ if (homeRegex.test(modified)) {
108
123
  modified = modified.replace(homeRegex, (match, p1) => {
109
124
  return `home: SamreOverlay(child: ${p1.trim()})`;
110
125
  });
@@ -125,22 +140,30 @@ export const FlutterUtil = {
125
140
  let sdkDeleted = false;
126
141
  let mainRestored = false;
127
142
 
143
+ // 1. Supprimer le fichier SDK
128
144
  if (fs.existsSync(sdkPath)) {
129
145
  fs.unlinkSync(sdkPath);
130
146
  sdkDeleted = true;
131
147
  }
132
148
 
149
+ // 2. Si un backup existe, essayer de le restaurer
133
150
  if (fs.existsSync(backupPath)) {
134
- fs.copyFileSync(backupPath, mainPath);
135
- fs.unlinkSync(backupPath);
136
- mainRestored = true;
137
- } else if (fs.existsSync(mainPath)) {
138
- // Nettoyage manuel si pas de backup
139
- let content = fs.readFileSync(mainPath, 'utf-8');
140
- content = content.replace(/import\s+['"]samre_sdk\.dart['"];\s*\n?/g, '');
141
- content = content.replace(/builder\s*:\s*\([^)]*\)\s*=>\s*SamreOverlay\s*\(\s*child\s*:\s*child\s*\?\?\s*const\s*SizedBox\(\)\s*\),?\s*\n?/g, '');
142
- content = content.replace(/SamreOverlay\s*\(\s*child\s*:\s*([^)]+)\)/g, '$1');
143
- fs.writeFileSync(mainPath, content, 'utf-8');
151
+ try {
152
+ const backupContent = fs.readFileSync(backupPath, 'utf-8');
153
+ const cleanBackup = this.cleanMainDartContent(backupContent);
154
+ fs.writeFileSync(mainPath, cleanBackup, 'utf-8');
155
+ fs.unlinkSync(backupPath);
156
+ mainRestored = true;
157
+ } catch {
158
+ // Fallback nettoyage direct
159
+ }
160
+ }
161
+
162
+ // 3. Dans tous les cas, s'assurer que main.dart est 100% purgé de toute trace de Samré
163
+ if (fs.existsSync(mainPath)) {
164
+ const currentContent = fs.readFileSync(mainPath, 'utf-8');
165
+ const cleanContent = this.cleanMainDartContent(currentContent);
166
+ fs.writeFileSync(mainPath, cleanContent, 'utf-8');
144
167
  mainRestored = true;
145
168
  }
146
169