@norrix/cli 0.0.32 → 0.0.34

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,63 @@
1
+ # @norrix/cli
2
+
3
+ Cloud build, OTA updates, and app store submissions for NativeScript apps.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @norrix/cli
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ # Sign in to your account
15
+ norrix sign-in
16
+
17
+ # Build your app
18
+ norrix build android release
19
+ norrix build ios release appstore
20
+ norrix build visionos release appstore
21
+
22
+ # Publish OTA updates
23
+ norrix update android
24
+ norrix update ios
25
+ norrix update visionos
26
+
27
+ # Submit to app stores
28
+ norrix submit android production
29
+ norrix submit ios
30
+ norrix submit visionos
31
+ ```
32
+
33
+ ## Commands
34
+
35
+ | Command | Description |
36
+ |---------|-------------|
37
+ | `build` | Build your app in the cloud |
38
+ | `update` | Publish OTA updates |
39
+ | `submit` | Submit to App Store / Google Play |
40
+ | `fingerprint` | Print or compare native fingerprints |
41
+ | `env` | Manage build environment variables |
42
+ | `orgs` | Manage organizations |
43
+ | `sign-in` | Authenticate with Norrix |
44
+ | `sign-out` | Sign out |
45
+ | `whoami` | Show current user |
46
+
47
+ ## Global Options
48
+
49
+ ```
50
+ --env <env> Target environment (prod, dev)
51
+ --dev Shortcut for --env dev
52
+ --verbose Enable verbose output
53
+ --help Display help
54
+ --version Display version
55
+ ```
56
+
57
+ ## Documentation
58
+
59
+ Full CLI reference and guides: **[docs.norrix.net/cli](https://docs.norrix.net/cli/)**
60
+
61
+ ## License
62
+
63
+ MIT
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'url';
8
8
  import archiver from 'archiver';
9
9
  // import FormData from 'form-data';
10
10
  import { configureAmplify, loadCliEnvFiles } from './amplify-config.js';
11
- import { computeFingerprint, writeRuntimeFingerprintFile } from './fingerprinting.js';
11
+ import { computeFingerprint, embedFingerprintInNativeResources, embedVersionInNativeResources } from './fingerprinting.js';
12
12
  import { loadNorrixConfig, hasNorrixConfig, saveNorrixConfig } from './config.js';
13
13
  import { detectWorkspaceContext, getNxProjectDependencies, getWorkspaceDependenciesFallback, createWorkspaceManifest, logWorkspaceContext, isAtWorkspaceRoot, discoverNativeScriptApps, getWorkspaceContextForApp, detectNxBuildConfigurations, } from './workspace.js';
14
14
  import { signIn as amplifySignIn, signOut as amplifySignOut, getCurrentUser, fetchAuthSession, } from 'aws-amplify/auth';
@@ -205,14 +205,16 @@ async function ensureOrgSelected(params) {
205
205
  export async function orgsList(verbose = false) {
206
206
  ensureInitialized();
207
207
  try {
208
- const { organizations, selectedOrganizationId } = await fetchOrganizations(verbose);
208
+ const { organizations } = await fetchOrganizations(verbose);
209
209
  if (!organizations.length) {
210
210
  console.log('No organizations found.');
211
211
  return;
212
212
  }
213
+ // Use locally stored org selection (same source as orgsCurrent)
214
+ const localSelectedOrgId = CURRENT_ORG_ID || getSelectedOrgId(CURRENT_ENV, API_URL);
213
215
  console.log('Organizations:');
214
216
  for (const o of organizations) {
215
- const selectedMark = selectedOrganizationId && o.id === selectedOrganizationId ? ' (selected)' : '';
217
+ const selectedMark = localSelectedOrgId && o.id === localSelectedOrgId ? ' (selected)' : '';
216
218
  console.log(`- ${o.name} [${o.role}] ${o.id}${selectedMark}`);
217
219
  }
218
220
  }
@@ -1424,9 +1426,9 @@ export async function build(cliPlatformArg, cliConfigurationArg, cliDistribution
1424
1426
  ]);
1425
1427
  platform = chosenPlatform;
1426
1428
  }
1427
- // 2.1 Determine configuration (CLI arg preferred, otherwise prompt)
1429
+ // 2.1 Determine configuration (CLI arg preferred, then config, otherwise prompt)
1428
1430
  const validConfigurations = ['debug', 'release'];
1429
- let configuration = (cliConfigurationArg || '').toLowerCase();
1431
+ let configuration = (cliConfigurationArg || norrixConfig.defaultConfiguration || '').toLowerCase();
1430
1432
  if (!validConfigurations.includes(configuration)) {
1431
1433
  if (opts.nonInteractive) {
1432
1434
  // Default to 'debug' in non-interactive mode if not specified
@@ -1440,7 +1442,7 @@ export async function build(cliPlatformArg, cliConfigurationArg, cliDistribution
1440
1442
  name: 'configuration',
1441
1443
  message: 'Build configuration:',
1442
1444
  choices: validConfigurations,
1443
- default: 'debug',
1445
+ default: norrixConfig.defaultConfiguration || 'debug',
1444
1446
  },
1445
1447
  ]);
1446
1448
  configuration = answer.configuration;
@@ -1908,7 +1910,33 @@ export async function build(cliPlatformArg, cliConfigurationArg, cliDistribution
1908
1910
  projectRoot,
1909
1911
  platform,
1910
1912
  });
1911
- writeRuntimeFingerprintFile(projectRoot, fingerprint, platform);
1913
+ // Embed fingerprint in native resources (Info.plist for iOS, app.gradle for Android)
1914
+ // This ensures the fingerprint is baked into the binary and cannot diverge from
1915
+ // what's recorded in the database. The fingerprint in native resources is the
1916
+ // single source of truth that the client SDK will read at runtime.
1917
+ const embeddedPaths = embedFingerprintInNativeResources(projectRoot, fingerprint, platform);
1918
+ if (verbose) {
1919
+ if (embeddedPaths.infoPlistPath) {
1920
+ console.log(`[fingerprint] Embedded hash in Info.plist: ${embeddedPaths.infoPlistPath}`);
1921
+ }
1922
+ if (embeddedPaths.appGradlePath) {
1923
+ console.log(`[fingerprint] Embedded hash in app.gradle: ${embeddedPaths.appGradlePath}`);
1924
+ }
1925
+ }
1926
+ // Embed version and build number in native resources
1927
+ // This ensures the binary (IPA/APK/AAB) reflects the version specified at build time.
1928
+ // The fingerprint remains stable because version fields are normalized out during hashing.
1929
+ if (version && buildNumber) {
1930
+ const versionEmbedPaths = embedVersionInNativeResources(projectRoot, version, buildNumber, platform);
1931
+ if (verbose) {
1932
+ if (versionEmbedPaths.infoPlistPath) {
1933
+ console.log(`[version] Embedded v${version} (${buildNumber}) in Info.plist: ${versionEmbedPaths.infoPlistPath}`);
1934
+ }
1935
+ if (versionEmbedPaths.appGradlePath) {
1936
+ console.log(`[version] Embedded v${version} (${buildNumber}) in app.gradle: ${versionEmbedPaths.appGradlePath}`);
1937
+ }
1938
+ }
1939
+ }
1912
1940
  spinner.start('Creating project archive...');
1913
1941
  // 3. Zip the project (workspace-aware)
1914
1942
  const { zipPath, workspaceContext } = await zipProject(projectName, workspaceCtx, false, verbose);