diff --git a/lib/DboBuilder/DboBuilder.ts b/lib/DboBuilder/DboBuilder.ts index 8fb8b216..10bb2256 100644 --- a/lib/DboBuilder/DboBuilder.ts +++ b/lib/DboBuilder/DboBuilder.ts @@ -11,8 +11,7 @@ import { } from "prostgles-types"; import { getDBSchema } from "../DBSchemaBuilder"; import { - DB, - Join, Prostgles + DB, Prostgles } from "../Prostgles"; import { PubSubManager } from "../PubSubManager/PubSubManager"; import { @@ -30,7 +29,7 @@ import { PGConstraint, getCanExecute, getConstraints, getSerializedClientErrorFr import { getTablesForSchemaPostgresSQL } from "./getTablesForSchemaPostgresSQL"; import { prepareShortestJoinPaths } from "./prepareShortestJoinPaths"; import { runSQL } from "./runSQL"; -import { PostgresNotifListenManager } from "../PostgresNotifListenManager"; +import { Join } from "../ProstglesTypes"; export * from "./DboBuilderTypes"; export * from "./dboBuilderUtils"; diff --git a/lib/DboBuilder/ViewHandler/ViewHandler.ts b/lib/DboBuilder/ViewHandler/ViewHandler.ts index c3ccf4ac..33ddb757 100644 --- a/lib/DboBuilder/ViewHandler/ViewHandler.ts +++ b/lib/DboBuilder/ViewHandler/ViewHandler.ts @@ -8,7 +8,7 @@ import { isObject } from "prostgles-types"; import { TableEvent } from "../../Logging"; -import { DB, Join } from "../../Prostgles"; +import { DB } from "../../Prostgles"; import { TableRule } from "../../PublishParser/PublishParser"; import { Graph } from "../../shortestPath"; import { @@ -31,6 +31,7 @@ import { prepareWhere } from "./prepareWhere"; import { size } from "./size"; import { LocalFuncs, subscribe } from "./subscribe"; import { validateViewRules } from "./validateViewRules"; +import { Join } from "../../ProstglesTypes"; export type JoinPaths = { t1: string; diff --git a/lib/DboBuilder/dboBuilderUtils.ts b/lib/DboBuilder/dboBuilderUtils.ts index 581c4339..756f5e2b 100644 --- a/lib/DboBuilder/dboBuilderUtils.ts +++ b/lib/DboBuilder/dboBuilderUtils.ts @@ -14,7 +14,6 @@ import { } from "prostgles-types"; import { DB, - ProstglesInitOptions } from "../Prostgles"; import { pickKeys } from "../PubSubManager/PubSubManager"; import { LocalParams, SortItem, pgp } from "./DboBuilderTypes"; @@ -23,6 +22,7 @@ import { ViewHandler } from "./ViewHandler/ViewHandler"; import { getSchemaFilter } from "./getTablesForSchemaPostgresSQL"; import { sqlErrCodeToMsg } from "./sqlErrCodeToMsg"; +import { ProstglesInitOptions } from "../ProstglesTypes"; export function escapeTSNames(str: string, capitalize = false): string { let res = str; res = (capitalize ? str[0]?.toUpperCase() : str[0]) + str.slice(1); diff --git a/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts b/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts index 8059ad59..f53e0bcf 100644 --- a/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +++ b/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts @@ -1,9 +1,10 @@ import { SQLResult, asName } from "prostgles-types"; import { omitKeys, tryCatch } from "prostgles-types/dist/util"; import { DboBuilder } from "../DboBuilder/DboBuilder"; -import { DBorTx, ProstglesInitOptions } from "../Prostgles"; +import { DBorTx } from "../Prostgles"; import { clone } from "../utils"; import { TableSchema, TableSchemaColumn } from "./DboBuilderTypes"; +import { ProstglesInitOptions } from "../ProstglesTypes"; const getMaterialViews = (db: DBorTx, schema: ProstglesInitOptions["schema"]) => { const { sql, schemaNames } = getSchemaFilter(schema); @@ -109,7 +110,8 @@ export const getSchemaFilter = (schema: ProstglesInitOptions["schema"] = { publi } } -// TODO: Add a onSocketConnect timeout for this query. Reason: this query gets blocked by prostgles.app_triggers from PubSubManager.addTrigger in some cases (pg_dump locks that table) +// TODO: Add a onSocketConnect timeout for this query. +// Reason: this query gets blocked by prostgles.app_triggers from PubSubManager.addTrigger in some cases (pg_dump locks that table) export async function getTablesForSchemaPostgresSQL( { db, runSQL }: DboBuilder, schema: ProstglesInitOptions["schema"] diff --git a/lib/DboBuilder/prepareShortestJoinPaths.ts b/lib/DboBuilder/prepareShortestJoinPaths.ts index 08c8c41b..42c84d76 100644 --- a/lib/DboBuilder/prepareShortestJoinPaths.ts +++ b/lib/DboBuilder/prepareShortestJoinPaths.ts @@ -1,5 +1,5 @@ import { DboBuilder } from "../DboBuilder/DboBuilder"; -import { JOIN_TYPES, Join } from "../Prostgles"; +import { JOIN_TYPES, Join } from "../ProstglesTypes"; import { Graph, findShortestPath } from "../shortestPath"; import { TableSchema } from "./DboBuilderTypes"; import { JoinPaths } from "./ViewHandler/ViewHandler"; diff --git a/lib/Prostgles.ts b/lib/Prostgles.ts index a28a85ac..7d8e316a 100644 --- a/lib/Prostgles.ts +++ b/lib/Prostgles.ts @@ -4,34 +4,32 @@ *--------------------------------------------------------------------------------------------*/ import * as pgPromise from 'pg-promise'; -import { Auth, AuthHandler, AuthRequestParams, SessionUser } from "./AuthHandler"; -import { EventTriggerTagFilter } from "./Event_Trigger_Tags"; -import { CloudClient, FileManager, ImageOptions, LocalConfig } from "./FileManager/FileManager"; +import { AuthHandler } from "./AuthHandler"; +import { FileManager } from "./FileManager/FileManager"; import { SchemaWatch } from "./SchemaWatch/SchemaWatch"; -import { DbConnection, DbConnectionOpts, OnInitReason, OnReadyCallback, initProstgles } from "./initProstgles"; +import { OnInitReason, initProstgles } from "./initProstgles"; import { clientCanRunSqlRequest, runClientMethod, runClientRequest, runClientSqlRequest } from "./runClientRequest"; import pg = require('pg-promise/typescript/pg-subset'); const { version } = require('../package.json'); -import { ExpressApp, RestApi, RestApiConfig } from "./RestApi"; -import TableConfigurator, { TableConfig } from "./TableConfig/TableConfig"; +import type { ProstglesInitOptions } from "./ProstglesTypes"; +import { RestApi } from "./RestApi"; +import TableConfigurator from "./TableConfig/TableConfig"; import { DBHandlerServer, DboBuilder, LocalParams, PRGLIOSocket, getErrorAsObject } from "./DboBuilder/DboBuilder"; export { DBHandlerServer }; export type PGP = pgPromise.IMain<{}, pg.IClient>; import { - AnyObject, CHANNELS, ClientSchema, - DBSchemaTable, FileColumnConfig, + DBSchemaTable, SQLRequest, TableSchemaForClient, getKeys, isObject, omitKeys, tryCatch } from "prostgles-types"; -import type { Server } from "socket.io"; import { DBEventsManager } from "./DBEventsManager"; -import { Publish, PublishMethods, PublishParams, PublishParser } from "./PublishParser/PublishParser"; +import { PublishParser } from "./PublishParser/PublishParser"; export type DB = pgPromise.IDatabase<{}, pg.IClient>; export type DBorTx = DB | pgPromise.ITask<{}> @@ -39,192 +37,7 @@ export type DBorTx = DB | pgPromise.ITask<{}> export const TABLE_METHODS = ["update", "find", "findOne", "insert", "delete", "upsert"] as const; -export const JOIN_TYPES = ["one-many", "many-one", "one-one", "many-many"] as const; -export type Join = { - tables: [string, string]; - on: { [key: string]: string }[]; // Allow multi references to table - type: typeof JOIN_TYPES[number]; -}; -export type Joins = Join[] | "inferred"; - - -type Keywords = { - $and: string; - $or: string; - $not: string; -}; - -export type DeepPartial = { - [P in keyof T]?: DeepPartial; -}; -// export type I18N_CONFIG = { -// fallbackLang: keyof LANG_IDS; -// column_labels?: DeepPartial<{ -// [table_name: string]: { -// [column_name: string]: { -// [lang_id in keyof LANG_IDS]: string -// } -// } -// }>; -// } - -/** - * Allows uploading and downloading files. - * Currently supports only S3. - * - * @description - * Will create a media table that contains file metadata and urls - * Inserting a file into this table through prostgles will upload it to S3 and insert the relevant metadata into the media table - * Requesting a file from HTTP GET {fileUrlPath}/{fileId} will: - * 1. check auth (if provided) - * 2. check the permissions in publish (if provided) - * 3. redirect the request to the signed url (if allowed) - * - * Specifying referencedTables will: - * 1. create a column in that table called media - * 2. create a lookup table lookup_media_{referencedTable} that joins referencedTable to the media table - */ -export type FileTableConfig = { - tableName?: string; /* defaults to 'media' */ - - /** - * GET path used in serving media. defaults to /${tableName} - */ - fileServeRoute?: string; - cloudClient?: CloudClient; - localConfig?: LocalConfig; - - /** - * If defined the the files will not be deleted immediately - * Instead, the "deleted" field will be updated to the current timestamp and after the day interval provided in "deleteAfterNDays" the files will be deleted - * "checkIntervalMinutes" is the frequency in hours at which the files ready for deletion are deleted - */ - delayedDelete?: { - /** - * Minimum amount of time measured in days for which the files will not be deleted after requesting delete - */ - deleteAfterNDays: number; - /** - * How freuquently the files will be checked for deletion delay - */ - checkIntervalHours?: number; - } - expressApp: ExpressApp; - referencedTables?: { - [tableName: string]: - - /** - * If defined then will try to create (if necessary) these columns which will reference files_table(id) - * Prostgles UI will use these hints (obtained through tableHandler.getInfo()) - * */ - | { type: "column", referenceColumns: Record } - }, - imageOptions?: ImageOptions -}; - -export type OnSchemaChangeCallback = ((event: { command: string; query: string }) => void); - -export type ProstglesInitOptions = { - dbConnection: DbConnection; - dbOptions?: DbConnectionOpts; - tsGeneratedTypesDir?: string; - disableRealtime?: boolean; - io?: Server; - publish?: Publish; - /** - * If true then will test all table methods on each socket connect - */ - testRulesOnConnect?: boolean; - publishMethods?: PublishMethods; - publishRawSQL?(params: PublishParams): ((boolean | "*") | Promise<(boolean | "*")>); - joins?: Joins; - schema?: Record | Record; - sqlFilePath?: string; - onReady: OnReadyCallback; - transactions?: string | boolean; - wsChannelNamePrefix?: string; - /** - * Use for connection verification. Will disconnect socket on any errors - */ - onSocketConnect?: (args: AuthRequestParams & { socket: PRGLIOSocket }) => void | Promise; - onSocketDisconnect?: (args: AuthRequestParams & { socket: PRGLIOSocket }) => void | Promise; - auth?: Auth; - DEBUG_MODE?: boolean; - watchSchemaType?: - - /** - * Will set database event trigger for schema changes. Requires superuser - * Default - */ - | "DDL_trigger" - - /** - * Will check client queries for schema changes - * fallback if DDL not possible - */ - | "prostgles_queries" - - /** - * If truthy then DBoGenerated.d.ts will be updated and "onReady" will be called with new schema on both client and server - */ - watchSchema?: - /** - * Will listen only to few events (create table/view) - */ - | boolean - - /** - * Will listen to specified events (or all if "*" is specified) - */ - | EventTriggerTagFilter - - /** - * Will only rewrite the DBoGenerated.d.ts found in tsGeneratedTypesDir - * This is meant to be used in development when server restarts on file change - */ - | "hotReloadMode" - - /** - * Function called when schema changes. Nothing else triggered - */ - | OnSchemaChangeCallback; - - keywords?: Keywords; - onNotice?: (notice: AnyObject, message?: string) => void; - fileTable?: FileTableConfig; - restApi?: RestApiConfig; - /** - * Creates tables and provides UI labels, autocomplete and hints for a given json structure - */ - tableConfig?: TableConfig; - tableConfigMigrations?: { - /** - * If false then prostgles won't start on any tableConfig error - * true by default - */ - silentFail?: boolean; - - version: number; - /** Table that will contain the schema version number and the tableConfig - * Defaults to schema_version - */ - versionTableName?: string; - /** - * Script run before tableConfig is loaded IF an older schema_version is present - */ - onMigrate: (args: { - db: DB; - oldVersion: number | undefined; - getConstraints: ( - table: string, - column?: string, - types?: ColConstraint["type"][] - ) => Promise - }) => void; - }; - onLog?: (evt: EventInfo) => Promise; -} /* 1. Connect to db @@ -246,11 +59,14 @@ const DEFAULT_KEYWORDS = { $not: "$not" }; +import { randomUUID } from "crypto"; import * as fs from 'fs'; -import { EventInfo } from "./Logging"; -import { ColConstraint } from "./TableConfig/getConstraintDefinitionQueries"; export class Prostgles { + /** + * Used facilitate concurrent prostgles connections to the same database + */ + readonly appId = randomUUID(); opts: ProstglesInitOptions = { DEBUG_MODE: false, dbConnection: { diff --git a/lib/ProstglesTypes.ts b/lib/ProstglesTypes.ts new file mode 100644 index 00000000..37421938 --- /dev/null +++ b/lib/ProstglesTypes.ts @@ -0,0 +1,193 @@ + +import { FileColumnConfig } from "prostgles-types"; +import { Auth, AuthRequestParams, SessionUser } from "./AuthHandler"; +import { EventTriggerTagFilter } from "./Event_Trigger_Tags"; +import { CloudClient, ImageOptions, LocalConfig } from "./FileManager/FileManager"; +import { EventInfo } from "./Logging"; +import { ExpressApp } from "./RestApi"; +import { OnSchemaChangeCallback } from "./SchemaWatch/SchemaWatch"; +import { ColConstraint } from "./TableConfig/getConstraintDefinitionQueries"; +import { DbConnection, DbConnectionOpts, OnReadyCallback } from "./initProstgles"; +import { RestApiConfig } from "./RestApi"; +import { TableConfig } from "./TableConfig/TableConfig"; + +import { PRGLIOSocket } from "./DboBuilder/DboBuilder"; + +import { + AnyObject +} from "prostgles-types"; +import type { Server } from "socket.io"; +import { Publish, PublishMethods, PublishParams } from "./PublishParser/PublishParser"; +import { DB } from "./Prostgles"; + +/** + * Allows uploading and downloading files. + * Currently supports only S3. + * + * @description + * Will create a media table that contains file metadata and urls + * Inserting a file into this table through prostgles will upload it to S3 and insert the relevant metadata into the media table + * Requesting a file from HTTP GET {fileUrlPath}/{fileId} will: + * 1. check auth (if provided) + * 2. check the permissions in publish (if provided) + * 3. redirect the request to the signed url (if allowed) + * + * Specifying referencedTables will: + * 1. create a column in that table called media + * 2. create a lookup table lookup_media_{referencedTable} that joins referencedTable to the media table + */ +export type FileTableConfig = { + tableName?: string; /* defaults to 'media' */ + + /** + * GET path used in serving media. defaults to /${tableName} + */ + fileServeRoute?: string; + + cloudClient?: CloudClient; + localConfig?: LocalConfig; + + /** + * If defined the the files will not be deleted immediately + * Instead, the "deleted" field will be updated to the current timestamp and after the day interval provided in "deleteAfterNDays" the files will be deleted + * "checkIntervalMinutes" is the frequency in hours at which the files ready for deletion are deleted + */ + delayedDelete?: { + /** + * Minimum amount of time measured in days for which the files will not be deleted after requesting delete + */ + deleteAfterNDays: number; + /** + * How freuquently the files will be checked for deletion delay + */ + checkIntervalHours?: number; + } + expressApp: ExpressApp; + referencedTables?: { + [tableName: string]: + + /** + * If defined then will try to create (if necessary) these columns which will reference files_table(id) + * Prostgles UI will use these hints (obtained through tableHandler.getInfo()) + * */ + | { type: "column", referenceColumns: Record } + }, + imageOptions?: ImageOptions +}; + + + +type Keywords = { + $and: string; + $or: string; + $not: string; +}; + +export const JOIN_TYPES = ["one-many", "many-one", "one-one", "many-many"] as const; +export type Join = { + tables: [string, string]; + on: { [key: string]: string }[]; // Allow multi references to table + type: typeof JOIN_TYPES[number]; +}; +type Joins = Join[] | "inferred"; + +export type ProstglesInitOptions = { + dbConnection: DbConnection; + dbOptions?: DbConnectionOpts; + tsGeneratedTypesDir?: string; + disableRealtime?: boolean; + io?: Server; + publish?: Publish; + /** + * If true then will test all table methods on each socket connect + */ + testRulesOnConnect?: boolean; + publishMethods?: PublishMethods; + publishRawSQL?(params: PublishParams): ((boolean | "*") | Promise<(boolean | "*")>); + joins?: Joins; + schema?: Record | Record; + sqlFilePath?: string; + onReady: OnReadyCallback; + transactions?: string | boolean; + wsChannelNamePrefix?: string; + /** + * Use for connection verification. Will disconnect socket on any errors + */ + onSocketConnect?: (args: AuthRequestParams & { socket: PRGLIOSocket }) => void | Promise; + onSocketDisconnect?: (args: AuthRequestParams & { socket: PRGLIOSocket }) => void | Promise; + auth?: Auth; + DEBUG_MODE?: boolean; + watchSchemaType?: + + /** + * Will set database event trigger for schema changes. Requires superuser + * Default + */ + | "DDL_trigger" + + /** + * Will check client queries for schema changes + * fallback if DDL not possible + */ + | "prostgles_queries" + + /** + * If truthy then DBoGenerated.d.ts will be updated and "onReady" will be called with new schema on both client and server + */ + watchSchema?: + /** + * Will listen only to few events (create table/view) + */ + | boolean + + /** + * Will listen to specified events (or all if "*" is specified) + */ + | EventTriggerTagFilter + + /** + * Will only rewrite the DBoGenerated.d.ts found in tsGeneratedTypesDir + * This is meant to be used in development when server restarts on file change + */ + | "hotReloadMode" + + /** + * Function called when schema changes. Nothing else triggered + */ + | OnSchemaChangeCallback; + + keywords?: Keywords; + onNotice?: (notice: AnyObject, message?: string) => void; + fileTable?: FileTableConfig; + restApi?: RestApiConfig; + /** + * Creates tables and provides UI labels, autocomplete and hints for a given json structure + */ + tableConfig?: TableConfig; + tableConfigMigrations?: { + /** + * If false then prostgles won't start on any tableConfig error + * true by default + */ + silentFail?: boolean; + + version: number; + /** Table that will contain the schema version number and the tableConfig + * Defaults to schema_version + */ + versionTableName?: string; + /** + * Script run before tableConfig is loaded IF an older schema_version is present + */ + onMigrate: (args: { + db: DB; + oldVersion: number | undefined; + getConstraints: ( + table: string, + column?: string, + types?: ColConstraint["type"][] + ) => Promise + }) => void; + }; + onLog?: (evt: EventInfo) => Promise; +} \ No newline at end of file diff --git a/lib/PubSubManager/PubSubManager.ts b/lib/PubSubManager/PubSubManager.ts index e75d7195..c8f24892 100644 --- a/lib/PubSubManager/PubSubManager.ts +++ b/lib/PubSubManager/PubSubManager.ts @@ -167,6 +167,10 @@ export class PubSubManager { return result; } + appInfoWasInserted = false; + get appId() { + return this.dboBuilder.prostgles.appId; + } get db(): DB { return this.dboBuilder.db; } @@ -195,12 +199,6 @@ export class PubSubManager { log("Created PubSubManager"); } - - /** - * Used facilitate concurrent prostgles connections to the same database - */ - appID?: string; - appCheckFrequencyMS = 10 * 1000; appCheck?: ReturnType; @@ -227,8 +225,6 @@ export class PubSubManager { checkedListenerTableCond?: string[]; initialiseEventTriggers = async () => { - if (!this.appID) throw "prepareTriggers failed: this.appID missing"; - const { watchSchema } = this.dboBuilder.prostgles.opts; if (watchSchema && !(await getIsSuperUser(this.db))) { console.warn("prostgles watchSchema requires superuser db user. Will not watch using event triggers") @@ -268,7 +264,7 @@ export class PubSubManager { DROP TABLE IF EXISTS %1$I; $q$, - ${asValue('triggers_' + this.appID)} + ${asValue('triggers_' + this.appId)} ); is_super_user := EXISTS (select 1 from pg_user where usename = CURRENT_USER AND usesuper IS TRUE); @@ -402,15 +398,14 @@ export class PubSubManager { addSub = addSub.bind(this); - getActiveListeners = (): { table_name: string; condition: string }[] => { - const result: { table_name: string; condition: string }[] = []; + const activeListeners: { table_name: string; condition: string }[] = []; const upsert = (t: string, c: string) => { - if (!result.find(r => r.table_name === t && r.condition === c)) { - result.push({ table_name: t, condition: c }); + if (!activeListeners.find(r => r.table_name === t && r.condition === c)) { + activeListeners.push({ table_name: t, condition: c }); } } - (this.syncs || []).map(s => { + (this.syncs ?? []).map(s => { upsert(s.table_name, s.condition) }); @@ -420,7 +415,7 @@ export class PubSubManager { }); }); - return result; + return activeListeners; } /** @@ -436,7 +431,7 @@ export class PubSubManager { FROM prostgles.v_triggers WHERE app_id = $1 ORDER BY table_name, condition - `, [this.appID] + `, [this.dboBuilder.prostgles.appId] ); this._triggers = {}; @@ -459,7 +454,6 @@ export class PubSubManager { const { table_name } = { ...params } let { condition } = { ...params } if (!table_name) throw "MISSING table_name"; - if (!this.appID) throw "MISSING appID"; if (!condition || !condition.trim().length) { condition = "TRUE"; @@ -479,8 +473,20 @@ export class PubSubManager { /* ${ PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID} */ LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE; - INSERT INTO prostgles.app_triggers (table_name, condition, app_id, related_view_name, related_view_def) - VALUES (${trgVals.tbl}, ${trgVals.cond}, ${asValue(this.appID)}, ${asValue(viewOptions?.viewName ?? null)}, ${asValue(viewOptions?.definition ?? null)}) + INSERT INTO prostgles.app_triggers ( + table_name, + condition, + app_id, + related_view_name, + related_view_def + ) + VALUES ( + ${trgVals.tbl}, + ${trgVals.cond}, + ${asValue(this.appId)}, + ${asValue(viewOptions?.viewName ?? null)}, + ${asValue(viewOptions?.definition ?? null)} + ) ON CONFLICT DO NOTHING; COMMIT WORK; diff --git a/lib/PubSubManager/getInitQuery.ts b/lib/PubSubManager/getInitQuery.ts index 95dde954..c77d3fc2 100644 --- a/lib/PubSubManager/getInitQuery.ts +++ b/lib/PubSubManager/getInitQuery.ts @@ -1,6 +1,7 @@ import { asValue, NOTIF_CHANNEL, NOTIF_TYPE, PubSubManager } from "./PubSubManager"; const { version } = require("../../package.json"); +import { getAppCheckQuery } from "./orphanTriggerCheck"; export const DB_OBJ_NAMES = { trigger_add_remove_func: "prostgles.trigger_add_remove_func", @@ -279,7 +280,6 @@ BEGIN err_detail = PG_EXCEPTION_DETAIL, err_hint = PG_EXCEPTION_HINT; - END; --RAISE NOTICE 'has_errors: % ', has_errors; @@ -323,6 +323,7 @@ BEGIN END IF; END IF; + ${getAppCheckQuery()} RETURN NULL; @@ -574,6 +575,8 @@ BEGIN ); END LOOP; + ${getAppCheckQuery()} + END IF; END; diff --git a/lib/PubSubManager/initPubSubManager.ts b/lib/PubSubManager/initPubSubManager.ts index d86ca7a2..6398a0c0 100644 --- a/lib/PubSubManager/initPubSubManager.ts +++ b/lib/PubSubManager/initPubSubManager.ts @@ -1,7 +1,7 @@ import { PostgresNotifListenManager } from "../PostgresNotifListenManager"; import { getWatchSchemaTagList } from "../SchemaWatch/getWatchSchemaTagList"; import { asValue, log, NOTIF_CHANNEL, PubSubManager } from "./PubSubManager"; -const REALTIME_TRIGGER_CHECK_QUERY = "prostgles-server internal query used to manage realtime triggers" as const; +export const REALTIME_TRIGGER_CHECK_QUERY = "prostgles-server internal query used to manage realtime triggers" as const; import { getInitQuery } from "./getInitQuery"; export async function initPubSubManager(this: PubSubManager): Promise { @@ -15,25 +15,37 @@ export async function initPubSubManager(this: PubSubManager): Promise { let checkForStaleTriggers = ""; - try { // drop owned by api + try { this.appChecking = true; @@ -43,7 +55,7 @@ export async function initPubSubManager(this: PubSubManager): Promise ` ( ${asValue(l.table_name)}, ${asValue(l.condition)} ) `).join(", ")} ) THEN NOW() ELSE last_used END - WHERE app_id = ${asValue(this.appID)}; + WHERE app_id = ${asValue(this.appId)}; `; const checkedListenerTableCond = listeners.map(l => `${l.table_name}.${l.condition}`); @@ -62,10 +74,11 @@ export async function initPubSubManager(this: PubSubManager): Promise pg_backend_pid();", - { qid: "%" + REALTIME_TRIGGER_CHECK_QUERY + "%" } + "SELECT state, pg_terminate_backend(pid) from pg_stat_activity \ + WHERE query ilike ${qid} \ + AND pid <> pg_backend_pid();", + { qid: `%${REALTIME_TRIGGER_CHECK_QUERY}%` } ); /** If no tries left @@ -150,7 +165,7 @@ export async function initPubSubManager(this: PubSubManager): Promise condition_ids.includes(i)); + const orphanedConditions = condition_ids.filter((condId) => typeof tableTriggers.at(condId) !== "string" ); + if(orphanedConditions.length){ + this.db + .any(" \ + DELETE FROM prostgles.app_triggers \ + WHERE table_name = $1 \ + AND id IN ($2:csv) \ + AND app_id = $3 \ + ", + [table_name, orphanedConditions, this.appId] + ) + .catch(e => { + console.error("Error deleting orphaned triggers", e); + }); + } conditions.map(condition => { diff --git a/lib/PubSubManager/orphanTriggerCheck.ts b/lib/PubSubManager/orphanTriggerCheck.ts new file mode 100644 index 00000000..12b5e9e0 --- /dev/null +++ b/lib/PubSubManager/orphanTriggerCheck.ts @@ -0,0 +1,79 @@ +import { PubSubManager } from './PubSubManager'; +import { REALTIME_TRIGGER_CHECK_QUERY } from "./initPubSubManager"; + +/** + * Schema and Data watch triggers (DB_OBJ_NAMES.schema_watch_func, DB_OBJ_NAMES.data_watch_func) + * survive and continue to user resources even after the client disconnects. + * We must therefore . + */ + +const queryIdentifier = "prostgles query used to keep track of which prgl backend clients are still connected"; +const connectedApplicationNamesQuery = ` + SELECT DISTINCT application_name + FROM prostgles.apps + WHERE application_name IN ( + SELECT application_name + FROM pg_catalog.pg_stat_activity + WHERE pid = pg_backend_pid() + ) +`; + +const LAST_CHECKED_SETTING_NAME = 'prostgles.last_checked'; + +/** It is a function to prevent undefined EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID */ +export const getAppCheckQuery = () => ` + /* + ${queryIdentifier} + ${REALTIME_TRIGGER_CHECK_QUERY} + ${PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID} + */ + IF + /* prostgles schema must exist */ + EXISTS ( + SELECT 1 + FROM information_schema.tables + WHERE table_schema = 'prostgles' + AND table_name = 'apps' + ) + /* Ensure we don't check too often */ + AND ( + NULLIF(current_setting('${LAST_CHECKED_SETTING_NAME}', true), '') IS NULL + OR current_setting('${LAST_CHECKED_SETTING_NAME}', true)::timestamp < NOW() - INTERVAL '1 minute' + ) + THEN + EXECUTE format('SET LOCAL ${LAST_CHECKED_SETTING_NAME} TO %L', now()); + --USED FOR DEBUG REMOVE + PERFORM pg_notify('prostgles', current_setting('${LAST_CHECKED_SETTING_NAME}', true)); + + IF EXISTS ( + ${connectedApplicationNamesQuery} + ) THEN + + /* Remove disconnected apps */ + WITH deleted_apps AS ( + DELETE FROM prostgles.apps a + WHERE NOT EXISTS ( + SELECT 1 + FROM pg_catalog.pg_stat_activity s + WHERE s.application_name = a.application_name + ) + RETURNING a.id + ) + DELETE FROM prostgles.app_triggers + WHERE app_id IN ( + SELECT id + FROM deleted_apps + ); + + END IF; + END IF; +`; + + + // /* Ensure we don't check in paralel */ + // AND NOT EXISTS ( + // SELECT 1 + // FROM pg_catalog.pg_stat_activity + // WHERE query ilike '%${queryIdentifier}%' + // AND state = 'active' + // ) \ No newline at end of file diff --git a/lib/SchemaWatch/SchemaWatch.ts b/lib/SchemaWatch/SchemaWatch.ts index a67f9907..ea3b1c53 100644 --- a/lib/SchemaWatch/SchemaWatch.ts +++ b/lib/SchemaWatch/SchemaWatch.ts @@ -1,6 +1,5 @@ import type { DboBuilder } from "../DboBuilder/DboBuilder"; import { EVENT_TRIGGER_TAGS } from "../Event_Trigger_Tags"; -import { OnSchemaChangeCallback } from "../Prostgles"; import { PubSubManager, log } from "../PubSubManager/PubSubManager"; import { ValidatedWatchSchemaType, getValidatedWatchSchemaType } from "./getValidatedWatchSchemaType"; const COMMAND_FIRST_KEYWORDS = EVENT_TRIGGER_TAGS @@ -11,6 +10,8 @@ const DB_FALLBACK_COMMANDS = Array.from(new Set(COMMAND_FIRST_KEYWORDS)); export type VoidFunction = () => void; +export type OnSchemaChangeCallback = ((event: { command: string; query: string }) => void); + export class SchemaWatch { dboBuilder: DboBuilder; diff --git a/lib/SchemaWatch/getValidatedWatchSchemaType.ts b/lib/SchemaWatch/getValidatedWatchSchemaType.ts index 584e7551..fb749c0e 100644 --- a/lib/SchemaWatch/getValidatedWatchSchemaType.ts +++ b/lib/SchemaWatch/getValidatedWatchSchemaType.ts @@ -1,5 +1,5 @@ import type { DboBuilder } from "../DboBuilder/DboBuilder"; -import { OnSchemaChangeCallback } from "../Prostgles"; +import { OnSchemaChangeCallback } from "./SchemaWatch"; export type ValidatedWatchSchemaType = | { watchType: "NONE" } diff --git a/lib/SchemaWatch/getWatchSchemaTagList.ts b/lib/SchemaWatch/getWatchSchemaTagList.ts index ad785c54..1360eec4 100644 --- a/lib/SchemaWatch/getWatchSchemaTagList.ts +++ b/lib/SchemaWatch/getWatchSchemaTagList.ts @@ -1,6 +1,6 @@ import { getKeys, isObject } from "prostgles-types"; import { EVENT_TRIGGER_TAGS } from "../Event_Trigger_Tags"; -import { ProstglesInitOptions } from "../Prostgles"; +import { ProstglesInitOptions } from "../ProstglesTypes"; export const getWatchSchemaTagList = (watchSchema: ProstglesInitOptions["watchSchema"]) => { if(!watchSchema) return undefined; diff --git a/lib/index.ts b/lib/index.ts index 32cdc565..eac9e411 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,5 +1,6 @@ import { SessionUser } from "./AuthHandler"; -import { Prostgles, ProstglesInitOptions } from "./Prostgles"; +import { Prostgles } from "./Prostgles"; +import { ProstglesInitOptions } from "./ProstglesTypes"; function prostgles(params: ProstglesInitOptions){ diff --git a/lib/initProstgles.ts b/lib/initProstgles.ts index c078f617..dac500d2 100644 --- a/lib/initProstgles.ts +++ b/lib/initProstgles.ts @@ -5,10 +5,11 @@ import { isEmpty, pickKeys } from "prostgles-types"; import { AuthHandler } from "./AuthHandler"; import { DBEventsManager } from "./DBEventsManager"; import { DBOFullyTyped } from "./DBSchemaBuilder"; -import { DBHandlerServer, Prostgles, ProstglesInitOptions, getIsSuperUser } from "./Prostgles"; +import { DBHandlerServer, Prostgles, getIsSuperUser } from "./Prostgles"; import { DbTableInfo, PublishParser } from "./PublishParser/PublishParser"; import { sleep } from "./utils"; import { SchemaWatch } from "./SchemaWatch/SchemaWatch"; +import { ProstglesInitOptions } from "./ProstglesTypes"; export type DbConnection = string | pg.IConnectionParameters; export type DbConnectionOpts = pg.IDefaults; @@ -58,9 +59,31 @@ export type InitResult = { export const initProstgles = async function(this: Prostgles, onReady: OnReadyCallbackBasic, reason: OnInitReason): Promise { this.loaded = false; - /* 1. Connect to db */ if (!this.db) { - const { db, pgp } = getDbConnection(this.opts.dbConnection, this.opts.dbOptions, this.opts.DEBUG_MODE, + let existingAppName = ""; + let connString = ""; + if(typeof this.opts.dbConnection === "string"){ + connString = this.opts.dbConnection; + } else if(this.opts.dbConnection.connectionString){ + connString = this.opts.dbConnection.connectionString; + } else { + existingAppName = this.opts.dbConnection.application_name ?? ""; + } + + if(connString){ + try { + const url = new URL(connString); + existingAppName = url.searchParams.get("application_name") ?? url.searchParams.get("ApplicationName") ?? ""; + } catch (e) { + + } + } + + const conObj = typeof this.opts.dbConnection === "string" ? { connectionString: this.opts.dbConnection } : this.opts.dbConnection + const application_name = `prostgles ${this.appId} ${existingAppName}`; + + /* 1. Connect to db */ + const { db, pgp } = getDbConnection({ ...conObj, application_name }, this.opts.dbOptions, this.opts.DEBUG_MODE, notice => { if (this.opts.onNotice) this.opts.onNotice(notice); if (this.dbEventsManager) { diff --git a/package-lock.json b/package-lock.json index 24898301..ba78c321 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prostgles-server", - "version": "4.2.72", + "version": "4.2.73", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "prostgles-server", - "version": "4.2.72", + "version": "4.2.73", "license": "MIT", "dependencies": { "bluebird": "^3.7.2", @@ -27,10 +27,10 @@ "@types/pg": "^8.11.5", "@types/pg-cursor": "^2.7.2", "@types/sharp": "^0.30.4", - "@types/socket.io": "^3.0.2", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "eslint": "^8.51.0", + "socket.io": "^4.7.5", "typescript": "^5.3.3" } }, @@ -385,16 +385,6 @@ "@types/node": "*" } }, - "node_modules/@types/socket.io": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.2.tgz", - "integrity": "sha512-pu0sN9m5VjCxBZVK8hW37ZcMe8rjn4HHggBN5CbaRTvFwv5jOmuIRZEuddsBPa9Th0ts0SIo3Niukq+95cMBbQ==", - "deprecated": "This is a stub types definition. socket.io provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "socket.io": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", @@ -971,9 +961,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/engine.io": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -985,7 +975,7 @@ "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" + "ws": "~8.17.1" }, "engines": { "node": ">=10.2.0" @@ -2475,6 +2465,27 @@ "ws": "~8.11.0" } }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", @@ -2737,16 +2748,16 @@ "dev": true }, "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -3083,15 +3094,6 @@ "@types/node": "*" } }, - "@types/socket.io": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.2.tgz", - "integrity": "sha512-pu0sN9m5VjCxBZVK8hW37ZcMe8rjn4HHggBN5CbaRTvFwv5jOmuIRZEuddsBPa9Th0ts0SIo3Niukq+95cMBbQ==", - "dev": true, - "requires": { - "socket.io": "*" - } - }, "@typescript-eslint/eslint-plugin": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", @@ -3478,9 +3480,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "engine.io": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "dev": true, "requires": { "@types/cookie": "^0.4.1", @@ -3492,7 +3494,7 @@ "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" + "ws": "~8.17.1" } }, "engine.io-parser": { @@ -4544,6 +4546,15 @@ "requires": { "debug": "~4.3.4", "ws": "~8.11.0" + }, + "dependencies": { + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "requires": {} + } } }, "socket.io-parser": { @@ -4729,9 +4740,9 @@ "dev": true }, "ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index a862706a..d953d4e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prostgles-server", - "version": "4.2.72", + "version": "4.2.73", "description": "", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -53,10 +53,10 @@ "@types/pg": "^8.11.5", "@types/pg-cursor": "^2.7.2", "@types/sharp": "^0.30.4", - "@types/socket.io": "^3.0.2", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "eslint": "^8.51.0", + "socket.io": "^4.7.5", "typescript": "^5.3.3" } } diff --git a/tests/isomorphicQueries.spec.ts b/tests/isomorphicQueries.spec.ts index 2e5d2ba6..fbfae49f 100644 --- a/tests/isomorphicQueries.spec.ts +++ b/tests/isomorphicQueries.spec.ts @@ -487,11 +487,11 @@ export const isomorphicQueries = async (db: DBOFullyTyped | DBHandlerClient, log ) as { tgname: string; enabled: boolean; }[]; } await sub.unsubscribe(); - let validTriggers = await getTableTriggers(table_name) - assert.equal(validTriggers.filter(t => t.enabled).length, 3); + let validTriggers = await getTableTriggers(table_name); + assert.equal(validTriggers.filter(t => t.enabled).length, 3, '3 Triggers should be enabled'); await db.sql?.(`DELETE FROM prostgles.app_triggers`, []); // WHERE table_name = $1 - validTriggers = await getTableTriggers(table_name) - assert.equal(validTriggers.length, 3); + validTriggers = await getTableTriggers(table_name); + assert.equal(validTriggers.length, 3, '3 Triggers should exist but be disabled'); assert.equal(validTriggers.filter(t => t.enabled).length, 0); } diff --git a/tests/server/index.ts b/tests/server/index.ts index 58b29404..e580e64e 100644 --- a/tests/server/index.ts +++ b/tests/server/index.ts @@ -124,6 +124,7 @@ function dd(){ expressApp: app, tableName: "files", }, + // DEBUG_MODE: true, restApi: { expressApp: app, routePrefix: "/api" diff --git a/tests/server/package-lock.json b/tests/server/package-lock.json index a4aa5282..71a69dd5 100644 --- a/tests/server/package-lock.json +++ b/tests/server/package-lock.json @@ -9,9 +9,9 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "express": "^4.18.2", + "express": "^4.19.2", "prostgles-server": "file:../..", - "socket.io": "^4.7.1" + "socket.io": "^4.7.5" }, "devDependencies": { "@types/node": "^20.9.2", @@ -21,7 +21,7 @@ }, "../..": { "name": "prostgles-server", - "version": "4.2.72", + "version": "4.2.73", "license": "MIT", "dependencies": { "bluebird": "^3.7.2", @@ -42,10 +42,10 @@ "@types/pg": "^8.11.5", "@types/pg-cursor": "^2.7.2", "@types/sharp": "^0.30.4", - "@types/socket.io": "^3.0.2", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "eslint": "^8.51.0", + "socket.io": "^4.7.5", "typescript": "^5.3.3" } }, @@ -60,9 +60,9 @@ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, "node_modules/@types/cors": { - "version": "2.8.13", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", - "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", "dependencies": { "@types/node": "*" } @@ -110,12 +110,12 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -123,7 +123,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -141,12 +141,18 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -164,17 +170,17 @@ } }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -218,6 +224,22 @@ "ms": "2.0.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -255,9 +277,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.1.tgz", - "integrity": "sha512-mGqhI+D7YxS9KJMppR6Iuo37Ed3abhU8NdfgSvJSDUafQutrN+sPTncJYTyM9+tkhSmWodKtVYGPPHyXJEwEQA==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -267,17 +289,17 @@ "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~5.1.0", - "ws": "~8.11.0" + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=10.2.0" } }, "node_modules/engine.io-parser": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.1.0.tgz", - "integrity": "sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", "engines": { "node": ">=10.0.0" } @@ -291,9 +313,9 @@ } }, "node_modules/engine.io/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -311,6 +333,45 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -340,16 +401,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -420,32 +481,62 @@ "dev": true }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dependencies": { - "function-bind": "^1.1.1" + "get-intrinsic": "^1.1.3" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { @@ -459,6 +550,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -589,9 +691,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -692,9 +794,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -771,6 +873,22 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -798,33 +916,37 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/socket.io": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz", - "integrity": "sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw==", + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.0", + "engine.io": "~6.5.2", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, "engines": { - "node": ">=10.0.0" + "node": ">=10.2.0" } }, "node_modules/socket.io-adapter": { @@ -1077,9 +1199,9 @@ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, "@types/cors": { - "version": "2.8.13", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", - "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", "requires": { "@types/node": "*" } @@ -1118,12 +1240,12 @@ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" }, "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -1131,7 +1253,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } @@ -1142,12 +1264,15 @@ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, "content-disposition": { @@ -1159,14 +1284,14 @@ } }, "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" }, "cookie-signature": { "version": "1.0.6", @@ -1201,6 +1326,16 @@ "ms": "2.0.0" } }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1228,9 +1363,9 @@ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "engine.io": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.1.tgz", - "integrity": "sha512-mGqhI+D7YxS9KJMppR6Iuo37Ed3abhU8NdfgSvJSDUafQutrN+sPTncJYTyM9+tkhSmWodKtVYGPPHyXJEwEQA==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "requires": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -1240,8 +1375,8 @@ "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~5.1.0", - "ws": "~8.11.0" + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" }, "dependencies": { "cookie": { @@ -1250,9 +1385,9 @@ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" }, "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "requires": { "ms": "2.1.2" } @@ -1261,13 +1396,32 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "requires": {} } } }, "engine.io-parser": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.1.0.tgz", - "integrity": "sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w==" + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==" + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, "escape-html": { "version": "1.0.3", @@ -1295,16 +1449,16 @@ } }, "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -1363,33 +1517,56 @@ "dev": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "requires": { - "function-bind": "^1.1.1" + "get-intrinsic": "^1.1.3" } }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1487,9 +1664,9 @@ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" }, "on-finished": { "version": "2.4.1", @@ -1534,7 +1711,6 @@ "@types/pg": "^8.11.5", "@types/pg-cursor": "^2.7.2", "@types/sharp": "^0.30.4", - "@types/socket.io": "^3.0.2", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "bluebird": "^3.7.2", @@ -1547,6 +1723,7 @@ "pg-promise": "^11.6.0", "prostgles-client": "^4.0.53", "prostgles-types": "^4.0.87", + "socket.io": "^4.7.5", "typescript": "^5.3.3" } }, @@ -1582,9 +1759,9 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -1640,6 +1817,19 @@ "send": "0.18.0" } }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -1661,25 +1851,26 @@ "dev": true }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, "socket.io": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz", - "integrity": "sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw==", + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", "requires": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.0", + "engine.io": "~6.5.2", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, diff --git a/tests/server/package.json b/tests/server/package.json index 8308f842..b42e2612 100644 --- a/tests/server/package.json +++ b/tests/server/package.json @@ -13,9 +13,9 @@ "author": "", "license": "ISC", "dependencies": { - "express": "^4.18.2", + "express": "^4.19.2", "prostgles-server": "file:../..", - "socket.io": "^4.7.1" + "socket.io": "^4.7.5" }, "devDependencies": { "@types/node": "^20.9.2", diff --git a/tests/server/testTableConfig.ts b/tests/server/testTableConfig.ts index 71dee66e..f058f76f 100644 --- a/tests/server/testTableConfig.ts +++ b/tests/server/testTableConfig.ts @@ -133,6 +133,7 @@ export const testTableConfig: TableConfig<{ en: 1, fr: 1 }> = { } }, api_table: { + dropIfExists: true, columns: { id: "SERIAL PRIMARY KEY", },