@pikku/core 0.9.11 → 0.10.0

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 (124) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/errors/errors.d.ts +2 -0
  3. package/dist/errors/errors.js +6 -0
  4. package/dist/function/function-runner.d.ts +15 -9
  5. package/dist/function/function-runner.js +55 -37
  6. package/dist/function/functions.types.d.ts +67 -1
  7. package/dist/function/functions.types.js +43 -1
  8. package/dist/index.d.ts +2 -6
  9. package/dist/index.js +2 -6
  10. package/dist/middleware/auth-apikey.d.ts +19 -11
  11. package/dist/middleware/auth-apikey.js +33 -33
  12. package/dist/middleware/auth-bearer.d.ts +34 -7
  13. package/dist/middleware/auth-bearer.js +53 -36
  14. package/dist/middleware/auth-cookie.d.ts +30 -12
  15. package/dist/middleware/auth-cookie.js +51 -43
  16. package/dist/middleware/timeout.d.ts +6 -2
  17. package/dist/middleware/timeout.js +7 -9
  18. package/dist/middleware-runner.d.ts +46 -43
  19. package/dist/middleware-runner.js +100 -69
  20. package/dist/permissions.d.ts +82 -20
  21. package/dist/permissions.js +176 -62
  22. package/dist/pikku-state.d.ts +46 -1
  23. package/dist/pikku-state.js +16 -1
  24. package/dist/services/content-service.d.ts +2 -3
  25. package/dist/services/index.d.ts +0 -1
  26. package/dist/services/index.js +0 -1
  27. package/dist/services/local-content.d.ts +2 -4
  28. package/dist/types/core.types.d.ts +110 -4
  29. package/dist/types/core.types.js +44 -1
  30. package/dist/utils.d.ts +1 -1
  31. package/dist/wirings/channel/channel-handler.d.ts +2 -2
  32. package/dist/wirings/channel/channel-handler.js +16 -12
  33. package/dist/wirings/channel/channel-runner.d.ts +2 -2
  34. package/dist/wirings/channel/channel-runner.js +6 -24
  35. package/dist/wirings/channel/channel.types.d.ts +15 -14
  36. package/dist/wirings/channel/local/local-channel-runner.js +12 -12
  37. package/dist/wirings/channel/serverless/serverless-channel-runner.js +7 -8
  38. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +12 -0
  39. package/dist/wirings/cli/channel/cli-channel-runner.js +83 -0
  40. package/dist/wirings/cli/channel/index.d.ts +1 -0
  41. package/dist/wirings/cli/channel/index.js +1 -0
  42. package/dist/wirings/cli/cli-runner.d.ts +42 -0
  43. package/dist/wirings/cli/cli-runner.js +352 -0
  44. package/dist/wirings/cli/cli.types.d.ts +204 -0
  45. package/dist/wirings/cli/cli.types.js +1 -0
  46. package/dist/wirings/cli/command-parser.d.ts +19 -0
  47. package/dist/wirings/cli/command-parser.js +403 -0
  48. package/dist/wirings/cli/index.d.ts +5 -0
  49. package/dist/wirings/cli/index.js +5 -0
  50. package/dist/wirings/http/http-runner.d.ts +59 -10
  51. package/dist/wirings/http/http-runner.js +138 -131
  52. package/dist/wirings/http/http.types.d.ts +11 -10
  53. package/dist/wirings/http/index.d.ts +1 -1
  54. package/dist/wirings/http/index.js +1 -1
  55. package/dist/wirings/http/pikku-fetch-http-response.js +3 -1
  56. package/dist/wirings/http/routers/http-router.d.ts +0 -2
  57. package/dist/wirings/http/routers/path-to-regex.d.ts +1 -1
  58. package/dist/wirings/http/routers/path-to-regex.js +5 -34
  59. package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
  60. package/dist/wirings/mcp/mcp-runner.d.ts +4 -5
  61. package/dist/wirings/mcp/mcp-runner.js +32 -34
  62. package/dist/wirings/mcp/mcp.types.d.ts +38 -14
  63. package/dist/wirings/queue/queue-runner.d.ts +2 -2
  64. package/dist/wirings/queue/queue-runner.js +25 -27
  65. package/dist/wirings/queue/queue.types.d.ts +6 -5
  66. package/dist/wirings/rpc/index.d.ts +1 -1
  67. package/dist/wirings/rpc/index.js +1 -1
  68. package/dist/wirings/rpc/rpc-runner.d.ts +6 -18
  69. package/dist/wirings/rpc/rpc-runner.js +13 -8
  70. package/dist/wirings/scheduler/scheduler-runner.d.ts +2 -2
  71. package/dist/wirings/scheduler/scheduler-runner.js +38 -35
  72. package/dist/wirings/scheduler/scheduler.types.d.ts +5 -4
  73. package/package.json +9 -7
  74. package/src/errors/errors.ts +6 -0
  75. package/src/factory-functions.test.ts +60 -1
  76. package/src/function/function-runner.test.ts +81 -26
  77. package/src/function/function-runner.ts +89 -57
  78. package/src/function/functions.types.ts +85 -2
  79. package/src/index.ts +6 -19
  80. package/src/middleware/auth-apikey.ts +42 -57
  81. package/src/middleware/auth-bearer.ts +66 -49
  82. package/src/middleware/auth-cookie.ts +63 -82
  83. package/src/middleware/timeout.ts +10 -14
  84. package/src/middleware-runner.test.ts +24 -16
  85. package/src/middleware-runner.ts +115 -87
  86. package/src/permissions.test.ts +26 -27
  87. package/src/permissions.ts +216 -104
  88. package/src/pikku-state.ts +79 -2
  89. package/src/services/content-service.ts +5 -4
  90. package/src/services/index.ts +0 -1
  91. package/src/services/local-content.ts +9 -4
  92. package/src/types/core.types.ts +143 -5
  93. package/src/utils.ts +1 -1
  94. package/src/wirings/channel/channel-handler.ts +18 -21
  95. package/src/wirings/channel/channel-runner.ts +19 -32
  96. package/src/wirings/channel/channel.types.ts +29 -16
  97. package/src/wirings/channel/local/local-channel-runner.ts +25 -15
  98. package/src/wirings/channel/serverless/serverless-channel-runner.ts +15 -17
  99. package/src/wirings/cli/channel/cli-channel-runner.ts +123 -0
  100. package/src/wirings/cli/channel/index.ts +1 -0
  101. package/src/wirings/cli/cli-runner.test.ts +403 -0
  102. package/src/wirings/cli/cli-runner.ts +539 -0
  103. package/src/wirings/cli/cli.types.ts +350 -0
  104. package/src/wirings/cli/command-parser.test.ts +445 -0
  105. package/src/wirings/cli/command-parser.ts +504 -0
  106. package/src/wirings/cli/index.ts +13 -0
  107. package/src/wirings/http/http-runner.test.ts +8 -7
  108. package/src/wirings/http/http-runner.ts +165 -158
  109. package/src/wirings/http/http.types.ts +58 -11
  110. package/src/wirings/http/index.ts +7 -1
  111. package/src/wirings/http/pikku-fetch-http-response.ts +3 -1
  112. package/src/wirings/http/routers/http-router.ts +0 -2
  113. package/src/wirings/http/routers/path-to-regex.test.ts +4 -5
  114. package/src/wirings/http/routers/path-to-regex.ts +6 -43
  115. package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
  116. package/src/wirings/mcp/mcp-runner.ts +58 -55
  117. package/src/wirings/mcp/mcp.types.ts +65 -14
  118. package/src/wirings/queue/queue-runner.ts +44 -47
  119. package/src/wirings/queue/queue.types.ts +10 -6
  120. package/src/wirings/rpc/index.ts +1 -1
  121. package/src/wirings/rpc/rpc-runner.ts +27 -9
  122. package/src/wirings/scheduler/scheduler-runner.ts +58 -56
  123. package/src/wirings/scheduler/scheduler.types.ts +10 -3
  124. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import { CLIMeta } from './cli.types.js';
2
+ /**
3
+ * Result of parsing CLI arguments
4
+ */
5
+ export interface ParsedCommand {
6
+ program: string;
7
+ commandPath: string[];
8
+ positionals: Record<string, any>;
9
+ options: Record<string, any>;
10
+ errors: string[];
11
+ }
12
+ /**
13
+ * Parses raw CLI arguments into structured data for a specific program
14
+ */
15
+ export declare function parseCLIArguments(args: string[], programName: string, allMeta: CLIMeta): ParsedCommand;
16
+ /**
17
+ * Generates help text for a command in a specific program
18
+ */
19
+ export declare function generateCommandHelp(programName: string, allMeta: CLIMeta, commandPath?: string[]): string;
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Parses raw CLI arguments into structured data for a specific program
3
+ */
4
+ export function parseCLIArguments(args, programName, allMeta) {
5
+ const result = {
6
+ program: programName,
7
+ commandPath: [],
8
+ positionals: {},
9
+ options: {},
10
+ errors: [],
11
+ };
12
+ const meta = allMeta.programs[programName];
13
+ if (!meta) {
14
+ result.errors.push(`Program not found: ${programName}`);
15
+ return result;
16
+ }
17
+ let currentIndex = 0;
18
+ let currentMeta = meta;
19
+ // Parse command path (non-flag arguments at the beginning)
20
+ while (currentIndex < args.length && !args[currentIndex].startsWith('-')) {
21
+ const arg = args[currentIndex];
22
+ // Check if this is a known subcommand
23
+ if (currentMeta.commands && currentMeta.commands[arg]) {
24
+ result.commandPath.push(arg);
25
+ currentMeta = {
26
+ program: currentMeta.program,
27
+ commands: currentMeta.commands[arg].subcommands || {},
28
+ options: {
29
+ ...currentMeta.options,
30
+ ...currentMeta.commands[arg].options,
31
+ },
32
+ defaultRenderName: currentMeta.commands[arg].renderName || currentMeta.defaultRenderName,
33
+ };
34
+ currentIndex++;
35
+ }
36
+ else {
37
+ // Not a subcommand, must be a positional argument
38
+ break;
39
+ }
40
+ }
41
+ // If no command was parsed, check for a default command
42
+ // Only use default if user didn't provide any non-flag arguments
43
+ const hasNonFlagArgs = args.some((arg, idx) => idx >= currentIndex && !arg.startsWith('-'));
44
+ if (result.commandPath.length === 0 && meta.commands && !hasNonFlagArgs) {
45
+ for (const [name, cmd] of Object.entries(meta.commands)) {
46
+ if (cmd.isDefault) {
47
+ result.commandPath.push(name);
48
+ currentMeta = {
49
+ program: currentMeta.program,
50
+ commands: cmd.subcommands || {},
51
+ options: {
52
+ ...currentMeta.options,
53
+ ...cmd.options,
54
+ },
55
+ defaultRenderName: cmd.renderName || currentMeta.defaultRenderName,
56
+ };
57
+ break;
58
+ }
59
+ }
60
+ }
61
+ // Get the final command metadata
62
+ const commandMeta = getCommandMeta(meta, result.commandPath);
63
+ if (!commandMeta) {
64
+ // If we have no command path but there are non-flag args, the first arg is likely an unknown command
65
+ if (result.commandPath.length === 0 &&
66
+ hasNonFlagArgs &&
67
+ args.length > 0 &&
68
+ !args[0].startsWith('-')) {
69
+ result.errors.push(`Unknown command: ${args[0]}`);
70
+ }
71
+ else {
72
+ result.errors.push(`Unknown command: ${result.commandPath.join(' ')}`);
73
+ }
74
+ return result;
75
+ }
76
+ // Collect all available options (global + inherited)
77
+ const availableOptions = collectAvailableOptions(meta, result.commandPath);
78
+ // Parse remaining arguments as positionals and options
79
+ const positionalArgs = [];
80
+ const optionArgs = {};
81
+ while (currentIndex < args.length) {
82
+ const arg = args[currentIndex];
83
+ if (arg.startsWith('--')) {
84
+ // Long option
85
+ const equalIndex = arg.indexOf('=');
86
+ if (equalIndex > 0) {
87
+ // --option=value format
88
+ const key = arg.slice(2, equalIndex);
89
+ const optionDef = availableOptions[key];
90
+ // Unknown options are allowed for forward compatibility
91
+ const value = arg.slice(equalIndex + 1);
92
+ optionArgs[key] = parseOptionValue(value, optionDef);
93
+ }
94
+ else {
95
+ // --option value format
96
+ const key = arg.slice(2);
97
+ const optionDef = availableOptions[key];
98
+ // Unknown options are allowed for forward compatibility
99
+ if (optionDef && optionDef.array) {
100
+ // Array option - collect all following non-flag values
101
+ currentIndex++;
102
+ const values = [];
103
+ while (currentIndex < args.length &&
104
+ !args[currentIndex].startsWith('-')) {
105
+ values.push(parseOptionValue(args[currentIndex], optionDef));
106
+ currentIndex++;
107
+ }
108
+ currentIndex--; // Back up one since we'll increment at loop end
109
+ optionArgs[key] = values;
110
+ }
111
+ else if (currentIndex + 1 < args.length &&
112
+ !args[currentIndex + 1].startsWith('-')) {
113
+ // Next arg is the value
114
+ currentIndex++;
115
+ optionArgs[key] = parseOptionValue(args[currentIndex], optionDef);
116
+ }
117
+ else {
118
+ // Boolean flag
119
+ optionArgs[key] = true;
120
+ }
121
+ }
122
+ }
123
+ else if (arg.startsWith('-') && arg.length > 1) {
124
+ // Short option(s)
125
+ for (let i = 1; i < arg.length; i++) {
126
+ const shortFlag = arg[i];
127
+ // Find the corresponding long option
128
+ const longOption = findLongOption(shortFlag, availableOptions);
129
+ if (longOption) {
130
+ // Check if this is the last character and there's a value
131
+ if (i === arg.length - 1 &&
132
+ currentIndex + 1 < args.length &&
133
+ !args[currentIndex + 1].startsWith('-')) {
134
+ currentIndex++;
135
+ optionArgs[longOption] = parseOptionValue(args[currentIndex], availableOptions[longOption]);
136
+ }
137
+ else {
138
+ // Boolean flag
139
+ optionArgs[longOption] = true;
140
+ }
141
+ }
142
+ else {
143
+ result.errors.push(`Unknown option: -${shortFlag}`);
144
+ }
145
+ }
146
+ }
147
+ else {
148
+ // Positional argument
149
+ positionalArgs.push(arg);
150
+ }
151
+ currentIndex++;
152
+ }
153
+ // Map positional arguments to named parameters
154
+ mapPositionalArguments(commandMeta.positionals, positionalArgs, result);
155
+ // Apply option defaults and validation
156
+ applyOptionDefaults(availableOptions, optionArgs, result);
157
+ result.options = optionArgs;
158
+ return result;
159
+ }
160
+ /**
161
+ * Gets the command metadata for a given path
162
+ */
163
+ function getCommandMeta(meta, path) {
164
+ if (path.length === 0) {
165
+ return null;
166
+ }
167
+ let current = meta.commands[path[0]];
168
+ if (!current) {
169
+ return null;
170
+ }
171
+ for (let i = 1; i < path.length; i++) {
172
+ if (!current.subcommands || !current.subcommands[path[i]]) {
173
+ return null;
174
+ }
175
+ current = current.subcommands[path[i]];
176
+ }
177
+ return current;
178
+ }
179
+ /**
180
+ * Collects all available options through the inheritance chain
181
+ */
182
+ function collectAvailableOptions(meta, path) {
183
+ let options = { ...meta.options };
184
+ if (path.length === 0) {
185
+ return options;
186
+ }
187
+ // Walk through the command path, merging options
188
+ let current = meta.commands[path[0]];
189
+ if (current) {
190
+ options = { ...options, ...current.options };
191
+ for (let i = 1; i < path.length; i++) {
192
+ if (current.subcommands && current.subcommands[path[i]]) {
193
+ current = current.subcommands[path[i]];
194
+ options = { ...options, ...current.options };
195
+ }
196
+ }
197
+ }
198
+ return options;
199
+ }
200
+ /**
201
+ * Finds the long option name for a short flag
202
+ */
203
+ function findLongOption(shortFlag, options) {
204
+ for (const [name, option] of Object.entries(options)) {
205
+ if (option.short === shortFlag) {
206
+ return name;
207
+ }
208
+ }
209
+ return null;
210
+ }
211
+ /**
212
+ * Parses an option value based on its definition
213
+ */
214
+ function parseOptionValue(value, optionDef) {
215
+ if (!optionDef) {
216
+ // No definition, try to infer type
217
+ if (value === 'true')
218
+ return true;
219
+ if (value === 'false')
220
+ return false;
221
+ if (/^\d+$/.test(value))
222
+ return parseInt(value, 10);
223
+ if (/^\d*\.\d+$/.test(value))
224
+ return parseFloat(value);
225
+ return value;
226
+ }
227
+ // Use default type from option definition
228
+ const defaultValue = optionDef.default;
229
+ if (typeof defaultValue === 'boolean') {
230
+ return value === 'true' || value === '1' || value === 'yes';
231
+ }
232
+ if (typeof defaultValue === 'number') {
233
+ return parseFloat(value);
234
+ }
235
+ // Check choices
236
+ if (optionDef.choices && !optionDef.choices.includes(value)) {
237
+ // Invalid choice, but return anyway (validation will catch it)
238
+ return value;
239
+ }
240
+ return value;
241
+ }
242
+ /**
243
+ * Maps positional arguments to named parameters
244
+ */
245
+ function mapPositionalArguments(positionalDefs, args, result) {
246
+ let argIndex = 0;
247
+ for (const def of positionalDefs) {
248
+ if (def.variadic) {
249
+ // Collect all remaining arguments
250
+ if (argIndex < args.length) {
251
+ result.positionals[def.name] = args.slice(argIndex);
252
+ argIndex = args.length;
253
+ }
254
+ else if (def.required) {
255
+ result.errors.push(`Missing required argument: ${def.name}`);
256
+ }
257
+ else {
258
+ result.positionals[def.name] = [];
259
+ }
260
+ }
261
+ else {
262
+ // Single argument
263
+ if (argIndex < args.length) {
264
+ result.positionals[def.name] = args[argIndex];
265
+ argIndex++;
266
+ }
267
+ else if (def.required) {
268
+ result.errors.push(`Missing required argument: ${def.name}`);
269
+ }
270
+ }
271
+ }
272
+ // Check for extra positional arguments
273
+ if (argIndex < args.length) {
274
+ result.errors.push(`Unexpected arguments: ${args.slice(argIndex).join(' ')}`);
275
+ }
276
+ }
277
+ /**
278
+ * Applies option defaults and validates choices
279
+ */
280
+ function applyOptionDefaults(optionDefs, options, result) {
281
+ for (const [name, def] of Object.entries(optionDefs)) {
282
+ // Apply default if not provided
283
+ if (!(name in options) && def.default !== undefined) {
284
+ options[name] = def.default;
285
+ }
286
+ // Check required
287
+ if (def.required && !(name in options)) {
288
+ result.errors.push(`Missing required option: --${name}`);
289
+ }
290
+ // Validate choices
291
+ if (def.choices && name in options) {
292
+ const value = options[name];
293
+ if (Array.isArray(value)) {
294
+ for (const v of value) {
295
+ if (!def.choices.includes(v)) {
296
+ result.errors.push(`Invalid value for --${name}: ${v}. Valid choices: ${def.choices.join(', ')}`);
297
+ }
298
+ }
299
+ }
300
+ else if (!def.choices.includes(value)) {
301
+ result.errors.push(`Invalid value for --${name}: ${value}. Valid choices: ${def.choices.join(', ')}`);
302
+ }
303
+ }
304
+ }
305
+ }
306
+ /**
307
+ * Generates help text for a command in a specific program
308
+ */
309
+ export function generateCommandHelp(programName, allMeta, commandPath = []) {
310
+ const lines = [];
311
+ const meta = allMeta.programs[programName];
312
+ if (!meta) {
313
+ return `Program not found: ${programName}`;
314
+ }
315
+ if (commandPath.length === 0) {
316
+ // Root help for the program
317
+ lines.push(`Usage: ${programName} <command> [options]`);
318
+ lines.push('');
319
+ lines.push('Commands:');
320
+ for (const [name, cmd] of Object.entries(meta.commands)) {
321
+ const desc = cmd.description || '';
322
+ const defaultMarker = cmd.isDefault ? ' (default)' : '';
323
+ lines.push(` ${name.padEnd(20)} ${desc}${defaultMarker}`);
324
+ }
325
+ if (Object.keys(meta.options).length > 0) {
326
+ lines.push('');
327
+ lines.push('Options:');
328
+ formatOptions(meta.options, lines);
329
+ }
330
+ }
331
+ else {
332
+ // Command-specific help
333
+ const commandMeta = getCommandMeta(meta, commandPath);
334
+ if (!commandMeta) {
335
+ return `Unknown command: ${commandPath.join(' ')}`;
336
+ }
337
+ // Usage line
338
+ let usage = `${programName} ${commandPath.join(' ')}`;
339
+ if (commandMeta.parameters) {
340
+ usage += ' ' + commandMeta.parameters;
341
+ }
342
+ lines.push(`Usage: ${usage} [options]`);
343
+ if (commandMeta.description) {
344
+ lines.push('');
345
+ lines.push(commandMeta.description);
346
+ }
347
+ // Positional arguments
348
+ if (commandMeta.positionals.length > 0) {
349
+ lines.push('');
350
+ lines.push('Arguments:');
351
+ for (const pos of commandMeta.positionals) {
352
+ const marker = pos.required ? '<required>' : '[optional]';
353
+ const variadic = pos.variadic ? '...' : '';
354
+ lines.push(` ${pos.name}${variadic} ${marker}`);
355
+ }
356
+ }
357
+ // Subcommands
358
+ if (commandMeta.subcommands &&
359
+ Object.keys(commandMeta.subcommands).length > 0) {
360
+ lines.push('');
361
+ lines.push('Subcommands:');
362
+ for (const [name, sub] of Object.entries(commandMeta.subcommands)) {
363
+ const desc = sub.description || '';
364
+ lines.push(` ${name.padEnd(20)} ${desc}`);
365
+ }
366
+ }
367
+ // Options
368
+ const availableOptions = collectAvailableOptions(meta, commandPath);
369
+ if (Object.keys(availableOptions).length > 0) {
370
+ lines.push('');
371
+ lines.push('Options:');
372
+ formatOptions(availableOptions, lines);
373
+ }
374
+ }
375
+ return lines.join('\n');
376
+ }
377
+ /**
378
+ * Formats options for help text
379
+ */
380
+ function formatOptions(options, lines) {
381
+ for (const [name, opt] of Object.entries(options)) {
382
+ let line = ' ';
383
+ if (opt.short) {
384
+ line += `-${opt.short}, `;
385
+ }
386
+ else {
387
+ line += ' ';
388
+ }
389
+ line += `--${name}`;
390
+ if (opt.default !== undefined && typeof opt.default !== 'boolean') {
391
+ line += ` <value>`;
392
+ }
393
+ line = line.padEnd(30);
394
+ line += opt.description || '';
395
+ if (opt.default !== undefined) {
396
+ line += ` (default: ${JSON.stringify(opt.default)})`;
397
+ }
398
+ if (opt.choices) {
399
+ line += ` [choices: ${opt.choices.join(', ')}]`;
400
+ }
401
+ lines.push(line);
402
+ }
403
+ }
@@ -0,0 +1,5 @@
1
+ export * from './cli.types.js';
2
+ export * from './cli-runner.js';
3
+ export * from './command-parser.js';
4
+ export { wireCLI, runCLICommand, pikkuCLIRender, executeCLI, CLIError, } from './cli-runner.js';
5
+ export { parseCLIArguments, generateCommandHelp } from './command-parser.js';
@@ -0,0 +1,5 @@
1
+ export * from './cli.types.js';
2
+ export * from './cli-runner.js';
3
+ export * from './command-parser.js';
4
+ export { wireCLI, runCLICommand, pikkuCLIRender, executeCLI, CLIError, } from './cli-runner.js';
5
+ export { parseCLIArguments, generateCommandHelp } from './command-parser.js';
@@ -1,18 +1,67 @@
1
1
  import { CoreHTTPFunctionWiring, RunHTTPWiringOptions, RunHTTPWiringParams, PikkuHTTP, PikkuHTTPRequest, PikkuHTTPResponse } from './http.types.js';
2
- import { CorePikkuMiddleware } from '../../types/core.types.js';
2
+ import { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission, CorePermissionGroup } from '../../function/functions.types.js';
3
+ import { CorePikkuMiddleware, CorePikkuMiddlewareGroup } from '../../types/core.types.js';
3
4
  import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
4
5
  /**
5
- * Registers middleware either globally or for a specific route.
6
+ * Registers HTTP middleware for a specific route pattern.
6
7
  *
7
- * When a string route pattern is provided along with middleware, the middleware
8
- * is applied only to that route. Otherwise, if an array is provided, it is treated
9
- * as global middleware (applied to all routes).
8
+ * This function registers middleware at runtime that will be applied to
9
+ * HTTP routes matching the specified pattern.
10
+ *
11
+ * For tree-shaking benefits, wrap in a factory function:
12
+ * `export const x = () => addHTTPMiddleware('pattern', [...])`
10
13
  *
11
14
  * @template PikkuMiddleware The middleware type.
12
- * @param {PikkuMiddleware[] | string} routeOrMiddleware - Either a global middleware array or a route pattern string.
13
- * @param {PikkuMiddleware[]} [middleware] - The middleware array to apply when a route pattern is specified.
15
+ * @param {string} pattern - Route pattern (e.g., '*' for all routes, '/api/*' for specific routes).
16
+ * @param {CorePikkuMiddlewareGroup} middleware - Array of middleware for this route pattern.
17
+ *
18
+ * @returns {CorePikkuMiddlewareGroup} The middleware array (for chaining/wrapping).
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Recommended: tree-shakeable
23
+ * export const httpGlobal = () => addHTTPMiddleware('*', [
24
+ * corsMiddleware,
25
+ * loggingMiddleware
26
+ * ])
27
+ *
28
+ * // Also works: no tree-shaking
29
+ * export const apiMiddleware = addHTTPMiddleware('/api/*', [
30
+ * authMiddleware
31
+ * ])
32
+ * ```
33
+ */
34
+ export declare const addHTTPMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(pattern: string, middleware: CorePikkuMiddlewareGroup) => CorePikkuMiddlewareGroup;
35
+ /**
36
+ * Registers HTTP permissions for a specific route pattern.
37
+ *
38
+ * This function registers permissions at runtime that will be applied to
39
+ * HTTP routes matching the specified pattern.
40
+ *
41
+ * For tree-shaking benefits, wrap in a factory function:
42
+ * `export const x = () => addHTTPPermission('pattern', [...])`
43
+ *
44
+ * @template PikkuPermission The permission type.
45
+ * @param {string} pattern - Route pattern (e.g., '*' for all routes, '/api/*' for specific routes).
46
+ * @param {CorePermissionGroup | CorePikkuPermission[]} permissions - Permissions for this route pattern.
47
+ *
48
+ * @returns {CorePermissionGroup | CorePikkuPermission[]} The permissions (for chaining/wrapping).
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * // Recommended: tree-shakeable
53
+ * export const httpGlobalPermissions = () => addHTTPPermission('*', [
54
+ * authenticatedPermission,
55
+ * rateLimitPermission
56
+ * ])
57
+ *
58
+ * // Also works: no tree-shaking
59
+ * export const apiPermissions = addHTTPPermission('/api/*', [
60
+ * adminPermission
61
+ * ])
62
+ * ```
14
63
  */
15
- export declare const addHTTPMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(routeOrMiddleware: PikkuMiddleware[] | string, middleware?: PikkuMiddleware[]) => void;
64
+ export declare const addHTTPPermission: <PikkuPermission extends CorePikkuPermission>(pattern: string, permissions: CorePermissionGroup | CorePikkuPermission[]) => CorePermissionGroup | CorePikkuPermission[];
16
65
  /**
17
66
  * Adds a new route to the global HTTP route registry.
18
67
  *
@@ -28,7 +77,7 @@ export declare const addHTTPMiddleware: <PikkuMiddleware extends CorePikkuMiddle
28
77
  * @template PikkuMiddleware Middleware type to be used with the route.
29
78
  * @param {CoreHTTPFunctionWiring<In, Out, Route, PikkuFunction, PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware>} httpWiring - The HTTP wiring configuration object.
30
79
  */
31
- export declare const wireHTTP: <In, Out, Route extends string, PikkuFunction, PikkuFunctionSessionless, PikkuPermissionGroup, PikkuMiddleware>(httpWiring: CoreHTTPFunctionWiring<In, Out, Route, PikkuFunction, PikkuFunctionSessionless, PikkuPermissionGroup, PikkuMiddleware>) => void;
80
+ export declare const wireHTTP: <In, Out, Route extends string, PikkuFunction extends CorePikkuFunction<In, Out> = CorePikkuFunction<In, Out>, PikkuFunctionSessionless extends CorePikkuFunctionSessionless<In, Out> = CorePikkuFunctionSessionless<In, Out>, PikkuPermissionGroup extends CorePikkuPermission<In> = CorePikkuPermission<In>, PikkuMiddleware extends CorePikkuMiddleware = CorePikkuMiddleware>(httpWiring: CoreHTTPFunctionWiring<In, Out, Route, PikkuFunction, PikkuFunctionSessionless, PikkuPermissionGroup, PikkuMiddleware>) => void;
32
81
  /**
33
82
  * Combines the request and response objects into a single HTTP interaction object.
34
83
  *
@@ -87,4 +136,4 @@ export declare const pikkuFetch: <In, Out>(request: Request | PikkuHTTPRequest,
87
136
  * @param {RunHTTPWiringOptions & RunHTTPWiringParams} options - Options such as singleton services, session handling, and error configuration.
88
137
  * @returns {Promise<Out | void>} The output from the route handler or void if an error occurred.
89
138
  */
90
- export declare const fetchData: <In, Out>(request: Request | PikkuHTTPRequest, response: PikkuHTTPResponse, { singletonServices, createSessionServices, skipUserSession, respondWith404, logWarningsForStatusCodes, coerceDataFromSchema, bubbleErrors, generateRequestId, ignoreMiddleware, }: RunHTTPWiringOptions & RunHTTPWiringParams) => Promise<Out | void>;
139
+ export declare const fetchData: <In, Out>(request: Request | PikkuHTTPRequest, response: PikkuHTTPResponse, { singletonServices, createSessionServices, skipUserSession, respondWith404, logWarningsForStatusCodes, coerceDataFromSchema, bubbleErrors, generateRequestId, }: RunHTTPWiringOptions & RunHTTPWiringParams) => Promise<Out | void>;