@korajs/core 0.4.0 → 0.6.0

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,5 +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 Operation, V as VersionVector, f as MigrationStep, g as StateMachineConstraint, T as TransitionMap, h as TransitionValidationResult } from './events-BMulupSB.cjs';
2
- export { i as CONNECTION_QUALITIES, j as ConnectionQuality, k as Constraint, l as FieldDescriptor, m as FieldKind, n as FieldMergeStrategy, H as HLCTimestamp, o as HybridLogicalClock, K as KoraEvent, p as KoraEventByType, q as KoraEventEmitter, r as KoraEventListener, s as KoraEventType, t as MERGE_STRATEGIES, u as MergeStrategy, v as MergeTrace, w as MigrationBuilder, x as OnDeleteAction, y as OperationInput, z as RelationType, B as RollbackBuilder, D as SequenceConfig, G as StateMachineDefinition, I as SyncDiagnosticsSnapshot, J as TimeSource, L as createOperation, N as isValidOperation, P as migrate, Q as t, U as verifyOperationIntegrity } from './events-BMulupSB.cjs';
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';
3
5
 
4
6
  /**
5
7
  * Base error class for all Kora errors.
@@ -9,6 +11,10 @@ declare class KoraError extends Error {
9
11
  readonly code: string;
10
12
  readonly context?: Record<string, unknown> | undefined;
11
13
  constructor(message: string, code: string, context?: Record<string, unknown> | undefined);
14
+ /**
15
+ * Actionable hint for resolving this error (from registry or error context).
16
+ */
17
+ get fix(): string | undefined;
12
18
  }
13
19
  /**
14
20
  * Thrown when schema validation fails during defineSchema() or at app initialization.
@@ -55,6 +61,12 @@ declare class SyncError extends KoraError {
55
61
  declare class StorageError extends KoraError {
56
62
  constructor(message: string, context?: Record<string, unknown>);
57
63
  }
64
+ /**
65
+ * Thrown when collection/query APIs are used before {@link KoraApp.ready} resolves.
66
+ */
67
+ declare class AppNotReadyError extends KoraError {
68
+ constructor(detail: string);
69
+ }
58
70
  /**
59
71
  * Thrown when the HLC detects excessive clock drift.
60
72
  * Drift > 60s: warning. Drift > 5min: this error is thrown, refusing to generate timestamps.
@@ -65,6 +77,41 @@ declare class ClockDriftError extends KoraError {
65
77
  constructor(currentHlcTime: number, physicalTime: number);
66
78
  }
67
79
 
80
+ /**
81
+ * Human-readable remediation hints keyed by {@link KoraError} `code`.
82
+ */
83
+ declare const KORA_ERROR_FIX_SUGGESTIONS: Record<string, string>;
84
+ /**
85
+ * Returns a suggested fix for a Kora error code, if one is known.
86
+ */
87
+ declare function getKoraErrorFix(code: string): string | undefined;
88
+
89
+ /**
90
+ * Tracks the latest operation per collection and within an open transaction
91
+ * to populate {@link Operation.causalDeps} for local mutations.
92
+ */
93
+ declare class CausalTracker {
94
+ private readonly lastOpIdByCollection;
95
+ private lastTransactionOpId;
96
+ /**
97
+ * Start a new transaction boundary. Clears in-transaction op ids.
98
+ */
99
+ beginTransaction(): void;
100
+ /**
101
+ * Clear the transaction boundary without recording ops (after rollback).
102
+ */
103
+ clearTransaction(): void;
104
+ /**
105
+ * Compute causal dependencies for the next operation in a collection.
106
+ * Uses direct parents only: collection head and the previous op in the open transaction.
107
+ */
108
+ nextCausalDeps(collection: string, inTransaction: boolean): string[];
109
+ /**
110
+ * Record an operation after it has been created and assigned an id.
111
+ */
112
+ afterOperation(collection: string, operationId: string, inTransaction: boolean): void;
113
+ }
114
+
68
115
  /**
69
116
  * Generates a UUID v7 per RFC 9562.
70
117
  * UUID v7 encodes a Unix timestamp in milliseconds in the most significant 48 bits,
@@ -97,6 +144,38 @@ declare function extractTimestamp(uuid: string): number;
97
144
  */
98
145
  declare function isValidUUIDv7(uuid: string): boolean;
99
146
 
147
+ /**
148
+ * Outcome of applying a single operation to materialized storage (local or remote).
149
+ */
150
+ declare const APPLY_RESULTS: readonly ["applied", "duplicate", "skipped", "rejected", "deferred"];
151
+ type ApplyResult = (typeof APPLY_RESULTS)[number];
152
+ /**
153
+ * Structured failure metadata when apply returns `skipped`, `rejected`, or `deferred`.
154
+ */
155
+ interface ApplyFailureReason {
156
+ code: string;
157
+ message: string;
158
+ retriable: boolean;
159
+ }
160
+ /** Well-known apply failure codes for DevTools and `sync:apply-failed` events. */
161
+ declare const APPLY_FAILURE_CODES: {
162
+ readonly APPLY_FAILED: "APPLY_FAILED";
163
+ readonly APPLY_SKIPPED: "APPLY_SKIPPED";
164
+ readonly APPLY_REJECTED: "APPLY_REJECTED";
165
+ readonly APPLY_DEFERRED: "APPLY_DEFERRED";
166
+ readonly CLOCK_DRIFT: "CLOCK_DRIFT";
167
+ readonly REFERENTIAL_INTEGRITY: "REFERENTIAL_INTEGRITY";
168
+ readonly SCHEMA_MISMATCH: "SCHEMA_MISMATCH";
169
+ };
170
+ /**
171
+ * Returns true when the apply outcome should surface as a failure to the developer.
172
+ */
173
+ declare function isApplyFailure(result: ApplyResult): boolean;
174
+ /**
175
+ * Default failure metadata when the store does not attach a specific reason.
176
+ */
177
+ declare function defaultApplyFailureReason(result: Exclude<ApplyResult, 'applied' | 'duplicate'>, overrides?: Partial<ApplyFailureReason>): ApplyFailureReason;
178
+
100
179
  /**
101
180
  * Atomic field operations for intent-preserving updates.
102
181
  *
@@ -219,6 +298,29 @@ interface SchemaInput {
219
298
  relations?: Record<string, RelationInput>;
220
299
  /** Schema migrations keyed by target version number. */
221
300
  migrations?: Record<number, MigrationDefinition>;
301
+ /**
302
+ * Declarative partial-sync rules.
303
+ *
304
+ * @example
305
+ * ```typescript
306
+ * sync: {
307
+ * todos: { where: { userId: true, orgId: true } },
308
+ * projects: { where: { orgId: true } },
309
+ * }
310
+ * ```
311
+ */
312
+ sync?: Record<string, SyncRuleInput>;
313
+ }
314
+ /**
315
+ * Developer input for a collection sync rule.
316
+ */
317
+ interface SyncRuleInput {
318
+ /**
319
+ * Field filters bound to scope values.
320
+ * Use `true` to bind a field to a scope value with the same name.
321
+ * Use a string to bind to a different scope value key.
322
+ */
323
+ where: Record<string, boolean | string>;
222
324
  }
223
325
  interface StateMachineInput {
224
326
  /** The enum field this state machine controls */
@@ -335,15 +437,23 @@ interface FieldKindToType {
335
437
  number: number;
336
438
  boolean: boolean;
337
439
  timestamp: number;
338
- richtext: Uint8Array;
440
+ richtext: string;
339
441
  enum: string;
340
442
  array: unknown[];
341
443
  }
342
444
  /**
343
- * Infers the TypeScript type for a single FieldBuilder.
344
- * Handles base fields, enums (with literal union), and arrays (with typed items).
445
+ * Infers the TypeScript type for a single field descriptor or builder.
446
+ * Supports both FieldBuilder (class instances) and FieldDescriptor (compiled objects).
345
447
  */
346
- type InferFieldType<F> = F extends EnumFieldBuilder<infer V, infer _Req, infer _Auto> ? V[number] : F extends ArrayFieldBuilder<infer K, infer _Req, infer _Auto> ? FieldKindToType[K][] : F extends FieldBuilder<infer K, infer _Req, infer _Auto> ? FieldKindToType[K] : unknown;
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 {
449
+ kind: 'enum';
450
+ enumValues: infer V;
451
+ } ? V extends readonly (infer S)[] ? S : string : F extends {
452
+ kind: 'array';
453
+ itemKind: infer K extends FieldKind;
454
+ } ? FieldKindToType[K][] : F extends {
455
+ kind: infer K extends FieldKind;
456
+ } ? FieldKindToType[K] : unknown;
347
457
  /**
348
458
  * Infers the full record type returned from queries.
349
459
  * Includes `id`, `createdAt`, `updatedAt` metadata fields.
@@ -357,40 +467,22 @@ type InferRecord<Fields extends Record<string, FieldBuilder<any, any, any>>> = {
357
467
  readonly [K in keyof Fields]: Fields[K] extends FieldBuilder<any, true, any> ? InferFieldType<Fields[K]> : InferFieldType<Fields[K]> | null;
358
468
  };
359
469
  /**
360
- * Helper: extract keys where the field is required and not auto.
361
- */
362
- type RequiredInsertKeys<Fields extends Record<string, FieldBuilder<any, any, any>>> = {
363
- [K in keyof Fields]: Fields[K] extends FieldBuilder<any, any, true> ? never : Fields[K] extends FieldBuilder<any, true, false> ? K : never;
364
- }[keyof Fields];
365
- /**
366
- * Helper: extract keys where the field is optional (not required) and not auto.
367
- */
368
- type OptionalInsertKeys<Fields extends Record<string, FieldBuilder<any, any, any>>> = {
369
- [K in keyof Fields]: Fields[K] extends FieldBuilder<any, any, true> ? never : Fields[K] extends FieldBuilder<any, true, false> ? never : K;
370
- }[keyof Fields];
371
- /**
372
- * Infers the insert input type.
470
+ * Infers the insert input type using inline key remapping.
373
471
  * - Required non-auto fields are required keys
374
472
  * - Optional/defaulted non-auto fields are optional keys
375
473
  * - Auto fields are excluded entirely
376
474
  */
377
475
  type InferInsertInput<Fields extends Record<string, FieldBuilder<any, any, any>>> = {
378
- [K in RequiredInsertKeys<Fields> & string]: InferFieldType<Fields[K]>;
476
+ [K in keyof Fields as Fields[K] extends FieldBuilder<any, any, true> ? never : Fields[K] extends FieldBuilder<any, true, false> ? K : never]: InferFieldType<Fields[K]>;
379
477
  } & {
380
- [K in OptionalInsertKeys<Fields> & string]?: InferFieldType<Fields[K]>;
478
+ [K in keyof Fields as Fields[K] extends FieldBuilder<any, any, true> ? never : Fields[K] extends FieldBuilder<any, true, false> ? never : K]?: InferFieldType<Fields[K]>;
381
479
  };
382
480
  /**
383
- * Helper: extract keys where the field is not auto.
384
- */
385
- type NonAutoKeys<Fields extends Record<string, FieldBuilder<any, any, any>>> = {
386
- [K in keyof Fields]: Fields[K] extends FieldBuilder<any, any, true> ? never : K;
387
- }[keyof Fields];
388
- /**
389
- * Infers the update input type.
481
+ * Infers the update input type using inline key remapping.
390
482
  * All non-auto fields are optional (partial update semantics).
391
483
  */
392
484
  type InferUpdateInput<Fields extends Record<string, FieldBuilder<any, any, any>>> = {
393
- [K in NonAutoKeys<Fields> & string]?: InferFieldType<Fields[K]>;
485
+ [K in keyof Fields as Fields[K] extends FieldBuilder<any, any, true> ? never : K]?: InferFieldType<Fields[K]>;
394
486
  };
395
487
 
396
488
  /**
@@ -418,9 +510,10 @@ declare function dominates(a: VersionVector, b: VersionVector): boolean;
418
510
  declare function vectorsEqual(a: VersionVector, b: VersionVector): boolean;
419
511
  /**
420
512
  * Operation log interface for computing deltas.
513
+ * getRange may be async (for DB-backed implementations) or sync (for in-memory).
421
514
  */
422
515
  interface OperationLog {
423
- getRange(nodeId: string, fromSeq: number, toSeq: number): Operation[];
516
+ getRange(nodeId: string, fromSeq: number, toSeq: number): Operation[] | Promise<Operation[]>;
424
517
  }
425
518
  /**
426
519
  * Compute the operations that `local` has but `remote` does not.
@@ -431,7 +524,7 @@ interface OperationLog {
431
524
  * @param operationLog - The operation log to fetch operations from
432
525
  * @returns Operations sorted in causal order
433
526
  */
434
- declare function computeDelta(localVector: VersionVector, remoteVector: VersionVector, operationLog: OperationLog): Operation[];
527
+ declare function computeDelta(localVector: VersionVector, remoteVector: VersionVector, operationLog: OperationLog): Promise<Operation[]>;
435
528
  /**
436
529
  * Serialize a version vector to a JSON-compatible string.
437
530
  */
@@ -442,31 +535,44 @@ declare function serializeVector(vector: VersionVector): string;
442
535
  declare function deserializeVector(s: string): VersionVector;
443
536
 
444
537
  /**
445
- * Per-collection scope map: `{ collectionName: { field: value, ... } }`
538
+ * Returns true when the schema declares partial sync rules at the root level.
539
+ */
540
+ declare function hasSchemaSyncRules(schema: SchemaDefinition): boolean;
541
+ /**
542
+ * Resolve field → scope-value-key bindings for a collection.
446
543
  *
447
- * Used to filter which operations a client should receive during sync.
544
+ * Sync rules take precedence over legacy `collection.scope` arrays.
545
+ * Returns `null` when the collection has no sync filtering configured.
448
546
  */
449
- type ScopeMap = Record<string, Record<string, unknown>>;
547
+ declare function getCollectionScopeBindings(schema: SchemaDefinition, collectionName: string): Record<string, string> | null;
450
548
  /**
451
- * Build a per-collection scope map from the schema's scope declarations
452
- * and the client's flat scope values.
549
+ * Returns whether a collection participates in sync filtering for this schema.
550
+ */
551
+ declare function isCollectionSyncScoped(schema: SchemaDefinition, collectionName: string): boolean;
552
+ /**
553
+ * Collect unique scope value keys referenced by sync rules and legacy scope fields.
554
+ */
555
+ declare function collectSchemaScopeValueKeys(schema: SchemaDefinition): string[];
556
+
557
+ /**
558
+ * Collect every unique scope field name declared across all collections.
453
559
  *
454
- * For each collection:
455
- * - If it declares scope fields, build a filter from the matching flat values.
456
- * - If it declares no scope fields, include it with an empty filter (no restriction).
560
+ * @deprecated Use {@link collectSchemaScopeValueKeys} instead.
561
+ */
562
+ declare function collectSchemaScopeFields(schema: SchemaDefinition): string[];
563
+ /**
564
+ * Extract flat scope values from JWT (or auth) claims using schema scope field names.
457
565
  *
458
- * @param schema - The schema definition with scope declarations
459
- * @param scopeValues - Flat key-value scope values from the client
460
- * @returns A per-collection scope map
566
+ * Resolution order for each scope field:
567
+ * 1. Top-level claim with the same name
568
+ * 2. Nested `claims.scope[field]` object
569
+ * 3. `userId` falls back to the standard JWT `sub` claim
461
570
  *
462
- * @example
463
- * ```typescript
464
- * // Schema declares: sales.scope = ['orgId', 'storeId']
465
- * // Client provides: { orgId: 'org-123', storeId: 'store-456' }
466
- * // Result: { sales: { orgId: 'org-123', storeId: 'store-456' }, products: {} }
467
- * ```
571
+ * @param schema - Schema with per-collection scope declarations
572
+ * @param claims - Decoded JWT claims (unverified; client-side scope hints only)
573
+ * @returns Flat key-value map suitable for {@link buildScopeMap}
468
574
  */
469
- declare function buildScopeMap(schema: SchemaDefinition, scopeValues: Record<string, unknown>): ScopeMap;
575
+ declare function extractScopeValuesFromClaims(schema: SchemaDefinition, claims: Record<string, unknown>): Record<string, unknown>;
470
576
 
471
577
  /**
472
578
  * Offline-safe sequence formatting.
@@ -493,6 +599,28 @@ declare function formatSequenceValue(template: string, counter: number, nodeId:
493
599
  */
494
600
  declare function defaultSequenceFormat(name: string): string;
495
601
 
602
+ /**
603
+ * Transforms operations created under an older schema version so they are valid
604
+ * after a schema upgrade. Used during sync when client and server schema versions differ
605
+ * but remain within the server's supported range.
606
+ */
607
+ interface OperationTransform {
608
+ /** Schema version the operation was authored against */
609
+ readonly fromVersion: number;
610
+ /** Target schema version after transformation */
611
+ readonly toVersion: number;
612
+ /**
613
+ * Transform a single operation. Return `null` to drop operations that cannot be migrated.
614
+ */
615
+ transform(operation: Operation): Operation | null;
616
+ }
617
+
618
+ /**
619
+ * Apply registered transforms until the operation matches `targetSchemaVersion`.
620
+ * Returns null when a transform drops the operation or no path exists.
621
+ */
622
+ declare function applyOperationTransforms(operation: Operation, targetSchemaVersion: number, transforms: readonly OperationTransform[]): Operation | null;
623
+
496
624
  /**
497
625
  * Convert migration steps to SQL statements.
498
626
  *
@@ -714,4 +842,4 @@ interface ProtoOutput {
714
842
  */
715
843
  declare function generateProtoDefinitions(schema: SchemaDefinition): ProtoOutput;
716
844
 
717
- export { ArrayFieldBuilder, AtomicOp, type AtomicOpSentinel, AtomicOpType, ClockDriftError, CollectionDefinition, type CollectionInput, type ConstraintInput, CustomResolver, EnumFieldBuilder, FieldBuilder, type FieldKindToType, type InferFieldType, type InferInsertInput, type InferRecord, type InferUpdateInput, KoraError, MergeConflictError, MigrationDefinition, MigrationRollbackError, MigrationStep, Operation, OperationError, type OperationLog, OperationType, type ProtoOutput, RandomSource, RelationDefinition, type RelationInput, type ReversibleMigration, SchemaDefinition, type SchemaInput, SchemaValidationError, type ScopeMap, StateMachineConstraint, type StateMachineInput, StorageError, SyncError, TransitionMap, TransitionValidationResult, type TypedSchemaDefinition, VersionVector, advanceVector, buildScopeMap, buildStateMachineConstraints, canAutoRollback, computeDelta, createReversibleMigration, createVersionVector, defaultSequenceFormat, defineSchema, deserializeVector, dominates, extractTimestamp, formatSequenceValue, generateFullDDL, generateProtoDefinitions, generateRollbackSteps, generateSQL, generateUUIDv7, getTransitionMap, isAtomicOp, isValidUUIDv7, mergeVectors, migrationStepsToSQL, op, resolveAtomicOp, rollbackStepsToSQL, serializeVector, toAtomicOp, validateRecord, validateTransition, vectorsEqual };
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 };