@r1tsu/payload
Version:
285 lines (284 loc) • 10 kB
JavaScript
import crypto from 'crypto';
import { decrypt, encrypt } from './auth/crypto.js';
import { APIKeyAuthentication } from './auth/strategies/apiKey.js';
import { JWTAuthentication } from './auth/strategies/jwt.js';
import localOperations from './collections/operations/local/index.js';
import { validateSchema } from './config/validate.js';
import { consoleEmailAdapter } from './email/consoleEmailAdapter.js';
import { fieldAffectsData } from './exports/types.js';
import localGlobalOperations from './globals/operations/local/index.js';
import flattenFields from './utilities/flattenTopLevelFields.js';
import Logger from './utilities/logger.js';
import { serverInit as serverInitTelemetry } from './utilities/telemetry/events/serverInit.js';
/**
* @description Payload
*/ export class BasePayload {
/**
* @description Authorization and Authentication using headers and cookies to run auth user strategies
* @returns cookies: Map<string, string>
* @returns permissions: Permissions
* @returns user: User
*/ auth = async (options)=>{
const { auth } = localOperations.auth;
return auth(this, options);
};
authStrategies;
collections = {};
config;
/**
* @description Performs count operation
* @param options
* @returns count of documents satisfying query
*/ count = async (options)=>{
const { count } = localOperations;
return count(this, options);
};
/**
* @description Performs create operation
* @param options
* @returns created document
*/ create = async (options)=>{
const { create } = localOperations;
return create(this, options);
};
db;
decrypt = decrypt;
duplicate = async (options)=>{
const { duplicate } = localOperations;
return duplicate(this, options);
};
email;
// TODO: re-implement or remove?
// errorHandler: ErrorHandler
encrypt = encrypt;
extensions;
/**
* @description Find documents with criteria
* @param options
* @returns documents satisfying query
*/ find = async (options)=>{
const { find } = localOperations;
return find(this, options);
};
/**
* @description Find document by ID
* @param options
* @returns document with specified ID
*/ findByID = async (options)=>{
const { findByID } = localOperations;
return findByID(this, options);
};
findGlobal = async (options)=>{
const { findOne } = localGlobalOperations;
return findOne(this, options);
};
/**
* @description Find global version by ID
* @param options
* @returns global version with specified ID
*/ findGlobalVersionByID = async (options)=>{
const { findVersionByID } = localGlobalOperations;
return findVersionByID(this, options);
};
/**
* @description Find global versions with criteria
* @param options
* @returns versions satisfying query
*/ findGlobalVersions = async (options)=>{
const { findVersions } = localGlobalOperations;
return findVersions(this, options);
};
/**
* @description Find version by ID
* @param options
* @returns version with specified ID
*/ findVersionByID = async (options)=>{
const { findVersionByID } = localOperations;
return findVersionByID(this, options);
};
/**
* @description Find versions with criteria
* @param options
* @returns versions satisfying query
*/ findVersions = async (options)=>{
const { findVersions } = localOperations;
return findVersions(this, options);
};
forgotPassword = async (options)=>{
const { forgotPassword } = localOperations.auth;
return forgotPassword(this, options);
};
getAPIURL = ()=>`${this.config.serverURL}${this.config.routes.api}`;
getAdminURL = ()=>`${this.config.serverURL}${this.config.routes.admin}`;
globals;
logger;
login = async (options)=>{
const { login } = localOperations.auth;
return login(this, options);
};
resetPassword = async (options)=>{
const { resetPassword } = localOperations.auth;
return resetPassword(this, options);
};
/**
* @description Restore global version by ID
* @param options
* @returns version with specified ID
*/ restoreGlobalVersion = async (options)=>{
const { restoreVersion } = localGlobalOperations;
return restoreVersion(this, options);
};
/**
* @description Restore version by ID
* @param options
* @returns version with specified ID
*/ restoreVersion = async (options)=>{
const { restoreVersion } = localOperations;
return restoreVersion(this, options);
};
schema;
secret;
sendEmail;
types;
unlock = async (options)=>{
const { unlock } = localOperations.auth;
return unlock(this, options);
};
updateGlobal = async (options)=>{
const { update } = localGlobalOperations;
return update(this, options);
};
validationRules;
verifyEmail = async (options)=>{
const { verifyEmail } = localOperations.auth;
return verifyEmail(this, options);
};
versions = {};
delete(options) {
const { deleteLocal } = localOperations;
return deleteLocal(this, options);
}
/**
* @description Initializes Payload
* @param options
*/ async init(options) {
if (!options?.config) {
throw new Error('Error: the payload config is required to initialize payload.');
}
this.logger = Logger('payload', options.loggerOptions, options.loggerDestination);
this.config = await options.config;
if (process.env.NODE_ENV !== 'production') {
validateSchema(this.config, this.logger);
}
if (!this.config.secret) {
throw new Error('Error: missing secret key. A secret key is needed to secure Payload.');
}
this.secret = crypto.createHash('sha256').update(this.config.secret).digest('hex').slice(0, 32);
this.globals = {
config: this.config.globals
};
this.config.collections.forEach((collection)=>{
const customID = flattenFields(collection.fields).find((field)=>fieldAffectsData(field) && field.name === 'id');
let customIDType;
if (customID?.type === 'number' || customID?.type === 'text') customIDType = customID.type;
this.collections[collection.slug] = {
config: collection,
customIDType
};
});
this.db = this.config.db.init({
payload: this
});
this.db.payload = this;
if (this.db?.init) {
await this.db.init();
}
if (!options.disableDBConnect && this.db.connect) {
await this.db.connect();
}
// Load email adapter
if (this.config.email instanceof Promise) {
const awaitedAdapter = await this.config.email;
this.email = awaitedAdapter({
payload: this
});
} else if (this.config.email) {
this.email = this.config.email({
payload: this
});
} else {
this.logger.warn(`No email adapter provided. Email will be written to console. More info at https://payloadcms.com/docs/email/overview.`);
this.email = consoleEmailAdapter({
payload: this
});
}
this.sendEmail = this.email['sendEmail'];
serverInitTelemetry(this);
// 1. loop over collections, if collection has auth strategy, initialize and push to array
let jwtStrategyEnabled = false;
this.authStrategies = this.config.collections.reduce((authStrategies, collection)=>{
if (collection?.auth) {
if (collection.auth.strategies.length > 0) {
authStrategies.push(...collection.auth.strategies);
}
// 2. if api key enabled, push api key strategy into the array
if (collection.auth?.useAPIKey) {
authStrategies.push({
name: `${collection.slug}-api-key`,
authenticate: APIKeyAuthentication(collection)
});
}
// 3. if localStrategy flag is true
if (!collection.auth.disableLocalStrategy && !jwtStrategyEnabled) {
jwtStrategyEnabled = true;
}
}
return authStrategies;
}, []);
// 4. if enabled, push jwt strategy into authStrategies last
if (jwtStrategyEnabled) {
this.authStrategies.push({
name: 'local-jwt',
authenticate: JWTAuthentication
});
}
if (!options.disableOnInit) {
if (typeof options.onInit === 'function') await options.onInit(this);
if (typeof this.config.onInit === 'function') await this.config.onInit(this);
}
return this;
}
update(options) {
const { update } = localOperations;
return update(this, options);
}
}
const initialized = new BasePayload();
export default initialized;
let cached = global._payload;
if (!cached) {
// eslint-disable-next-line no-multi-assign
cached = global._payload = {
payload: null,
promise: null
};
}
export const getPayload = async (options)=>{
if (!options?.config) {
throw new Error('Error: the payload config is required for getPayload to work.');
}
if (cached.payload) {
return cached.payload;
}
if (!cached.promise) {
cached.promise = new BasePayload().init(options);
}
try {
cached.payload = await cached.promise;
} catch (e) {
cached.promise = null;
throw e;
}
return cached.payload;
};
//# sourceMappingURL=index.js.map