prostgles-server 4.2.626 → 4.2.628
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/debug/prostgles-types-4.0.285.tgz +0 -0
- package/dist/Audit/getAuditTableRules.js +1 -1
- package/dist/Audit/getAuditTableRules.js.map +1 -1
- package/dist/DBSchemaBuilder/DBSchemaBuilder.d.ts +4 -4
- package/dist/DBSchemaBuilder/DBSchemaBuilder.d.ts.map +1 -1
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js +1 -1
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions/Functions.d.ts +3 -1
- package/dist/DboBuilder/QueryBuilder/Functions/Functions.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions/Functions.js +18 -11
- package/dist/DboBuilder/QueryBuilder/Functions/Functions.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions/HASHING_FUNCTIONS.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions/HASHING_FUNCTIONS.js +16 -21
- package/dist/DboBuilder/QueryBuilder/Functions/HASHING_FUNCTIONS.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions/utils.d.ts +1 -0
- package/dist/DboBuilder/QueryBuilder/Functions/utils.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions/utils.js +3 -1
- package/dist/DboBuilder/QueryBuilder/Functions/utils.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts +18 -2
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +54 -16
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts +1 -1
- package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getNewQuery.js +40 -6
- package/dist/DboBuilder/QueryBuilder/getNewQuery.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/parseJoinSelect.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/parseJoinSelect.js +2 -12
- package/dist/DboBuilder/QueryBuilder/parseJoinSelect.js.map +1 -1
- package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js +7 -6
- package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/find.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/find.js +2 -29
- package/dist/DboBuilder/ViewHandler/find.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/parseComplexFilter.d.ts +4 -1
- package/dist/DboBuilder/ViewHandler/parseComplexFilter.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/parseComplexFilter.js +9 -2
- package/dist/DboBuilder/ViewHandler/parseComplexFilter.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/subscribe.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/subscribe.js +8 -3
- package/dist/DboBuilder/ViewHandler/subscribe.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/validateSelectParams.d.ts +3 -0
- package/dist/DboBuilder/ViewHandler/validateSelectParams.d.ts.map +1 -0
- package/dist/DboBuilder/ViewHandler/validateSelectParams.js +48 -0
- package/dist/DboBuilder/ViewHandler/validateSelectParams.js.map +1 -0
- package/dist/DboBuilder/getCondition.d.ts.map +1 -1
- package/dist/DboBuilder/getCondition.js +9 -3
- package/dist/DboBuilder/getCondition.js.map +1 -1
- package/dist/DboBuilder/getSubscribeRelatedTables.d.ts.map +1 -1
- package/dist/DboBuilder/getSubscribeRelatedTables.js +7 -2
- package/dist/DboBuilder/getSubscribeRelatedTables.js.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.js +1 -1
- package/dist/PubSubManager/PubSubManager.js.map +1 -1
- package/dist/PubSubManager/addSub.js +1 -1
- package/dist/PubSubManager/addSub.js.map +1 -1
- package/dist/StorageClient/fileVersionUtils.d.ts +3 -3
- package/dist/StorageClient/fileVersionUtils.d.ts.map +1 -1
- package/dist/StorageClient/fileVersionUtils.js.map +1 -1
- package/dist/TableConfig/initTableConfig.d.ts.map +1 -1
- package/dist/TableConfig/initTableConfig.js +1 -4
- package/dist/TableConfig/initTableConfig.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/typeTests/DBOFullyTyped.spec.js.map +1 -1
- package/lib/Audit/getAuditTableRules.ts +1 -1
- package/lib/DBSchemaBuilder/DBSchemaBuilder.ts +6 -7
- package/lib/DBSchemaBuilder/getClientDBGeneratedSchemas.ts +1 -1
- package/lib/DboBuilder/QueryBuilder/Functions/Functions.ts +38 -13
- package/lib/DboBuilder/QueryBuilder/Functions/HASHING_FUNCTIONS.ts +28 -24
- package/lib/DboBuilder/QueryBuilder/Functions/utils.ts +10 -0
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +95 -18
- package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +58 -10
- package/lib/DboBuilder/QueryBuilder/parseJoinSelect.ts +2 -13
- package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +9 -8
- package/lib/DboBuilder/ViewHandler/find.ts +2 -32
- package/lib/DboBuilder/ViewHandler/parseComplexFilter.ts +10 -2
- package/lib/DboBuilder/ViewHandler/subscribe.ts +10 -3
- package/lib/DboBuilder/ViewHandler/validateSelectParams.ts +51 -0
- package/lib/DboBuilder/getCondition.ts +11 -3
- package/lib/DboBuilder/getSubscribeRelatedTables.ts +10 -3
- package/lib/PubSubManager/PubSubManager.ts +1 -1
- package/lib/PubSubManager/addSub.ts +1 -1
- package/lib/StorageClient/fileVersionUtils.ts +3 -3
- package/lib/TableConfig/initTableConfig.ts +1 -6
- package/lib/index.ts +5 -1
- package/lib/typeTests/DBOFullyTyped.spec.ts +1 -1
- package/package.json +2 -2
|
@@ -34,6 +34,8 @@ export const parseComplexFilter = ({
|
|
|
34
34
|
allowed_colnames,
|
|
35
35
|
columns,
|
|
36
36
|
}: Args) => {
|
|
37
|
+
const columnsUsed: string[] = [];
|
|
38
|
+
|
|
37
39
|
/**
|
|
38
40
|
* { $funcName: [arg1, arg2] }
|
|
39
41
|
* { $column: "column_name" }
|
|
@@ -45,8 +47,9 @@ export const parseComplexFilter = ({
|
|
|
45
47
|
throw `expecting: \n { $column: "column_name" } received:\n ${JSON.stringify(funcData)}`;
|
|
46
48
|
}
|
|
47
49
|
if (!allowed_colnames.includes(column)) {
|
|
48
|
-
throw `
|
|
50
|
+
throw `Disallowed or Invalid column ${column}. Allowed columns: ${allowed_colnames}`;
|
|
49
51
|
}
|
|
52
|
+
columnsUsed.push(column);
|
|
50
53
|
return asNameAlias(column, tableAliasRaw);
|
|
51
54
|
}
|
|
52
55
|
const { funcName, args } = parseFunctionObject(funcData);
|
|
@@ -56,6 +59,8 @@ export const parseComplexFilter = ({
|
|
|
56
59
|
functions: FUNCTIONS,
|
|
57
60
|
allowedFields: allowed_colnames,
|
|
58
61
|
});
|
|
62
|
+
const fields = funcDef.getFields(args);
|
|
63
|
+
columnsUsed.push(...(fields === "*" ? allowed_colnames : fields));
|
|
59
64
|
return funcDef.getQuery({
|
|
60
65
|
args,
|
|
61
66
|
tableAliasRaw,
|
|
@@ -108,5 +113,8 @@ export const parseComplexFilter = ({
|
|
|
108
113
|
result += ` ${sqlOperand} ${rightVal}`;
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
return
|
|
116
|
+
return {
|
|
117
|
+
condition: result,
|
|
118
|
+
columnsUsed: Array.from(new Set(columnsUsed)),
|
|
119
|
+
};
|
|
112
120
|
};
|
|
@@ -77,9 +77,16 @@ async function subscribe(
|
|
|
77
77
|
newQuery,
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
const [firstField, ...otherFields] =
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
const [firstField, ...otherFields] = Array.from(
|
|
81
|
+
new Set([
|
|
82
|
+
...newQuery.select
|
|
83
|
+
.filter((s) => s.selected)
|
|
84
|
+
.flatMap((item) => [...item.fields, ...(item.dependencyFields ?? [])]),
|
|
85
|
+
...newQuery.orderByItems
|
|
86
|
+
.map(({ key }) => key)
|
|
87
|
+
.filter((key) => this.column_names.includes(key)),
|
|
88
|
+
]),
|
|
89
|
+
);
|
|
83
90
|
|
|
84
91
|
const commonSubOpts = {
|
|
85
92
|
table_info: this.tableOrViewInfo,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getJSONBObjectSchemaValidationError, getKeys, type SelectParams } from "prostgles-types";
|
|
2
|
+
|
|
3
|
+
export const validateSelectParams = (
|
|
4
|
+
selectParams: any,
|
|
5
|
+
): selectParams is SelectParams | undefined => {
|
|
6
|
+
if (selectParams === undefined) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
const allowedReturnTypes = getKeys({
|
|
10
|
+
row: 1,
|
|
11
|
+
statement: 1,
|
|
12
|
+
value: 1,
|
|
13
|
+
values: 1,
|
|
14
|
+
"statement-no-rls": 1,
|
|
15
|
+
"statement-where": 1,
|
|
16
|
+
} satisfies Record<Required<SelectParams>["returnType"], 1>);
|
|
17
|
+
|
|
18
|
+
const selectParamsValidation = getJSONBObjectSchemaValidationError(
|
|
19
|
+
{
|
|
20
|
+
select: {
|
|
21
|
+
oneOf: [{ enum: ["*", ""] as const }, { record: { values: "any" } }, "string[]"],
|
|
22
|
+
optional: true,
|
|
23
|
+
},
|
|
24
|
+
orderBy: {
|
|
25
|
+
oneOf: [
|
|
26
|
+
{ record: { values: "any" } },
|
|
27
|
+
{ arrayOf: { record: { values: "any" } } },
|
|
28
|
+
"string[]",
|
|
29
|
+
"string",
|
|
30
|
+
],
|
|
31
|
+
optional: true,
|
|
32
|
+
},
|
|
33
|
+
offset: { type: "integer", optional: true },
|
|
34
|
+
limit: { type: "integer", nullable: true, optional: true },
|
|
35
|
+
returnType: {
|
|
36
|
+
enum: allowedReturnTypes,
|
|
37
|
+
optional: true,
|
|
38
|
+
},
|
|
39
|
+
groupBy: { type: "boolean", optional: true },
|
|
40
|
+
having: { record: { values: "any" }, optional: true },
|
|
41
|
+
abortSignal: { type: "any", optional: true },
|
|
42
|
+
},
|
|
43
|
+
selectParams,
|
|
44
|
+
"selectParams",
|
|
45
|
+
);
|
|
46
|
+
if (selectParamsValidation.error !== undefined) {
|
|
47
|
+
throw `selectParams validation error: ${JSON.stringify(selectParamsValidation.error)}`;
|
|
48
|
+
}
|
|
49
|
+
selectParamsValidation.data satisfies SelectParams;
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
@@ -44,6 +44,11 @@ export async function getCondition(
|
|
|
44
44
|
const filter = { ...rawFilter };
|
|
45
45
|
|
|
46
46
|
const existsConfigs = getExistsFilters(filter, this);
|
|
47
|
+
const dependencyColumns = existsConfigs.flatMap((existsConfig) =>
|
|
48
|
+
existsConfig.isJoined ?
|
|
49
|
+
(existsConfig.parsedPath[0]?.on.flatMap((columnPair) => Object.keys(columnPair)) ?? [])
|
|
50
|
+
: [],
|
|
51
|
+
);
|
|
47
52
|
|
|
48
53
|
const functionConditions: string[] = [];
|
|
49
54
|
const funcFilter = FILTER_FUNCS.filter((f) => f.name in filter);
|
|
@@ -59,6 +64,7 @@ export async function getCondition(
|
|
|
59
64
|
if (disallowedCols.length) {
|
|
60
65
|
throw `Invalid/disallowed columns found in function filter: ${disallowedCols}`;
|
|
61
66
|
}
|
|
67
|
+
dependencyColumns.push(...fields);
|
|
62
68
|
functionConditions.push(
|
|
63
69
|
f.getQuery({
|
|
64
70
|
args: funcArgs,
|
|
@@ -89,6 +95,7 @@ export async function getCondition(
|
|
|
89
95
|
const compCol = computedFields.find((cf) => cf.name === key);
|
|
90
96
|
if (compCol) {
|
|
91
97
|
if (!p.select) throw new Error("Computed column filter requires p.select.fields");
|
|
98
|
+
dependencyColumns.push(...p.select.fields);
|
|
92
99
|
computedColConditions.push(
|
|
93
100
|
compCol.getQuery({
|
|
94
101
|
tableAliasRaw: tableAlias?.raw,
|
|
@@ -157,14 +164,15 @@ export async function getCondition(
|
|
|
157
164
|
const complexFilters: string[] = [];
|
|
158
165
|
const complexFilterKey = "$filter";
|
|
159
166
|
if (complexFilterKey in filter) {
|
|
160
|
-
const
|
|
167
|
+
const complexFilter = parseComplexFilter({
|
|
161
168
|
filter,
|
|
162
169
|
complexFilterKey,
|
|
163
170
|
tableAliasRaw: tableAlias?.raw,
|
|
164
171
|
allowed_colnames,
|
|
165
172
|
columns: this.columns,
|
|
166
173
|
});
|
|
167
|
-
complexFilters.push(
|
|
174
|
+
complexFilters.push(complexFilter.condition);
|
|
175
|
+
dependencyColumns.push(...complexFilter.columnsUsed);
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
/* Parse join filters
|
|
@@ -238,7 +246,7 @@ export async function getCondition(
|
|
|
238
246
|
|
|
239
247
|
/* sorted to ensure duplicate subscription channels are not created due to different condition order */
|
|
240
248
|
return {
|
|
241
|
-
columnsUsed: q?.columnsUsed ?? [],
|
|
249
|
+
columnsUsed: Array.from(new Set([...(q?.columnsUsed ?? []), ...dependencyColumns])),
|
|
242
250
|
exists: existsConfigs,
|
|
243
251
|
condition: templates.sort().join(" AND \n"),
|
|
244
252
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AnyObject, ParsedJoinPath, SubscribeParams } from "prostgles-types";
|
|
2
|
-
import { asName,
|
|
2
|
+
import { asName, isEmpty, reverseParsedPath } from "prostgles-types";
|
|
3
3
|
import type { ParsedTableRule } from "../PublishParser/PublishParser";
|
|
4
4
|
import type { ViewSubscriptionOptions } from "../PubSubManager/PubSubManager";
|
|
5
5
|
import type { Filter, LocalParams } from "./DboBuilder";
|
|
@@ -36,6 +36,9 @@ export async function getSubscribeRelatedTables(
|
|
|
36
36
|
relatedTables: [],
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
const dependencyExists = newQuery.select
|
|
40
|
+
.filter((item) => item.selected)
|
|
41
|
+
.flatMap((item) => item.dependencyExists ?? []);
|
|
39
42
|
const nonExistsFilter = newQuery.whereOpts.exists.length ? {} : filter;
|
|
40
43
|
const pushRelatedTable = async (
|
|
41
44
|
relatedTableName: string,
|
|
@@ -112,11 +115,15 @@ export async function getSubscribeRelatedTables(
|
|
|
112
115
|
await pushRelatedTable(
|
|
113
116
|
j.table.raw,
|
|
114
117
|
j.joinPath,
|
|
115
|
-
j.select
|
|
118
|
+
j.select
|
|
119
|
+
.filter((item) => item.selected)
|
|
120
|
+
.flatMap((item) => [...item.fields, ...(item.dependencyFields ?? [])]),
|
|
116
121
|
{},
|
|
117
122
|
);
|
|
118
123
|
}
|
|
119
|
-
for (const existsFilter of newQuery.whereOpts.exists.filter(
|
|
124
|
+
for (const existsFilter of [...newQuery.whereOpts.exists, ...dependencyExists].filter(
|
|
125
|
+
(existsFilter) => existsFilter.isJoined,
|
|
126
|
+
)) {
|
|
120
127
|
for (const [index, pathItem] of existsFilter.parsedPath.entries()) {
|
|
121
128
|
const isLast = index === existsFilter.parsedPath.length - 1;
|
|
122
129
|
await pushRelatedTable(
|
|
@@ -200,7 +200,7 @@ export class PubSubManager {
|
|
|
200
200
|
|
|
201
201
|
subs: Subscription[] = [];
|
|
202
202
|
syncs: SyncParams[] = [];
|
|
203
|
-
readonly
|
|
203
|
+
readonly socketChannelPrefix = CHANNELS._preffix;
|
|
204
204
|
postgresNotifListenManager?: PostgresNotifListenManager;
|
|
205
205
|
|
|
206
206
|
private constructor(dboBuilder: DboBuilder) {
|
|
@@ -45,7 +45,7 @@ export async function addSub(
|
|
|
45
45
|
throw "addSub: cannot have socket AND func";
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const channel_name = `${this.
|
|
48
|
+
const channel_name = `${this.socketChannelPrefix}.${table_name}.${JSON.stringify(filter)}.${JSON.stringify(selectParams)}.m.sub`;
|
|
49
49
|
const mainTrigger = {
|
|
50
50
|
table_name: table_name,
|
|
51
51
|
condition: parseCondition(condition),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TableHandler } from "prostgles-types";
|
|
1
|
+
import type { TableHandler, TableHandlerForColumns } from "prostgles-types";
|
|
2
2
|
import type { TableHandlers } from "../DboBuilder/DboBuilder";
|
|
3
3
|
import type { FileTableConfig } from "../ProstglesTypes";
|
|
4
4
|
import type {
|
|
@@ -24,14 +24,14 @@ export const isFileVersionTable = (
|
|
|
24
24
|
Boolean(config?.versioning && getFileVersionTableName(config) === tableName);
|
|
25
25
|
|
|
26
26
|
export const getFileTableHandler = (dbo: TableHandlers, config: FileTableConfig) => {
|
|
27
|
-
const handler = dbo[config.tableName] as
|
|
27
|
+
const handler = dbo[config.tableName] as TableHandlerForColumns<FileTableRow> | undefined;
|
|
28
28
|
if (!handler) throw new Error(`File table not found: ${config.tableName}`);
|
|
29
29
|
return handler;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
export const getFileRevisionsTableHandler = (dbo: TableHandlers, config: FileTableConfig) => {
|
|
33
33
|
const handler = dbo[getFileVersionTableName(config)] as
|
|
34
|
-
TableHandler<
|
|
34
|
+
TableHandler<FileVersionTableSchema, "fileVersions"> | undefined;
|
|
35
35
|
if (!handler) throw new Error(`File table not found: ${config.tableName}`);
|
|
36
36
|
return handler;
|
|
37
37
|
};
|
|
@@ -183,8 +183,6 @@ export const initTableConfig = async function (this: TableConfigurator) {
|
|
|
183
183
|
});
|
|
184
184
|
if (tableColumnDefinition?.isCreate) {
|
|
185
185
|
queries.push(...(constraintDefs?.map((c) => c.alterQuery) ?? []));
|
|
186
|
-
await runQueries(queries);
|
|
187
|
-
await this.prostgles.rebuildDBO();
|
|
188
186
|
} else if (tableColumnDefinition) {
|
|
189
187
|
const fullSchema = await getFutureTableSchema({
|
|
190
188
|
db: this.db,
|
|
@@ -219,10 +217,7 @@ export const initTableConfig = async function (this: TableConfigurator) {
|
|
|
219
217
|
constraintDefs?.forEach((c) => {
|
|
220
218
|
if (!c.name) return;
|
|
221
219
|
const fc = futureCons.find((nc) => nc.name === c.name);
|
|
222
|
-
if (
|
|
223
|
-
fc &&
|
|
224
|
-
!currCons.some((cc) => cc.name === c.name && cc.definition === fc.definition)
|
|
225
|
-
) {
|
|
220
|
+
if (fc && !currCons.some((cc) => cc.name === c.name && cc.definition === fc.definition)) {
|
|
226
221
|
queries.push(`${ALTER_TABLE_Q} ADD CONSTRAINT ${asName(c.name)} ${c.content};`);
|
|
227
222
|
}
|
|
228
223
|
});
|
package/lib/index.ts
CHANGED
|
@@ -45,7 +45,11 @@ export type {
|
|
|
45
45
|
InitResult,
|
|
46
46
|
OnReadyParams,
|
|
47
47
|
} from "./initProstgles";
|
|
48
|
-
export type {
|
|
48
|
+
export type {
|
|
49
|
+
FileTableConfig,
|
|
50
|
+
ProstglesInitOptions,
|
|
51
|
+
TableConfigMigrations,
|
|
52
|
+
} from "./ProstglesTypes";
|
|
49
53
|
export type * from "./TableConfig/TableConfigTypes";
|
|
50
54
|
export type * from "./Audit/AuditTypes";
|
|
51
55
|
export type * from "./TableHooks/TableHooks";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prostgles-server",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.628",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"pg": "^8.23.0",
|
|
58
58
|
"pg-cursor": "^2.22.0",
|
|
59
59
|
"pg-promise": "^12.7.1",
|
|
60
|
-
"prostgles-types": "^4.0.
|
|
60
|
+
"prostgles-types": "^4.0.290"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@eslint/js": "^9.22.0",
|