@korajs/server 1.0.0-beta.5 → 1.0.0-beta.7

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/index.cjs CHANGED
@@ -395,6 +395,9 @@ function serializeFieldValue(value, descriptor) {
395
395
  if (value === null || value === void 0) return null;
396
396
  switch (descriptor.kind) {
397
397
  case "array":
398
+ case "object":
399
+ case "json":
400
+ case "blob":
398
401
  return typeof value === "string" ? value : JSON.stringify(value);
399
402
  case "boolean":
400
403
  return value ? 1 : 0;
@@ -408,6 +411,9 @@ function deserializeFieldValue(value, descriptor) {
408
411
  if (value === null || value === void 0) return null;
409
412
  switch (descriptor.kind) {
410
413
  case "array":
414
+ case "object":
415
+ case "json":
416
+ case "blob":
411
417
  return typeof value === "string" ? JSON.parse(value) : value;
412
418
  case "boolean":
413
419
  return value === 1 || value === true;
@@ -2734,6 +2740,20 @@ function warnIfMultiTenantWithoutScopes(auth, resolvedScopes, schema) {
2734
2740
  "[kora] An authenticated session resolved to no sync scopes, so every user will sync every other user's data. Return per-user sync scopes from your auth provider (for example KoraAuthProvider's resolveScopes) to isolate tenants. Note: declaring sync rules in your schema is not enough on its own \u2014 the per-user values come from the auth provider. (This warning is expected for single-tenant apps where all authenticated users are meant to share the same data.)"
2735
2741
  );
2736
2742
  }
2743
+ function stableStringify(value) {
2744
+ if (Array.isArray(value)) {
2745
+ return `[${value.map((item) => stableStringify(item)).join(",")}]`;
2746
+ }
2747
+ if (value && typeof value === "object") {
2748
+ const record = value;
2749
+ const entries = Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`);
2750
+ return `{${entries.join(",")}}`;
2751
+ }
2752
+ return JSON.stringify(value);
2753
+ }
2754
+ function sameScopeMap(a, b) {
2755
+ return stableStringify(a ?? null) === stableStringify(b ?? null);
2756
+ }
2737
2757
  var ClientSession = class _ClientSession {
2738
2758
  state = "connected";
2739
2759
  clientNodeId = null;
@@ -2775,6 +2795,7 @@ var ClientSession = class _ClientSession {
2775
2795
  auth;
2776
2796
  serializer;
2777
2797
  emitter;
2798
+ logger;
2778
2799
  batchSize;
2779
2800
  schemaVersion;
2780
2801
  supportedSchemaVersions;
@@ -2799,6 +2820,7 @@ var ClientSession = class _ClientSession {
2799
2820
  this.auth = options.auth ?? null;
2800
2821
  this.serializer = options.serializer ?? new import_sync3.NegotiatedMessageSerializer("json");
2801
2822
  this.emitter = options.emitter ?? null;
2823
+ this.logger = options.logger ?? null;
2802
2824
  this.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
2803
2825
  this.schemaVersion = options.schemaVersion ?? DEFAULT_SCHEMA_VERSION;
2804
2826
  const supported = options.supportedSchemaVersions;
@@ -3033,6 +3055,18 @@ var ClientSession = class _ClientSession {
3033
3055
  }
3034
3056
  handleMessageFailure(error) {
3035
3057
  const reason = error instanceof Error ? error.message : "Message handling failed";
3058
+ this.logger?.log({
3059
+ timestamp: Date.now(),
3060
+ level: "error",
3061
+ event: "session.message_failed",
3062
+ sessionId: this.sessionId,
3063
+ nodeId: this.clientNodeId ?? void 0,
3064
+ error: reason,
3065
+ details: {
3066
+ state: this.state,
3067
+ errorName: error instanceof Error ? error.name : typeof error
3068
+ }
3069
+ });
3036
3070
  this.sendError("SYNC_ERROR", reason, true);
3037
3071
  this.close(reason);
3038
3072
  }
@@ -3072,6 +3106,9 @@ var ClientSession = class _ClientSession {
3072
3106
  }
3073
3107
  this.resumeDeltaCursor = msg.deltaCursor ? (0, import_sync3.decodeDeltaCursor)(msg.deltaCursor) : null;
3074
3108
  this.clientDeliveryWatermark = msg.lastDeliverySequence ?? null;
3109
+ if (this.clientDeliveryWatermark !== null && !sameScopeMap(msg.syncScope, this.authContext?.scopes)) {
3110
+ this.clientDeliveryWatermark = 0;
3111
+ }
3075
3112
  const clientUsesWatermark = this.clientDeliveryWatermark !== null;
3076
3113
  let serverMaxDelivery = 0;
3077
3114
  if (clientUsesWatermark) {
@@ -3199,20 +3236,17 @@ var ClientSession = class _ClientSession {
3199
3236
  continue;
3200
3237
  }
3201
3238
  }
3202
- try {
3203
- const applyResult = await applyServerOperation(this.store, op);
3204
- if (applyResult.rejection) {
3205
- this.sendError(
3206
- applyResult.rejection.code,
3207
- applyResult.rejection.message,
3208
- applyResult.rejection.retriable
3209
- );
3210
- continue;
3211
- }
3212
- if (applyResult.result === "applied") {
3213
- applied.push(...applyResult.appliedOperations);
3214
- }
3215
- } catch {
3239
+ const applyResult = await applyServerOperation(this.store, op);
3240
+ if (applyResult.rejection) {
3241
+ this.sendError(
3242
+ applyResult.rejection.code,
3243
+ applyResult.rejection.message,
3244
+ applyResult.rejection.retriable
3245
+ );
3246
+ continue;
3247
+ }
3248
+ if (applyResult.result === "applied") {
3249
+ applied.push(...applyResult.appliedOperations);
3216
3250
  }
3217
3251
  }
3218
3252
  if (rejected.length > 0) {
@@ -4608,6 +4642,7 @@ var KoraSyncServer = class _KoraSyncServer {
4608
4642
  auth: this.auth ?? void 0,
4609
4643
  serializer: this.serializer,
4610
4644
  emitter: sessionEmitter,
4645
+ logger: this.logger,
4611
4646
  batchSize: this.batchSize,
4612
4647
  schemaVersion: this.schemaVersion,
4613
4648
  supportedSchemaVersions: this.supportedSchemaVersions,
@@ -4936,6 +4971,7 @@ function createProductionServer(config) {
4936
4971
  const port = config.port ?? (Number(process.env.PORT) || 3001);
4937
4972
  const staticDir = config.staticDir ?? "./dist";
4938
4973
  const syncPath = config.syncPath ?? "/kora-sync";
4974
+ const crossOriginEmbedderPolicy = config.crossOriginEmbedderPolicy ?? "credentialless";
4939
4975
  const syncServer = new KoraSyncServer({
4940
4976
  store: config.store,
4941
4977
  enableDashboard: true,
@@ -5106,7 +5142,7 @@ function createProductionServer(config) {
5106
5142
  });
5107
5143
  async function handleRequest(req, res) {
5108
5144
  res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
5109
- res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
5145
+ res.setHeader("Cross-Origin-Embedder-Policy", crossOriginEmbedderPolicy);
5110
5146
  const url = new URL(req.url || "/", `http://${req.headers.host}`);
5111
5147
  if (url.pathname === "/health") {
5112
5148
  const status = await syncServer.getStatus();