@pikku/cli 0.12.19 → 0.12.21

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 (105) hide show
  1. package/console-app/assets/{index-DAQHIRK3.js → index-DXLy-_D4.js} +181 -181
  2. package/console-app/index.html +1 -1
  3. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  4. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  5. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  6. package/dist/.pikku/cli/pikku-cli-channel.js +6 -1
  7. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  8. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  9. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  10. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +32 -2
  11. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  12. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  13. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  14. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  15. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  16. package/dist/.pikku/function/pikku-function-types.gen.d.ts +8 -2
  17. package/dist/.pikku/function/pikku-function-types.gen.js +4 -1
  18. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  19. package/dist/.pikku/function/pikku-functions-meta.gen.json +223 -121
  20. package/dist/.pikku/function/pikku-functions.gen.js +13 -9
  21. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  22. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  23. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  24. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
  25. package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
  26. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  27. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  28. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  29. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  30. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  31. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  32. package/dist/.pikku/pikku-services.gen.d.ts +2 -1
  33. package/dist/.pikku/pikku-services.gen.js +1 -0
  34. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  35. package/dist/.pikku/pikku-types.gen.js +1 -1
  36. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  37. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  38. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  39. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +15 -9
  40. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  41. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  42. package/dist/.pikku/schemas/register.gen.js +13 -7
  43. package/dist/.pikku/schemas/schemas/DevInput.schema.json +1 -0
  44. package/dist/.pikku/schemas/schemas/PikkuCommandHTTPOutput.schema.json +1 -0
  45. package/dist/.pikku/schemas/schemas/PikkuCommandQueueOutput.schema.json +1 -0
  46. package/dist/.pikku/schemas/schemas/WorkflowRunStatus.schema.json +1 -1
  47. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  48. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  49. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  50. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  51. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  52. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  53. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  54. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  55. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  56. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  57. package/dist/.pikku/workflow/meta/allWorkflow.gen.json +623 -154
  58. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  59. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  60. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  61. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  62. package/dist/src/cli.wiring.js +32 -2
  63. package/dist/src/deploy/analyzer/manifest.d.ts +10 -0
  64. package/dist/src/deploy/build-pipeline.d.ts +2 -0
  65. package/dist/src/deploy/build-pipeline.js +44 -6
  66. package/dist/src/deploy/bundler/bundler.d.ts +2 -1
  67. package/dist/src/deploy/bundler/bundler.js +28 -5
  68. package/dist/src/deploy/bundler/dep-extractor.d.ts +5 -2
  69. package/dist/src/deploy/bundler/dep-extractor.js +103 -23
  70. package/dist/src/deploy/bundler/types.d.ts +5 -1
  71. package/dist/src/deploy/codegen/per-unit-codegen.d.ts +3 -1
  72. package/dist/src/deploy/codegen/per-unit-codegen.js +3 -1
  73. package/dist/src/deploy/plan/planner.js +25 -3
  74. package/dist/src/deploy/plan/provider.d.ts +2 -0
  75. package/dist/src/functions/commands/deploy-apply.js +6 -4
  76. package/dist/src/functions/commands/deploy-plan.js +7 -1
  77. package/dist/src/functions/commands/dev.d.ts +13 -0
  78. package/dist/src/functions/commands/dev.js +187 -0
  79. package/dist/src/functions/commands/pikku-command-summary.js +4 -1
  80. package/dist/src/functions/commands/versions-update.js +9 -3
  81. package/dist/src/functions/wirings/channels/pikku-command-channels.d.ts +1 -1
  82. package/dist/src/functions/wirings/channels/pikku-command-channels.js +1 -1
  83. package/dist/src/functions/wirings/console/pikku-command-console-functions.js +5 -1
  84. package/dist/src/functions/wirings/functions/serialize-function-types.js +31 -1
  85. package/dist/src/functions/wirings/http/pikku-command-http-routes.d.ts +1 -1
  86. package/dist/src/functions/wirings/http/pikku-command-http-routes.js +1 -1
  87. package/dist/src/functions/wirings/queue/pikku-command-queue-map.d.ts +1 -1
  88. package/dist/src/functions/wirings/queue/pikku-command-queue-map.js +1 -1
  89. package/dist/src/functions/wirings/queue/pikku-command-queue.d.ts +1 -1
  90. package/dist/src/functions/wirings/queue/pikku-command-queue.js +1 -1
  91. package/dist/src/functions/wirings/rpc/pikku-command-public-rpc.js +5 -1
  92. package/dist/src/functions/wirings/rpc/pikku-command-remote-rpc.js +5 -1
  93. package/dist/src/functions/wirings/rpc/serialize-typed-rpc-map.js +16 -2
  94. package/dist/src/functions/wirings/workflow/serialize-workflow-routes.js +44 -2
  95. package/dist/src/functions/workflows/all.workflow.js +5 -10
  96. package/dist/src/scaffold/rpc-remote.gen.js +1 -1
  97. package/dist/src/scaffold/workflow-routes.gen.js +36 -4
  98. package/dist/src/services/cli-logger.service.d.ts +22 -2
  99. package/dist/src/services/cli-logger.service.js +97 -21
  100. package/dist/src/services.js +8 -1
  101. package/dist/tsconfig.tsbuildinfo +1 -1
  102. package/package.json +8 -4
  103. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +0 -10
  104. package/dist/.pikku/cli/pikku-cli-client.gen.js +0 -44
  105. /package/dist/.pikku/schemas/schemas/{PikkuChannelsOutput.schema.json → PikkuCommandChannelsOutput.schema.json} +0 -0
@@ -94,7 +94,6 @@ export async function resolveProvider(config, providerName) {
94
94
  }
95
95
  const ANSI = {
96
96
  green: '\x1b[32m',
97
- red: '\x1b[31m',
98
97
  bold: '\x1b[1m',
99
98
  reset: '\x1b[0m',
100
99
  };
@@ -119,8 +118,12 @@ async function runDeploy(provider, providerDir, logger, resultFile) {
119
118
  deployResult = await provider.deploy({
120
119
  buildDir: providerDir,
121
120
  logger,
122
- onProgress: (_step, _detail) => {
123
- process.stdout.write(` ${ANSI.green}done${ANSI.reset}\n`);
121
+ onProgress: (step, detail) => {
122
+ logger.info({
123
+ message: `[${step}] ${detail}`,
124
+ type: 'progress',
125
+ data: { progress: { step, detail } },
126
+ });
124
127
  },
125
128
  });
126
129
  }
@@ -132,7 +135,6 @@ async function runDeploy(provider, providerDir, logger, resultFile) {
132
135
  };
133
136
  }
134
137
  await writeResultFile(resultFile, deployResult);
135
- console.log('');
136
138
  if (deployResult.success) {
137
139
  logger.info(`${ANSI.green}${ANSI.bold}Deployment complete.${ANSI.reset}`);
138
140
  logger.info(` ${deployResult.workersDeployed?.length ?? 0} units deployed, ${deployResult.resourcesCreated?.length ?? 0} resources created`);
@@ -89,7 +89,13 @@ export const deployPlan = pikkuSessionlessFunc({
89
89
  unitCount: result.bundled.length,
90
90
  totalSizeBytes: totalSize,
91
91
  errors: result.bundleErrors,
92
- manifest: result.manifest,
92
+ codegenErrors: result.codegenErrors,
93
+ summary: plan.summary,
94
+ changeCount: plan.changes.length,
95
+ artifacts: {
96
+ deploymentManifestPath: result.deploymentManifestPath,
97
+ infraPath: result.infraPath,
98
+ },
93
99
  }, null, 2), 'utf-8');
94
100
  }
95
101
  },
@@ -0,0 +1,13 @@
1
+ export declare const dev: import("#pikku").PikkuFunctionConfig<{
2
+ port?: string;
3
+ watch?: boolean;
4
+ hmr?: boolean;
5
+ }, void, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<{
6
+ port?: string;
7
+ watch?: boolean;
8
+ hmr?: boolean;
9
+ }, void, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<{
10
+ port?: string;
11
+ watch?: boolean;
12
+ hmr?: boolean;
13
+ }, void, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
@@ -0,0 +1,187 @@
1
+ import { createServer } from 'http';
2
+ import { join, resolve } from 'path';
3
+ import { Readable } from 'stream';
4
+ import { pikkuSessionlessFunc } from '#pikku';
5
+ import chokidar from 'chokidar';
6
+ import { pikkuDevReloader } from '@pikku/core/dev';
7
+ import { ConsoleLogger, InMemoryQueueService, InMemoryWorkflowService, InMemoryTriggerService, InMemoryAIRunStateService, } from '@pikku/core/services';
8
+ import { stopSingletonServices } from '@pikku/core';
9
+ import { pikkuState } from '@pikku/core/internal';
10
+ import { fetchData, PikkuFetchHTTPResponse, logRoutes, } from '@pikku/core/http';
11
+ import { compileAllSchemas } from '@pikku/core/schema';
12
+ import { pikkuWebsocketHandler } from '@pikku/ws';
13
+ import { WebSocketServer } from 'ws';
14
+ import { InMemorySchedulerService } from '@pikku/schedule';
15
+ function incomingMessageToRequest(req) {
16
+ const url = new URL(req.url || '/', 'http://localhost');
17
+ const method = req.method ? req.method.toUpperCase() : 'GET';
18
+ const headers = new Headers();
19
+ for (const [key, value] of Object.entries(req.headers)) {
20
+ if (value) {
21
+ headers.set(key, Array.isArray(value) ? value.join(', ') : value);
22
+ }
23
+ }
24
+ let body = null;
25
+ if (method !== 'GET' && method !== 'HEAD') {
26
+ body = Readable.toWeb(req);
27
+ }
28
+ return new Request(url.toString(), {
29
+ method,
30
+ headers,
31
+ body,
32
+ // @ts-ignore - duplex is needed for streaming body in Node.js
33
+ duplex: 'half',
34
+ });
35
+ }
36
+ async function writeResponse(nodeRes, webResponse) {
37
+ const headers = {};
38
+ webResponse.headers.forEach((value, name) => {
39
+ const lower = name.toLowerCase();
40
+ if (lower === 'set-cookie') {
41
+ const existing = headers[lower];
42
+ if (Array.isArray(existing)) {
43
+ existing.push(value);
44
+ }
45
+ else {
46
+ headers[lower] = [value];
47
+ }
48
+ }
49
+ else {
50
+ headers[lower] = value;
51
+ }
52
+ });
53
+ nodeRes.writeHead(webResponse.status, headers);
54
+ if (webResponse.body) {
55
+ const reader = webResponse.body.getReader();
56
+ try {
57
+ while (true) {
58
+ const { done, value } = await reader.read();
59
+ if (done)
60
+ break;
61
+ nodeRes.write(value);
62
+ }
63
+ }
64
+ finally {
65
+ reader.releaseLock();
66
+ }
67
+ }
68
+ nodeRes.end();
69
+ }
70
+ export const dev = pikkuSessionlessFunc({
71
+ remote: true,
72
+ func: async ({ logger, config, getInspectorState }, { port, watch, hmr }, { rpc }) => {
73
+ const resolvedPort = parseInt(port || '3000', 10);
74
+ const hostname = 'localhost';
75
+ const enableWatch = watch !== false;
76
+ const enableHmr = hmr !== false;
77
+ await rpc.invoke('all');
78
+ const inspectorState = await getInspectorState(true);
79
+ const { pikkuConfigFactory, singletonServicesFactory } = inspectorState.filesAndMethods;
80
+ if (!pikkuConfigFactory || !singletonServicesFactory) {
81
+ logger.error('createConfig and createSingletonServices must be defined in your project');
82
+ return;
83
+ }
84
+ const pikkuDir = resolve(config.rootDir, config.outDir);
85
+ const bootstrapPath = join(pikkuDir, 'pikku-bootstrap.gen.js');
86
+ await import(bootstrapPath);
87
+ const configModule = await import(pikkuConfigFactory.file);
88
+ const servicesModule = await import(singletonServicesFactory.file);
89
+ const userCreateConfig = configModule[pikkuConfigFactory.variable];
90
+ const userCreateSingletonServices = servicesModule[singletonServicesFactory.variable];
91
+ const userConfig = await userCreateConfig();
92
+ const schedulerService = new InMemorySchedulerService();
93
+ const inMemoryServices = {
94
+ logger: new ConsoleLogger(),
95
+ schedulerService,
96
+ queueService: new InMemoryQueueService(),
97
+ workflowService: new InMemoryWorkflowService(),
98
+ triggerService: new InMemoryTriggerService(),
99
+ aiRunStateService: new InMemoryAIRunStateService(),
100
+ };
101
+ const singletonServices = await userCreateSingletonServices(userConfig, inMemoryServices);
102
+ pikkuState(null, 'package', 'singletonServices', singletonServices);
103
+ compileAllSchemas(logger);
104
+ logRoutes(logger);
105
+ const server = createServer(async (req, res) => {
106
+ const request = incomingMessageToRequest(req);
107
+ const pikkuResponse = new PikkuFetchHTTPResponse();
108
+ await fetchData(request, pikkuResponse, { respondWith404: true });
109
+ const response = pikkuResponse.toResponse();
110
+ await writeResponse(res, response);
111
+ });
112
+ const wss = new WebSocketServer({ noServer: true });
113
+ pikkuWebsocketHandler({ server, wss, logger });
114
+ await schedulerService.start();
115
+ await new Promise((resolve) => {
116
+ server.listen(resolvedPort, hostname, () => {
117
+ logger.info(`Dev server running at http://${hostname}:${resolvedPort}`);
118
+ resolve();
119
+ });
120
+ });
121
+ let configWatcher;
122
+ let watcher;
123
+ process.once('SIGINT', async () => {
124
+ logger.info('Stopping dev server...');
125
+ try {
126
+ await stopSingletonServices();
127
+ await configWatcher?.close();
128
+ await watcher?.close();
129
+ await new Promise((resolve, reject) => wss.close((err) => (err ? reject(err) : resolve())));
130
+ await new Promise((resolve, reject) => server.close((err) => (err ? reject(err) : resolve())));
131
+ }
132
+ finally {
133
+ process.exit(0);
134
+ }
135
+ });
136
+ if (enableHmr) {
137
+ await pikkuDevReloader({
138
+ srcDirectories: config.srcDirectories,
139
+ logger,
140
+ });
141
+ }
142
+ if (enableWatch) {
143
+ const genIgnore = /\.gen\.tsx?$/;
144
+ configWatcher = chokidar.watch(config.srcDirectories, {
145
+ ignoreInitial: true,
146
+ ignored: genIgnore,
147
+ });
148
+ const generatorWatcher = () => {
149
+ watcher?.close();
150
+ logger.info(`• Watching directories: \n - ${config.srcDirectories.join('\n - ')}`);
151
+ watcher = chokidar.watch(config.srcDirectories, {
152
+ ignoreInitial: true,
153
+ ignored: genIgnore,
154
+ });
155
+ watcher.on('ready', async () => {
156
+ const handle = async () => {
157
+ try {
158
+ const start = Date.now();
159
+ await rpc.invoke('all');
160
+ logger.info({
161
+ message: `✓ Generated in ${Date.now() - start}ms`,
162
+ type: 'timing',
163
+ });
164
+ }
165
+ catch (err) {
166
+ logger.error(`Error running watch: ${err}`);
167
+ }
168
+ };
169
+ await handle();
170
+ let timeout;
171
+ const deduped = (_file) => {
172
+ if (timeout) {
173
+ clearTimeout(timeout);
174
+ }
175
+ timeout = setTimeout(handle, 10);
176
+ };
177
+ watcher?.on('change', deduped);
178
+ watcher?.on('add', deduped);
179
+ watcher?.on('unlink', deduped);
180
+ });
181
+ };
182
+ configWatcher.on('ready', generatorWatcher);
183
+ configWatcher.on('change', generatorWatcher);
184
+ }
185
+ await new Promise(() => { });
186
+ },
187
+ });
@@ -49,7 +49,10 @@ export const pikkuSummary = pikkuSessionlessFunc({
49
49
  summary.set('workflowGraphs', workflowGraphsCount);
50
50
  }
51
51
  if (!logger.isSilent()) {
52
- console.log(summary.format());
52
+ // Route through the logger so JSON mode emits a single NDJSON
53
+ // record instead of raw chalk-coloured text written directly to
54
+ // stdout (which would break NDJSON consumers).
55
+ logger.info({ message: summary.format(), type: 'summary' });
53
56
  }
54
57
  },
55
58
  });
@@ -7,12 +7,18 @@ export const pikkuVersionsUpdate = pikkuSessionlessFunc({
7
7
  const manifestPath = join(config.rootDir, 'versions.pikku.json');
8
8
  const visitState = await getInspectorState();
9
9
  if (!visitState.manifest.initial) {
10
- throw new Error(`Version manifest not found at ${manifestPath}. Run 'pikku versions init' to create one.`);
10
+ logger.warn(`Run 'pikku versions init' to enable contract versioning.`);
11
+ return;
11
12
  }
12
13
  const immutabilityErrors = visitState.manifest.errors.filter((e) => e.code === ErrorCode.FUNCTION_VERSION_MODIFIED);
13
14
  if (immutabilityErrors.length > 0) {
14
- const messages = immutabilityErrors.map((e) => `[${e.code}] ${e.message}`);
15
- throw new Error(messages.join('\n'));
15
+ for (const e of immutabilityErrors) {
16
+ logger.critical(ErrorCode.FUNCTION_VERSION_MODIFIED, e.message);
17
+ }
18
+ if (logger.hasCriticalErrors()) {
19
+ process.exit(1);
20
+ }
21
+ return;
16
22
  }
17
23
  await saveManifest(manifestPath, visitState.manifest.current);
18
24
  logger.debug(`Version manifest updated at ${manifestPath}`);
@@ -1 +1 @@
1
- export declare const pikkuChannels: import("#pikku").PikkuFunctionConfig<void, boolean | undefined, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, boolean | undefined, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, boolean | undefined, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
1
+ export declare const pikkuCommandChannels: import("#pikku").PikkuFunctionConfig<void, boolean | undefined, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, boolean | undefined, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, boolean | undefined, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
@@ -4,7 +4,7 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
4
4
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
5
5
  import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
6
6
  import { stripVerboseFields, hasVerboseFields, } from '../../../utils/strip-verbose-meta.js';
7
- export const pikkuChannels = pikkuSessionlessFunc({
7
+ export const pikkuCommandChannels = pikkuSessionlessFunc({
8
8
  func: async ({ logger, config, getInspectorState }) => {
9
9
  const visitState = await getInspectorState();
10
10
  const { channelsWiringFile, channelsWiringMetaFile, channelsWiringMetaJsonFile, packageMappings, schema, } = config;
@@ -4,7 +4,11 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
4
4
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
5
5
  import { serializeConsoleFunctions } from './serialize-console-functions.js';
6
6
  export const pikkuConsoleFunctions = pikkuSessionlessFunc({
7
- func: async ({ logger, config }) => {
7
+ func: async ({ logger, config, variables }) => {
8
+ const deployCodegenFlag = await variables.get('PIKKU_DEPLOY_CODEGEN');
9
+ if (deployCodegenFlag === '1') {
10
+ return false;
11
+ }
8
12
  if (config.scaffold?.console) {
9
13
  const pathToPikkuTypes = getFileImportRelativePath(config.consoleFunctionsFile, config.typesDeclarationFile, config.packageMappings);
10
14
  const pathToAgentTypes = getFileImportRelativePath(config.consoleFunctionsFile, config.agentTypesFile, config.packageMappings);
@@ -12,7 +12,7 @@ export const serializeFunctionTypes = (userSessionTypeImport, userSessionTypeNam
12
12
  * Core function, middleware, and permission types for all wirings
13
13
  */
14
14
 
15
- import type { CorePikkuMiddleware, CorePermissionGroup, PikkuWire, PickRequired } from '@pikku/core'
15
+ import type { CorePikkuMiddleware, CorePermissionGroup, ListInput, ListOutput, PikkuWire, PickRequired } from '@pikku/core'
16
16
  import type { CorePikkuFunctionConfig, CorePikkuAuth, CorePikkuAuthConfig, CorePikkuPermission } from '@pikku/core/function'
17
17
  import { pikkuAuth as pikkuAuthCore } from '@pikku/core/function'
18
18
  import { addMiddleware as addMiddlewareCore, addPermission as addPermissionCore } from '@pikku/core/middleware'
@@ -338,10 +338,13 @@ export type PikkuFunctionConfigWithSchema<
338
338
  RequiredWires extends keyof PikkuWire = never
339
339
  > = {
340
340
  name?: string
341
+ description?: string
341
342
  tags?: string[]
342
343
  expose?: boolean
343
344
  mcp?: boolean
344
345
  internal?: boolean
346
+ remote?: boolean
347
+ deploy?: 'serverless' | 'server' | 'auto'
345
348
  approvalRequired?: boolean
346
349
  approvalDescription?: InputSchema extends StandardSchemaV1 ? PikkuApprovalDescription<InferSchemaOutput<InputSchema>> : never
347
350
  func: PikkuFunction<
@@ -415,6 +418,32 @@ export function pikkuFunc(func: any) {
415
418
  return typeof func === 'function' ? { func } : func
416
419
  }
417
420
 
421
+ export type PikkuListFunction<
422
+ F extends Record<string, unknown> = {},
423
+ Row = unknown,
424
+ S extends string = never
425
+ > =
426
+ | PikkuFunction<ListInput<F, S>, ListOutput<Row>, 'session' | 'rpc'>
427
+ | PikkuFunctionSessionless<
428
+ ListInput<F, S>,
429
+ ListOutput<Row>,
430
+ 'session' | 'rpc'
431
+ >
432
+
433
+ export const pikkuListFunc = <
434
+ F extends Record<string, unknown> = {},
435
+ Row = unknown,
436
+ S extends string = never
437
+ >(
438
+ config: PikkuFunctionConfig<
439
+ ListInput<F, S>,
440
+ ListOutput<Row>,
441
+ 'session' | 'rpc'
442
+ >
443
+ ): PikkuFunctionConfig<ListInput<F, S>, ListOutput<Row>, 'session' | 'rpc'> => {
444
+ return pikkuFunc(config)
445
+ }
446
+
418
447
  /**
419
448
  * Configuration object for sessionless Pikku functions with Zod schema validation.
420
449
  */
@@ -430,6 +459,7 @@ export type PikkuFunctionSessionlessConfigWithSchema<
430
459
  mcp?: boolean
431
460
  internal?: boolean
432
461
  remote?: boolean
462
+ deploy?: 'serverless' | 'server' | 'auto'
433
463
  approvalRequired?: boolean
434
464
  approvalDescription?: InputSchema extends StandardSchemaV1 ? PikkuApprovalDescription<InferSchemaOutput<InputSchema>> : never
435
465
  func: PikkuFunctionSessionless<
@@ -1 +1 @@
1
- export declare const pikkuHTTP: import("#pikku").PikkuFunctionConfig<void, boolean | undefined, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, boolean | undefined, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, boolean | undefined, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
1
+ export declare const pikkuCommandHTTP: import("#pikku").PikkuFunctionConfig<void, boolean | undefined, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, boolean | undefined, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, boolean | undefined, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
@@ -4,7 +4,7 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
4
4
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
5
5
  import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
6
6
  import { stripVerboseFields, hasVerboseFields, } from '../../../utils/strip-verbose-meta.js';
7
- export const pikkuHTTP = pikkuSessionlessFunc({
7
+ export const pikkuCommandHTTP = pikkuSessionlessFunc({
8
8
  func: async ({ logger, config, getInspectorState }) => {
9
9
  const visitState = await getInspectorState();
10
10
  const { httpWiringsFile, httpWiringMetaFile, httpWiringMetaJsonFile, packageMappings, schema, } = config;
@@ -1 +1 @@
1
- export declare const pikkuQueueMap: import("#pikku").PikkuFunctionConfig<void, void, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, void, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, void, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
1
+ export declare const pikkuCommandQueueMap: import("#pikku").PikkuFunctionConfig<void, void, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, void, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, void, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
@@ -2,7 +2,7 @@ import { pikkuSessionlessFunc } from '#pikku';
2
2
  import { writeFileInDir } from '../../../utils/file-writer.js';
3
3
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
4
4
  import { serializeQueueMap } from './serialize-queue-map.js';
5
- export const pikkuQueueMap = pikkuSessionlessFunc({
5
+ export const pikkuCommandQueueMap = pikkuSessionlessFunc({
6
6
  func: async ({ logger, config, getInspectorState }) => {
7
7
  const { queueWorkers, functions, resolvedIOTypes } = await getInspectorState();
8
8
  const { queueMapDeclarationFile, packageMappings } = config;
@@ -1 +1 @@
1
- export declare const pikkuQueue: import("#pikku").PikkuFunctionConfig<void, boolean | undefined, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, boolean | undefined, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, boolean | undefined, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
1
+ export declare const pikkuCommandQueue: import("#pikku").PikkuFunctionConfig<void, boolean | undefined, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, boolean | undefined, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, boolean | undefined, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
@@ -5,7 +5,7 @@ import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-
5
5
  import { serializeQueueMeta, serializeQueueMetaTS, } from './serialize-queue-meta.js';
6
6
  import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
7
7
  import { stripVerboseFields, hasVerboseFields, } from '../../../utils/strip-verbose-meta.js';
8
- export const pikkuQueue = pikkuSessionlessFunc({
8
+ export const pikkuCommandQueue = pikkuSessionlessFunc({
9
9
  func: async ({ logger, config, getInspectorState }) => {
10
10
  const visitState = await getInspectorState();
11
11
  const { queueWorkersWiringFile, queueWorkersWiringMetaFile, queueWorkersWiringMetaJsonFile, packageMappings, schema, } = config;
@@ -4,7 +4,11 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
4
4
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
5
5
  import { serializePublicRPC } from './serialize-public-rpc.js';
6
6
  export const pikkuPublicRPC = pikkuSessionlessFunc({
7
- func: async ({ logger, config }) => {
7
+ func: async ({ logger, config, variables }) => {
8
+ const deployCodegenFlag = await variables.get('PIKKU_DEPLOY_CODEGEN');
9
+ if (deployCodegenFlag === '1') {
10
+ return false;
11
+ }
8
12
  if (config.scaffold?.rpc) {
9
13
  const pathToPikkuTypes = getFileImportRelativePath(config.publicRpcFile, config.typesDeclarationFile, config.packageMappings);
10
14
  await writeFileInDir(logger, config.publicRpcFile, serializePublicRPC(pathToPikkuTypes, config.scaffold.rpc === 'auth', config.globalHTTPPrefix || ''));
@@ -4,7 +4,11 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
4
4
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
5
5
  import { serializeRemoteRPC } from './serialize-remote-rpc.js';
6
6
  export const pikkuRemoteRPC = pikkuSessionlessFunc({
7
- func: async ({ logger, config }) => {
7
+ func: async ({ logger, config, variables }) => {
8
+ const deployCodegenFlag = await variables.get('PIKKU_DEPLOY_CODEGEN');
9
+ if (deployCodegenFlag === '1') {
10
+ return false;
11
+ }
8
12
  if (config.remoteRpcWorkersFile) {
9
13
  const pathToPikkuTypes = getFileImportRelativePath(config.remoteRpcWorkersFile, config.typesDeclarationFile, config.packageMappings);
10
14
  await writeFileInDir(logger, config.remoteRpcWorkersFile, serializeRemoteRPC(pathToPikkuTypes));
@@ -41,13 +41,13 @@ ${addonImports}
41
41
  ${mergedRPCMap}
42
42
 
43
43
  export type RPCInvoke = <Name extends keyof FlattenedRPCMap>(
44
- ...args: FlattenedRPCMap[Name]['input'] extends void | null
44
+ ...args: IsVoidishInput<FlattenedRPCMap[Name]['input']> extends true
45
45
  ? [name: Name]
46
46
  : [name: Name, data: FlattenedRPCMap[Name]['input']]
47
47
  ) => Promise<FlattenedRPCMap[Name]['output']>
48
48
 
49
49
  export type RPCRemote = <Name extends keyof FlattenedRPCMap>(
50
- ...args: FlattenedRPCMap[Name]['input'] extends void | null
50
+ ...args: IsVoidishInput<FlattenedRPCMap[Name]['input']> extends true
51
51
  ? [name: Name]
52
52
  : [name: Name, data: FlattenedRPCMap[Name]['input']]
53
53
  ) => Promise<FlattenedRPCMap[Name]['output']>
@@ -117,6 +117,13 @@ function generateMergedRPCMap(wireAddonDeclarations) {
117
117
  return `
118
118
  // No addon packages, use RPCMap directly
119
119
  export type FlattenedRPCMap = RPCMap
120
+
121
+ type IsAny<T> = 0 extends (1 & T) ? true : false
122
+ type IsVoidishInput<T> = IsAny<T> extends true
123
+ ? false
124
+ : [T] extends [void | null | undefined]
125
+ ? true
126
+ : false
120
127
  `;
121
128
  }
122
129
  // TypeScript utility to flatten namespaced RPC maps
@@ -131,6 +138,13 @@ export type FlattenedRPCMap =
131
138
  RPCMap${Array.from(wireAddonDeclarations.keys())
132
139
  .map((namespace) => ` & PrefixKeys<${toPascalCase(namespace)}RPCMap, '${namespace}'>`)
133
140
  .join('')}
141
+
142
+ type IsAny<T> = 0 extends (1 & T) ? true : false
143
+ type IsVoidishInput<T> = IsAny<T> extends true
144
+ ? false
145
+ : [T] extends [void | null | undefined]
146
+ ? true
147
+ : false
134
148
  `;
135
149
  return utilityTypes;
136
150
  }
@@ -25,7 +25,7 @@ export const workflowStarter = pikkuSessionlessFunc<
25
25
  >({
26
26
  auth: ${authFlag},
27
27
  func: async (_services, { workflowName, data }, { rpc }) => {
28
- return await rpc.startWorkflow(workflowName as any, data ?? {})
28
+ return await rpc.startWorkflow(workflowName as any, (data ?? {}) as any)
29
29
  },
30
30
  })
31
31
 
@@ -68,6 +68,7 @@ export const workflowStatusStream = pikkuSessionlessFunc<
68
68
 
69
69
  const terminalStatuses = new Set(['completed', 'failed', 'cancelled'])
70
70
  let lastHash = ''
71
+ let initSent = false
71
72
 
72
73
  const poll = async () => {
73
74
  const run = await workflowRunService.getRun(runId)
@@ -78,6 +79,26 @@ export const workflowStatusStream = pikkuSessionlessFunc<
78
79
 
79
80
  const steps = await workflowRunService.getRunSteps(runId)
80
81
 
82
+ if (!initSent && run.deterministic) {
83
+ const statusByStep = new Map(
84
+ steps.map((s: { stepName: string; status: string }) => [
85
+ s.stepName,
86
+ s.status,
87
+ ])
88
+ )
89
+ channel.send({
90
+ type: 'init',
91
+ deterministic: true,
92
+ steps: (run.plannedSteps ?? []).map(
93
+ (s: { stepName: string }) => ({
94
+ stepName: s.stepName,
95
+ status: statusByStep.get(s.stepName) ?? 'pending',
96
+ })
97
+ ),
98
+ })
99
+ initSent = true
100
+ }
101
+
81
102
  const hash = JSON.stringify({
82
103
  s: run.status,
83
104
  steps: steps.map((s: { stepName: string; status: string }) => [s.stepName, s.status]),
@@ -133,6 +154,7 @@ export const workflowStatusStreamFull = pikkuSessionlessFunc<
133
154
 
134
155
  const terminalStatuses = new Set(['completed', 'failed', 'cancelled'])
135
156
  let lastHash = ''
157
+ let initSent = false
136
158
 
137
159
  const poll = async () => {
138
160
  const run = await workflowRunService.getRun(runId)
@@ -143,6 +165,26 @@ export const workflowStatusStreamFull = pikkuSessionlessFunc<
143
165
 
144
166
  const steps = await workflowRunService.getRunSteps(runId)
145
167
 
168
+ if (!initSent && run.deterministic) {
169
+ const statusByStep = new Map(
170
+ steps.map((s: { stepName: string; status: string }) => [
171
+ s.stepName,
172
+ s.status,
173
+ ])
174
+ )
175
+ channel.send({
176
+ type: 'init',
177
+ deterministic: true,
178
+ steps: (run.plannedSteps ?? []).map(
179
+ (s: { stepName: string }) => ({
180
+ stepName: s.stepName,
181
+ status: statusByStep.get(s.stepName) ?? 'pending',
182
+ })
183
+ ),
184
+ })
185
+ initSent = true
186
+ }
187
+
146
188
  const hash = JSON.stringify({
147
189
  s: run.status,
148
190
  o: run.output,
@@ -193,7 +235,7 @@ export const graphStarter = pikkuSessionlessFunc<
193
235
  >({
194
236
  auth: ${authFlag},
195
237
  func: async (_services, { workflowName, nodeId, data }, { rpc }) => {
196
- return await rpc.startWorkflow(workflowName as any, data ?? {}, { startNode: nodeId })
238
+ return await rpc.startWorkflow(workflowName as any, (data ?? {}) as any, { startNode: nodeId })
197
239
  },
198
240
  })
199
241
 
@@ -128,7 +128,7 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
128
128
  }
129
129
  if (!config.addon) {
130
130
  const [http, scheduler, triggers] = await Promise.all([
131
- workflow.do('HTTP', 'pikkuHTTP', null),
131
+ workflow.do('HTTP', 'pikkuCommandHTTP', null),
132
132
  workflow.do('Scheduler', 'pikkuScheduler', null),
133
133
  workflow.do('Trigger', 'pikkuTrigger', null),
134
134
  ]);
@@ -158,15 +158,15 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
158
158
  }
159
159
  if (!config.addon) {
160
160
  const [queues, channels, gateways, mcp, cli] = await Promise.all([
161
- workflow.do('Queue', 'pikkuQueue', null),
162
- workflow.do('Channels', 'pikkuChannels', null),
161
+ workflow.do('Queue', 'pikkuCommandQueue', null),
162
+ workflow.do('Channels', 'pikkuCommandChannels', null),
163
163
  workflow.do('Gateway', 'pikkuGateway', null),
164
164
  workflow.do('MCP', 'pikkuMCP', null),
165
165
  workflow.do('CLI', 'pikkuCLI', null),
166
166
  ]);
167
167
  if (queues) {
168
168
  await Promise.all([
169
- workflow.do('Queue map', 'pikkuQueueMap', null),
169
+ workflow.do('Queue map', 'pikkuCommandQueueMap', null),
170
170
  workflow.do('Queue service', 'pikkuQueueService', null),
171
171
  ]);
172
172
  allImports.push(config.queueWorkersWiringMetaFile, config.queueWorkersWiringFile);
@@ -200,12 +200,7 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
200
200
  await workflow.do('OpenAPI re-inspect', async () => getInspectorState(true));
201
201
  await workflow.do('OpenAPI', 'pikkuOpenAPI', null);
202
202
  }
203
- try {
204
- await workflow.do('Versions update', 'pikkuVersionsUpdate', null);
205
- }
206
- catch {
207
- logger.warn(`Run 'pikku versions init' to enable contract versioning.`);
208
- }
203
+ await workflow.do('Versions update', 'pikkuVersionsUpdate', null);
209
204
  await workflow.do('Bootstrap', 'pikkuBootstrap', { allImports });
210
205
  await workflow.do('Summary', 'pikkuSummary', null);
211
206
  },
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.19
2
+ * This file was generated by @pikku/cli@0.12.21
3
3
  */
4
4
  /**
5
5
  * Auto-generated remote internal RPC queue worker and HTTP endpoint