reactronic 0.24.301 → 0.24.303

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.
@@ -1,4 +1,4 @@
1
- export { all, pause } from "./util/Utils.js";
1
+ export { all, pause, proceedSyncOrAsync } from "./util/Utils.js";
2
2
  export { MergeList } from "./util/MergeList.js";
3
3
  export type { MergedItem, MergeListReader } from "./util/MergeList.js";
4
4
  export { SealedArray } from "./util/SealedArray.js";
@@ -1,4 +1,4 @@
1
- export { all, pause } from "./util/Utils.js";
1
+ export { all, pause, proceedSyncOrAsync } from "./util/Utils.js";
2
2
  export { MergeList } from "./util/MergeList.js";
3
3
  export { SealedArray } from "./util/SealedArray.js";
4
4
  export { SealedMap } from "./util/SealedMap.js";
@@ -38,7 +38,7 @@ export declare class Changeset implements AbstractChangeset {
38
38
  static dispose(obj: any): void;
39
39
  static doDispose(ctx: Changeset, h: ObjectHandle): ObjectVersion;
40
40
  private isNewObjectVersionRequired;
41
- acquire(outer: Changeset): void;
41
+ acquire(outer: Changeset): boolean;
42
42
  bumpBy(timestamp: number): void;
43
43
  rebase(): ObjectVersion[] | undefined;
44
44
  private merge;
@@ -52,7 +52,7 @@ export declare class Changeset implements AbstractChangeset {
52
52
  }
53
53
  export declare class Dump {
54
54
  static valueHint: (value: any) => string;
55
- static obj(h: ObjectHandle | undefined, fk?: FieldKey | undefined, stamp?: number, snapshotId?: number, originSnapshotId?: number, value?: any): string;
55
+ static obj(h: ObjectHandle | undefined, fk?: FieldKey | undefined, stamp?: number, changesetId?: number, lastEditorChangesetId?: number, value?: any): string;
56
56
  static snapshot2(h: ObjectHandle, s: AbstractChangeset, fk?: FieldKey, o?: FieldVersion): string;
57
57
  static snapshot(ov: ObjectVersion, fk?: FieldKey): string;
58
58
  static conflicts(conflicts: ObjectVersion[]): string;
@@ -76,7 +76,7 @@ export class Changeset {
76
76
  const revision = fk === Meta.Handle ? 1 : ov.revision + 1;
77
77
  const data = Object.assign({}, fk === Meta.Handle ? value : ov.data);
78
78
  Meta.set(data, Meta.Handle, h);
79
- Meta.set(data, Meta.Revision, new FieldVersion(revision));
79
+ Meta.set(data, Meta.Revision, new FieldVersion(revision, this.id));
80
80
  ov = new ObjectVersion(this, ov, data);
81
81
  this.items.set(h, ov);
82
82
  h.editing = ov;
@@ -95,11 +95,12 @@ export class Changeset {
95
95
  if (existing === undefined || existing.content !== content || sensitivity) {
96
96
  const existingContent = existing === null || existing === void 0 ? void 0 : existing.content;
97
97
  if (ov.former.objectVersion.data[fk] === existing) {
98
- existing = ov.data[fk] = new FieldVersion(content);
98
+ existing = ov.data[fk] = new FieldVersion(content, this.id);
99
99
  Changeset.markEdited(existingContent, content, true, ov, fk, h);
100
100
  }
101
101
  else {
102
102
  existing.content = content;
103
+ existing.lastEditorChangesetId = this.id;
103
104
  Changeset.markEdited(existingContent, content, true, ov, fk, h);
104
105
  }
105
106
  }
@@ -136,7 +137,8 @@ export class Changeset {
136
137
  return ov.changeset !== this && !this.sealed;
137
138
  }
138
139
  acquire(outer) {
139
- if (!this.sealed && this.revision === UNDEFINED_REVISION) {
140
+ const result = !this.sealed && this.revision === UNDEFINED_REVISION;
141
+ if (result) {
140
142
  const ahead = this.options.token === undefined || outer.revision === UNDEFINED_REVISION;
141
143
  this.revision = ahead ? Changeset.stampGen : outer.revision;
142
144
  Changeset.pending.push(this);
@@ -145,6 +147,7 @@ export class Changeset {
145
147
  if (Log.isOn && Log.opt.transaction)
146
148
  Log.write("╔══", `s${this.revision}`, `${this.hint}`);
147
149
  }
150
+ return result;
148
151
  }
149
152
  bumpBy(timestamp) {
150
153
  if (timestamp > this.bumper)
@@ -313,7 +316,7 @@ Changeset.propagateAllChangesThroughSubscriptions = (changeset) => { };
313
316
  Changeset.revokeAllSubscriptions = (changeset) => { };
314
317
  Changeset.enqueueReactiveFunctionsToRun = (reactive) => { };
315
318
  export class Dump {
316
- static obj(h, fk, stamp, snapshotId, originSnapshotId, value) {
319
+ static obj(h, fk, stamp, changesetId, lastEditorChangesetId, value) {
317
320
  const member = fk !== undefined ? `.${fk.toString()}` : "";
318
321
  let result;
319
322
  if (h !== undefined) {
@@ -321,7 +324,7 @@ export class Dump {
321
324
  if (stamp === undefined)
322
325
  result = `${h.hint}${member}${v} #${h.id}`;
323
326
  else
324
- result = `${h.hint}${member}${v} #${h.id}t${snapshotId}s${stamp}${originSnapshotId !== undefined && originSnapshotId !== 0 ? `t${originSnapshotId}` : ""}`;
327
+ result = `${h.hint}${member}${v} #${h.id}t${changesetId}s${stamp}${lastEditorChangesetId !== undefined ? `e${lastEditorChangesetId}` : ""}`;
325
328
  }
326
329
  else
327
330
  result = `boot${member}`;
@@ -329,12 +332,12 @@ export class Dump {
329
332
  }
330
333
  static snapshot2(h, s, fk, o) {
331
334
  var _a;
332
- return Dump.obj(h, fk, s.timestamp, s.id, o === null || o === void 0 ? void 0 : o.originSnapshotId, (_a = o === null || o === void 0 ? void 0 : o.content) !== null && _a !== void 0 ? _a : Meta.Undefined);
335
+ return Dump.obj(h, fk, s.timestamp, s.id, o === null || o === void 0 ? void 0 : o.lastEditorChangesetId, (_a = o === null || o === void 0 ? void 0 : o.content) !== null && _a !== void 0 ? _a : Meta.Undefined);
333
336
  }
334
337
  static snapshot(ov, fk) {
335
338
  const h = Meta.get(ov.data, Meta.Handle);
336
339
  const fv = fk !== undefined ? ov.data[fk] : undefined;
337
- return Dump.obj(h, fk, ov.changeset.timestamp, ov.changeset.id, fv === null || fv === void 0 ? void 0 : fv.originSnapshotId);
340
+ return Dump.obj(h, fk, ov.changeset.timestamp, ov.changeset.id, fv === null || fv === void 0 ? void 0 : fv.lastEditorChangesetId);
338
341
  }
339
342
  static conflicts(conflicts) {
340
343
  return conflicts.map(ours => {
@@ -8,9 +8,9 @@ export type AbstractChangeset = {
8
8
  export declare class FieldVersion<T = any> {
9
9
  content: T;
10
10
  observers?: Set<Observer>;
11
+ lastEditorChangesetId: number;
11
12
  get isLaunch(): boolean;
12
- get originSnapshotId(): number | undefined;
13
- constructor(content: T);
13
+ constructor(content: T, lastEditorChangesetId: number);
14
14
  }
15
15
  export type Observer = {
16
16
  readonly order: number;
@@ -3,8 +3,7 @@ import { Meta } from "./Meta.js";
3
3
  export { Meta } from "./Meta.js";
4
4
  export class FieldVersion {
5
5
  get isLaunch() { return false; }
6
- get originSnapshotId() { return 0; }
7
- constructor(content) { this.content = content; }
6
+ constructor(content, lastEditorChangesetId) { this.content = content; this.lastEditorChangesetId = lastEditorChangesetId; }
8
7
  }
9
8
  export class ObjectVersion {
10
9
  constructor(changeset, former, data) {
@@ -16,9 +16,9 @@ export declare class IndicatorImpl extends Indicator {
16
16
  busyDuration: number;
17
17
  readonly internals: {
18
18
  whenBusy: Promise<void> | undefined;
19
- resolveWhenBusy: ((value?: void | undefined) => void) | undefined;
19
+ resolveWhenBusy: ((value?: void) => void) | undefined;
20
20
  whenIdle: Promise<void> | undefined;
21
- resolveWhenIdle: ((value?: void | undefined) => void) | undefined;
21
+ resolveWhenIdle: ((value?: void) => void) | undefined;
22
22
  started: number;
23
23
  activationDelay: number;
24
24
  activationTimeout: undefined;
@@ -100,7 +100,7 @@ export class JournalImpl extends Journal {
100
100
  const content = undoing ? vp.formerContent : vp.freshContent;
101
101
  const ov = ctx.getEditableObjectVersion(h, fk, content);
102
102
  if (ov.changeset === ctx) {
103
- ov.data[fk] = new FieldVersion(content);
103
+ ov.data[fk] = new FieldVersion(content, ctx.id);
104
104
  const existing = ov.former.objectVersion.data[fk];
105
105
  Changeset.markEdited(existing, content, existing !== content, ov, fk, h);
106
106
  }
@@ -122,7 +122,7 @@ export class Mvcc {
122
122
  }
123
123
  static decorateData(isObservable, proto, fk) {
124
124
  if (isObservable) {
125
- Meta.acquire(proto, Meta.Initial)[fk] = new FieldVersion(undefined);
125
+ Meta.acquire(proto, Meta.Initial)[fk] = new FieldVersion(undefined, 0);
126
126
  const get = function () {
127
127
  const h = Mvcc.acquireHandle(this);
128
128
  return Mvcc.observable.get(h, fk, this);
@@ -181,7 +181,7 @@ export class Mvcc {
181
181
  h = new ObjectHandle(obj, obj, Mvcc.observable, ov, obj.constructor.name);
182
182
  Meta.set(ov.data, Meta.Handle, h);
183
183
  Meta.set(obj, Meta.Handle, h);
184
- Meta.set(ov.data, Meta.Revision, new FieldVersion(1));
184
+ Meta.set(ov.data, Meta.Revision, new FieldVersion(1, 0));
185
185
  }
186
186
  return h;
187
187
  }
@@ -36,6 +36,7 @@ export declare class MvccArray<T> extends MvccObject {
36
36
  reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
37
37
  reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
38
38
  reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;
39
+ find(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): T | undefined;
39
40
  find<S extends T>(predicate: (this: void, value: T, index: number, obj: T[]) => value is S, thisArg?: any): S | undefined;
40
41
  findIndex(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): number;
41
42
  fill(value: T, start?: number, end?: number): this;
@@ -47,12 +47,12 @@ export class MvccArray extends MvccObject {
47
47
  }
48
48
  }
49
49
  export class TransactionalArray extends MvccArray {
50
- constructor(args) {
51
- super(false, args !== undefined ? new Array(args) : new Array());
50
+ constructor(...args) {
51
+ super(false, new Array(...args));
52
52
  }
53
53
  }
54
54
  export class ObservableArray extends MvccArray {
55
- constructor(args) {
56
- super(true, args !== undefined ? new Array(args) : new Array());
55
+ constructor(...args) {
56
+ super(true, new Array(...args));
57
57
  }
58
58
  }
@@ -51,7 +51,6 @@ declare class Launch extends FieldVersion implements Observer {
51
51
  successor: Launch | undefined;
52
52
  constructor(transaction: Transaction, operation: OperationImpl, changeset: AbstractChangeset, former: Launch | OptionsImpl, clone: boolean);
53
53
  get isLaunch(): boolean;
54
- get originSnapshotId(): number;
55
54
  hint(): string;
56
55
  get order(): number;
57
56
  get ["#this#"](): string;
@@ -80,7 +79,7 @@ declare class Launch extends FieldVersion implements Observer {
80
79
  private static revokeAllSubscriptions;
81
80
  private static propagateFieldChangeThroughSubscriptions;
82
81
  private static enqueueReactiveFunctionsToRun;
83
- private static createFieldVersion;
82
+ private static migrateFieldVersion;
84
83
  private static processQueuedReactiveOperations;
85
84
  private unsubscribeFromAllObservables;
86
85
  private subscribeTo;
@@ -194,7 +194,7 @@ export class OperationImpl {
194
194
  }
195
195
  class Launch extends FieldVersion {
196
196
  constructor(transaction, operation, changeset, former, clone) {
197
- super(undefined);
197
+ super(undefined, 0);
198
198
  this.margin = Launch.current ? Launch.current.margin + 1 : 1;
199
199
  this.transaction = transaction;
200
200
  this.operation = operation;
@@ -205,6 +205,7 @@ class Launch extends FieldVersion {
205
205
  this.cause = former.obsoleteDueTo;
206
206
  this.args = former.args;
207
207
  if (clone) {
208
+ this.lastEditorChangesetId = former.lastEditorChangesetId;
208
209
  this.result = former.result;
209
210
  this.error = former.error;
210
211
  this.started = former.started;
@@ -213,6 +214,7 @@ class Launch extends FieldVersion {
213
214
  this.successor = former.successor;
214
215
  }
215
216
  else {
217
+ this.lastEditorChangesetId = changeset.id;
216
218
  this.result = undefined;
217
219
  this.error = undefined;
218
220
  this.started = 0;
@@ -222,6 +224,7 @@ class Launch extends FieldVersion {
222
224
  }
223
225
  }
224
226
  else {
227
+ this.lastEditorChangesetId = changeset.id;
225
228
  this.options = former;
226
229
  this.cause = undefined;
227
230
  this.args = BOOT_ARGS;
@@ -234,8 +237,7 @@ class Launch extends FieldVersion {
234
237
  }
235
238
  }
236
239
  get isLaunch() { return true; }
237
- get originSnapshotId() { return this.changeset.id; }
238
- hint() { return `${Dump.snapshot2(this.operation.ownerHandle, this.changeset, this.operation.fieldKey)}`; }
240
+ hint() { return `${Dump.snapshot2(this.operation.ownerHandle, this.changeset, this.operation.fieldKey, this)}`; }
239
241
  get order() { return this.options.order; }
240
242
  get ["#this#"]() {
241
243
  return `Operation: ${this.why()}`;
@@ -287,7 +289,7 @@ class Launch extends FieldVersion {
287
289
  var _a, _b, _c;
288
290
  if (this.observables !== undefined) {
289
291
  const skip = !observable.isLaunch &&
290
- changeset === this.changeset;
292
+ changeset.id === this.lastEditorChangesetId;
291
293
  if (!skip) {
292
294
  const why = `${Dump.snapshot2(h, changeset, fk, observable)} ◀◀ ${outer}`;
293
295
  const isReactive = this.options.kind === Kind.reactive;
@@ -309,7 +311,7 @@ class Launch extends FieldVersion {
309
311
  tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Dump.snapshot2(h, changeset, fk)} changed by T${changeset.id}[${changeset.hint}]`), null);
310
312
  }
311
313
  else if (Log.isOn && (Log.opt.obsolete || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.obsolete)))
312
- Log.write(" ", "x", `${this.hint()} is not obsolete due to its own change to ${Dump.snapshot2(h, changeset, fk)}`);
314
+ Log.write(" ", "x", `${this.hint()} is not obsolete due to its own change to ${Dump.snapshot2(h, changeset, fk, observable)}`);
313
315
  }
314
316
  }
315
317
  relaunchIfNotUpToDate(now, nothrow) {
@@ -557,12 +559,12 @@ class Launch extends FieldVersion {
557
559
  if (isReactiveLoopRequired)
558
560
  OperationImpl.proceedWithinGivenLaunch(undefined, Launch.processQueuedReactiveOperations);
559
561
  }
560
- static createFieldVersion(fv, target) {
562
+ static migrateFieldVersion(fv, target) {
561
563
  let result;
562
564
  if (fv instanceof Launch)
563
565
  result = new Launch(target, fv.operation, target.changeset, fv, true);
564
566
  else
565
- result = new FieldVersion(fv === null || fv === void 0 ? void 0 : fv.content);
567
+ result = new FieldVersion(fv.content, fv.lastEditorChangesetId);
566
568
  return result;
567
569
  }
568
570
  static processQueuedReactiveOperations() {
@@ -602,14 +604,14 @@ class Launch extends FieldVersion {
602
604
  observable.observers.add(this);
603
605
  this.observables.set(observable, subscription);
604
606
  if (Log.isOn && (Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
605
- Log.write("║", " ∞", `${this.hint()} is subscribed to ${Dump.snapshot2(h, ov.changeset, fk)}${subscription.usageCount > 1 ? ` (${subscription.usageCount} times)` : ""}`);
607
+ Log.write("║", " ∞", `${this.hint()} is subscribed to ${Dump.snapshot2(h, ov.changeset, fk, observable)}${subscription.usageCount > 1 ? ` (${subscription.usageCount} times)` : ""}`);
606
608
  }
607
609
  else if (Log.isOn && (Log.opt.read || ((_b = this.options.logging) === null || _b === void 0 ? void 0 : _b.read)))
608
- Log.write("║", " x", `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h, ov.changeset, fk)}`);
610
+ Log.write("║", " x", `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h, ov.changeset, fk, observable)}`);
609
611
  }
610
612
  else {
611
613
  if (Log.isOn && (Log.opt.read || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.read)))
612
- Log.write("║", " x", `${this.hint()} is NOT subscribed to already obsolete ${Dump.snapshot2(h, ov.changeset, fk)}`);
614
+ Log.write("║", " x", `${this.hint()} is NOT subscribed to already obsolete ${Dump.snapshot2(h, ov.changeset, fk, observable)}`);
613
615
  }
614
616
  return ok;
615
617
  }
@@ -655,7 +657,7 @@ class Launch extends FieldVersion {
655
657
  Changeset.propagateAllChangesThroughSubscriptions = Launch.propagateAllChangesThroughSubscriptions;
656
658
  Changeset.revokeAllSubscriptions = Launch.revokeAllSubscriptions;
657
659
  Changeset.enqueueReactiveFunctionsToRun = Launch.enqueueReactiveFunctionsToRun;
658
- TransactionImpl.createFieldVersion = Launch.createFieldVersion;
660
+ TransactionImpl.migrateFieldVersion = Launch.migrateFieldVersion;
659
661
  Mvcc.createOperation = Launch.createOperation;
660
662
  Mvcc.rememberOperationOptions = Launch.rememberOperationOptions;
661
663
  Promise.prototype.then = reactronicHookedThen;
@@ -693,7 +695,7 @@ function valueHint(value) {
693
695
  else if (value instanceof Map)
694
696
  result = `Map(${value.size})`;
695
697
  else if (value instanceof Launch)
696
- result = `#${value.operation.ownerHandle.id}t${value.changeset.id}s${value.changeset.timestamp}${value.originSnapshotId !== undefined && value.originSnapshotId !== 0 ? `t${value.originSnapshotId}` : ""}`;
698
+ result = `#${value.operation.ownerHandle.id}t${value.changeset.id}s${value.changeset.timestamp}${value.lastEditorChangesetId !== undefined && value.lastEditorChangesetId !== 0 ? `t${value.lastEditorChangesetId}` : ""}`;
697
699
  else if (value === Meta.Undefined)
698
700
  result = "undefined";
699
701
  else if (typeof (value) === "string")
@@ -1,9 +1,9 @@
1
1
  import { LoggingOptions } from "../Logging.js";
2
2
  import { MergeListReader, MergedItem } from "../util/MergeList.js";
3
3
  import { MemberOptions } from "../Options.js";
4
- export type Script<T> = (el: T, basis: () => void) => void;
5
- export type ScriptAsync<T> = (el: T, basis: () => Promise<void>) => Promise<void>;
6
- export type Handler<T = unknown, R = void> = (el: T) => R;
4
+ export type Script<E> = (el: E, basis: () => void) => void;
5
+ export type ScriptAsync<E> = (el: E, basis: () => Promise<void>) => Promise<void>;
6
+ export type Handler<E = unknown, R = void> = (el: E) => R;
7
7
  export declare enum Mode {
8
8
  default = 0,
9
9
  independentUpdate = 1,
@@ -61,6 +61,7 @@ export type RxNodeDecl<E = unknown> = {
61
61
  key?: string;
62
62
  mode?: Mode;
63
63
  creation?: Script<E>;
64
+ creationAsync?: ScriptAsync<E>;
64
65
  destruction?: Script<E>;
65
66
  triggers?: unknown;
66
67
  basis?: RxNodeDecl<E>;
@@ -83,10 +84,10 @@ export type RxNodeContext<T extends Object = Object> = {
83
84
  export declare abstract class BaseDriver<E = unknown> implements RxNodeDriver<E> {
84
85
  readonly name: string;
85
86
  readonly isPartition: boolean;
86
- readonly initialize?: Handler<E, void> | undefined;
87
- constructor(name: string, isPartition: boolean, initialize?: Handler<E, void> | undefined);
87
+ readonly initialize?: Handler<E> | undefined;
88
+ constructor(name: string, isPartition: boolean, initialize?: Handler<E> | undefined);
88
89
  abstract allocate(node: RxNode<E>): E;
89
- create(node: RxNode<E>): void;
90
+ create(node: RxNode<E>): void | Promise<void>;
90
91
  destroy(node: RxNode<E>, isLeader: boolean): boolean;
91
92
  mount(node: RxNode<E>): void;
92
93
  update(node: RxNode<E>): void | Promise<void>;
@@ -16,8 +16,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
16
16
  step((generator = generator.apply(thisArg, _arguments || [])).next());
17
17
  });
18
18
  };
19
+ import { misuse } from "../util/Dbg.js";
19
20
  import { MergeList } from "../util/MergeList.js";
20
- import { emitLetters, getCallerInfo } from "../util/Utils.js";
21
+ import { emitLetters, getCallerInfo, proceedSyncOrAsync } from "../util/Utils.js";
21
22
  import { Isolation, Reentrance } from "../Options.js";
22
23
  import { ObservableObject } from "../core/Mvcc.js";
23
24
  import { Transaction } from "../core/Transaction.js";
@@ -105,7 +106,7 @@ export class RxNode {
105
106
  triggerDeactivation(impl.seat, true, true);
106
107
  }
107
108
  static updateNestedNodesThenDo(action) {
108
- runUpdateNestedNodesThenDo(undefined, action);
109
+ runUpdateNestedNodesThenDo(RxNodeImpl.ownSeat, undefined, action);
109
110
  }
110
111
  static markAsMounted(node, yes) {
111
112
  const n = node;
@@ -152,7 +153,7 @@ export class BaseDriver {
152
153
  create(node) {
153
154
  var _a;
154
155
  (_a = this.initialize) === null || _a === void 0 ? void 0 : _a.call(this, node.element);
155
- invokeCreationUsingBasisChain(node.element, node.declaration);
156
+ return invokeCreationUsingBasisChain(node.element, node.declaration);
156
157
  }
157
158
  destroy(node, isLeader) {
158
159
  invokeDestructionUsingBasisChain(node.element, node.declaration);
@@ -161,7 +162,7 @@ export class BaseDriver {
161
162
  mount(node) {
162
163
  }
163
164
  update(node) {
164
- invokeScriptUsingBasisChain(node.element, node.declaration);
165
+ return invokeScriptUsingBasisChain(node.element, node.declaration);
165
166
  }
166
167
  child(ownerNode, childDriver, childDeclaration, childBasis) {
167
168
  return undefined;
@@ -199,20 +200,40 @@ function getModeUsingBasisChain(declaration) {
199
200
  return (_a = declaration === null || declaration === void 0 ? void 0 : declaration.mode) !== null && _a !== void 0 ? _a : ((declaration === null || declaration === void 0 ? void 0 : declaration.basis) ? getModeUsingBasisChain(declaration === null || declaration === void 0 ? void 0 : declaration.basis) : Mode.default);
200
201
  }
201
202
  function invokeScriptUsingBasisChain(element, declaration) {
203
+ let result = undefined;
202
204
  const basis = declaration.basis;
203
205
  const script = declaration.script;
204
- if (script)
205
- script(element, basis ? () => invokeScriptUsingBasisChain(element, basis) : NOP);
206
+ const scriptAsync = declaration.scriptAsync;
207
+ if (script && scriptAsync) {
208
+ throw misuse("'script' and 'scriptAsync' cannot be defined together");
209
+ }
210
+ if (script) {
211
+ result = script(element, basis ? () => invokeScriptUsingBasisChain(element, basis) : NOP);
212
+ }
213
+ else if (scriptAsync) {
214
+ result = scriptAsync(element, basis ? () => invokeScriptUsingBasisChain(element, basis) : NOP_ASYNC);
215
+ }
206
216
  else if (basis)
207
- invokeScriptUsingBasisChain(element, basis);
217
+ result = invokeScriptUsingBasisChain(element, basis);
218
+ return result;
208
219
  }
209
220
  function invokeCreationUsingBasisChain(element, declaration) {
221
+ let result = undefined;
210
222
  const basis = declaration.basis;
211
223
  const creation = declaration.creation;
212
- if (creation)
213
- creation(element, basis ? () => invokeCreationUsingBasisChain(element, basis) : NOP);
224
+ const creationAsync = declaration.creationAsync;
225
+ if (creation && creationAsync) {
226
+ throw misuse("'creation' and 'creationAsync' cannot be defined together");
227
+ }
228
+ if (creation) {
229
+ result = creation(element, basis ? () => invokeCreationUsingBasisChain(element, basis) : NOP);
230
+ }
231
+ else if (creationAsync) {
232
+ result = creationAsync(element, basis ? () => invokeCreationUsingBasisChain(element, basis) : NOP_ASYNC);
233
+ }
214
234
  else if (basis)
215
- invokeCreationUsingBasisChain(element, basis);
235
+ result = invokeCreationUsingBasisChain(element, basis);
236
+ return result;
216
237
  }
217
238
  function invokeDestructionUsingBasisChain(element, declaration) {
218
239
  const basis = declaration.basis;
@@ -344,49 +365,50 @@ __decorate([
344
365
  function getNodeKey(node) {
345
366
  return node.stamp >= 0 ? node.key : undefined;
346
367
  }
347
- function runUpdateNestedNodesThenDo(error, action) {
348
- var _a;
349
- const ownSeat = RxNodeImpl.ownSeat;
350
- const owner = ownSeat.instance;
351
- const children = owner.children;
352
- if (children.isMergeInProgress) {
353
- let promised = undefined;
354
- try {
355
- children.endMerge(error);
356
- for (const child of children.removedItems(true))
357
- triggerDeactivation(child, true, true);
358
- if (!error) {
359
- const sequential = children.isStrict;
360
- let p1 = undefined;
361
- let p2 = undefined;
362
- let mounting = false;
363
- let partition = owner;
364
- for (const child of children.items()) {
365
- if (Transaction.isCanceled)
366
- break;
367
- const childNode = child.instance;
368
- const isPart = childNode.driver.isPartition;
369
- const host = isPart ? owner : partition;
370
- mounting = markToMountIfNecessary(mounting, host, child, children, sequential);
371
- const p = (_a = childNode.priority) !== null && _a !== void 0 ? _a : Priority.realtime;
372
- if (p === Priority.realtime)
373
- triggerUpdateViaSeat(child);
374
- else if (p === Priority.normal)
375
- p1 = push(child, p1);
376
- else
377
- p2 = push(child, p2);
378
- if (isPart)
379
- partition = childNode;
368
+ function runUpdateNestedNodesThenDo(ownSeat, error, action) {
369
+ runInside(ownSeat, () => {
370
+ var _a;
371
+ const owner = ownSeat.instance;
372
+ const children = owner.children;
373
+ if (children.isMergeInProgress) {
374
+ let promised = undefined;
375
+ try {
376
+ children.endMerge(error);
377
+ for (const child of children.removedItems(true))
378
+ triggerDeactivation(child, true, true);
379
+ if (!error) {
380
+ const sequential = children.isStrict;
381
+ let p1 = undefined;
382
+ let p2 = undefined;
383
+ let mounting = false;
384
+ let partition = owner;
385
+ for (const child of children.items()) {
386
+ if (Transaction.isCanceled)
387
+ break;
388
+ const childNode = child.instance;
389
+ const isPart = childNode.driver.isPartition;
390
+ const host = isPart ? owner : partition;
391
+ mounting = markToMountIfNecessary(mounting, host, child, children, sequential);
392
+ const p = (_a = childNode.priority) !== null && _a !== void 0 ? _a : Priority.realtime;
393
+ if (p === Priority.realtime)
394
+ triggerUpdateViaSeat(child);
395
+ else if (p === Priority.normal)
396
+ p1 = push(child, p1);
397
+ else
398
+ p2 = push(child, p2);
399
+ if (isPart)
400
+ partition = childNode;
401
+ }
402
+ if (!Transaction.isCanceled && (p1 !== undefined || p2 !== undefined))
403
+ promised = startIncrementalUpdate(ownSeat, children, p1, p2).then(() => action(error), e => action(e));
380
404
  }
381
- if (!Transaction.isCanceled && (p1 !== undefined || p2 !== undefined))
382
- promised = startIncrementalUpdate(ownSeat, children, p1, p2).then(() => action(error), e => action(e));
405
+ }
406
+ finally {
407
+ if (!promised)
408
+ action(error);
383
409
  }
384
410
  }
385
- finally {
386
- if (!promised)
387
- action(error);
388
- }
389
- }
411
+ });
390
412
  }
391
413
  function markToMountIfNecessary(mounting, host, seat, children, sequential) {
392
414
  const node = seat.instance;
@@ -489,13 +511,10 @@ function updateNow(seat) {
489
511
  node.children.beginMerge();
490
512
  const driver = node.driver;
491
513
  result = driver.update(node);
492
- if (result instanceof Promise)
493
- result.then(v => { runUpdateNestedNodesThenDo(undefined, NOP); return v; }, e => { console.log(e); runUpdateNestedNodesThenDo(e !== null && e !== void 0 ? e : new Error("unknown error"), NOP); });
494
- else
495
- runUpdateNestedNodesThenDo(undefined, NOP);
514
+ result = proceedSyncOrAsync(result, v => { runUpdateNestedNodesThenDo(seat, undefined, NOP); return v; }, e => { console.log(e); runUpdateNestedNodesThenDo(seat, e !== null && e !== void 0 ? e : new Error("unknown error"), NOP); });
496
515
  }
497
516
  catch (e) {
498
- runUpdateNestedNodesThenDo(e, NOP);
517
+ runUpdateNestedNodesThenDo(seat, e, NOP);
499
518
  console.log(`Update failed: ${node.key}`);
500
519
  console.log(`${e}`);
501
520
  }
@@ -613,6 +632,7 @@ function defaultReject(error) {
613
632
  }
614
633
  Promise.prototype.then = reactronicDomHookedThen;
615
634
  const NOP = (...args) => { };
635
+ const NOP_ASYNC = (...args) => __awaiter(void 0, void 0, void 0, function* () { });
616
636
  let gOwnSeat = undefined;
617
637
  let gFirstToDispose = undefined;
618
638
  let gLastToDispose = undefined;
@@ -62,7 +62,7 @@ export declare class TransactionImpl extends Transaction {
62
62
  cancel(error: Error, restartAfter?: Worker | null): this;
63
63
  get isCanceled(): boolean;
64
64
  get isFinished(): boolean;
65
- whenFinished(): Promise<void>;
65
+ whenFinished(includingParent?: boolean): Promise<void>;
66
66
  static run<T>(options: SnapshotOptions | null, func: F<T>, ...args: any[]): T;
67
67
  static isolate<T>(func: F<T>, ...args: any[]): T;
68
68
  static outside<T>(func: F<T>, ...args: any[]): T;
@@ -84,6 +84,6 @@ export declare class TransactionImpl extends Transaction {
84
84
  private acquirePromise;
85
85
  private static getCurrentChangeset;
86
86
  private static getEditableChangeset;
87
- static createFieldVersion: (fv: FieldVersion, target: Transaction) => FieldVersion;
87
+ static migrateFieldVersion: (fv: FieldVersion, target: Transaction) => FieldVersion;
88
88
  static _init(): void;
89
89
  }
@@ -108,9 +108,11 @@ export class TransactionImpl extends Transaction {
108
108
  get isFinished() {
109
109
  return this.sealed && this.pending === 0;
110
110
  }
111
- whenFinished() {
111
+ whenFinished(includingParent) {
112
112
  return __awaiter(this, void 0, void 0, function* () {
113
- if (!this.isFinished)
113
+ if (includingParent && this.parent)
114
+ yield this.parent.whenFinished(includingParent);
115
+ else if (!this.isFinished)
114
116
  yield this.acquirePromise();
115
117
  });
116
118
  }
@@ -209,6 +211,7 @@ export class TransactionImpl extends Transaction {
209
211
  runImpl(logging, func, ...args) {
210
212
  let result;
211
213
  const outer = TransactionImpl.curr;
214
+ const p = this.parent;
212
215
  try {
213
216
  if (outer === TransactionImpl.none) {
214
217
  TransactionImpl.frameStartTime = performance.now();
@@ -216,7 +219,9 @@ export class TransactionImpl extends Transaction {
216
219
  }
217
220
  TransactionImpl.curr = this;
218
221
  this.pending++;
219
- this.changeset.acquire(outer.changeset);
222
+ const acquired = this.changeset.acquire(outer.changeset);
223
+ if (acquired && p)
224
+ p.run(() => p.pending++);
220
225
  result = func(...args);
221
226
  if (this.sealed && this.pending === 1) {
222
227
  if (!this.canceled)
@@ -234,6 +239,8 @@ export class TransactionImpl extends Transaction {
234
239
  this.pending--;
235
240
  if (this.sealed && this.pending === 0) {
236
241
  const reactive = this.applyOrDiscard();
242
+ if (p)
243
+ p.runImpl(undefined, () => p.pending--);
237
244
  TransactionImpl.curr = outer;
238
245
  TransactionImpl.outside(Changeset.enqueueReactiveFunctionsToRun, reactive);
239
246
  }
@@ -312,9 +319,17 @@ export class TransactionImpl extends Transaction {
312
319
  if (Log.opt.transaction)
313
320
  Log.write(changeset.timestamp < UNDEFINED_REVISION ? "╚══" : "═══", `s${this.timestamp}`, `${this.hint} - ${error ? "CANCEL" : "APPLY"}(${this.changeset.items.size})${error ? ` - ${error}` : ""}`);
314
321
  }
315
- if (!error && !this.parent)
322
+ let obsolete = changeset.obsolete;
323
+ if (changeset.parent) {
324
+ if (changeset.obsolete.length > 0) {
325
+ for (const o of changeset.obsolete)
326
+ changeset.parent.obsolete.push(o);
327
+ obsolete = [];
328
+ }
329
+ }
330
+ else if (!error)
316
331
  Changeset.propagateAllChangesThroughSubscriptions(changeset);
317
- return changeset.obsolete;
332
+ return obsolete;
318
333
  }
319
334
  applyObjectChanges(h, ov) {
320
335
  const parent = this.parent;
@@ -342,7 +357,7 @@ export class TransactionImpl extends Transaction {
342
357
  const fv = ov.data[fk];
343
358
  const fvParent = ovParent.data[fk];
344
359
  if (fv.isLaunch) {
345
- const migrated = TransactionImpl.createFieldVersion(fv, tParent);
360
+ const migrated = TransactionImpl.migrateFieldVersion(fv, tParent);
346
361
  if (ovParent.former.objectVersion.data[fk] !== fvParent) {
347
362
  let observers = fvParent.observers;
348
363
  if (observers) {
@@ -462,7 +477,7 @@ TransactionImpl.curr = TransactionImpl.none;
462
477
  TransactionImpl.inspection = false;
463
478
  TransactionImpl.frameStartTime = 0;
464
479
  TransactionImpl.frameOverCounter = 0;
465
- TransactionImpl.createFieldVersion = function (fv, target) {
480
+ TransactionImpl.migrateFieldVersion = function (fv, target) {
466
481
  throw misuse("this implementation of cloneLaunch should never be called");
467
482
  };
468
483
  TransactionImpl._init();
@@ -7,6 +7,7 @@ export declare class Utils {
7
7
  export declare function UNDEF(...args: any[]): never;
8
8
  export declare function all(promises: Array<Promise<any>>): Promise<any[]>;
9
9
  export declare function pause<T>(timeout: number): Promise<T>;
10
+ export declare function proceedSyncOrAsync<T>(result: T | Promise<T>, success: (v: any) => T, failure: (e: any) => T): T | Promise<T>;
10
11
  export declare function emitLetters(n: number): string;
11
12
  export declare function objectHasMember<T>(obj: any, member: string): obj is T;
12
13
  export declare function getCallerInfo(prefix: string): string;
@@ -53,6 +53,14 @@ export function pause(timeout) {
53
53
  setTimeout(resolve.bind(null, () => resolve), timeout);
54
54
  });
55
55
  }
56
+ export function proceedSyncOrAsync(result, success, failure) {
57
+ let r;
58
+ if (result instanceof Promise)
59
+ r = result.then(v => success(v), e => failure(e));
60
+ else
61
+ r = success(result);
62
+ return r;
63
+ }
56
64
  export function emitLetters(n) {
57
65
  if (n < 0)
58
66
  throw new Error(`emitLetters: argument (${n}) should not be negative or zero`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactronic",
3
- "version": "0.24.301",
3
+ "version": "0.24.303",
4
4
  "description": "Reactronic - Transactional Reactive State Management",
5
5
  "publisher": "Nezaboodka Software",
6
6
  "license": "Apache-2.0",
@@ -40,7 +40,7 @@
40
40
  "eslint": "8.57.0",
41
41
  "react": "18.3.1",
42
42
  "ts-node": "10.9.2",
43
- "typescript": "5.3.2"
43
+ "typescript": "5.5.4"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "eslint source/**.ts test/**.test.ts react/**.tsx && tsc",