@baseplate-dev/project-builder-lib 0.5.1 → 0.5.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/CHANGELOG.md +473 -0
- package/dist/definition/model/model-field-utils.js +4 -4
- package/dist/definition/model/model-field-utils.js.map +1 -1
- package/dist/definition/model/model-utils.js +3 -3
- package/dist/definition/model/model-utils.js.map +1 -1
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -1
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/migration-007-model-graphql.js +1 -1
- package/dist/migrations/migration-007-model-graphql.js.map +1 -1
- package/dist/migrations/migration-020-move-redis-to-infrastructure.js +1 -1
- package/dist/migrations/migration-020-move-redis-to-infrastructure.js.map +1 -1
- package/dist/migrations/migration-021-migrate-bullmq-to-plugin.js +1 -1
- package/dist/migrations/migration-021-migrate-bullmq-to-plugin.js.map +1 -1
- package/dist/migrations/migration-023-assign-app-ports.d.ts +34 -0
- package/dist/migrations/migration-023-assign-app-ports.d.ts.map +1 -0
- package/dist/migrations/migration-023-assign-app-ports.js +49 -0
- package/dist/migrations/migration-023-assign-app-ports.js.map +1 -0
- package/dist/plugins/spec/config-spec.js +2 -2
- package/dist/plugins/spec/config-spec.js.map +1 -1
- package/dist/references/collect-refs.d.ts +5 -1
- package/dist/references/collect-refs.d.ts.map +1 -1
- package/dist/references/collect-refs.js +20 -1
- package/dist/references/collect-refs.js.map +1 -1
- package/dist/references/definition-ref-builder.d.ts.map +1 -1
- package/dist/references/expression-types.d.ts +152 -0
- package/dist/references/expression-types.d.ts.map +1 -0
- package/dist/references/expression-types.js +46 -0
- package/dist/references/expression-types.js.map +1 -0
- package/dist/references/extend-parser-context-with-refs.d.ts +13 -0
- package/dist/references/extend-parser-context-with-refs.d.ts.map +1 -1
- package/dist/references/extend-parser-context-with-refs.js +39 -1
- package/dist/references/extend-parser-context-with-refs.js.map +1 -1
- package/dist/references/extract-definition-refs.d.ts +6 -3
- package/dist/references/extract-definition-refs.d.ts.map +1 -1
- package/dist/references/extract-definition-refs.js +25 -4
- package/dist/references/extract-definition-refs.js.map +1 -1
- package/dist/references/index.d.ts +1 -0
- package/dist/references/index.d.ts.map +1 -1
- package/dist/references/index.js +1 -0
- package/dist/references/index.js.map +1 -1
- package/dist/references/markers.d.ts +23 -0
- package/dist/references/markers.d.ts.map +1 -1
- package/dist/references/markers.js +16 -0
- package/dist/references/markers.js.map +1 -1
- package/dist/references/resolve-zod-ref-payload-names.d.ts.map +1 -1
- package/dist/references/resolve-zod-ref-payload-names.js +1 -0
- package/dist/references/resolve-zod-ref-payload-names.js.map +1 -1
- package/dist/references/strip-ref-markers.d.ts +3 -3
- package/dist/references/strip-ref-markers.d.ts.map +1 -1
- package/dist/references/strip-ref-markers.js +7 -4
- package/dist/references/strip-ref-markers.js.map +1 -1
- package/dist/references/types.d.ts +5 -0
- package/dist/references/types.d.ts.map +1 -1
- package/dist/references/types.js.map +1 -1
- package/dist/schema/apps/backend/index.d.ts +2 -0
- package/dist/schema/apps/backend/index.d.ts.map +1 -1
- package/dist/schema/apps/backend/index.js +1 -0
- package/dist/schema/apps/backend/index.js.map +1 -1
- package/dist/schema/apps/base.d.ts +2 -0
- package/dist/schema/apps/base.d.ts.map +1 -1
- package/dist/schema/apps/base.js +1 -0
- package/dist/schema/apps/base.js.map +1 -1
- package/dist/schema/apps/web/admin/sections/crud-actions/types.d.ts.map +1 -1
- package/dist/schema/apps/web/web-app.d.ts +2 -0
- package/dist/schema/apps/web/web-app.d.ts.map +1 -1
- package/dist/schema/apps/web/web-app.js +1 -0
- package/dist/schema/apps/web/web-app.js.map +1 -1
- package/dist/schema/creator/types.d.ts +6 -1
- package/dist/schema/creator/types.d.ts.map +1 -1
- package/dist/schema/models/authorizer/authorizer-expression-acorn-parser.d.ts +30 -0
- package/dist/schema/models/authorizer/authorizer-expression-acorn-parser.d.ts.map +1 -0
- package/dist/schema/models/authorizer/authorizer-expression-acorn-parser.js +291 -0
- package/dist/schema/models/authorizer/authorizer-expression-acorn-parser.js.map +1 -0
- package/dist/schema/models/authorizer/authorizer-expression-ast.d.ts +159 -0
- package/dist/schema/models/authorizer/authorizer-expression-ast.d.ts.map +1 -0
- package/dist/schema/models/authorizer/authorizer-expression-ast.js +31 -0
- package/dist/schema/models/authorizer/authorizer-expression-ast.js.map +1 -0
- package/dist/schema/models/authorizer/authorizer-expression-parser.d.ts +77 -0
- package/dist/schema/models/authorizer/authorizer-expression-parser.d.ts.map +1 -0
- package/dist/schema/models/authorizer/authorizer-expression-parser.js +147 -0
- package/dist/schema/models/authorizer/authorizer-expression-parser.js.map +1 -0
- package/dist/schema/models/authorizer/authorizer-expression-validator.d.ts +51 -0
- package/dist/schema/models/authorizer/authorizer-expression-validator.d.ts.map +1 -0
- package/dist/schema/models/authorizer/authorizer-expression-validator.js +125 -0
- package/dist/schema/models/authorizer/authorizer-expression-validator.js.map +1 -0
- package/dist/schema/models/authorizer/authorizer.d.ts +59 -0
- package/dist/schema/models/authorizer/authorizer.d.ts.map +1 -0
- package/dist/schema/models/authorizer/authorizer.js +56 -0
- package/dist/schema/models/authorizer/authorizer.js.map +1 -0
- package/dist/schema/models/authorizer/index.d.ts +7 -0
- package/dist/schema/models/authorizer/index.d.ts.map +1 -0
- package/dist/schema/models/authorizer/index.js +7 -0
- package/dist/schema/models/authorizer/index.js.map +1 -0
- package/dist/schema/models/authorizer/types.d.ts +6 -0
- package/dist/schema/models/authorizer/types.d.ts.map +1 -0
- package/dist/schema/models/authorizer/types.js +8 -0
- package/dist/schema/models/authorizer/types.js.map +1 -0
- package/dist/schema/models/index.d.ts +2 -860
- package/dist/schema/models/index.d.ts.map +1 -1
- package/dist/schema/models/index.js +2 -222
- package/dist/schema/models/index.js.map +1 -1
- package/dist/schema/models/models.d.ts +914 -0
- package/dist/schema/models/models.d.ts.map +1 -0
- package/dist/schema/models/models.js +225 -0
- package/dist/schema/models/models.js.map +1 -0
- package/dist/schema/project-definition.d.ts +46 -2
- package/dist/schema/project-definition.d.ts.map +1 -1
- package/dist/schema/settings/settings.d.ts +2 -2
- package/dist/schema/settings/theme.d.ts +3 -3
- package/dist/tools/model-merger/model-merger.js +1 -1
- package/dist/tools/model-merger/model-merger.js.map +1 -1
- package/dist/utils/color-conversions.js +1 -1
- package/dist/utils/color-conversions.js.map +1 -1
- package/dist/web/components/feature-combobox-field.d.ts.map +1 -1
- package/dist/web/components/feature-combobox-field.js +1 -1
- package/dist/web/components/feature-combobox-field.js.map +1 -1
- package/dist/web/components/model-combobox-field.d.ts.map +1 -1
- package/dist/web/components/model-combobox-field.js +1 -1
- package/dist/web/components/model-combobox-field.js.map +1 -1
- package/dist/web/components/model-merger-result-alert.js +1 -1
- package/package.json +11 -9
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for authorizer expressions using Acorn.
|
|
3
|
+
*
|
|
4
|
+
* Parses expressions with implicit auth context:
|
|
5
|
+
* - `model.id === userId`
|
|
6
|
+
* - `hasRole('admin')`
|
|
7
|
+
* - `hasSomeRole(['admin', 'moderator'])`
|
|
8
|
+
* - `model.id === userId || hasRole('admin')`
|
|
9
|
+
*
|
|
10
|
+
* Uses Acorn to parse as JavaScript, then converts the ESTree AST
|
|
11
|
+
* to our domain-specific AST, rejecting unsupported constructs.
|
|
12
|
+
*/
|
|
13
|
+
import { parse } from 'acorn';
|
|
14
|
+
import { AuthorizerExpressionParseError } from './authorizer-expression-ast.js';
|
|
15
|
+
/**
|
|
16
|
+
* Parse an authorizer expression string into our domain AST.
|
|
17
|
+
*
|
|
18
|
+
* @param input - The expression string to parse
|
|
19
|
+
* @returns The parsed expression info including AST and dependencies
|
|
20
|
+
* @throws {AuthorizerExpressionParseError} If the expression is invalid
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const result = parseAuthorizerExpression("model.id === auth.userId");
|
|
25
|
+
* // result.ast = { type: 'fieldComparison', ... }
|
|
26
|
+
* // result.modelFieldRefs = ['id']
|
|
27
|
+
* // result.authFieldRefs = ['userId']
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function parseAuthorizerExpression(input) {
|
|
31
|
+
// Parse with Acorn
|
|
32
|
+
let program;
|
|
33
|
+
try {
|
|
34
|
+
program = parse(input, {
|
|
35
|
+
ecmaVersion: 2020,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error instanceof SyntaxError) {
|
|
40
|
+
throw new AuthorizerExpressionParseError(`Invalid expression syntax: ${error.message}`,
|
|
41
|
+
// SyntaxError thrown by Acorn have a pos property
|
|
42
|
+
error.pos);
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
// Check body is an expression
|
|
47
|
+
if (program.body.length !== 1) {
|
|
48
|
+
throw new AuthorizerExpressionParseError('Expression must be a single expression statement, e.g. model.id === auth.userId', 0, input.length);
|
|
49
|
+
}
|
|
50
|
+
const expressionStatement = program.body[0];
|
|
51
|
+
if (expressionStatement.type !== 'ExpressionStatement') {
|
|
52
|
+
throw new AuthorizerExpressionParseError('Line must be an expression statement, e.g. model.id === auth.userId', expressionStatement);
|
|
53
|
+
}
|
|
54
|
+
// Convert ESTree to our domain AST
|
|
55
|
+
const ast = convertNode(expressionStatement.expression);
|
|
56
|
+
// Extract dependency information
|
|
57
|
+
const info = extractInfo(ast);
|
|
58
|
+
return {
|
|
59
|
+
ast,
|
|
60
|
+
...info,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert an ESTree expression node to our domain AST.
|
|
65
|
+
*/
|
|
66
|
+
function convertNode(node) {
|
|
67
|
+
switch (node.type) {
|
|
68
|
+
case 'LogicalExpression': {
|
|
69
|
+
return convertLogicalExpression(node);
|
|
70
|
+
}
|
|
71
|
+
case 'BinaryExpression': {
|
|
72
|
+
return convertBinaryExpression(node);
|
|
73
|
+
}
|
|
74
|
+
case 'CallExpression': {
|
|
75
|
+
return convertCallExpression(node);
|
|
76
|
+
}
|
|
77
|
+
case 'MemberExpression': {
|
|
78
|
+
// A bare member expression like `model.id` without comparison
|
|
79
|
+
throw new AuthorizerExpressionParseError('Field reference must be part of a comparison (e.g., model.id === auth.userId)', node);
|
|
80
|
+
}
|
|
81
|
+
default: {
|
|
82
|
+
throw new AuthorizerExpressionParseError(`Unsupported expression type: ${node.type}`, node);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Convert a LogicalExpression (|| or &&) to BinaryLogicalNode.
|
|
88
|
+
*/
|
|
89
|
+
function convertLogicalExpression(node) {
|
|
90
|
+
if (node.operator !== '||' && node.operator !== '&&') {
|
|
91
|
+
throw new AuthorizerExpressionParseError(`Unsupported logical operator: ${node.operator}. Only || and && are supported.`, node.left.end, node.right.start);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
type: 'binaryLogical',
|
|
95
|
+
operator: node.operator,
|
|
96
|
+
left: convertNode(node.left),
|
|
97
|
+
right: convertNode(node.right),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Convert a BinaryExpression (===) to FieldComparisonNode.
|
|
102
|
+
*/
|
|
103
|
+
function convertBinaryExpression(node) {
|
|
104
|
+
if (node.operator !== '===') {
|
|
105
|
+
throw new AuthorizerExpressionParseError(`Unsupported comparison operator: ${node.operator}. Only === is supported.`, node.left.end, node.right.start);
|
|
106
|
+
}
|
|
107
|
+
// Acorn's BinaryExpression allows PrivateIdentifier for ES2022+, but we only
|
|
108
|
+
// support MemberExpression field refs. convertFieldRef will throw if given
|
|
109
|
+
// anything other than MemberExpression.
|
|
110
|
+
return {
|
|
111
|
+
type: 'fieldComparison',
|
|
112
|
+
operator: '===',
|
|
113
|
+
left: convertFieldRef(node.left),
|
|
114
|
+
right: convertFieldRef(node.right),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Convert a CallExpression to HasRoleNode or HasSomeRoleNode.
|
|
119
|
+
* Supports:
|
|
120
|
+
* - `hasRole('admin')`
|
|
121
|
+
* - `hasSomeRole(['admin', 'moderator'])`
|
|
122
|
+
*/
|
|
123
|
+
function convertCallExpression(node) {
|
|
124
|
+
// Only support direct calls (e.g., hasRole(...))
|
|
125
|
+
if (node.callee.type !== 'Identifier') {
|
|
126
|
+
throw new AuthorizerExpressionParseError('Function calls must be standalone (hasRole, hasSomeRole)', node.callee);
|
|
127
|
+
}
|
|
128
|
+
const funcName = node.callee.name;
|
|
129
|
+
if (funcName === 'hasRole') {
|
|
130
|
+
return parseHasRoleArgs(node, 'hasRole()');
|
|
131
|
+
}
|
|
132
|
+
if (funcName === 'hasSomeRole') {
|
|
133
|
+
return parseHasSomeRoleArgs(node, 'hasSomeRole()');
|
|
134
|
+
}
|
|
135
|
+
throw new AuthorizerExpressionParseError(`Unknown function '${funcName}'. Use hasRole() or hasSomeRole().`, node.callee);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Parse hasRole('role') arguments.
|
|
139
|
+
*/
|
|
140
|
+
function parseHasRoleArgs(node, funcName) {
|
|
141
|
+
// Must have exactly one string argument
|
|
142
|
+
if (node.arguments.length !== 1) {
|
|
143
|
+
throw new AuthorizerExpressionParseError(`${funcName} requires exactly one argument, got ${node.arguments.length}`, node);
|
|
144
|
+
}
|
|
145
|
+
const arg = node.arguments[0];
|
|
146
|
+
if (arg.type !== 'Literal' || typeof arg.value !== 'string') {
|
|
147
|
+
throw new AuthorizerExpressionParseError(`${funcName} argument must be a string literal`, arg);
|
|
148
|
+
}
|
|
149
|
+
const role = arg.value;
|
|
150
|
+
return {
|
|
151
|
+
type: 'hasRole',
|
|
152
|
+
role,
|
|
153
|
+
roleStart: arg.start,
|
|
154
|
+
roleEnd: arg.end,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Parse hasSomeRole(['role1', 'role2']) arguments.
|
|
159
|
+
*/
|
|
160
|
+
function parseHasSomeRoleArgs(node, funcName) {
|
|
161
|
+
// Must have exactly one array argument
|
|
162
|
+
if (node.arguments.length !== 1) {
|
|
163
|
+
throw new AuthorizerExpressionParseError(`${funcName} requires exactly one argument, got ${node.arguments.length}`, node);
|
|
164
|
+
}
|
|
165
|
+
const arg = node.arguments[0];
|
|
166
|
+
if (arg.type !== 'ArrayExpression') {
|
|
167
|
+
throw new AuthorizerExpressionParseError(`${funcName} argument must be an array literal (e.g., ['admin', 'moderator'])`, arg);
|
|
168
|
+
}
|
|
169
|
+
const roles = [];
|
|
170
|
+
const rolesStart = [];
|
|
171
|
+
const rolesEnd = [];
|
|
172
|
+
for (const element of arg.elements) {
|
|
173
|
+
if (!element) {
|
|
174
|
+
throw new AuthorizerExpressionParseError(`${funcName} array cannot have empty elements`, arg);
|
|
175
|
+
}
|
|
176
|
+
if (element.type !== 'Literal' || typeof element.value !== 'string') {
|
|
177
|
+
throw new AuthorizerExpressionParseError(`${funcName} array elements must be string literals`, element);
|
|
178
|
+
}
|
|
179
|
+
roles.push(element.value);
|
|
180
|
+
rolesStart.push(element.start);
|
|
181
|
+
rolesEnd.push(element.end);
|
|
182
|
+
}
|
|
183
|
+
if (roles.length === 0) {
|
|
184
|
+
throw new AuthorizerExpressionParseError(`${funcName} requires at least one role`, arg);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
type: 'hasSomeRole',
|
|
188
|
+
roles,
|
|
189
|
+
rolesStart,
|
|
190
|
+
rolesEnd,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Convert to FieldRefNode.
|
|
195
|
+
* Supports:
|
|
196
|
+
* - Standalone identifier for implicit auth context: `userId`
|
|
197
|
+
* - Member expressions: `model.field`
|
|
198
|
+
*/
|
|
199
|
+
function convertFieldRef(node) {
|
|
200
|
+
// Handle standalone identifier (implicit auth context)
|
|
201
|
+
if (node.type === 'Identifier') {
|
|
202
|
+
const identifier = node;
|
|
203
|
+
const { name } = identifier;
|
|
204
|
+
// Only userId is valid as a standalone identifier (implicit auth context)
|
|
205
|
+
if (name === 'userId') {
|
|
206
|
+
return {
|
|
207
|
+
type: 'fieldRef',
|
|
208
|
+
source: 'auth',
|
|
209
|
+
field: 'userId',
|
|
210
|
+
start: node.start,
|
|
211
|
+
end: node.end,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
throw new AuthorizerExpressionParseError(`Unknown identifier '${name}'. Did you mean 'model.${name}' or use 'userId' for auth context?`, node);
|
|
215
|
+
}
|
|
216
|
+
if (node.type !== 'MemberExpression') {
|
|
217
|
+
throw new AuthorizerExpressionParseError('Expected field reference (model.field or userId)', node);
|
|
218
|
+
}
|
|
219
|
+
const memberExpr = node;
|
|
220
|
+
// Object must be an identifier
|
|
221
|
+
if (memberExpr.object.type !== 'Identifier') {
|
|
222
|
+
throw new AuthorizerExpressionParseError('Field reference must start with model', memberExpr.object);
|
|
223
|
+
}
|
|
224
|
+
const source = memberExpr.object.name;
|
|
225
|
+
if (source !== 'model') {
|
|
226
|
+
throw new AuthorizerExpressionParseError(`Field reference must start with 'model', not '${source}'`, memberExpr.object);
|
|
227
|
+
}
|
|
228
|
+
// Property must be a simple identifier (not computed)
|
|
229
|
+
if (memberExpr.computed) {
|
|
230
|
+
throw new AuthorizerExpressionParseError('Computed property access (e.g., model["field"]) is not supported', memberExpr.property);
|
|
231
|
+
}
|
|
232
|
+
if (memberExpr.property.type !== 'Identifier') {
|
|
233
|
+
throw new AuthorizerExpressionParseError('Expected field name identifier', memberExpr.property);
|
|
234
|
+
}
|
|
235
|
+
const field = memberExpr.property.name;
|
|
236
|
+
return {
|
|
237
|
+
type: 'fieldRef',
|
|
238
|
+
source: 'model',
|
|
239
|
+
field,
|
|
240
|
+
start: node.start,
|
|
241
|
+
end: node.end,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Extract dependency information from the parsed AST.
|
|
246
|
+
*/
|
|
247
|
+
function extractInfo(ast) {
|
|
248
|
+
const modelFieldRefs = [];
|
|
249
|
+
const authFieldRefs = [];
|
|
250
|
+
const roleRefs = [];
|
|
251
|
+
let requiresModel = false;
|
|
252
|
+
function walk(node) {
|
|
253
|
+
switch (node.type) {
|
|
254
|
+
case 'fieldComparison': {
|
|
255
|
+
walkFieldRef(node.left);
|
|
256
|
+
walkFieldRef(node.right);
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
case 'hasRole': {
|
|
260
|
+
roleRefs.push(node.role);
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
case 'hasSomeRole': {
|
|
264
|
+
roleRefs.push(...node.roles);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
case 'binaryLogical': {
|
|
268
|
+
walk(node.left);
|
|
269
|
+
walk(node.right);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function walkFieldRef(node) {
|
|
275
|
+
if (node.source === 'model') {
|
|
276
|
+
modelFieldRefs.push(node.field);
|
|
277
|
+
requiresModel = true;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
authFieldRefs.push(node.field);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
walk(ast);
|
|
284
|
+
return {
|
|
285
|
+
modelFieldRefs: [...new Set(modelFieldRefs)],
|
|
286
|
+
authFieldRefs: [...new Set(authFieldRefs)],
|
|
287
|
+
roleRefs: [...new Set(roleRefs)],
|
|
288
|
+
requiresModel,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=authorizer-expression-acorn-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorizer-expression-acorn-parser.js","sourceRoot":"","sources":["../../../../src/schema/models/authorizer/authorizer-expression-acorn-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAY9B,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAC;AAEhF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAa;IAEb,mBAAmB;IACnB,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE;YACrB,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,MAAM,IAAI,8BAA8B,CACtC,8BAA8B,KAAK,CAAC,OAAO,EAAE;YAC7C,kDAAkD;YACjD,KAAoC,CAAC,GAAG,CAC1C,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,8BAA8B;IAC9B,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,8BAA8B,CACtC,iFAAiF,EACjF,CAAC,EACD,KAAK,CAAC,MAAM,CACb,CAAC;IACJ,CAAC;IACD,MAAM,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE5C,IAAI,mBAAmB,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;QACvD,MAAM,IAAI,8BAA8B,CACtC,qEAAqE,EACrE,mBAAmB,CACpB,CAAC;IACJ,CAAC;IAED,mCAAmC;IACnC,MAAM,GAAG,GAAG,WAAW,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAExD,iCAAiC;IACjC,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAE9B,OAAO;QACL,GAAG;QACH,GAAG,IAAI;KACR,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,IAAgB;IACnC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;QAED,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;QAED,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QAED,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,8DAA8D;YAC9D,MAAM,IAAI,8BAA8B,CACtC,+EAA+E,EAC/E,IAAI,CACL,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,IAAI,8BAA8B,CACtC,gCAAgC,IAAI,CAAC,IAAI,EAAE,EAC3C,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,IAAuB;IACvD,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QACrD,MAAM,IAAI,8BAA8B,CACtC,iCAAiC,IAAI,CAAC,QAAQ,iCAAiC,EAC/E,IAAI,CAAC,IAAI,CAAC,GAAG,EACb,IAAI,CAAC,KAAK,CAAC,KAAK,CACjB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5B,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAAC,IAAsB;IACrD,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAC5B,MAAM,IAAI,8BAA8B,CACtC,oCAAoC,IAAI,CAAC,QAAQ,0BAA0B,EAC3E,IAAI,CAAC,IAAI,CAAC,GAAG,EACb,IAAI,CAAC,KAAK,CAAC,KAAK,CACjB,CAAC;IACJ,CAAC;IAED,6EAA6E;IAC7E,2EAA2E;IAC3E,wCAAwC;IACxC,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,IAAkB,CAAC;QAC9C,KAAK,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;KACnC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,qBAAqB,CAC5B,IAAoB;IAEpB,iDAAiD;IACjD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACtC,MAAM,IAAI,8BAA8B,CACtC,0DAA0D,EAC1D,IAAI,CAAC,MAAM,CACZ,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAElC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC/B,OAAO,oBAAoB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,IAAI,8BAA8B,CACtC,qBAAqB,QAAQ,oCAAoC,EACjE,IAAI,CAAC,MAAM,CACZ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,IAAoB,EAAE,QAAgB;IAC9D,wCAAwC;IACxC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,8BAA8B,CACtC,GAAG,QAAQ,uCAAuC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EACzE,IAAI,CACL,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC5D,MAAM,IAAI,8BAA8B,CACtC,GAAG,QAAQ,oCAAoC,EAC/C,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC;IAEvB,OAAO;QACL,IAAI,EAAE,SAAS;QACf,IAAI;QACJ,SAAS,EAAE,GAAG,CAAC,KAAK;QACpB,OAAO,EAAE,GAAG,CAAC,GAAG;KACjB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAC3B,IAAoB,EACpB,QAAgB;IAEhB,uCAAuC;IACvC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,8BAA8B,CACtC,GAAG,QAAQ,uCAAuC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EACzE,IAAI,CACL,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,GAAG,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACnC,MAAM,IAAI,8BAA8B,CACtC,GAAG,QAAQ,mEAAmE,EAC9E,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,8BAA8B,CACtC,GAAG,QAAQ,mCAAmC,EAC9C,GAAG,CACJ,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACpE,MAAM,IAAI,8BAA8B,CACtC,GAAG,QAAQ,yCAAyC,EACpD,OAAO,CACR,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1B,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC/B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,8BAA8B,CACtC,GAAG,QAAQ,6BAA6B,EACxC,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,KAAK;QACL,UAAU;QACV,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,IAAgB;IACvC,uDAAuD;IACvD,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,IAAI,CAAC;QACxB,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC;QAE5B,0EAA0E;QAC1E,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE,QAAQ;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,GAAG,EAAE,IAAI,CAAC,GAAG;aACd,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,8BAA8B,CACtC,uBAAuB,IAAI,0BAA0B,IAAI,qCAAqC,EAC9F,IAAI,CACL,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QACrC,MAAM,IAAI,8BAA8B,CACtC,kDAAkD,EAClD,IAAI,CACL,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC;IAExB,+BAA+B;IAC/B,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC5C,MAAM,IAAI,8BAA8B,CACtC,uCAAuC,EACvC,UAAU,CAAC,MAAM,CAClB,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC;IACtC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,8BAA8B,CACtC,iDAAiD,MAAM,GAAG,EAC1D,UAAU,CAAC,MAAM,CAClB,CAAC;IACJ,CAAC;IAED,sDAAsD;IACtD,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,MAAM,IAAI,8BAA8B,CACtC,kEAAkE,EAClE,UAAU,CAAC,QAAQ,CACpB,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC9C,MAAM,IAAI,8BAA8B,CACtC,gCAAgC,EAChC,UAAU,CAAC,QAAQ,CACpB,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;IAEvC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,OAAO;QACf,KAAK;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAClB,GAA6B;IAE7B,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,SAAS,IAAI,CAAC,IAA8B;QAC1C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,iBAAiB,CAAC,CAAC,CAAC;gBACvB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxB,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACzB,MAAM;YACR,CAAC;YAED,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzB,MAAM;YACR,CAAC;YAED,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC7B,MAAM;YACR,CAAC;YAED,KAAK,eAAe,CAAC,CAAC,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACjB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,YAAY,CAAC,IAAkB;QACtC,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAC5B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,OAAO;QACL,cAAc,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5C,aAAa,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;QAC1C,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,aAAa;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST node types for authorizer expressions.
|
|
3
|
+
*
|
|
4
|
+
* These represent the semantic structure of expressions like:
|
|
5
|
+
* - `model.id === userId`
|
|
6
|
+
* - `hasRole('admin')`
|
|
7
|
+
* - `hasSomeRole(['admin', 'moderator'])`
|
|
8
|
+
* - `model.id === userId || hasRole('admin')`
|
|
9
|
+
*
|
|
10
|
+
* The AST is produced by parsing with Acorn and converting from ESTree.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Root expression node - the result of parsing an authorizer expression.
|
|
14
|
+
*/
|
|
15
|
+
export type AuthorizerExpressionNode = FieldComparisonNode | HasRoleNode | HasSomeRoleNode | BinaryLogicalNode;
|
|
16
|
+
/**
|
|
17
|
+
* A field comparison expression: `left === right`
|
|
18
|
+
*
|
|
19
|
+
* Currently only supports strict equality (`===`).
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // model.id === auth.userId
|
|
24
|
+
* {
|
|
25
|
+
* type: 'fieldComparison',
|
|
26
|
+
* operator: '===',
|
|
27
|
+
* left: { type: 'fieldRef', source: 'model', field: 'id', ... },
|
|
28
|
+
* right: { type: 'fieldRef', source: 'auth', field: 'userId', ... },
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export interface FieldComparisonNode {
|
|
33
|
+
type: 'fieldComparison';
|
|
34
|
+
operator: '===';
|
|
35
|
+
left: FieldRefNode;
|
|
36
|
+
right: FieldRefNode;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A role check expression: `hasRole('roleName')`
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* // hasRole('admin')
|
|
44
|
+
* {
|
|
45
|
+
* type: 'hasRole',
|
|
46
|
+
* role: 'admin',
|
|
47
|
+
* roleStart: 8,
|
|
48
|
+
* roleEnd: 15,
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export interface HasRoleNode {
|
|
53
|
+
type: 'hasRole';
|
|
54
|
+
/** The role name being checked */
|
|
55
|
+
role: string;
|
|
56
|
+
/** Start position of the role string in the source (for rename tracking) */
|
|
57
|
+
roleStart: number;
|
|
58
|
+
/** End position of the role string in the source (for rename tracking) */
|
|
59
|
+
roleEnd: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A role check expression for multiple roles: `hasSomeRole(['role1', 'role2'])`
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* // hasSomeRole(['admin', 'moderator'])
|
|
67
|
+
* {
|
|
68
|
+
* type: 'hasSomeRole',
|
|
69
|
+
* roles: ['admin', 'moderator'],
|
|
70
|
+
* rolesStart: [13, 22],
|
|
71
|
+
* rolesEnd: [20, 33],
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export interface HasSomeRoleNode {
|
|
76
|
+
type: 'hasSomeRole';
|
|
77
|
+
/** The role names being checked */
|
|
78
|
+
roles: string[];
|
|
79
|
+
/** Start positions of each role string in the source (for rename tracking) */
|
|
80
|
+
rolesStart: number[];
|
|
81
|
+
/** End positions of each role string in the source (for rename tracking) */
|
|
82
|
+
rolesEnd: number[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* A binary logical expression: `left || right` or `left && right`
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* // model.id === auth.userId || auth.hasRole('admin')
|
|
90
|
+
* {
|
|
91
|
+
* type: 'binaryLogical',
|
|
92
|
+
* operator: '||',
|
|
93
|
+
* left: { type: 'fieldComparison', ... },
|
|
94
|
+
* right: { type: 'hasRole', ... },
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export interface BinaryLogicalNode {
|
|
99
|
+
type: 'binaryLogical';
|
|
100
|
+
operator: '||' | '&&';
|
|
101
|
+
left: AuthorizerExpressionNode;
|
|
102
|
+
right: AuthorizerExpressionNode;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A reference to a field on either `model` or `auth`.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* // model.id
|
|
110
|
+
* { type: 'fieldRef', source: 'model', field: 'id', start: 0, end: 8 }
|
|
111
|
+
*
|
|
112
|
+
* // userId - implicit auth context
|
|
113
|
+
* { type: 'fieldRef', source: 'auth', field: 'userId', start: 13, end: 19 }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export interface FieldRefNode {
|
|
117
|
+
type: 'fieldRef';
|
|
118
|
+
/** The source object - either 'model' or 'auth' */
|
|
119
|
+
source: 'model' | 'auth';
|
|
120
|
+
/** The field name being accessed */
|
|
121
|
+
field: string;
|
|
122
|
+
/** Start position in the source (for rename tracking) */
|
|
123
|
+
start: number;
|
|
124
|
+
/** End position in the source (for rename tracking) */
|
|
125
|
+
end: number;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Information extracted from a parsed expression for dependency tracking.
|
|
129
|
+
*/
|
|
130
|
+
export interface AuthorizerExpressionInfo {
|
|
131
|
+
/** The parsed AST */
|
|
132
|
+
ast: AuthorizerExpressionNode;
|
|
133
|
+
/** Model field names referenced (e.g., ['id', 'authorId']) */
|
|
134
|
+
modelFieldRefs: string[];
|
|
135
|
+
/** Auth field names referenced (e.g., ['userId']) */
|
|
136
|
+
authFieldRefs: string[];
|
|
137
|
+
/** Role names referenced (e.g., ['admin', 'user']) */
|
|
138
|
+
roleRefs: string[];
|
|
139
|
+
/** Whether the expression requires the model instance */
|
|
140
|
+
requiresModel: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Position information for error reporting.
|
|
144
|
+
* Compatible with Acorn AST nodes which have start/end properties.
|
|
145
|
+
*/
|
|
146
|
+
export interface NodePosition {
|
|
147
|
+
start: number;
|
|
148
|
+
end: number;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Error thrown when parsing an authorizer expression fails.
|
|
152
|
+
*/
|
|
153
|
+
export declare class AuthorizerExpressionParseError extends Error {
|
|
154
|
+
readonly startPosition?: number;
|
|
155
|
+
readonly endPosition?: number;
|
|
156
|
+
constructor(message: string, position?: NodePosition);
|
|
157
|
+
constructor(message: string, startPosition?: number, endPosition?: number);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=authorizer-expression-ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorizer-expression-ast.d.ts","sourceRoot":"","sources":["../../../../src/schema/models/authorizer/authorizer-expression-ast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAChC,mBAAmB,GACnB,WAAW,GACX,eAAe,GACf,iBAAiB,CAAC;AAEtB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,mCAAmC;IACnC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,wBAAwB,CAAC;IAC/B,KAAK,EAAE,wBAAwB,CAAC;CACjC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,mDAAmD;IACnD,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,qBAAqB;IACrB,GAAG,EAAE,wBAAwB,CAAC;IAC9B,8DAA8D;IAC9D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qDAAqD;IACrD,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,yDAAyD;IACzD,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,YAAY;gBACxC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;CAiB1E"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST node types for authorizer expressions.
|
|
3
|
+
*
|
|
4
|
+
* These represent the semantic structure of expressions like:
|
|
5
|
+
* - `model.id === userId`
|
|
6
|
+
* - `hasRole('admin')`
|
|
7
|
+
* - `hasSomeRole(['admin', 'moderator'])`
|
|
8
|
+
* - `model.id === userId || hasRole('admin')`
|
|
9
|
+
*
|
|
10
|
+
* The AST is produced by parsing with Acorn and converting from ESTree.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when parsing an authorizer expression fails.
|
|
14
|
+
*/
|
|
15
|
+
export class AuthorizerExpressionParseError extends Error {
|
|
16
|
+
startPosition;
|
|
17
|
+
endPosition;
|
|
18
|
+
constructor(message, positionOrStart, endPosition) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = 'AuthorizerExpressionParseError';
|
|
21
|
+
if (typeof positionOrStart === 'object') {
|
|
22
|
+
this.startPosition = positionOrStart.start;
|
|
23
|
+
this.endPosition = positionOrStart.end;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
this.startPosition = positionOrStart;
|
|
27
|
+
this.endPosition = endPosition;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=authorizer-expression-ast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorizer-expression-ast.js","sourceRoot":"","sources":["../../../../src/schema/models/authorizer/authorizer-expression-ast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAwJH;;GAEG;AACH,MAAM,OAAO,8BAA+B,SAAQ,KAAK;IAC9C,aAAa,CAAU;IACvB,WAAW,CAAU;IAI9B,YACE,OAAe,EACf,eAAuC,EACvC,WAAoB;QAEpB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC;QAE7C,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE,CAAC;YACxC,IAAI,CAAC,aAAa,GAAG,eAAe,CAAC,KAAK,CAAC;YAC3C,IAAI,CAAC,WAAW,GAAG,eAAe,CAAC,GAAG,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,aAAa,GAAG,eAAe,CAAC;YACrC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QACjC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { RefExpressionDependency, RefExpressionWarning, ResolvedExpressionSlots } from '#src/references/expression-types.js';
|
|
3
|
+
import { RefExpressionParser } from '#src/references/expression-types.js';
|
|
4
|
+
import type { modelEntityType } from '../types.js';
|
|
5
|
+
import type { AuthorizerExpressionInfo } from './authorizer-expression-ast.js';
|
|
6
|
+
/**
|
|
7
|
+
* Expression parser for model authorizer role expressions.
|
|
8
|
+
*
|
|
9
|
+
* Parses expressions like:
|
|
10
|
+
* - `model.id === auth.userId` (ownership check)
|
|
11
|
+
* - `auth.hasRole('admin')` (global role check)
|
|
12
|
+
* - `model.id === auth.userId || auth.hasRole('admin')` (combined)
|
|
13
|
+
*
|
|
14
|
+
* Uses Acorn to parse JavaScript expressions and validates
|
|
15
|
+
* that only supported constructs are used.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const schema = z.object({
|
|
20
|
+
* expression: ctx.withExpression(authorizerExpressionParser, { model: modelSlot }),
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class AuthorizerExpressionParser extends RefExpressionParser<string, AuthorizerExpressionInfo | undefined, {
|
|
25
|
+
model: typeof modelEntityType;
|
|
26
|
+
}> {
|
|
27
|
+
readonly name = "authorizer-expression";
|
|
28
|
+
/**
|
|
29
|
+
* Zod schema for validating expression strings.
|
|
30
|
+
* Requires a non-empty string value.
|
|
31
|
+
*/
|
|
32
|
+
readonly schema: z.ZodString;
|
|
33
|
+
/**
|
|
34
|
+
* Parse the expression string into an AST.
|
|
35
|
+
*
|
|
36
|
+
* @param value - The expression string
|
|
37
|
+
* @param _projectDef - The project definition (unused during parsing)
|
|
38
|
+
* @returns The parsed expression info, or undefined if parsing fails
|
|
39
|
+
*/
|
|
40
|
+
parse(value: string): AuthorizerExpressionInfo | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Get validation warnings for the expression.
|
|
43
|
+
*
|
|
44
|
+
* Validates:
|
|
45
|
+
* - Syntax errors from parsing
|
|
46
|
+
* - Model field references exist
|
|
47
|
+
* - Auth field references are valid
|
|
48
|
+
* - Role names exist in project config (warning only)
|
|
49
|
+
*/
|
|
50
|
+
getWarnings(value: string, parseResult: AuthorizerExpressionInfo | undefined, projectDef: unknown, resolvedSlots: ResolvedExpressionSlots<{
|
|
51
|
+
model: typeof modelEntityType;
|
|
52
|
+
}>): RefExpressionWarning[];
|
|
53
|
+
/**
|
|
54
|
+
* Get entity/field dependencies from the expression.
|
|
55
|
+
*
|
|
56
|
+
* Currently returns empty array as we don't yet track
|
|
57
|
+
* entity-level dependencies (just field names).
|
|
58
|
+
* Future: could track model field entity references for renames.
|
|
59
|
+
*/
|
|
60
|
+
getDependencies(): RefExpressionDependency[];
|
|
61
|
+
/**
|
|
62
|
+
* Update the expression when dependencies are renamed.
|
|
63
|
+
*
|
|
64
|
+
* Currently returns value unchanged as we don't yet
|
|
65
|
+
* support field renames in expressions.
|
|
66
|
+
*/
|
|
67
|
+
updateForRename(value: string): string;
|
|
68
|
+
/**
|
|
69
|
+
* Extract model context from the project definition container using resolved slots.
|
|
70
|
+
*/
|
|
71
|
+
private getModelContext;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Singleton instance of AuthorizerExpressionParser.
|
|
75
|
+
*/
|
|
76
|
+
export declare const authorizerExpressionParser: AuthorizerExpressionParser;
|
|
77
|
+
//# sourceMappingURL=authorizer-expression-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorizer-expression-parser.d.ts","sourceRoot":"","sources":["../../../../src/schema/models/authorizer/authorizer-expression-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EACV,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACxB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAE1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAM/E;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB,CACjE,MAAM,EACN,wBAAwB,GAAG,SAAS,EACpC;IAAE,KAAK,EAAE,OAAO,eAAe,CAAA;CAAE,CAClC;IACC,QAAQ,CAAC,IAAI,2BAA2B;IAExC;;;OAGG;IACH,QAAQ,CAAC,MAAM,cAA+C;IAE9D;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS;IAY1D;;;;;;;;OAQG;IACH,WAAW,CACT,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,wBAAwB,GAAG,SAAS,EACjD,UAAU,EAAE,OAAO,EACnB,aAAa,EAAE,uBAAuB,CAAC;QAAE,KAAK,EAAE,OAAO,eAAe,CAAA;KAAE,CAAC,GACxE,oBAAoB,EAAE;IAuCzB;;;;;;OAMG;IACH,eAAe,IAAI,uBAAuB,EAAE;IAK5C;;;;;OAKG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAKtC;;OAEG;IACH,OAAO,CAAC,eAAe;CAyCxB;AAED;;GAEG;AACH,eAAO,MAAM,0BAA0B,4BAAmC,CAAC"}
|