@korajs/core 1.0.0-beta.0 → 1.0.0-beta.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/bindings/index.d.cts +2 -2
- package/dist/bindings/index.d.ts +2 -2
- package/dist/{build-scope-map-DOf4JLTh.d.ts → build-scope-map-BvdTzmm4.d.ts} +1 -1
- package/dist/{build-scope-map-BIeawJzC.d.cts → build-scope-map-K25AyQXb.d.cts} +1 -1
- package/dist/{events-BynBOsO3.d.cts → events-DhblJN4r.d.cts} +144 -2
- package/dist/{events-BynBOsO3.d.ts → events-DhblJN4r.d.ts} +144 -2
- package/dist/index.cjs +566 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +174 -7
- package/dist/index.d.ts +174 -7
- package/dist/index.js +553 -22
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +2 -2
- package/dist/internal.d.ts +2 -2
- package/dist/{operation-D5WOZYvy.d.ts → operation-CC7O3-wf.d.ts} +1 -1
- package/dist/{operation-BpZlYSpe.d.cts → operation-D-pemjcf.d.cts} +1 -1
- package/package.json +2 -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-DhblJN4r.cjs';
|
|
2
|
+
import { S as ScopeMap } from '../build-scope-map-K25AyQXb.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-DhblJN4r.js';
|
|
2
|
+
import { S as ScopeMap } from '../build-scope-map-BvdTzmm4.js';
|
|
3
3
|
|
|
4
4
|
/** Sync status shape consumed by framework binding hooks (matches {@link SyncStatusInfo} in `@korajs/sync`). */
|
|
5
5
|
interface KoraBindingSyncStatus {
|
|
@@ -89,6 +89,56 @@ declare class ArrayFieldBuilder<ItemKind extends FieldKind = FieldKind, Req exte
|
|
|
89
89
|
merge(strategy: FieldMergeStrategy): ArrayFieldBuilder<ItemKind, Req, Auto>;
|
|
90
90
|
_build(): FieldDescriptor;
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Field builder for structured object fields with a nested field schema.
|
|
94
|
+
*
|
|
95
|
+
* Each nested key merges by its own declared kind (scalars via LWW, nested
|
|
96
|
+
* arrays via add-wins, nested objects recursively), so two devices editing
|
|
97
|
+
* different keys of the same object offline both converge on reconnect instead
|
|
98
|
+
* of one clobbering the other.
|
|
99
|
+
*/
|
|
100
|
+
declare class ObjectFieldBuilder<Req extends boolean = true, Auto extends boolean = false> extends FieldBuilder<'object', Req, Auto> {
|
|
101
|
+
private readonly _fields;
|
|
102
|
+
constructor(fields: Record<string, FieldBuilder>, required?: Req, defaultValue?: unknown, auto?: Auto, mergeStrategy?: FieldMergeStrategy | null);
|
|
103
|
+
optional(): ObjectFieldBuilder<false, Auto>;
|
|
104
|
+
default(value: Record<string, unknown>): ObjectFieldBuilder<false, Auto>;
|
|
105
|
+
auto(): ObjectFieldBuilder<false, true>;
|
|
106
|
+
merge(strategy: FieldMergeStrategy): ObjectFieldBuilder<Req, Auto>;
|
|
107
|
+
_build(): FieldDescriptor;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Field builder for dynamic-key JSON values. Carries a compile-time shape `T`
|
|
111
|
+
* for inference while merging structurally as a convergent CRDT: a plain-object
|
|
112
|
+
* value recurses as a map, an array merges add-wins, any other value is a scalar
|
|
113
|
+
* leaf under last-write-wins.
|
|
114
|
+
*/
|
|
115
|
+
declare class JsonFieldBuilder<T = unknown, Req extends boolean = true, Auto extends boolean = false> extends FieldBuilder<'json', Req, Auto> {
|
|
116
|
+
optional(): JsonFieldBuilder<T, false, Auto>;
|
|
117
|
+
default(value: T): JsonFieldBuilder<T, false, Auto>;
|
|
118
|
+
auto(): JsonFieldBuilder<T, false, true>;
|
|
119
|
+
merge(strategy: FieldMergeStrategy): JsonFieldBuilder<T, Req, Auto>;
|
|
120
|
+
_build(): FieldDescriptor;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Field builder for secret fields (passwords, tokens, API keys).
|
|
124
|
+
*
|
|
125
|
+
* A secret field's value is never exposed in merge traces, DevTools, or logs
|
|
126
|
+
* (it is redacted at the point traces are built). Its at-rest protection is
|
|
127
|
+
* chosen with `.hashed()` (one-way, for passwords) or `.encrypted()` (reversible,
|
|
128
|
+
* for tokens); the default is `encrypted`.
|
|
129
|
+
*/
|
|
130
|
+
declare class SecretFieldBuilder<Req extends boolean = true, Auto extends boolean = false> extends FieldBuilder<'secret', Req, Auto> {
|
|
131
|
+
private readonly _secretMode;
|
|
132
|
+
constructor(secretMode?: SecretMode, required?: Req, defaultValue?: unknown, auto?: Auto, mergeStrategy?: FieldMergeStrategy | null);
|
|
133
|
+
/** Store this secret as a one-way salted hash (passwords: verify, never read back). */
|
|
134
|
+
hashed(): SecretFieldBuilder<Req, Auto>;
|
|
135
|
+
/** Store this secret as reversible ciphertext (tokens/keys: decrypt to use). */
|
|
136
|
+
encrypted(): SecretFieldBuilder<Req, Auto>;
|
|
137
|
+
optional(): SecretFieldBuilder<false, Auto>;
|
|
138
|
+
auto(): SecretFieldBuilder<false, true>;
|
|
139
|
+
merge(strategy: FieldMergeStrategy): SecretFieldBuilder<Req, Auto>;
|
|
140
|
+
_build(): FieldDescriptor;
|
|
141
|
+
}
|
|
92
142
|
/**
|
|
93
143
|
* Type builder namespace. The developer's primary interface for defining field types.
|
|
94
144
|
*
|
|
@@ -103,6 +153,8 @@ declare class ArrayFieldBuilder<ItemKind extends FieldKind = FieldKind, Req exte
|
|
|
103
153
|
* notes: t.richtext(),
|
|
104
154
|
* tags: t.array(t.string()).default([]),
|
|
105
155
|
* priority: t.enum(['low', 'medium', 'high']).default('medium'),
|
|
156
|
+
* settings: t.object({ theme: t.string(), fontSize: t.number() }),
|
|
157
|
+
* metadata: t.json<{ source: string }>(),
|
|
106
158
|
* createdAt: t.timestamp().auto(),
|
|
107
159
|
* }
|
|
108
160
|
* ```
|
|
@@ -115,6 +167,10 @@ declare const t: {
|
|
|
115
167
|
richtext(): FieldBuilder<"richtext", true, false>;
|
|
116
168
|
enum<const V extends readonly string[]>(values: V): EnumFieldBuilder<V, true, false>;
|
|
117
169
|
array<K extends FieldKind>(itemBuilder: FieldBuilder<K>): ArrayFieldBuilder<K, true, false>;
|
|
170
|
+
object(fields: Record<string, FieldBuilder>): ObjectFieldBuilder<true, false>;
|
|
171
|
+
json<T = unknown>(): JsonFieldBuilder<T, true, false>;
|
|
172
|
+
blob(): FieldBuilder<"blob", true, false>;
|
|
173
|
+
secret(): SecretFieldBuilder<true, false>;
|
|
118
174
|
};
|
|
119
175
|
|
|
120
176
|
/**
|
|
@@ -390,7 +446,39 @@ interface OperationInput {
|
|
|
390
446
|
/** Version vector: maps nodeId to the max sequence number seen from that node */
|
|
391
447
|
type VersionVector = Map<string, number>;
|
|
392
448
|
/** Field kinds supported by the schema system */
|
|
393
|
-
type FieldKind = 'string' | 'number' | 'boolean' | 'timestamp' | 'richtext' | 'enum' | 'array';
|
|
449
|
+
type FieldKind = 'string' | 'number' | 'boolean' | 'timestamp' | 'richtext' | 'enum' | 'array' | 'object' | 'json' | 'blob' | 'secret';
|
|
450
|
+
/**
|
|
451
|
+
* How a `secret` field's value is protected at rest.
|
|
452
|
+
* - `hashed`: one-way (passwords). Stored as a salted hash; never read back.
|
|
453
|
+
* - `encrypted`: reversible (tokens, keys). Stored as ciphertext; decrypted to use.
|
|
454
|
+
*/
|
|
455
|
+
type SecretMode = 'hashed' | 'encrypted';
|
|
456
|
+
/**
|
|
457
|
+
* A content-addressed reference to binary data stored out of band.
|
|
458
|
+
*
|
|
459
|
+
* A `blob` field never carries the bytes in the operation log; it carries this
|
|
460
|
+
* small reference. The bytes live in a content-addressed blob store, keyed by
|
|
461
|
+
* `hash`, so identical content is stored once and never re-synced to a peer that
|
|
462
|
+
* already has that hash.
|
|
463
|
+
*/
|
|
464
|
+
interface BlobRef {
|
|
465
|
+
/** Hex-encoded SHA-256 hash of the bytes. The content address. */
|
|
466
|
+
hash: string;
|
|
467
|
+
/** Size of the bytes in bytes. */
|
|
468
|
+
size: number;
|
|
469
|
+
/** Optional MIME type (for example "image/png"). */
|
|
470
|
+
mimeType?: string;
|
|
471
|
+
/** Optional original filename. */
|
|
472
|
+
filename?: string;
|
|
473
|
+
/**
|
|
474
|
+
* Hex-encoded SHA-256 hash of this blob's manifest — the small chunk index a
|
|
475
|
+
* peer fetches first to learn how to pull the bytes out of band. Present when
|
|
476
|
+
* the blob was stored for transfer; absent for a bare reference created without
|
|
477
|
+
* chunking. Because it is a content address like `hash`, the manifest is fetched
|
|
478
|
+
* and integrity-verified over the same channel as the chunks.
|
|
479
|
+
*/
|
|
480
|
+
manifestHash?: string;
|
|
481
|
+
}
|
|
394
482
|
/**
|
|
395
483
|
* Comprehensive sync diagnostics snapshot.
|
|
396
484
|
* Provides connection, latency, throughput, queue, and error metrics
|
|
@@ -490,6 +578,17 @@ interface FieldDescriptor {
|
|
|
490
578
|
mergeStrategy: FieldMergeStrategy | null;
|
|
491
579
|
/** State machine transition map for enum fields. Null if no transitions declared. */
|
|
492
580
|
transitions: TransitionMap | null;
|
|
581
|
+
/**
|
|
582
|
+
* Nested field descriptors for `object` fields (each key merges by its own
|
|
583
|
+
* kind). Null for `json` fields (dynamic keys, resolved structurally) and for
|
|
584
|
+
* all non-structured kinds.
|
|
585
|
+
*/
|
|
586
|
+
nestedFields?: Record<string, FieldDescriptor> | null;
|
|
587
|
+
/**
|
|
588
|
+
* At-rest protection mode for `secret` fields (`hashed` or `encrypted`).
|
|
589
|
+
* Null/absent for every other kind.
|
|
590
|
+
*/
|
|
591
|
+
secretMode?: SecretMode | null;
|
|
493
592
|
}
|
|
494
593
|
/**
|
|
495
594
|
* Defines a state machine on an enum field, constraining valid state transitions.
|
|
@@ -727,6 +826,21 @@ type KoraEvent = {
|
|
|
727
826
|
code: string;
|
|
728
827
|
message: string;
|
|
729
828
|
retriable: boolean;
|
|
829
|
+
} | {
|
|
830
|
+
/**
|
|
831
|
+
* The server rejected one of THIS client's outbound operations before it
|
|
832
|
+
* became authoritative. The op has been diverted out of the pending sync
|
|
833
|
+
* queue into the durable rejected store (kept, not retried); the app can
|
|
834
|
+
* surface the reason and decide whether to roll back the optimistic local
|
|
835
|
+
* write or let the user edit and resubmit.
|
|
836
|
+
*/
|
|
837
|
+
type: 'sync:operation-rejected';
|
|
838
|
+
operationId: string;
|
|
839
|
+
collection: string;
|
|
840
|
+
recordId: string;
|
|
841
|
+
code: string;
|
|
842
|
+
message: string;
|
|
843
|
+
retriable: boolean;
|
|
730
844
|
} | {
|
|
731
845
|
type: 'query:subscribed';
|
|
732
846
|
queryId: string;
|
|
@@ -781,6 +895,34 @@ type KoraEvent = {
|
|
|
781
895
|
type: 'store:quota-exceeded';
|
|
782
896
|
dbName: string;
|
|
783
897
|
message: string;
|
|
898
|
+
} | {
|
|
899
|
+
/**
|
|
900
|
+
* OPFS persistence was unavailable, so the store fell back to a
|
|
901
|
+
* NON-PERSISTENT in-memory database. Anything written this session is lost
|
|
902
|
+
* on reload. This is emitted instead of failing silently so the condition
|
|
903
|
+
* is observable rather than a data-loss trap.
|
|
904
|
+
*/
|
|
905
|
+
type: 'store:opfs-unavailable';
|
|
906
|
+
dbName: string;
|
|
907
|
+
/**
|
|
908
|
+
* Why OPFS could not be used. `lock-conflict` means another runtime on this
|
|
909
|
+
* origin already holds the OPFS pool for this database; `timeout` means the
|
|
910
|
+
* VFS install did not complete in time (common in headless CI); `unsupported`
|
|
911
|
+
* means the runtime has no usable OPFS.
|
|
912
|
+
*/
|
|
913
|
+
reason: 'lock-conflict' | 'timeout' | 'unsupported';
|
|
914
|
+
message: string;
|
|
915
|
+
} | {
|
|
916
|
+
/**
|
|
917
|
+
* Another runtime on this origin was already using this database name, so
|
|
918
|
+
* this runtime attached to it as a follower and now SHARES that one
|
|
919
|
+
* database. That is intended for multiple tabs of the SAME app; it is a bug
|
|
920
|
+
* if these are logically separate apps, which should each use a distinct
|
|
921
|
+
* store name (`store: { name: '...' }`) to stay isolated.
|
|
922
|
+
*/
|
|
923
|
+
type: 'store:db-name-collision';
|
|
924
|
+
dbName: string;
|
|
925
|
+
message: string;
|
|
784
926
|
} | {
|
|
785
927
|
type: 'replay:completed';
|
|
786
928
|
targetOperationId: string;
|
|
@@ -805,4 +947,4 @@ interface KoraEventEmitter {
|
|
|
805
947
|
emit<T extends KoraEventType>(event: KoraEventByType<T>): void;
|
|
806
948
|
}
|
|
807
949
|
|
|
808
|
-
export { type AtomicOpType as A, type
|
|
950
|
+
export { type AtomicOpType as A, type BlobRef as B, type CollectionDefinition as C, type SecretMode as D, EnumFieldBuilder as E, FieldBuilder as F, type SequenceConfig as G, type HLCTimestamp as H, type StateMachineDefinition as I, JsonFieldBuilder as J, type KoraEvent as K, type SyncDiagnosticsSnapshot as L, type MigrationDefinition as M, type SyncRuleDefinition as N, type OperationType as O, type TimeSource as P, migrate as Q, type RandomSource as R, type SchemaDefinition as S, type TransitionMap as T, t as U, type VersionVector as V, type AtomicOp as a, type CustomResolver as b, type RelationDefinition as c, ArrayFieldBuilder as d, type FieldKind as e, type Operation as f, type MigrationStep as g, type StateMachineConstraint as h, type TransitionValidationResult as i, CONNECTION_QUALITIES as j, type ConnectionQuality as k, type Constraint as l, type FieldDescriptor as m, type FieldMergeStrategy as n, type KoraEventByType as o, type KoraEventEmitter as p, type KoraEventListener as q, type KoraEventType as r, MERGE_STRATEGIES as s, type MergeStrategy as t, type MergeTrace as u, MigrationBuilder as v, type OnDeleteAction as w, type OperationInput as x, type RelationType as y, RollbackBuilder as z };
|
|
@@ -89,6 +89,56 @@ declare class ArrayFieldBuilder<ItemKind extends FieldKind = FieldKind, Req exte
|
|
|
89
89
|
merge(strategy: FieldMergeStrategy): ArrayFieldBuilder<ItemKind, Req, Auto>;
|
|
90
90
|
_build(): FieldDescriptor;
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Field builder for structured object fields with a nested field schema.
|
|
94
|
+
*
|
|
95
|
+
* Each nested key merges by its own declared kind (scalars via LWW, nested
|
|
96
|
+
* arrays via add-wins, nested objects recursively), so two devices editing
|
|
97
|
+
* different keys of the same object offline both converge on reconnect instead
|
|
98
|
+
* of one clobbering the other.
|
|
99
|
+
*/
|
|
100
|
+
declare class ObjectFieldBuilder<Req extends boolean = true, Auto extends boolean = false> extends FieldBuilder<'object', Req, Auto> {
|
|
101
|
+
private readonly _fields;
|
|
102
|
+
constructor(fields: Record<string, FieldBuilder>, required?: Req, defaultValue?: unknown, auto?: Auto, mergeStrategy?: FieldMergeStrategy | null);
|
|
103
|
+
optional(): ObjectFieldBuilder<false, Auto>;
|
|
104
|
+
default(value: Record<string, unknown>): ObjectFieldBuilder<false, Auto>;
|
|
105
|
+
auto(): ObjectFieldBuilder<false, true>;
|
|
106
|
+
merge(strategy: FieldMergeStrategy): ObjectFieldBuilder<Req, Auto>;
|
|
107
|
+
_build(): FieldDescriptor;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Field builder for dynamic-key JSON values. Carries a compile-time shape `T`
|
|
111
|
+
* for inference while merging structurally as a convergent CRDT: a plain-object
|
|
112
|
+
* value recurses as a map, an array merges add-wins, any other value is a scalar
|
|
113
|
+
* leaf under last-write-wins.
|
|
114
|
+
*/
|
|
115
|
+
declare class JsonFieldBuilder<T = unknown, Req extends boolean = true, Auto extends boolean = false> extends FieldBuilder<'json', Req, Auto> {
|
|
116
|
+
optional(): JsonFieldBuilder<T, false, Auto>;
|
|
117
|
+
default(value: T): JsonFieldBuilder<T, false, Auto>;
|
|
118
|
+
auto(): JsonFieldBuilder<T, false, true>;
|
|
119
|
+
merge(strategy: FieldMergeStrategy): JsonFieldBuilder<T, Req, Auto>;
|
|
120
|
+
_build(): FieldDescriptor;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Field builder for secret fields (passwords, tokens, API keys).
|
|
124
|
+
*
|
|
125
|
+
* A secret field's value is never exposed in merge traces, DevTools, or logs
|
|
126
|
+
* (it is redacted at the point traces are built). Its at-rest protection is
|
|
127
|
+
* chosen with `.hashed()` (one-way, for passwords) or `.encrypted()` (reversible,
|
|
128
|
+
* for tokens); the default is `encrypted`.
|
|
129
|
+
*/
|
|
130
|
+
declare class SecretFieldBuilder<Req extends boolean = true, Auto extends boolean = false> extends FieldBuilder<'secret', Req, Auto> {
|
|
131
|
+
private readonly _secretMode;
|
|
132
|
+
constructor(secretMode?: SecretMode, required?: Req, defaultValue?: unknown, auto?: Auto, mergeStrategy?: FieldMergeStrategy | null);
|
|
133
|
+
/** Store this secret as a one-way salted hash (passwords: verify, never read back). */
|
|
134
|
+
hashed(): SecretFieldBuilder<Req, Auto>;
|
|
135
|
+
/** Store this secret as reversible ciphertext (tokens/keys: decrypt to use). */
|
|
136
|
+
encrypted(): SecretFieldBuilder<Req, Auto>;
|
|
137
|
+
optional(): SecretFieldBuilder<false, Auto>;
|
|
138
|
+
auto(): SecretFieldBuilder<false, true>;
|
|
139
|
+
merge(strategy: FieldMergeStrategy): SecretFieldBuilder<Req, Auto>;
|
|
140
|
+
_build(): FieldDescriptor;
|
|
141
|
+
}
|
|
92
142
|
/**
|
|
93
143
|
* Type builder namespace. The developer's primary interface for defining field types.
|
|
94
144
|
*
|
|
@@ -103,6 +153,8 @@ declare class ArrayFieldBuilder<ItemKind extends FieldKind = FieldKind, Req exte
|
|
|
103
153
|
* notes: t.richtext(),
|
|
104
154
|
* tags: t.array(t.string()).default([]),
|
|
105
155
|
* priority: t.enum(['low', 'medium', 'high']).default('medium'),
|
|
156
|
+
* settings: t.object({ theme: t.string(), fontSize: t.number() }),
|
|
157
|
+
* metadata: t.json<{ source: string }>(),
|
|
106
158
|
* createdAt: t.timestamp().auto(),
|
|
107
159
|
* }
|
|
108
160
|
* ```
|
|
@@ -115,6 +167,10 @@ declare const t: {
|
|
|
115
167
|
richtext(): FieldBuilder<"richtext", true, false>;
|
|
116
168
|
enum<const V extends readonly string[]>(values: V): EnumFieldBuilder<V, true, false>;
|
|
117
169
|
array<K extends FieldKind>(itemBuilder: FieldBuilder<K>): ArrayFieldBuilder<K, true, false>;
|
|
170
|
+
object(fields: Record<string, FieldBuilder>): ObjectFieldBuilder<true, false>;
|
|
171
|
+
json<T = unknown>(): JsonFieldBuilder<T, true, false>;
|
|
172
|
+
blob(): FieldBuilder<"blob", true, false>;
|
|
173
|
+
secret(): SecretFieldBuilder<true, false>;
|
|
118
174
|
};
|
|
119
175
|
|
|
120
176
|
/**
|
|
@@ -390,7 +446,39 @@ interface OperationInput {
|
|
|
390
446
|
/** Version vector: maps nodeId to the max sequence number seen from that node */
|
|
391
447
|
type VersionVector = Map<string, number>;
|
|
392
448
|
/** Field kinds supported by the schema system */
|
|
393
|
-
type FieldKind = 'string' | 'number' | 'boolean' | 'timestamp' | 'richtext' | 'enum' | 'array';
|
|
449
|
+
type FieldKind = 'string' | 'number' | 'boolean' | 'timestamp' | 'richtext' | 'enum' | 'array' | 'object' | 'json' | 'blob' | 'secret';
|
|
450
|
+
/**
|
|
451
|
+
* How a `secret` field's value is protected at rest.
|
|
452
|
+
* - `hashed`: one-way (passwords). Stored as a salted hash; never read back.
|
|
453
|
+
* - `encrypted`: reversible (tokens, keys). Stored as ciphertext; decrypted to use.
|
|
454
|
+
*/
|
|
455
|
+
type SecretMode = 'hashed' | 'encrypted';
|
|
456
|
+
/**
|
|
457
|
+
* A content-addressed reference to binary data stored out of band.
|
|
458
|
+
*
|
|
459
|
+
* A `blob` field never carries the bytes in the operation log; it carries this
|
|
460
|
+
* small reference. The bytes live in a content-addressed blob store, keyed by
|
|
461
|
+
* `hash`, so identical content is stored once and never re-synced to a peer that
|
|
462
|
+
* already has that hash.
|
|
463
|
+
*/
|
|
464
|
+
interface BlobRef {
|
|
465
|
+
/** Hex-encoded SHA-256 hash of the bytes. The content address. */
|
|
466
|
+
hash: string;
|
|
467
|
+
/** Size of the bytes in bytes. */
|
|
468
|
+
size: number;
|
|
469
|
+
/** Optional MIME type (for example "image/png"). */
|
|
470
|
+
mimeType?: string;
|
|
471
|
+
/** Optional original filename. */
|
|
472
|
+
filename?: string;
|
|
473
|
+
/**
|
|
474
|
+
* Hex-encoded SHA-256 hash of this blob's manifest — the small chunk index a
|
|
475
|
+
* peer fetches first to learn how to pull the bytes out of band. Present when
|
|
476
|
+
* the blob was stored for transfer; absent for a bare reference created without
|
|
477
|
+
* chunking. Because it is a content address like `hash`, the manifest is fetched
|
|
478
|
+
* and integrity-verified over the same channel as the chunks.
|
|
479
|
+
*/
|
|
480
|
+
manifestHash?: string;
|
|
481
|
+
}
|
|
394
482
|
/**
|
|
395
483
|
* Comprehensive sync diagnostics snapshot.
|
|
396
484
|
* Provides connection, latency, throughput, queue, and error metrics
|
|
@@ -490,6 +578,17 @@ interface FieldDescriptor {
|
|
|
490
578
|
mergeStrategy: FieldMergeStrategy | null;
|
|
491
579
|
/** State machine transition map for enum fields. Null if no transitions declared. */
|
|
492
580
|
transitions: TransitionMap | null;
|
|
581
|
+
/**
|
|
582
|
+
* Nested field descriptors for `object` fields (each key merges by its own
|
|
583
|
+
* kind). Null for `json` fields (dynamic keys, resolved structurally) and for
|
|
584
|
+
* all non-structured kinds.
|
|
585
|
+
*/
|
|
586
|
+
nestedFields?: Record<string, FieldDescriptor> | null;
|
|
587
|
+
/**
|
|
588
|
+
* At-rest protection mode for `secret` fields (`hashed` or `encrypted`).
|
|
589
|
+
* Null/absent for every other kind.
|
|
590
|
+
*/
|
|
591
|
+
secretMode?: SecretMode | null;
|
|
493
592
|
}
|
|
494
593
|
/**
|
|
495
594
|
* Defines a state machine on an enum field, constraining valid state transitions.
|
|
@@ -727,6 +826,21 @@ type KoraEvent = {
|
|
|
727
826
|
code: string;
|
|
728
827
|
message: string;
|
|
729
828
|
retriable: boolean;
|
|
829
|
+
} | {
|
|
830
|
+
/**
|
|
831
|
+
* The server rejected one of THIS client's outbound operations before it
|
|
832
|
+
* became authoritative. The op has been diverted out of the pending sync
|
|
833
|
+
* queue into the durable rejected store (kept, not retried); the app can
|
|
834
|
+
* surface the reason and decide whether to roll back the optimistic local
|
|
835
|
+
* write or let the user edit and resubmit.
|
|
836
|
+
*/
|
|
837
|
+
type: 'sync:operation-rejected';
|
|
838
|
+
operationId: string;
|
|
839
|
+
collection: string;
|
|
840
|
+
recordId: string;
|
|
841
|
+
code: string;
|
|
842
|
+
message: string;
|
|
843
|
+
retriable: boolean;
|
|
730
844
|
} | {
|
|
731
845
|
type: 'query:subscribed';
|
|
732
846
|
queryId: string;
|
|
@@ -781,6 +895,34 @@ type KoraEvent = {
|
|
|
781
895
|
type: 'store:quota-exceeded';
|
|
782
896
|
dbName: string;
|
|
783
897
|
message: string;
|
|
898
|
+
} | {
|
|
899
|
+
/**
|
|
900
|
+
* OPFS persistence was unavailable, so the store fell back to a
|
|
901
|
+
* NON-PERSISTENT in-memory database. Anything written this session is lost
|
|
902
|
+
* on reload. This is emitted instead of failing silently so the condition
|
|
903
|
+
* is observable rather than a data-loss trap.
|
|
904
|
+
*/
|
|
905
|
+
type: 'store:opfs-unavailable';
|
|
906
|
+
dbName: string;
|
|
907
|
+
/**
|
|
908
|
+
* Why OPFS could not be used. `lock-conflict` means another runtime on this
|
|
909
|
+
* origin already holds the OPFS pool for this database; `timeout` means the
|
|
910
|
+
* VFS install did not complete in time (common in headless CI); `unsupported`
|
|
911
|
+
* means the runtime has no usable OPFS.
|
|
912
|
+
*/
|
|
913
|
+
reason: 'lock-conflict' | 'timeout' | 'unsupported';
|
|
914
|
+
message: string;
|
|
915
|
+
} | {
|
|
916
|
+
/**
|
|
917
|
+
* Another runtime on this origin was already using this database name, so
|
|
918
|
+
* this runtime attached to it as a follower and now SHARES that one
|
|
919
|
+
* database. That is intended for multiple tabs of the SAME app; it is a bug
|
|
920
|
+
* if these are logically separate apps, which should each use a distinct
|
|
921
|
+
* store name (`store: { name: '...' }`) to stay isolated.
|
|
922
|
+
*/
|
|
923
|
+
type: 'store:db-name-collision';
|
|
924
|
+
dbName: string;
|
|
925
|
+
message: string;
|
|
784
926
|
} | {
|
|
785
927
|
type: 'replay:completed';
|
|
786
928
|
targetOperationId: string;
|
|
@@ -805,4 +947,4 @@ interface KoraEventEmitter {
|
|
|
805
947
|
emit<T extends KoraEventType>(event: KoraEventByType<T>): void;
|
|
806
948
|
}
|
|
807
949
|
|
|
808
|
-
export { type AtomicOpType as A, type
|
|
950
|
+
export { type AtomicOpType as A, type BlobRef as B, type CollectionDefinition as C, type SecretMode as D, EnumFieldBuilder as E, FieldBuilder as F, type SequenceConfig as G, type HLCTimestamp as H, type StateMachineDefinition as I, JsonFieldBuilder as J, type KoraEvent as K, type SyncDiagnosticsSnapshot as L, type MigrationDefinition as M, type SyncRuleDefinition as N, type OperationType as O, type TimeSource as P, migrate as Q, type RandomSource as R, type SchemaDefinition as S, type TransitionMap as T, t as U, type VersionVector as V, type AtomicOp as a, type CustomResolver as b, type RelationDefinition as c, ArrayFieldBuilder as d, type FieldKind as e, type Operation as f, type MigrationStep as g, type StateMachineConstraint as h, type TransitionValidationResult as i, CONNECTION_QUALITIES as j, type ConnectionQuality as k, type Constraint as l, type FieldDescriptor as m, type FieldMergeStrategy as n, type KoraEventByType as o, type KoraEventEmitter as p, type KoraEventListener as q, type KoraEventType as r, MERGE_STRATEGIES as s, type MergeStrategy as t, type MergeTrace as u, MigrationBuilder as v, type OnDeleteAction as w, type OperationInput as x, type RelationType as y, RollbackBuilder as z };
|