@arch-cadre/modules 0.0.49 → 0.0.50

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.
@@ -1,188 +1,238 @@
1
1
  "use server";
2
-
3
- import { getModuleInstance, getModules } from "./manage.mjs";
4
- import { db } from "@arch-cadre/core/server";
2
+ import { exec } from "node:child_process";
5
3
  import fs from "node:fs/promises";
6
4
  import path from "node:path";
5
+ import { promisify } from "node:util";
7
6
  import { systemModulesTable } from "@arch-cadre/core";
7
+ import { db } from "@arch-cadre/core/server";
8
8
  import { eq } from "drizzle-orm";
9
- import { exec } from "node:child_process";
10
- import { promisify } from "node:util";
11
-
12
- //#region src/server/lifecycle.ts
9
+ import { getModuleInstance, getModules } from "./manage.js";
13
10
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
14
11
  async function updateStep(moduleId, step) {
15
- console.log(`[Kernel] "${moduleId}" step: ${step}`);
16
- await db.update(systemModulesTable).set({ lastStep: step }).where(eq(systemModulesTable.id, moduleId));
12
+ console.log(`[Kernel] "${moduleId}" step: ${step}`);
13
+ await db.update(systemModulesTable).set({ lastStep: step }).where(eq(systemModulesTable.id, moduleId));
17
14
  }
18
15
  async function resolveSchemaPath(moduleId) {
19
- const root = process.cwd();
20
- if (moduleId === "@arch-cadre/core" || moduleId === "core") {
21
- const p = path.join(root, "node_modules", "@kryo", "core", "dist", "server", "database", "schema.cjs");
22
- try {
23
- await fs.access(p);
24
- return p;
25
- } catch {
26
- const devP = path.resolve(root, "../../packages/kryo-core/src/server/database/schema.ts");
27
- try {
28
- await fs.access(devP);
29
- return devP;
30
- } catch {}
31
- }
32
- return null;
33
- }
34
- const cleanId = moduleId.replace("@arch-cadre/", "");
35
- const possible = [
36
- path.join(root, "modules", cleanId, "schema.ts"),
37
- path.join(root, "modules", moduleId, "schema.ts"),
38
- path.join(root, "node_modules", moduleId, "dist", "schema.cjs"),
39
- path.join(root, "node_modules", `@arch-cadre/${cleanId}`, "dist", "schema.cjs"),
40
- path.join(root, "node_modules", moduleId, "src", "schema.ts"),
41
- path.join(root, "node_modules", `@arch-cadre/${cleanId}`, "src", "schema.ts"),
42
- path.resolve(root, "../../packages", cleanId, "src", "schema.ts"),
43
- path.resolve(root, "../../packages", `kryo-${cleanId}`, "src", "schema.ts"),
44
- path.resolve(root, "../../packages", cleanId, "schema.ts")
45
- ];
46
- for (const p of possible) try {
47
- await fs.access(p);
48
- console.log(`[Kernel:Lifecycle] Resolved schema for ${moduleId} at: ${p}`);
49
- return p;
50
- } catch {
51
- console.warn(`[Kernel:Lifecycle] Unresolved schema for ${moduleId} at: ${p}`);
52
- }
53
- console.warn(`[Kernel:Lifecycle] Could not resolve schema path for: ${moduleId}`);
54
- return null;
16
+ const root = process.cwd();
17
+ if (moduleId === "@arch-cadre/core" || moduleId === "core") {
18
+ const p = path.join(
19
+ root,
20
+ "node_modules",
21
+ "@kryo",
22
+ "core",
23
+ "dist",
24
+ "server",
25
+ "database",
26
+ "schema.cjs"
27
+ );
28
+ try {
29
+ await fs.access(p);
30
+ return p;
31
+ } catch {
32
+ const devP = path.resolve(
33
+ root,
34
+ "../../packages/kryo-core/src/server/database/schema.ts"
35
+ );
36
+ try {
37
+ await fs.access(devP);
38
+ return devP;
39
+ } catch {
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ const cleanId = moduleId.replace("@arch-cadre/", "");
45
+ const possible = [
46
+ // Local module
47
+ path.join(root, "modules", cleanId, "schema.ts"),
48
+ path.join(root, "modules", moduleId, "schema.ts"),
49
+ // node_modules (installed or symlinked)
50
+ path.join(root, "node_modules", moduleId, "dist", "schema.cjs"),
51
+ path.join(
52
+ root,
53
+ "node_modules",
54
+ `@arch-cadre/${cleanId}`,
55
+ "dist",
56
+ "schema.cjs"
57
+ ),
58
+ path.join(root, "node_modules", moduleId, "src", "schema.ts"),
59
+ path.join(
60
+ root,
61
+ "node_modules",
62
+ `@arch-cadre/${cleanId}`,
63
+ "src",
64
+ "schema.ts"
65
+ ),
66
+ // Monorepo packages (searching by various naming conventions)
67
+ path.resolve(root, "../../packages", cleanId, "src", "schema.ts"),
68
+ path.resolve(root, "../../packages", `kryo-${cleanId}`, "src", "schema.ts"),
69
+ path.resolve(root, "../../packages", cleanId, "schema.ts")
70
+ ];
71
+ for (const p of possible) {
72
+ try {
73
+ await fs.access(p);
74
+ console.log(
75
+ `[Kernel:Lifecycle] Resolved schema for ${moduleId} at: ${p}`
76
+ );
77
+ return p;
78
+ } catch {
79
+ console.warn(
80
+ `[Kernel:Lifecycle] Unresolved schema for ${moduleId} at: ${p}`
81
+ );
82
+ }
83
+ }
84
+ console.warn(
85
+ `[Kernel:Lifecycle] Could not resolve schema path for: ${moduleId}`
86
+ );
87
+ return null;
55
88
  }
56
- async function pushModuleSchema(moduleId) {
57
- const execAsync = promisify(exec);
58
- console.log(`[Kernel:Lifecycle] Targeted sync for module: ${moduleId}`);
59
- const root = process.cwd();
60
- const enabledFromDb = await db.select({ id: systemModulesTable.id }).from(systemModulesTable).where(eq(systemModulesTable.enabled, true));
61
- const activeModuleIds = new Set(enabledFromDb.map((m) => m.id));
62
- activeModuleIds.add("@arch-cadre/core");
63
- activeModuleIds.add(moduleId);
64
- const schemaPaths = [];
65
- for (const id of Array.from(activeModuleIds)) {
66
- const p = await resolveSchemaPath(id);
67
- if (p) schemaPaths.push(p);
68
- }
69
- if (schemaPaths.length === 0) {
70
- console.warn(`[Kernel:Lifecycle] No schema paths resolved for ${moduleId}, skipping push.`);
71
- return;
72
- }
73
- const configPath = path.join(root, "drizzle.config.ts");
74
- const cmd = `"${path.join(root, "node_modules", ".bin", "drizzle-kit")}" push --force --config=${configPath}`;
75
- console.log(`[Kernel:Lifecycle] Executing isolated migration. Modules: ${Array.from(activeModuleIds).join(", ")}`);
76
- try {
77
- await execAsync(cmd, {
78
- env: {
79
- ...process.env,
80
- CI: "true",
81
- DRIZZLE_SCHEMA_OVERRIDE: schemaPaths.join(",")
82
- },
83
- cwd: root
84
- });
85
- console.log(`[Kernel:Lifecycle] Isolated migration successful for ${moduleId}`);
86
- } catch (e) {
87
- console.error(`[Kernel:Lifecycle] Isolated migration failed for ${moduleId}:`);
88
- console.error(e.stdout || e.message);
89
- throw new Error(`Migration failed: ${moduleId}`);
90
- }
89
+ export async function pushModuleSchema(moduleId) {
90
+ const execAsync = promisify(exec);
91
+ console.log(`[Kernel:Lifecycle] Targeted sync for module: ${moduleId}`);
92
+ const root = process.cwd();
93
+ const enabledFromDb = await db.select({ id: systemModulesTable.id }).from(systemModulesTable).where(eq(systemModulesTable.enabled, true));
94
+ const activeModuleIds = new Set(enabledFromDb.map((m) => m.id));
95
+ activeModuleIds.add("@arch-cadre/core");
96
+ activeModuleIds.add(moduleId);
97
+ const schemaPaths = [];
98
+ for (const id of Array.from(activeModuleIds)) {
99
+ const p = await resolveSchemaPath(id);
100
+ if (p) schemaPaths.push(p);
101
+ }
102
+ if (schemaPaths.length === 0) {
103
+ console.warn(
104
+ `[Kernel:Lifecycle] No schema paths resolved for ${moduleId}, skipping push.`
105
+ );
106
+ return;
107
+ }
108
+ const configPath = path.join(root, "drizzle.config.ts");
109
+ const drizzleKitBin = path.join(root, "node_modules", ".bin", "drizzle-kit");
110
+ const cmd = `"${drizzleKitBin}" push --force --config=${configPath}`;
111
+ console.log(
112
+ `[Kernel:Lifecycle] Executing isolated migration. Modules: ${Array.from(activeModuleIds).join(", ")}`
113
+ );
114
+ try {
115
+ await execAsync(cmd, {
116
+ env: {
117
+ ...process.env,
118
+ CI: "true",
119
+ // Pass the calculated schemas to our dynamic drizzle.config.ts
120
+ DRIZZLE_SCHEMA_OVERRIDE: schemaPaths.join(",")
121
+ },
122
+ cwd: root
123
+ });
124
+ console.log(
125
+ `[Kernel:Lifecycle] Isolated migration successful for ${moduleId}`
126
+ );
127
+ } catch (e) {
128
+ console.error(
129
+ `[Kernel:Lifecycle] Isolated migration failed for ${moduleId}:`
130
+ );
131
+ console.error(e.stdout || e.message);
132
+ throw new Error(`Migration failed: ${moduleId}`);
133
+ }
91
134
  }
92
135
  async function performToggle(moduleId, isEnabled) {
93
- try {
94
- const allModules = await getModules();
95
- const manifest = allModules.find((m) => m.id === moduleId);
96
- await updateStep(moduleId, "Validate module...");
97
- await sleep(500);
98
- if (!manifest) return;
99
- if (isEnabled) {
100
- await updateStep(moduleId, "Queued...");
101
- await sleep(500);
102
- if (manifest.dependencies?.length) {
103
- const pendingDeps = manifest.dependencies.filter((depId) => {
104
- const dep = allModules.find((m) => m.id === depId);
105
- return dep && !dep.enabled && !dep.system;
106
- });
107
- if (pendingDeps.length > 0) for (const depId of pendingDeps) {
108
- await updateStep(moduleId, `Waiting for dependency "${depId}"...`);
109
- await performToggle(depId, true);
110
- await sleep(500);
111
- }
112
- }
113
- await updateStep(moduleId, "Initializing...");
114
- await sleep(500);
115
- await db.update(systemModulesTable).set({ enabled: true }).where(eq(systemModulesTable.id, moduleId));
116
- const instance = await getModuleInstance(moduleId);
117
- await updateStep(moduleId, "Migrate database...");
118
- await sleep(500);
119
- try {
120
- if (instance?.onMigrate) await instance.onMigrate();
121
- else await pushModuleSchema(moduleId);
122
- await updateStep(moduleId, "Migration successful");
123
- } catch (e) {
124
- console.error(`[Kernel] Migration failed for ${moduleId}:`, e);
125
- await updateStep(moduleId, `Migration failed: ${e.message}`);
126
- await sleep(500);
127
- }
128
- if (instance?.onEnable) {
129
- await updateStep(moduleId, "Running setup...");
130
- await sleep(500);
131
- await instance.onEnable();
132
- }
133
- await updateStep(moduleId, "Finishing...");
134
- await sleep(500);
135
- await db.update(systemModulesTable).set({
136
- installed: true,
137
- lastStep: null
138
- }).where(eq(systemModulesTable.id, moduleId));
139
- } else {
140
- const dependents = allModules.filter((m) => {
141
- if (!m.enabled || m.id === moduleId) return false;
142
- if (m.dependencies?.includes(moduleId)) return true;
143
- if (m.extends?.includes(moduleId)) return m.extends.filter((targetId) => {
144
- if (targetId === moduleId) return false;
145
- return allModules.find((mod) => mod.id === targetId)?.enabled;
146
- }).length === 0;
147
- return false;
148
- });
149
- if (dependents.length > 0) {
150
- await updateStep(moduleId, `Deactivating dependents...`);
151
- for (const dep of dependents) {
152
- await performToggle(dep.id, false);
153
- await sleep(500);
154
- }
155
- }
156
- await updateStep(moduleId, "Deactivating...");
157
- const instance = await getModuleInstance(moduleId);
158
- if (instance?.onDisable) await instance.onDisable();
159
- await db.update(systemModulesTable).set({
160
- enabled: false,
161
- installed: false
162
- }).where(eq(systemModulesTable.id, moduleId));
163
- await updateStep(moduleId, null);
164
- }
165
- } catch (e) {
166
- console.error(`[Kernel] Fatal error for ${moduleId}:`, e);
167
- await updateStep(moduleId, `Error: ${e.message}`);
168
- }
136
+ try {
137
+ const allModules = await getModules();
138
+ const manifest = allModules.find((m) => m.id === moduleId);
139
+ await updateStep(moduleId, "Validate module...");
140
+ await sleep(500);
141
+ if (!manifest) return;
142
+ if (isEnabled) {
143
+ await updateStep(moduleId, "Queued...");
144
+ await sleep(500);
145
+ if (manifest.dependencies?.length) {
146
+ const pendingDeps = manifest.dependencies.filter((depId) => {
147
+ const dep = allModules.find((m) => m.id === depId);
148
+ return dep && !dep.enabled && !dep.system;
149
+ });
150
+ if (pendingDeps.length > 0) {
151
+ for (const depId of pendingDeps) {
152
+ await updateStep(moduleId, `Waiting for dependency "${depId}"...`);
153
+ await performToggle(depId, true);
154
+ await sleep(500);
155
+ }
156
+ }
157
+ }
158
+ await updateStep(moduleId, "Initializing...");
159
+ await sleep(500);
160
+ await db.update(systemModulesTable).set({ enabled: true }).where(eq(systemModulesTable.id, moduleId));
161
+ const instance = await getModuleInstance(moduleId);
162
+ await updateStep(moduleId, "Migrate database...");
163
+ await sleep(500);
164
+ try {
165
+ if (instance?.onMigrate) {
166
+ await instance.onMigrate();
167
+ } else {
168
+ await pushModuleSchema(moduleId);
169
+ }
170
+ await updateStep(moduleId, "Migration successful");
171
+ } catch (e) {
172
+ console.error(`[Kernel] Migration failed for ${moduleId}:`, e);
173
+ await updateStep(moduleId, `Migration failed: ${e.message}`);
174
+ await sleep(500);
175
+ }
176
+ if (instance?.onEnable) {
177
+ await updateStep(moduleId, "Running setup...");
178
+ await sleep(500);
179
+ await instance.onEnable();
180
+ }
181
+ await updateStep(moduleId, "Finishing...");
182
+ await sleep(500);
183
+ await db.update(systemModulesTable).set({ installed: true, lastStep: null }).where(eq(systemModulesTable.id, moduleId));
184
+ } else {
185
+ const dependents = allModules.filter((m) => {
186
+ if (!m.enabled || m.id === moduleId) return false;
187
+ if (m.dependencies?.includes(moduleId)) return true;
188
+ if (m.extends?.includes(moduleId)) {
189
+ const otherActiveTargets = m.extends.filter((targetId) => {
190
+ if (targetId === moduleId) return false;
191
+ const target = allModules.find((mod) => mod.id === targetId);
192
+ return target?.enabled;
193
+ });
194
+ return otherActiveTargets.length === 0;
195
+ }
196
+ return false;
197
+ });
198
+ if (dependents.length > 0) {
199
+ await updateStep(moduleId, `Deactivating dependents...`);
200
+ for (const dep of dependents) {
201
+ await performToggle(dep.id, false);
202
+ await sleep(500);
203
+ }
204
+ }
205
+ await updateStep(moduleId, "Deactivating...");
206
+ const instance = await getModuleInstance(moduleId);
207
+ if (instance?.onDisable) await instance.onDisable();
208
+ await db.update(systemModulesTable).set({ enabled: false, installed: false }).where(eq(systemModulesTable.id, moduleId));
209
+ await updateStep(moduleId, null);
210
+ }
211
+ } catch (e) {
212
+ console.error(`[Kernel] Fatal error for ${moduleId}:`, e);
213
+ await updateStep(moduleId, `Error: ${e.message}`);
214
+ }
169
215
  }
170
- async function toggleModuleState(moduleId, isEnabled) {
171
- const manifest = (await getModules()).find((m) => m.id === moduleId);
172
- if (!manifest) throw new Error(`Module "${moduleId}" not found`);
173
- if (manifest.enabled === isEnabled) return { success: true };
174
- performToggle(moduleId, isEnabled);
175
- return { success: true };
216
+ export async function toggleModuleState(moduleId, isEnabled) {
217
+ const allModules = await getModules();
218
+ const manifest = allModules.find((m) => m.id === moduleId);
219
+ if (!manifest) throw new Error(`Module "${moduleId}" not found`);
220
+ if (manifest.enabled === isEnabled) return { success: true };
221
+ void performToggle(moduleId, isEnabled);
222
+ return { success: true };
176
223
  }
177
- async function initOperationalModules() {
178
- const allModules = await getModules();
179
- for (const mod of allModules) if (mod.enabled) try {
180
- const instance = await getModuleInstance(mod.id);
181
- if (instance?.init) await instance.init();
182
- } catch (e) {
183
- console.error(`[Kernel] Failed to init module ${mod.id}:`, e);
184
- }
224
+ export async function initOperationalModules() {
225
+ const allModules = await getModules();
226
+ for (const mod of allModules) {
227
+ if (mod.enabled) {
228
+ try {
229
+ const instance = await getModuleInstance(mod.id);
230
+ if (instance?.init) {
231
+ await instance.init();
232
+ }
233
+ } catch (e) {
234
+ console.error(`[Kernel] Failed to init module ${mod.id}:`, e);
235
+ }
236
+ }
237
+ }
185
238
  }
186
-
187
- //#endregion
188
- export { initOperationalModules, pushModuleSchema, toggleModuleState };