@korajs/core 1.0.0-beta.4 → 1.0.0-beta.6
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/bindings/index.d.cts +2 -2
- package/dist/bindings/index.d.ts +2 -2
- package/dist/{build-scope-map-K25AyQXb.d.cts → build-scope-map-Bm6Lqo9F.d.cts} +1 -1
- package/dist/{build-scope-map-BvdTzmm4.d.ts → build-scope-map-C60lT-4I.d.ts} +1 -1
- package/dist/{events-DhblJN4r.d.cts → events-CT9y24ht.d.cts} +12 -0
- package/dist/{events-DhblJN4r.d.ts → events-CT9y24ht.d.ts} +12 -0
- package/dist/index.cjs +91 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -5
- package/dist/index.d.ts +53 -5
- package/dist/index.js +89 -16
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +2 -2
- package/dist/internal.d.ts +2 -2
- package/dist/{operation-D-pemjcf.d.cts → operation-BxQjKMvK.d.cts} +1 -1
- package/dist/{operation-CC7O3-wf.d.ts → operation-C9BEVSX4.d.ts} +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as KoraEventEmitter } from '../events-
|
|
2
|
-
import { S as ScopeMap } from '../build-scope-map-
|
|
1
|
+
import { p as KoraEventEmitter } from '../events-CT9y24ht.cjs';
|
|
2
|
+
import { S as ScopeMap } from '../build-scope-map-Bm6Lqo9F.cjs';
|
|
3
3
|
|
|
4
4
|
/** Sync status shape consumed by framework binding hooks (matches {@link SyncStatusInfo} in `@korajs/sync`). */
|
|
5
5
|
interface KoraBindingSyncStatus {
|
package/dist/bindings/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as KoraEventEmitter } from '../events-
|
|
2
|
-
import { S as ScopeMap } from '../build-scope-map-
|
|
1
|
+
import { p as KoraEventEmitter } from '../events-CT9y24ht.js';
|
|
2
|
+
import { S as ScopeMap } from '../build-scope-map-C60lT-4I.js';
|
|
3
3
|
|
|
4
4
|
/** Sync status shape consumed by framework binding hooks (matches {@link SyncStatusInfo} in `@korajs/sync`). */
|
|
5
5
|
interface KoraBindingSyncStatus {
|
|
@@ -912,6 +912,18 @@ type KoraEvent = {
|
|
|
912
912
|
*/
|
|
913
913
|
reason: 'lock-conflict' | 'timeout' | 'unsupported';
|
|
914
914
|
message: string;
|
|
915
|
+
} | {
|
|
916
|
+
/**
|
|
917
|
+
* A preferred storage backend could not provide durable storage, so Kora
|
|
918
|
+
* promoted the app to another durable backend before user code observed the
|
|
919
|
+
* store. This is informational: data still survives reloads.
|
|
920
|
+
*/
|
|
921
|
+
type: 'store:storage-fallback';
|
|
922
|
+
dbName: string;
|
|
923
|
+
from: 'opfs' | 'sqlite-wasm';
|
|
924
|
+
to: 'indexeddb';
|
|
925
|
+
reason: 'lock-conflict' | 'timeout' | 'unsupported';
|
|
926
|
+
message: string;
|
|
915
927
|
} | {
|
|
916
928
|
/**
|
|
917
929
|
* Another runtime on this origin was already using this database name, so
|
|
@@ -912,6 +912,18 @@ type KoraEvent = {
|
|
|
912
912
|
*/
|
|
913
913
|
reason: 'lock-conflict' | 'timeout' | 'unsupported';
|
|
914
914
|
message: string;
|
|
915
|
+
} | {
|
|
916
|
+
/**
|
|
917
|
+
* A preferred storage backend could not provide durable storage, so Kora
|
|
918
|
+
* promoted the app to another durable backend before user code observed the
|
|
919
|
+
* store. This is informational: data still survives reloads.
|
|
920
|
+
*/
|
|
921
|
+
type: 'store:storage-fallback';
|
|
922
|
+
dbName: string;
|
|
923
|
+
from: 'opfs' | 'sqlite-wasm';
|
|
924
|
+
to: 'indexeddb';
|
|
925
|
+
reason: 'lock-conflict' | 'timeout' | 'unsupported';
|
|
926
|
+
message: string;
|
|
915
927
|
} | {
|
|
916
928
|
/**
|
|
917
929
|
* Another runtime on this origin was already using this database name, so
|
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
StorageError: () => StorageError,
|
|
47
47
|
SyncError: () => SyncError,
|
|
48
48
|
advanceVector: () => advanceVector,
|
|
49
|
+
applyAtomicOp: () => applyAtomicOp,
|
|
49
50
|
applyOperationTransforms: () => applyOperationTransforms,
|
|
50
51
|
base64ToBytes: () => base64ToBytes,
|
|
51
52
|
buildScopeMap: () => buildScopeMap,
|
|
@@ -95,6 +96,7 @@ __export(index_exports, {
|
|
|
95
96
|
migrationStepsToSQL: () => migrationStepsToSQL,
|
|
96
97
|
op: () => op,
|
|
97
98
|
quoteIdent: () => quoteIdent,
|
|
99
|
+
replayOperationsForRecord: () => replayOperationsForRecord,
|
|
98
100
|
resolveAtomicOp: () => resolveAtomicOp,
|
|
99
101
|
revealSecret: () => revealSecret,
|
|
100
102
|
rollbackStepsToSQL: () => rollbackStepsToSQL,
|
|
@@ -968,32 +970,36 @@ var KORA_ATOMIC_OP = /* @__PURE__ */ Symbol.for("kora.atomic_op");
|
|
|
968
970
|
function isAtomicOp(value) {
|
|
969
971
|
return typeof value === "object" && value !== null && KORA_ATOMIC_OP in value && value[KORA_ATOMIC_OP] === true;
|
|
970
972
|
}
|
|
971
|
-
function
|
|
972
|
-
switch (
|
|
973
|
+
function applyAtomicOp(currentValue, atomicOp) {
|
|
974
|
+
switch (atomicOp.type) {
|
|
973
975
|
case "increment": {
|
|
974
976
|
const current = typeof currentValue === "number" ? currentValue : 0;
|
|
975
|
-
const operand =
|
|
977
|
+
const operand = atomicOp.value;
|
|
976
978
|
return current + operand;
|
|
977
979
|
}
|
|
978
980
|
case "max": {
|
|
979
981
|
const current = typeof currentValue === "number" ? currentValue : Number.NEGATIVE_INFINITY;
|
|
980
|
-
return Math.max(current,
|
|
982
|
+
return Math.max(current, atomicOp.value);
|
|
981
983
|
}
|
|
982
984
|
case "min": {
|
|
983
985
|
const current = typeof currentValue === "number" ? currentValue : Number.POSITIVE_INFINITY;
|
|
984
|
-
return Math.min(current,
|
|
986
|
+
return Math.min(current, atomicOp.value);
|
|
985
987
|
}
|
|
986
988
|
case "append": {
|
|
987
989
|
const current = Array.isArray(currentValue) ? [...currentValue] : [];
|
|
988
|
-
current.push(
|
|
990
|
+
current.push(atomicOp.value);
|
|
989
991
|
return current;
|
|
990
992
|
}
|
|
991
993
|
case "remove": {
|
|
992
994
|
if (!Array.isArray(currentValue)) return [];
|
|
993
|
-
|
|
995
|
+
const target = JSON.stringify(atomicOp.value);
|
|
996
|
+
return currentValue.filter((item) => JSON.stringify(item) !== target);
|
|
994
997
|
}
|
|
995
998
|
}
|
|
996
999
|
}
|
|
1000
|
+
function resolveAtomicOp(currentValue, sentinel) {
|
|
1001
|
+
return applyAtomicOp(currentValue, { type: sentinel.type, value: sentinel.value });
|
|
1002
|
+
}
|
|
997
1003
|
function createSentinel(type, value) {
|
|
998
1004
|
return Object.freeze({
|
|
999
1005
|
[KORA_ATOMIC_OP]: true,
|
|
@@ -1061,6 +1067,46 @@ function toAtomicOp(sentinel) {
|
|
|
1061
1067
|
return { type: sentinel.type, value: sentinel.value };
|
|
1062
1068
|
}
|
|
1063
1069
|
|
|
1070
|
+
// src/operations/replay-record.ts
|
|
1071
|
+
function replayOperationsForRecord(ops) {
|
|
1072
|
+
let record = null;
|
|
1073
|
+
let deleted = false;
|
|
1074
|
+
const lastWriterKind = {};
|
|
1075
|
+
for (const op2 of ops) {
|
|
1076
|
+
switch (op2.type) {
|
|
1077
|
+
case "insert":
|
|
1078
|
+
if (op2.data) {
|
|
1079
|
+
record = { ...op2.data };
|
|
1080
|
+
deleted = false;
|
|
1081
|
+
for (const field of Object.keys(op2.data)) {
|
|
1082
|
+
lastWriterKind[field] = "lww";
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
break;
|
|
1086
|
+
case "update":
|
|
1087
|
+
if (op2.data) {
|
|
1088
|
+
const next = { ...record ?? {} };
|
|
1089
|
+
for (const [field, value] of Object.entries(op2.data)) {
|
|
1090
|
+
const atomicOp = op2.atomicOps?.[field];
|
|
1091
|
+
if (atomicOp && lastWriterKind[field] === `atomic:${atomicOp.type}`) {
|
|
1092
|
+
next[field] = applyAtomicOp(next[field], atomicOp);
|
|
1093
|
+
} else {
|
|
1094
|
+
next[field] = value;
|
|
1095
|
+
}
|
|
1096
|
+
lastWriterKind[field] = atomicOp ? `atomic:${atomicOp.type}` : "lww";
|
|
1097
|
+
}
|
|
1098
|
+
record = next;
|
|
1099
|
+
deleted = false;
|
|
1100
|
+
}
|
|
1101
|
+
break;
|
|
1102
|
+
case "delete":
|
|
1103
|
+
deleted = true;
|
|
1104
|
+
break;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
return deleted ? null : record;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1064
1110
|
// src/operations/op-data-binary.ts
|
|
1065
1111
|
function isKoraBytesValue(value) {
|
|
1066
1112
|
if (typeof value !== "object" || value === null) {
|
|
@@ -2332,10 +2378,17 @@ function validateFieldValue(collection, fieldName, descriptor, value) {
|
|
|
2332
2378
|
break;
|
|
2333
2379
|
}
|
|
2334
2380
|
case "json": {
|
|
2335
|
-
|
|
2381
|
+
const nonJson = findNonJsonSerializable(value, fieldName);
|
|
2382
|
+
if (nonJson) {
|
|
2336
2383
|
throw new SchemaValidationError(
|
|
2337
|
-
`Field "${fieldName}" in collection "${collection}" must be JSON-serializable
|
|
2338
|
-
{
|
|
2384
|
+
`Field "${fieldName}" in collection "${collection}" must be JSON-serializable; found ${nonJson.receivedType} at "${nonJson.path}"`,
|
|
2385
|
+
{
|
|
2386
|
+
collection,
|
|
2387
|
+
field: fieldName,
|
|
2388
|
+
expectedType: "json",
|
|
2389
|
+
receivedType: nonJson.receivedType,
|
|
2390
|
+
path: nonJson.path
|
|
2391
|
+
}
|
|
2339
2392
|
);
|
|
2340
2393
|
}
|
|
2341
2394
|
break;
|
|
@@ -2372,21 +2425,41 @@ function isPlainObject(value) {
|
|
|
2372
2425
|
const proto = Object.getPrototypeOf(value);
|
|
2373
2426
|
return proto === null || proto === Object.prototype;
|
|
2374
2427
|
}
|
|
2375
|
-
function
|
|
2428
|
+
function findNonJsonSerializable(value, path, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2376
2429
|
if (value === null) {
|
|
2377
|
-
return
|
|
2430
|
+
return null;
|
|
2378
2431
|
}
|
|
2379
2432
|
const type = typeof value;
|
|
2380
2433
|
if (type === "string" || type === "number" || type === "boolean") {
|
|
2381
|
-
|
|
2434
|
+
if (type === "number" && !Number.isFinite(value)) {
|
|
2435
|
+
return { path, receivedType: describeType(value) };
|
|
2436
|
+
}
|
|
2437
|
+
return null;
|
|
2438
|
+
}
|
|
2439
|
+
if (type === "undefined" || type === "function" || type === "symbol" || type === "bigint") {
|
|
2440
|
+
return { path, receivedType: describeType(value) };
|
|
2382
2441
|
}
|
|
2383
2442
|
if (Array.isArray(value)) {
|
|
2384
|
-
|
|
2443
|
+
for (let index = 0; index < value.length; index++) {
|
|
2444
|
+
const invalid = findNonJsonSerializable(value[index], `${path}[${index}]`, seen);
|
|
2445
|
+
if (invalid) return invalid;
|
|
2446
|
+
}
|
|
2447
|
+
return null;
|
|
2385
2448
|
}
|
|
2386
2449
|
if (type === "object") {
|
|
2387
|
-
|
|
2450
|
+
const objectValue = value;
|
|
2451
|
+
if (seen.has(objectValue)) {
|
|
2452
|
+
return { path, receivedType: "circular object" };
|
|
2453
|
+
}
|
|
2454
|
+
seen.add(objectValue);
|
|
2455
|
+
for (const [key, nestedValue] of Object.entries(objectValue)) {
|
|
2456
|
+
const invalid = findNonJsonSerializable(nestedValue, `${path}.${key}`, seen);
|
|
2457
|
+
if (invalid) return invalid;
|
|
2458
|
+
}
|
|
2459
|
+
seen.delete(objectValue);
|
|
2460
|
+
return null;
|
|
2388
2461
|
}
|
|
2389
|
-
return
|
|
2462
|
+
return { path, receivedType: describeType(value) };
|
|
2390
2463
|
}
|
|
2391
2464
|
function describeType(value) {
|
|
2392
2465
|
if (value === null) {
|
|
@@ -3283,6 +3356,7 @@ function generateProtoDefinitions(schema) {
|
|
|
3283
3356
|
StorageError,
|
|
3284
3357
|
SyncError,
|
|
3285
3358
|
advanceVector,
|
|
3359
|
+
applyAtomicOp,
|
|
3286
3360
|
applyOperationTransforms,
|
|
3287
3361
|
base64ToBytes,
|
|
3288
3362
|
buildScopeMap,
|
|
@@ -3332,6 +3406,7 @@ function generateProtoDefinitions(schema) {
|
|
|
3332
3406
|
migrationStepsToSQL,
|
|
3333
3407
|
op,
|
|
3334
3408
|
quoteIdent,
|
|
3409
|
+
replayOperationsForRecord,
|
|
3335
3410
|
resolveAtomicOp,
|
|
3336
3411
|
revealSecret,
|
|
3337
3412
|
rollbackStepsToSQL,
|