@korajs/core 1.0.0-beta.2 → 1.0.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +55 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -1
- package/dist/index.d.ts +49 -1
- package/dist/index.js +53 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -359,6 +359,20 @@ interface AtomicOpSentinel {
|
|
|
359
359
|
* @returns true if the value is an AtomicOpSentinel
|
|
360
360
|
*/
|
|
361
361
|
declare function isAtomicOp(value: unknown): value is AtomicOpSentinel;
|
|
362
|
+
/**
|
|
363
|
+
* Apply a plain atomic op (`{ type, value }`) to a current value, producing the
|
|
364
|
+
* concrete result. This is the single source of truth for atomic-op semantics:
|
|
365
|
+
* {@link resolveAtomicOp} (sentinel form, used on the write path) delegates here,
|
|
366
|
+
* and the server's materialization replays stored atomic ops through it, so the
|
|
367
|
+
* server's materialized view composes concurrent atomic writes identically to the
|
|
368
|
+
* client. Folding this over a field's writes in HLC order yields, for a same-type
|
|
369
|
+
* atomic chain, exactly the composed intent (sum of increments, max of maxes, ...).
|
|
370
|
+
*
|
|
371
|
+
* @param currentValue - The current value of the field
|
|
372
|
+
* @param atomicOp - The atomic op to apply (type + operand)
|
|
373
|
+
* @returns The resulting concrete value
|
|
374
|
+
*/
|
|
375
|
+
declare function applyAtomicOp(currentValue: unknown, atomicOp: AtomicOp): unknown;
|
|
362
376
|
/**
|
|
363
377
|
* Resolve an atomic op sentinel against a current value to produce a concrete result.
|
|
364
378
|
*
|
|
@@ -437,6 +451,40 @@ declare const op: {
|
|
|
437
451
|
*/
|
|
438
452
|
declare function toAtomicOp(sentinel: AtomicOpSentinel): AtomicOp;
|
|
439
453
|
|
|
454
|
+
/** One operation's contribution to a record's materialized state. */
|
|
455
|
+
interface ReplayOperation {
|
|
456
|
+
type: string;
|
|
457
|
+
data: Record<string, unknown> | null;
|
|
458
|
+
/**
|
|
459
|
+
* Atomic-op intents carried by this operation, per field. When present, a field
|
|
460
|
+
* is composed (rather than overwritten) if the previous writer on that field was
|
|
461
|
+
* an atomic op of the same type. Absent means every field resolves by
|
|
462
|
+
* last-write-wins.
|
|
463
|
+
*/
|
|
464
|
+
atomicOps?: Record<string, AtomicOp> | null;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Replay a list of operations (MUST be pre-sorted in HLC total order —
|
|
468
|
+
* wallTime, then logical, then nodeId) to produce the current state of a single
|
|
469
|
+
* record, composing atomic-op intents.
|
|
470
|
+
*
|
|
471
|
+
* Per field, an atomic op composes onto the running value only when the field's
|
|
472
|
+
* previous writer was an atomic op of the SAME type (a same-type atomic chain:
|
|
473
|
+
* concurrent increments sum, maxes take the max, appends accumulate); any other
|
|
474
|
+
* write, including the first atomic write after a plain set, resolves by
|
|
475
|
+
* last-write-wins on the resolved value. Because operations are folded in HLC order,
|
|
476
|
+
* the current op always wins that last-write-wins comparison, so the result is
|
|
477
|
+
* deterministic and identical on every replica that folds the same operation set.
|
|
478
|
+
*
|
|
479
|
+
* This is the single definition of atomic materialization shared by the client
|
|
480
|
+
* (`@korajs/store` apply pipeline) and the server (`@korajs/server` materialization),
|
|
481
|
+
* so both converge to the same value for any number of concurrent atomic writers.
|
|
482
|
+
*
|
|
483
|
+
* Returns the record field data (without `id`) or null if the record was deleted
|
|
484
|
+
* or never inserted.
|
|
485
|
+
*/
|
|
486
|
+
declare function replayOperationsForRecord(ops: ReplayOperation[]): Record<string, unknown> | null;
|
|
487
|
+
|
|
440
488
|
/**
|
|
441
489
|
* Canonical JSON-safe encoding of binary bytes stored inside `op.data` /
|
|
442
490
|
* `op.previousData` (currently richtext field values). A raw Uint8Array
|
|
@@ -1077,4 +1125,4 @@ interface ProtoOutput {
|
|
|
1077
1125
|
*/
|
|
1078
1126
|
declare function generateProtoDefinitions(schema: SchemaDefinition): ProtoOutput;
|
|
1079
1127
|
|
|
1080
|
-
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, quoteIdent, resolveAtomicOp, revealSecret, rollbackStepsToSQL, serializeVector, toAtomicOp, transformSecretFieldsForWrite, validateRecord, validateTransition, vectorsEqual, verifySecret, verifySecretValue };
|
|
1128
|
+
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 ReplayOperation, type ReversibleMigration, SchemaDefinition, type SchemaInput, SchemaValidationError, type SecretKeyProvider, StateMachineConstraint, type StateMachineInput, StorageError, SyncError, TransitionMap, TransitionValidationResult, type TypedSchemaDefinition, VersionVector, advanceVector, applyAtomicOp, 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, quoteIdent, replayOperationsForRecord, resolveAtomicOp, revealSecret, rollbackStepsToSQL, serializeVector, toAtomicOp, transformSecretFieldsForWrite, validateRecord, validateTransition, vectorsEqual, verifySecret, verifySecretValue };
|
package/dist/index.d.ts
CHANGED
|
@@ -359,6 +359,20 @@ interface AtomicOpSentinel {
|
|
|
359
359
|
* @returns true if the value is an AtomicOpSentinel
|
|
360
360
|
*/
|
|
361
361
|
declare function isAtomicOp(value: unknown): value is AtomicOpSentinel;
|
|
362
|
+
/**
|
|
363
|
+
* Apply a plain atomic op (`{ type, value }`) to a current value, producing the
|
|
364
|
+
* concrete result. This is the single source of truth for atomic-op semantics:
|
|
365
|
+
* {@link resolveAtomicOp} (sentinel form, used on the write path) delegates here,
|
|
366
|
+
* and the server's materialization replays stored atomic ops through it, so the
|
|
367
|
+
* server's materialized view composes concurrent atomic writes identically to the
|
|
368
|
+
* client. Folding this over a field's writes in HLC order yields, for a same-type
|
|
369
|
+
* atomic chain, exactly the composed intent (sum of increments, max of maxes, ...).
|
|
370
|
+
*
|
|
371
|
+
* @param currentValue - The current value of the field
|
|
372
|
+
* @param atomicOp - The atomic op to apply (type + operand)
|
|
373
|
+
* @returns The resulting concrete value
|
|
374
|
+
*/
|
|
375
|
+
declare function applyAtomicOp(currentValue: unknown, atomicOp: AtomicOp): unknown;
|
|
362
376
|
/**
|
|
363
377
|
* Resolve an atomic op sentinel against a current value to produce a concrete result.
|
|
364
378
|
*
|
|
@@ -437,6 +451,40 @@ declare const op: {
|
|
|
437
451
|
*/
|
|
438
452
|
declare function toAtomicOp(sentinel: AtomicOpSentinel): AtomicOp;
|
|
439
453
|
|
|
454
|
+
/** One operation's contribution to a record's materialized state. */
|
|
455
|
+
interface ReplayOperation {
|
|
456
|
+
type: string;
|
|
457
|
+
data: Record<string, unknown> | null;
|
|
458
|
+
/**
|
|
459
|
+
* Atomic-op intents carried by this operation, per field. When present, a field
|
|
460
|
+
* is composed (rather than overwritten) if the previous writer on that field was
|
|
461
|
+
* an atomic op of the same type. Absent means every field resolves by
|
|
462
|
+
* last-write-wins.
|
|
463
|
+
*/
|
|
464
|
+
atomicOps?: Record<string, AtomicOp> | null;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Replay a list of operations (MUST be pre-sorted in HLC total order —
|
|
468
|
+
* wallTime, then logical, then nodeId) to produce the current state of a single
|
|
469
|
+
* record, composing atomic-op intents.
|
|
470
|
+
*
|
|
471
|
+
* Per field, an atomic op composes onto the running value only when the field's
|
|
472
|
+
* previous writer was an atomic op of the SAME type (a same-type atomic chain:
|
|
473
|
+
* concurrent increments sum, maxes take the max, appends accumulate); any other
|
|
474
|
+
* write, including the first atomic write after a plain set, resolves by
|
|
475
|
+
* last-write-wins on the resolved value. Because operations are folded in HLC order,
|
|
476
|
+
* the current op always wins that last-write-wins comparison, so the result is
|
|
477
|
+
* deterministic and identical on every replica that folds the same operation set.
|
|
478
|
+
*
|
|
479
|
+
* This is the single definition of atomic materialization shared by the client
|
|
480
|
+
* (`@korajs/store` apply pipeline) and the server (`@korajs/server` materialization),
|
|
481
|
+
* so both converge to the same value for any number of concurrent atomic writers.
|
|
482
|
+
*
|
|
483
|
+
* Returns the record field data (without `id`) or null if the record was deleted
|
|
484
|
+
* or never inserted.
|
|
485
|
+
*/
|
|
486
|
+
declare function replayOperationsForRecord(ops: ReplayOperation[]): Record<string, unknown> | null;
|
|
487
|
+
|
|
440
488
|
/**
|
|
441
489
|
* Canonical JSON-safe encoding of binary bytes stored inside `op.data` /
|
|
442
490
|
* `op.previousData` (currently richtext field values). A raw Uint8Array
|
|
@@ -1077,4 +1125,4 @@ interface ProtoOutput {
|
|
|
1077
1125
|
*/
|
|
1078
1126
|
declare function generateProtoDefinitions(schema: SchemaDefinition): ProtoOutput;
|
|
1079
1127
|
|
|
1080
|
-
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, quoteIdent, resolveAtomicOp, revealSecret, rollbackStepsToSQL, serializeVector, toAtomicOp, transformSecretFieldsForWrite, validateRecord, validateTransition, vectorsEqual, verifySecret, verifySecretValue };
|
|
1128
|
+
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 ReplayOperation, type ReversibleMigration, SchemaDefinition, type SchemaInput, SchemaValidationError, type SecretKeyProvider, StateMachineConstraint, type StateMachineInput, StorageError, SyncError, TransitionMap, TransitionValidationResult, type TypedSchemaDefinition, VersionVector, advanceVector, applyAtomicOp, 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, quoteIdent, replayOperationsForRecord, resolveAtomicOp, revealSecret, rollbackStepsToSQL, serializeVector, toAtomicOp, transformSecretFieldsForWrite, validateRecord, validateTransition, vectorsEqual, verifySecret, verifySecretValue };
|
package/dist/index.js
CHANGED
|
@@ -365,32 +365,36 @@ var KORA_ATOMIC_OP = /* @__PURE__ */ Symbol.for("kora.atomic_op");
|
|
|
365
365
|
function isAtomicOp(value) {
|
|
366
366
|
return typeof value === "object" && value !== null && KORA_ATOMIC_OP in value && value[KORA_ATOMIC_OP] === true;
|
|
367
367
|
}
|
|
368
|
-
function
|
|
369
|
-
switch (
|
|
368
|
+
function applyAtomicOp(currentValue, atomicOp) {
|
|
369
|
+
switch (atomicOp.type) {
|
|
370
370
|
case "increment": {
|
|
371
371
|
const current = typeof currentValue === "number" ? currentValue : 0;
|
|
372
|
-
const operand =
|
|
372
|
+
const operand = atomicOp.value;
|
|
373
373
|
return current + operand;
|
|
374
374
|
}
|
|
375
375
|
case "max": {
|
|
376
376
|
const current = typeof currentValue === "number" ? currentValue : Number.NEGATIVE_INFINITY;
|
|
377
|
-
return Math.max(current,
|
|
377
|
+
return Math.max(current, atomicOp.value);
|
|
378
378
|
}
|
|
379
379
|
case "min": {
|
|
380
380
|
const current = typeof currentValue === "number" ? currentValue : Number.POSITIVE_INFINITY;
|
|
381
|
-
return Math.min(current,
|
|
381
|
+
return Math.min(current, atomicOp.value);
|
|
382
382
|
}
|
|
383
383
|
case "append": {
|
|
384
384
|
const current = Array.isArray(currentValue) ? [...currentValue] : [];
|
|
385
|
-
current.push(
|
|
385
|
+
current.push(atomicOp.value);
|
|
386
386
|
return current;
|
|
387
387
|
}
|
|
388
388
|
case "remove": {
|
|
389
389
|
if (!Array.isArray(currentValue)) return [];
|
|
390
|
-
|
|
390
|
+
const target = JSON.stringify(atomicOp.value);
|
|
391
|
+
return currentValue.filter((item) => JSON.stringify(item) !== target);
|
|
391
392
|
}
|
|
392
393
|
}
|
|
393
394
|
}
|
|
395
|
+
function resolveAtomicOp(currentValue, sentinel) {
|
|
396
|
+
return applyAtomicOp(currentValue, { type: sentinel.type, value: sentinel.value });
|
|
397
|
+
}
|
|
394
398
|
function createSentinel(type, value) {
|
|
395
399
|
return Object.freeze({
|
|
396
400
|
[KORA_ATOMIC_OP]: true,
|
|
@@ -458,6 +462,46 @@ function toAtomicOp(sentinel) {
|
|
|
458
462
|
return { type: sentinel.type, value: sentinel.value };
|
|
459
463
|
}
|
|
460
464
|
|
|
465
|
+
// src/operations/replay-record.ts
|
|
466
|
+
function replayOperationsForRecord(ops) {
|
|
467
|
+
let record = null;
|
|
468
|
+
let deleted = false;
|
|
469
|
+
const lastWriterKind = {};
|
|
470
|
+
for (const op2 of ops) {
|
|
471
|
+
switch (op2.type) {
|
|
472
|
+
case "insert":
|
|
473
|
+
if (op2.data) {
|
|
474
|
+
record = { ...op2.data };
|
|
475
|
+
deleted = false;
|
|
476
|
+
for (const field of Object.keys(op2.data)) {
|
|
477
|
+
lastWriterKind[field] = "lww";
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
break;
|
|
481
|
+
case "update":
|
|
482
|
+
if (op2.data) {
|
|
483
|
+
const next = { ...record ?? {} };
|
|
484
|
+
for (const [field, value] of Object.entries(op2.data)) {
|
|
485
|
+
const atomicOp = op2.atomicOps?.[field];
|
|
486
|
+
if (atomicOp && lastWriterKind[field] === `atomic:${atomicOp.type}`) {
|
|
487
|
+
next[field] = applyAtomicOp(next[field], atomicOp);
|
|
488
|
+
} else {
|
|
489
|
+
next[field] = value;
|
|
490
|
+
}
|
|
491
|
+
lastWriterKind[field] = atomicOp ? `atomic:${atomicOp.type}` : "lww";
|
|
492
|
+
}
|
|
493
|
+
record = next;
|
|
494
|
+
deleted = false;
|
|
495
|
+
}
|
|
496
|
+
break;
|
|
497
|
+
case "delete":
|
|
498
|
+
deleted = true;
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return deleted ? null : record;
|
|
503
|
+
}
|
|
504
|
+
|
|
461
505
|
// src/operations/op-data-binary.ts
|
|
462
506
|
function isKoraBytesValue(value) {
|
|
463
507
|
if (typeof value !== "object" || value === null) {
|
|
@@ -2561,6 +2605,7 @@ export {
|
|
|
2561
2605
|
StorageError,
|
|
2562
2606
|
SyncError,
|
|
2563
2607
|
advanceVector,
|
|
2608
|
+
applyAtomicOp,
|
|
2564
2609
|
applyOperationTransforms,
|
|
2565
2610
|
base64ToBytes,
|
|
2566
2611
|
buildScopeMap,
|
|
@@ -2610,6 +2655,7 @@ export {
|
|
|
2610
2655
|
migrationStepsToSQL,
|
|
2611
2656
|
op,
|
|
2612
2657
|
quoteIdent,
|
|
2658
|
+
replayOperationsForRecord,
|
|
2613
2659
|
resolveAtomicOp,
|
|
2614
2660
|
revealSecret,
|
|
2615
2661
|
rollbackStepsToSQL,
|