@restura/core 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -3
- package/dist/index.js +86 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -934,8 +934,10 @@ declare abstract class PsqlConnection {
|
|
|
934
934
|
readonly instanceId: UUID;
|
|
935
935
|
protected constructor(instanceId?: UUID);
|
|
936
936
|
protected abstract query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
937
|
-
queryOne<T>(query: string, options:
|
|
938
|
-
|
|
937
|
+
queryOne<T>(query: string, options: unknown[], requesterDetails: RequesterDetails): Promise<T>;
|
|
938
|
+
queryOneSchema<T>(query: string, params: unknown[], requesterDetails: RequesterDetails, zodSchema: z.ZodSchema<T>): Promise<T>;
|
|
939
|
+
runQuery<T>(query: string, options: unknown[], requesterDetails: RequesterDetails): Promise<T[]>;
|
|
940
|
+
runQuerySchema<T>(query: string, params: unknown[], requesterDetails: RequesterDetails, zodSchema: z.ZodSchema<T>): Promise<T[]>;
|
|
939
941
|
private logQueryDuration;
|
|
940
942
|
private logSqlStatement;
|
|
941
943
|
}
|
|
@@ -1059,9 +1061,13 @@ declare class PsqlEngine extends SqlEngine {
|
|
|
1059
1061
|
setupTriggerListeners: Promise<void> | undefined;
|
|
1060
1062
|
private triggerClient;
|
|
1061
1063
|
private scratchDbName;
|
|
1064
|
+
private reconnectAttempts;
|
|
1065
|
+
private readonly MAX_RECONNECT_ATTEMPTS;
|
|
1066
|
+
private readonly INITIAL_RECONNECT_DELAY;
|
|
1062
1067
|
constructor(psqlConnectionPool: PsqlPool, shouldListenForDbTriggers?: boolean, scratchDatabaseSuffix?: string);
|
|
1063
1068
|
close(): Promise<void>;
|
|
1064
1069
|
private setupPgReturnTypes;
|
|
1070
|
+
private reconnectTriggerClient;
|
|
1065
1071
|
private listenForDbTriggers;
|
|
1066
1072
|
private handleTrigger;
|
|
1067
1073
|
createDatabaseFromSchema(schema: ResturaSchema, connection: PsqlPool): Promise<string>;
|
|
@@ -1140,4 +1146,4 @@ declare function isValueNumber(value: unknown): value is number;
|
|
|
1140
1146
|
*/
|
|
1141
1147
|
declare function SQL(strings: TemplateStringsArray, ...values: unknown[]): string;
|
|
1142
1148
|
|
|
1143
|
-
export { type ActionColumnChangeData, type ActionColumnChangeFilter, type ActionRowDeleteData, type ActionRowDeleteFilter, type ActionRowInsertData, type ActionRowInsertFilter, type ApiMethod, type AsyncExpressApplication, type AuthenticateHandler, type AuthenticatedRequesterDetails, type ConjunctionTypes, type DatabaseActionData, type DynamicObject, type ErrorCode, type EventType, HtmlStatusCodes, type LoggerConfigSchema, type MatchTypes, type MutationType, type OnValidAuthenticationCallback, type PageQuery, PsqlConnection, PsqlEngine, PsqlPool, PsqlTransaction, type QueryMetadata, type RequesterDetails, type ResturaConfigSchema, RsError, type RsErrorData, type RsErrorInternalData, type RsHeaders, type RsPagedResponseData, type RsRequest, type RsResponse, type RsResponseData, type RsRouteHandler, SQL, type SchemaChangeValue, type SchemaPreview, type SqlMutationData, type StandardOrderTypes, type TriggerResult, apiGenerator, escapeColumnName, eventManager, filterPsqlParser, insertObjectQuery, isSchemaValid, isValueNumber, logger, modelGenerator, questionMarksToOrderedParams, restura, resturaGlobalTypesGenerator, updateObjectQuery };
|
|
1149
|
+
export { type ActionColumnChangeData, type ActionColumnChangeFilter, type ActionRowDeleteData, type ActionRowDeleteFilter, type ActionRowInsertData, type ActionRowInsertFilter, type ApiMethod, type AsyncExpressApplication, type AuthenticateHandler, type AuthenticatedRequesterDetails, type ConjunctionTypes, type DatabaseActionData, type DynamicObject, type ErrorCode, type EventType, HtmlStatusCodes, type LoggerConfigSchema, type MatchTypes, type MutationType, type OnValidAuthenticationCallback, type PageQuery, PsqlConnection, PsqlEngine, PsqlPool, PsqlTransaction, type QueryMetadata, type RequesterDetails, type ResturaConfigSchema, type ResturaSchema, RsError, type RsErrorData, type RsErrorInternalData, type RsHeaders, type RsPagedResponseData, type RsRequest, type RsResponse, type RsResponseData, type RsRouteHandler, SQL, type SchemaChangeValue, type SchemaPreview, type SqlMutationData, type StandardOrderTypes, type TriggerResult, apiGenerator, escapeColumnName, eventManager, filterPsqlParser, insertObjectQuery, isSchemaValid, isValueNumber, logger, modelGenerator, questionMarksToOrderedParams, restura, resturaGlobalTypesGenerator, resturaSchema, updateObjectQuery };
|
package/dist/index.js
CHANGED
|
@@ -1617,6 +1617,7 @@ import pg from "pg";
|
|
|
1617
1617
|
import crypto from "crypto";
|
|
1618
1618
|
import format3 from "pg-format";
|
|
1619
1619
|
import { format as sqlFormat } from "sql-formatter";
|
|
1620
|
+
import { z as z6 } from "zod/v4";
|
|
1620
1621
|
|
|
1621
1622
|
// src/restura/sql/PsqlUtils.ts
|
|
1622
1623
|
import format2 from "pg-format";
|
|
@@ -1691,7 +1692,6 @@ var PsqlConnection = class {
|
|
|
1691
1692
|
constructor(instanceId) {
|
|
1692
1693
|
this.instanceId = instanceId || crypto.randomUUID();
|
|
1693
1694
|
}
|
|
1694
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1695
1695
|
async queryOne(query, options, requesterDetails) {
|
|
1696
1696
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1697
1697
|
const meta = { connectionInstanceId: this.instanceId, ...requesterDetails };
|
|
@@ -1713,7 +1713,21 @@ var PsqlConnection = class {
|
|
|
1713
1713
|
throw new RsError("DATABASE_ERROR", `${error.message}`);
|
|
1714
1714
|
}
|
|
1715
1715
|
}
|
|
1716
|
-
|
|
1716
|
+
async queryOneSchema(query, params, requesterDetails, zodSchema) {
|
|
1717
|
+
const result = await this.queryOne(query, params, requesterDetails);
|
|
1718
|
+
try {
|
|
1719
|
+
return zodSchema.parse(result);
|
|
1720
|
+
} catch (error) {
|
|
1721
|
+
if (error instanceof z6.ZodError) {
|
|
1722
|
+
logger.error("Invalid data returned from database:");
|
|
1723
|
+
logger.silly("\n" + JSON.stringify(result, null, 2));
|
|
1724
|
+
logger.error("\n" + z6.prettifyError(error));
|
|
1725
|
+
} else {
|
|
1726
|
+
logger.error(error);
|
|
1727
|
+
}
|
|
1728
|
+
throw new RsError("DATABASE_ERROR", `Invalid data returned from database`);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1717
1731
|
async runQuery(query, options, requesterDetails) {
|
|
1718
1732
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1719
1733
|
const meta = { connectionInstanceId: this.instanceId, ...requesterDetails };
|
|
@@ -1732,6 +1746,21 @@ var PsqlConnection = class {
|
|
|
1732
1746
|
throw new RsError("DATABASE_ERROR", `${error.message}`);
|
|
1733
1747
|
}
|
|
1734
1748
|
}
|
|
1749
|
+
async runQuerySchema(query, params, requesterDetails, zodSchema) {
|
|
1750
|
+
const result = await this.runQuery(query, params, requesterDetails);
|
|
1751
|
+
try {
|
|
1752
|
+
return z6.array(zodSchema).parse(result);
|
|
1753
|
+
} catch (error) {
|
|
1754
|
+
if (error instanceof z6.ZodError) {
|
|
1755
|
+
logger.error("Invalid data returned from database:");
|
|
1756
|
+
logger.silly("\n" + JSON.stringify(result, null, 2));
|
|
1757
|
+
logger.error("\n" + z6.prettifyError(error));
|
|
1758
|
+
} else {
|
|
1759
|
+
logger.error(error);
|
|
1760
|
+
}
|
|
1761
|
+
throw new RsError("DATABASE_ERROR", `Invalid data returned from database`);
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1735
1764
|
logQueryDuration(startTime) {
|
|
1736
1765
|
if (logger.level === "silly") {
|
|
1737
1766
|
const [seconds, nanoseconds] = process.hrtime(startTime);
|
|
@@ -2045,6 +2074,7 @@ var systemUser = {
|
|
|
2045
2074
|
isSystemUser: true
|
|
2046
2075
|
};
|
|
2047
2076
|
var PsqlEngine = class extends SqlEngine {
|
|
2077
|
+
// 5 seconds
|
|
2048
2078
|
constructor(psqlConnectionPool, shouldListenForDbTriggers = false, scratchDatabaseSuffix = "") {
|
|
2049
2079
|
super();
|
|
2050
2080
|
this.psqlConnectionPool = psqlConnectionPool;
|
|
@@ -2057,6 +2087,9 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
2057
2087
|
setupTriggerListeners;
|
|
2058
2088
|
triggerClient;
|
|
2059
2089
|
scratchDbName = "";
|
|
2090
|
+
reconnectAttempts = 0;
|
|
2091
|
+
MAX_RECONNECT_ATTEMPTS = 5;
|
|
2092
|
+
INITIAL_RECONNECT_DELAY = 5e3;
|
|
2060
2093
|
async close() {
|
|
2061
2094
|
if (this.triggerClient) {
|
|
2062
2095
|
await this.triggerClient.end();
|
|
@@ -2072,6 +2105,34 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
2072
2105
|
return val === null ? null : Number(val);
|
|
2073
2106
|
});
|
|
2074
2107
|
}
|
|
2108
|
+
async reconnectTriggerClient() {
|
|
2109
|
+
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
2110
|
+
logger.error("Max reconnection attempts reached for trigger client. Stopping reconnection attempts.");
|
|
2111
|
+
return;
|
|
2112
|
+
}
|
|
2113
|
+
if (this.triggerClient) {
|
|
2114
|
+
try {
|
|
2115
|
+
await this.triggerClient.end();
|
|
2116
|
+
} catch (error) {
|
|
2117
|
+
logger.error(`Error closing trigger client: ${error}`);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
const delay = this.INITIAL_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts);
|
|
2121
|
+
logger.info(
|
|
2122
|
+
`Attempting to reconnect trigger client in ${delay / 1e3} seconds... (Attempt ${this.reconnectAttempts + 1}/${this.MAX_RECONNECT_ATTEMPTS})`
|
|
2123
|
+
);
|
|
2124
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
2125
|
+
this.reconnectAttempts++;
|
|
2126
|
+
try {
|
|
2127
|
+
await this.listenForDbTriggers();
|
|
2128
|
+
this.reconnectAttempts = 0;
|
|
2129
|
+
} catch (error) {
|
|
2130
|
+
logger.error(`Reconnection attempt ${this.reconnectAttempts} failed: ${error}`);
|
|
2131
|
+
if (this.reconnectAttempts < this.MAX_RECONNECT_ATTEMPTS) {
|
|
2132
|
+
await this.reconnectTriggerClient();
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2075
2136
|
async listenForDbTriggers() {
|
|
2076
2137
|
this.triggerClient = new Client({
|
|
2077
2138
|
user: this.psqlConnectionPool.poolConfig.user,
|
|
@@ -2081,18 +2142,28 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
2081
2142
|
port: this.psqlConnectionPool.poolConfig.port,
|
|
2082
2143
|
connectionTimeoutMillis: this.psqlConnectionPool.poolConfig.connectionTimeoutMillis
|
|
2083
2144
|
});
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
await this.
|
|
2094
|
-
}
|
|
2095
|
-
|
|
2145
|
+
try {
|
|
2146
|
+
await this.triggerClient.connect();
|
|
2147
|
+
const promises = [];
|
|
2148
|
+
promises.push(this.triggerClient.query("LISTEN insert"));
|
|
2149
|
+
promises.push(this.triggerClient.query("LISTEN update"));
|
|
2150
|
+
promises.push(this.triggerClient.query("LISTEN delete"));
|
|
2151
|
+
await Promise.all(promises);
|
|
2152
|
+
this.triggerClient.on("error", async (error) => {
|
|
2153
|
+
logger.error(`Trigger client error: ${error}`);
|
|
2154
|
+
await this.reconnectTriggerClient();
|
|
2155
|
+
});
|
|
2156
|
+
this.triggerClient.on("notification", async (msg) => {
|
|
2157
|
+
if (msg.channel === "insert" || msg.channel === "update" || msg.channel === "delete") {
|
|
2158
|
+
const payload = ObjectUtils4.safeParse(msg.payload);
|
|
2159
|
+
await this.handleTrigger(payload, msg.channel.toUpperCase());
|
|
2160
|
+
}
|
|
2161
|
+
});
|
|
2162
|
+
logger.info("Successfully connected to database triggers");
|
|
2163
|
+
} catch (error) {
|
|
2164
|
+
logger.error(`Failed to setup trigger listeners: ${error}`);
|
|
2165
|
+
await this.reconnectTriggerClient();
|
|
2166
|
+
}
|
|
2096
2167
|
}
|
|
2097
2168
|
async handleTrigger(payload, mutationType) {
|
|
2098
2169
|
if (payload.queryMetadata && payload.queryMetadata.connectionInstanceId === this.psqlConnectionPool.instanceId) {
|
|
@@ -3232,6 +3303,7 @@ export {
|
|
|
3232
3303
|
questionMarksToOrderedParams,
|
|
3233
3304
|
restura,
|
|
3234
3305
|
resturaGlobalTypesGenerator,
|
|
3306
|
+
resturaSchema,
|
|
3235
3307
|
updateObjectQuery
|
|
3236
3308
|
};
|
|
3237
3309
|
//# sourceMappingURL=index.js.map
|