@opensaas/stack-core 0.1.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/.turbo/turbo-build.log +4 -0
- package/README.md +447 -0
- package/dist/access/engine.d.ts +73 -0
- package/dist/access/engine.d.ts.map +1 -0
- package/dist/access/engine.js +244 -0
- package/dist/access/engine.js.map +1 -0
- package/dist/access/field-transforms.d.ts +47 -0
- package/dist/access/field-transforms.d.ts.map +1 -0
- package/dist/access/field-transforms.js +2 -0
- package/dist/access/field-transforms.js.map +1 -0
- package/dist/access/index.d.ts +3 -0
- package/dist/access/index.d.ts.map +1 -0
- package/dist/access/index.js +2 -0
- package/dist/access/index.js.map +1 -0
- package/dist/access/types.d.ts +83 -0
- package/dist/access/types.d.ts.map +1 -0
- package/dist/access/types.js +2 -0
- package/dist/access/types.js.map +1 -0
- package/dist/config/index.d.ts +39 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +38 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +413 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/context/index.d.ts +31 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +524 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/nested-operations.d.ts +10 -0
- package/dist/context/nested-operations.d.ts.map +1 -0
- package/dist/context/nested-operations.js +261 -0
- package/dist/context/nested-operations.js.map +1 -0
- package/dist/fields/index.d.ts +78 -0
- package/dist/fields/index.d.ts.map +1 -0
- package/dist/fields/index.js +381 -0
- package/dist/fields/index.js.map +1 -0
- package/dist/hooks/index.d.ts +58 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +79 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/case-utils.d.ts +49 -0
- package/dist/lib/case-utils.d.ts.map +1 -0
- package/dist/lib/case-utils.js +68 -0
- package/dist/lib/case-utils.js.map +1 -0
- package/dist/lib/case-utils.test.d.ts +2 -0
- package/dist/lib/case-utils.test.d.ts.map +1 -0
- package/dist/lib/case-utils.test.js +101 -0
- package/dist/lib/case-utils.test.js.map +1 -0
- package/dist/utils/password.d.ts +81 -0
- package/dist/utils/password.d.ts.map +1 -0
- package/dist/utils/password.js +132 -0
- package/dist/utils/password.js.map +1 -0
- package/dist/validation/schema.d.ts +17 -0
- package/dist/validation/schema.d.ts.map +1 -0
- package/dist/validation/schema.js +42 -0
- package/dist/validation/schema.js.map +1 -0
- package/dist/validation/schema.test.d.ts +2 -0
- package/dist/validation/schema.test.d.ts.map +1 -0
- package/dist/validation/schema.test.js +143 -0
- package/dist/validation/schema.test.js.map +1 -0
- package/docs/type-distribution-fix.md +136 -0
- package/package.json +48 -0
- package/src/access/engine.ts +360 -0
- package/src/access/field-transforms.ts +99 -0
- package/src/access/index.ts +20 -0
- package/src/access/types.ts +103 -0
- package/src/config/index.ts +71 -0
- package/src/config/types.ts +478 -0
- package/src/context/index.ts +814 -0
- package/src/context/nested-operations.ts +412 -0
- package/src/fields/index.ts +438 -0
- package/src/hooks/index.ts +132 -0
- package/src/index.ts +62 -0
- package/src/lib/case-utils.test.ts +127 -0
- package/src/lib/case-utils.ts +74 -0
- package/src/utils/password.ts +147 -0
- package/src/validation/schema.test.ts +171 -0
- package/src/validation/schema.ts +59 -0
- package/tests/access-relationships.test.ts +613 -0
- package/tests/access.test.ts +499 -0
- package/tests/config.test.ts +195 -0
- package/tests/context.test.ts +248 -0
- package/tests/hooks.test.ts +417 -0
- package/tests/password-type-distribution.test.ts +155 -0
- package/tests/password-types.test.ts +147 -0
- package/tests/password.test.ts +249 -0
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +27 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if access control result is a boolean
|
|
3
|
+
*/
|
|
4
|
+
export function isBoolean(value) {
|
|
5
|
+
return typeof value === 'boolean';
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Check if access control result is a Prisma filter
|
|
9
|
+
*/
|
|
10
|
+
export function isPrismaFilter(value) {
|
|
11
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse a relationship ref and get the related list configuration
|
|
15
|
+
* Relationship refs are in the format "ListName.fieldName"
|
|
16
|
+
*
|
|
17
|
+
* @param relationshipRef - The ref string (e.g., "Post.author")
|
|
18
|
+
* @param config - The OpenSaas configuration
|
|
19
|
+
* @returns The related list name and config, or null if not found
|
|
20
|
+
*/
|
|
21
|
+
export function getRelatedListConfig(relationshipRef, config) {
|
|
22
|
+
// Parse ref format: "ListName.fieldName"
|
|
23
|
+
const parts = relationshipRef.split('.');
|
|
24
|
+
if (parts.length !== 2) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const listName = parts[0];
|
|
28
|
+
const listConfig = config.lists[listName];
|
|
29
|
+
if (!listConfig) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return { listName, listConfig };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Execute an access control function
|
|
36
|
+
*/
|
|
37
|
+
export async function checkAccess(accessControl, args) {
|
|
38
|
+
// No access control means deny by default
|
|
39
|
+
if (!accessControl) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
// Execute the access control function
|
|
43
|
+
const result = await accessControl(args);
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Merge user filter with access control filter
|
|
48
|
+
*/
|
|
49
|
+
export function mergeFilters(userFilter, accessFilter) {
|
|
50
|
+
// If access is denied, return null
|
|
51
|
+
if (accessFilter === false) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
// If access is fully granted, use user filter
|
|
55
|
+
if (accessFilter === true) {
|
|
56
|
+
return userFilter || {};
|
|
57
|
+
}
|
|
58
|
+
// Merge access filter with user filter
|
|
59
|
+
if (!userFilter) {
|
|
60
|
+
return accessFilter;
|
|
61
|
+
}
|
|
62
|
+
// Combine filters with AND
|
|
63
|
+
return {
|
|
64
|
+
AND: [accessFilter, userFilter],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check field-level access for a specific operation
|
|
69
|
+
*/
|
|
70
|
+
export async function checkFieldAccess(fieldAccess, operation, args) {
|
|
71
|
+
if (!fieldAccess) {
|
|
72
|
+
return true; // No field access means allow
|
|
73
|
+
}
|
|
74
|
+
const accessControl = fieldAccess[operation];
|
|
75
|
+
if (!accessControl) {
|
|
76
|
+
return true; // No specific access control means allow
|
|
77
|
+
}
|
|
78
|
+
const result = await accessControl(args);
|
|
79
|
+
// If result is false, deny access
|
|
80
|
+
if (result === false) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
// If result is true, allow access
|
|
84
|
+
if (result === true) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
// If result is a filter object, check if the item matches
|
|
88
|
+
// For field-level access, we need to evaluate the filter against the item
|
|
89
|
+
if (typeof result === 'object' && args.item) {
|
|
90
|
+
return matchesFilter(args.item, result);
|
|
91
|
+
}
|
|
92
|
+
// Default to allowing access if we can't determine
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Simple filter matching for field-level access
|
|
97
|
+
* Checks if an item matches a Prisma-like filter object
|
|
98
|
+
*/
|
|
99
|
+
function matchesFilter(item, filter) {
|
|
100
|
+
for (const [key, condition] of Object.entries(filter)) {
|
|
101
|
+
if (typeof condition === 'object' && condition !== null) {
|
|
102
|
+
// Handle nested conditions like { equals: value }
|
|
103
|
+
if ('equals' in condition) {
|
|
104
|
+
if (item[key] !== condition.equals) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if ('not' in condition) {
|
|
109
|
+
if (item[key] === condition.not) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Add more condition types as needed
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// Direct equality check
|
|
117
|
+
if (item[key] !== condition) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Build Prisma include object with access control filters
|
|
126
|
+
* This allows us to filter relationships at the database level instead of in memory
|
|
127
|
+
*/
|
|
128
|
+
export async function buildIncludeWithAccessControl(fieldConfigs, args, config, depth = 0) {
|
|
129
|
+
const MAX_DEPTH = 5;
|
|
130
|
+
if (depth >= MAX_DEPTH) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
const include = {};
|
|
134
|
+
let hasRelationships = false;
|
|
135
|
+
for (const [fieldName, fieldConfig] of Object.entries(fieldConfigs)) {
|
|
136
|
+
if (fieldConfig?.type === 'relationship' && 'ref' in fieldConfig && fieldConfig.ref) {
|
|
137
|
+
hasRelationships = true;
|
|
138
|
+
const relatedConfig = getRelatedListConfig(fieldConfig.ref, config);
|
|
139
|
+
if (relatedConfig) {
|
|
140
|
+
// Check query access for the related list
|
|
141
|
+
const queryAccess = relatedConfig.listConfig.access?.operation?.query;
|
|
142
|
+
const accessResult = await checkAccess(queryAccess, {
|
|
143
|
+
session: args.session,
|
|
144
|
+
context: args.context,
|
|
145
|
+
});
|
|
146
|
+
// If access is completely denied, exclude this relationship
|
|
147
|
+
if (accessResult === false) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// Build the include entry
|
|
151
|
+
const includeEntry = {};
|
|
152
|
+
// If access returns a filter, add it to the where clause
|
|
153
|
+
if (typeof accessResult === 'object') {
|
|
154
|
+
includeEntry.where = accessResult;
|
|
155
|
+
}
|
|
156
|
+
// Recursively build nested includes
|
|
157
|
+
const nestedInclude = await buildIncludeWithAccessControl(relatedConfig.listConfig.fields, args, config, depth + 1);
|
|
158
|
+
if (nestedInclude && Object.keys(nestedInclude).length > 0) {
|
|
159
|
+
includeEntry.include = nestedInclude;
|
|
160
|
+
}
|
|
161
|
+
// Add to include object
|
|
162
|
+
include[fieldName] = Object.keys(includeEntry).length > 0 ? includeEntry : true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return hasRelationships ? include : undefined;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Filter fields from an object based on read access
|
|
170
|
+
* Recursively applies access control to nested relationships
|
|
171
|
+
*/
|
|
172
|
+
export async function filterReadableFields(item, fieldConfigs, args, config, depth = 0) {
|
|
173
|
+
const filtered = {};
|
|
174
|
+
const MAX_DEPTH = 5; // Prevent infinite recursion
|
|
175
|
+
for (const [fieldName, value] of Object.entries(item)) {
|
|
176
|
+
const fieldConfig = fieldConfigs[fieldName];
|
|
177
|
+
// Always include id, createdAt, updatedAt
|
|
178
|
+
if (['id', 'createdAt', 'updatedAt'].includes(fieldName)) {
|
|
179
|
+
filtered[fieldName] = value;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
// Check field access
|
|
183
|
+
const canRead = await checkFieldAccess(fieldConfig?.access, 'read', {
|
|
184
|
+
...args,
|
|
185
|
+
item,
|
|
186
|
+
});
|
|
187
|
+
if (!canRead) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
// Handle relationship fields - recursively filter fields within related items
|
|
191
|
+
// Note: Access control filtering is now done at database level via buildIncludeWithAccessControl
|
|
192
|
+
// This only handles field-level access (hiding sensitive fields)
|
|
193
|
+
if (config &&
|
|
194
|
+
fieldConfig?.type === 'relationship' &&
|
|
195
|
+
'ref' in fieldConfig &&
|
|
196
|
+
fieldConfig.ref &&
|
|
197
|
+
value !== null &&
|
|
198
|
+
value !== undefined &&
|
|
199
|
+
depth < MAX_DEPTH) {
|
|
200
|
+
const relatedConfig = getRelatedListConfig(fieldConfig.ref, config);
|
|
201
|
+
if (relatedConfig) {
|
|
202
|
+
// For many relationships (arrays) - recursively filter fields in each item
|
|
203
|
+
if (Array.isArray(value)) {
|
|
204
|
+
filtered[fieldName] = await Promise.all(value.map((relatedItem) => filterReadableFields(relatedItem, relatedConfig.listConfig.fields, args, config, depth + 1)));
|
|
205
|
+
}
|
|
206
|
+
// For single relationships (objects) - recursively filter fields
|
|
207
|
+
else if (typeof value === 'object') {
|
|
208
|
+
filtered[fieldName] = await filterReadableFields(value, relatedConfig.listConfig.fields, args, config, depth + 1);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// Related config not found, include the value as-is
|
|
213
|
+
filtered[fieldName] = value;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
// Non-relationship field or no config provided
|
|
218
|
+
filtered[fieldName] = value;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return filtered;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Filter fields from input data based on write access (create/update)
|
|
225
|
+
*/
|
|
226
|
+
export async function filterWritableFields(data, fieldConfigs, operation, args) {
|
|
227
|
+
const filtered = {};
|
|
228
|
+
for (const [fieldName, value] of Object.entries(data)) {
|
|
229
|
+
const fieldConfig = fieldConfigs[fieldName];
|
|
230
|
+
// Skip system fields
|
|
231
|
+
if (['id', 'createdAt', 'updatedAt'].includes(fieldName)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
// Check field access
|
|
235
|
+
const canWrite = await checkFieldAccess(fieldConfig?.access, operation, {
|
|
236
|
+
...args,
|
|
237
|
+
});
|
|
238
|
+
if (canWrite) {
|
|
239
|
+
filtered[fieldName] = value;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return filtered;
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/access/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { OpenSaasConfig, FieldConfig } from '../config/types.js';
|
|
2
|
+
import type { HashedPassword } from '../utils/password.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract the return type of a field's afterOperation hook
|
|
5
|
+
* If the field has an afterOperation hook, infer its return type
|
|
6
|
+
* Otherwise, use the original type
|
|
7
|
+
*/
|
|
8
|
+
export type InferFieldReadType<TField extends FieldConfig, TOriginal> = TField extends {
|
|
9
|
+
hooks?: {
|
|
10
|
+
afterOperation?: (...args: any[]) => infer R;
|
|
11
|
+
};
|
|
12
|
+
} ? R extends never ? TOriginal : R : TOriginal;
|
|
13
|
+
/**
|
|
14
|
+
* Transform a Prisma model's field types based on OpenSaas field configs
|
|
15
|
+
* This applies afterOperation hook transformations to field types
|
|
16
|
+
*/
|
|
17
|
+
export type TransformModelFields<TModel extends Record<string, any>, TFields extends Record<string, FieldConfig>> = {
|
|
18
|
+
[K in keyof TModel]: K extends keyof TFields ? InferFieldReadType<TFields[K], TModel[K]> : TModel[K];
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Get the field configs for a specific list from the OpenSaas config
|
|
22
|
+
*/
|
|
23
|
+
export type GetListFields<TConfig extends OpenSaasConfig, TListKey extends keyof TConfig['lists']> = TConfig['lists'][TListKey]['fields'];
|
|
24
|
+
/**
|
|
25
|
+
* Transform a Prisma model result based on OpenSaas config
|
|
26
|
+
* Applies field hooks transformations
|
|
27
|
+
*/
|
|
28
|
+
export type TransformResult<TConfig extends OpenSaasConfig, TListKey extends keyof TConfig['lists'], TResult> = TResult extends Record<string, any> ? TransformModelFields<TResult, GetListFields<TConfig, TListKey>> : TResult;
|
|
29
|
+
/**
|
|
30
|
+
* Transform a Prisma operation's return type
|
|
31
|
+
* Handles single results, arrays, and null cases
|
|
32
|
+
*/
|
|
33
|
+
export type TransformOperationResult<TConfig extends OpenSaasConfig, TListKey extends keyof TConfig['lists'], TResult> = TResult extends Promise<infer R> ? Promise<R extends Array<infer Item> ? Array<TransformResult<TConfig, TListKey, Item>> : R extends null ? null : TransformResult<TConfig, TListKey, R>> : never;
|
|
34
|
+
/**
|
|
35
|
+
* Known field type mappings for afterOperation hooks
|
|
36
|
+
* These provide concrete type hints for common field transformations
|
|
37
|
+
*/
|
|
38
|
+
export interface FieldTypeTransforms {
|
|
39
|
+
password: HashedPassword;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Helper to infer field type based on field config type
|
|
43
|
+
*/
|
|
44
|
+
export type InferFieldTypeTransform<TField extends FieldConfig> = TField extends {
|
|
45
|
+
type: infer TType;
|
|
46
|
+
} ? TType extends keyof FieldTypeTransforms ? FieldTypeTransforms[TType] : never : never;
|
|
47
|
+
//# sourceMappingURL=field-transforms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-transforms.d.ts","sourceRoot":"","sources":["../../src/access/field-transforms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,CAAC,MAAM,SAAS,WAAW,EAAE,SAAS,IAAI,MAAM,SAAS;IAIrF,KAAK,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,CAAA;KAAE,CAAA;CACzD,GACG,CAAC,SAAS,KAAK,GACb,SAAS,GACT,CAAC,GACH,SAAS,CAAA;AAEb;;;GAGG;AACH,MAAM,MAAM,oBAAoB,CAI9B,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IACzC;KACD,CAAC,IAAI,MAAM,MAAM,GAAG,CAAC,SAAS,MAAM,OAAO,GACxC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,GACzC,MAAM,CAAC,CAAC,CAAC;CACd,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CACvB,OAAO,SAAS,cAAc,EAC9B,QAAQ,SAAS,MAAM,OAAO,CAAC,OAAO,CAAC,IACrC,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAA;AAExC;;;GAGG;AACH,MAAM,MAAM,eAAe,CACzB,OAAO,SAAS,cAAc,EAC9B,QAAQ,SAAS,MAAM,OAAO,CAAC,OAAO,CAAC,EACvC,OAAO,IAKP,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC/B,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,GAC/D,OAAO,CAAA;AAEb;;;GAGG;AACH,MAAM,MAAM,wBAAwB,CAClC,OAAO,SAAS,cAAc,EAC9B,QAAQ,SAAS,MAAM,OAAO,CAAC,OAAO,CAAC,EACvC,OAAO,IAEP,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAC5B,OAAO,CACL,CAAC,SAAS,KAAK,CAAC,MAAM,IAAI,CAAC,GACvB,KAAK,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,GAC/C,CAAC,SAAS,IAAI,GACZ,IAAI,GACJ,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,CAC5C,GACD,KAAK,CAAA;AAEX;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,cAAc,CAAA;CAIzB;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,CAAC,MAAM,SAAS,WAAW,IAAI,MAAM,SAAS;IAC/E,IAAI,EAAE,MAAM,KAAK,CAAA;CAClB,GACG,KAAK,SAAS,MAAM,mBAAmB,GACrC,mBAAmB,CAAC,KAAK,CAAC,GAC1B,KAAK,GACP,KAAK,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-transforms.js","sourceRoot":"","sources":["../../src/access/field-transforms.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { AccessControl, FieldAccess, Session, AccessContext, PrismaFilter, AccessControlledDB, PrismaClientLike, } from './types.js';
|
|
2
|
+
export { checkAccess, mergeFilters, checkFieldAccess, filterReadableFields, filterWritableFields, isBoolean, isPrismaFilter, getRelatedListConfig, buildIncludeWithAccessControl, } from './engine.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/access/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,WAAW,EACX,OAAO,EACP,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/access/index.ts"],"names":[],"mappings":"AASA,OAAO,EACL,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session type - can be extended by users
|
|
3
|
+
*/
|
|
4
|
+
export type Session = {
|
|
5
|
+
userId?: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
} | null;
|
|
8
|
+
/**
|
|
9
|
+
* Generic Prisma model delegate type
|
|
10
|
+
*/
|
|
11
|
+
export type PrismaModelDelegate = {
|
|
12
|
+
findUnique: (args: unknown) => Promise<unknown>;
|
|
13
|
+
findFirst: (args: unknown) => Promise<unknown>;
|
|
14
|
+
findMany: (args: unknown) => Promise<unknown[]>;
|
|
15
|
+
create: (args: unknown) => Promise<unknown>;
|
|
16
|
+
update: (args: unknown) => Promise<unknown>;
|
|
17
|
+
delete: (args: unknown) => Promise<unknown>;
|
|
18
|
+
count: (args?: unknown) => Promise<number>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Generic Prisma client type
|
|
22
|
+
* This is intentionally permissive to allow actual PrismaClient types
|
|
23
|
+
* Uses `any` because Prisma generates highly complex client types that are difficult to constrain
|
|
24
|
+
* This type is used as a generic constraint and the actual type safety comes from TPrisma parameter
|
|
25
|
+
*/
|
|
26
|
+
export type PrismaClientLike = any;
|
|
27
|
+
/**
|
|
28
|
+
* Map Prisma client to access-controlled database context
|
|
29
|
+
* Preserves Prisma's type information for each model
|
|
30
|
+
*/
|
|
31
|
+
export type AccessControlledDB<TPrisma extends PrismaClientLike> = {
|
|
32
|
+
[K in keyof TPrisma]: TPrisma[K] extends {
|
|
33
|
+
findUnique: any;
|
|
34
|
+
findMany: any;
|
|
35
|
+
create: any;
|
|
36
|
+
update: any;
|
|
37
|
+
delete: any;
|
|
38
|
+
count: any;
|
|
39
|
+
} ? {
|
|
40
|
+
findUnique: TPrisma[K]['findUnique'];
|
|
41
|
+
findMany: TPrisma[K]['findMany'];
|
|
42
|
+
create: TPrisma[K]['create'];
|
|
43
|
+
update: TPrisma[K]['update'];
|
|
44
|
+
delete: TPrisma[K]['delete'];
|
|
45
|
+
count: TPrisma[K]['count'];
|
|
46
|
+
} : never;
|
|
47
|
+
} & {
|
|
48
|
+
[key: string]: any;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Context type (simplified for access control)
|
|
52
|
+
*/
|
|
53
|
+
export type AccessContext<TPrisma extends PrismaClientLike = PrismaClientLike> = {
|
|
54
|
+
session: Session;
|
|
55
|
+
prisma: TPrisma;
|
|
56
|
+
db: AccessControlledDB<TPrisma>;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Prisma filter type - represents a where clause
|
|
61
|
+
* Uses Partial to allow filtering by any subset of fields
|
|
62
|
+
*/
|
|
63
|
+
export type PrismaFilter<T = Record<string, unknown>> = Partial<Record<keyof T, unknown>>;
|
|
64
|
+
/**
|
|
65
|
+
* Access control function type
|
|
66
|
+
* Can return:
|
|
67
|
+
* - boolean: true = allow, false = deny
|
|
68
|
+
* - PrismaFilter: Prisma where clause to filter results
|
|
69
|
+
*/
|
|
70
|
+
export type AccessControl<T = Record<string, unknown>> = (args: {
|
|
71
|
+
session: Session;
|
|
72
|
+
item?: T;
|
|
73
|
+
context: AccessContext;
|
|
74
|
+
}) => boolean | PrismaFilter<T> | Promise<boolean | PrismaFilter<T>>;
|
|
75
|
+
/**
|
|
76
|
+
* Field-level access control
|
|
77
|
+
*/
|
|
78
|
+
export type FieldAccess = {
|
|
79
|
+
read?: AccessControl;
|
|
80
|
+
create?: AccessControl;
|
|
81
|
+
update?: AccessControl;
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/access/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/access/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { OpenSaasConfig, ListConfig, FieldConfig, OperationAccess, Hooks } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Helper function to define configuration with type safety
|
|
4
|
+
*/
|
|
5
|
+
export declare function config(config: OpenSaasConfig): OpenSaasConfig;
|
|
6
|
+
/**
|
|
7
|
+
* Helper function to define a list with type safety
|
|
8
|
+
*
|
|
9
|
+
* Accepts raw field configs and transforms them to inject the item type T
|
|
10
|
+
* This enables proper typing in field hooks where item: T
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import type { User } from './.opensaas/types'
|
|
15
|
+
*
|
|
16
|
+
* User: list<User>({
|
|
17
|
+
* fields: {
|
|
18
|
+
* password: password({
|
|
19
|
+
* hooks: {
|
|
20
|
+
* resolveInput: async ({ inputValue, item }) => {
|
|
21
|
+
* // item is typed as User | undefined
|
|
22
|
+
* // inputValue is typed as string | undefined
|
|
23
|
+
* return hashPassword(inputValue)
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* })
|
|
27
|
+
* }
|
|
28
|
+
* })
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function list<T = any>(config: {
|
|
32
|
+
fields: Record<string, FieldConfig>;
|
|
33
|
+
access?: {
|
|
34
|
+
operation?: OperationAccess<T>;
|
|
35
|
+
};
|
|
36
|
+
hooks?: Hooks<T>;
|
|
37
|
+
}): ListConfig<T>;
|
|
38
|
+
export type { OpenSaasConfig, ListConfig, FieldConfig, BaseFieldConfig, TextField, IntegerField, CheckboxField, TimestampField, PasswordField, SelectField, RelationshipField, OperationAccess, Hooks, FieldHooks, FieldsWithItemType, DatabaseConfig, SessionConfig, UIConfig, ThemeConfig, ThemePreset, ThemeColors, } from './types.js';
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAEjG;;GAEG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAE7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,wBAAgB,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACnC,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAA;KAC/B,CAAA;IACD,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;CACjB,GAAG,UAAU,CAAC,CAAC,CAAC,CAIhB;AAGD,YAAY,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,EACT,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,KAAK,EACL,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,QAAQ,EACR,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to define configuration with type safety
|
|
3
|
+
*/
|
|
4
|
+
export function config(config) {
|
|
5
|
+
return config;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Helper function to define a list with type safety
|
|
9
|
+
*
|
|
10
|
+
* Accepts raw field configs and transforms them to inject the item type T
|
|
11
|
+
* This enables proper typing in field hooks where item: T
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import type { User } from './.opensaas/types'
|
|
16
|
+
*
|
|
17
|
+
* User: list<User>({
|
|
18
|
+
* fields: {
|
|
19
|
+
* password: password({
|
|
20
|
+
* hooks: {
|
|
21
|
+
* resolveInput: async ({ inputValue, item }) => {
|
|
22
|
+
* // item is typed as User | undefined
|
|
23
|
+
* // inputValue is typed as string | undefined
|
|
24
|
+
* return hashPassword(inputValue)
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* })
|
|
28
|
+
* }
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
export function list(config) {
|
|
34
|
+
// At runtime, field configs are unchanged
|
|
35
|
+
// At type level, they're transformed to inject T as the item type
|
|
36
|
+
return config;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,MAAsB;IAC3C,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,8DAA8D;AAC9D,MAAM,UAAU,IAAI,CAAU,MAM7B;IACC,0CAA0C;IAC1C,kEAAkE;IAClE,OAAO,MAAuB,CAAA;AAChC,CAAC"}
|