further types

This commit is contained in:
James
2020-11-29 15:40:11 -05:00
23 changed files with 119 additions and 82 deletions

14
demo/client/index.html Normal file
View File

@@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div id="app"></div>
<div id="portal"></div>
</body>
</html>

View File

@@ -35,7 +35,7 @@ export default buildConfig({
serverURL: 'http://localhost:3000',
admin: {
user: 'admins',
// indexHTML: 'custom-index.html',
indexHTML: path.resolve(__dirname, './client/index.html'),
// meta: {
// titleSuffix: '- Payload Demo',
// // ogImage: '/static/find-image-here.jpg',

View File

@@ -13,7 +13,7 @@
"scripts": {
"copyfiles": "copyfiles src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png} dist/",
"build:components": "webpack --config src/webpack/components.config.js",
"build": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.js node dist/src/bin/build",
"build": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.ts node dist/src/bin/build",
"build:tsc": "tsc",
"build:analyze": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.js PAYLOAD_ANALYZE_BUNDLE=true node src/bin/build",
"cov": "npm run core:build && node ./node_modules/jest/bin/jest.js src/tests --coverage",

View File

@@ -59,8 +59,8 @@ export type User = {
type GenerateVerifyEmailHTML = (args: { req: PayloadRequest, token: string, user: any}) => Promise<string> | string
type GenerateVerifyEmailSubject = (args: { req: PayloadRequest, token: string, user: any}) => Promise<string> | string
type GenerateForgotPasswordEmailHTML = (args?: { token?: string, email?: string, req?: PayloadRequest }) => string
type GenerateForgotPasswordEmailSubject = (args?: { req?: PayloadRequest }) => string
type GenerateForgotPasswordEmailHTML = (args?: { token?: string, email?: string, req?: PayloadRequest }) => Promise<string> | string
type GenerateForgotPasswordEmailSubject = (args?: { req?: PayloadRequest }) => Promise<string> | string
export interface IncomingAuthType {
tokenExpiration?: number;

View File

@@ -6,14 +6,11 @@ import getWebpackProdConfig from '../webpack/getWebpackProdConfig';
import findConfig from '../config/find';
import loadConfig from '../config/load';
import { buildConfig } from '../config/build';
import babelConfig from '../babel.config';
const configPath = findConfig();
const build = (): void => {
export const build = (): void => {
try {
require('@babel/register')(babelConfig);
const loadedConfig = loadConfig();
const config = buildConfig(loadedConfig);
const webpackProdConfig = getWebpackProdConfig({
@@ -43,6 +40,3 @@ const build = (): void => {
if (module.id === require.main.id) {
build();
}
export default build;

View File

@@ -1,5 +1,13 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import minimist from 'minimist';
import build from './build';
import babelConfig from '../babel.config';
require('@babel/register')({
...babelConfig,
extensions: ['.ts', '.tsx', '.js', '.jsx'],
});
const { build } = require('./build');
const args = minimist(process.argv.slice(2));

View File

@@ -44,42 +44,48 @@ const collectionSchema = joi.object().keys({
afterLogin: joi.array().items(joi.func()).default([]),
afterForgotPassword: joi.array().items(joi.func()).default([]),
}).default(),
auth: joi.object({
tokenExpiration: joi.number(),
depth: joi.number().default(0),
verify: joi.alternatives().try(
joi.boolean(),
joi.object().keys({
auth: joi.alternatives().try(
joi.object({
tokenExpiration: joi.number(),
depth: joi.number().default(0),
verify: joi.alternatives().try(
joi.boolean(),
joi.object().keys({
generateEmailHTML: joi.func(),
generateEmailSubject: joi.func(),
}),
),
lockTime: joi.number(),
useAPIKey: joi.boolean(),
cookies: joi.object().keys({
secure: joi.boolean(),
sameSite: joi.string(), // TODO: add further specificity with joi.xor
domain: joi.string(),
}),
forgotPassword: joi.object().keys({
generateEmailHTML: joi.func(),
generateEmailSubject: joi.func(),
}),
),
lockTime: joi.number(),
useAPIKey: joi.boolean(),
cookies: joi.object().keys({
secure: joi.boolean(),
sameSite: joi.string(), // TODO: add further specificity with joi.xor
domain: joi.string(),
maxLoginAttempts: joi.number(),
}),
forgotPassword: joi.object().keys({
generateEmailHTML: joi.func(),
generateEmailSubject: joi.func(),
joi.boolean(),
).default(false),
upload: joi.alternatives().try(
joi.object({
staticURL: joi.string(),
staticDir: joi.string(),
adminThumbnail: joi.string(),
imageSizes: joi.array().items(
joi.object().keys({
name: joi.string(),
width: joi.number(),
height: joi.number(),
crop: joi.string(), // TODO: add further specificity with joi.xor
}),
),
}),
maxLoginAttempts: joi.number(),
}).default(false),
upload: joi.object({
staticURL: joi.string(),
staticDir: joi.string(),
adminThumbnail: joi.string(),
imageSizes: joi.array().items(
joi.object().keys({
name: joi.string(),
width: joi.number(),
height: joi.number(),
crop: joi.string(), // TODO: add further specificity with joi.xor
}),
),
}).default(false),
joi.boolean(),
).default(false),
});
export default collectionSchema;

View File

@@ -118,13 +118,13 @@ export type PayloadCollectionConfig = {
afterLogin?: AfterLoginHook[];
afterForgotPassword?: AfterForgotPasswordHook[];
};
access: {
create: Access;
read: Access;
update: Access;
delete: Access;
admin: Access;
unlock: Access;
access?: {
create?: Access;
read?: Access;
update?: Access;
delete?: Access;
admin?: Access;
unlock?: Access;
};
auth?: Auth | boolean;
upload?: Upload | boolean;

View File

@@ -1,4 +1,6 @@
export default async function find(options) {
import { FindOptions } from '../../../types';
export default async function find(options: FindOptions) {
const {
collection: collectionSlug,
depth,

View File

@@ -9,6 +9,7 @@ import { PayloadCollectionConfig } from '../collections/config/types';
import { PayloadGlobalConfig } from '../globals/config/types';
import { PayloadRequest } from '../express/types/payloadRequest';
import InitializeGraphQL from '../graphql';
import { Where } from '../types';
type MockEmailTransport = {
transport?: 'mock';
@@ -47,7 +48,7 @@ export type MockEmailCredentials = {
web: string;
};
export type Access = (args?: any) => boolean;
export type Access = (args?: any) => boolean | Where;
export type PayloadConfig = {
admin?: {

View File

@@ -1,7 +1,7 @@
import passport from 'passport';
import { PayloadConfig } from '../../config/types';
import { Payload } from '../../index';
export default (config: PayloadConfig) => {
export default (config: Payload) => {
const methods = config.collections.reduce((enabledMethods, collection) => {
if (collection.auth && collection.auth.useAPIKey) {
const collectionMethods = [...enabledMethods];

View File

@@ -1,15 +1,16 @@
import { Request } from 'express';
import { Payload } from '../../index';
import { Collection } from '../../collections/config/types';
import { User } from '../../auth/types';
export type PayloadRequest = Request & {
payload: Payload;
locale?: string;
fallbackLocale?: string;
collection?: Collection;
payloadAPI: 'REST' | 'local'
payloadAPI: 'REST' | 'local' | 'graphQL'
file?: {
name: string,
}
// user: User
user: User | null
};

View File

@@ -207,6 +207,13 @@ export const richText = baseField.keys({
}),
});
export const date = baseField.keys({
type: joi.string().valid('date').required(),
name: joi.string().required(),
defaultValue: joi.string(),
});
const fieldSchema = joi.alternatives()
.try(
text,
@@ -224,6 +231,7 @@ const fieldSchema = joi.alternatives()
upload,
richText,
blocks,
date,
)
.id('field');

View File

@@ -2,15 +2,18 @@
import { CSSProperties } from 'react';
import { PayloadRequest } from '../../express/types/payloadRequest';
import { Access } from '../../config/types';
import { Document } from '../../types';
// TODO: add generic type and use mongoose types for originalDoc & data
export type FieldHook = (args: {
value?: any,
originalDoc?: any,
data?: any,
value?: unknown,
originalDoc?: Document,
data?: {
[key: string]: unknown
},
operation?: 'create' | 'update',
req?: PayloadRequest
}) => Promise<any> | any;
}) => Promise<unknown> | unknown;
type FieldBase = {
name: string;
@@ -33,7 +36,7 @@ type FieldBase = {
afterRead?: FieldHook[];
}
admin?: {
position?: 'sidebar';
position?: string;
width?: string;
style?: CSSProperties;
readOnly?: boolean;

View File

@@ -3,9 +3,9 @@ import crypto from 'crypto';
import { TestAccount } from 'nodemailer';
import { AuthenticateOptions } from 'passport';
import {
Config,
EmailOptions,
InitOptions,
PayloadConfig,
} from './config/types';
import {
Collection,
@@ -53,7 +53,7 @@ require('isomorphic-fetch');
* @description Payload
*/
export class Payload {
config: PayloadConfig = loadConfig();
config: Config = loadConfig();
collections: Collection[] = [];

View File

@@ -2,6 +2,12 @@ import { PayloadRequest } from '../express/types/payloadRequest';
import { Field } from '../fields/config/types';
import { Payload } from '../index';
export { FieldHook } from '../fields/config/types';
export type Where = {
[key: string]: unknown
}
export type Document = {
id: string;
[key: string]: unknown;

View File

@@ -3,7 +3,7 @@ import { promisify } from 'util';
const stat = promisify(fs.stat);
export default async (fileName) => {
export default async (fileName: string): Promise<boolean> => {
try {
await stat(fileName);
return true;

View File

@@ -1,4 +1,4 @@
export default function formatBytes(bytes, decimals = 0) {
export default function formatBytes(bytes: number, decimals = 0): string {
if (bytes === 0) return '0 bytes';
const k = 1024;

View File

@@ -1,7 +1,7 @@
import sanitize from 'sanitize-filename';
import fileExists from './fileExists';
const incrementName = (name) => {
const incrementName = (name: string) => {
const extension = name.split('.').pop();
const baseFilename = sanitize(name.substr(0, name.lastIndexOf('.')) || name);
let incrementedName = baseFilename;
@@ -19,7 +19,7 @@ const incrementName = (name) => {
return `${incrementedName}.${extension}`;
};
async function getSafeFileName(staticPath, desiredFilename) {
async function getSafeFileName(staticPath: string, desiredFilename: string): Promise<string> {
let modifiedFilename = desiredFilename;
// eslint-disable-next-line no-await-in-loop

View File

@@ -1,6 +1,7 @@
import isImage from './isImage';
import { FileData } from './types';
const getThumbnail = (mimeType, staticURL, filename, sizes, adminThumbnail): string | boolean => {
const getThumbnail = (mimeType: string, staticURL: string, filename: string, sizes: FileData[], adminThumbnail: string): string | boolean => {
if (isImage(mimeType)) {
if (sizes?.[adminThumbnail]?.filename) {
return `${staticURL}/${sizes[adminThumbnail].filename}`;

View File

@@ -3,7 +3,7 @@ import sharp from 'sharp';
import sanitize from 'sanitize-filename';
import getImageSize from './getImageSize';
import fileExists from './fileExists';
import { Collection } from '../collections/config/types';
import { CollectionConfig } from '../collections/config/types';
import { FileSizes } from './types';
function getOutputImage(sourceImage, size) {
@@ -28,7 +28,7 @@ function getOutputImage(sourceImage, size) {
*/
export default async function resizeAndSave(
staticPath: string,
config: Collection,
config: CollectionConfig,
savedFilename: string,
mimeType: string,
): Promise<FileSizes> {

View File

@@ -1,9 +1,9 @@
import { DuplicateCollection } from '../errors';
import { Collection } from '../collections/config/types';
import { CollectionConfig } from '../collections/config/types';
const getDuplicates = (arr) => arr.filter((item, index) => arr.indexOf(item) !== index);
const getDuplicates = (arr: string[]) => arr.filter((item, index) => arr.indexOf(item) !== index);
const checkDuplicateCollections = (collections: Collection[]): void => {
const checkDuplicateCollections = (collections: CollectionConfig[]): void => {
const duplicateSlugs = getDuplicates(collections.map((c) => c.slug));
if (duplicateSlugs.length > 0) {
throw new DuplicateCollection('slug', duplicateSlugs);

View File

@@ -91,6 +91,7 @@ export default (config: Config): Configuration => {
alias: {
'payload/config': config.paths.config,
'@payloadcms/payload$': mockModulePath,
'payload-scss-overrides': config.paths.scss,
},
extensions: ['.ts', '.tsx', '.js', '.json'],
},
@@ -99,9 +100,7 @@ export default (config: Config): Configuration => {
{ process: 'process/browser' },
),
new HtmlWebpackPlugin({
template: config.admin && config.admin.indexHTML
? path.join(config.paths.configDir, config.admin.indexHTML)
: path.resolve(__dirname, '../admin/index.html'),
template: config.admin.indexHTML,
filename: path.normalize('./index.html'),
}),
new webpack.DefinePlugin(Object.entries(config.publicENV).reduce((values, [key, val]) => ({
@@ -125,12 +124,6 @@ export default (config: Config): Configuration => {
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}
if (config.paths.scss) {
webpackConfig.resolve.alias['payload-scss-overrides'] = path.join(config.paths.configDir, config.paths.scss);
} else {
webpackConfig.resolve.alias['payload-scss-overrides'] = path.resolve(__dirname, '../admin/scss/overrides.scss');
}
if (config.webpack && typeof config.webpack === 'function') {
webpackConfig = config.webpack(webpackConfig);
}