@aws-amplify/data-schema 0.13.10 → 0.13.12
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/lib-esm/src/Authorization.d.ts +24 -1
- package/lib-esm/src/Authorization.js +26 -1
- package/lib-esm/src/CustomOperation.d.ts +3 -3
- package/lib-esm/src/Handler.d.ts +1 -1
- package/lib-esm/src/ModelSchema.d.ts +5 -4
- package/lib-esm/src/SchemaProcessor.js +82 -12
- package/lib-esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { UnionToIntersection } from '@aws-amplify/data-schema-types';
|
|
1
|
+
import type { UnionToIntersection, FunctionSchemaAccess } from '@aws-amplify/data-schema-types';
|
|
2
2
|
declare const __data: unique symbol;
|
|
3
3
|
/**
|
|
4
4
|
* All possible providers.
|
|
@@ -41,6 +41,24 @@ export type Strategy = (typeof Strategies)[number];
|
|
|
41
41
|
*/
|
|
42
42
|
export declare const Operations: readonly ["create", "update", "delete", "read", "get", "list", "sync", "listen", "search"];
|
|
43
43
|
export type Operation = (typeof Operations)[number];
|
|
44
|
+
/**
|
|
45
|
+
* The operations that can be performed against an API by a Lambda function.
|
|
46
|
+
*/
|
|
47
|
+
export declare const ResourceOperations: readonly ["query", "mutate", "listen"];
|
|
48
|
+
export type ResourceOperation = (typeof ResourceOperations)[number];
|
|
49
|
+
/**
|
|
50
|
+
* Super-set of regular auth type; includes schema-level resource access configuration
|
|
51
|
+
*/
|
|
52
|
+
export type SchemaAuthorization<AuthStrategy extends Strategy, AuthField extends string | undefined, AuthFieldPlurality extends boolean> = Authorization<AuthStrategy, AuthField, AuthFieldPlurality> | ResourceAuthorization;
|
|
53
|
+
export type ResourceAuthorization = {
|
|
54
|
+
[__data]: ResourceAuthorizationData;
|
|
55
|
+
};
|
|
56
|
+
type DefineFunction = FunctionSchemaAccess['resourceProvider'];
|
|
57
|
+
export type ResourceAuthorizationData = {
|
|
58
|
+
strategy: 'resource';
|
|
59
|
+
resource: DefineFunction;
|
|
60
|
+
operations?: ResourceOperation[];
|
|
61
|
+
};
|
|
44
62
|
export type Authorization<AuthStrategy extends Strategy, AuthField extends string | undefined, AuthFieldPlurality extends boolean> = {
|
|
45
63
|
[__data]: {
|
|
46
64
|
strategy?: AuthStrategy;
|
|
@@ -200,7 +218,11 @@ export declare const allow: {
|
|
|
200
218
|
readonly custom: (provider?: CustomProvider) => Authorization<"custom", undefined, false> & {
|
|
201
219
|
to: typeof to;
|
|
202
220
|
};
|
|
221
|
+
readonly resource: (fn: DefineFunction) => ResourceAuthorization & {
|
|
222
|
+
to: typeof resourceTo;
|
|
223
|
+
};
|
|
203
224
|
};
|
|
225
|
+
declare function resourceTo<SELF extends ResourceAuthorization>(this: SELF, operations: ResourceOperation[]): Omit<SELF, "to">;
|
|
204
226
|
/**
|
|
205
227
|
* Turns the type from a list of `Authorization` rules like this:
|
|
206
228
|
*
|
|
@@ -261,4 +283,5 @@ export declare const accessData: <T extends Authorization<any, any, any>>(author
|
|
|
261
283
|
identityClaim?: string | undefined;
|
|
262
284
|
groupClaim?: string | undefined;
|
|
263
285
|
};
|
|
286
|
+
export declare const accessSchemaData: <T extends SchemaAuthorization<any, any, any>>(authorization: T) => T[typeof __data];
|
|
264
287
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.accessData = exports.allow = exports.Operations = exports.Strategies = exports.CustomProviders = exports.GroupProviders = exports.OwnerProviders = exports.PrivateProviders = exports.PublicProviders = exports.Providers = void 0;
|
|
3
|
+
exports.accessSchemaData = exports.accessData = exports.allow = exports.ResourceOperations = exports.Operations = exports.Strategies = exports.CustomProviders = exports.GroupProviders = exports.OwnerProviders = exports.PrivateProviders = exports.PublicProviders = exports.Providers = void 0;
|
|
4
4
|
const __data = Symbol('data');
|
|
5
5
|
/**
|
|
6
6
|
* All possible providers.
|
|
@@ -57,6 +57,10 @@ exports.Operations = [
|
|
|
57
57
|
'listen',
|
|
58
58
|
'search',
|
|
59
59
|
];
|
|
60
|
+
/**
|
|
61
|
+
* The operations that can be performed against an API by a Lambda function.
|
|
62
|
+
*/
|
|
63
|
+
exports.ResourceOperations = ['query', 'mutate', 'listen'];
|
|
60
64
|
/**
|
|
61
65
|
* Creates a shallow copy of an object with an individual field pruned away.
|
|
62
66
|
*
|
|
@@ -302,6 +306,27 @@ exports.allow = {
|
|
|
302
306
|
to,
|
|
303
307
|
});
|
|
304
308
|
},
|
|
309
|
+
resource(fn) {
|
|
310
|
+
return resourceAuthData(fn, {
|
|
311
|
+
to: resourceTo,
|
|
312
|
+
});
|
|
313
|
+
},
|
|
305
314
|
};
|
|
315
|
+
function resourceTo(operations) {
|
|
316
|
+
this[__data].operations = operations;
|
|
317
|
+
return omit(this, 'to');
|
|
318
|
+
}
|
|
319
|
+
function resourceAuthData(resource, builderMethods) {
|
|
320
|
+
return {
|
|
321
|
+
[__data]: {
|
|
322
|
+
strategy: 'resource',
|
|
323
|
+
resource,
|
|
324
|
+
},
|
|
325
|
+
...builderMethods,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
306
328
|
const accessData = (authorization) => authorization[__data];
|
|
307
329
|
exports.accessData = accessData;
|
|
330
|
+
// TODO: delete when we make resource auth available at each level in the schema (model, field)
|
|
331
|
+
const accessSchemaData = (authorization) => authorization[__data];
|
|
332
|
+
exports.accessSchemaData = accessSchemaData;
|
|
@@ -5,7 +5,7 @@ import { Authorization } from './Authorization';
|
|
|
5
5
|
import { RefType, InternalRef } from './RefType';
|
|
6
6
|
import { EnumType, EnumTypeParamShape } from './EnumType';
|
|
7
7
|
import { CustomType } from './CustomType';
|
|
8
|
-
import type { HandlerType as Handler } from './Handler';
|
|
8
|
+
import type { CustomHandler, FunctionHandler, HandlerType as Handler } from './Handler';
|
|
9
9
|
declare const queryBrand = "queryCustomOperation";
|
|
10
10
|
declare const mutationBrand = "mutationCustomOperation";
|
|
11
11
|
declare const subscriptionBrand = "subscriptionCustomOperation";
|
|
@@ -15,7 +15,7 @@ type CustomReturnType = RefType<any> | CustomType<any>;
|
|
|
15
15
|
type CustomFunctionRefType = string;
|
|
16
16
|
type InternalCustomArguments = Record<string, InternalField>;
|
|
17
17
|
type InternalCustomReturnType = InternalRef;
|
|
18
|
-
type HandlerInputType =
|
|
18
|
+
type HandlerInputType = FunctionHandler[] | CustomHandler[] | Handler;
|
|
19
19
|
export declare const CustomOperationNames: readonly ["Query", "Mutation", "Subscription"];
|
|
20
20
|
type CustomOperationName = (typeof CustomOperationNames)[number];
|
|
21
21
|
type CustomData = {
|
|
@@ -24,7 +24,7 @@ type CustomData = {
|
|
|
24
24
|
functionRef: string | null;
|
|
25
25
|
authorization: Authorization<any, any, any>[];
|
|
26
26
|
typeName: CustomOperationName;
|
|
27
|
-
handlers: Handler | null;
|
|
27
|
+
handlers: Handler[] | null;
|
|
28
28
|
};
|
|
29
29
|
type InternalCustomData = CustomData & {
|
|
30
30
|
arguments: InternalCustomArguments;
|
package/lib-esm/src/Handler.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Brand } from './util';
|
|
2
2
|
import { RefType } from './RefType';
|
|
3
|
-
export type HandlerType = InlineSqlHandler
|
|
3
|
+
export type HandlerType = InlineSqlHandler | SqlReferenceHandler | CustomHandler | FunctionHandler;
|
|
4
4
|
declare const dataSymbol: unique symbol;
|
|
5
5
|
type AllHandlers = InlineSqlHandler | SqlReferenceHandler | CustomHandler | FunctionHandler;
|
|
6
6
|
export declare function getHandlerData<H extends AllHandlers>(handler: H): H[typeof dataSymbol];
|
|
@@ -3,7 +3,7 @@ import { type ModelType, type ModelTypeParamShape, type InternalModel, SchemaMod
|
|
|
3
3
|
import type { EnumType, EnumTypeParamShape } from './EnumType';
|
|
4
4
|
import type { CustomType, CustomTypeParamShape } from './CustomType';
|
|
5
5
|
import type { CustomOperation, CustomOperationParamShape, InternalCustom, MutationCustomOperation, QueryCustomOperation, SubscriptionCustomOperation } from './CustomOperation';
|
|
6
|
-
import {
|
|
6
|
+
import { SchemaAuthorization } from './Authorization';
|
|
7
7
|
type SchemaContent = ModelType<ModelTypeParamShape, any> | CustomType<CustomTypeParamShape> | EnumType<EnumTypeParamShape> | CustomOperation<CustomOperationParamShape, any>;
|
|
8
8
|
type ModelSchemaContents = Record<string, SchemaContent>;
|
|
9
9
|
type InternalSchemaModels = Record<string, InternalModel | EnumType<any> | CustomType<any> | InternalCustom>;
|
|
@@ -35,7 +35,7 @@ export type SchemaConfig<DE extends DatasourceEngine, DC extends DatasourceConfi
|
|
|
35
35
|
};
|
|
36
36
|
export type ModelSchemaParamShape = {
|
|
37
37
|
types: ModelSchemaContents;
|
|
38
|
-
authorization:
|
|
38
|
+
authorization: SchemaAuthorization<any, any, any>[];
|
|
39
39
|
configuration: SchemaConfig<any, any>;
|
|
40
40
|
};
|
|
41
41
|
export type SQLModelSchemaParamShape = ModelSchemaParamShape & {
|
|
@@ -44,11 +44,12 @@ export type SQLModelSchemaParamShape = ModelSchemaParamShape & {
|
|
|
44
44
|
export type InternalSchema = {
|
|
45
45
|
data: {
|
|
46
46
|
types: InternalSchemaModels;
|
|
47
|
-
authorization:
|
|
47
|
+
authorization: SchemaAuthorization<any, any, any>[];
|
|
48
|
+
configuration: SchemaConfig<any, any>;
|
|
48
49
|
};
|
|
49
50
|
};
|
|
50
51
|
export type ModelSchema<T extends ModelSchemaParamShape, UsedMethods extends 'authorization' = never> = Omit<{
|
|
51
|
-
authorization: <AuthRules extends
|
|
52
|
+
authorization: <AuthRules extends SchemaAuthorization<any, any, any>>(auth: AuthRules[]) => ModelSchema<SetTypeSubArg<T, 'authorization', AuthRules[]>, UsedMethods | 'authorization'>;
|
|
52
53
|
}, UsedMethods> & {
|
|
53
54
|
data: T;
|
|
54
55
|
models: {
|
|
@@ -155,8 +155,8 @@ function refFieldToGql(fieldDef) {
|
|
|
155
155
|
}
|
|
156
156
|
return field;
|
|
157
157
|
}
|
|
158
|
-
function customOperationToGql(typeName, typeDef, authorization, isCustom = false) {
|
|
159
|
-
const { arguments: fieldArgs, returnType, functionRef } = typeDef.data;
|
|
158
|
+
function customOperationToGql(typeName, typeDef, authorization, isCustom = false, databaseType) {
|
|
159
|
+
const { arguments: fieldArgs, returnType, functionRef, handlers, } = typeDef.data;
|
|
160
160
|
let callSignature = typeName;
|
|
161
161
|
const implicitModels = [];
|
|
162
162
|
const { authString } = isCustom
|
|
@@ -181,10 +181,29 @@ function customOperationToGql(typeName, typeDef, authorization, isCustom = false
|
|
|
181
181
|
callSignature += `(${gqlFields.join(', ')})`;
|
|
182
182
|
implicitModels.push(...models);
|
|
183
183
|
}
|
|
184
|
-
const
|
|
185
|
-
const
|
|
184
|
+
const handler = handlers && handlers[0];
|
|
185
|
+
const brand = handler && (0, util_1.getBrand)(handler);
|
|
186
|
+
let gqlHandlerContent = '';
|
|
187
|
+
if (functionRef) {
|
|
188
|
+
gqlHandlerContent = `@function(name: "${functionRef}") `;
|
|
189
|
+
}
|
|
190
|
+
else if (databaseType === 'sql' && handler && brand === 'inlineSql') {
|
|
191
|
+
gqlHandlerContent = `@sql(statement: ${escapeGraphQlString(String((0, Handler_1.getHandlerData)(handler)))}) `;
|
|
192
|
+
}
|
|
193
|
+
else if (databaseType === 'sql' && handler && brand === 'sqlReference') {
|
|
194
|
+
gqlHandlerContent = `@sql(reference: "${(0, Handler_1.getHandlerData)(handler)}") `;
|
|
195
|
+
}
|
|
196
|
+
const gqlField = `${callSignature}: ${returnTypeName} ${gqlHandlerContent}${authString}`;
|
|
186
197
|
return { gqlField, models: implicitModels };
|
|
187
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Escape a string that will be used inside of a graphql string.
|
|
201
|
+
* @param str The input string to be escaped
|
|
202
|
+
* @returns The string with special charactars escaped
|
|
203
|
+
*/
|
|
204
|
+
function escapeGraphQlString(str) {
|
|
205
|
+
return JSON.stringify(str);
|
|
206
|
+
}
|
|
188
207
|
/**
|
|
189
208
|
* Tests whether two ModelField definitions are in conflict.
|
|
190
209
|
*
|
|
@@ -243,6 +262,18 @@ function mergeFieldObjects(...fieldsObjects) {
|
|
|
243
262
|
}
|
|
244
263
|
return result;
|
|
245
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Throws if resource/lambda auth is configured at the model or field level
|
|
267
|
+
*
|
|
268
|
+
* @param authorization A list of authorization rules.
|
|
269
|
+
*/
|
|
270
|
+
function validateAuth(authorization = []) {
|
|
271
|
+
for (const entry of authorization) {
|
|
272
|
+
if (ruleIsResourceAuth(entry)) {
|
|
273
|
+
throw new Error('Lambda resource authorization is only confiugrable at the schema level');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
246
277
|
/**
|
|
247
278
|
* Given a list of authorization rules, produces a set of the implied owner and/or
|
|
248
279
|
* group fields, along with the associated graphql `@auth` string directive.
|
|
@@ -530,7 +561,9 @@ const idFields = (model) => {
|
|
|
530
561
|
function processFieldLevelAuthRules(fields, authFields) {
|
|
531
562
|
const fieldLevelAuthRules = {};
|
|
532
563
|
for (const [fieldName, fieldDef] of Object.entries(fields)) {
|
|
533
|
-
const
|
|
564
|
+
const fieldAuth = fieldDef?.data?.authorization || [];
|
|
565
|
+
validateAuth(fieldAuth);
|
|
566
|
+
const { authString, authFields: fieldAuthField } = calculateAuth(fieldAuth);
|
|
534
567
|
if (authString)
|
|
535
568
|
fieldLevelAuthRules[fieldName] = authString;
|
|
536
569
|
if (fieldAuthField) {
|
|
@@ -621,18 +654,55 @@ const transformedSecondaryIndexesForModel = (secondaryIndexes) => {
|
|
|
621
654
|
return acc;
|
|
622
655
|
}, {});
|
|
623
656
|
};
|
|
657
|
+
const ruleIsResourceAuth = (authRule) => {
|
|
658
|
+
const data = (0, Authorization_1.accessSchemaData)(authRule);
|
|
659
|
+
return data.strategy === 'resource';
|
|
660
|
+
};
|
|
661
|
+
/**
|
|
662
|
+
* Separates out lambda resource auth rules from remaining schema rules.
|
|
663
|
+
*
|
|
664
|
+
* @param authRules schema auth rules
|
|
665
|
+
*/
|
|
666
|
+
const extractFunctionSchemaAccess = (authRules) => {
|
|
667
|
+
const schemaAuth = [];
|
|
668
|
+
const functionSchemaAccess = [];
|
|
669
|
+
const defaultActions = [
|
|
670
|
+
'query',
|
|
671
|
+
'mutate',
|
|
672
|
+
'listen',
|
|
673
|
+
];
|
|
674
|
+
for (const rule of authRules) {
|
|
675
|
+
if (ruleIsResourceAuth(rule)) {
|
|
676
|
+
const ruleData = (0, Authorization_1.accessSchemaData)(rule);
|
|
677
|
+
const fnAccess = {
|
|
678
|
+
resourceProvider: ruleData.resource,
|
|
679
|
+
actions: ruleData.operations || defaultActions,
|
|
680
|
+
};
|
|
681
|
+
functionSchemaAccess.push(fnAccess);
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
schemaAuth.push(rule);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return { schemaAuth, functionSchemaAccess };
|
|
688
|
+
};
|
|
624
689
|
const schemaPreprocessor = (schema) => {
|
|
625
690
|
const gqlModels = [];
|
|
626
691
|
const customQueries = [];
|
|
627
692
|
const customMutations = [];
|
|
628
693
|
const customSubscriptions = [];
|
|
629
694
|
const jsFunctions = [];
|
|
695
|
+
const databaseType = schema.data.configuration.database.engine === 'dynamodb'
|
|
696
|
+
? 'dynamodb'
|
|
697
|
+
: 'sql';
|
|
630
698
|
const fkFields = allImpliedFKs(schema);
|
|
631
699
|
const topLevelTypes = Object.entries(schema.data.types);
|
|
700
|
+
const { schemaAuth, functionSchemaAccess } = extractFunctionSchemaAccess(schema.data.authorization);
|
|
632
701
|
for (const [typeName, typeDef] of topLevelTypes) {
|
|
702
|
+
validateAuth(typeDef.data?.authorization);
|
|
633
703
|
const mostRelevantAuthRules = typeDef.data?.authorization?.length > 0
|
|
634
704
|
? typeDef.data.authorization
|
|
635
|
-
:
|
|
705
|
+
: schemaAuth;
|
|
636
706
|
if (!isInternalModel(typeDef)) {
|
|
637
707
|
if (isEnumType(typeDef)) {
|
|
638
708
|
if (typeDef.values.some((value) => /\s/.test(value))) {
|
|
@@ -655,7 +725,7 @@ const schemaPreprocessor = (schema) => {
|
|
|
655
725
|
}
|
|
656
726
|
else if (isCustomOperation(typeDef)) {
|
|
657
727
|
const { typeName: opType } = typeDef.data;
|
|
658
|
-
const { gqlField, models, jsFunctionForField } = transformCustomOperations(typeDef, typeName, mostRelevantAuthRules);
|
|
728
|
+
const { gqlField, models, jsFunctionForField } = transformCustomOperations(typeDef, typeName, mostRelevantAuthRules, databaseType);
|
|
659
729
|
topLevelTypes.push(...models);
|
|
660
730
|
if (jsFunctionForField) {
|
|
661
731
|
jsFunctions.push(jsFunctionForField);
|
|
@@ -706,7 +776,7 @@ const schemaPreprocessor = (schema) => {
|
|
|
706
776
|
};
|
|
707
777
|
gqlModels.push(...generateCustomOperationTypes(customOperations));
|
|
708
778
|
const processedSchema = gqlModels.join('\n\n');
|
|
709
|
-
return { schema: processedSchema, jsFunctions };
|
|
779
|
+
return { schema: processedSchema, jsFunctions, functionSchemaAccess };
|
|
710
780
|
};
|
|
711
781
|
function validateCustomOperations(typeDef, typeName, authRules) {
|
|
712
782
|
const { functionRef, handlers } = typeDef.data;
|
|
@@ -789,7 +859,7 @@ const handleCustom = (handlers, opType, typeName) => {
|
|
|
789
859
|
};
|
|
790
860
|
return jsFn;
|
|
791
861
|
};
|
|
792
|
-
function transformCustomOperations(typeDef, typeName, authRules) {
|
|
862
|
+
function transformCustomOperations(typeDef, typeName, authRules, databaseType) {
|
|
793
863
|
const { typeName: opType, handlers } = typeDef.data;
|
|
794
864
|
let jsFunctionForField = undefined;
|
|
795
865
|
validateCustomOperations(typeDef, typeName, authRules);
|
|
@@ -797,7 +867,7 @@ function transformCustomOperations(typeDef, typeName, authRules) {
|
|
|
797
867
|
jsFunctionForField = handleCustom(handlers, opType, typeName);
|
|
798
868
|
}
|
|
799
869
|
const isCustom = Boolean(jsFunctionForField);
|
|
800
|
-
const { gqlField, models } = customOperationToGql(typeName, typeDef, authRules, isCustom);
|
|
870
|
+
const { gqlField, models } = customOperationToGql(typeName, typeDef, authRules, isCustom, databaseType);
|
|
801
871
|
return { gqlField, models, jsFunctionForField };
|
|
802
872
|
}
|
|
803
873
|
function generateCustomOperationTypes({ queries, mutations, subscriptions, }) {
|
|
@@ -819,7 +889,7 @@ function generateCustomOperationTypes({ queries, mutations, subscriptions, }) {
|
|
|
819
889
|
* @returns DerivedApiDefinition that conforms to IAmplifyGraphqlDefinition
|
|
820
890
|
*/
|
|
821
891
|
function processSchema(arg) {
|
|
822
|
-
const { schema, jsFunctions } = schemaPreprocessor(arg.schema);
|
|
823
|
-
return { schema, functionSlots: [], jsFunctions };
|
|
892
|
+
const { schema, jsFunctions, functionSchemaAccess } = schemaPreprocessor(arg.schema);
|
|
893
|
+
return { schema, functionSlots: [], jsFunctions, functionSchemaAccess };
|
|
824
894
|
}
|
|
825
895
|
exports.processSchema = processSchema;
|