@classytic/arc 1.1.0 → 2.1.3
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 +247 -794
- package/bin/arc.js +91 -52
- package/dist/EventTransport-BkUDYZEb.d.mts +99 -0
- package/dist/HookSystem-BsGV-j2l.mjs +404 -0
- package/dist/ResourceRegistry-7Ic20ZMw.mjs +249 -0
- package/dist/adapters/index.d.mts +5 -0
- package/dist/adapters/index.mjs +3 -0
- package/dist/audit/index.d.mts +81 -0
- package/dist/audit/index.mjs +275 -0
- package/dist/audit/mongodb.d.mts +5 -0
- package/dist/audit/mongodb.mjs +3 -0
- package/dist/audited-CGdLiSlE.mjs +140 -0
- package/dist/auth/index.d.mts +188 -0
- package/dist/auth/index.mjs +1096 -0
- package/dist/auth/redis-session.d.mts +43 -0
- package/dist/auth/redis-session.mjs +75 -0
- package/dist/betterAuthOpenApi-DjWDddNc.mjs +249 -0
- package/dist/cache/index.d.mts +145 -0
- package/dist/cache/index.mjs +91 -0
- package/dist/caching-GSDJcA6-.mjs +93 -0
- package/dist/chunk-C7Uep-_p.mjs +20 -0
- package/dist/circuitBreaker-DYhWBW_D.mjs +1096 -0
- package/dist/cli/commands/describe.d.mts +18 -0
- package/dist/cli/commands/describe.mjs +238 -0
- package/dist/cli/commands/docs.d.mts +13 -0
- package/dist/cli/commands/docs.mjs +52 -0
- package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -2
- package/dist/cli/commands/generate.mjs +357 -0
- package/dist/cli/commands/{init.d.ts → init.d.mts} +11 -8
- package/dist/cli/commands/{init.js → init.mjs} +807 -617
- package/dist/cli/commands/introspect.d.mts +10 -0
- package/dist/cli/commands/introspect.mjs +75 -0
- package/dist/cli/index.d.mts +16 -0
- package/dist/cli/index.mjs +156 -0
- package/dist/constants-DdXFXQtN.mjs +84 -0
- package/dist/core/index.d.mts +5 -0
- package/dist/core/index.mjs +4 -0
- package/dist/createApp-D2D5XXaV.mjs +559 -0
- package/dist/defineResource-PXzSJ15_.mjs +2197 -0
- package/dist/discovery/index.d.mts +46 -0
- package/dist/discovery/index.mjs +109 -0
- package/dist/docs/index.d.mts +162 -0
- package/dist/docs/index.mjs +74 -0
- package/dist/elevation-DGo5shaX.d.mts +87 -0
- package/dist/elevation-DSTbVvYj.mjs +113 -0
- package/dist/errorHandler-C3GY3_ow.mjs +108 -0
- package/dist/errorHandler-CW3OOeYq.d.mts +72 -0
- package/dist/errors-DAWRdiYP.d.mts +124 -0
- package/dist/errors-DBANPbGr.mjs +211 -0
- package/dist/eventPlugin-BEOvaDqo.mjs +229 -0
- package/dist/eventPlugin-H6wDDjGO.d.mts +124 -0
- package/dist/events/index.d.mts +53 -0
- package/dist/events/index.mjs +51 -0
- package/dist/events/transports/redis-stream-entry.d.mts +2 -0
- package/dist/events/transports/redis-stream-entry.mjs +177 -0
- package/dist/events/transports/redis.d.mts +76 -0
- package/dist/events/transports/redis.mjs +124 -0
- package/dist/externalPaths-SyPF2tgK.d.mts +50 -0
- package/dist/factory/index.d.mts +63 -0
- package/dist/factory/index.mjs +3 -0
- package/dist/fastifyAdapter-C8DlE0YH.d.mts +216 -0
- package/dist/fields-Bi_AVKSo.d.mts +109 -0
- package/dist/fields-CTd_CrKr.mjs +114 -0
- package/dist/hooks/index.d.mts +4 -0
- package/dist/hooks/index.mjs +3 -0
- package/dist/idempotency/index.d.mts +96 -0
- package/dist/idempotency/index.mjs +319 -0
- package/dist/idempotency/mongodb.d.mts +2 -0
- package/dist/idempotency/mongodb.mjs +114 -0
- package/dist/idempotency/redis.d.mts +2 -0
- package/dist/idempotency/redis.mjs +103 -0
- package/dist/index.d.mts +260 -0
- package/dist/index.mjs +104 -0
- package/dist/integrations/event-gateway.d.mts +46 -0
- package/dist/integrations/event-gateway.mjs +43 -0
- package/dist/integrations/index.d.mts +5 -0
- package/dist/integrations/index.mjs +1 -0
- package/dist/integrations/jobs.d.mts +103 -0
- package/dist/integrations/jobs.mjs +123 -0
- package/dist/integrations/streamline.d.mts +60 -0
- package/dist/integrations/streamline.mjs +125 -0
- package/dist/integrations/websocket.d.mts +82 -0
- package/dist/integrations/websocket.mjs +288 -0
- package/dist/interface-CSNjltAc.d.mts +77 -0
- package/dist/interface-DTbsvIWe.d.mts +54 -0
- package/dist/interface-e9XfSsUV.d.mts +1097 -0
- package/dist/introspectionPlugin-B3JkrjwU.mjs +53 -0
- package/dist/keys-DhqDRxv3.mjs +42 -0
- package/dist/logger-ByrvQWZO.mjs +78 -0
- package/dist/memory-B2v7KrCB.mjs +143 -0
- package/dist/migrations/index.d.mts +156 -0
- package/dist/migrations/index.mjs +260 -0
- package/dist/mongodb-ClykrfGo.d.mts +118 -0
- package/dist/mongodb-DNKEExbf.mjs +93 -0
- package/dist/mongodb-Dg8O_gvd.d.mts +71 -0
- package/dist/openapi-9nB_kiuR.mjs +525 -0
- package/dist/org/index.d.mts +68 -0
- package/dist/org/index.mjs +513 -0
- package/dist/org/types.d.mts +82 -0
- package/dist/org/types.mjs +1 -0
- package/dist/permissions/index.d.mts +278 -0
- package/dist/permissions/index.mjs +579 -0
- package/dist/plugins/index.d.mts +172 -0
- package/dist/plugins/index.mjs +522 -0
- package/dist/plugins/response-cache.d.mts +87 -0
- package/dist/plugins/response-cache.mjs +283 -0
- package/dist/plugins/tracing-entry.d.mts +2 -0
- package/dist/plugins/tracing-entry.mjs +185 -0
- package/dist/pluralize-CM-jZg7p.mjs +86 -0
- package/dist/policies/{index.d.ts → index.d.mts} +204 -170
- package/dist/policies/index.mjs +321 -0
- package/dist/presets/{index.d.ts → index.d.mts} +62 -131
- package/dist/presets/index.mjs +143 -0
- package/dist/presets/multiTenant.d.mts +24 -0
- package/dist/presets/multiTenant.mjs +113 -0
- package/dist/presets-BTeYbw7h.d.mts +57 -0
- package/dist/presets-CeFtfDR8.mjs +119 -0
- package/dist/prisma-C3iornoK.d.mts +274 -0
- package/dist/prisma-DJbMt3yf.mjs +627 -0
- package/dist/queryCachePlugin-B6R0d4av.mjs +138 -0
- package/dist/queryCachePlugin-Q6SYuHZ6.d.mts +71 -0
- package/dist/redis-UwjEp8Ea.d.mts +49 -0
- package/dist/redis-stream-CBg0upHI.d.mts +103 -0
- package/dist/registry/index.d.mts +11 -0
- package/dist/registry/index.mjs +4 -0
- package/dist/requestContext-xi6OKBL-.mjs +55 -0
- package/dist/schemaConverter-Dtg0Kt9T.mjs +98 -0
- package/dist/schemas/index.d.mts +63 -0
- package/dist/schemas/index.mjs +82 -0
- package/dist/scope/index.d.mts +21 -0
- package/dist/scope/index.mjs +65 -0
- package/dist/sessionManager-D_iEHjQl.d.mts +186 -0
- package/dist/sse-DkqQ1uxb.mjs +123 -0
- package/dist/testing/index.d.mts +907 -0
- package/dist/testing/index.mjs +1976 -0
- package/dist/tracing-8CEbhF0w.d.mts +70 -0
- package/dist/typeGuards-DwxA1t_L.mjs +9 -0
- package/dist/types/index.d.mts +946 -0
- package/dist/types/index.mjs +14 -0
- package/dist/types-B0dhNrnd.d.mts +445 -0
- package/dist/types-Beqn1Un7.mjs +38 -0
- package/dist/types-DelU6kln.mjs +25 -0
- package/dist/types-RLkFVgaw.d.mts +101 -0
- package/dist/utils/index.d.mts +747 -0
- package/dist/utils/index.mjs +6 -0
- package/package.json +194 -68
- package/dist/BaseController-DVAiHxEQ.d.ts +0 -233
- package/dist/adapters/index.d.ts +0 -237
- package/dist/adapters/index.js +0 -668
- package/dist/arcCorePlugin-CsShQdyP.d.ts +0 -273
- package/dist/audit/index.d.ts +0 -195
- package/dist/audit/index.js +0 -319
- package/dist/auth/index.d.ts +0 -47
- package/dist/auth/index.js +0 -174
- package/dist/cli/commands/docs.d.ts +0 -11
- package/dist/cli/commands/docs.js +0 -474
- package/dist/cli/commands/generate.js +0 -334
- package/dist/cli/commands/introspect.d.ts +0 -8
- package/dist/cli/commands/introspect.js +0 -338
- package/dist/cli/index.d.ts +0 -4
- package/dist/cli/index.js +0 -3269
- package/dist/core/index.d.ts +0 -220
- package/dist/core/index.js +0 -2786
- package/dist/createApp-Ce9wl8W9.d.ts +0 -77
- package/dist/docs/index.d.ts +0 -166
- package/dist/docs/index.js +0 -658
- package/dist/errors-8WIxGS_6.d.ts +0 -122
- package/dist/events/index.d.ts +0 -117
- package/dist/events/index.js +0 -89
- package/dist/factory/index.d.ts +0 -38
- package/dist/factory/index.js +0 -1652
- package/dist/hooks/index.d.ts +0 -4
- package/dist/hooks/index.js +0 -199
- package/dist/idempotency/index.d.ts +0 -323
- package/dist/idempotency/index.js +0 -500
- package/dist/index-B4t03KQ0.d.ts +0 -1366
- package/dist/index.d.ts +0 -135
- package/dist/index.js +0 -4756
- package/dist/migrations/index.d.ts +0 -185
- package/dist/migrations/index.js +0 -274
- package/dist/org/index.d.ts +0 -129
- package/dist/org/index.js +0 -220
- package/dist/permissions/index.d.ts +0 -144
- package/dist/permissions/index.js +0 -103
- package/dist/plugins/index.d.ts +0 -46
- package/dist/plugins/index.js +0 -1069
- package/dist/policies/index.js +0 -196
- package/dist/presets/index.js +0 -384
- package/dist/presets/multiTenant.d.ts +0 -39
- package/dist/presets/multiTenant.js +0 -112
- package/dist/registry/index.d.ts +0 -16
- package/dist/registry/index.js +0 -253
- package/dist/testing/index.d.ts +0 -618
- package/dist/testing/index.js +0 -48020
- package/dist/types/index.d.ts +0 -4
- package/dist/types/index.js +0 -8
- package/dist/types-B99TBmFV.d.ts +0 -76
- package/dist/types-BvckRbs2.d.ts +0 -143
- package/dist/utils/index.d.ts +0 -679
- package/dist/utils/index.js +0 -931
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
|
|
4
|
-
// src/cli/commands/generate.ts
|
|
5
|
-
function isTypeScriptProject() {
|
|
6
|
-
return existsSync(join(process.cwd(), "tsconfig.json"));
|
|
7
|
-
}
|
|
8
|
-
function getTemplates(ts) {
|
|
9
|
-
return {
|
|
10
|
-
model: (name) => `/**
|
|
11
|
-
* ${name} Model
|
|
12
|
-
* Generated by Arc CLI
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import mongoose${ts ? ", { type HydratedDocument }" : ""} from 'mongoose';
|
|
16
|
-
|
|
17
|
-
const { Schema } = mongoose;
|
|
18
|
-
${ts ? `
|
|
19
|
-
type ${name} = {
|
|
20
|
-
name: string;
|
|
21
|
-
description?: string;
|
|
22
|
-
isActive: boolean;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export type ${name}Document = HydratedDocument<${name}>;
|
|
26
|
-
` : ""}
|
|
27
|
-
const ${name.toLowerCase()}Schema = new Schema${ts ? `<${name}>` : ""}(
|
|
28
|
-
{
|
|
29
|
-
name: { type: String, required: true, trim: true },
|
|
30
|
-
description: { type: String, trim: true },
|
|
31
|
-
isActive: { type: Boolean, default: true },
|
|
32
|
-
},
|
|
33
|
-
{ timestamps: true }
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
// Indexes
|
|
37
|
-
${name.toLowerCase()}Schema.index({ name: 1 });
|
|
38
|
-
${name.toLowerCase()}Schema.index({ isActive: 1 });
|
|
39
|
-
|
|
40
|
-
const ${name} = mongoose.models.${name}${ts ? ` as mongoose.Model<${name}>` : ""} || mongoose.model${ts ? `<${name}>` : ""}('${name}', ${name.toLowerCase()}Schema);
|
|
41
|
-
export default ${name};
|
|
42
|
-
`,
|
|
43
|
-
repository: (name) => `/**
|
|
44
|
-
* ${name} Repository
|
|
45
|
-
* Generated by Arc CLI
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
import {
|
|
49
|
-
Repository,
|
|
50
|
-
methodRegistryPlugin,
|
|
51
|
-
softDeletePlugin,
|
|
52
|
-
mongoOperationsPlugin,
|
|
53
|
-
} from '@classytic/mongokit';
|
|
54
|
-
${ts ? `import type { ${name}Document } from './${name.toLowerCase()}.model.js';` : ""}
|
|
55
|
-
import ${name} from './${name.toLowerCase()}.model.js';
|
|
56
|
-
|
|
57
|
-
class ${name}Repository extends Repository${ts ? `<${name}Document>` : ""} {
|
|
58
|
-
constructor() {
|
|
59
|
-
super(${name}${ts ? " as any" : ""}, [
|
|
60
|
-
methodRegistryPlugin(),
|
|
61
|
-
softDeletePlugin(),
|
|
62
|
-
mongoOperationsPlugin(),
|
|
63
|
-
]);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Find all active records
|
|
68
|
-
*/
|
|
69
|
-
async findActive() {
|
|
70
|
-
return this.Model.find({ isActive: true, deletedAt: null }).lean();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Add custom repository methods here
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const ${name.toLowerCase()}Repository = new ${name}Repository();
|
|
77
|
-
export default ${name.toLowerCase()}Repository;
|
|
78
|
-
export { ${name}Repository };
|
|
79
|
-
`,
|
|
80
|
-
controller: (name) => `/**
|
|
81
|
-
* ${name} Controller
|
|
82
|
-
* Generated by Arc CLI
|
|
83
|
-
*/
|
|
84
|
-
|
|
85
|
-
import { BaseController } from '@classytic/arc';
|
|
86
|
-
import ${name.toLowerCase()}Repository from './${name.toLowerCase()}.repository.js';
|
|
87
|
-
import { ${name.toLowerCase()}SchemaOptions } from './${name.toLowerCase()}.schemas.js';
|
|
88
|
-
|
|
89
|
-
class ${name}Controller extends BaseController {
|
|
90
|
-
constructor() {
|
|
91
|
-
super(${name.toLowerCase()}Repository${ts ? " as any" : ""}, { schemaOptions: ${name.toLowerCase()}SchemaOptions });
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Add custom controller methods here
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const ${name.toLowerCase()}Controller = new ${name}Controller();
|
|
98
|
-
export default ${name.toLowerCase()}Controller;
|
|
99
|
-
`,
|
|
100
|
-
schemas: (name) => `/**
|
|
101
|
-
* ${name} Schemas
|
|
102
|
-
* Generated by Arc CLI
|
|
103
|
-
*/
|
|
104
|
-
|
|
105
|
-
import ${name} from './${name.toLowerCase()}.model.js';
|
|
106
|
-
import { buildCrudSchemasFromModel } from '@classytic/mongokit/utils';
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* CRUD Schemas with Field Rules
|
|
110
|
-
*/
|
|
111
|
-
const crudSchemas = buildCrudSchemasFromModel(${name}, {
|
|
112
|
-
strictAdditionalProperties: true,
|
|
113
|
-
fieldRules: {
|
|
114
|
-
// Mark fields as system-managed (excluded from create/update)
|
|
115
|
-
// deletedAt: { systemManaged: true },
|
|
116
|
-
},
|
|
117
|
-
query: {
|
|
118
|
-
filterableFields: {
|
|
119
|
-
isActive: 'boolean',
|
|
120
|
-
createdAt: 'date',
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
// Schema options for controller
|
|
126
|
-
export const ${name.toLowerCase()}SchemaOptions${ts ? ": any" : ""} = {
|
|
127
|
-
query: {
|
|
128
|
-
filterableFields: {
|
|
129
|
-
isActive: 'boolean',
|
|
130
|
-
createdAt: 'date',
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
export default crudSchemas;
|
|
136
|
-
`,
|
|
137
|
-
resource: (name) => `/**
|
|
138
|
-
* ${name} Resource
|
|
139
|
-
* Generated by Arc CLI
|
|
140
|
-
*/
|
|
141
|
-
|
|
142
|
-
import { defineResource } from '@classytic/arc';
|
|
143
|
-
import { createAdapter } from '#shared/adapter.js';
|
|
144
|
-
import { publicReadPermissions } from '#shared/permissions.js';
|
|
145
|
-
import ${name} from './${name.toLowerCase()}.model.js';
|
|
146
|
-
import ${name.toLowerCase()}Repository from './${name.toLowerCase()}.repository.js';
|
|
147
|
-
import ${name.toLowerCase()}Controller from './${name.toLowerCase()}.controller.js';
|
|
148
|
-
|
|
149
|
-
const ${name.toLowerCase()}Resource = defineResource({
|
|
150
|
-
name: '${name.toLowerCase()}',
|
|
151
|
-
displayName: '${name}s',
|
|
152
|
-
prefix: '/${name.toLowerCase()}s',
|
|
153
|
-
|
|
154
|
-
adapter: createAdapter(${name}, ${name.toLowerCase()}Repository),
|
|
155
|
-
controller: ${name.toLowerCase()}Controller,
|
|
156
|
-
|
|
157
|
-
presets: ['softDelete'],
|
|
158
|
-
|
|
159
|
-
permissions: publicReadPermissions,
|
|
160
|
-
|
|
161
|
-
// Add custom routes here:
|
|
162
|
-
// additionalRoutes: [
|
|
163
|
-
// {
|
|
164
|
-
// method: 'GET',
|
|
165
|
-
// path: '/custom',
|
|
166
|
-
// summary: 'Custom endpoint',
|
|
167
|
-
// handler: async (request, reply) => { ... },
|
|
168
|
-
// },
|
|
169
|
-
// ],
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
export default ${name.toLowerCase()}Resource;
|
|
173
|
-
`,
|
|
174
|
-
test: (name) => `/**
|
|
175
|
-
* ${name} Tests
|
|
176
|
-
* Generated by Arc CLI
|
|
177
|
-
*/
|
|
178
|
-
|
|
179
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
180
|
-
import mongoose from 'mongoose';
|
|
181
|
-
import { createAppInstance } from '../src/app.js';
|
|
182
|
-
${ts ? "import type { FastifyInstance } from 'fastify';\n" : ""}
|
|
183
|
-
describe('${name} Resource', () => {
|
|
184
|
-
let app${ts ? ": FastifyInstance" : ""};
|
|
185
|
-
|
|
186
|
-
beforeAll(async () => {
|
|
187
|
-
const testDbUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/test-${name.toLowerCase()}';
|
|
188
|
-
await mongoose.connect(testDbUri);
|
|
189
|
-
app = await createAppInstance();
|
|
190
|
-
await app.ready();
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
afterAll(async () => {
|
|
194
|
-
await app.close();
|
|
195
|
-
await mongoose.connection.close();
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
describe('GET /${name.toLowerCase()}s', () => {
|
|
199
|
-
it('should return a list', async () => {
|
|
200
|
-
const response = await app.inject({
|
|
201
|
-
method: 'GET',
|
|
202
|
-
url: '/${name.toLowerCase()}s',
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
expect(response.statusCode).toBe(200);
|
|
206
|
-
const body = JSON.parse(response.body);
|
|
207
|
-
expect(body).toHaveProperty('docs');
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
`
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
async function generate(type, args) {
|
|
215
|
-
if (!type) {
|
|
216
|
-
console.error("Error: Missing type argument");
|
|
217
|
-
console.log("Usage: arc generate <resource|controller|model|repository|schemas> <name>");
|
|
218
|
-
process.exit(1);
|
|
219
|
-
}
|
|
220
|
-
const [name] = args;
|
|
221
|
-
if (!name) {
|
|
222
|
-
console.error("Error: Missing name argument");
|
|
223
|
-
console.log("Usage: arc generate <type> <name>");
|
|
224
|
-
console.log("Example: arc generate resource product");
|
|
225
|
-
process.exit(1);
|
|
226
|
-
}
|
|
227
|
-
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
228
|
-
const lowerName = name.toLowerCase();
|
|
229
|
-
const ts = isTypeScriptProject();
|
|
230
|
-
const ext = ts ? "ts" : "js";
|
|
231
|
-
const templates = getTemplates(ts);
|
|
232
|
-
const resourcePath = join(process.cwd(), "src", "resources", lowerName);
|
|
233
|
-
switch (type) {
|
|
234
|
-
case "resource":
|
|
235
|
-
case "r":
|
|
236
|
-
await generateResource(capitalizedName, lowerName, resourcePath, templates, ext);
|
|
237
|
-
break;
|
|
238
|
-
case "controller":
|
|
239
|
-
case "c":
|
|
240
|
-
await generateFile(capitalizedName, lowerName, resourcePath, "controller", templates.controller, ext);
|
|
241
|
-
break;
|
|
242
|
-
case "model":
|
|
243
|
-
case "m":
|
|
244
|
-
await generateFile(capitalizedName, lowerName, resourcePath, "model", templates.model, ext);
|
|
245
|
-
break;
|
|
246
|
-
case "repository":
|
|
247
|
-
case "repo":
|
|
248
|
-
await generateFile(capitalizedName, lowerName, resourcePath, "repository", templates.repository, ext);
|
|
249
|
-
break;
|
|
250
|
-
case "schemas":
|
|
251
|
-
case "s":
|
|
252
|
-
await generateFile(capitalizedName, lowerName, resourcePath, "schemas", templates.schemas, ext);
|
|
253
|
-
break;
|
|
254
|
-
default:
|
|
255
|
-
console.error(`Unknown type: ${type}`);
|
|
256
|
-
console.log("Available types: resource, controller, model, repository, schemas");
|
|
257
|
-
process.exit(1);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
async function generateResource(name, lowerName, resourcePath, templates, ext) {
|
|
261
|
-
console.log(`
|
|
262
|
-
📦 Generating resource: ${name}...
|
|
263
|
-
`);
|
|
264
|
-
if (!existsSync(resourcePath)) {
|
|
265
|
-
mkdirSync(resourcePath, { recursive: true });
|
|
266
|
-
console.log(` 📁 Created: src/resources/${lowerName}/`);
|
|
267
|
-
}
|
|
268
|
-
const files = {
|
|
269
|
-
[`${lowerName}.model.${ext}`]: templates.model(name),
|
|
270
|
-
[`${lowerName}.repository.${ext}`]: templates.repository(name),
|
|
271
|
-
[`${lowerName}.controller.${ext}`]: templates.controller(name),
|
|
272
|
-
[`${lowerName}.schemas.${ext}`]: templates.schemas(name),
|
|
273
|
-
[`${lowerName}.resource.${ext}`]: templates.resource(name)
|
|
274
|
-
};
|
|
275
|
-
for (const [filename, content] of Object.entries(files)) {
|
|
276
|
-
const filepath = join(resourcePath, filename);
|
|
277
|
-
if (existsSync(filepath)) {
|
|
278
|
-
console.warn(` ⚠ Skipped: ${filename} (already exists)`);
|
|
279
|
-
} else {
|
|
280
|
-
writeFileSync(filepath, content);
|
|
281
|
-
console.log(` ✅ Created: ${filename}`);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
const testsDir = join(process.cwd(), "tests");
|
|
285
|
-
if (!existsSync(testsDir)) {
|
|
286
|
-
mkdirSync(testsDir, { recursive: true });
|
|
287
|
-
}
|
|
288
|
-
const testPath = join(testsDir, `${lowerName}.test.${ext}`);
|
|
289
|
-
if (!existsSync(testPath)) {
|
|
290
|
-
writeFileSync(testPath, templates.test(name));
|
|
291
|
-
console.log(` ✅ Created: tests/${lowerName}.test.${ext}`);
|
|
292
|
-
}
|
|
293
|
-
console.log(`
|
|
294
|
-
╔═══════════════════════════════════════════════════════════════╗
|
|
295
|
-
║ ✅ Resource Generated! ║
|
|
296
|
-
╚═══════════════════════════════════════════════════════════════╝
|
|
297
|
-
|
|
298
|
-
Next steps:
|
|
299
|
-
|
|
300
|
-
1. Register in src/resources/index.${ext}:
|
|
301
|
-
import ${lowerName}Resource from './${lowerName}/${lowerName}.resource.js';
|
|
302
|
-
|
|
303
|
-
export const resources = [
|
|
304
|
-
// ... existing resources
|
|
305
|
-
${lowerName}Resource,
|
|
306
|
-
];
|
|
307
|
-
|
|
308
|
-
2. Customize the model schema in:
|
|
309
|
-
src/resources/${lowerName}/${lowerName}.model.${ext}
|
|
310
|
-
|
|
311
|
-
3. Run tests:
|
|
312
|
-
npm test
|
|
313
|
-
`);
|
|
314
|
-
}
|
|
315
|
-
async function generateFile(name, lowerName, resourcePath, fileType, template, ext) {
|
|
316
|
-
console.log(`
|
|
317
|
-
📦 Generating ${fileType}: ${name}...
|
|
318
|
-
`);
|
|
319
|
-
if (!existsSync(resourcePath)) {
|
|
320
|
-
mkdirSync(resourcePath, { recursive: true });
|
|
321
|
-
console.log(` 📁 Created: src/resources/${lowerName}/`);
|
|
322
|
-
}
|
|
323
|
-
const filename = `${lowerName}.${fileType}.${ext}`;
|
|
324
|
-
const filepath = join(resourcePath, filename);
|
|
325
|
-
if (existsSync(filepath)) {
|
|
326
|
-
console.error(` ❌ Error: ${filename} already exists`);
|
|
327
|
-
process.exit(1);
|
|
328
|
-
}
|
|
329
|
-
writeFileSync(filepath, template(name));
|
|
330
|
-
console.log(` ✅ Created: ${filename}`);
|
|
331
|
-
}
|
|
332
|
-
var generate_default = generate;
|
|
333
|
-
|
|
334
|
-
export { generate_default as default, generate };
|
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
import fp from 'fastify-plugin';
|
|
2
|
-
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __esm = (fn, res) => function __init() {
|
|
6
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
-
};
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// src/registry/ResourceRegistry.ts
|
|
14
|
-
var ResourceRegistry, registryKey, globalScope, resourceRegistry;
|
|
15
|
-
var init_ResourceRegistry = __esm({
|
|
16
|
-
"src/registry/ResourceRegistry.ts"() {
|
|
17
|
-
ResourceRegistry = class {
|
|
18
|
-
_resources;
|
|
19
|
-
_frozen;
|
|
20
|
-
constructor() {
|
|
21
|
-
this._resources = /* @__PURE__ */ new Map();
|
|
22
|
-
this._frozen = false;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Register a resource
|
|
26
|
-
*/
|
|
27
|
-
register(resource, options = {}) {
|
|
28
|
-
if (this._frozen) {
|
|
29
|
-
throw new Error(
|
|
30
|
-
`Registry frozen. Cannot register '${resource.name}' after startup.`
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
if (this._resources.has(resource.name)) {
|
|
34
|
-
throw new Error(`Resource '${resource.name}' already registered.`);
|
|
35
|
-
}
|
|
36
|
-
const entry = {
|
|
37
|
-
name: resource.name,
|
|
38
|
-
displayName: resource.displayName,
|
|
39
|
-
tag: resource.tag,
|
|
40
|
-
prefix: resource.prefix,
|
|
41
|
-
module: options.module ?? void 0,
|
|
42
|
-
adapter: resource.adapter ? {
|
|
43
|
-
type: resource.adapter.type,
|
|
44
|
-
name: resource.adapter.name
|
|
45
|
-
} : null,
|
|
46
|
-
permissions: resource.permissions,
|
|
47
|
-
presets: resource._appliedPresets ?? [],
|
|
48
|
-
routes: [],
|
|
49
|
-
// Populated later by getIntrospection()
|
|
50
|
-
additionalRoutes: resource.additionalRoutes.map((r) => ({
|
|
51
|
-
method: r.method,
|
|
52
|
-
path: r.path,
|
|
53
|
-
handler: typeof r.handler === "string" ? r.handler : r.handler.name || "anonymous",
|
|
54
|
-
summary: r.summary,
|
|
55
|
-
description: r.description,
|
|
56
|
-
permissions: r.permissions,
|
|
57
|
-
wrapHandler: r.wrapHandler,
|
|
58
|
-
schema: r.schema
|
|
59
|
-
// Include schema for OpenAPI docs
|
|
60
|
-
})),
|
|
61
|
-
events: Object.keys(resource.events ?? {}),
|
|
62
|
-
registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
63
|
-
disableDefaultRoutes: resource.disableDefaultRoutes,
|
|
64
|
-
openApiSchemas: options.openApiSchemas,
|
|
65
|
-
plugin: resource.toPlugin()
|
|
66
|
-
// Store plugin factory
|
|
67
|
-
};
|
|
68
|
-
this._resources.set(resource.name, entry);
|
|
69
|
-
return this;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Get resource by name
|
|
73
|
-
*/
|
|
74
|
-
get(name) {
|
|
75
|
-
return this._resources.get(name);
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Get all resources
|
|
79
|
-
*/
|
|
80
|
-
getAll() {
|
|
81
|
-
return Array.from(this._resources.values());
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Get resources by module
|
|
85
|
-
*/
|
|
86
|
-
getByModule(moduleName) {
|
|
87
|
-
return this.getAll().filter((r) => r.module === moduleName);
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Get resources by preset
|
|
91
|
-
*/
|
|
92
|
-
getByPreset(presetName) {
|
|
93
|
-
return this.getAll().filter((r) => r.presets.includes(presetName));
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Check if resource exists
|
|
97
|
-
*/
|
|
98
|
-
has(name) {
|
|
99
|
-
return this._resources.has(name);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Get registry statistics
|
|
103
|
-
*/
|
|
104
|
-
getStats() {
|
|
105
|
-
const resources = this.getAll();
|
|
106
|
-
const presetCounts = {};
|
|
107
|
-
for (const r of resources) {
|
|
108
|
-
for (const preset of r.presets) {
|
|
109
|
-
presetCounts[preset] = (presetCounts[preset] ?? 0) + 1;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return {
|
|
113
|
-
totalResources: resources.length,
|
|
114
|
-
byModule: this._groupBy(resources, "module"),
|
|
115
|
-
presetUsage: presetCounts,
|
|
116
|
-
totalRoutes: resources.reduce((sum, r) => {
|
|
117
|
-
const defaultRouteCount = r.disableDefaultRoutes ? 0 : 5;
|
|
118
|
-
return sum + (r.additionalRoutes?.length ?? 0) + defaultRouteCount;
|
|
119
|
-
}, 0),
|
|
120
|
-
totalEvents: resources.reduce((sum, r) => sum + (r.events?.length ?? 0), 0)
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Get full introspection data
|
|
125
|
-
*/
|
|
126
|
-
getIntrospection() {
|
|
127
|
-
return {
|
|
128
|
-
resources: this.getAll().map((r) => {
|
|
129
|
-
const defaultRoutes = r.disableDefaultRoutes ? [] : [
|
|
130
|
-
{ method: "GET", path: r.prefix, operation: "list" },
|
|
131
|
-
{ method: "GET", path: `${r.prefix}/:id`, operation: "get" },
|
|
132
|
-
{ method: "POST", path: r.prefix, operation: "create" },
|
|
133
|
-
{ method: "PATCH", path: `${r.prefix}/:id`, operation: "update" },
|
|
134
|
-
{ method: "DELETE", path: `${r.prefix}/:id`, operation: "delete" }
|
|
135
|
-
];
|
|
136
|
-
return {
|
|
137
|
-
name: r.name,
|
|
138
|
-
displayName: r.displayName,
|
|
139
|
-
prefix: r.prefix,
|
|
140
|
-
module: r.module,
|
|
141
|
-
presets: r.presets,
|
|
142
|
-
permissions: r.permissions,
|
|
143
|
-
routes: [
|
|
144
|
-
...defaultRoutes,
|
|
145
|
-
...r.additionalRoutes?.map((ar) => ({
|
|
146
|
-
method: ar.method,
|
|
147
|
-
path: `${r.prefix}${ar.path}`,
|
|
148
|
-
operation: typeof ar.handler === "string" ? ar.handler : "custom",
|
|
149
|
-
handler: typeof ar.handler === "string" ? ar.handler : void 0,
|
|
150
|
-
summary: ar.summary
|
|
151
|
-
})) ?? []
|
|
152
|
-
],
|
|
153
|
-
events: r.events
|
|
154
|
-
};
|
|
155
|
-
}),
|
|
156
|
-
stats: this.getStats(),
|
|
157
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Freeze registry (prevent further registrations)
|
|
162
|
-
*/
|
|
163
|
-
freeze() {
|
|
164
|
-
this._frozen = true;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Check if frozen
|
|
168
|
-
*/
|
|
169
|
-
isFrozen() {
|
|
170
|
-
return this._frozen;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Unfreeze registry (for testing)
|
|
174
|
-
*/
|
|
175
|
-
_unfreeze() {
|
|
176
|
-
this._frozen = false;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Clear all resources (for testing)
|
|
180
|
-
*/
|
|
181
|
-
_clear() {
|
|
182
|
-
this._resources.clear();
|
|
183
|
-
this._frozen = false;
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Group by key
|
|
187
|
-
*/
|
|
188
|
-
_groupBy(arr, key) {
|
|
189
|
-
const result = {};
|
|
190
|
-
for (const item of arr) {
|
|
191
|
-
const k = String(item[key] ?? "uncategorized");
|
|
192
|
-
result[k] = (result[k] ?? 0) + 1;
|
|
193
|
-
}
|
|
194
|
-
return result;
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
registryKey = /* @__PURE__ */ Symbol.for("arc.resourceRegistry");
|
|
198
|
-
globalScope = globalThis;
|
|
199
|
-
resourceRegistry = globalScope[registryKey] ?? new ResourceRegistry();
|
|
200
|
-
if (!globalScope[registryKey]) {
|
|
201
|
-
globalScope[registryKey] = resourceRegistry;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
var introspectionPlugin, introspectionPlugin_default;
|
|
206
|
-
var init_introspectionPlugin = __esm({
|
|
207
|
-
"src/registry/introspectionPlugin.ts"() {
|
|
208
|
-
init_ResourceRegistry();
|
|
209
|
-
introspectionPlugin = async (fastify, opts = {}) => {
|
|
210
|
-
const {
|
|
211
|
-
prefix = "/_resources",
|
|
212
|
-
authRoles = ["superadmin"],
|
|
213
|
-
enabled = process.env.NODE_ENV !== "production" || process.env.ENABLE_INTROSPECTION === "true"
|
|
214
|
-
} = opts;
|
|
215
|
-
if (!enabled) {
|
|
216
|
-
fastify.log?.info?.("Introspection plugin disabled");
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
const typedFastify = fastify;
|
|
220
|
-
const authMiddleware = authRoles.length > 0 && typedFastify.authenticate ? [
|
|
221
|
-
typedFastify.authenticate,
|
|
222
|
-
typedFastify.authorize?.(...authRoles)
|
|
223
|
-
].filter(Boolean) : [];
|
|
224
|
-
await fastify.register(async (instance) => {
|
|
225
|
-
instance.get(
|
|
226
|
-
"/",
|
|
227
|
-
{
|
|
228
|
-
preHandler: authMiddleware
|
|
229
|
-
},
|
|
230
|
-
async (_req, _reply) => {
|
|
231
|
-
return resourceRegistry.getIntrospection();
|
|
232
|
-
}
|
|
233
|
-
);
|
|
234
|
-
instance.get(
|
|
235
|
-
"/stats",
|
|
236
|
-
{
|
|
237
|
-
preHandler: authMiddleware
|
|
238
|
-
},
|
|
239
|
-
async (_req, _reply) => {
|
|
240
|
-
return resourceRegistry.getStats();
|
|
241
|
-
}
|
|
242
|
-
);
|
|
243
|
-
instance.get(
|
|
244
|
-
"/:name",
|
|
245
|
-
{
|
|
246
|
-
schema: {
|
|
247
|
-
params: {
|
|
248
|
-
type: "object",
|
|
249
|
-
properties: {
|
|
250
|
-
name: { type: "string" }
|
|
251
|
-
},
|
|
252
|
-
required: ["name"]
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
preHandler: authMiddleware
|
|
256
|
-
},
|
|
257
|
-
async (req, reply) => {
|
|
258
|
-
const resource = resourceRegistry.get(req.params.name);
|
|
259
|
-
if (!resource) {
|
|
260
|
-
return reply.code(404).send({
|
|
261
|
-
error: `Resource '${req.params.name}' not found`
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
return resource;
|
|
265
|
-
}
|
|
266
|
-
);
|
|
267
|
-
}, { prefix });
|
|
268
|
-
fastify.log?.info?.(`Introspection API at ${prefix}`);
|
|
269
|
-
};
|
|
270
|
-
introspectionPlugin_default = fp(introspectionPlugin, { name: "arc-introspection" });
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
// src/registry/index.ts
|
|
275
|
-
var registry_exports = {};
|
|
276
|
-
__export(registry_exports, {
|
|
277
|
-
ResourceRegistry: () => ResourceRegistry,
|
|
278
|
-
introspectionPlugin: () => introspectionPlugin_default,
|
|
279
|
-
introspectionPluginFn: () => introspectionPlugin,
|
|
280
|
-
resourceRegistry: () => resourceRegistry
|
|
281
|
-
});
|
|
282
|
-
var init_registry = __esm({
|
|
283
|
-
"src/registry/index.ts"() {
|
|
284
|
-
init_ResourceRegistry();
|
|
285
|
-
init_introspectionPlugin();
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
// src/cli/commands/introspect.ts
|
|
290
|
-
async function introspect(args) {
|
|
291
|
-
console.log("Introspecting Arc resources...\n");
|
|
292
|
-
try {
|
|
293
|
-
const { resourceRegistry: resourceRegistry2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
294
|
-
const resources = resourceRegistry2.getAll();
|
|
295
|
-
if (resources.length === 0) {
|
|
296
|
-
console.log("⚠️ No resources registered.");
|
|
297
|
-
console.log("\nTo introspect resources, you need to load them first:");
|
|
298
|
-
console.log(" arc introspect --entry ./index.js");
|
|
299
|
-
console.log("\nWhere index.js imports all your resource definitions.");
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
console.log(`Found ${resources.length} resource(s):
|
|
303
|
-
`);
|
|
304
|
-
resources.forEach((resource, index) => {
|
|
305
|
-
console.log(`${index + 1}. ${resource.name}`);
|
|
306
|
-
console.log(` Display Name: ${resource.displayName}`);
|
|
307
|
-
console.log(` Prefix: ${resource.prefix}`);
|
|
308
|
-
console.log(` Module: ${resource.module || "none"}`);
|
|
309
|
-
if (resource.permissions) {
|
|
310
|
-
console.log(` Permissions:`);
|
|
311
|
-
Object.entries(resource.permissions).forEach(([op, roles]) => {
|
|
312
|
-
console.log(` ${op}: [${roles.join(", ")}]`);
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
if (resource.presets && resource.presets.length > 0) {
|
|
316
|
-
console.log(` Presets: ${resource.presets.join(", ")}`);
|
|
317
|
-
}
|
|
318
|
-
if (resource.additionalRoutes && resource.additionalRoutes.length > 0) {
|
|
319
|
-
console.log(` Additional Routes: ${resource.additionalRoutes.length}`);
|
|
320
|
-
}
|
|
321
|
-
console.log("");
|
|
322
|
-
});
|
|
323
|
-
const stats = resourceRegistry2.getStats();
|
|
324
|
-
console.log("Summary:");
|
|
325
|
-
console.log(` Total Resources: ${stats.totalResources}`);
|
|
326
|
-
console.log(` With Presets: ${resources.filter((r) => r.presets?.length > 0).length}`);
|
|
327
|
-
console.log(
|
|
328
|
-
` With Custom Routes: ${resources.filter((r) => r.additionalRoutes && r.additionalRoutes.length > 0).length}`
|
|
329
|
-
);
|
|
330
|
-
} catch (error) {
|
|
331
|
-
console.error("Error:", error.message);
|
|
332
|
-
console.log("\nTip: Run this command after starting your application.");
|
|
333
|
-
process.exit(1);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
var introspect_default = introspect;
|
|
337
|
-
|
|
338
|
-
export { introspect_default as default, introspect };
|
package/dist/cli/index.d.ts
DELETED