@codeimplants/version-control 1.0.0 → 1.0.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 ADDED
@@ -0,0 +1,344 @@
1
+ # Version Control SDK
2
+
3
+ A lightweight, backend-driven SDK that enables remote control of app version behavior including soft updates, force updates, and maintenance mode for mobile and web applications.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Soft Updates** - Notify users about new versions with optional updates
8
+ - ⚡ **Force Updates** - Enforce minimum version requirements
9
+ - 🔧 **Maintenance Mode** - Put your app in maintenance mode remotely
10
+ - 🛑 **Kill Switch** - Emergency app disable capability
11
+ - ðŸ“ą **Cross-Platform** - Works on iOS, Android, and Web
12
+ - ðŸŽŊ **Auto-Detection** - Automatically detects platform, version, and app ID
13
+ - 🔌 **Backend-Driven** - All decisions made server-side for instant updates
14
+ - ðŸŠķ **Lightweight** - Minimal dependencies and footprint
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @codeimplants/version-control
20
+ ```
21
+
22
+ Or with yarn:
23
+
24
+ ```bash
25
+ yarn add @codeimplants/version-control
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ### Simple Usage
31
+
32
+ ```typescript
33
+ import { VersionSDK } from "@codeimplants/version-control";
34
+
35
+ // Quick check with minimal config
36
+ const decision = await VersionSDK.check(
37
+ "https://api.yourapp.com",
38
+ "your-api-key",
39
+ );
40
+
41
+ // Handle the decision
42
+ switch (decision.action) {
43
+ case "FORCE_UPDATE":
44
+ // Show force update dialog
45
+ window.location.href = decision.storeUrl;
46
+ break;
47
+ case "SOFT_UPDATE":
48
+ // Show optional update dialog
49
+ showUpdatePrompt(decision.message, decision.storeUrl);
50
+ break;
51
+ case "MAINTENANCE":
52
+ // Show maintenance screen
53
+ showMaintenanceScreen(decision.message);
54
+ break;
55
+ case "KILL_SWITCH":
56
+ // App is disabled
57
+ showKillSwitchScreen(decision.message);
58
+ break;
59
+ case "NONE":
60
+ // Continue normally
61
+ break;
62
+ }
63
+ ```
64
+
65
+ ### Advanced Usage
66
+
67
+ ```typescript
68
+ import { VersionSDK, VCConfig } from "@codeimplants/version-control";
69
+
70
+ const config: VCConfig = {
71
+ backendUrl: "https://api.yourapp.com",
72
+ apiKey: "your-api-key",
73
+ appId: "com.yourapp.mobile", // Optional: auto-detected
74
+ platform: "ios", // Optional: auto-detected
75
+ version: "2.1.0", // Optional: auto-detected
76
+ timeout: 8000, // Optional: default 8000ms
77
+ debug: true, // Optional: enable logging
78
+ };
79
+
80
+ const sdk = VersionSDK.init(config);
81
+ const decision = await sdk.checkVersion();
82
+ ```
83
+
84
+ ## Auto-Detection
85
+
86
+ The SDK automatically detects the following if not provided:
87
+
88
+ ### Platform Detection
89
+
90
+ - **Capacitor**: Detects iOS/Android via Capacitor.getPlatform()
91
+ - **React Native**: Detects via navigator.product
92
+ - **User Agent**: Falls back to UA string parsing
93
+ - **Web**: Default fallback
94
+
95
+ ### Version Detection
96
+
97
+ Checks in order:
98
+
99
+ 1. Capacitor App plugin (`Capacitor.Plugins.App.getInfo()`)
100
+ 2. Global variables: `APP_VERSION`, `__VERSION__`, `VERSION`, `packageVersion`
101
+ 3. Fallback: `"1.0.0"`
102
+
103
+ ### App ID Detection
104
+
105
+ Checks in order:
106
+
107
+ 1. Capacitor App plugin bundle ID
108
+ 2. Global variables: `APP_ID`, `__APP_ID__`, `BUNDLE_ID`, `PACKAGE_NAME`
109
+ 3. Fallback: `"unknown.app"`
110
+
111
+ ## Configuration
112
+
113
+ ### VCConfig
114
+
115
+ ```typescript
116
+ interface VCConfig {
117
+ backendUrl: string; // Your backend API URL (required)
118
+ apiKey?: string; // API key for authentication
119
+ appId?: string; // App identifier (auto-detected if not provided)
120
+ platform?: Platform; // 'android' | 'ios' | 'web' | 'all'
121
+ version?: string; // Current app version (auto-detected if not provided)
122
+ timeout?: number; // Request timeout in ms (default: 8000)
123
+ debug?: boolean; // Enable debug logging
124
+ }
125
+ ```
126
+
127
+ ## Response Types
128
+
129
+ ### VCDecision
130
+
131
+ ```typescript
132
+ interface VCDecision {
133
+ action: VCAction; // The action to take
134
+ message?: string; // User-facing message
135
+ storeUrl?: string; // App store URL for updates
136
+ minVersion?: string; // Minimum required version (for FORCE_UPDATE)
137
+ latestVersion?: string; // Latest available version
138
+ raw?: any; // Raw backend response
139
+ }
140
+ ```
141
+
142
+ ### Actions
143
+
144
+ - **`NONE`** - No action required, app is up to date
145
+ - **`SOFT_UPDATE`** - Update available but optional
146
+ - **`FORCE_UPDATE`** - Update required to continue
147
+ - **`MAINTENANCE`** - App is in maintenance mode
148
+ - **`KILL_SWITCH`** - App is disabled
149
+ - **`BLOCKED`** - Access blocked for this version/platform
150
+
151
+ ## Backend Integration
152
+
153
+ The SDK expects your backend endpoint to accept POST requests at `/sdk/version/check`:
154
+
155
+ ### Request Format
156
+
157
+ ```typescript
158
+ {
159
+ "appId": "com.yourapp.mobile",
160
+ "platform": "ios",
161
+ "currentVersion": "2.0.0",
162
+ "environment": "prod"
163
+ }
164
+ ```
165
+
166
+ ### Response Format
167
+
168
+ ```typescript
169
+ {
170
+ "status": "FORCE_UPDATE", // VCAction
171
+ "message": "Please update to continue",
172
+ "title": "Update Required",
173
+ "minVersion": "2.1.0",
174
+ "latestVersion": "2.3.0",
175
+ "storeUrl": "https://apps.apple.com/..."
176
+ }
177
+ ```
178
+
179
+ ## Examples
180
+
181
+ ### React Example
182
+
183
+ ```typescript
184
+ import React, { useEffect, useState } from 'react';
185
+ import { VersionSDK, VCDecision } from '@codeimplants/version-control';
186
+
187
+ function App() {
188
+ const [versionCheck, setVersionCheck] = useState<VCDecision | null>(null);
189
+
190
+ useEffect(() => {
191
+ async function checkVersion() {
192
+ const decision = await VersionSDK.check(
193
+ 'https://api.yourapp.com',
194
+ 'your-api-key'
195
+ );
196
+ setVersionCheck(decision);
197
+ }
198
+ checkVersion();
199
+ }, []);
200
+
201
+ if (versionCheck?.action === 'FORCE_UPDATE') {
202
+ return (
203
+ <div className="update-required">
204
+ <h1>Update Required</h1>
205
+ <p>{versionCheck.message}</p>
206
+ <button onClick={() => window.location.href = versionCheck.storeUrl}>
207
+ Update Now
208
+ </button>
209
+ </div>
210
+ );
211
+ }
212
+
213
+ if (versionCheck?.action === 'MAINTENANCE') {
214
+ return (
215
+ <div className="maintenance">
216
+ <h1>Maintenance Mode</h1>
217
+ <p>{versionCheck.message}</p>
218
+ </div>
219
+ );
220
+ }
221
+
222
+ return <YourApp />;
223
+ }
224
+ ```
225
+
226
+ ### Capacitor/Ionic Example
227
+
228
+ ```typescript
229
+ import { VersionSDK } from "@codeimplants/version-control";
230
+ import { AlertController } from "@ionic/angular";
231
+
232
+ export class AppComponent {
233
+ constructor(private alertController: AlertController) {}
234
+
235
+ async ngOnInit() {
236
+ const decision = await VersionSDK.check(
237
+ "https://api.yourapp.com",
238
+ "your-api-key",
239
+ );
240
+
241
+ if (decision.action === "SOFT_UPDATE") {
242
+ const alert = await this.alertController.create({
243
+ header: "Update Available",
244
+ message: decision.message,
245
+ buttons: [
246
+ { text: "Later", role: "cancel" },
247
+ {
248
+ text: "Update",
249
+ handler: () => {
250
+ window.open(decision.storeUrl, "_system");
251
+ },
252
+ },
253
+ ],
254
+ });
255
+ await alert.present();
256
+ }
257
+ }
258
+ }
259
+ ```
260
+
261
+ ### React Native Example
262
+
263
+ ```typescript
264
+ import { VersionSDK } from "@codeimplants/version-control";
265
+ import { Alert, Linking } from "react-native";
266
+
267
+ async function checkAppVersion() {
268
+ const decision = await VersionSDK.check(
269
+ "https://api.yourapp.com",
270
+ "your-api-key",
271
+ );
272
+
273
+ if (decision.action === "FORCE_UPDATE") {
274
+ Alert.alert(
275
+ "Update Required",
276
+ decision.message,
277
+ [
278
+ {
279
+ text: "Update Now",
280
+ onPress: () => Linking.openURL(decision.storeUrl),
281
+ },
282
+ ],
283
+ { cancelable: false },
284
+ );
285
+ }
286
+ }
287
+ ```
288
+
289
+ ## Version Comparison
290
+
291
+ The SDK uses semantic versioning (semver) comparison:
292
+
293
+ ```typescript
294
+ // Examples of version comparisons
295
+ "1.0.0" < "1.0.1"; // true
296
+ "1.0.0" < "1.1.0"; // true
297
+ "2.0.0" > "1.9.9"; // true
298
+ "1.0" === "1.0.0"; // true (normalized)
299
+ ```
300
+
301
+ ## Error Handling
302
+
303
+ The SDK gracefully handles errors and returns `{ action: "NONE" }` if:
304
+
305
+ - Network request fails
306
+ - Backend is unreachable
307
+ - Request times out
308
+ - Invalid response format
309
+
310
+ Enable debug mode to see detailed error logs:
311
+
312
+ ```typescript
313
+ const config = {
314
+ backendUrl: "https://api.yourapp.com",
315
+ debug: true, // Logs all requests and responses
316
+ };
317
+ ```
318
+
319
+ ## Best Practices
320
+
321
+ 1. **Check on App Launch** - Always check version status when the app starts
322
+ 2. **Cache Decisions** - Cache the decision for a reasonable time (e.g., 1 hour)
323
+ 3. **Handle Offline** - Gracefully handle offline scenarios (SDK returns `NONE`)
324
+ 4. **User Experience** - Don't interrupt critical user flows with update prompts
325
+ 5. **Test Thoroughly** - Test all action types before deploying rules
326
+ 6. **Gradual Rollouts** - Use backend rules to gradually roll out forced updates
327
+
328
+ ## Platform Support
329
+
330
+ - ✅ iOS (Native & Web)
331
+ - ✅ Android (Native & Web)
332
+ - ✅ Web Browsers
333
+ - ✅ Capacitor
334
+ - ✅ React Native
335
+ - ✅ Ionic
336
+ - ✅ Cordova
337
+
338
+ ## TypeScript
339
+
340
+ The SDK is written in TypeScript and includes full type definitions.
341
+
342
+ ## License
343
+
344
+ MIT
package/package.json CHANGED
@@ -1,6 +1,27 @@
1
1
  {
2
2
  "name": "@codeimplants/version-control",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
+ "description": "A lightweight cross-platform SDK to remotely control app version behavior such as soft update, force update, and maintenance mode using backend-driven rules, without enforcing UI.",
5
+ "keywords": [
6
+ "version-control",
7
+ "app-version",
8
+ "mobile-versioning",
9
+ "force-update",
10
+ "soft-update",
11
+ "maintenance-mode",
12
+ "capacitor",
13
+ "ionic",
14
+ "react-native",
15
+ "react",
16
+ "angular",
17
+ "android",
18
+ "ios",
19
+ "mobile-sdk",
20
+ "update-management",
21
+ "feature-control",
22
+ "remote-config",
23
+ "sdk"
24
+ ],
4
25
  "main": "dist/index.js",
5
26
  "types": "dist/index.d.ts",
6
27
  "scripts": {
@@ -1 +0,0 @@
1
- {"hash":"27fad7e4fc35ffd5","duration":4627}
@@ -1 +0,0 @@
1
- {"hash":"3a784e60ef4fd5a6","duration":1325}
@@ -1 +0,0 @@
1
- {"hash":"5ff842ce2cdfa953","duration":1270}
@@ -1 +0,0 @@
1
- {"hash":"60a231c552bcee53","duration":2326}
@@ -1 +0,0 @@
1
- {"hash":"6c7d12bf8eda1401","duration":1164}
@@ -1 +0,0 @@
1
- {"hash":"b1169bf3a222dd96","duration":2680}
@@ -1 +0,0 @@
1
- {"hash":"bef44a5355c4c0bf","duration":2233}
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1 +0,0 @@
1
- 2026-01-29T08:29:08.349183Z WARN daemon_server: turborepo_lib::commands::daemon: daemon already running
@@ -1,2 +0,0 @@
1
- 2026-01-30T13:27:33.409085Z WARN daemon_server: turborepo_lib::commands::daemon: daemon already running
2
- 2026-01-30T19:18:48.539522Z WARN daemon_server: turborepo_lib::commands::daemon: daemon already running