@microsoft/power-apps-native-host 0.2.22 → 0.3.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/README.md +162 -26
- package/compatibility/current.json +87 -0
- package/lib/NOTICE.txt +140 -1226
- package/lib/commonjs/auth/AuthContext.js +74 -18
- package/lib/commonjs/auth/AuthContext.web.js +32 -0
- package/lib/commonjs/auth/completePowerAppsAuthSession.js +16 -0
- package/lib/commonjs/bridge/NativePowerAppsBridge.js +20 -17
- package/lib/commonjs/bridge/PowerPagesBridge.js +157 -0
- package/lib/commonjs/bridge/bridgeState.js +40 -0
- package/lib/commonjs/connections/ConnectionSetupScreen.js +459 -80
- package/lib/commonjs/connections/PowerPlatformConnectionApi.js +946 -0
- package/lib/commonjs/connections/connectionMetadata.js +127 -0
- package/lib/commonjs/connections/connectionState.js +96 -0
- package/lib/commonjs/connections/disambiguate.js +19 -11
- package/lib/commonjs/connections/resolveConnections.js +347 -0
- package/lib/commonjs/connections/types.js +106 -0
- package/lib/commonjs/{platform → connections}/useConnectionRefs.js +128 -65
- package/lib/commonjs/connections/useConnectionSetup.js +111 -52
- package/lib/commonjs/controls/FilePicker.js +6 -0
- package/lib/commonjs/controls/ImagePicker.js +8 -0
- package/lib/commonjs/index.js +188 -6
- package/lib/commonjs/logger.js +9 -6
- package/lib/commonjs/offline/createOfflineHostActivationCallbacks.js +61 -0
- package/lib/commonjs/offline/useOfflineIntegration.js +12 -0
- package/lib/commonjs/offline/useOfflineIntegration.web.js +11 -0
- package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.js +46 -0
- package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.web.js +13 -0
- package/lib/commonjs/platform/DataverseDataSources.js +14 -0
- package/lib/commonjs/platform/DataverseGlobalDiscoveryApi.js +49 -0
- package/lib/commonjs/platform/GlobalDiscovery.js +51 -0
- package/lib/commonjs/platform/PowerPlatformEnvironmentApi.js +6 -106
- package/lib/commonjs/provider/PowerAppsHostProvider.js +156 -25
- package/lib/commonjs/provider/PowerAppsHostProvider.web.js +41 -0
- package/lib/commonjs/provider/PowerAppsProvider.js +229 -133
- package/lib/commonjs/provider/SessionDetailsGesture.js +216 -0
- package/lib/commonjs/telemetry/OfflineSdkTelemetry.js +95 -0
- package/lib/commonjs/telemetry/OfflineSdkTelemetry.web.js +9 -0
- package/lib/commonjs/telemetry/index.js +22 -3
- package/lib/module/auth/AuthContext.js +74 -18
- package/lib/module/auth/AuthContext.web.js +26 -0
- package/lib/module/auth/completePowerAppsAuthSession.js +11 -0
- package/lib/module/bridge/NativePowerAppsBridge.js +21 -18
- package/lib/module/bridge/PowerPagesBridge.js +151 -0
- package/lib/module/bridge/bridgeState.js +34 -0
- package/lib/module/connections/ConnectionSetupScreen.js +460 -81
- package/lib/module/connections/PowerPlatformConnectionApi.js +932 -0
- package/lib/module/connections/connectionMetadata.js +112 -0
- package/lib/module/connections/connectionState.js +82 -0
- package/lib/module/connections/disambiguate.js +19 -12
- package/lib/module/connections/resolveConnections.js +342 -0
- package/lib/module/connections/types.js +91 -0
- package/lib/module/{platform → connections}/useConnectionRefs.js +129 -66
- package/lib/module/connections/useConnectionSetup.js +113 -54
- package/lib/module/controls/FilePicker.js +6 -0
- package/lib/module/controls/ImagePicker.js +8 -0
- package/lib/module/index.js +14 -6
- package/lib/module/logger.js +8 -6
- package/lib/module/offline/createOfflineHostActivationCallbacks.js +55 -0
- package/lib/module/offline/useOfflineIntegration.js +3 -0
- package/lib/module/offline/useOfflineIntegration.web.js +7 -0
- package/lib/module/offline/useOfflineIntegrationWithStartupGate.js +42 -0
- package/lib/module/offline/useOfflineIntegrationWithStartupGate.web.js +9 -0
- package/lib/module/platform/DataverseDataSources.js +10 -0
- package/lib/module/platform/DataverseGlobalDiscoveryApi.js +45 -0
- package/lib/module/platform/GlobalDiscovery.js +45 -0
- package/lib/module/platform/PowerPlatformEnvironmentApi.js +5 -104
- package/lib/module/provider/PowerAppsHostProvider.js +159 -28
- package/lib/module/provider/PowerAppsHostProvider.web.js +36 -0
- package/lib/module/provider/PowerAppsProvider.js +233 -137
- package/lib/module/provider/SessionDetailsGesture.js +211 -0
- package/lib/module/telemetry/OfflineSdkTelemetry.js +91 -0
- package/lib/module/telemetry/OfflineSdkTelemetry.web.js +5 -0
- package/lib/module/telemetry/index.js +15 -4
- package/lib/typescript/commonjs/auth/AuthContext.d.ts +3 -1
- package/lib/typescript/commonjs/auth/AuthContext.web.d.ts +21 -0
- package/lib/typescript/commonjs/auth/completePowerAppsAuthSession.d.ts +8 -0
- package/lib/typescript/commonjs/bridge/PowerPagesBridge.d.ts +18 -0
- package/lib/typescript/commonjs/bridge/bridgeState.d.ts +5 -0
- package/lib/typescript/commonjs/connections/ConnectionSetupScreen.d.ts +28 -7
- package/lib/typescript/commonjs/{platform → connections}/PowerPlatformConnectionApi.d.ts +52 -43
- package/lib/typescript/commonjs/connections/connectionMetadata.d.ts +66 -0
- package/lib/typescript/commonjs/connections/connectionState.d.ts +16 -0
- package/lib/typescript/commonjs/connections/disambiguate.d.ts +4 -2
- package/lib/typescript/commonjs/{platform → connections}/resolveConnections.d.ts +19 -19
- package/lib/typescript/commonjs/connections/types.d.ts +129 -1
- package/lib/typescript/commonjs/{platform → connections}/useConnectionRefs.d.ts +33 -24
- package/lib/typescript/commonjs/connections/useConnectionSetup.d.ts +12 -8
- package/lib/typescript/commonjs/controls/FilePicker.d.ts +7 -1
- package/lib/typescript/commonjs/controls/ImagePicker.d.ts +9 -1
- package/lib/typescript/commonjs/index.d.ts +20 -10
- package/lib/typescript/commonjs/logger.d.ts +4 -4
- package/lib/typescript/commonjs/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
- package/lib/typescript/commonjs/offline/useOfflineIntegration.d.ts +2 -0
- package/lib/typescript/commonjs/offline/useOfflineIntegration.web.d.ts +4 -0
- package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.d.ts +15 -0
- package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
- package/lib/typescript/commonjs/platform/DataverseDataSources.d.ts +27 -0
- package/lib/typescript/commonjs/platform/DataverseGlobalDiscoveryApi.d.ts +3 -0
- package/lib/typescript/commonjs/platform/GlobalDiscovery.d.ts +4 -0
- package/lib/typescript/commonjs/platform/PowerPlatformEnvironmentApi.d.ts +3 -74
- package/lib/typescript/commonjs/provider/PowerAppsHostProvider.d.ts +29 -18
- package/lib/typescript/commonjs/provider/PowerAppsHostProvider.web.d.ts +5 -0
- package/lib/typescript/commonjs/provider/PowerAppsProvider.d.ts +32 -10
- package/lib/typescript/commonjs/provider/SessionDetailsGesture.d.ts +13 -0
- package/lib/typescript/commonjs/telemetry/OfflineSdkTelemetry.d.ts +15 -0
- package/lib/typescript/commonjs/telemetry/OfflineSdkTelemetry.web.d.ts +2 -0
- package/lib/typescript/commonjs/telemetry/index.d.ts +13 -1
- package/lib/typescript/module/auth/AuthContext.d.ts +3 -1
- package/lib/typescript/module/auth/AuthContext.web.d.ts +21 -0
- package/lib/typescript/module/auth/completePowerAppsAuthSession.d.ts +8 -0
- package/lib/typescript/module/bridge/PowerPagesBridge.d.ts +18 -0
- package/lib/typescript/module/bridge/bridgeState.d.ts +5 -0
- package/lib/typescript/module/connections/ConnectionSetupScreen.d.ts +28 -7
- package/lib/typescript/module/{platform → connections}/PowerPlatformConnectionApi.d.ts +52 -43
- package/lib/typescript/module/connections/connectionMetadata.d.ts +66 -0
- package/lib/typescript/module/connections/connectionState.d.ts +16 -0
- package/lib/typescript/module/connections/disambiguate.d.ts +4 -2
- package/lib/typescript/module/{platform → connections}/resolveConnections.d.ts +19 -19
- package/lib/typescript/module/connections/types.d.ts +129 -1
- package/lib/typescript/module/{platform → connections}/useConnectionRefs.d.ts +33 -24
- package/lib/typescript/module/connections/useConnectionSetup.d.ts +12 -8
- package/lib/typescript/module/controls/FilePicker.d.ts +7 -1
- package/lib/typescript/module/controls/ImagePicker.d.ts +9 -1
- package/lib/typescript/module/index.d.ts +24 -14
- package/lib/typescript/module/logger.d.ts +4 -4
- package/lib/typescript/module/offline/createOfflineHostActivationCallbacks.d.ts +12 -0
- package/lib/typescript/module/offline/useOfflineIntegration.d.ts +2 -0
- package/lib/typescript/module/offline/useOfflineIntegration.web.d.ts +4 -0
- package/lib/typescript/module/offline/useOfflineIntegrationWithStartupGate.d.ts +15 -0
- package/lib/typescript/module/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
- package/lib/typescript/module/platform/DataverseDataSources.d.ts +27 -0
- package/lib/typescript/module/platform/DataverseGlobalDiscoveryApi.d.ts +3 -0
- package/lib/typescript/module/platform/GlobalDiscovery.d.ts +4 -0
- package/lib/typescript/module/platform/PowerPlatformEnvironmentApi.d.ts +3 -74
- package/lib/typescript/module/provider/PowerAppsHostProvider.d.ts +29 -18
- package/lib/typescript/module/provider/PowerAppsHostProvider.web.d.ts +5 -0
- package/lib/typescript/module/provider/PowerAppsProvider.d.ts +34 -12
- package/lib/typescript/module/provider/SessionDetailsGesture.d.ts +13 -0
- package/lib/typescript/module/telemetry/OfflineSdkTelemetry.d.ts +15 -0
- package/lib/typescript/module/telemetry/OfflineSdkTelemetry.web.d.ts +2 -0
- package/lib/typescript/module/telemetry/index.d.ts +13 -1
- package/package.json +43 -18
- package/scripts/build-ios-base.js +66 -27
- package/scripts/bundle.js +212 -5
- package/scripts/generate-connector-schemas.js +8 -6
- package/scripts/metro-logger.js +213 -0
- package/scripts/start-web.mjs +137 -0
- package/scripts/upgrade/runtime.js +463 -0
- package/scripts/upgrade/system.js +244 -0
- package/scripts/upgrade-authoring.js +534 -0
- package/scripts/upgrade.js +188 -0
- package/scripts/wrap.js +536 -0
- package/lib/commonjs/platform/PowerPlatformConnectionApi.js +0 -606
- package/lib/commonjs/platform/resolveConnections.js +0 -264
- package/lib/module/platform/PowerPlatformConnectionApi.js +0 -595
- package/lib/module/platform/resolveConnections.js +0 -259
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const childProcess = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { isLocked, setLockProvider, withLock } = require('@ster5/global-mutex');
|
|
7
|
+
const { parsePatch } = require('diff');
|
|
8
|
+
const { resolveWorkspaceRoot } = require('resolve-workspace-root');
|
|
9
|
+
const writeFileAtomic = require('write-file-atomic');
|
|
10
|
+
const { assertSafeFilePath, readJson } = require('./runtime');
|
|
11
|
+
|
|
12
|
+
const UPGRADE_LOCK_PATH = '.powerapps-native/upgrade';
|
|
13
|
+
const UPGRADE_JOURNAL_PATH = '.powerapps-native/upgrade-journal.json';
|
|
14
|
+
setLockProvider('native');
|
|
15
|
+
|
|
16
|
+
function detectPackageManager(projectRoot) {
|
|
17
|
+
const workspaceRoot = resolveWorkspaceRoot(projectRoot) || projectRoot;
|
|
18
|
+
for (const current of workspaceRoot === projectRoot ? [projectRoot] : [workspaceRoot, projectRoot]) {
|
|
19
|
+
const locks = [
|
|
20
|
+
['npm', 'package-lock.json'], ['npm', 'npm-shrinkwrap.json'], ['yarn', 'yarn.lock'],
|
|
21
|
+
['pnpm', 'pnpm-lock.yaml'], ['bun', 'bun.lock'], ['bun', 'bun.lockb'],
|
|
22
|
+
].filter(([, lock]) => fs.existsSync(path.join(current, lock)));
|
|
23
|
+
const managers = [...new Set(locks.map(([manager]) => manager))];
|
|
24
|
+
if (managers.length > 1) throw new Error(`Multiple package-manager lockfiles found in ${current}: ${locks.map(([, lock]) => lock).join(', ')}`);
|
|
25
|
+
const packagePath = path.join(current, 'package.json');
|
|
26
|
+
const declaredManager = fs.existsSync(packagePath)
|
|
27
|
+
? String(readJson(packagePath).packageManager || '').split('@')[0]
|
|
28
|
+
: '';
|
|
29
|
+
if (managers.length === 1) {
|
|
30
|
+
if (declaredManager && ['npm', 'pnpm', 'bun', 'yarn'].includes(declaredManager) && declaredManager !== managers[0]) {
|
|
31
|
+
throw new Error(`packageManager declares ${declaredManager}, but ${locks[0][1]} selects ${managers[0]} in ${current}`);
|
|
32
|
+
}
|
|
33
|
+
return supportedManager(managers[0], current);
|
|
34
|
+
}
|
|
35
|
+
if (['npm', 'pnpm', 'bun', 'yarn'].includes(declaredManager)) return supportedManager(declaredManager, current);
|
|
36
|
+
}
|
|
37
|
+
return { name: 'npm', root: projectRoot };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function supportedManager(name, root) {
|
|
41
|
+
if (name === 'yarn') throw new Error('Yarn is not currently supported; use npm, pnpm, or Bun');
|
|
42
|
+
return { name, root };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function run(command, args, cwd, capture = false) {
|
|
46
|
+
const result = childProcess.spawnSync(command, args, { cwd, encoding: 'utf8', stdio: capture ? 'pipe' : 'inherit' });
|
|
47
|
+
if (result.error) throw result.error;
|
|
48
|
+
if (result.status !== 0) {
|
|
49
|
+
if (capture && result.stderr) process.stderr.write(result.stderr);
|
|
50
|
+
throw new Error(`${command} ${args.join(' ')} failed with exit code ${result.status}`);
|
|
51
|
+
}
|
|
52
|
+
return result.stdout;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function expoInstallArgs(packageManager) {
|
|
56
|
+
return ['install', '--fix', ...(packageManager === 'bun' ? [] : [`--${packageManager}`])];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function packageInstallArgs(packageManager) {
|
|
60
|
+
return ['install', ...(packageManager === 'npm' ? ['--force'] : [])];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function installAndValidate(projectRoot, packageManager, expoDoctorVersion) {
|
|
64
|
+
const manager = typeof packageManager === 'string' ? { name: packageManager, root: projectRoot } : packageManager;
|
|
65
|
+
run(manager.name, packageInstallArgs(manager.name), manager.root);
|
|
66
|
+
const binName = process.platform === 'win32' ? 'expo.cmd' : 'expo';
|
|
67
|
+
const localBin = path.join(projectRoot, 'node_modules', '.bin', binName);
|
|
68
|
+
const rootBin = path.join(manager.root, 'node_modules', '.bin', binName);
|
|
69
|
+
const expoBin = fs.existsSync(localBin) ? localBin : rootBin;
|
|
70
|
+
if (!fs.existsSync(expoBin)) throw new Error('Expo CLI was not installed after package installation');
|
|
71
|
+
run(expoBin, expoInstallArgs(manager.name), projectRoot);
|
|
72
|
+
run(expoBin, ['install', '--check'], projectRoot);
|
|
73
|
+
run(expoBin, ['config', '--type', 'prebuild', '--json'], projectRoot, true);
|
|
74
|
+
if (!expoDoctorVersion) throw new Error('Compatibility profile is missing expoDoctorVersion');
|
|
75
|
+
const commands = { npm: ['npx', ['--yes']], pnpm: ['pnpm', ['dlx']], bun: ['bunx', []] };
|
|
76
|
+
const [command, args] = commands[manager.name];
|
|
77
|
+
run(command, [...args, `expo-doctor@${expoDoctorVersion}`], projectRoot);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function writeAtomic(filePath, content, mode) {
|
|
81
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
82
|
+
const targetMode = mode ? (typeof mode === 'number' ? mode : Number.parseInt(String(mode).slice(-3), 8)) : undefined;
|
|
83
|
+
writeFileAtomic.sync(filePath, content, { mode: targetMode });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function snapshotFiles(filePaths) {
|
|
87
|
+
return new Map([...new Set(filePaths)].map(filePath => {
|
|
88
|
+
if (!fs.existsSync(filePath)) return [filePath, null];
|
|
89
|
+
const stat = fs.lstatSync(filePath);
|
|
90
|
+
if (stat.isSymbolicLink()) throw new Error(`Cannot snapshot symbolic link: ${filePath}`);
|
|
91
|
+
return [filePath, { content: fs.readFileSync(filePath), mode: stat.mode & 0o777 }];
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function restoreFiles(snapshot) {
|
|
96
|
+
for (const [filePath, entry] of snapshot) {
|
|
97
|
+
if (entry === null) fs.rmSync(filePath, { force: true });
|
|
98
|
+
else {
|
|
99
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
100
|
+
fs.writeFileSync(filePath, entry.content);
|
|
101
|
+
fs.chmodSync(filePath, entry.mode);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function withUpgradeLock(projectRoot, action) {
|
|
107
|
+
ensureControlDirectory(projectRoot);
|
|
108
|
+
const fileToLock = path.join(projectRoot, UPGRADE_LOCK_PATH);
|
|
109
|
+
try {
|
|
110
|
+
return await withLock({ fileToLock, stale: 30000, retries: 0 }, action);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (/already being held/i.test(error.message)) throw new Error('Another upgrade is running');
|
|
113
|
+
throw error;
|
|
114
|
+
} finally {
|
|
115
|
+
if (!await isLocked(fileToLock)) fs.rmSync(fileToLock, { force: true });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function assertNoActiveUpgrade(projectRoot) {
|
|
120
|
+
if (await isLocked(path.join(projectRoot, UPGRADE_LOCK_PATH))) throw new Error('Another upgrade is running');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function ensureControlDirectory(projectRoot) {
|
|
124
|
+
const directory = path.join(projectRoot, '.powerapps-native');
|
|
125
|
+
assertSafeFilePath(projectRoot, directory);
|
|
126
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
127
|
+
if (fs.lstatSync(directory).isSymbolicLink()) throw new Error('.powerapps-native cannot be a symbolic link');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function writeJournal(projectRoot, snapshot) {
|
|
131
|
+
const files = [...snapshot].map(([filePath, entry]) => ({
|
|
132
|
+
path: filePath,
|
|
133
|
+
existed: entry !== null,
|
|
134
|
+
mode: entry?.mode,
|
|
135
|
+
content: entry?.content.toString('base64'),
|
|
136
|
+
}));
|
|
137
|
+
writeAtomic(path.join(projectRoot, UPGRADE_JOURNAL_PATH), `${JSON.stringify({ schemaVersion: 1, files }, null, 2)}\n`, 0o600);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function recoverInterruptedUpgrade(projectRoot) {
|
|
141
|
+
const journalPath = path.join(projectRoot, UPGRADE_JOURNAL_PATH);
|
|
142
|
+
if (!fs.existsSync(journalPath)) return false;
|
|
143
|
+
const journal = readJson(journalPath);
|
|
144
|
+
if (journal.schemaVersion !== 1 || !Array.isArray(journal.files)) throw new Error('Upgrade journal is invalid; restore it manually');
|
|
145
|
+
const manager = detectPackageManager(projectRoot);
|
|
146
|
+
const allowedLockfiles = new Set(lockfilePaths(manager.root).map(filePath => path.resolve(filePath)));
|
|
147
|
+
const seen = new Set();
|
|
148
|
+
const snapshot = new Map(journal.files.map(file => validateJournalEntry(file, projectRoot, manager.root, allowedLockfiles, seen)));
|
|
149
|
+
restoreFiles(snapshot);
|
|
150
|
+
fs.rmSync(journalPath, { force: true });
|
|
151
|
+
console.warn('[upgrade-template] Recovered files from an interrupted upgrade phase.');
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function validateJournalEntry(file, projectRoot, managerRoot, allowedLockfiles, seen) {
|
|
156
|
+
if (!file || typeof file.path !== 'string' || typeof file.existed !== 'boolean') throw new Error('Upgrade journal contains an invalid file entry');
|
|
157
|
+
const filePath = path.resolve(file.path);
|
|
158
|
+
const root = path.resolve(projectRoot);
|
|
159
|
+
if (!(filePath === root || filePath.startsWith(`${root}${path.sep}`) || allowedLockfiles.has(filePath))) throw new Error(`Upgrade journal contains unsafe path: ${file.path}`);
|
|
160
|
+
assertSafeFilePath(allowedLockfiles.has(filePath) ? managerRoot : projectRoot, filePath);
|
|
161
|
+
if (fs.existsSync(filePath) && fs.lstatSync(filePath).isSymbolicLink()) throw new Error(`Upgrade journal targets symbolic link: ${file.path}`);
|
|
162
|
+
if (seen.has(filePath)) throw new Error(`Upgrade journal contains duplicate path: ${file.path}`);
|
|
163
|
+
seen.add(filePath);
|
|
164
|
+
if (!file.existed) return [filePath, null];
|
|
165
|
+
if (!Number.isInteger(file.mode) || file.mode < 0 || file.mode > 0o777 || !isCanonicalBase64(file.content)) throw new Error(`Upgrade journal contains invalid backup data for ${file.path}`);
|
|
166
|
+
return [filePath, { content: Buffer.from(file.content, 'base64'), mode: file.mode }];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function isCanonicalBase64(value) {
|
|
170
|
+
return typeof value === 'string' && value.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(value) && Buffer.from(value, 'base64').toString('base64') === value;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function lockfilePaths(root) {
|
|
174
|
+
return ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lock', 'bun.lockb'].map(name => path.join(root, name));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function configFilePaths(root) {
|
|
178
|
+
return ['app.json', 'app.config.json', 'app.config.js', 'app.config.ts', 'babel.config.js', 'metro.config.js', 'tsconfig.json'].map(name => path.join(root, name));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function applyOperations(projectRoot, operations) {
|
|
182
|
+
for (const operation of operations) {
|
|
183
|
+
assertSafeFilePath(projectRoot, operation.filePath);
|
|
184
|
+
if (operation.delete) fs.rmSync(operation.filePath, { force: true });
|
|
185
|
+
else writeAtomic(operation.filePath, operation.content, operation.mode);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function executePhase(projectRoot, operations, packageManager, install, validate = installAndValidate, expoDoctorVersion) {
|
|
190
|
+
const manager = typeof packageManager === 'string' ? { name: packageManager, root: projectRoot } : packageManager;
|
|
191
|
+
const stateOperations = operations.filter(operation => operation.state);
|
|
192
|
+
const projectOperations = operations.filter(operation => !operation.state);
|
|
193
|
+
const snapshot = snapshotFiles([
|
|
194
|
+
...operations.map(operation => operation.filePath), path.join(projectRoot, 'package.json'),
|
|
195
|
+
...lockfilePaths(manager.root), ...configFilePaths(projectRoot),
|
|
196
|
+
]);
|
|
197
|
+
writeJournal(projectRoot, snapshot);
|
|
198
|
+
try {
|
|
199
|
+
applyOperations(projectRoot, projectOperations);
|
|
200
|
+
if (install) validate(projectRoot, manager, expoDoctorVersion);
|
|
201
|
+
applyOperations(projectRoot, stateOperations);
|
|
202
|
+
fs.rmSync(path.join(projectRoot, UPGRADE_JOURNAL_PATH), { force: true });
|
|
203
|
+
} catch (error) {
|
|
204
|
+
restoreFiles(snapshot);
|
|
205
|
+
fs.rmSync(path.join(projectRoot, UPGRADE_JOURNAL_PATH), { force: true });
|
|
206
|
+
throw new Error(`${error.message}. This migration phase was rolled back; node_modules may require reinstalling.`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function writeRejects(operations) {
|
|
211
|
+
for (const operation of operations.filter(operation => operation.reject)) writeAtomic(operation.filePath, operation.content, operation.mode);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function cleanupRejects(projectRoot, migration) {
|
|
215
|
+
if (!migration) return;
|
|
216
|
+
for (const patch of migration.patch.trim() ? parsePatch(migration.patch) : []) {
|
|
217
|
+
const relativePath = patch.newFileName === '/dev/null' ? patch.oldFileName : patch.newFileName;
|
|
218
|
+
if (relativePath && relativePath !== '/dev/null') fs.rmSync(`${path.resolve(projectRoot, relativePath)}.power-apps-${migration.id}.rej`, { force: true });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function reportNativeProjectState(projectRoot) {
|
|
223
|
+
const nativeDirectories = ['android', 'ios'].filter(name => fs.existsSync(path.join(projectRoot, name)));
|
|
224
|
+
if (nativeDirectories.length) console.warn(`[upgrade-template] Native directories detected (${nativeDirectories.join(', ')}). They are not modified automatically. Regenerate them with Expo Prebuild only if they are CNG-managed; otherwise apply native upgrade changes manually.`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function shouldValidate(migration, operations) {
|
|
228
|
+
return Boolean(migration) || operations.some(operation => !operation.state);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports = {
|
|
232
|
+
UPGRADE_JOURNAL_PATH,
|
|
233
|
+
assertNoActiveUpgrade,
|
|
234
|
+
cleanupRejects,
|
|
235
|
+
detectPackageManager,
|
|
236
|
+
executePhase,
|
|
237
|
+
expoInstallArgs,
|
|
238
|
+
packageInstallArgs,
|
|
239
|
+
recoverInterruptedUpgrade,
|
|
240
|
+
reportNativeProjectState,
|
|
241
|
+
shouldValidate,
|
|
242
|
+
withUpgradeLock,
|
|
243
|
+
writeRejects,
|
|
244
|
+
};
|