@feltdb/core 0.11.0 → 0.11.2

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.
@@ -9,7 +9,7 @@ import { createRequire } from 'node:module';
9
9
  import { spawn, spawnSync } from 'child_process';
10
10
  import { randomBytes } from 'crypto';
11
11
  import { createInterface } from 'node:readline/promises';
12
- import { createFeltDB, diffFlowSpec, formatFlowSpec, InvestigationLifecycleManager, listFeltDBModules, parseFlowSpec, planFlowSpecMigration, renderConvergenceDiagnostic, renderProposalDiagnostic, resolveFeltDBModule, resolveModuleIntent, startLocalDevelopmentAuthority, validateFlowSpec, verifyProposalConvergence } from '@feltdb/core';
12
+ import { createFeltDB, diffFlowSpec, emptyFlowSpec, formatFlowSpec, InvestigationLifecycleManager, listFeltDBModules, parseFlowSpec, planFlowSpecMigration, renderConvergenceDiagnostic, renderProposalDiagnostic, resolveFeltDBModule, resolveModuleIntent, startLocalDevelopmentAuthority, validateFlowSpec, verifyProposalConvergence } from '@feltdb/core';
13
13
  import { collectApplicationUnderstanding } from '@feltdb/core';
14
14
  import { collectRepositoryEvidence } from './repository-evidence.js';
15
15
  import { discoverWorkspace, ensureWorkspaceGitIgnored, generatePairingToken, persistPairingToken, displayWorkspaceStatus, initializeWorkspace, startPairingDiscoveryServer } from './workspace-integration.js';
@@ -902,9 +902,40 @@ async function promptSecret(message) {
902
902
  input.on('keypress', onKeypress);
903
903
  });
904
904
  }
905
+ export function ensureManagedProjectContract(projectDir) {
906
+ const projectName = path.basename(projectDir);
907
+ const flowApp = projectName.replace(/[^A-Za-z0-9_]/g, '_').replace(/^[^A-Za-z_]/, '_$&');
908
+ const configPath = path.join(projectDir, 'feltdb.config.json');
909
+ const flowPath = path.join(projectDir, 'feltdb.flow');
910
+ const created = { config: false, flow: false };
911
+ if (!fs.existsSync(configPath)) {
912
+ fs.writeFileSync(configPath, `${JSON.stringify({
913
+ namespace: projectName,
914
+ mode: 'remote',
915
+ runtime: 'managed',
916
+ storage: 'managed',
917
+ application: { lifecycle: 'managed' },
918
+ }, null, 2)}\n`);
919
+ created.config = true;
920
+ }
921
+ if (!fs.existsSync(flowPath)) {
922
+ const draft = formatFlowSpec(emptyFlowSpec(flowApp)).replace(/\n\napp /, '\n\n// Recovery draft: define the application contract before publishing.\napp ');
923
+ fs.writeFileSync(flowPath, draft);
924
+ created.flow = true;
925
+ }
926
+ return { ...created, configPath, flowPath };
927
+ }
905
928
  async function handleInitManaged(args) {
906
929
  loadProjectEnvironment();
907
930
  const projectDir = process.cwd();
931
+ const initialized = ensureManagedProjectContract(projectDir);
932
+ if (initialized.config)
933
+ console.log('✓ Created feltdb.config.json');
934
+ if (initialized.flow) {
935
+ console.log('⚠️ feltdb.flow was missing; created an empty recovery draft.');
936
+ console.log(' FeltDB cannot infer the application authority from source code.');
937
+ console.log(' Review and complete feltdb.flow before publishing.\n');
938
+ }
908
939
  // Check if already managed
909
940
  const managedState = readManagedProjectState(projectDir);
910
941
  if (managedState.applicationId) {
@@ -915,7 +946,33 @@ async function handleInitManaged(args) {
915
946
  if (managedState.revisionId) {
916
947
  console.log(`Revision: ${managedState.revisionId}`);
917
948
  }
918
- console.log('\nTo update credentials, manually edit .env.local and .feltdb/managed.json\n');
949
+ if (initialized.flow) {
950
+ console.log('\nAutomatic publication is blocked because feltdb.flow is a recovery draft.');
951
+ console.log('Review feltdb.flow, then run:');
952
+ console.log(' feltdb validate');
953
+ console.log(' feltdb publish --approve-destructive-changes --yes\n');
954
+ return;
955
+ }
956
+ const publishExisting = args.includes('--publish') || args.includes('--yes');
957
+ if (!publishExisting) {
958
+ console.log('\nThe existing application can be repaired in place without changing its identity or credentials.');
959
+ console.log('Run the explicit repair path:');
960
+ console.log(' feltdb init-managed --publish --yes\n');
961
+ return;
962
+ }
963
+ console.log('\n🔨 Validating and publishing the authoritative feltdb.flow...\n');
964
+ const result = await publishApplication({
965
+ cwd: projectDir,
966
+ yes: true,
967
+ approveDestructive: true,
968
+ });
969
+ if (result.status === 'published') {
970
+ const finalized = await finalizeManagedProvisioning({ projectDir });
971
+ console.log(`✓ Existing managed application repaired at revision ${finalized.revisionId}\n`);
972
+ }
973
+ else {
974
+ console.log('✓ Existing managed application already has this active contract.\n');
975
+ }
919
976
  return;
920
977
  }
921
978
  // Prompt for credentials
@@ -930,9 +987,7 @@ async function handleInitManaged(args) {
930
987
  prompt.close();
931
988
  console.log('\nProvisioning managed account...\n');
932
989
  try {
933
- const projectConfig = fs.existsSync(path.join(projectDir, 'feltdb.config.json'))
934
- ? JSON.parse(fs.readFileSync(path.join(projectDir, 'feltdb.config.json'), 'utf8'))
935
- : {};
990
+ const projectConfig = JSON.parse(fs.readFileSync(initialized.configPath, 'utf8'));
936
991
  const namespace = projectConfig.namespace || path.basename(projectDir);
937
992
  const applicationName = projectConfig.name || path.basename(projectDir);
938
993
  const managed = await configureManagedAccount({
@@ -945,22 +1000,24 @@ async function handleInitManaged(args) {
945
1000
  console.log(`✓ Managed application: ${managed.application.name}`);
946
1001
  console.log(`✓ Namespace: ${managed.application.namespace || namespace}`);
947
1002
  console.log(`✓ Environment configured in .env.local\n`);
1003
+ if (initialized.flow) {
1004
+ console.log('✅ Managed connection setup complete.');
1005
+ console.log('Automatic publication was skipped because feltdb.flow had to be recovered.');
1006
+ console.log('Review feltdb.flow, then run:');
1007
+ console.log(' feltdb validate');
1008
+ console.log(' feltdb publish --approve-destructive-changes --yes\n');
1009
+ return;
1010
+ }
948
1011
  // Ask if user wants to publish the initial revision
949
1012
  const publishPrompt = await import('node:readline/promises').then(m => m.createInterface({ input: process.stdin, output: process.stdout }));
950
1013
  const shouldPublish = await publishPrompt.question('Publish initial application revision now? [Y/n] ');
951
1014
  publishPrompt.close();
952
1015
  if (!/^(n|no)$/i.test(shouldPublish.trim())) {
953
1016
  console.log('\n🔨 Building and publishing initial revision...\n');
954
- const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
955
- // Run publish
956
- await new Promise((resolve, reject) => {
957
- const child = spawn(npm, ['run', 'feltdb:publish'], {
958
- cwd: projectDir,
959
- stdio: 'inherit',
960
- env: process.env,
961
- });
962
- child.once('error', reject);
963
- child.once('exit', code => code === 0 ? resolve() : reject(new Error(`feltdb publish exited with status ${code ?? 'unknown'}`)));
1017
+ await publishApplication({
1018
+ cwd: projectDir,
1019
+ yes: true,
1020
+ approveDestructive: true,
964
1021
  });
965
1022
  console.log('\n✓ Initial revision published\n');
966
1023
  // Finalize and verify
@@ -976,7 +1033,7 @@ async function handleInitManaged(args) {
976
1033
  else {
977
1034
  console.log('\n✅ Managed setup complete!\n');
978
1035
  console.log('Next steps:');
979
- console.log(' 1. npm run feltdb:publish (to publish your initial revision)');
1036
+ console.log(' 1. feltdb publish --approve-destructive-changes --yes (to publish your initial revision)');
980
1037
  console.log(' 2. npm run dev (to start development)\n');
981
1038
  }
982
1039
  }
@@ -1,4 +1,4 @@
1
1
  // One release train keeps generated applications installable. The repository
2
2
  // validation script checks these values against every workspace manifest.
3
- export const FELTDB_PACKAGE_VERSION = '0.11.0';
3
+ export const FELTDB_PACKAGE_VERSION = '0.11.2';
4
4
  export const feltdbPackageRange = `^${FELTDB_PACKAGE_VERSION}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feltdb/core",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "FeltDB Core - Application-facing database with Browser, Local, and Server runtimes. Durable state, reactive APIs.",
5
5
  "license": "MIT",
6
6
  "type": "module",