@pikku/cli 0.12.15 → 0.12.16
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-CzMWJFqj.js +700 -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-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -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 +68 -5
- 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 +16 -19
- package/dist/.pikku/function/pikku-function-types.gen.js +15 -19
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +190 -107
- package/dist/.pikku/function/pikku-functions.gen.js +6 -2
- 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-meta.gen.json +18 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +2 -2
- package/dist/.pikku/http/pikku-http-wirings.gen.js +3 -3
- 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 +3 -10
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -18
- package/dist/.pikku/pikku-meta-service.gen.d.ts +7 -0
- package/dist/.pikku/pikku-meta-service.gen.js +9 -0
- package/dist/.pikku/pikku-services.gen.d.ts +2 -1
- package/dist/.pikku/pikku-services.gen.js +1 -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/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +5 -1
- 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 +15 -7
- package/dist/.pikku/schemas/schemas/DeployApplyInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/DeployPlanInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuNewAddonInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuWorkflowRoutesOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/RemoteRPCHandlerInput.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/pikku-workflow-types.gen.d.ts +3 -24
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -14
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/src/cli.wiring.js +63 -4
- package/dist/src/deploy/analyzer/analyzer.d.ts +16 -0
- package/dist/src/deploy/analyzer/analyzer.js +557 -0
- package/dist/src/deploy/analyzer/index.d.ts +3 -0
- package/dist/src/deploy/analyzer/index.js +1 -0
- package/dist/src/deploy/analyzer/manifest.d.ts +112 -0
- package/dist/src/deploy/analyzer/manifest.js +8 -0
- package/dist/src/deploy/build-pipeline.d.ts +39 -0
- package/dist/src/deploy/build-pipeline.js +209 -0
- package/dist/src/deploy/bundler/bundler.d.ts +30 -0
- package/dist/src/deploy/bundler/bundler.js +196 -0
- package/dist/src/deploy/bundler/dep-extractor.d.ts +35 -0
- package/dist/src/deploy/bundler/dep-extractor.js +213 -0
- package/dist/src/deploy/bundler/index.d.ts +3 -0
- package/dist/src/deploy/bundler/index.js +2 -0
- package/dist/src/deploy/bundler/types.d.ts +21 -0
- package/dist/src/deploy/bundler/types.js +5 -0
- package/dist/src/deploy/codegen/index.d.ts +2 -0
- package/dist/src/deploy/codegen/index.js +1 -0
- package/dist/src/deploy/codegen/per-unit-codegen.d.ts +44 -0
- package/dist/src/deploy/codegen/per-unit-codegen.js +216 -0
- package/dist/src/deploy/plan/executor.d.ts +9 -0
- package/dist/src/deploy/plan/executor.js +49 -0
- package/dist/src/deploy/plan/formatter.d.ts +4 -0
- package/dist/src/deploy/plan/formatter.js +114 -0
- package/dist/src/deploy/plan/index.d.ts +5 -0
- package/dist/src/deploy/plan/index.js +3 -0
- package/dist/src/deploy/plan/planner.d.ts +4 -0
- package/dist/src/deploy/plan/planner.js +220 -0
- package/dist/src/deploy/plan/provider.d.ts +30 -0
- package/dist/src/deploy/plan/provider.js +1 -0
- package/dist/src/deploy/plan/types.d.ts +29 -0
- package/dist/src/deploy/plan/types.js +1 -0
- package/dist/src/deploy/provider-adapter.d.ts +111 -0
- package/dist/src/deploy/provider-adapter.js +10 -0
- package/dist/src/functions/commands/all.js +6 -2
- package/dist/src/functions/commands/deploy-apply.d.ts +22 -0
- package/dist/src/functions/commands/deploy-apply.js +206 -0
- package/dist/src/functions/commands/deploy-info.d.ts +1 -0
- package/dist/src/functions/commands/deploy-info.js +122 -0
- package/dist/src/functions/commands/deploy-plan.d.ts +10 -0
- package/dist/src/functions/commands/deploy-plan.js +96 -0
- package/dist/src/functions/commands/enable.js +1 -1
- package/dist/src/functions/commands/new-addon.d.ts +3 -0
- package/dist/src/functions/commands/new-addon.js +68 -2
- package/dist/src/functions/commands/pikku-command-bootstrap.js +30 -20
- package/dist/src/functions/runtimes/nextjs/pikku-command-nextjs.js +7 -3
- package/dist/src/functions/wirings/ai-agent/pikku-command-ai-agent.js +7 -5
- package/dist/src/functions/wirings/channels/pikku-channels.js +3 -0
- package/dist/src/functions/wirings/channels/pikku-command-channels.js +3 -0
- package/dist/src/functions/wirings/cli/pikku-command-cli.js +3 -0
- package/dist/src/functions/wirings/cli/serialize-channel-cli.js +2 -2
- package/dist/src/functions/wirings/console/serialize-console-functions.js +2 -2
- package/dist/src/functions/wirings/functions/pikku-command-services.d.ts +1 -1
- package/dist/src/functions/wirings/functions/pikku-command-services.js +9 -2
- package/dist/src/functions/wirings/functions/serialize-function-imports.js +5 -3
- package/dist/src/functions/wirings/functions/serialize-function-types.js +17 -19
- package/dist/src/functions/wirings/http/pikku-command-http-routes.js +3 -0
- package/dist/src/functions/wirings/http/pikku-http-routes.js +3 -0
- package/dist/src/functions/wirings/mcp/pikku-command-mcp.js +6 -0
- package/dist/src/functions/wirings/package/pikku-command-package.js +1 -1
- package/dist/src/functions/wirings/package/serialize-package.d.ts +1 -1
- package/dist/src/functions/wirings/package/serialize-package.js +5 -2
- package/dist/src/functions/wirings/queue/pikku-command-queue.js +4 -0
- package/dist/src/functions/wirings/queue/pikku-queue.js +4 -0
- package/dist/src/functions/wirings/queue/serialize-queue-map.js +4 -1
- package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +10 -3
- package/dist/src/functions/wirings/rpc/serialize-public-rpc.js +5 -27
- package/dist/src/functions/wirings/rpc/serialize-remote-rpc.js +11 -14
- package/dist/src/functions/wirings/rpc/serialize-rpc-wrapper.js +28 -3
- package/dist/src/functions/wirings/rpc/serialize-typed-rpc-map.js +15 -5
- package/dist/src/functions/wirings/scheduler/pikku-command-scheduler.js +4 -0
- package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.d.ts +1 -0
- package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.js +21 -0
- package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +10 -9
- package/dist/src/functions/wirings/workflow/serialize-workflow-map.d.ts +6 -1
- package/dist/src/functions/wirings/workflow/serialize-workflow-map.js +42 -5
- package/dist/src/functions/wirings/workflow/serialize-workflow-registration.d.ts +1 -1
- package/dist/src/functions/wirings/workflow/serialize-workflow-registration.js +3 -2
- package/dist/src/functions/wirings/workflow/serialize-workflow-routes.d.ts +4 -0
- package/dist/src/functions/wirings/workflow/serialize-workflow-routes.js +139 -0
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +4 -51
- package/dist/src/scaffold/rpc-remote.gen.d.ts +10 -0
- package/dist/src/scaffold/rpc-remote.gen.js +22 -0
- package/dist/src/services.js +12 -7
- package/dist/src/utils/pikku-cli-config.d.ts +1 -1
- package/dist/src/utils/pikku-cli-config.js +30 -28
- package/dist/src/utils/strip-verbose-meta.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -4
- package/console-app/assets/index-robZPL3O.js +0 -672
- package/dist/src/functions/wirings/workflow/serialize-workflow-workers.d.ts +0 -4
- package/dist/src/functions/wirings/workflow/serialize-workflow-workers.js +0 -47
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared build pipeline for deploy plan and apply.
|
|
3
|
+
*
|
|
4
|
+
* Runs: analyze → per-unit codegen → entry generation → bundle → configs
|
|
5
|
+
* Outputs everything to .deploy/<provider>/ without deploying.
|
|
6
|
+
*/
|
|
7
|
+
import type { InspectorState } from '@pikku/inspector';
|
|
8
|
+
import type { DeploymentManifest } from './analyzer/manifest.js';
|
|
9
|
+
import type { BundleResult } from './bundler/index.js';
|
|
10
|
+
import type { ProviderAdapter } from './provider-adapter.js';
|
|
11
|
+
export interface BuildLogger {
|
|
12
|
+
info(msg: string): void;
|
|
13
|
+
error(msg: string): void;
|
|
14
|
+
debug(msg: string): void;
|
|
15
|
+
}
|
|
16
|
+
export interface BuildPipelineResult {
|
|
17
|
+
manifest: DeploymentManifest;
|
|
18
|
+
providerDir: string;
|
|
19
|
+
projectId: string;
|
|
20
|
+
bundled: BundleResult[];
|
|
21
|
+
bundleErrors: Array<{
|
|
22
|
+
unitName: string;
|
|
23
|
+
error: string;
|
|
24
|
+
}>;
|
|
25
|
+
codegenErrors: Array<{
|
|
26
|
+
unitName: string;
|
|
27
|
+
error: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export declare function runBuildPipeline(options: {
|
|
31
|
+
projectDir: string;
|
|
32
|
+
projectId: string;
|
|
33
|
+
provider: ProviderAdapter;
|
|
34
|
+
inspectorState: InspectorState;
|
|
35
|
+
serverlessIncompatible?: string[];
|
|
36
|
+
getEntryContext: (unitDir: string, pikkuDir: string, unit: DeploymentManifest['units'][0], state: InspectorState) => unknown;
|
|
37
|
+
deployDir?: string;
|
|
38
|
+
logger: BuildLogger;
|
|
39
|
+
}): Promise<BuildPipelineResult>;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared build pipeline for deploy plan and apply.
|
|
3
|
+
*
|
|
4
|
+
* Runs: analyze → per-unit codegen → entry generation → bundle → configs
|
|
5
|
+
* Outputs everything to .deploy/<provider>/ without deploying.
|
|
6
|
+
*/
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { mkdir, writeFile, copyFile } from 'node:fs/promises';
|
|
10
|
+
import { analyzeDeployment } from './analyzer/index.js';
|
|
11
|
+
import { generatePerUnitCodegen } from './codegen/per-unit-codegen.js';
|
|
12
|
+
import { bundleUnits } from './bundler/index.js';
|
|
13
|
+
function findLockfile(projectDir) {
|
|
14
|
+
for (const name of ['yarn.lock', 'package-lock.json', 'pnpm-lock.yaml']) {
|
|
15
|
+
const p = join(projectDir, name);
|
|
16
|
+
if (existsSync(p))
|
|
17
|
+
return p;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
export async function runBuildPipeline(options) {
|
|
22
|
+
const { projectDir, projectId, provider, inspectorState, getEntryContext, logger, } = options;
|
|
23
|
+
const deployDir = options.deployDir ?? join(projectDir, '.deploy');
|
|
24
|
+
const providerDir = join(deployDir, provider.deployDirName);
|
|
25
|
+
// Step 1: Analyze
|
|
26
|
+
const manifest = analyzeDeployment(inspectorState, {
|
|
27
|
+
projectId,
|
|
28
|
+
serverlessIncompatible: options.serverlessIncompatible,
|
|
29
|
+
});
|
|
30
|
+
let bundled = [];
|
|
31
|
+
let bundleErrors = [];
|
|
32
|
+
let codegenErrors = [];
|
|
33
|
+
if (provider.singleUnit) {
|
|
34
|
+
// Single-unit mode: bundle everything into one unit, use project's .pikku/ directly
|
|
35
|
+
logger.info('Building standalone bundle...');
|
|
36
|
+
const unitName = projectId;
|
|
37
|
+
const singleUnit = {
|
|
38
|
+
name: unitName,
|
|
39
|
+
role: 'function',
|
|
40
|
+
target: 'serverless',
|
|
41
|
+
functionIds: Object.keys(inspectorState.functions.meta),
|
|
42
|
+
services: [],
|
|
43
|
+
dependsOn: [],
|
|
44
|
+
handlers: [],
|
|
45
|
+
tags: [],
|
|
46
|
+
};
|
|
47
|
+
manifest.units = [singleUnit];
|
|
48
|
+
const unitDir = join(providerDir, unitName);
|
|
49
|
+
const pikkuDir = join(projectDir, '.pikku');
|
|
50
|
+
await mkdir(unitDir, { recursive: true });
|
|
51
|
+
const ctx = getEntryContext(unitDir, pikkuDir, singleUnit, inspectorState);
|
|
52
|
+
const source = provider.generateEntrySource(ctx);
|
|
53
|
+
const entryPath = join(unitDir, 'entry.ts');
|
|
54
|
+
await writeFile(entryPath, source, 'utf-8');
|
|
55
|
+
const entryFiles = new Map();
|
|
56
|
+
entryFiles.set(unitName, entryPath);
|
|
57
|
+
const bundleResult = await bundleUnits(projectDir, manifest, entryFiles, providerDir, {
|
|
58
|
+
externals: provider.getExternals?.(),
|
|
59
|
+
aliases: provider.getAliases?.(),
|
|
60
|
+
define: provider.getDefine?.(),
|
|
61
|
+
platform: provider.getPlatform?.(),
|
|
62
|
+
format: provider.getFormat?.(),
|
|
63
|
+
});
|
|
64
|
+
bundled = bundleResult.results;
|
|
65
|
+
bundleErrors = bundleResult.errors;
|
|
66
|
+
logger.info(`Bundled standalone${bundleErrors.length > 0 ? ` (${bundleErrors.length} errors)` : ''}`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// Multi-unit mode: per-function decomposition
|
|
70
|
+
const serverlessUnits = manifest.units.filter((u) => u.target === 'serverless');
|
|
71
|
+
const serverUnits = manifest.units.filter((u) => u.target === 'server');
|
|
72
|
+
logger.info(`Found ${manifest.units.length} units (${serverlessUnits.length} serverless, ${serverUnits.length} server), ${manifest.queues.length} queues, ${manifest.scheduledTasks.length} scheduled tasks`);
|
|
73
|
+
if (manifest.units.length === 0) {
|
|
74
|
+
return {
|
|
75
|
+
manifest,
|
|
76
|
+
providerDir,
|
|
77
|
+
projectId,
|
|
78
|
+
bundled: [],
|
|
79
|
+
bundleErrors: [],
|
|
80
|
+
codegenErrors: [],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// Step 2: Per-unit filtered codegen (serverless units only)
|
|
84
|
+
// Server units share a single codegen pass (step 2b).
|
|
85
|
+
const serverlessManifest = { ...manifest, units: serverlessUnits };
|
|
86
|
+
logger.info('Generating per-unit codegen...');
|
|
87
|
+
const { unitPikkuDirs, errors: serverlessCodegenErrors } = await generatePerUnitCodegen({
|
|
88
|
+
projectDir,
|
|
89
|
+
manifest: serverlessManifest,
|
|
90
|
+
inspectorState,
|
|
91
|
+
deployDir: providerDir,
|
|
92
|
+
onProgress: (unitName, status, error) => {
|
|
93
|
+
if (status === 'start') {
|
|
94
|
+
logger.info(` Codegen: ${unitName}...`);
|
|
95
|
+
}
|
|
96
|
+
else if (status === 'done') {
|
|
97
|
+
logger.info(` Codegen: ${unitName} done`);
|
|
98
|
+
}
|
|
99
|
+
else if (status === 'error') {
|
|
100
|
+
logger.error(` Codegen: ${unitName} failed — ${error}`);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
codegenErrors = serverlessCodegenErrors;
|
|
105
|
+
// Step 2b: Server units — single codegen pass with all server function IDs
|
|
106
|
+
if (serverUnits.length > 0) {
|
|
107
|
+
const serverUnitName = 'server';
|
|
108
|
+
// Create a merged server unit with all server function IDs
|
|
109
|
+
const mergedServerUnit = {
|
|
110
|
+
name: serverUnitName,
|
|
111
|
+
role: 'function',
|
|
112
|
+
target: 'server',
|
|
113
|
+
functionIds: serverUnits.flatMap((u) => u.functionIds),
|
|
114
|
+
services: [],
|
|
115
|
+
dependsOn: [],
|
|
116
|
+
handlers: serverUnits.flatMap((u) => u.handlers),
|
|
117
|
+
tags: [],
|
|
118
|
+
};
|
|
119
|
+
// Run per-unit codegen for the merged server unit (tree-shakes to only server functions)
|
|
120
|
+
const serverManifest = { ...manifest, units: [mergedServerUnit] };
|
|
121
|
+
const { unitPikkuDirs: serverPikkuDirs, errors: serverCodegenErrors } = await generatePerUnitCodegen({
|
|
122
|
+
projectDir,
|
|
123
|
+
manifest: serverManifest,
|
|
124
|
+
inspectorState,
|
|
125
|
+
deployDir: providerDir,
|
|
126
|
+
onProgress: (unitName, status, error) => {
|
|
127
|
+
if (status === 'start')
|
|
128
|
+
logger.info(` Codegen: ${unitName}...`);
|
|
129
|
+
else if (status === 'done')
|
|
130
|
+
logger.info(` Codegen: ${unitName} done`);
|
|
131
|
+
else if (status === 'error')
|
|
132
|
+
logger.error(` Codegen: ${unitName} failed — ${error}`);
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
for (const [k, v] of serverPikkuDirs)
|
|
136
|
+
unitPikkuDirs.set(k, v);
|
|
137
|
+
codegenErrors.push(...serverCodegenErrors);
|
|
138
|
+
// Replace individual server units with the merged one in the manifest
|
|
139
|
+
manifest.units = [...serverlessUnits, mergedServerUnit];
|
|
140
|
+
logger.info(` Server container: ${serverUnits.length} functions merged into one unit`);
|
|
141
|
+
}
|
|
142
|
+
logger.info(`Codegen complete: ${unitPikkuDirs.size} units`);
|
|
143
|
+
// Step 3: Generate entry points + Bundle
|
|
144
|
+
logger.info('Bundling...');
|
|
145
|
+
const entryFiles = new Map();
|
|
146
|
+
for (const unit of manifest.units) {
|
|
147
|
+
const pikkuDir = unitPikkuDirs.get(unit.name);
|
|
148
|
+
if (!pikkuDir)
|
|
149
|
+
continue;
|
|
150
|
+
const unitDir = join(providerDir, unit.name);
|
|
151
|
+
const entryPath = join(unitDir, 'entry.ts');
|
|
152
|
+
await mkdir(unitDir, { recursive: true });
|
|
153
|
+
const ctx = getEntryContext(unitDir, pikkuDir, unit, inspectorState);
|
|
154
|
+
const source = provider.generateEntrySource(ctx);
|
|
155
|
+
await writeFile(entryPath, source, 'utf-8');
|
|
156
|
+
entryFiles.set(unit.name, entryPath);
|
|
157
|
+
}
|
|
158
|
+
const bundleResult = await bundleUnits(projectDir, manifest, entryFiles, providerDir, {
|
|
159
|
+
externals: provider.getExternals?.(),
|
|
160
|
+
aliases: provider.getAliases?.(),
|
|
161
|
+
define: provider.getDefine?.(),
|
|
162
|
+
platform: provider.getPlatform?.(),
|
|
163
|
+
format: provider.getFormat?.(),
|
|
164
|
+
});
|
|
165
|
+
bundled = bundleResult.results;
|
|
166
|
+
bundleErrors = bundleResult.errors;
|
|
167
|
+
logger.info(`Bundled ${bundled.length} units${bundleErrors.length > 0 ? ` (${bundleErrors.length} failed)` : ''}`);
|
|
168
|
+
}
|
|
169
|
+
if (bundleErrors.length > 0) {
|
|
170
|
+
for (const f of bundleErrors) {
|
|
171
|
+
logger.error(` Failed: ${f.unitName} — ${f.error}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Step 4: Generate configs + infra manifest
|
|
175
|
+
const infraContent = provider.generateInfraManifest(manifest);
|
|
176
|
+
if (infraContent) {
|
|
177
|
+
await writeFile(join(providerDir, 'infra.json'), infraContent, 'utf-8');
|
|
178
|
+
logger.info('Generated infrastructure manifest');
|
|
179
|
+
}
|
|
180
|
+
if (provider.generateProviderConfigs) {
|
|
181
|
+
const providerConfigs = provider.generateProviderConfigs(manifest);
|
|
182
|
+
for (const [filename, content] of providerConfigs) {
|
|
183
|
+
const filePath = join(providerDir, filename);
|
|
184
|
+
await mkdir(join(filePath, '..'), { recursive: true });
|
|
185
|
+
await writeFile(filePath, content, 'utf-8');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const lockfileSrc = findLockfile(projectDir);
|
|
189
|
+
for (const unit of manifest.units) {
|
|
190
|
+
const unitDir = join(providerDir, unit.name);
|
|
191
|
+
await mkdir(unitDir, { recursive: true });
|
|
192
|
+
const configs = provider.generateUnitConfigs(unit, manifest, projectId);
|
|
193
|
+
for (const [filename, content] of configs) {
|
|
194
|
+
await writeFile(join(unitDir, filename), content, 'utf-8');
|
|
195
|
+
}
|
|
196
|
+
if (lockfileSrc) {
|
|
197
|
+
await copyFile(lockfileSrc, join(unitDir, 'yarn.lock'));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
logger.info(`Generated ${manifest.units.length} provider config files`);
|
|
201
|
+
return {
|
|
202
|
+
manifest,
|
|
203
|
+
providerDir,
|
|
204
|
+
projectId,
|
|
205
|
+
bundled,
|
|
206
|
+
bundleErrors,
|
|
207
|
+
codegenErrors,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main esbuild bundling pipeline for Pikku.
|
|
3
|
+
*
|
|
4
|
+
* For each deployment unit in a DeploymentManifest, this module:
|
|
5
|
+
* 1. Takes a pre-generated entry point (provided by the deploy provider)
|
|
6
|
+
* 2. Runs esbuild with bundle:true, npm packages external
|
|
7
|
+
* 3. Stubs Node.js-only gen files that aren't needed by this unit
|
|
8
|
+
* 4. Parses the metafile to extract external dependencies
|
|
9
|
+
* 5. Generates a minimal package.json with exact versions
|
|
10
|
+
* 6. Writes all artifacts to `<outputDir>/<unit-name>/`
|
|
11
|
+
*/
|
|
12
|
+
import type { DeploymentManifest, BundleOutput } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Bundles all deployment units defined in a DeploymentManifest.
|
|
15
|
+
*
|
|
16
|
+
* Entry points must be pre-generated by the provider-specific package
|
|
17
|
+
* (e.g. @pikku/deploy-cloudflare) and passed in as entryFiles.
|
|
18
|
+
*
|
|
19
|
+
* @param projectDir - Root directory of the Pikku project
|
|
20
|
+
* @param manifest - The deployment manifest describing all units
|
|
21
|
+
* @param entryFiles - Map of unit name -> entry file path (generated by the deploy provider)
|
|
22
|
+
* @param outputDir - Base output directory (defaults to `<projectDir>/.deploy/build`)
|
|
23
|
+
*/
|
|
24
|
+
export declare function bundleUnits(projectDir: string, manifest: DeploymentManifest, entryFiles: Map<string, string>, outputDir?: string, options?: {
|
|
25
|
+
externals?: string[];
|
|
26
|
+
aliases?: Record<string, string>;
|
|
27
|
+
define?: Record<string, string>;
|
|
28
|
+
platform?: 'node' | 'neutral' | 'browser';
|
|
29
|
+
format?: 'esm' | 'cjs';
|
|
30
|
+
}): Promise<BundleOutput>;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main esbuild bundling pipeline for Pikku.
|
|
3
|
+
*
|
|
4
|
+
* For each deployment unit in a DeploymentManifest, this module:
|
|
5
|
+
* 1. Takes a pre-generated entry point (provided by the deploy provider)
|
|
6
|
+
* 2. Runs esbuild with bundle:true, npm packages external
|
|
7
|
+
* 3. Stubs Node.js-only gen files that aren't needed by this unit
|
|
8
|
+
* 4. Parses the metafile to extract external dependencies
|
|
9
|
+
* 5. Generates a minimal package.json with exact versions
|
|
10
|
+
* 6. Writes all artifacts to `<outputDir>/<unit-name>/`
|
|
11
|
+
*/
|
|
12
|
+
import { build } from 'esbuild';
|
|
13
|
+
import { writeFile, mkdir, stat, readFile } from 'node:fs/promises';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { extractDependencies, generateMinimalPackageJson, } from './dep-extractor.js';
|
|
16
|
+
/**
|
|
17
|
+
* Mapping of service name -> gen file pattern that should be stubbed
|
|
18
|
+
* when the service is not required by a deployment unit.
|
|
19
|
+
*/
|
|
20
|
+
const SERVICE_GEN_FILE_MAP = {
|
|
21
|
+
metaService: /pikku-meta-service\.gen/,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Read the per-unit pikku-services.gen.ts and return the set of gen file
|
|
25
|
+
* patterns that should be stubbed (because their service is not required).
|
|
26
|
+
*/
|
|
27
|
+
async function getDeadGenFilePatterns(unitOutputDir) {
|
|
28
|
+
const patterns = [];
|
|
29
|
+
try {
|
|
30
|
+
const servicesPath = join(unitOutputDir, '.pikku', 'pikku-services.gen.ts');
|
|
31
|
+
const content = await readFile(servicesPath, 'utf-8');
|
|
32
|
+
const match = content.match(/export const requiredSingletonServices = \{([^}]+)\}/);
|
|
33
|
+
if (match) {
|
|
34
|
+
for (const line of match[1].split('\n')) {
|
|
35
|
+
const kv = line.match(/'([^']+)':\s*false/);
|
|
36
|
+
if (kv && SERVICE_GEN_FILE_MAP[kv[1]]) {
|
|
37
|
+
patterns.push(SERVICE_GEN_FILE_MAP[kv[1]]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// No services gen — no stubs needed
|
|
44
|
+
}
|
|
45
|
+
return patterns;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* esbuild plugin that stubs gen files for services not needed by this unit.
|
|
49
|
+
* This prevents Node.js-only modules (e.g. LocalMetaService which uses fs)
|
|
50
|
+
* from being pulled into serverless worker bundles via dynamic imports.
|
|
51
|
+
*/
|
|
52
|
+
function createDeadModuleStubPlugin(patterns) {
|
|
53
|
+
return {
|
|
54
|
+
name: 'pikku-dead-module-stub',
|
|
55
|
+
setup(build) {
|
|
56
|
+
if (patterns.length === 0)
|
|
57
|
+
return;
|
|
58
|
+
const combined = new RegExp(patterns.map((p) => p.source).join('|'));
|
|
59
|
+
build.onResolve({ filter: combined }, (args) => ({
|
|
60
|
+
path: args.path,
|
|
61
|
+
namespace: 'pikku-stub',
|
|
62
|
+
}));
|
|
63
|
+
build.onLoad({ filter: /.*/, namespace: 'pikku-stub' }, () => ({
|
|
64
|
+
contents: 'export {}',
|
|
65
|
+
loader: 'js',
|
|
66
|
+
}));
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const BUNDLE_FILENAME = 'bundle.js';
|
|
71
|
+
const METAFILE_FILENAME = 'metafile.json';
|
|
72
|
+
const PACKAGE_JSON_FILENAME = 'package.json';
|
|
73
|
+
/**
|
|
74
|
+
* Bundles a single deployment unit using esbuild.
|
|
75
|
+
*
|
|
76
|
+
* Produces three files in the unit output directory:
|
|
77
|
+
* - bundle.js: The bundled code (user code only, external deps as bare imports)
|
|
78
|
+
* - metafile.json: esbuild's metafile for analysis
|
|
79
|
+
* - package.json: Minimal manifest with only the external deps this unit needs
|
|
80
|
+
*/
|
|
81
|
+
async function bundleUnit(options) {
|
|
82
|
+
const { unit, entryPath, unitOutputDir, projectDir, externals, aliases, define, platform, format, } = options;
|
|
83
|
+
await mkdir(unitOutputDir, { recursive: true });
|
|
84
|
+
const bundlePath = join(unitOutputDir, BUNDLE_FILENAME);
|
|
85
|
+
const metafilePath = join(unitOutputDir, METAFILE_FILENAME);
|
|
86
|
+
const packageJsonPath = join(unitOutputDir, PACKAGE_JSON_FILENAME);
|
|
87
|
+
// Determine which gen files to stub based on per-unit service requirements
|
|
88
|
+
const deadPatterns = await getDeadGenFilePatterns(unitOutputDir);
|
|
89
|
+
// Run esbuild — inline everything into a self-contained bundle.
|
|
90
|
+
// Only Node built-ins are kept external (CF Workers provides them).
|
|
91
|
+
// The stub plugin replaces gen files for unused services with empty
|
|
92
|
+
// modules, preventing Node.js-only code from entering the bundle.
|
|
93
|
+
// Resolve node_modules paths up the directory tree for workspace packages
|
|
94
|
+
const nodePaths = [];
|
|
95
|
+
let dir = projectDir;
|
|
96
|
+
while (true) {
|
|
97
|
+
const nm = join(dir, 'node_modules');
|
|
98
|
+
nodePaths.push(nm);
|
|
99
|
+
const parent = join(dir, '..');
|
|
100
|
+
if (parent === dir)
|
|
101
|
+
break;
|
|
102
|
+
dir = parent;
|
|
103
|
+
}
|
|
104
|
+
// For ESM + node platform, CJS deps may use require() for builtins.
|
|
105
|
+
// esbuild wraps these as __require() which fails at runtime in ESM.
|
|
106
|
+
// The banner shims require via createRequire so CJS builtins resolve.
|
|
107
|
+
const resolvedFormat = format ?? 'esm';
|
|
108
|
+
const banner = resolvedFormat === 'esm' && (platform ?? 'node') === 'node'
|
|
109
|
+
? { js: `import { createRequire } from 'module'; const require = createRequire(import.meta.url);` }
|
|
110
|
+
: undefined;
|
|
111
|
+
const result = await build({
|
|
112
|
+
entryPoints: [entryPath],
|
|
113
|
+
bundle: true,
|
|
114
|
+
absWorkingDir: projectDir,
|
|
115
|
+
nodePaths,
|
|
116
|
+
platform: platform ?? 'node',
|
|
117
|
+
format: resolvedFormat,
|
|
118
|
+
banner,
|
|
119
|
+
metafile: true,
|
|
120
|
+
target: 'es2022',
|
|
121
|
+
outfile: bundlePath,
|
|
122
|
+
minify: false,
|
|
123
|
+
sourcemap: true,
|
|
124
|
+
logLevel: 'warning',
|
|
125
|
+
loader: { '.ts': 'ts' },
|
|
126
|
+
external: externals ?? ['node:*'],
|
|
127
|
+
alias: aliases,
|
|
128
|
+
define,
|
|
129
|
+
plugins: [createDeadModuleStubPlugin(deadPatterns)],
|
|
130
|
+
});
|
|
131
|
+
// Write metafile
|
|
132
|
+
const metafileJson = JSON.stringify(result.metafile, null, 2);
|
|
133
|
+
await writeFile(metafilePath, metafileJson, 'utf-8');
|
|
134
|
+
// Extract dependencies and generate minimal package.json
|
|
135
|
+
const dependencies = await extractDependencies(result.metafile, projectDir);
|
|
136
|
+
const packageJson = generateMinimalPackageJson(unit.name, dependencies);
|
|
137
|
+
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf-8');
|
|
138
|
+
// Get bundle size
|
|
139
|
+
const bundleStat = await stat(bundlePath);
|
|
140
|
+
return {
|
|
141
|
+
unitName: unit.name,
|
|
142
|
+
bundlePath,
|
|
143
|
+
packageJsonPath,
|
|
144
|
+
metafilePath,
|
|
145
|
+
bundleSizeBytes: bundleStat.size,
|
|
146
|
+
externalPackages: dependencies,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Bundles all deployment units defined in a DeploymentManifest.
|
|
151
|
+
*
|
|
152
|
+
* Entry points must be pre-generated by the provider-specific package
|
|
153
|
+
* (e.g. @pikku/deploy-cloudflare) and passed in as entryFiles.
|
|
154
|
+
*
|
|
155
|
+
* @param projectDir - Root directory of the Pikku project
|
|
156
|
+
* @param manifest - The deployment manifest describing all units
|
|
157
|
+
* @param entryFiles - Map of unit name -> entry file path (generated by the deploy provider)
|
|
158
|
+
* @param outputDir - Base output directory (defaults to `<projectDir>/.deploy/build`)
|
|
159
|
+
*/
|
|
160
|
+
export async function bundleUnits(projectDir, manifest, entryFiles, outputDir, options) {
|
|
161
|
+
const buildDir = outputDir ?? join(projectDir, '.deploy', 'build');
|
|
162
|
+
const results = [];
|
|
163
|
+
const errors = [];
|
|
164
|
+
if (manifest.units.length === 0) {
|
|
165
|
+
return { results, errors };
|
|
166
|
+
}
|
|
167
|
+
for (const unit of manifest.units) {
|
|
168
|
+
const entryPath = entryFiles.get(unit.name);
|
|
169
|
+
if (!entryPath) {
|
|
170
|
+
errors.push({
|
|
171
|
+
unitName: unit.name,
|
|
172
|
+
error: `No entry point provided for unit "${unit.name}"`,
|
|
173
|
+
});
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const unitOutputDir = join(buildDir, unit.name);
|
|
177
|
+
try {
|
|
178
|
+
const result = await bundleUnit({
|
|
179
|
+
unit,
|
|
180
|
+
entryPath,
|
|
181
|
+
unitOutputDir,
|
|
182
|
+
projectDir,
|
|
183
|
+
...options,
|
|
184
|
+
});
|
|
185
|
+
results.push(result);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
189
|
+
errors.push({
|
|
190
|
+
unitName: unit.name,
|
|
191
|
+
error: message,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return { results, errors };
|
|
196
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts external dependency information from esbuild metafiles.
|
|
3
|
+
*
|
|
4
|
+
* Parses esbuild's metafile JSON to find all node_modules references,
|
|
5
|
+
* then resolves their exact versions from the project's package.json
|
|
6
|
+
* and/or yarn.lock to produce a minimal package.json.
|
|
7
|
+
*/
|
|
8
|
+
import type { Metafile } from 'esbuild';
|
|
9
|
+
/**
|
|
10
|
+
* Extracts bare package names from esbuild metafile imports.
|
|
11
|
+
*
|
|
12
|
+
* When esbuild runs with `packages: 'external'`, external imports appear
|
|
13
|
+
* in the metafile's outputs[].imports array with `external: true`.
|
|
14
|
+
* This function collects all unique package names from those imports.
|
|
15
|
+
*/
|
|
16
|
+
export declare function extractExternalPackages(metafile: Metafile): Set<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Parses a bare import specifier into a package name.
|
|
19
|
+
*
|
|
20
|
+
* Handles scoped packages (`@scope/pkg`) and deep imports (`pkg/sub/path`).
|
|
21
|
+
* Returns null for relative imports or other non-package specifiers.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parsePackageName(specifier: string): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Given an esbuild metafile, extracts all external packages and resolves
|
|
26
|
+
* their versions from the project's dependency files.
|
|
27
|
+
*
|
|
28
|
+
* Returns a record of package name to exact version, suitable for
|
|
29
|
+
* writing into a minimal package.json.
|
|
30
|
+
*/
|
|
31
|
+
export declare function extractDependencies(metafile: Metafile, projectDir: string): Promise<Record<string, string>>;
|
|
32
|
+
/**
|
|
33
|
+
* Generates a minimal package.json content object for a unit bundle.
|
|
34
|
+
*/
|
|
35
|
+
export declare function generateMinimalPackageJson(unitName: string, dependencies: Record<string, string>): Record<string, unknown>;
|