s3db.js 11.0.0 → 11.0.2
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 +55 -2
- package/dist/s3db.cjs.js.map +1 -1
- package/dist/s3db.es.js +55 -2
- package/dist/s3db.es.js.map +1 -1
- package/package.json +2 -1
- package/src/plugins/eventual-consistency/analytics.js +12 -0
- package/src/plugins/eventual-consistency/consolidation.js +55 -1
- package/dist/s3db-cli.js +0 -54741
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "s3db.js",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.2",
|
|
4
4
|
"description": "Use AWS S3, the world's most reliable document storage, as a database with this ORM.",
|
|
5
5
|
"main": "dist/s3db.cjs.js",
|
|
6
6
|
"module": "dist/s3db.es.js",
|
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"dev": "rollup -c -w",
|
|
134
134
|
"test": "pnpm run test:js && pnpm run test:ts",
|
|
135
135
|
"test:js": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
136
|
+
"test:quick": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js --maxWorkers=2 --bail",
|
|
136
137
|
"test:ts": "tsc --noEmit --project tests/typescript/tsconfig.json",
|
|
137
138
|
"test:coverage": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js --coverage --maxWorkers=1",
|
|
138
139
|
"test:serial": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js --runInBand",
|
|
@@ -17,6 +17,18 @@ import { groupByCohort } from "./utils.js";
|
|
|
17
17
|
export async function updateAnalytics(transactions, analyticsResource, config) {
|
|
18
18
|
if (!analyticsResource || transactions.length === 0) return;
|
|
19
19
|
|
|
20
|
+
// CRITICAL VALIDATION: Ensure field is set in config
|
|
21
|
+
// This can be undefined due to race conditions when multiple handlers share config
|
|
22
|
+
if (!config.field) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`[EventualConsistency] CRITICAL BUG: config.field is undefined in updateAnalytics()!\n` +
|
|
25
|
+
`This indicates a race condition in the plugin where multiple handlers are sharing the same config object.\n` +
|
|
26
|
+
`Config: ${JSON.stringify({ resource: config.resource, field: config.field })}\n` +
|
|
27
|
+
`Transactions count: ${transactions.length}\n` +
|
|
28
|
+
`AnalyticsResource: ${analyticsResource?.name || 'unknown'}`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
if (config.verbose) {
|
|
21
33
|
console.log(
|
|
22
34
|
`[EventualConsistency] ${config.resource}.${config.field} - ` +
|
|
@@ -413,17 +413,71 @@ export async function consolidateRecord(
|
|
|
413
413
|
);
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
+
// 🔥 DEBUG: Log BEFORE update
|
|
417
|
+
if (config.verbose) {
|
|
418
|
+
console.log(
|
|
419
|
+
`🔥 [DEBUG] BEFORE targetResource.update() {` +
|
|
420
|
+
`\n originalId: '${originalId}',` +
|
|
421
|
+
`\n field: '${config.field}',` +
|
|
422
|
+
`\n consolidatedValue: ${consolidatedValue},` +
|
|
423
|
+
`\n currentValue: ${currentValue}` +
|
|
424
|
+
`\n}`
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
416
428
|
// Update the original record
|
|
417
429
|
// NOTE: We do NOT attempt to insert non-existent records because:
|
|
418
430
|
// 1. Target resources typically have required fields we don't know about
|
|
419
431
|
// 2. Record creation should be the application's responsibility
|
|
420
432
|
// 3. Transactions will remain pending until the record is created
|
|
421
|
-
const [updateOk, updateErr] = await tryFn(() =>
|
|
433
|
+
const [updateOk, updateErr, updateResult] = await tryFn(() =>
|
|
422
434
|
targetResource.update(originalId, {
|
|
423
435
|
[config.field]: consolidatedValue
|
|
424
436
|
})
|
|
425
437
|
);
|
|
426
438
|
|
|
439
|
+
// 🔥 DEBUG: Log AFTER update
|
|
440
|
+
if (config.verbose) {
|
|
441
|
+
console.log(
|
|
442
|
+
`🔥 [DEBUG] AFTER targetResource.update() {` +
|
|
443
|
+
`\n updateOk: ${updateOk},` +
|
|
444
|
+
`\n updateErr: ${updateErr?.message || 'undefined'},` +
|
|
445
|
+
`\n updateResult: ${JSON.stringify(updateResult, null, 2)},` +
|
|
446
|
+
`\n hasField: ${updateResult?.[config.field]}` +
|
|
447
|
+
`\n}`
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// 🔥 VERIFY: Check if update actually persisted
|
|
452
|
+
if (updateOk && config.verbose) {
|
|
453
|
+
// Bypass cache to get fresh data
|
|
454
|
+
const [verifyOk, verifyErr, verifiedRecord] = await tryFn(() =>
|
|
455
|
+
targetResource.get(originalId, { skipCache: true })
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
console.log(
|
|
459
|
+
`🔥 [DEBUG] VERIFICATION (fresh from S3, no cache) {` +
|
|
460
|
+
`\n verifyOk: ${verifyOk},` +
|
|
461
|
+
`\n verifiedRecord[${config.field}]: ${verifiedRecord?.[config.field]},` +
|
|
462
|
+
`\n expectedValue: ${consolidatedValue},` +
|
|
463
|
+
`\n ✅ MATCH: ${verifiedRecord?.[config.field] === consolidatedValue}` +
|
|
464
|
+
`\n}`
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
// If verification fails, this is a critical bug
|
|
468
|
+
if (verifyOk && verifiedRecord?.[config.field] !== consolidatedValue) {
|
|
469
|
+
console.error(
|
|
470
|
+
`❌ [CRITICAL BUG] Update reported success but value not persisted!` +
|
|
471
|
+
`\n Resource: ${config.resource}` +
|
|
472
|
+
`\n Field: ${config.field}` +
|
|
473
|
+
`\n Record ID: ${originalId}` +
|
|
474
|
+
`\n Expected: ${consolidatedValue}` +
|
|
475
|
+
`\n Actually got: ${verifiedRecord?.[config.field]}` +
|
|
476
|
+
`\n This indicates a bug in s3db.js resource.update()`
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
427
481
|
if (!updateOk) {
|
|
428
482
|
// Check if record doesn't exist
|
|
429
483
|
if (updateErr?.message?.includes('does not exist')) {
|