@korajs/core 0.6.0 → 1.0.0-beta.1

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.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { R as RandomSource, A as AtomicOpType, a as AtomicOp, F as FieldBuilder, C as CustomResolver, M as MigrationDefinition, S as SchemaDefinition, b as CollectionDefinition, c as RelationDefinition, O as OperationType, E as EnumFieldBuilder, d as ArrayFieldBuilder, e as FieldKind, f as Operation, V as VersionVector, g as MigrationStep, h as StateMachineConstraint, T as TransitionMap, i as TransitionValidationResult } from './events-D-FWfFg8.cjs';
2
- export { j as CONNECTION_QUALITIES, k as ConnectionQuality, l as Constraint, m as FieldDescriptor, n as FieldMergeStrategy, H as HLCTimestamp, K as KoraEvent, o as KoraEventByType, p as KoraEventEmitter, q as KoraEventListener, r as KoraEventType, s as MERGE_STRATEGIES, t as MergeStrategy, u as MergeTrace, v as MigrationBuilder, w as OnDeleteAction, x as OperationInput, y as RelationType, z as RollbackBuilder, B as SequenceConfig, D as StateMachineDefinition, G as SyncDiagnosticsSnapshot, I as SyncRuleDefinition, J as TimeSource, L as migrate, N as t } from './events-D-FWfFg8.cjs';
3
- export { H as HybridLogicalClock, c as createOperation, i as isValidOperation, v as verifyOperationIntegrity } from './operation-3-ZJJf3w.cjs';
4
- export { S as ScopeMap, b as buildScopeMap } from './build-scope-map-B1CcncZN.cjs';
1
+ import { R as RandomSource, B as BlobRef, C as CollectionDefinition, A as AtomicOpType, a as AtomicOp, F as FieldBuilder, b as CustomResolver, M as MigrationDefinition, S as SchemaDefinition, c as RelationDefinition, O as OperationType, E as EnumFieldBuilder, J as JsonFieldBuilder, d as ArrayFieldBuilder, e as FieldKind, f as Operation, V as VersionVector, g as MigrationStep, h as StateMachineConstraint, T as TransitionMap, i as TransitionValidationResult } from './events-CqDkr1LN.cjs';
2
+ export { j as CONNECTION_QUALITIES, k as ConnectionQuality, l as Constraint, m as FieldDescriptor, n as FieldMergeStrategy, H as HLCTimestamp, K as KoraEvent, o as KoraEventByType, p as KoraEventEmitter, q as KoraEventListener, r as KoraEventType, s as MERGE_STRATEGIES, t as MergeStrategy, u as MergeTrace, v as MigrationBuilder, w as OnDeleteAction, x as OperationInput, y as RelationType, z as RollbackBuilder, D as SecretMode, G as SequenceConfig, I as StateMachineDefinition, L as SyncDiagnosticsSnapshot, N as SyncRuleDefinition, P as TimeSource, Q as migrate, U as t } from './events-CqDkr1LN.cjs';
3
+ export { H as HybridLogicalClock, M as MAX_LOGICAL, c as createOperation, i as isValidOperation, v as verifyOperationIntegrity } from './operation-CFoY-ZmB.cjs';
4
+ export { S as ScopeMap, b as buildScopeMap } from './build-scope-map-DtTr9C7A.cjs';
5
5
 
6
6
  /**
7
7
  * Base error class for all Kora errors.
@@ -71,6 +71,23 @@ declare class AppNotReadyError extends KoraError {
71
71
  * Thrown when the HLC detects excessive clock drift.
72
72
  * Drift > 60s: warning. Drift > 5min: this error is thrown, refusing to generate timestamps.
73
73
  */
74
+ declare class RemoteClockDriftError extends KoraError {
75
+ readonly remoteWallTime: number;
76
+ readonly localReferenceTime: number;
77
+ constructor(remoteWallTime: number, localReferenceTime: number);
78
+ }
79
+ /**
80
+ * Thrown when an HLC timestamp has structurally invalid fields: non-integer or
81
+ * negative wallTime/logical, or a logical counter beyond the serializable cap.
82
+ * Rejected BEFORE any clock state changes, so a malformed remote timestamp can
83
+ * never corrupt a replica's clock or break the lexicographic ordering of the
84
+ * serialized form.
85
+ */
86
+ declare class InvalidTimestampError extends KoraError {
87
+ readonly wallTime: number;
88
+ readonly logical: number;
89
+ constructor(message: string, wallTime: number, logical: number);
90
+ }
74
91
  declare class ClockDriftError extends KoraError {
75
92
  readonly currentHlcTime: number;
76
93
  readonly physicalTime: number;
@@ -144,6 +161,137 @@ declare function extractTimestamp(uuid: string): number;
144
161
  */
145
162
  declare function isValidUUIDv7(uuid: string): boolean;
146
163
 
164
+ /**
165
+ * Compute the hex-encoded SHA-256 content hash of a byte buffer.
166
+ *
167
+ * This is the content address of a blob: identical bytes always hash to the same
168
+ * value, which is what lets the blob store deduplicate content and lets a peer
169
+ * skip transferring bytes it already holds.
170
+ *
171
+ * @param bytes - The binary content to hash
172
+ * @returns The hex-encoded SHA-256 hash
173
+ */
174
+ declare function hashBlob(bytes: Uint8Array): Promise<string>;
175
+ /** Optional metadata carried alongside a blob reference. */
176
+ interface BlobRefMetadata {
177
+ mimeType?: string;
178
+ filename?: string;
179
+ }
180
+ /**
181
+ * Create a content-addressed {@link BlobRef} for a byte buffer.
182
+ *
183
+ * @param bytes - The binary content
184
+ * @param metadata - Optional MIME type and filename
185
+ * @returns A reference carrying the content hash, size, and metadata
186
+ */
187
+ declare function createBlobRef(bytes: Uint8Array, metadata?: BlobRefMetadata): Promise<BlobRef>;
188
+ /**
189
+ * Type guard: whether a value is a structurally valid {@link BlobRef}.
190
+ *
191
+ * Validates the shape only (a non-empty hex hash and a non-negative size); it
192
+ * does not verify that the bytes behind the hash exist or match. Integrity
193
+ * verification against the actual bytes happens in the blob store on read.
194
+ */
195
+ declare function isBlobRef(value: unknown): value is BlobRef;
196
+
197
+ /**
198
+ * Field-level cryptography for `secret` fields.
199
+ *
200
+ * Two protection modes, matching the two ways secrets are used:
201
+ * - `encrypted`: reversible AES-256-GCM (tokens, API keys — decrypt to use).
202
+ * - `hashed`: one-way PBKDF2-SHA-256 with a random salt (passwords — verify only).
203
+ *
204
+ * These primitives use only the standard WebCrypto API so they live in
205
+ * `@korajs/core` with no dependency on `@korajs/auth`; a `secret` field is
206
+ * therefore self-contained. Higher-level key management composes on top.
207
+ */
208
+ /**
209
+ * Encrypt a secret's plaintext with AES-256-GCM under a key derived from
210
+ * `secretKey`. The returned string bundles the salt, IV, and ciphertext (all hex,
211
+ * dot-separated) so it is self-describing and safe to store and sync.
212
+ *
213
+ * @param plaintext - The secret value to protect
214
+ * @param secretKey - The key material (from a key provider), never stored
215
+ * @returns An opaque `v1.salt.iv.ciphertext` string
216
+ */
217
+ declare function encryptSecret(plaintext: string, secretKey: string): Promise<string>;
218
+ /**
219
+ * Decrypt a value produced by {@link encryptSecret} with the same key.
220
+ *
221
+ * @param encrypted - The `v1.salt.iv.ciphertext` string
222
+ * @param secretKey - The key material used to encrypt
223
+ * @returns The original plaintext
224
+ * @throws If the format is invalid or the key is wrong (GCM auth failure)
225
+ */
226
+ declare function decryptSecret(encrypted: string, secretKey: string): Promise<string>;
227
+ /**
228
+ * One-way hash a secret (a password) with PBKDF2-SHA-256 and a random salt.
229
+ * The result bundles the salt and hash so {@link verifySecret} needs nothing
230
+ * else. There is no way to recover the plaintext from the result.
231
+ *
232
+ * @param plaintext - The secret value to hash
233
+ * @returns An opaque `v1.salt.hash` string
234
+ */
235
+ declare function hashSecret(plaintext: string): Promise<string>;
236
+ /**
237
+ * Verify a plaintext against a value produced by {@link hashSecret}, in constant
238
+ * time with respect to the stored hash.
239
+ *
240
+ * @param plaintext - The candidate secret
241
+ * @param stored - The `v1.salt.hash` string
242
+ * @returns Whether the plaintext matches
243
+ */
244
+ declare function verifySecret(plaintext: string, stored: string): Promise<boolean>;
245
+
246
+ /**
247
+ * Provider of the key material used to encrypt reversible (`encrypted`) secret
248
+ * fields. Called at write and reveal time so the key can be loaded lazily (for
249
+ * example derived from a user passphrase after unlock). Returns undefined when
250
+ * no key is available.
251
+ */
252
+ type SecretKeyProvider = () => string | undefined | Promise<string | undefined>;
253
+ /** Thrown when an `encrypted` secret field is written or read without a key. */
254
+ declare class MissingSecretKeyError extends Error {
255
+ readonly field: string;
256
+ constructor(field: string);
257
+ }
258
+ /**
259
+ * Transform the secret fields of a record's write payload into their at-rest
260
+ * form BEFORE the operation is created, so plaintext never enters the operation
261
+ * log, the store, or the sync stream.
262
+ *
263
+ * - `hashed` fields become a one-way salted hash.
264
+ * - `encrypted` fields become ciphertext (requires a key).
265
+ *
266
+ * Non-secret fields, and secret fields not present in `data`, are passed through
267
+ * untouched. Null/undefined secret values are left as-is (nothing to protect).
268
+ *
269
+ * @param data - The validated write payload (plaintext secret values)
270
+ * @param collectionDef - The collection definition (for field kinds/modes)
271
+ * @param keyProvider - Supplies the encryption key for `encrypted` fields
272
+ * @returns A new payload with secret fields replaced by their at-rest form
273
+ */
274
+ declare function transformSecretFieldsForWrite(data: Record<string, unknown>, collectionDef: CollectionDefinition, keyProvider?: SecretKeyProvider): Promise<Record<string, unknown>>;
275
+ /**
276
+ * Reveal the plaintext of an `encrypted` secret field's stored value. Throws for
277
+ * `hashed` fields, which are one-way and cannot be revealed.
278
+ *
279
+ * @param storedValue - The at-rest value (ciphertext)
280
+ * @param mode - The field's secret mode
281
+ * @param keyProvider - Supplies the decryption key
282
+ * @param field - Field name (for error messages)
283
+ * @returns The decrypted plaintext
284
+ */
285
+ declare function revealSecret(storedValue: string, mode: 'hashed' | 'encrypted', keyProvider: SecretKeyProvider | undefined, field?: string): Promise<string>;
286
+ /**
287
+ * Verify a plaintext candidate against a `hashed` secret field's stored value.
288
+ *
289
+ * @param candidate - The plaintext to check (for example a login password)
290
+ * @param storedValue - The stored one-way hash
291
+ * @returns Whether the candidate matches
292
+ */
293
+ declare function verifySecretValue(candidate: string, storedValue: string): Promise<boolean>;
294
+
147
295
  /**
148
296
  * Outcome of applying a single operation to materialized storage (local or remote).
149
297
  */
@@ -289,6 +437,57 @@ declare const op: {
289
437
  */
290
438
  declare function toAtomicOp(sentinel: AtomicOpSentinel): AtomicOp;
291
439
 
440
+ /**
441
+ * Canonical JSON-safe encoding of binary bytes stored inside `op.data` /
442
+ * `op.previousData` (currently richtext field values). A raw Uint8Array
443
+ * JSON-serializes to a numeric-key object and an ArrayBuffer to `{}` (silent
444
+ * data loss), which breaks content-hash stability, persistence round-trips,
445
+ * remote application, and merge. Tagging the bytes as base64 at
446
+ * operation-creation time makes the hashed value, the persisted JSON, the wire
447
+ * payload, and the value the merge engine sees the identical canonical value.
448
+ *
449
+ * This convention lives in `@korajs/core` because `op.data` is a core concept:
450
+ * both `@korajs/store` (persistence, creation) and `@korajs/merge` (CRDT merge)
451
+ * must agree on it, and neither may depend on the other.
452
+ */
453
+ interface KoraBytesValue {
454
+ $koraBytes: string;
455
+ }
456
+ /**
457
+ * Type guard for the tagged binary form. Requires exactly the single
458
+ * `$koraBytes` key so arbitrary user objects that happen to contain the key
459
+ * are never silently reinterpreted as bytes.
460
+ */
461
+ declare function isKoraBytesValue(value: unknown): value is KoraBytesValue;
462
+ /**
463
+ * Detects the numeric-key object shape a raw Uint8Array produced when
464
+ * JSON-serialized before the tagged encoding existed ({"0":1,"1":2,...}).
465
+ */
466
+ declare function isLegacyNumericByteObject(value: unknown): value is Record<string, number>;
467
+ /**
468
+ * Dependency-free base64 encoder. btoa is unavailable for bytes in Node and
469
+ * Buffer is unavailable in browsers, so a manual implementation is the only
470
+ * deterministic option that works in every runtime Kora targets.
471
+ */
472
+ declare function bytesToBase64(bytes: Uint8Array): string;
473
+ /**
474
+ * Inverse of {@link bytesToBase64}.
475
+ */
476
+ declare function base64ToBytes(base64: string): Uint8Array;
477
+ /**
478
+ * Normalize a validated binary-or-string value into the canonical form stored
479
+ * in `op.data`: strings pass through unchanged (backward compatible with every
480
+ * existing operation), binary values become the tagged base64 form.
481
+ */
482
+ declare function encodeBytesForOpData(value: string | Uint8Array | ArrayBuffer): string | KoraBytesValue;
483
+ /**
484
+ * Reverse of {@link encodeBytesForOpData}, tolerant of every shape a binary
485
+ * op-data value has ever taken: canonical strings and tagged bytes, in-memory
486
+ * Uint8Array/ArrayBuffer (ops that never round-tripped through JSON), and
487
+ * pre-fix numeric-key objects.
488
+ */
489
+ declare function decodeBytesFromOpData(value: unknown): string | Uint8Array;
490
+
292
491
  /**
293
492
  * Input shape for defineSchema() — what the developer writes.
294
493
  */
@@ -440,12 +639,16 @@ interface FieldKindToType {
440
639
  richtext: string;
441
640
  enum: string;
442
641
  array: unknown[];
642
+ object: Record<string, unknown>;
643
+ json: unknown;
644
+ blob: BlobRef;
645
+ secret: string;
443
646
  }
444
647
  /**
445
648
  * Infers the TypeScript type for a single field descriptor or builder.
446
649
  * Supports both FieldBuilder (class instances) and FieldDescriptor (compiled objects).
447
650
  */
448
- type InferFieldType<F> = F extends EnumFieldBuilder<infer V, any, any> ? V[number] : F extends ArrayFieldBuilder<infer K, any, any> ? FieldKindToType[K][] : F extends FieldBuilder<infer K, any, any> ? K extends keyof FieldKindToType ? FieldKindToType[K] : unknown : F extends {
651
+ type InferFieldType<F> = F extends EnumFieldBuilder<infer V, any, any> ? V[number] : F extends JsonFieldBuilder<infer T, any, any> ? T : F extends ArrayFieldBuilder<infer K, any, any> ? FieldKindToType[K][] : F extends FieldBuilder<infer K, any, any> ? K extends keyof FieldKindToType ? FieldKindToType[K] : unknown : F extends {
449
652
  kind: 'enum';
450
653
  enumValues: infer V;
451
654
  } ? V extends readonly (infer S)[] ? S : string : F extends {
@@ -842,4 +1045,4 @@ interface ProtoOutput {
842
1045
  */
843
1046
  declare function generateProtoDefinitions(schema: SchemaDefinition): ProtoOutput;
844
1047
 
845
- export { APPLY_FAILURE_CODES, APPLY_RESULTS, AppNotReadyError, type ApplyFailureReason, type ApplyResult, ArrayFieldBuilder, AtomicOp, type AtomicOpSentinel, AtomicOpType, CausalTracker, ClockDriftError, CollectionDefinition, type CollectionInput, type ConstraintInput, CustomResolver, EnumFieldBuilder, FieldBuilder, FieldKind, type FieldKindToType, type InferFieldType, type InferInsertInput, type InferRecord, type InferUpdateInput, KORA_ERROR_FIX_SUGGESTIONS, KoraError, MergeConflictError, MigrationDefinition, MigrationRollbackError, MigrationStep, Operation, OperationError, type OperationLog, type OperationTransform, OperationType, type ProtoOutput, RandomSource, RelationDefinition, type RelationInput, type ReversibleMigration, SchemaDefinition, type SchemaInput, SchemaValidationError, StateMachineConstraint, type StateMachineInput, StorageError, SyncError, TransitionMap, TransitionValidationResult, type TypedSchemaDefinition, VersionVector, advanceVector, applyOperationTransforms, buildStateMachineConstraints, canAutoRollback, collectSchemaScopeFields, collectSchemaScopeValueKeys, computeDelta, createReversibleMigration, createVersionVector, defaultApplyFailureReason, defaultSequenceFormat, defineSchema, deserializeVector, dominates, extractScopeValuesFromClaims, extractTimestamp, formatSequenceValue, generateFullDDL, generateProtoDefinitions, generateRollbackSteps, generateSQL, generateUUIDv7, getCollectionScopeBindings, getKoraErrorFix, getTransitionMap, hasSchemaSyncRules, isApplyFailure, isAtomicOp, isCollectionSyncScoped, isValidUUIDv7, mergeVectors, migrationStepsToSQL, op, resolveAtomicOp, rollbackStepsToSQL, serializeVector, toAtomicOp, validateRecord, validateTransition, vectorsEqual };
1048
+ export { APPLY_FAILURE_CODES, APPLY_RESULTS, AppNotReadyError, type ApplyFailureReason, type ApplyResult, ArrayFieldBuilder, AtomicOp, type AtomicOpSentinel, AtomicOpType, BlobRef, type BlobRefMetadata, CausalTracker, ClockDriftError, CollectionDefinition, type CollectionInput, type ConstraintInput, CustomResolver, EnumFieldBuilder, FieldBuilder, FieldKind, type FieldKindToType, type InferFieldType, type InferInsertInput, type InferRecord, type InferUpdateInput, InvalidTimestampError, KORA_ERROR_FIX_SUGGESTIONS, type KoraBytesValue, KoraError, MergeConflictError, MigrationDefinition, MigrationRollbackError, MigrationStep, MissingSecretKeyError, Operation, OperationError, type OperationLog, type OperationTransform, OperationType, type ProtoOutput, RandomSource, RelationDefinition, type RelationInput, RemoteClockDriftError, type ReversibleMigration, SchemaDefinition, type SchemaInput, SchemaValidationError, type SecretKeyProvider, StateMachineConstraint, type StateMachineInput, StorageError, SyncError, TransitionMap, TransitionValidationResult, type TypedSchemaDefinition, VersionVector, advanceVector, applyOperationTransforms, base64ToBytes, buildStateMachineConstraints, bytesToBase64, canAutoRollback, collectSchemaScopeFields, collectSchemaScopeValueKeys, computeDelta, createBlobRef, createReversibleMigration, createVersionVector, decodeBytesFromOpData, decryptSecret, defaultApplyFailureReason, defaultSequenceFormat, defineSchema, deserializeVector, dominates, encodeBytesForOpData, encryptSecret, extractScopeValuesFromClaims, extractTimestamp, formatSequenceValue, generateFullDDL, generateProtoDefinitions, generateRollbackSteps, generateSQL, generateUUIDv7, getCollectionScopeBindings, getKoraErrorFix, getTransitionMap, hasSchemaSyncRules, hashBlob, hashSecret, isApplyFailure, isAtomicOp, isBlobRef, isCollectionSyncScoped, isKoraBytesValue, isLegacyNumericByteObject, isValidUUIDv7, mergeVectors, migrationStepsToSQL, op, resolveAtomicOp, revealSecret, rollbackStepsToSQL, serializeVector, toAtomicOp, transformSecretFieldsForWrite, validateRecord, validateTransition, vectorsEqual, verifySecret, verifySecretValue };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { R as RandomSource, A as AtomicOpType, a as AtomicOp, F as FieldBuilder, C as CustomResolver, M as MigrationDefinition, S as SchemaDefinition, b as CollectionDefinition, c as RelationDefinition, O as OperationType, E as EnumFieldBuilder, d as ArrayFieldBuilder, e as FieldKind, f as Operation, V as VersionVector, g as MigrationStep, h as StateMachineConstraint, T as TransitionMap, i as TransitionValidationResult } from './events-D-FWfFg8.js';
2
- export { j as CONNECTION_QUALITIES, k as ConnectionQuality, l as Constraint, m as FieldDescriptor, n as FieldMergeStrategy, H as HLCTimestamp, K as KoraEvent, o as KoraEventByType, p as KoraEventEmitter, q as KoraEventListener, r as KoraEventType, s as MERGE_STRATEGIES, t as MergeStrategy, u as MergeTrace, v as MigrationBuilder, w as OnDeleteAction, x as OperationInput, y as RelationType, z as RollbackBuilder, B as SequenceConfig, D as StateMachineDefinition, G as SyncDiagnosticsSnapshot, I as SyncRuleDefinition, J as TimeSource, L as migrate, N as t } from './events-D-FWfFg8.js';
3
- export { H as HybridLogicalClock, c as createOperation, i as isValidOperation, v as verifyOperationIntegrity } from './operation-CygOwIjZ.js';
4
- export { S as ScopeMap, b as buildScopeMap } from './build-scope-map-BmgAT82h.js';
1
+ import { R as RandomSource, B as BlobRef, C as CollectionDefinition, A as AtomicOpType, a as AtomicOp, F as FieldBuilder, b as CustomResolver, M as MigrationDefinition, S as SchemaDefinition, c as RelationDefinition, O as OperationType, E as EnumFieldBuilder, J as JsonFieldBuilder, d as ArrayFieldBuilder, e as FieldKind, f as Operation, V as VersionVector, g as MigrationStep, h as StateMachineConstraint, T as TransitionMap, i as TransitionValidationResult } from './events-CqDkr1LN.js';
2
+ export { j as CONNECTION_QUALITIES, k as ConnectionQuality, l as Constraint, m as FieldDescriptor, n as FieldMergeStrategy, H as HLCTimestamp, K as KoraEvent, o as KoraEventByType, p as KoraEventEmitter, q as KoraEventListener, r as KoraEventType, s as MERGE_STRATEGIES, t as MergeStrategy, u as MergeTrace, v as MigrationBuilder, w as OnDeleteAction, x as OperationInput, y as RelationType, z as RollbackBuilder, D as SecretMode, G as SequenceConfig, I as StateMachineDefinition, L as SyncDiagnosticsSnapshot, N as SyncRuleDefinition, P as TimeSource, Q as migrate, U as t } from './events-CqDkr1LN.js';
3
+ export { H as HybridLogicalClock, M as MAX_LOGICAL, c as createOperation, i as isValidOperation, v as verifyOperationIntegrity } from './operation-BJtu18Fi.js';
4
+ export { S as ScopeMap, b as buildScopeMap } from './build-scope-map-DvOHbYjn.js';
5
5
 
6
6
  /**
7
7
  * Base error class for all Kora errors.
@@ -71,6 +71,23 @@ declare class AppNotReadyError extends KoraError {
71
71
  * Thrown when the HLC detects excessive clock drift.
72
72
  * Drift > 60s: warning. Drift > 5min: this error is thrown, refusing to generate timestamps.
73
73
  */
74
+ declare class RemoteClockDriftError extends KoraError {
75
+ readonly remoteWallTime: number;
76
+ readonly localReferenceTime: number;
77
+ constructor(remoteWallTime: number, localReferenceTime: number);
78
+ }
79
+ /**
80
+ * Thrown when an HLC timestamp has structurally invalid fields: non-integer or
81
+ * negative wallTime/logical, or a logical counter beyond the serializable cap.
82
+ * Rejected BEFORE any clock state changes, so a malformed remote timestamp can
83
+ * never corrupt a replica's clock or break the lexicographic ordering of the
84
+ * serialized form.
85
+ */
86
+ declare class InvalidTimestampError extends KoraError {
87
+ readonly wallTime: number;
88
+ readonly logical: number;
89
+ constructor(message: string, wallTime: number, logical: number);
90
+ }
74
91
  declare class ClockDriftError extends KoraError {
75
92
  readonly currentHlcTime: number;
76
93
  readonly physicalTime: number;
@@ -144,6 +161,137 @@ declare function extractTimestamp(uuid: string): number;
144
161
  */
145
162
  declare function isValidUUIDv7(uuid: string): boolean;
146
163
 
164
+ /**
165
+ * Compute the hex-encoded SHA-256 content hash of a byte buffer.
166
+ *
167
+ * This is the content address of a blob: identical bytes always hash to the same
168
+ * value, which is what lets the blob store deduplicate content and lets a peer
169
+ * skip transferring bytes it already holds.
170
+ *
171
+ * @param bytes - The binary content to hash
172
+ * @returns The hex-encoded SHA-256 hash
173
+ */
174
+ declare function hashBlob(bytes: Uint8Array): Promise<string>;
175
+ /** Optional metadata carried alongside a blob reference. */
176
+ interface BlobRefMetadata {
177
+ mimeType?: string;
178
+ filename?: string;
179
+ }
180
+ /**
181
+ * Create a content-addressed {@link BlobRef} for a byte buffer.
182
+ *
183
+ * @param bytes - The binary content
184
+ * @param metadata - Optional MIME type and filename
185
+ * @returns A reference carrying the content hash, size, and metadata
186
+ */
187
+ declare function createBlobRef(bytes: Uint8Array, metadata?: BlobRefMetadata): Promise<BlobRef>;
188
+ /**
189
+ * Type guard: whether a value is a structurally valid {@link BlobRef}.
190
+ *
191
+ * Validates the shape only (a non-empty hex hash and a non-negative size); it
192
+ * does not verify that the bytes behind the hash exist or match. Integrity
193
+ * verification against the actual bytes happens in the blob store on read.
194
+ */
195
+ declare function isBlobRef(value: unknown): value is BlobRef;
196
+
197
+ /**
198
+ * Field-level cryptography for `secret` fields.
199
+ *
200
+ * Two protection modes, matching the two ways secrets are used:
201
+ * - `encrypted`: reversible AES-256-GCM (tokens, API keys — decrypt to use).
202
+ * - `hashed`: one-way PBKDF2-SHA-256 with a random salt (passwords — verify only).
203
+ *
204
+ * These primitives use only the standard WebCrypto API so they live in
205
+ * `@korajs/core` with no dependency on `@korajs/auth`; a `secret` field is
206
+ * therefore self-contained. Higher-level key management composes on top.
207
+ */
208
+ /**
209
+ * Encrypt a secret's plaintext with AES-256-GCM under a key derived from
210
+ * `secretKey`. The returned string bundles the salt, IV, and ciphertext (all hex,
211
+ * dot-separated) so it is self-describing and safe to store and sync.
212
+ *
213
+ * @param plaintext - The secret value to protect
214
+ * @param secretKey - The key material (from a key provider), never stored
215
+ * @returns An opaque `v1.salt.iv.ciphertext` string
216
+ */
217
+ declare function encryptSecret(plaintext: string, secretKey: string): Promise<string>;
218
+ /**
219
+ * Decrypt a value produced by {@link encryptSecret} with the same key.
220
+ *
221
+ * @param encrypted - The `v1.salt.iv.ciphertext` string
222
+ * @param secretKey - The key material used to encrypt
223
+ * @returns The original plaintext
224
+ * @throws If the format is invalid or the key is wrong (GCM auth failure)
225
+ */
226
+ declare function decryptSecret(encrypted: string, secretKey: string): Promise<string>;
227
+ /**
228
+ * One-way hash a secret (a password) with PBKDF2-SHA-256 and a random salt.
229
+ * The result bundles the salt and hash so {@link verifySecret} needs nothing
230
+ * else. There is no way to recover the plaintext from the result.
231
+ *
232
+ * @param plaintext - The secret value to hash
233
+ * @returns An opaque `v1.salt.hash` string
234
+ */
235
+ declare function hashSecret(plaintext: string): Promise<string>;
236
+ /**
237
+ * Verify a plaintext against a value produced by {@link hashSecret}, in constant
238
+ * time with respect to the stored hash.
239
+ *
240
+ * @param plaintext - The candidate secret
241
+ * @param stored - The `v1.salt.hash` string
242
+ * @returns Whether the plaintext matches
243
+ */
244
+ declare function verifySecret(plaintext: string, stored: string): Promise<boolean>;
245
+
246
+ /**
247
+ * Provider of the key material used to encrypt reversible (`encrypted`) secret
248
+ * fields. Called at write and reveal time so the key can be loaded lazily (for
249
+ * example derived from a user passphrase after unlock). Returns undefined when
250
+ * no key is available.
251
+ */
252
+ type SecretKeyProvider = () => string | undefined | Promise<string | undefined>;
253
+ /** Thrown when an `encrypted` secret field is written or read without a key. */
254
+ declare class MissingSecretKeyError extends Error {
255
+ readonly field: string;
256
+ constructor(field: string);
257
+ }
258
+ /**
259
+ * Transform the secret fields of a record's write payload into their at-rest
260
+ * form BEFORE the operation is created, so plaintext never enters the operation
261
+ * log, the store, or the sync stream.
262
+ *
263
+ * - `hashed` fields become a one-way salted hash.
264
+ * - `encrypted` fields become ciphertext (requires a key).
265
+ *
266
+ * Non-secret fields, and secret fields not present in `data`, are passed through
267
+ * untouched. Null/undefined secret values are left as-is (nothing to protect).
268
+ *
269
+ * @param data - The validated write payload (plaintext secret values)
270
+ * @param collectionDef - The collection definition (for field kinds/modes)
271
+ * @param keyProvider - Supplies the encryption key for `encrypted` fields
272
+ * @returns A new payload with secret fields replaced by their at-rest form
273
+ */
274
+ declare function transformSecretFieldsForWrite(data: Record<string, unknown>, collectionDef: CollectionDefinition, keyProvider?: SecretKeyProvider): Promise<Record<string, unknown>>;
275
+ /**
276
+ * Reveal the plaintext of an `encrypted` secret field's stored value. Throws for
277
+ * `hashed` fields, which are one-way and cannot be revealed.
278
+ *
279
+ * @param storedValue - The at-rest value (ciphertext)
280
+ * @param mode - The field's secret mode
281
+ * @param keyProvider - Supplies the decryption key
282
+ * @param field - Field name (for error messages)
283
+ * @returns The decrypted plaintext
284
+ */
285
+ declare function revealSecret(storedValue: string, mode: 'hashed' | 'encrypted', keyProvider: SecretKeyProvider | undefined, field?: string): Promise<string>;
286
+ /**
287
+ * Verify a plaintext candidate against a `hashed` secret field's stored value.
288
+ *
289
+ * @param candidate - The plaintext to check (for example a login password)
290
+ * @param storedValue - The stored one-way hash
291
+ * @returns Whether the candidate matches
292
+ */
293
+ declare function verifySecretValue(candidate: string, storedValue: string): Promise<boolean>;
294
+
147
295
  /**
148
296
  * Outcome of applying a single operation to materialized storage (local or remote).
149
297
  */
@@ -289,6 +437,57 @@ declare const op: {
289
437
  */
290
438
  declare function toAtomicOp(sentinel: AtomicOpSentinel): AtomicOp;
291
439
 
440
+ /**
441
+ * Canonical JSON-safe encoding of binary bytes stored inside `op.data` /
442
+ * `op.previousData` (currently richtext field values). A raw Uint8Array
443
+ * JSON-serializes to a numeric-key object and an ArrayBuffer to `{}` (silent
444
+ * data loss), which breaks content-hash stability, persistence round-trips,
445
+ * remote application, and merge. Tagging the bytes as base64 at
446
+ * operation-creation time makes the hashed value, the persisted JSON, the wire
447
+ * payload, and the value the merge engine sees the identical canonical value.
448
+ *
449
+ * This convention lives in `@korajs/core` because `op.data` is a core concept:
450
+ * both `@korajs/store` (persistence, creation) and `@korajs/merge` (CRDT merge)
451
+ * must agree on it, and neither may depend on the other.
452
+ */
453
+ interface KoraBytesValue {
454
+ $koraBytes: string;
455
+ }
456
+ /**
457
+ * Type guard for the tagged binary form. Requires exactly the single
458
+ * `$koraBytes` key so arbitrary user objects that happen to contain the key
459
+ * are never silently reinterpreted as bytes.
460
+ */
461
+ declare function isKoraBytesValue(value: unknown): value is KoraBytesValue;
462
+ /**
463
+ * Detects the numeric-key object shape a raw Uint8Array produced when
464
+ * JSON-serialized before the tagged encoding existed ({"0":1,"1":2,...}).
465
+ */
466
+ declare function isLegacyNumericByteObject(value: unknown): value is Record<string, number>;
467
+ /**
468
+ * Dependency-free base64 encoder. btoa is unavailable for bytes in Node and
469
+ * Buffer is unavailable in browsers, so a manual implementation is the only
470
+ * deterministic option that works in every runtime Kora targets.
471
+ */
472
+ declare function bytesToBase64(bytes: Uint8Array): string;
473
+ /**
474
+ * Inverse of {@link bytesToBase64}.
475
+ */
476
+ declare function base64ToBytes(base64: string): Uint8Array;
477
+ /**
478
+ * Normalize a validated binary-or-string value into the canonical form stored
479
+ * in `op.data`: strings pass through unchanged (backward compatible with every
480
+ * existing operation), binary values become the tagged base64 form.
481
+ */
482
+ declare function encodeBytesForOpData(value: string | Uint8Array | ArrayBuffer): string | KoraBytesValue;
483
+ /**
484
+ * Reverse of {@link encodeBytesForOpData}, tolerant of every shape a binary
485
+ * op-data value has ever taken: canonical strings and tagged bytes, in-memory
486
+ * Uint8Array/ArrayBuffer (ops that never round-tripped through JSON), and
487
+ * pre-fix numeric-key objects.
488
+ */
489
+ declare function decodeBytesFromOpData(value: unknown): string | Uint8Array;
490
+
292
491
  /**
293
492
  * Input shape for defineSchema() — what the developer writes.
294
493
  */
@@ -440,12 +639,16 @@ interface FieldKindToType {
440
639
  richtext: string;
441
640
  enum: string;
442
641
  array: unknown[];
642
+ object: Record<string, unknown>;
643
+ json: unknown;
644
+ blob: BlobRef;
645
+ secret: string;
443
646
  }
444
647
  /**
445
648
  * Infers the TypeScript type for a single field descriptor or builder.
446
649
  * Supports both FieldBuilder (class instances) and FieldDescriptor (compiled objects).
447
650
  */
448
- type InferFieldType<F> = F extends EnumFieldBuilder<infer V, any, any> ? V[number] : F extends ArrayFieldBuilder<infer K, any, any> ? FieldKindToType[K][] : F extends FieldBuilder<infer K, any, any> ? K extends keyof FieldKindToType ? FieldKindToType[K] : unknown : F extends {
651
+ type InferFieldType<F> = F extends EnumFieldBuilder<infer V, any, any> ? V[number] : F extends JsonFieldBuilder<infer T, any, any> ? T : F extends ArrayFieldBuilder<infer K, any, any> ? FieldKindToType[K][] : F extends FieldBuilder<infer K, any, any> ? K extends keyof FieldKindToType ? FieldKindToType[K] : unknown : F extends {
449
652
  kind: 'enum';
450
653
  enumValues: infer V;
451
654
  } ? V extends readonly (infer S)[] ? S : string : F extends {
@@ -842,4 +1045,4 @@ interface ProtoOutput {
842
1045
  */
843
1046
  declare function generateProtoDefinitions(schema: SchemaDefinition): ProtoOutput;
844
1047
 
845
- export { APPLY_FAILURE_CODES, APPLY_RESULTS, AppNotReadyError, type ApplyFailureReason, type ApplyResult, ArrayFieldBuilder, AtomicOp, type AtomicOpSentinel, AtomicOpType, CausalTracker, ClockDriftError, CollectionDefinition, type CollectionInput, type ConstraintInput, CustomResolver, EnumFieldBuilder, FieldBuilder, FieldKind, type FieldKindToType, type InferFieldType, type InferInsertInput, type InferRecord, type InferUpdateInput, KORA_ERROR_FIX_SUGGESTIONS, KoraError, MergeConflictError, MigrationDefinition, MigrationRollbackError, MigrationStep, Operation, OperationError, type OperationLog, type OperationTransform, OperationType, type ProtoOutput, RandomSource, RelationDefinition, type RelationInput, type ReversibleMigration, SchemaDefinition, type SchemaInput, SchemaValidationError, StateMachineConstraint, type StateMachineInput, StorageError, SyncError, TransitionMap, TransitionValidationResult, type TypedSchemaDefinition, VersionVector, advanceVector, applyOperationTransforms, buildStateMachineConstraints, canAutoRollback, collectSchemaScopeFields, collectSchemaScopeValueKeys, computeDelta, createReversibleMigration, createVersionVector, defaultApplyFailureReason, defaultSequenceFormat, defineSchema, deserializeVector, dominates, extractScopeValuesFromClaims, extractTimestamp, formatSequenceValue, generateFullDDL, generateProtoDefinitions, generateRollbackSteps, generateSQL, generateUUIDv7, getCollectionScopeBindings, getKoraErrorFix, getTransitionMap, hasSchemaSyncRules, isApplyFailure, isAtomicOp, isCollectionSyncScoped, isValidUUIDv7, mergeVectors, migrationStepsToSQL, op, resolveAtomicOp, rollbackStepsToSQL, serializeVector, toAtomicOp, validateRecord, validateTransition, vectorsEqual };
1048
+ export { APPLY_FAILURE_CODES, APPLY_RESULTS, AppNotReadyError, type ApplyFailureReason, type ApplyResult, ArrayFieldBuilder, AtomicOp, type AtomicOpSentinel, AtomicOpType, BlobRef, type BlobRefMetadata, CausalTracker, ClockDriftError, CollectionDefinition, type CollectionInput, type ConstraintInput, CustomResolver, EnumFieldBuilder, FieldBuilder, FieldKind, type FieldKindToType, type InferFieldType, type InferInsertInput, type InferRecord, type InferUpdateInput, InvalidTimestampError, KORA_ERROR_FIX_SUGGESTIONS, type KoraBytesValue, KoraError, MergeConflictError, MigrationDefinition, MigrationRollbackError, MigrationStep, MissingSecretKeyError, Operation, OperationError, type OperationLog, type OperationTransform, OperationType, type ProtoOutput, RandomSource, RelationDefinition, type RelationInput, RemoteClockDriftError, type ReversibleMigration, SchemaDefinition, type SchemaInput, SchemaValidationError, type SecretKeyProvider, StateMachineConstraint, type StateMachineInput, StorageError, SyncError, TransitionMap, TransitionValidationResult, type TypedSchemaDefinition, VersionVector, advanceVector, applyOperationTransforms, base64ToBytes, buildStateMachineConstraints, bytesToBase64, canAutoRollback, collectSchemaScopeFields, collectSchemaScopeValueKeys, computeDelta, createBlobRef, createReversibleMigration, createVersionVector, decodeBytesFromOpData, decryptSecret, defaultApplyFailureReason, defaultSequenceFormat, defineSchema, deserializeVector, dominates, encodeBytesForOpData, encryptSecret, extractScopeValuesFromClaims, extractTimestamp, formatSequenceValue, generateFullDDL, generateProtoDefinitions, generateRollbackSteps, generateSQL, generateUUIDv7, getCollectionScopeBindings, getKoraErrorFix, getTransitionMap, hasSchemaSyncRules, hashBlob, hashSecret, isApplyFailure, isAtomicOp, isBlobRef, isCollectionSyncScoped, isKoraBytesValue, isLegacyNumericByteObject, isValidUUIDv7, mergeVectors, migrationStepsToSQL, op, resolveAtomicOp, revealSecret, rollbackStepsToSQL, serializeVector, toAtomicOp, transformSecretFieldsForWrite, validateRecord, validateTransition, vectorsEqual, verifySecret, verifySecretValue };