s3db.js 7.3.6 → 7.3.9
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/s3db.cjs.js +117 -31
- package/dist/s3db.cjs.min.js +1 -1
- package/dist/s3db.es.js +117 -31
- package/dist/s3db.es.min.js +1 -1
- package/dist/s3db.iife.js +117 -31
- package/dist/s3db.iife.min.js +1 -1
- package/package.json +1 -1
- package/src/plugins/replicators/bigquery-replicator.class.js +106 -52
- package/src/plugins/replicators/postgres-replicator.class.js +34 -4
- package/src/plugins/replicators/s3db-replicator.class.js +34 -11
- package/src/plugins/replicators/sqs-replicator.class.js +28 -5
package/dist/s3db.iife.js
CHANGED
|
@@ -8983,11 +8983,21 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
8983
8983
|
}));
|
|
8984
8984
|
}
|
|
8985
8985
|
applyTransform(data, transformFn) {
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8986
|
+
let cleanData = this._cleanInternalFields(data);
|
|
8987
|
+
if (!transformFn) return cleanData;
|
|
8988
|
+
let transformedData = JSON.parse(JSON.stringify(cleanData));
|
|
8989
8989
|
return transformFn(transformedData);
|
|
8990
8990
|
}
|
|
8991
|
+
_cleanInternalFields(data) {
|
|
8992
|
+
if (!data || typeof data !== "object") return data;
|
|
8993
|
+
const cleanData = { ...data };
|
|
8994
|
+
Object.keys(cleanData).forEach((key) => {
|
|
8995
|
+
if (key.startsWith("$") || key.startsWith("_")) {
|
|
8996
|
+
delete cleanData[key];
|
|
8997
|
+
}
|
|
8998
|
+
});
|
|
8999
|
+
return cleanData;
|
|
9000
|
+
}
|
|
8991
9001
|
async replicate(resourceName, operation, data, id, beforeData = null) {
|
|
8992
9002
|
if (!this.enabled || !this.shouldReplicateResource(resourceName)) {
|
|
8993
9003
|
return { skipped: true, reason: "resource_not_included" };
|
|
@@ -9009,7 +9019,17 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9009
9019
|
let job;
|
|
9010
9020
|
if (operation === "insert") {
|
|
9011
9021
|
const transformedData = this.applyTransform(data, tableConfig.transform);
|
|
9012
|
-
|
|
9022
|
+
try {
|
|
9023
|
+
job = await table.insert([transformedData]);
|
|
9024
|
+
} catch (error) {
|
|
9025
|
+
const { errors: errors2, response } = error;
|
|
9026
|
+
if (this.config.verbose) {
|
|
9027
|
+
console.error("[BigqueryReplicator] BigQuery insert error details:");
|
|
9028
|
+
if (errors2) console.error("Errors:", JSON.stringify(errors2, null, 2));
|
|
9029
|
+
if (response) console.error("Response:", JSON.stringify(response, null, 2));
|
|
9030
|
+
}
|
|
9031
|
+
throw error;
|
|
9032
|
+
}
|
|
9013
9033
|
} else if (operation === "update") {
|
|
9014
9034
|
const transformedData = this.applyTransform(data, tableConfig.transform);
|
|
9015
9035
|
const keys = Object.keys(transformedData).filter((k) => k !== "id");
|
|
@@ -9035,6 +9055,10 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9035
9055
|
lastError = error;
|
|
9036
9056
|
if (this.config.verbose) {
|
|
9037
9057
|
console.warn(`[BigqueryReplicator] Update attempt ${attempt} failed: ${error.message}`);
|
|
9058
|
+
if (error.errors) {
|
|
9059
|
+
console.error("[BigqueryReplicator] BigQuery update error details:");
|
|
9060
|
+
console.error("Errors:", JSON.stringify(error.errors, null, 2));
|
|
9061
|
+
}
|
|
9038
9062
|
}
|
|
9039
9063
|
if (error?.message?.includes("streaming buffer") && attempt < maxRetries) {
|
|
9040
9064
|
const delaySeconds = 30;
|
|
@@ -9050,13 +9074,23 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9050
9074
|
if (!job) throw lastError;
|
|
9051
9075
|
} else if (operation === "delete") {
|
|
9052
9076
|
const query = `DELETE FROM \`${this.projectId}.${this.datasetId}.${tableConfig.table}\` WHERE id = @id`;
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9077
|
+
try {
|
|
9078
|
+
const [deleteJob] = await this.bigqueryClient.createQueryJob({
|
|
9079
|
+
query,
|
|
9080
|
+
params: { id },
|
|
9081
|
+
location: this.location
|
|
9082
|
+
});
|
|
9083
|
+
await deleteJob.getQueryResults();
|
|
9084
|
+
job = [deleteJob];
|
|
9085
|
+
} catch (error) {
|
|
9086
|
+
if (this.config.verbose) {
|
|
9087
|
+
console.error("[BigqueryReplicator] BigQuery delete error details:");
|
|
9088
|
+
console.error("Query:", query);
|
|
9089
|
+
if (error.errors) console.error("Errors:", JSON.stringify(error.errors, null, 2));
|
|
9090
|
+
if (error.response) console.error("Response:", JSON.stringify(error.response, null, 2));
|
|
9091
|
+
}
|
|
9092
|
+
throw error;
|
|
9093
|
+
}
|
|
9060
9094
|
} else {
|
|
9061
9095
|
throw new Error(`Unsupported operation: ${operation}`);
|
|
9062
9096
|
}
|
|
@@ -9089,6 +9123,9 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9089
9123
|
}
|
|
9090
9124
|
}
|
|
9091
9125
|
const success = errors.length === 0;
|
|
9126
|
+
if (errors.length > 0) {
|
|
9127
|
+
console.warn(`[BigqueryReplicator] Replication completed with errors for ${resourceName}:`, errors);
|
|
9128
|
+
}
|
|
9092
9129
|
this.emit("replicated", {
|
|
9093
9130
|
replicator: this.name,
|
|
9094
9131
|
resourceName,
|
|
@@ -9139,6 +9176,9 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9139
9176
|
errors.push({ id: record.id, error: err.message });
|
|
9140
9177
|
}
|
|
9141
9178
|
}
|
|
9179
|
+
if (errors.length > 0) {
|
|
9180
|
+
console.warn(`[BigqueryReplicator] Batch replication completed with ${errors.length} error(s) for ${resourceName}:`, errors);
|
|
9181
|
+
}
|
|
9142
9182
|
return {
|
|
9143
9183
|
success: errors.length === 0,
|
|
9144
9184
|
results,
|
|
@@ -9325,16 +9365,18 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9325
9365
|
const [okTable, errTable] = await try_fn_default(async () => {
|
|
9326
9366
|
let result2;
|
|
9327
9367
|
if (operation === "insert") {
|
|
9328
|
-
const
|
|
9329
|
-
const
|
|
9368
|
+
const cleanData = this._cleanInternalFields(data);
|
|
9369
|
+
const keys = Object.keys(cleanData);
|
|
9370
|
+
const values = keys.map((k) => cleanData[k]);
|
|
9330
9371
|
const columns = keys.map((k) => `"${k}"`).join(", ");
|
|
9331
9372
|
const params = keys.map((_, i) => `$${i + 1}`).join(", ");
|
|
9332
9373
|
const sql = `INSERT INTO ${table} (${columns}) VALUES (${params}) ON CONFLICT (id) DO NOTHING RETURNING *`;
|
|
9333
9374
|
result2 = await this.client.query(sql, values);
|
|
9334
9375
|
} else if (operation === "update") {
|
|
9335
|
-
const
|
|
9376
|
+
const cleanData = this._cleanInternalFields(data);
|
|
9377
|
+
const keys = Object.keys(cleanData).filter((k) => k !== "id");
|
|
9336
9378
|
const setClause = keys.map((k, i) => `"${k}"=$${i + 1}`).join(", ");
|
|
9337
|
-
const values = keys.map((k) =>
|
|
9379
|
+
const values = keys.map((k) => cleanData[k]);
|
|
9338
9380
|
values.push(id);
|
|
9339
9381
|
const sql = `UPDATE ${table} SET ${setClause} WHERE id=$${keys.length + 1} RETURNING *`;
|
|
9340
9382
|
result2 = await this.client.query(sql, values);
|
|
@@ -9369,6 +9411,9 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9369
9411
|
}
|
|
9370
9412
|
}
|
|
9371
9413
|
const success = errors.length === 0;
|
|
9414
|
+
if (errors.length > 0) {
|
|
9415
|
+
console.warn(`[PostgresReplicator] Replication completed with errors for ${resourceName}:`, errors);
|
|
9416
|
+
}
|
|
9372
9417
|
this.emit("replicated", {
|
|
9373
9418
|
replicator: this.name,
|
|
9374
9419
|
resourceName,
|
|
@@ -9419,6 +9464,9 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9419
9464
|
errors.push({ id: record.id, error: err.message });
|
|
9420
9465
|
}
|
|
9421
9466
|
}
|
|
9467
|
+
if (errors.length > 0) {
|
|
9468
|
+
console.warn(`[PostgresReplicator] Batch replication completed with ${errors.length} error(s) for ${resourceName}:`, errors);
|
|
9469
|
+
}
|
|
9422
9470
|
return {
|
|
9423
9471
|
success: errors.length === 0,
|
|
9424
9472
|
results,
|
|
@@ -9438,6 +9486,16 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
9438
9486
|
this.emit("connection_error", { replicator: this.name, error: err.message });
|
|
9439
9487
|
return false;
|
|
9440
9488
|
}
|
|
9489
|
+
_cleanInternalFields(data) {
|
|
9490
|
+
if (!data || typeof data !== "object") return data;
|
|
9491
|
+
const cleanData = { ...data };
|
|
9492
|
+
Object.keys(cleanData).forEach((key) => {
|
|
9493
|
+
if (key.startsWith("$") || key.startsWith("_")) {
|
|
9494
|
+
delete cleanData[key];
|
|
9495
|
+
}
|
|
9496
|
+
});
|
|
9497
|
+
return cleanData;
|
|
9498
|
+
}
|
|
9441
9499
|
async cleanup() {
|
|
9442
9500
|
if (this.client) await this.client.end();
|
|
9443
9501
|
}
|
|
@@ -13169,7 +13227,7 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
13169
13227
|
super();
|
|
13170
13228
|
this.version = "1";
|
|
13171
13229
|
this.s3dbVersion = (() => {
|
|
13172
|
-
const [ok, err, version] = try_fn_default(() => true ? "7.3.
|
|
13230
|
+
const [ok, err, version] = try_fn_default(() => true ? "7.3.8" : "latest");
|
|
13173
13231
|
return ok ? version : "latest";
|
|
13174
13232
|
})();
|
|
13175
13233
|
this.resources = {};
|
|
@@ -13833,36 +13891,47 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
13833
13891
|
return result;
|
|
13834
13892
|
}
|
|
13835
13893
|
_applyTransformer(resource, data) {
|
|
13894
|
+
let cleanData = this._cleanInternalFields(data);
|
|
13836
13895
|
const normResource = normalizeResourceName$1(resource);
|
|
13837
13896
|
const entry = this.resourcesMap[normResource];
|
|
13838
13897
|
let result;
|
|
13839
|
-
if (!entry) return
|
|
13898
|
+
if (!entry) return cleanData;
|
|
13840
13899
|
if (Array.isArray(entry)) {
|
|
13841
13900
|
for (const item of entry) {
|
|
13842
13901
|
if (typeof item === "object" && item.transform && typeof item.transform === "function") {
|
|
13843
|
-
result = item.transform(
|
|
13902
|
+
result = item.transform(cleanData);
|
|
13844
13903
|
break;
|
|
13845
13904
|
} else if (typeof item === "object" && item.transformer && typeof item.transformer === "function") {
|
|
13846
|
-
result = item.transformer(
|
|
13905
|
+
result = item.transformer(cleanData);
|
|
13847
13906
|
break;
|
|
13848
13907
|
}
|
|
13849
13908
|
}
|
|
13850
|
-
if (!result) result =
|
|
13909
|
+
if (!result) result = cleanData;
|
|
13851
13910
|
} else if (typeof entry === "object") {
|
|
13852
13911
|
if (typeof entry.transform === "function") {
|
|
13853
|
-
result = entry.transform(
|
|
13912
|
+
result = entry.transform(cleanData);
|
|
13854
13913
|
} else if (typeof entry.transformer === "function") {
|
|
13855
|
-
result = entry.transformer(
|
|
13914
|
+
result = entry.transformer(cleanData);
|
|
13856
13915
|
}
|
|
13857
13916
|
} else if (typeof entry === "function") {
|
|
13858
|
-
result = entry(
|
|
13917
|
+
result = entry(cleanData);
|
|
13859
13918
|
} else {
|
|
13860
|
-
result =
|
|
13919
|
+
result = cleanData;
|
|
13861
13920
|
}
|
|
13862
|
-
if (result &&
|
|
13863
|
-
if (!result &&
|
|
13921
|
+
if (result && cleanData && cleanData.id && !result.id) result.id = cleanData.id;
|
|
13922
|
+
if (!result && cleanData) result = cleanData;
|
|
13864
13923
|
return result;
|
|
13865
13924
|
}
|
|
13925
|
+
_cleanInternalFields(data) {
|
|
13926
|
+
if (!data || typeof data !== "object") return data;
|
|
13927
|
+
const cleanData = { ...data };
|
|
13928
|
+
Object.keys(cleanData).forEach((key) => {
|
|
13929
|
+
if (key.startsWith("$") || key.startsWith("_")) {
|
|
13930
|
+
delete cleanData[key];
|
|
13931
|
+
}
|
|
13932
|
+
});
|
|
13933
|
+
return cleanData;
|
|
13934
|
+
}
|
|
13866
13935
|
_resolveDestResource(resource, data) {
|
|
13867
13936
|
const normResource = normalizeResourceName$1(resource);
|
|
13868
13937
|
const entry = this.resourcesMap[normResource];
|
|
@@ -13911,6 +13980,9 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
13911
13980
|
errors.push({ id: record.id, error: err.message });
|
|
13912
13981
|
}
|
|
13913
13982
|
}
|
|
13983
|
+
if (errors.length > 0) {
|
|
13984
|
+
console.warn(`[S3dbReplicator] Batch replication completed with ${errors.length} error(s) for ${resourceName}:`, errors);
|
|
13985
|
+
}
|
|
13914
13986
|
this.emit("batch_replicated", {
|
|
13915
13987
|
replicator: this.name,
|
|
13916
13988
|
resourceName,
|
|
@@ -14049,15 +14121,26 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
14049
14121
|
throw new Error(`No queue URL found for resource '${resource}'`);
|
|
14050
14122
|
}
|
|
14051
14123
|
_applyTransformer(resource, data) {
|
|
14124
|
+
let cleanData = this._cleanInternalFields(data);
|
|
14052
14125
|
const entry = this.resources[resource];
|
|
14053
|
-
let result =
|
|
14054
|
-
if (!entry) return
|
|
14126
|
+
let result = cleanData;
|
|
14127
|
+
if (!entry) return cleanData;
|
|
14055
14128
|
if (typeof entry.transform === "function") {
|
|
14056
|
-
result = entry.transform(
|
|
14129
|
+
result = entry.transform(cleanData);
|
|
14057
14130
|
} else if (typeof entry.transformer === "function") {
|
|
14058
|
-
result = entry.transformer(
|
|
14131
|
+
result = entry.transformer(cleanData);
|
|
14059
14132
|
}
|
|
14060
|
-
return result ||
|
|
14133
|
+
return result || cleanData;
|
|
14134
|
+
}
|
|
14135
|
+
_cleanInternalFields(data) {
|
|
14136
|
+
if (!data || typeof data !== "object") return data;
|
|
14137
|
+
const cleanData = { ...data };
|
|
14138
|
+
Object.keys(cleanData).forEach((key) => {
|
|
14139
|
+
if (key.startsWith("$") || key.startsWith("_")) {
|
|
14140
|
+
delete cleanData[key];
|
|
14141
|
+
}
|
|
14142
|
+
});
|
|
14143
|
+
return cleanData;
|
|
14061
14144
|
}
|
|
14062
14145
|
/**
|
|
14063
14146
|
* Create standardized message structure
|
|
@@ -14208,6 +14291,9 @@ ${JSON.stringify(validation, null, 2)}`,
|
|
|
14208
14291
|
}
|
|
14209
14292
|
}
|
|
14210
14293
|
}
|
|
14294
|
+
if (errors.length > 0) {
|
|
14295
|
+
console.warn(`[SqsReplicator] Batch replication completed with ${errors.length} error(s) for ${resource}:`, errors);
|
|
14296
|
+
}
|
|
14211
14297
|
this.emit("batch_replicated", {
|
|
14212
14298
|
replicator: this.name,
|
|
14213
14299
|
resource,
|