@postxl/schema 1.5.0 → 1.7.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/dist/extract-inline-enums.d.ts +19 -0
- package/dist/extract-inline-enums.js +195 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/model/model.json-decoder.d.ts +23 -0
- package/dist/model/model.json-decoder.js +2 -0
- package/dist/model/model.transformer.d.ts +92 -0
- package/dist/model/model.types.d.ts +2 -0
- package/dist/project-schema/project-schema.auth.d.ts +50 -0
- package/dist/project-schema/project-schema.auth.js +59 -0
- package/dist/project-schema/project-schema.json-decoder.d.ts +85 -1
- package/dist/project-schema/project-schema.json-decoder.js +21 -7
- package/dist/project-schema/project-schema.transformer.d.ts +118 -2
- package/dist/project-schema/project-schema.transformer.js +37 -8
- package/dist/project-schema/project-schema.types.d.ts +9 -0
- package/package.json +2 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts inline enum definitions from model fields and promotes them to top-level enums.
|
|
3
|
+
*
|
|
4
|
+
* When a field's `type` is an object or array (instead of a string), it is treated as an
|
|
5
|
+
* inline enum definition. The enum members are extracted, a name is generated as
|
|
6
|
+
* `{ModelName}{PascalCase(fieldName)}`, and the field's `type` is replaced with that name.
|
|
7
|
+
*
|
|
8
|
+
* Inline enum format examples:
|
|
9
|
+
*
|
|
10
|
+
* Object format:
|
|
11
|
+
* "type": { "Draft": "description", "Published": "description" }
|
|
12
|
+
*
|
|
13
|
+
* Array format:
|
|
14
|
+
* "type": ["Draft", { "value": "Published", "description": "..." }]
|
|
15
|
+
*
|
|
16
|
+
* The field's `description` is copied to the enum and also kept on the field.
|
|
17
|
+
* The enum's database schema is derived from the parent model's `schema` property.
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractInlineEnumDefinitions(input: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractInlineEnumDefinitions = extractInlineEnumDefinitions;
|
|
4
|
+
const utils_1 = require("@postxl/utils");
|
|
5
|
+
/**
|
|
6
|
+
* Extracts inline enum definitions from model fields and promotes them to top-level enums.
|
|
7
|
+
*
|
|
8
|
+
* When a field's `type` is an object or array (instead of a string), it is treated as an
|
|
9
|
+
* inline enum definition. The enum members are extracted, a name is generated as
|
|
10
|
+
* `{ModelName}{PascalCase(fieldName)}`, and the field's `type` is replaced with that name.
|
|
11
|
+
*
|
|
12
|
+
* Inline enum format examples:
|
|
13
|
+
*
|
|
14
|
+
* Object format:
|
|
15
|
+
* "type": { "Draft": "description", "Published": "description" }
|
|
16
|
+
*
|
|
17
|
+
* Array format:
|
|
18
|
+
* "type": ["Draft", { "value": "Published", "description": "..." }]
|
|
19
|
+
*
|
|
20
|
+
* The field's `description` is copied to the enum and also kept on the field.
|
|
21
|
+
* The enum's database schema is derived from the parent model's `schema` property.
|
|
22
|
+
*/
|
|
23
|
+
function extractInlineEnumDefinitions(input) {
|
|
24
|
+
const models = input.models;
|
|
25
|
+
if (!models || typeof models !== 'object') {
|
|
26
|
+
return input;
|
|
27
|
+
}
|
|
28
|
+
const extractedEnums = [];
|
|
29
|
+
const existingEnumNames = getExistingEnumNames(input.enums);
|
|
30
|
+
const generatedEnumNames = new Set();
|
|
31
|
+
let modelsModified = false;
|
|
32
|
+
const createProcessField = (modelSchema) => (modelName, fieldName, fieldDef) => {
|
|
33
|
+
const type = fieldDef.type;
|
|
34
|
+
if (type === undefined || type === null || typeof type === 'string') {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
// type is an object or array — this is an inline enum definition
|
|
38
|
+
const enumName = modelName + (0, utils_1.toPascalCase)(fieldName);
|
|
39
|
+
if (existingEnumNames.has(enumName)) {
|
|
40
|
+
throw new Error(`Inline enum "${enumName}" generated from field "${modelName}.${fieldName}" conflicts with an existing top-level enum of the same name. ` +
|
|
41
|
+
`Rename the field or define the enum in the top-level "enums" section instead.`);
|
|
42
|
+
}
|
|
43
|
+
if (generatedEnumNames.has(enumName)) {
|
|
44
|
+
throw new Error(`Inline enum "${enumName}" generated from field "${modelName}.${fieldName}" conflicts with another inline enum of the same name. ` +
|
|
45
|
+
`Rename one of the fields to avoid the collision.`);
|
|
46
|
+
}
|
|
47
|
+
generatedEnumNames.add(enumName);
|
|
48
|
+
const enumDef = {
|
|
49
|
+
name: enumName,
|
|
50
|
+
members: type,
|
|
51
|
+
};
|
|
52
|
+
// Copy description to the enum (it stays on the field as well)
|
|
53
|
+
if (fieldDef.description !== undefined) {
|
|
54
|
+
enumDef.description = fieldDef.description;
|
|
55
|
+
}
|
|
56
|
+
// Use the parent model's schema for the enum
|
|
57
|
+
if (modelSchema !== undefined) {
|
|
58
|
+
enumDef.schema = modelSchema;
|
|
59
|
+
}
|
|
60
|
+
extractedEnums.push(enumDef);
|
|
61
|
+
// Build the modified field: replace type with enum name, remove schema (not a field property)
|
|
62
|
+
const modifiedField = {};
|
|
63
|
+
for (const [key, value] of Object.entries(fieldDef)) {
|
|
64
|
+
if (key === 'type') {
|
|
65
|
+
modifiedField.type = enumName;
|
|
66
|
+
}
|
|
67
|
+
else if (key === 'schema') {
|
|
68
|
+
// schema is not a field property — skip it
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
modifiedField[key] = value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return modifiedField;
|
|
76
|
+
};
|
|
77
|
+
let newModels = models;
|
|
78
|
+
if (Array.isArray(models)) {
|
|
79
|
+
const modifiedModels = models.map((model) => {
|
|
80
|
+
if (!model || typeof model !== 'object' || !model.name) {
|
|
81
|
+
return model;
|
|
82
|
+
}
|
|
83
|
+
const modelSchema = model.schema;
|
|
84
|
+
const newFields = processFields(model.name, model.fields, createProcessField(modelSchema));
|
|
85
|
+
if (newFields === undefined) {
|
|
86
|
+
return model;
|
|
87
|
+
}
|
|
88
|
+
modelsModified = true;
|
|
89
|
+
return { ...model, fields: newFields };
|
|
90
|
+
});
|
|
91
|
+
if (modelsModified) {
|
|
92
|
+
newModels = modifiedModels;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const modifiedModels = {};
|
|
97
|
+
for (const [modelName, modelDef] of Object.entries(models)) {
|
|
98
|
+
if (!modelDef || typeof modelDef !== 'object') {
|
|
99
|
+
modifiedModels[modelName] = modelDef;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const model = modelDef;
|
|
103
|
+
const modelSchema = model.schema;
|
|
104
|
+
const newFields = processFields(modelName, model.fields, createProcessField(modelSchema));
|
|
105
|
+
if (newFields === undefined) {
|
|
106
|
+
modifiedModels[modelName] = modelDef;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
modelsModified = true;
|
|
110
|
+
modifiedModels[modelName] = { ...model, fields: newFields };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (modelsModified) {
|
|
114
|
+
newModels = modifiedModels;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (extractedEnums.length === 0) {
|
|
118
|
+
return input;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
...input,
|
|
122
|
+
models: newModels,
|
|
123
|
+
enums: mergeEnums(input.enums, extractedEnums),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function processFields(modelName, fields, processField) {
|
|
127
|
+
if (!fields || typeof fields !== 'object') {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
let anyModified = false;
|
|
131
|
+
if (Array.isArray(fields)) {
|
|
132
|
+
const modifiedFields = fields.map((field) => {
|
|
133
|
+
if (!field || typeof field !== 'object' || !field.name) {
|
|
134
|
+
return field;
|
|
135
|
+
}
|
|
136
|
+
const result = processField(modelName, field.name, field);
|
|
137
|
+
if (result === undefined) {
|
|
138
|
+
return field;
|
|
139
|
+
}
|
|
140
|
+
anyModified = true;
|
|
141
|
+
return result;
|
|
142
|
+
});
|
|
143
|
+
return anyModified ? modifiedFields : undefined;
|
|
144
|
+
}
|
|
145
|
+
const modifiedFields = {};
|
|
146
|
+
for (const [fieldName, fieldDef] of Object.entries(fields)) {
|
|
147
|
+
if (!fieldDef || typeof fieldDef !== 'object') {
|
|
148
|
+
modifiedFields[fieldName] = fieldDef;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const result = processField(modelName, fieldName, fieldDef);
|
|
152
|
+
if (result === undefined) {
|
|
153
|
+
modifiedFields[fieldName] = fieldDef;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
anyModified = true;
|
|
157
|
+
modifiedFields[fieldName] = result;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return anyModified ? modifiedFields : undefined;
|
|
161
|
+
}
|
|
162
|
+
function getExistingEnumNames(enums) {
|
|
163
|
+
const names = new Set();
|
|
164
|
+
if (Array.isArray(enums)) {
|
|
165
|
+
for (const e of enums) {
|
|
166
|
+
if (e && typeof e === 'object' && typeof e.name === 'string') {
|
|
167
|
+
names.add(e.name);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else if (enums && typeof enums === 'object') {
|
|
172
|
+
for (const key of Object.keys(enums)) {
|
|
173
|
+
names.add(key);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return names;
|
|
177
|
+
}
|
|
178
|
+
function mergeEnums(existing, extracted) {
|
|
179
|
+
if (existing === undefined || existing === null) {
|
|
180
|
+
return extracted;
|
|
181
|
+
}
|
|
182
|
+
if (Array.isArray(existing)) {
|
|
183
|
+
return [...existing, ...extracted];
|
|
184
|
+
}
|
|
185
|
+
if (typeof existing === 'object') {
|
|
186
|
+
// Existing enums are in object format — convert extracted enums to object format and merge
|
|
187
|
+
const result = { ...existing };
|
|
188
|
+
for (const enumDef of extracted) {
|
|
189
|
+
const { name, ...rest } = enumDef;
|
|
190
|
+
result[name] = rest;
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
return existing;
|
|
195
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { zProjectSchema } from './project-schema/project-schema.transformer';
|
|
2
|
+
export * from './project-schema/project-schema.auth';
|
|
2
3
|
export * from './project-schema/project-schema.brands';
|
|
3
4
|
export * from './project-schema/project-schema.types';
|
|
4
5
|
export type { ProjectSchemaJSON } from './project-schema/project-schema.json-decoder';
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.zProjectSchema = void 0;
|
|
18
18
|
var project_schema_transformer_1 = require("./project-schema/project-schema.transformer");
|
|
19
19
|
Object.defineProperty(exports, "zProjectSchema", { enumerable: true, get: function () { return project_schema_transformer_1.zProjectSchema; } });
|
|
20
|
+
__exportStar(require("./project-schema/project-schema.auth"), exports);
|
|
20
21
|
__exportStar(require("./project-schema/project-schema.brands"), exports);
|
|
21
22
|
__exportStar(require("./project-schema/project-schema.types"), exports);
|
|
22
23
|
__exportStar(require("./enum/enum.defaults"), exports);
|
|
@@ -4,6 +4,29 @@ export declare const zModelJSON: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.Z
|
|
|
4
4
|
name: z.ZodString;
|
|
5
5
|
description: z.ZodOptional<z.ZodString>;
|
|
6
6
|
isReadonly: z.ZodOptional<z.ZodBoolean>;
|
|
7
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
8
|
+
read: z.ZodOptional<z.ZodObject<{
|
|
9
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>>;
|
|
11
|
+
write: z.ZodOptional<z.ZodObject<{
|
|
12
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
13
|
+
}, z.core.$strip>>;
|
|
14
|
+
create: z.ZodOptional<z.ZodObject<{
|
|
15
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
16
|
+
}, z.core.$strip>>;
|
|
17
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
19
|
+
}, z.core.$strip>>;
|
|
20
|
+
delete: z.ZodOptional<z.ZodObject<{
|
|
21
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
24
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
25
|
+
}, z.core.$strip>>>;
|
|
26
|
+
adminUi: z.ZodOptional<z.ZodObject<{
|
|
27
|
+
visibleFor: z.ZodArray<z.ZodString>;
|
|
28
|
+
}, z.core.$strip>>;
|
|
29
|
+
}, z.core.$strip>>;
|
|
7
30
|
schema: z.ZodOptional<z.ZodString>;
|
|
8
31
|
databaseName: z.ZodOptional<z.ZodString>;
|
|
9
32
|
excelName: z.ZodOptional<z.ZodString>;
|
|
@@ -5,6 +5,7 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const utils_1 = require("@postxl/utils");
|
|
6
6
|
const brands_1 = require("../field/shared/brands");
|
|
7
7
|
const normalize_named_collection_1 = require("../normalize-named-collection");
|
|
8
|
+
const project_schema_auth_1 = require("../project-schema/project-schema.auth");
|
|
8
9
|
exports.zModelNameJSON = zod_1.z
|
|
9
10
|
//
|
|
10
11
|
.string()
|
|
@@ -39,6 +40,7 @@ exports.zModelJSON = zod_1.z.preprocess((input) => {
|
|
|
39
40
|
.boolean()
|
|
40
41
|
.optional()
|
|
41
42
|
.describe(`Indicates if the model is readonly. To be used for system models that should not be editable through actions (e.g. Mutation, Action).`),
|
|
43
|
+
auth: project_schema_auth_1.zAuthRuleSetJSON.optional().describe('Authorization rules for this model.'),
|
|
42
44
|
//
|
|
43
45
|
schema: zod_1.z
|
|
44
46
|
//
|
|
@@ -21,6 +21,29 @@ export declare function modelJSONTransformer(input: ModelJSON, ctx: z.Refinement
|
|
|
21
21
|
seed: number;
|
|
22
22
|
items: number;
|
|
23
23
|
};
|
|
24
|
+
auth?: {
|
|
25
|
+
read?: {
|
|
26
|
+
anyRole: string[];
|
|
27
|
+
} | undefined;
|
|
28
|
+
write?: {
|
|
29
|
+
anyRole: string[];
|
|
30
|
+
} | undefined;
|
|
31
|
+
create?: {
|
|
32
|
+
anyRole: string[];
|
|
33
|
+
} | undefined;
|
|
34
|
+
update?: {
|
|
35
|
+
anyRole: string[];
|
|
36
|
+
} | undefined;
|
|
37
|
+
delete?: {
|
|
38
|
+
anyRole: string[];
|
|
39
|
+
} | undefined;
|
|
40
|
+
actions?: Record<string, {
|
|
41
|
+
anyRole: string[];
|
|
42
|
+
}> | undefined;
|
|
43
|
+
adminUi?: {
|
|
44
|
+
visibleFor: string[];
|
|
45
|
+
} | undefined;
|
|
46
|
+
} | undefined;
|
|
24
47
|
source?: Record<string, unknown> | undefined;
|
|
25
48
|
};
|
|
26
49
|
export type ModelEnriched = ReturnType<typeof modelJSONTransformer>;
|
|
@@ -41,6 +64,29 @@ declare function addDefaults({ description, fields, standardFields, seed, faker,
|
|
|
41
64
|
items: number;
|
|
42
65
|
};
|
|
43
66
|
name: string;
|
|
67
|
+
auth?: {
|
|
68
|
+
read?: {
|
|
69
|
+
anyRole: string[];
|
|
70
|
+
} | undefined;
|
|
71
|
+
write?: {
|
|
72
|
+
anyRole: string[];
|
|
73
|
+
} | undefined;
|
|
74
|
+
create?: {
|
|
75
|
+
anyRole: string[];
|
|
76
|
+
} | undefined;
|
|
77
|
+
update?: {
|
|
78
|
+
anyRole: string[];
|
|
79
|
+
} | undefined;
|
|
80
|
+
delete?: {
|
|
81
|
+
anyRole: string[];
|
|
82
|
+
} | undefined;
|
|
83
|
+
actions?: Record<string, {
|
|
84
|
+
anyRole: string[];
|
|
85
|
+
}> | undefined;
|
|
86
|
+
adminUi?: {
|
|
87
|
+
visibleFor: string[];
|
|
88
|
+
} | undefined;
|
|
89
|
+
} | undefined;
|
|
44
90
|
schema?: string | undefined;
|
|
45
91
|
defaultField?: string | undefined;
|
|
46
92
|
labelField?: string | undefined;
|
|
@@ -69,6 +115,29 @@ declare function brandModel({ name, schema, databaseName, standardFields, defaul
|
|
|
69
115
|
seed: number;
|
|
70
116
|
items: number;
|
|
71
117
|
};
|
|
118
|
+
auth?: {
|
|
119
|
+
read?: {
|
|
120
|
+
anyRole: string[];
|
|
121
|
+
} | undefined;
|
|
122
|
+
write?: {
|
|
123
|
+
anyRole: string[];
|
|
124
|
+
} | undefined;
|
|
125
|
+
create?: {
|
|
126
|
+
anyRole: string[];
|
|
127
|
+
} | undefined;
|
|
128
|
+
update?: {
|
|
129
|
+
anyRole: string[];
|
|
130
|
+
} | undefined;
|
|
131
|
+
delete?: {
|
|
132
|
+
anyRole: string[];
|
|
133
|
+
} | undefined;
|
|
134
|
+
actions?: Record<string, {
|
|
135
|
+
anyRole: string[];
|
|
136
|
+
}> | undefined;
|
|
137
|
+
adminUi?: {
|
|
138
|
+
visibleFor: string[];
|
|
139
|
+
} | undefined;
|
|
140
|
+
} | undefined;
|
|
72
141
|
source?: Record<string, unknown> | undefined;
|
|
73
142
|
};
|
|
74
143
|
type BrandedModel = ReturnType<typeof brandModel>;
|
|
@@ -93,6 +162,29 @@ declare function combineFields({ fields, standardFields, ...model }: BrandedMode
|
|
|
93
162
|
seed: number;
|
|
94
163
|
items: number;
|
|
95
164
|
};
|
|
165
|
+
auth?: {
|
|
166
|
+
read?: {
|
|
167
|
+
anyRole: string[];
|
|
168
|
+
} | undefined;
|
|
169
|
+
write?: {
|
|
170
|
+
anyRole: string[];
|
|
171
|
+
} | undefined;
|
|
172
|
+
create?: {
|
|
173
|
+
anyRole: string[];
|
|
174
|
+
} | undefined;
|
|
175
|
+
update?: {
|
|
176
|
+
anyRole: string[];
|
|
177
|
+
} | undefined;
|
|
178
|
+
delete?: {
|
|
179
|
+
anyRole: string[];
|
|
180
|
+
} | undefined;
|
|
181
|
+
actions?: Record<string, {
|
|
182
|
+
anyRole: string[];
|
|
183
|
+
}> | undefined;
|
|
184
|
+
adminUi?: {
|
|
185
|
+
visibleFor: string[];
|
|
186
|
+
} | undefined;
|
|
187
|
+
} | undefined;
|
|
96
188
|
source?: Record<string, unknown> | undefined;
|
|
97
189
|
};
|
|
98
190
|
export type CombinedFields = ReturnType<typeof combineFields>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as Field from '../field';
|
|
2
|
+
import { AuthRuleSet } from '../project-schema/project-schema.auth';
|
|
2
3
|
import { DatabaseSchemaName } from '../project-schema/project-schema.brands';
|
|
3
4
|
import * as Branded from './model.brands';
|
|
4
5
|
export type Models = Map<Branded.ModelName, Model>;
|
|
@@ -39,6 +40,7 @@ export type Model = {
|
|
|
39
40
|
*/
|
|
40
41
|
items: number;
|
|
41
42
|
};
|
|
43
|
+
auth?: AuthRuleSet;
|
|
42
44
|
};
|
|
43
45
|
export type ModelIndex = Field.FieldName[];
|
|
44
46
|
export type Seed = Record<string, unknown>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const zAuthRoleRuleJSON: z.ZodObject<{
|
|
3
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
4
|
+
}, z.core.$strip>;
|
|
5
|
+
export declare const zAuthRuleSetJSON: z.ZodObject<{
|
|
6
|
+
read: z.ZodOptional<z.ZodObject<{
|
|
7
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
8
|
+
}, z.core.$strip>>;
|
|
9
|
+
write: z.ZodOptional<z.ZodObject<{
|
|
10
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
11
|
+
}, z.core.$strip>>;
|
|
12
|
+
create: z.ZodOptional<z.ZodObject<{
|
|
13
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>>;
|
|
15
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
16
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
17
|
+
}, z.core.$strip>>;
|
|
18
|
+
delete: z.ZodOptional<z.ZodObject<{
|
|
19
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
22
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
23
|
+
}, z.core.$strip>>>;
|
|
24
|
+
adminUi: z.ZodOptional<z.ZodObject<{
|
|
25
|
+
visibleFor: z.ZodArray<z.ZodString>;
|
|
26
|
+
}, z.core.$strip>>;
|
|
27
|
+
}, z.core.$strip>;
|
|
28
|
+
export declare const zAuthScopeRuleSetJSON: z.ZodObject<{
|
|
29
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
30
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>>>;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
export declare const zProjectAuthJSON: z.ZodObject<{
|
|
34
|
+
provider: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"keycloak">>>;
|
|
35
|
+
roleClaimPath: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
36
|
+
defaultDeny: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
37
|
+
scopes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
38
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
39
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
40
|
+
}, z.core.$strip>>>;
|
|
41
|
+
}, z.core.$strip>>>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
export type AuthRoleRuleJSON = z.infer<typeof zAuthRoleRuleJSON>;
|
|
44
|
+
export type AuthRuleSetJSON = z.infer<typeof zAuthRuleSetJSON>;
|
|
45
|
+
export type AuthScopeRuleSetJSON = z.infer<typeof zAuthScopeRuleSetJSON>;
|
|
46
|
+
export type ProjectAuthJSON = z.infer<typeof zProjectAuthJSON>;
|
|
47
|
+
export type AuthRoleRule = AuthRoleRuleJSON;
|
|
48
|
+
export type AuthRuleSet = AuthRuleSetJSON;
|
|
49
|
+
export type AuthScopeRuleSet = AuthScopeRuleSetJSON;
|
|
50
|
+
export type ProjectAuth = ProjectAuthJSON;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.zProjectAuthJSON = exports.zAuthScopeRuleSetJSON = exports.zAuthRuleSetJSON = exports.zAuthRoleRuleJSON = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const zNonEmptyRole = zod_1.z.string().min(1, { error: 'Role must not be empty.' });
|
|
6
|
+
exports.zAuthRoleRuleJSON = zod_1.z.object({
|
|
7
|
+
anyRole: zod_1.z
|
|
8
|
+
.array(zNonEmptyRole)
|
|
9
|
+
.min(1, { error: 'anyRole must contain at least one role.' })
|
|
10
|
+
.describe('Allow access when the user has at least one of the listed roles.'),
|
|
11
|
+
});
|
|
12
|
+
exports.zAuthRuleSetJSON = zod_1.z.object({
|
|
13
|
+
read: exports.zAuthRoleRuleJSON.optional().describe('Role rule for read access to model data.'),
|
|
14
|
+
write: exports.zAuthRoleRuleJSON.optional().describe('Role rule for write access shorthand (create, update, delete).'),
|
|
15
|
+
create: exports.zAuthRoleRuleJSON.optional().describe('Role rule for create access.'),
|
|
16
|
+
update: exports.zAuthRoleRuleJSON.optional().describe('Role rule for update access.'),
|
|
17
|
+
delete: exports.zAuthRoleRuleJSON.optional().describe('Role rule for delete access.'),
|
|
18
|
+
actions: zod_1.z
|
|
19
|
+
.record(zod_1.z.string().min(1), exports.zAuthRoleRuleJSON)
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Role rules for model actions. Keys are action names, e.g. "publish".'),
|
|
22
|
+
adminUi: zod_1.z
|
|
23
|
+
.object({
|
|
24
|
+
visibleFor: zod_1.z
|
|
25
|
+
.array(zNonEmptyRole)
|
|
26
|
+
.min(1, { error: 'visibleFor must contain at least one role.' })
|
|
27
|
+
.describe('Roles that can see and access this model in the Admin UI.'),
|
|
28
|
+
})
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Admin UI visibility settings for this schema/model.'),
|
|
31
|
+
});
|
|
32
|
+
exports.zAuthScopeRuleSetJSON = zod_1.z.object({
|
|
33
|
+
actions: zod_1.z
|
|
34
|
+
.record(zod_1.z.string().min(1), exports.zAuthRoleRuleJSON)
|
|
35
|
+
.optional()
|
|
36
|
+
.describe('Role rules for actions within this scope. Keys are action names or "*".'),
|
|
37
|
+
});
|
|
38
|
+
exports.zProjectAuthJSON = zod_1.z.object({
|
|
39
|
+
provider: zod_1.z
|
|
40
|
+
.literal('keycloak')
|
|
41
|
+
.optional()
|
|
42
|
+
.default('keycloak')
|
|
43
|
+
.describe('Authentication/authorization provider used by generated projects.'),
|
|
44
|
+
roleClaimPath: zod_1.z
|
|
45
|
+
.string()
|
|
46
|
+
.min(1)
|
|
47
|
+
.optional()
|
|
48
|
+
.default('realm_access.roles')
|
|
49
|
+
.describe('JWT claim path that contains roles, e.g. "realm_access.roles".'),
|
|
50
|
+
defaultDeny: zod_1.z
|
|
51
|
+
.boolean()
|
|
52
|
+
.optional()
|
|
53
|
+
.default(true)
|
|
54
|
+
.describe('If true, access is denied when no matching auth rule is configured.'),
|
|
55
|
+
scopes: zod_1.z
|
|
56
|
+
.record(zod_1.z.string().min(1), exports.zAuthScopeRuleSetJSON)
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Authorization rules for non-model action scopes (for example "import").'),
|
|
59
|
+
});
|
|
@@ -1,19 +1,103 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const zSchemaName: z.ZodString;
|
|
3
|
+
export declare const zSchemaJSON: z.ZodObject<{
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
6
|
+
read: z.ZodOptional<z.ZodObject<{
|
|
7
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
8
|
+
}, z.core.$strip>>;
|
|
9
|
+
write: z.ZodOptional<z.ZodObject<{
|
|
10
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
11
|
+
}, z.core.$strip>>;
|
|
12
|
+
create: z.ZodOptional<z.ZodObject<{
|
|
13
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>>;
|
|
15
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
16
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
17
|
+
}, z.core.$strip>>;
|
|
18
|
+
delete: z.ZodOptional<z.ZodObject<{
|
|
19
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
22
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
23
|
+
}, z.core.$strip>>>;
|
|
24
|
+
adminUi: z.ZodOptional<z.ZodObject<{
|
|
25
|
+
visibleFor: z.ZodArray<z.ZodString>;
|
|
26
|
+
}, z.core.$strip>>;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
}, z.core.$strip>;
|
|
3
29
|
export declare const zProjectSchemaJSON: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
|
|
4
30
|
name: z.ZodString;
|
|
5
31
|
slug: z.ZodString;
|
|
6
32
|
description: z.ZodOptional<z.ZodString>;
|
|
7
33
|
projectType: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"standalone">, z.ZodLiteral<"workspace">]>>>;
|
|
8
34
|
version: z.ZodOptional<z.ZodString>;
|
|
9
|
-
schemas: z.ZodOptional<z.ZodArray<z.ZodString
|
|
35
|
+
schemas: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
36
|
+
name: z.ZodString;
|
|
37
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
38
|
+
read: z.ZodOptional<z.ZodObject<{
|
|
39
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
40
|
+
}, z.core.$strip>>;
|
|
41
|
+
write: z.ZodOptional<z.ZodObject<{
|
|
42
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
create: z.ZodOptional<z.ZodObject<{
|
|
45
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
46
|
+
}, z.core.$strip>>;
|
|
47
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
49
|
+
}, z.core.$strip>>;
|
|
50
|
+
delete: z.ZodOptional<z.ZodObject<{
|
|
51
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
54
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
55
|
+
}, z.core.$strip>>>;
|
|
56
|
+
adminUi: z.ZodOptional<z.ZodObject<{
|
|
57
|
+
visibleFor: z.ZodArray<z.ZodString>;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
}, z.core.$strip>>;
|
|
60
|
+
}, z.core.$strip>]>>>;
|
|
10
61
|
defaultSchema: z.ZodOptional<z.ZodString>;
|
|
62
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
63
|
+
provider: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"keycloak">>>;
|
|
64
|
+
roleClaimPath: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
65
|
+
defaultDeny: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
66
|
+
scopes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
67
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
68
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
69
|
+
}, z.core.$strip>>>;
|
|
70
|
+
}, z.core.$strip>>>;
|
|
71
|
+
}, z.core.$strip>>;
|
|
11
72
|
systemUser: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
12
73
|
standardModels: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
13
74
|
models: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
|
|
14
75
|
name: z.ZodString;
|
|
15
76
|
description: z.ZodOptional<z.ZodString>;
|
|
16
77
|
isReadonly: z.ZodOptional<z.ZodBoolean>;
|
|
78
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
79
|
+
read: z.ZodOptional<z.ZodObject<{
|
|
80
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
81
|
+
}, z.core.$strip>>;
|
|
82
|
+
write: z.ZodOptional<z.ZodObject<{
|
|
83
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
84
|
+
}, z.core.$strip>>;
|
|
85
|
+
create: z.ZodOptional<z.ZodObject<{
|
|
86
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
87
|
+
}, z.core.$strip>>;
|
|
88
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
89
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
90
|
+
}, z.core.$strip>>;
|
|
91
|
+
delete: z.ZodOptional<z.ZodObject<{
|
|
92
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
93
|
+
}, z.core.$strip>>;
|
|
94
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
95
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
96
|
+
}, z.core.$strip>>>;
|
|
97
|
+
adminUi: z.ZodOptional<z.ZodObject<{
|
|
98
|
+
visibleFor: z.ZodArray<z.ZodString>;
|
|
99
|
+
}, z.core.$strip>>;
|
|
100
|
+
}, z.core.$strip>>;
|
|
17
101
|
schema: z.ZodOptional<z.ZodString>;
|
|
18
102
|
databaseName: z.ZodOptional<z.ZodString>;
|
|
19
103
|
excelName: z.ZodOptional<z.ZodString>;
|
|
@@ -33,18 +33,24 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.zProjectSchemaJSON = exports.zSchemaName = void 0;
|
|
36
|
+
exports.zProjectSchemaJSON = exports.zSchemaJSON = exports.zSchemaName = void 0;
|
|
37
37
|
const zod_1 = require("zod");
|
|
38
38
|
const utils_1 = require("@postxl/utils");
|
|
39
39
|
const Enum = __importStar(require("../enum"));
|
|
40
|
+
const extract_inline_enums_1 = require("../extract-inline-enums");
|
|
40
41
|
const Model = __importStar(require("../model"));
|
|
41
42
|
const normalize_named_collection_1 = require("../normalize-named-collection");
|
|
43
|
+
const project_schema_auth_1 = require("./project-schema.auth");
|
|
42
44
|
exports.zSchemaName = zod_1.z
|
|
43
45
|
//
|
|
44
46
|
.string()
|
|
45
47
|
.min(1, { error: 'Schema name must not be empty' })
|
|
46
48
|
.regex(/^\w+$/, { error: 'Schema name can only contain letters, numbers and underscores.' })
|
|
47
49
|
.describe('Name of the database schema.');
|
|
50
|
+
exports.zSchemaJSON = zod_1.z.object({
|
|
51
|
+
name: exports.zSchemaName,
|
|
52
|
+
auth: project_schema_auth_1.zAuthRuleSetJSON.optional(),
|
|
53
|
+
});
|
|
48
54
|
exports.zProjectSchemaJSON = zod_1.z
|
|
49
55
|
// We want to keep any extra fields that are not defined in the schema. However, these fields should
|
|
50
56
|
// not really be exposed as "main fields" of the parsed schema - instead, they should be nested under
|
|
@@ -54,13 +60,18 @@ exports.zProjectSchemaJSON = zod_1.z
|
|
|
54
60
|
.preprocess((input) => {
|
|
55
61
|
if (typeof input === 'object' && input !== null) {
|
|
56
62
|
const original = input;
|
|
63
|
+
// Extract inline enum definitions from model fields before normalization.
|
|
64
|
+
// This converts inline enum types (objects/arrays in field.type) to top-level enums
|
|
65
|
+
// and replaces the field type with the generated enum name.
|
|
66
|
+
const withExtractedEnums = (0, extract_inline_enums_1.extractInlineEnumDefinitions)(original);
|
|
57
67
|
return {
|
|
58
|
-
...
|
|
59
|
-
models: (0, normalize_named_collection_1.normalizeNamedCollection)(
|
|
60
|
-
enums: (0, normalize_named_collection_1.normalizeNamedCollection)(
|
|
68
|
+
...withExtractedEnums,
|
|
69
|
+
models: (0, normalize_named_collection_1.normalizeNamedCollection)(withExtractedEnums.models),
|
|
70
|
+
enums: (0, normalize_named_collection_1.normalizeNamedCollection)(withExtractedEnums.enums),
|
|
61
71
|
// We omit models from the source fields as we keep the original input in model.source
|
|
62
|
-
// as part of the model schema.
|
|
63
|
-
|
|
72
|
+
// as part of the model schema. We use the post-extraction data so that source.enums
|
|
73
|
+
// reflects the extracted inline enums.
|
|
74
|
+
source: (0, utils_1.omit)(withExtractedEnums, 'models'),
|
|
64
75
|
};
|
|
65
76
|
}
|
|
66
77
|
return input;
|
|
@@ -95,7 +106,7 @@ exports.zProjectSchemaJSON = zod_1.z
|
|
|
95
106
|
.describe('The version of the project/schema. Should follow semantic versioning, see https://semver.org/.'),
|
|
96
107
|
schemas: zod_1.z
|
|
97
108
|
//
|
|
98
|
-
.array(exports.zSchemaName)
|
|
109
|
+
.array(zod_1.z.union([exports.zSchemaName, exports.zSchemaJSON]))
|
|
99
110
|
.min(1, {
|
|
100
111
|
error: 'Schemas of the project must not be empty! If you want to use the default schemas, omit this field.',
|
|
101
112
|
})
|
|
@@ -105,6 +116,9 @@ exports.zProjectSchemaJSON = zod_1.z
|
|
|
105
116
|
//
|
|
106
117
|
.optional()
|
|
107
118
|
.describe(`The default database schema that is used if model/enum does not specify a schema. If not provided, the default schema "Data" is used.`),
|
|
119
|
+
auth: project_schema_auth_1.zProjectAuthJSON
|
|
120
|
+
.optional()
|
|
121
|
+
.describe('Project-level authentication settings (provider, role claim path, and default behavior).'),
|
|
108
122
|
systemUser: zod_1.z
|
|
109
123
|
//
|
|
110
124
|
.record(zod_1.z.string(), zod_1.z.any())
|
|
@@ -11,14 +11,72 @@ export declare const zProjectSchema: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown,
|
|
|
11
11
|
description: z.ZodOptional<z.ZodString>;
|
|
12
12
|
projectType: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"standalone">, z.ZodLiteral<"workspace">]>>>;
|
|
13
13
|
version: z.ZodOptional<z.ZodString>;
|
|
14
|
-
schemas: z.ZodOptional<z.ZodArray<z.ZodString
|
|
14
|
+
schemas: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
15
|
+
name: z.ZodString;
|
|
16
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
17
|
+
read: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
19
|
+
}, z.core.$strip>>;
|
|
20
|
+
write: z.ZodOptional<z.ZodObject<{
|
|
21
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
create: z.ZodOptional<z.ZodObject<{
|
|
24
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
25
|
+
}, z.core.$strip>>;
|
|
26
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
27
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
28
|
+
}, z.core.$strip>>;
|
|
29
|
+
delete: z.ZodOptional<z.ZodObject<{
|
|
30
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>>;
|
|
32
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
33
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
34
|
+
}, z.core.$strip>>>;
|
|
35
|
+
adminUi: z.ZodOptional<z.ZodObject<{
|
|
36
|
+
visibleFor: z.ZodArray<z.ZodString>;
|
|
37
|
+
}, z.core.$strip>>;
|
|
38
|
+
}, z.core.$strip>>;
|
|
39
|
+
}, z.core.$strip>]>>>;
|
|
15
40
|
defaultSchema: z.ZodOptional<z.ZodString>;
|
|
41
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
42
|
+
provider: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"keycloak">>>;
|
|
43
|
+
roleClaimPath: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
44
|
+
defaultDeny: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
45
|
+
scopes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
46
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
47
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
48
|
+
}, z.core.$strip>>>;
|
|
49
|
+
}, z.core.$strip>>>;
|
|
50
|
+
}, z.core.$strip>>;
|
|
16
51
|
systemUser: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
17
52
|
standardModels: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
18
53
|
models: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
|
|
19
54
|
name: z.ZodString;
|
|
20
55
|
description: z.ZodOptional<z.ZodString>;
|
|
21
56
|
isReadonly: z.ZodOptional<z.ZodBoolean>;
|
|
57
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
58
|
+
read: z.ZodOptional<z.ZodObject<{
|
|
59
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
60
|
+
}, z.core.$strip>>;
|
|
61
|
+
write: z.ZodOptional<z.ZodObject<{
|
|
62
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
63
|
+
}, z.core.$strip>>;
|
|
64
|
+
create: z.ZodOptional<z.ZodObject<{
|
|
65
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
68
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
69
|
+
}, z.core.$strip>>;
|
|
70
|
+
delete: z.ZodOptional<z.ZodObject<{
|
|
71
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
72
|
+
}, z.core.$strip>>;
|
|
73
|
+
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
74
|
+
anyRole: z.ZodArray<z.ZodString>;
|
|
75
|
+
}, z.core.$strip>>>;
|
|
76
|
+
adminUi: z.ZodOptional<z.ZodObject<{
|
|
77
|
+
visibleFor: z.ZodArray<z.ZodString>;
|
|
78
|
+
}, z.core.$strip>>;
|
|
79
|
+
}, z.core.$strip>>;
|
|
22
80
|
schema: z.ZodOptional<z.ZodString>;
|
|
23
81
|
databaseName: z.ZodOptional<z.ZodString>;
|
|
24
82
|
excelName: z.ZodOptional<z.ZodString>;
|
|
@@ -56,14 +114,72 @@ export declare const zProjectSchema: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown,
|
|
|
56
114
|
source: Record<string, unknown>;
|
|
57
115
|
description?: string | undefined;
|
|
58
116
|
version?: string | undefined;
|
|
59
|
-
schemas?: string
|
|
117
|
+
schemas?: (string | {
|
|
118
|
+
name: string;
|
|
119
|
+
auth?: {
|
|
120
|
+
read?: {
|
|
121
|
+
anyRole: string[];
|
|
122
|
+
} | undefined;
|
|
123
|
+
write?: {
|
|
124
|
+
anyRole: string[];
|
|
125
|
+
} | undefined;
|
|
126
|
+
create?: {
|
|
127
|
+
anyRole: string[];
|
|
128
|
+
} | undefined;
|
|
129
|
+
update?: {
|
|
130
|
+
anyRole: string[];
|
|
131
|
+
} | undefined;
|
|
132
|
+
delete?: {
|
|
133
|
+
anyRole: string[];
|
|
134
|
+
} | undefined;
|
|
135
|
+
actions?: Record<string, {
|
|
136
|
+
anyRole: string[];
|
|
137
|
+
}> | undefined;
|
|
138
|
+
adminUi?: {
|
|
139
|
+
visibleFor: string[];
|
|
140
|
+
} | undefined;
|
|
141
|
+
} | undefined;
|
|
142
|
+
})[] | undefined;
|
|
60
143
|
defaultSchema?: string | undefined;
|
|
144
|
+
auth?: {
|
|
145
|
+
provider: "keycloak";
|
|
146
|
+
roleClaimPath: string;
|
|
147
|
+
defaultDeny: boolean;
|
|
148
|
+
scopes?: Record<string, {
|
|
149
|
+
actions?: Record<string, {
|
|
150
|
+
anyRole: string[];
|
|
151
|
+
}> | undefined;
|
|
152
|
+
}> | undefined;
|
|
153
|
+
} | undefined;
|
|
61
154
|
systemUser?: Record<string, any> | undefined;
|
|
62
155
|
standardModels?: string[] | undefined;
|
|
63
156
|
models?: {
|
|
64
157
|
name: string;
|
|
65
158
|
description?: string | undefined;
|
|
66
159
|
isReadonly?: boolean | undefined;
|
|
160
|
+
auth?: {
|
|
161
|
+
read?: {
|
|
162
|
+
anyRole: string[];
|
|
163
|
+
} | undefined;
|
|
164
|
+
write?: {
|
|
165
|
+
anyRole: string[];
|
|
166
|
+
} | undefined;
|
|
167
|
+
create?: {
|
|
168
|
+
anyRole: string[];
|
|
169
|
+
} | undefined;
|
|
170
|
+
update?: {
|
|
171
|
+
anyRole: string[];
|
|
172
|
+
} | undefined;
|
|
173
|
+
delete?: {
|
|
174
|
+
anyRole: string[];
|
|
175
|
+
} | undefined;
|
|
176
|
+
actions?: Record<string, {
|
|
177
|
+
anyRole: string[];
|
|
178
|
+
}> | undefined;
|
|
179
|
+
adminUi?: {
|
|
180
|
+
visibleFor: string[];
|
|
181
|
+
} | undefined;
|
|
182
|
+
} | undefined;
|
|
67
183
|
schema?: string | undefined;
|
|
68
184
|
databaseName?: string | undefined;
|
|
69
185
|
excelName?: string | undefined;
|
|
@@ -43,6 +43,21 @@ const Model = __importStar(require("../model"));
|
|
|
43
43
|
const Branded = __importStar(require("./project-schema.brands"));
|
|
44
44
|
const project_schema_defaults_1 = require("./project-schema.defaults");
|
|
45
45
|
const project_schema_json_decoder_1 = require("./project-schema.json-decoder");
|
|
46
|
+
function extractSchemaNamesAndAuth(schemas) {
|
|
47
|
+
const schemaNames = [];
|
|
48
|
+
const schemaAuth = new Map();
|
|
49
|
+
for (const schema of schemas ?? []) {
|
|
50
|
+
if (typeof schema === 'string') {
|
|
51
|
+
schemaNames.push(schema);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
schemaNames.push(schema.name);
|
|
55
|
+
if (schema.auth) {
|
|
56
|
+
schemaAuth.set(schema.name, schema.auth);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { schemaNames, schemaAuth };
|
|
60
|
+
}
|
|
46
61
|
function transformProjectSchemaJSON(input, ctx) {
|
|
47
62
|
const result = (0, utils_1.pipeZodTransformers)(input, ctx, [
|
|
48
63
|
convertRecordsToMaps,
|
|
@@ -68,8 +83,9 @@ function convertRecordsToMaps(input) {
|
|
|
68
83
|
};
|
|
69
84
|
}
|
|
70
85
|
function addDefaults(input) {
|
|
71
|
-
const
|
|
72
|
-
const
|
|
86
|
+
const { schemaNames, schemaAuth } = extractSchemaNamesAndAuth(input.schemas);
|
|
87
|
+
const schemas = schemaNames.length > 0 ? schemaNames : [project_schema_defaults_1.databaseSchemaNameData, project_schema_defaults_1.databaseSchemaNameConfig];
|
|
88
|
+
const defaultSchema = getDefaultSchema(schemaNames, input.defaultSchema);
|
|
73
89
|
return {
|
|
74
90
|
name: input.name,
|
|
75
91
|
slug: input.slug,
|
|
@@ -77,7 +93,9 @@ function addDefaults(input) {
|
|
|
77
93
|
projectType: input.projectType ?? 'standalone',
|
|
78
94
|
version: input.version ?? '0.0.1',
|
|
79
95
|
schemas,
|
|
96
|
+
schemaAuth,
|
|
80
97
|
defaultSchema,
|
|
98
|
+
...(input.auth ? { auth: input.auth } : {}),
|
|
81
99
|
systemUser: {
|
|
82
100
|
...project_schema_defaults_1.defaultSystemUser,
|
|
83
101
|
...input.systemUser,
|
|
@@ -101,12 +119,13 @@ function getDefaultSchema(schemas, defaultSchema) {
|
|
|
101
119
|
}
|
|
102
120
|
return schemas[0];
|
|
103
121
|
}
|
|
104
|
-
function brandProjectSchema({ name, slug, schemas, defaultSchema, standardModels, standardEnums, ...input }) {
|
|
122
|
+
function brandProjectSchema({ name, slug, schemas, schemaAuth, defaultSchema, standardModels, standardEnums, ...input }) {
|
|
105
123
|
return {
|
|
106
124
|
...input,
|
|
107
125
|
name: Branded.toProjectSchemaName(name),
|
|
108
126
|
slug: Branded.toProjectSlug(slug),
|
|
109
127
|
databaseSchemas: schemas.map((s) => Branded.toDatabaseSchemaName(s)),
|
|
128
|
+
schemaAuth: new Map([...schemaAuth.entries()].map(([schemaName, auth]) => [Branded.toDatabaseSchemaName(schemaName), auth])),
|
|
110
129
|
defaultDatabaseSchema: Branded.toDatabaseSchemaName(defaultSchema),
|
|
111
130
|
standardModels: standardModels.map((s) => Model.toModelName(s)),
|
|
112
131
|
standardEnums: standardEnums.map((s) => Enum.toEnumName(s)),
|
|
@@ -259,10 +278,19 @@ function transformModels(projectSchema, ctx) {
|
|
|
259
278
|
const model = transformModel(projectSchema.models.get(inputModelName), projectSchema, ctx);
|
|
260
279
|
models.set(model.name, model);
|
|
261
280
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
281
|
+
const { auth, ...remainingProjectSchema } = projectSchema;
|
|
282
|
+
// Keep optional field shape clean: only include `auth` when it is actually set,
|
|
283
|
+
// instead of returning `auth: undefined`.
|
|
284
|
+
return auth
|
|
285
|
+
? {
|
|
286
|
+
...remainingProjectSchema,
|
|
287
|
+
auth,
|
|
288
|
+
models,
|
|
289
|
+
}
|
|
290
|
+
: {
|
|
291
|
+
...remainingProjectSchema,
|
|
292
|
+
models,
|
|
293
|
+
};
|
|
266
294
|
}
|
|
267
295
|
function transformModel(model, projectSchema, ctx) {
|
|
268
296
|
const fields = transformFields(model, projectSchema, ctx);
|
|
@@ -271,9 +299,10 @@ function transformModel(model, projectSchema, ctx) {
|
|
|
271
299
|
const defaultField = extractDefaultField(model, fields, ctx);
|
|
272
300
|
const labelField = extractLabelField(model, fields, ctx);
|
|
273
301
|
const keyField = extractKeyField(model, fields, idField, ctx);
|
|
274
|
-
const { defaultFieldName, labelFieldName, keyFieldName, ...remainingModel } = model;
|
|
302
|
+
const { defaultFieldName, labelFieldName, keyFieldName, auth, ...remainingModel } = model;
|
|
275
303
|
return {
|
|
276
304
|
...remainingModel,
|
|
305
|
+
...(auth ? { auth } : {}),
|
|
277
306
|
databaseSchema: model.schema ?? projectSchema.defaultDatabaseSchema,
|
|
278
307
|
fields,
|
|
279
308
|
defaultField,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Enum from '../enum';
|
|
2
2
|
import * as Model from '../model';
|
|
3
|
+
import { AuthRuleSet, ProjectAuth } from './project-schema.auth';
|
|
3
4
|
import * as Branded from './project-schema.brands';
|
|
4
5
|
/**
|
|
5
6
|
* Overall project configuration.
|
|
@@ -39,6 +40,14 @@ export type ProjectSchema = {
|
|
|
39
40
|
* If not provided, the default schema "Data" is used.
|
|
40
41
|
*/
|
|
41
42
|
defaultDatabaseSchema: Branded.DatabaseSchemaName;
|
|
43
|
+
/**
|
|
44
|
+
* Global authorization configuration for this project.
|
|
45
|
+
*/
|
|
46
|
+
auth?: ProjectAuth;
|
|
47
|
+
/**
|
|
48
|
+
* Schema-level authorization defaults by database schema.
|
|
49
|
+
*/
|
|
50
|
+
schemaAuth: Map<Branded.DatabaseSchemaName, AuthRuleSet>;
|
|
42
51
|
/**
|
|
43
52
|
* The system user that is used for root/system tasks, e.g. data seeding.
|
|
44
53
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postxl/schema",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Decoders for PXL Schema definitions and validation for PXL code generation framework",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"directory": "packages/schema"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@postxl/utils": "^1.3.
|
|
39
|
+
"@postxl/utils": "^1.3.4"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {},
|
|
42
42
|
"wallaby": {
|