@pikku/cli 0.12.23 → 0.12.25
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/cli.schema.json +1 -1
- package/console-app/assets/index-D4DgafuS.js +232 -0
- package/console-app/index.html +1 -1
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +16 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +41 -0
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +130 -66
- package/dist/.pikku/function/pikku-functions.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +3 -1
- package/dist/.pikku/pikku-services.gen.js +2 -0
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +20 -17
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +13 -3
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuEmailsOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuFunctionTypesSplitInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuTriggerTypesInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/WorkspaceValidateInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/WorkspaceValidateOutput.schema.json +1 -0
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/meta/allWorkflow.gen.json +5 -5
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/cli.wiring.js +31 -0
- package/dist/src/fabric/functions/validate-core.d.ts +20 -0
- package/dist/src/fabric/functions/validate-core.js +227 -0
- package/dist/src/fabric/functions/validate.function.js +11 -3
- package/dist/src/functions/commands/bootstrap.js +2 -2
- package/dist/src/functions/commands/console.js +7 -4
- package/dist/src/functions/commands/db-migrate.js +2 -3
- package/dist/src/functions/commands/db-reset.js +3 -4
- package/dist/src/functions/commands/db-seed.js +2 -3
- package/dist/src/functions/commands/db-shared.d.ts +2 -15
- package/dist/src/functions/commands/db-shared.js +43 -17
- package/dist/src/functions/commands/dev.js +28 -8
- package/dist/src/functions/commands/emails-init.d.ts +5 -0
- package/dist/src/functions/commands/emails-init.js +162 -0
- package/dist/src/functions/commands/load-user-project.js +12 -3
- package/dist/src/functions/commands/watch.js +7 -4
- package/dist/src/functions/commands/workspace-validate.d.ts +33 -0
- package/dist/src/functions/commands/workspace-validate.js +9 -0
- package/dist/src/functions/db/coercion-plugin.d.ts +7 -0
- package/dist/src/functions/db/coercion-plugin.js +99 -0
- package/dist/src/functions/db/local-db.d.ts +2 -2
- package/dist/src/functions/db/local-db.js +13 -8
- package/dist/src/functions/db/seed.d.ts +2 -2
- package/dist/src/functions/db/sql-migrator.d.ts +3 -3
- package/dist/src/functions/db/sqlite-codegen.d.ts +3 -3
- package/dist/src/functions/db/sqlite-kysely.d.ts +8 -0
- package/dist/src/functions/db/sqlite-kysely.js +62 -0
- package/dist/src/functions/db/sqlite-runtime-bun.d.ts +2 -0
- package/dist/src/functions/db/sqlite-runtime-bun.js +52 -0
- package/dist/src/functions/db/sqlite-runtime-node.d.ts +2 -0
- package/dist/src/functions/db/sqlite-runtime-node.js +51 -0
- package/dist/src/functions/db/sqlite-runtime.d.ts +20 -0
- package/dist/src/functions/db/sqlite-runtime.js +13 -0
- package/dist/src/functions/validate/workspace-validate.d.ts +34 -0
- package/dist/src/functions/validate/workspace-validate.js +258 -0
- package/dist/src/functions/wirings/cli/pikku-command-cli-types.js +1 -1
- package/dist/src/functions/wirings/emails/pikku-command-emails.d.ts +6 -0
- package/dist/src/functions/wirings/emails/pikku-command-emails.js +172 -0
- package/dist/src/functions/wirings/emails/serialize-emails.d.ts +20 -0
- package/dist/src/functions/wirings/emails/serialize-emails.js +168 -0
- package/dist/src/functions/wirings/functions/pikku-command-function-types-split.d.ts +7 -1
- package/dist/src/functions/wirings/functions/pikku-command-function-types-split.js +2 -2
- package/dist/src/functions/wirings/triggers/pikku-command-trigger-types.d.ts +7 -1
- package/dist/src/functions/wirings/triggers/pikku-command-trigger-types.js +2 -2
- package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +1 -1
- package/dist/src/functions/workflows/all.workflow.js +12 -7
- package/dist/src/scaffold/rpc-remote.gen.js +1 -1
- package/dist/src/utils/pikku-cli-config.js +6 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/skills/pikku-auth-js/SKILL.md +271 -58
- package/console-app/assets/index-CAk106ji.js +0 -232
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const FabricValidateInput: z.ZodObject<{}, z.core.$strip>;
|
|
3
|
+
export declare const FabricValidateOutput: z.ZodObject<{
|
|
4
|
+
ok: z.ZodBoolean;
|
|
5
|
+
root: z.ZodString;
|
|
6
|
+
findings: z.ZodArray<z.ZodObject<{
|
|
7
|
+
id: z.ZodString;
|
|
8
|
+
severity: z.ZodEnum<{
|
|
9
|
+
info: "info";
|
|
10
|
+
warn: "warn";
|
|
11
|
+
error: "error";
|
|
12
|
+
}>;
|
|
13
|
+
message: z.ZodString;
|
|
14
|
+
path: z.ZodString;
|
|
15
|
+
fixHint: z.ZodString;
|
|
16
|
+
}, z.core.$strip>>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
export declare function runFabricValidate(startDir?: string): Promise<z.infer<typeof FabricValidateOutput>>;
|
|
19
|
+
export declare const runValidate: typeof runFabricValidate;
|
|
20
|
+
export declare const renderValidate: (_s: unknown, { ok, root, findings }: z.infer<typeof FabricValidateOutput>) => void;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { added, changed, dim, removed } from '../lib/output.js';
|
|
6
|
+
import { WorkspaceValidateOutput, readJsonSafe, readTextSafe, runWorkspaceValidate, } from '../../functions/validate/workspace-validate.js';
|
|
7
|
+
export const FabricValidateInput = z.object({});
|
|
8
|
+
export const FabricValidateOutput = WorkspaceValidateOutput;
|
|
9
|
+
const POSTGRES_SQL_PATTERNS = [
|
|
10
|
+
{
|
|
11
|
+
re: /\b(?:SMALL|BIG)?SERIAL\b/i,
|
|
12
|
+
label: 'SERIAL / BIGSERIAL / SMALLSERIAL',
|
|
13
|
+
},
|
|
14
|
+
{ re: /\bJSONB\b/i, label: 'JSONB' },
|
|
15
|
+
{ re: /\bCREATE\s+SEQUENCE\b/i, label: 'CREATE SEQUENCE' },
|
|
16
|
+
{ re: /\bgen_random_uuid\s*\(\s*\)/i, label: 'gen_random_uuid()' },
|
|
17
|
+
{ re: /::[a-z_]+/i, label: ':: type cast' },
|
|
18
|
+
{ re: /\bTSVECTOR\b/i, label: 'TSVECTOR' },
|
|
19
|
+
{ re: /\bARRAY\s*\[/i, label: 'ARRAY[…]' },
|
|
20
|
+
];
|
|
21
|
+
export async function runFabricValidate(startDir = process.cwd()) {
|
|
22
|
+
const workspaceResult = await runWorkspaceValidate(startDir);
|
|
23
|
+
const root = workspaceResult.root;
|
|
24
|
+
const findings = [...workspaceResult.findings];
|
|
25
|
+
const e = (id, message, path, fixHint) => {
|
|
26
|
+
findings.push({ id, severity: 'error', message, path, fixHint });
|
|
27
|
+
};
|
|
28
|
+
const w = (id, message, path, fixHint) => {
|
|
29
|
+
findings.push({ id, severity: 'warn', message, path, fixHint });
|
|
30
|
+
};
|
|
31
|
+
const info = (id, message, path, fixHint) => {
|
|
32
|
+
findings.push({ id, severity: 'info', message, path, fixHint });
|
|
33
|
+
};
|
|
34
|
+
const fabricConfigPath = join(root, 'fabric.config.json');
|
|
35
|
+
const fabricConfig = await readJsonSafe(fabricConfigPath);
|
|
36
|
+
if (!fabricConfig) {
|
|
37
|
+
info('fabric-config-missing', 'fabric.config.json not found — project has not been linked to fabric yet', fabricConfigPath, 'Run `pikku fabric link` to create it, or create manually: {"projectId": "__PROJECT_ID__"}');
|
|
38
|
+
}
|
|
39
|
+
else if (!fabricConfig.projectId) {
|
|
40
|
+
info('fabric-config-no-project-id', 'fabric.config.json is missing "projectId"', fabricConfigPath, 'Add "projectId": "<your-project-id>" to fabric.config.json, or run `pikku fabric link`');
|
|
41
|
+
}
|
|
42
|
+
else if (fabricConfig.projectId === '__PROJECT_ID__') {
|
|
43
|
+
info('fabric-config-placeholder-project-id', 'fabric.config.json has a placeholder projectId ("__PROJECT_ID__") — project is not linked', fabricConfigPath, 'Run `pikku fabric link` to replace the placeholder with a real project ID');
|
|
44
|
+
}
|
|
45
|
+
const rootPkgPath = join(root, 'package.json');
|
|
46
|
+
const rootPkg = await readJsonSafe(rootPkgPath);
|
|
47
|
+
if (rootPkg) {
|
|
48
|
+
const allDeps = {
|
|
49
|
+
...rootPkg.dependencies,
|
|
50
|
+
...rootPkg.devDependencies,
|
|
51
|
+
};
|
|
52
|
+
if (!allDeps['@pikku/fabric-cli']) {
|
|
53
|
+
info('missing-fabric-cli', '@pikku/fabric-cli not in devDependencies — fabric CLI commands (validate, deploy) will not be available', rootPkgPath, 'Add "@pikku/fabric-cli" to devDependencies: use "file:./vendor/pikku-fabric-cli.tgz" (bundled release) or "portal:/path/to/pikku/packages/fabric-cli" (local dev)');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const fnDir = join(root, 'packages', 'functions');
|
|
57
|
+
const functionsSdkPkgName = (await readJsonSafe(join(root, 'packages', 'functions-sdk', 'package.json')))?.name;
|
|
58
|
+
const themePkgName = (await readJsonSafe(join(root, 'packages', 'theme', 'package.json')))?.name;
|
|
59
|
+
const componentsPkgName = (await readJsonSafe(join(root, 'packages', 'components', 'package.json')))?.name;
|
|
60
|
+
if (existsSync(fnDir)) {
|
|
61
|
+
const fnPkgPath = join(fnDir, 'package.json');
|
|
62
|
+
const fnPkg = await readJsonSafe(fnPkgPath);
|
|
63
|
+
if (fnPkg) {
|
|
64
|
+
const fnAllDeps = {
|
|
65
|
+
...fnPkg.dependencies,
|
|
66
|
+
...fnPkg.devDependencies,
|
|
67
|
+
...fnPkg.peerDependencies,
|
|
68
|
+
};
|
|
69
|
+
if (fnAllDeps['@pikku/kysely-postgres']) {
|
|
70
|
+
e('fn-pkg-postgres-dep', '@pikku/kysely-postgres is in packages/functions dependencies — Fabric uses SQLite/libSQL (Turso), not PostgreSQL', fnPkgPath, 'Remove @pikku/kysely-postgres and use @pikku/kysely-sqlite with LibsqlWebDialect instead');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const servicesPath = join(fnDir, 'src', 'services.ts');
|
|
74
|
+
const servicesText = await readTextSafe(servicesPath);
|
|
75
|
+
if (servicesText) {
|
|
76
|
+
const usesKysely = /\bKysely\b/.test(servicesText);
|
|
77
|
+
const usesLibsql = servicesText.includes('@pikku/kysely-sqlite') ||
|
|
78
|
+
servicesText.includes('LibsqlWebDialect');
|
|
79
|
+
const usesProcessEnv = /\bprocess\.env\.[A-Z_]/.test(servicesText);
|
|
80
|
+
if (usesKysely && !usesLibsql) {
|
|
81
|
+
e('services-wrong-db-adapter', 'services.ts uses Kysely but not LibsqlWebDialect — Fabric injects a Turso/libSQL DATABASE_URL at runtime, not a PostgreSQL URL', servicesPath, 'Import LibsqlWebDialect from @pikku/kysely-sqlite and replace the dialect: new Kysely({ dialect: new LibsqlWebDialect({ url: databaseUrl }) })');
|
|
82
|
+
}
|
|
83
|
+
if (usesProcessEnv) {
|
|
84
|
+
info('services-process-env', 'services.ts reads process.env directly — prefer variables.get() for portable secret/variable access', servicesPath, 'Replace process.env.SOME_VAR with await variables.get("SOME_VAR") — declare the binding with wireVariable/wireSecret; process.env is fine for optional/non-secret config');
|
|
85
|
+
}
|
|
86
|
+
if (usesLibsql &&
|
|
87
|
+
rootPkg &&
|
|
88
|
+
!rootPkg.dependencies?.['@pikku/kysely-sqlite'] &&
|
|
89
|
+
!rootPkg.devDependencies?.['@pikku/kysely-sqlite']) {
|
|
90
|
+
e('missing-kysely-sqlite', 'services.ts imports @pikku/kysely-sqlite but it is not in root package.json', rootPkgPath, 'Add "@pikku/kysely-sqlite": "file:./vendor/pikku-kysely-sqlite.tgz" to dependencies');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// db/migrations/ — presence, numbering and SQL dialect
|
|
94
|
+
const migrationsDir = join(fnDir, 'db', 'migrations');
|
|
95
|
+
if (!existsSync(migrationsDir)) {
|
|
96
|
+
e('migrations-dir-missing', 'packages/functions/db/migrations/ not found', migrationsDir, 'Create db/migrations/ and add numbered .sql files (e.g. 0001-init.sql) using SQLite-compatible syntax');
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
try {
|
|
100
|
+
const files = (await readdir(migrationsDir)).filter((f) => f.endsWith('.sql'));
|
|
101
|
+
const nums = [];
|
|
102
|
+
for (const f of files) {
|
|
103
|
+
const m = f.match(/^(\d+)/);
|
|
104
|
+
if (m)
|
|
105
|
+
nums.push(parseInt(m[1], 10));
|
|
106
|
+
}
|
|
107
|
+
for (let idx = 1; idx < nums.length; idx++) {
|
|
108
|
+
if (nums[idx] !== nums[idx - 1] + 1) {
|
|
109
|
+
const missing = `${nums[idx - 1] + 1}..${nums[idx] - 1}`;
|
|
110
|
+
e('migration-gap', `Migration numbering gap: IDs ${missing} are missing`, migrationsDir, 'Migrations must be consecutive. Add the missing .sql file or renumber if not yet applied.');
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const f of files) {
|
|
115
|
+
const sql = await readTextSafe(join(migrationsDir, f));
|
|
116
|
+
if (!sql)
|
|
117
|
+
continue;
|
|
118
|
+
const hits = POSTGRES_SQL_PATTERNS.filter(({ re }) => re.test(sql)).map(({ label }) => label);
|
|
119
|
+
if (hits.length > 0) {
|
|
120
|
+
e(`migration-postgres-sql-${f.replace(/[^a-z0-9]/gi, '-')}`, `${f} contains PostgreSQL syntax (${hits.join(', ')}) — Fabric uses SQLite/libSQL (Turso)`, join(migrationsDir, f), "Rewrite the migration using SQLite-compatible syntax: TEXT instead of JSONB, INTEGER PRIMARY KEY for auto-increment, datetime('now') instead of NOW(), no :: casts");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// readdir failure — skip
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// db/seed.sql
|
|
129
|
+
const seedPath = join(fnDir, 'db', 'seed.sql');
|
|
130
|
+
if (!existsSync(seedPath)) {
|
|
131
|
+
e('seed-sql-missing', 'packages/functions/db/seed.sql not found', seedPath, 'Create db/seed.sql with idempotent INSERT OR IGNORE statements for demo/test data');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const appsDir = join(root, 'apps');
|
|
135
|
+
if (existsSync(appsDir)) {
|
|
136
|
+
if (fabricConfig) {
|
|
137
|
+
const frontends = (fabricConfig.frontends ?? {});
|
|
138
|
+
for (const [slug, fe] of Object.entries(frontends)) {
|
|
139
|
+
const cwd = fe.cwd?.replace(/^\.\//, '');
|
|
140
|
+
if (cwd && !existsSync(join(root, cwd))) {
|
|
141
|
+
e(`frontend-cwd-missing-${slug}`, `fabric.config.json frontend "${slug}" declares cwd "${cwd}" but that directory does not exist`, join(root, cwd), 'Create the directory or update the cwd in fabric.config.json');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
let appEntries = [];
|
|
146
|
+
try {
|
|
147
|
+
appEntries = (await readdir(appsDir, { withFileTypes: true }))
|
|
148
|
+
.filter((e) => e.isDirectory())
|
|
149
|
+
.map((e) => e.name);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// ignore
|
|
153
|
+
}
|
|
154
|
+
const declaredCwds = fabricConfig
|
|
155
|
+
? new Set(Object.values((fabricConfig.frontends ?? {})).map((f) => f.cwd?.replace(/^\.\//, '') ?? ''))
|
|
156
|
+
: null;
|
|
157
|
+
for (const name of appEntries) {
|
|
158
|
+
const appPath = join(appsDir, name);
|
|
159
|
+
const cwd = `apps/${name}`;
|
|
160
|
+
if (declaredCwds && !declaredCwds.has(cwd)) {
|
|
161
|
+
w(`app-not-declared-${name}`, `apps/${name} is not declared in fabric.config.json frontends`, appPath, `Add an entry to fabric.config.json: { "frontends": { "${name}": { "cwd": "${cwd}", "kind": "ssr" } } }`);
|
|
162
|
+
}
|
|
163
|
+
const appPkg = await readJsonSafe(join(appPath, 'package.json'));
|
|
164
|
+
if (!appPkg)
|
|
165
|
+
continue;
|
|
166
|
+
const appDeps = { ...appPkg.dependencies };
|
|
167
|
+
if (functionsSdkPkgName && !appDeps[functionsSdkPkgName]) {
|
|
168
|
+
info(`app-missing-functions-sdk-${name}`, `apps/${name} does not depend on ${functionsSdkPkgName} — the generated RPC client and React Query hooks`, join(appPath, 'package.json'), `Add "${functionsSdkPkgName}: workspace:*" to apps/${name}/package.json dependencies`);
|
|
169
|
+
}
|
|
170
|
+
if (themePkgName && !appDeps[themePkgName]) {
|
|
171
|
+
info(`app-missing-theme-${name}`, `apps/${name} does not depend on ${themePkgName}`, join(appPath, 'package.json'), `Add "${themePkgName}: workspace:*" to apps/${name}/package.json dependencies`);
|
|
172
|
+
}
|
|
173
|
+
if (componentsPkgName && !appDeps[componentsPkgName]) {
|
|
174
|
+
info(`app-missing-components-${name}`, `apps/${name} does not depend on ${componentsPkgName}`, join(appPath, 'package.json'), `Add "${componentsPkgName}: workspace:*" to apps/${name}/package.json dependencies`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const designDocUrl = 'https://pikkufabric.dev/docs/design';
|
|
179
|
+
if (!existsSync(join(root, 'packages', 'theme'))) {
|
|
180
|
+
info('theme-missing', 'packages/theme/ not found — Fabric design features require a theme package', join(root, 'packages', 'theme'), `Create packages/theme/ with your Mantine theme tokens. See ${designDocUrl}`);
|
|
181
|
+
}
|
|
182
|
+
if (!existsSync(join(root, 'packages', 'components'))) {
|
|
183
|
+
info('components-missing', 'packages/components/ not found — Fabric design features require a components package', join(root, 'packages', 'components'), `Create packages/components/ with your shared UI components. See ${designDocUrl}`);
|
|
184
|
+
}
|
|
185
|
+
const ok = !findings.some((f) => f.severity === 'error');
|
|
186
|
+
return { ok, root, findings };
|
|
187
|
+
}
|
|
188
|
+
export const runValidate = runFabricValidate;
|
|
189
|
+
export const renderValidate = (_s, { ok, root, findings }) => {
|
|
190
|
+
if (findings.length === 0) {
|
|
191
|
+
console.log(added('✓ All checks passed — project is fabric-compatible'));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const relPath = (p) => p.startsWith(root + '/') || p.startsWith(root + '\\')
|
|
195
|
+
? p.slice(root.length + 1)
|
|
196
|
+
: p;
|
|
197
|
+
const errors = findings.filter((f) => f.severity === 'error');
|
|
198
|
+
const warns = findings.filter((f) => f.severity === 'warn');
|
|
199
|
+
const infos = findings.filter((f) => f.severity === 'info');
|
|
200
|
+
for (const f of [...errors, ...warns, ...infos]) {
|
|
201
|
+
const icon = f.severity === 'error'
|
|
202
|
+
? removed('✗')
|
|
203
|
+
: f.severity === 'warn'
|
|
204
|
+
? changed('⚠')
|
|
205
|
+
: dim('ℹ');
|
|
206
|
+
console.log(`${icon} ${f.message}`);
|
|
207
|
+
console.log(` ${dim('path:')} ${relPath(f.path)}`);
|
|
208
|
+
console.log(` ${dim('fix:')} ${f.fixHint}`);
|
|
209
|
+
console.log();
|
|
210
|
+
}
|
|
211
|
+
const counts = [];
|
|
212
|
+
if (errors.length) {
|
|
213
|
+
counts.push(removed(`${errors.length} error${errors.length !== 1 ? 's' : ''}`));
|
|
214
|
+
}
|
|
215
|
+
if (warns.length) {
|
|
216
|
+
counts.push(changed(`${warns.length} warning${warns.length !== 1 ? 's' : ''}`));
|
|
217
|
+
}
|
|
218
|
+
if (infos.length) {
|
|
219
|
+
counts.push(dim(`${infos.length} info${infos.length !== 1 ? 's' : ''}`));
|
|
220
|
+
}
|
|
221
|
+
console.log('─'.repeat(40));
|
|
222
|
+
console.log(counts.join(' '));
|
|
223
|
+
if (ok) {
|
|
224
|
+
console.log();
|
|
225
|
+
console.log(added('✓') + ' ' + dim('no errors — project can be linked to fabric'));
|
|
226
|
+
}
|
|
227
|
+
};
|
|
@@ -194,9 +194,12 @@ export async function runValidate(startDir = process.cwd()) {
|
|
|
194
194
|
e('missing-kysely-sqlite', 'services.ts imports @pikku/kysely-sqlite but it is not in root package.json', rootPkgPath, 'Add "@pikku/kysely-sqlite": "file:./vendor/pikku-kysely-sqlite.tgz" to dependencies');
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
|
-
// db/migrations/ — numbering and SQL dialect
|
|
197
|
+
// db/migrations/ — presence, numbering and SQL dialect
|
|
198
198
|
const migrationsDir = join(fnDir, 'db', 'migrations');
|
|
199
|
-
if (existsSync(migrationsDir)) {
|
|
199
|
+
if (!existsSync(migrationsDir)) {
|
|
200
|
+
e('migrations-dir-missing', 'packages/functions/db/migrations/ not found', migrationsDir, 'Create db/migrations/ and add numbered .sql files (e.g. 0001-init.sql) using SQLite-compatible syntax');
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
200
203
|
try {
|
|
201
204
|
const files = (await readdir(migrationsDir))
|
|
202
205
|
.filter((f) => f.endsWith('.sql'))
|
|
@@ -210,7 +213,7 @@ export async function runValidate(startDir = process.cwd()) {
|
|
|
210
213
|
for (let idx = 1; idx < nums.length; idx++) {
|
|
211
214
|
if (nums[idx] !== nums[idx - 1] + 1) {
|
|
212
215
|
const missing = `${nums[idx - 1] + 1}..${nums[idx] - 1}`;
|
|
213
|
-
e('migration-gap', `Migration numbering gap: IDs ${missing} are missing`, migrationsDir, 'Migrations must be consecutive
|
|
216
|
+
e('migration-gap', `Migration numbering gap: IDs ${missing} are missing`, migrationsDir, 'Migrations must be consecutive. Add the missing .sql file or renumber if not yet applied.');
|
|
214
217
|
break;
|
|
215
218
|
}
|
|
216
219
|
}
|
|
@@ -229,6 +232,11 @@ export async function runValidate(startDir = process.cwd()) {
|
|
|
229
232
|
// readdir failure — skip
|
|
230
233
|
}
|
|
231
234
|
}
|
|
235
|
+
// db/seed.sql
|
|
236
|
+
const seedPath = join(fnDir, 'db', 'seed.sql');
|
|
237
|
+
if (!existsSync(seedPath)) {
|
|
238
|
+
e('seed-sql-missing', 'packages/functions/db/seed.sql not found', seedPath, 'Create db/seed.sql with idempotent INSERT OR IGNORE statements for demo/test data');
|
|
239
|
+
}
|
|
232
240
|
// db.types.ts — should only re-export from .pikku
|
|
233
241
|
const dbTypesPath = join(fnDir, 'src', 'types', 'db.types.ts');
|
|
234
242
|
const dbTypesText = await readTextSafe(dbTypesPath);
|
|
@@ -3,14 +3,14 @@ export const bootstrap = pikkuVoidFunc({
|
|
|
3
3
|
remote: true,
|
|
4
4
|
func: async ({ logger, getInspectorState }, _data, { rpc }) => {
|
|
5
5
|
await getInspectorState(false, true, true);
|
|
6
|
-
await rpc.invoke('pikkuFunctionTypesSplit');
|
|
6
|
+
await rpc.invoke('pikkuFunctionTypesSplit', { bootstrap: true });
|
|
7
7
|
await rpc.invoke('pikkuFunctionTypes');
|
|
8
8
|
await rpc.invoke('pikkuHTTPTypes');
|
|
9
9
|
await rpc.invoke('pikkuChannelTypes');
|
|
10
10
|
await rpc.invoke('pikkuSchedulerTypes');
|
|
11
11
|
await rpc.invoke('pikkuQueueTypes');
|
|
12
12
|
await rpc.invoke('pikkuWorkflow', { bootstrap: true });
|
|
13
|
-
await rpc.invoke('pikkuTriggerTypes');
|
|
13
|
+
await rpc.invoke('pikkuTriggerTypes', { bootstrap: true });
|
|
14
14
|
await rpc.invoke('pikkuMCPTypes');
|
|
15
15
|
await rpc.invoke('pikkuAIAgentTypes');
|
|
16
16
|
await rpc.invoke('pikkuNodeTypes');
|
|
@@ -23,6 +23,9 @@ const MIME_TYPES = {
|
|
|
23
23
|
export const consoleCommand = pikkuSessionlessFunc({
|
|
24
24
|
remote: true,
|
|
25
25
|
func: async ({ logger, config }, { port, open: openBrowser, hmr }, { rpc }) => {
|
|
26
|
+
const watchDirectories = [
|
|
27
|
+
...new Set([config.emailTemplatesDir, ...config.srcDirectories].filter(Boolean)),
|
|
28
|
+
];
|
|
26
29
|
if (!config.scaffold?.console) {
|
|
27
30
|
logger.error('Console is not enabled. Add { "scaffold": { "console": "no-auth" } } to your pikku.config.json');
|
|
28
31
|
return;
|
|
@@ -68,19 +71,19 @@ export const consoleCommand = pikkuSessionlessFunc({
|
|
|
68
71
|
});
|
|
69
72
|
if (hmr) {
|
|
70
73
|
await pikkuDevReloader({
|
|
71
|
-
srcDirectories:
|
|
74
|
+
srcDirectories: watchDirectories,
|
|
72
75
|
logger,
|
|
73
76
|
});
|
|
74
77
|
}
|
|
75
|
-
const configWatcher = chokidar.watch(
|
|
78
|
+
const configWatcher = chokidar.watch(watchDirectories, {
|
|
76
79
|
ignoreInitial: true,
|
|
77
80
|
ignored: /.*\.gen\.tsx?/,
|
|
78
81
|
});
|
|
79
82
|
let watcher = new chokidar.FSWatcher({});
|
|
80
83
|
const generatorWatcher = () => {
|
|
81
84
|
watcher.close();
|
|
82
|
-
logger.info(`• Watching directories: \n - ${
|
|
83
|
-
watcher = chokidar.watch(
|
|
85
|
+
logger.info(`• Watching directories: \n - ${watchDirectories.join('\n - ')}`);
|
|
86
|
+
watcher = chokidar.watch(watchDirectories, {
|
|
84
87
|
ignoreInitial: true,
|
|
85
88
|
ignored: /.*\.gen\.ts/,
|
|
86
89
|
});
|
|
@@ -3,10 +3,9 @@ import { resolveLocalDb, migrateAndCodegen } from '../db/local-db.js';
|
|
|
3
3
|
import { loadUserConfigForDb } from './db-shared.js';
|
|
4
4
|
export const dbMigrate = pikkuSessionlessFunc({
|
|
5
5
|
remote: true,
|
|
6
|
-
func: async ({ logger, config
|
|
6
|
+
func: async ({ logger, config }) => {
|
|
7
7
|
const userConfig = await loadUserConfigForDb({
|
|
8
8
|
config,
|
|
9
|
-
getInspectorState,
|
|
10
9
|
logger,
|
|
11
10
|
});
|
|
12
11
|
if (!userConfig)
|
|
@@ -16,7 +15,7 @@ export const dbMigrate = pikkuSessionlessFunc({
|
|
|
16
15
|
logger.error('pikku db migrate: dev.db is not configured in your pikku config.');
|
|
17
16
|
throw new Error('dev.db not configured');
|
|
18
17
|
}
|
|
19
|
-
const { migrate, codegen, zod } = migrateAndCodegen(resolved);
|
|
18
|
+
const { migrate, codegen, zod } = await migrateAndCodegen(resolved);
|
|
20
19
|
if (migrate.applied.length === 0) {
|
|
21
20
|
logger.info(`db migrate: no pending migrations (${migrate.skipped.length} already applied)`);
|
|
22
21
|
}
|
|
@@ -3,10 +3,9 @@ import { resolveLocalDb, reset, migrateAndCodegen, seed, } from '../db/local-db.
|
|
|
3
3
|
import { loadUserConfigForDb } from './db-shared.js';
|
|
4
4
|
export const dbReset = pikkuSessionlessFunc({
|
|
5
5
|
remote: true,
|
|
6
|
-
func: async ({ logger, config
|
|
6
|
+
func: async ({ logger, config }) => {
|
|
7
7
|
const userConfig = await loadUserConfigForDb({
|
|
8
8
|
config,
|
|
9
|
-
getInspectorState,
|
|
10
9
|
logger,
|
|
11
10
|
});
|
|
12
11
|
if (!userConfig)
|
|
@@ -18,7 +17,7 @@ export const dbReset = pikkuSessionlessFunc({
|
|
|
18
17
|
}
|
|
19
18
|
reset(resolved, config.rootDir);
|
|
20
19
|
logger.info(`db reset: removed ${resolved.dbFile}`);
|
|
21
|
-
const { migrate, codegen, zod } = migrateAndCodegen(resolved);
|
|
20
|
+
const { migrate, codegen, zod } = await migrateAndCodegen(resolved);
|
|
22
21
|
for (const name of migrate.applied) {
|
|
23
22
|
logger.info(`db reset: applied ${name}`);
|
|
24
23
|
}
|
|
@@ -28,7 +27,7 @@ export const dbReset = pikkuSessionlessFunc({
|
|
|
28
27
|
logger.info(zod.written
|
|
29
28
|
? `db reset: regenerated ${zod.outFile} (${zod.tables.length} tables)`
|
|
30
29
|
: `db reset: ${zod.outFile} unchanged`);
|
|
31
|
-
const seedResult = seed(resolved);
|
|
30
|
+
const seedResult = await seed(resolved);
|
|
32
31
|
if (seedResult.applied) {
|
|
33
32
|
logger.info(`db reset: seeded ${resolved.seedFile} (${seedResult.bytes} bytes)`);
|
|
34
33
|
}
|
|
@@ -3,10 +3,9 @@ import { resolveLocalDb, seed } from '../db/local-db.js';
|
|
|
3
3
|
import { loadUserConfigForDb } from './db-shared.js';
|
|
4
4
|
export const dbSeed = pikkuSessionlessFunc({
|
|
5
5
|
remote: true,
|
|
6
|
-
func: async ({ logger, config
|
|
6
|
+
func: async ({ logger, config }) => {
|
|
7
7
|
const userConfig = await loadUserConfigForDb({
|
|
8
8
|
config,
|
|
9
|
-
getInspectorState,
|
|
10
9
|
logger,
|
|
11
10
|
});
|
|
12
11
|
if (!userConfig)
|
|
@@ -16,7 +15,7 @@ export const dbSeed = pikkuSessionlessFunc({
|
|
|
16
15
|
logger.error('pikku db seed: dev.db is not configured in your pikku config.');
|
|
17
16
|
throw new Error('dev.db not configured');
|
|
18
17
|
}
|
|
19
|
-
const result = seed(resolved);
|
|
18
|
+
const result = await seed(resolved);
|
|
20
19
|
if (!result.applied) {
|
|
21
20
|
logger.info(`db seed: no ${resolved.seedFile} found, nothing to do`);
|
|
22
21
|
}
|
|
@@ -8,25 +8,12 @@ export interface UserConfigShape {
|
|
|
8
8
|
interface LoadOptions {
|
|
9
9
|
config: {
|
|
10
10
|
rootDir: string;
|
|
11
|
-
|
|
11
|
+
srcDirectories: string[];
|
|
12
12
|
};
|
|
13
|
-
getInspectorState: (refresh: boolean) => Promise<{
|
|
14
|
-
filesAndMethods: {
|
|
15
|
-
pikkuConfigFactory?: {
|
|
16
|
-
file: string;
|
|
17
|
-
variable: string;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
}>;
|
|
21
13
|
logger: {
|
|
22
14
|
error: (msg: string) => void;
|
|
15
|
+
warn: (msg: string) => void;
|
|
23
16
|
};
|
|
24
17
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Load the user's pikkuConfig the same way `dev.ts` does — through the
|
|
27
|
-
* inspector state, then by importing the user's config factory file.
|
|
28
|
-
* Returns `null` (and logs the error) if the project hasn't defined a
|
|
29
|
-
* pikkuConfigFactory, so the caller can early-exit.
|
|
30
|
-
*/
|
|
31
18
|
export declare function loadUserConfigForDb(options: LoadOptions): Promise<UserConfigShape | null>;
|
|
32
19
|
export {};
|
|
@@ -1,25 +1,51 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { resolve, join } from 'path';
|
|
3
|
+
import { loadUserModule } from './load-user-project.js';
|
|
4
|
+
function findUserConfigFactoryFile(rootDir, srcDirectories) {
|
|
5
|
+
for (const srcDir of srcDirectories) {
|
|
6
|
+
for (const name of ['config.ts', 'config.js']) {
|
|
7
|
+
const candidate = resolve(rootDir, srcDir, name);
|
|
8
|
+
if (existsSync(candidate))
|
|
9
|
+
return candidate;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
for (const name of ['config.ts', 'config.js']) {
|
|
13
|
+
const candidate = join(rootDir, name);
|
|
14
|
+
if (existsSync(candidate))
|
|
15
|
+
return candidate;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
9
19
|
export async function loadUserConfigForDb(options) {
|
|
10
|
-
const { config,
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
const { config, logger } = options;
|
|
21
|
+
const hasConventionalDbAssets = existsSync(join(config.rootDir, 'db', 'migrations')) ||
|
|
22
|
+
existsSync(join(config.rootDir, 'db', 'seed.sql'));
|
|
23
|
+
const configFactoryFile = findUserConfigFactoryFile(config.rootDir, config.srcDirectories);
|
|
24
|
+
if (!configFactoryFile) {
|
|
25
|
+
if (hasConventionalDbAssets) {
|
|
26
|
+
return { dev: { db: true } };
|
|
27
|
+
}
|
|
14
28
|
logger.error('createConfig must be defined in your project');
|
|
15
29
|
return null;
|
|
16
30
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
let configModule;
|
|
32
|
+
try {
|
|
33
|
+
configModule = await loadUserModule(configFactoryFile);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (hasConventionalDbAssets) {
|
|
37
|
+
logger.warn(`Falling back to default local db config because '${configFactoryFile}' could not be loaded: ${error.message}`);
|
|
38
|
+
return { dev: { db: true } };
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
const userCreateConfig = configModule.createConfig;
|
|
21
43
|
if (typeof userCreateConfig !== 'function') {
|
|
22
|
-
|
|
44
|
+
if (hasConventionalDbAssets) {
|
|
45
|
+
logger.warn(`Falling back to default local db config because '${configFactoryFile}' does not export createConfig`);
|
|
46
|
+
return { dev: { db: true } };
|
|
47
|
+
}
|
|
48
|
+
logger.error(`Expected 'createConfig' in '${configFactoryFile}' to be a function`);
|
|
23
49
|
return null;
|
|
24
50
|
}
|
|
25
51
|
return (await userCreateConfig());
|
|
@@ -3,7 +3,7 @@ import { join, resolve } from 'path';
|
|
|
3
3
|
import { pikkuSessionlessFunc } from '#pikku';
|
|
4
4
|
import chokidar from 'chokidar';
|
|
5
5
|
import { pikkuDevReloader } from '@pikku/core/dev';
|
|
6
|
-
import { ConsoleLogger, InMemoryQueueService, InMemoryWorkflowService, InMemoryTriggerService, InMemoryAIRunStateService, } from '@pikku/core/services';
|
|
6
|
+
import { ConsoleLogger, LocalEmailService, InMemoryQueueService, InMemoryWorkflowService, InMemoryTriggerService, InMemoryAIRunStateService, } from '@pikku/core/services';
|
|
7
7
|
import { KyselyAIStorageService, KyselyAIRunStateService, KyselyAgentRunService, } from '@pikku/kysely';
|
|
8
8
|
import { stopSingletonServices } from '@pikku/core';
|
|
9
9
|
import { pikkuState } from '@pikku/core/internal';
|
|
@@ -23,6 +23,9 @@ export const dev = pikkuSessionlessFunc({
|
|
|
23
23
|
const hostname = 'localhost';
|
|
24
24
|
const enableWatch = watch !== false;
|
|
25
25
|
const enableHmr = hmr !== false;
|
|
26
|
+
const watchDirectories = [
|
|
27
|
+
...new Set([config.emailTemplatesDir, ...config.srcDirectories].filter(Boolean)),
|
|
28
|
+
];
|
|
26
29
|
const commandSingletonServices = pikkuState(null, 'package', 'singletonServices');
|
|
27
30
|
const commandFunctionMeta = {
|
|
28
31
|
...pikkuState(null, 'function', 'meta'),
|
|
@@ -49,7 +52,22 @@ export const dev = pikkuSessionlessFunc({
|
|
|
49
52
|
const previousRPCMeta = pikkuState(null, 'rpc', 'meta');
|
|
50
53
|
const previousWorkflowsMeta = pikkuState(null, 'workflows', 'meta');
|
|
51
54
|
const previousWorkflowRegistrations = pikkuState(null, 'workflows', 'registrations');
|
|
52
|
-
|
|
55
|
+
// During hot-reload (when user services are already live), build a hybrid services
|
|
56
|
+
// object: user services (so in-flight requests keep kysely/content/etc.) overlaid
|
|
57
|
+
// with the CLI config (outDir, scaffold, schemaDirectory, etc. — required by
|
|
58
|
+
// allWorkflow for code generation paths). Replacing the entire services object with
|
|
59
|
+
// commandSingletonServices during hot-reload caused a race condition where concurrent
|
|
60
|
+
// auth requests saw CLI services (no kysely) and crashed.
|
|
61
|
+
const isHotReload = previousSingletonServices !== commandSingletonServices &&
|
|
62
|
+
!!previousSingletonServices;
|
|
63
|
+
const codegenServices = isHotReload
|
|
64
|
+
? {
|
|
65
|
+
...previousSingletonServices,
|
|
66
|
+
config: commandSingletonServices?.config ??
|
|
67
|
+
previousSingletonServices.config,
|
|
68
|
+
}
|
|
69
|
+
: commandSingletonServices;
|
|
70
|
+
pikkuState(null, 'package', 'singletonServices', codegenServices);
|
|
53
71
|
pikkuState(null, 'function', 'functions', new Map([...previousFunctions.entries(), ...commandFunctions.entries()]));
|
|
54
72
|
pikkuState(null, 'function', 'meta', {
|
|
55
73
|
...previousFunctionMeta,
|
|
@@ -98,7 +116,7 @@ export const dev = pikkuSessionlessFunc({
|
|
|
98
116
|
const userCreateConfig = configModule[pikkuConfigFactory.variable];
|
|
99
117
|
const userCreateSingletonServices = servicesModule[singletonServicesFactory.variable];
|
|
100
118
|
const userConfig = await userCreateConfig();
|
|
101
|
-
const resolvedLocalDb = resolveLocalDb(userConfig.dev?.db, config.rootDir, config.outDir, config.runtimeDir);
|
|
119
|
+
const resolvedLocalDb = resolveLocalDb(userConfig.dev?.db ?? true, config.rootDir, config.outDir, config.runtimeDir);
|
|
102
120
|
const kysely = resolvedLocalDb
|
|
103
121
|
? await createKysely(resolvedLocalDb)
|
|
104
122
|
: undefined;
|
|
@@ -136,8 +154,10 @@ export const dev = pikkuSessionlessFunc({
|
|
|
136
154
|
// single instance under both names so addons like @pikku/addon-console
|
|
137
155
|
// can read runs in dev without projects having to wire their own backing
|
|
138
156
|
// store.
|
|
157
|
+
const devLogger = new ConsoleLogger();
|
|
139
158
|
const inMemoryServices = {
|
|
140
|
-
logger:
|
|
159
|
+
logger: devLogger,
|
|
160
|
+
emailService: new LocalEmailService(),
|
|
141
161
|
metaService: new LocalMetaService(pikkuDir),
|
|
142
162
|
schedulerService,
|
|
143
163
|
queueService: new InMemoryQueueService(),
|
|
@@ -190,20 +210,20 @@ export const dev = pikkuSessionlessFunc({
|
|
|
190
210
|
});
|
|
191
211
|
if (enableHmr) {
|
|
192
212
|
await pikkuDevReloader({
|
|
193
|
-
srcDirectories:
|
|
213
|
+
srcDirectories: watchDirectories,
|
|
194
214
|
logger,
|
|
195
215
|
});
|
|
196
216
|
}
|
|
197
217
|
if (enableWatch) {
|
|
198
218
|
const genIgnore = /\.gen\.tsx?$/;
|
|
199
|
-
configWatcher = chokidar.watch(
|
|
219
|
+
configWatcher = chokidar.watch(watchDirectories, {
|
|
200
220
|
ignoreInitial: true,
|
|
201
221
|
ignored: genIgnore,
|
|
202
222
|
});
|
|
203
223
|
const generatorWatcher = () => {
|
|
204
224
|
watcher?.close();
|
|
205
|
-
logger.info(`• Watching directories: \n - ${
|
|
206
|
-
watcher = chokidar.watch(
|
|
225
|
+
logger.info(`• Watching directories: \n - ${watchDirectories.join('\n - ')}`);
|
|
226
|
+
watcher = chokidar.watch(watchDirectories, {
|
|
207
227
|
ignoreInitial: true,
|
|
208
228
|
ignored: genIgnore,
|
|
209
229
|
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type EmailsInitInput = {
|
|
2
|
+
force?: boolean;
|
|
3
|
+
};
|
|
4
|
+
export declare const pikkuEmailsInit: import("#pikku").PikkuFunctionConfig<EmailsInitInput, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<EmailsInitInput, void, "rpc" | "session", import("#pikku").Services> | import("#pikku").PikkuFunction<EmailsInitInput, void, "rpc" | "session", import("#pikku").Services>, undefined, undefined>;
|
|
5
|
+
export {};
|