@pikku/cli 0.6.16 → 0.6.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @pikku/cli
2
2
 
3
+ ## 0.6.17
4
+
5
+ ### Patch Changes
6
+
7
+ - 57f5d8c: refactor: moving getSession out of nextjs wrapper since it bundles all routes and only needs middleware
8
+ - 141d690: feat: creating a nextJS http wrapper for proxying
9
+ - e5a5a12: feat: adding watch command (pikki all --watch)
10
+ - 0ad27a2: chore: switching from glon to tinyblobby
11
+
3
12
  ## 0.6.16
4
13
 
5
14
  ### Patch Changes
package/bin/pikku-all.ts CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  PikkuCLIOptions,
7
7
  writeFileInDir,
8
8
  } from '../src/utils.js'
9
- import { getPikkuCLIConfig } from '../src/pikku-cli-config.js'
9
+ import { getPikkuCLIConfig, PikkuCLIConfig } from '../src/pikku-cli-config.js'
10
10
  import { pikkuHTTP } from './pikku-http.js'
11
11
  import { pikkuFunctionTypes } from './pikku-function-types.js'
12
12
  import { pikkuHTTPMap } from './pikku-routes-map.js'
@@ -20,10 +20,9 @@ import { pikkuScheduler } from './pikku-scheduler.js'
20
20
  import { pikkuSchemas } from './pikku-schemas.js'
21
21
  import { pikkuWebSocket } from './pikku-websocket.js'
22
22
  import { inspectorGlob } from '../src/inspector-glob.js'
23
+ import chokidar from 'chokidar'
23
24
 
24
- export const action = async (options: PikkuCLIOptions): Promise<void> => {
25
- logPikkuLogo()
26
-
25
+ const runAll = async (cliConfig: PikkuCLIConfig, options: PikkuCLIOptions) => {
27
26
  const imports: string[] = []
28
27
  const addImport = (from: string) => {
29
28
  imports.push(
@@ -31,13 +30,6 @@ export const action = async (options: PikkuCLIOptions): Promise<void> => {
31
30
  )
32
31
  }
33
32
 
34
- const cliConfig = await getPikkuCLIConfig(
35
- options.config,
36
- [],
37
- options.tags,
38
- true
39
- )
40
-
41
33
  let typesDeclarationFileExists = true
42
34
  let visitState = await inspectorGlob(
43
35
  cliConfig.rootDir,
@@ -99,6 +91,71 @@ export const action = async (options: PikkuCLIOptions): Promise<void> => {
99
91
  await writeFileInDir(cliConfig.bootstrapFile, imports.join('\n'))
100
92
  }
101
93
 
94
+ const watch = (cliConfig: PikkuCLIConfig, options: PikkuCLIOptions) => {
95
+ const configWatcher = chokidar.watch(cliConfig.routeDirectories, {
96
+ ignoreInitial: true,
97
+ ignored: /.*\.gen\.tsx?/,
98
+ })
99
+
100
+ let watcher = new chokidar.FSWatcher({})
101
+
102
+ const generatorWatcher = () => {
103
+ watcher.close()
104
+
105
+ logInfo(
106
+ `• Watching directories: \n - ${cliConfig.routeDirectories.join('\n - ')}`
107
+ )
108
+ watcher = chokidar.watch(cliConfig.routeDirectories, {
109
+ ignoreInitial: true,
110
+ ignored: /.*\.gen\.ts/,
111
+ })
112
+
113
+ watcher.on('ready', async () => {
114
+ const handle = async () => {
115
+ try {
116
+ await runAll(cliConfig, options)
117
+ } catch (err) {
118
+ console.error(err)
119
+ console.info()
120
+ }
121
+ }
122
+
123
+ await handle()
124
+
125
+ let timeout: ReturnType<typeof setTimeout> | undefined
126
+
127
+ const deduped = (_file: string) => {
128
+ if (timeout) {
129
+ clearTimeout(timeout)
130
+ }
131
+ timeout = setTimeout(handle, 10)
132
+ }
133
+
134
+ watcher.on('change', deduped)
135
+ watcher.on('add', deduped)
136
+ watcher.on('unlink', deduped)
137
+ })
138
+ }
139
+
140
+ configWatcher.on('ready', generatorWatcher)
141
+ configWatcher.on('change', generatorWatcher)
142
+ }
143
+
144
+ export const action = async (options: PikkuCLIOptions): Promise<void> => {
145
+ logPikkuLogo()
146
+
147
+ const cliConfig = await getPikkuCLIConfig(
148
+ options.config,
149
+ [],
150
+ options.tags,
151
+ true
152
+ )
153
+
154
+ if (options.watch) {
155
+ watch(cliConfig, options)
156
+ }
157
+ }
158
+
102
159
  export const all = (program: Command): void => {
103
160
  program
104
161
  .command('all', { isDefault: true })
@@ -114,5 +171,6 @@ export const all = (program: Command): void => {
114
171
  )
115
172
  .option('-c | --config <string>', 'The path to pikku cli config file')
116
173
  .option('-t | --tags <tags...>', 'Which tags to filter by')
174
+ .option('-w | --watch', 'Whether to watch file changes')
117
175
  .action(action)
118
176
  }
@@ -1,5 +1,6 @@
1
1
  import { Command } from 'commander'
2
- import { serializeNextJsWrapper } from '../src/nextjs/serialize-nextjs-wrapper.js'
2
+ import { serializeNextJsBackendWrapper as serializeNextBackendWrapper } from '../src/nextjs/serialize-nextjs-backend-wrapper.js'
3
+ import { serializeNextJsHTTPWrapper as serializeNextHTTPWrapper } from '../src/nextjs/serialize-nextjs-http-wrapper.js'
3
4
  import {
4
5
  getFileImportRelativePath,
5
6
  getPikkuFilesAndMethods,
@@ -14,11 +15,13 @@ import { inspectorGlob } from '../src/inspector-glob.js'
14
15
 
15
16
  export const pikkuNext = async (
16
17
  {
17
- nextJSfile,
18
+ nextBackendFile,
19
+ nextHTTPFile,
18
20
  routesFile,
19
21
  routesMapDeclarationFile,
20
22
  schemaDirectory,
21
23
  packageMappings,
24
+ fetchFile,
22
25
  }: PikkuCLIConfig,
23
26
  visitState: InspectorState,
24
27
  options: PikkuCLIOptions
@@ -26,21 +29,28 @@ export const pikkuNext = async (
26
29
  return await logCommandInfoAndTime(
27
30
  'Generating nextjs wrapper',
28
31
  'Generated nextjs wrapper',
29
- [nextJSfile === undefined, 'nextjs outfile is not defined'],
32
+ [nextBackendFile === undefined, 'nextjs outfile is not defined'],
30
33
  async () => {
31
- if (!nextJSfile) {
32
- throw new Error('nextJSfile is required in pikku config')
34
+ if (!nextBackendFile || !nextHTTPFile) {
35
+ throw new Error(
36
+ 'nextBackendFile or nextHTTPFile is required in pikku config'
37
+ )
38
+ }
39
+
40
+ if (nextHTTPFile && !fetchFile) {
41
+ throw new Error(
42
+ 'fetchFile is required in pikku config in order for nextJS http wrapper to work'
43
+ )
33
44
  }
34
45
 
35
46
  const {
36
47
  pikkuConfigFactory,
37
48
  singletonServicesFactory,
38
49
  sessionServicesFactory,
39
- userSessionType,
40
50
  } = await getPikkuFilesAndMethods(
41
51
  visitState,
42
52
  packageMappings,
43
- nextJSfile,
53
+ nextBackendFile,
44
54
  options,
45
55
  {
46
56
  config: true,
@@ -49,37 +59,46 @@ export const pikkuNext = async (
49
59
  }
50
60
  )
51
61
 
52
- const pikkuConfigImport = `import { ${pikkuConfigFactory.variable} as createConfig } from '${getFileImportRelativePath(nextJSfile, pikkuConfigFactory.file, packageMappings)}'`
53
- const singletonServicesImport = `import { ${singletonServicesFactory.variable} as createSingletonServices } from '${getFileImportRelativePath(nextJSfile, singletonServicesFactory.file, packageMappings)}'`
54
- const sessionServicesImport = `import { ${sessionServicesFactory.variable} as createSessionServices } from '${getFileImportRelativePath(nextJSfile, sessionServicesFactory.file, packageMappings)}'`
55
- const userSessionImport = `import type { ${userSessionType.type} as UserSession } from '${getFileImportRelativePath(nextJSfile, userSessionType.file, packageMappings)}'`
62
+ const pikkuConfigImport = `import { ${pikkuConfigFactory.variable} as createConfig } from '${getFileImportRelativePath(nextBackendFile, pikkuConfigFactory.file, packageMappings)}'`
63
+ const singletonServicesImport = `import { ${singletonServicesFactory.variable} as createSingletonServices } from '${getFileImportRelativePath(nextBackendFile, singletonServicesFactory.file, packageMappings)}'`
64
+ const sessionServicesImport = `import { ${sessionServicesFactory.variable} as createSessionServices } from '${getFileImportRelativePath(nextBackendFile, sessionServicesFactory.file, packageMappings)}'`
56
65
 
57
66
  const routesPath = getFileImportRelativePath(
58
- nextJSfile,
67
+ nextBackendFile,
59
68
  routesFile,
60
69
  packageMappings
61
70
  )
62
71
  const routesMapDeclarationPath = getFileImportRelativePath(
63
- nextJSfile,
72
+ nextBackendFile,
64
73
  routesMapDeclarationFile,
65
74
  packageMappings
66
75
  )
67
76
  const schemasPath = getFileImportRelativePath(
68
- nextJSfile,
77
+ nextBackendFile,
69
78
  `${schemaDirectory}/register.gen.ts`,
70
79
  packageMappings
71
80
  )
72
81
 
73
- const content = serializeNextJsWrapper(
74
- routesPath,
75
- routesMapDeclarationPath,
76
- schemasPath,
77
- pikkuConfigImport,
78
- singletonServicesImport,
79
- sessionServicesImport,
80
- userSessionImport
81
- )
82
- await writeFileInDir(nextJSfile, content)
82
+ if (nextBackendFile) {
83
+ const content = serializeNextBackendWrapper(
84
+ routesPath,
85
+ routesMapDeclarationPath,
86
+ schemasPath,
87
+ pikkuConfigImport,
88
+ singletonServicesImport,
89
+ sessionServicesImport
90
+ )
91
+ await writeFileInDir(nextBackendFile, content)
92
+ }
93
+
94
+ if (nextHTTPFile) {
95
+ const pikkuFetchImport = `import { PikkuFetch } from '${getFileImportRelativePath(nextBackendFile, fetchFile!, packageMappings)}'`
96
+ const content = serializeNextHTTPWrapper(
97
+ routesMapDeclarationPath,
98
+ pikkuFetchImport
99
+ )
100
+ await writeFileInDir(nextHTTPFile, content)
101
+ }
83
102
  }
84
103
  )
85
104
  }
@@ -88,7 +107,7 @@ export const action = async (options: PikkuCLIOptions): Promise<void> => {
88
107
  logPikkuLogo()
89
108
  const cliConfig = await getPikkuCLIConfig(
90
109
  options.config,
91
- ['rootDir', 'schemaDirectory', 'configDir', 'nextJSfile'],
110
+ ['rootDir', 'schemaDirectory', 'configDir', 'nextBackendFile'],
92
111
  options.tags,
93
112
  true
94
113
  )
package/cli.schema.json CHANGED
@@ -138,7 +138,10 @@
138
138
  "fetchFile": {
139
139
  "type": "string"
140
140
  },
141
- "nextJSfile": {
141
+ "nextBackendFile": {
142
+ "type": "string"
143
+ },
144
+ "nextHTTPFile": {
142
145
  "type": "string"
143
146
  },
144
147
  "openAPI": {
@@ -13,13 +13,12 @@ import { pikkuScheduler } from './pikku-scheduler.js';
13
13
  import { pikkuSchemas } from './pikku-schemas.js';
14
14
  import { pikkuWebSocket } from './pikku-websocket.js';
15
15
  import { inspectorGlob } from '../src/inspector-glob.js';
16
- export const action = async (options) => {
17
- logPikkuLogo();
16
+ import chokidar from 'chokidar';
17
+ const runAll = async (cliConfig, options) => {
18
18
  const imports = [];
19
19
  const addImport = (from) => {
20
20
  imports.push(`import '${getFileImportRelativePath(cliConfig.bootstrapFile, from, cliConfig.packageMappings)}'`);
21
21
  };
22
- const cliConfig = await getPikkuCLIConfig(options.config, [], options.tags, true);
23
22
  let typesDeclarationFileExists = true;
24
23
  let visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories, cliConfig.filters);
25
24
  if (!existsSync(cliConfig.typesDeclarationFile)) {
@@ -59,6 +58,52 @@ export const action = async (options) => {
59
58
  }
60
59
  await writeFileInDir(cliConfig.bootstrapFile, imports.join('\n'));
61
60
  };
61
+ const watch = (cliConfig, options) => {
62
+ const configWatcher = chokidar.watch(cliConfig.routeDirectories, {
63
+ ignoreInitial: true,
64
+ ignored: /.*\.gen\.tsx?/,
65
+ });
66
+ let watcher = new chokidar.FSWatcher({});
67
+ const generatorWatcher = () => {
68
+ watcher.close();
69
+ logInfo(`• Watching directories: \n - ${cliConfig.routeDirectories.join('\n - ')}`);
70
+ watcher = chokidar.watch(cliConfig.routeDirectories, {
71
+ ignoreInitial: true,
72
+ ignored: /.*\.gen\.ts/,
73
+ });
74
+ watcher.on('ready', async () => {
75
+ const handle = async () => {
76
+ try {
77
+ await runAll(cliConfig, options);
78
+ }
79
+ catch (err) {
80
+ console.error(err);
81
+ console.info();
82
+ }
83
+ };
84
+ await handle();
85
+ let timeout;
86
+ const deduped = (_file) => {
87
+ if (timeout) {
88
+ clearTimeout(timeout);
89
+ }
90
+ timeout = setTimeout(handle, 10);
91
+ };
92
+ watcher.on('change', deduped);
93
+ watcher.on('add', deduped);
94
+ watcher.on('unlink', deduped);
95
+ });
96
+ };
97
+ configWatcher.on('ready', generatorWatcher);
98
+ configWatcher.on('change', generatorWatcher);
99
+ };
100
+ export const action = async (options) => {
101
+ logPikkuLogo();
102
+ const cliConfig = await getPikkuCLIConfig(options.config, [], options.tags, true);
103
+ if (options.watch) {
104
+ watch(cliConfig, options);
105
+ }
106
+ };
62
107
  export const all = (program) => {
63
108
  program
64
109
  .command('all', { isDefault: true })
@@ -68,5 +113,6 @@ export const all = (program) => {
68
113
  .option('-se | --session-services-factory-type', 'The type of your session services factory')
69
114
  .option('-c | --config <string>', 'The path to pikku cli config file')
70
115
  .option('-t | --tags <tags...>', 'Which tags to filter by')
116
+ .option('-w | --watch', 'Whether to watch file changes')
71
117
  .action(action);
72
118
  };
@@ -2,6 +2,6 @@ import { Command } from 'commander';
2
2
  import { PikkuCLIOptions } from '../src/utils.js';
3
3
  import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
4
4
  import { InspectorState } from '@pikku/inspector';
5
- export declare const pikkuNext: ({ nextJSfile, routesFile, routesMapDeclarationFile, schemaDirectory, packageMappings, }: PikkuCLIConfig, visitState: InspectorState, options: PikkuCLIOptions) => Promise<boolean>;
5
+ export declare const pikkuNext: ({ nextBackendFile, nextHTTPFile, routesFile, routesMapDeclarationFile, schemaDirectory, packageMappings, fetchFile, }: PikkuCLIConfig, visitState: InspectorState, options: PikkuCLIOptions) => Promise<boolean>;
6
6
  export declare const action: (options: PikkuCLIOptions) => Promise<void>;
7
7
  export declare const nextjs: (program: Command) => void;
@@ -1,31 +1,41 @@
1
- import { serializeNextJsWrapper } from '../src/nextjs/serialize-nextjs-wrapper.js';
1
+ import { serializeNextJsBackendWrapper as serializeNextBackendWrapper } from '../src/nextjs/serialize-nextjs-backend-wrapper.js';
2
+ import { serializeNextJsHTTPWrapper as serializeNextHTTPWrapper } from '../src/nextjs/serialize-nextjs-http-wrapper.js';
2
3
  import { getFileImportRelativePath, getPikkuFilesAndMethods, logCommandInfoAndTime, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
3
4
  import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
4
5
  import { inspectorGlob } from '../src/inspector-glob.js';
5
- export const pikkuNext = async ({ nextJSfile, routesFile, routesMapDeclarationFile, schemaDirectory, packageMappings, }, visitState, options) => {
6
- return await logCommandInfoAndTime('Generating nextjs wrapper', 'Generated nextjs wrapper', [nextJSfile === undefined, 'nextjs outfile is not defined'], async () => {
7
- if (!nextJSfile) {
8
- throw new Error('nextJSfile is required in pikku config');
6
+ export const pikkuNext = async ({ nextBackendFile, nextHTTPFile, routesFile, routesMapDeclarationFile, schemaDirectory, packageMappings, fetchFile, }, visitState, options) => {
7
+ return await logCommandInfoAndTime('Generating nextjs wrapper', 'Generated nextjs wrapper', [nextBackendFile === undefined, 'nextjs outfile is not defined'], async () => {
8
+ if (!nextBackendFile || !nextHTTPFile) {
9
+ throw new Error('nextBackendFile or nextHTTPFile is required in pikku config');
9
10
  }
10
- const { pikkuConfigFactory, singletonServicesFactory, sessionServicesFactory, userSessionType, } = await getPikkuFilesAndMethods(visitState, packageMappings, nextJSfile, options, {
11
+ if (nextHTTPFile && !fetchFile) {
12
+ throw new Error('fetchFile is required in pikku config in order for nextJS http wrapper to work');
13
+ }
14
+ const { pikkuConfigFactory, singletonServicesFactory, sessionServicesFactory, } = await getPikkuFilesAndMethods(visitState, packageMappings, nextBackendFile, options, {
11
15
  config: true,
12
16
  singletonServicesFactory: true,
13
17
  sessionServicesFactory: true,
14
18
  });
15
- const pikkuConfigImport = `import { ${pikkuConfigFactory.variable} as createConfig } from '${getFileImportRelativePath(nextJSfile, pikkuConfigFactory.file, packageMappings)}'`;
16
- const singletonServicesImport = `import { ${singletonServicesFactory.variable} as createSingletonServices } from '${getFileImportRelativePath(nextJSfile, singletonServicesFactory.file, packageMappings)}'`;
17
- const sessionServicesImport = `import { ${sessionServicesFactory.variable} as createSessionServices } from '${getFileImportRelativePath(nextJSfile, sessionServicesFactory.file, packageMappings)}'`;
18
- const userSessionImport = `import type { ${userSessionType.type} as UserSession } from '${getFileImportRelativePath(nextJSfile, userSessionType.file, packageMappings)}'`;
19
- const routesPath = getFileImportRelativePath(nextJSfile, routesFile, packageMappings);
20
- const routesMapDeclarationPath = getFileImportRelativePath(nextJSfile, routesMapDeclarationFile, packageMappings);
21
- const schemasPath = getFileImportRelativePath(nextJSfile, `${schemaDirectory}/register.gen.ts`, packageMappings);
22
- const content = serializeNextJsWrapper(routesPath, routesMapDeclarationPath, schemasPath, pikkuConfigImport, singletonServicesImport, sessionServicesImport, userSessionImport);
23
- await writeFileInDir(nextJSfile, content);
19
+ const pikkuConfigImport = `import { ${pikkuConfigFactory.variable} as createConfig } from '${getFileImportRelativePath(nextBackendFile, pikkuConfigFactory.file, packageMappings)}'`;
20
+ const singletonServicesImport = `import { ${singletonServicesFactory.variable} as createSingletonServices } from '${getFileImportRelativePath(nextBackendFile, singletonServicesFactory.file, packageMappings)}'`;
21
+ const sessionServicesImport = `import { ${sessionServicesFactory.variable} as createSessionServices } from '${getFileImportRelativePath(nextBackendFile, sessionServicesFactory.file, packageMappings)}'`;
22
+ const routesPath = getFileImportRelativePath(nextBackendFile, routesFile, packageMappings);
23
+ const routesMapDeclarationPath = getFileImportRelativePath(nextBackendFile, routesMapDeclarationFile, packageMappings);
24
+ const schemasPath = getFileImportRelativePath(nextBackendFile, `${schemaDirectory}/register.gen.ts`, packageMappings);
25
+ if (nextBackendFile) {
26
+ const content = serializeNextBackendWrapper(routesPath, routesMapDeclarationPath, schemasPath, pikkuConfigImport, singletonServicesImport, sessionServicesImport);
27
+ await writeFileInDir(nextBackendFile, content);
28
+ }
29
+ if (nextHTTPFile) {
30
+ const pikkuFetchImport = `import { PikkuFetch } from '${getFileImportRelativePath(nextBackendFile, fetchFile, packageMappings)}'`;
31
+ const content = serializeNextHTTPWrapper(routesMapDeclarationPath, pikkuFetchImport);
32
+ await writeFileInDir(nextHTTPFile, content);
33
+ }
24
34
  });
25
35
  };
26
36
  export const action = async (options) => {
27
37
  logPikkuLogo();
28
- const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'nextJSfile'], options.tags, true);
38
+ const cliConfig = await getPikkuCLIConfig(options.config, ['rootDir', 'schemaDirectory', 'configDir', 'nextBackendFile'], options.tags, true);
29
39
  const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories, cliConfig.filters);
30
40
  await pikkuNext(cliConfig, visitState, options);
31
41
  };
@@ -1,5 +1,5 @@
1
1
  import * as path from 'path';
2
- import { glob } from 'glob';
2
+ import { glob } from 'tinyglobby';
3
3
  import { inspect } from '@pikku/inspector';
4
4
  import { logCommandInfoAndTime } from './utils.js';
5
5
  export const inspectorGlob = async (rootDir, routeDirectories, filters) => {
@@ -0,0 +1 @@
1
+ export declare const serializeNextJsBackendWrapper: (routesPath: string, routesMapPath: string, schemasPath: string, configImport: string, singleServicesFactoryImport: string, sessionServicesImport: string) => string;
@@ -1,18 +1,16 @@
1
- export const serializeNextJsWrapper = (routesPath, routesMapPath, schemasPath, configImport, singleServicesFactoryImport, sessionServicesImport, userSessionTypeImport) => {
1
+ export const serializeNextJsBackendWrapper = (routesPath, routesMapPath, schemasPath, configImport, singleServicesFactoryImport, sessionServicesImport) => {
2
2
  return `'server-only'
3
3
 
4
4
  /**
5
5
  * This file provides a wrapper around the PikkuNextJS class to allow for methods to be type checked against your routes.
6
6
  * It ensures type safety for route handling methods when integrating with the @pikku/core framework.
7
7
  */
8
- import { PikkuMiddleware } from '@pikku/core'
9
- import { PikkuNextJS, PikkuNextRequest } from '@pikku/next'
8
+ import { PikkuNextJS } from '@pikku/next'
10
9
  import type { RoutesMap, RouteHandlerOf, RoutesWithMethod } from '${routesMapPath}'
11
10
 
12
11
  ${configImport}
13
12
  ${singleServicesFactoryImport}
14
13
  ${sessionServicesImport}
15
- ${userSessionTypeImport}
16
14
 
17
15
  import '${routesPath}'
18
16
  import '${schemasPath}'
@@ -24,7 +22,7 @@ let _pikku: PikkuNextJS | undefined
24
22
  *
25
23
  * @returns An object containing methods for making dynamic and static action requests, as well as session retrieval.
26
24
  */
27
- export const pikku = () => {
25
+ export const pikku = (_options?: any) => {
28
26
  if (!_pikku) {
29
27
  _pikku = new PikkuNextJS(
30
28
  createConfig as any,
@@ -33,20 +31,6 @@ export const pikku = () => {
33
31
  )
34
32
  }
35
33
 
36
- /**
37
- * Retrieves the user session using the current PikkuNextJS instance.
38
- *
39
- * @param request - The Next.js request object.
40
- * @param middleware - An array of middleware functions to process the request.
41
- * @returns A promise that resolves to the user session.
42
- */
43
- const getSession = async (
44
- request: PikkuNextRequest,
45
- middleware: PikkuMiddleware[]
46
- ): Promise<UserSession | undefined> => {
47
- return _pikku!.getSession(request, middleware) as any
48
- }
49
-
50
34
  /**
51
35
  * Makes a dynamic action request for a specified route and method.
52
36
  * Dynamic requests may access headers and cookies and are therefore unsuitable for precompile stages.
@@ -184,7 +168,6 @@ export const pikku = () => {
184
168
  }
185
169
 
186
170
  return {
187
- getSession,
188
171
  get: dynamicGet,
189
172
  post: dynamicPost,
190
173
  patch: dynamicPatch,
@@ -0,0 +1 @@
1
+ export declare const serializeNextJsHTTPWrapper: (routesMapPath: string, pikkuFetchImport: string) => string;
@@ -0,0 +1,160 @@
1
+ export const serializeNextJsHTTPWrapper = (routesMapPath, pikkuFetchImport) => {
2
+ return `'server-only'
3
+
4
+ /**
5
+ * This file provides a wrapper around the PikkuNextJS class to allow for methods to be type checked against your routes.
6
+ * It ensures type safety for route handling methods when integrating with the @pikku/core framework.
7
+ */
8
+ import { CorePikkuFetchOptions } from '@pikku/fetch'
9
+ import type { RoutesMap, RouteHandlerOf, RoutesWithMethod } from '${routesMapPath}'
10
+
11
+ let _pikku: PikkuFetch | undefined
12
+
13
+ ${pikkuFetchImport}
14
+
15
+ /**
16
+ * Initializes and returns an instance of PikkuNextJS with helper methods for handling route requests.
17
+ *
18
+ * @returns An object containing methods for making dynamic and static action requests, as well as session retrieval.
19
+ */
20
+ export const pikku = (options?: CorePikkuFetchOptions) => {
21
+ if (!_pikku) {
22
+ _pikku = new PikkuFetch(options)
23
+ }
24
+
25
+ const dynamicActionRequest = async <
26
+ Route extends keyof RoutesMap,
27
+ Method extends keyof RoutesMap[Route]
28
+ >(
29
+ route: Route,
30
+ method: Method,
31
+ data: RouteHandlerOf<Route, Method>['input'] = null
32
+ ): Promise<RouteHandlerOf<Route, Method>['output']> => {
33
+ return (_pikku! as any)[method](route, data as any)
34
+ }
35
+
36
+ /**
37
+ * Makes a static action request for a specified route and method.
38
+ * Static requests do not depend on headers or cookies and are suitable for precompile stages.
39
+ *
40
+ * @template Route - The route key from the RoutesMap.
41
+ * @template Method - The method key from the specified route.
42
+ * @param route - The route identifier.
43
+ * @param method - The HTTP method to be used for the request.
44
+ * @param data - The input data for the request, defaults to null.
45
+ * @returns A promise that resolves to the output of the route handler.
46
+ */
47
+ const staticActionRequest = async <
48
+ Route extends keyof RoutesMap,
49
+ Method extends keyof RoutesMap[Route]
50
+ >(
51
+ route: Route,
52
+ method: Method,
53
+ data: RouteHandlerOf<Route, Method>['input'] = null
54
+ ): Promise<RouteHandlerOf<Route, Method>['output']> => {
55
+ return (_pikku! as any)[method](route, data as any)
56
+ }
57
+
58
+ /**
59
+ * Makes a dynamic POST request for a specified route.
60
+ *
61
+ * @template Route - The route key with the POST method.
62
+ * @param route - The route identifier.
63
+ * @param data - The input data for the POST request, defaults to null.
64
+ * @returns A promise that resolves to the output of the POST handler.
65
+ */
66
+ const dynamicPost = <Route extends RoutesWithMethod<'POST'>>(
67
+ route: Route,
68
+ data: RouteHandlerOf<Route, 'POST'>['input'] = null
69
+ ): Promise<RouteHandlerOf<Route, 'POST'>['output']> => {
70
+ return dynamicActionRequest(route, 'POST', data)
71
+ }
72
+
73
+ /**
74
+ * Makes a dynamic GET request for a specified route.
75
+ *
76
+ * @template Route - The route key with the GET method.
77
+ * @param route - The route identifier.
78
+ * @param data - The input data for the GET request, defaults to null.
79
+ * @returns A promise that resolves to the output of the GET handler.
80
+ */
81
+ const dynamicGet = <Route extends RoutesWithMethod<'GET'>>(
82
+ route: Route,
83
+ data: RouteHandlerOf<Route, 'GET'>['input'] = null
84
+ ): Promise<RouteHandlerOf<Route, 'GET'>['output']> => {
85
+ return dynamicActionRequest(route, 'GET', data)
86
+ }
87
+
88
+ /**
89
+ * Makes a dynamic PATCH request for a specified route.
90
+ *
91
+ * @template Route - The route key with the PATCH method.
92
+ * @param route - The route identifier.
93
+ * @param data - The input data for the PATCH request, defaults to null.
94
+ * @returns A promise that resolves to the output of the PATCH handler.
95
+ */
96
+ const dynamicPatch = <Route extends RoutesWithMethod<'PATCH'>>(
97
+ route: Route,
98
+ data: RouteHandlerOf<Route, 'PATCH'>['input'] = null
99
+ ): Promise<RouteHandlerOf<Route, 'PATCH'>['output']> => {
100
+ return dynamicActionRequest(route, 'PATCH', data)
101
+ }
102
+
103
+ /**
104
+ * Makes a dynamic DELETE request for a specified route.
105
+ *
106
+ * @template Route - The route key with the DELETE method.
107
+ * @param route - The route identifier.
108
+ * @param data - The input data for the DELETE request, defaults to null.
109
+ * @returns A promise that resolves to the output of the DELETE handler.
110
+ */
111
+ const dynamicDel = <Route extends RoutesWithMethod<'DELETE'>>(
112
+ route: Route,
113
+ data: RouteHandlerOf<Route, 'DELETE'>['input'] = null
114
+ ): Promise<RouteHandlerOf<Route, 'DELETE'>['output']> => {
115
+ return dynamicActionRequest(route, 'DELETE', data)
116
+ }
117
+
118
+ // Static Requests
119
+
120
+ /**
121
+ * Makes a static POST request for a specified route.
122
+ *
123
+ * @template Route - The route key with the POST method.
124
+ * @param route - The route identifier.
125
+ * @param data - The input data for the POST request, defaults to null.
126
+ * @returns A promise that resolves to the output of the POST handler.
127
+ */
128
+ const staticPost = <Route extends RoutesWithMethod<'POST'>>(
129
+ route: Route,
130
+ data: RouteHandlerOf<Route, 'POST'>['input'] = null
131
+ ): Promise<RouteHandlerOf<Route, 'POST'>['output']> => {
132
+ return staticActionRequest(route, 'POST', data)
133
+ }
134
+
135
+ /**
136
+ * Makes a static GET request for a specified route.
137
+ *
138
+ * @template Route - The route key with the GET method.
139
+ * @param route - The route identifier.
140
+ * @param data - The input data for the GET request, defaults to null.
141
+ * @returns A promise that resolves to the output of the GET handler.
142
+ */
143
+ const staticGet = <Route extends RoutesWithMethod<'GET'>>(
144
+ route: Route,
145
+ data: RouteHandlerOf<Route, 'GET'>['input'] = null
146
+ ): Promise<RouteHandlerOf<Route, 'GET'>['output']> => {
147
+ return staticActionRequest(route, 'GET', data)
148
+ }
149
+
150
+ return {
151
+ get: dynamicGet,
152
+ post: dynamicPost,
153
+ patch: dynamicPatch,
154
+ del: dynamicDel,
155
+ staticGet,
156
+ staticPost
157
+ }
158
+ }
159
+ `;
160
+ };
@@ -20,7 +20,8 @@ export type PikkuCLIConfig = {
20
20
  supportsImportAttributes: boolean;
21
21
  configDir: string;
22
22
  tsconfig: string;
23
- nextJSfile?: string;
23
+ nextBackendFile?: string;
24
+ nextHTTPFile?: string;
24
25
  fetchFile?: string;
25
26
  websocketFile?: string;
26
27
  openAPI?: {
@@ -1,6 +1,11 @@
1
1
  import { join, dirname, resolve, isAbsolute } from 'path';
2
2
  import { readdir, readFile } from 'fs/promises';
3
- const CONFIG_DIR_FILES = ['nextJSfile', 'fetchFile', 'websocketFile'];
3
+ const CONFIG_DIR_FILES = [
4
+ 'nextBackendFile',
5
+ 'nextHTTPFile',
6
+ 'fetchFile',
7
+ 'websocketFile',
8
+ ];
4
9
  export const getPikkuCLIConfig = async (configFile = undefined, requiredFields, tags = [], exitProcess = false) => {
5
10
  const config = await _getPikkuCLIConfig(configFile, requiredFields, tags, exitProcess);
6
11
  return config;
@@ -18,6 +18,7 @@ export type FilesAndMethods = {
18
18
  sessionServicesFactory: Meta;
19
19
  };
20
20
  export interface PikkuCLIOptions {
21
+ watch?: boolean;
21
22
  config?: string;
22
23
  configFileType?: string;
23
24
  userSessionType?: string;
@@ -1 +1 @@
1
- {"root":["../bin/pikku-all.ts","../bin/pikku-channels-map.ts","../bin/pikku-channels.ts","../bin/pikku-fetch.ts","../bin/pikku-function-types.ts","../bin/pikku-http.ts","../bin/pikku-nextjs.ts","../bin/pikku-openapi.ts","../bin/pikku-routes-map.ts","../bin/pikku-scheduler.ts","../bin/pikku-schemas.ts","../bin/pikku-websocket.ts","../bin/pikku.ts","../src/inspector-glob.ts","../src/pikku-cli-config.ts","../src/utils.ts","../src/channels/serialize-channels.ts","../src/channels/serialize-typed-channel-map.ts","../src/channels/serialize-websocket-wrapper.ts","../src/core/serialize-import-map.ts","../src/core/serialize-pikku-types.ts","../src/http/serialize-fetch-wrapper.ts","../src/http/serialize-route-imports.ts","../src/http/serialize-route-meta.ts","../src/http/serialize-typed-route-map.ts","../src/nextjs/serialize-nextjs-wrapper.ts","../src/openapi/openapi-spec-generator.ts","../src/scheduler/serialize-schedulers.ts","../src/schema/schema-generator.ts"],"version":"5.7.3"}
1
+ {"root":["../bin/pikku-all.ts","../bin/pikku-channels-map.ts","../bin/pikku-channels.ts","../bin/pikku-fetch.ts","../bin/pikku-function-types.ts","../bin/pikku-http.ts","../bin/pikku-nextjs.ts","../bin/pikku-openapi.ts","../bin/pikku-routes-map.ts","../bin/pikku-scheduler.ts","../bin/pikku-schemas.ts","../bin/pikku-websocket.ts","../bin/pikku.ts","../src/inspector-glob.ts","../src/pikku-cli-config.ts","../src/utils.ts","../src/channels/serialize-channels.ts","../src/channels/serialize-typed-channel-map.ts","../src/channels/serialize-websocket-wrapper.ts","../src/core/serialize-import-map.ts","../src/core/serialize-pikku-types.ts","../src/http/serialize-fetch-wrapper.ts","../src/http/serialize-route-imports.ts","../src/http/serialize-route-meta.ts","../src/http/serialize-typed-route-map.ts","../src/nextjs/serialize-nextjs-backend-wrapper.ts","../src/nextjs/serialize-nextjs-http-wrapper.ts","../src/openapi/openapi-spec-generator.ts","../src/scheduler/serialize-schedulers.ts","../src/schema/schema-generator.ts"],"version":"5.7.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/cli",
3
- "version": "0.6.16",
3
+ "version": "0.6.17",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -28,8 +28,8 @@
28
28
  "@types/uuid": "^10.0.0",
29
29
  "chalk": "^5.4.1",
30
30
  "commander": "^12",
31
- "glob": "^10",
32
31
  "path-to-regexp": "^8.2.0",
32
+ "tinyglobby": "^0.2.12",
33
33
  "ts-json-schema-generator": "^2.3.0",
34
34
  "typescript": "^5.6",
35
35
  "yaml": "^2.6.0"
@@ -1,5 +1,5 @@
1
1
  import * as path from 'path'
2
- import { glob } from 'glob'
2
+ import { glob } from 'tinyglobby'
3
3
  import { InspectorFilters, InspectorState, inspect } from '@pikku/inspector'
4
4
  import { logCommandInfoAndTime } from './utils.js'
5
5
 
@@ -1,11 +1,10 @@
1
- export const serializeNextJsWrapper = (
1
+ export const serializeNextJsBackendWrapper = (
2
2
  routesPath: string,
3
3
  routesMapPath: string,
4
4
  schemasPath: string,
5
5
  configImport: string,
6
6
  singleServicesFactoryImport: string,
7
- sessionServicesImport: string,
8
- userSessionTypeImport: string
7
+ sessionServicesImport: string
9
8
  ) => {
10
9
  return `'server-only'
11
10
 
@@ -13,14 +12,12 @@ export const serializeNextJsWrapper = (
13
12
  * This file provides a wrapper around the PikkuNextJS class to allow for methods to be type checked against your routes.
14
13
  * It ensures type safety for route handling methods when integrating with the @pikku/core framework.
15
14
  */
16
- import { PikkuMiddleware } from '@pikku/core'
17
- import { PikkuNextJS, PikkuNextRequest } from '@pikku/next'
15
+ import { PikkuNextJS } from '@pikku/next'
18
16
  import type { RoutesMap, RouteHandlerOf, RoutesWithMethod } from '${routesMapPath}'
19
17
 
20
18
  ${configImport}
21
19
  ${singleServicesFactoryImport}
22
20
  ${sessionServicesImport}
23
- ${userSessionTypeImport}
24
21
 
25
22
  import '${routesPath}'
26
23
  import '${schemasPath}'
@@ -32,7 +29,7 @@ let _pikku: PikkuNextJS | undefined
32
29
  *
33
30
  * @returns An object containing methods for making dynamic and static action requests, as well as session retrieval.
34
31
  */
35
- export const pikku = () => {
32
+ export const pikku = (_options?: any) => {
36
33
  if (!_pikku) {
37
34
  _pikku = new PikkuNextJS(
38
35
  createConfig as any,
@@ -41,20 +38,6 @@ export const pikku = () => {
41
38
  )
42
39
  }
43
40
 
44
- /**
45
- * Retrieves the user session using the current PikkuNextJS instance.
46
- *
47
- * @param request - The Next.js request object.
48
- * @param middleware - An array of middleware functions to process the request.
49
- * @returns A promise that resolves to the user session.
50
- */
51
- const getSession = async (
52
- request: PikkuNextRequest,
53
- middleware: PikkuMiddleware[]
54
- ): Promise<UserSession | undefined> => {
55
- return _pikku!.getSession(request, middleware) as any
56
- }
57
-
58
41
  /**
59
42
  * Makes a dynamic action request for a specified route and method.
60
43
  * Dynamic requests may access headers and cookies and are therefore unsuitable for precompile stages.
@@ -192,7 +175,6 @@ export const pikku = () => {
192
175
  }
193
176
 
194
177
  return {
195
- getSession,
196
178
  get: dynamicGet,
197
179
  post: dynamicPost,
198
180
  patch: dynamicPatch,
@@ -0,0 +1,163 @@
1
+ export const serializeNextJsHTTPWrapper = (
2
+ routesMapPath: string,
3
+ pikkuFetchImport: string
4
+ ) => {
5
+ return `'server-only'
6
+
7
+ /**
8
+ * This file provides a wrapper around the PikkuNextJS class to allow for methods to be type checked against your routes.
9
+ * It ensures type safety for route handling methods when integrating with the @pikku/core framework.
10
+ */
11
+ import { CorePikkuFetchOptions } from '@pikku/fetch'
12
+ import type { RoutesMap, RouteHandlerOf, RoutesWithMethod } from '${routesMapPath}'
13
+
14
+ let _pikku: PikkuFetch | undefined
15
+
16
+ ${pikkuFetchImport}
17
+
18
+ /**
19
+ * Initializes and returns an instance of PikkuNextJS with helper methods for handling route requests.
20
+ *
21
+ * @returns An object containing methods for making dynamic and static action requests, as well as session retrieval.
22
+ */
23
+ export const pikku = (options?: CorePikkuFetchOptions) => {
24
+ if (!_pikku) {
25
+ _pikku = new PikkuFetch(options)
26
+ }
27
+
28
+ const dynamicActionRequest = async <
29
+ Route extends keyof RoutesMap,
30
+ Method extends keyof RoutesMap[Route]
31
+ >(
32
+ route: Route,
33
+ method: Method,
34
+ data: RouteHandlerOf<Route, Method>['input'] = null
35
+ ): Promise<RouteHandlerOf<Route, Method>['output']> => {
36
+ return (_pikku! as any)[method](route, data as any)
37
+ }
38
+
39
+ /**
40
+ * Makes a static action request for a specified route and method.
41
+ * Static requests do not depend on headers or cookies and are suitable for precompile stages.
42
+ *
43
+ * @template Route - The route key from the RoutesMap.
44
+ * @template Method - The method key from the specified route.
45
+ * @param route - The route identifier.
46
+ * @param method - The HTTP method to be used for the request.
47
+ * @param data - The input data for the request, defaults to null.
48
+ * @returns A promise that resolves to the output of the route handler.
49
+ */
50
+ const staticActionRequest = async <
51
+ Route extends keyof RoutesMap,
52
+ Method extends keyof RoutesMap[Route]
53
+ >(
54
+ route: Route,
55
+ method: Method,
56
+ data: RouteHandlerOf<Route, Method>['input'] = null
57
+ ): Promise<RouteHandlerOf<Route, Method>['output']> => {
58
+ return (_pikku! as any)[method](route, data as any)
59
+ }
60
+
61
+ /**
62
+ * Makes a dynamic POST request for a specified route.
63
+ *
64
+ * @template Route - The route key with the POST method.
65
+ * @param route - The route identifier.
66
+ * @param data - The input data for the POST request, defaults to null.
67
+ * @returns A promise that resolves to the output of the POST handler.
68
+ */
69
+ const dynamicPost = <Route extends RoutesWithMethod<'POST'>>(
70
+ route: Route,
71
+ data: RouteHandlerOf<Route, 'POST'>['input'] = null
72
+ ): Promise<RouteHandlerOf<Route, 'POST'>['output']> => {
73
+ return dynamicActionRequest(route, 'POST', data)
74
+ }
75
+
76
+ /**
77
+ * Makes a dynamic GET request for a specified route.
78
+ *
79
+ * @template Route - The route key with the GET method.
80
+ * @param route - The route identifier.
81
+ * @param data - The input data for the GET request, defaults to null.
82
+ * @returns A promise that resolves to the output of the GET handler.
83
+ */
84
+ const dynamicGet = <Route extends RoutesWithMethod<'GET'>>(
85
+ route: Route,
86
+ data: RouteHandlerOf<Route, 'GET'>['input'] = null
87
+ ): Promise<RouteHandlerOf<Route, 'GET'>['output']> => {
88
+ return dynamicActionRequest(route, 'GET', data)
89
+ }
90
+
91
+ /**
92
+ * Makes a dynamic PATCH request for a specified route.
93
+ *
94
+ * @template Route - The route key with the PATCH method.
95
+ * @param route - The route identifier.
96
+ * @param data - The input data for the PATCH request, defaults to null.
97
+ * @returns A promise that resolves to the output of the PATCH handler.
98
+ */
99
+ const dynamicPatch = <Route extends RoutesWithMethod<'PATCH'>>(
100
+ route: Route,
101
+ data: RouteHandlerOf<Route, 'PATCH'>['input'] = null
102
+ ): Promise<RouteHandlerOf<Route, 'PATCH'>['output']> => {
103
+ return dynamicActionRequest(route, 'PATCH', data)
104
+ }
105
+
106
+ /**
107
+ * Makes a dynamic DELETE request for a specified route.
108
+ *
109
+ * @template Route - The route key with the DELETE method.
110
+ * @param route - The route identifier.
111
+ * @param data - The input data for the DELETE request, defaults to null.
112
+ * @returns A promise that resolves to the output of the DELETE handler.
113
+ */
114
+ const dynamicDel = <Route extends RoutesWithMethod<'DELETE'>>(
115
+ route: Route,
116
+ data: RouteHandlerOf<Route, 'DELETE'>['input'] = null
117
+ ): Promise<RouteHandlerOf<Route, 'DELETE'>['output']> => {
118
+ return dynamicActionRequest(route, 'DELETE', data)
119
+ }
120
+
121
+ // Static Requests
122
+
123
+ /**
124
+ * Makes a static POST request for a specified route.
125
+ *
126
+ * @template Route - The route key with the POST method.
127
+ * @param route - The route identifier.
128
+ * @param data - The input data for the POST request, defaults to null.
129
+ * @returns A promise that resolves to the output of the POST handler.
130
+ */
131
+ const staticPost = <Route extends RoutesWithMethod<'POST'>>(
132
+ route: Route,
133
+ data: RouteHandlerOf<Route, 'POST'>['input'] = null
134
+ ): Promise<RouteHandlerOf<Route, 'POST'>['output']> => {
135
+ return staticActionRequest(route, 'POST', data)
136
+ }
137
+
138
+ /**
139
+ * Makes a static GET request for a specified route.
140
+ *
141
+ * @template Route - The route key with the GET method.
142
+ * @param route - The route identifier.
143
+ * @param data - The input data for the GET request, defaults to null.
144
+ * @returns A promise that resolves to the output of the GET handler.
145
+ */
146
+ const staticGet = <Route extends RoutesWithMethod<'GET'>>(
147
+ route: Route,
148
+ data: RouteHandlerOf<Route, 'GET'>['input'] = null
149
+ ): Promise<RouteHandlerOf<Route, 'GET'>['output']> => {
150
+ return staticActionRequest(route, 'GET', data)
151
+ }
152
+
153
+ return {
154
+ get: dynamicGet,
155
+ post: dynamicPost,
156
+ patch: dynamicPatch,
157
+ del: dynamicDel,
158
+ staticGet,
159
+ staticPost
160
+ }
161
+ }
162
+ `
163
+ }
@@ -28,7 +28,8 @@ export type PikkuCLIConfig = {
28
28
  configDir: string
29
29
  tsconfig: string
30
30
 
31
- nextJSfile?: string
31
+ nextBackendFile?: string
32
+ nextHTTPFile?: string
32
33
  fetchFile?: string
33
34
  websocketFile?: string
34
35
 
@@ -40,7 +41,12 @@ export type PikkuCLIConfig = {
40
41
  filters: InspectorFilters
41
42
  } & PikkuCLICoreOutputFiles
42
43
 
43
- const CONFIG_DIR_FILES = ['nextJSfile', 'fetchFile', 'websocketFile']
44
+ const CONFIG_DIR_FILES = [
45
+ 'nextBackendFile',
46
+ 'nextHTTPFile',
47
+ 'fetchFile',
48
+ 'websocketFile',
49
+ ]
44
50
 
45
51
  export const getPikkuCLIConfig = async (
46
52
  configFile: string | undefined = undefined,
package/src/utils.ts CHANGED
@@ -59,6 +59,7 @@ export type FilesAndMethods = {
59
59
  }
60
60
 
61
61
  export interface PikkuCLIOptions {
62
+ watch?: boolean
62
63
  config?: string
63
64
  configFileType?: string
64
65
  userSessionType?: string
@@ -1 +0,0 @@
1
- export declare const serializeNextJsWrapper: (routesPath: string, routesMapPath: string, schemasPath: string, configImport: string, singleServicesFactoryImport: string, sessionServicesImport: string, userSessionTypeImport: string) => string;