@logbrew/sdk 0.1.21 → 0.1.23

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.
Files changed (2) hide show
  1. package/core.cjs +33 -12
  2. package/package.json +1 -1
package/core.cjs CHANGED
@@ -334,14 +334,7 @@ class LogBrewClient {
334
334
  this.eventStore = resolvedEventStore;
335
335
  let recovered;
336
336
  try {
337
- recovered = loadStoredEvents({
338
- batchPrefixBytes: this.batchPrefixBytes,
339
- batchSuffixBytes: this.batchSuffixBytes,
340
- eventStore: resolvedEventStore,
341
- maxBatchBytes,
342
- maxQueueBytes,
343
- maxQueueSize
344
- });
337
+ recovered = loadStoredEvents(this);
345
338
  } catch (error) {
346
339
  if (ownsEventStore) {
347
340
  try {
@@ -822,6 +815,7 @@ class LogBrewClient {
822
815
  }
823
816
 
824
817
  async #flushSnapshot(transport) {
818
+ this.#synchronizeEventStore();
825
819
  let remainingEvents = this.events.length;
826
820
  if (remainingEvents === 0) {
827
821
  return { statusCode: 204, attempts: 0, batches: 0 };
@@ -851,6 +845,17 @@ class LogBrewClient {
851
845
  return { statusCode, attempts, batches };
852
846
  }
853
847
 
848
+ #synchronizeEventStore() {
849
+ if (!this.eventStore) return;
850
+ const recovered = loadStoredEvents(this);
851
+ if (!isOrderedSubsequence(this.serializedEvents, recovered.serializedEvents))
852
+ throw new SdkError("persistence_error", "event store lost a queued record");
853
+ this.events = recovered.events;
854
+ this.serializedEvents = recovered.serializedEvents;
855
+ this.serializedEventBytes = recovered.serializedEventBytes;
856
+ this.queuedEventBytes = recovered.queuedEventBytes;
857
+ }
858
+
854
859
  #nextBatch(maxEvents) {
855
860
  let bodyBytes = this.batchPrefixBytes + this.batchSuffixBytes;
856
861
  let eventsCount = 0;
@@ -1194,6 +1199,19 @@ function loadStoredEvents({
1194
1199
  return { events, queuedEventBytes, serializedEventBytes, serializedEvents };
1195
1200
  }
1196
1201
 
1202
+ function isOrderedSubsequence(expected, actual) {
1203
+ let index = 0;
1204
+ for (const value of actual) {
1205
+ index += value === expected[index] ? 1 : 0;
1206
+ }
1207
+ return index === expected.length;
1208
+ }
1209
+
1210
+ function structuralJson(value) {
1211
+ return JSON.stringify(value, (_, entry) => entry && !Array.isArray(entry) && typeof entry === "object"
1212
+ ? Object.fromEntries(Object.entries(entry).sort(([left], [right]) => left.localeCompare(right))) : entry);
1213
+ }
1214
+
1197
1215
  function normalizeStoredRecord(record) {
1198
1216
  try {
1199
1217
  if (!record || Array.isArray(record) || typeof record !== "object") {
@@ -1215,11 +1233,14 @@ function normalizeStoredRecord(record) {
1215
1233
  if (JSON.stringify(event) !== serializedEvent || utf8ByteLength(serializedEvent) !== eventBytes) {
1216
1234
  throw invalidStoredRecord();
1217
1235
  }
1218
- const context = event.attributes.context;
1236
+ const recoveredAttributes = event.type === "issue" && event.attributes.level === "fatal"
1237
+ ? { ...event.attributes, level: "critical" }
1238
+ : event.attributes;
1239
+ const context = recoveredAttributes.context;
1219
1240
  const recoveredEvent = context && !Array.isArray(context) && typeof context === "object"
1220
1241
  && context.schemaVersion === undefined
1221
- ? { ...event, attributes: { ...event.attributes, context: { schemaVersion: 1, ...context } } }
1222
- : event;
1242
+ ? { ...event, attributes: { ...recoveredAttributes, context: { schemaVersion: 1, ...context } } }
1243
+ : { ...event, attributes: recoveredAttributes };
1223
1244
  const normalizedEvent = {
1224
1245
  type: recoveredEvent.type,
1225
1246
  id: recoveredEvent.id,
@@ -1227,7 +1248,7 @@ function normalizeStoredRecord(record) {
1227
1248
  attributes: validator(recoveredEvent.attributes)
1228
1249
  };
1229
1250
  const normalizedSerializedEvent = JSON.stringify(normalizedEvent);
1230
- if (normalizedSerializedEvent !== JSON.stringify(recoveredEvent)) {
1251
+ if (structuralJson(normalizedEvent) !== structuralJson(recoveredEvent)) {
1231
1252
  throw invalidStoredRecord();
1232
1253
  }
1233
1254
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logbrew/sdk",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "Public LogBrew JavaScript SDK for building, validating, and flushing event batches.",
5
5
  "type": "module",
6
6
  "main": "./index.cjs",