@aopslabs/aops 0.3.1 → 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.
@@ -13,7 +13,7 @@ import { resolveCommunityOfflineRelease, resolveCommunityPublishedRelease, } fro
13
13
  import { inspectCommunityDoctor } from './community-doctor.js';
14
14
  import { buildCommunityInstanceContract, } from '../lib/community-instance-contract.js';
15
15
  import { asCommunityDiagnosticError } from '../lib/community-diagnostic.js';
16
- import { assertCommunityNativePathLayout, attestCommunityNativeExternalSnapshot, inspectCommunityNativeInstall, inspectCommunityNativeRuntime, loadExternalPostgresUrl, loadExternalServerAuthConfig, planCommunityNativeInstalledMigration, readCommunityNativeLogs, rollbackCommunityNativeApplication, resolveCommunityNativeLaunchMode, resolveCommunityNativePaths, setupCommunityNativeInstall, startCommunityNativeInstall, stopCommunityNativeInstall, } from '../lib/community-native-lifecycle.js';
16
+ import { assertCommunityNativePathLayout, attestCommunityNativeExternalSnapshot, inspectCommunityNativeInstall, inspectCommunityNativeRuntime, loadExternalPostgresUrl, loadExternalServerAuthConfig, planCommunityNativeInstalledMigration, readCommunityNativeLogs, rollbackCommunityNativeApplication, resolveCommunityNativeInstalledNpmSourceRoot, resolveCommunityNativeLaunchMode, resolveCommunityNativePaths, setupCommunityNativeInstall, startCommunityNativeInstall, stopCommunityNativeInstall, } from '../lib/community-native-lifecycle.js';
17
17
  import { inspectCommunityNativeApplicationRecoveryStatus } from '../lib/community-native-application-recovery.js';
18
18
  import { inspectCommunityNativeDatabaseRecoveryStatus, restoreCommunityNativeDatabaseForUpdate, } from '../lib/community-native-database-recovery.js';
19
19
  import { inspectCommunityNativePostgres, removeCommunityNativePostgresContainerForReset, removeCommunityNativeManagedPostgres, } from '../lib/community-native-postgres.js';
@@ -214,6 +214,8 @@ function resolveDependencies(dependencies = {}) {
214
214
  planNativeMigration: dependencies.planNativeMigration ?? planCommunityNativeInstalledMigration,
215
215
  attestNativeExternalSnapshot: dependencies.attestNativeExternalSnapshot ?? attestCommunityNativeExternalSnapshot,
216
216
  setupNativeInstall: dependencies.setupNativeInstall ?? setupCommunityNativeInstall,
217
+ startNativeInstall: dependencies.startNativeInstall ?? startCommunityNativeInstall,
218
+ resolveNativeInstalledNpmSourceRoot: dependencies.resolveNativeInstalledNpmSourceRoot ?? resolveCommunityNativeInstalledNpmSourceRoot,
217
219
  rollbackNativeApplication: dependencies.rollbackNativeApplication ?? rollbackCommunityNativeApplication,
218
220
  restoreNativeDatabase: dependencies.restoreNativeDatabase ?? restoreCommunityNativeDatabaseForUpdate,
219
221
  stopNativeCockpit: dependencies.stopNativeCockpit ?? stopCommunityNativeCockpit,
@@ -764,8 +766,9 @@ export async function runCommunityServerStart(options, dependencies = {}) {
764
766
  await withMutatingCommandScope(dependencies, async (runtime, signal) => {
765
767
  const native = inspectNativeFrom(options);
766
768
  if (native.status === 'installed') {
767
- const launch = await withNativeOperation(options, 'start', runtime, signal, () => startCommunityNativeInstall({
769
+ const launch = await withNativeOperation(options, 'start', runtime, signal, () => runtime.startNativeInstall({
768
770
  ...installSelection(options),
771
+ adoptSourceRoot: runtime.resolveNativeInstalledNpmSourceRoot(),
769
772
  mode: resolveCommunityNativeLaunchMode(options),
770
773
  signal,
771
774
  }));
@@ -66,7 +66,7 @@ function guidance(code) {
66
66
  return {
67
67
  summary: 'The installed npm server package no longer matches the source or build fingerprint AOPS previously verified.',
68
68
  nextActions: Object.freeze([
69
- 'Reinstall the matching public `@aopslabs/aops` and `@aopslabs/aops-server` packages separately.',
69
+ 'Reinstall the public `@aopslabs/aops` package so npm restores its exact Server dependency.',
70
70
  'Re-run `aops setup init` for the selected path after the verified package bytes have been restored.',
71
71
  ]),
72
72
  };
@@ -7,7 +7,8 @@ import { fileURLToPath } from 'node:url';
7
7
  import { parseEnv } from 'node:util';
8
8
  import { COMMUNITY_NATIVE_CHILD_PROTOCOL, COMMUNITY_NATIVE_CONTROL_PROTOCOL, } from './community-native-child.js';
9
9
  import { resolveCommunityInstallPaths } from './community-lifecycle.js';
10
- import { COMMUNITY_NATIVE_POSTGRES_CONTRACT_PATH, assertCommunityNativePostgresInstanceState, assertCommunityNativePostgresState, buildCommunityNativePostgresUrl, setupCommunityNativePostgres, startCommunityNativePostgres, stopCommunityNativePostgres, } from './community-native-postgres.js';
10
+ import { buildCommunityInstanceContract, } from './community-instance-contract.js';
11
+ import { COMMUNITY_NATIVE_POSTGRES_CONTRACT_PATH, assertCommunityNativePostgresInstanceState, assertCommunityNativePostgresState, buildCommunityNativePostgresUrl, setupCommunityNativePostgres, startCommunityNativePostgres, } from './community-native-postgres.js';
11
12
  import { COMMUNITY_NATIVE_MIGRATION_POLICY_PATH, assertCommunityNativeMigrationReceiptV1, planCommunityNativeMigration, runCommunityNativeMigration, } from './community-native-migration.js';
12
13
  import { createCommunityExternalSnapshotAttestationV1, writeCommunityExternalSnapshotAttestationV1, } from './community-migration-snapshot.js';
13
14
  import { createCommunityNativeApplicationReferenceV1, readCommunityNativeApplicationUpdate, sameCommunityNativeApplicationContent, writeCommunityNativeApplicationRollbackOutcome, writeCommunityNativeApplicationRollbackPrepared, writeCommunityNativeApplicationUpdateOutcome, writeCommunityNativeApplicationUpdatePrepared, } from './community-native-application-recovery.js';
@@ -660,20 +661,29 @@ function sourceLayout(root, manifest = sourcePackage(root)) {
660
661
  function isPackagedCommunityServerSource(source) {
661
662
  return sourceLayout(source.root).kind === 'npm-package';
662
663
  }
664
+ function isPersistedPackagedCommunityServerState(state) {
665
+ return samePhysicalPath(state.build.hostEntry, path.join(state.source.root, PACKAGE_BUILD_PATHS.hostEntry)) &&
666
+ samePhysicalPath(state.build.handlerEntry, path.join(state.source.root, PACKAGE_BUILD_PATHS.handlerEntry)) &&
667
+ samePhysicalPath(state.build.cockpitIndex, path.join(state.source.root, PACKAGE_BUILD_PATHS.cockpitIndex));
668
+ }
663
669
  export function isCommunityNativeNpmPackageSource(sourceRoot) {
664
670
  const resolved = path.resolve(sourceRoot);
665
671
  return sourceLayout(realpathSync(resolved)).kind === 'npm-package';
666
672
  }
667
673
  export function resolveCommunityNativeDefaultSourceRoot(fallbackRoot = process.cwd(), moduleUrl = import.meta.url) {
674
+ return resolveCommunityNativeInstalledNpmSourceRoot(moduleUrl) ?? path.resolve(fallbackRoot);
675
+ }
676
+ export function resolveCommunityNativeInstalledNpmSourceRoot(moduleUrl = import.meta.url) {
668
677
  try {
669
678
  const require = createRequire(moduleUrl);
670
679
  const packageJsonPath = require.resolve(`${PUBLIC_SERVER_PACKAGE_NAME}/package.json`);
671
680
  const packageRoot = path.dirname(packageJsonPath);
672
- sourceLayout(packageRoot);
681
+ if (sourceLayout(packageRoot).kind !== 'npm-package')
682
+ return null;
673
683
  return packageRoot;
674
684
  }
675
685
  catch {
676
- return path.resolve(fallbackRoot);
686
+ return null;
677
687
  }
678
688
  }
679
689
  export function inspectCommunityNativeSource(sourceRoot = process.cwd()) {
@@ -827,6 +837,12 @@ export function reconcileCommunityNativePriorApplication(params) {
827
837
  throw new Error('community_native_container_postgres_contract_required');
828
838
  }
829
839
  if (!samePhysicalPath(state.source.root, selectedSource.root)) {
840
+ if (sourceLayout(selectedSource.root).kind === 'npm-package') {
841
+ const comparison = compareCommunityReleaseVersions(selectedSource.releaseVersion, state.source.releaseVersion);
842
+ if (comparison < 0) {
843
+ throw new Error(`community_native_application_downgrade_refused:${state.source.releaseVersion}:to:${selectedSource.releaseVersion}`);
844
+ }
845
+ }
830
846
  return 'application-source-adopted';
831
847
  }
832
848
  try {
@@ -1620,15 +1636,6 @@ export async function stopCommunityNativeInstall(params = {}) {
1620
1636
  now,
1621
1637
  });
1622
1638
  if (observed.runtimeState === 'stopped' || observed.runtimeState === 'crashed') {
1623
- if (inspection.state.postgres.mode === 'container') {
1624
- await stopCommunityNativePostgres({
1625
- state: inspection.state.postgres,
1626
- instanceName: inspection.state.instanceName,
1627
- instanceRoot: inspection.paths.instanceRoot,
1628
- runtime: params.postgresRuntime,
1629
- signal: params.signal,
1630
- });
1631
- }
1632
1639
  return { status: 'already-stopped', state: inspection.state, process: observed.process };
1633
1640
  }
1634
1641
  if (!observed.process || !observed.identity || !observed.supervisorAlive ||
@@ -1654,15 +1661,6 @@ export async function stopCommunityNativeInstall(params = {}) {
1654
1661
  };
1655
1662
  delete stopped.failure;
1656
1663
  writeProcess(inspection.paths, stopped);
1657
- if (inspection.state.postgres.mode === 'container') {
1658
- await stopCommunityNativePostgres({
1659
- state: inspection.state.postgres,
1660
- instanceName: inspection.state.instanceName,
1661
- instanceRoot: inspection.paths.instanceRoot,
1662
- runtime: params.postgresRuntime,
1663
- signal: params.signal,
1664
- });
1665
- }
1666
1664
  return { status: 'stopped', state: inspection.state, process: stopped };
1667
1665
  }
1668
1666
  await runtime.sleep(READY_POLL_MS, params.signal);
@@ -2443,15 +2441,62 @@ export async function startCommunityNativeInstall(params) {
2443
2441
  if (inspection.status !== 'installed' || !inspection.state) {
2444
2442
  throw new Error(`community_native_not_installed:${inspection.status}:${inspection.error ?? 'run_server_setup'}`);
2445
2443
  }
2444
+ const runtime = params.runtime ?? communityNativeRuntime;
2445
+ const now = params.now ?? (() => new Date());
2446
+ const createId = params.createId ?? randomUUID;
2447
+ const mode = params.mode ?? 'detached';
2448
+ const readyTimeoutMs = params.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS;
2449
+ if (params.adoptSourceRoot
2450
+ && isPersistedPackagedCommunityServerState(inspection.state)
2451
+ && inspection.state.server.host === '127.0.0.1'
2452
+ && inspection.state.server.exposure === 'loopback'
2453
+ && inspection.state.server.authProvider === 'trusted-local') {
2454
+ const selectedSource = inspectCommunityNativeSource(params.adoptSourceRoot);
2455
+ const state = inspection.state;
2456
+ const contract = buildCommunityInstanceContract({
2457
+ runtime: 'native',
2458
+ postgres: state.postgres.mode,
2459
+ postgresConfig: state.postgres.mode === 'external' ? state.postgres.configRef : undefined,
2460
+ postgresTls: state.postgres.mode === 'external' ? state.postgres.tlsPolicy : undefined,
2461
+ exposure: state.server.exposure,
2462
+ auth: state.server.authProvider,
2463
+ publicPort: state.server.publicPort,
2464
+ instance: state.instanceName,
2465
+ port: state.server.port,
2466
+ processEnv: params.env,
2467
+ });
2468
+ const reconciliation = reconcileCommunityNativePriorApplication({
2469
+ state,
2470
+ selectedSource,
2471
+ contract,
2472
+ selectedExternalConfigRef: state.postgres.mode === 'external' ? state.postgres.configRef : undefined,
2473
+ });
2474
+ if (reconciliation === 'application-source-adopted') {
2475
+ const refreshed = await setupCommunityNativeInstall({
2476
+ contract,
2477
+ sourceRoot: selectedSource.root,
2478
+ dataRoot: params.dataRoot,
2479
+ mode,
2480
+ runtime,
2481
+ postgresRuntime: params.postgresRuntime,
2482
+ now,
2483
+ createId,
2484
+ readyTimeoutMs,
2485
+ env: params.env,
2486
+ signal: params.signal,
2487
+ });
2488
+ return refreshed.launch;
2489
+ }
2490
+ }
2446
2491
  return launchInstalledNative({
2447
2492
  paths: inspection.paths,
2448
2493
  state: inspection.state,
2449
- mode: params.mode ?? 'detached',
2450
- runtime: params.runtime ?? communityNativeRuntime,
2494
+ mode,
2495
+ runtime,
2451
2496
  postgresRuntime: params.postgresRuntime,
2452
- now: params.now ?? (() => new Date()),
2453
- createId: params.createId ?? randomUUID,
2454
- readyTimeoutMs: params.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,
2497
+ now,
2498
+ createId,
2499
+ readyTimeoutMs,
2455
2500
  env: params.env,
2456
2501
  signal: params.signal,
2457
2502
  });
@@ -302,8 +302,11 @@ async function verifyContainer(runtime, state, instanceName, signal, verifyPersi
302
302
  (hostPort !== null && (!Number.isSafeInteger(hostPort) || hostPort < 1 || hostPort > 65_535)) ||
303
303
  (verifyPersistedPort && hostPort !== null && hostPort !== state.port))
304
304
  throw new Error('community_native_postgres_container_port_binding_drift');
305
- if (verifyPersistedPort && await mappedPort(runtime, state, signal) !== state.port) {
306
- throw new Error('community_native_postgres_container_port_binding_drift');
305
+ if (verifyPersistedPort) {
306
+ const observed = await containerState(runtime, state.containerName, signal);
307
+ if (observed.status === 'running' && await mappedPort(runtime, state, signal) !== state.port) {
308
+ throw new Error('community_native_postgres_container_port_binding_drift');
309
+ }
307
310
  }
308
311
  const restartPolicy = await inspectContainerJson(runtime, state.containerName, '{{json .HostConfig.RestartPolicy}}', 'container_restart_policy_inspect', signal);
309
312
  if (!restartPolicy || typeof restartPolicy !== 'object' || Array.isArray(restartPolicy) ||
@@ -476,19 +479,6 @@ export async function startCommunityNativePostgres(params) {
476
479
  if (port !== state.port)
477
480
  throw new Error('community_native_postgres_port_mapping_drift:run_server_setup_--apply');
478
481
  }
479
- export async function stopCommunityNativePostgres(params) {
480
- throwIfCommunityCommandAborted(params.signal);
481
- const state = assertCommunityNativePostgresInstanceState(params);
482
- const runtime = params.runtime ?? communityNativePostgresRuntime;
483
- if (!await verifyContainer(runtime, state, params.instanceName, params.signal)) {
484
- throw new Error('community_native_postgres_container_missing');
485
- }
486
- const observed = await containerState(runtime, state.containerName, params.signal);
487
- if (observed.status === 'exited' || observed.status === 'created')
488
- return 'already-stopped';
489
- await runDocker(runtime, ['container', 'stop', '--time', '15', state.containerName], 'container_stop', params.signal);
490
- return 'stopped';
491
- }
492
482
  export async function removeCommunityNativePostgresContainer(params) {
493
483
  throwIfCommunityCommandAborted(params.signal);
494
484
  const state = assertCommunityNativePostgresInstanceState(params);
@@ -709,12 +709,12 @@ export async function inspectSetupReadiness(options = {}) {
709
709
  : 'Native source runtime requirements are available.'
710
710
  : needsDocker
711
711
  ? 'The installed npm server runtime (or an explicit source checkout) and a running Docker daemon are required.'
712
- : 'Install the matching @aopslabs/aops-server package separately, or provide a valid development checkout with pnpm 11.',
712
+ : 'Install or update @aopslabs/aops so its matching Server dependency is present, or provide a valid development checkout with pnpm 11.',
713
713
  next: runtimeReady
714
714
  ? undefined
715
715
  : needsDocker
716
716
  ? 'Install and start Docker Desktop/Engine, then retry the npm-server setup.'
717
- : 'Install the matching npm server package or provide a valid Community source checkout.',
717
+ : 'Install or update the @aopslabs/aops package, or provide a valid Community source checkout.',
718
718
  data: {
719
719
  node: process.version,
720
720
  sourceRoot: selectedSourceRoot,
Binary file
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@aopslabs/aops",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "type": "module",
5
5
  "description": "AOPS CLI and terminal setup application.",
6
- "aopsDockerServerVersion": "0.2.3",
6
+ "aopsDockerServerVersion": "0.2.5",
7
7
  "license": "SEE LICENSE IN LICENSE",
8
8
  "repository": {
9
9
  "type": "git",
@@ -46,7 +46,7 @@
46
46
  "test:target-transport": "node --test test/target-transport.test.mjs",
47
47
  "test:r6-cutover-baseline": "node scripts/verify-r6-cutover-baseline.mjs",
48
48
  "test:r6-auth-cutover": "node --test test/r6-auth-cutover.test.mjs",
49
- "test:container-runtime": "node --test test/container-runtime.test.mjs",
49
+ "test:container-runtime": "node --test test/container-runtime.test.mjs test/community-native-postgres.test.mjs",
50
50
  "test:kernel-alignment": "node --test test/kernel-alignment.test.mjs",
51
51
  "test:home": "node --test test/home-menu.test.mjs",
52
52
  "test:launchers": "node --test test/terminal-launchers.test.mjs",
@@ -55,10 +55,11 @@
55
55
  "start": "node dist/main.js"
56
56
  },
57
57
  "dependencies": {
58
+ "@aopslabs/aops-server": "0.2.5",
58
59
  "@aopslabs/artifact-trust-contracts": "0.3.0",
59
60
  "@aopslabs/cli-kit": "0.1.0",
60
61
  "@aopslabs/aops-host-registration": "0.2.0",
61
- "@aopslabs/aops-pg-bootstrap": "0.2.0",
62
+ "@aopslabs/aops-pg-bootstrap": "0.2.1",
62
63
  "@aopslabs/aops-runtime-config": "0.2.0",
63
64
  "@sigstore/bundle": "4.0.0",
64
65
  "@sigstore/protobuf-specs": "0.5.1",