@edium/halifax 2.2.3 → 2.3.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.
- package/CHANGELOG.md +133 -0
- package/README_AUTH.md +2 -2
- package/README_AUTOCRUD.md +5 -4
- package/README_CACHE.md +6 -0
- package/README_CLASSES.md +13 -6
- package/README_INTERFACES.md +13 -11
- package/README_OPENAPI.md +1 -1
- package/README_REPO_ADAPTERS.md +10 -0
- package/dist/adapters/orm/drizzle/DrizzleAdapter.d.ts +5 -0
- package/dist/adapters/orm/drizzle/DrizzleAdapter.js +9 -1
- package/dist/adapters/orm/prisma/PrismaAdapter.d.ts +1 -2
- package/dist/adapters/orm/prisma/PrismaAdapter.js +106 -34
- package/dist/adapters/orm/prisma/astToPrisma.js +6 -0
- package/dist/auth/strategies/JwtClaimsAuthStrategy.js +2 -8
- package/dist/auth/strategies/PassportStrategies.js +3 -9
- package/dist/auth/strategies/types.d.ts +7 -0
- package/dist/auth/strategies/types.js +13 -1
- package/dist/core/cache/CacheStore.d.ts +12 -0
- package/dist/core/cache/createCachingRepository.js +10 -1
- package/dist/core/cache/in-memory/InMemoryCacheStore.d.ts +14 -1
- package/dist/core/cache/in-memory/InMemoryCacheStore.js +29 -1
- package/dist/core/cache/redis/RedisCacheStore.d.ts +6 -0
- package/dist/core/cache/redis/RedisCacheStore.js +14 -0
- package/dist/core/cache/redis/RedisLikeClient.d.ts +2 -0
- package/dist/core/crudRouter.js +2 -20
- package/dist/core/fields.d.ts +11 -1
- package/dist/core/fields.js +19 -0
- package/dist/core/handlerUtils.d.ts +6 -0
- package/dist/core/handlerUtils.js +15 -11
- package/dist/core/handlers/create.js +3 -2
- package/dist/core/handlers/query.js +3 -5
- package/dist/core/handlers/readMany.js +3 -5
- package/dist/core/handlers/readOne.js +3 -6
- package/dist/core/handlers/updateMany.js +3 -4
- package/dist/core/queryString.d.ts +10 -0
- package/dist/core/queryString.js +23 -0
- package/dist/core/validation.js +5 -11
- package/dist/openapi/specGenerator.js +19 -19
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defaultCrudPermissions } from '../core/types.js';
|
|
2
|
-
import { mergeFieldDefinitions } from '../core/fields.js';
|
|
2
|
+
import { mergeFieldDefinitions, mergeRelationDefinitions, normalizeEnvelope } from '../core/fields.js';
|
|
3
3
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
4
4
|
// Exhaustive map from every FieldType to its JSON Schema type string.
|
|
5
5
|
// Adding a new FieldType causes a compile error here until the map is updated — no switch to edit.
|
|
@@ -21,9 +21,6 @@ function toPascalCase(routePrefix) {
|
|
|
21
21
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
22
22
|
.join('');
|
|
23
23
|
}
|
|
24
|
-
function normalizeEnvelope(value) {
|
|
25
|
-
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
26
|
-
}
|
|
27
24
|
function mergeFields(resource) {
|
|
28
25
|
const idField = resource.repository?.idField ?? 'id';
|
|
29
26
|
return mergeFieldDefinitions(resource).map((f) => ({
|
|
@@ -31,14 +28,6 @@ function mergeFields(resource) {
|
|
|
31
28
|
writable: f.name === idField ? f.writable === true : f.writable !== false
|
|
32
29
|
}));
|
|
33
30
|
}
|
|
34
|
-
function mergeRelations(resource) {
|
|
35
|
-
const byName = new Map();
|
|
36
|
-
for (const r of resource.repository?.relations ?? [])
|
|
37
|
-
byName.set(r.name, r);
|
|
38
|
-
for (const r of resource.relations ?? [])
|
|
39
|
-
byName.set(r.name, r);
|
|
40
|
-
return [...byName.values()];
|
|
41
|
-
}
|
|
42
31
|
// Wraps a schema under an envelope key if one is active.
|
|
43
32
|
function withEnvelope(schema, envelope) {
|
|
44
33
|
if (!envelope)
|
|
@@ -202,7 +191,7 @@ const sharedSchemas = {
|
|
|
202
191
|
' { "field": "published", "comparison": "=", "value": true },',
|
|
203
192
|
' { "field": "createdAt", "comparison": ">=", "value": "2024-01-01T00:00:00Z" }',
|
|
204
193
|
' ],',
|
|
205
|
-
' "orderBy": [{ "field": "createdAt", "
|
|
194
|
+
' "orderBy": [{ "field": "createdAt", "order": "DESC" }],',
|
|
206
195
|
' "limit": 20,',
|
|
207
196
|
' "offset": 0,',
|
|
208
197
|
' "fields": ["id", "title", "createdAt"],',
|
|
@@ -228,10 +217,10 @@ const sharedSchemas = {
|
|
|
228
217
|
description: 'Sort order. Multiple entries produce multi-column sorting.',
|
|
229
218
|
items: {
|
|
230
219
|
type: 'object',
|
|
231
|
-
required: ['field', '
|
|
220
|
+
required: ['field', 'order'],
|
|
232
221
|
properties: {
|
|
233
222
|
field: { type: 'string', description: 'Field name to sort by (must be sortable).' },
|
|
234
|
-
|
|
223
|
+
order: { type: 'string', enum: ['ASC', 'DESC'] }
|
|
235
224
|
}
|
|
236
225
|
}
|
|
237
226
|
},
|
|
@@ -240,7 +229,11 @@ const sharedSchemas = {
|
|
|
240
229
|
items: { type: 'string' },
|
|
241
230
|
description: 'Relation names to eagerly load (if the resource supports includes).'
|
|
242
231
|
},
|
|
243
|
-
distinct: {
|
|
232
|
+
distinct: {
|
|
233
|
+
type: 'array',
|
|
234
|
+
items: { type: 'string' },
|
|
235
|
+
description: 'Field names to de-duplicate results on (maps to SQL DISTINCT ON these columns).'
|
|
236
|
+
}
|
|
244
237
|
}
|
|
245
238
|
}
|
|
246
239
|
};
|
|
@@ -285,10 +278,17 @@ export function generateOpenApiSpec(resources, options = {}) {
|
|
|
285
278
|
: {})
|
|
286
279
|
}
|
|
287
280
|
};
|
|
281
|
+
// Note: resources here are the *raw* definitions as passed by the caller — they have NOT
|
|
282
|
+
// been through crudRouter's `normalizeResource()`. That means `mergeFields` and
|
|
283
|
+
// `mergeRelationDefinitions` below re-derive the same merged views that the router already
|
|
284
|
+
// computed at startup. This is intentional: the spec generator is a standalone function
|
|
285
|
+
// (called outside the router for static generation tooling), so it can't rely on the
|
|
286
|
+
// router's normalized state. If crudRouter ever caches normalized resources, pass them
|
|
287
|
+
// here instead to avoid the duplicate merge work.
|
|
288
288
|
for (const resource of resources) {
|
|
289
289
|
const permissions = { ...defaultCrudPermissions, ...resource.permissions };
|
|
290
290
|
const fields = mergeFields(resource);
|
|
291
|
-
const relations =
|
|
291
|
+
const relations = mergeRelationDefinitions(resource);
|
|
292
292
|
const idField = resource.repository?.idField ?? 'id';
|
|
293
293
|
const schemaBase = toPascalCase(resource.routePrefix);
|
|
294
294
|
const tag = resource.name ?? schemaBase;
|
|
@@ -502,10 +502,10 @@ export function generateOpenApiSpec(resources, options = {}) {
|
|
|
502
502
|
type: 'array',
|
|
503
503
|
items: {
|
|
504
504
|
type: 'object',
|
|
505
|
-
required: ['field', '
|
|
505
|
+
required: ['field', 'order'],
|
|
506
506
|
properties: {
|
|
507
507
|
field: { type: 'string' },
|
|
508
|
-
|
|
508
|
+
order: { type: 'string', enum: ['ASC', 'DESC'] }
|
|
509
509
|
}
|
|
510
510
|
}
|
|
511
511
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edium/halifax",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Auto-generate type-safe REST CRUD APIs from your data models. Adapter-driven: Express/Fastify/HyperExpress, Prisma (PostgreSQL, MySQL, MariaDB, SQL Server, CockroachDB, SQLite), JWT/API-key auth, multi-tenancy, a dynamic query builder, and pluggable Redis caching.",
|
|
5
5
|
"author": "David LaTour <david@edium.com>",
|
|
6
6
|
"homepage": "https://github.com/splayfee/halifax#readme",
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
],
|
|
167
167
|
"dependencies": {
|
|
168
168
|
"uuid": "^14.0.0",
|
|
169
|
-
"@edium/halifax-types": "2.
|
|
169
|
+
"@edium/halifax-types": "2.3.0"
|
|
170
170
|
},
|
|
171
171
|
"scripts": {
|
|
172
172
|
"build": "rm -rf dist && tsc --build && tsc-alias",
|