@appweaver/cli 1.0.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 (76) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +7 -0
  3. package/build/build-command.d.ts +2 -0
  4. package/build/build-command.js +15 -0
  5. package/build/build-project.d.ts +8 -0
  6. package/build/build-project.js +19 -0
  7. package/build/index.d.ts +2 -0
  8. package/build/index.js +18 -0
  9. package/generate/generate-command.d.ts +2 -0
  10. package/generate/generate-command.js +38 -0
  11. package/generate/generate-schema.d.ts +12 -0
  12. package/generate/generate-schema.js +475 -0
  13. package/generate/generate-types.d.ts +10 -0
  14. package/generate/generate-types.js +86 -0
  15. package/generate/index.d.ts +3 -0
  16. package/generate/index.js +19 -0
  17. package/migrate/index.d.ts +1 -0
  18. package/migrate/index.js +17 -0
  19. package/migrate/migrate-command.d.ts +2 -0
  20. package/migrate/migrate-command.js +13 -0
  21. package/migration/index.d.ts +1 -0
  22. package/migration/index.js +17 -0
  23. package/migration/migration-command.d.ts +2 -0
  24. package/migration/migration-command.js +34 -0
  25. package/openapi/index.d.ts +1 -0
  26. package/openapi/index.js +17 -0
  27. package/openapi/openapi-command.d.ts +2 -0
  28. package/openapi/openapi-command.js +46 -0
  29. package/package.json +56 -0
  30. package/seed/index.d.ts +1 -0
  31. package/seed/index.js +17 -0
  32. package/seed/seed-command.d.ts +2 -0
  33. package/seed/seed-command.js +33 -0
  34. package/skill/GUIDELINES.md +298 -0
  35. package/skill/SKILL.md +593 -0
  36. package/skill/references/cache.md +207 -0
  37. package/skill/references/cli.md +213 -0
  38. package/skill/references/client.md +507 -0
  39. package/skill/references/configuration.md +402 -0
  40. package/skill/references/database.md +134 -0
  41. package/skill/references/dependency-injection.md +214 -0
  42. package/skill/references/events.md +152 -0
  43. package/skill/references/mailer.md +235 -0
  44. package/skill/references/queue.md +196 -0
  45. package/skill/references/resources.md +961 -0
  46. package/skill/references/scheduler.md +184 -0
  47. package/skill/references/security.md +694 -0
  48. package/skill/references/storage.md +251 -0
  49. package/start/index.d.ts +2 -0
  50. package/start/index.js +18 -0
  51. package/start/start-command.d.ts +2 -0
  52. package/start/start-command.js +17 -0
  53. package/start/start-project.d.ts +8 -0
  54. package/start/start-project.js +147 -0
  55. package/testing/index.d.ts +1 -0
  56. package/testing/index.js +17 -0
  57. package/testing/testing-command.d.ts +2 -0
  58. package/testing/testing-command.js +96 -0
  59. package/update/index.d.ts +2 -0
  60. package/update/index.js +18 -0
  61. package/update/update-command.d.ts +2 -0
  62. package/update/update-command.js +84 -0
  63. package/update/update-packages.d.ts +10 -0
  64. package/update/update-packages.js +45 -0
  65. package/update/update-skill.d.ts +8 -0
  66. package/update/update-skill.js +93 -0
  67. package/utils/index.d.ts +3 -0
  68. package/utils/index.js +19 -0
  69. package/utils/loader-util.d.ts +29 -0
  70. package/utils/loader-util.js +132 -0
  71. package/utils/path-util.d.ts +41 -0
  72. package/utils/path-util.js +98 -0
  73. package/utils/process-util.d.ts +39 -0
  74. package/utils/process-util.js +92 -0
  75. package/weaver.d.ts +2 -0
  76. package/weaver.js +53 -0
@@ -0,0 +1,251 @@
1
+ # Storage
2
+
3
+ The storage module handles file persistence: storing, streaming, and deleting binary content. The default
4
+ implementation (`FilesystemStorage`) writes files to a local directory using a configurable name pattern. The module
5
+ supports range-based streaming for efficient large-file delivery (e.g., video, audio).
6
+
7
+ ## Injecting Storage
8
+
9
+ ```ts
10
+ import { inject } from '@appweaver/core';
11
+ import { Storage } from '@appweaver/common';
12
+
13
+ const storage = inject(Storage);
14
+ ```
15
+
16
+ ---
17
+
18
+ #### `storage.store(fileName, data)`
19
+
20
+ Persists a readable stream under the given file name. Returns the stored file's path/ID (derived from
21
+ `STORAGE_NAME_PATTERN`), or `null` on failure.
22
+
23
+ | Parameter | Type | Description |
24
+ |------------|------------|--------------------------------------------|
25
+ | `fileName` | `string` | Original file name (used for name pattern) |
26
+ | `data` | `Readable` | Node.js readable stream with the content |
27
+
28
+ ```ts
29
+ import { createReadStream } from 'node:fs';
30
+
31
+ const fileId = await storage.store('avatar.png', createReadStream('/tmp/upload.png'));
32
+ // fileId e.g. "avatar-a3f8bc12.png"
33
+ ```
34
+
35
+ **From a multipart upload (Fastify example):**
36
+
37
+ ```ts
38
+ const upload = await req.file();
39
+ const fileId = await storage.store(upload.filename, upload.file);
40
+ ```
41
+
42
+ ---
43
+
44
+ #### `storage.stream(fileName, start, end?)`
45
+
46
+ Returns a `ContentStream` for the stored file, or `null` if the file does not exist. Supports range requests.
47
+
48
+ | Parameter | Type | Description |
49
+ |------------|----------|--------------------------------------------|
50
+ | `fileName` | `string` | File ID returned by `store` |
51
+ | `start` | `number` | Byte offset to start reading from |
52
+ | `end` | `number` | Byte offset to stop reading at (inclusive) |
53
+
54
+ ```ts
55
+ type ContentStream = {
56
+ stream: Readable;
57
+ size: number; // total file size in bytes
58
+ };
59
+ ```
60
+
61
+ **Full file download:**
62
+
63
+ ```ts
64
+ const result = await storage.stream('avatar-a3f8bc12.png', 0);
65
+ if (!result) throw new Error('File not found');
66
+
67
+ reply.header('Content-Length', result.size);
68
+ reply.send(result.stream);
69
+ ```
70
+
71
+ **Range request (e.g., video seeking):**
72
+
73
+ ```ts
74
+ const { start, end } = parseRangeHeader(req.headers.range, fileSize);
75
+ const result = await storage.stream(fileId, start, end);
76
+
77
+ reply
78
+ .status(206)
79
+ .header('Content-Range', `bytes ${start}-${end}/${fileSize}`)
80
+ .send(result.stream);
81
+ ```
82
+
83
+ ---
84
+
85
+ #### `storage.exists(fileName)`
86
+
87
+ Returns `true` if the file exists in storage.
88
+
89
+ ```ts
90
+ if (await storage.exists('avatar-a3f8bc12.png')) {
91
+ // safe to stream
92
+ }
93
+ ```
94
+
95
+ ---
96
+
97
+ #### `storage.delete(fileName)`
98
+
99
+ Deletes the stored file. Returns `true` if the file existed and was removed.
100
+
101
+ ```ts
102
+ await storage.delete('avatar-a3f8bc12.png');
103
+ ```
104
+
105
+ ---
106
+
107
+ #### `storage.checkHealth()`
108
+
109
+ Verifies that the storage directory is readable and writable. Returns a `HealthCheckResult`.
110
+
111
+ ---
112
+
113
+ ## File name pattern
114
+
115
+ Stored files are renamed according to `STORAGE_NAME_PATTERN`. The default pattern is `{name}-{hash}.{extension}`, which
116
+ produces collision-resistant names while preserving the original extension.
117
+
118
+ Available placeholders:
119
+
120
+ | Placeholder | Resolved to |
121
+ |---------------|-----------------------------|
122
+ | `{name}` | Base name without extension |
123
+ | `{hash}` | Short content hash |
124
+ | `{extension}` | Original file extension |
125
+
126
+ Example: storing `photo.jpg` produces `photo-c7d3a1f2.jpg`.
127
+
128
+ ---
129
+
130
+ ## Configuration
131
+
132
+ | Key | Type | Default | Description |
133
+ |------------------------------|----------|------------------------------------------------|-------------------------------------------------------|
134
+ | `STORAGE_PATH` | `string` | `'./storage'` | Root directory where files are stored |
135
+ | `STORAGE_NAME_PATTERN` | `string` | `'{name}-{hash}.{extension}'` | Template for deriving the stored file name |
136
+ | `STORAGE_CACHE_TTL` | `int` | `86400000` | Cache TTL for storage responses in milliseconds (24h) |
137
+ | `STORAGE_FILES_ROUTE_PREFIX` | `string` | `/files` | URL prefix for file access routes. |
138
+ | `STORAGE_PROVIDER` | `string` | `'@appweaver/core/storage/filesystem-storage'` | Path to the Storage implementation |
139
+
140
+ **`appweaver.json` example:**
141
+
142
+ ```json
143
+ {
144
+ "STORAGE_PATH": "./uploads",
145
+ "STORAGE_NAME_PATTERN": "{name}-{hash}.{extension}"
146
+ }
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Real-world example
152
+
153
+ ```ts
154
+ import { inject } from '@appweaver/core';
155
+ import { Storage } from '@appweaver/common';
156
+
157
+ export class AvatarService {
158
+ private readonly _storage = inject(Storage);
159
+
160
+ async upload(userId: number, stream: Readable, originalName: string): Promise<string> {
161
+ const fileId = await this._storage.store(originalName, stream);
162
+ if (!fileId) throw new Error('Upload failed');
163
+
164
+ await saveAvatarRecord(userId, fileId);
165
+ return fileId;
166
+ }
167
+
168
+ async download(fileId: string): Promise<{ stream: Readable; size: number }> {
169
+ const result = await this._storage.stream(fileId, 0);
170
+ if (!result) throw new Error('File not found');
171
+ return result;
172
+ }
173
+
174
+ async remove(fileId: string): Promise<void> {
175
+ await this._storage.delete(fileId);
176
+ await deleteAvatarRecord(fileId);
177
+ }
178
+ }
179
+ ```
180
+
181
+ ---
182
+
183
+ ## FileService usage
184
+
185
+ The `FileService` provides higher-level file management specifically for **Resource Models**. Unlike the raw `Storage`
186
+ module, it automatically manages the database records (`File` entries) and enforces security policies defined on your
187
+ models.
188
+
189
+ ### Injecting FileService
190
+
191
+ ```ts
192
+ import { inject } from '@appweaver/core';
193
+ import { FileService } from '@appweaver/core/storage';
194
+
195
+ const fileService = inject(FileService);
196
+ ```
197
+
198
+ ### Saving a file
199
+
200
+ When saving a file via `FileService`, you must provide the multipart data, the resource instance it belongs to, and its
201
+ `ResourceClient`.
202
+
203
+ ```ts
204
+ import { inject, injectService, injectModel } from '@appweaver/core';
205
+ import { FileService } from '@appweaver/core/storage';
206
+
207
+ export class PostService {
208
+ private readonly _fileService = inject(FileService);
209
+ private readonly _postService = injectService('Post');
210
+ private readonly _postClient = injectModel('Post');
211
+
212
+ async uploadImage(postId: number, data: MultipartFile) {
213
+ const post = await this._postService.find(postId);
214
+
215
+ // saveFile stores the file in Storage AND creates a File record in the DB
216
+ // linked to the 'image' field of the 'post' resource.
217
+ const file = await this._fileService.saveFile(data, post, this._postClient);
218
+
219
+ return file;
220
+ }
221
+ }
222
+ ```
223
+
224
+ ### Streaming a file
225
+
226
+ `FileService.stream()` handles authorization checks (public, private, or protected) and range-based requests
227
+ automatically.
228
+
229
+ ```ts
230
+ // Streams a file while checking if the current user has access
231
+ const fileStream = await fileService.stream('photo-c7d3a1f2.jpg', req.headers.range);
232
+
233
+ reply
234
+ .status(fileStream.start > 0 ? 206 : 200)
235
+ .header('Content-Type', fileStream.mimeType)
236
+ .header('Content-Disposition', `attachment; filename="${fileStream.fileName}"`)
237
+ .send(fileStream.content.stream);
238
+ ```
239
+
240
+ ### Deleting a file
241
+
242
+ Deleting a file via `FileService` removes it from both the storage backend and the database.
243
+
244
+ ```ts
245
+ await fileService.deleteFile(
246
+ 'photo-c7d3a1f2.jpg',
247
+ 'image', // resource field name
248
+ post, // resource instance
249
+ postClient // ResourceClient
250
+ );
251
+ ```
@@ -0,0 +1,2 @@
1
+ export * from './start-command';
2
+ export * from './start-project';
package/start/index.js ADDED
@@ -0,0 +1,18 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./start-command"), exports);
18
+ __exportStar(require("./start-project"), exports);
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function startCommand(program: Command): void;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startCommand = startCommand;
4
+ const start_project_1 = require("./start-project");
5
+ function startCommand(program) {
6
+ program
7
+ .command('start')
8
+ .alias('s')
9
+ .description('Start the application.')
10
+ .option('-p, --project [path]', 'TypeScript project config file.', 'tsconfig.build.json')
11
+ .option('-w, --watch', 'Run in watch mode.')
12
+ .action(async (_, command) => {
13
+ const projectFile = command.getOptionValue('project');
14
+ const watch = command.getOptionValue('watch');
15
+ await (0, start_project_1.startProject)(projectFile, watch);
16
+ });
17
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Starts the project using the specified project file and runtime options.
3
+ *
4
+ * @param {string} projectFile - The path to the project file that should be used.
5
+ * @param {boolean} watch - A flag indicating whether to enable watch mode for automatic restarts on file changes.
6
+ * @return {Promise<void>} A promise that resolves when the project has started.
7
+ */
8
+ export declare function startProject(projectFile: string, watch: boolean): Promise<void>;
@@ -0,0 +1,147 @@
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.startProject = startProject;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const promises_1 = require("node:fs/promises");
9
+ const client_1 = require("tsc-watch/client");
10
+ const tsc_alias_1 = require("tsc-alias");
11
+ const common_1 = require("@appweaver/common");
12
+ const utils_1 = require("../utils");
13
+ /**
14
+ * Starts the project using the specified project file and runtime options.
15
+ *
16
+ * @param {string} projectFile - The path to the project file that should be used.
17
+ * @param {boolean} watch - A flag indicating whether to enable watch mode for automatic restarts on file changes.
18
+ * @return {Promise<void>} A promise that resolves when the project has started.
19
+ */
20
+ async function startProject(projectFile, watch) {
21
+ const mainFilePath = node_path_1.default.join(common_1.config.APP_BUILD_PATH, common_1.config.APP_MAIN_FILE_PATH.replace(/\.ts$/i, '.js'));
22
+ if ((0, utils_1.isBunProcess)() && common_1.config.APP_RUNTIME === common_1.Runtime.Bun) {
23
+ await startBunProject(mainFilePath, watch);
24
+ }
25
+ else {
26
+ await startNodeProject(mainFilePath, projectFile, watch);
27
+ }
28
+ }
29
+ /**
30
+ * Starts a Node.js project by executing the specified main file.
31
+ * Optionally enables watch mode to monitor file changes.
32
+ *
33
+ * @param {string} mainFilePath - The path to the main file to be executed.
34
+ * @param {string} projectFile - The project configuration file used during execution.
35
+ * @param {boolean} watch - Whether to enable watch mode for file changes.
36
+ * @return {Promise<void>} A promise that resolves when the operation completes.
37
+ */
38
+ async function startNodeProject(mainFilePath, projectFile, watch) {
39
+ if (watch) {
40
+ await watchNodeProject(mainFilePath, projectFile);
41
+ }
42
+ else {
43
+ await (0, utils_1.runProcess)('node', [mainFilePath]);
44
+ }
45
+ }
46
+ /**
47
+ * Starts a Bun project by running the specified main file. Optionally enables a watch mode.
48
+ *
49
+ * @param {string} mainFilePath - The path to the main file to run with Bun.
50
+ * @param {boolean} watch - Determines whether the Bun process should execute in watch mode.
51
+ * @return {Promise<void>} A promise that resolves when the Bun process starts or when the watch mode is initiated.
52
+ */
53
+ async function startBunProject(mainFilePath, watch) {
54
+ if (watch) {
55
+ await watchBunProcess();
56
+ }
57
+ else {
58
+ await (0, utils_1.runProcess)('bun', [mainFilePath]);
59
+ }
60
+ }
61
+ /**
62
+ * Watches the specified Node.js project for changes, recompiles TypeScript files, replaces aliases in import patsh,
63
+ * and restarts the main application process upon successful compilation.
64
+ *
65
+ * @param {string} mainFilePath - The entry point of the application that will be executed after each successful
66
+ * compilation.
67
+ * @param {string} projectFile - The TypeScript config file path (tsconfig.json).
68
+ * @return {Promise<void>} A promise that resolves when the watching process is stopped.
69
+ */
70
+ async function watchNodeProject(mainFilePath, projectFile) {
71
+ let abortController;
72
+ const watch = new client_1.TscWatchClient();
73
+ // Handler for every successful compilation of watched code, aborts previous
74
+ // process and starts a new one
75
+ watch.on('success', async () => {
76
+ if (abortController) {
77
+ abortController.abort();
78
+ }
79
+ abortController = new AbortController();
80
+ // Replace import alias paths in compiled code
81
+ await (0, tsc_alias_1.replaceTscAliasPaths)({ configFile: projectFile });
82
+ // Start the main application process
83
+ await (0, utils_1.runProcess)('node', [mainFilePath], {
84
+ signal: abortController.signal
85
+ });
86
+ });
87
+ // Handler for any compilation error to abort previously started process
88
+ watch.on('compile_errors', () => {
89
+ abortController?.abort();
90
+ });
91
+ // Cleanup should be done only once on process termination
92
+ let cleanedUp = false;
93
+ const cleanup = () => {
94
+ if (cleanedUp) {
95
+ return;
96
+ }
97
+ cleanedUp = true;
98
+ abortController?.abort();
99
+ watch.kill();
100
+ };
101
+ // When process is terminated in any way, all processes should be aborted
102
+ process.on('SIGINT', cleanup);
103
+ process.on('SIGTERM', cleanup);
104
+ process.on('exit', cleanup);
105
+ watch.start('-p', projectFile);
106
+ }
107
+ /**
108
+ * Monitors file changes in the specified directory and restarts the Bun process accordingly.
109
+ * The function uses a debounced mechanism to prevent restarting the process too frequently.
110
+ * Debounce threshold is 200 milliseconds.
111
+ *
112
+ * @return {Promise<void>} A promise that resolves when the watching process is stopped.
113
+ */
114
+ async function watchBunProcess() {
115
+ let abortController;
116
+ let debounceTimer;
117
+ // Starts a new process and aborts the previous one
118
+ async function start() {
119
+ if (abortController) {
120
+ abortController.abort();
121
+ }
122
+ abortController = new AbortController();
123
+ await (0, utils_1.runProcess)('bun', [common_1.config.APP_MAIN_FILE_PATH], {
124
+ signal: abortController.signal
125
+ });
126
+ }
127
+ // Initially start the application process
128
+ start().catch((err) => {
129
+ console.error(err);
130
+ process.exit(1);
131
+ });
132
+ // Wait before starting watcher to prevent restarts during init phase
133
+ await new Promise((r) => setTimeout(r, 200));
134
+ // Watch for file changes and start new process using debounce timer
135
+ for await (const info of (0, promises_1.watch)(common_1.config.APP_SOURCE_PATH, { recursive: true })) {
136
+ if (info.filename === null) {
137
+ // Skip non-file change events
138
+ continue;
139
+ }
140
+ if (debounceTimer) {
141
+ clearTimeout(debounceTimer);
142
+ }
143
+ debounceTimer = setTimeout(async () => {
144
+ await start();
145
+ }, 100);
146
+ }
147
+ }
@@ -0,0 +1 @@
1
+ export * from './testing-command';
@@ -0,0 +1,17 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./testing-command"), exports);
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function testingCommand(program: Command): void;
@@ -0,0 +1,96 @@
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.testingCommand = testingCommand;
7
+ const promises_1 = __importDefault(require("node:fs/promises"));
8
+ const common_1 = require("@appweaver/common");
9
+ const generate_1 = require("../generate");
10
+ const utils_1 = require("../utils");
11
+ function testingCommand(program) {
12
+ const testCommand = program
13
+ .command('test')
14
+ .alias('t')
15
+ .description('Perform operations used during testing.');
16
+ testCommand
17
+ .command('setup')
18
+ .description('Setup temporary test data (database schema and migrations).')
19
+ .option('-d, --dir [tempDir]', 'Directory used by tests to store temporary data.', './temp')
20
+ .option('--modelPattern [pattern]', 'Glob pattern for finding model files. (default: from config or env).')
21
+ .option('--schemaPath [path]', 'Output path for generated Prisma schema. (default: from config or env).')
22
+ .option('--clientPath [path]', 'Output path for generated Prisma client (default: from config or env).')
23
+ .option('--migrationName [name]', 'Name for the new migration.', 'init_test')
24
+ .option('--verbose', 'Print verbose output.')
25
+ .action(async (_, command) => {
26
+ (0, utils_1.assertEnv)('test', '"weaver test setup" must be started in "test" environment (NODE_ENV=test).');
27
+ const quiet = !command.getOptionValue('verbose');
28
+ const tempDir = command.getOptionValue('dir');
29
+ const storagePath = common_1.config.STORAGE_PATH;
30
+ const schemaPath = command.getOptionValue('schemaPath') ?? common_1.config.DATABASE_SCHEMA_PATH;
31
+ const clientPath = command.getOptionValue('clientPath') ??
32
+ common_1.config.DATABASE_CLIENT_OUTPUT_DIR_PATH;
33
+ (0, utils_1.assertPathInside)(tempDir, storagePath, `Storage path must be inside temp directory: ${tempDir}`);
34
+ (0, utils_1.assertPathInside)(tempDir, schemaPath, `Schema path must be inside temp directory: ${tempDir}`);
35
+ (0, utils_1.assertPathInside)(tempDir, clientPath, `Client output path must be inside temp directory: ${tempDir}`);
36
+ await (0, utils_1.rimrafPath)(tempDir, quiet);
37
+ await promises_1.default.mkdir(storagePath, { recursive: true });
38
+ console.log('Storage initialized');
39
+ const models = await (0, utils_1.loadModels)(command.getOptionValue('modelPattern') ?? common_1.config.RESOURCE_MODEL_PATTERN);
40
+ const generateStatus = await (0, generate_1.generateSchema)(models, schemaPath, clientPath, quiet);
41
+ if (generateStatus !== 0) {
42
+ console.error('Failed to generate Prisma schema');
43
+ process.exit(generateStatus);
44
+ }
45
+ const migrateStatus = await (0, utils_1.runProcess)('prisma', ['migrate', 'dev', '--name', command.getOptionValue('migrationName')], { quiet });
46
+ if (migrateStatus !== 0) {
47
+ console.error('Failed to generate new migration');
48
+ process.exit(migrateStatus);
49
+ }
50
+ console.log('Database initialized');
51
+ });
52
+ testCommand
53
+ .command('reset')
54
+ .description('Reset database and/or file storage in temporary directory.')
55
+ .option('-d, --dir [tempDir]', 'Directory used by tests to store temporary data.', './temp')
56
+ .option('--database', 'Reset database content.')
57
+ .option('--storage', 'Reset storage files.')
58
+ .option('--verbose', 'Print verbose output.')
59
+ .action(async (_, command) => {
60
+ (0, utils_1.assertEnv)('test', '"weaver test reset" must be started in "test" environment (NODE_ENV=test).');
61
+ const quiet = !command.getOptionValue('verbose');
62
+ const tempDir = command.getOptionValue('dir');
63
+ const storagePath = common_1.config.STORAGE_PATH;
64
+ (0, utils_1.assertPathInside)(tempDir, storagePath, `Storage path must be inside temp directory: ${tempDir}`);
65
+ const resetAll = !command.getOptionValue('database') &&
66
+ !command.getOptionValue('storage');
67
+ if (command.getOptionValue('database') || resetAll) {
68
+ const migrateStatus = await (0, utils_1.runProcess)('prisma', ['migrate', 'reset', '-f'], { quiet });
69
+ if (migrateStatus !== 0) {
70
+ console.error('Failed to migrate database');
71
+ process.exit(migrateStatus);
72
+ }
73
+ console.log('Database reset');
74
+ }
75
+ if (command.getOptionValue('storage') || resetAll) {
76
+ const result = await (0, utils_1.rimrafPath)(storagePath, quiet);
77
+ if (result) {
78
+ console.log('Storage cleared');
79
+ }
80
+ }
81
+ });
82
+ testCommand
83
+ .command('teardown')
84
+ .description('Remove temporary test directory.')
85
+ .option('-d, --dir [tempDir]', 'Directory used by tests to store temporary data.', './temp')
86
+ .option('--verbose', 'Print verbose output.')
87
+ .action(async (_, command) => {
88
+ (0, utils_1.assertEnv)('test', '"weaver test teardown" must be started in "test" environment (NODE_ENV=test).');
89
+ const quiet = !command.getOptionValue('verbose');
90
+ const tempDir = command.getOptionValue('dir');
91
+ const result = await (0, utils_1.rimrafPath)(tempDir, quiet);
92
+ if (result) {
93
+ console.log(`Removed temporary directory ${tempDir}`);
94
+ }
95
+ });
96
+ }
@@ -0,0 +1,2 @@
1
+ export * from './update-command';
2
+ export * from './update-packages';
@@ -0,0 +1,18 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./update-command"), exports);
18
+ __exportStar(require("./update-packages"), exports);
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function updateCommand(program: Command): void;