@opensaas/stack-core 0.38.0 → 0.39.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 +1 -1
- package/CHANGELOG.md +123 -0
- package/CLAUDE.md +21 -0
- package/dist/access/access-filter.d.ts +46 -1
- package/dist/access/access-filter.d.ts.map +1 -1
- package/dist/access/access-filter.js +113 -4
- package/dist/access/access-filter.js.map +1 -1
- package/dist/access/declared-dependencies.d.ts.map +1 -1
- package/dist/access/declared-dependencies.js +4 -9
- package/dist/access/declared-dependencies.js.map +1 -1
- package/dist/access/engine.d.ts +0 -20
- package/dist/access/engine.d.ts.map +1 -1
- package/dist/access/engine.js +0 -25
- package/dist/access/engine.js.map +1 -1
- package/dist/access/errors.d.ts +49 -0
- package/dist/access/errors.d.ts.map +1 -1
- package/dist/access/errors.js +75 -0
- package/dist/access/errors.js.map +1 -1
- package/dist/access/field-access.d.ts +39 -1
- package/dist/access/field-access.d.ts.map +1 -1
- package/dist/access/field-access.js +108 -42
- package/dist/access/field-access.js.map +1 -1
- package/dist/access/field-access.test.js +229 -2
- package/dist/access/field-access.test.js.map +1 -1
- package/dist/access/field-transforms.d.ts +0 -27
- package/dist/access/field-transforms.d.ts.map +1 -1
- package/dist/access/field-visibility.d.ts +0 -4
- package/dist/access/field-visibility.d.ts.map +1 -1
- package/dist/access/field-visibility.js +13 -39
- package/dist/access/field-visibility.js.map +1 -1
- package/dist/access/index.d.ts +6 -2
- package/dist/access/index.d.ts.map +1 -1
- package/dist/access/index.js +12 -2
- package/dist/access/index.js.map +1 -1
- package/dist/access/query-validation.d.ts +121 -0
- package/dist/access/query-validation.d.ts.map +1 -0
- package/dist/access/query-validation.js +292 -0
- package/dist/access/query-validation.js.map +1 -0
- package/dist/access/relationship-count.d.ts.map +1 -1
- package/dist/access/relationship-count.js +2 -10
- package/dist/access/relationship-count.js.map +1 -1
- package/dist/access/relationship-label-filter.d.ts +23 -23
- package/dist/access/relationship-label-filter.d.ts.map +1 -1
- package/dist/access/relationship-label-filter.js +5 -76
- package/dist/access/relationship-label-filter.js.map +1 -1
- package/dist/access/relationship-label-filter.test.js +19 -56
- package/dist/access/relationship-label-filter.test.js.map +1 -1
- package/dist/access/transaction-registry.d.ts +45 -0
- package/dist/access/transaction-registry.d.ts.map +1 -0
- package/dist/access/transaction-registry.js +37 -0
- package/dist/access/transaction-registry.js.map +1 -0
- package/dist/access/types.d.ts +55 -59
- package/dist/access/types.d.ts.map +1 -1
- package/dist/config/index.d.ts +9 -7
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +10 -18
- package/dist/config/index.js.map +1 -1
- package/dist/config/label.d.ts +6 -13
- package/dist/config/label.d.ts.map +1 -1
- package/dist/config/label.js +6 -13
- package/dist/config/label.js.map +1 -1
- package/dist/config/nav-count.d.ts +11 -19
- package/dist/config/nav-count.d.ts.map +1 -1
- package/dist/config/nav-count.js +11 -19
- package/dist/config/nav-count.js.map +1 -1
- package/dist/config/plugin-engine.d.ts +0 -10
- package/dist/config/plugin-engine.d.ts.map +1 -1
- package/dist/config/plugin-engine.js +1 -37
- package/dist/config/plugin-engine.js.map +1 -1
- package/dist/config/types.d.ts +94 -109
- package/dist/config/types.d.ts.map +1 -1
- package/dist/context/apply-defaults.d.ts +8 -31
- package/dist/context/apply-defaults.d.ts.map +1 -1
- package/dist/context/apply-defaults.js +12 -41
- package/dist/context/apply-defaults.js.map +1 -1
- package/dist/context/hook-pipeline.d.ts +4 -29
- package/dist/context/hook-pipeline.d.ts.map +1 -1
- package/dist/context/hook-pipeline.js +8 -41
- package/dist/context/hook-pipeline.js.map +1 -1
- package/dist/context/index.d.ts +4 -15
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +190 -193
- package/dist/context/index.js.map +1 -1
- package/dist/context/nested-operations.d.ts +7 -26
- package/dist/context/nested-operations.d.ts.map +1 -1
- package/dist/context/nested-operations.js +73 -171
- package/dist/context/nested-operations.js.map +1 -1
- package/dist/context/transaction-boundary.d.ts +36 -47
- package/dist/context/transaction-boundary.d.ts.map +1 -1
- package/dist/context/transaction-boundary.js +92 -79
- package/dist/context/transaction-boundary.js.map +1 -1
- package/dist/context/write-pipeline.d.ts +25 -64
- package/dist/context/write-pipeline.d.ts.map +1 -1
- package/dist/context/write-pipeline.js +81 -111
- package/dist/context/write-pipeline.js.map +1 -1
- package/dist/fields/format-prisma-default.d.ts.map +1 -1
- package/dist/fields/format-prisma-default.js +4 -7
- package/dist/fields/format-prisma-default.js.map +1 -1
- package/dist/fields/index.d.ts +17 -2
- package/dist/fields/index.d.ts.map +1 -1
- package/dist/fields/index.js +136 -147
- package/dist/fields/index.js.map +1 -1
- package/dist/filter/collect.d.ts +26 -3
- package/dist/filter/collect.d.ts.map +1 -1
- package/dist/filter/collect.js +30 -12
- package/dist/filter/collect.js.map +1 -1
- package/dist/filter/filter.test.js +98 -15
- package/dist/filter/filter.test.js.map +1 -1
- package/dist/filter/index.d.ts +1 -0
- package/dist/filter/index.d.ts.map +1 -1
- package/dist/filter/index.js.map +1 -1
- package/dist/filter/map.d.ts.map +1 -1
- package/dist/filter/map.js +0 -5
- package/dist/filter/map.js.map +1 -1
- package/dist/filter/parse.d.ts.map +1 -1
- package/dist/filter/parse.js +2 -9
- package/dist/filter/parse.js.map +1 -1
- package/dist/filter/serialize.d.ts.map +1 -1
- package/dist/filter/serialize.js +2 -4
- package/dist/filter/serialize.js.map +1 -1
- package/dist/hooks/index.d.ts +4 -42
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +5 -59
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -4
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +4 -0
- package/dist/internal.js.map +1 -1
- package/dist/lib/case-utils.d.ts +0 -32
- package/dist/lib/case-utils.d.ts.map +1 -1
- package/dist/lib/case-utils.js +0 -32
- package/dist/lib/case-utils.js.map +1 -1
- package/dist/mcp/handler.d.ts +0 -4
- package/dist/mcp/handler.d.ts.map +1 -1
- package/dist/mcp/handler.js +12 -69
- package/dist/mcp/handler.js.map +1 -1
- package/dist/query/index.d.ts +26 -227
- package/dist/query/index.d.ts.map +1 -1
- package/dist/query/index.js +14 -117
- package/dist/query/index.js.map +1 -1
- package/dist/utils/password.d.ts +0 -68
- package/dist/utils/password.d.ts.map +1 -1
- package/dist/utils/password.js +7 -76
- package/dist/utils/password.js.map +1 -1
- package/dist/validation/field-config.d.ts.map +1 -1
- package/dist/validation/field-config.js +0 -6
- package/dist/validation/field-config.js.map +1 -1
- package/dist/validation/schema.d.ts +0 -7
- package/dist/validation/schema.d.ts.map +1 -1
- package/dist/validation/schema.js +0 -10
- package/dist/validation/schema.js.map +1 -1
- package/package.json +1 -1
- package/src/access/access-filter.ts +152 -5
- package/src/access/declared-dependencies.ts +4 -9
- package/src/access/engine.ts +0 -25
- package/src/access/errors.ts +81 -0
- package/src/access/field-access.test.ts +312 -2
- package/src/access/field-access.ts +118 -42
- package/src/access/field-transforms.ts +8 -39
- package/src/access/field-visibility.ts +16 -47
- package/src/access/index.ts +20 -2
- package/src/access/query-validation.ts +359 -0
- package/src/access/relationship-count.ts +2 -10
- package/src/access/relationship-label-filter.test.ts +19 -68
- package/src/access/relationship-label-filter.ts +27 -104
- package/src/access/transaction-registry.ts +58 -0
- package/src/access/types.ts +83 -86
- package/src/config/index.ts +10 -22
- package/src/config/label.ts +6 -13
- package/src/config/nav-count.ts +11 -19
- package/src/config/plugin-engine.ts +1 -37
- package/src/config/types.ts +95 -110
- package/src/context/apply-defaults.ts +12 -44
- package/src/context/hook-pipeline.ts +12 -67
- package/src/context/index.ts +263 -247
- package/src/context/nested-operations.ts +94 -226
- package/src/context/transaction-boundary.ts +113 -109
- package/src/context/write-pipeline.ts +99 -155
- package/src/fields/format-prisma-default.ts +4 -7
- package/src/fields/index.ts +155 -147
- package/src/filter/collect.ts +48 -12
- package/src/filter/filter.test.ts +153 -15
- package/src/filter/index.ts +1 -0
- package/src/filter/map.ts +0 -5
- package/src/filter/parse.ts +2 -9
- package/src/filter/serialize.ts +2 -4
- package/src/hooks/index.ts +5 -59
- package/src/index.ts +23 -4
- package/src/internal.ts +5 -0
- package/src/lib/case-utils.ts +0 -32
- package/src/mcp/handler.ts +13 -71
- package/src/query/index.ts +29 -235
- package/src/utils/password.ts +7 -76
- package/src/validation/field-config.ts +0 -6
- package/src/validation/schema.ts +0 -10
- package/tests/context.test.ts +700 -1
- package/tests/field-types.test.ts +222 -0
- package/tests/mcp-handler.test.ts +34 -0
- package/tests/transaction-boundary-outermost.test.ts +530 -0
- package/tsconfig.tsbuildinfo +1 -1
package/dist/query/index.d.ts
CHANGED
|
@@ -1,52 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unwrap the item type from a field type, stripping null, undefined, and
|
|
3
|
-
* Array wrappers so we can constrain nested fragment shapes.
|
|
4
|
-
*
|
|
5
|
-
* Examples:
|
|
6
|
-
* User | null → User
|
|
7
|
-
* User[] → User
|
|
8
|
-
* (User | null)[] → User
|
|
9
|
-
*/
|
|
10
1
|
type UnwrapItem<T> = NonNullable<T> extends Array<infer U> ? NonNullable<U> : NonNullable<T>;
|
|
11
2
|
/**
|
|
12
|
-
* A selector for a relationship field
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* 1. A `Fragment` directly (shorthand — no extra Prisma args on the nested query).
|
|
16
|
-
* 2. An object `{ query, where?, orderBy?, take?, skip? }` to combine a fragment
|
|
17
|
-
* with Prisma filter/ordering/pagination applied to the nested relationship.
|
|
18
|
-
*
|
|
19
|
-
* @example Shorthand (most common)
|
|
20
|
-
* ```ts
|
|
21
|
-
* const postFrag = defineFragment<Post>()({
|
|
22
|
-
* id: true,
|
|
23
|
-
* author: authorFragment, // shorthand
|
|
24
|
-
* } as const)
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
|
-
* @example With nested filtering
|
|
28
|
-
* ```ts
|
|
29
|
-
* const postFrag = defineFragment<Post>()({
|
|
30
|
-
* id: true,
|
|
31
|
-
* comments: {
|
|
32
|
-
* query: commentFragment,
|
|
33
|
-
* where: { approved: true },
|
|
34
|
-
* orderBy: { createdAt: 'desc' },
|
|
35
|
-
* take: 5,
|
|
36
|
-
* },
|
|
37
|
-
* } as const)
|
|
38
|
-
* ```
|
|
39
|
-
*
|
|
40
|
-
* @example Variables via factory function
|
|
41
|
-
* ```ts
|
|
42
|
-
* function makePostFragment(status: string) {
|
|
43
|
-
* return defineFragment<Post>()({
|
|
44
|
-
* id: true,
|
|
45
|
-
* comments: { query: commentFragment, where: { status } },
|
|
46
|
-
* } as const)
|
|
47
|
-
* }
|
|
48
|
-
* type PostData = ResultOf<ReturnType<typeof makePostFragment>>
|
|
49
|
-
* ```
|
|
3
|
+
* A selector for a relationship field: either a {@link Fragment} directly
|
|
4
|
+
* (shorthand), or `{ query, where?, orderBy?, take?, skip? }` to combine a
|
|
5
|
+
* fragment with Prisma filter/ordering/pagination on the nested relationship.
|
|
50
6
|
*/
|
|
51
7
|
export type RelationSelector<TRelated extends Record<string, unknown>> = Fragment<TRelated, FieldSelection<TRelated>> | {
|
|
52
8
|
readonly query: Fragment<TRelated, FieldSelection<TRelated>>;
|
|
@@ -56,103 +12,45 @@ export type RelationSelector<TRelated extends Record<string, unknown>> = Fragmen
|
|
|
56
12
|
readonly skip?: number;
|
|
57
13
|
};
|
|
58
14
|
/**
|
|
59
|
-
* A field selection for model type `TItem`.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* - `true` — include the scalar/primitive field as-is
|
|
63
|
-
* - A `Fragment` — include a relationship and recurse (shorthand)
|
|
64
|
-
* - A `RelationSelector` — include a relationship with optional Prisma filter/ordering
|
|
65
|
-
*
|
|
66
|
-
* Only keys present in `TItem` are accepted. For relationship (object) fields
|
|
67
|
-
* you may pass a Fragment, a RelationSelector, or `true` (returns the raw Prisma
|
|
68
|
-
* value and loses type narrowing).
|
|
69
|
-
*
|
|
70
|
-
* @example
|
|
71
|
-
* ```ts
|
|
72
|
-
* const sel: FieldSelection<Post> = {
|
|
73
|
-
* id: true,
|
|
74
|
-
* title: true,
|
|
75
|
-
* author: authorFragment,
|
|
76
|
-
* comments: { query: commentFragment, where: { approved: true } },
|
|
77
|
-
* }
|
|
78
|
-
* ```
|
|
15
|
+
* A field selection for model type `TItem`. Passing `true` for a
|
|
16
|
+
* relationship field returns the raw Prisma value and loses type narrowing —
|
|
17
|
+
* use a {@link Fragment} or {@link RelationSelector} to keep it typed.
|
|
79
18
|
*/
|
|
80
19
|
export type FieldSelection<T> = {
|
|
81
20
|
readonly [K in keyof T]?: UnwrapItem<T[K]> extends Record<string, unknown> ? RelationSelector<UnwrapItem<T[K]>> | true : true;
|
|
82
21
|
};
|
|
83
22
|
/**
|
|
84
23
|
* A reusable, composable field-selection descriptor for model type `TItem`.
|
|
85
|
-
*
|
|
86
|
-
* Create with {@link defineFragment}. Compose by referencing another Fragment
|
|
87
|
-
* (or a {@link RelationSelector}) as the value for a relationship key.
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* ```ts
|
|
91
|
-
* const userFragment = defineFragment<User>()({ id: true, name: true } as const)
|
|
92
|
-
* const postFragment = defineFragment<Post>()({
|
|
93
|
-
* id: true,
|
|
94
|
-
* title: true,
|
|
95
|
-
* author: userFragment,
|
|
96
|
-
* } as const)
|
|
97
|
-
* ```
|
|
24
|
+
* Create with {@link defineFragment}.
|
|
98
25
|
*/
|
|
99
26
|
export type Fragment<TItem, TFields extends FieldSelection<TItem> = FieldSelection<TItem>> = {
|
|
100
27
|
readonly _type: 'fragment';
|
|
101
28
|
readonly _fields: TFields;
|
|
102
29
|
};
|
|
103
|
-
/**
|
|
104
|
-
* @internal
|
|
105
|
-
* Extract the Fragment from either a Fragment directly or a RelationSelector object.
|
|
106
|
-
* Returns `never` for scalar `true` selections (so they fall to the scalar branch).
|
|
107
|
-
*/
|
|
30
|
+
/** @internal Returns `never` for scalar `true` selections, so they fall to the scalar branch in {@link SelectedFields}. */
|
|
108
31
|
type ExtractFragment<TSelector> = TSelector extends Fragment<infer TItem, infer TFields> ? Fragment<TItem, TFields> : TSelector extends {
|
|
109
32
|
readonly query: Fragment<infer TItem, infer TFields>;
|
|
110
33
|
} ? Fragment<TItem, TFields> : never;
|
|
111
|
-
/**
|
|
112
|
-
* @internal
|
|
113
|
-
* Map a FieldSelection over a model type, computing the picked output type.
|
|
114
|
-
*/
|
|
34
|
+
/** @internal */
|
|
115
35
|
type SelectedFields<TItem, TFields extends FieldSelection<TItem>> = {
|
|
116
36
|
[K in keyof TFields & keyof TItem]: [ExtractFragment<TFields[K]>] extends [never] ? TItem[K] : TItem[K] extends Array<unknown> ? ResultOf<ExtractFragment<TFields[K]>>[] : null extends TItem[K] ? ResultOf<ExtractFragment<TFields[K]>> | null : undefined extends TItem[K] ? ResultOf<ExtractFragment<TFields[K]>> | undefined : ResultOf<ExtractFragment<TFields[K]>>;
|
|
117
37
|
};
|
|
118
38
|
/**
|
|
119
|
-
* Infer the TypeScript result type from a Fragment
|
|
120
|
-
*
|
|
121
|
-
* Analogous to `gql.tada`'s `ResultOf` helper — given a fragment definition,
|
|
122
|
-
* `ResultOf` tells you exactly what shape you will receive at runtime.
|
|
123
|
-
*
|
|
124
|
-
* - Scalar fields selected with `true` retain their original Prisma type.
|
|
125
|
-
* - Relationship fields selected with a nested Fragment/RelationSelector are
|
|
126
|
-
* recursively narrowed.
|
|
127
|
-
* - Nullability and array wrappers from the original model type are preserved.
|
|
128
|
-
*
|
|
129
|
-
* @example
|
|
130
|
-
* ```ts
|
|
131
|
-
* type UserData = ResultOf<typeof userFragment>
|
|
132
|
-
* // → { id: string; name: string }
|
|
133
|
-
*
|
|
134
|
-
* type PostData = ResultOf<typeof postFragment>
|
|
135
|
-
* // → { id: string; title: string; author: { id: string; name: string } | null }
|
|
136
|
-
* ```
|
|
39
|
+
* Infer the TypeScript result type from a {@link Fragment} — the shape
|
|
40
|
+
* `runQuery`/`runQueryOne` return at runtime for that fragment.
|
|
137
41
|
*/
|
|
138
42
|
export type ResultOf<F> = F extends Fragment<infer TItem, infer TFields> ? SelectedFields<TItem, TFields> : never;
|
|
139
43
|
/**
|
|
140
44
|
* Arguments accepted by {@link runQuery}.
|
|
141
45
|
*/
|
|
142
46
|
export type QueryArgs = {
|
|
143
|
-
/** Prisma where filter
|
|
47
|
+
/** Prisma where filter — the access control layer additionally scopes results. */
|
|
144
48
|
where?: Record<string, unknown>;
|
|
145
|
-
/** Prisma orderBy clause. Pass a single object or an array for multi-column ordering. */
|
|
146
49
|
orderBy?: Record<string, 'asc' | 'desc'> | Array<Record<string, 'asc' | 'desc'>>;
|
|
147
|
-
/** Maximum number of records to return. */
|
|
148
50
|
take?: number;
|
|
149
|
-
/** Number of records to skip (for pagination). */
|
|
150
51
|
skip?: number;
|
|
151
52
|
};
|
|
152
|
-
/**
|
|
153
|
-
* Minimal context shape required by the query runners.
|
|
154
|
-
* Compatible with the full `AccessContext` produced by `getContext()`.
|
|
155
|
-
*/
|
|
53
|
+
/** Compatible with the full `AccessContext` produced by `getContext()`. */
|
|
156
54
|
export interface QueryRunnerContext {
|
|
157
55
|
db: {
|
|
158
56
|
[key: string]: {
|
|
@@ -162,77 +60,18 @@ export interface QueryRunnerContext {
|
|
|
162
60
|
};
|
|
163
61
|
}
|
|
164
62
|
/**
|
|
165
|
-
* Create a type-safe, reusable fragment for a given model type.
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* (from the explicit type parameter) and the field selection (from the
|
|
169
|
-
* argument), without requiring you to repeat yourself.
|
|
170
|
-
*
|
|
171
|
-
* @example Basic usage
|
|
172
|
-
* ```ts
|
|
173
|
-
* import type { User } from '.prisma/client'
|
|
174
|
-
* import { defineFragment } from '@opensaas/stack-core'
|
|
175
|
-
*
|
|
176
|
-
* export const userFragment = defineFragment<User>()({
|
|
177
|
-
* id: true,
|
|
178
|
-
* name: true,
|
|
179
|
-
* email: true,
|
|
180
|
-
* } as const)
|
|
181
|
-
* ```
|
|
182
|
-
*
|
|
183
|
-
* @example Compose fragments
|
|
184
|
-
* ```ts
|
|
185
|
-
* import type { Post } from '.prisma/client'
|
|
186
|
-
*
|
|
187
|
-
* export const postFragment = defineFragment<Post>()({
|
|
188
|
-
* id: true,
|
|
189
|
-
* title: true,
|
|
190
|
-
* author: userFragment,
|
|
191
|
-
* } as const)
|
|
192
|
-
* ```
|
|
193
|
-
*
|
|
194
|
-
* @example Nested filtering with RelationSelector
|
|
195
|
-
* ```ts
|
|
196
|
-
* export const postWithApprovedComments = defineFragment<Post>()({
|
|
197
|
-
* id: true,
|
|
198
|
-
* title: true,
|
|
199
|
-
* comments: {
|
|
200
|
-
* query: commentFragment,
|
|
201
|
-
* where: { approved: true },
|
|
202
|
-
* orderBy: { createdAt: 'desc' },
|
|
203
|
-
* take: 5,
|
|
204
|
-
* },
|
|
205
|
-
* } as const)
|
|
206
|
-
* ```
|
|
207
|
-
*
|
|
208
|
-
* @example Variables via factory function
|
|
209
|
-
* ```ts
|
|
210
|
-
* function makePostFragment(status: string) {
|
|
211
|
-
* return defineFragment<Post>()({
|
|
212
|
-
* id: true,
|
|
213
|
-
* comments: { query: commentFragment, where: { status } },
|
|
214
|
-
* } as const)
|
|
215
|
-
* }
|
|
216
|
-
* type PostData = ResultOf<ReturnType<typeof makePostFragment>>
|
|
217
|
-
*
|
|
218
|
-
* const posts = await context.db.post.findMany({
|
|
219
|
-
* query: makePostFragment('approved'),
|
|
220
|
-
* where: { published: true },
|
|
221
|
-
* })
|
|
222
|
-
* ```
|
|
63
|
+
* Create a type-safe, reusable fragment for a given model type. Curried so
|
|
64
|
+
* TypeScript can infer the model type from the explicit type parameter and
|
|
65
|
+
* the field selection from the argument.
|
|
223
66
|
*/
|
|
224
67
|
export declare function defineFragment<TItem>(): <TFields extends FieldSelection<TItem>>(fields: TFields) => Fragment<TItem, TFields>;
|
|
225
68
|
/** @internal */
|
|
226
69
|
export declare function isFragment(value: unknown): value is Fragment<unknown, FieldSelection<unknown>>;
|
|
227
70
|
/**
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
* scalar columns by default. Only relationship fields backed by a Fragment or
|
|
233
|
-
* RelationSelector generate include entries (recursively).
|
|
234
|
-
*
|
|
235
|
-
* Exported for use in `context/index.ts` when the `query` parameter is present.
|
|
71
|
+
* Build the Prisma `include` map for a field selection's nested fragments.
|
|
72
|
+
* Scalar fields (`true`) need no include entry — Prisma returns all scalar
|
|
73
|
+
* columns by default; only relationship fields backed by a Fragment or
|
|
74
|
+
* RelationSelector generate one (recursively).
|
|
236
75
|
* @internal
|
|
237
76
|
*/
|
|
238
77
|
export declare function buildInclude(fields: FieldSelection<unknown>): Record<string, unknown> | undefined;
|
|
@@ -267,61 +106,21 @@ export type FieldSelectionScope = {
|
|
|
267
106
|
export declare function buildFieldSelectionScope(fields: FieldSelection<unknown>): FieldSelectionScope;
|
|
268
107
|
/**
|
|
269
108
|
* Recursively pick only the fields requested by a fragment from a raw Prisma
|
|
270
|
-
* result object
|
|
271
|
-
* produced by `ResultOf<F>`.
|
|
272
|
-
*
|
|
273
|
-
* Exported for use in `context/index.ts`.
|
|
109
|
+
* result object, so the runtime shape matches `ResultOf<F>`.
|
|
274
110
|
* @internal
|
|
275
111
|
*/
|
|
276
112
|
export declare function pickFields<TItem, TFields extends FieldSelection<TItem>>(item: TItem, fields: TFields): SelectedFields<TItem, TFields>;
|
|
277
113
|
/**
|
|
278
114
|
* Execute a fragment-based query against a list, returning all matching
|
|
279
|
-
* records shaped to the fragment's field selection.
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
* control rules defined in your config are still enforced.
|
|
283
|
-
*
|
|
284
|
-
* **Tip:** You can also call `context.db.post.findMany({ query: fragment, ... })`
|
|
285
|
-
* directly — both forms produce the same result.
|
|
286
|
-
*
|
|
287
|
-
* @param context - An `AccessContext` (or any object with a compatible `db`).
|
|
288
|
-
* @param listKey - The PascalCase list name (e.g. `'Post'`, `'BlogPost'`).
|
|
289
|
-
* @param fragment - A fragment created with {@link defineFragment}.
|
|
290
|
-
* @param args - Optional query arguments (where, orderBy, take, skip).
|
|
291
|
-
* @returns An array typed to exactly the fragment's field selection.
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* ```ts
|
|
295
|
-
* const posts = await runQuery(context, 'Post', postFragment, {
|
|
296
|
-
* where: { published: true },
|
|
297
|
-
* orderBy: { createdAt: 'desc' },
|
|
298
|
-
* take: 10,
|
|
299
|
-
* })
|
|
300
|
-
* // posts: Array<ResultOf<typeof postFragment>>
|
|
301
|
-
* ```
|
|
115
|
+
* records shaped to the fragment's field selection. Calls
|
|
116
|
+
* `context.db[listKey].findMany()` under the hood, so access control still
|
|
117
|
+
* applies.
|
|
302
118
|
*/
|
|
303
119
|
export declare function runQuery<TItem, TFields extends FieldSelection<TItem>>(context: QueryRunnerContext, listKey: string, fragment: Fragment<TItem, TFields>, args?: QueryArgs): Promise<SelectedFields<TItem, TFields>[]>;
|
|
304
120
|
/**
|
|
305
121
|
* Execute a fragment-based query that returns a single record (or `null`).
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
* control rules are still enforced.
|
|
309
|
-
*
|
|
310
|
-
* **Tip:** You can also call `context.db.post.findUnique({ where: { id }, query: fragment })`
|
|
311
|
-
* directly.
|
|
312
|
-
*
|
|
313
|
-
* @param context - An `AccessContext` (or any object with a compatible `db`).
|
|
314
|
-
* @param listKey - The PascalCase list name (e.g. `'Post'`).
|
|
315
|
-
* @param fragment - A fragment created with {@link defineFragment}.
|
|
316
|
-
* @param where - A Prisma where clause to identify the record.
|
|
317
|
-
* @returns The matched record shaped to the fragment, or `null`.
|
|
318
|
-
*
|
|
319
|
-
* @example
|
|
320
|
-
* ```ts
|
|
321
|
-
* const post = await runQueryOne(context, 'Post', postFragment, { id: postId })
|
|
322
|
-
* if (!post) return notFound()
|
|
323
|
-
* // post: ResultOf<typeof postFragment>
|
|
324
|
-
* ```
|
|
122
|
+
* Calls `context.db[listKey].findFirst()` under the hood, so access control
|
|
123
|
+
* still applies.
|
|
325
124
|
*/
|
|
326
125
|
export declare function runQueryOne<TItem, TFields extends FieldSelection<TItem>>(context: QueryRunnerContext, listKey: string, fragment: Fragment<TItem, TFields>, where: Record<string, unknown>): Promise<SelectedFields<TItem, TFields> | null>;
|
|
327
126
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAMA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"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"}
|
package/dist/query/index.js
CHANGED
|
@@ -3,64 +3,9 @@ import { getDbKey } from '../lib/case-utils.js';
|
|
|
3
3
|
// Fragment factory
|
|
4
4
|
// ─────────────────────────────────────────────────────────────
|
|
5
5
|
/**
|
|
6
|
-
* Create a type-safe, reusable fragment for a given model type.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (from the explicit type parameter) and the field selection (from the
|
|
10
|
-
* argument), without requiring you to repeat yourself.
|
|
11
|
-
*
|
|
12
|
-
* @example Basic usage
|
|
13
|
-
* ```ts
|
|
14
|
-
* import type { User } from '.prisma/client'
|
|
15
|
-
* import { defineFragment } from '@opensaas/stack-core'
|
|
16
|
-
*
|
|
17
|
-
* export const userFragment = defineFragment<User>()({
|
|
18
|
-
* id: true,
|
|
19
|
-
* name: true,
|
|
20
|
-
* email: true,
|
|
21
|
-
* } as const)
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* @example Compose fragments
|
|
25
|
-
* ```ts
|
|
26
|
-
* import type { Post } from '.prisma/client'
|
|
27
|
-
*
|
|
28
|
-
* export const postFragment = defineFragment<Post>()({
|
|
29
|
-
* id: true,
|
|
30
|
-
* title: true,
|
|
31
|
-
* author: userFragment,
|
|
32
|
-
* } as const)
|
|
33
|
-
* ```
|
|
34
|
-
*
|
|
35
|
-
* @example Nested filtering with RelationSelector
|
|
36
|
-
* ```ts
|
|
37
|
-
* export const postWithApprovedComments = defineFragment<Post>()({
|
|
38
|
-
* id: true,
|
|
39
|
-
* title: true,
|
|
40
|
-
* comments: {
|
|
41
|
-
* query: commentFragment,
|
|
42
|
-
* where: { approved: true },
|
|
43
|
-
* orderBy: { createdAt: 'desc' },
|
|
44
|
-
* take: 5,
|
|
45
|
-
* },
|
|
46
|
-
* } as const)
|
|
47
|
-
* ```
|
|
48
|
-
*
|
|
49
|
-
* @example Variables via factory function
|
|
50
|
-
* ```ts
|
|
51
|
-
* function makePostFragment(status: string) {
|
|
52
|
-
* return defineFragment<Post>()({
|
|
53
|
-
* id: true,
|
|
54
|
-
* comments: { query: commentFragment, where: { status } },
|
|
55
|
-
* } as const)
|
|
56
|
-
* }
|
|
57
|
-
* type PostData = ResultOf<ReturnType<typeof makePostFragment>>
|
|
58
|
-
*
|
|
59
|
-
* const posts = await context.db.post.findMany({
|
|
60
|
-
* query: makePostFragment('approved'),
|
|
61
|
-
* where: { published: true },
|
|
62
|
-
* })
|
|
63
|
-
* ```
|
|
6
|
+
* Create a type-safe, reusable fragment for a given model type. Curried so
|
|
7
|
+
* TypeScript can infer the model type from the explicit type parameter and
|
|
8
|
+
* the field selection from the argument.
|
|
64
9
|
*/
|
|
65
10
|
export function defineFragment() {
|
|
66
11
|
return function (fields) {
|
|
@@ -68,7 +13,7 @@ export function defineFragment() {
|
|
|
68
13
|
};
|
|
69
14
|
}
|
|
70
15
|
// ─────────────────────────────────────────────────────────────
|
|
71
|
-
// Runtime helpers
|
|
16
|
+
// Runtime helpers
|
|
72
17
|
// ─────────────────────────────────────────────────────────────
|
|
73
18
|
/** @internal */
|
|
74
19
|
export function isFragment(value) {
|
|
@@ -78,14 +23,10 @@ export function isFragment(value) {
|
|
|
78
23
|
value._type === 'fragment');
|
|
79
24
|
}
|
|
80
25
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* scalar columns by default. Only relationship fields backed by a Fragment or
|
|
86
|
-
* RelationSelector generate include entries (recursively).
|
|
87
|
-
*
|
|
88
|
-
* Exported for use in `context/index.ts` when the `query` parameter is present.
|
|
26
|
+
* Build the Prisma `include` map for a field selection's nested fragments.
|
|
27
|
+
* Scalar fields (`true`) need no include entry — Prisma returns all scalar
|
|
28
|
+
* columns by default; only relationship fields backed by a Fragment or
|
|
29
|
+
* RelationSelector generate one (recursively).
|
|
89
30
|
* @internal
|
|
90
31
|
*/
|
|
91
32
|
export function buildInclude(fields) {
|
|
@@ -95,14 +36,12 @@ export function buildInclude(fields) {
|
|
|
95
36
|
if (value === null || value === true || typeof value !== 'object')
|
|
96
37
|
continue;
|
|
97
38
|
const val = value;
|
|
98
|
-
// ── Shorthand: Fragment directly ──────────────────────────
|
|
99
39
|
if (isFragment(val)) {
|
|
100
40
|
hasIncludes = true;
|
|
101
41
|
const nestedInclude = buildInclude(val._fields);
|
|
102
42
|
include[key] = nestedInclude ? { include: nestedInclude } : true;
|
|
103
43
|
continue;
|
|
104
44
|
}
|
|
105
|
-
// ── RelationSelector: { query, where?, orderBy?, take?, skip? } ──
|
|
106
45
|
if ('query' in val && isFragment(val.query)) {
|
|
107
46
|
hasIncludes = true;
|
|
108
47
|
const selector = val;
|
|
@@ -153,10 +92,7 @@ export function buildFieldSelectionScope(fields) {
|
|
|
153
92
|
}
|
|
154
93
|
/**
|
|
155
94
|
* Recursively pick only the fields requested by a fragment from a raw Prisma
|
|
156
|
-
* result object
|
|
157
|
-
* produced by `ResultOf<F>`.
|
|
158
|
-
*
|
|
159
|
-
* Exported for use in `context/index.ts`.
|
|
95
|
+
* result object, so the runtime shape matches `ResultOf<F>`.
|
|
160
96
|
* @internal
|
|
161
97
|
*/
|
|
162
98
|
export function pickFields(item, fields) {
|
|
@@ -170,7 +106,6 @@ export function pickFields(item, fields) {
|
|
|
170
106
|
if (value === null || typeof value !== 'object')
|
|
171
107
|
continue;
|
|
172
108
|
const val = value;
|
|
173
|
-
// ── Shorthand: Fragment directly ──────────────────────────
|
|
174
109
|
if (isFragment(val)) {
|
|
175
110
|
if (Array.isArray(fieldValue)) {
|
|
176
111
|
result[key] = fieldValue.map((elem) => pickFields(elem, val._fields));
|
|
@@ -183,7 +118,6 @@ export function pickFields(item, fields) {
|
|
|
183
118
|
}
|
|
184
119
|
continue;
|
|
185
120
|
}
|
|
186
|
-
// ── RelationSelector: { query, where?, ... } ──────────────
|
|
187
121
|
if ('query' in val && isFragment(val.query)) {
|
|
188
122
|
const nestedFrag = val.query;
|
|
189
123
|
if (Array.isArray(fieldValue)) {
|
|
@@ -205,29 +139,9 @@ export function pickFields(item, fields) {
|
|
|
205
139
|
// ─────────────────────────────────────────────────────────────
|
|
206
140
|
/**
|
|
207
141
|
* Execute a fragment-based query against a list, returning all matching
|
|
208
|
-
* records shaped to the fragment's field selection.
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* control rules defined in your config are still enforced.
|
|
212
|
-
*
|
|
213
|
-
* **Tip:** You can also call `context.db.post.findMany({ query: fragment, ... })`
|
|
214
|
-
* directly — both forms produce the same result.
|
|
215
|
-
*
|
|
216
|
-
* @param context - An `AccessContext` (or any object with a compatible `db`).
|
|
217
|
-
* @param listKey - The PascalCase list name (e.g. `'Post'`, `'BlogPost'`).
|
|
218
|
-
* @param fragment - A fragment created with {@link defineFragment}.
|
|
219
|
-
* @param args - Optional query arguments (where, orderBy, take, skip).
|
|
220
|
-
* @returns An array typed to exactly the fragment's field selection.
|
|
221
|
-
*
|
|
222
|
-
* @example
|
|
223
|
-
* ```ts
|
|
224
|
-
* const posts = await runQuery(context, 'Post', postFragment, {
|
|
225
|
-
* where: { published: true },
|
|
226
|
-
* orderBy: { createdAt: 'desc' },
|
|
227
|
-
* take: 10,
|
|
228
|
-
* })
|
|
229
|
-
* // posts: Array<ResultOf<typeof postFragment>>
|
|
230
|
-
* ```
|
|
142
|
+
* records shaped to the fragment's field selection. Calls
|
|
143
|
+
* `context.db[listKey].findMany()` under the hood, so access control still
|
|
144
|
+
* applies.
|
|
231
145
|
*/
|
|
232
146
|
export async function runQuery(context, listKey, fragment, args) {
|
|
233
147
|
const dbKey = getDbKey(listKey);
|
|
@@ -248,25 +162,8 @@ export async function runQuery(context, listKey, fragment, args) {
|
|
|
248
162
|
}
|
|
249
163
|
/**
|
|
250
164
|
* Execute a fragment-based query that returns a single record (or `null`).
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* control rules are still enforced.
|
|
254
|
-
*
|
|
255
|
-
* **Tip:** You can also call `context.db.post.findUnique({ where: { id }, query: fragment })`
|
|
256
|
-
* directly.
|
|
257
|
-
*
|
|
258
|
-
* @param context - An `AccessContext` (or any object with a compatible `db`).
|
|
259
|
-
* @param listKey - The PascalCase list name (e.g. `'Post'`).
|
|
260
|
-
* @param fragment - A fragment created with {@link defineFragment}.
|
|
261
|
-
* @param where - A Prisma where clause to identify the record.
|
|
262
|
-
* @returns The matched record shaped to the fragment, or `null`.
|
|
263
|
-
*
|
|
264
|
-
* @example
|
|
265
|
-
* ```ts
|
|
266
|
-
* const post = await runQueryOne(context, 'Post', postFragment, { id: postId })
|
|
267
|
-
* if (!post) return notFound()
|
|
268
|
-
* // post: ResultOf<typeof postFragment>
|
|
269
|
-
* ```
|
|
165
|
+
* Calls `context.db[listKey].findFirst()` under the hood, so access control
|
|
166
|
+
* still applies.
|
|
270
167
|
*/
|
|
271
168
|
export async function runQueryOne(context, listKey, fragment, where) {
|
|
272
169
|
const dbKey = getDbKey(listKey);
|
package/dist/query/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/password.d.ts
CHANGED
|
@@ -1,81 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hash a plain text password using bcrypt
|
|
3
|
-
*
|
|
4
|
-
* @param plainPassword - The plain text password to hash
|
|
5
|
-
* @param costFactor - The bcrypt cost factor (default: 10)
|
|
6
|
-
* @returns Promise resolving to the hashed password
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* const hashed = await hashPassword('mypassword')
|
|
11
|
-
* // Returns: $2a$10$...
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
1
|
export declare function hashPassword(plainPassword: string, costFactor?: number): Promise<string>;
|
|
15
|
-
/**
|
|
16
|
-
* Compare a plain text password with a hashed password
|
|
17
|
-
*
|
|
18
|
-
* @param plainPassword - The plain text password to compare
|
|
19
|
-
* @param hashedPassword - The hashed password to compare against
|
|
20
|
-
* @returns Promise resolving to true if passwords match, false otherwise
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```typescript
|
|
24
|
-
* const isValid = await comparePassword('mypassword', hashedPassword)
|
|
25
|
-
* if (isValid) {
|
|
26
|
-
* // Password is correct
|
|
27
|
-
* }
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
30
2
|
export declare function comparePassword(plainPassword: string, hashedPassword: string): Promise<boolean>;
|
|
31
|
-
/**
|
|
32
|
-
* Check if a string appears to be a bcrypt hash
|
|
33
|
-
* Bcrypt hashes follow the format: $2a$10$...
|
|
34
|
-
*
|
|
35
|
-
* @param value - The string to check
|
|
36
|
-
* @returns True if the string looks like a bcrypt hash
|
|
37
|
-
*/
|
|
38
3
|
export declare function isHashedPassword(value: string): boolean;
|
|
39
|
-
/**
|
|
40
|
-
* HashedPassword class wraps a bcrypt hash and provides a compare method
|
|
41
|
-
* This allows password field values to be used as strings while also
|
|
42
|
-
* providing a convenient compare() method for authentication
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```typescript
|
|
46
|
-
* const user = await context.db.user.findUnique({ where: { id: '1' } })
|
|
47
|
-
* const isValid = await user.password.compare('plaintextPassword')
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
4
|
export declare class HashedPassword {
|
|
51
5
|
private readonly hash;
|
|
52
6
|
constructor(hash: string);
|
|
53
|
-
/**
|
|
54
|
-
* Compare a plain text password with this hashed password
|
|
55
|
-
*
|
|
56
|
-
* @param plainPassword - The plain text password to compare
|
|
57
|
-
* @returns Promise resolving to true if passwords match
|
|
58
|
-
*/
|
|
59
7
|
compare(plainPassword: string): Promise<boolean>;
|
|
60
|
-
/**
|
|
61
|
-
* Get the underlying hash string
|
|
62
|
-
* This allows the HashedPassword to be used anywhere a string is expected
|
|
63
|
-
*/
|
|
64
8
|
toString(): string;
|
|
65
|
-
/**
|
|
66
|
-
* Get the underlying hash when used in string contexts
|
|
67
|
-
* This allows the HashedPassword to be coerced to a string automatically
|
|
68
|
-
*/
|
|
69
9
|
[Symbol.toPrimitive](hint: string): string;
|
|
70
|
-
/**
|
|
71
|
-
* Return the hash for JSON serialization
|
|
72
|
-
* This ensures the hash is properly serialized when converting to JSON
|
|
73
|
-
*/
|
|
74
10
|
toJSON(): string;
|
|
75
|
-
/**
|
|
76
|
-
* Get the underlying hash value
|
|
77
|
-
* This allows accessing the raw hash string
|
|
78
|
-
*/
|
|
79
11
|
valueOf(): string;
|
|
80
12
|
}
|
|
81
13
|
//# sourceMappingURL=password.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/utils/password.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/utils/password.ts"],"names":[],"mappings":"AAKA,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,UAAU,GAAE,MAA4B,GACvC,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAIvD;AAID,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,MAAM,EAIxC;IAEK,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAErD;IAED,QAAQ,IAAI,MAAM,CAEjB;IAGD,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKzC;IAGD,MAAM,IAAI,MAAM,CAEf;IAED,OAAO,IAAI,MAAM,CAEhB;CACF"}
|