@adminforth/import-export 1.4.24 → 1.4.26
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/build.log +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +72 -18
- package/index.ts +75 -19
- package/package.json +5 -2
- package/pnpm-workspace.yaml +4 -0
package/build.log
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
7
7
|
authResourceId: string;
|
|
8
8
|
adminforth: IAdminForth;
|
|
9
9
|
constructor(options: PluginOptions);
|
|
10
|
+
private isRowValid;
|
|
10
11
|
modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource): Promise<void>;
|
|
11
12
|
validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource): void;
|
|
12
13
|
instanceUniqueRepresentation(pluginOptions: any): string;
|
package/dist/index.js
CHANGED
|
@@ -7,12 +7,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { AdminForthPlugin, suggestIfTypo, AdminForthFilterOperators, Filters, AdminForthDataTypes } from "adminforth";
|
|
10
|
+
import { AdminForthPlugin, suggestIfTypo, AdminForthFilterOperators, Filters, AdminForthDataTypes, rejectApiRawFilters } from "adminforth";
|
|
11
|
+
import pLimit from 'p-limit';
|
|
11
12
|
export default class ImportExport extends AdminForthPlugin {
|
|
12
13
|
constructor(options) {
|
|
13
14
|
super(options, import.meta.url);
|
|
14
15
|
this.options = options;
|
|
15
16
|
}
|
|
17
|
+
isRowValid(row) {
|
|
18
|
+
let errors = [];
|
|
19
|
+
for (const col of Object.keys(row)) {
|
|
20
|
+
const resourceCol = this.resourceConfig.columns.find(c => c.name === col);
|
|
21
|
+
if (!resourceCol) {
|
|
22
|
+
errors.push(`Column '${col}' not found in resource configuration.`);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (resourceCol.backendOnly) {
|
|
26
|
+
errors.push(`Column '${col}' is backend only and cannot be imported.`);
|
|
27
|
+
}
|
|
28
|
+
if (resourceCol.enum && !resourceCol.enum.some(e => e.value === row[col])) {
|
|
29
|
+
errors.push(`Column '${col}' has an enum of [${resourceCol.enum.map(e => e.label).join(', ')}] but got value '${row[col]}'.`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return errors;
|
|
33
|
+
}
|
|
16
34
|
modifyResourceConfig(adminforth, resourceConfig) {
|
|
17
35
|
const _super = Object.create(null, {
|
|
18
36
|
modifyResourceConfig: { get: () => super.modifyResourceConfig }
|
|
@@ -53,9 +71,12 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
53
71
|
server.endpoint({
|
|
54
72
|
method: 'POST',
|
|
55
73
|
path: `/plugin/${this.pluginInstanceId}/export-csv`,
|
|
56
|
-
noAuth: true,
|
|
57
74
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body }) {
|
|
58
75
|
const { filters, sort } = body;
|
|
76
|
+
const rawFilterError = rejectApiRawFilters(body.filters);
|
|
77
|
+
if (rawFilterError) {
|
|
78
|
+
return rawFilterError;
|
|
79
|
+
}
|
|
59
80
|
const data = yield this.adminforth.connectors[this.resourceConfig.dataSource].getData({
|
|
60
81
|
resource: this.resourceConfig,
|
|
61
82
|
limit: 1e6,
|
|
@@ -65,7 +86,7 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
65
86
|
getTotals: true,
|
|
66
87
|
});
|
|
67
88
|
// prepare data for PapaParse unparse
|
|
68
|
-
const columns = this.resourceConfig.columns.filter((col) => !col.virtual);
|
|
89
|
+
const columns = this.resourceConfig.columns.filter((col) => !col.virtual && !col.backendOnly);
|
|
69
90
|
const columnsToForceQuote = columns.map(col => {
|
|
70
91
|
return col.type !== AdminForthDataTypes.FLOAT
|
|
71
92
|
&& col.type !== AdminForthDataTypes.INTEGER
|
|
@@ -86,11 +107,11 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
86
107
|
server.endpoint({
|
|
87
108
|
method: 'POST',
|
|
88
109
|
path: `/plugin/${this.pluginInstanceId}/import-csv`,
|
|
89
|
-
|
|
90
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body }) {
|
|
110
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, query, headers, cookies, requestUrl, response }) {
|
|
91
111
|
const { data } = body;
|
|
92
112
|
const columns = this.getColumnNames(data);
|
|
93
113
|
const { errors, resourceColumns } = this.validateColumns(columns);
|
|
114
|
+
const resource = this.adminforth.config.resources.find(r => r.resourceId === this.resourceConfig.resourceId);
|
|
94
115
|
if (errors.length > 0) {
|
|
95
116
|
return { ok: false, errors };
|
|
96
117
|
}
|
|
@@ -99,35 +120,58 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
99
120
|
console.log('Prepared rows for import:', rows);
|
|
100
121
|
let importedCount = 0;
|
|
101
122
|
let updatedCount = 0;
|
|
102
|
-
|
|
123
|
+
const limit = pLimit(100);
|
|
124
|
+
yield Promise.all(rows.map((row) => limit(() => __awaiter(this, void 0, void 0, function* () {
|
|
103
125
|
try {
|
|
104
|
-
|
|
126
|
+
const rowErrors = yield this.isRowValid(row);
|
|
127
|
+
if (rowErrors.length > 0) {
|
|
128
|
+
errors.push(...rowErrors);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const recordId = primaryKeyColumn ? row[primaryKeyColumn.name] : undefined;
|
|
132
|
+
if (primaryKeyColumn && recordId) {
|
|
105
133
|
const existingRecord = yield this.adminforth.resource(this.resourceConfig.resourceId)
|
|
106
|
-
.list([Filters.EQ(primaryKeyColumn.name,
|
|
134
|
+
.list([Filters.EQ(primaryKeyColumn.name, recordId)]);
|
|
107
135
|
if (existingRecord.length > 0) {
|
|
108
|
-
|
|
109
|
-
|
|
136
|
+
const connector = this.adminforth.connectors[resource.dataSource];
|
|
137
|
+
const oldRecord = yield connector.getRecordByPrimaryKey(resource, recordId);
|
|
138
|
+
if (!oldRecord) {
|
|
139
|
+
const primaryKeyColumn = resource.columns.find((col) => col.primaryKey);
|
|
140
|
+
return { error: `Record with ${primaryKeyColumn.name} ${recordId} not found` };
|
|
141
|
+
}
|
|
142
|
+
const { error } = yield this.adminforth.updateResourceRecord({
|
|
143
|
+
resource, updates: row, adminUser, oldRecord, recordId, response,
|
|
144
|
+
extra: { body, query, headers, cookies, requestUrl, response }
|
|
145
|
+
});
|
|
146
|
+
if (error) {
|
|
147
|
+
return { error };
|
|
148
|
+
}
|
|
110
149
|
updatedCount++;
|
|
111
150
|
return;
|
|
112
151
|
}
|
|
113
152
|
}
|
|
114
|
-
yield this.adminforth.
|
|
153
|
+
yield this.adminforth.createResourceRecord({
|
|
154
|
+
resource: resource,
|
|
155
|
+
record: row,
|
|
156
|
+
adminUser: adminUser,
|
|
157
|
+
extra: { body, query, headers, cookies, requestUrl, response }
|
|
158
|
+
});
|
|
115
159
|
importedCount++;
|
|
116
160
|
}
|
|
117
161
|
catch (e) {
|
|
118
162
|
errors.push(e.message);
|
|
119
163
|
}
|
|
120
|
-
})));
|
|
164
|
+
}))));
|
|
121
165
|
return { ok: true, importedCount, updatedCount, errors };
|
|
122
166
|
})
|
|
123
167
|
});
|
|
124
168
|
server.endpoint({
|
|
125
169
|
method: 'POST',
|
|
126
170
|
path: `/plugin/${this.pluginInstanceId}/import-csv-new-only`,
|
|
127
|
-
|
|
128
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body }) {
|
|
171
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, query, headers, cookies, requestUrl, response }) {
|
|
129
172
|
const { data } = body;
|
|
130
173
|
const columns = this.getColumnNames(data);
|
|
174
|
+
const resource = this.adminforth.config.resources.find(r => r.resourceId === this.resourceConfig.resourceId);
|
|
131
175
|
const { errors, resourceColumns } = this.validateColumns(columns);
|
|
132
176
|
if (errors.length > 0) {
|
|
133
177
|
return { ok: false, errors };
|
|
@@ -135,8 +179,14 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
135
179
|
const primaryKeyColumn = this.resourceConfig.columns.find(col => col.primaryKey);
|
|
136
180
|
const rows = this.buildRowsFromData(data, columns, resourceColumns, { coerceTypes: true });
|
|
137
181
|
let importedCount = 0;
|
|
138
|
-
|
|
182
|
+
const limit = pLimit(100);
|
|
183
|
+
yield Promise.all(rows.map((row) => limit(() => __awaiter(this, void 0, void 0, function* () {
|
|
139
184
|
try {
|
|
185
|
+
const rowErrors = yield this.isRowValid(row);
|
|
186
|
+
if (rowErrors.length > 0) {
|
|
187
|
+
errors.push(...rowErrors);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
140
190
|
if (primaryKeyColumn && row[primaryKeyColumn.name]) {
|
|
141
191
|
const existingRecord = yield this.adminforth.resource(this.resourceConfig.resourceId)
|
|
142
192
|
.list([Filters.EQ(primaryKeyColumn.name, row[primaryKeyColumn.name])]);
|
|
@@ -144,20 +194,24 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
144
194
|
return;
|
|
145
195
|
}
|
|
146
196
|
}
|
|
147
|
-
yield this.adminforth.
|
|
197
|
+
yield this.adminforth.createResourceRecord({
|
|
198
|
+
resource: resource,
|
|
199
|
+
record: row,
|
|
200
|
+
adminUser: adminUser,
|
|
201
|
+
extra: { body, query, headers, cookies, requestUrl, response }
|
|
202
|
+
});
|
|
148
203
|
importedCount++;
|
|
149
204
|
}
|
|
150
205
|
catch (e) {
|
|
151
206
|
errors.push(e.message);
|
|
152
207
|
}
|
|
153
|
-
})));
|
|
208
|
+
}))));
|
|
154
209
|
return { ok: true, importedCount, errors };
|
|
155
210
|
})
|
|
156
211
|
});
|
|
157
212
|
server.endpoint({
|
|
158
213
|
method: 'POST',
|
|
159
214
|
path: `/plugin/${this.pluginInstanceId}/check-records`,
|
|
160
|
-
noAuth: true,
|
|
161
215
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body }) {
|
|
162
216
|
const { data } = body;
|
|
163
217
|
const primaryKeyColumn = this.resourceConfig.columns.find(col => col.primaryKey);
|
package/index.ts
CHANGED
|
@@ -1,18 +1,38 @@
|
|
|
1
|
-
import { AdminForthPlugin, suggestIfTypo, AdminForthFilterOperators, Filters, AdminForthDataTypes } from "adminforth";
|
|
1
|
+
import { AdminForthPlugin, suggestIfTypo, AdminForthFilterOperators, Filters, AdminForthDataTypes, rejectApiRawFilters } from "adminforth";
|
|
2
2
|
import type { IAdminForth, IHttpServer, AdminForthResourceColumn, AdminForthComponentDeclaration, AdminForthResource } from "adminforth";
|
|
3
3
|
import type { PluginOptions } from './types.js';
|
|
4
|
+
import pLimit from 'p-limit';
|
|
4
5
|
|
|
5
6
|
export default class ImportExport extends AdminForthPlugin {
|
|
6
7
|
options: PluginOptions;
|
|
7
8
|
emailField: AdminForthResourceColumn;
|
|
8
9
|
authResourceId: string;
|
|
9
10
|
adminforth: IAdminForth;
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
constructor(options: PluginOptions) {
|
|
12
14
|
super(options, import.meta.url);
|
|
13
15
|
this.options = options;
|
|
14
16
|
}
|
|
15
17
|
|
|
18
|
+
private isRowValid(row: Record<string, unknown>): string[] {
|
|
19
|
+
let errors = [];
|
|
20
|
+
for (const col of Object.keys(row)) {
|
|
21
|
+
const resourceCol = this.resourceConfig.columns.find(c => c.name === col);
|
|
22
|
+
if (!resourceCol) {
|
|
23
|
+
errors.push(`Column '${col}' not found in resource configuration.`);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (resourceCol.backendOnly) {
|
|
27
|
+
errors.push(`Column '${col}' is backend only and cannot be imported.`);
|
|
28
|
+
}
|
|
29
|
+
if (resourceCol.enum && !resourceCol.enum.some(e => e.value === row[col])) {
|
|
30
|
+
errors.push(`Column '${col}' has an enum of [${resourceCol.enum.map(e => e.label).join(', ')}] but got value '${row[col]}'.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return errors;
|
|
34
|
+
}
|
|
35
|
+
|
|
16
36
|
async modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
|
|
17
37
|
super.modifyResourceConfig(adminforth, resourceConfig);
|
|
18
38
|
if (!resourceConfig.options.pageInjections) {
|
|
@@ -53,10 +73,12 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
53
73
|
server.endpoint({
|
|
54
74
|
method: 'POST',
|
|
55
75
|
path: `/plugin/${this.pluginInstanceId}/export-csv`,
|
|
56
|
-
noAuth: true,
|
|
57
76
|
handler: async ({ body }) => {
|
|
58
77
|
const { filters, sort } = body;
|
|
59
|
-
|
|
78
|
+
const rawFilterError = rejectApiRawFilters(body.filters);
|
|
79
|
+
if (rawFilterError) {
|
|
80
|
+
return rawFilterError;
|
|
81
|
+
}
|
|
60
82
|
const data = await this.adminforth.connectors[this.resourceConfig.dataSource].getData({
|
|
61
83
|
resource: this.resourceConfig,
|
|
62
84
|
limit: 1e6,
|
|
@@ -67,7 +89,7 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
67
89
|
});
|
|
68
90
|
|
|
69
91
|
// prepare data for PapaParse unparse
|
|
70
|
-
const columns = this.resourceConfig.columns.filter((col) => !col.virtual);
|
|
92
|
+
const columns = this.resourceConfig.columns.filter((col) => !col.virtual && !col.backendOnly);
|
|
71
93
|
|
|
72
94
|
const columnsToForceQuote = columns.map(col => {
|
|
73
95
|
return col.type !== AdminForthDataTypes.FLOAT
|
|
@@ -93,11 +115,12 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
93
115
|
server.endpoint({
|
|
94
116
|
method: 'POST',
|
|
95
117
|
path: `/plugin/${this.pluginInstanceId}/import-csv`,
|
|
96
|
-
|
|
97
|
-
handler: async ({ body }) => {
|
|
118
|
+
handler: async ({ body, adminUser, query, headers, cookies, requestUrl, response }) => {
|
|
98
119
|
const { data } = body;
|
|
99
120
|
const columns = this.getColumnNames(data);
|
|
100
121
|
const { errors, resourceColumns } = this.validateColumns(columns);
|
|
122
|
+
const resource = this.adminforth.config.resources.find(r => r.resourceId === this.resourceConfig.resourceId);
|
|
123
|
+
|
|
101
124
|
if (errors.length > 0) {
|
|
102
125
|
return { ok: false, errors };
|
|
103
126
|
}
|
|
@@ -108,26 +131,49 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
108
131
|
|
|
109
132
|
let importedCount = 0;
|
|
110
133
|
let updatedCount = 0;
|
|
134
|
+
const limit = pLimit(100);
|
|
111
135
|
|
|
112
|
-
await Promise.all(rows.map(async (
|
|
136
|
+
await Promise.all(rows.map((row) => limit(async () => {
|
|
113
137
|
try {
|
|
114
|
-
|
|
138
|
+
const rowErrors = await this.isRowValid(row);
|
|
139
|
+
if (rowErrors.length > 0) {
|
|
140
|
+
errors.push(...rowErrors);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const recordId = primaryKeyColumn ? row[primaryKeyColumn.name] as string : undefined;
|
|
144
|
+
if (primaryKeyColumn && recordId) {
|
|
115
145
|
const existingRecord = await this.adminforth.resource(this.resourceConfig.resourceId)
|
|
116
|
-
.list([Filters.EQ(primaryKeyColumn.name,
|
|
146
|
+
.list([Filters.EQ(primaryKeyColumn.name, recordId)]);
|
|
117
147
|
|
|
118
148
|
if (existingRecord.length > 0) {
|
|
119
|
-
|
|
120
|
-
|
|
149
|
+
const connector = this.adminforth.connectors[resource.dataSource];
|
|
150
|
+
const oldRecord = await connector.getRecordByPrimaryKey(resource, recordId)
|
|
151
|
+
if (!oldRecord) {
|
|
152
|
+
const primaryKeyColumn = resource.columns.find((col) => col.primaryKey);
|
|
153
|
+
return { error: `Record with ${primaryKeyColumn.name} ${recordId} not found` };
|
|
154
|
+
}
|
|
155
|
+
const { error } = await this.adminforth.updateResourceRecord({
|
|
156
|
+
resource, updates: row, adminUser, oldRecord, recordId, response,
|
|
157
|
+
extra: { body, query, headers, cookies, requestUrl, response }
|
|
158
|
+
});
|
|
159
|
+
if (error) {
|
|
160
|
+
return { error };
|
|
161
|
+
}
|
|
121
162
|
updatedCount++;
|
|
122
163
|
return;
|
|
123
164
|
}
|
|
124
165
|
}
|
|
125
|
-
await this.adminforth.
|
|
166
|
+
await this.adminforth.createResourceRecord({
|
|
167
|
+
resource: resource,
|
|
168
|
+
record: row,
|
|
169
|
+
adminUser: adminUser,
|
|
170
|
+
extra: { body, query, headers, cookies, requestUrl, response }
|
|
171
|
+
});
|
|
126
172
|
importedCount++;
|
|
127
173
|
} catch (e) {
|
|
128
174
|
errors.push(e.message);
|
|
129
175
|
}
|
|
130
|
-
}));
|
|
176
|
+
})));
|
|
131
177
|
|
|
132
178
|
return { ok: true, importedCount, updatedCount, errors };
|
|
133
179
|
}
|
|
@@ -136,10 +182,10 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
136
182
|
server.endpoint({
|
|
137
183
|
method: 'POST',
|
|
138
184
|
path: `/plugin/${this.pluginInstanceId}/import-csv-new-only`,
|
|
139
|
-
|
|
140
|
-
handler: async ({ body }) => {
|
|
185
|
+
handler: async ({ body, adminUser, query, headers, cookies, requestUrl, response }) => {
|
|
141
186
|
const { data } = body;
|
|
142
187
|
const columns = this.getColumnNames(data);
|
|
188
|
+
const resource = this.adminforth.config.resources.find(r => r.resourceId === this.resourceConfig.resourceId);
|
|
143
189
|
const { errors, resourceColumns } = this.validateColumns(columns);
|
|
144
190
|
if (errors.length > 0) {
|
|
145
191
|
return { ok: false, errors };
|
|
@@ -149,9 +195,15 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
149
195
|
const rows = this.buildRowsFromData(data, columns, resourceColumns, { coerceTypes: true });
|
|
150
196
|
|
|
151
197
|
let importedCount = 0;
|
|
198
|
+
const limit = pLimit(100);
|
|
152
199
|
|
|
153
|
-
await Promise.all(rows.map(async (
|
|
200
|
+
await Promise.all(rows.map((row) => limit(async () => {
|
|
154
201
|
try {
|
|
202
|
+
const rowErrors = await this.isRowValid(row);
|
|
203
|
+
if (rowErrors.length > 0) {
|
|
204
|
+
errors.push(...rowErrors);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
155
207
|
if (primaryKeyColumn && row[primaryKeyColumn.name]) {
|
|
156
208
|
const existingRecord = await this.adminforth.resource(this.resourceConfig.resourceId)
|
|
157
209
|
.list([Filters.EQ(primaryKeyColumn.name, row[primaryKeyColumn.name])]);
|
|
@@ -160,12 +212,17 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
160
212
|
return;
|
|
161
213
|
}
|
|
162
214
|
}
|
|
163
|
-
await this.adminforth.
|
|
215
|
+
await this.adminforth.createResourceRecord({
|
|
216
|
+
resource: resource,
|
|
217
|
+
record: row,
|
|
218
|
+
adminUser: adminUser,
|
|
219
|
+
extra: { body, query, headers, cookies, requestUrl, response }
|
|
220
|
+
});
|
|
164
221
|
importedCount++;
|
|
165
222
|
} catch (e) {
|
|
166
223
|
errors.push(e.message);
|
|
167
224
|
}
|
|
168
|
-
}));
|
|
225
|
+
})));
|
|
169
226
|
|
|
170
227
|
return { ok: true, importedCount, errors };
|
|
171
228
|
}
|
|
@@ -174,7 +231,6 @@ export default class ImportExport extends AdminForthPlugin {
|
|
|
174
231
|
server.endpoint({
|
|
175
232
|
method: 'POST',
|
|
176
233
|
path: `/plugin/${this.pluginInstanceId}/check-records`,
|
|
177
|
-
noAuth: true,
|
|
178
234
|
handler: async ({ body }) => {
|
|
179
235
|
const { data } = body as { data: Record<string, unknown[]> };
|
|
180
236
|
const primaryKeyColumn = this.resourceConfig.columns.find(col => col.primaryKey);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminforth/import-export",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.26",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^22.10.7",
|
|
32
|
-
"adminforth": "^3.
|
|
32
|
+
"adminforth": "^3.4.0",
|
|
33
33
|
"semantic-release": "^24.2.1",
|
|
34
34
|
"semantic-release-slack-bot": "^4.0.2",
|
|
35
35
|
"typescript": "^5.7.3"
|
|
@@ -58,5 +58,8 @@
|
|
|
58
58
|
"prerelease": true
|
|
59
59
|
}
|
|
60
60
|
]
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"p-limit": "^7.3.0"
|
|
61
64
|
}
|
|
62
65
|
}
|