@aws-amplify/data-schema 1.1.4 → 1.1.6

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.
Files changed (57) hide show
  1. package/dist/cjs/CustomOperation.js +46 -0
  2. package/dist/cjs/CustomOperation.js.map +1 -1
  3. package/dist/cjs/CustomType.js +32 -0
  4. package/dist/cjs/CustomType.js.map +1 -1
  5. package/dist/cjs/Handler.js +62 -0
  6. package/dist/cjs/Handler.js.map +1 -1
  7. package/dist/cjs/ModelRelationalField.js +82 -3
  8. package/dist/cjs/ModelRelationalField.js.map +1 -1
  9. package/dist/cjs/util/Brand.js +4 -4
  10. package/dist/cjs/util/Brand.js.map +1 -1
  11. package/dist/cjs/util/usedMethods.js +4 -0
  12. package/dist/cjs/util/usedMethods.js.map +1 -0
  13. package/dist/esm/CustomOperation.d.ts +49 -3
  14. package/dist/esm/CustomOperation.mjs +46 -0
  15. package/dist/esm/CustomOperation.mjs.map +1 -1
  16. package/dist/esm/CustomType.d.ts +35 -3
  17. package/dist/esm/CustomType.mjs +32 -0
  18. package/dist/esm/CustomType.mjs.map +1 -1
  19. package/dist/esm/EnumType.d.ts +7 -9
  20. package/dist/esm/Handler.d.ts +62 -0
  21. package/dist/esm/Handler.mjs +62 -0
  22. package/dist/esm/Handler.mjs.map +1 -1
  23. package/dist/esm/MappedTypes/CustomOperations.d.ts +3 -3
  24. package/dist/esm/MappedTypes/ExtractNonModelTypes.d.ts +4 -4
  25. package/dist/esm/MappedTypes/ResolveFieldProperties.d.ts +2 -2
  26. package/dist/esm/MappedTypes/ResolveSchema.d.ts +6 -6
  27. package/dist/esm/ModelField.d.ts +16 -13
  28. package/dist/esm/ModelRelationalField.d.ts +83 -4
  29. package/dist/esm/ModelRelationalField.mjs +82 -3
  30. package/dist/esm/ModelRelationalField.mjs.map +1 -1
  31. package/dist/esm/ModelSchema.d.ts +4 -4
  32. package/dist/esm/ModelType.d.ts +16 -12
  33. package/dist/esm/RefType.d.ts +1 -1
  34. package/dist/esm/util/Brand.d.ts +1 -2
  35. package/dist/esm/util/Brand.mjs +1 -1
  36. package/dist/esm/util/Brand.mjs.map +1 -1
  37. package/dist/esm/util/usedMethods.d.ts +4 -0
  38. package/dist/esm/util/usedMethods.mjs +2 -0
  39. package/dist/esm/util/usedMethods.mjs.map +1 -0
  40. package/dist/meta/cjs.tsbuildinfo +1 -1
  41. package/package.json +1 -1
  42. package/src/CustomOperation.ts +49 -7
  43. package/src/CustomType.ts +36 -8
  44. package/src/EnumType.ts +16 -22
  45. package/src/Handler.ts +62 -0
  46. package/src/MappedTypes/CustomOperations.ts +4 -6
  47. package/src/MappedTypes/ExtractNonModelTypes.ts +39 -40
  48. package/src/MappedTypes/ResolveFieldProperties.ts +2 -2
  49. package/src/MappedTypes/ResolveSchema.ts +18 -21
  50. package/src/ModelField.ts +34 -19
  51. package/src/ModelRelationalField.ts +83 -4
  52. package/src/ModelSchema.ts +8 -12
  53. package/src/ModelType.ts +30 -34
  54. package/src/RefType.ts +1 -1
  55. package/src/SchemaProcessor.ts +21 -41
  56. package/src/util/Brand.ts +1 -1
  57. package/src/util/usedMethods.ts +5 -0
@@ -1,14 +1,13 @@
1
1
  import { SetTypeSubArg } from '@aws-amplify/data-schema-types';
2
2
  import { Brand, brand } from './util';
3
-
4
- import { ModelField, InternalField } from './ModelField';
3
+ import { InternalField, type BaseModelField } from './ModelField';
5
4
  import {
6
5
  AllowModifierForCustomOperation,
7
6
  Authorization,
8
7
  allowForCustomOperations,
9
8
  } from './Authorization';
10
9
  import { RefType, InternalRef } from './RefType';
11
- import { EnumType, EnumTypeParamShape } from './EnumType';
10
+ import { EnumType } from './EnumType';
12
11
  import { CustomType } from './CustomType';
13
12
  import type {
14
13
  CustomHandler,
@@ -25,10 +24,7 @@ type CustomOperationBrand =
25
24
  | typeof mutationBrand
26
25
  | typeof subscriptionBrand;
27
26
 
28
- type CustomArguments = Record<
29
- string,
30
- ModelField<any, any> | EnumType<EnumTypeParamShape>
31
- >;
27
+ type CustomArguments = Record<string, BaseModelField | EnumType>;
32
28
 
33
29
  type SubscriptionSource = RefType<any, any>;
34
30
  type InternalSubscriptionSource = InternalRef;
@@ -202,6 +198,26 @@ export type QueryCustomOperation = CustomOperation<
202
198
  typeof queryBrand
203
199
  >;
204
200
 
201
+ /**
202
+ * Use a custom query to define an API request that will retrieve backend data.
203
+ * @see {@link https://docs.amplify.aws/react/build-a-backend/data/custom-business-logic/}
204
+ * @example
205
+ * const schema = a.schema({
206
+ * echo: a
207
+ * .query()
208
+ * .arguments({ content: a.string() })
209
+ * .returns(a.ref('EchoResponse'))
210
+ * .authorization(allow => [allow.publicApiKey()])
211
+ * // 3. set the function has the handler
212
+ * .handler(a.handler.function(echoHandler)),
213
+ *
214
+ * EchoResponse: a.customType({
215
+ * content: a.string(),
216
+ * executionDuration: a.float()
217
+ * }),
218
+ * });
219
+ * @returns a custom query
220
+ */
205
221
  export function query(): CustomOperation<
206
222
  {
207
223
  arguments: null;
@@ -222,6 +238,18 @@ export type MutationCustomOperation = CustomOperation<
222
238
  typeof mutationBrand
223
239
  >;
224
240
 
241
+ /**
242
+ * Use a custom mutation to define an API request that will modify backend data or trigger a subscription event.
243
+ * @see {@link https://docs.amplify.aws/react/build-a-backend/data/custom-business-logic/}
244
+ * @example
245
+ * likePost: a
246
+ * .mutation()
247
+ * .arguments({ postId: a.string() })
248
+ * .returns(a.ref('Post'))
249
+ * .authorization(allow => [allow.publicApiKey()])
250
+ * .handler(a.handler.function(echoHandler))
251
+ * @returns a custom mutation
252
+ */
225
253
  export function mutation(): CustomOperation<
226
254
  {
227
255
  arguments: null;
@@ -242,6 +270,20 @@ export type SubscriptionCustomOperation = CustomOperation<
242
270
  typeof subscriptionBrand
243
271
  >;
244
272
 
273
+ /**
274
+ * Define a custom subscription to receive an event when a mutation is triggered
275
+ * @see {@link https://docs.amplify.aws/react/build-a-backend/data/custom-subscription/}
276
+ * @example
277
+ * // Subscribe to incoming messages
278
+ * receive: a.subscription()
279
+ * // subscribes to the 'publish' mutation
280
+ * .for(a.ref('publish'))
281
+ * // subscription handler to set custom filters
282
+ * .handler(a.handler.custom({entry: './receive.js'}))
283
+ * // authorization rules as to who can subscribe to the data
284
+ * .authorization(allow => [allow.publicApiKey()]),
285
+ * @returns a custom subscription
286
+ */
245
287
  export function subscription(): CustomOperation<
246
288
  {
247
289
  arguments: null;
package/src/CustomType.ts CHANGED
@@ -1,11 +1,7 @@
1
1
  import type { Brand } from './util';
2
- import type {
3
- ModelField,
4
- InternalField,
5
- ModelFieldTypeParamOuter,
6
- } from './ModelField';
2
+ import type { InternalField, BaseModelField } from './ModelField';
7
3
  import type { RefType } from './RefType';
8
- import type { EnumType, EnumTypeParamShape } from './EnumType';
4
+ import type { EnumType } from './EnumType';
9
5
 
10
6
  /**
11
7
  * Custom Types
@@ -19,9 +15,9 @@ export type CustomTypeAllowedModifiers = 'authorization' | 'array' | 'required';
19
15
 
20
16
  type CustomTypeFields = Record<
21
17
  string,
22
- | ModelField<ModelFieldTypeParamOuter, CustomTypeAllowedModifiers, any>
18
+ | BaseModelField
23
19
  | RefType<any, any, any>
24
- | EnumType<EnumTypeParamShape>
20
+ | EnumType
25
21
  | CustomType<CustomTypeParamShape>
26
22
  >;
27
23
 
@@ -60,6 +56,38 @@ function _customType<T extends CustomTypeParamShape>(fields: T['fields']) {
60
56
  return { data } as InternalCustomType as CustomType<T>;
61
57
  }
62
58
 
59
+ /**
60
+ * Define a custom type. This type represents an inline, typed JSON object.
61
+ * @see {@link https://docs.amplify.aws/react/build-a-backend/data/data-modeling/add-fields/#specify-a-custom-field-type}
62
+ * @param fields the fields to be added to the custom type
63
+ * @returns a custom type
64
+ * @example
65
+ * a.schema({
66
+ * Post: a.model({
67
+ * location: a.customType({
68
+ * lat: a.float(),
69
+ * long: a.float(),
70
+ * }),
71
+ * content: a.string(),
72
+ * }),
73
+ * });
74
+ * @example
75
+ * a.schema({
76
+ * Location: a.customType({
77
+ * lat: a.float(),
78
+ * long: a.float(),
79
+ * }),
80
+ *
81
+ * Post: a.model({
82
+ * location: a.ref('Location'),
83
+ * content: a.string(),
84
+ * }),
85
+ *
86
+ * User: a.model({
87
+ * lastKnownLocation: a.ref('Location'),
88
+ * }),
89
+ * });
90
+ */
63
91
  export function customType<T extends CustomTypeFields>(
64
92
  fields: T,
65
93
  ): CustomType<{ fields: T }> {
package/src/EnumType.ts CHANGED
@@ -1,36 +1,30 @@
1
- import { Brand } from './util';
1
+ import type { brandSymbol } from './util/Brand.js';
2
2
 
3
- type EnumTypeData = {
4
- type: 'enum';
5
- values: readonly string[];
6
- };
7
-
8
- export type EnumTypeParamShape = {
9
- type: 'enum';
10
- values: readonly string[];
11
- };
3
+ type EnumTypeParamShape<values extends readonly string[] = readonly string[]> =
4
+ {
5
+ type: 'enum';
6
+ values: values;
7
+ };
12
8
 
13
- export type EnumType<T extends EnumTypeParamShape> = T & Brand<'enum'>;
9
+ export interface EnumType<values extends readonly string[] = readonly string[]>
10
+ extends EnumTypeParamShape<values> {
11
+ [brandSymbol]: 'enum';
12
+ }
14
13
 
15
- function _enum<T extends EnumTypeParamShape>(values: T['values']) {
16
- const data: EnumTypeData = {
14
+ function _enum<values extends readonly string[]>(values: values) {
15
+ const data: EnumTypeParamShape = {
17
16
  type: 'enum',
18
17
  values,
19
18
  };
20
19
 
21
- return data as EnumType<T>;
20
+ return data as EnumType<values>;
22
21
  }
23
22
 
24
- type EnumTypeArgFactory<Values extends readonly string[]> = {
25
- type: 'enum';
26
- values: Values;
27
- };
28
-
29
23
  /**
30
24
  * this type param pattern allows us to infer literal type values from the array without using the `as const` suffix
31
25
  */
32
- export function enumType<Value extends string, T extends readonly Value[]>(
33
- values: T,
26
+ export function enumType<const values extends readonly string[]>(
27
+ values: values,
34
28
  ) {
35
- return _enum<EnumTypeArgFactory<T>>(values);
29
+ return _enum(values);
36
30
  }
package/src/Handler.ts CHANGED
@@ -92,6 +92,33 @@ export type CustomHandler = { [dataSymbol]: CustomHandlerData } & Brand<
92
92
  typeof customHandlerBrand
93
93
  >;
94
94
 
95
+ /**
96
+ * Use a custom JavaScript resolver to handle a query, mutation, or subscription.
97
+ * @see {@link https://docs.amplify.aws/react/build-a-backend/data/custom-business-logic/#step-2---configure-custom-business-logic-handler-code}
98
+ * @param customHandler `{ entry: "path-to-javascript-resolver-file.js", dataSource: "Data Source name added via "backend.data.add*DataSoruce(...)"}`
99
+ * @returns A JavaScript resolver attached to the query, mutation, or subscription.
100
+ * @example
101
+ * const schema = a.schema({
102
+ * Post: a.model({
103
+ * content: a.string(),
104
+ * likes: a.integer()
105
+ * .authorization(allow => [allow.authenticated().to(['read'])])
106
+ * }).authorization(allow => [
107
+ * allow.owner(),
108
+ * allow.authenticated().to(['read'])
109
+ * ]),
110
+ *
111
+ * likePost: a
112
+ * .mutation()
113
+ * .arguments({ postId: a.id() })
114
+ * .returns(a.ref('Post'))
115
+ * .authorization(allow => [allow.authenticated()])
116
+ * .handler(a.handler.custom({
117
+ * dataSource: a.ref('Post'),
118
+ * entry: './increment-like.js'
119
+ * }))
120
+ * });
121
+ */
95
122
  function custom(customHandler: CustomHandlerInput): CustomHandler {
96
123
  // used to determine caller directory in order to resolve relative path downstream
97
124
  const stack = new Error().stack;
@@ -113,6 +140,41 @@ export type FunctionHandler = {
113
140
  [dataSymbol]: FunctionHandlerData;
114
141
  } & Brand<typeof functionHandlerBrand>;
115
142
 
143
+ /**
144
+ * Use a function created via `defineFunction` to handle the custom query/mutation/subscription. In your function handler,
145
+ * you can use the `Schema["YOUR_QUERY_OR_MUTATION_NAME"]["functionHandler"]` utility type to type the handler function.
146
+ * @example
147
+ * import {
148
+ * type ClientSchema,
149
+ * a,
150
+ * defineData,
151
+ * defineFunction // 1.Import "defineFunction" to create new functions
152
+ * } from '@aws-amplify/backend';
153
+ *
154
+ * // 2. define a function
155
+ * const echoHandler = defineFunction({
156
+ * entry: './echo-handler/handler.ts'
157
+ * })
158
+ *
159
+ * const schema = a.schema({
160
+ * EchoResponse: a.customType({
161
+ * content: a.string(),
162
+ * executionDuration: a.float()
163
+ * }),
164
+ *
165
+ * echo: a
166
+ * .query()
167
+ * .arguments({ content: a.string() })
168
+ * .returns(a.ref('EchoResponse'))
169
+ * .authorization(allow => [allow.publicApiKey()])
170
+ * // 3. set the function has the handler
171
+ * .handler(a.handler.function(echoHandler))
172
+ * });
173
+ * @see {@link https://docs.amplify.aws/react/build-a-backend/data/custom-business-logic/}
174
+ * @param fn A function created via `defineFunction`. Alternatively, you can pass in a "string" of the function name and pass
175
+ * in a corresponding value into the `functionMap` property of defineData.
176
+ * @returns A handler for the query / mutation / subscription
177
+ */
116
178
  function fcn(fn: FunctionHandlerData): FunctionHandler {
117
179
  return { [dataSymbol]: fn, ...buildHandler(functionHandlerBrand) };
118
180
  }
@@ -4,7 +4,7 @@ import type {
4
4
  CustomOperation,
5
5
  CustomOperationParamShape,
6
6
  } from '../CustomOperation';
7
- import type { ModelField } from '../ModelField';
7
+ import type { BaseModelField } from '../ModelField';
8
8
  import type { RefType, RefTypeParamShape } from '../RefType';
9
9
  import type {
10
10
  ResolveFieldRequirements,
@@ -66,10 +66,8 @@ export type CustomOpArguments<Shape extends CustomOperationParamShape> =
66
66
  Shape['arguments'] extends null
67
67
  ? never
68
68
  : ResolveFieldRequirements<{
69
- [FieldName in keyof Shape['arguments']]: Shape['arguments'][FieldName] extends ModelField<
70
- infer R,
71
- any,
72
- any
69
+ [FieldName in keyof Shape['arguments']]: Shape['arguments'][FieldName] extends BaseModelField<
70
+ infer R
73
71
  >
74
72
  ? R
75
73
  : never;
@@ -101,7 +99,7 @@ export type CustomOpReturnType<
101
99
  NonModelTypes,
102
100
  CustomOperations
103
101
  >
104
- : Shape['returnType'] extends ModelField<infer R, any, any>
102
+ : Shape['returnType'] extends BaseModelField<infer R>
105
103
  ? R
106
104
  : Shape['returnType'] extends CustomType<infer R>
107
105
  ?
@@ -1,6 +1,6 @@
1
1
  import type { UnionToIntersection } from '@aws-amplify/data-schema-types';
2
2
  import type { CustomType, CustomTypeParamShape } from '../CustomType';
3
- import type { EnumType, EnumTypeParamShape } from '../EnumType';
3
+ import type { EnumType } from '../EnumType';
4
4
  import type {
5
5
  SchemaTypes,
6
6
  ModelAndCustomTypes,
@@ -9,7 +9,7 @@ import type {
9
9
  import type { ModelType, ModelTypeParamShape } from '../ModelType';
10
10
 
11
11
  export type NonModelTypesShape = {
12
- enums: Record<string, EnumType<any>>;
12
+ enums: Record<string, any>;
13
13
  customTypes: Record<string, any>;
14
14
  };
15
15
 
@@ -51,43 +51,44 @@ export type ExtractNonModelTypes<Schema> = ResolveNonModelFields<
51
51
  export type ExtractAndFlattenImplicitNonModelTypesFromFields<
52
52
  ParentTypeName extends string,
53
53
  Fields,
54
- > = {
55
- // loop through the fields - omit the field that's not a non-model type
56
- [FieldProp in keyof Fields as Fields[FieldProp] extends
57
- | EnumType<EnumTypeParamShape>
58
- | CustomType<CustomTypeParamShape>
59
- ? FieldProp
60
- : never]: (
61
- x: NonNullable<Fields[FieldProp]> extends infer FieldType
62
- ? // if the filed is a enum extract it as is
63
- FieldType extends EnumType<EnumTypeParamShape>
64
- ? {
65
- [Key in `${ParentTypeName}${Capitalize<
66
- FieldProp & string
67
- >}`]: Fields[FieldProp];
68
- }
69
- : // if the field is a CustomType
70
- FieldType extends CustomType<
71
- infer CustomTypeShape extends CustomTypeParamShape
72
- >
73
- ? // recursively extract to the Nested CustomType, and return the
74
- // merge of the current CustomType and the extracted (if any)
75
- ExtractAndFlattenImplicitNonModelTypesFromFields<
76
- `${ParentTypeName}${Capitalize<FieldProp & string>}`,
77
- CustomTypeShape['fields']
78
- > & {
54
+ > =
55
+ {
56
+ // loop through the fields - omit the field that's not a non-model type
57
+ [FieldProp in keyof Fields as Fields[FieldProp] extends
58
+ | EnumType
59
+ | CustomType<CustomTypeParamShape>
60
+ ? FieldProp
61
+ : never]: (
62
+ x: NonNullable<Fields[FieldProp]> extends infer FieldType
63
+ ? // if the filed is a enum extract it as is
64
+ FieldType extends EnumType
65
+ ? {
79
66
  [Key in `${ParentTypeName}${Capitalize<
80
67
  FieldProp & string
81
68
  >}`]: Fields[FieldProp];
82
69
  }
83
- : never
84
- : never,
85
- ) => void;
86
- } extends Record<string, infer Func>
87
- ? Func extends (x: infer P) => void
88
- ? P // extract the union of all types of the `x` param used above
89
- : Record<never, never> // return an empty mapped object (nothing got extracted)
90
- : Record<never, never>; // return an empty mapped object (nothing got extracted)
70
+ : // if the field is a CustomType
71
+ FieldType extends CustomType<
72
+ infer CustomTypeShape extends CustomTypeParamShape
73
+ >
74
+ ? // recursively extract to the Nested CustomType, and return the
75
+ // merge of the current CustomType and the extracted (if any)
76
+ ExtractAndFlattenImplicitNonModelTypesFromFields<
77
+ `${ParentTypeName}${Capitalize<FieldProp & string>}`,
78
+ CustomTypeShape['fields']
79
+ > & {
80
+ [Key in `${ParentTypeName}${Capitalize<
81
+ FieldProp & string
82
+ >}`]: Fields[FieldProp];
83
+ }
84
+ : never
85
+ : never,
86
+ ) => void;
87
+ } extends Record<string, infer Func>
88
+ ? Func extends (x: infer P) => void
89
+ ? P // extract the union of all types of the `x` param used above
90
+ : Record<never, never> // return an empty mapped object (nothing got extracted)
91
+ : Record<never, never>; // return an empty mapped object (nothing got extracted)
91
92
 
92
93
  /**
93
94
  * Pulls out implicit, i.e. field-level non-model types from `ModelType` and
@@ -129,12 +130,10 @@ type ResolveNonModelTypes<
129
130
  ResolvedSchema = SchemaTypes<Schema> & Extracted,
130
131
  > = {
131
132
  enums: {
132
- [Model in keyof ResolvedSchema as ResolvedSchema[Model] extends EnumType<EnumTypeParamShape>
133
+ [Model in keyof ResolvedSchema as ResolvedSchema[Model] extends EnumType
133
134
  ? Model
134
- : never]: ResolvedSchema[Model] extends EnumType<
135
- infer R extends EnumTypeParamShape
136
- >
137
- ? R['values'][number]
135
+ : never]: ResolvedSchema[Model] extends EnumType<infer values>
136
+ ? values[number]
138
137
  : never;
139
138
  };
140
139
  customTypes: {
@@ -20,7 +20,7 @@ import type { RefType, RefTypeParamShape } from '../RefType';
20
20
  import type { NonModelTypesShape } from './ExtractNonModelTypes';
21
21
 
22
22
  import type { CustomType, CustomTypeParamShape } from '../CustomType';
23
- import type { EnumType, EnumTypeParamShape } from '../EnumType';
23
+ import type { EnumType } from '../EnumType';
24
24
  import type {
25
25
  CustomOperation,
26
26
  CustomOperationParamShape,
@@ -214,7 +214,7 @@ type Intersection<
214
214
  // TODO: this should probably happen in InjectImplicitModelFields instead. Keeping here for now to reduce refactor
215
215
  // blast radius
216
216
  export type ModelImpliedAuthFields<Schema extends GenericModelSchema<any>> = {
217
- [ModelKey in keyof Schema['data']['types'] as Schema['data']['types'][ModelKey] extends EnumType<EnumTypeParamShape>
217
+ [ModelKey in keyof Schema['data']['types'] as Schema['data']['types'][ModelKey] extends EnumType
218
218
  ? never
219
219
  : Schema['data']['types'][ModelKey] extends CustomType<CustomTypeParamShape>
220
220
  ? never
@@ -5,9 +5,9 @@ import type {
5
5
  ModelRelationshipTypes,
6
6
  RelationTypeFunctionOmitMapping,
7
7
  } from '../ModelRelationalField';
8
- import type { ModelField } from '../ModelField';
8
+ import type { BaseModelField } from '../ModelField';
9
9
  import type { CustomType, CustomTypeParamShape } from '../CustomType';
10
- import type { EnumType, EnumTypeParamShape } from '../EnumType';
10
+ import type { EnumType } from '../EnumType';
11
11
  import type { RefType, RefTypeParamShape } from '../RefType';
12
12
  import type {
13
13
  CustomOperation,
@@ -17,9 +17,8 @@ import type {
17
17
  export type ResolveSchema<Schema> = FieldTypes<ModelTypes<SchemaTypes<Schema>>>;
18
18
 
19
19
  // TODO: find better name
20
- export type SchemaTypes<T> = T extends GenericModelSchema<any>
21
- ? T['data']['types']
22
- : never;
20
+ export type SchemaTypes<T> =
21
+ T extends GenericModelSchema<any> ? T['data']['types'] : never;
23
22
 
24
23
  /**
25
24
  * Resolves model types
@@ -30,7 +29,7 @@ export type SchemaTypes<T> = T extends GenericModelSchema<any>
30
29
  */
31
30
  export type ModelTypes<Schema> = {
32
31
  [Model in keyof Schema as Schema[Model] extends
33
- | EnumType<EnumTypeParamShape>
32
+ | EnumType
34
33
  | CustomType<CustomTypeParamShape>
35
34
  | CustomOperation<CustomOperationParamShape, any>
36
35
  ? never
@@ -45,14 +44,16 @@ export type ModelTypes<Schema> = {
45
44
  */
46
45
  export type ModelAndCustomTypes<Schema> = {
47
46
  [Model in keyof Schema as Schema[Model] extends
48
- | EnumType<EnumTypeParamShape>
47
+ | EnumType
49
48
  | CustomOperation<CustomOperationParamShape, any>
50
49
  ? never
51
- : Model]: Schema[Model] extends ModelType<any, any>
50
+ : // TODO: This should use BaseModel, but seems to only work because it relies on
51
+ // omitting extra methods
52
+ Model]: Schema[Model] extends
53
+ | ModelType<any, any>
54
+ | CustomType<CustomTypeParamShape>
52
55
  ? Schema[Model]
53
- : Schema[Model] extends CustomType<CustomTypeParamShape>
54
- ? Schema[Model]
55
- : never;
56
+ : never;
56
57
  };
57
58
 
58
59
  /**
@@ -62,11 +63,9 @@ export type ModelAndCustomTypes<Schema> = {
62
63
  */
63
64
  export type FieldTypes<T> = {
64
65
  [ModelProp in keyof T]: {
65
- [FieldProp in keyof T[ModelProp]]: T[ModelProp][FieldProp] extends ModelField<
66
+ [FieldProp in keyof T[ModelProp]]: T[ModelProp][FieldProp] extends BaseModelField<
66
67
  // Match the most common field type to improve resolving performance
67
- infer R,
68
- any,
69
- any
68
+ infer R
70
69
  >
71
70
  ? R
72
71
  : T[ModelProp][FieldProp] extends RefType<
@@ -80,7 +79,7 @@ export type FieldTypes<T> = {
80
79
  : T[ModelProp][FieldProp] | null
81
80
  : // replace non-model types with Ref
82
81
  T[ModelProp][FieldProp] extends
83
- | EnumType<EnumTypeParamShape>
82
+ | EnumType
84
83
  | CustomType<CustomTypeParamShape>
85
84
  ? RefType<{
86
85
  link: `${Capitalize<ModelProp & string>}${Capitalize<
@@ -114,10 +113,8 @@ export type FieldTypes<T> = {
114
113
  */
115
114
  export type FieldTypesOfCustomType<T> = {
116
115
  [CustomTypeName in keyof T]: {
117
- [FieldProp in keyof T[CustomTypeName]]: T[CustomTypeName][FieldProp] extends ModelField<
118
- infer R,
119
- any,
120
- any
116
+ [FieldProp in keyof T[CustomTypeName]]: T[CustomTypeName][FieldProp] extends BaseModelField<
117
+ infer R
121
118
  >
122
119
  ? R
123
120
  : T[CustomTypeName][FieldProp] extends RefType<
@@ -131,7 +128,7 @@ export type FieldTypesOfCustomType<T> = {
131
128
  : T[CustomTypeName][FieldProp] | null
132
129
  : // replace non-model types with Ref
133
130
  T[CustomTypeName][FieldProp] extends
134
- | EnumType<EnumTypeParamShape>
131
+ | EnumType
135
132
  | CustomType<CustomTypeParamShape>
136
133
  ? RefType<{
137
134
  link: `${Capitalize<CustomTypeName & string>}${Capitalize<
package/src/ModelField.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { Brand, brand } from './util';
1
+ import { brand } from './util';
2
2
  import { AllowModifier, Authorization, allow } from './Authorization';
3
+ import type { methodKeyOf, satisfy } from './util/usedMethods.js';
4
+ import type { brandSymbol } from './util/Brand.js';
3
5
 
4
6
  /**
5
7
  * Used to "attach" auth types to ModelField without exposing them on the builder.
@@ -34,7 +36,7 @@ export enum ModelFieldDataType {
34
36
  }
35
37
 
36
38
  type FieldMeta = {
37
- lastInvokedMethod: null | keyof ModelField<ModelFieldTypeParamOuter>;
39
+ lastInvokedMethod: null | methodKeyOf<ModelField>;
38
40
  };
39
41
 
40
42
  type FieldData = {
@@ -67,56 +69,69 @@ export type ArrayField<T> = [T] extends [ModelFieldTypeParamInner]
67
69
  ? Array<T> | null // optional by default
68
70
  : never;
69
71
 
72
+ export type BaseModelField<
73
+ T extends ModelFieldTypeParamOuter = ModelFieldTypeParamOuter,
74
+ > = ModelField<T, UsableModelFieldKey, any>;
75
+
76
+ export type UsableModelFieldKey = satisfy<
77
+ methodKeyOf<ModelField>,
78
+ 'required' | 'default' | 'authorization'
79
+ >;
80
+
70
81
  /**
71
82
  * Public API for the chainable builder methods exposed by Model Field.
72
83
  * The type is narrowing e.g., after calling .array() it will be omitted from intellisense suggestions
73
84
  *
74
85
  * @typeParam T - holds the JS data type of the field
75
- * @typeParam K - union of strings representing already-invoked method names. Used to improve Intellisense
86
+ * @typeParam UsedMethod - union of strings representing already-invoked method names. Used to improve Intellisense
76
87
  */
77
88
  export type ModelField<
78
- T extends ModelFieldTypeParamOuter,
79
- // rename K
80
- K extends keyof ModelField<T> = never,
89
+ T extends ModelFieldTypeParamOuter = ModelFieldTypeParamOuter,
90
+ UsedMethod extends UsableModelFieldKey = never,
81
91
  Auth = undefined,
82
92
  > = Omit<
83
93
  {
94
+ // This is a lie. This property is never set at runtime. It's just used to smuggle auth types through.
95
+ [__auth]?: Auth;
96
+ [brandSymbol]: typeof brandName;
97
+
84
98
  /**
85
99
  * Marks a field as required.
86
100
  */
87
- required(): ModelField<Required<T>, K | 'required'>;
101
+ required(): ModelField<Required<T>, UsedMethod | 'required'>;
88
102
  // Exclude `optional` after calling array, because both the value and the array itself can be optional
89
103
  /**
90
104
  * Converts a field type definition to an array of the field type.
91
105
  */
92
- array(): ModelField<ArrayField<T>, Exclude<K, 'required'> | 'array'>;
106
+ array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'>>;
93
107
  // TODO: should be T, but .array breaks this constraint. Fix later
94
108
  /**
95
109
  * Sets a default value for the scalar type.
96
110
  * @param value the default value
97
111
  */
98
- default(value: ModelFieldTypeParamOuter): ModelField<T, K | 'default'>;
112
+ default(
113
+ value: ModelFieldTypeParamOuter,
114
+ ): ModelField<T, UsedMethod | 'default'>;
99
115
  /**
100
- * Configures field-level authorization rules. Pass in an array of authorizations `(a.allow.____)` to mix and match
116
+ * Configures field-level authorization rules. Pass in an array of authorizations `(allow => allow.____)` to mix and match
101
117
  * multiple authorization rules for this field.
102
118
  */
103
119
  authorization<AuthRuleType extends Authorization<any, any, any>>(
104
- callback: (allow: Omit<AllowModifier, 'resource'>) => AuthRuleType | AuthRuleType[],
105
- ): ModelField<T, K | 'authorization', AuthRuleType>;
120
+ callback: (
121
+ allow: Omit<AllowModifier, 'resource'>,
122
+ ) => AuthRuleType | AuthRuleType[],
123
+ ): ModelField<T, UsedMethod | 'authorization', AuthRuleType>;
106
124
  },
107
- K
108
- > & {
109
- // This is a lie. This property is never set at runtime. It's just used to smuggle auth types through.
110
- [__auth]?: Auth;
111
- } & Brand<typeof brandName>;
125
+ UsedMethod
126
+ >;
112
127
 
113
128
  /**
114
129
  * Internal representation of Model Field that exposes the `data` property.
115
130
  * Used at buildtime.
116
131
  */
117
- export type InternalField = ModelField<ModelFieldTypeParamOuter, never> & {
132
+ export interface InternalField extends ModelField {
118
133
  data: FieldData;
119
- };
134
+ }
120
135
 
121
136
  /**
122
137
  * Model Field Implementation