From 2b70e4aed813e8220f6962468e3df61c9c715168 Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Wed, 7 Jan 2026 22:10:53 +0100 Subject: [PATCH 01/10] fix: Add server-side Cloud Code types for parse/node - Add CloudServer.d.ts with comprehensive server-side type definitions - Use module augmentation in node.d.ts to extend Cloud module - Add BeforeDeleteRequest and AfterDeleteRequest interfaces - Add type tests for server-side Cloud functions Types include: define, job, beforeSave, afterSave, beforeDelete, afterDelete, beforeFind, afterFind, beforeLogin, afterLogin, afterLogout, file triggers, LiveQuery triggers, httpRequest, sendEmail --- types/CloudServer.d.ts | 919 +++++++++++++++++++++++++++++++++++++++++ types/node.d.ts | 43 ++ types/tests.ts | 21 + 3 files changed, 983 insertions(+) create mode 100644 types/CloudServer.d.ts diff --git a/types/CloudServer.d.ts b/types/CloudServer.d.ts new file mode 100644 index 000000000..d89dc3270 --- /dev/null +++ b/types/CloudServer.d.ts @@ -0,0 +1,919 @@ +/** + * Server-side Cloud Code types for Parse Server. + * These types are only available when using `parse/node` import. + * + * @module CloudServer + */ + +import ParseObject from './ParseObject'; +import ParseUser from './ParseUser'; +import ParseFile from './ParseFile'; +import ParseQuery from './ParseQuery'; + +// ============================================================================ +// Request Interfaces +// ============================================================================ + +/** + * Request object for Cloud Functions defined with `Parse.Cloud.define`. + */ +export interface FunctionRequest> { + /** + * If set, the installationId triggering the request. + */ + installationId?: string; + /** + * If true, means the master key was used. + */ + master: boolean; + /** + * If set, the user that made the request. + */ + user?: ParseUser; + /** + * The params passed to the cloud function. + */ + params: T; + /** + * The IP address of the client making the request. + */ + ip: string; + /** + * The original HTTP headers for the request. + */ + headers: Record; + /** + * The current logger inside Parse Server. + */ + log: any; + /** + * The name of the Cloud function. + */ + functionName: string; + /** + * A dictionary that is accessible in triggers. + */ + context: Record; + /** + * The Parse Server config. + */ + config: any; +} + +/** + * Response object for Express-style Cloud Functions. + */ +export interface FunctionResponse { + /** + * Send a success response with optional result data. + */ + success: (result?: any) => void; + /** + * Send an error response with optional message. + */ + error: (message?: string) => void; + /** + * Set the HTTP status code for the response. + */ + status: (code: number) => FunctionResponse; + /** + * Set a header on the response. + */ + header: (name: string, value: string) => FunctionResponse; +} + +/** + * Base request object for trigger hooks (beforeSave, afterSave, etc.). + */ +export interface TriggerRequest { + /** + * If set, the installationId triggering the request. + */ + installationId?: string; + /** + * If true, means the master key was used. + */ + master: boolean; + /** + * If true, means the trigger is being invoked as a challenge. + */ + isChallenge: boolean; + /** + * If set, the user that made the request. + */ + user?: ParseUser; + /** + * The object triggering the hook. + */ + object: T; + /** + * If set, the object as currently stored (for updates). + */ + original?: T; + /** + * The IP address of the client making the request. + */ + ip: string; + /** + * The original HTTP headers for the request. + */ + headers: Record; + /** + * The name of the trigger (e.g., "beforeSave", "afterSave"). + */ + triggerName: string; + /** + * The current logger inside Parse Server. + */ + log: any; + /** + * A dictionary that is accessible in triggers. + */ + context: Record; + /** + * The Parse Server config. + */ + config: any; +} + +/** + * Request object for beforeSave triggers. + */ +export interface BeforeSaveRequest extends TriggerRequest {} + +/** + * Request object for afterSave triggers. + */ +export interface AfterSaveRequest extends TriggerRequest {} + +/** + * Request object for beforeDelete triggers. + */ +export interface BeforeDeleteRequest extends TriggerRequest {} + +/** + * Request object for afterDelete triggers. + */ +export interface AfterDeleteRequest extends TriggerRequest {} + +/** + * Request object for beforeFind triggers. + */ +export interface BeforeFindRequest { + /** + * If set, the installationId triggering the request. + */ + installationId?: string; + /** + * If true, means the master key was used. + */ + master: boolean; + /** + * If set, the user that made the request. + */ + user?: ParseUser; + /** + * The query being executed. + */ + query: ParseQuery; + /** + * The IP address of the client making the request. + */ + ip: string; + /** + * The original HTTP headers for the request. + */ + headers: Record; + /** + * The name of the trigger. + */ + triggerName: string; + /** + * The current logger inside Parse Server. + */ + log: any; + /** + * If true, the query is a get operation. + */ + isGet: boolean; + /** + * The Parse Server config. + */ + config: any; + /** + * If set, the read preference for the query. + */ + readPreference?: string; + /** + * If true, the query is a count operation. + */ + count?: boolean; +} + +/** + * Request object for afterFind triggers. + */ +export interface AfterFindRequest { + /** + * If set, the installationId triggering the request. + */ + installationId?: string; + /** + * If true, means the master key was used. + */ + master: boolean; + /** + * If set, the user that made the request. + */ + user?: ParseUser; + /** + * The query that was executed. + */ + query: ParseQuery; + /** + * The results returned by the query. + */ + results: T[]; + /** + * The IP address of the client making the request. + */ + ip: string; + /** + * The original HTTP headers for the request. + */ + headers: Record; + /** + * The name of the trigger. + */ + triggerName: string; + /** + * The current logger inside Parse Server. + */ + log: any; + /** + * The Parse Server config. + */ + config: any; +} + +/** + * Request object for file triggers (beforeSaveFile, afterSaveFile, etc.). + */ +export interface FileTriggerRequest { + /** + * If set, the installationId triggering the request. + */ + installationId?: string; + /** + * If true, means the master key was used. + */ + master: boolean; + /** + * If set, the user that made the request. + */ + user?: ParseUser; + /** + * The file being saved or deleted. + */ + file: ParseFile; + /** + * The size of the file in bytes. + */ + fileSize: number; + /** + * The content length of the request. + */ + contentLength: number; + /** + * The IP address of the client making the request. + */ + ip: string; + /** + * The original HTTP headers for the request. + */ + headers: Record; + /** + * The name of the trigger. + */ + triggerName: string; + /** + * The current logger inside Parse Server. + */ + log: any; + /** + * The Parse Server config. + */ + config: any; +} + +/** + * Request object for beforeConnect LiveQuery trigger. + */ +export interface ConnectTriggerRequest { + /** + * If set, the installationId triggering the request. + */ + installationId?: string; + /** + * If true, means the master key was used. + */ + useMasterKey: boolean; + /** + * If set, the user that made the request. + */ + user?: ParseUser; + /** + * The number of connected clients. + */ + clients: number; + /** + * The number of active subscriptions. + */ + subscriptions: number; + /** + * The session token if available. + */ + sessionToken?: string; +} + +/** + * Request object for afterLiveQueryEvent trigger. + */ +export interface LiveQueryEventTrigger { + /** + * If set, the installationId triggering the request. + */ + installationId?: string; + /** + * If true, means the master key was used. + */ + useMasterKey: boolean; + /** + * If set, the user that made the request. + */ + user?: ParseUser; + /** + * The session token if available. + */ + sessionToken?: string; + /** + * The event type (create, update, delete, enter, leave). + */ + event: string; + /** + * The object that triggered the event. + */ + object: T; + /** + * The original object before modification (for updates). + */ + original?: T; + /** + * The number of connected clients. + */ + clients: number; + /** + * The number of active subscriptions. + */ + subscriptions: number; + /** + * If false, the event will not be sent to clients. + */ + sendEvent: boolean; +} + +/** + * Request object for background jobs defined with `Parse.Cloud.job`. + */ +export interface JobRequest { + /** + * The params passed to the background job. + */ + params: Record; + /** + * A function to update the status message of the job. + */ + message: (message: string) => void; + /** + * The Parse Server config. + */ + config: any; +} + +// ============================================================================ +// Validator Types +// ============================================================================ + +/** + * Configuration for a single field in the validator. + */ +export interface ValidatorField { + /** + * The expected type of the field. + */ + type?: any; + /** + * If true, the field cannot be modified after creation. + */ + constant?: boolean; + /** + * Default value for the field. + */ + default?: any; + /** + * Valid options for the field value. + */ + options?: any[] | (() => any[]) | any; + /** + * If true, the field is required. + */ + required?: boolean; + /** + * Custom error message for validation failure. + */ + error?: string; +} + +/** + * Validator configuration for Cloud Functions and triggers. + */ +export interface ValidatorObject { + /** + * If true, requires a user to be logged in. + */ + requireUser?: boolean; + /** + * If true, requires the master key. + */ + requireMaster?: boolean; + /** + * If true, validates the master key. + */ + validateMasterKey?: boolean; + /** + * If true, skips validation when master key is used. + */ + skipWithMasterKey?: boolean; + /** + * Requires the user to have any of these roles. + */ + requireAnyUserRoles?: string[] | (() => string[]); + /** + * Requires the user to have all of these roles. + */ + requireAllUserRoles?: string[] | (() => string[]); + /** + * Required keys on the user object. + */ + requireUserKeys?: string[] | Record; + /** + * Field validation configuration. + */ + fields?: string[] | Record; + /** + * Rate limiting configuration. + */ + rateLimit?: { + /** + * The path to apply rate limiting to. + */ + requestPath?: string; + /** + * HTTP methods to rate limit. + */ + requestMethods?: string | string[]; + /** + * Time window in milliseconds. + */ + requestTimeWindow?: number; + /** + * Maximum number of requests in the time window. + */ + requestCount?: number; + /** + * Custom error message when rate limit is exceeded. + */ + errorResponseMessage?: string; + /** + * If true, includes internal requests in rate limiting. + */ + includeInternalRequests?: boolean; + /** + * If true, includes master key requests in rate limiting. + */ + includeMasterKey?: boolean; + }; +} + +// ============================================================================ +// HTTP Request Types +// ============================================================================ + +/** + * Options for `Parse.Cloud.httpRequest`. + */ +export interface HTTPOptions { + /** + * The body of the request. + */ + body?: string | object; + /** + * Callback for error responses. + */ + error?: (response: HTTPResponse) => void; + /** + * If true, follows HTTP redirects. + */ + followRedirects?: boolean; + /** + * HTTP headers for the request. + */ + headers?: Record; + /** + * HTTP method for the request. + */ + method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS'; + /** + * Query parameters for the request. + */ + params?: string | Record; + /** + * Callback for success responses. + */ + success?: (response: HTTPResponse) => void; + /** + * The URL to send the request to. + */ + url: string; +} + +/** + * Response from `Parse.Cloud.httpRequest`. + */ +export interface HTTPResponse { + /** + * The raw response buffer. + */ + buffer?: Buffer; + /** + * Cookies from the response. + */ + cookies?: Record; + /** + * The parsed response data. + */ + data?: any; + /** + * HTTP headers from the response. + */ + headers?: Record; + /** + * HTTP status code. + */ + status: number; + /** + * The raw response text. + */ + text?: string; +} + +// ============================================================================ +// Read Preference Enum +// ============================================================================ + +/** + * Read preference options for MongoDB queries. + */ +export enum ReadPreferenceOption { + Primary = 'PRIMARY', + PrimaryPreferred = 'PRIMARY_PREFERRED', + Secondary = 'SECONDARY', + SecondaryPreferred = 'SECONDARY_PREFERRED', + Nearest = 'NEAREST', +} + +// ============================================================================ +// Cloud Function Declarations +// ============================================================================ + +/** + * Defines a Cloud Function. + * + * @example + * ```typescript + * Parse.Cloud.define('hello', (request) => { + * return `Hello, ${request.params.name}!`; + * }); + * ``` + * + * @param name - The name of the Cloud Function. + * @param handler - The function to execute. + * @param validator - Optional validator configuration. + */ +export function define = Record>( + name: string, + handler: (request: FunctionRequest) => any, + validator?: ValidatorObject | ((request: FunctionRequest) => any) +): void; + +/** + * Defines a Cloud Function with Express-style response object. + * + * @param name - The name of the Cloud Function. + * @param handler - The function to execute with request and response objects. + * @param validator - Optional validator configuration. + */ +export function define = Record>( + name: string, + handler: (request: FunctionRequest, response: FunctionResponse) => any, + validator?: ValidatorObject | ((request: FunctionRequest) => any) +): void; + +/** + * Defines a background job. + * + * @example + * ```typescript + * Parse.Cloud.job('myJob', (request) => { + * request.message('Processing...'); + * // Do background work + * }); + * ``` + * + * @param name - The name of the background job. + * @param handler - The function to execute. + */ +export function job(name: string, handler: (request: JobRequest) => any): void; + +// ============================================================================ +// Object Lifecycle Hooks +// ============================================================================ + +/** + * Registers a beforeSave trigger for a class. + * + * @example + * ```typescript + * Parse.Cloud.beforeSave('MyClass', (request) => { + * request.object.set('updatedBy', request.user); + * }); + * ``` + * + * @param className - The class name or constructor. + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function beforeSave( + className: string | { new (): T }, + handler: (request: BeforeSaveRequest) => T | void | Promise, + validator?: ValidatorObject | ((request: BeforeSaveRequest) => any) +): void; + +/** + * Registers an afterSave trigger for a class. + * + * @param className - The class name or constructor. + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function afterSave( + className: string | { new (): T }, + handler: (request: AfterSaveRequest) => void | Promise, + validator?: ValidatorObject | ((request: AfterSaveRequest) => any) +): void; + +/** + * Registers a beforeDelete trigger for a class. + * + * @param className - The class name or constructor. + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function beforeDelete( + className: string | { new (): T }, + handler: (request: BeforeDeleteRequest) => void | Promise, + validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any) +): void; + +/** + * Registers an afterDelete trigger for a class. + * + * @param className - The class name or constructor. + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function afterDelete( + className: string | { new (): T }, + handler: (request: AfterDeleteRequest) => void | Promise, + validator?: ValidatorObject | ((request: AfterDeleteRequest) => any) +): void; + +// ============================================================================ +// Query Hooks +// ============================================================================ + +/** + * Registers a beforeFind trigger for a class. + * + * @example + * ```typescript + * Parse.Cloud.beforeFind('MyClass', (request) => { + * // Modify the query + * request.query.equalTo('active', true); + * return request.query; + * }); + * ``` + * + * @param className - The class name or constructor. + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function beforeFind( + className: string | { new (): T }, + handler: (request: BeforeFindRequest) => ParseQuery | void | Promise | void>, + validator?: ValidatorObject | ((request: BeforeFindRequest) => any) +): void; + +/** + * Registers an afterFind trigger for a class. + * + * @param className - The class name or constructor. + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function afterFind( + className: string | { new (): T }, + handler: (request: AfterFindRequest) => T[] | void | Promise, + validator?: ValidatorObject | ((request: AfterFindRequest) => any) +): void; + +// ============================================================================ +// Auth Hooks +// ============================================================================ + +/** + * Registers a beforeLogin trigger. + * + * @example + * ```typescript + * Parse.Cloud.beforeLogin((request) => { + * if (request.object.get('banned')) { + * throw new Error('User is banned'); + * } + * }); + * ``` + * + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function beforeLogin( + handler: (request: TriggerRequest) => void | Promise, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +/** + * Registers an afterLogin trigger. + * + * @param handler - The trigger function. + */ +export function afterLogin(handler: (request: TriggerRequest) => void | Promise): void; + +/** + * Registers an afterLogout trigger. + * + * @param handler - The trigger function. + */ +export function afterLogout(handler: (request: TriggerRequest) => void | Promise): void; + +/** + * Registers a beforePasswordResetRequest trigger. + * + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function beforePasswordResetRequest( + handler: (request: TriggerRequest) => void | Promise, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +// ============================================================================ +// File Hooks +// ============================================================================ + +/** + * Registers a beforeSaveFile trigger. + * + * @example + * ```typescript + * Parse.Cloud.beforeSaveFile((request) => { + * // Validate or modify file before saving + * if (request.fileSize > 10 * 1024 * 1024) { + * throw new Error('File too large'); + * } + * }); + * ``` + * + * @param handler - The trigger function. + */ +export function beforeSaveFile( + handler: (request: FileTriggerRequest) => ParseFile | void | Promise +): void; + +/** + * Registers an afterSaveFile trigger. + * + * @param handler - The trigger function. + */ +export function afterSaveFile(handler: (request: FileTriggerRequest) => void | Promise): void; + +/** + * Registers a beforeDeleteFile trigger. + * + * @param handler - The trigger function. + */ +export function beforeDeleteFile(handler: (request: FileTriggerRequest) => void | Promise): void; + +/** + * Registers an afterDeleteFile trigger. + * + * @param handler - The trigger function. + */ +export function afterDeleteFile(handler: (request: FileTriggerRequest) => void | Promise): void; + +// ============================================================================ +// LiveQuery Hooks +// ============================================================================ + +/** + * Registers a beforeConnect trigger for LiveQuery. + * + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function beforeConnect( + handler: (request: ConnectTriggerRequest) => void | Promise, + validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any) +): void; + +/** + * Registers a beforeSubscribe trigger for LiveQuery. + * + * @param className - The class name or constructor. + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function beforeSubscribe( + className: string | { new (): T }, + handler: (request: TriggerRequest) => void | Promise, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +/** + * Registers an afterLiveQueryEvent trigger. + * + * @param className - The class name or constructor. + * @param handler - The trigger function. + * @param validator - Optional validator configuration. + */ +export function afterLiveQueryEvent( + className: string | { new (): T }, + handler: (request: LiveQueryEventTrigger) => void | Promise, + validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any) +): void; + +// ============================================================================ +// Utility Functions +// ============================================================================ + +/** + * Sends an email using the configured email adapter. + * + * @param data - Email configuration. + */ +export function sendEmail(data: { + from?: string; + to: string; + subject?: string; + text?: string; + html?: string; +}): Promise; + +/** + * Makes an HTTP request. + * + * @example + * ```typescript + * const response = await Parse.Cloud.httpRequest({ + * url: 'https://api.example.com/data', + * method: 'GET', + * headers: { + * 'Authorization': 'Bearer token' + * } + * }); + * console.log(response.data); + * ``` + * + * @param options - HTTP request options. + * @returns The HTTP response. + */ +export function httpRequest(options: HTTPOptions): Promise; diff --git a/types/node.d.ts b/types/node.d.ts index f8a7890db..79bc5f13a 100644 --- a/types/node.d.ts +++ b/types/node.d.ts @@ -1,3 +1,46 @@ import * as parse from './index'; +// Augment Cloud module to include server-side types for parse/node +declare module './Cloud' { + // Request types - alias to CloudServer definitions + export type FunctionRequest> = import('./CloudServer').FunctionRequest; + export type TriggerRequest = import('./CloudServer').TriggerRequest; + export type BeforeSaveRequest = import('./CloudServer').BeforeSaveRequest; + export type AfterSaveRequest = import('./CloudServer').AfterSaveRequest; + export type BeforeDeleteRequest = import('./CloudServer').BeforeDeleteRequest; + export type AfterDeleteRequest = import('./CloudServer').AfterDeleteRequest; + export type BeforeFindRequest = import('./CloudServer').BeforeFindRequest; + export type AfterFindRequest = import('./CloudServer').AfterFindRequest; + export type FileTriggerRequest = import('./CloudServer').FileTriggerRequest; + export type ConnectTriggerRequest = import('./CloudServer').ConnectTriggerRequest; + export type LiveQueryEventTrigger = import('./CloudServer').LiveQueryEventTrigger; + export type JobRequest = import('./CloudServer').JobRequest; + export type ValidatorField = import('./CloudServer').ValidatorField; + export type ValidatorObject = import('./CloudServer').ValidatorObject; + export type HTTPOptions = import('./CloudServer').HTTPOptions; + export type HTTPResponse = import('./CloudServer').HTTPResponse; + + // Functions - reuse signatures from CloudServer + export const define: typeof import('./CloudServer').define; + export const job: typeof import('./CloudServer').job; + export const beforeSave: typeof import('./CloudServer').beforeSave; + export const afterSave: typeof import('./CloudServer').afterSave; + export const beforeDelete: typeof import('./CloudServer').beforeDelete; + export const afterDelete: typeof import('./CloudServer').afterDelete; + export const beforeFind: typeof import('./CloudServer').beforeFind; + export const afterFind: typeof import('./CloudServer').afterFind; + export const beforeLogin: typeof import('./CloudServer').beforeLogin; + export const afterLogin: typeof import('./CloudServer').afterLogin; + export const afterLogout: typeof import('./CloudServer').afterLogout; + export const beforeSaveFile: typeof import('./CloudServer').beforeSaveFile; + export const afterSaveFile: typeof import('./CloudServer').afterSaveFile; + export const beforeDeleteFile: typeof import('./CloudServer').beforeDeleteFile; + export const afterDeleteFile: typeof import('./CloudServer').afterDeleteFile; + export const beforeConnect: typeof import('./CloudServer').beforeConnect; + export const beforeSubscribe: typeof import('./CloudServer').beforeSubscribe; + export const afterLiveQueryEvent: typeof import('./CloudServer').afterLiveQueryEvent; + export const httpRequest: typeof import('./CloudServer').httpRequest; + export const sendEmail: typeof import('./CloudServer').sendEmail; +} + export = parse; diff --git a/types/tests.ts b/types/tests.ts index 4421ec84d..20736222b 100644 --- a/types/tests.ts +++ b/types/tests.ts @@ -2256,3 +2256,24 @@ function LiveQueryEvents() { Parse.LiveQuery.on('error', (error: any) => {}); } } + +// Test server-side Cloud Code types (only available in parse/node) +function test_cloud_server_functions() { + // Using ParseNode (parse/node), NOT Parse (parse) + // Server-side functions should be available on ParseNode.Cloud + ParseNode.Cloud.define('testFunction', req => { + return 'result'; + }); + + ParseNode.Cloud.beforeSave('TestClass', req => { + // req.object should be typed + }); + + ParseNode.Cloud.job('testJob', req => { + req.message('Processing...'); + }); + + // These should NOT exist on regular Parse (browser) + // @ts-expect-error - define should not exist on browser Parse.Cloud + Parse.Cloud.define('test', () => {}); +} From 51fab0a388d6e5dbe3c78cec28814dbc68ef16ac Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Wed, 7 Jan 2026 23:46:23 +0100 Subject: [PATCH 02/10] fix: Add missing generic and export in node.d.ts - Add generic type parameter to LiveQueryEventTrigger - Export beforePasswordResetRequest function --- types/node.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/node.d.ts b/types/node.d.ts index 79bc5f13a..0367dd11f 100644 --- a/types/node.d.ts +++ b/types/node.d.ts @@ -13,7 +13,7 @@ declare module './Cloud' { export type AfterFindRequest = import('./CloudServer').AfterFindRequest; export type FileTriggerRequest = import('./CloudServer').FileTriggerRequest; export type ConnectTriggerRequest = import('./CloudServer').ConnectTriggerRequest; - export type LiveQueryEventTrigger = import('./CloudServer').LiveQueryEventTrigger; + export type LiveQueryEventTrigger = import('./CloudServer').LiveQueryEventTrigger; export type JobRequest = import('./CloudServer').JobRequest; export type ValidatorField = import('./CloudServer').ValidatorField; export type ValidatorObject = import('./CloudServer').ValidatorObject; @@ -32,6 +32,7 @@ declare module './Cloud' { export const beforeLogin: typeof import('./CloudServer').beforeLogin; export const afterLogin: typeof import('./CloudServer').afterLogin; export const afterLogout: typeof import('./CloudServer').afterLogout; + export const beforePasswordResetRequest: typeof import('./CloudServer').beforePasswordResetRequest; export const beforeSaveFile: typeof import('./CloudServer').beforeSaveFile; export const afterSaveFile: typeof import('./CloudServer').afterSaveFile; export const beforeDeleteFile: typeof import('./CloudServer').beforeDeleteFile; From 08766aba9757f3ce6a2eb33ae93ac5e6e7d177ca Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Wed, 7 Jan 2026 23:52:11 +0100 Subject: [PATCH 03/10] fix: Add missing exports and context property to find requests --- types/CloudServer.d.ts | 8 ++++++++ types/node.d.ts | 2 ++ 2 files changed, 10 insertions(+) diff --git a/types/CloudServer.d.ts b/types/CloudServer.d.ts index d89dc3270..7375c386e 100644 --- a/types/CloudServer.d.ts +++ b/types/CloudServer.d.ts @@ -200,6 +200,10 @@ export interface BeforeFindRequest { * The Parse Server config. */ config: any; + /** + * A dictionary that is accessible in triggers. + */ + context: Record; /** * If set, the read preference for the query. */ @@ -254,6 +258,10 @@ export interface AfterFindRequest { * The Parse Server config. */ config: any; + /** + * A dictionary that is accessible in triggers. + */ + context: Record; } /** diff --git a/types/node.d.ts b/types/node.d.ts index 0367dd11f..5f2c47369 100644 --- a/types/node.d.ts +++ b/types/node.d.ts @@ -19,6 +19,8 @@ declare module './Cloud' { export type ValidatorObject = import('./CloudServer').ValidatorObject; export type HTTPOptions = import('./CloudServer').HTTPOptions; export type HTTPResponse = import('./CloudServer').HTTPResponse; + export type FunctionResponse = import('./CloudServer').FunctionResponse; + export const ReadPreferenceOption: typeof import('./CloudServer').ReadPreferenceOption; // Functions - reuse signatures from CloudServer export const define: typeof import('./CloudServer').define; From b09807b654ab726ae06ab211eb933e1a3ae6d344 Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Thu, 8 Jan 2026 15:15:00 +0100 Subject: [PATCH 04/10] refactor: Move Cloud types to source and add comprehensive tests --- src/CloudCode.ts | 309 ++++++++++++++ types/CloudCode.d.ts | 206 +++++++++ types/CloudServer.d.ts | 927 ----------------------------------------- types/node.d.ts | 82 ++-- types/tests.ts | 221 +++++++++- 5 files changed, 769 insertions(+), 976 deletions(-) delete mode 100644 types/CloudServer.d.ts diff --git a/src/CloudCode.ts b/src/CloudCode.ts index d8b272d3e..9b88be2e8 100644 --- a/src/CloudCode.ts +++ b/src/CloudCode.ts @@ -1,3 +1,312 @@ +import type ParseObject from './ParseObject'; +import type ParseUser from './ParseUser'; +import type ParseFile from './ParseFile'; +import type ParseQuery from './ParseQuery'; + +// ============================================================================ +// Request Interfaces +// ============================================================================ + +export interface FunctionRequest> { + installationId?: string; + master: boolean; + user?: ParseUser; + params: T; + ip: string; + headers: Record; + log: any; + functionName: string; + context: Record; + config: any; +} + +export interface FunctionResponse { + success: (result?: any) => void; + error: (message?: string) => void; + status: (code: number) => FunctionResponse; + header: (name: string, value: string) => FunctionResponse; +} + +export interface TriggerRequest { + installationId?: string; + master: boolean; + isChallenge: boolean; + user?: ParseUser; + object: T; + original?: T; + ip: string; + headers: Record; + triggerName: string; + log: any; + context: Record; + config: any; +} + +export interface BeforeSaveRequest extends TriggerRequest {} +export interface AfterSaveRequest extends TriggerRequest {} +export interface BeforeDeleteRequest extends TriggerRequest {} +export interface AfterDeleteRequest extends TriggerRequest {} + +export interface BeforeFindRequest { + installationId?: string; + master: boolean; + user?: ParseUser; + query: ParseQuery; + ip: string; + headers: Record; + triggerName: string; + log: any; + isGet: boolean; + config: any; + context: Record; + readPreference?: string; + count?: boolean; +} + +export interface AfterFindRequest { + installationId?: string; + master: boolean; + user?: ParseUser; + query: ParseQuery; + results: T[]; + ip: string; + headers: Record; + triggerName: string; + log: any; + config: any; + context: Record; +} + +export interface FileTriggerRequest { + installationId?: string; + master: boolean; + user?: ParseUser; + file: ParseFile; + fileSize: number; + contentLength: number; + ip: string; + headers: Record; + triggerName: string; + log: any; + config: any; +} + +export interface ConnectTriggerRequest { + installationId?: string; + useMasterKey: boolean; + user?: ParseUser; + clients: number; + subscriptions: number; + sessionToken?: string; +} + +export interface LiveQueryEventTrigger { + installationId?: string; + useMasterKey: boolean; + user?: ParseUser; + sessionToken?: string; + event: string; + object: T; + original?: T; + clients: number; + subscriptions: number; + sendEvent: boolean; +} + +export interface JobRequest { + params: Record; + message: (message: string) => void; + config: any; +} + +// ============================================================================ +// Validator Types +// ============================================================================ + +export interface ValidatorField { + type?: any; + constant?: boolean; + default?: any; + options?: any[] | (() => any[]) | any; + required?: boolean; + error?: string; +} + +export interface ValidatorObject { + requireUser?: boolean; + requireMaster?: boolean; + validateMasterKey?: boolean; + skipWithMasterKey?: boolean; + requireAnyUserRoles?: string[] | (() => string[]); + requireAllUserRoles?: string[] | (() => string[]); + requireUserKeys?: string[] | Record; + fields?: string[] | Record; + rateLimit?: { + requestPath?: string; + requestMethods?: string | string[]; + requestTimeWindow?: number; + requestCount?: number; + errorResponseMessage?: string; + includeInternalRequests?: boolean; + includeMasterKey?: boolean; + }; +} + +// ============================================================================ +// HTTP Types +// ============================================================================ + +export interface HTTPOptions { + body?: string | object; + error?: (response: HTTPResponse) => void; + followRedirects?: boolean; + headers?: Record; + method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS'; + params?: string | Record; + success?: (response: HTTPResponse) => void; + url: string; +} + +export interface HTTPResponse { + buffer?: Buffer; + cookies?: Record; + data?: any; + headers?: Record; + status: number; + text?: string; +} + +// ============================================================================ +// Enum +// ============================================================================ + +export enum ReadPreferenceOption { + Primary = 'PRIMARY', + PrimaryPreferred = 'PRIMARY_PREFERRED', + Secondary = 'SECONDARY', + SecondaryPreferred = 'SECONDARY_PREFERRED', + Nearest = 'NEAREST', +} + +// ============================================================================ +// Function Declarations (server-side only, implemented by Parse Server) +// ============================================================================ + +export declare function define = Record>( + name: string, + handler: (request: FunctionRequest) => any, + validator?: ValidatorObject | ((request: FunctionRequest) => any) +): void; + +export declare function define = Record>( + name: string, + handler: (request: FunctionRequest, response: FunctionResponse) => any, + validator?: ValidatorObject | ((request: FunctionRequest) => any) +): void; + +export declare function job(name: string, handler: (request: JobRequest) => any): void; + +export declare function beforeSave( + className: string | { new (): T }, + handler: (request: BeforeSaveRequest) => T | void | Promise, + validator?: ValidatorObject | ((request: BeforeSaveRequest) => any) +): void; + +export declare function afterSave( + className: string | { new (): T }, + handler: (request: AfterSaveRequest) => void | Promise, + validator?: ValidatorObject | ((request: AfterSaveRequest) => any) +): void; + +export declare function beforeDelete( + className: string | { new (): T }, + handler: (request: BeforeDeleteRequest) => void | Promise, + validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any) +): void; + +export declare function afterDelete( + className: string | { new (): T }, + handler: (request: AfterDeleteRequest) => void | Promise, + validator?: ValidatorObject | ((request: AfterDeleteRequest) => any) +): void; + +export declare function beforeFind( + className: string | { new (): T }, + handler: (request: BeforeFindRequest) => ParseQuery | void | Promise | void>, + validator?: ValidatorObject | ((request: BeforeFindRequest) => any) +): void; + +export declare function afterFind( + className: string | { new (): T }, + handler: (request: AfterFindRequest) => T[] | void | Promise, + validator?: ValidatorObject | ((request: AfterFindRequest) => any) +): void; + +export declare function beforeLogin( + handler: (request: TriggerRequest) => void | Promise, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +export declare function afterLogin( + handler: (request: TriggerRequest) => void | Promise +): void; + +export declare function afterLogout( + handler: (request: TriggerRequest) => void | Promise +): void; + +export declare function beforePasswordResetRequest( + handler: (request: TriggerRequest) => void | Promise, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +export declare function beforeSaveFile( + handler: (request: FileTriggerRequest) => ParseFile | void | Promise +): void; + +export declare function afterSaveFile( + handler: (request: FileTriggerRequest) => void | Promise +): void; + +export declare function beforeDeleteFile( + handler: (request: FileTriggerRequest) => void | Promise +): void; + +export declare function afterDeleteFile( + handler: (request: FileTriggerRequest) => void | Promise +): void; + +export declare function beforeConnect( + handler: (request: ConnectTriggerRequest) => void | Promise, + validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any) +): void; + +export declare function beforeSubscribe( + className: string | { new (): T }, + handler: (request: TriggerRequest) => void | Promise, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +export declare function afterLiveQueryEvent( + className: string | { new (): T }, + handler: (request: LiveQueryEventTrigger) => void | Promise, + validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any) +): void; + +export declare function sendEmail(data: { + from?: string; + to: string; + subject?: string; + text?: string; + html?: string; +}): Promise; + +export declare function httpRequest(options: HTTPOptions): Promise; + +// ============================================================================ +// JSDoc Documentation (for documentation generation) +// ============================================================================ + /** * Defines a Cloud Function. * diff --git a/types/CloudCode.d.ts b/types/CloudCode.d.ts index 5307f7c29..7668a2926 100644 --- a/types/CloudCode.d.ts +++ b/types/CloudCode.d.ts @@ -1,3 +1,209 @@ +import type ParseObject from './ParseObject'; +import type ParseUser from './ParseUser'; +import type ParseFile from './ParseFile'; +import type ParseQuery from './ParseQuery'; +export interface FunctionRequest> { + installationId?: string; + master: boolean; + user?: ParseUser; + params: T; + ip: string; + headers: Record; + log: any; + functionName: string; + context: Record; + config: any; +} +export interface FunctionResponse { + success: (result?: any) => void; + error: (message?: string) => void; + status: (code: number) => FunctionResponse; + header: (name: string, value: string) => FunctionResponse; +} +export interface TriggerRequest { + installationId?: string; + master: boolean; + isChallenge: boolean; + user?: ParseUser; + object: T; + original?: T; + ip: string; + headers: Record; + triggerName: string; + log: any; + context: Record; + config: any; +} +export interface BeforeSaveRequest extends TriggerRequest { +} +export interface AfterSaveRequest extends TriggerRequest { +} +export interface BeforeDeleteRequest extends TriggerRequest { +} +export interface AfterDeleteRequest extends TriggerRequest { +} +export interface BeforeFindRequest { + installationId?: string; + master: boolean; + user?: ParseUser; + query: ParseQuery; + ip: string; + headers: Record; + triggerName: string; + log: any; + isGet: boolean; + config: any; + context: Record; + readPreference?: string; + count?: boolean; +} +export interface AfterFindRequest { + installationId?: string; + master: boolean; + user?: ParseUser; + query: ParseQuery; + results: T[]; + ip: string; + headers: Record; + triggerName: string; + log: any; + config: any; + context: Record; +} +export interface FileTriggerRequest { + installationId?: string; + master: boolean; + user?: ParseUser; + file: ParseFile; + fileSize: number; + contentLength: number; + ip: string; + headers: Record; + triggerName: string; + log: any; + config: any; +} +export interface ConnectTriggerRequest { + installationId?: string; + useMasterKey: boolean; + user?: ParseUser; + clients: number; + subscriptions: number; + sessionToken?: string; +} +export interface LiveQueryEventTrigger { + installationId?: string; + useMasterKey: boolean; + user?: ParseUser; + sessionToken?: string; + event: string; + object: T; + original?: T; + clients: number; + subscriptions: number; + sendEvent: boolean; +} +export interface JobRequest { + params: Record; + message: (message: string) => void; + config: any; +} +export interface ValidatorField { + type?: any; + constant?: boolean; + default?: any; + options?: any[] | (() => any[]) | any; + required?: boolean; + error?: string; +} +export interface ValidatorObject { + requireUser?: boolean; + requireMaster?: boolean; + validateMasterKey?: boolean; + skipWithMasterKey?: boolean; + requireAnyUserRoles?: string[] | (() => string[]); + requireAllUserRoles?: string[] | (() => string[]); + requireUserKeys?: string[] | Record; + fields?: string[] | Record; + rateLimit?: { + requestPath?: string; + requestMethods?: string | string[]; + requestTimeWindow?: number; + requestCount?: number; + errorResponseMessage?: string; + includeInternalRequests?: boolean; + includeMasterKey?: boolean; + }; +} +export interface HTTPOptions { + body?: string | object; + error?: (response: HTTPResponse) => void; + followRedirects?: boolean; + headers?: Record; + method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS'; + params?: string | Record; + success?: (response: HTTPResponse) => void; + url: string; +} +export interface HTTPResponse { + buffer?: Buffer; + cookies?: Record; + data?: any; + headers?: Record; + status: number; + text?: string; +} +export declare enum ReadPreferenceOption { + Primary = "PRIMARY", + PrimaryPreferred = "PRIMARY_PREFERRED", + Secondary = "SECONDARY", + SecondaryPreferred = "SECONDARY_PREFERRED", + Nearest = "NEAREST" +} +export declare function define = Record>(name: string, handler: (request: FunctionRequest) => any, validator?: ValidatorObject | ((request: FunctionRequest) => any)): void; +export declare function define = Record>(name: string, handler: (request: FunctionRequest, response: FunctionResponse) => any, validator?: ValidatorObject | ((request: FunctionRequest) => any)): void; +export declare function job(name: string, handler: (request: JobRequest) => any): void; +export declare function beforeSave(className: string | { + new (): T; +}, handler: (request: BeforeSaveRequest) => T | void | Promise, validator?: ValidatorObject | ((request: BeforeSaveRequest) => any)): void; +export declare function afterSave(className: string | { + new (): T; +}, handler: (request: AfterSaveRequest) => void | Promise, validator?: ValidatorObject | ((request: AfterSaveRequest) => any)): void; +export declare function beforeDelete(className: string | { + new (): T; +}, handler: (request: BeforeDeleteRequest) => void | Promise, validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any)): void; +export declare function afterDelete(className: string | { + new (): T; +}, handler: (request: AfterDeleteRequest) => void | Promise, validator?: ValidatorObject | ((request: AfterDeleteRequest) => any)): void; +export declare function beforeFind(className: string | { + new (): T; +}, handler: (request: BeforeFindRequest) => ParseQuery | void | Promise | void>, validator?: ValidatorObject | ((request: BeforeFindRequest) => any)): void; +export declare function afterFind(className: string | { + new (): T; +}, handler: (request: AfterFindRequest) => T[] | void | Promise, validator?: ValidatorObject | ((request: AfterFindRequest) => any)): void; +export declare function beforeLogin(handler: (request: TriggerRequest) => void | Promise, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +export declare function afterLogin(handler: (request: TriggerRequest) => void | Promise): void; +export declare function afterLogout(handler: (request: TriggerRequest) => void | Promise): void; +export declare function beforePasswordResetRequest(handler: (request: TriggerRequest) => void | Promise, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +export declare function beforeSaveFile(handler: (request: FileTriggerRequest) => ParseFile | void | Promise): void; +export declare function afterSaveFile(handler: (request: FileTriggerRequest) => void | Promise): void; +export declare function beforeDeleteFile(handler: (request: FileTriggerRequest) => void | Promise): void; +export declare function afterDeleteFile(handler: (request: FileTriggerRequest) => void | Promise): void; +export declare function beforeConnect(handler: (request: ConnectTriggerRequest) => void | Promise, validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any)): void; +export declare function beforeSubscribe(className: string | { + new (): T; +}, handler: (request: TriggerRequest) => void | Promise, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +export declare function afterLiveQueryEvent(className: string | { + new (): T; +}, handler: (request: LiveQueryEventTrigger) => void | Promise, validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any)): void; +export declare function sendEmail(data: { + from?: string; + to: string; + subject?: string; + text?: string; + html?: string; +}): Promise; +export declare function httpRequest(options: HTTPOptions): Promise; /** * Defines a Cloud Function. * diff --git a/types/CloudServer.d.ts b/types/CloudServer.d.ts deleted file mode 100644 index 7375c386e..000000000 --- a/types/CloudServer.d.ts +++ /dev/null @@ -1,927 +0,0 @@ -/** - * Server-side Cloud Code types for Parse Server. - * These types are only available when using `parse/node` import. - * - * @module CloudServer - */ - -import ParseObject from './ParseObject'; -import ParseUser from './ParseUser'; -import ParseFile from './ParseFile'; -import ParseQuery from './ParseQuery'; - -// ============================================================================ -// Request Interfaces -// ============================================================================ - -/** - * Request object for Cloud Functions defined with `Parse.Cloud.define`. - */ -export interface FunctionRequest> { - /** - * If set, the installationId triggering the request. - */ - installationId?: string; - /** - * If true, means the master key was used. - */ - master: boolean; - /** - * If set, the user that made the request. - */ - user?: ParseUser; - /** - * The params passed to the cloud function. - */ - params: T; - /** - * The IP address of the client making the request. - */ - ip: string; - /** - * The original HTTP headers for the request. - */ - headers: Record; - /** - * The current logger inside Parse Server. - */ - log: any; - /** - * The name of the Cloud function. - */ - functionName: string; - /** - * A dictionary that is accessible in triggers. - */ - context: Record; - /** - * The Parse Server config. - */ - config: any; -} - -/** - * Response object for Express-style Cloud Functions. - */ -export interface FunctionResponse { - /** - * Send a success response with optional result data. - */ - success: (result?: any) => void; - /** - * Send an error response with optional message. - */ - error: (message?: string) => void; - /** - * Set the HTTP status code for the response. - */ - status: (code: number) => FunctionResponse; - /** - * Set a header on the response. - */ - header: (name: string, value: string) => FunctionResponse; -} - -/** - * Base request object for trigger hooks (beforeSave, afterSave, etc.). - */ -export interface TriggerRequest { - /** - * If set, the installationId triggering the request. - */ - installationId?: string; - /** - * If true, means the master key was used. - */ - master: boolean; - /** - * If true, means the trigger is being invoked as a challenge. - */ - isChallenge: boolean; - /** - * If set, the user that made the request. - */ - user?: ParseUser; - /** - * The object triggering the hook. - */ - object: T; - /** - * If set, the object as currently stored (for updates). - */ - original?: T; - /** - * The IP address of the client making the request. - */ - ip: string; - /** - * The original HTTP headers for the request. - */ - headers: Record; - /** - * The name of the trigger (e.g., "beforeSave", "afterSave"). - */ - triggerName: string; - /** - * The current logger inside Parse Server. - */ - log: any; - /** - * A dictionary that is accessible in triggers. - */ - context: Record; - /** - * The Parse Server config. - */ - config: any; -} - -/** - * Request object for beforeSave triggers. - */ -export interface BeforeSaveRequest extends TriggerRequest {} - -/** - * Request object for afterSave triggers. - */ -export interface AfterSaveRequest extends TriggerRequest {} - -/** - * Request object for beforeDelete triggers. - */ -export interface BeforeDeleteRequest extends TriggerRequest {} - -/** - * Request object for afterDelete triggers. - */ -export interface AfterDeleteRequest extends TriggerRequest {} - -/** - * Request object for beforeFind triggers. - */ -export interface BeforeFindRequest { - /** - * If set, the installationId triggering the request. - */ - installationId?: string; - /** - * If true, means the master key was used. - */ - master: boolean; - /** - * If set, the user that made the request. - */ - user?: ParseUser; - /** - * The query being executed. - */ - query: ParseQuery; - /** - * The IP address of the client making the request. - */ - ip: string; - /** - * The original HTTP headers for the request. - */ - headers: Record; - /** - * The name of the trigger. - */ - triggerName: string; - /** - * The current logger inside Parse Server. - */ - log: any; - /** - * If true, the query is a get operation. - */ - isGet: boolean; - /** - * The Parse Server config. - */ - config: any; - /** - * A dictionary that is accessible in triggers. - */ - context: Record; - /** - * If set, the read preference for the query. - */ - readPreference?: string; - /** - * If true, the query is a count operation. - */ - count?: boolean; -} - -/** - * Request object for afterFind triggers. - */ -export interface AfterFindRequest { - /** - * If set, the installationId triggering the request. - */ - installationId?: string; - /** - * If true, means the master key was used. - */ - master: boolean; - /** - * If set, the user that made the request. - */ - user?: ParseUser; - /** - * The query that was executed. - */ - query: ParseQuery; - /** - * The results returned by the query. - */ - results: T[]; - /** - * The IP address of the client making the request. - */ - ip: string; - /** - * The original HTTP headers for the request. - */ - headers: Record; - /** - * The name of the trigger. - */ - triggerName: string; - /** - * The current logger inside Parse Server. - */ - log: any; - /** - * The Parse Server config. - */ - config: any; - /** - * A dictionary that is accessible in triggers. - */ - context: Record; -} - -/** - * Request object for file triggers (beforeSaveFile, afterSaveFile, etc.). - */ -export interface FileTriggerRequest { - /** - * If set, the installationId triggering the request. - */ - installationId?: string; - /** - * If true, means the master key was used. - */ - master: boolean; - /** - * If set, the user that made the request. - */ - user?: ParseUser; - /** - * The file being saved or deleted. - */ - file: ParseFile; - /** - * The size of the file in bytes. - */ - fileSize: number; - /** - * The content length of the request. - */ - contentLength: number; - /** - * The IP address of the client making the request. - */ - ip: string; - /** - * The original HTTP headers for the request. - */ - headers: Record; - /** - * The name of the trigger. - */ - triggerName: string; - /** - * The current logger inside Parse Server. - */ - log: any; - /** - * The Parse Server config. - */ - config: any; -} - -/** - * Request object for beforeConnect LiveQuery trigger. - */ -export interface ConnectTriggerRequest { - /** - * If set, the installationId triggering the request. - */ - installationId?: string; - /** - * If true, means the master key was used. - */ - useMasterKey: boolean; - /** - * If set, the user that made the request. - */ - user?: ParseUser; - /** - * The number of connected clients. - */ - clients: number; - /** - * The number of active subscriptions. - */ - subscriptions: number; - /** - * The session token if available. - */ - sessionToken?: string; -} - -/** - * Request object for afterLiveQueryEvent trigger. - */ -export interface LiveQueryEventTrigger { - /** - * If set, the installationId triggering the request. - */ - installationId?: string; - /** - * If true, means the master key was used. - */ - useMasterKey: boolean; - /** - * If set, the user that made the request. - */ - user?: ParseUser; - /** - * The session token if available. - */ - sessionToken?: string; - /** - * The event type (create, update, delete, enter, leave). - */ - event: string; - /** - * The object that triggered the event. - */ - object: T; - /** - * The original object before modification (for updates). - */ - original?: T; - /** - * The number of connected clients. - */ - clients: number; - /** - * The number of active subscriptions. - */ - subscriptions: number; - /** - * If false, the event will not be sent to clients. - */ - sendEvent: boolean; -} - -/** - * Request object for background jobs defined with `Parse.Cloud.job`. - */ -export interface JobRequest { - /** - * The params passed to the background job. - */ - params: Record; - /** - * A function to update the status message of the job. - */ - message: (message: string) => void; - /** - * The Parse Server config. - */ - config: any; -} - -// ============================================================================ -// Validator Types -// ============================================================================ - -/** - * Configuration for a single field in the validator. - */ -export interface ValidatorField { - /** - * The expected type of the field. - */ - type?: any; - /** - * If true, the field cannot be modified after creation. - */ - constant?: boolean; - /** - * Default value for the field. - */ - default?: any; - /** - * Valid options for the field value. - */ - options?: any[] | (() => any[]) | any; - /** - * If true, the field is required. - */ - required?: boolean; - /** - * Custom error message for validation failure. - */ - error?: string; -} - -/** - * Validator configuration for Cloud Functions and triggers. - */ -export interface ValidatorObject { - /** - * If true, requires a user to be logged in. - */ - requireUser?: boolean; - /** - * If true, requires the master key. - */ - requireMaster?: boolean; - /** - * If true, validates the master key. - */ - validateMasterKey?: boolean; - /** - * If true, skips validation when master key is used. - */ - skipWithMasterKey?: boolean; - /** - * Requires the user to have any of these roles. - */ - requireAnyUserRoles?: string[] | (() => string[]); - /** - * Requires the user to have all of these roles. - */ - requireAllUserRoles?: string[] | (() => string[]); - /** - * Required keys on the user object. - */ - requireUserKeys?: string[] | Record; - /** - * Field validation configuration. - */ - fields?: string[] | Record; - /** - * Rate limiting configuration. - */ - rateLimit?: { - /** - * The path to apply rate limiting to. - */ - requestPath?: string; - /** - * HTTP methods to rate limit. - */ - requestMethods?: string | string[]; - /** - * Time window in milliseconds. - */ - requestTimeWindow?: number; - /** - * Maximum number of requests in the time window. - */ - requestCount?: number; - /** - * Custom error message when rate limit is exceeded. - */ - errorResponseMessage?: string; - /** - * If true, includes internal requests in rate limiting. - */ - includeInternalRequests?: boolean; - /** - * If true, includes master key requests in rate limiting. - */ - includeMasterKey?: boolean; - }; -} - -// ============================================================================ -// HTTP Request Types -// ============================================================================ - -/** - * Options for `Parse.Cloud.httpRequest`. - */ -export interface HTTPOptions { - /** - * The body of the request. - */ - body?: string | object; - /** - * Callback for error responses. - */ - error?: (response: HTTPResponse) => void; - /** - * If true, follows HTTP redirects. - */ - followRedirects?: boolean; - /** - * HTTP headers for the request. - */ - headers?: Record; - /** - * HTTP method for the request. - */ - method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS'; - /** - * Query parameters for the request. - */ - params?: string | Record; - /** - * Callback for success responses. - */ - success?: (response: HTTPResponse) => void; - /** - * The URL to send the request to. - */ - url: string; -} - -/** - * Response from `Parse.Cloud.httpRequest`. - */ -export interface HTTPResponse { - /** - * The raw response buffer. - */ - buffer?: Buffer; - /** - * Cookies from the response. - */ - cookies?: Record; - /** - * The parsed response data. - */ - data?: any; - /** - * HTTP headers from the response. - */ - headers?: Record; - /** - * HTTP status code. - */ - status: number; - /** - * The raw response text. - */ - text?: string; -} - -// ============================================================================ -// Read Preference Enum -// ============================================================================ - -/** - * Read preference options for MongoDB queries. - */ -export enum ReadPreferenceOption { - Primary = 'PRIMARY', - PrimaryPreferred = 'PRIMARY_PREFERRED', - Secondary = 'SECONDARY', - SecondaryPreferred = 'SECONDARY_PREFERRED', - Nearest = 'NEAREST', -} - -// ============================================================================ -// Cloud Function Declarations -// ============================================================================ - -/** - * Defines a Cloud Function. - * - * @example - * ```typescript - * Parse.Cloud.define('hello', (request) => { - * return `Hello, ${request.params.name}!`; - * }); - * ``` - * - * @param name - The name of the Cloud Function. - * @param handler - The function to execute. - * @param validator - Optional validator configuration. - */ -export function define = Record>( - name: string, - handler: (request: FunctionRequest) => any, - validator?: ValidatorObject | ((request: FunctionRequest) => any) -): void; - -/** - * Defines a Cloud Function with Express-style response object. - * - * @param name - The name of the Cloud Function. - * @param handler - The function to execute with request and response objects. - * @param validator - Optional validator configuration. - */ -export function define = Record>( - name: string, - handler: (request: FunctionRequest, response: FunctionResponse) => any, - validator?: ValidatorObject | ((request: FunctionRequest) => any) -): void; - -/** - * Defines a background job. - * - * @example - * ```typescript - * Parse.Cloud.job('myJob', (request) => { - * request.message('Processing...'); - * // Do background work - * }); - * ``` - * - * @param name - The name of the background job. - * @param handler - The function to execute. - */ -export function job(name: string, handler: (request: JobRequest) => any): void; - -// ============================================================================ -// Object Lifecycle Hooks -// ============================================================================ - -/** - * Registers a beforeSave trigger for a class. - * - * @example - * ```typescript - * Parse.Cloud.beforeSave('MyClass', (request) => { - * request.object.set('updatedBy', request.user); - * }); - * ``` - * - * @param className - The class name or constructor. - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function beforeSave( - className: string | { new (): T }, - handler: (request: BeforeSaveRequest) => T | void | Promise, - validator?: ValidatorObject | ((request: BeforeSaveRequest) => any) -): void; - -/** - * Registers an afterSave trigger for a class. - * - * @param className - The class name or constructor. - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function afterSave( - className: string | { new (): T }, - handler: (request: AfterSaveRequest) => void | Promise, - validator?: ValidatorObject | ((request: AfterSaveRequest) => any) -): void; - -/** - * Registers a beforeDelete trigger for a class. - * - * @param className - The class name or constructor. - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function beforeDelete( - className: string | { new (): T }, - handler: (request: BeforeDeleteRequest) => void | Promise, - validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any) -): void; - -/** - * Registers an afterDelete trigger for a class. - * - * @param className - The class name or constructor. - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function afterDelete( - className: string | { new (): T }, - handler: (request: AfterDeleteRequest) => void | Promise, - validator?: ValidatorObject | ((request: AfterDeleteRequest) => any) -): void; - -// ============================================================================ -// Query Hooks -// ============================================================================ - -/** - * Registers a beforeFind trigger for a class. - * - * @example - * ```typescript - * Parse.Cloud.beforeFind('MyClass', (request) => { - * // Modify the query - * request.query.equalTo('active', true); - * return request.query; - * }); - * ``` - * - * @param className - The class name or constructor. - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function beforeFind( - className: string | { new (): T }, - handler: (request: BeforeFindRequest) => ParseQuery | void | Promise | void>, - validator?: ValidatorObject | ((request: BeforeFindRequest) => any) -): void; - -/** - * Registers an afterFind trigger for a class. - * - * @param className - The class name or constructor. - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function afterFind( - className: string | { new (): T }, - handler: (request: AfterFindRequest) => T[] | void | Promise, - validator?: ValidatorObject | ((request: AfterFindRequest) => any) -): void; - -// ============================================================================ -// Auth Hooks -// ============================================================================ - -/** - * Registers a beforeLogin trigger. - * - * @example - * ```typescript - * Parse.Cloud.beforeLogin((request) => { - * if (request.object.get('banned')) { - * throw new Error('User is banned'); - * } - * }); - * ``` - * - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function beforeLogin( - handler: (request: TriggerRequest) => void | Promise, - validator?: ValidatorObject | ((request: TriggerRequest) => any) -): void; - -/** - * Registers an afterLogin trigger. - * - * @param handler - The trigger function. - */ -export function afterLogin(handler: (request: TriggerRequest) => void | Promise): void; - -/** - * Registers an afterLogout trigger. - * - * @param handler - The trigger function. - */ -export function afterLogout(handler: (request: TriggerRequest) => void | Promise): void; - -/** - * Registers a beforePasswordResetRequest trigger. - * - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function beforePasswordResetRequest( - handler: (request: TriggerRequest) => void | Promise, - validator?: ValidatorObject | ((request: TriggerRequest) => any) -): void; - -// ============================================================================ -// File Hooks -// ============================================================================ - -/** - * Registers a beforeSaveFile trigger. - * - * @example - * ```typescript - * Parse.Cloud.beforeSaveFile((request) => { - * // Validate or modify file before saving - * if (request.fileSize > 10 * 1024 * 1024) { - * throw new Error('File too large'); - * } - * }); - * ``` - * - * @param handler - The trigger function. - */ -export function beforeSaveFile( - handler: (request: FileTriggerRequest) => ParseFile | void | Promise -): void; - -/** - * Registers an afterSaveFile trigger. - * - * @param handler - The trigger function. - */ -export function afterSaveFile(handler: (request: FileTriggerRequest) => void | Promise): void; - -/** - * Registers a beforeDeleteFile trigger. - * - * @param handler - The trigger function. - */ -export function beforeDeleteFile(handler: (request: FileTriggerRequest) => void | Promise): void; - -/** - * Registers an afterDeleteFile trigger. - * - * @param handler - The trigger function. - */ -export function afterDeleteFile(handler: (request: FileTriggerRequest) => void | Promise): void; - -// ============================================================================ -// LiveQuery Hooks -// ============================================================================ - -/** - * Registers a beforeConnect trigger for LiveQuery. - * - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function beforeConnect( - handler: (request: ConnectTriggerRequest) => void | Promise, - validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any) -): void; - -/** - * Registers a beforeSubscribe trigger for LiveQuery. - * - * @param className - The class name or constructor. - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function beforeSubscribe( - className: string | { new (): T }, - handler: (request: TriggerRequest) => void | Promise, - validator?: ValidatorObject | ((request: TriggerRequest) => any) -): void; - -/** - * Registers an afterLiveQueryEvent trigger. - * - * @param className - The class name or constructor. - * @param handler - The trigger function. - * @param validator - Optional validator configuration. - */ -export function afterLiveQueryEvent( - className: string | { new (): T }, - handler: (request: LiveQueryEventTrigger) => void | Promise, - validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any) -): void; - -// ============================================================================ -// Utility Functions -// ============================================================================ - -/** - * Sends an email using the configured email adapter. - * - * @param data - Email configuration. - */ -export function sendEmail(data: { - from?: string; - to: string; - subject?: string; - text?: string; - html?: string; -}): Promise; - -/** - * Makes an HTTP request. - * - * @example - * ```typescript - * const response = await Parse.Cloud.httpRequest({ - * url: 'https://api.example.com/data', - * method: 'GET', - * headers: { - * 'Authorization': 'Bearer token' - * } - * }); - * console.log(response.data); - * ``` - * - * @param options - HTTP request options. - * @returns The HTTP response. - */ -export function httpRequest(options: HTTPOptions): Promise; diff --git a/types/node.d.ts b/types/node.d.ts index 5f2c47369..adb8882ff 100644 --- a/types/node.d.ts +++ b/types/node.d.ts @@ -2,48 +2,48 @@ import * as parse from './index'; // Augment Cloud module to include server-side types for parse/node declare module './Cloud' { - // Request types - alias to CloudServer definitions - export type FunctionRequest> = import('./CloudServer').FunctionRequest; - export type TriggerRequest = import('./CloudServer').TriggerRequest; - export type BeforeSaveRequest = import('./CloudServer').BeforeSaveRequest; - export type AfterSaveRequest = import('./CloudServer').AfterSaveRequest; - export type BeforeDeleteRequest = import('./CloudServer').BeforeDeleteRequest; - export type AfterDeleteRequest = import('./CloudServer').AfterDeleteRequest; - export type BeforeFindRequest = import('./CloudServer').BeforeFindRequest; - export type AfterFindRequest = import('./CloudServer').AfterFindRequest; - export type FileTriggerRequest = import('./CloudServer').FileTriggerRequest; - export type ConnectTriggerRequest = import('./CloudServer').ConnectTriggerRequest; - export type LiveQueryEventTrigger = import('./CloudServer').LiveQueryEventTrigger; - export type JobRequest = import('./CloudServer').JobRequest; - export type ValidatorField = import('./CloudServer').ValidatorField; - export type ValidatorObject = import('./CloudServer').ValidatorObject; - export type HTTPOptions = import('./CloudServer').HTTPOptions; - export type HTTPResponse = import('./CloudServer').HTTPResponse; - export type FunctionResponse = import('./CloudServer').FunctionResponse; - export const ReadPreferenceOption: typeof import('./CloudServer').ReadPreferenceOption; + // Request types - alias to CloudCode definitions + export type FunctionRequest> = import('./CloudCode').FunctionRequest; + export type FunctionResponse = import('./CloudCode').FunctionResponse; + export type TriggerRequest = import('./CloudCode').TriggerRequest; + export type BeforeSaveRequest = import('./CloudCode').BeforeSaveRequest; + export type AfterSaveRequest = import('./CloudCode').AfterSaveRequest; + export type BeforeDeleteRequest = import('./CloudCode').BeforeDeleteRequest; + export type AfterDeleteRequest = import('./CloudCode').AfterDeleteRequest; + export type BeforeFindRequest = import('./CloudCode').BeforeFindRequest; + export type AfterFindRequest = import('./CloudCode').AfterFindRequest; + export type FileTriggerRequest = import('./CloudCode').FileTriggerRequest; + export type ConnectTriggerRequest = import('./CloudCode').ConnectTriggerRequest; + export type LiveQueryEventTrigger = import('./CloudCode').LiveQueryEventTrigger; + export type JobRequest = import('./CloudCode').JobRequest; + export type ValidatorField = import('./CloudCode').ValidatorField; + export type ValidatorObject = import('./CloudCode').ValidatorObject; + export type HTTPOptions = import('./CloudCode').HTTPOptions; + export type HTTPResponse = import('./CloudCode').HTTPResponse; + export const ReadPreferenceOption: typeof import('./CloudCode').ReadPreferenceOption; - // Functions - reuse signatures from CloudServer - export const define: typeof import('./CloudServer').define; - export const job: typeof import('./CloudServer').job; - export const beforeSave: typeof import('./CloudServer').beforeSave; - export const afterSave: typeof import('./CloudServer').afterSave; - export const beforeDelete: typeof import('./CloudServer').beforeDelete; - export const afterDelete: typeof import('./CloudServer').afterDelete; - export const beforeFind: typeof import('./CloudServer').beforeFind; - export const afterFind: typeof import('./CloudServer').afterFind; - export const beforeLogin: typeof import('./CloudServer').beforeLogin; - export const afterLogin: typeof import('./CloudServer').afterLogin; - export const afterLogout: typeof import('./CloudServer').afterLogout; - export const beforePasswordResetRequest: typeof import('./CloudServer').beforePasswordResetRequest; - export const beforeSaveFile: typeof import('./CloudServer').beforeSaveFile; - export const afterSaveFile: typeof import('./CloudServer').afterSaveFile; - export const beforeDeleteFile: typeof import('./CloudServer').beforeDeleteFile; - export const afterDeleteFile: typeof import('./CloudServer').afterDeleteFile; - export const beforeConnect: typeof import('./CloudServer').beforeConnect; - export const beforeSubscribe: typeof import('./CloudServer').beforeSubscribe; - export const afterLiveQueryEvent: typeof import('./CloudServer').afterLiveQueryEvent; - export const httpRequest: typeof import('./CloudServer').httpRequest; - export const sendEmail: typeof import('./CloudServer').sendEmail; + // Functions - reuse signatures from CloudCode + export const define: typeof import('./CloudCode').define; + export const job: typeof import('./CloudCode').job; + export const beforeSave: typeof import('./CloudCode').beforeSave; + export const afterSave: typeof import('./CloudCode').afterSave; + export const beforeDelete: typeof import('./CloudCode').beforeDelete; + export const afterDelete: typeof import('./CloudCode').afterDelete; + export const beforeFind: typeof import('./CloudCode').beforeFind; + export const afterFind: typeof import('./CloudCode').afterFind; + export const beforeLogin: typeof import('./CloudCode').beforeLogin; + export const afterLogin: typeof import('./CloudCode').afterLogin; + export const afterLogout: typeof import('./CloudCode').afterLogout; + export const beforePasswordResetRequest: typeof import('./CloudCode').beforePasswordResetRequest; + export const beforeSaveFile: typeof import('./CloudCode').beforeSaveFile; + export const afterSaveFile: typeof import('./CloudCode').afterSaveFile; + export const beforeDeleteFile: typeof import('./CloudCode').beforeDeleteFile; + export const afterDeleteFile: typeof import('./CloudCode').afterDeleteFile; + export const beforeConnect: typeof import('./CloudCode').beforeConnect; + export const beforeSubscribe: typeof import('./CloudCode').beforeSubscribe; + export const afterLiveQueryEvent: typeof import('./CloudCode').afterLiveQueryEvent; + export const httpRequest: typeof import('./CloudCode').httpRequest; + export const sendEmail: typeof import('./CloudCode').sendEmail; } export = parse; diff --git a/types/tests.ts b/types/tests.ts index 20736222b..81a84c6fb 100644 --- a/types/tests.ts +++ b/types/tests.ts @@ -2259,21 +2259,226 @@ function LiveQueryEvents() { // Test server-side Cloud Code types (only available in parse/node) function test_cloud_server_functions() { - // Using ParseNode (parse/node), NOT Parse (parse) - // Server-side functions should be available on ParseNode.Cloud - ParseNode.Cloud.define('testFunction', req => { + // ============================================================================ + // Cloud.define Tests + // ============================================================================ + + // Basic define with request properties + ParseNode.Cloud.define('basicFunc', (request) => { + request.params; + request.user; + request.master; + request.ip; + request.headers; + request.functionName; + request.context; return 'result'; }); - ParseNode.Cloud.beforeSave('TestClass', req => { - // req.object should be typed + // Define with validator options + ParseNode.Cloud.define('validatedFunc', (request) => {}, { + requireUser: true, + requireMaster: false, + validateMasterKey: false, + skipWithMasterKey: true, + requireAnyUserRoles: ['Admin', 'Moderator'], + requireAllUserRoles: ['User'], + fields: { + name: { type: String, required: true }, + age: { type: Number, default: 0 } + } + }); + + // Define with FunctionResponse (Express-style) + ParseNode.Cloud.define('expressStyleFunc', (request, response) => { + response.success({ data: 'value' }); + response.error('Something went wrong'); + }); + + // ============================================================================ + // Object Lifecycle Triggers + // ============================================================================ + + // beforeSave with request properties + ParseNode.Cloud.beforeSave('TestClass', (request) => { + request.object; + request.original; + request.user; + request.master; + request.context; + request.isChallenge; + request.ip; + request.headers; + request.triggerName; + }); + + // afterSave + ParseNode.Cloud.afterSave('TestClass', async (request) => { + const obj = request.object; + const original = request.original; + const context = request.context; + }); + + // beforeDelete + ParseNode.Cloud.beforeDelete('TestClass', (request) => { + return Promise.resolve(); + }); + + // afterDelete + ParseNode.Cloud.afterDelete('TestClass', (request) => { + return Promise.resolve(); + }); + + // ============================================================================ + // Query Triggers + // ============================================================================ + + // beforeFind with ReadPreferenceOption + ParseNode.Cloud.beforeFind('TestClass', (request) => { + request.query; + request.isGet; + request.count; + request.readPreference; + request.context; + + // Test ReadPreferenceOption enum + const primary = ParseNode.Cloud.ReadPreferenceOption.Primary; + const primaryPreferred = ParseNode.Cloud.ReadPreferenceOption.PrimaryPreferred; + const secondary = ParseNode.Cloud.ReadPreferenceOption.Secondary; + const secondaryPreferred = ParseNode.Cloud.ReadPreferenceOption.SecondaryPreferred; + const nearest = ParseNode.Cloud.ReadPreferenceOption.Nearest; + }); + + // afterFind + ParseNode.Cloud.afterFind('TestClass', (request) => { + request.query; + request.results; + return request.results; + }); + + // ============================================================================ + // Auth Triggers + // ============================================================================ + + // beforeLogin + ParseNode.Cloud.beforeLogin((request) => { + request.object; + request.user; + }); + + // afterLogin + ParseNode.Cloud.afterLogin((request) => { + return Promise.resolve(); + }); + + // afterLogout + ParseNode.Cloud.afterLogout((request) => { + return Promise.resolve(); + }); + + // beforePasswordResetRequest + ParseNode.Cloud.beforePasswordResetRequest((request) => { + request.object; + }); + + // ============================================================================ + // File Triggers + // ============================================================================ + + // beforeSaveFile + ParseNode.Cloud.beforeSaveFile((request) => { + request.file; + request.fileSize; + request.contentLength; + request.user; + request.master; + }); + + // afterSaveFile + ParseNode.Cloud.afterSaveFile((request) => {}); + + // beforeDeleteFile + ParseNode.Cloud.beforeDeleteFile((request) => {}); + + // afterDeleteFile + ParseNode.Cloud.afterDeleteFile((request) => {}); + + // ============================================================================ + // LiveQuery Triggers + // ============================================================================ + + // beforeConnect + ParseNode.Cloud.beforeConnect((request) => { + request.useMasterKey; + request.user; + request.clients; + request.subscriptions; + request.sessionToken; }); - ParseNode.Cloud.job('testJob', req => { - req.message('Processing...'); + // beforeSubscribe + ParseNode.Cloud.beforeSubscribe('TestClass', (request) => { + request.object; + request.user; }); - // These should NOT exist on regular Parse (browser) + // afterLiveQueryEvent + ParseNode.Cloud.afterLiveQueryEvent('TestClass', (request) => { + request.event; + request.object; + request.original; + request.sendEvent; + request.clients; + request.subscriptions; + }); + + // ============================================================================ + // Job Tests + // ============================================================================ + + ParseNode.Cloud.job('comprehensiveJob', (request) => { + request.params; + request.message('Processing step 1...'); + request.config; + }); + + // ============================================================================ + // Utility Functions + // ============================================================================ + + // httpRequest + ParseNode.Cloud.httpRequest({ + url: 'https://example.com', + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: { key: 'value' }, + followRedirects: true + }).then((response) => { + response.status; + response.data; + response.text; + response.headers; + }); + + // sendEmail + ParseNode.Cloud.sendEmail({ + to: 'test@example.com', + from: 'noreply@example.com', + subject: 'Test', + text: 'Hello', + html: '

Hello

' + }); + + // ============================================================================ + // Browser Exclusion Tests - these should NOT compile on browser Parse + // ============================================================================ + // @ts-expect-error - define should not exist on browser Parse.Cloud Parse.Cloud.define('test', () => {}); + // @ts-expect-error - beforeSave should not exist on browser Parse.Cloud + Parse.Cloud.beforeSave('Test', () => {}); + // @ts-expect-error - job should not exist on browser Parse.Cloud + Parse.Cloud.job('test', () => {}); + // @ts-expect-error - httpRequest should not exist on browser Parse.Cloud + Parse.Cloud.httpRequest({ url: '' }); } From 0cc5c268b7b9f60f7193cb73a0b41cc3b50bc3f7 Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Thu, 8 Jan 2026 15:51:26 +0100 Subject: [PATCH 05/10] fix: ESLint errors in Cloud Code tests --- types/tests.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/types/tests.ts b/types/tests.ts index 81a84c6fb..2dfba3656 100644 --- a/types/tests.ts +++ b/types/tests.ts @@ -2289,12 +2289,6 @@ function test_cloud_server_functions() { } }); - // Define with FunctionResponse (Express-style) - ParseNode.Cloud.define('expressStyleFunc', (request, response) => { - response.success({ data: 'value' }); - response.error('Something went wrong'); - }); - // ============================================================================ // Object Lifecycle Triggers // ============================================================================ @@ -2313,7 +2307,7 @@ function test_cloud_server_functions() { }); // afterSave - ParseNode.Cloud.afterSave('TestClass', async (request) => { + ParseNode.Cloud.afterSave('TestClass', (request) => { const obj = request.object; const original = request.original; const context = request.context; @@ -2447,7 +2441,7 @@ function test_cloud_server_functions() { // ============================================================================ // httpRequest - ParseNode.Cloud.httpRequest({ + void ParseNode.Cloud.httpRequest({ url: 'https://example.com', method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -2461,7 +2455,7 @@ function test_cloud_server_functions() { }); // sendEmail - ParseNode.Cloud.sendEmail({ + void ParseNode.Cloud.sendEmail({ to: 'test@example.com', from: 'noreply@example.com', subject: 'Test', @@ -2480,5 +2474,5 @@ function test_cloud_server_functions() { // @ts-expect-error - job should not exist on browser Parse.Cloud Parse.Cloud.job('test', () => {}); // @ts-expect-error - httpRequest should not exist on browser Parse.Cloud - Parse.Cloud.httpRequest({ url: '' }); + void Parse.Cloud.httpRequest({ url: '' }); } From 62ff1f1224f883b8cbc5bca70f0db5131c790a0f Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Thu, 8 Jan 2026 15:59:25 +0100 Subject: [PATCH 06/10] fix: ESLint errors in CloudCode.ts --- src/CloudCode.ts | 64 ++++++++++++++++++++------------------------ types/CloudCode.d.ts | 63 +++++++++++++++---------------------------- 2 files changed, 50 insertions(+), 77 deletions(-) diff --git a/src/CloudCode.ts b/src/CloudCode.ts index 9b88be2e8..80dacf3b8 100644 --- a/src/CloudCode.ts +++ b/src/CloudCode.ts @@ -42,10 +42,10 @@ export interface TriggerRequest { config: any; } -export interface BeforeSaveRequest extends TriggerRequest {} -export interface AfterSaveRequest extends TriggerRequest {} -export interface BeforeDeleteRequest extends TriggerRequest {} -export interface AfterDeleteRequest extends TriggerRequest {} +export type BeforeSaveRequest = TriggerRequest; +export type AfterSaveRequest = TriggerRequest; +export type BeforeDeleteRequest = TriggerRequest; +export type AfterDeleteRequest = TriggerRequest; export interface BeforeFindRequest { installationId?: string; @@ -198,98 +198,92 @@ export declare function define = Record) => any) ): void; -export declare function define = Record>( - name: string, - handler: (request: FunctionRequest, response: FunctionResponse) => any, - validator?: ValidatorObject | ((request: FunctionRequest) => any) -): void; - export declare function job(name: string, handler: (request: JobRequest) => any): void; export declare function beforeSave( - className: string | { new (): T }, - handler: (request: BeforeSaveRequest) => T | void | Promise, + className: string | (new () => T), + handler: (request: BeforeSaveRequest) => T | undefined | Promise, validator?: ValidatorObject | ((request: BeforeSaveRequest) => any) ): void; export declare function afterSave( - className: string | { new (): T }, - handler: (request: AfterSaveRequest) => void | Promise, + className: string | (new () => T), + handler: (request: AfterSaveRequest) => Promise | undefined, validator?: ValidatorObject | ((request: AfterSaveRequest) => any) ): void; export declare function beforeDelete( - className: string | { new (): T }, - handler: (request: BeforeDeleteRequest) => void | Promise, + className: string | (new () => T), + handler: (request: BeforeDeleteRequest) => Promise | undefined, validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any) ): void; export declare function afterDelete( - className: string | { new (): T }, - handler: (request: AfterDeleteRequest) => void | Promise, + className: string | (new () => T), + handler: (request: AfterDeleteRequest) => Promise | undefined, validator?: ValidatorObject | ((request: AfterDeleteRequest) => any) ): void; export declare function beforeFind( - className: string | { new (): T }, - handler: (request: BeforeFindRequest) => ParseQuery | void | Promise | void>, + className: string | (new () => T), + handler: (request: BeforeFindRequest) => ParseQuery | undefined | Promise | undefined>, validator?: ValidatorObject | ((request: BeforeFindRequest) => any) ): void; export declare function afterFind( - className: string | { new (): T }, - handler: (request: AfterFindRequest) => T[] | void | Promise, + className: string | (new () => T), + handler: (request: AfterFindRequest) => T[] | undefined | Promise, validator?: ValidatorObject | ((request: AfterFindRequest) => any) ): void; export declare function beforeLogin( - handler: (request: TriggerRequest) => void | Promise, + handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any) ): void; export declare function afterLogin( - handler: (request: TriggerRequest) => void | Promise + handler: (request: TriggerRequest) => Promise | undefined ): void; export declare function afterLogout( - handler: (request: TriggerRequest) => void | Promise + handler: (request: TriggerRequest) => Promise | undefined ): void; export declare function beforePasswordResetRequest( - handler: (request: TriggerRequest) => void | Promise, + handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any) ): void; export declare function beforeSaveFile( - handler: (request: FileTriggerRequest) => ParseFile | void | Promise + handler: (request: FileTriggerRequest) => ParseFile | undefined | Promise ): void; export declare function afterSaveFile( - handler: (request: FileTriggerRequest) => void | Promise + handler: (request: FileTriggerRequest) => Promise | undefined ): void; export declare function beforeDeleteFile( - handler: (request: FileTriggerRequest) => void | Promise + handler: (request: FileTriggerRequest) => Promise | undefined ): void; export declare function afterDeleteFile( - handler: (request: FileTriggerRequest) => void | Promise + handler: (request: FileTriggerRequest) => Promise | undefined ): void; export declare function beforeConnect( - handler: (request: ConnectTriggerRequest) => void | Promise, + handler: (request: ConnectTriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any) ): void; export declare function beforeSubscribe( - className: string | { new (): T }, - handler: (request: TriggerRequest) => void | Promise, + className: string | (new () => T), + handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any) ): void; export declare function afterLiveQueryEvent( - className: string | { new (): T }, - handler: (request: LiveQueryEventTrigger) => void | Promise, + className: string | (new () => T), + handler: (request: LiveQueryEventTrigger) => Promise | undefined, validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any) ): void; diff --git a/types/CloudCode.d.ts b/types/CloudCode.d.ts index 7668a2926..eabd0a42c 100644 --- a/types/CloudCode.d.ts +++ b/types/CloudCode.d.ts @@ -34,14 +34,10 @@ export interface TriggerRequest { context: Record; config: any; } -export interface BeforeSaveRequest extends TriggerRequest { -} -export interface AfterSaveRequest extends TriggerRequest { -} -export interface BeforeDeleteRequest extends TriggerRequest { -} -export interface AfterDeleteRequest extends TriggerRequest { -} +export type BeforeSaveRequest = TriggerRequest; +export type AfterSaveRequest = TriggerRequest; +export type BeforeDeleteRequest = TriggerRequest; +export type AfterDeleteRequest = TriggerRequest; export interface BeforeFindRequest { installationId?: string; master: boolean; @@ -161,41 +157,24 @@ export declare enum ReadPreferenceOption { Nearest = "NEAREST" } export declare function define = Record>(name: string, handler: (request: FunctionRequest) => any, validator?: ValidatorObject | ((request: FunctionRequest) => any)): void; -export declare function define = Record>(name: string, handler: (request: FunctionRequest, response: FunctionResponse) => any, validator?: ValidatorObject | ((request: FunctionRequest) => any)): void; export declare function job(name: string, handler: (request: JobRequest) => any): void; -export declare function beforeSave(className: string | { - new (): T; -}, handler: (request: BeforeSaveRequest) => T | void | Promise, validator?: ValidatorObject | ((request: BeforeSaveRequest) => any)): void; -export declare function afterSave(className: string | { - new (): T; -}, handler: (request: AfterSaveRequest) => void | Promise, validator?: ValidatorObject | ((request: AfterSaveRequest) => any)): void; -export declare function beforeDelete(className: string | { - new (): T; -}, handler: (request: BeforeDeleteRequest) => void | Promise, validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any)): void; -export declare function afterDelete(className: string | { - new (): T; -}, handler: (request: AfterDeleteRequest) => void | Promise, validator?: ValidatorObject | ((request: AfterDeleteRequest) => any)): void; -export declare function beforeFind(className: string | { - new (): T; -}, handler: (request: BeforeFindRequest) => ParseQuery | void | Promise | void>, validator?: ValidatorObject | ((request: BeforeFindRequest) => any)): void; -export declare function afterFind(className: string | { - new (): T; -}, handler: (request: AfterFindRequest) => T[] | void | Promise, validator?: ValidatorObject | ((request: AfterFindRequest) => any)): void; -export declare function beforeLogin(handler: (request: TriggerRequest) => void | Promise, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; -export declare function afterLogin(handler: (request: TriggerRequest) => void | Promise): void; -export declare function afterLogout(handler: (request: TriggerRequest) => void | Promise): void; -export declare function beforePasswordResetRequest(handler: (request: TriggerRequest) => void | Promise, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; -export declare function beforeSaveFile(handler: (request: FileTriggerRequest) => ParseFile | void | Promise): void; -export declare function afterSaveFile(handler: (request: FileTriggerRequest) => void | Promise): void; -export declare function beforeDeleteFile(handler: (request: FileTriggerRequest) => void | Promise): void; -export declare function afterDeleteFile(handler: (request: FileTriggerRequest) => void | Promise): void; -export declare function beforeConnect(handler: (request: ConnectTriggerRequest) => void | Promise, validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any)): void; -export declare function beforeSubscribe(className: string | { - new (): T; -}, handler: (request: TriggerRequest) => void | Promise, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; -export declare function afterLiveQueryEvent(className: string | { - new (): T; -}, handler: (request: LiveQueryEventTrigger) => void | Promise, validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any)): void; +export declare function beforeSave(className: string | (new () => T), handler: (request: BeforeSaveRequest) => T | undefined | Promise, validator?: ValidatorObject | ((request: BeforeSaveRequest) => any)): void; +export declare function afterSave(className: string | (new () => T), handler: (request: AfterSaveRequest) => Promise | undefined, validator?: ValidatorObject | ((request: AfterSaveRequest) => any)): void; +export declare function beforeDelete(className: string | (new () => T), handler: (request: BeforeDeleteRequest) => Promise | undefined, validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any)): void; +export declare function afterDelete(className: string | (new () => T), handler: (request: AfterDeleteRequest) => Promise | undefined, validator?: ValidatorObject | ((request: AfterDeleteRequest) => any)): void; +export declare function beforeFind(className: string | (new () => T), handler: (request: BeforeFindRequest) => ParseQuery | undefined | Promise | undefined>, validator?: ValidatorObject | ((request: BeforeFindRequest) => any)): void; +export declare function afterFind(className: string | (new () => T), handler: (request: AfterFindRequest) => T[] | undefined | Promise, validator?: ValidatorObject | ((request: AfterFindRequest) => any)): void; +export declare function beforeLogin(handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +export declare function afterLogin(handler: (request: TriggerRequest) => Promise | undefined): void; +export declare function afterLogout(handler: (request: TriggerRequest) => Promise | undefined): void; +export declare function beforePasswordResetRequest(handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +export declare function beforeSaveFile(handler: (request: FileTriggerRequest) => ParseFile | undefined | Promise): void; +export declare function afterSaveFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; +export declare function beforeDeleteFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; +export declare function afterDeleteFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; +export declare function beforeConnect(handler: (request: ConnectTriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any)): void; +export declare function beforeSubscribe(className: string | (new () => T), handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +export declare function afterLiveQueryEvent(className: string | (new () => T), handler: (request: LiveQueryEventTrigger) => Promise | undefined, validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any)): void; export declare function sendEmail(data: { from?: string; to: string; From 17da4a8ca194c48d4df1c793afffc8a1f6bc7e30 Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Thu, 8 Jan 2026 21:41:27 +0100 Subject: [PATCH 07/10] refactor: Move JSDoc to functions and clean up Cloud Code tests - Move JSDoc documentation directly above each function declaration - Remove section divider comments (// ====) - Merge test_cloud_server_functions into test_cloud_functions - Use ParseNode.Cloud for server-side tests - Add proper descriptions to @ts-expect-error comments --- src/CloudCode.ts | 599 +++++++++++++++++++++++------------------------ types/tests.ts | 539 +++++++++++++----------------------------- 2 files changed, 460 insertions(+), 678 deletions(-) diff --git a/src/CloudCode.ts b/src/CloudCode.ts index 80dacf3b8..08bf56658 100644 --- a/src/CloudCode.ts +++ b/src/CloudCode.ts @@ -3,10 +3,13 @@ import type ParseUser from './ParseUser'; import type ParseFile from './ParseFile'; import type ParseQuery from './ParseQuery'; -// ============================================================================ -// Request Interfaces -// ============================================================================ - +/** + * @typedef Parse.Cloud.FunctionRequest + * @property {string} installationId If set, the installationId triggering the request. + * @property {boolean} master If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {object} params The params passed to the cloud function. + */ export interface FunctionRequest> { installationId?: string; master: boolean; @@ -27,6 +30,18 @@ export interface FunctionResponse { header: (name: string, value: string) => FunctionResponse; } +/** + * @typedef Parse.Cloud.TriggerRequest + * @property {string} installationId If set, the installationId triggering the request. + * @property {boolean} master If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {Parse.Object} object The object triggering the hook. + * @property {string} ip The IP address of the client making the request. + * @property {object} headers The original HTTP headers for the request. + * @property {string} triggerName The name of the trigger (`beforeSave`, `afterSave`, ...) + * @property {object} log The current logger inside Parse Server. + * @property {Parse.Object} original If set, the object, as currently stored. + */ export interface TriggerRequest { installationId?: string; master: boolean; @@ -77,6 +92,17 @@ export interface AfterFindRequest { context: Record; } +/** + * @typedef Parse.Cloud.FileTriggerRequest + * @property {string} installationId If set, the installationId triggering the request. + * @property {boolean} master If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {Parse.File} file The file triggering the hook. + * @property {string} ip The IP address of the client making the request. + * @property {object} headers The original HTTP headers for the request. + * @property {string} triggerName The name of the trigger (`beforeSaveFile`, `afterSaveFile`, ...) + * @property {object} log The current logger inside Parse Server. + */ export interface FileTriggerRequest { installationId?: string; master: boolean; @@ -91,6 +117,15 @@ export interface FileTriggerRequest { config: any; } +/** + * @typedef Parse.Cloud.ConnectTriggerRequest + * @property {string} installationId If set, the installationId triggering the request. + * @property {boolean} useMasterKey If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {number} clients The number of clients connected. + * @property {number} subscriptions The number of subscriptions connected. + * @property {string} sessionToken If set, the session of the user that made the request. + */ export interface ConnectTriggerRequest { installationId?: string; useMasterKey: boolean; @@ -113,16 +148,17 @@ export interface LiveQueryEventTrigger { sendEvent: boolean; } +/** + * @typedef Parse.Cloud.JobRequest + * @property {object} params The params passed to the background job. + * @property {Function} message If message is called with a string argument, will update the current message to be stored in the job status. + */ export interface JobRequest { params: Record; message: (message: string) => void; config: any; } -// ============================================================================ -// Validator Types -// ============================================================================ - export interface ValidatorField { type?: any; constant?: boolean; @@ -152,10 +188,15 @@ export interface ValidatorObject { }; } -// ============================================================================ -// HTTP Types -// ============================================================================ - +/** + * @typedef Parse.Cloud.HTTPOptions + * @property {string | object} body The body of the request. + * @property {boolean} followRedirects Whether to follow redirects caused by HTTP 3xx responses. Defaults to false. + * @property {object} headers The headers for the request. + * @property {string} method The method of the request. GET, POST, PUT, DELETE, HEAD, and OPTIONS are supported. + * @property {string | object} params The query portion of the url. + * @property {string} url The url to send the request to. + */ export interface HTTPOptions { body?: string | object; error?: (response: HTTPResponse) => void; @@ -167,6 +208,15 @@ export interface HTTPOptions { url: string; } +/** + * @typedef Parse.Cloud.HTTPResponse + * @property {Buffer} buffer The raw byte representation of the response body. + * @property {object} cookies The cookies sent by the server. + * @property {object} data The parsed response body as a JavaScript object. + * @property {object} headers The headers sent by the server. + * @property {number} status The status code. + * @property {string} text The raw text representation of the response body. + */ export interface HTTPResponse { buffer?: Buffer; cookies?: Record; @@ -176,10 +226,6 @@ export interface HTTPResponse { text?: string; } -// ============================================================================ -// Enum -// ============================================================================ - export enum ReadPreferenceOption { Primary = 'PRIMARY', PrimaryPreferred = 'PRIMARY_PREFERRED', @@ -188,182 +234,95 @@ export enum ReadPreferenceOption { Nearest = 'NEAREST', } -// ============================================================================ -// Function Declarations (server-side only, implemented by Parse Server) -// ============================================================================ - +/** + * Defines a Cloud Function. + * + * **Available in Cloud Code only.** + * + * @param name The name of the Cloud Function + * @param handler The Cloud Function to register. This function should take one parameter {@link FunctionRequest} + * @param validator An optional function to validate the request + */ export declare function define = Record>( name: string, handler: (request: FunctionRequest) => any, validator?: ValidatorObject | ((request: FunctionRequest) => any) ): void; -export declare function job(name: string, handler: (request: JobRequest) => any): void; - -export declare function beforeSave( - className: string | (new () => T), - handler: (request: BeforeSaveRequest) => T | undefined | Promise, - validator?: ValidatorObject | ((request: BeforeSaveRequest) => any) -): void; - -export declare function afterSave( - className: string | (new () => T), - handler: (request: AfterSaveRequest) => Promise | undefined, - validator?: ValidatorObject | ((request: AfterSaveRequest) => any) -): void; - -export declare function beforeDelete( - className: string | (new () => T), - handler: (request: BeforeDeleteRequest) => Promise | undefined, - validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any) -): void; - -export declare function afterDelete( - className: string | (new () => T), - handler: (request: AfterDeleteRequest) => Promise | undefined, - validator?: ValidatorObject | ((request: AfterDeleteRequest) => any) -): void; - -export declare function beforeFind( - className: string | (new () => T), - handler: (request: BeforeFindRequest) => ParseQuery | undefined | Promise | undefined>, - validator?: ValidatorObject | ((request: BeforeFindRequest) => any) -): void; - -export declare function afterFind( - className: string | (new () => T), - handler: (request: AfterFindRequest) => T[] | undefined | Promise, - validator?: ValidatorObject | ((request: AfterFindRequest) => any) -): void; - -export declare function beforeLogin( - handler: (request: TriggerRequest) => Promise | undefined, - validator?: ValidatorObject | ((request: TriggerRequest) => any) -): void; - -export declare function afterLogin( - handler: (request: TriggerRequest) => Promise | undefined -): void; - -export declare function afterLogout( - handler: (request: TriggerRequest) => Promise | undefined -): void; - -export declare function beforePasswordResetRequest( - handler: (request: TriggerRequest) => Promise | undefined, - validator?: ValidatorObject | ((request: TriggerRequest) => any) -): void; - -export declare function beforeSaveFile( - handler: (request: FileTriggerRequest) => ParseFile | undefined | Promise -): void; - -export declare function afterSaveFile( - handler: (request: FileTriggerRequest) => Promise | undefined -): void; - -export declare function beforeDeleteFile( - handler: (request: FileTriggerRequest) => Promise | undefined -): void; - -export declare function afterDeleteFile( - handler: (request: FileTriggerRequest) => Promise | undefined -): void; - -export declare function beforeConnect( - handler: (request: ConnectTriggerRequest) => Promise | undefined, - validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any) -): void; - -export declare function beforeSubscribe( - className: string | (new () => T), - handler: (request: TriggerRequest) => Promise | undefined, - validator?: ValidatorObject | ((request: TriggerRequest) => any) -): void; - -export declare function afterLiveQueryEvent( - className: string | (new () => T), - handler: (request: LiveQueryEventTrigger) => Promise | undefined, - validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any) -): void; - -export declare function sendEmail(data: { - from?: string; - to: string; - subject?: string; - text?: string; - html?: string; -}): Promise; - -export declare function httpRequest(options: HTTPOptions): Promise; - -// ============================================================================ -// JSDoc Documentation (for documentation generation) -// ============================================================================ - /** - * Defines a Cloud Function. + * Defines a Background Job. * * **Available in Cloud Code only.** * - * @function define - * @name Parse.Cloud.define - * @param {string} name The name of the Cloud Function - * @param {Function} data The Cloud Function to register. This function should take one parameter {@link Parse.Cloud.FunctionRequest} + * @param name The name of the Background Job + * @param handler The Background Job to register. This function should take one parameter {@link JobRequest} */ +export declare function job(name: string, handler: (request: JobRequest) => any): void; /** - * Registers an after delete function. + * Registers a before save function. * * **Available in Cloud Code only.** * - * If you want to use afterDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. + * If you want to use beforeSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), + * you should pass the class itself and not the String for arg1. + * * ``` - * Parse.Cloud.afterDelete('MyCustomClass', (request) => { + * Parse.Cloud.beforeSave('MyCustomClass', (request) => { * // code here * }) * - * Parse.Cloud.afterDelete(Parse.User, (request) => { + * Parse.Cloud.beforeSave(Parse.User, (request) => { * // code here * }) - *``` + * ``` * - * @function afterDelete - * @name Parse.Cloud.afterDelete - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the after delete function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run after a delete. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param className The Parse.Object subclass to register the before save function for. + * @param handler The function to run before a save. + * @param validator An optional function to validate the request */ +export declare function beforeSave( + className: string | (new () => T), + handler: (request: BeforeSaveRequest) => T | undefined | Promise, + validator?: ValidatorObject | ((request: BeforeSaveRequest) => any) +): void; /** - * * Registers an after save function. * * **Available in Cloud Code only.** * - * If you want to use afterSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. + * If you want to use afterSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), + * you should pass the class itself and not the String for arg1. * * ``` - * Parse.Cloud.afterSave('MyCustomClass', function(request) { + * Parse.Cloud.afterSave('MyCustomClass', (request) => { * // code here * }) * - * Parse.Cloud.afterSave(Parse.User, function(request) { + * Parse.Cloud.afterSave(Parse.User, (request) => { * // code here * }) * ``` * - * @function afterSave - * @name Parse.Cloud.afterSave - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the after save function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run after a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param className The Parse.Object subclass to register the after save function for. + * @param handler The function to run after a save. + * @param validator An optional function to validate the request */ +export declare function afterSave( + className: string | (new () => T), + handler: (request: AfterSaveRequest) => Promise | undefined, + validator?: ValidatorObject | ((request: AfterSaveRequest) => any) +): void; /** - * Registers an before delete function. + * Registers a before delete function. * * **Available in Cloud Code only.** * - * If you want to use beforeDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. + * If you want to use beforeDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), + * you should pass the class itself and not the String for arg1. + * * ``` * Parse.Cloud.beforeDelete('MyCustomClass', (request) => { * // code here @@ -372,115 +331,191 @@ export declare function httpRequest(options: HTTPOptions): Promise * Parse.Cloud.beforeDelete(Parse.User, (request) => { * // code here * }) - *``` + * ``` * - * @function beforeDelete - * @name Parse.Cloud.beforeDelete - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the before delete function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run before a delete. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param className The Parse.Object subclass to register the before delete function for. + * @param handler The function to run before a delete. + * @param validator An optional function to validate the request */ +export declare function beforeDelete( + className: string | (new () => T), + handler: (request: BeforeDeleteRequest) => Promise | undefined, + validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any) +): void; /** - * - * Registers an before save function. + * Registers an after delete function. * * **Available in Cloud Code only.** * - * If you want to use beforeSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. + * If you want to use afterDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), + * you should pass the class itself and not the String for arg1. * * ``` - * Parse.Cloud.beforeSave('MyCustomClass', (request) => { + * Parse.Cloud.afterDelete('MyCustomClass', (request) => { * // code here * }) * - * Parse.Cloud.beforeSave(Parse.User, (request) => { + * Parse.Cloud.afterDelete(Parse.User, (request) => { * // code here * }) * ``` * - * @function beforeSave - * @name Parse.Cloud.beforeSave - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the after save function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run before a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param className The Parse.Object subclass to register the after delete function for. + * @param handler The function to run after a delete. + * @param validator An optional function to validate the request */ +export declare function afterDelete( + className: string | (new () => T), + handler: (request: AfterDeleteRequest) => Promise | undefined, + validator?: ValidatorObject | ((request: AfterDeleteRequest) => any) +): void; /** + * Registers a before find function. * - * Registers an before save file function. A new Parse.File can be returned to override the file that gets saved. - * If you want to replace the rquesting Parse.File with a Parse.File that is already saved, simply return the already saved Parse.File. - * You can also add metadata to the file that will be stored via whatever file storage solution you're using. + * **Available in Cloud Code only.** + * + * @param className The Parse.Object subclass to register the before find function for. + * @param handler The function to run before a find. + * @param validator An optional function to validate the request + */ +export declare function beforeFind( + className: string | (new () => T), + handler: (request: BeforeFindRequest) => ParseQuery | undefined | Promise | undefined>, + validator?: ValidatorObject | ((request: BeforeFindRequest) => any) +): void; + +/** + * Registers an after find function. * * **Available in Cloud Code only.** * - * Example: Adding metadata and tags - * ``` - * Parse.Cloud.beforeSaveFile(({ file, user }) => { - * file.addMetadata('foo', 'bar'); - * file.addTag('createdBy', user.id); - * }); + * @param className The Parse.Object subclass to register the after find function for. + * @param handler The function to run after a find. + * @param validator An optional function to validate the request + */ +export declare function afterFind( + className: string | (new () => T), + handler: (request: AfterFindRequest) => T[] | undefined | Promise, + validator?: ValidatorObject | ((request: AfterFindRequest) => any) +): void; + +/** + * Registers a before login function. * - * ``` + * **Available in Cloud Code only.** * - * Example: replacing file with an already saved file + * @param handler The function to run before a login. + * @param validator An optional function to validate the request + */ +export declare function beforeLogin( + handler: (request: TriggerRequest) => Promise | undefined, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +/** + * Registers an after login function. * - * ``` - * Parse.Cloud.beforeSaveFile(({ file, user }) => { - * return user.get('avatar'); - * }); + * **Available in Cloud Code only.** * - * ``` + * @param handler The function to run after a login. + */ +export declare function afterLogin( + handler: (request: TriggerRequest) => Promise | undefined +): void; + +/** + * Registers an after logout function. + * + * **Available in Cloud Code only.** + * + * @param handler The function to run after a logout. + */ +export declare function afterLogout( + handler: (request: TriggerRequest) => Promise | undefined +): void; + +/** + * Registers a before password reset request function. + * + * **Available in Cloud Code only.** + * + * @param handler The function to run before a password reset request. + * @param validator An optional function to validate the request + */ +export declare function beforePasswordResetRequest( + handler: (request: TriggerRequest) => Promise | undefined, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +/** + * Registers a before save file function. + * + * **Available in Cloud Code only.** * - * Example: replacing file with a different file + * A new Parse.File can be returned to override the file that gets saved. * * ``` * Parse.Cloud.beforeSaveFile(({ file, user }) => { - * const metadata = { foo: 'bar' }; - * const tags = { createdBy: user.id }; - * const newFile = new Parse.File(file.name(), , 'text/plain', metadata, tags); - * return newFile; + * file.addMetadata('foo', 'bar'); + * file.addTag('createdBy', user.id); * }); - * * ``` * - * @function beforeSaveFile - * @name Parse.Cloud.beforeSaveFile - * @param {Function} func The function to run before a file saves. This function should take one parameter, a {@link Parse.Cloud.FileTriggerRequest}. + * @param handler The function to run before a file saves. */ +export declare function beforeSaveFile( + handler: (request: FileTriggerRequest) => ParseFile | undefined | Promise +): void; /** - * * Registers an after save file function. * * **Available in Cloud Code only.** * - * Example: creating a new object that references this file in a separate collection * ``` * Parse.Cloud.afterSaveFile(async ({ file, user }) => { * const fileObject = new Parse.Object('FileObject'); - * fileObject.set('metadata', file.metadata()); - * fileObject.set('tags', file.tags()); * fileObject.set('name', file.name()); * fileObject.set('createdBy', user); * await fileObject.save({ sessionToken: user.getSessionToken() }); * }); + * ``` * - * @method afterSaveFile - * @name Parse.Cloud.afterSaveFile - * @param {Function} func The function to run after a file saves. This function should take one parameter, a {@link Parse.Cloud.FileTriggerRequest}. + * @param handler The function to run after a file saves. */ +export declare function afterSaveFile( + handler: (request: FileTriggerRequest) => Promise | undefined +): void; /** - * @function beforeConnect - * @name Parse.Cloud.beforeConnect - * @param {Function} func The function to before connection is made. This function can be async and should take just one parameter, {@link Parse.Cloud.ConnectTriggerRequest}. + * Registers a before delete file function. + * + * **Available in Cloud Code only.** + * + * @param handler The function to run before a file is deleted. */ +export declare function beforeDeleteFile( + handler: (request: FileTriggerRequest) => Promise | undefined +): void; + /** + * Registers an after delete file function. * - * Registers a before connect function. + * **Available in Cloud Code only.** + * + * @param handler The function to run after a file is deleted. + */ +export declare function afterDeleteFile( + handler: (request: FileTriggerRequest) => Promise | undefined +): void; + +/** + * Registers a before connect function for LiveQuery. * * **Available in Cloud Code only.** * - * Example: restrict LiveQueries to logged in users. * ``` * Parse.Cloud.beforeConnect((request) => { * if (!request.user) { @@ -488,141 +523,89 @@ export declare function httpRequest(options: HTTPOptions): Promise * } * }); * ``` + * + * @param handler The function to run before a LiveQuery connection is made. + * @param validator An optional function to validate the request */ +export declare function beforeConnect( + handler: (request: ConnectTriggerRequest) => Promise | undefined, + validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any) +): void; /** - * @function beforeSubscribe - * @name Parse.Cloud.beforeSubscribe - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the before subscription function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run before a subscription. This function can be async and should take one parameter, a {@link Parse.Cloud.TriggerRequest}. - */ -/** - * - * Registers a before subscribe function. + * Registers a before subscribe function for LiveQuery. * * **Available in Cloud Code only.** - * Example: restrict subscriptions to MyObject to Admin accounts only. + * * ``` - * Parse.Cloud.beforeSubscribe('MyObject', (request) => { + * Parse.Cloud.beforeSubscribe('MyObject', (request) => { * if (!request.user.get('Admin')) { - * throw new Parse.Error(101, 'You are not authorized to subscribe to MyObject.'); + * throw new Parse.Error(101, 'You are not authorized to subscribe to MyObject.'); * } - * let query = request.query; // the Parse.Query - * query.select("name","year") + * let query = request.query; + * query.select("name", "year"); * }); * ``` + * + * @param className The Parse.Object subclass to register the before subscribe function for. + * @param handler The function to run before a subscription. + * @param validator An optional function to validate the request */ +export declare function beforeSubscribe( + className: string | (new () => T), + handler: (request: TriggerRequest) => Promise | undefined, + validator?: ValidatorObject | ((request: TriggerRequest) => any) +): void; + +/** + * Registers an after live query event function. + * + * **Available in Cloud Code only.** + * + * @param className The Parse.Object subclass to register the after live query event function for. + * @param handler The function to run after a live query event. + * @param validator An optional function to validate the request + */ +export declare function afterLiveQueryEvent( + className: string | (new () => T), + handler: (request: LiveQueryEventTrigger) => Promise | undefined, + validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any) +): void; + +/** + * Sends an email. + * + * **Available in Cloud Code only.** + * + * @param data The email data including to, from, subject, text, and html. + */ +export declare function sendEmail(data: { + from?: string; + to: string; + subject?: string; + text?: string; + html?: string; +}): Promise; /** * Makes an HTTP Request. * * **Available in Cloud Code only.** * - * By default, Parse.Cloud.httpRequest does not follow redirects caused by HTTP 3xx response codes. You can use the followRedirects option in the {@link Parse.Cloud.HTTPOptions} object to change this behavior. + * By default, Parse.Cloud.httpRequest does not follow redirects caused by HTTP 3xx response codes. + * You can use the followRedirects option in the {@link HTTPOptions} object to change this behavior. * - * Sample request: * ``` * Parse.Cloud.httpRequest({ * url: 'http://www.example.com/' * }).then(function(httpResponse) { - * // success * console.log(httpResponse.text); - * },function(httpResponse) { - * // error + * }, function(httpResponse) { * console.error('Request failed with response code ' + httpResponse.status); * }); * ``` * - * @function httpRequest - * @name Parse.Cloud.httpRequest - * @param {Parse.Cloud.HTTPOptions} options The Parse.Cloud.HTTPOptions object that makes the request. - * @returns {Promise} A promise that will be resolved with a {@link Parse.Cloud.HTTPResponse} object when the request completes. - */ - -/** - * Defines a Background Job. - * - * **Available in Cloud Code only.** - * - * @function job - * @name Parse.Cloud.job - * @param {string} name The name of the Background Job - * @param {Function} func The Background Job to register. This function should take two parameters a {@link Parse.Cloud.JobRequest} and a {@link Parse.Cloud.JobStatus} - */ - -/** - * @typedef Parse.Cloud.TriggerRequest - * @property {string} installationId If set, the installationId triggering the request. - * @property {boolean} master If true, means the master key was used. - * @property {Parse.User} user If set, the user that made the request. - * @property {Parse.Object} object The object triggering the hook. - * @property {string} ip The IP address of the client making the request. - * @property {object} headers The original HTTP headers for the request. - * @property {string} triggerName The name of the trigger (`beforeSave`, `afterSave`, ...) - * @property {object} log The current logger inside Parse Server. - * @property {Parse.Object} original If set, the object, as currently stored. - */ - -/** - * @typedef Parse.Cloud.FileTriggerRequest - * @property {string} installationId If set, the installationId triggering the request. - * @property {boolean} master If true, means the master key was used. - * @property {Parse.User} user If set, the user that made the request. - * @property {Parse.File} file The file triggering the hook. - * @property {string} ip The IP address of the client making the request. - * @property {object} headers The original HTTP headers for the request. - * @property {string} triggerName The name of the trigger (`beforeSaveFile`, `afterSaveFile`, ...) - * @property {object} log The current logger inside Parse Server. - */ - -/** - * @typedef Parse.Cloud.ConnectTriggerRequest - * @property {string} installationId If set, the installationId triggering the request. - * @property {boolean} useMasterKey If true, means the master key was used. - * @property {Parse.User} user If set, the user that made the request. - * @property {number} clients The number of clients connected. - * @property {number} subscriptions The number of subscriptions connected. - * @property {string} sessionToken If set, the session of the user that made the request. - */ - -/** - * @typedef Parse.Cloud.FunctionRequest - * @property {string} installationId If set, the installationId triggering the request. - * @property {boolean} master If true, means the master key was used. - * @property {Parse.User} user If set, the user that made the request. - * @property {object} params The params passed to the cloud function. - */ - -/** - * @typedef Parse.Cloud.JobRequest - * @property {object} params The params passed to the background job. - */ - -/** - * @typedef Parse.Cloud.JobStatus - * @property {Function} error If error is called, will end the job unsuccessfully with an optional completion message to be stored in the job status. - * @property {Function} message If message is called with a string argument, will update the current message to be stored in the job status. - * @property {Function} success If success is called, will end the job successfullly with the optional completion message to be stored in the job status. - */ - -/** - * @typedef Parse.Cloud.HTTPOptions - * @property {string | object} body The body of the request. If it is a JSON object, then the Content-Type set in the headers must be application/x-www-form-urlencoded or application/json. You can also set this to a {@link Buffer} object to send raw bytes. If you use a Buffer, you should also set the Content-Type header explicitly to describe what these bytes represent. - * @property {Function} error The function that is called when the request fails. It will be passed a Parse.Cloud.HTTPResponse object. - * @property {boolean} followRedirects Whether to follow redirects caused by HTTP 3xx responses. Defaults to false. - * @property {object} headers The headers for the request. - * @property {string} method The method of the request. GET, POST, PUT, DELETE, HEAD, and OPTIONS are supported. Will default to GET if not specified. - * @property {string | object} params The query portion of the url. You can pass a JSON object of key value pairs like params: {q : 'Sean Plott'} or a raw string like params:q=Sean Plott. - * @property {Function} success The function that is called when the request successfully completes. It will be passed a Parse.Cloud.HTTPResponse object. - * @property {string} url The url to send the request to. - */ - -/** - * @typedef Parse.Cloud.HTTPResponse - * @property {Buffer} buffer The raw byte representation of the response body. Use this to receive binary data. See Buffer for more details. - * @property {object} cookies The cookies sent by the server. The keys in this object are the names of the cookies. The values are Parse.Cloud.Cookie objects. - * @property {object} data The parsed response body as a JavaScript object. This is only available when the response Content-Type is application/x-www-form-urlencoded or application/json. - * @property {object} headers The headers sent by the server. The keys in this object are the names of the headers. We do not support multiple response headers with the same name. In the common case of Set-Cookie headers, please use the cookies field instead. - * @property {number} status The status code. - * @property {string} text The raw text representation of the response body. + * @param options The HTTPOptions object that makes the request. + * @returns A promise that will be resolved with a {@link HTTPResponse} object when the request completes. */ +export declare function httpRequest(options: HTTPOptions): Promise; diff --git a/types/tests.ts b/types/tests.ts index 2dfba3656..0f1870242 100644 --- a/types/tests.ts +++ b/types/tests.ts @@ -549,170 +549,188 @@ async function test_facebook_util() { async function test_cloud_functions() { // $ExpectType any await Parse.Cloud.run('SomeFunction'); + // $ExpectType any await Parse.Cloud.run('SomeFunction', { something: 'whatever' }); + // $ExpectType any await Parse.Cloud.run('SomeFunction', null, { useMasterKey: true }); - // ExpectType boolean + + // $ExpectType boolean await Parse.Cloud.run<() => boolean>('SomeFunction'); + // $ExpectType boolean await Parse.Cloud.run<() => boolean>('SomeFunction', null); + // $ExpectType boolean await Parse.Cloud.run<() => boolean>('SomeFunction', null, { useMasterKey: true }); + // $ExpectType number - await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', { - paramA: 'hello', - }); - // $ExpectError + await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', { paramA: 'hello' }); + + // @ts-expect-error - params are required await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction'); - await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', { - // $ExpectError - paramZ: 'hello', + + // @ts-expect-error - wrong param name + await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', { paramZ: 'hello' }); + + // @ts-expect-error - params are required, null not allowed + await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', null, { useMasterKey: true }); + + // @ts-expect-error - params must be object not string + await Parse.Cloud.run<(params: string) => any>('SomeFunction', 'hello'); + + ParseNode.Cloud.afterDelete('MyCustomClass', request => { + request.object; + request.user; }); - // $ExpectError - await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', null, { - useMasterKey: true, + + ParseNode.Cloud.afterSave('MyCustomClass', request => { + if (!request.context) { + throw new Error('Request context should be defined'); + } + request.object; }); - // $ExpectError - await Parse.Cloud.run<(params: string) => any>('SomeFunction', 'hello'); - // Parse.Cloud.afterDelete('MyCustomClass', (request: Parse.Cloud.AfterDeleteRequest) => { - // // result - // }); - // Parse.Cloud.afterSave('MyCustomClass', (request: Parse.Cloud.AfterSaveRequest) => { - // if (!request.context) { - // throw new Error('Request context should be defined'); - // } - // // result - // }); - // Parse.Cloud.beforeDelete('MyCustomClass', (request: Parse.Cloud.BeforeDeleteRequest) => { - // // result - // }); - // Parse.Cloud.beforeDelete('MyCustomClass', async (request: Parse.Cloud.BeforeDeleteRequest) => { - // // result - // }); - // interface BeforeSaveObject { - // immutable: boolean; - // } - // Parse.Cloud.beforeSave('MyCustomClass', request => { - // if (request.object.isNew()) { - // if (!request.object.has('immutable')) throw new Error('Field immutable is required'); - // } else { - // const original = request.original; - // if (original == null) { - // // When the object is not new, request.original must be defined - // throw new Error('Original must me defined for an existing object'); - // } - // if (original.get('immutable') !== request.object.get('immutable')) { - // throw new Error('This field cannot be changed'); - // } - // } - // if (!request.context) { - // throw new Error('Request context should be defined'); - // } - // }); - // Parse.Cloud.beforeFind('MyCustomClass', (request: Parse.Cloud.BeforeFindRequest) => { - // const query = request.query; // the Parse.Query - // const user = request.user; // the user - // const isMaster = request.master; // if the query is run with masterKey - // const isCount = request.count; // if the query is a count operation (available on parse-server 2.4.0 or up) - // const isGet = request.isGet; // if the query is a get operation - // // All possible read preferences - // request.readPreference = Parse.Cloud.ReadPreferenceOption.Primary; - // request.readPreference = Parse.Cloud.ReadPreferenceOption.PrimaryPreferred; - // request.readPreference = Parse.Cloud.ReadPreferenceOption.Secondary; - // request.readPreference = Parse.Cloud.ReadPreferenceOption.SecondaryPreferred; - // request.readPreference = Parse.Cloud.ReadPreferenceOption.Nearest; - // }); - // Parse.Cloud.beforeFind('MyCustomClass', (request: Parse.Cloud.BeforeFindRequest) => { - // const query = request.query; // the Parse.Query - // return new Parse.Query('QueryMe!'); - // }); - // Parse.Cloud.beforeFind('MyCustomClass', (request: Parse.Cloud.BeforeFindRequest) => { - // const query = request.query; // the Parse.Query - // return new Parse.Query('QueryMe, IN THE FUTURE!'); - // }); - // Parse.Cloud.afterFind('MyCustomClass', (request: Parse.Cloud.AfterFindRequest) => { - // return new Parse.Object('MyCustomClass'); - // }); - // Parse.Cloud.beforeLogin((request: Parse.Cloud.TriggerRequest) => { - // return Promise.resolve(); - // }); - // Parse.Cloud.afterLogin((request: Parse.Cloud.TriggerRequest) => { - // return Promise.resolve(); - // }); - // Parse.Cloud.afterLogout((request: Parse.Cloud.TriggerRequest) => { - // return Promise.resolve(); - // }); - // Parse.Cloud.beforeSaveFile((request: Parse.Cloud.FileTriggerRequest) => { - // return Promise.resolve(new Parse.File('myFile.txt', { base64: '' })); - // }); - // Parse.Cloud.beforeSaveFile((request: Parse.Cloud.FileTriggerRequest) => {}); - // Parse.Cloud.beforeDeleteFile((request: Parse.Cloud.FileTriggerRequest) => {}); - // Parse.Cloud.afterDeleteFile((request: Parse.Cloud.FileTriggerRequest) => {}); - // Parse.Cloud.define('AFunc', (request: Parse.Cloud.FunctionRequest) => { - // return 'Some result'; - // }); - // Parse.Cloud.define( - // 'AFunc', - // (request: Parse.Cloud.FunctionRequest) => { - // return 'Some result'; - // }, - // { - // requireUser: true, - // requireMaster: true, - // validateMasterKey: true, - // skipWithMasterKey: true, - // requireAnyUserRoles: ['a'], - // requireAllUserRoles: ['a'], - // fields: { - // name: { - // type: String, - // constant: true, - // default: true, - // options: [], - // error: 'invalid field.', - // }, - // }, - // requireUserKeys: { - // name: { - // type: String, - // constant: true, - // default: true, - // options: [], - // error: 'invalid field.', - // }, - // }, - // } - // ); - // Parse.Cloud.define('AFunc', request => { - // // $ExpectType Params - // request.params; - // // $ExpectType any - // request.params.anything; - // }); - // Parse.Cloud.define<() => void>('AFunc', request => { - // // $ExpectType {} - // request.params; - // }); - // Parse.Cloud.define<(params: { something: string }) => number>('AFunc', request => { - // // $ExpectType { something: string; } - // request.params; - // // $ExpectError - // request.params.somethingElse; - // return 123; - // }); - // // $ExpectError - // Parse.Cloud.define('AFunc'); - // // $ExpectError - // Parse.Cloud.define<() => string>('AFunc', () => 123); - // // $ExpectError - // Parse.Cloud.define<(params: string) => number>('AFunc', () => 123); - // Parse.Cloud.job('AJob', (request: Parse.Cloud.JobRequest) => { - // request.message('Message to associate with this job run'); - // }); - await Parse.Cloud.startJob('AJob', {}).then(v => v); - await Parse.Cloud.getJobStatus('AJob').then(v => v); - await Parse.Cloud.getJobsData().then(v => v); + + ParseNode.Cloud.beforeDelete('MyCustomClass', request => { + request.object; + }); + + ParseNode.Cloud.beforeSave('MyCustomClass', request => { + if (request.object.isNew()) { + if (!request.object.has('immutable')) throw new Error('Field immutable is required'); + } else { + const original = request.original; + if (original == null) { + throw new Error('Original must be defined for an existing object'); + } + if (original.get('immutable') !== request.object.get('immutable')) { + throw new Error('This field cannot be changed'); + } + } + if (!request.context) { + throw new Error('Request context should be defined'); + } + }); + + ParseNode.Cloud.beforeFind('MyCustomClass', request => { + request.query; + request.user; + request.master; + request.count; + request.isGet; + + request.readPreference = ParseNode.Cloud.ReadPreferenceOption.Primary; + request.readPreference = ParseNode.Cloud.ReadPreferenceOption.PrimaryPreferred; + request.readPreference = ParseNode.Cloud.ReadPreferenceOption.Secondary; + request.readPreference = ParseNode.Cloud.ReadPreferenceOption.SecondaryPreferred; + request.readPreference = ParseNode.Cloud.ReadPreferenceOption.Nearest; + }); + + ParseNode.Cloud.beforeFind('MyCustomClass', request => { + request.query; + return new Parse.Query('QueryMe!'); + }); + + ParseNode.Cloud.afterFind('MyCustomClass', request => { + request.results; + return request.results; + }); + + ParseNode.Cloud.beforeLogin(request => { + request.object; + request.user; + }); + + ParseNode.Cloud.afterLogin(request => { + request.object; + }); + + ParseNode.Cloud.afterLogout(request => { + request.object; + }); + + ParseNode.Cloud.beforeSaveFile(request => { + request.file; + request.fileSize; + return new Parse.File('myFile.txt', { base64: '' }); + }); + + ParseNode.Cloud.beforeSaveFile(request => { + request.file; + }); + + ParseNode.Cloud.beforeDeleteFile(request => { + request.file; + }); + + ParseNode.Cloud.afterDeleteFile(request => { + request.file; + }); + + ParseNode.Cloud.define('AFunc', request => { + request.params; + return 'Some result'; + }); + + ParseNode.Cloud.define( + 'AFunc', + request => { + request.params; + return 'Some result'; + }, + { + requireUser: true, + requireMaster: true, + validateMasterKey: true, + skipWithMasterKey: true, + requireAnyUserRoles: ['a'], + requireAllUserRoles: ['a'], + fields: { + name: { + type: String, + constant: true, + default: true, + options: [], + error: 'invalid field.', + }, + }, + requireUserKeys: { + name: { + type: String, + constant: true, + default: true, + options: [], + error: 'invalid field.', + }, + }, + }, + ); + + ParseNode.Cloud.define('AFunc', request => { + request.params; + request.params.anything; + }); + + ParseNode.Cloud.job('AJob', request => { + request.params; + request.message('Message to associate with this job run'); + }); + + void Parse.Cloud.startJob('AJob', {}).then(v => v); + + void Parse.Cloud.getJobStatus('AJob').then(v => v); + + void Parse.Cloud.getJobsData().then(v => v); + + // @ts-expect-error - define should not exist on browser Parse.Cloud + Parse.Cloud.define('test', () => {}); + // @ts-expect-error - beforeSave should not exist on browser Parse.Cloud + Parse.Cloud.beforeSave('Test', () => {}); + // @ts-expect-error - job should not exist on browser Parse.Cloud + Parse.Cloud.job('test', () => {}); + // @ts-expect-error - httpRequest should not exist on browser Parse.Cloud + void Parse.Cloud.httpRequest({ url: '' }); } class PlaceObject extends Parse.Object {} @@ -2257,222 +2275,3 @@ function LiveQueryEvents() { } } -// Test server-side Cloud Code types (only available in parse/node) -function test_cloud_server_functions() { - // ============================================================================ - // Cloud.define Tests - // ============================================================================ - - // Basic define with request properties - ParseNode.Cloud.define('basicFunc', (request) => { - request.params; - request.user; - request.master; - request.ip; - request.headers; - request.functionName; - request.context; - return 'result'; - }); - - // Define with validator options - ParseNode.Cloud.define('validatedFunc', (request) => {}, { - requireUser: true, - requireMaster: false, - validateMasterKey: false, - skipWithMasterKey: true, - requireAnyUserRoles: ['Admin', 'Moderator'], - requireAllUserRoles: ['User'], - fields: { - name: { type: String, required: true }, - age: { type: Number, default: 0 } - } - }); - - // ============================================================================ - // Object Lifecycle Triggers - // ============================================================================ - - // beforeSave with request properties - ParseNode.Cloud.beforeSave('TestClass', (request) => { - request.object; - request.original; - request.user; - request.master; - request.context; - request.isChallenge; - request.ip; - request.headers; - request.triggerName; - }); - - // afterSave - ParseNode.Cloud.afterSave('TestClass', (request) => { - const obj = request.object; - const original = request.original; - const context = request.context; - }); - - // beforeDelete - ParseNode.Cloud.beforeDelete('TestClass', (request) => { - return Promise.resolve(); - }); - - // afterDelete - ParseNode.Cloud.afterDelete('TestClass', (request) => { - return Promise.resolve(); - }); - - // ============================================================================ - // Query Triggers - // ============================================================================ - - // beforeFind with ReadPreferenceOption - ParseNode.Cloud.beforeFind('TestClass', (request) => { - request.query; - request.isGet; - request.count; - request.readPreference; - request.context; - - // Test ReadPreferenceOption enum - const primary = ParseNode.Cloud.ReadPreferenceOption.Primary; - const primaryPreferred = ParseNode.Cloud.ReadPreferenceOption.PrimaryPreferred; - const secondary = ParseNode.Cloud.ReadPreferenceOption.Secondary; - const secondaryPreferred = ParseNode.Cloud.ReadPreferenceOption.SecondaryPreferred; - const nearest = ParseNode.Cloud.ReadPreferenceOption.Nearest; - }); - - // afterFind - ParseNode.Cloud.afterFind('TestClass', (request) => { - request.query; - request.results; - return request.results; - }); - - // ============================================================================ - // Auth Triggers - // ============================================================================ - - // beforeLogin - ParseNode.Cloud.beforeLogin((request) => { - request.object; - request.user; - }); - - // afterLogin - ParseNode.Cloud.afterLogin((request) => { - return Promise.resolve(); - }); - - // afterLogout - ParseNode.Cloud.afterLogout((request) => { - return Promise.resolve(); - }); - - // beforePasswordResetRequest - ParseNode.Cloud.beforePasswordResetRequest((request) => { - request.object; - }); - - // ============================================================================ - // File Triggers - // ============================================================================ - - // beforeSaveFile - ParseNode.Cloud.beforeSaveFile((request) => { - request.file; - request.fileSize; - request.contentLength; - request.user; - request.master; - }); - - // afterSaveFile - ParseNode.Cloud.afterSaveFile((request) => {}); - - // beforeDeleteFile - ParseNode.Cloud.beforeDeleteFile((request) => {}); - - // afterDeleteFile - ParseNode.Cloud.afterDeleteFile((request) => {}); - - // ============================================================================ - // LiveQuery Triggers - // ============================================================================ - - // beforeConnect - ParseNode.Cloud.beforeConnect((request) => { - request.useMasterKey; - request.user; - request.clients; - request.subscriptions; - request.sessionToken; - }); - - // beforeSubscribe - ParseNode.Cloud.beforeSubscribe('TestClass', (request) => { - request.object; - request.user; - }); - - // afterLiveQueryEvent - ParseNode.Cloud.afterLiveQueryEvent('TestClass', (request) => { - request.event; - request.object; - request.original; - request.sendEvent; - request.clients; - request.subscriptions; - }); - - // ============================================================================ - // Job Tests - // ============================================================================ - - ParseNode.Cloud.job('comprehensiveJob', (request) => { - request.params; - request.message('Processing step 1...'); - request.config; - }); - - // ============================================================================ - // Utility Functions - // ============================================================================ - - // httpRequest - void ParseNode.Cloud.httpRequest({ - url: 'https://example.com', - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: { key: 'value' }, - followRedirects: true - }).then((response) => { - response.status; - response.data; - response.text; - response.headers; - }); - - // sendEmail - void ParseNode.Cloud.sendEmail({ - to: 'test@example.com', - from: 'noreply@example.com', - subject: 'Test', - text: 'Hello', - html: '

Hello

' - }); - - // ============================================================================ - // Browser Exclusion Tests - these should NOT compile on browser Parse - // ============================================================================ - - // @ts-expect-error - define should not exist on browser Parse.Cloud - Parse.Cloud.define('test', () => {}); - // @ts-expect-error - beforeSave should not exist on browser Parse.Cloud - Parse.Cloud.beforeSave('Test', () => {}); - // @ts-expect-error - job should not exist on browser Parse.Cloud - Parse.Cloud.job('test', () => {}); - // @ts-expect-error - httpRequest should not exist on browser Parse.Cloud - void Parse.Cloud.httpRequest({ url: '' }); -} From 469b4db78cbc5afe58ae2811cd3660e7e496957f Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Thu, 8 Jan 2026 21:43:44 +0100 Subject: [PATCH 08/10] fix: Add missing JSDoc params for sendEmail function --- src/CloudCode.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/CloudCode.ts b/src/CloudCode.ts index 08bf56658..5ce768c67 100644 --- a/src/CloudCode.ts +++ b/src/CloudCode.ts @@ -577,7 +577,12 @@ export declare function afterLiveQueryEvent * * **Available in Cloud Code only.** * - * @param data The email data including to, from, subject, text, and html. + * @param data The email data. + * @param data.from The sender email address. + * @param data.to The recipient email address. + * @param data.subject The email subject. + * @param data.text The plain text content. + * @param data.html The HTML content. */ export declare function sendEmail(data: { from?: string; From 685cf2d3c2e2dc0e99c279a3e22af3fe7e259509 Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Thu, 8 Jan 2026 21:51:39 +0100 Subject: [PATCH 09/10] chore: Regenerate type definitions --- types/CloudCode.d.ts | 435 +++++++++++++++++++++++-------------------- 1 file changed, 233 insertions(+), 202 deletions(-) diff --git a/types/CloudCode.d.ts b/types/CloudCode.d.ts index eabd0a42c..b698a29ad 100644 --- a/types/CloudCode.d.ts +++ b/types/CloudCode.d.ts @@ -2,6 +2,13 @@ import type ParseObject from './ParseObject'; import type ParseUser from './ParseUser'; import type ParseFile from './ParseFile'; import type ParseQuery from './ParseQuery'; +/** + * @typedef Parse.Cloud.FunctionRequest + * @property {string} installationId If set, the installationId triggering the request. + * @property {boolean} master If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {object} params The params passed to the cloud function. + */ export interface FunctionRequest> { installationId?: string; master: boolean; @@ -20,6 +27,18 @@ export interface FunctionResponse { status: (code: number) => FunctionResponse; header: (name: string, value: string) => FunctionResponse; } +/** + * @typedef Parse.Cloud.TriggerRequest + * @property {string} installationId If set, the installationId triggering the request. + * @property {boolean} master If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {Parse.Object} object The object triggering the hook. + * @property {string} ip The IP address of the client making the request. + * @property {object} headers The original HTTP headers for the request. + * @property {string} triggerName The name of the trigger (`beforeSave`, `afterSave`, ...) + * @property {object} log The current logger inside Parse Server. + * @property {Parse.Object} original If set, the object, as currently stored. + */ export interface TriggerRequest { installationId?: string; master: boolean; @@ -66,6 +85,17 @@ export interface AfterFindRequest { config: any; context: Record; } +/** + * @typedef Parse.Cloud.FileTriggerRequest + * @property {string} installationId If set, the installationId triggering the request. + * @property {boolean} master If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {Parse.File} file The file triggering the hook. + * @property {string} ip The IP address of the client making the request. + * @property {object} headers The original HTTP headers for the request. + * @property {string} triggerName The name of the trigger (`beforeSaveFile`, `afterSaveFile`, ...) + * @property {object} log The current logger inside Parse Server. + */ export interface FileTriggerRequest { installationId?: string; master: boolean; @@ -79,6 +109,15 @@ export interface FileTriggerRequest { log: any; config: any; } +/** + * @typedef Parse.Cloud.ConnectTriggerRequest + * @property {string} installationId If set, the installationId triggering the request. + * @property {boolean} useMasterKey If true, means the master key was used. + * @property {Parse.User} user If set, the user that made the request. + * @property {number} clients The number of clients connected. + * @property {number} subscriptions The number of subscriptions connected. + * @property {string} sessionToken If set, the session of the user that made the request. + */ export interface ConnectTriggerRequest { installationId?: string; useMasterKey: boolean; @@ -99,6 +138,11 @@ export interface LiveQueryEventTrigger { subscriptions: number; sendEvent: boolean; } +/** + * @typedef Parse.Cloud.JobRequest + * @property {object} params The params passed to the background job. + * @property {Function} message If message is called with a string argument, will update the current message to be stored in the job status. + */ export interface JobRequest { params: Record; message: (message: string) => void; @@ -131,6 +175,15 @@ export interface ValidatorObject { includeMasterKey?: boolean; }; } +/** + * @typedef Parse.Cloud.HTTPOptions + * @property {string | object} body The body of the request. + * @property {boolean} followRedirects Whether to follow redirects caused by HTTP 3xx responses. Defaults to false. + * @property {object} headers The headers for the request. + * @property {string} method The method of the request. GET, POST, PUT, DELETE, HEAD, and OPTIONS are supported. + * @property {string | object} params The query portion of the url. + * @property {string} url The url to send the request to. + */ export interface HTTPOptions { body?: string | object; error?: (response: HTTPResponse) => void; @@ -141,6 +194,15 @@ export interface HTTPOptions { success?: (response: HTTPResponse) => void; url: string; } +/** + * @typedef Parse.Cloud.HTTPResponse + * @property {Buffer} buffer The raw byte representation of the response body. + * @property {object} cookies The cookies sent by the server. + * @property {object} data The parsed response body as a JavaScript object. + * @property {object} headers The headers sent by the server. + * @property {number} status The status code. + * @property {string} text The raw text representation of the response body. + */ export interface HTTPResponse { buffer?: Buffer; cookies?: Record; @@ -156,93 +218,79 @@ export declare enum ReadPreferenceOption { SecondaryPreferred = "SECONDARY_PREFERRED", Nearest = "NEAREST" } -export declare function define = Record>(name: string, handler: (request: FunctionRequest) => any, validator?: ValidatorObject | ((request: FunctionRequest) => any)): void; -export declare function job(name: string, handler: (request: JobRequest) => any): void; -export declare function beforeSave(className: string | (new () => T), handler: (request: BeforeSaveRequest) => T | undefined | Promise, validator?: ValidatorObject | ((request: BeforeSaveRequest) => any)): void; -export declare function afterSave(className: string | (new () => T), handler: (request: AfterSaveRequest) => Promise | undefined, validator?: ValidatorObject | ((request: AfterSaveRequest) => any)): void; -export declare function beforeDelete(className: string | (new () => T), handler: (request: BeforeDeleteRequest) => Promise | undefined, validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any)): void; -export declare function afterDelete(className: string | (new () => T), handler: (request: AfterDeleteRequest) => Promise | undefined, validator?: ValidatorObject | ((request: AfterDeleteRequest) => any)): void; -export declare function beforeFind(className: string | (new () => T), handler: (request: BeforeFindRequest) => ParseQuery | undefined | Promise | undefined>, validator?: ValidatorObject | ((request: BeforeFindRequest) => any)): void; -export declare function afterFind(className: string | (new () => T), handler: (request: AfterFindRequest) => T[] | undefined | Promise, validator?: ValidatorObject | ((request: AfterFindRequest) => any)): void; -export declare function beforeLogin(handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; -export declare function afterLogin(handler: (request: TriggerRequest) => Promise | undefined): void; -export declare function afterLogout(handler: (request: TriggerRequest) => Promise | undefined): void; -export declare function beforePasswordResetRequest(handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; -export declare function beforeSaveFile(handler: (request: FileTriggerRequest) => ParseFile | undefined | Promise): void; -export declare function afterSaveFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; -export declare function beforeDeleteFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; -export declare function afterDeleteFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; -export declare function beforeConnect(handler: (request: ConnectTriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any)): void; -export declare function beforeSubscribe(className: string | (new () => T), handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; -export declare function afterLiveQueryEvent(className: string | (new () => T), handler: (request: LiveQueryEventTrigger) => Promise | undefined, validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any)): void; -export declare function sendEmail(data: { - from?: string; - to: string; - subject?: string; - text?: string; - html?: string; -}): Promise; -export declare function httpRequest(options: HTTPOptions): Promise; /** * Defines a Cloud Function. * * **Available in Cloud Code only.** * - * @function define - * @name Parse.Cloud.define - * @param {string} name The name of the Cloud Function - * @param {Function} data The Cloud Function to register. This function should take one parameter {@link Parse.Cloud.FunctionRequest} + * @param name The name of the Cloud Function + * @param handler The Cloud Function to register. This function should take one parameter {@link FunctionRequest} + * @param validator An optional function to validate the request */ +export declare function define = Record>(name: string, handler: (request: FunctionRequest) => any, validator?: ValidatorObject | ((request: FunctionRequest) => any)): void; /** - * Registers an after delete function. + * Defines a Background Job. + * + * **Available in Cloud Code only.** + * + * @param name The name of the Background Job + * @param handler The Background Job to register. This function should take one parameter {@link JobRequest} + */ +export declare function job(name: string, handler: (request: JobRequest) => any): void; +/** + * Registers a before save function. * * **Available in Cloud Code only.** * - * If you want to use afterDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. + * If you want to use beforeSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), + * you should pass the class itself and not the String for arg1. + * * ``` - * Parse.Cloud.afterDelete('MyCustomClass', (request) => { + * Parse.Cloud.beforeSave('MyCustomClass', (request) => { * // code here * }) * - * Parse.Cloud.afterDelete(Parse.User, (request) => { + * Parse.Cloud.beforeSave(Parse.User, (request) => { * // code here * }) - *``` + * ``` * - * @function afterDelete - * @name Parse.Cloud.afterDelete - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the after delete function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run after a delete. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param className The Parse.Object subclass to register the before save function for. + * @param handler The function to run before a save. + * @param validator An optional function to validate the request */ +export declare function beforeSave(className: string | (new () => T), handler: (request: BeforeSaveRequest) => T | undefined | Promise, validator?: ValidatorObject | ((request: BeforeSaveRequest) => any)): void; /** - * * Registers an after save function. * * **Available in Cloud Code only.** * - * If you want to use afterSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. + * If you want to use afterSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), + * you should pass the class itself and not the String for arg1. * * ``` - * Parse.Cloud.afterSave('MyCustomClass', function(request) { + * Parse.Cloud.afterSave('MyCustomClass', (request) => { * // code here * }) * - * Parse.Cloud.afterSave(Parse.User, function(request) { + * Parse.Cloud.afterSave(Parse.User, (request) => { * // code here * }) * ``` * - * @function afterSave - * @name Parse.Cloud.afterSave - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the after save function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run after a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param className The Parse.Object subclass to register the after save function for. + * @param handler The function to run after a save. + * @param validator An optional function to validate the request */ +export declare function afterSave(className: string | (new () => T), handler: (request: AfterSaveRequest) => Promise | undefined, validator?: ValidatorObject | ((request: AfterSaveRequest) => any)): void; /** - * Registers an before delete function. + * Registers a before delete function. * * **Available in Cloud Code only.** * - * If you want to use beforeDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. + * If you want to use beforeDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), + * you should pass the class itself and not the String for arg1. + * * ``` * Parse.Cloud.beforeDelete('MyCustomClass', (request) => { * // code here @@ -251,111 +299,145 @@ export declare function httpRequest(options: HTTPOptions): Promise * Parse.Cloud.beforeDelete(Parse.User, (request) => { * // code here * }) - *``` + * ``` * - * @function beforeDelete - * @name Parse.Cloud.beforeDelete - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the before delete function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run before a delete. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param className The Parse.Object subclass to register the before delete function for. + * @param handler The function to run before a delete. + * @param validator An optional function to validate the request */ +export declare function beforeDelete(className: string | (new () => T), handler: (request: BeforeDeleteRequest) => Promise | undefined, validator?: ValidatorObject | ((request: BeforeDeleteRequest) => any)): void; /** - * - * Registers an before save function. + * Registers an after delete function. * * **Available in Cloud Code only.** * - * If you want to use beforeSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1. + * If you want to use afterDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), + * you should pass the class itself and not the String for arg1. * * ``` - * Parse.Cloud.beforeSave('MyCustomClass', (request) => { + * Parse.Cloud.afterDelete('MyCustomClass', (request) => { * // code here * }) * - * Parse.Cloud.beforeSave(Parse.User, (request) => { + * Parse.Cloud.afterDelete(Parse.User, (request) => { * // code here * }) * ``` * - * @function beforeSave - * @name Parse.Cloud.beforeSave - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the after save function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run before a save. This function should take just one parameter, {@link Parse.Cloud.TriggerRequest}. + * @param className The Parse.Object subclass to register the after delete function for. + * @param handler The function to run after a delete. + * @param validator An optional function to validate the request */ +export declare function afterDelete(className: string | (new () => T), handler: (request: AfterDeleteRequest) => Promise | undefined, validator?: ValidatorObject | ((request: AfterDeleteRequest) => any)): void; /** + * Registers a before find function. + * + * **Available in Cloud Code only.** * - * Registers an before save file function. A new Parse.File can be returned to override the file that gets saved. - * If you want to replace the rquesting Parse.File with a Parse.File that is already saved, simply return the already saved Parse.File. - * You can also add metadata to the file that will be stored via whatever file storage solution you're using. + * @param className The Parse.Object subclass to register the before find function for. + * @param handler The function to run before a find. + * @param validator An optional function to validate the request + */ +export declare function beforeFind(className: string | (new () => T), handler: (request: BeforeFindRequest) => ParseQuery | undefined | Promise | undefined>, validator?: ValidatorObject | ((request: BeforeFindRequest) => any)): void; +/** + * Registers an after find function. * * **Available in Cloud Code only.** * - * Example: Adding metadata and tags - * ``` - * Parse.Cloud.beforeSaveFile(({ file, user }) => { - * file.addMetadata('foo', 'bar'); - * file.addTag('createdBy', user.id); - * }); + * @param className The Parse.Object subclass to register the after find function for. + * @param handler The function to run after a find. + * @param validator An optional function to validate the request + */ +export declare function afterFind(className: string | (new () => T), handler: (request: AfterFindRequest) => T[] | undefined | Promise, validator?: ValidatorObject | ((request: AfterFindRequest) => any)): void; +/** + * Registers a before login function. * - * ``` + * **Available in Cloud Code only.** + * + * @param handler The function to run before a login. + * @param validator An optional function to validate the request + */ +export declare function beforeLogin(handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +/** + * Registers an after login function. * - * Example: replacing file with an already saved file + * **Available in Cloud Code only.** * - * ``` - * Parse.Cloud.beforeSaveFile(({ file, user }) => { - * return user.get('avatar'); - * }); + * @param handler The function to run after a login. + */ +export declare function afterLogin(handler: (request: TriggerRequest) => Promise | undefined): void; +/** + * Registers an after logout function. * - * ``` + * **Available in Cloud Code only.** + * + * @param handler The function to run after a logout. + */ +export declare function afterLogout(handler: (request: TriggerRequest) => Promise | undefined): void; +/** + * Registers a before password reset request function. + * + * **Available in Cloud Code only.** * - * Example: replacing file with a different file + * @param handler The function to run before a password reset request. + * @param validator An optional function to validate the request + */ +export declare function beforePasswordResetRequest(handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +/** + * Registers a before save file function. + * + * **Available in Cloud Code only.** + * + * A new Parse.File can be returned to override the file that gets saved. * * ``` * Parse.Cloud.beforeSaveFile(({ file, user }) => { - * const metadata = { foo: 'bar' }; - * const tags = { createdBy: user.id }; - * const newFile = new Parse.File(file.name(), , 'text/plain', metadata, tags); - * return newFile; + * file.addMetadata('foo', 'bar'); + * file.addTag('createdBy', user.id); * }); - * * ``` * - * @function beforeSaveFile - * @name Parse.Cloud.beforeSaveFile - * @param {Function} func The function to run before a file saves. This function should take one parameter, a {@link Parse.Cloud.FileTriggerRequest}. + * @param handler The function to run before a file saves. */ +export declare function beforeSaveFile(handler: (request: FileTriggerRequest) => ParseFile | undefined | Promise): void; /** - * * Registers an after save file function. * * **Available in Cloud Code only.** * - * Example: creating a new object that references this file in a separate collection * ``` * Parse.Cloud.afterSaveFile(async ({ file, user }) => { * const fileObject = new Parse.Object('FileObject'); - * fileObject.set('metadata', file.metadata()); - * fileObject.set('tags', file.tags()); * fileObject.set('name', file.name()); * fileObject.set('createdBy', user); * await fileObject.save({ sessionToken: user.getSessionToken() }); * }); + * ``` * - * @method afterSaveFile - * @name Parse.Cloud.afterSaveFile - * @param {Function} func The function to run after a file saves. This function should take one parameter, a {@link Parse.Cloud.FileTriggerRequest}. + * @param handler The function to run after a file saves. */ +export declare function afterSaveFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; /** - * @function beforeConnect - * @name Parse.Cloud.beforeConnect - * @param {Function} func The function to before connection is made. This function can be async and should take just one parameter, {@link Parse.Cloud.ConnectTriggerRequest}. + * Registers a before delete file function. + * + * **Available in Cloud Code only.** + * + * @param handler The function to run before a file is deleted. */ +export declare function beforeDeleteFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; /** + * Registers an after delete file function. + * + * **Available in Cloud Code only.** * - * Registers a before connect function. + * @param handler The function to run after a file is deleted. + */ +export declare function afterDeleteFile(handler: (request: FileTriggerRequest) => Promise | undefined): void; +/** + * Registers a before connect function for LiveQuery. * * **Available in Cloud Code only.** * - * Example: restrict LiveQueries to logged in users. * ``` * Parse.Cloud.beforeConnect((request) => { * if (!request.user) { @@ -363,130 +445,79 @@ export declare function httpRequest(options: HTTPOptions): Promise * } * }); * ``` + * + * @param handler The function to run before a LiveQuery connection is made. + * @param validator An optional function to validate the request */ +export declare function beforeConnect(handler: (request: ConnectTriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: ConnectTriggerRequest) => any)): void; /** - * @function beforeSubscribe - * @name Parse.Cloud.beforeSubscribe - * @param {(string | Parse.Object)} arg1 The Parse.Object subclass to register the before subscription function for. This can instead be a String that is the className of the subclass. - * @param {Function} func The function to run before a subscription. This function can be async and should take one parameter, a {@link Parse.Cloud.TriggerRequest}. - */ -/** - * - * Registers a before subscribe function. + * Registers a before subscribe function for LiveQuery. * * **Available in Cloud Code only.** - * Example: restrict subscriptions to MyObject to Admin accounts only. + * * ``` - * Parse.Cloud.beforeSubscribe('MyObject', (request) => { + * Parse.Cloud.beforeSubscribe('MyObject', (request) => { * if (!request.user.get('Admin')) { - * throw new Parse.Error(101, 'You are not authorized to subscribe to MyObject.'); + * throw new Parse.Error(101, 'You are not authorized to subscribe to MyObject.'); * } - * let query = request.query; // the Parse.Query - * query.select("name","year") + * let query = request.query; + * query.select("name", "year"); * }); * ``` + * + * @param className The Parse.Object subclass to register the before subscribe function for. + * @param handler The function to run before a subscription. + * @param validator An optional function to validate the request + */ +export declare function beforeSubscribe(className: string | (new () => T), handler: (request: TriggerRequest) => Promise | undefined, validator?: ValidatorObject | ((request: TriggerRequest) => any)): void; +/** + * Registers an after live query event function. + * + * **Available in Cloud Code only.** + * + * @param className The Parse.Object subclass to register the after live query event function for. + * @param handler The function to run after a live query event. + * @param validator An optional function to validate the request + */ +export declare function afterLiveQueryEvent(className: string | (new () => T), handler: (request: LiveQueryEventTrigger) => Promise | undefined, validator?: ValidatorObject | ((request: LiveQueryEventTrigger) => any)): void; +/** + * Sends an email. + * + * **Available in Cloud Code only.** + * + * @param data The email data. + * @param data.from The sender email address. + * @param data.to The recipient email address. + * @param data.subject The email subject. + * @param data.text The plain text content. + * @param data.html The HTML content. */ +export declare function sendEmail(data: { + from?: string; + to: string; + subject?: string; + text?: string; + html?: string; +}): Promise; /** * Makes an HTTP Request. * * **Available in Cloud Code only.** * - * By default, Parse.Cloud.httpRequest does not follow redirects caused by HTTP 3xx response codes. You can use the followRedirects option in the {@link Parse.Cloud.HTTPOptions} object to change this behavior. + * By default, Parse.Cloud.httpRequest does not follow redirects caused by HTTP 3xx response codes. + * You can use the followRedirects option in the {@link HTTPOptions} object to change this behavior. * - * Sample request: * ``` * Parse.Cloud.httpRequest({ * url: 'http://www.example.com/' * }).then(function(httpResponse) { - * // success * console.log(httpResponse.text); - * },function(httpResponse) { - * // error + * }, function(httpResponse) { * console.error('Request failed with response code ' + httpResponse.status); * }); * ``` * - * @function httpRequest - * @name Parse.Cloud.httpRequest - * @param {Parse.Cloud.HTTPOptions} options The Parse.Cloud.HTTPOptions object that makes the request. - * @returns {Promise} A promise that will be resolved with a {@link Parse.Cloud.HTTPResponse} object when the request completes. - */ -/** - * Defines a Background Job. - * - * **Available in Cloud Code only.** - * - * @function job - * @name Parse.Cloud.job - * @param {string} name The name of the Background Job - * @param {Function} func The Background Job to register. This function should take two parameters a {@link Parse.Cloud.JobRequest} and a {@link Parse.Cloud.JobStatus} - */ -/** - * @typedef Parse.Cloud.TriggerRequest - * @property {string} installationId If set, the installationId triggering the request. - * @property {boolean} master If true, means the master key was used. - * @property {Parse.User} user If set, the user that made the request. - * @property {Parse.Object} object The object triggering the hook. - * @property {string} ip The IP address of the client making the request. - * @property {object} headers The original HTTP headers for the request. - * @property {string} triggerName The name of the trigger (`beforeSave`, `afterSave`, ...) - * @property {object} log The current logger inside Parse Server. - * @property {Parse.Object} original If set, the object, as currently stored. - */ -/** - * @typedef Parse.Cloud.FileTriggerRequest - * @property {string} installationId If set, the installationId triggering the request. - * @property {boolean} master If true, means the master key was used. - * @property {Parse.User} user If set, the user that made the request. - * @property {Parse.File} file The file triggering the hook. - * @property {string} ip The IP address of the client making the request. - * @property {object} headers The original HTTP headers for the request. - * @property {string} triggerName The name of the trigger (`beforeSaveFile`, `afterSaveFile`, ...) - * @property {object} log The current logger inside Parse Server. - */ -/** - * @typedef Parse.Cloud.ConnectTriggerRequest - * @property {string} installationId If set, the installationId triggering the request. - * @property {boolean} useMasterKey If true, means the master key was used. - * @property {Parse.User} user If set, the user that made the request. - * @property {number} clients The number of clients connected. - * @property {number} subscriptions The number of subscriptions connected. - * @property {string} sessionToken If set, the session of the user that made the request. - */ -/** - * @typedef Parse.Cloud.FunctionRequest - * @property {string} installationId If set, the installationId triggering the request. - * @property {boolean} master If true, means the master key was used. - * @property {Parse.User} user If set, the user that made the request. - * @property {object} params The params passed to the cloud function. - */ -/** - * @typedef Parse.Cloud.JobRequest - * @property {object} params The params passed to the background job. - */ -/** - * @typedef Parse.Cloud.JobStatus - * @property {Function} error If error is called, will end the job unsuccessfully with an optional completion message to be stored in the job status. - * @property {Function} message If message is called with a string argument, will update the current message to be stored in the job status. - * @property {Function} success If success is called, will end the job successfullly with the optional completion message to be stored in the job status. - */ -/** - * @typedef Parse.Cloud.HTTPOptions - * @property {string | object} body The body of the request. If it is a JSON object, then the Content-Type set in the headers must be application/x-www-form-urlencoded or application/json. You can also set this to a {@link Buffer} object to send raw bytes. If you use a Buffer, you should also set the Content-Type header explicitly to describe what these bytes represent. - * @property {Function} error The function that is called when the request fails. It will be passed a Parse.Cloud.HTTPResponse object. - * @property {boolean} followRedirects Whether to follow redirects caused by HTTP 3xx responses. Defaults to false. - * @property {object} headers The headers for the request. - * @property {string} method The method of the request. GET, POST, PUT, DELETE, HEAD, and OPTIONS are supported. Will default to GET if not specified. - * @property {string | object} params The query portion of the url. You can pass a JSON object of key value pairs like params: {q : 'Sean Plott'} or a raw string like params:q=Sean Plott. - * @property {Function} success The function that is called when the request successfully completes. It will be passed a Parse.Cloud.HTTPResponse object. - * @property {string} url The url to send the request to. - */ -/** - * @typedef Parse.Cloud.HTTPResponse - * @property {Buffer} buffer The raw byte representation of the response body. Use this to receive binary data. See Buffer for more details. - * @property {object} cookies The cookies sent by the server. The keys in this object are the names of the cookies. The values are Parse.Cloud.Cookie objects. - * @property {object} data The parsed response body as a JavaScript object. This is only available when the response Content-Type is application/x-www-form-urlencoded or application/json. - * @property {object} headers The headers sent by the server. The keys in this object are the names of the headers. We do not support multiple response headers with the same name. In the common case of Set-Cookie headers, please use the cookies field instead. - * @property {number} status The status code. - * @property {string} text The raw text representation of the response body. + * @param options The HTTPOptions object that makes the request. + * @returns A promise that will be resolved with a {@link HTTPResponse} object when the request completes. */ +export declare function httpRequest(options: HTTPOptions): Promise; From 4a2dffea0113165db7b5fc0505ab49fba37573ac Mon Sep 17 00:00:00 2001 From: Joseph Hajjar Date: Wed, 21 Jan 2026 19:28:55 +0100 Subject: [PATCH 10/10] test: Add type tests for LiveQuery triggers, httpRequest, and sendEmail --- types/tests.ts | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/types/tests.ts b/types/tests.ts index 0f1870242..0c242a3af 100644 --- a/types/tests.ts +++ b/types/tests.ts @@ -668,6 +668,64 @@ async function test_cloud_functions() { request.file; }); + ParseNode.Cloud.beforeConnect(request => { + request.user; + request.installationId; + request.useMasterKey; + request.clients; + request.subscriptions; + request.sessionToken; + }); + + ParseNode.Cloud.beforeSubscribe('MyCustomClass', request => { + request.object; + request.user; + request.original; + request.installationId; + }); + + ParseNode.Cloud.afterLiveQueryEvent('MyCustomClass', request => { + request.event; + request.object; + request.original; + request.user; + request.sendEvent; + request.clients; + request.subscriptions; + request.sessionToken; + }); + + ParseNode.Cloud.beforePasswordResetRequest(request => { + request.object; + request.user; + request.master; + request.ip; + request.headers; + }); + + void ParseNode.Cloud.httpRequest({ + url: 'https://example.com', + method: 'GET', + headers: { 'Content-Type': 'application/json' }, + body: { key: 'value' }, + followRedirects: true, + }).then(response => { + response.status; + response.data; + response.text; + response.headers; + response.buffer; + response.cookies; + }); + + void ParseNode.Cloud.sendEmail({ + to: 'test@example.com', + from: 'sender@example.com', + subject: 'Test Subject', + text: 'Plain text content', + html: '

HTML content

', + }); + ParseNode.Cloud.define('AFunc', request => { request.params; return 'Some result'; @@ -731,6 +789,16 @@ async function test_cloud_functions() { Parse.Cloud.job('test', () => {}); // @ts-expect-error - httpRequest should not exist on browser Parse.Cloud void Parse.Cloud.httpRequest({ url: '' }); + // @ts-expect-error - beforeConnect should not exist on browser Parse.Cloud + Parse.Cloud.beforeConnect(() => {}); + // @ts-expect-error - beforeSubscribe should not exist on browser Parse.Cloud + Parse.Cloud.beforeSubscribe('Test', () => {}); + // @ts-expect-error - afterLiveQueryEvent should not exist on browser Parse.Cloud + Parse.Cloud.afterLiveQueryEvent('Test', () => {}); + // @ts-expect-error - beforePasswordResetRequest should not exist on browser Parse.Cloud + Parse.Cloud.beforePasswordResetRequest(() => {}); + // @ts-expect-error - sendEmail should not exist on browser Parse.Cloud + void Parse.Cloud.sendEmail({ to: '' }); } class PlaceObject extends Parse.Object {}