diff --git a/src/requests/typings.ts b/src/requests/typings.ts deleted file mode 100644 index 0969b0a1..00000000 --- a/src/requests/typings.ts +++ /dev/null @@ -1,124 +0,0 @@ -// Remove when this eslint rule covers all the cases -// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/ROADMAP.md -/*eslint-disable no-unused-vars*/ -import * as runtypes from 'runtypes' -import { PlainClientAPI } from 'contentful-management' - -export enum ContentfulHeader { - Timestamp = 'x-contentful-timestamp', - SignedHeaders = 'x-contentful-signed-headers', - Signature = 'x-contentful-signature', -} - -export enum ContentfulContextHeader { - SpaceId = 'x-contentful-space-id', - EnvironmentId = 'x-contentful-environment-id', - UserId = 'x-contentful-user-id', - AppId = 'x-contentful-app-id', -} - -const MethodValidator = runtypes.Union( - runtypes.Literal('GET'), - runtypes.Literal('PATCH'), - runtypes.Literal('HEAD'), - runtypes.Literal('POST'), - runtypes.Literal('DELETE'), - runtypes.Literal('OPTIONS'), - runtypes.Literal('PUT') -) - -const PathValidator = runtypes.String.withConstraint((s) => s.startsWith('/'), { - name: 'CanonicalURI', -}) - -const SignatureValidator = runtypes.String.withConstraint((s) => s.length === 64, { - name: 'SignatureLength', -}) - -export const CanonicalRequestValidator = runtypes - .Record({ - method: MethodValidator, - path: PathValidator, - }) - .And( - runtypes.Partial({ - headers: runtypes.Dictionary(runtypes.String, 'string'), - body: runtypes.String, - }) - ) -export type CanonicalRequest = runtypes.Static - -export const SecretValidator = runtypes.String.withConstraint((s) => s.length === 64, { - name: 'SecretLength', -}) -export type Secret = runtypes.Static - -// Only dates after 01-01-2020 -export const TimestampValidator = runtypes.Number.withConstraint((n) => n > 1577836800000, { - name: 'TimestampAge', -}) -export type Timestamp = runtypes.Static - -const SignedHeadersValidator = runtypes - .Array(runtypes.String) - .withConstraint((l) => l.length >= 2, { name: 'MissingTimestampOrSignedHeaders' }) - -export const RequestMetadataValidator = runtypes.Record({ - signature: SignatureValidator, - timestamp: TimestampValidator, - signedHeaders: SignedHeadersValidator, -}) -export type RequestMetadata = runtypes.Static - -export const TimeToLiveValidator = runtypes.Number.withConstraint((n) => n >= 0, { - name: 'PositiveNumber', -}) -export type TimeToLive = runtypes.Static - -export type NormalizedCanonicalRequest = { - method: CanonicalRequest['method'] - path: CanonicalRequest['path'] - headers: [key: string, value: string][] - body: CanonicalRequest['body'] -} - -export type SubjectHeadersApp = { appId: string } -export type AppContextSignedHeaders = { [ContentfulContextHeader.AppId]: string } -export type SubjectHeadersUser = { userId: string } -export type UserContextSignedHeaders = { [ContentfulContextHeader.UserId]: string } - -export type Context = { - spaceId: string - envId: string -} & SubjectContext - -type SignedHeadersWithoutSubject = { - [ContentfulContextHeader.SpaceId]: string - [ContentfulContextHeader.EnvironmentId]: string -} - -export type SignedContextHeaders = SignedHeadersWithoutSubject & - SubjectSignedHeaders - -export type SignedRequestWithoutContextHeaders = { - [key in ContentfulHeader]: string -} -export type SignedRequestWithContextHeadersWithUser = SignedRequestWithoutContextHeaders & - SignedContextHeaders -export type SignedRequestWithContextHeadersWithApp = SignedRequestWithoutContextHeaders & - SignedContextHeaders - -export type SignedRequestHeaders = - | SignedRequestWithContextHeadersWithUser - | SignedRequestWithContextHeadersWithApp - | SignedRequestWithoutContextHeaders - -export type AppActionCallContext = { - cma: PlainClientAPI - appActionCallContext: { - spaceId: string - environmentId: string - appInstallationId: string - userId: string - } -} diff --git a/src/requests/typings/appAction.ts b/src/requests/typings/appAction.ts new file mode 100644 index 00000000..468e3fbe --- /dev/null +++ b/src/requests/typings/appAction.ts @@ -0,0 +1,11 @@ +import { PlainClientAPI } from 'contentful-management' + +export type AppActionCallContext = { + cma: PlainClientAPI + appActionCallContext: { + spaceId: string + environmentId: string + appInstallationId: string + userId: string + } +} diff --git a/src/requests/typings/deliveryFunction.ts b/src/requests/typings/deliveryFunction.ts new file mode 100644 index 00000000..f729c828 --- /dev/null +++ b/src/requests/typings/deliveryFunction.ts @@ -0,0 +1,62 @@ +// Remove when this eslint rule covers all the cases +// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/ROADMAP.md +/*eslint-disable no-unused-vars*/ + +export enum DeliveryFunctionRequestEventType { + GRAPHQL_FIELD_MAPPING = 'graphql.field.mapping', + GRAPHQL_QUERY = 'graphql.query', +} + +export type GraphQLFieldTypeMappingRequest = { + fields: { contentTypeId: string; field: Field }[] +} + +type Field = { + id: string + type: string +} + +export type GraphQLFieldTypeMappingResponse = GraphQLFieldTypeMapping[] + +export type GraphQLFieldTypeMapping = { + contentTypeId: string + fieldId: string + graphQLOutputType: string + graphQLQueryField: string + graphQLQueryArgument: string +} + +export type GraphQLQueryRequest = { + query: string + variables: Record + operationName?: string +} + +/** + * @see https://spec.graphql.org/October2021/#sec-Response + */ +export type GraphQLQueryResponse = { + data?: Record | null + errors?: readonly Record[] + extensions?: Record +} + +/** + * P: Possibility to type app installation parameters + */ +export type DeliveryFunctionEventContext

= Record> = { + spaceId: string + environmentId: string + appInstallationParameters: P +} + +export type DeliveryFunctionEventHandlers = { + [DeliveryFunctionRequestEventType.GRAPHQL_FIELD_MAPPING]: ( + event: GraphQLFieldTypeMappingRequest, + context: DeliveryFunctionEventContext + ) => Promise + [DeliveryFunctionRequestEventType.GRAPHQL_QUERY]: ( + event: GraphQLQueryRequest, + context: DeliveryFunctionEventContext + ) => Promise +} diff --git a/src/requests/typings/index.ts b/src/requests/typings/index.ts new file mode 100644 index 00000000..b4e5bfb2 --- /dev/null +++ b/src/requests/typings/index.ts @@ -0,0 +1,4 @@ +export * from './appAction' +export * from './deliveryFunction' +export * from './request' +export * from './validators' diff --git a/src/requests/typings/request.ts b/src/requests/typings/request.ts new file mode 100644 index 00000000..50e7941d --- /dev/null +++ b/src/requests/typings/request.ts @@ -0,0 +1,55 @@ +// Remove when this eslint rule covers all the cases +// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/ROADMAP.md +/*eslint-disable no-unused-vars*/ +import { CanonicalRequest } from './validators' + +export enum ContentfulHeader { + Timestamp = 'x-contentful-timestamp', + SignedHeaders = 'x-contentful-signed-headers', + Signature = 'x-contentful-signature', +} + +export enum ContentfulContextHeader { + SpaceId = 'x-contentful-space-id', + EnvironmentId = 'x-contentful-environment-id', + UserId = 'x-contentful-user-id', + AppId = 'x-contentful-app-id', +} + +export type NormalizedCanonicalRequest = { + method: CanonicalRequest['method'] + path: CanonicalRequest['path'] + headers: [key: string, value: string][] + body: CanonicalRequest['body'] +} + +export type SubjectHeadersApp = { appId: string } +export type AppContextSignedHeaders = { [ContentfulContextHeader.AppId]: string } +export type SubjectHeadersUser = { userId: string } +export type UserContextSignedHeaders = { [ContentfulContextHeader.UserId]: string } + +export type Context = { + spaceId: string + envId: string +} & SubjectContext + +type SignedHeadersWithoutSubject = { + [ContentfulContextHeader.SpaceId]: string + [ContentfulContextHeader.EnvironmentId]: string +} + +export type SignedContextHeaders = SignedHeadersWithoutSubject & + SubjectSignedHeaders + +export type SignedRequestWithoutContextHeaders = { + [key in ContentfulHeader]: string +} +export type SignedRequestWithContextHeadersWithUser = SignedRequestWithoutContextHeaders & + SignedContextHeaders +export type SignedRequestWithContextHeadersWithApp = SignedRequestWithoutContextHeaders & + SignedContextHeaders + +export type SignedRequestHeaders = + | SignedRequestWithContextHeadersWithUser + | SignedRequestWithContextHeadersWithApp + | SignedRequestWithoutContextHeaders diff --git a/src/requests/typings/validators.ts b/src/requests/typings/validators.ts new file mode 100644 index 00000000..37963cdd --- /dev/null +++ b/src/requests/typings/validators.ts @@ -0,0 +1,59 @@ +import * as runtypes from 'runtypes' + +const MethodValidator = runtypes.Union( + runtypes.Literal('GET'), + runtypes.Literal('PATCH'), + runtypes.Literal('HEAD'), + runtypes.Literal('POST'), + runtypes.Literal('DELETE'), + runtypes.Literal('OPTIONS'), + runtypes.Literal('PUT') +) + +const PathValidator = runtypes.String.withConstraint((s) => s.startsWith('/'), { + name: 'CanonicalURI', +}) + +const SignatureValidator = runtypes.String.withConstraint((s) => s.length === 64, { + name: 'SignatureLength', +}) + +export const CanonicalRequestValidator = runtypes + .Record({ + method: MethodValidator, + path: PathValidator, + }) + .And( + runtypes.Partial({ + headers: runtypes.Dictionary(runtypes.String, 'string'), + body: runtypes.String, + }) + ) +export type CanonicalRequest = runtypes.Static + +export const SecretValidator = runtypes.String.withConstraint((s) => s.length === 64, { + name: 'SecretLength', +}) +export type Secret = runtypes.Static + +// Only dates after 01-01-2020 +export const TimestampValidator = runtypes.Number.withConstraint((n) => n > 1577836800000, { + name: 'TimestampAge', +}) +export type Timestamp = runtypes.Static + +const SignedHeadersValidator = runtypes + .Array(runtypes.String) + .withConstraint((l) => l.length >= 2, { name: 'MissingTimestampOrSignedHeaders' }) + +export const RequestMetadataValidator = runtypes.Record({ + signature: SignatureValidator, + timestamp: TimestampValidator, + signedHeaders: SignedHeadersValidator, +}) +export type RequestMetadata = runtypes.Static + +export const TimeToLiveValidator = runtypes.Number.withConstraint((n) => n >= 0, { + name: 'PositiveNumber', +}) +export type TimeToLive = runtypes.Static