@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.
Files changed (160) hide show
  1. package/cli.schema.json +1 -1
  2. package/console-app/assets/index-CzMWJFqj.js +700 -0
  3. package/console-app/index.html +1 -1
  4. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  5. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  6. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  7. package/dist/.pikku/cli/pikku-cli-channel.js +16 -1
  8. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  9. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  10. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  11. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  12. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  13. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +68 -5
  14. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  15. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  16. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  17. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  18. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  19. package/dist/.pikku/function/pikku-function-types.gen.d.ts +16 -19
  20. package/dist/.pikku/function/pikku-function-types.gen.js +15 -19
  21. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  22. package/dist/.pikku/function/pikku-functions-meta.gen.json +190 -107
  23. package/dist/.pikku/function/pikku-functions.gen.js +6 -2
  24. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  25. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  26. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  27. package/dist/.pikku/http/pikku-http-wirings-meta.gen.json +18 -1
  28. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +2 -2
  29. package/dist/.pikku/http/pikku-http-wirings.gen.js +3 -3
  30. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  31. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  32. package/dist/.pikku/pikku-bootstrap.gen.d.ts +3 -10
  33. package/dist/.pikku/pikku-bootstrap.gen.js +1 -18
  34. package/dist/.pikku/pikku-meta-service.gen.d.ts +7 -0
  35. package/dist/.pikku/pikku-meta-service.gen.js +9 -0
  36. package/dist/.pikku/pikku-services.gen.d.ts +2 -1
  37. package/dist/.pikku/pikku-services.gen.js +1 -0
  38. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  39. package/dist/.pikku/pikku-types.gen.js +1 -1
  40. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  41. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  42. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  43. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +5 -1
  44. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  45. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  46. package/dist/.pikku/schemas/register.gen.js +15 -7
  47. package/dist/.pikku/schemas/schemas/DeployApplyInput.schema.json +1 -0
  48. package/dist/.pikku/schemas/schemas/DeployPlanInput.schema.json +1 -0
  49. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  50. package/dist/.pikku/schemas/schemas/PikkuNewAddonInput.schema.json +1 -1
  51. package/dist/.pikku/schemas/schemas/PikkuWorkflowRoutesOutput.schema.json +1 -0
  52. package/dist/.pikku/schemas/schemas/RemoteRPCHandlerInput.schema.json +1 -0
  53. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  54. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  55. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  56. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  57. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  58. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  59. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  60. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  61. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  62. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  63. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +3 -24
  64. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -14
  65. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  66. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.d.ts +1 -1
  67. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  68. package/dist/src/cli.wiring.js +63 -4
  69. package/dist/src/deploy/analyzer/analyzer.d.ts +16 -0
  70. package/dist/src/deploy/analyzer/analyzer.js +557 -0
  71. package/dist/src/deploy/analyzer/index.d.ts +3 -0
  72. package/dist/src/deploy/analyzer/index.js +1 -0
  73. package/dist/src/deploy/analyzer/manifest.d.ts +112 -0
  74. package/dist/src/deploy/analyzer/manifest.js +8 -0
  75. package/dist/src/deploy/build-pipeline.d.ts +39 -0
  76. package/dist/src/deploy/build-pipeline.js +209 -0
  77. package/dist/src/deploy/bundler/bundler.d.ts +30 -0
  78. package/dist/src/deploy/bundler/bundler.js +196 -0
  79. package/dist/src/deploy/bundler/dep-extractor.d.ts +35 -0
  80. package/dist/src/deploy/bundler/dep-extractor.js +213 -0
  81. package/dist/src/deploy/bundler/index.d.ts +3 -0
  82. package/dist/src/deploy/bundler/index.js +2 -0
  83. package/dist/src/deploy/bundler/types.d.ts +21 -0
  84. package/dist/src/deploy/bundler/types.js +5 -0
  85. package/dist/src/deploy/codegen/index.d.ts +2 -0
  86. package/dist/src/deploy/codegen/index.js +1 -0
  87. package/dist/src/deploy/codegen/per-unit-codegen.d.ts +44 -0
  88. package/dist/src/deploy/codegen/per-unit-codegen.js +216 -0
  89. package/dist/src/deploy/plan/executor.d.ts +9 -0
  90. package/dist/src/deploy/plan/executor.js +49 -0
  91. package/dist/src/deploy/plan/formatter.d.ts +4 -0
  92. package/dist/src/deploy/plan/formatter.js +114 -0
  93. package/dist/src/deploy/plan/index.d.ts +5 -0
  94. package/dist/src/deploy/plan/index.js +3 -0
  95. package/dist/src/deploy/plan/planner.d.ts +4 -0
  96. package/dist/src/deploy/plan/planner.js +220 -0
  97. package/dist/src/deploy/plan/provider.d.ts +30 -0
  98. package/dist/src/deploy/plan/provider.js +1 -0
  99. package/dist/src/deploy/plan/types.d.ts +29 -0
  100. package/dist/src/deploy/plan/types.js +1 -0
  101. package/dist/src/deploy/provider-adapter.d.ts +111 -0
  102. package/dist/src/deploy/provider-adapter.js +10 -0
  103. package/dist/src/functions/commands/all.js +6 -2
  104. package/dist/src/functions/commands/deploy-apply.d.ts +22 -0
  105. package/dist/src/functions/commands/deploy-apply.js +206 -0
  106. package/dist/src/functions/commands/deploy-info.d.ts +1 -0
  107. package/dist/src/functions/commands/deploy-info.js +122 -0
  108. package/dist/src/functions/commands/deploy-plan.d.ts +10 -0
  109. package/dist/src/functions/commands/deploy-plan.js +96 -0
  110. package/dist/src/functions/commands/enable.js +1 -1
  111. package/dist/src/functions/commands/new-addon.d.ts +3 -0
  112. package/dist/src/functions/commands/new-addon.js +68 -2
  113. package/dist/src/functions/commands/pikku-command-bootstrap.js +30 -20
  114. package/dist/src/functions/runtimes/nextjs/pikku-command-nextjs.js +7 -3
  115. package/dist/src/functions/wirings/ai-agent/pikku-command-ai-agent.js +7 -5
  116. package/dist/src/functions/wirings/channels/pikku-channels.js +3 -0
  117. package/dist/src/functions/wirings/channels/pikku-command-channels.js +3 -0
  118. package/dist/src/functions/wirings/cli/pikku-command-cli.js +3 -0
  119. package/dist/src/functions/wirings/cli/serialize-channel-cli.js +2 -2
  120. package/dist/src/functions/wirings/console/serialize-console-functions.js +2 -2
  121. package/dist/src/functions/wirings/functions/pikku-command-services.d.ts +1 -1
  122. package/dist/src/functions/wirings/functions/pikku-command-services.js +9 -2
  123. package/dist/src/functions/wirings/functions/serialize-function-imports.js +5 -3
  124. package/dist/src/functions/wirings/functions/serialize-function-types.js +17 -19
  125. package/dist/src/functions/wirings/http/pikku-command-http-routes.js +3 -0
  126. package/dist/src/functions/wirings/http/pikku-http-routes.js +3 -0
  127. package/dist/src/functions/wirings/mcp/pikku-command-mcp.js +6 -0
  128. package/dist/src/functions/wirings/package/pikku-command-package.js +1 -1
  129. package/dist/src/functions/wirings/package/serialize-package.d.ts +1 -1
  130. package/dist/src/functions/wirings/package/serialize-package.js +5 -2
  131. package/dist/src/functions/wirings/queue/pikku-command-queue.js +4 -0
  132. package/dist/src/functions/wirings/queue/pikku-queue.js +4 -0
  133. package/dist/src/functions/wirings/queue/serialize-queue-map.js +4 -1
  134. package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +10 -3
  135. package/dist/src/functions/wirings/rpc/serialize-public-rpc.js +5 -27
  136. package/dist/src/functions/wirings/rpc/serialize-remote-rpc.js +11 -14
  137. package/dist/src/functions/wirings/rpc/serialize-rpc-wrapper.js +28 -3
  138. package/dist/src/functions/wirings/rpc/serialize-typed-rpc-map.js +15 -5
  139. package/dist/src/functions/wirings/scheduler/pikku-command-scheduler.js +4 -0
  140. package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.d.ts +1 -0
  141. package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.js +21 -0
  142. package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +10 -9
  143. package/dist/src/functions/wirings/workflow/serialize-workflow-map.d.ts +6 -1
  144. package/dist/src/functions/wirings/workflow/serialize-workflow-map.js +42 -5
  145. package/dist/src/functions/wirings/workflow/serialize-workflow-registration.d.ts +1 -1
  146. package/dist/src/functions/wirings/workflow/serialize-workflow-registration.js +3 -2
  147. package/dist/src/functions/wirings/workflow/serialize-workflow-routes.d.ts +4 -0
  148. package/dist/src/functions/wirings/workflow/serialize-workflow-routes.js +139 -0
  149. package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +4 -51
  150. package/dist/src/scaffold/rpc-remote.gen.d.ts +10 -0
  151. package/dist/src/scaffold/rpc-remote.gen.js +22 -0
  152. package/dist/src/services.js +12 -7
  153. package/dist/src/utils/pikku-cli-config.d.ts +1 -1
  154. package/dist/src/utils/pikku-cli-config.js +30 -28
  155. package/dist/src/utils/strip-verbose-meta.js +2 -0
  156. package/dist/tsconfig.tsbuildinfo +1 -1
  157. package/package.json +8 -4
  158. package/console-app/assets/index-robZPL3O.js +0 -672
  159. package/dist/src/functions/wirings/workflow/serialize-workflow-workers.d.ts +0 -4
  160. 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>;