@classytic/arc 1.0.0 → 1.0.8
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/README.md +65 -35
- package/bin/arc.js +118 -103
- package/dist/BaseController-nNRS3vpA.d.ts +233 -0
- package/dist/adapters/index.d.ts +2 -2
- package/dist/{arcCorePlugin-DTPWXcZN.d.ts → arcCorePlugin-CAjBQtZB.d.ts} +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/cli/commands/generate.d.ts +16 -0
- package/dist/cli/commands/generate.js +334 -0
- package/dist/cli/commands/init.d.ts +24 -0
- package/dist/cli/commands/init.js +2425 -0
- package/dist/cli/index.d.ts +4 -43
- package/dist/cli/index.js +3160 -411
- package/dist/core/index.d.ts +220 -0
- package/dist/core/index.js +2764 -0
- package/dist/{createApp-pzUAkzbz.d.ts → createApp-CjN9zZSL.d.ts} +1 -1
- package/dist/docs/index.js +19 -11
- package/dist/factory/index.d.ts +4 -4
- package/dist/factory/index.js +6 -23
- package/dist/hooks/index.d.ts +1 -1
- package/dist/{index-DkAW8BXh.d.ts → index-D5QTob1X.d.ts} +32 -12
- package/dist/index.d.ts +7 -203
- package/dist/index.js +108 -113
- package/dist/org/index.d.ts +1 -1
- package/dist/permissions/index.js +5 -2
- package/dist/plugins/index.d.ts +2 -2
- package/dist/presets/index.d.ts +6 -6
- package/dist/presets/index.js +3 -1
- package/dist/presets/multiTenant.d.ts +1 -1
- package/dist/registry/index.d.ts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +6 -23
- package/dist/types/index.d.ts +1 -1
- package/dist/{types-0IPhH_NR.d.ts → types-zpN48n6B.d.ts} +1 -1
- package/dist/utils/index.d.ts +28 -4
- package/dist/utils/index.js +17 -8
- package/package.json +8 -14
package/README.md
CHANGED
|
@@ -281,7 +281,14 @@ export default defineResource({
|
|
|
281
281
|
path: '/featured',
|
|
282
282
|
handler: 'getFeatured', // Controller method name
|
|
283
283
|
permissions: allowPublic(), // Permission function
|
|
284
|
-
wrapHandler: true, //
|
|
284
|
+
wrapHandler: true, // Arc context pattern (IRequestContext)
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
method: 'GET',
|
|
288
|
+
path: '/:id/download',
|
|
289
|
+
handler: 'downloadFile', // Fastify native handler
|
|
290
|
+
permissions: requireAuth(),
|
|
291
|
+
wrapHandler: false, // Native Fastify (request, reply)
|
|
285
292
|
},
|
|
286
293
|
],
|
|
287
294
|
});
|
|
@@ -293,6 +300,7 @@ Extend BaseController for built-in security and CRUD:
|
|
|
293
300
|
|
|
294
301
|
```typescript
|
|
295
302
|
import { BaseController } from '@classytic/arc';
|
|
303
|
+
import type { IRequestContext, IControllerResponse } from '@classytic/arc';
|
|
296
304
|
import type { ISoftDeleteController, ISlugLookupController } from '@classytic/arc/presets';
|
|
297
305
|
|
|
298
306
|
// Type-safe controller with preset interfaces
|
|
@@ -302,21 +310,29 @@ class ProductController
|
|
|
302
310
|
{
|
|
303
311
|
constructor() {
|
|
304
312
|
super(productRepository);
|
|
305
|
-
|
|
306
|
-
// TypeScript ensures these methods exist (required by presets)
|
|
307
|
-
this.getBySlug = this.getBySlug.bind(this);
|
|
308
|
-
this.getDeleted = this.getDeleted.bind(this);
|
|
309
|
-
this.restore = this.restore.bind(this);
|
|
310
313
|
}
|
|
311
314
|
|
|
312
|
-
// Custom method
|
|
313
|
-
async getFeatured(req
|
|
314
|
-
|
|
315
|
+
// Custom method - Arc context pattern
|
|
316
|
+
async getFeatured(req: IRequestContext): Promise<IControllerResponse> {
|
|
317
|
+
const { organizationId } = req;
|
|
318
|
+
|
|
315
319
|
const products = await this.repository.findAll({
|
|
316
|
-
filter: { isFeatured: true },
|
|
317
|
-
...this._applyFilters(req),
|
|
320
|
+
filter: { isFeatured: true, organizationId },
|
|
318
321
|
});
|
|
319
|
-
|
|
322
|
+
|
|
323
|
+
return { success: true, data: products };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Preset methods
|
|
327
|
+
async getBySlug(req: IRequestContext): Promise<IControllerResponse> {
|
|
328
|
+
const { slug } = req.params;
|
|
329
|
+
const product = await this.repository.getBySlug(slug);
|
|
330
|
+
|
|
331
|
+
if (!product) {
|
|
332
|
+
return { success: false, error: 'Product not found', status: 404 };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return { success: true, data: product };
|
|
320
336
|
}
|
|
321
337
|
}
|
|
322
338
|
```
|
|
@@ -329,17 +345,36 @@ class ProductController
|
|
|
329
345
|
|
|
330
346
|
**Note:** Presets like `multiTenant`, `ownedByUser`, and `audited` don't require controller methods—they work via middleware.
|
|
331
347
|
|
|
348
|
+
### Request Context API
|
|
349
|
+
|
|
350
|
+
Controller methods receive `req: IRequestContext`:
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
interface IRequestContext {
|
|
354
|
+
params: Record<string, string>; // Route params: /users/:id
|
|
355
|
+
query: Record<string, unknown>; // Query string: ?page=1
|
|
356
|
+
body: unknown; // Request body
|
|
357
|
+
user: UserBase | null; // Authenticated user
|
|
358
|
+
headers: Record<string, string | undefined>; // Request headers
|
|
359
|
+
organizationId?: string; // Multi-tenant org ID
|
|
360
|
+
metadata?: Record<string, unknown>; // Custom data, _policyFilters, middleware context
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Key Fields:**
|
|
365
|
+
- `req.metadata` - Custom data from hooks, policies, or middleware
|
|
366
|
+
- `req.organizationId` - Set by `multiTenant` preset or org scope plugin
|
|
367
|
+
- `req.user` - Set by auth plugin, preserves original auth structure
|
|
368
|
+
|
|
332
369
|
### TypeScript Strict Mode
|
|
333
370
|
|
|
334
|
-
For maximum type safety
|
|
371
|
+
For maximum type safety:
|
|
335
372
|
|
|
336
373
|
```typescript
|
|
337
|
-
import { BaseController } from '@classytic/arc';
|
|
338
|
-
import type { Document } from 'mongoose';
|
|
374
|
+
import { BaseController, IRequestContext, IControllerResponse } from '@classytic/arc';
|
|
339
375
|
import type { ISoftDeleteController, ISlugLookupController } from '@classytic/arc/presets';
|
|
340
376
|
|
|
341
|
-
|
|
342
|
-
interface ProductDocument extends Document {
|
|
377
|
+
interface Product {
|
|
343
378
|
_id: string;
|
|
344
379
|
name: string;
|
|
345
380
|
slug: string;
|
|
@@ -347,43 +382,38 @@ interface ProductDocument extends Document {
|
|
|
347
382
|
deletedAt?: Date;
|
|
348
383
|
}
|
|
349
384
|
|
|
350
|
-
// Strict controller with generics
|
|
351
385
|
class ProductController
|
|
352
|
-
extends BaseController<
|
|
353
|
-
implements
|
|
354
|
-
ISoftDeleteController<ProductDocument>,
|
|
355
|
-
ISlugLookupController<ProductDocument>
|
|
386
|
+
extends BaseController<Product>
|
|
387
|
+
implements ISoftDeleteController<Product>, ISlugLookupController<Product>
|
|
356
388
|
{
|
|
357
|
-
|
|
358
|
-
async getBySlug(req, reply): Promise<void> {
|
|
389
|
+
async getBySlug(req: IRequestContext): Promise<IControllerResponse<Product>> {
|
|
359
390
|
const { slug } = req.params;
|
|
360
391
|
const product = await this.repository.getBySlug(slug);
|
|
361
392
|
|
|
362
393
|
if (!product) {
|
|
363
|
-
return
|
|
394
|
+
return { success: false, error: 'Product not found', status: 404 };
|
|
364
395
|
}
|
|
365
396
|
|
|
366
|
-
return
|
|
397
|
+
return { success: true, data: product };
|
|
367
398
|
}
|
|
368
399
|
|
|
369
|
-
async getDeleted(req
|
|
400
|
+
async getDeleted(req: IRequestContext): Promise<IControllerResponse<Product[]>> {
|
|
370
401
|
const products = await this.repository.findDeleted();
|
|
371
|
-
return
|
|
402
|
+
return { success: true, data: products };
|
|
372
403
|
}
|
|
373
404
|
|
|
374
|
-
async restore(req
|
|
405
|
+
async restore(req: IRequestContext): Promise<IControllerResponse<Product>> {
|
|
375
406
|
const { id } = req.params;
|
|
376
407
|
const product = await this.repository.restore(id);
|
|
377
|
-
return
|
|
408
|
+
return { success: true, data: product };
|
|
378
409
|
}
|
|
379
410
|
}
|
|
380
411
|
```
|
|
381
412
|
|
|
382
|
-
**Benefits
|
|
383
|
-
- Compile-time
|
|
384
|
-
- IntelliSense autocomplete
|
|
385
|
-
-
|
|
386
|
-
- Refactoring safety across large codebases
|
|
413
|
+
**Benefits:**
|
|
414
|
+
- Compile-time type checking
|
|
415
|
+
- IntelliSense autocomplete
|
|
416
|
+
- Safe refactoring
|
|
387
417
|
|
|
388
418
|
### Repositories
|
|
389
419
|
|
package/bin/arc.js
CHANGED
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
* Arc CLI - Smart Backend Framework
|
|
5
5
|
*
|
|
6
6
|
* Commands:
|
|
7
|
-
* arc
|
|
8
|
-
* arc generate
|
|
9
|
-
* arc generate
|
|
10
|
-
* arc
|
|
11
|
-
* arc
|
|
7
|
+
* arc init [name] Initialize a new Arc project
|
|
8
|
+
* arc generate resource <name> Generate a new resource
|
|
9
|
+
* arc generate controller <name> Generate a controller only
|
|
10
|
+
* arc generate model <name> Generate a model only
|
|
11
|
+
* arc introspect Show all registered resources
|
|
12
|
+
* arc docs [output-path] Export OpenAPI specification
|
|
12
13
|
*
|
|
13
14
|
* Examples:
|
|
14
|
-
* arc
|
|
15
|
-
* arc
|
|
15
|
+
* arc init my-api
|
|
16
|
+
* arc init my-api --mongokit --single --ts
|
|
17
|
+
* arc generate resource product
|
|
18
|
+
* arc g r invoice
|
|
16
19
|
* arc introspect
|
|
17
20
|
* arc docs ./openapi.json
|
|
18
21
|
*/
|
|
@@ -60,6 +63,11 @@ const [command, subcommand, ...rest] = args;
|
|
|
60
63
|
async function main() {
|
|
61
64
|
try {
|
|
62
65
|
switch (command) {
|
|
66
|
+
case 'init':
|
|
67
|
+
case 'new':
|
|
68
|
+
await handleInit(subcommand ? [subcommand, ...rest] : rest);
|
|
69
|
+
break;
|
|
70
|
+
|
|
63
71
|
case 'generate':
|
|
64
72
|
case 'g':
|
|
65
73
|
await handleGenerate(subcommand, rest);
|
|
@@ -76,12 +84,12 @@ async function main() {
|
|
|
76
84
|
break;
|
|
77
85
|
|
|
78
86
|
default:
|
|
79
|
-
console.error(
|
|
87
|
+
console.error(`Unknown command: ${command}`);
|
|
80
88
|
console.error('Run "arc --help" for usage');
|
|
81
89
|
process.exit(1);
|
|
82
90
|
}
|
|
83
91
|
} catch (err) {
|
|
84
|
-
console.error(
|
|
92
|
+
console.error(`Error: ${err.message}`);
|
|
85
93
|
if (process.env.DEBUG) {
|
|
86
94
|
console.error(err.stack);
|
|
87
95
|
}
|
|
@@ -93,13 +101,19 @@ async function main() {
|
|
|
93
101
|
// Command Handlers
|
|
94
102
|
// ============================================================================
|
|
95
103
|
|
|
104
|
+
async function handleInit(args) {
|
|
105
|
+
const options = parseInitOptions(args);
|
|
106
|
+
const { init } = await import('../dist/cli/commands/init.js');
|
|
107
|
+
await init(options);
|
|
108
|
+
}
|
|
109
|
+
|
|
96
110
|
async function handleGenerate(type, args) {
|
|
97
111
|
if (!type) {
|
|
98
|
-
console.error('
|
|
99
|
-
console.log('\nUsage: arc generate <resource|controller|model> <name>
|
|
112
|
+
console.error('Missing type argument');
|
|
113
|
+
console.log('\nUsage: arc generate <resource|controller|model|repository|schemas> <name>');
|
|
100
114
|
console.log('\nExamples:');
|
|
101
|
-
console.log(' arc generate resource product
|
|
102
|
-
console.log(' arc g r invoice
|
|
115
|
+
console.log(' arc generate resource product');
|
|
116
|
+
console.log(' arc g r invoice');
|
|
103
117
|
process.exit(1);
|
|
104
118
|
}
|
|
105
119
|
|
|
@@ -108,30 +122,32 @@ async function handleGenerate(type, args) {
|
|
|
108
122
|
r: 'resource',
|
|
109
123
|
c: 'controller',
|
|
110
124
|
m: 'model',
|
|
125
|
+
repo: 'repository',
|
|
126
|
+
s: 'schemas',
|
|
111
127
|
resource: 'resource',
|
|
112
128
|
controller: 'controller',
|
|
113
129
|
model: 'model',
|
|
130
|
+
repository: 'repository',
|
|
131
|
+
schemas: 'schemas',
|
|
114
132
|
};
|
|
115
133
|
|
|
116
134
|
const normalizedType = typeMap[type.toLowerCase()];
|
|
117
135
|
if (!normalizedType) {
|
|
118
|
-
console.error(
|
|
119
|
-
console.log('Available types: resource (r), controller (c), model (m)');
|
|
136
|
+
console.error(`Unknown type: ${type}`);
|
|
137
|
+
console.log('Available types: resource (r), controller (c), model (m), repository (repo), schemas (s)');
|
|
120
138
|
process.exit(1);
|
|
121
139
|
}
|
|
122
140
|
|
|
123
141
|
const name = args[0];
|
|
124
142
|
if (!name) {
|
|
125
|
-
console.error('
|
|
126
|
-
console.log(`\nUsage: arc generate ${normalizedType} <name
|
|
143
|
+
console.error('Missing name argument');
|
|
144
|
+
console.log(`\nUsage: arc generate ${normalizedType} <name>`);
|
|
127
145
|
process.exit(1);
|
|
128
146
|
}
|
|
129
147
|
|
|
130
|
-
const options = parseGenerateOptions(args.slice(1));
|
|
131
|
-
|
|
132
148
|
// Import and run
|
|
133
|
-
const { generate } = await import('../dist/cli/
|
|
134
|
-
await generate(normalizedType,
|
|
149
|
+
const { generate } = await import('../dist/cli/commands/generate.js');
|
|
150
|
+
await generate(normalizedType, args);
|
|
135
151
|
}
|
|
136
152
|
|
|
137
153
|
async function handleIntrospect(args) {
|
|
@@ -143,11 +159,11 @@ async function handleIntrospect(args) {
|
|
|
143
159
|
const absolutePath = resolve(process.cwd(), entryPath);
|
|
144
160
|
const fileUrl = pathToFileURL(absolutePath).href;
|
|
145
161
|
|
|
146
|
-
console.log(
|
|
162
|
+
console.log(`Loading resources from: ${entryPath}\n`);
|
|
147
163
|
try {
|
|
148
164
|
await import(fileUrl);
|
|
149
165
|
} catch (err) {
|
|
150
|
-
console.error(
|
|
166
|
+
console.error(`Failed to load entry file: ${err.message}`);
|
|
151
167
|
if (process.env.DEBUG) {
|
|
152
168
|
console.error(err.stack);
|
|
153
169
|
}
|
|
@@ -168,11 +184,11 @@ async function handleDocs(args) {
|
|
|
168
184
|
const absolutePath = resolve(process.cwd(), entryPath);
|
|
169
185
|
const fileUrl = pathToFileURL(absolutePath).href;
|
|
170
186
|
|
|
171
|
-
console.log(
|
|
187
|
+
console.log(`Loading resources from: ${entryPath}\n`);
|
|
172
188
|
try {
|
|
173
189
|
await import(fileUrl);
|
|
174
190
|
} catch (err) {
|
|
175
|
-
console.error(
|
|
191
|
+
console.error(`Failed to load entry file: ${err.message}`);
|
|
176
192
|
if (process.env.DEBUG) {
|
|
177
193
|
console.error(err.stack);
|
|
178
194
|
}
|
|
@@ -190,57 +206,54 @@ async function handleDocs(args) {
|
|
|
190
206
|
// Option Parsing
|
|
191
207
|
// ============================================================================
|
|
192
208
|
|
|
193
|
-
function
|
|
209
|
+
function parseInitOptions(args) {
|
|
194
210
|
const opts = {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
211
|
+
name: undefined,
|
|
212
|
+
adapter: undefined,
|
|
213
|
+
tenant: undefined,
|
|
214
|
+
typescript: undefined,
|
|
215
|
+
skipInstall: false,
|
|
200
216
|
force: false,
|
|
201
|
-
typescript: true, // Default to TypeScript
|
|
202
|
-
outputDir: process.cwd(),
|
|
203
217
|
};
|
|
204
218
|
|
|
205
219
|
for (let i = 0; i < args.length; i++) {
|
|
206
220
|
const arg = args[i];
|
|
207
221
|
const next = args[i + 1];
|
|
208
222
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
break;
|
|
223
|
+
// First non-flag argument is the project name
|
|
224
|
+
if (!arg.startsWith('-') && !opts.name) {
|
|
225
|
+
opts.name = arg;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
215
228
|
|
|
216
|
-
|
|
217
|
-
case '
|
|
218
|
-
|
|
229
|
+
switch (arg) {
|
|
230
|
+
case '--name':
|
|
231
|
+
case '-n':
|
|
232
|
+
opts.name = next;
|
|
219
233
|
i++;
|
|
220
234
|
break;
|
|
221
235
|
|
|
222
|
-
case '--
|
|
223
|
-
opts.
|
|
224
|
-
i++;
|
|
236
|
+
case '--mongokit':
|
|
237
|
+
opts.adapter = 'mongokit';
|
|
225
238
|
break;
|
|
226
239
|
|
|
227
|
-
case '--
|
|
228
|
-
|
|
229
|
-
opts.outputDir = next;
|
|
230
|
-
i++;
|
|
240
|
+
case '--custom':
|
|
241
|
+
opts.adapter = 'custom';
|
|
231
242
|
break;
|
|
232
243
|
|
|
233
|
-
case '--
|
|
234
|
-
|
|
244
|
+
case '--multi-tenant':
|
|
245
|
+
case '--multi':
|
|
246
|
+
opts.tenant = 'multi';
|
|
235
247
|
break;
|
|
236
248
|
|
|
237
|
-
case '--
|
|
238
|
-
|
|
249
|
+
case '--single-tenant':
|
|
250
|
+
case '--single':
|
|
251
|
+
opts.tenant = 'single';
|
|
239
252
|
break;
|
|
240
253
|
|
|
241
|
-
case '--
|
|
242
|
-
case '
|
|
243
|
-
opts.
|
|
254
|
+
case '--ts':
|
|
255
|
+
case '--typescript':
|
|
256
|
+
opts.typescript = true;
|
|
244
257
|
break;
|
|
245
258
|
|
|
246
259
|
case '--js':
|
|
@@ -248,9 +261,13 @@ function parseGenerateOptions(args) {
|
|
|
248
261
|
opts.typescript = false;
|
|
249
262
|
break;
|
|
250
263
|
|
|
251
|
-
case '--
|
|
252
|
-
|
|
253
|
-
|
|
264
|
+
case '--skip-install':
|
|
265
|
+
opts.skipInstall = true;
|
|
266
|
+
break;
|
|
267
|
+
|
|
268
|
+
case '--force':
|
|
269
|
+
case '-f':
|
|
270
|
+
opts.force = true;
|
|
254
271
|
break;
|
|
255
272
|
}
|
|
256
273
|
}
|
|
@@ -264,15 +281,14 @@ function parseGenerateOptions(args) {
|
|
|
264
281
|
|
|
265
282
|
function printHelp() {
|
|
266
283
|
console.log(`
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
║ Resource-Oriented Backend Framework ║
|
|
270
|
-
╚═══════════════════════════════════════════════════════════════╝
|
|
284
|
+
Arc CLI v${VERSION}
|
|
285
|
+
Resource-Oriented Backend Framework
|
|
271
286
|
|
|
272
287
|
USAGE
|
|
273
288
|
arc <command> [options]
|
|
274
289
|
|
|
275
290
|
COMMANDS
|
|
291
|
+
init, new Initialize a new Arc project
|
|
276
292
|
generate, g Generate resources, controllers, or models
|
|
277
293
|
introspect, i Show all registered resources
|
|
278
294
|
docs, d Export OpenAPI specification
|
|
@@ -283,56 +299,55 @@ GLOBAL OPTIONS
|
|
|
283
299
|
--version, -v Show version
|
|
284
300
|
--help, -h Show this help
|
|
285
301
|
|
|
302
|
+
INIT OPTIONS
|
|
303
|
+
--mongokit Use MongoKit adapter (default, recommended)
|
|
304
|
+
--custom Use custom adapter (empty template)
|
|
305
|
+
--multi-tenant, --multi Multi-tenant mode (adds org scoping)
|
|
306
|
+
--single-tenant, --single Single-tenant mode (default)
|
|
307
|
+
--ts, --typescript Generate TypeScript (default)
|
|
308
|
+
--js, --javascript Generate JavaScript
|
|
309
|
+
--force, -f Overwrite existing directory
|
|
310
|
+
--skip-install Skip npm install after scaffolding
|
|
311
|
+
|
|
286
312
|
GENERATE SUBCOMMANDS
|
|
287
|
-
resource, r
|
|
288
|
-
controller, c
|
|
289
|
-
model, m
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
• multiTenant - Organization scoping
|
|
298
|
-
• tree - Hierarchical data support
|
|
299
|
-
• audited - Audit logging
|
|
300
|
-
--parent-field <name> Custom parent field for tree preset
|
|
301
|
-
--output, -o <path> Output directory (default: cwd)
|
|
302
|
-
--no-tests Skip test file generation
|
|
303
|
-
--dry-run Preview without creating files
|
|
304
|
-
--force, -f Overwrite existing files
|
|
305
|
-
--js, --javascript Generate JavaScript (default: TypeScript)
|
|
313
|
+
resource, r Generate full resource (model, repo, controller, schemas, resource)
|
|
314
|
+
controller, c Generate controller only
|
|
315
|
+
model, m Generate model only
|
|
316
|
+
repository, repo Generate repository only
|
|
317
|
+
schemas, s Generate schemas only
|
|
318
|
+
|
|
319
|
+
GENERATE NOTES
|
|
320
|
+
- Auto-detects TypeScript/JavaScript from tsconfig.json
|
|
321
|
+
- Files are created in src/resources/<name>/ directory
|
|
322
|
+
- Uses prefixed filenames: <name>.model.ts, <name>.repository.ts, etc.
|
|
306
323
|
|
|
307
324
|
EXAMPLES
|
|
308
|
-
#
|
|
309
|
-
arc
|
|
325
|
+
# Initialize a new project (interactive prompts)
|
|
326
|
+
arc init my-api
|
|
310
327
|
|
|
311
|
-
#
|
|
312
|
-
arc
|
|
328
|
+
# Initialize with all options (non-interactive)
|
|
329
|
+
arc init my-api --mongokit --single --ts
|
|
313
330
|
|
|
314
|
-
#
|
|
315
|
-
arc
|
|
331
|
+
# Initialize a JavaScript single-tenant app
|
|
332
|
+
arc init my-api --mongokit --single --js
|
|
316
333
|
|
|
317
|
-
#
|
|
318
|
-
arc
|
|
334
|
+
# Generate a product resource
|
|
335
|
+
arc generate resource product
|
|
319
336
|
|
|
320
|
-
#
|
|
321
|
-
arc
|
|
337
|
+
# Shorthand for generating a resource
|
|
338
|
+
arc g r invoice
|
|
339
|
+
|
|
340
|
+
# Generate only a controller
|
|
341
|
+
arc g controller auth
|
|
322
342
|
|
|
323
|
-
#
|
|
324
|
-
arc
|
|
343
|
+
# Generate only a model
|
|
344
|
+
arc g model order
|
|
325
345
|
|
|
326
|
-
#
|
|
327
|
-
arc
|
|
346
|
+
# Export OpenAPI spec (load resources first)
|
|
347
|
+
arc docs ./docs/openapi.json --entry ./dist/index.js
|
|
328
348
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
slugLookup Adds: slug field, GET /slug/:slug endpoint
|
|
332
|
-
ownedByUser Adds: createdBy field, ownership validation
|
|
333
|
-
multiTenant Adds: organizationId field, org scoping middleware
|
|
334
|
-
tree Adds: parent field, GET /tree, GET /:id/children
|
|
335
|
-
audited Adds: audit log entries for all mutations
|
|
349
|
+
# Show registered resources
|
|
350
|
+
arc introspect --entry ./dist/index.js
|
|
336
351
|
|
|
337
352
|
MORE INFO
|
|
338
353
|
Documentation: https://github.com/classytic/arc
|