feat: Add TypeScript definitions (#9693)

This commit is contained in:
Diamond Lewis
2025-04-15 06:59:58 -05:00
committed by GitHub
parent 39ef22d5c9
commit e86718fc59
19 changed files with 1482 additions and 36 deletions

View File

@@ -0,0 +1,5 @@
// TODO: Remove when @parse/fs-files-adapter is typed
declare module '@parse/fs-files-adapter' {
const FileSystemAdapter: any;
export default FileSystemAdapter;
}

5
types/@types/deepcopy/index.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
// TODO: Remove when https://github.com/sasaplus1/deepcopy.js/issues/278 is fixed
declare type Customizer = (value: any, valueType: string) => unknown;
declare type Options = Customizer | { customizer: Customizer };
declare function deepcopy<T>(value: T, options?: Options): T;
export default deepcopy;

View File

@@ -0,0 +1,40 @@
import { Auth } from '../Auth';
declare class ParseLiveQueryServer {
server: any;
config: any;
clients: Map<string, any>;
subscriptions: Map<string, any>;
parseWebSocketServer: any;
keyPairs: any;
subscriber: any;
authCache: any;
cacheController: any;
constructor(server: any, config?: any, parseServerConfig?: any);
connect(): Promise<void>;
shutdown(): Promise<void>;
_createSubscribers(): void;
_inflateParseObject(message: any): void;
_onAfterDelete(message: any): Promise<void>;
_onAfterSave(message: any): Promise<void>;
_onConnect(parseWebsocket: any): void;
_matchesSubscription(parseObject: any, subscription: any): boolean;
_clearCachedRoles(userId: string): Promise<void>;
getAuthForSessionToken(sessionToken?: string): Promise<{
auth?: Auth;
userId?: string;
}>;
_matchesCLP(classLevelPermissions?: any, object?: any, client?: any, requestId?: number, op?: string): Promise<any>;
_filterSensitiveData(classLevelPermissions?: any, res?: any, client?: any, requestId?: number, op?: string, query?: any): Promise<void>;
_getCLPOperation(query: any): "get" | "find";
_verifyACL(acl: any, token: string): Promise<boolean>;
getAuthFromClient(client: any, requestId: number, sessionToken?: string): Promise<Auth>;
_checkWatchFields(client: any, requestId: any, message: any): any;
_matchesACL(acl: any, client: any, requestId: number): Promise<boolean>;
_handleConnect(parseWebsocket: any, request: any): Promise<any>;
_hasMasterKey(request: any, validKeyPairs: any): boolean;
_validateKeys(request: any, validKeyPairs: any): boolean;
_handleSubscribe(parseWebsocket: any, request: any): Promise<any>;
_handleUpdateSubscription(parseWebsocket: any, request: any): any;
_handleUnsubscribe(parseWebsocket: any, request: any, notifyClient?: boolean): any;
}
export { ParseLiveQueryServer };

251
types/Options/index.d.ts vendored Normal file
View File

@@ -0,0 +1,251 @@
// This file is manually updated to match src/Options/index.js until typed
import { AnalyticsAdapter } from '../Adapters/Analytics/AnalyticsAdapter';
import { CacheAdapter } from '../Adapters/Cache/CacheAdapter';
import { MailAdapter } from '../Adapters/Email/MailAdapter';
import { FilesAdapter } from '../Adapters/Files/FilesAdapter';
import { LoggerAdapter } from '../Adapters/Logger/LoggerAdapter';
import { PubSubAdapter } from '../Adapters/PubSub/PubSubAdapter';
import { StorageAdapter } from '../Adapters/Storage/StorageAdapter';
import { WSSAdapter } from '../Adapters/WebSocketServer/WSSAdapter';
import { CheckGroup } from '../Security/CheckGroup';
export interface SchemaOptions {
definitions: any;
strict?: boolean;
deleteExtraFields?: boolean;
recreateModifiedFields?: boolean;
lockSchemas?: boolean;
beforeMigration?: () => void | Promise<void>;
afterMigration?: () => void | Promise<void>;
}
type Adapter<T> = string | T;
type NumberOrBoolean = number | boolean;
type NumberOrString = number | string;
type ProtectedFields = any;
type StringOrStringArray = string | string[];
type RequestKeywordDenylist = {
key: string;
value: any;
};
export interface ParseServerOptions {
appId: string;
masterKey: (() => void) | string;
masterKeyTtl?: number;
maintenanceKey: string;
serverURL: string;
masterKeyIps?: (string[]);
maintenanceKeyIps?: (string[]);
appName?: string;
allowHeaders?: (string[]);
allowOrigin?: StringOrStringArray;
analyticsAdapter?: Adapter<AnalyticsAdapter>;
filesAdapter?: Adapter<FilesAdapter>;
push?: any;
scheduledPush?: boolean;
loggerAdapter?: Adapter<LoggerAdapter>;
jsonLogs?: boolean;
logsFolder?: string;
verbose?: boolean;
logLevel?: string;
logLevels?: LogLevels;
maxLogFiles?: NumberOrString;
silent?: boolean;
databaseURI: string;
databaseOptions?: DatabaseOptions;
databaseAdapter?: Adapter<StorageAdapter>;
enableCollationCaseComparison?: boolean;
convertEmailToLowercase?: boolean;
convertUsernameToLowercase?: boolean;
cloud?: string;
collectionPrefix?: string;
clientKey?: string;
javascriptKey?: string;
dotNetKey?: string;
encryptionKey?: string;
restAPIKey?: string;
readOnlyMasterKey?: string;
webhookKey?: string;
fileKey?: string;
preserveFileName?: boolean;
userSensitiveFields?: (string[]);
protectedFields?: ProtectedFields;
enableAnonymousUsers?: boolean;
allowClientClassCreation?: boolean;
allowCustomObjectId?: boolean;
auth?: Record<string, AuthAdapter>;
enableInsecureAuthAdapters?: boolean;
maxUploadSize?: string;
verifyUserEmails?: (boolean | void);
preventLoginWithUnverifiedEmail?: boolean;
preventSignupWithUnverifiedEmail?: boolean;
emailVerifyTokenValidityDuration?: number;
emailVerifyTokenReuseIfValid?: boolean;
sendUserEmailVerification?: (boolean | void);
accountLockout?: AccountLockoutOptions;
passwordPolicy?: PasswordPolicyOptions;
cacheAdapter?: Adapter<CacheAdapter>;
emailAdapter?: Adapter<MailAdapter>;
encodeParseObjectInCloudFunction?: boolean;
publicServerURL?: string;
pages?: PagesOptions;
customPages?: CustomPagesOptions;
liveQuery?: LiveQueryOptions;
sessionLength?: number;
extendSessionOnUse?: boolean;
defaultLimit?: number;
maxLimit?: number;
expireInactiveSessions?: boolean;
revokeSessionOnPasswordReset?: boolean;
cacheTTL?: number;
cacheMaxSize?: number;
directAccess?: boolean;
enableExpressErrorHandler?: boolean;
objectIdSize?: number;
port?: number;
host?: string;
mountPath?: string;
cluster?: NumberOrBoolean;
middleware?: ((() => void) | string);
trustProxy?: any;
startLiveQueryServer?: boolean;
liveQueryServerOptions?: LiveQueryServerOptions;
idempotencyOptions?: IdempotencyOptions;
fileUpload?: FileUploadOptions;
graphQLSchema?: string;
mountGraphQL?: boolean;
graphQLPath?: string;
mountPlayground?: boolean;
playgroundPath?: string;
schema?: SchemaOptions;
serverCloseComplete?: () => void;
security?: SecurityOptions;
enforcePrivateUsers?: boolean;
allowExpiredAuthDataToken?: boolean;
requestKeywordDenylist?: (RequestKeywordDenylist[]);
rateLimit?: (RateLimitOptions[]);
}
export interface RateLimitOptions {
requestPath: string;
requestTimeWindow?: number;
requestCount?: number;
errorResponseMessage?: string;
requestMethods?: (string[]);
includeMasterKey?: boolean;
includeInternalRequests?: boolean;
redisUrl?: string;
zone?: string;
}
export interface SecurityOptions {
enableCheck?: boolean;
enableCheckLog?: boolean;
checkGroups?: (CheckGroup[]);
}
export interface PagesOptions {
enableRouter?: boolean;
enableLocalization?: boolean;
localizationJsonPath?: string;
localizationFallbackLocale?: string;
placeholders?: any;
forceRedirect?: boolean;
pagesPath?: string;
pagesEndpoint?: string;
customUrls?: PagesCustomUrlsOptions;
customRoutes?: (PagesRoute[]);
}
export interface PagesRoute {
path: string;
method: string;
handler: () => void;
}
export interface PagesCustomUrlsOptions {
passwordReset?: string;
passwordResetLinkInvalid?: string;
passwordResetSuccess?: string;
emailVerificationSuccess?: string;
emailVerificationSendFail?: string;
emailVerificationSendSuccess?: string;
emailVerificationLinkInvalid?: string;
emailVerificationLinkExpired?: string;
}
export interface CustomPagesOptions {
invalidLink?: string;
linkSendFail?: string;
choosePassword?: string;
linkSendSuccess?: string;
verifyEmailSuccess?: string;
passwordResetSuccess?: string;
invalidVerificationLink?: string;
expiredVerificationLink?: string;
invalidPasswordResetLink?: string;
parseFrameURL?: string;
}
export interface LiveQueryOptions {
classNames?: (string[]);
redisOptions?: any;
redisURL?: string;
pubSubAdapter?: Adapter<PubSubAdapter>;
wssAdapter?: Adapter<WSSAdapter>;
}
export interface LiveQueryServerOptions {
appId?: string;
masterKey?: string;
serverURL?: string;
keyPairs?: any;
websocketTimeout?: number;
cacheTimeout?: number;
logLevel?: string;
port?: number;
redisOptions?: any;
redisURL?: string;
pubSubAdapter?: Adapter<PubSubAdapter>;
wssAdapter?: Adapter<WSSAdapter>;
}
export interface IdempotencyOptions {
paths?: (string[]);
ttl?: number;
}
export interface AccountLockoutOptions {
duration?: number;
threshold?: number;
unlockOnPasswordReset?: boolean;
}
export interface PasswordPolicyOptions {
validatorPattern?: string;
validatorCallback?: () => void;
validationError?: string;
doNotAllowUsername?: boolean;
maxPasswordAge?: number;
maxPasswordHistory?: number;
resetTokenValidityDuration?: number;
resetTokenReuseIfValid?: boolean;
resetPasswordSuccessOnInvalidEmail?: boolean;
}
export interface FileUploadOptions {
fileExtensions?: (string[]);
enableForAnonymousUser?: boolean;
enableForAuthenticatedUser?: boolean;
enableForPublic?: boolean;
}
export interface DatabaseOptions {
enableSchemaHooks?: boolean;
schemaCacheTtl?: number;
retryWrites?: boolean;
maxTimeMS?: number;
maxStalenessSeconds?: number;
minPoolSize?: number;
maxPoolSize?: number;
connectTimeoutMS?: number;
socketTimeoutMS?: number;
autoSelectFamily?: boolean;
autoSelectFamilyAttemptTimeout?: number;
}
export interface AuthAdapter {
enabled?: boolean;
}
export interface LogLevels {
triggerAfter?: string;
triggerBeforeSuccess?: string;
triggerBeforeError?: string;
cloudFunctionSuccess?: string;
cloudFunctionError?: string;
}
export {};

60
types/ParseServer.d.ts vendored Normal file
View File

@@ -0,0 +1,60 @@
import { ParseServerOptions, LiveQueryServerOptions } from './Options';
import { ParseLiveQueryServer } from './LiveQuery/ParseLiveQueryServer';
declare class ParseServer {
_app: any;
config: any;
server: any;
expressApp: any;
liveQueryServer: any;
/**
* @constructor
* @param {ParseServerOptions} options the parse server initialization options
*/
constructor(options: ParseServerOptions);
/**
* Starts Parse Server as an express app; this promise resolves when Parse Server is ready to accept requests.
*/
start(): Promise<this>;
get app(): any;
/**
* Stops the parse server, cancels any ongoing requests and closes all connections.
*
* Currently, express doesn't shut down immediately after receiving SIGINT/SIGTERM
* if it has client connections that haven't timed out.
* (This is a known issue with node - https://github.com/nodejs/node/issues/2642)
*
* @returns {Promise<void>} a promise that resolves when the server is stopped
*/
handleShutdown(): Promise<void>;
/**
* @static
* Create an express app for the parse server
* @param {Object} options let you specify the maxUploadSize when creating the express app */
static app(options: any): any;
static promiseRouter({ appId }: {
appId: any;
}): any;
/**
* starts the parse server's express app
* @param {ParseServerOptions} options to use to start the server
* @returns {ParseServer} the parse server instance
*/
startApp(options: ParseServerOptions): Promise<this>;
/**
* Creates a new ParseServer and starts it.
* @param {ParseServerOptions} options used to start the server
* @returns {ParseServer} the parse server instance
*/
static startApp(options: ParseServerOptions): Promise<ParseServer>;
/**
* Helper method to create a liveQuery server
* @static
* @param {Server} httpServer an optional http server to pass
* @param {LiveQueryServerOptions} config options for the liveQueryServer
* @param {ParseServerOptions} options options for the ParseServer
* @returns {Promise<ParseLiveQueryServer>} the live query server instance
*/
static createLiveQueryServer(httpServer: any, config: LiveQueryServerOptions, options: ParseServerOptions): Promise<ParseLiveQueryServer>;
static verifyServerUrl(): any;
}
export default ParseServer;

30
types/eslint.config.mjs Normal file
View File

@@ -0,0 +1,30 @@
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import expectType from 'eslint-plugin-expect-type/configs/recommended';
export default tseslint.config({
files: ['**/*.js', '**/*.ts'],
extends: [
expectType,
eslint.configs.recommended,
...tseslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
],
plugins: {
'@typescript-eslint': tseslint.plugin,
},
rules: {
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-return": "off",
},
languageOptions: {
parser: tseslint.parser,
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
});

21
types/index.d.ts vendored
View File

@@ -0,0 +1,21 @@
import ParseServer from './ParseServer';
import FileSystemAdapter from '@parse/fs-files-adapter';
import InMemoryCacheAdapter from './Adapters/Cache/InMemoryCacheAdapter';
import NullCacheAdapter from './Adapters/Cache/NullCacheAdapter';
import RedisCacheAdapter from './Adapters/Cache/RedisCacheAdapter';
import LRUCacheAdapter from './Adapters/Cache/LRUCache.js';
import * as TestUtils from './TestUtils';
import * as SchemaMigrations from './SchemaMigrations/Migrations';
import AuthAdapter from './Adapters/Auth/AuthAdapter';
import { PushWorker } from './Push/PushWorker';
import { ParseServerOptions } from './Options';
import { ParseGraphQLServer } from './GraphQL/ParseGraphQLServer';
declare const _ParseServer: {
(options: ParseServerOptions): ParseServer;
createLiveQueryServer: typeof ParseServer.createLiveQueryServer;
startApp: typeof ParseServer.startApp;
};
declare const S3Adapter: any;
declare const GCSAdapter: any;
export default ParseServer;
export { S3Adapter, GCSAdapter, FileSystemAdapter, InMemoryCacheAdapter, NullCacheAdapter, RedisCacheAdapter, LRUCacheAdapter, TestUtils, PushWorker, ParseGraphQLServer, _ParseServer as ParseServer, SchemaMigrations, AuthAdapter, };

44
types/tests.ts Normal file
View File

@@ -0,0 +1,44 @@
import ParseServer, { FileSystemAdapter } from 'parse-server';
async function server() {
// $ExpectType ParseServer
const parseServer = await ParseServer.startApp({});
// $ExpectType void
await parseServer.handleShutdown();
// $ExpectType any
parseServer.app;
// $ExpectType any
ParseServer.app({});
// $ExpectType any
ParseServer.promiseRouter({ appId: 'appId' });
// $ExpectType ParseLiveQueryServer
await ParseServer.createLiveQueryServer({}, {}, {});
// $ExpectType any
ParseServer.verifyServerUrl();
// $ExpectError
await ParseServer.startApp();
// $ExpectError
ParseServer.promiseRouter();
// $ExpectError
await ParseServer.createLiveQueryServer();
// $ExpectType ParseServer
const parseServer2 = new ParseServer({});
// $ExpectType ParseServer
await parseServer2.start();
}
function exports() {
// $ExpectType any
FileSystemAdapter;
}

View File

@@ -13,6 +13,12 @@
// If the library is an external module (uses `export`), this allows your test file to import "mylib" instead of "./index".
// If the library is global (cannot be imported via `import` or `require`), leave this out.
"baseUrl": ".",
"paths": { "parse": ["."] }
}
"paths": {
"parse-server": ["."],
"@parse/fs-files-adapter": ["./@types/@parse/fs-files-adapter"],
}
},
"include": [
"tests.ts"
]
}