@pasosdejesus/m 0.16.1 → 0.17.1

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/m.js CHANGED
@@ -28,6 +28,7 @@ import { cliTranslations } from './i18n/locales/cli.js';
28
28
  import { problem, success } from './util/colors.js';
29
29
  import { parseFlags } from './util/cli-parser.js';
30
30
  import { getPluginCommands } from './plugin.js';
31
+ import { loadExtensions } from './util/extensions.js';
31
32
  // Custom .env loading
32
33
  const CWD = process.cwd();
33
34
  const searchPaths = [
@@ -39,10 +40,52 @@ for (const p of searchPaths) {
39
40
  if (fs.existsSync(p))
40
41
  dotenv.config({ path: p, override: true, quiet: true });
41
42
  }
43
+ /**
44
+ * Auto-discover plugins from package.json.
45
+ * Looks for dependencies matching @pasosdejesus/m-* pattern
46
+ * and imports them (each plugin self-registers via registerCommands).
47
+ */
48
+ async function loadPlugins() {
49
+ const pkgPaths = [
50
+ path.join(CWD, 'package.json'),
51
+ path.join(CWD, '..', 'package.json'),
52
+ path.join(CWD, '..', '..', 'package.json'),
53
+ ];
54
+ let pkg = null;
55
+ for (const p of pkgPaths) {
56
+ if (fs.existsSync(p)) {
57
+ try {
58
+ pkg = JSON.parse(fs.readFileSync(p, 'utf-8'));
59
+ break;
60
+ }
61
+ catch { }
62
+ }
63
+ }
64
+ if (!pkg)
65
+ return;
66
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
67
+ for (const [name] of Object.entries(deps)) {
68
+ // Match @pasosdejesus/m-* plugins (e.g., @pasosdejesus/mpdj)
69
+ if (name.startsWith('@pasosdejesus/m') && name !== '@pasosdejesus/m') {
70
+ try {
71
+ await import(name);
72
+ }
73
+ catch {
74
+ // Plugin not installed or not a valid module — skip silently
75
+ }
76
+ }
77
+ // Also support packages with mEngine: true metadata
78
+ // This requires resolving the package.json of the dependency
79
+ }
80
+ }
42
81
  async function main() {
43
82
  const locale = detectLocale();
44
83
  setLocale(locale);
45
84
  const cliT = createTranslator(locale, cliTranslations, commonCli);
85
+ // Auto-discover plugins from package.json
86
+ await loadPlugins();
87
+ // Load m-extensions/ (project-specific hooks)
88
+ await loadExtensions();
46
89
  const commands = {
47
90
  'db:create': { handler: runDbCreate, description: cliT('cmd.db_create_description') },
48
91
  'db:drop': { handler: runDbDrop, description: cliT('cmd.db_drop_description') },
package/dist/plugin.d.ts CHANGED
@@ -7,4 +7,5 @@ export interface CommandDef {
7
7
  }
8
8
  export declare function registerCommands(commands: Record<string, CommandDef>): void;
9
9
  export declare function getPluginCommands(): Record<string, CommandDef>;
10
+ export { registerHook, runHooks } from './util/hooks.js';
10
11
  //# sourceMappingURL=plugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,IAAI,CAE3E;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAE9D"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,IAAI,CAE3E;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAE9D;AAGD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA"}
package/dist/plugin.js CHANGED
@@ -5,3 +5,5 @@ export function registerCommands(commands) {
5
5
  export function getPluginCommands() {
6
6
  return pluginCommands;
7
7
  }
8
+ // Re-export hooks API for m-extensions/
9
+ export { registerHook, runHooks } from './util/hooks.js';
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/tasks/db.ts"],"names":[],"mappings":"AAyNA,wBAAsB,WAAW,kBAUhC;AAED,wBAAsB,SAAS,kBAU9B;AAED,wBAAsB,oBAAoB,kBAyIzC;AAED,wBAAsB,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,iBAyDhD;AAED,wBAAsB,mBAAmB,kBAkBxC;AAkBD,wBAAsB,kBAAkB,kBAyCvC;AAED,wBAAsB,kBAAkB,kBAgCvC;AAED,wBAAsB,aAAa,kBAclC;AAED,wBAAsB,YAAY,kBAwCjC;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,iBA4B9C;AAED,wBAAsB,aAAa,kBAuBlC;AAED,wBAAsB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,iBA6B5C;AAED,wBAAsB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,iBAmD/C;AAED,wBAAsB,SAAS,kBAAoD;AAEnF;;GAEG;AACH,wBAAsB,UAAU,kBAsF/B"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/tasks/db.ts"],"names":[],"mappings":"AAyNA,wBAAsB,WAAW,kBAUhC;AAED,wBAAsB,SAAS,kBAU9B;AAED,wBAAsB,oBAAoB,kBAyJzC;AAED,wBAAsB,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,iBAyDhD;AAED,wBAAsB,mBAAmB,kBAkBxC;AAkBD,wBAAsB,kBAAkB,kBAyCvC;AAED,wBAAsB,kBAAkB,kBAgCvC;AAED,wBAAsB,aAAa,kBAclC;AAED,wBAAsB,YAAY,kBAwCjC;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,iBA4B9C;AAED,wBAAsB,aAAa,kBAuBlC;AAED,wBAAsB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,iBA6B5C;AAED,wBAAsB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,iBAmD/C;AAED,wBAAsB,SAAS,kBAAoD;AAEnF;;GAEG;AACH,wBAAsB,UAAU,kBAsF/B"}
package/dist/tasks/db.js CHANGED
@@ -254,6 +254,10 @@ export async function runDbSuperCreateUser() {
254
254
  // No modificar la siguiente línea fruto de larga experimentación.
255
255
  const alterCmdForOpenBSD = `psql ${psqlSuperArgs} -d postgres -c \\\"ALTER USER ${user} WITH PASSWORD '${pass}';\\\"`.trim();
256
256
  const alterCmdForShell = `psql ${psqlConnArgs} -d postgres -c "ALTER USER \"${user}\" WITH PASSWORD '${pass}';"`;
257
+ // Conceder privilegios de superusuario al usuario recién creado.
258
+ // Usa psqlSuperArgs porque otorgar SUPERUSER requiere conexión como superusuario.
259
+ const superuserCmdForOpenBSD = `psql ${psqlSuperArgs} -d postgres -c \\\"ALTER USER ${user} WITH SUPERUSER;\\\"`.trim();
260
+ const superuserCmdForShell = `psql ${psqlSuperArgs} -d postgres -c "ALTER USER \"${user}\" WITH SUPERUSER;"`;
257
261
  const pgSuperUser = process.env.PG_SUPERUSER;
258
262
  const pgSuperUserPassword = process.env.PG_SUPERUSER_PASSWORD;
259
263
  const runPriv = (mode, cmd) => {
@@ -331,6 +335,17 @@ export async function runDbSuperCreateUser() {
331
335
  problem(t('db.super.password_failed_mode', mode, lastErr));
332
336
  continue;
333
337
  }
338
+ else {
339
+ success(t('db.super.password_success', user));
340
+ }
341
+ const superuserCmd = (mode === 'openbsd_su') ? superuserCmdForOpenBSD : superuserCmdForShell;
342
+ res = runPriv(mode, superuserCmd);
343
+ if (res.status !== 0) {
344
+ const stderr = (res.stderr || '').toString();
345
+ lastErr = stderr || `Exit code ${res.status}`;
346
+ problem(t('db.super.password_failed_mode', mode, lastErr));
347
+ continue;
348
+ }
334
349
  else {
335
350
  success(t('db.super.password_success', user));
336
351
  opSuccess = true;
@@ -12,9 +12,9 @@
12
12
  * ```
13
13
  */
14
14
  export declare class MockKysely {
15
- private _executeTakeFirst;
16
- private _execute;
17
- private _sqlExecute;
15
+ _executeTakeFirst: (...args: any[]) => any;
16
+ _execute: (...args: any[]) => any;
17
+ _sqlExecute: (query: any) => any;
18
18
  constructor(options?: {
19
19
  executeTakeFirst?: (...args: any[]) => any;
20
20
  execute?: (...args: any[]) => any;
@@ -89,7 +89,63 @@ export declare function createMockKysely(options?: {
89
89
  /** Whether to skip mocking the config module (default: false) */
90
90
  skipConfigMock?: boolean;
91
91
  }): {
92
- MockKysely: typeof MockKysely;
92
+ MockKysely: {
93
+ new (): {
94
+ _executeTakeFirst: (...args: any[]) => any;
95
+ _execute: (...args: any[]) => any;
96
+ _sqlExecute: (query: any) => any;
97
+ selectFrom(): /*elided*/ any;
98
+ where(): /*elided*/ any;
99
+ selectAll(): /*elided*/ any;
100
+ select(...args: any[]): /*elided*/ any;
101
+ orderBy(): /*elided*/ any;
102
+ limit(): /*elided*/ any;
103
+ groupBy(): /*elided*/ any;
104
+ having(): /*elided*/ any;
105
+ leftJoin(): /*elided*/ any;
106
+ innerJoin(): /*elided*/ any;
107
+ insertInto(): /*elided*/ any;
108
+ values(): /*elided*/ any;
109
+ returningAll(): /*elided*/ any;
110
+ updateTable(): /*elided*/ any;
111
+ set(): /*elided*/ any;
112
+ deleteFrom(): /*elided*/ any;
113
+ with(): /*elided*/ any;
114
+ transaction(): {
115
+ execute: (callback: any) => Promise<any>;
116
+ };
117
+ executeTakeFirst(): any;
118
+ executeTakeFirstOrThrow(): any;
119
+ execute(): any;
120
+ getExecutor(): {
121
+ executeQuery: (query: any) => any;
122
+ provideConnection: (callback: any) => Promise<any>;
123
+ releaseConnection: () => void;
124
+ transformQuery: (query: any, transformer: any) => any;
125
+ compileQuery: (query: any, ctx: any) => {
126
+ sql: string;
127
+ parameters: never[];
128
+ };
129
+ };
130
+ fn: {
131
+ countAll: import("vitest").Mock<() => {
132
+ as: import("vitest").Mock<() => {}>;
133
+ }>;
134
+ sum: import("vitest").Mock<() => {
135
+ as: import("vitest").Mock<() => {}>;
136
+ }>;
137
+ avg: import("vitest").Mock<() => {
138
+ as: import("vitest").Mock<() => {}>;
139
+ }>;
140
+ max: import("vitest").Mock<() => {
141
+ as: import("vitest").Mock<() => {}>;
142
+ }>;
143
+ min: import("vitest").Mock<() => {
144
+ as: import("vitest").Mock<() => {}>;
145
+ }>;
146
+ };
147
+ };
148
+ };
93
149
  mockExecuteTakeFirst: import("vitest").Mock<(...args: any[]) => any>;
94
150
  mockExecute: import("vitest").Mock<(...args: any[]) => any>;
95
151
  mockSqlExecute: import("vitest").Mock<(...args: any[]) => any>;
@@ -117,7 +173,63 @@ export declare function createMockKysely(options?: {
117
173
  * Pre-configured mock for database operations in API routes
118
174
  */
119
175
  export declare const apiDbMocks: {
120
- MockKysely: typeof MockKysely;
176
+ MockKysely: {
177
+ new (): {
178
+ _executeTakeFirst: (...args: any[]) => any;
179
+ _execute: (...args: any[]) => any;
180
+ _sqlExecute: (query: any) => any;
181
+ selectFrom(): /*elided*/ any;
182
+ where(): /*elided*/ any;
183
+ selectAll(): /*elided*/ any;
184
+ select(...args: any[]): /*elided*/ any;
185
+ orderBy(): /*elided*/ any;
186
+ limit(): /*elided*/ any;
187
+ groupBy(): /*elided*/ any;
188
+ having(): /*elided*/ any;
189
+ leftJoin(): /*elided*/ any;
190
+ innerJoin(): /*elided*/ any;
191
+ insertInto(): /*elided*/ any;
192
+ values(): /*elided*/ any;
193
+ returningAll(): /*elided*/ any;
194
+ updateTable(): /*elided*/ any;
195
+ set(): /*elided*/ any;
196
+ deleteFrom(): /*elided*/ any;
197
+ with(): /*elided*/ any;
198
+ transaction(): {
199
+ execute: (callback: any) => Promise<any>;
200
+ };
201
+ executeTakeFirst(): any;
202
+ executeTakeFirstOrThrow(): any;
203
+ execute(): any;
204
+ getExecutor(): {
205
+ executeQuery: (query: any) => any;
206
+ provideConnection: (callback: any) => Promise<any>;
207
+ releaseConnection: () => void;
208
+ transformQuery: (query: any, transformer: any) => any;
209
+ compileQuery: (query: any, ctx: any) => {
210
+ sql: string;
211
+ parameters: never[];
212
+ };
213
+ };
214
+ fn: {
215
+ countAll: import("vitest").Mock<() => {
216
+ as: import("vitest").Mock<() => {}>;
217
+ }>;
218
+ sum: import("vitest").Mock<() => {
219
+ as: import("vitest").Mock<() => {}>;
220
+ }>;
221
+ avg: import("vitest").Mock<() => {
222
+ as: import("vitest").Mock<() => {}>;
223
+ }>;
224
+ max: import("vitest").Mock<() => {
225
+ as: import("vitest").Mock<() => {}>;
226
+ }>;
227
+ min: import("vitest").Mock<() => {
228
+ as: import("vitest").Mock<() => {}>;
229
+ }>;
230
+ };
231
+ };
232
+ };
121
233
  mockExecuteTakeFirst: import("vitest").Mock<(...args: any[]) => any>;
122
234
  mockExecute: import("vitest").Mock<(...args: any[]) => any>;
123
235
  mockSqlExecute: import("vitest").Mock<(...args: any[]) => any>;
@@ -145,7 +257,63 @@ export declare const apiDbMocks: {
145
257
  * Pre-configured mock for database operations in lib functions
146
258
  */
147
259
  export declare const libDbMocks: {
148
- MockKysely: typeof MockKysely;
260
+ MockKysely: {
261
+ new (): {
262
+ _executeTakeFirst: (...args: any[]) => any;
263
+ _execute: (...args: any[]) => any;
264
+ _sqlExecute: (query: any) => any;
265
+ selectFrom(): /*elided*/ any;
266
+ where(): /*elided*/ any;
267
+ selectAll(): /*elided*/ any;
268
+ select(...args: any[]): /*elided*/ any;
269
+ orderBy(): /*elided*/ any;
270
+ limit(): /*elided*/ any;
271
+ groupBy(): /*elided*/ any;
272
+ having(): /*elided*/ any;
273
+ leftJoin(): /*elided*/ any;
274
+ innerJoin(): /*elided*/ any;
275
+ insertInto(): /*elided*/ any;
276
+ values(): /*elided*/ any;
277
+ returningAll(): /*elided*/ any;
278
+ updateTable(): /*elided*/ any;
279
+ set(): /*elided*/ any;
280
+ deleteFrom(): /*elided*/ any;
281
+ with(): /*elided*/ any;
282
+ transaction(): {
283
+ execute: (callback: any) => Promise<any>;
284
+ };
285
+ executeTakeFirst(): any;
286
+ executeTakeFirstOrThrow(): any;
287
+ execute(): any;
288
+ getExecutor(): {
289
+ executeQuery: (query: any) => any;
290
+ provideConnection: (callback: any) => Promise<any>;
291
+ releaseConnection: () => void;
292
+ transformQuery: (query: any, transformer: any) => any;
293
+ compileQuery: (query: any, ctx: any) => {
294
+ sql: string;
295
+ parameters: never[];
296
+ };
297
+ };
298
+ fn: {
299
+ countAll: import("vitest").Mock<() => {
300
+ as: import("vitest").Mock<() => {}>;
301
+ }>;
302
+ sum: import("vitest").Mock<() => {
303
+ as: import("vitest").Mock<() => {}>;
304
+ }>;
305
+ avg: import("vitest").Mock<() => {
306
+ as: import("vitest").Mock<() => {}>;
307
+ }>;
308
+ max: import("vitest").Mock<() => {
309
+ as: import("vitest").Mock<() => {}>;
310
+ }>;
311
+ min: import("vitest").Mock<() => {
312
+ as: import("vitest").Mock<() => {}>;
313
+ }>;
314
+ };
315
+ };
316
+ };
149
317
  mockExecuteTakeFirst: import("vitest").Mock<(...args: any[]) => any>;
150
318
  mockExecute: import("vitest").Mock<(...args: any[]) => any>;
151
319
  mockSqlExecute: import("vitest").Mock<(...args: any[]) => any>;
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-mocks.d.ts","sourceRoot":"","sources":["../../src/test-utils/kysely-mocks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;;;GAOG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,iBAAiB,CAAyB;IAClD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,WAAW,CAAqB;gBAE5B,OAAO,CAAC,EAAE;QACpB,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;QAC1C,OAAO,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;QACjC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;KACjC;IAMD,UAAU;IACV,KAAK;IACL,SAAS;IACT,MAAM,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IACrB,OAAO;IACP,KAAK;IACL,OAAO;IACP,MAAM;IACN,QAAQ;IACR,SAAS;IACT,UAAU;IACV,MAAM;IACN,YAAY;IACZ,WAAW;IACX,GAAG;IACH,UAAU;IACV,IAAI;IAEJ,WAAW;4BAEmB,GAAG;;IAUjC,gBAAgB;IAChB,uBAAuB;IACvB,OAAO;IACP,WAAW;8BAEe,GAAG;sCACW,GAAG;;gCAEf,GAAG,eAAe,GAAG;8BACvB,GAAG,OAAO,GAAG;;;;;IAIvC,EAAE;;;;;;;;;;;;;;;;MAMD;CACF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE;IACxC,gBAAgB,CAAC,EAAE,GAAG,CAAA;IACtB,OAAO,CAAC,EAAE,GAAG,CAAA;IACb,UAAU,CAAC,EAAE,GAAG,CAAA;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,cAAc,CAAC,EAAE,OAAO,CAAA;CACpB;;;;;;;;yCAoBe,GAAG;;;IAapB;;;OAGG;;IAqBH;;OAEG;;IASH;;OAEG;;EAQN;AAED;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;yCA/DF,GAAG;;;IAapB;;;OAGG;;IAqBH;;OAEG;;IASH;;OAEG;;CAaqC,CAAA;AAE5C;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;yCApEF,GAAG;;;IAapB;;;OAGG;;IAqBH;;OAEG;;IASH;;OAEG;;CAkBqC,CAAA;AAE5C;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY;;;;;;;;;;;;;;;;;;;;;;;EAyB3B"}
1
+ {"version":3,"file":"kysely-mocks.d.ts","sourceRoot":"","sources":["../../src/test-utils/kysely-mocks.ts"],"names":[],"mappings":"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"}
@@ -91,6 +91,17 @@ export function createMockKysely(options = {}) {
91
91
  if (opts.sqlExecute !== undefined) {
92
92
  mockSqlExecute.mockImplementation(options.sqlExecute);
93
93
  }
94
+ // Wire the MockKysely class to the shared mock functions so that
95
+ // libDbMocks.mockExecute (etc.) reflect actual DB calls made by the code.
96
+ class WiredMockKysely extends MockKysely {
97
+ constructor() {
98
+ super({
99
+ executeTakeFirst: mockExecuteTakeFirst,
100
+ execute: mockExecute,
101
+ sqlExecute: mockSqlExecute,
102
+ });
103
+ }
104
+ }
94
105
  const mockSql = vi.fn(() => ({
95
106
  as: vi.fn().mockReturnValue({}),
96
107
  execute: mockSqlExecute,
@@ -98,7 +109,7 @@ export function createMockKysely(options = {}) {
98
109
  }));
99
110
  const mockPgPool = vi.fn();
100
111
  return {
101
- MockKysely,
112
+ MockKysely: WiredMockKysely,
102
113
  mockExecuteTakeFirst,
103
114
  mockExecute,
104
115
  mockSqlExecute,
@@ -110,7 +121,7 @@ export function createMockKysely(options = {}) {
110
121
  */
111
122
  setupMocks() {
112
123
  vi.mock('kysely', () => ({
113
- Kysely: MockKysely,
124
+ Kysely: WiredMockKysely,
114
125
  PostgresDialect: vi.fn(),
115
126
  sql: mockSql,
116
127
  }));
@@ -121,7 +132,7 @@ export function createMockKysely(options = {}) {
121
132
  const skipConfigMock = opts.skipConfigMock || false;
122
133
  if (!skipConfigMock) {
123
134
  vi.mock('@/.config/kysely.config', () => ({
124
- newKyselyPostgresql: vi.fn(() => new MockKysely()),
135
+ newKyselyPostgresql: vi.fn(() => new WiredMockKysely()),
125
136
  }));
126
137
  }
127
138
  },
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Extension loader for m — auto-discovers and loads m-extensions/.
3
+ *
4
+ * Searches upward from process.cwd() for a directory named "m-extensions"
5
+ * and imports all .js and .ts files found within.
6
+ *
7
+ * "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
8
+ */
9
+ /**
10
+ * Load all extension files from m-extensions/ directory.
11
+ * Each file is dynamically imported; its side effects (registerHook calls)
12
+ * register hooks that will fire at the appropriate extension points.
13
+ */
14
+ export declare function loadExtensions(): Promise<void>;
15
+ //# sourceMappingURL=extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/util/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwBH;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBpD"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Extension loader for m — auto-discovers and loads m-extensions/.
3
+ *
4
+ * Searches upward from process.cwd() for a directory named "m-extensions"
5
+ * and imports all .js and .ts files found within.
6
+ *
7
+ * "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
8
+ */
9
+ import { readdir, access as fsAccess } from 'node:fs/promises';
10
+ import { join, dirname } from 'node:path';
11
+ /**
12
+ * Find the nearest m-extensions/ directory by searching upward from cwd.
13
+ */
14
+ async function findExtensionsDir() {
15
+ let dir = process.cwd();
16
+ for (let i = 0; i < 10; i++) {
17
+ const extDir = join(dir, 'm-extensions');
18
+ try {
19
+ await fsAccess(extDir);
20
+ return extDir;
21
+ }
22
+ catch {
23
+ const parent = dirname(dir);
24
+ if (parent === dir)
25
+ break;
26
+ dir = parent;
27
+ }
28
+ }
29
+ return null;
30
+ }
31
+ /**
32
+ * Load all extension files from m-extensions/ directory.
33
+ * Each file is dynamically imported; its side effects (registerHook calls)
34
+ * register hooks that will fire at the appropriate extension points.
35
+ */
36
+ export async function loadExtensions() {
37
+ const extDir = await findExtensionsDir();
38
+ if (!extDir)
39
+ return;
40
+ let files;
41
+ try {
42
+ files = await readdir(extDir);
43
+ }
44
+ catch {
45
+ return;
46
+ }
47
+ for (const file of files) {
48
+ if (!file.endsWith('.js') && !file.endsWith('.ts'))
49
+ continue;
50
+ if (file.endsWith('.d.ts'))
51
+ continue;
52
+ try {
53
+ await import(join(extDir, file));
54
+ }
55
+ catch (err) {
56
+ console.error(`[m] Failed to load extension ${file}: ${err.message || err}`);
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Hook system for m extensions.
3
+ *
4
+ * Projects can register hooks to inject logic at specific extension points.
5
+ * Hooks are async callbacks that receive a context object.
6
+ *
7
+ * "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
8
+ */
9
+ /**
10
+ * Register a hook callback for a named extension point.
11
+ * Safe to call multiple times — callbacks are appended.
12
+ */
13
+ export declare function registerHook(name: string, callback: (ctx: any) => Promise<void>): void;
14
+ /**
15
+ * Run all registered hooks for a named extension point.
16
+ * Callbacks are executed in series (order of registration).
17
+ * Errors are caught and logged; they do not stop subsequent hooks.
18
+ */
19
+ export declare function runHooks(name: string, ctx: any): Promise<void>;
20
+ /**
21
+ * Clear all registered hooks (for testing).
22
+ */
23
+ export declare function clearHooks(): void;
24
+ /**
25
+ * Get hook names and callback counts (for debugging/testing).
26
+ */
27
+ export declare function debugHooks(): Record<string, number>;
28
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/util/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAKtF;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAWpE;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMnD"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Hook system for m extensions.
3
+ *
4
+ * Projects can register hooks to inject logic at specific extension points.
5
+ * Hooks are async callbacks that receive a context object.
6
+ *
7
+ * "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
8
+ */
9
+ const hooks = new Map();
10
+ /**
11
+ * Register a hook callback for a named extension point.
12
+ * Safe to call multiple times — callbacks are appended.
13
+ */
14
+ export function registerHook(name, callback) {
15
+ if (!hooks.has(name)) {
16
+ hooks.set(name, []);
17
+ }
18
+ hooks.get(name).push(callback);
19
+ }
20
+ /**
21
+ * Run all registered hooks for a named extension point.
22
+ * Callbacks are executed in series (order of registration).
23
+ * Errors are caught and logged; they do not stop subsequent hooks.
24
+ */
25
+ export async function runHooks(name, ctx) {
26
+ const callbacks = hooks.get(name);
27
+ if (!callbacks || callbacks.length === 0)
28
+ return;
29
+ for (const cb of callbacks) {
30
+ try {
31
+ await cb(ctx);
32
+ }
33
+ catch (err) {
34
+ console.error(`[m] Hook "${name}" failed: ${err.message || err}`);
35
+ }
36
+ }
37
+ }
38
+ /**
39
+ * Clear all registered hooks (for testing).
40
+ */
41
+ export function clearHooks() {
42
+ hooks.clear();
43
+ }
44
+ /**
45
+ * Get hook names and callback counts (for debugging/testing).
46
+ */
47
+ export function debugHooks() {
48
+ const out = {};
49
+ for (const [name, cbs] of hooks) {
50
+ out[name] = cbs.length;
51
+ }
52
+ return out;
53
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pasosdejesus/m",
3
- "version": "0.16.1",
3
+ "version": "0.17.1",
4
4
  "description": "Motor para crear y gestionar proyectos al estilo Pasos de Jesus.",
5
5
  "author": "",
6
6
  "license": "ISC",