@microsoft/power-apps-native-host 0.2.25 → 0.3.3
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 +21 -10
- package/compatibility/current.json +31 -4
- package/lib/NOTICE.txt +1325 -24
- package/lib/commonjs/auth/AuthContext.js +110 -33
- package/lib/commonjs/bridge/NativePowerAppsBridge.js +11 -18
- package/lib/commonjs/bridge/PowerPagesBridge.js +27 -8
- package/lib/commonjs/bridge/bridgeState.js +40 -0
- package/lib/commonjs/config/babelConfig.js +13 -0
- package/lib/commonjs/config/expoConfig.js +71 -0
- package/lib/commonjs/config/metroConfig.js +70 -0
- package/lib/commonjs/config/metroLogger.js +182 -0
- package/lib/commonjs/config/tamaguiConfig.js +98 -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 +348 -0
- package/lib/commonjs/connections/types.js +106 -0
- package/lib/commonjs/{platform → connections}/useConnectionRefs.js +130 -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 +167 -4
- package/lib/commonjs/logger.js +9 -6
- package/lib/commonjs/offline/createOfflineHostActivationCallbacks.js +61 -0
- package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.js +48 -0
- package/lib/commonjs/offline/useOfflineIntegrationWithStartupGate.web.js +13 -0
- package/lib/commonjs/platform/DataverseDataSources.js +18 -0
- package/lib/commonjs/platform/DataverseGlobalDiscoveryApi.js +94 -0
- package/lib/commonjs/platform/GlobalDiscovery.js +51 -0
- package/lib/commonjs/platform/PowerPlatformEnvironmentApi.js +6 -106
- package/lib/commonjs/provider/PowerAppsHostProvider.js +157 -25
- package/lib/commonjs/provider/PowerAppsProvider.js +178 -134
- package/lib/commonjs/provider/SessionDetailsGesture.js +208 -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 +110 -33
- package/lib/module/bridge/NativePowerAppsBridge.js +12 -19
- package/lib/module/bridge/PowerPagesBridge.js +27 -8
- package/lib/module/bridge/bridgeState.js +34 -0
- package/lib/module/config/babelConfig.js +9 -0
- package/lib/module/config/expoConfig.js +67 -0
- package/lib/module/config/metroConfig.js +65 -0
- package/lib/module/config/metroLogger.js +175 -0
- package/lib/module/config/tamaguiConfig.js +93 -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 +343 -0
- package/lib/module/connections/types.js +91 -0
- package/lib/module/{platform → connections}/useConnectionRefs.js +131 -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 -4
- package/lib/module/logger.js +8 -6
- package/lib/module/offline/createOfflineHostActivationCallbacks.js +55 -0
- package/lib/module/offline/useOfflineIntegrationWithStartupGate.js +44 -0
- package/lib/module/offline/useOfflineIntegrationWithStartupGate.web.js +9 -0
- package/lib/module/platform/DataverseDataSources.js +13 -0
- package/lib/module/platform/DataverseGlobalDiscoveryApi.js +89 -0
- package/lib/module/platform/GlobalDiscovery.js +45 -0
- package/lib/module/platform/PowerPlatformEnvironmentApi.js +5 -104
- package/lib/module/provider/PowerAppsHostProvider.js +160 -28
- package/lib/module/provider/PowerAppsProvider.js +182 -138
- package/lib/module/provider/SessionDetailsGesture.js +203 -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 +1 -0
- package/lib/typescript/commonjs/bridge/bridgeState.d.ts +5 -0
- package/lib/typescript/commonjs/config/babelConfig.d.ts +12 -0
- package/lib/typescript/commonjs/config/expoConfig.d.ts +21 -0
- package/lib/typescript/commonjs/config/metroConfig.d.ts +6 -0
- package/lib/typescript/commonjs/config/metroLogger.d.ts +21 -0
- package/lib/typescript/commonjs/config/tamaguiConfig.d.ts +1792 -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 +22 -20
- package/lib/typescript/commonjs/connections/types.d.ts +129 -1
- package/lib/typescript/commonjs/{platform → connections}/useConnectionRefs.d.ts +36 -25
- 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 +18 -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/useOfflineIntegrationWithStartupGate.d.ts +15 -0
- package/lib/typescript/commonjs/offline/useOfflineIntegrationWithStartupGate.web.d.ts +6 -0
- package/lib/typescript/commonjs/platform/DataverseDataSources.d.ts +28 -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/PowerAppsProvider.d.ts +54 -9
- 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 +1 -0
- package/lib/typescript/module/bridge/bridgeState.d.ts +5 -0
- package/lib/typescript/module/config/babelConfig.d.ts +12 -0
- package/lib/typescript/module/config/expoConfig.d.ts +21 -0
- package/lib/typescript/module/config/metroConfig.d.ts +6 -0
- package/lib/typescript/module/config/metroLogger.d.ts +21 -0
- package/lib/typescript/module/config/tamaguiConfig.d.ts +1792 -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 +22 -20
- package/lib/typescript/module/connections/types.d.ts +129 -1
- package/lib/typescript/module/{platform → connections}/useConnectionRefs.d.ts +36 -25
- 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 +18 -10
- package/lib/typescript/module/logger.d.ts +4 -4
- package/lib/typescript/module/offline/createOfflineHostActivationCallbacks.d.ts +12 -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 +28 -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/PowerAppsProvider.d.ts +54 -9
- 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 +52 -13
- package/scripts/build-codegen-package.js +283 -0
- package/scripts/start-web.mjs +9 -5
- package/scripts/upgrade/runtime.js +139 -24
- package/scripts/upgrade-authoring.js +274 -180
- package/scripts/upgrade.js +10 -16
- package/src/config/generated-config.d.ts +4 -0
- package/src/config/index.d.ts +3 -0
- package/src/config/tsconfig.json +26 -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
|
@@ -6,16 +6,30 @@ const path = require('path');
|
|
|
6
6
|
const { applyPatch, formatPatch, parsePatch, reversePatch } = require('diff');
|
|
7
7
|
|
|
8
8
|
const HOST_PACKAGE = '@microsoft/power-apps-native-host';
|
|
9
|
-
const TEMPLATE_VERSION_PATH = '.
|
|
9
|
+
const TEMPLATE_VERSION_PATH = 'app.json';
|
|
10
10
|
const TSCONFIG_PATH = 'tsconfig.json';
|
|
11
|
+
const GITIGNORE_PATH = '.gitignore';
|
|
12
|
+
const GITIGNORE_START = '# POWER APPS MANAGED START - DO NOT REMOVE OR RENAME THE COMMENT';
|
|
13
|
+
const GITIGNORE_END = '# POWER APPS MANAGED END - DO NOT REMOVE OR RENAME THE COMMENT';
|
|
11
14
|
const TEMPLATE_MANAGED_PATHS = [
|
|
15
|
+
GITIGNORE_PATH,
|
|
12
16
|
TEMPLATE_VERSION_PATH,
|
|
13
17
|
'app.config.js',
|
|
18
|
+
'babel.config.js',
|
|
19
|
+
'metro.config.js',
|
|
14
20
|
'package-lock.json',
|
|
15
21
|
'package.json',
|
|
22
|
+
'power-apps-env.d.ts',
|
|
23
|
+
'tamagui.config.ts',
|
|
16
24
|
TSCONFIG_PATH,
|
|
17
25
|
];
|
|
18
|
-
const UNIFIED_PATCH_MANAGED_PATHS = [
|
|
26
|
+
const UNIFIED_PATCH_MANAGED_PATHS = [
|
|
27
|
+
'app.config.js',
|
|
28
|
+
'babel.config.js',
|
|
29
|
+
'metro.config.js',
|
|
30
|
+
'power-apps-env.d.ts',
|
|
31
|
+
'tamagui.config.ts',
|
|
32
|
+
];
|
|
19
33
|
|
|
20
34
|
function isTemplateManagedPath(relativePath) {
|
|
21
35
|
return TEMPLATE_MANAGED_PATHS.includes(relativePath);
|
|
@@ -151,10 +165,21 @@ function patchPackageJson(source, profile, hostVersion, transitions = null) {
|
|
|
151
165
|
packageJson.dependencies ||= {};
|
|
152
166
|
setManagedValues(packageJson, { expo: profile.expoVersion }, 'dependencies', changes);
|
|
153
167
|
setManagedValues(packageJson, { [HOST_PACKAGE]: hostVersion }, 'dependencies', changes);
|
|
154
|
-
if (transitions)
|
|
168
|
+
if (transitions) {
|
|
169
|
+
applyPackageTransitions(packageJson, transitions, changes, warnings);
|
|
170
|
+
applyJsonTransitions(packageJson, transitions.fields, [], changes, warnings);
|
|
171
|
+
applyJsonTransitions(packageJson, transitions.scripts, ['scripts'], changes, warnings);
|
|
172
|
+
}
|
|
155
173
|
ensureManagedValues(packageJson, profile.managedDependencies, 'dependencies', changes, warnings);
|
|
156
174
|
ensureManagedValues(packageJson, profile.managedDevDependencies, 'devDependencies', changes, warnings);
|
|
157
175
|
ensureManagedValues(packageJson, profile.managedOverrides, 'overrides', changes, warnings);
|
|
176
|
+
ensureManagedValues(packageJson, profile.managedScripts, 'scripts', changes, warnings);
|
|
177
|
+
for (const [name, value] of Object.entries(profile.managedFields || {})) {
|
|
178
|
+
if (packageJson[name] === undefined) {
|
|
179
|
+
changes.push(`add missing ${name}: ${formatValue(value)}`);
|
|
180
|
+
packageJson[name] = value;
|
|
181
|
+
} else if (!sameValue(packageJson[name], value)) warnings.push(`retain customized ${name}`);
|
|
182
|
+
}
|
|
158
183
|
return {
|
|
159
184
|
changed: changes.length > 0,
|
|
160
185
|
changes,
|
|
@@ -169,18 +194,18 @@ function applyJsonTransitions(target, transitions, sectionPath, changes, warning
|
|
|
169
194
|
section[segment] ||= {};
|
|
170
195
|
section = section[segment];
|
|
171
196
|
}
|
|
172
|
-
const prefix = sectionPath.join('.');
|
|
197
|
+
const prefix = sectionPath.length ? `${sectionPath.join('.')}.` : '';
|
|
173
198
|
for (const [name, transition] of Object.entries(transitions || {})) {
|
|
174
199
|
const current = section[name];
|
|
175
200
|
if (transition.to === null) {
|
|
176
201
|
if (sameValue(current, transition.from)) {
|
|
177
|
-
changes.push(`remove ${prefix}
|
|
202
|
+
changes.push(`remove ${prefix}${name}`);
|
|
178
203
|
delete section[name];
|
|
179
|
-
} else if (current !== undefined) warnings.push(`retain customized ${prefix}
|
|
204
|
+
} else if (current !== undefined) warnings.push(`retain customized ${prefix}${name}`);
|
|
180
205
|
} else if (current === undefined || sameValue(current, transition.from)) {
|
|
181
|
-
changes.push(`${prefix}
|
|
206
|
+
changes.push(`${prefix}${name}: ${formatValue(current ?? '(missing)')} -> ${formatValue(transition.to)}`);
|
|
182
207
|
section[name] = transition.to;
|
|
183
|
-
} else if (!sameValue(current, transition.to)) warnings.push(`retain customized ${prefix}
|
|
208
|
+
} else if (!sameValue(current, transition.to)) warnings.push(`retain customized ${prefix}${name}`);
|
|
184
209
|
}
|
|
185
210
|
}
|
|
186
211
|
|
|
@@ -188,6 +213,8 @@ function patchTsconfigJson(source, transitions = null) {
|
|
|
188
213
|
const tsconfig = JSON.parse(source);
|
|
189
214
|
const changes = [];
|
|
190
215
|
const warnings = [];
|
|
216
|
+
applyJsonTransitions(tsconfig, transitions?.fields, [], changes, warnings);
|
|
217
|
+
applyJsonTransitions(tsconfig, transitions?.compilerOptions, ['compilerOptions'], changes, warnings);
|
|
191
218
|
applyJsonTransitions(tsconfig, transitions?.paths, ['compilerOptions', 'paths'], changes, warnings);
|
|
192
219
|
return {
|
|
193
220
|
changed: changes.length > 0,
|
|
@@ -197,6 +224,31 @@ function patchTsconfigJson(source, transitions = null) {
|
|
|
197
224
|
};
|
|
198
225
|
}
|
|
199
226
|
|
|
227
|
+
function patchGitignore(source, transition) {
|
|
228
|
+
if (!transition) return { changed: false, changes: [], warnings: [], content: source };
|
|
229
|
+
const start = source.indexOf(GITIGNORE_START);
|
|
230
|
+
const end = source.indexOf(GITIGNORE_END);
|
|
231
|
+
const duplicateStart = start !== -1 && source.indexOf(GITIGNORE_START, start + GITIGNORE_START.length) !== -1;
|
|
232
|
+
const duplicateEnd = end !== -1 && source.indexOf(GITIGNORE_END, end + GITIGNORE_END.length) !== -1;
|
|
233
|
+
const block = `${GITIGNORE_START}\n${transition.to.trimEnd()}\n${GITIGNORE_END}`;
|
|
234
|
+
if (start === -1 && end === -1) {
|
|
235
|
+
const separator = source.length && !source.endsWith('\n\n') ? (source.endsWith('\n') ? '\n' : '\n\n') : '';
|
|
236
|
+
return { changed: true, changes: ['add Power Apps managed .gitignore block'], warnings: [], content: `${source}${separator}${block}\n` };
|
|
237
|
+
}
|
|
238
|
+
if (start === -1 || end < start || duplicateStart || duplicateEnd) {
|
|
239
|
+
throw new Error(`${GITIGNORE_PATH} has invalid Power Apps managed markers`);
|
|
240
|
+
}
|
|
241
|
+
const blockEnd = end + GITIGNORE_END.length;
|
|
242
|
+
const current = source.slice(start + GITIGNORE_START.length, end).replace(/^\r?\n|\r?\n$/g, '');
|
|
243
|
+
if (current === transition.to.trimEnd()) return { changed: false, changes: [], warnings: [], content: source };
|
|
244
|
+
return {
|
|
245
|
+
changed: true,
|
|
246
|
+
changes: ['update Power Apps managed .gitignore block'],
|
|
247
|
+
warnings: current === transition.from?.trimEnd() ? [] : ['replace customized Power Apps managed .gitignore block'],
|
|
248
|
+
content: `${source.slice(0, start)}${block}${source.slice(blockEnd)}`,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
200
252
|
function buildMigrationOperations(projectRoot, migration) {
|
|
201
253
|
if (!migration) return { operations: [], conflicts: [] };
|
|
202
254
|
const operations = [];
|
|
@@ -278,17 +330,18 @@ function addConflict(operations, conflicts, filePath, relativePath, migrationId,
|
|
|
278
330
|
});
|
|
279
331
|
}
|
|
280
332
|
|
|
281
|
-
function readProjectState(projectRoot
|
|
333
|
+
function readProjectState(projectRoot) {
|
|
282
334
|
const statePath = path.join(projectRoot, TEMPLATE_VERSION_PATH);
|
|
283
335
|
if (fs.existsSync(statePath)) {
|
|
284
|
-
const state = readJson(statePath);
|
|
285
|
-
if (state
|
|
286
|
-
|
|
287
|
-
|
|
336
|
+
const state = readJson(statePath).expo?.extra?.powerappsNative;
|
|
337
|
+
if (state) {
|
|
338
|
+
if (state.schemaVersion !== 1) throw new Error(`${TEMPLATE_VERSION_PATH} uses unsupported schemaVersion ${state.schemaVersion}`);
|
|
339
|
+
if (!Number.isInteger(state.templateVersion)) throw new Error(`${TEMPLATE_VERSION_PATH} has an invalid templateVersion`);
|
|
340
|
+
validateNativeRuntimeVersions(state.nativeRuntimeVersions, `${TEMPLATE_VERSION_PATH} state`);
|
|
341
|
+
return state;
|
|
342
|
+
}
|
|
288
343
|
}
|
|
289
|
-
|
|
290
|
-
if (targetVersion === 1) return { schemaVersion: 1, templateVersion: 1 };
|
|
291
|
-
throw new Error(`Template state is missing. Rerun with --from-version <version> after identifying the app's source template version.`);
|
|
344
|
+
throw new Error(`Template state is missing from ${TEMPLATE_VERSION_PATH}.`);
|
|
292
345
|
}
|
|
293
346
|
|
|
294
347
|
function selectNextMigration(migrations, fromVersion, targetVersion) {
|
|
@@ -306,6 +359,7 @@ function selectNextMigration(migrations, fromVersion, targetVersion) {
|
|
|
306
359
|
function loadMigrations(profile, migrationsDirectory) {
|
|
307
360
|
if (profile.schemaVersion !== 1) throw new Error(`Compatibility profile uses unsupported schemaVersion ${profile.schemaVersion}`);
|
|
308
361
|
if (!Number.isInteger(profile.targetTemplateVersion) || profile.targetTemplateVersion < 1) throw new Error('Compatibility profile has an invalid targetTemplateVersion');
|
|
362
|
+
validateNativeRuntime(profile.nativeRuntime, 'Compatibility profile');
|
|
309
363
|
const ids = profile.migrations || [];
|
|
310
364
|
if (new Set(ids).size !== ids.length) throw new Error('Compatibility profile contains duplicate migration IDs');
|
|
311
365
|
const migrations = ids.map(migrationId => loadMigration(migrationId, migrationsDirectory));
|
|
@@ -330,10 +384,45 @@ function loadMigration(migrationId, migrationsDirectory) {
|
|
|
330
384
|
if (!migration.targetProfile?.hostVersion || !migration.targetProfile?.expoVersion || !migration.targetProfile?.expoDoctorVersion) {
|
|
331
385
|
throw new Error(`Migration ${migration.id} has an incomplete target profile`);
|
|
332
386
|
}
|
|
387
|
+
for (const platform of ['android', 'ios']) {
|
|
388
|
+
const from = migration.nativeRuntimeTransition?.from?.[platform];
|
|
389
|
+
const to = migration.nativeRuntimeTransition?.to?.[platform];
|
|
390
|
+
if (!Number.isInteger(from?.version) || !Number.isInteger(to?.version) || to.version < from.version || to.version > from.version + 1) {
|
|
391
|
+
throw new Error(`Migration ${migration.id} has invalid ${platform} native runtime versions`);
|
|
392
|
+
}
|
|
393
|
+
if (!isHash(from.fingerprint) || !isHash(to.fingerprint)) {
|
|
394
|
+
throw new Error(`Migration ${migration.id} has invalid ${platform} native runtime fingerprints`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
validateNativeRuntime(migration.targetProfile.nativeRuntime, `Migration ${migration.id} target profile`);
|
|
398
|
+
if (JSON.stringify(migration.targetProfile.nativeRuntime) !== JSON.stringify(migration.nativeRuntimeTransition.to)) {
|
|
399
|
+
throw new Error(`Migration ${migration.id} target profile native runtime does not match its transition`);
|
|
400
|
+
}
|
|
333
401
|
validatePatchMetadata(migration, patch);
|
|
334
402
|
return { ...migration, patch };
|
|
335
403
|
}
|
|
336
404
|
|
|
405
|
+
function isHash(value) {
|
|
406
|
+
return typeof value === 'string' && /^[a-f0-9]{64}$/.test(value);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function validateNativeRuntime(nativeRuntime, label) {
|
|
410
|
+
for (const platform of ['android', 'ios']) {
|
|
411
|
+
const runtime = nativeRuntime?.[platform];
|
|
412
|
+
if (!Number.isInteger(runtime?.version) || runtime.version < 1 || !isHash(runtime.fingerprint)) {
|
|
413
|
+
throw new Error(`${label} has invalid ${platform} native runtime metadata`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function validateNativeRuntimeVersions(versions, label) {
|
|
419
|
+
for (const platform of ['android', 'ios']) {
|
|
420
|
+
if (!Number.isInteger(versions?.[platform]) || versions[platform] < 1) {
|
|
421
|
+
throw new Error(`${label} has invalid ${platform} native runtime version`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
337
426
|
function validatePatchMetadata(migration, patch) {
|
|
338
427
|
try {
|
|
339
428
|
const parsedPatches = parseMigrationPatch(patch);
|
|
@@ -383,18 +472,21 @@ function validateGraph(migrations, targetVersion) {
|
|
|
383
472
|
}
|
|
384
473
|
if (migrations.length) {
|
|
385
474
|
const firstVersion = Math.min(...fromVersions);
|
|
475
|
+
if (firstVersion !== 1) throw new Error('Migration graph must start at template version 1');
|
|
386
476
|
for (let version = firstVersion; version < targetVersion; version += 1) {
|
|
387
477
|
if (!fromVersions.has(version)) throw new Error(`Migration graph is missing template version ${version} -> ${version + 1}`);
|
|
388
478
|
}
|
|
389
479
|
if (Math.max(...migrations.map(migration => migration.toTemplateVersion)) !== targetVersion) {
|
|
390
480
|
throw new Error(`Migration graph does not reach target template version ${targetVersion}`);
|
|
391
481
|
}
|
|
482
|
+
} else if (targetVersion > 1) {
|
|
483
|
+
throw new Error(`Migration graph does not reach target template version ${targetVersion}`);
|
|
392
484
|
}
|
|
393
485
|
}
|
|
394
486
|
|
|
395
|
-
function buildUpgradePlan(projectRoot, profile, hostVersion,
|
|
487
|
+
function buildUpgradePlan(projectRoot, profile, hostVersion, migrationsDirectory, includeState = true) {
|
|
396
488
|
const migrations = loadMigrations(profile, migrationsDirectory);
|
|
397
|
-
const state = readProjectState(projectRoot
|
|
489
|
+
const state = readProjectState(projectRoot);
|
|
398
490
|
const migration = selectNextMigration(migrations, state.templateVersion, profile.targetTemplateVersion);
|
|
399
491
|
const targetProfile = migration ? migration.targetProfile : profile;
|
|
400
492
|
const targetHostVersion = migration ? migration.targetProfile.hostVersion : hostVersion;
|
|
@@ -410,7 +502,18 @@ function buildUpgradePlan(projectRoot, profile, hostVersion, fromVersion, migrat
|
|
|
410
502
|
const tsconfigPatch = patchTsconfigJson(source, migration.tsconfigTransitions);
|
|
411
503
|
if (tsconfigPatch.changed) operations.push({ filePath: tsconfigPath, ...tsconfigPatch });
|
|
412
504
|
}
|
|
413
|
-
if (
|
|
505
|
+
if (migration?.gitignoreTransition) {
|
|
506
|
+
const gitignorePath = path.join(projectRoot, GITIGNORE_PATH);
|
|
507
|
+
const source = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf8') : '';
|
|
508
|
+
const gitignorePatch = patchGitignore(source, migration.gitignoreTransition);
|
|
509
|
+
if (gitignorePatch.changed) operations.push({ filePath: gitignorePath, ...gitignorePatch });
|
|
510
|
+
}
|
|
511
|
+
if (includeState) addStateOperation(
|
|
512
|
+
operations,
|
|
513
|
+
projectRoot,
|
|
514
|
+
migration?.toTemplateVersion || profile.targetTemplateVersion,
|
|
515
|
+
targetProfile.nativeRuntime,
|
|
516
|
+
);
|
|
414
517
|
return {
|
|
415
518
|
operations,
|
|
416
519
|
conflicts: [],
|
|
@@ -422,16 +525,26 @@ function buildUpgradePlan(projectRoot, profile, hostVersion, fromVersion, migrat
|
|
|
422
525
|
};
|
|
423
526
|
}
|
|
424
527
|
|
|
425
|
-
function addStateOperation(operations, projectRoot, targetVersion) {
|
|
528
|
+
function addStateOperation(operations, projectRoot, targetVersion, nativeRuntime) {
|
|
426
529
|
const statePath = path.join(projectRoot, TEMPLATE_VERSION_PATH);
|
|
427
|
-
const nextState = {
|
|
428
|
-
|
|
530
|
+
const nextState = {
|
|
531
|
+
schemaVersion: 1,
|
|
532
|
+
templateVersion: targetVersion,
|
|
533
|
+
nativeRuntimeVersions: Object.fromEntries(
|
|
534
|
+
['android', 'ios'].map(platform => [platform, nativeRuntime[platform].version]),
|
|
535
|
+
),
|
|
536
|
+
};
|
|
537
|
+
const appConfig = fs.existsSync(statePath) ? readJson(statePath) : {};
|
|
538
|
+
const currentState = appConfig.expo?.extra?.powerappsNative || null;
|
|
429
539
|
if (JSON.stringify(currentState) !== JSON.stringify(nextState)) {
|
|
540
|
+
appConfig.expo ||= {};
|
|
541
|
+
appConfig.expo.extra ||= {};
|
|
542
|
+
appConfig.expo.extra.powerappsNative = nextState;
|
|
430
543
|
operations.push({
|
|
431
544
|
filePath: statePath,
|
|
432
545
|
changed: true,
|
|
433
|
-
changes: [`record template version ${targetVersion}`],
|
|
434
|
-
content: `${JSON.stringify(
|
|
546
|
+
changes: [`record template version ${targetVersion} and native runtime compatibility`],
|
|
547
|
+
content: `${JSON.stringify(appConfig, null, 2)}\n`,
|
|
435
548
|
state: true,
|
|
436
549
|
});
|
|
437
550
|
}
|
|
@@ -448,8 +561,10 @@ module.exports = {
|
|
|
448
561
|
isCustomerOwnedPath,
|
|
449
562
|
isTemplateManagedPath,
|
|
450
563
|
isUnifiedPatchManagedPath,
|
|
564
|
+
loadMigrations,
|
|
451
565
|
parseFileMode,
|
|
452
566
|
patchTsconfigJson,
|
|
567
|
+
patchGitignore,
|
|
453
568
|
patchPackageJson,
|
|
454
569
|
readJson,
|
|
455
570
|
readProjectState,
|