@rvoh/psychic 0.33.0 → 0.34.1

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 (52) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/src/bin/index.js +9 -7
  3. package/dist/cjs/src/cli/helpers/PackageManager.js +41 -0
  4. package/dist/cjs/src/cli/helpers/cli-prompt.js +45 -0
  5. package/dist/cjs/src/cli/helpers/cli-select.js +135 -0
  6. package/dist/cjs/src/cli/helpers/colorize.js +11 -0
  7. package/dist/cjs/src/cli/index.js +42 -0
  8. package/dist/cjs/src/generate/helpers/reduxBindings/printFinalStepsMessage.js +37 -0
  9. package/dist/cjs/src/generate/helpers/reduxBindings/promptForOptions.js +81 -0
  10. package/dist/cjs/src/generate/helpers/reduxBindings/writeApiFile.js +93 -0
  11. package/dist/cjs/src/generate/helpers/reduxBindings/writeInitializer.js +76 -0
  12. package/dist/cjs/src/generate/helpers/reduxBindings/writeOpenapiJsonFile.js +52 -0
  13. package/dist/cjs/src/generate/initializer/syncEnums.js +75 -0
  14. package/dist/cjs/src/generate/openapi/reduxBindings.js +36 -0
  15. package/dist/cjs/src/helpers/autogeneratedFileDisclaimer.js +0 -38
  16. package/dist/cjs/src/psychic-app/helpers/PsychicImporter.js +9 -0
  17. package/dist/cjs/src/psychic-app/helpers/import/importInitializers.js +34 -0
  18. package/dist/cjs/src/psychic-app/index.js +12 -15
  19. package/dist/esm/src/bin/index.js +9 -7
  20. package/dist/esm/src/cli/helpers/PackageManager.js +35 -0
  21. package/dist/esm/src/cli/helpers/cli-prompt.js +19 -0
  22. package/dist/esm/src/cli/helpers/cli-select.js +106 -0
  23. package/dist/esm/src/cli/helpers/colorize.js +5 -0
  24. package/dist/esm/src/cli/index.js +42 -0
  25. package/dist/esm/src/generate/helpers/reduxBindings/printFinalStepsMessage.js +31 -0
  26. package/dist/esm/src/generate/helpers/reduxBindings/promptForOptions.js +75 -0
  27. package/dist/esm/src/generate/helpers/reduxBindings/writeApiFile.js +67 -0
  28. package/dist/esm/src/generate/helpers/reduxBindings/writeInitializer.js +47 -0
  29. package/dist/esm/src/generate/helpers/reduxBindings/writeOpenapiJsonFile.js +23 -0
  30. package/dist/esm/src/generate/initializer/syncEnums.js +46 -0
  31. package/dist/esm/src/generate/openapi/reduxBindings.js +30 -0
  32. package/dist/esm/src/helpers/autogeneratedFileDisclaimer.js +0 -38
  33. package/dist/esm/src/psychic-app/helpers/PsychicImporter.js +9 -0
  34. package/dist/esm/src/psychic-app/helpers/import/importInitializers.js +25 -0
  35. package/dist/esm/src/psychic-app/index.js +12 -15
  36. package/dist/types/src/bin/index.d.ts +1 -1
  37. package/dist/types/src/cli/helpers/PackageManager.d.ts +7 -0
  38. package/dist/types/src/cli/helpers/cli-prompt.d.ts +1 -0
  39. package/dist/types/src/cli/helpers/cli-select.d.ts +17 -0
  40. package/dist/types/src/cli/helpers/colorize.d.ts +6 -0
  41. package/dist/types/src/generate/helpers/reduxBindings/printFinalStepsMessage.d.ts +2 -0
  42. package/dist/types/src/generate/helpers/reduxBindings/promptForOptions.d.ts +2 -0
  43. package/dist/types/src/generate/helpers/reduxBindings/writeApiFile.d.ts +4 -0
  44. package/dist/types/src/generate/helpers/reduxBindings/writeInitializer.d.ts +3 -0
  45. package/dist/types/src/generate/helpers/reduxBindings/writeOpenapiJsonFile.d.ts +7 -0
  46. package/dist/types/src/generate/initializer/syncEnums.d.ts +1 -0
  47. package/dist/types/src/generate/openapi/reduxBindings.d.ts +23 -0
  48. package/dist/types/src/psychic-app/helpers/PsychicImporter.d.ts +2 -0
  49. package/dist/types/src/psychic-app/helpers/import/importInitializers.d.ts +5 -0
  50. package/dist/types/src/psychic-app/index.d.ts +4 -10
  51. package/dist/types/src/psychic-app/types.d.ts +2 -0
  52. package/package.json +2 -2
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- > ATTENTION: we are currently in the process of releasing this code to the world, as of the afternoon of March 10th, 2025. This notice will be removed, and the version of this repo will be bumped to 1.0.0, once all of the repos have been migrated to the new spaces and we can verify that it is all working. This is anticipated to be done in early April, 2025.
1
+ > ATTENTION: we are currently in the process of releasing this code to the world, as of the afternoon of May 2nd, 2025. This notice will be removed, and the version of this repo will be bumped to 1.0.0, once all of the repos have been migrated to the new spaces and we can verify that it is all working. This is anticipated to be done sometime in the next month
2
2
 
3
3
  # Psychic
4
4
 
@@ -69,9 +69,6 @@ class PsychicBin {
69
69
  static async postSync() {
70
70
  const psychicApp = index_js_1.default.getOrFail();
71
71
  await PsychicBin.syncOpenapiJson();
72
- if (psychicApp.openapi?.syncEnumsToClient) {
73
- await this.syncClientEnums();
74
- }
75
72
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
73
  let output = {};
77
74
  for (const hook of psychicApp.specialHooks.sync) {
@@ -105,12 +102,17 @@ class PsychicBin {
105
102
  await (0, generateRouteTypes_js_1.default)(routes);
106
103
  dream_1.DreamCLI.logger.logEndProgress();
107
104
  }
108
- static async syncClientEnums() {
105
+ static async syncClientEnums(outfile) {
109
106
  dream_1.DreamCLI.logger.logStartProgress(`syncing client enums...`);
110
- const psychicApp = index_js_1.default.getOrFail();
111
- const apiPath = path.join(psychicApp.clientRoot, psychicApp.client.apiPath);
112
107
  const enumsStr = await (0, enumsFileStr_js_1.default)();
113
- await fs.writeFile(`${apiPath}/enums.ts`, enumsStr);
108
+ try {
109
+ const dir = path.dirname(outfile);
110
+ await fs.mkdir(dir, { recursive: true });
111
+ }
112
+ catch {
113
+ // noop
114
+ }
115
+ await fs.writeFile(outfile, enumsStr, {});
114
116
  dream_1.DreamCLI.logger.logEndProgress();
115
117
  }
116
118
  }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_js_1 = __importDefault(require("../../psychic-app/index.js"));
7
+ class PackageManager {
8
+ static get packageManager() {
9
+ return index_js_1.default.getOrFail().packageManager;
10
+ }
11
+ static add(dependencyOrDependencies, { dev } = {}) {
12
+ const dependency = Array.isArray(dependencyOrDependencies)
13
+ ? dependencyOrDependencies.join(' ')
14
+ : dependencyOrDependencies;
15
+ if (dev) {
16
+ switch (this.packageManager) {
17
+ case 'npm':
18
+ return `${this.packageManager} install --save-dev ${dependency}`;
19
+ default:
20
+ return `${this.packageManager} add -D ${dependency}`;
21
+ }
22
+ }
23
+ else {
24
+ switch (this.packageManager) {
25
+ case 'npm':
26
+ return `${this.packageManager} install ${dependency}`;
27
+ default:
28
+ return `${this.packageManager} add ${dependency}`;
29
+ }
30
+ }
31
+ }
32
+ static run(cmd) {
33
+ switch (this.packageManager) {
34
+ case 'npm':
35
+ return `npm run ${cmd}`;
36
+ default:
37
+ return `${this.packageManager} ${cmd}`;
38
+ }
39
+ }
40
+ }
41
+ exports.default = PackageManager;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.default = cliPrompt;
27
+ const readline = __importStar(require("node:readline"));
28
+ const input = process.stdin;
29
+ const output = process.stdout;
30
+ async function cliPrompt(question) {
31
+ const rl = readline.createInterface({
32
+ input,
33
+ output,
34
+ });
35
+ return new Promise(resolve => {
36
+ if (process.env.BYPASS_CLI_PROMPT === '1')
37
+ resolve('');
38
+ else {
39
+ rl.question(question, value => {
40
+ rl.close();
41
+ resolve(value);
42
+ });
43
+ }
44
+ });
45
+ }
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const yoctocolors_1 = __importDefault(require("yoctocolors"));
30
+ const readline = __importStar(require("readline"));
31
+ const input = process.stdin;
32
+ const output = process.stdout;
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ class CLISelect {
35
+ question;
36
+ selectIndex = 0;
37
+ options;
38
+ selector = '>';
39
+ isFirstTimeShowMenu = true;
40
+ cb = null;
41
+ constructor(question, options) {
42
+ this.question = question;
43
+ this.options = options;
44
+ }
45
+ async run() {
46
+ this.init();
47
+ return new Promise(accept => {
48
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
49
+ this.cb = accept;
50
+ });
51
+ }
52
+ keyPressedHandler(_, key) {
53
+ if (key) {
54
+ const optionLength = this.options.length - 1;
55
+ if (key.name === 'down' && this.selectIndex < optionLength) {
56
+ this.selectIndex += 1;
57
+ this.createOptionMenu();
58
+ }
59
+ else if (key.name === 'up' && this.selectIndex > 0) {
60
+ this.selectIndex -= 1;
61
+ this.createOptionMenu();
62
+ }
63
+ else if (key.name === 'return') {
64
+ this.cb?.(this.options[this.selectIndex]);
65
+ input.removeAllListeners('keypress');
66
+ output.write('\n');
67
+ input.setRawMode(false);
68
+ input.pause();
69
+ }
70
+ else if (key.name === 'escape' || (key.name === 'c' && key.ctrl)) {
71
+ this.close();
72
+ }
73
+ }
74
+ }
75
+ ansiEraseLines(count) {
76
+ //adapted from sindresorhus ansi-escape module
77
+ const ESC = '\u001B[';
78
+ const eraseLine = ESC + '2K';
79
+ const cursorUp = (count = 1) => ESC + count + 'A';
80
+ const cursorLeft = ESC + 'G';
81
+ let clear = '';
82
+ for (let i = 0; i < count; i++) {
83
+ clear += eraseLine + (i < count - 1 ? cursorUp() : '');
84
+ }
85
+ if (count) {
86
+ clear += cursorLeft;
87
+ }
88
+ return clear;
89
+ }
90
+ init() {
91
+ console.log(`\n${this.question}`);
92
+ readline.emitKeypressEvents(input);
93
+ this.start();
94
+ }
95
+ start() {
96
+ //setup the input for reading
97
+ input.setRawMode(true);
98
+ input.resume();
99
+ input.on('keypress', (event, key) => this.keyPressedHandler(event, key));
100
+ if (this.selectIndex >= 0) {
101
+ this.createOptionMenu();
102
+ }
103
+ }
104
+ close = () => {
105
+ input.setRawMode(false);
106
+ input.pause();
107
+ process.exit(0);
108
+ };
109
+ getPadding(num = 10) {
110
+ let text = ' ';
111
+ for (let i = 0; i < num; i++) {
112
+ text += ' ';
113
+ }
114
+ return text;
115
+ }
116
+ createOptionMenu() {
117
+ const optionLength = this.options.length;
118
+ if (this.isFirstTimeShowMenu) {
119
+ this.isFirstTimeShowMenu = false;
120
+ }
121
+ else {
122
+ output.write(this.ansiEraseLines(optionLength));
123
+ }
124
+ const padding = this.getPadding(0);
125
+ const cursor = yoctocolors_1.default.magenta(this.selector);
126
+ for (let i = 0; i < optionLength; i++) {
127
+ const selectedOption = i === this.selectIndex
128
+ ? `${cursor} ${this.options[i]}`
129
+ : `${cursor.replace(/.*/, ' ')} ${this.options[i]}`;
130
+ const ending = i !== optionLength - 1 ? '\n' : '';
131
+ output.write(padding + selectedOption + ending);
132
+ }
133
+ }
134
+ }
135
+ exports.default = CLISelect;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = colorize;
7
+ const yoctocolors_1 = __importDefault(require("yoctocolors"));
8
+ function colorize(text, { color, bgColor, }) {
9
+ const foregroundApplied = color ? yoctocolors_1.default[color](text) : text;
10
+ return bgColor ? yoctocolors_1.default[bgColor](foregroundApplied) : foregroundApplied;
11
+ }
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const dream_1 = require("@rvoh/dream");
7
7
  const index_js_1 = __importDefault(require("../bin/index.js"));
8
+ const reduxBindings_js_1 = __importDefault(require("../generate/openapi/reduxBindings.js"));
9
+ const syncEnums_js_1 = __importDefault(require("../generate/initializer/syncEnums.js"));
8
10
  class PsychicCLI {
9
11
  static provide(program, { initializePsychicApp, seedDb, }) {
10
12
  dream_1.DreamCLI.generateDreamCli(program, {
@@ -37,6 +39,37 @@ class PsychicCLI {
37
39
  await index_js_1.default.generateController(controllerName, actions);
38
40
  process.exit();
39
41
  });
42
+ program
43
+ .command('generate:openapi:redux')
44
+ .alias('g:openapi:redux')
45
+ .description('generates openapi redux bindings to connect one of your openapi files to one of your clients')
46
+ .option('--schema-file', 'the path from your api root to the openapi file you wish to use to generate your schema, i.e. ./openapi/openapi.json')
47
+ .option('--api-file', 'the path to the boilerplate api file that will be used to scaffold your backend endpoints together with, i.e. ../client/app/api.ts')
48
+ .option('--api-import', 'the camelCased name of the export from your api module, i.e. emptyBackendApi')
49
+ .option('--output-file', 'the path to the file that will contain your typescript openapi redux bindings, i.e. ../client/app/myBackendApi.ts')
50
+ .option('--export-name', 'the camelCased name to use for your exported api, i.e. myBackendApi')
51
+ .action(async ({ schemaFile, apiFile, apiImport, outputFile, exportName, }) => {
52
+ await initializePsychicApp();
53
+ await (0, reduxBindings_js_1.default)({
54
+ exportName,
55
+ schemaFile,
56
+ apiFile,
57
+ apiImport,
58
+ outputFile,
59
+ });
60
+ process.exit();
61
+ });
62
+ program
63
+ .command('generate:initializer:sync-enums')
64
+ .alias('g:initializer:sync-enums')
65
+ .description('generates an initializer in your app for syncing enums to a particular path.')
66
+ .argument('<outfile>', 'the path from your backend directory to the location which you want the enums copied. Should end with .ts, i.e. "../client/src/api/enums.ts"')
67
+ .option('--initializer-filename', 'the name you want the file to be in your initializers folder. defaults to `sync-enums.ts`')
68
+ .action(async (outfile, { initializerName, }) => {
69
+ await initializePsychicApp();
70
+ await (0, syncEnums_js_1.default)(outfile, initializerName);
71
+ process.exit();
72
+ });
40
73
  program
41
74
  .command('routes')
42
75
  .description('examines your current models, building a type-map of the associations so that the ORM can understand your relational setup. This is commited to your repo, and synced to the dream repo for consumption within the underlying library.')
@@ -75,6 +108,15 @@ class PsychicCLI {
75
108
  await index_js_1.default.syncOpenapiJson();
76
109
  process.exit();
77
110
  });
111
+ program
112
+ .command('sync:client:enums')
113
+ .argument('<outfile>', 'the path from your backend directory to the location which you want the enums copied. Should end with .ts, i.e. "../client/src/api/enums.ts"')
114
+ .description('syncs your backend enums to a location of your choosing')
115
+ .action(async (outfile) => {
116
+ await initializePsychicApp();
117
+ await index_js_1.default.syncClientEnums(outfile);
118
+ process.exit();
119
+ });
78
120
  }
79
121
  }
80
122
  exports.default = PsychicCLI;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = printFinalStepsMessage;
7
+ const dream_1 = require("@rvoh/dream");
8
+ const colorize_js_1 = __importDefault(require("../../../cli/helpers/colorize.js"));
9
+ function printFinalStepsMessage(opts) {
10
+ const importLine = (0, colorize_js_1.default)(`+ import { ${opts.exportName} } from '${opts.apiFile}'`, { color: 'green' });
11
+ const reducerLine = (0, colorize_js_1.default)(` + [${opts.exportName}.reducerPath]: ${opts.exportName}.reducer,`, {
12
+ color: 'green',
13
+ });
14
+ const middlewareLine = (0, colorize_js_1.default)(` + middleware: gDM => gDM().concat(${opts.exportName}.middleware),`, {
15
+ color: 'green',
16
+ });
17
+ dream_1.DreamCLI.logger.log(`
18
+ Finished generating redux bindings for your application,
19
+ but to wire them into your app, we're going to need your help.
20
+ Be sure to add the following to your root store to bind your new
21
+ api module into your redux app, i.e.
22
+
23
+ // add this line, fix the import path if necessary
24
+ ${importLine}
25
+
26
+ export const store = configureStore({
27
+ reducer: {
28
+ // ...
29
+ // add this line
30
+ ${reducerLine}
31
+ },
32
+
33
+ // add this line
34
+ ${middlewareLine}
35
+ })
36
+ `, { logPrefix: '' });
37
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = promptForOptions;
7
+ const dream_1 = require("@rvoh/dream");
8
+ const cli_prompt_js_1 = __importDefault(require("../../../cli/helpers/cli-prompt.js"));
9
+ const index_js_1 = __importDefault(require("../../../psychic-app/index.js"));
10
+ async function promptForOptions(options) {
11
+ if (!options.schemaFile) {
12
+ const defaultVal = './openapi/openapi.json';
13
+ const answer = await (0, cli_prompt_js_1.default)(`\
14
+ What would you like the schemaFile to be?
15
+
16
+ The schemaFile is the openapi file that @rtk-query/codegen-openapi will read to produce
17
+ all of its redux bindings. If not provided, it will default to
18
+
19
+ ${defaultVal}
20
+ `);
21
+ options.schemaFile = answer || defaultVal;
22
+ }
23
+ if (!options.exportName) {
24
+ const defaultVal = `${(0, dream_1.camelize)(index_js_1.default.getOrFail().appName)}Api`;
25
+ const answer = await (0, cli_prompt_js_1.default)(`\
26
+ What would you like the exportName to be?
27
+
28
+ The exportName is used to name the final output of the @rtk-query/codegen-openapi utility.
29
+ It will encase all of the backend endpoints that have been consumed via the specified openapi
30
+ file. We recommend naming it something like the name of your app, i.e.
31
+
32
+ ${defaultVal}
33
+ `);
34
+ options.exportName = answer || defaultVal;
35
+ }
36
+ if (!options.outputFile) {
37
+ const defaultVal = `../client/app/api/${(0, dream_1.camelize)(options.exportName)}.ts`;
38
+ const answer = await (0, cli_prompt_js_1.default)(`\
39
+ What would you like the outputFile to be?
40
+
41
+ The outputFile is the path to the generated openapi redux bindings. If not provided,
42
+ it will default to:
43
+
44
+ ${defaultVal}
45
+ `);
46
+ options.outputFile = answer || defaultVal;
47
+ }
48
+ if (!options.apiFile) {
49
+ const defaultVal = '../client/app/api/api.ts';
50
+ const answer = await (0, cli_prompt_js_1.default)(`\
51
+ What would you like the path to your apiFile to be?
52
+
53
+ The apiFile option specifies which base api file to use to mix in your backend endpoints with.
54
+ This option is provided by the @rtk-query/codegen-openapi library to enable you to define
55
+ custom api behavior, such as defining a base url, adding header preparation steps, etc...
56
+
57
+ We expect you to provide this path with the api root in mind, so you will need to consider
58
+ how to travel to the desired filepath from within your psychic project, i.e.
59
+
60
+ ${defaultVal}
61
+ `);
62
+ options.apiFile = answer || defaultVal;
63
+ }
64
+ if (!options.apiImport) {
65
+ const defaultVal = `empty${(0, dream_1.pascalize)(options.exportName)}`;
66
+ const answer = await (0, cli_prompt_js_1.default)(`\
67
+ What would you like the path to your apiImport to be?
68
+
69
+ The apiImport option specifies the export key for the api module being exported from the
70
+ file found at the apiFile path.
71
+
72
+ This option is provided by the @rtk-query/codegen-openapi library to inform it of which
73
+ named export in your apiFile it should be mixing your backend api with. If not provided,
74
+ it will default to
75
+
76
+ ${defaultVal}
77
+ `);
78
+ options.apiImport = answer || defaultVal;
79
+ }
80
+ return options;
81
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.default = writeApiFile;
27
+ const fs = __importStar(require("node:fs/promises"));
28
+ const path = __importStar(require("node:path"));
29
+ async function writeApiFile({ apiFile, apiImport }) {
30
+ const destDir = path.dirname(apiFile);
31
+ try {
32
+ await fs.access(apiFile);
33
+ return; // early return if the file already exists
34
+ }
35
+ catch {
36
+ // noop
37
+ }
38
+ try {
39
+ await fs.access(destDir);
40
+ }
41
+ catch {
42
+ await fs.mkdir(destDir, { recursive: true });
43
+ }
44
+ const contents = `\
45
+ // Or from '@reduxjs/toolkit/query' if not using the auto-generated hooks
46
+ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
47
+ import { RootState } from '../store' // update this to the correct path to your app's store
48
+
49
+ function baseUrl() {
50
+ // add custom code here for determining your application's baseUrl
51
+ // this would generally be something different, depending on if you
52
+ // are in dev/test/production environments. For dev, you might want
53
+ // http://localhost:7777, while test may be http://localhost:7778, or
54
+ // some other port, depending on how you have your spec hooks configured.
55
+ // for production, it should be the real host for your application, i.e.
56
+ // https://myapi.com
57
+
58
+ return 'http://localhost:7777'
59
+ }
60
+
61
+ // initialize an empty api service that we'll inject endpoints into later as needed
62
+ export const ${apiImport} = createApi({
63
+ // forces cache to bust any time a component is mounted
64
+ refetchOnMountOrArgChange: true,
65
+ keepUnusedDataFor: 0,
66
+
67
+ baseQuery: fetchBaseQuery({
68
+ baseUrl: baseURL(),
69
+ credentials: 'include',
70
+
71
+ // we recommend that you use a function like this for preparing
72
+ // headers, so that you can make sure any necessary auth tokens
73
+ // used by your app can be applied to the headers when any requests
74
+ // are made to your backend api.
75
+ // prepareHeaders: (headers, { getState }) => {
76
+ // return new Promise(resolve => {
77
+ // function checkToken() {
78
+ // const token = (getState() as RootState).app.authToken
79
+ // if (token) {
80
+ // headers.set('Authorization', \`Bearer \${token}\`)
81
+ // resolve(headers)
82
+ // } else {
83
+ // setTimeout(checkToken, 500) // try again in 500ms
84
+ // }
85
+ // }
86
+ // checkToken()
87
+ // })
88
+ // },
89
+ }),
90
+ endpoints: () => ({}),
91
+ })`;
92
+ await fs.writeFile(apiFile, contents);
93
+ }
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.default = writeInitializer;
30
+ const dream_1 = require("@rvoh/dream");
31
+ const fs = __importStar(require("node:fs/promises"));
32
+ const path = __importStar(require("node:path"));
33
+ const psychicPath_js_1 = __importDefault(require("../../../helpers/path/psychicPath.js"));
34
+ async function writeInitializer({ exportName }) {
35
+ const pascalized = (0, dream_1.pascalize)(exportName);
36
+ const camelized = (0, dream_1.camelize)(exportName);
37
+ const destDir = path.join((0, psychicPath_js_1.default)('conf'), 'initializers', 'openapi');
38
+ const initializerFilename = `${camelized}.ts`;
39
+ const initializerPath = path.join(destDir, initializerFilename);
40
+ try {
41
+ await fs.access(initializerPath);
42
+ return; // early return if the file already exists
43
+ }
44
+ catch {
45
+ // noop
46
+ }
47
+ try {
48
+ await fs.access(destDir);
49
+ }
50
+ catch {
51
+ await fs.mkdir(destDir, { recursive: true });
52
+ }
53
+ const filePath = path.join('.', 'src', 'conf', 'openapi', `${camelized}.openapi-codegen.json`);
54
+ const contents = `\
55
+ import { DreamCLI } from '@rvoh/dream'
56
+ import { PsychicApp } from '@rvoh/psychic'
57
+ import AppEnv from '../AppEnv.js'
58
+
59
+ export default function initialize${pascalized}(psy: PsychicApp) {
60
+ psy.on('sync', async () => {
61
+ if (AppEnv.isDevelopmentOrTest) {
62
+ DreamCLI.logger.logStartProgress(\`[${camelized}] syncing...\`)
63
+ await DreamCLI.spawn('npx @rtk-query/codegen-openapi ${filePath}', {
64
+ onStdout: message => {
65
+ DreamCLI.logger.logContinueProgress(\`[${camelized}]\` + ' ' + message, {
66
+ logPrefixColor: 'green',
67
+ })
68
+ },
69
+ })
70
+ DreamCLI.logger.logEndProgress()
71
+ }
72
+ })
73
+ }\
74
+ `;
75
+ await fs.writeFile(initializerPath, contents);
76
+ }