@memberjunction/open-app-engine 6.2.0-edge.6 → 6.2.0-edge.8
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/dist/dependency/dependency-graph-builder.d.ts +7 -2
- package/dist/dependency/dependency-graph-builder.d.ts.map +1 -1
- package/dist/dependency/dependency-graph-builder.js +42 -10
- package/dist/dependency/dependency-graph-builder.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/install/history-recorder.d.ts.map +1 -1
- package/dist/install/history-recorder.js +1 -0
- package/dist/install/history-recorder.js.map +1 -1
- package/dist/install/install-orchestrator.d.ts +2 -0
- package/dist/install/install-orchestrator.d.ts.map +1 -1
- package/dist/install/install-orchestrator.js +170 -78
- package/dist/install/install-orchestrator.js.map +1 -1
- package/dist/install/package-manager.d.ts +20 -0
- package/dist/install/package-manager.d.ts.map +1 -1
- package/dist/install/package-manager.js +126 -5
- package/dist/install/package-manager.js.map +1 -1
- package/dist/install/schema-manager.d.ts +1 -2
- package/dist/install/schema-manager.d.ts.map +1 -1
- package/dist/install/schema-manager.js +3 -3
- package/dist/install/schema-manager.js.map +1 -1
- package/dist/install/template-user.d.ts.map +1 -1
- package/dist/install/template-user.js +1 -0
- package/dist/install/template-user.js.map +1 -1
- package/dist/types/open-app-types.d.ts +1 -0
- package/dist/types/open-app-types.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -12,7 +12,7 @@ import { OfferTemplateUser } from './template-user.js';
|
|
|
12
12
|
import { ExtractApplicationIds } from './migration-application-ids.js';
|
|
13
13
|
import { CreateAppTempDir } from './temp-dir.js';
|
|
14
14
|
import { RunAppMigrations } from './migration-runner.js';
|
|
15
|
-
import { AddAppPackages, RemoveAppPackages, RunPackageInstallAsync, BumpPrefixedDependencies } from './package-manager.js';
|
|
15
|
+
import { AddAppPackages, RemoveAppPackages, RunPackageInstallAsync, BumpPrefixedDependencies, PreflightAppPackages } from './package-manager.js';
|
|
16
16
|
import { BuildHookResolutionBases, ResolveHookModule } from './hook-module-resolver.js';
|
|
17
17
|
import { AddServerDynamicPackages, AddClientDynamicPackages, RemoveServerDynamicPackages, PruneDynamicPackagesNotInManifest, ToggleServerDynamicPackages, AddEntityPackageMapping, RemoveEntityPackageMapping, AddExcludeSchema, RemoveExcludeSchema } from './config-manager.js';
|
|
18
18
|
import { AngularConfigManager } from './angular-config-manager.js';
|
|
@@ -56,6 +56,7 @@ export async function InstallApp(options, context) {
|
|
|
56
56
|
const { Callbacks } = context;
|
|
57
57
|
let createdAppId;
|
|
58
58
|
let manifest;
|
|
59
|
+
let teardownScripts;
|
|
59
60
|
const subpath = options.Subpath ?? ParseGitHubUrl(options.Source)?.Subpath;
|
|
60
61
|
try {
|
|
61
62
|
const explicitVersion = options.Version;
|
|
@@ -84,6 +85,10 @@ export async function InstallApp(options, context) {
|
|
|
84
85
|
if (!compatResult.Compatible) {
|
|
85
86
|
return BuildFailureResult('Install', manifest.name, manifest.version, 'Schema', startTime, compatResult.Message ?? 'Incompatible MJ version');
|
|
86
87
|
}
|
|
88
|
+
const preflight = await PreflightManifestPackages(manifest, context, effectivePackageVersion, effectiveVersionStrategy);
|
|
89
|
+
if (!preflight.Success) {
|
|
90
|
+
return BuildFailureResult('Install', manifest.name, manifest.version, 'Packages', startTime, preflight.ErrorMessage ?? 'Package preflight failed');
|
|
91
|
+
}
|
|
87
92
|
if (!options._skipDependencyResolution) {
|
|
88
93
|
const depResult = await ResolveDependencyChain(manifest, context);
|
|
89
94
|
if (!depResult.Success) {
|
|
@@ -138,16 +143,19 @@ export async function InstallApp(options, context) {
|
|
|
138
143
|
await PersistCanonicalSchemaName(manifest, context);
|
|
139
144
|
}
|
|
140
145
|
if (manifest.migrations && manifest.schema) {
|
|
146
|
+
if (schemaCreated) {
|
|
147
|
+
teardownScripts = await PrefetchTeardownScripts(manifest, context, subpath);
|
|
148
|
+
}
|
|
141
149
|
const migrationResult = await HandleMigrations(manifest, context, subpath);
|
|
142
150
|
if (!migrationResult.Success) {
|
|
143
|
-
await CompensateSchemaOnFailure(manifest, context, schemaCreated, options.AllowDoubleUnderscoreSchema === true, Callbacks, subpath);
|
|
151
|
+
await CompensateSchemaOnFailure(manifest, context, schemaCreated, options.AllowDoubleUnderscoreSchema === true, Callbacks, subpath, teardownScripts);
|
|
144
152
|
return BuildFailureResult('Install', manifest.name, manifest.version, 'Migration', startTime, migrationResult.ErrorMessage ?? 'Migration failed');
|
|
145
153
|
}
|
|
146
154
|
}
|
|
147
155
|
Callbacks?.OnProgress?.('Record', 'Recording app installation...');
|
|
148
156
|
const recordResult = await RecordInstallationAtomically(context.ContextUser, manifest, Callbacks, undefined, subpath);
|
|
149
157
|
if (!recordResult.Success) {
|
|
150
|
-
await CompensateSchemaOnFailure(manifest, context, schemaCreated, options.AllowDoubleUnderscoreSchema === true, Callbacks, subpath);
|
|
158
|
+
await CompensateSchemaOnFailure(manifest, context, schemaCreated, options.AllowDoubleUnderscoreSchema === true, Callbacks, subpath, teardownScripts);
|
|
151
159
|
return BuildFailureResult('Install', manifest.name, manifest.version, 'Record', startTime, recordResult.ErrorMessage ?? 'Failed to record installation');
|
|
152
160
|
}
|
|
153
161
|
createdAppId = recordResult.AppId;
|
|
@@ -267,6 +275,9 @@ export async function InstallApp(options, context) {
|
|
|
267
275
|
Callbacks?.OnError?.('Install', message);
|
|
268
276
|
return BuildFailureResult('Install', options.Source, '', phase, startTime, message);
|
|
269
277
|
}
|
|
278
|
+
finally {
|
|
279
|
+
ReleaseTeardownScripts(teardownScripts, context);
|
|
280
|
+
}
|
|
270
281
|
}
|
|
271
282
|
async function RecordInstallationAtomically(contextUser, manifest, callbacks, provider, subpath) {
|
|
272
283
|
const md = (provider ?? new Metadata());
|
|
@@ -289,7 +300,7 @@ async function RecordInstallationAtomically(contextUser, manifest, callbacks, pr
|
|
|
289
300
|
return { Success: false, ErrorMessage: `Transaction failed: ${message}` };
|
|
290
301
|
}
|
|
291
302
|
}
|
|
292
|
-
async function CompensateSchemaOnFailure(manifest, context, schemaWasCreated, allowDoubleUnderscore, callbacks, subpath) {
|
|
303
|
+
async function CompensateSchemaOnFailure(manifest, context, schemaWasCreated, allowDoubleUnderscore, callbacks, subpath, teardownScripts) {
|
|
293
304
|
if (!schemaWasCreated || !manifest.schema) {
|
|
294
305
|
return;
|
|
295
306
|
}
|
|
@@ -310,37 +321,65 @@ async function CompensateSchemaOnFailure(manifest, context, schemaWasCreated, al
|
|
|
310
321
|
const msg = error instanceof Error ? error.message : String(error);
|
|
311
322
|
callbacks?.OnError?.('Rollback', `Failed to remove entity metadata for '${schemaName}' during rollback: ${msg}`);
|
|
312
323
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
catch (error) {
|
|
321
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
322
|
-
callbacks?.OnError?.('Rollback', `Teardown failed during rollback: ${msg}`);
|
|
324
|
+
const dropOptions = { allowDoubleUnderscore, CoreSchema: context.MJCoreSchema };
|
|
325
|
+
if (!manifest.migrations?.teardownDirectory) {
|
|
326
|
+
if (manifest.migrations) {
|
|
327
|
+
callbacks?.OnWarn?.('Rollback', `'${manifest.name}' declares migrations but no teardownDirectory — rows its migrations wrote to the shared core schema WILL remain after this rollback. ` +
|
|
328
|
+
`If those rows were seeded with fixed IDs, reinstalling this app may fail with a primary-key violation until they are removed manually.`);
|
|
323
329
|
}
|
|
330
|
+
await DropSchemaAndReport(schemaName, manifest.name, 'Rollback', dropOptions, context);
|
|
331
|
+
return;
|
|
324
332
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
333
|
+
const firstAttempt = await RunRollbackTeardown(manifest, context, teardownScripts, subpath);
|
|
334
|
+
const dropResult = await DropSchemaAndReport(schemaName, manifest.name, 'Rollback', dropOptions, context);
|
|
335
|
+
if (firstAttempt.Success) {
|
|
336
|
+
return;
|
|
328
337
|
}
|
|
338
|
+
if (!dropResult.Success) {
|
|
339
|
+
callbacks?.OnError?.('Rollback', `Teardown failed during rollback: ${firstAttempt.ErrorMessage ?? 'unknown error'}`);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
callbacks?.OnProgress?.('Rollback', `Teardown failed with schema '${schemaName}' in place; running it again now that the schema is dropped...`);
|
|
343
|
+
const secondAttempt = await RunRollbackTeardown(manifest, context, teardownScripts, subpath);
|
|
344
|
+
if (!secondAttempt.Success) {
|
|
345
|
+
callbacks?.OnError?.('Rollback', `Teardown failed during rollback, before and after dropping schema '${schemaName}'. ` +
|
|
346
|
+
`With the schema: ${firstAttempt.ErrorMessage ?? 'unknown error'}. Without it: ${secondAttempt.ErrorMessage ?? 'unknown error'}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async function RunRollbackTeardown(manifest, context, teardownScripts, subpath) {
|
|
329
350
|
try {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
callbacks?.OnError?.('Rollback', `Failed to drop schema '${schemaName}' during rollback: ${dropResult.ErrorMessage ?? 'unknown error'}`);
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
callbacks?.OnProgress?.('Rollback', `Schema '${schemaName}' dropped successfully`);
|
|
337
|
-
}
|
|
351
|
+
return teardownScripts
|
|
352
|
+
? await RunTeardownScripts(manifest, context, teardownScripts)
|
|
353
|
+
: await HandleTeardown(manifest, context, subpath);
|
|
338
354
|
}
|
|
339
|
-
catch (
|
|
340
|
-
|
|
341
|
-
callbacks?.OnError?.('Rollback', `Failed to drop schema '${schemaName}' during rollback: ${msg}`);
|
|
355
|
+
catch (error) {
|
|
356
|
+
return { Success: false, ErrorMessage: error instanceof Error ? error.message : String(error) };
|
|
342
357
|
}
|
|
343
358
|
}
|
|
359
|
+
export async function DropSchemaAndReport(schemaName, appName, phase, options, context) {
|
|
360
|
+
const callbacks = context.Callbacks;
|
|
361
|
+
const nameCheck = ValidateSchemaName(schemaName, options);
|
|
362
|
+
if (!nameCheck.Success) {
|
|
363
|
+
const refusal = BuildSchemaDropRefusalMessage(nameCheck, appName, schemaName);
|
|
364
|
+
callbacks?.OnError?.(phase, refusal);
|
|
365
|
+
return { Success: false, ErrorMessage: refusal };
|
|
366
|
+
}
|
|
367
|
+
callbacks?.OnProgress?.(phase, `Dropping schema '${schemaName}'...`);
|
|
368
|
+
let result;
|
|
369
|
+
try {
|
|
370
|
+
result = await DropAppSchema(schemaName, context.DatabaseProvider, options);
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
374
|
+
result = { Success: false, ErrorMessage: `Failed to drop schema '${schemaName}': ${message}` };
|
|
375
|
+
}
|
|
376
|
+
if (!result.Success) {
|
|
377
|
+
callbacks?.OnError?.(phase, `Schema '${schemaName}' was not dropped: ${result.ErrorMessage ?? 'unknown error'}`);
|
|
378
|
+
return result;
|
|
379
|
+
}
|
|
380
|
+
callbacks?.OnProgress?.(phase, `Schema '${schemaName}' dropped successfully`);
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
344
383
|
export async function UpgradeApp(options, context) {
|
|
345
384
|
const startTime = Date.now();
|
|
346
385
|
const { Callbacks } = context;
|
|
@@ -401,6 +440,7 @@ export async function UpgradeApp(options, context) {
|
|
|
401
440
|
if (manifest.schema) {
|
|
402
441
|
const schemaValidation = ValidateSchemaName(manifest.schema.name, {
|
|
403
442
|
allowDoubleUnderscore: options.AllowDoubleUnderscoreSchema === true,
|
|
443
|
+
CoreSchema: context.MJCoreSchema,
|
|
404
444
|
});
|
|
405
445
|
if (!schemaValidation.Success) {
|
|
406
446
|
return BuildFailureResult('Upgrade', options.AppName, targetVersion, 'Schema', startTime, schemaValidation.ErrorMessage ?? 'Invalid schema name');
|
|
@@ -412,6 +452,12 @@ export async function UpgradeApp(options, context) {
|
|
|
412
452
|
return BuildFailureResult('Upgrade', options.AppName, targetVersion, 'Schema', startTime, migratable.ErrorMessage ?? 'Cannot run migrations in the app schema');
|
|
413
453
|
}
|
|
414
454
|
}
|
|
455
|
+
const effectiveUpgradeVersion = explicitUpgradeVersion ? targetVersion.replace(/^v/, '') : manifest.version;
|
|
456
|
+
const effectiveUpgradeStrategy = explicitUpgradeVersion ? 'exact' : context.VersionStrategy;
|
|
457
|
+
const preflight = await PreflightManifestPackages(manifest, context, effectiveUpgradeVersion, effectiveUpgradeStrategy);
|
|
458
|
+
if (!preflight.Success) {
|
|
459
|
+
return BuildFailureResult('Upgrade', options.AppName, targetVersion, 'Packages', startTime, preflight.ErrorMessage ?? 'Package preflight failed');
|
|
460
|
+
}
|
|
415
461
|
if (manifest.dependencies && Object.keys(manifest.dependencies).length > 0) {
|
|
416
462
|
const depResult = await ResolveDependencyChain(manifest, context);
|
|
417
463
|
if (!depResult.Success) {
|
|
@@ -455,8 +501,6 @@ export async function UpgradeApp(options, context) {
|
|
|
455
501
|
}
|
|
456
502
|
let npmInstallWarning;
|
|
457
503
|
if (!IsStepDone(UPGRADE_STEP_ORDER, resumeCheckpoint, 'PackagesInstalled')) {
|
|
458
|
-
const effectiveUpgradeVersion = explicitUpgradeVersion ? targetVersion.replace(/^v/, '') : manifest.version;
|
|
459
|
-
const effectiveUpgradeStrategy = explicitUpgradeVersion ? 'exact' : context.VersionStrategy;
|
|
460
504
|
const pkgResult = await HandlePackageInstallation(manifest, context, effectiveUpgradeVersion, effectiveUpgradeStrategy, options.Verbose);
|
|
461
505
|
if (!pkgResult.Success) {
|
|
462
506
|
if (pkgResult.PackageJsonUpdated) {
|
|
@@ -668,23 +712,11 @@ export async function RemoveApp(options, context) {
|
|
|
668
712
|
}
|
|
669
713
|
let schemaDropError;
|
|
670
714
|
if (!options.KeepData && existingApp.SchemaName && !schemaShared) {
|
|
671
|
-
const
|
|
715
|
+
const dropResult = await DropSchemaAndReport(existingApp.SchemaName, existingApp.Name, 'Schema', {
|
|
672
716
|
allowDoubleUnderscore: options.AllowDoubleUnderscoreSchema === true,
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
Callbacks?.OnError?.('Schema', schemaDropError);
|
|
677
|
-
}
|
|
678
|
-
else {
|
|
679
|
-
Callbacks?.OnProgress?.('Schema', `Dropping schema '${existingApp.SchemaName}'...`);
|
|
680
|
-
const dropResult = await DropAppSchema(existingApp.SchemaName, context.DatabaseProvider, {
|
|
681
|
-
allowDoubleUnderscore: options.AllowDoubleUnderscoreSchema === true,
|
|
682
|
-
});
|
|
683
|
-
if (!dropResult.Success) {
|
|
684
|
-
schemaDropError = dropResult.ErrorMessage;
|
|
685
|
-
Callbacks?.OnError?.('Schema', `Failed to drop schema: ${dropResult.ErrorMessage}`);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
717
|
+
CoreSchema: context.MJCoreSchema,
|
|
718
|
+
}, context);
|
|
719
|
+
schemaDropError = dropResult.Success ? undefined : dropResult.ErrorMessage;
|
|
688
720
|
}
|
|
689
721
|
const removalErrors = [
|
|
690
722
|
shareCheckError,
|
|
@@ -859,18 +891,18 @@ async function ResolveDependencyChain(manifest, context) {
|
|
|
859
891
|
Repository: manifest.repository,
|
|
860
892
|
Dependencies: dependencies,
|
|
861
893
|
};
|
|
862
|
-
const result = await ResolveDependencyGraph(root, installedMap, BuildManifestFetcher(context));
|
|
894
|
+
const result = await ResolveDependencyGraph(root, installedMap, BuildManifestFetcher(context), (repoUrl, versionRange) => ResolveDependencyVersion(repoUrl, versionRange, context.GitHubOptions));
|
|
863
895
|
if (!result.Success) {
|
|
864
896
|
return { Success: false, ErrorMessage: result.ErrorMessage };
|
|
865
897
|
}
|
|
866
898
|
const depsToInstall = (result.InstallOrder ?? [])
|
|
867
899
|
.filter((d) => !d.AlreadyInstalled)
|
|
868
|
-
.map((d) => ({ AppName: d.AppName, Repository: d.Repository, VersionRange: d.VersionRange, Subpath: d.Subpath }));
|
|
900
|
+
.map((d) => ({ AppName: d.AppName, Repository: d.Repository, VersionRange: d.VersionRange, Subpath: d.Subpath, Version: d.ResolvedVersion }));
|
|
869
901
|
return { Success: true, DepsToInstall: depsToInstall };
|
|
870
902
|
}
|
|
871
903
|
function BuildManifestFetcher(context) {
|
|
872
|
-
return async (repoUrl, subpath) => {
|
|
873
|
-
const fetched = await FetchManifestFromGitHub(repoUrl,
|
|
904
|
+
return async (repoUrl, subpath, version) => {
|
|
905
|
+
const fetched = await FetchManifestFromGitHub(repoUrl, version, context.GitHubOptions, subpath);
|
|
874
906
|
if (!fetched.Success || !fetched.ManifestJSON) {
|
|
875
907
|
return { Success: false, ErrorMessage: fetched.ErrorMessage ?? 'Failed to fetch manifest' };
|
|
876
908
|
}
|
|
@@ -883,6 +915,7 @@ function BuildManifestFetcher(context) {
|
|
|
883
915
|
Manifest: {
|
|
884
916
|
name: parsed.Manifest.name,
|
|
885
917
|
repository: parsed.Manifest.repository,
|
|
918
|
+
version: parsed.Manifest.version,
|
|
886
919
|
dependencies: (parsed.Manifest.dependencies ?? {}),
|
|
887
920
|
},
|
|
888
921
|
};
|
|
@@ -897,14 +930,10 @@ async function InstallDependencies(deps, context, inherited) {
|
|
|
897
930
|
};
|
|
898
931
|
}
|
|
899
932
|
context.Callbacks?.OnProgress?.('Dependencies', `Installing dependency from ${dep.Repository}...`);
|
|
900
|
-
const resolved = await ResolveDependencyVersion(dep.Repository, dep.VersionRange, context.GitHubOptions);
|
|
901
|
-
if (resolved.ErrorMessage) {
|
|
902
|
-
return { Success: false, ErrorMessage: `Cannot install dependency '${dep.AppName}': ${resolved.ErrorMessage}` };
|
|
903
|
-
}
|
|
904
933
|
const result = await InstallApp({
|
|
905
934
|
Source: dep.Repository,
|
|
906
935
|
Subpath: dep.Subpath,
|
|
907
|
-
Version:
|
|
936
|
+
Version: dep.Version,
|
|
908
937
|
_skipDependencyResolution: true,
|
|
909
938
|
AllowDoubleUnderscoreSchema: inherited.AllowDoubleUnderscoreSchema,
|
|
910
939
|
Verbose: inherited.Verbose,
|
|
@@ -961,7 +990,10 @@ async function HandleSchemaCreation(manifest, context, options) {
|
|
|
961
990
|
if (!manifest.schema) {
|
|
962
991
|
return { Success: true };
|
|
963
992
|
}
|
|
964
|
-
const validation = ValidateSchemaName(manifest.schema.name, {
|
|
993
|
+
const validation = ValidateSchemaName(manifest.schema.name, {
|
|
994
|
+
allowDoubleUnderscore: options.AllowDoubleUnderscore,
|
|
995
|
+
CoreSchema: context.MJCoreSchema,
|
|
996
|
+
});
|
|
965
997
|
if (!validation.Success) {
|
|
966
998
|
return { Success: false, ErrorMessage: validation.ErrorMessage };
|
|
967
999
|
}
|
|
@@ -1058,6 +1090,18 @@ function CleanupTempDir(tempDir, phase, context) {
|
|
|
1058
1090
|
}
|
|
1059
1091
|
}
|
|
1060
1092
|
async function HandleTeardown(manifest, context, subpath) {
|
|
1093
|
+
const download = await DownloadTeardownScripts(manifest, context, subpath);
|
|
1094
|
+
if (!download.Success || !download.Scripts) {
|
|
1095
|
+
return download;
|
|
1096
|
+
}
|
|
1097
|
+
try {
|
|
1098
|
+
return await RunTeardownScripts(manifest, context, download.Scripts);
|
|
1099
|
+
}
|
|
1100
|
+
finally {
|
|
1101
|
+
ReleaseTeardownScripts(download.Scripts, context);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
async function DownloadTeardownScripts(manifest, context, subpath) {
|
|
1061
1105
|
const teardownDir = manifest.migrations?.teardownDirectory;
|
|
1062
1106
|
if (!teardownDir) {
|
|
1063
1107
|
return { Success: true };
|
|
@@ -1069,36 +1113,61 @@ async function HandleTeardown(manifest, context, subpath) {
|
|
|
1069
1113
|
context.Callbacks?.OnProgress?.('Metadata', 'Downloading teardown scripts...');
|
|
1070
1114
|
const download = await DownloadMigrations(manifest.repository, manifest.version, dir, tempDir, context.GitHubOptions, subpath, manifest.name);
|
|
1071
1115
|
if (!download.Success) {
|
|
1116
|
+
CleanupTempDir(tempDir, 'Metadata', context);
|
|
1072
1117
|
return { Success: false, ErrorMessage: `Failed to download teardown scripts: ${download.ErrorMessage}` };
|
|
1073
1118
|
}
|
|
1074
1119
|
const files = (download.Files ?? []).filter((f) => f.endsWith('.sql')).sort();
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1120
|
+
return { Success: true, Scripts: { TempDir: tempDir, SourceDir: dir, Files: files } };
|
|
1121
|
+
}
|
|
1122
|
+
catch (error) {
|
|
1123
|
+
CleanupTempDir(tempDir, 'Metadata', context);
|
|
1124
|
+
throw error;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
async function PrefetchTeardownScripts(manifest, context, subpath) {
|
|
1128
|
+
try {
|
|
1129
|
+
const download = await DownloadTeardownScripts(manifest, context, subpath);
|
|
1130
|
+
if (!download.Success) {
|
|
1131
|
+
context.Callbacks?.OnWarn?.('Migration', `${download.ErrorMessage ?? 'Failed to download teardown scripts'}. A rollback will try to download them again.`);
|
|
1078
1132
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1133
|
+
return download.Scripts;
|
|
1134
|
+
}
|
|
1135
|
+
catch (error) {
|
|
1136
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1137
|
+
context.Callbacks?.OnWarn?.('Migration', `Failed to download teardown scripts: ${message}. A rollback will try to download them again.`);
|
|
1138
|
+
return undefined;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
function ReleaseTeardownScripts(scripts, context) {
|
|
1142
|
+
if (scripts) {
|
|
1143
|
+
CleanupTempDir(scripts.TempDir, 'Metadata', context);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
async function RunTeardownScripts(manifest, context, scripts) {
|
|
1147
|
+
const files = scripts.Files;
|
|
1148
|
+
if (files.length === 0) {
|
|
1149
|
+
context.Callbacks?.OnWarn?.('Metadata', `No teardown scripts in '${scripts.SourceDir}' — this app's rows in the shared core schema will NOT be retired on remove.`);
|
|
1150
|
+
return { Success: true };
|
|
1151
|
+
}
|
|
1152
|
+
const mjSchema = context.MJCoreSchema ?? '__mj';
|
|
1153
|
+
context.Callbacks?.OnProgress?.('Metadata', `Running ${files.length} teardown script(s) against '${mjSchema}'...`);
|
|
1154
|
+
await context.DatabaseProvider.BeginTransaction();
|
|
1155
|
+
try {
|
|
1156
|
+
for (const file of files) {
|
|
1157
|
+
const sql = readFileSync(join(scripts.TempDir, file), 'utf-8').split('${mjSchema}').join(mjSchema);
|
|
1158
|
+
if (sql.trim()) {
|
|
1159
|
+
await context.DatabaseProvider.ExecuteSQL(sql);
|
|
1088
1160
|
}
|
|
1089
|
-
await context.DatabaseProvider.CommitTransaction();
|
|
1090
1161
|
}
|
|
1091
|
-
|
|
1092
|
-
await context.DatabaseProvider.RollbackTransaction();
|
|
1093
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1094
|
-
return { Success: false, ErrorMessage: `Teardown failed for '${manifest.name}' (rolled back): ${message}` };
|
|
1095
|
-
}
|
|
1096
|
-
context.Callbacks?.OnSuccess?.('Metadata', `Retired this app's rows from '${mjSchema}' (${files.length} teardown script(s)).`);
|
|
1097
|
-
return { Success: true };
|
|
1162
|
+
await context.DatabaseProvider.CommitTransaction();
|
|
1098
1163
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1164
|
+
catch (error) {
|
|
1165
|
+
await context.DatabaseProvider.RollbackTransaction();
|
|
1166
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1167
|
+
return { Success: false, ErrorMessage: `Teardown failed for '${manifest.name}' (rolled back): ${message}` };
|
|
1101
1168
|
}
|
|
1169
|
+
context.Callbacks?.OnSuccess?.('Metadata', `Retired this app's rows from '${mjSchema}' (${files.length} teardown script(s)).`);
|
|
1170
|
+
return { Success: true };
|
|
1102
1171
|
}
|
|
1103
1172
|
async function DownloadAppMigrations(manifest, context, tempDir, subpath) {
|
|
1104
1173
|
const baseDir = manifest.migrations.directory;
|
|
@@ -1116,6 +1185,29 @@ async function DownloadAppMigrations(manifest, context, tempDir, subpath) {
|
|
|
1116
1185
|
}
|
|
1117
1186
|
return DownloadMigrations(manifest.repository, manifest.version, baseDir, tempDir, context.GitHubOptions, subpath, manifest.name);
|
|
1118
1187
|
}
|
|
1188
|
+
async function PreflightManifestPackages(manifest, context, packageVersion, versionStrategy) {
|
|
1189
|
+
if (!manifest.packages) {
|
|
1190
|
+
return { Success: true };
|
|
1191
|
+
}
|
|
1192
|
+
context.Callbacks?.OnProgress?.('Packages', 'Checking app packages against the npm registry...');
|
|
1193
|
+
const result = await PreflightAppPackages({
|
|
1194
|
+
RepoRoot: context.RepoRoot,
|
|
1195
|
+
ServerPackages: manifest.packages.server ?? [],
|
|
1196
|
+
ClientPackages: manifest.packages.client ?? [],
|
|
1197
|
+
SharedPackages: manifest.packages.shared ?? [],
|
|
1198
|
+
Version: packageVersion,
|
|
1199
|
+
PackageManager: context.PackageManager,
|
|
1200
|
+
VersionStrategy: versionStrategy,
|
|
1201
|
+
RegistryUrl: manifest.packages.registry,
|
|
1202
|
+
});
|
|
1203
|
+
if (result.SkippedReason) {
|
|
1204
|
+
context.Callbacks?.OnProgress?.('Packages', `Skipped the registry check: ${result.SkippedReason}.`);
|
|
1205
|
+
}
|
|
1206
|
+
for (const warning of result.Warnings) {
|
|
1207
|
+
context.Callbacks?.OnWarn?.('Packages', warning);
|
|
1208
|
+
}
|
|
1209
|
+
return result.Success ? { Success: true } : { Success: false, ErrorMessage: result.ErrorMessage };
|
|
1210
|
+
}
|
|
1119
1211
|
async function HandlePackageInstallation(manifest, context, packageVersion, versionStrategy, verbose) {
|
|
1120
1212
|
if (!manifest.packages) {
|
|
1121
1213
|
return { Success: true };
|